//# CalSet.cc: Implementation of Calibration parameter cache
//# Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003
//# Associated Universities, Inc. Washington DC, USA.
//#
//# This library is free software; you can redistribute it and/or modify it
//# under the terms of the GNU Library General Public License as published by
//# the Free Software Foundation; either version 2 of the License, or (at your
//# option) any later version.
//#
//# This library is distributed in the hope that it will be useful, but WITHOUT
//# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
//# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
//# License for more details.
//#
//# You should have received a copy of the GNU Library General Public License
//# along with this library; if not, write to the Free Software Foundation,
//# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
//#
//# Correspondence concerning AIPS++ should be addressed as follows:
//#        Internet email: aips2-request@nrao.edu.
//#        Postal address: AIPS++ Project Office
//#                        National Radio Astronomy Observatory
//#                        520 Edgemont Road
//#                        Charlottesville, VA 22903-2475 USA
//#

#include <algorithm>
#include <synthesis/CalTables/CalSet.h>

#include <synthesis/CalTables/CalTable2.h>
//#include <synthesis/CalTables/CalTable.h>
#include <synthesis/CalTables/CalDescColumns2.h>
#include <synthesis/CalTables/SolvableVJTable.h>
#include <synthesis/CalTables/CalMainColumns2.h>

#include <synthesis/CalTables/TimeVarVJDesc.h>
#include <synthesis/CalTables/SolvableVJDesc.h>
#include <synthesis/CalTables/SolvableVJMRec.h>
#include <synthesis/CalTables/SolvableVJMCol.h>

#include <casacore/tables/Tables/TableDesc.h>
#include <casacore/tables/Tables/SetupNewTab.h>
#include <casacore/tables/Tables/Table.h>
#include <casacore/tables/Tables/ScaColDesc.h>
#include <casacore/tables/Tables/ArrColDesc.h>
#include <casacore/tables/Tables/ScalarColumn.h>
#include <casacore/tables/Tables/ArrayColumn.h>
#include <casacore/tables/Tables/RefRows.h>

#include <casacore/casa/Arrays.h>
#include <casacore/scimath/Mathematics/MatrixMathLA.h>
#include <casacore/casa/BasicSL/String.h>
#include <casacore/casa/Utilities/Assert.h>
#include <casacore/casa/OS/Timer.h>
#include <casacore/casa/Exceptions/Error.h>
#include <casacore/casa/OS/Path.h>
#include <casacore/casa/sstream.h>

#include <casacore/casa/Logging/LogMessage.h>
#include <casacore/casa/Logging/LogSink.h>

namespace casa { //# NAMESPACE CASA - BEGIN

// ------------------------------------------------------------------

// From shape only, this is the solve context
template<class T> CalSet<T>::CalSet(const casacore::Int& nSpw) :
  calTableName_(""),
  nSpw_(nSpw),
  nPar_(0),
  nChan_(0),
  nElem_(0),
  nTime_(0),
  spwOK_(nSpw_,false),
  startChan_(nSpw_,0),  
  freq_(nSpw_,NULL),
  MJDStart_(nSpw_,NULL),
  MJDStop_(nSpw_,NULL),
  MJDTimeStamp_(nSpw_,NULL),
  fieldId_(nSpw_,NULL),
  fieldName_(nSpw_,NULL),
  sourceName_(nSpw_,NULL),
  par_(nSpw_,NULL),
  parOK_(nSpw_,NULL),
  parErr_(nSpw_,NULL),
  parSNR_(nSpw_,NULL),
  //  iSolutionOK_(nSpw_,NULL),
  iFit_(nSpw_,NULL),
  iFitwt_(nSpw_,NULL),
  solutionOK_(nSpw_,NULL),
  fit_(nSpw_,NULL),
  fitwt_(nSpw_,NULL)
{
  calTabDesc_=NULL;
  calTab_=NULL;
  svjmcol_=NULL;
};

// From shape only, this is the solve context
template<class T> CalSet<T>::CalSet(const casacore::Int& nSpw,
				    const casacore::Int& nPar,
				    const casacore::Vector<casacore::Int>& nChan,
				    const casacore::Int& nElem,
				    const casacore::Vector<casacore::Int>& nTime) :
  calTableName_(""),
  nSpw_(nSpw),
  nPar_(nPar),
  nChan_(nChan),
  nElem_(nElem),
  nTime_(nTime),
  spwOK_(nSpw_,false),
  startChan_(nSpw_,0),  
  freq_(nSpw_,NULL),
  MJDStart_(nSpw_,NULL),
  MJDStop_(nSpw_,NULL),
  MJDTimeStamp_(nSpw_,NULL),
  fieldId_(nSpw_,NULL),
  fieldName_(nSpw_,NULL),
  sourceName_(nSpw_,NULL),
  par_(nSpw_,NULL),
  parOK_(nSpw_,NULL),
  parErr_(nSpw_,NULL),
  parSNR_(nSpw_,NULL),
  //  iSolutionOK_(nSpw_,NULL),
  iFit_(nSpw_,NULL),
  iFitwt_(nSpw_,NULL),
  solutionOK_(nSpw_,NULL),
  fit_(nSpw_,NULL),
  fitwt_(nSpw_,NULL)
{
  calTabDesc_=NULL;
  calTab_=NULL;
  svjmcol_=NULL;
  // Resize caches
  inflate();  
};


// From existing CalTable name, this is apply context
template<class T> CalSet<T>::CalSet(const casacore::String& calTableName,
				    const casacore::String& select,
				    const casacore::Int& nSpw,
				    const casacore::Int& nPar,
				    const casacore::Int& nElem) : 
  calTableName_(calTableName),
  nSpw_(nSpw),
  nPar_(nPar),
  nChan_(nSpw,0),
  nElem_(nElem),
  nTime_(nSpw,0),
  spwOK_(nSpw_,false),
  startChan_(nSpw_,0),  
  freq_(nSpw_,NULL),
  MJDStart_(nSpw_,NULL),
  MJDStop_(nSpw_,NULL),
  MJDTimeStamp_(nSpw_,NULL),
  fieldId_(nSpw_,NULL),
  fieldName_(nSpw_,NULL),
  sourceName_(nSpw_,NULL),
  par_(nSpw_,NULL),
  parOK_(nSpw_,NULL),
  parErr_(nSpw_,NULL),
  parSNR_(nSpw_,NULL),
  //  iSolutionOK_(nSpw_,NULL),
  iFit_(nSpw_,NULL),
  iFitwt_(nSpw_,NULL),
  solutionOK_(nSpw_,NULL),
  fit_(nSpw_,NULL),
  fitwt_(nSpw_,NULL)
{
  calTabDesc_=NULL;
  calTab_=NULL;
  svjmcol_=NULL;

  // Fill from table
  load(calTableName,select);

  // Set spwOK_ according to available calibration
  setSpwOK();

}

template<class T> CalSet<T>::~CalSet() {
  deflate();
}

template<class T> void CalSet<T>::resize(const casacore::Int& nPar,
					 const casacore::Vector<casacore::Int>& nChan,
					 const casacore::Int& nElem,
					 const casacore::Vector<casacore::Int>& nTime) {
  nPar_=nPar;
  nChan_=nChan;
  nElem_=nElem;
  nTime_=nTime;

  inflate();

}



// Inflate cache to proper size
template<class T> void CalSet<T>::inflate() {
  
  // Construct shaped pointed-to objects in cache

  // TODO:
  //  Consider initialization value (per type)

  // Delete exiting cache
  deflate();

  for (casacore::Int ispw=0; ispw<nSpw_; ispw++) {
    casacore::uInt ntime=nTime_(ispw);
    if (ntime > 0) {

      freq_[ispw]         = new casacore::Vector<casacore::Double>(nChan_(ispw),0.0);
      
      MJDStart_[ispw]     = new casacore::Vector<casacore::Double>(ntime,0.0);
      MJDStop_[ispw]      = new casacore::Vector<casacore::Double>(ntime,0.0);
      MJDTimeStamp_[ispw] = new casacore::Vector<casacore::Double>(ntime,0.0);
      fieldName_[ispw]    = new casacore::Vector<casacore::String>(ntime,"");
      sourceName_[ispw]   = new casacore::Vector<casacore::String>(ntime,"");
      fieldId_[ispw]      = new casacore::Vector<casacore::Int>(ntime,-1);

      casacore::IPosition parshape(4,nPar_,nChan_(ispw),nElem_,ntime);
      par_[ispw]     = new casacore::Array<T>(parshape,(T)1.0);
      parOK_[ispw]   = new casacore::Array<casacore::Bool>(parshape,false);
      parErr_[ispw]  = new casacore::Array<casacore::Float>(parshape,0.0f);
      parSNR_[ispw]  = new casacore::Array<casacore::Float>(parshape,0.0f);

      //      iSolutionOK_[ispw]  = new casacore::Matrix<casacore::Bool>(nElem_,ntime,false);
      iFit_[ispw]         = new casacore::Matrix<casacore::Float>(nElem_,ntime,0.0f);
      iFitwt_[ispw]       = new casacore::Matrix<casacore::Float>(nElem_,ntime,0.0f);
      solutionOK_[ispw]   = new casacore::Vector<casacore::Bool>(ntime,false);
      fit_[ispw]          = new casacore::Vector<casacore::Float>(ntime,0.0f);
      fitwt_[ispw]        = new casacore::Vector<casacore::Float>(ntime,0.0f);
    }
  }

}




template<class T> void CalSet<T>::deflate() {
  
  // Delete parameter memory

  for (casacore::Int ispw=0; ispw<nSpw_; ispw++) {
    if (MJDStart_[ispw])     delete MJDStart_[ispw];
    if (MJDStop_[ispw])      delete MJDStop_[ispw];
    if (MJDTimeStamp_[ispw]) delete MJDTimeStamp_[ispw];
    if (fieldName_[ispw])    delete fieldName_[ispw];
    if (sourceName_[ispw])   delete sourceName_[ispw];
    if (fieldId_[ispw])      delete fieldId_[ispw];
    if (par_[ispw])          delete par_[ispw];
    if (parOK_[ispw])        delete parOK_[ispw];
    if (parErr_[ispw])       delete parErr_[ispw];
    if (parSNR_[ispw])       delete parSNR_[ispw];
    //    if (iSolutionOK_[ispw])  delete iSolutionOK_[ispw];
    if (iFit_[ispw])         delete iFit_[ispw];
    if (iFitwt_[ispw])       delete iFitwt_[ispw];
    if (solutionOK_[ispw])   delete solutionOK_[ispw];
    if (fit_[ispw])          delete fit_[ispw];
    if (fitwt_[ispw])        delete fitwt_[ispw];
    MJDStart_[ispw]=NULL;
    MJDStop_[ispw]=NULL;
    MJDTimeStamp_[ispw]=NULL;
    fieldName_[ispw]=NULL;
    sourceName_[ispw]=NULL;
    fieldId_[ispw]=NULL;
    par_[ispw]=NULL;
    parOK_[ispw]=NULL;
    parErr_[ispw]=NULL;
    parSNR_[ispw]=NULL;
    //    iSolutionOK_[ispw]=NULL;
    iFit_[ispw]=NULL;
    iFitwt_[ispw]=NULL;
    solutionOK_[ispw]=NULL;
    fit_[ispw]=NULL;
    fitwt_[ispw]=NULL;
  }
}



template<class T> void CalSet<T>::load (const casacore::String& file, 
					const casacore::String& select)
{
  // Load data from a calibration table
  // casacore::Input:
  //    file         const casacore::String&       Cal table name
  //    select       const casacore::String&       Selection string
  //


  //  cout << "CalSet::load...(nSpw_=" << nSpw_ << ")" << endl;

  casacore::Timer timer;
  timer.mark();
  
  casacore::LogMessage message(casacore::LogOrigin("CalSet","load"));
  
  // Decode the Jones matrix type
  /*
  casacore::Int jonesType = 0;
  if (nPar_ == 1) jonesType = 1;
  if (nPar_ == 2) jonesType = 2;
  if (nPar_ == 4) jonesType = 3;
  */

 // Open, select, sort the calibration table
  SolvableVisJonesTable svjtab(file);
  svjtab.select2(select);

  // Get no. of antennas and time slots
  casacore::Int numberAnt = svjtab.maxAntenna() + 1;

  //  cout << "Initial selection: " << timer.all_usec()/1.0e6 << endl;
  timer.mark();

  AlwaysAssert(numberAnt==nElem_,casacore::AipsError)

  casacore::Int nDesc=svjtab.nRowDesc();
  casacore::Vector<casacore::Int> spwmap(nDesc,-1);

  casacore::Vector<casacore::Int> nRowPerCDI;
  svjtab.rowsPerCalDescId(nRowPerCDI);

  //  cout << "Optimized CDI count: " << timer.all_usec()/1.0e6 << endl;
  timer.mark();

  for (casacore::Int idesc=0;idesc<nDesc;idesc++) {

    // This cal desc
    CalDescRecord* calDescRec = new CalDescRecord (svjtab.getRowDesc(idesc));

    // Get this spw ID
    casacore::Vector<casacore::Int> spwlist;
    calDescRec->getSpwId(spwlist);
    casacore::Int nSpw; spwlist.shape(nSpw);
    if (nSpw > 1) {};  // ERROR!!!  Should only be one spw per cal desc!
    spwmap(idesc)=spwlist(0);

    // Trap spwids that do not occur in the MS
    // (Since we rely on the casacore::MS meta info for the calibration solutions,
    //  we cannot identify spws that do not occur in the MS.)
    if (spwlist(0)>nSpw_-1)
      throw(casacore::AipsError("Caltable '"+file+"' contains spw = "+
		      casacore::String::toString(spwlist(0))+
		      " which does not occur in the MS.  Cannot proceed."));

    // In next few steps, need to watch for repeat spws in new cal descs!!

    // Get number of channels this spw
    casacore::Vector<casacore::Int> nchanlist;

    calDescRec->getNumChan(nchanlist);
    nChan_(spwmap(idesc))=nchanlist(0);

    // Get channel range / start channel
    casacore::Cube<casacore::Int> chanRange;
    calDescRec->getChanRange(chanRange);
    startChan_(spwmap(idesc))=chanRange(0,0,0);

    // Get slot count for this desc's spw
    nTime_(spwmap(idesc))=nRowPerCDI(idesc)/numberAnt;

    delete calDescRec;  
  }

  //  cout << "CalDesc sizeup: " << timer.all_usec()/1.0e6 << endl;
  //  cout << "nTime_ = " << nTime_ << endl;

  timer.mark();

  // At this point, we know how big our slot-dep caches must be
  //  (in private data), so initialize them
  inflate();

  // Remember if we found and filled any solutions
  casacore::Bool solfillok(false);

  //  cout << "CalSet inflated: " << timer.all_usec()/1.0e6 << endl;


  // Fill per caldesc
  casacore::Double ttime(0.0);
  for (casacore::Int idesc=0;idesc<nDesc;idesc++) {

    //    cout << "CDI = " << idesc << " "<< flush;

    timer.mark();

    casacore::Int thisSpw=spwmap(idesc);
      
    // Reopen and globally select caltable
    //SolvableVisJonesTable svjtabspw(file);
    CalTable2 svjtabspw(file);
    svjtabspw.select2(select);

    //    cout << " Sel: " << timer.all_usec()/1.0e6 << flush;

    // isolate this caldesc:
    std::ostringstream selectstr;
    selectstr << "CAL_DESC_ID == " << idesc;
    casacore::String caldescsel; caldescsel = selectstr.str();
    svjtabspw.select2(caldescsel);

    //    cout << " CDIsel: " << timer.all_usec()/1.0e6 << flush;

    //    cout << "Sorting..." << endl;
    casacore::Block<casacore::String> scol(1);
    scol[0]="TIME";
    svjtabspw.sort2(scol);

    //    cout << " casacore::Sort: " << timer.all_usec()/1.0e6 << flush;

    casacore::Int nrow = svjtabspw.nRowMain();
    casacore::IPosition out(3,0,0,0);   // par, chan, row
    casacore::IPosition in(4,0,0,0,0);  // par, chan, ant, slot
    if (nrow>0) {

      // Found some solutions to fill
      solfillok=true;

      // Ensure sorted on time
      casacore::Block <casacore::String> sortCol(1,"TIME");
      svjtabspw.sort2(sortCol);
      
      // Extract the gain table columns
      //ROSolvableVisJonesMCol svjmcol(svjtabspw);
      ROSolvableCalSetMCol<T> *svjmcol;
      svjmcol= new ROSolvableCalSetMCol<T>(svjtabspw);

      casacore::Vector<casacore::Int>    calDescId;  (*svjmcol).calDescId().getColumn(calDescId);
      casacore::Vector<casacore::Double> time;       (*svjmcol).time().getColumn(time);
      casacore::Vector<casacore::Double> interval;   (*svjmcol).interval().getColumn(interval);
      casacore::Vector<casacore::Int>    antenna1;   (*svjmcol).antenna1().getColumn(antenna1);
      //      cout << "antennas = " << antenna1 << endl;
      casacore::Vector<casacore::Int>    fieldId;    (*svjmcol).fieldId().getColumn(fieldId);
      //      cout << "fieldId = " << fieldId << endl;
      casacore::Vector<casacore::String> fieldName;  (*svjmcol).fieldName().getColumn(fieldName);
      casacore::Vector<casacore::String> sourceName; (*svjmcol).sourceName().getColumn(sourceName);
      casacore::Vector<casacore::Bool>   totalSolOk; (*svjmcol).totalSolnOk().getColumn(totalSolOk);
      casacore::Vector<casacore::Float>  totalFit;   (*svjmcol).totalFit().getColumn(totalFit);
      casacore::Vector<casacore::Float>  totalFitWt; (*svjmcol).totalFitWgt().getColumn(totalFitWt);
      casacore::Array<T> gain;       (*svjmcol).gain().getColumn(gain);
      casacore::Cube<casacore::Bool>     solOk;      (*svjmcol).solnOk().getColumn(solOk);
      casacore::Cube<casacore::Float>    fit;        (*svjmcol).fit().getColumn(fit);
      casacore::Cube<casacore::Float>    fitWt;      (*svjmcol).fitWgt().getColumn(fitWt);
      casacore::Cube<casacore::Bool>     flag;       (*svjmcol).flag().getColumn(flag);
      casacore::Cube<casacore::Float>    snr;        (*svjmcol).snr().getColumn(snr);

      // Read the calibration information
      casacore::Double /*lastTime(-1.0),*/ thisTime(0.0), thisInterval(0.0);
      casacore::Int islot(-1);
      casacore::Int iant;

      for (casacore::Int irow=0; irow<nrow; irow++) {
	out(2)=irow;

	thisTime=time(irow);
	
	// If this is a new solution
	if (irow%numberAnt==0) {

	  islot++;
	  in(3)=islot;
	  
	  thisInterval=interval(irow);
	  (*MJDTimeStamp_[thisSpw])(islot) = thisTime;
	  (*MJDStart_[thisSpw])(islot) = thisTime - thisInterval / 2.0;
	  (*MJDStop_[thisSpw])(islot) = thisTime + thisInterval / 2.0;
	  (*fieldId_[thisSpw])(islot) = fieldId(irow);
	  (*fieldName_[thisSpw])(islot) = fieldName(irow);
	  (*sourceName_[thisSpw])(islot) = sourceName(irow);
	  
	  (*solutionOK_[thisSpw])(islot) = totalSolOk(irow);
	  (*fit_[thisSpw])(islot) = totalFit(irow);
	  (*fitwt_[thisSpw])(islot) = totalFitWt(irow);
	  
	  //lastTime = thisTime;
	};
	
	iant=antenna1(irow);
	in(2)=iant;

	//	(*iSolutionOK_[thisSpw])(iant,islot) = solOk(0,0,irow);
	(*iFit_[thisSpw])(iant,islot) = fit(0,0,irow);
	(*iFitwt_[thisSpw])(iant,islot) = fitWt(0,0,irow);
	
	for (casacore::Int ichan=0; ichan<nChan_(thisSpw); ichan++) {


	  out(1)=in(1)=ichan;

	  for (casacore::Int ipar=0; ipar<nPar_; ipar++) {
	    in(0)=out(0)=ipar;
	    (*par_[thisSpw])(in)=gain(out);
	    (*parOK_[thisSpw])(in) = (solOk(out) && !flag(out));
	    (*parSNR_[thisSpw])(in) = snr(out);
	  }
	}
	
      } // irow
    } // nrow>0

    //    cout << "cs fields = " << *fieldId_[thisSpw] << endl;

    casacore::Double itime=timer.all_usec()/1.0e6;
    ttime+=itime;

    //    cout << " Totals: " << itime << " " << ttime << endl;

  } // idesc

  // If we found no solutions in selected table, abort:
  if (!solfillok) {
      throw(casacore::AipsError(" Specified cal table selection selects no solutions in this table.  Please review setapply settings."));
  }


};

template<class T> void CalSet<T>::initCalTableDesc(const casacore::String& type, const casacore::Int& parType)
{
  if (calTabDesc_) {delete calTabDesc_;calTabDesc_=NULL;}
  calTabDesc_=new CalTableDesc2(type,parType);
}

template<class T> void CalSet<T>::attach()
{
}


template<class T> void CalSet<T>::store (const casacore::String& file, 
					 const casacore::String& type,
					 const casacore::Bool& append,
					 const casacore::String& msname)
{
  // Write the solutions to an output calibration table
  // casacore::Input:
  //    file           casacore::String        Cal table name
  //    append         casacore::Bool          Append if true, else overwrite
  //

  // total rows to be written per Spw
  casacore::Vector<casacore::Int> nRow(nSpw_,0);
  for (casacore::Int iSpw=0;iSpw<nSpw_;iSpw++) 
    if (solutionOK_[iSpw])
      nRow(iSpw)=nElem_*ntrue(*(solutionOK_[iSpw]));

  // Escape if nothing to write
  if (sum(nRow)==0)
    throw(casacore::AipsError("No valid calibration solutions; no table written."));

  // Initialization:
  // No. of rows in cal_main, cal_desc and cal_history
  casacore::Int nMain = 0; 
  casacore::Int nDesc = 0;
  //casacore::Int nHist = 0;
  
  if (calTabDesc_ == NULL)
    {
      std::ostringstream str;
      str << "CalSet::store(): Perhaps CalSet.initCalTableDesc() was not called "
	  << "before calling CalSet::store()?"
	  << "  Jones = " << type << "   File = " << file;
      
      throw(casacore::AipsError(str.str()));
    }

  calTabDesc_->addDesc(calTabDesc_->defaultFitDesc(),calTabDesc_->calMainDesc());

  // Calibration table
  //  SolvableVisJonesTable *tab;
  
  // Open the output file if it already exists and is being appended to.
  if (calTab_) delete calTab_; calTab_=NULL;

  if (append && casacore::Table::isWritable (file)) {
    //    tab  = new SolvableVisJonesTable (file, casacore::Table::Update);
    calTab_  = new CalTable2 (file, *calTabDesc_, casacore::Table::Update);
    nMain = calTab_->nRowMain();
    nDesc = calTab_->nRowDesc();
    //nHist = calTab_->nRowHistory();
  } else {
    // Create a new calibration table
    casacore::Table::TableOption access = casacore::Table::New;
    //    tab = new SolvableVisJonesTable (file, type, access);
    calTab_ = new CalTable2 (file, *calTabDesc_, access);
  };
  
  // Write every spw w/ max number of channels 
  //  (eventually, CalTable should permit variable-shape cols)
  casacore::Int maxNumChan(1);
  for (casacore::Int iSpw=0; iSpw<nSpw_; iSpw++) 
    if (par_[iSpw]!=NULL) 
      maxNumChan=std::max(maxNumChan,nChan_(iSpw));

  // Some default values
  casacore::Double dzero = 0;
  casacore::IPosition ip(2,1,maxNumChan);

  // CalDesc Sub-table records
  CalDescRecord* descRec;
  casacore::Vector<casacore::Int> calDescNum(nSpw_); calDescNum=-1;
  for (casacore::Int iSpw=0; iSpw<nSpw_; iSpw++) {

    // Write a CalDesc for each spw which has solutions
    // Note: CalDesc index != SpwId, in general

    if (nRow(iSpw)>0 && par_[iSpw]!=NULL) {

      // Access to existing CAL_DESC columns:
      CalDescColumns2 cd(*calTab_);

      // Check if this spw already in CAL_DESC 
      //      cout << "spwCol = " << cd.spwId().getColumn() << endl;

      casacore::Bool newCD(true);
      for (casacore::Int iCD=0;iCD<nDesc;iCD++) {

	casacore::IPosition iCDip(1,0);
	if ( iSpw==(cd.spwId()(iCD))(iCDip) ) {
	  // Don't need new CAL_DESC entry
	  newCD=false;
	  calDescNum(iSpw)=iCD;
	  break;
	}
      }

      if (newCD) {

	// Cal_desc fields
	casacore::Vector <casacore::Int> spwId(1,iSpw);
	casacore::Matrix <casacore::Double> chanFreq(ip, dzero); 
	casacore::Matrix <casacore::Double> chanWidth(ip, dzero);
	casacore::Array <casacore::String> polznType(ip, casacore::String(""));
	casacore::Cube <casacore::Int> chanRange(casacore::IPosition(3,2,1,maxNumChan), 0);
	casacore::Vector <casacore::Int> numChan(1,nChan_(iSpw));
	for (casacore::Int ichan=0; ichan<nChan_(iSpw); ichan++) {
	  chanRange(0,0,ichan)=startChan_(iSpw);
	  chanRange(1,0,ichan)=startChan_(iSpw) + nChan_(iSpw) -1;
	}
	
	// Fill the cal_desc record
	descRec = new CalDescRecord;
	descRec->defineNumSpw (1);
	descRec->defineNumChan (numChan);
	descRec->defineNumReceptors (2);
	descRec->defineNJones (2);
	descRec->defineSpwId (spwId);
	descRec->defineChanFreq (chanFreq);
	descRec->defineChanWidth (chanWidth);
	descRec->defineChanRange (chanRange);
	descRec->definePolznType (polznType);
	descRec->defineJonesType ("full");
	descRec->defineMSName (casacore::Path(msname).baseName());
	//	descRec->defineMSName ("");
	
	// Write the cal_desc record

	calTab_->putRowDesc (nDesc, *descRec);
	delete descRec;
	
	// This spw will have this calDesc index in main table
	calDescNum(iSpw) = nDesc;
	nDesc++;
      }

    }
    
  }


  // Now write MAIN table in column-wise fashion
  
  // Starting row in this slot

  for (casacore::Int iSpw=0; iSpw<nSpw_; iSpw++) {

    // Write table for spws which have solutions
    if (par_[iSpw]!=NULL) {

      // Create references to cal data for this spw
      casacore::Vector<casacore::Bool>    thisSolOK;        thisSolOK.reference(*(solutionOK_[iSpw]));
      casacore::Vector<casacore::Double>  thisMJDTimeStamp; thisMJDTimeStamp.reference(*(MJDTimeStamp_[iSpw]));
      casacore::Vector<casacore::Double>  thisMJDStart;     thisMJDStart.reference(*(MJDStart_[iSpw]));
      casacore::Vector<casacore::Double>  thisMJDStop;      thisMJDStop.reference(*(MJDStop_[iSpw]));
      casacore::Vector<casacore::Int>     thisFieldId;      thisFieldId.reference(*(fieldId_[iSpw]));
      casacore::Vector<casacore::String>  thisFieldName;    thisFieldName.reference(*(fieldName_[iSpw]));
      casacore::Vector<casacore::String>  thisSourceName;   thisSourceName.reference(*(sourceName_[iSpw]));
      casacore::Vector<casacore::Float>   thisFit;          thisFit.reference(*(fit_[iSpw]));
      casacore::Vector<casacore::Float>   thisFitwt;        thisFitwt.reference(*(fitwt_[iSpw]));
      //      casacore::Array<casacore::Complex>  thisAntGain;      thisAntGain.reference(*(par_[iSpw]));
      casacore::Array<T>  thisAntGain;      thisAntGain.reference(*(par_[iSpw]));
      //      casacore::Matrix<casacore::Bool>    thisISolutionOK;  thisISolutionOK.reference(*(iSolutionOK_[iSpw]));
      casacore::Matrix<casacore::Float>   thisIFit;         thisIFit.reference(*(iFit_[iSpw]));
      casacore::Matrix<casacore::Float>   thisIFitwt;       thisIFitwt.reference(*(iFitwt_[iSpw]));

      casacore::Int thisnRow=nRow(iSpw);
      
      // Only if there are rows to add to table
      if (thisnRow > 0) {

	// These are constant columns (with boring values, currently)
	casacore::Vector<casacore::Double> timeEP(thisnRow,0.0);
	casacore::Vector<casacore::Int> feed1(thisnRow,0);
	casacore::Vector<casacore::Int> arrayId(thisnRow,0);
	casacore::Vector<casacore::Int> obsId(thisnRow,0);
	casacore::Vector<casacore::Int> scanNum(thisnRow,0);
	casacore::Vector<casacore::Int> procId(thisnRow,0);
	casacore::Vector<casacore::Int> stateId(thisnRow,0);
	casacore::Vector<casacore::Int> phaseId(thisnRow,0);
	casacore::Vector<casacore::Int> pulsarBin(thisnRow,0);
	casacore::Vector<casacore::Int> pulsarGateId(thisnRow,0);
	casacore::Vector<casacore::Int> freqGroup(thisnRow,0);
	casacore::Vector<casacore::Int> calHistId(thisnRow,0);
	
	// This is constant
	casacore::Vector<casacore::Int> calDescId(thisnRow,calDescNum(iSpw));
	
	// These are constant per slot
	//   (these cols should be incremental)
	casacore::Vector<casacore::Double> time(thisnRow,0.0);
	casacore::Vector<casacore::Double> interval(thisnRow,0.0);
	casacore::Vector<casacore::Int>    fieldId(thisnRow,0);
	casacore::Vector<casacore::String> fieldName(thisnRow,"");
	casacore::Vector<casacore::String> sourceName(thisnRow,"");
	casacore::Vector<casacore::Bool>   totalSolOk(thisnRow,false);
	casacore::Vector<casacore::Float>  totalFit(thisnRow,0.0);
	casacore::Vector<casacore::Float>  totalFitWt(thisnRow,0.0);
	
	// These vary
	casacore::Vector<casacore::Int>    antenna1(thisnRow,0);
	casacore::Cube<T>  gain(casacore::IPosition(3,nPar(),maxNumChan,thisnRow),T(0.0));
	casacore::Cube<casacore::Bool>     solOk(nPar(),maxNumChan,thisnRow,false);
	casacore::Cube<casacore::Float>    fit(1,maxNumChan,thisnRow,0.0);
	casacore::Cube<casacore::Float>    fitWt(1,maxNumChan,thisnRow,0.0);
	casacore::Cube<casacore::Bool>     flag(nPar(),maxNumChan,thisnRow,false);
	casacore::Cube<casacore::Float>    snr(nPar(),maxNumChan,thisnRow,false);

	casacore::IPosition out(3,0,0,0);   // par, chan, row
	casacore::IPosition in(4,0,0,0,0);  // par, chan, ant, slot
	casacore::Int thisRow(0);
	for (casacore::Int islot = 0; islot < nTime_(iSpw); islot++) {
	  in(3)=islot;
	  if (thisSolOK(islot)) {
	    
	    // Fill slot-constant cols:
	    casacore::Slice thisSlice(thisRow,nElem_);
	    time(thisSlice)=thisMJDTimeStamp(islot);
	    casacore::Double dt=(thisMJDStop(islot) - thisMJDStart(islot));
	    if (dt<0.0) dt=1.0;
	    interval(thisSlice)=dt;
	    fieldId(thisSlice)=thisFieldId(islot);
	    fieldName(thisSlice)=thisFieldName(islot);
	    sourceName(thisSlice)=thisSourceName(islot);
	    totalSolOk(thisSlice)=thisSolOK(islot);
	    totalFit(thisSlice)=thisFit(islot);
	    totalFitWt(thisSlice)=thisFitwt(islot);
	    
	    // Loop over the number of antennas
	    for (casacore::Int iant = 0; iant < nElem_; iant++) {
	      out(2)=thisRow;
	      in(2)=iant;
	      // Antenna index
	      antenna1(thisRow)=iant;
	      
	      gain.xyPlane(thisRow)(casacore::IPosition(2,0,0),casacore::IPosition(2,nPar()-1,nChan_(iSpw)-1))=
		thisAntGain(casacore::IPosition(4,0,0,iant,islot),
			    casacore::IPosition(4,nPar()-1,nChan_(iSpw)-1,iant,islot)).nonDegenerate(2);

	      // Per-chan fit pars
	      for (casacore::Int ichan=0; ichan<nChan_(iSpw); ichan++) {
		// Gain stats  (slot constant, per spw?)
		//solOk(0,ichan,thisRow) = thisISolutionOK(iant,islot);
		fit(0,ichan,thisRow) = thisIFit(iant,islot);
		fitWt(0,ichan,thisRow) = thisIFitwt(iant,islot);


		for (casacore::Int ipar=0; ipar<nPar(); ++ipar) {
		  solOk(ipar,ichan,thisRow) = parOK(iSpw)(casacore::IPosition(4,ipar,ichan,iant,islot));
		  flag(ipar,ichan,thisRow) = !solOk(ipar,ichan,thisRow);
		  snr(ipar,ichan,thisRow) = parSNR(iSpw)(casacore::IPosition(4,ipar,ichan,iant,islot));
		} // ipar
	      } // ichan
	      
	      // next time round is next row
	      thisRow++;
	    }; // iant

	    
	  }; // thisSolOK(islot)
	}; // islot
	
	// Now push everything to the disk table
	calTab_->addRowMain(thisnRow);
	//	SolvableVisJonesMCol svjmcol(*tab);
	if (svjmcol_) {delete svjmcol_; svjmcol_=NULL;}
	svjmcol_ = new SolvableCalSetMCol<T>(*calTab_);

	casacore::RefRows refRows(nMain,nMain+thisnRow-1);
	svjmcol_->time().putColumnCells(refRows,time);
	svjmcol_->timeEP().putColumnCells(refRows,timeEP);
	svjmcol_->interval().putColumnCells(refRows,interval);
	svjmcol_->antenna1().putColumnCells(refRows,antenna1);
	svjmcol_->feed1().putColumnCells(refRows,feed1);
	svjmcol_->fieldId().putColumnCells(refRows,fieldId);
	svjmcol_->arrayId().putColumnCells(refRows,arrayId);
	svjmcol_->obsId().putColumnCells(refRows,obsId);
	svjmcol_->scanNo().putColumnCells(refRows,scanNum);
	svjmcol_->processorId().putColumnCells(refRows,procId);
	svjmcol_->stateId().putColumnCells(refRows,stateId);
	svjmcol_->phaseId().putColumnCells(refRows,phaseId);
	svjmcol_->pulsarBin().putColumnCells(refRows,pulsarBin);
	svjmcol_->pulsarGateId().putColumnCells(refRows,pulsarGateId);
	svjmcol_->freqGrp().putColumnCells(refRows,freqGroup);
	svjmcol_->fieldName().putColumnCells(refRows,fieldName);
	svjmcol_->sourceName().putColumnCells(refRows,sourceName);
	svjmcol_->gain().putColumnCells(refRows,gain);
	svjmcol_->totalSolnOk().putColumnCells(refRows,totalSolOk);
	svjmcol_->totalFit().putColumnCells(refRows,totalFit);
	svjmcol_->totalFitWgt().putColumnCells(refRows,totalFitWt);
	svjmcol_->solnOk().putColumnCells(refRows,solOk);
	svjmcol_->fit().putColumnCells(refRows,fit);
	svjmcol_->fitWgt().putColumnCells(refRows,fitWt);
	svjmcol_->calDescId().putColumnCells(refRows,calDescId);
	svjmcol_->calHistoryId().putColumnCells(refRows,calHistId);
	svjmcol_->flag().putColumnCells(refRows,flag);
	svjmcol_->snr().putColumnCells(refRows,snr);
	
	nMain = calTab_->nRowMain();
	
      } // thisnRow > 0
    } // par_[iSpw]!=NULL
  } // iSpw

  delete calTab_;

};
/*
template<class T> void CalSet<T>::store (const casacore::String& file, 
					 const casacore::String& type,
					 const casacore::String& msname,
					 const casacore::Bool& append)
{
  // Write the solutions to an output calibration table
  // casacore::Input:
  //    file           casacore::String        Cal table name
  //    append         casacore::Bool          Append if true, else overwrite
  //

  // total rows to be written per Spw
  casacore::Vector<casacore::Int> nRow(nSpw_,0);
  for (casacore::Int iSpw=0;iSpw<nSpw_;iSpw++) 
    if (solutionOK_[iSpw])
      nRow(iSpw)=nElem_*ntrue(*(solutionOK_[iSpw]));

  // Escape if nothing to write
  if (sum(nRow)==0)
    throw(casacore::AipsError("No valid calibration solutions; no table written."));

  // Initialization:
  // No. of rows in cal_main, cal_desc and cal_history
  casacore::Int nMain = 0; 
  casacore::Int nDesc = 0;
  //casacore::Int nHist = 0;
  
  // Calibration table
  SolvableVisJonesTable *tab;
  
  // Open the output file if it already exists and is being appended to.
  if (append && casacore::Table::isWritable (file)) {
    tab  = new SolvableVisJonesTable (file, casacore::Table::Update);
    nMain = tab->nRowMain();
    nDesc = tab->nRowDesc();
    //nHist = tab->nRowHistory();
  } else {
    // Create a new calibration table
    casacore::Table::TableOption access = casacore::Table::New;
    tab = new SolvableVisJonesTable (file, type, access);
  };
  
  // Write every spw w/ max number of channels 
  //  (eventually, CalTable should permit variable-shape cols)
  casacore::Int maxNumChan(1);
  for (casacore::Int iSpw=0; iSpw<nSpw_; iSpw++) 
    if (par_[iSpw]!=NULL) 
      maxNumChan=max(maxNumChan,nChan_(iSpw));

  // Some default values
  casacore::Double dzero = 0;
  casacore::IPosition ip(2,1,maxNumChan);

  // CalDesc Sub-table records
  CalDescRecord* descRec;
  casacore::Vector<casacore::Int> calDescNum(nSpw_); calDescNum=-1;
  for (casacore::Int iSpw=0; iSpw<nSpw_; iSpw++) {

    // Write a CalDesc for each spw which has solutions
    // Note: CalDesc index != SpwId, in general

    if (nRow(iSpw)>0 && par_[iSpw]!=NULL) {

      // Access to existing CAL_DESC columns:
      CalDescColumns cd(*tab);

      // Check if this spw already in CAL_DESC 
      //      cout << "spwCol = " << cd.spwId().getColumn() << endl;

      casacore::Bool newCD(true);
      for (casacore::Int iCD=0;iCD<nDesc;iCD++) {

	casacore::IPosition iCDip(1,0);
	if ( iSpw==(cd.spwId()(iCD))(iCDip) ) {
	  // Don't need new CAL_DESC entry
	  newCD=false;
	  calDescNum(iSpw)=iCD;
	  break;
	}
      }

      if (newCD) {

	// Cal_desc fields
	casacore::Vector <casacore::Int> spwId(1,iSpw);
	casacore::Matrix <casacore::Double> chanFreq(ip, dzero); 
	casacore::Matrix <casacore::Double> chanWidth(ip, dzero);
	casacore::Array <casacore::String> polznType(ip, "");
	casacore::Cube <casacore::Int> chanRange(casacore::IPosition(3,2,1,maxNumChan), 0);
	casacore::Vector <casacore::Int> numChan(1,nChan_(iSpw));
	for (casacore::Int ichan=0; ichan<nChan_(iSpw); ichan++) {
	  chanRange(0,0,ichan)=startChan_(iSpw);
	  chanRange(1,0,ichan)=startChan_(iSpw) + nChan_(iSpw) -1;
	}
	
	// Fill the cal_desc record
	descRec = new CalDescRecord;
	descRec->defineNumSpw (1);
	descRec->defineNumChan (numChan);
	descRec->defineNumReceptors (2);
	descRec->defineNJones (2);
	descRec->defineSpwId (spwId);
	descRec->defineChanFreq (chanFreq);
	descRec->defineChanWidth (chanWidth);
	descRec->defineChanRange (chanRange);
	descRec->definePolznType (polznType);
	descRec->defineJonesType ("full");
	descRec->defineMSName (casacore::Path(msname).baseName());
	
	// Write the cal_desc record

	tab->putRowDesc (nDesc, *descRec);
	delete descRec;
	
	// This spw will have this calDesc index in main table
	calDescNum(iSpw) = nDesc;
	nDesc++;
      }

    }
    
  }


  // Now write MAIN table in column-wise fashion
  
  // Starting row in this slot

  for (casacore::Int iSpw=0; iSpw<nSpw_; iSpw++) {

    // Write table for spws which have solutions
    if (par_[iSpw]!=NULL) {

      // Create references to cal data for this spw
      casacore::Vector<casacore::Bool>    thisSolOK;        thisSolOK.reference(*(solutionOK_[iSpw]));
      casacore::Vector<casacore::Double>  thisMJDTimeStamp; thisMJDTimeStamp.reference(*(MJDTimeStamp_[iSpw]));
      casacore::Vector<casacore::Double>  thisMJDStart;     thisMJDStart.reference(*(MJDStart_[iSpw]));
      casacore::Vector<casacore::Double>  thisMJDStop;      thisMJDStop.reference(*(MJDStop_[iSpw]));
      casacore::Vector<casacore::Int>     thisFieldId;      thisFieldId.reference(*(fieldId_[iSpw]));
      casacore::Vector<casacore::String>  thisFieldName;    thisFieldName.reference(*(fieldName_[iSpw]));
      casacore::Vector<casacore::String>  thisSourceName;   thisSourceName.reference(*(sourceName_[iSpw]));
      casacore::Vector<casacore::Float>   thisFit;          thisFit.reference(*(fit_[iSpw]));
      casacore::Vector<casacore::Float>   thisFitwt;        thisFitwt.reference(*(fitwt_[iSpw]));
      casacore::Array<casacore::Complex>  thisAntGain;      thisAntGain.reference(*(par_[iSpw]));
      //      casacore::Matrix<casacore::Bool>    thisISolutionOK;  thisISolutionOK.reference(*(iSolutionOK_[iSpw]));
      casacore::Matrix<casacore::Float>   thisIFit;         thisIFit.reference(*(iFit_[iSpw]));
      casacore::Matrix<casacore::Float>   thisIFitwt;       thisIFitwt.reference(*(iFitwt_[iSpw]));

      casacore::Int thisnRow=nRow(iSpw);
      
      // Only if there are rows to add to table
      if (thisnRow > 0) {

	// These are constant columns (with boring values, currently)
	casacore::Vector<casacore::Double> timeEP(thisnRow,0.0);
	casacore::Vector<casacore::Int> feed1(thisnRow,0);
	casacore::Vector<casacore::Int> arrayId(thisnRow,0);
	casacore::Vector<casacore::Int> obsId(thisnRow,0);
	casacore::Vector<casacore::Int> scanNum(thisnRow,0);
	casacore::Vector<casacore::Int> procId(thisnRow,0);
	casacore::Vector<casacore::Int> stateId(thisnRow,0);
	casacore::Vector<casacore::Int> phaseId(thisnRow,0);
	casacore::Vector<casacore::Int> pulsarBin(thisnRow,0);
	casacore::Vector<casacore::Int> pulsarGateId(thisnRow,0);
	casacore::Vector<casacore::Int> freqGroup(thisnRow,0);
	casacore::Vector<casacore::Int> calHistId(thisnRow,0);
	
	// This is constant
	casacore::Vector<casacore::Int> calDescId(thisnRow,calDescNum(iSpw));
	
	// These are constant per slot
	//   (these cols should be incremental)
	casacore::Vector<casacore::Double> time(thisnRow,0.0);
	casacore::Vector<casacore::Double> interval(thisnRow,0.0);
	casacore::Vector<casacore::Int>    fieldId(thisnRow,0);
	casacore::Vector<casacore::String> fieldName(thisnRow,"");
	casacore::Vector<casacore::String> sourceName(thisnRow,"");
	casacore::Vector<casacore::Bool>   totalSolOk(thisnRow,false);
	casacore::Vector<casacore::Float>  totalFit(thisnRow,0.0);
	casacore::Vector<casacore::Float>  totalFitWt(thisnRow,0.0);
	
	// These vary
	casacore::Vector<casacore::Int>    antenna1(thisnRow,0);
	casacore::Cube<casacore::Complex>  gain(casacore::IPosition(3,nPar(),maxNumChan,thisnRow),casacore::Complex(0.0,0.0));
	casacore::Cube<casacore::Bool>     solOk(nPar(),maxNumChan,thisnRow,false);
	casacore::Cube<casacore::Float>    fit(1,maxNumChan,thisnRow,0.0);
	casacore::Cube<casacore::Float>    fitWt(1,maxNumChan,thisnRow,0.0);
	casacore::Cube<casacore::Bool>     flag(nPar(),maxNumChan,thisnRow,false);
	casacore::Cube<casacore::Float>    snr(nPar(),maxNumChan,thisnRow,false);

	casacore::IPosition out(3,0,0,0);   // par, chan, row
	casacore::IPosition in(4,0,0,0,0);  // par, chan, ant, slot
	casacore::Int thisRow(0);
	for (casacore::Int islot = 0; islot < nTime_(iSpw); islot++) {
	  in(3)=islot;
	  if (thisSolOK(islot)) {
	    
	    // Fill slot-constant cols:
	    casacore::Slice thisSlice(thisRow,nElem_);
	    time(thisSlice)=thisMJDTimeStamp(islot);
	    casacore::Double dt=(thisMJDStop(islot) - thisMJDStart(islot));
	    if (dt<0.0) dt=1.0;
	    interval(thisSlice)=dt;
	    fieldId(thisSlice)=thisFieldId(islot);
	    fieldName(thisSlice)=thisFieldName(islot);
	    sourceName(thisSlice)=thisSourceName(islot);
	    totalSolOk(thisSlice)=thisSolOK(islot);
	    totalFit(thisSlice)=thisFit(islot);
	    totalFitWt(thisSlice)=thisFitwt(islot);
	    
	    // Loop over the number of antennas
	    for (casacore::Int iant = 0; iant < nElem_; iant++) {
	      out(2)=thisRow;
	      in(2)=iant;
	      // Antenna index
	      antenna1(thisRow)=iant;
	      

	      gain.xyPlane(thisRow)(casacore::IPosition(2,0,0),casacore::IPosition(2,nPar()-1,nChan_(iSpw)-1))=
		thisAntGain(casacore::IPosition(4,0,0,iant,islot),casacore::IPosition(4,nPar()-1,nChan_(iSpw)-1,iant,islot)).nonDegenerate(2);

	      
	      // Per-chan fit pars
	      for (casacore::Int ichan=0; ichan<nChan_(iSpw); ichan++) {
		// Gain stats  (slot constant, per spw?)
		//solOk(0,ichan,thisRow) = thisISolutionOK(iant,islot);
		fit(0,ichan,thisRow) = thisIFit(iant,islot);
		fitWt(0,ichan,thisRow) = thisIFitwt(iant,islot);


		for (casacore::Int ipar=0; ipar<nPar(); ++ipar) {
		  solOk(ipar,ichan,thisRow) = parOK(iSpw)(casacore::IPosition(4,ipar,ichan,iant,islot));
		  flag(ipar,ichan,thisRow) = !solOk(ipar,ichan,thisRow);
		  snr(ipar,ichan,thisRow) = parSNR(iSpw)(casacore::IPosition(4,ipar,ichan,iant,islot));
		}
	      }
	      
	      // next time round is next row
	      thisRow++;
	    };
	    
	  };
	};
	
	// Now push everything to the disk table
	tab->addRowMain(thisnRow);
	SolvableVisJonesMCol svjmcol(*tab);
	
	casacore::RefRows refRows(nMain,nMain+thisnRow-1);
	svjmcol.time().putColumnCells(refRows,time);
	svjmcol.timeEP().putColumnCells(refRows,timeEP);
	svjmcol.interval().putColumnCells(refRows,interval);
	svjmcol.antenna1().putColumnCells(refRows,antenna1);
	svjmcol.feed1().putColumnCells(refRows,feed1);
	svjmcol.fieldId().putColumnCells(refRows,fieldId);
	svjmcol.arrayId().putColumnCells(refRows,arrayId);
	svjmcol.obsId().putColumnCells(refRows,obsId);
	svjmcol.scanNo().putColumnCells(refRows,scanNum);
	svjmcol.processorId().putColumnCells(refRows,procId);
	svjmcol.stateId().putColumnCells(refRows,stateId);
	svjmcol.phaseId().putColumnCells(refRows,phaseId);
	svjmcol.pulsarBin().putColumnCells(refRows,pulsarBin);
	svjmcol.pulsarGateId().putColumnCells(refRows,pulsarGateId);
	svjmcol.freqGrp().putColumnCells(refRows,freqGroup);
	svjmcol.fieldName().putColumnCells(refRows,fieldName);
	svjmcol.sourceName().putColumnCells(refRows,sourceName);
	svjmcol.gain().putColumnCells(refRows,gain);
	svjmcol.totalSolnOk().putColumnCells(refRows,totalSolOk);
	svjmcol.totalFit().putColumnCells(refRows,totalFit);
	svjmcol.totalFitWgt().putColumnCells(refRows,totalFitWt);
	svjmcol.solnOk().putColumnCells(refRows,solOk);
	svjmcol.fit().putColumnCells(refRows,fit);
	svjmcol.fitWgt().putColumnCells(refRows,fitWt);
	svjmcol.calDescId().putColumnCells(refRows,calDescId);
	svjmcol.calHistoryId().putColumnCells(refRows,calHistId);
	svjmcol.flag().putColumnCells(refRows,flag);
	svjmcol.snr().putColumnCells(refRows,snr);
	
	
	nMain = tab->nRowMain();
	
      }
    }
  }

  delete tab;

};
*/
} //# NAMESPACE CASA - END