LCOV - code coverage report
Current view: top level - synthesis/CalTables - NewCalTable.cc (source / functions) Hit Total Coverage
Test: casa_coverage.info Lines: 291 626 46.5 %
Date: 2023-10-25 08:47:59 Functions: 28 50 56.0 %

          Line data    Source code
       1             : //# NewCalTable.cc: Implementation of NewCalTable.h
       2             : //# Copyright (C) 2011 
       3             : //# Associated Universities, Inc. Washington DC, USA.
       4             : //#
       5             : //# This library is free software; you can redistribute it and/or modify it
       6             : //# under the terms of the GNU Library General Public License as published by
       7             : //# the Free Software Foundation; either version 2 of the License, or (at your
       8             : //# option) any later version.
       9             : //#
      10             : //# This library is distributed in the hope that it will be useful, but WITHOUT
      11             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
      13             : //# License for more details.
      14             : //#
      15             : //# You should have received a copy of the GNU Library General Public License
      16             : //# along with this library; if not, write to the Free Software Foundation,
      17             : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
      18             : //#
      19             : //# Correspondence concerning AIPS++ should be addressed as follows:
      20             : //#        Internet email: aips2-request@nrao.edu.
      21             : //#        Postal address: AIPS++ Project Office
      22             : //#                        National Radio Astronomy Observatory
      23             : //#                        520 Edgemont Road
      24             : //#                        Charlottesville, VA 22903-2475 USA
      25             : //#
      26             : //# $Id$
      27             : //----------------------------------------------------------------------------
      28             : 
      29             : #include <synthesis/CalTables/NewCalTable.h>
      30             : #include <synthesis/CalTables/CTColumns.h>
      31             : #include <synthesis/CalTables/CTMainColumns.h>
      32             : #include <casacore/ms/MeasurementSets/MeasurementSet.h>
      33             : #include <casacore/ms/MSOper/MSMetaData.h>
      34             : #include <casacore/tables/Tables/ScalarColumn.h>
      35             : #include <casacore/tables/Tables/ScaColDesc.h>
      36             : #include <casacore/tables/Tables/SetupNewTab.h>
      37             : #include <casacore/tables/Tables/TableCopy.h>
      38             : #include <casacore/tables/Tables/TableRow.h>
      39             : #include <casacore/tables/TaQL/TableParse.h>
      40             : #include <casacore/tables/Tables/TableInfo.h>
      41             : #include <casacore/measures/Measures/MEpoch.h>
      42             : #include <casacore/casa/Arrays.h>
      43             : #include <casacore/casa/Arrays/ArrayMath.h>
      44             : #include <casacore/casa/Logging/LogIO.h>
      45             : #include <synthesis/CalTables/CTEnums.h>
      46             : 
      47             : using namespace casacore;
      48             : namespace casa { //# NAMESPACE CASA - BEGIN
      49             : 
      50             : //----------------------------------------------------------------------------
      51             : 
      52        2603 : NewCalTable::NewCalTable() :
      53        2603 :   Table()
      54             : {
      55             :   // Form CTDesc from parameters
      56        5206 :   String parTypeStr("Complex");
      57             : 
      58        7809 :   CTDesc nctd(parTypeStr,"unknown","unknown","unknown");
      59             : 
      60             :   // Form underlying generic Table according to the CTDesc
      61        7809 :   SetupNewTable calMainTab("nullNewCalTable.tempMemCalTable",nctd.calMainDesc(),Table::New);
      62        5206 :   Table tab(calMainTab, Table::Memory, 0, false); 
      63        2603 :   *this = tab;
      64             :   
      65             :   // Set the table info record
      66        2603 :   this->setTableInfo();
      67        2603 : };
      68             : 
      69             : //----------------------------------------------------------------------------
      70             : 
      71      205629 : NewCalTable::~NewCalTable()
      72             : {
      73             : // Default desctructor
      74      205629 : };
      75             : 
      76             : //----------------------------------------------------------------------------
      77         428 : NewCalTable::NewCalTable (const String& tableName, CTDesc& ctableDesc,
      78         428 :                           Table::TableOption access, Table::TableType ttype):
      79         428 :               Table()
      80             : {
      81             : // Construct from a cal table name, descriptor and access option.
      82             : // Used for creating new tables.
      83             : // Input:
      84             : //    tableName        const String&         Cal table name
      85             : //    ctableDesc       const CTDesc&   Cal table descriptor
      86             : //    access           Table::TableOption    Access mode
      87             : //    ttype            Table::TableType      Memory or Plain
      88             : //
      89             : 
      90         428 :   if (access == Table::New || access == Table::NewNoReplace ||
      91             :       access == Table::Scratch) {
      92             : 
      93             :     // Form underlying generic Table according to the supplied desc
      94         856 :     SetupNewTable calMainTab(tableName,ctableDesc.calMainDesc(),access);
      95         856 :     Table tab(calMainTab, ttype, 0, false); 
      96         428 :     *this = tab;
      97             : 
      98             :     // Set the table info record
      99         428 :     this->setTableInfo();
     100             : 
     101             :     // Form (empty) subtables
     102         856 :     this->createSubTables();
     103             :   }
     104             :   else
     105           0 :     throw(AipsError("Creating NewCalTable from scratch must use access=Table::New or TableNewNoReplace or Table::Scratch"));
     106         428 : };
     107             : 
     108             : 
     109             : //----------------------------------------------------------------------------
     110           0 : NewCalTable::NewCalTable (SetupNewTable& newtab, uInt nrow, Bool initialize):
     111           0 :               Table(newtab, nrow, initialize)
     112             : {
     113             : // Construct from a cal table name, descriptor and access option.
     114             : // Used for creating new tables.
     115             : // Input:
     116             : //    newtab           SetupNewtable&   
     117             : //    nrow             uInt                  n rows
     118             : //    initialize       Bool                   
     119             : //
     120           0 : };
     121             : 
     122             : //----------------------------------------------------------------------------
     123             : // Create an empty NewCalTable conveniently
     124          18 : NewCalTable::NewCalTable(String tableName,VisCalEnum::VCParType parType,
     125          18 :                          String typeName,String msName,Bool doSingleChan) : 
     126          18 :   Table()
     127             : {
     128             :   // Form CTDesc from parameters
     129          36 :   String parTypeStr = ((parType==VisCalEnum::COMPLEX) ? "Complex" : "Float");
     130             : 
     131          36 :   CTDesc nctd(parTypeStr,msName,typeName,"unknown");
     132             : 
     133             :   // Form underlying generic Table according to the CTDesc
     134          54 :   SetupNewTable calMainTab(tableName+".tempMemCalTable",nctd.calMainDesc(),Table::New);
     135          36 :   Table tab(calMainTab, Table::Memory, 0, false); 
     136          18 :   *this = tab;
     137             :   
     138             :   // Set the table info record
     139          18 :   this->setTableInfo();
     140             : 
     141             :   // Add (empty) subtables
     142          18 :   this->createSubTables();
     143             : 
     144             :   // Copy subtables from the supplied MS
     145          18 :   this->setMetaInfo(msName);
     146             : 
     147             :   // Reset Spw channelization, if nec.
     148             :   //  (very basic, uses chan n/2 freq)
     149          18 :   if (doSingleChan)
     150           8 :     this->makeSpwSingleChan();
     151             : 
     152          18 : }
     153             : 
     154             : //----------------------------------------------------------------------------
     155         748 : NewCalTable::NewCalTable (const String& tableName, Table::TableOption access, 
     156         748 :                           Table::TableType ttype): Table(tableName,access)
     157             : {
     158             : // Construct from an existing cal table, and access option.
     159             : // 
     160             : // Input:
     161             : //    tableName        const String&         Cal table name
     162             : //    access           Table::TableOption    Access mode
     163             : //    ttype            Table::TableType      Memory or Plain
     164             : //
     165             :   //cerr<<"ctor: from existing cal table with name, option"<<endl;
     166             : 
     167         748 :   if (ttype==Table::Memory) 
     168         452 :     *this = this->copyToMemoryTable(tableName+".tempMemCalTable");
     169             :  
     170        2221 :   if (!this->tableDesc().isColumn(NCT::fieldName(NCT::OBSERVATION_ID)) ||
     171        1473 :       !this->keywordSet().isDefined("OBSERVATION")) 
     172          23 :     addPhoneyObs();
     173             : 
     174             :   // Attach subtable accessors
     175         748 :   attachSubTables();
     176             : 
     177         748 : };
     178             : 
     179           0 : NewCalTable::NewCalTable (const String& tableName,
     180             :     const casacore::TableLock& lockOptions, Table::TableOption access,
     181           0 :     Table::TableType ttype): Table(tableName, lockOptions, access)
     182             : {
     183             :   // Construct from an existing cal table, with lock, access, and type options.
     184           0 :   if (ttype==Table::Memory) 
     185           0 :     *this = this->copyToMemoryTable(tableName+".tempMemCalTable");
     186           0 :   if (!this->tableDesc().isColumn(NCT::fieldName(NCT::OBSERVATION_ID)) ||
     187           0 :       !this->keywordSet().isDefined("OBSERVATION")) {
     188           0 :     addPhoneyObs();
     189             :   }
     190           0 :   attachSubTables();
     191           0 : }
     192             : //----------------------------------------------------------------------------
     193             : 
     194             : // Factory method that has Back Compat option
     195         452 : NewCalTable NewCalTable::createCT(const String& tableName, 
     196             :                                   Table::TableOption access, 
     197             :                                   Table::TableType ttype, 
     198             :                                   Bool doBackCompat) {
     199             :   // Handle back compat
     200         452 :   if (doBackCompat)
     201         452 :     NewCalTable::CTBackCompat(tableName);
     202             : 
     203             :   // Ordinary ctor
     204         452 :   return NewCalTable(tableName,access,ttype);
     205             : 
     206             : }
     207             : // Factory method that has Back Compat option
     208           0 : NewCalTable* NewCalTable::createCTptr(const String& tableName, 
     209             :                                      Table::TableOption access, 
     210             :                                      Table::TableType ttype, 
     211             :                                      Bool doBackCompat) {
     212             :   // Handle back compat
     213           0 :   if (doBackCompat)
     214           0 :     NewCalTable::CTBackCompat(tableName);
     215             : 
     216             :   // Ordinary ctor
     217           0 :   return new NewCalTable(tableName,access,ttype);
     218             : 
     219             : }
     220             : 
     221             : //----------------------------------------------------------------------------
     222           0 : NewCalTable::NewCalTable(String tableName, String CorF,
     223             :                          Int nObs, Int nScanPerObs, Int nTimePerScan,
     224             :                          Int nAnt, Int nSpw, Vector<Int> nChan, 
     225             :                          Int nFld, 
     226             :                          Double rTime, Double tint,
     227           0 :                          Bool disk, Bool verbose) :
     228           0 :   Table()
     229             : {
     230             : 
     231           0 :   String caltype("");
     232           0 :   if (CorF=="Complex")
     233           0 :     caltype="T";
     234           0 :   else if (CorF=="Float")
     235           0 :     caltype="K";
     236             :   else
     237           0 :     throw(AipsError("CorF must be 'Complex' or 'Float'"));
     238             : 
     239           0 :   CTDesc nctd(CorF,"none",caltype,"circ");
     240             : 
     241             :   // Form underlying generic Table according to the supplied desc
     242           0 :   SetupNewTable calMainTab(tableName+".tempMemCalTable",nctd.calMainDesc(),Table::New);
     243           0 :   Table tab(calMainTab, Table::Memory, 0, false); 
     244           0 :   *this = tab;
     245             :   
     246             :   // Set the table info record
     247           0 :   this->setTableInfo();
     248             : 
     249             :   // Add (empty) subtables
     250           0 :   this->createSubTables();
     251             : 
     252             :   // Fill it generically
     253           0 :   this->fillGenericContents(nObs,nScanPerObs,nTimePerScan,
     254             :                             nAnt,nSpw,nChan,
     255             :                             nFld,rTime,tint,verbose);
     256             : 
     257           0 :   if (disk) {
     258             :     // Write it out to disk
     259           0 :     if (verbose) cout << "Writing out to disk: "+tableName << endl;
     260           0 :     this->writeToDisk(tableName);
     261             :   }
     262             : 
     263           0 : }
     264             : 
     265             : // Create an empty NewCalTable from a SimpleSimVi2Parameters object
     266           0 : NewCalTable::NewCalTable(String tableName, String CorF, String caltype,
     267             :                          const vi::SimpleSimVi2Parameters& ssp,
     268           0 :                          Bool disk,Bool verbose) :
     269           0 :   Table()
     270             : {
     271             : 
     272           0 :   if (CorF!="Complex" &&
     273           0 :       CorF!="Float")
     274           0 :     throw(AipsError("CorF must be 'Complex' or 'Float'"));
     275             : 
     276           0 :   CTDesc nctd(CorF,"none",caltype,"circ");
     277             : 
     278             :   // Form underlying generic Table according to the supplied desc
     279           0 :   SetupNewTable calMainTab(tableName+".tempMemCalTable",nctd.calMainDesc(),Table::New);
     280           0 :   Table tab(calMainTab, Table::Memory, 0, false); 
     281           0 :   *this = tab;
     282             :   
     283             :   // Set the table info record
     284           0 :   this->setTableInfo();
     285             : 
     286             :   // Add (empty) subtables
     287           0 :   this->createSubTables();
     288             : 
     289             :   // Fill generic subtables, according to SimpleSimVi2Parameters
     290           0 :   fillGenericObs(ssp);
     291           0 :   fillGenericField(ssp);
     292           0 :   fillGenericAntenna(ssp);
     293           0 :   fillGenericSpw(ssp);
     294             : 
     295           0 :   if (disk) {
     296             :     // Write it out to disk
     297           0 :     if (verbose) cout << "Writing out to disk: "+tableName << endl;
     298           0 :     this->writeToDisk(tableName);
     299             :   }
     300             : 
     301           0 : }
     302             : 
     303             : 
     304             : 
     305             : //----------------------------------------------------------------------------
     306             : 
     307       97012 : NewCalTable::NewCalTable (const Table& table): Table(table)
     308             : {
     309             : // Construct from an existing table object
     310             :   //cerr<<"constructed from an existing newcaltable as table"<<endl;
     311       97012 :   attachSubTables();
     312       97012 : };
     313             : 
     314             : //----------------------------------------------------------------------------
     315             : 
     316       12299 : NewCalTable::NewCalTable (const NewCalTable& other): Table(other)
     317             : {
     318             : // Copy constructor
     319             : // Input:
     320             : //    other            const NewCalTable&       Existing NewCalTable object
     321             : //
     322             :    //cerr<<"copy constructor ...."<<endl;
     323       12299 :    copyMemCalSubtables(other);
     324       12299 :    attachSubTables();
     325       12299 : };
     326             : 
     327             : //----------------------------------------------------------------------------
     328             : 
     329        5804 : NewCalTable& NewCalTable::operator= (const NewCalTable& other)
     330             : {
     331             : // Assignment operator
     332             : // Input:
     333             : //    other            const CalTable&       RHS CalTable object
     334             : //
     335             :   //cerr<<"assignment operator..."<<endl;
     336        5804 :   if (this != &other) {
     337        5804 :     clearSubtables();
     338        5804 :     Table::operator=(other);
     339        5804 :     if (!conformant(this->tableDesc()))
     340             :         throw (AipsError("NewCalTable( const NewCalTable&) - "
     341           0 :                          "table is not a valid caltable"));
     342        5804 :     attachSubTables();
     343             :   }
     344        5804 :   return *this;
     345             : };
     346             : 
     347             : 
     348             : //----------------------------------------------------------------------------
     349             : 
     350             : // Handle backward compatibility
     351         455 : Bool NewCalTable::CTBackCompat(const String& caltable) {
     352             :   
     353         455 :   Bool doBC(false);
     354             : 
     355             :   // Detect backward compatibility issues 
     356         455 :   Table tab(caltable,Table::Old);
     357             : 
     358             :   // pre-v41 had no OBSERVATION/OBSERVATION_ID
     359        1355 :   doBC=(!tab.tableDesc().isColumn(NCT::fieldName(NCT::OBSERVATION_ID)) ||
     360         900 :         !tab.keywordSet().isDefined("OBSERVATION"));
     361             : 
     362         455 :   if (doBC)
     363          10 :     NewCalTable backcompat(caltable,Table::Update,Table::Plain);
     364             : 
     365         910 :   return true;
     366             : 
     367             : }
     368             : 
     369             : 
     370             : //----------------------------------------------------------------------------
     371        3049 : void NewCalTable::setTableInfo() {
     372        3049 :       this->tableInfo().setType(TableInfo::type(TableInfo::ME_CALIBRATION));
     373        3049 :       this->tableInfo().setSubType(this->tableDesc().getType());
     374        3049 : }
     375             : 
     376             : //----------------------------------------------------------------------------
     377         446 : void NewCalTable::createSubTables() {
     378             :       
     379             :   // Names
     380         892 :   String  calObsName=this->tableName()+"/OBSERVATION";
     381         892 :   String  calAntennaName=this->tableName()+"/ANTENNA";
     382         892 :   String  calFieldName=this->tableName()+"/FIELD";
     383         892 :   String  calSpectralWindowName=this->tableName()+"/SPECTRAL_WINDOW";
     384         892 :   String  calHistoryName=this->tableName()+"/HISTORY";
     385             :   
     386         446 :   Table::TableOption access(Table::TableOption(this->tableOption()));
     387         446 :   Table::TableType type(this->tableType());
     388             : 
     389             :   // Assign them to keywords
     390         892 :   SetupNewTable obstab(calObsName,CTObservation::requiredTableDesc(),access); 
     391         446 :   this->rwKeywordSet().defineTable("OBSERVATION", Table(obstab,type));
     392         446 :   observation_p = CTObservation(this->keywordSet().asTable("OBSERVATION"));
     393             : 
     394         892 :   SetupNewTable antennatab(calAntennaName,CTAntenna::requiredTableDesc(),access); 
     395         446 :   this->rwKeywordSet().defineTable("ANTENNA", Table(antennatab,type));
     396         446 :   antenna_p = CTAntenna(this->keywordSet().asTable("ANTENNA"));
     397             : 
     398         892 :   SetupNewTable fieldtab(calFieldName,CTField::requiredTableDesc(),access); 
     399         446 :   this->rwKeywordSet().defineTable("FIELD", Table(fieldtab,type));
     400         446 :   field_p = CTField(this->keywordSet().asTable("FIELD"));
     401             : 
     402         892 :   SetupNewTable spwtab(calSpectralWindowName,CTSpectralWindow::requiredTableDesc(),access); 
     403         446 :   this->rwKeywordSet().defineTable("SPECTRAL_WINDOW", Table(spwtab,type));
     404         446 :   spectralWindow_p = CTSpectralWindow(this->keywordSet().asTable("SPECTRAL_WINDOW"));
     405             :   
     406         446 :   SetupNewTable histab(calHistoryName,CTHistory::requiredTableDesc(),access); 
     407         446 :   this->rwKeywordSet().defineTable("HISTORY", Table(histab,type));
     408         446 :   history_p = CTHistory(this->keywordSet().asTable("HISTORY"));
     409         446 : };
     410             : 
     411             : 
     412             : //----------------------------------------------------------------------------
     413      115863 : void NewCalTable::attachSubTables()
     414             : {
     415             : 
     416      115863 :   if (this->keywordSet().isDefined("OBSERVATION"))
     417      109765 :     observation_p = CTObservation(this->keywordSet().asTable("OBSERVATION"));
     418             : 
     419      115863 :   if (this->keywordSet().isDefined("ANTENNA"))
     420      109765 :     antenna_p = CTAntenna(this->keywordSet().asTable("ANTENNA"));
     421             : 
     422      115863 :   if (this->keywordSet().isDefined("FIELD"))
     423      109765 :     field_p = CTField(this->keywordSet().asTable("FIELD"));
     424             : 
     425      115863 :   if (this->keywordSet().isDefined("SPECTRAL_WINDOW"))
     426      109765 :     spectralWindow_p = CTSpectralWindow(this->keywordSet().asTable("SPECTRAL_WINDOW"));
     427             : 
     428      115863 :   if (this->keywordSet().isDefined("HISTORY"))
     429      109765 :     history_p = CTHistory(this->keywordSet().asTable("HISTORY"));
     430             : 
     431      115863 : }
     432             : 
     433             : //----------------------------------------------------------------------------
     434        5804 : void NewCalTable::clearSubtables()
     435             : {
     436        5804 :    observation_p=CTObservation();
     437        5804 :    antenna_p=CTAntenna();
     438        5804 :    field_p=CTField();
     439        5804 :    spectralWindow_p=CTSpectralWindow();
     440        5804 :    history_p = CTHistory();
     441        5804 : }
     442             : //----------------------------------------------------------------------------
     443       12299 : void NewCalTable::copyMemCalSubtables(const NewCalTable & other)
     444             : {
     445       12299 :    copyMemCalSubtable(other.observation_p, observation_p);
     446       12299 :    copyMemCalSubtable(other.antenna_p, antenna_p);
     447       12299 :    copyMemCalSubtable(other.field_p, field_p);
     448       12299 :    copyMemCalSubtable(other.spectralWindow_p, spectralWindow_p);
     449       12299 :    copyMemCalSubtable(other.history_p, history_p);
     450       12299 : }
     451             : //----------------------------------------------------------------------------
     452       61495 : void NewCalTable::copyMemCalSubtable(const Table & otherCalsubtable, Table & calSubtable )
     453             : {
     454             :   //if (! otherCalsubtable.isNull () && otherCalsubtable.tableType() == Table::Memory){
     455       61495 :   if (! otherCalsubtable.isNull ()){
     456       61310 :         calSubtable = otherCalsubtable;
     457             :     }
     458       61495 : }
     459             : 
     460             : //----------------------------------------------------------------------------
     461          48 : Bool NewCalTable::isComplex() {
     462          48 :   return (this->keywordSet().asString("ParType")=="Complex");
     463             : }
     464             : 
     465             : //----------------------------------------------------------------------------
     466           0 : String NewCalTable::polBasis() {
     467           0 :   return this->keywordSet().asString("PolBasis");
     468             : }
     469             : 
     470             : //----------------------------------------------------------------------------
     471           4 : String NewCalTable::CASAvers() {
     472           4 :   if (this->keywordSet().fieldNumber("CASA_Version")==-1)
     473             :     // Handle non-existent keyword
     474           0 :     return String("Unknown");
     475             :   else
     476           4 :     return this->keywordSet().asString("CASA_Version");
     477             : }
     478             : 
     479             : //----------------------------------------------------------------------------
     480           0 : Record NewCalTable::getRowMain (const Int& jrow)
     481             : {
     482             : // Get a row from cal_main
     483             : // Input:
     484             : //    jrow             const Int&            Row number
     485             : // Output:
     486             : //    getRowMain       Record                Row record
     487             : //
     488           0 :   ROTableRow trow (*this);
     489           0 :   trow.get (jrow);
     490           0 :   return trow.record();
     491             : };
     492             : 
     493             : //----------------------------------------------------------------------------
     494           0 : void NewCalTable::putRowMain (const Int& jrow, CTMainRecord& tableRec)
     495             : {
     496             : // Get a row from cal_main
     497             : // Input:
     498             : //    jrow             const Int&            Row number
     499             : //    tableRec         const CalMainRecord&  Table record 
     500             : //
     501             : // Add rows as required
     502           0 :   Int nMaxRow = this->nrow();
     503           0 :   Int nAdd = jrow - nMaxRow + 1;
     504           0 :   if (nAdd > 0) {
     505           0 :     this->addRow (nAdd);
     506             :   };
     507             : 
     508             : // Write the record
     509           0 :   TableRow trow (*this);
     510           0 :   TableRecord trec = tableRec.record();
     511           0 :   trow.putMatchingFields (jrow, trec);
     512           0 : };
     513             : 
     514             : //----------------------------------------------------------------------------
     515         446 : void NewCalTable::setMetaInfo(const String& msName)
     516             : {
     517             : // set Meta data info:
     518             : // put parent MS name and (for now) make copy of Antenna, Field, and SpW 
     519             : // sub-tables.
     520         892 :   MeasurementSet inms(msName);
     521         892 :   const MSObservation msobstab = inms.observation();
     522         892 :   const MSAntenna msantab = inms.antenna();
     523         892 :   const MSField msfldtab = inms.field();
     524         892 :   const MSSpectralWindow msspwtab = inms.spectralWindow();
     525             : 
     526             :   // deep copy subtables from an MS to NCT 
     527             :   // by TableCopy::copyRows
     528             :   //copy obs table
     529         892 :   CTObservation calobstab(this->observation());
     530         446 :   TableCopy::copyRows(calobstab,msobstab);
     531             :   //copy antenna table
     532         892 :   CTAntenna calantab(this->antenna());
     533         446 :   TableCopy::copyRows(calantab,msantab);
     534             : 
     535             :   //copy field table
     536         892 :   CTField calfldtab(this->field());
     537         446 :   TableCopy::copyRows(calfldtab,msfldtab);
     538             : 
     539             :   // copy nominal Eph object directions into CTField
     540         446 :   handleEphObj(msfldtab,msName);
     541             : 
     542             :   //copy spectralWindow table
     543         446 :   CTSpectralWindow calspwtab(this->spectralWindow());
     544         446 :   TableCopy::copyRows(calspwtab,msspwtab);
     545             : 
     546             :   // Record only the basename of the MS 
     547         446 :   this->rwKeywordSet().define(RecordFieldId("MSName"),Path(msName).baseName());
     548         446 : }
     549             : 
     550         446 : void NewCalTable::handleEphObj(const MSField& msfldtab,const String& msName) {
     551             : 
     552             :   // If EPHEMERIS_ID column exists in the MS FIELD subtable, we
     553             :   //   may have some Eph Objects to get directions for.
     554         446 :   const String ephColName = MSField::columnName(MSField::EPHEMERIS_ID);
     555         446 :   if (msfldtab.actualTableDesc().isColumn(ephColName)) {
     556         339 :     MSFieldColumns msfcol(msfldtab);
     557         339 :     Vector<Int> ephid=msfcol.ephemerisId().getColumn();
     558             : 
     559             :     // Do nothing if no eph objects
     560         339 :     if (max(ephid)<0) return;
     561             :     
     562           0 :     const MeasurementSet ms(msName);
     563           0 :     MSMetaData msmd(&ms,-1.0f);
     564           0 :     CTFieldColumns ctfcol(field_p);
     565           0 :     for (uInt i=0;i<ephid.nelements();++i) {
     566           0 :       if (ephid(i)>-1) {
     567           0 :         Matrix<Double> dir(2,1,0.0);
     568             :         // Calculate nominal position from the MS
     569           0 :         dir=msmd.getReferenceDirection(i).getAngle().getValue();
     570             :         // Write the nominal position into the caltable dir columns
     571           0 :         ctfcol.referenceDir().put(i,dir);
     572           0 :         ctfcol.phaseDir().put(i,dir);
     573           0 :         ctfcol.delayDir().put(i,dir);
     574             :       }
     575             :     }
     576             :   }
     577             : }
     578             : 
     579             : 
     580             : //----------------------------------------------------------------------------
     581        5804 : Bool NewCalTable::conformant(const TableDesc& tabDesc)
     582             : {
     583             : // Check if input table description is confomrant with
     584             : // the new caltable format (or should I named this "validate" ...as 
     585             : // in MS case...)
     586        5804 :   Bool eqDType=false;
     587       11608 :   CTDesc calTD = CTDesc(false);  // opt out of OBS_ID, because we aren't insisting on it yet
     588       11608 :   TableDesc requiredCalTD = calTD.calMainDesc();
     589        5804 :   Bool isCalTableDesc = tabDesc.columnDescSet().isSuperset(requiredCalTD.columnDescSet(), eqDType);
     590        5804 :   if (!isCalTableDesc) {
     591           0 :     cerr<<"NewCalTable::conformant: tabDesc is not superset of requiredCalMain"<<endl;
     592             :   };
     593       11608 :   Vector<String> colNames(requiredCalTD.columnNames());
     594        5804 :   Vector<String> incolNames(tabDesc.columnNames());
     595        5804 :   uInt ncols = colNames.nelements();
     596       69648 :   for (uInt j=0; j < ncols; j++) {
     597             :   }
     598        5804 :   Bool check = true;
     599       69648 :   for (uInt i=0; i < ncols; i++) {
     600      127688 :     TableRecord keySet = tabDesc[colNames(i)].keywordSet();
     601      127688 :     TableRecord reqKeySet = requiredCalTD[colNames(i)].keywordSet();
     602       63844 :     if (reqKeySet.isDefined("QuantumUnits")) {
     603       11608 :       check = keySet.isDefined("QuantumUnits");
     604       11608 :       if (!check) {
     605           0 :         cerr<<"NewCalTable::conformant: column:"<<colNames(i)<<" does not have a unit"<<endl;
     606             :       }
     607             :       else {
     608       11608 :         check =  allEQ(keySet.asArrayString("QuantumUnits"), reqKeySet.asArrayString("QuantumUnits"));
     609       11608 :         if (!check) {
     610           0 :           cerr<<"NewCalTable::conformant column:"<<colNames(i)
     611           0 :                <<" has an invalid QuantumUnits:"<<keySet.asArrayString("QuantumUnits")<<endl;
     612             :         }
     613             :       }
     614             :     }
     615             :   }
     616       11608 :   return isCalTableDesc && check;
     617             : };
     618             : 
     619             : //----------------------------------------------------------------------------
     620         468 : void NewCalTable::writeToDisk(const String& outTableName)
     621             : {
     622         936 :   Block<String> sortcols(4);
     623         468 :   sortcols[0]="SPECTRAL_WINDOW_ID"; 
     624         468 :   sortcols[1]="TIME"; 
     625         468 :   sortcols[2]="ANTENNA1"; 
     626         468 :   sortcols[3]="ANTENNA2"; 
     627         936 :   Table sorted = this->sort(sortcols,Sort::Ascending,Sort::HeapSort);
     628         468 :   sorted.deepCopy(outTableName,Table::New);
     629         468 : };
     630             : 
     631           0 : Complex NewCalTable::NCTtestvalueC(Int iant,Int ispw,Double ich,Double time,Double refTime,Double tint) {
     632             : 
     633           0 :   Double a=1.0 + Double(iant)/10.0 + Double(ispw)/100.0 + ich/10000.0;
     634           0 :   Double dt=(time-refTime)/tint;
     635           0 :   Double p=dt+ich/100.0; 
     636           0 :   return Complex(Float(a*cos(p)),Float(a*sin(p)));
     637             : 
     638             : }
     639             : 
     640           0 : Float NewCalTable::NCTtestvalueF(Int iant,Int ispw,Double ich,Double time,Double refTime,Double tint) {
     641             : 
     642           0 :   Double dt=(time-refTime)/tint;
     643           0 :   Double a=dt + Double(iant)/10.0 + Double(ispw)/100.0 + ich/10000.0;
     644           0 :   return Float(a);
     645             : 
     646             : }
     647             : 
     648             : 
     649             : //----------------------------------------------------------------------------
     650           0 : void NewCalTable::fillGenericContents(Int nObs, Int nScanPerObs,Int nTimePerScan,
     651             :                                       Int nAnt, Int nSpw, Vector<Int> nChan, 
     652             :                                       Int nFld, 
     653             :                                       Double rTime, Double tint,
     654             :                                       Bool verbose) {
     655             : 
     656             :   // Cope with unspecified time info
     657           0 :   if (rTime==0.0) rTime=4832568000.0;
     658           0 :   if (tint==0.0) tint=60.0;
     659             : 
     660           0 :   if (verbose) {
     661           0 :     cout << nFld << " "
     662           0 :          << nAnt << " "
     663           0 :          << nSpw << " "
     664           0 :          << nChan << " "
     665           0 :          << nObs << " "
     666           0 :          << nScanPerObs << " "
     667           0 :          << nTimePerScan << " "
     668           0 :          << endl;
     669           0 :     cout.precision(15);
     670             :   }
     671             :   
     672             :   // fill subtables
     673           0 :   fillGenericObs(nObs);
     674           0 :   fillGenericField(nFld);
     675           0 :   fillGenericAntenna(nAnt);
     676           0 :   fillGenericSpw(nSpw,nChan);
     677             : 
     678             :   // The per-solution antenna indices
     679           0 :   Vector<Int> antlist(nAnt);
     680           0 :   indgen(antlist);
     681           0 :   Int refant=0;  // for ANTENNA2
     682             : 
     683             :   // T-like
     684           0 :   Int nPar(1);
     685             : 
     686           0 :   Double thistime(rTime-tint);  // first sample will be at rTime
     687             : 
     688           0 :   CTMainColumns ncmc(*this);
     689             : 
     690           0 :   Int thisscan(0);
     691           0 :   for (Int iobs=0;iobs<nObs;++iobs) {
     692           0 :     if (verbose) cout << "Obs=" << iobs << endl;
     693           0 :     Int thisfield(-1);
     694           0 :     for (Int iscan=0;iscan<nScanPerObs;++iscan) {
     695           0 :       thisscan+=1;    //  unique scans
     696           0 :       thisfield+=1;   // each scan is a new field
     697           0 :       thisfield=thisfield%nFld;   // never more than nFld-1
     698           0 :       if (verbose) cout << " Scan=" << thisscan << "  Field=" <<thisfield << endl; 
     699           0 :       for (Int itime=0;itime<nTimePerScan;++itime) {
     700           0 :         thistime+=tint; // every tint
     701           0 :         if (verbose) cout << "  Time="<< thistime << endl;
     702             : 
     703           0 :         for (Int ispw=0;ispw<nSpw;++ispw) {
     704             : 
     705           0 :           if (verbose) cout << "   Spw=" << ispw << endl;
     706             :           
     707             :           // add rows
     708           0 :           Int nAddRows=nAnt;
     709           0 :           RefRows rows(this->nrow(),this->nrow()+nAddRows-1,1); 
     710           0 :           this->addRow(nAddRows);
     711             : 
     712           0 :           if (verbose) cout << "    Adding " << nAnt << " rows; total=" << this->nrow() << endl;
     713             :           
     714             :           // fill columns in new rows
     715           0 :           ncmc.time().putColumnCells(rows,Vector<Double>(nAddRows,thistime));
     716           0 :           ncmc.interval().putColumnCells(rows,Vector<Double>(nAddRows,tint));
     717           0 :           ncmc.fieldId().putColumnCells(rows,Vector<Int>(nAddRows,thisfield));
     718           0 :           ncmc.spwId().putColumnCells(rows,Vector<Int>(nAddRows,ispw));
     719           0 :           ncmc.antenna1().putColumnCells(rows,antlist);
     720           0 :           ncmc.antenna2().putColumnCells(rows,Vector<Int>(nAddRows,refant));
     721           0 :           ncmc.obsId().putColumnCells(rows,Vector<Int>(nAddRows,iobs));
     722           0 :           ncmc.scanNo().putColumnCells(rows,Vector<Int>(nAddRows,thisscan));
     723             : 
     724             : 
     725           0 :           if (isComplex()) {
     726           0 :             Cube<Complex> par(nPar,nChan(ispw),nAddRows);
     727           0 :             for (Int iant=0;iant<nAnt;++iant) {
     728           0 :               for (Int ich=0;ich<nChan(ispw);++ich) {
     729           0 :                 par.xyPlane(iant).column(ich)=NCTtestvalueC(iant,ispw,ich,thistime,rTime,tint);
     730             :               }
     731             :             }
     732           0 :             ncmc.cparam().putColumnCells(rows,par);
     733             :           }
     734             :           else {
     735           0 :             Cube<Float> par(nPar,nChan(ispw),nAddRows);
     736           0 :             for (Int iant=0;iant<nAnt;++iant) {
     737           0 :               for (Int ich=0;ich<nChan(ispw);++ich) {
     738           0 :                 par.xyPlane(iant).column(ich)=NCTtestvalueF(iant,ispw,ich,thistime,rTime,tint);
     739             :               }
     740             :             }
     741           0 :             ncmc.fparam().putColumnCells(rows,par);
     742             :           }
     743             : 
     744           0 :           Cube<Float> parerr(nPar,nChan(ispw),nAddRows);
     745           0 :           parerr=0.001;
     746           0 :           ncmc.paramerr().putColumnCells(rows,parerr);
     747           0 :           Cube<Float> snr(nPar,nChan(ispw),nAddRows);
     748           0 :           snr=999.0;
     749           0 :           ncmc.snr().putColumnCells(rows,snr);
     750           0 :           Cube<Float> wt(nPar,nChan(ispw),nAddRows);
     751           0 :           wt=1.0;
     752           0 :           ncmc.weight().putColumnCells(rows,wt);
     753           0 :           Cube<Bool> flag(nPar,nChan(ispw),nAddRows);
     754           0 :           flag=false;
     755           0 :           ncmc.flag().putColumnCells(rows,flag);
     756             :         }
     757             :       }
     758             :     }
     759             :   }
     760             :   
     761           0 : }
     762             : 
     763             : //----------------------------------------------------------------------------
     764          23 : void NewCalTable::fillGenericObs(Int nObs) { 
     765             : 
     766          23 :   this->observation().addRow(nObs);
     767          46 :   MSObservationColumns oc(this->observation());
     768          46 :   Vector<Double> tr(2,0.0);
     769          23 :   tr(1)=7609161600.0;  // the year 2100 (forever-ish)
     770          46 :   for (Int iobs=0;iobs<nObs;++iobs) {
     771          23 :     oc.timeRange().put(iobs,tr);
     772          23 :     oc.observer().put(iobs,String("unknown"));
     773          23 :     oc.project().put(iobs,String("unknown"));
     774          23 :     oc.telescopeName().put(iobs,String("unknown"));
     775          23 :     oc.flagRow().put(iobs,false);
     776             :   }
     777          23 : }
     778             : 
     779             : //----------------------------------------------------------------------------
     780           0 : void NewCalTable::fillGenericField(Int nFld) { 
     781             : 
     782           0 :   this->field().addRow(nFld);
     783           0 :   MSFieldColumns fc(this->field());
     784           0 :   for (Int ifld=0;ifld<nFld;++ifld) {
     785           0 :     fc.name().put(ifld,("Field_"+String::toString(ifld)));
     786           0 :     fc.flagRow().put(ifld,false);
     787             :   }
     788           0 : }
     789             : 
     790             : 
     791             : 
     792             : //----------------------------------------------------------------------------
     793           0 : void NewCalTable::fillGenericAntenna(Int nAnt) {
     794             : 
     795           0 :   this->antenna().addRow(nAnt);
     796           0 :   MSAntennaColumns ac(this->antenna());
     797           0 :   for (Int iant=0;iant<nAnt;++iant) {
     798           0 :     ac.name().put(iant,("Antenna_"+String::toString(iant)));
     799           0 :     ac.station().put(iant,("Station_"+String::toString(iant)));
     800           0 :     ac.type().put(iant,"GROUND-BASED");
     801           0 :     ac.mount().put(iant,"ALT-AZ");
     802           0 :     ac.dishDiameter().put(iant,25.0);
     803           0 :     ac.offset().put(iant,Vector<Double>(3,0.0));
     804           0 :     ac.position().put(iant,Vector<Double>(3,0.0));
     805           0 :     ac.flagRow().put(iant,false);
     806             :   }
     807             : 
     808           0 : }
     809             : 
     810             : 
     811             : //----------------------------------------------------------------------------
     812           0 : void NewCalTable::fillGenericSpw(Int nSpw,Vector<Int>& nChan) {
     813             : 
     814           0 :   this->spectralWindow().addRow(nSpw);
     815           0 :   MSSpWindowColumns sc(this->spectralWindow());
     816           0 :   for (Int ispw=0;ispw<nSpw;++ispw) {
     817           0 :     Double refFreq(60.0e9+Double(ispw)*1.0e9);  // Every GHz
     818           0 :     Double width(1.0e6);  // 1 MHz channels
     819           0 :     Vector<Double> chanfreq(nChan(ispw),refFreq);
     820           0 :     for (Int ich=0;ich<nChan(ispw);++ich) chanfreq(ich)+=(Double(ich)+0.5)*width;
     821             : 
     822           0 :     sc.name().put(ispw,("SPW_"+String::toString(ispw)));
     823           0 :     sc.refFrequency().put(ispw,refFreq);
     824           0 :     sc.numChan().put(ispw,nChan(ispw));
     825           0 :     sc.chanFreq().put(ispw,chanfreq);
     826             :     
     827           0 :     Vector<Double> res(nChan(ispw),width);
     828             : 
     829           0 :     sc.chanWidth().put(ispw,res);
     830           0 :     sc.effectiveBW().put(ispw,res);
     831           0 :     sc.resolution().put(ispw,res);
     832           0 :     sc.totalBandwidth().put(ispw,sum(res));
     833           0 :     sc.flagRow().put(ispw,false);
     834             :   }
     835           0 : }
     836             : 
     837             : //----------------------------------------------------------------------------
     838           0 : void NewCalTable::fillGenericObs(const vi::SimpleSimVi2Parameters& /*ssp*/) { 
     839           0 :   this->fillGenericObs(1); // Just one, for now
     840           0 : }
     841             : 
     842             : //----------------------------------------------------------------------------
     843           0 : void NewCalTable::fillGenericField(const vi::SimpleSimVi2Parameters& ssp) { 
     844           0 :   this->fillGenericField(ssp.nField_);
     845           0 : }
     846             : 
     847             : //----------------------------------------------------------------------------
     848           0 : void NewCalTable::fillGenericAntenna(const vi::SimpleSimVi2Parameters& ssp) { 
     849           0 :   this->fillGenericAntenna(ssp.nAnt_);
     850           0 : }
     851             : 
     852             : 
     853             : //----------------------------------------------------------------------------
     854           0 : void NewCalTable::fillGenericSpw(const vi::SimpleSimVi2Parameters& ssp) { 
     855             : 
     856             :   // Gather info from the SimpleSimVi2Parameters
     857           0 :   const Int& nSpw(ssp.nSpw_);
     858           0 :   const Vector<Int>& nChan(ssp.nChan_);
     859             : 
     860           0 :   this->spectralWindow().addRow(nSpw);
     861           0 :   MSSpWindowColumns sc(this->spectralWindow());
     862           0 :   for (Int ispw=0;ispw<nSpw;++ispw) {
     863           0 :     const Double& refFreq(ssp.refFreq_(ispw));
     864           0 :     const Double& width(ssp.df_(ispw));
     865           0 :     Vector<Double> chanfreq(nChan(ispw),refFreq);
     866           0 :     for (Int ich=0;ich<nChan(ispw);++ich) chanfreq(ich)+=(Double(ich)+0.5)*width;
     867             : 
     868           0 :     sc.name().put(ispw,("SPW_"+String::toString(ispw)));
     869           0 :     sc.refFrequency().put(ispw,refFreq);
     870           0 :     sc.numChan().put(ispw,nChan(ispw));
     871           0 :     sc.chanFreq().put(ispw,chanfreq);
     872             :     
     873           0 :     Vector<Double> res(nChan(ispw),width);
     874             : 
     875           0 :     sc.chanWidth().put(ispw,res);
     876           0 :     sc.effectiveBW().put(ispw,res);
     877           0 :     sc.resolution().put(ispw,res);
     878           0 :     sc.totalBandwidth().put(ispw,sum(res));
     879           0 :     sc.flagRow().put(ispw,false);
     880             :   }
     881           0 : }
     882             : 
     883             : 
     884             : 
     885             : //----------------------------------------------------------------------------
     886           0 : void NewCalTable::fillAntBasedMainRows(uInt nrows, 
     887             :                                        Double time,Double interval,
     888             :                                        Int fieldId,uInt spwId,Int scanNo,
     889             :                                        const Vector<Int>& ant1list, Int refant,
     890             :                                        const Cube<Complex>& cparam,
     891             :                                        const Cube<Bool>& flag,
     892             :                                        const Cube<Float>& paramErr,
     893             :                                        const Cube<Float>& snr) {
     894             : 
     895             :   // Forward to obsId-capable method with obsID=0
     896           0 :   this->fillAntBasedMainRows(nrows,
     897             :                              time,interval,
     898             :                              fieldId,spwId,0,scanNo,
     899             :                              ant1list,refant,
     900             :                              cparam,flag,paramErr,snr);
     901             : 
     902           0 : }
     903             : 
     904           0 : void NewCalTable::fillAntBasedMainRows(uInt nrows, 
     905             :                                        Double time,Double interval,
     906             :                                        Int fieldId,uInt spwId,Int obsId, Int scanNo,
     907             :                                        const Vector<Int>& ant1list, Int refant,
     908             :                                        const Cube<Complex>& cparam,
     909             :                                        const Cube<Bool>& flag,
     910             :                                        const Cube<Float>& paramErr,
     911             :                                        const Cube<Float>& snr) {
     912             :   
     913             :   // Verify that we are Complex
     914           0 :   TableRecord keywords=this->keywordSet();
     915           0 :   if (!keywords.isDefined("ParType") ||
     916           0 :       keywords.asString("ParType")!="Complex")
     917           0 :     throw(AipsError("NewCalTable::fillAntBasedMainRows: NewCalTable's ParType is not Complex"));
     918             : 
     919             :   // First, verify internal consistency
     920           0 :   IPosition csh=cparam.shape();
     921             : 
     922             :   // Data must conform to specified nrows
     923           0 :   AlwaysAssert( (cparam.nplane()==nrows), AipsError);
     924           0 :   AlwaysAssert( (cparam.shape()==flag.shape()), AipsError);
     925             : 
     926             :   // Stat arrays much match cparam shape
     927           0 :   if (paramErr.nelements()>0) 
     928           0 :     AlwaysAssert( (paramErr.shape()==cparam.shape()), AipsError);
     929           0 :   if (snr.nelements()>0)
     930           0 :     AlwaysAssert( (snr.shape()==cparam.shape()), AipsError);
     931             : 
     932             :   // Specified indices must be rational
     933           0 :   AlwaysAssert( (spwId<this->spectralWindow().nrow()), AipsError);
     934           0 :   AlwaysAssert( (fieldId<Int(this->field().nrow())), AipsError);
     935             : 
     936             :   // Handle ant1list
     937           0 :   Vector<Int> ant1;
     938           0 :   if (ant1list.nelements()>0) {
     939           0 :     AlwaysAssert( (min(ant1list)>0), AipsError); // must be definite
     940           0 :     AlwaysAssert( (max(ant1list)<Int(this->antenna().nrow())), AipsError);
     941           0 :     ant1.reference(ant1list);
     942             :   }
     943             :   else {
     944             :     // Generate the ant1 list
     945           0 :     ant1.resize(nrows);
     946           0 :     indgen(ant1);
     947             :   }
     948             : 
     949             :   // All seems well, so add rows
     950           0 :   RefRows rows(this->nrow(),this->nrow()+nrows-1,1);
     951           0 :   this->addRow(nrows);
     952             :   
     953           0 :   CTMainColumns mc(*this);
     954             :   
     955             :   // Meta-info (these are uniform for all rows)
     956           0 :   mc.time().putColumnCells(rows,Vector<Double>(nrows,time));
     957           0 :   mc.fieldId().putColumnCells(rows,Vector<Int>(nrows,fieldId));
     958           0 :   mc.spwId().putColumnCells(rows,Vector<Int>(nrows,spwId));
     959           0 :   mc.obsId().putColumnCells(rows,Vector<Int>(nrows,obsId));
     960           0 :   mc.scanNo().putColumnCells(rows,Vector<Int>(nrows,scanNo));
     961           0 :   mc.interval().putColumnCells(rows,Vector<Double>(nrows,interval));
     962             :   
     963             :   // Antenna
     964           0 :   mc.antenna1().putColumnCells(rows,ant1);
     965           0 :   mc.antenna2().putColumnCells(rows,Vector<Int>(nrows,refant));  // uniform
     966             : 
     967             :   // Complex CPARAM column
     968           0 :   mc.cparam().putColumnCells(rows,cparam);
     969             : 
     970             :   // Fill stats
     971           0 :   mc.flag().putColumnCells(rows,flag);
     972           0 :   if (paramErr.nelements()>0)
     973           0 :     mc.paramerr().putColumnCells(rows,paramErr);
     974             :   else
     975             :     // zeros, w/ correct shape
     976           0 :     mc.paramerr().putColumnCells(rows,Cube<Float>(csh,0.0));
     977           0 :   if (snr.nelements()>0) 
     978           0 :     mc.snr().putColumnCells(rows,snr);
     979             :   else
     980             :     // ones, w/ correct shape
     981           0 :     mc.paramerr().putColumnCells(rows,Cube<Float>(csh,1.0));
     982             : 
     983           0 : }
     984             : 
     985           0 : void NewCalTable::setSpwFreqs(Int spw, const Vector<Double>& freq, 
     986             :                               const Vector<Double>& chanwidth) { 
     987             : 
     988             : 
     989           0 :   MSSpWindowColumns spwcol(this->spectralWindow());
     990             : 
     991           0 :   AlwaysAssert( (spw<Int(spwcol.nrow())), AipsError );
     992             :   
     993           0 :   uInt nchan=freq.nelements();
     994           0 :   IPosition sh(1,nchan);
     995             : 
     996           0 :   spwcol.numChan().put(spw,nchan);
     997           0 :   spwcol.chanFreq().setShape(spw,sh);
     998           0 :   spwcol.chanFreq().put(spw,freq);
     999             :   
    1000           0 :   if (chanwidth.nelements()==0) {
    1001             : 
    1002           0 :     if (nchan>1) {
    1003           0 :       Double width=freq(1)-freq(0);
    1004           0 :       Vector<Double> widthV(nchan,width);
    1005             :       
    1006           0 :       spwcol.chanWidth().setShape(spw,sh);
    1007           0 :       spwcol.chanWidth().put(spw,widthV);
    1008           0 :       spwcol.resolution().setShape(spw,sh);
    1009           0 :       spwcol.resolution().put(spw,widthV);
    1010           0 :       spwcol.effectiveBW().setShape(spw,sh);
    1011           0 :       spwcol.effectiveBW().put(spw,widthV);
    1012             :   
    1013           0 :       Double totalBW=nchan*width;
    1014           0 :       spwcol.totalBandwidth().put(spw,totalBW);
    1015             :     }
    1016             :     else
    1017           0 :       throw(AipsError("NewCalTable::setSpwFreqs: Problem resetting SPECTRAL_WINDOW info"));
    1018             : 
    1019             : 
    1020             :   }
    1021             :   else {
    1022           0 :     AlwaysAssert( (chanwidth.nelements()==nchan), AipsError);
    1023             :     
    1024           0 :     spwcol.chanWidth().setShape(spw,sh);
    1025           0 :     spwcol.chanWidth().put(spw,chanwidth);
    1026           0 :     spwcol.resolution().setShape(spw,sh);
    1027           0 :     spwcol.resolution().put(spw,chanwidth);
    1028           0 :     spwcol.effectiveBW().setShape(spw,sh);
    1029           0 :     spwcol.effectiveBW().put(spw,chanwidth);
    1030             : 
    1031           0 :     spwcol.totalBandwidth().put(spw,sum(chanwidth));
    1032             : 
    1033             :   }
    1034             : 
    1035             : 
    1036           0 : }
    1037             : 
    1038             : // Set FLAG_ROW in SPECTRAL_WINDOW subtable for spws absent in MAIN
    1039             : //  (this enables append to permit revision when appropriate)
    1040         466 : void NewCalTable::flagAbsentSpws() {
    1041             : 
    1042         932 :   CTColumns ctcol(*this);
    1043             : 
    1044             :   // Extract unique spws in MAIN
    1045         932 :   Vector<Int> spwids;
    1046         466 :   ctcol.spwId().getColumn(spwids);
    1047         466 :   Int nspw=genSort(spwids,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
    1048         466 :   spwids.resize(nspw,true);
    1049             : 
    1050             :   // Revise SPW FLAG_ROW
    1051         932 :   Vector<Bool> spwfr;
    1052         466 :   ctcol.spectralWindow().flagRow().getColumn(spwfr);
    1053         466 :   spwfr.set(true);
    1054        6565 :   for (Int ispw=0;ispw<nspw;++ispw) {
    1055        6099 :     uInt thisspw=spwids(ispw);
    1056        6099 :     if (thisspw<spwfr.nelements()) 
    1057        6099 :       spwfr(thisspw)=false;  // unflagged
    1058             :     else
    1059           0 :       throw(AipsError("NewCalTable::flagAbsentSpws: Main table contains spwids not in SpW subtable"));
    1060             :   }
    1061             : 
    1062             :   // Put FLAG_ROW back
    1063         466 :   ctcol.spectralWindow().flagRow().putColumn(spwfr);
    1064             : 
    1065         466 : }
    1066             : // Merge SPW subtable rows from another NewCalTable
    1067           6 : void NewCalTable::mergeSpwMetaInfo(const NewCalTable& other) {
    1068             : 
    1069             :   // Access this' SPW subtable
    1070          12 :   CTSpWindowColumns spwcols(this->spectralWindow());
    1071             : 
    1072             :   // Access other's SPW subtable
    1073          12 :   ROCTSpWindowColumns ospwcols(other.spectralWindow());
    1074             : 
    1075             :   // Just make sure that they have the same number of rows:
    1076             :   //  (should be guaranteed by having been derived from the same MS)
    1077           6 :   if (spwcols.nrow()!=ospwcols.nrow())
    1078           0 :     throw(AipsError("NewCalTable::mergeSpwMetaInfo: Attempt to merge unrelated SPW subtables."));
    1079             : 
    1080             :   // Loop over other's spws
    1081           6 :   uInt onspw=ospwcols.nrow();
    1082          25 :   for (uInt ispw=0;ispw<onspw;++ispw) {
    1083             : 
    1084             :     // Only if other's ispw is not flagged...
    1085          19 :     if (!ospwcols.flagRow()(ispw)) {
    1086             : 
    1087             :       try {
    1088             : 
    1089             :         // Certain meta info must already be equivalent
    1090          12 :         AlwaysAssert( spwcols.name()(ispw)==ospwcols.name()(ispw), AipsError);
    1091          12 :         AlwaysAssert( spwcols.measFreqRef()(ispw)==ospwcols.measFreqRef()(ispw), AipsError);
    1092          12 :         AlwaysAssert( spwcols.netSideband()(ispw)==ospwcols.netSideband()(ispw), AipsError);
    1093          12 :         AlwaysAssert( spwcols.ifConvChain()(ispw)==ospwcols.ifConvChain()(ispw), AipsError);
    1094          12 :         AlwaysAssert( spwcols.freqGroup()(ispw)==ospwcols.freqGroup()(ispw), AipsError);
    1095          12 :         AlwaysAssert( spwcols.freqGroupName()(ispw)==ospwcols.freqGroupName()(ispw), AipsError);
    1096             :       }
    1097           0 :       catch ( AipsError x ) {
    1098           0 :         throw(AipsError("Spw meta information incongruent; cannot merge it for append."));
    1099             :       }
    1100             : 
    1101             :       // ...and this' ispw _is_ flagged
    1102          12 :       if (spwcols.flagRow()(ispw)) {
    1103             : 
    1104             :         // Copy from other to this:
    1105           1 :         Int nchan=ospwcols.numChan()(ispw);
    1106           1 :         IPosition sh(1,nchan);
    1107             : 
    1108           1 :         spwcols.numChan().put(ispw,nchan);
    1109           1 :         spwcols.chanFreq().setShape(ispw,sh);
    1110           1 :         spwcols.chanFreq().put(ispw,ospwcols.chanFreq()(ispw));
    1111           1 :         spwcols.chanWidth().setShape(ispw,sh);
    1112           1 :         spwcols.chanWidth().put(ispw,ospwcols.chanWidth()(ispw));
    1113           1 :         spwcols.resolution().setShape(ispw,sh);
    1114           1 :         spwcols.resolution().put(ispw,ospwcols.resolution()(ispw));
    1115           1 :         spwcols.effectiveBW().setShape(ispw,sh);
    1116           1 :         spwcols.effectiveBW().put(ispw,ospwcols.effectiveBW()(ispw));
    1117             : 
    1118           1 :         spwcols.refFrequency().put(ispw,ospwcols.refFrequency()(ispw));
    1119           1 :         spwcols.totalBandwidth().put(ispw,ospwcols.totalBandwidth()(ispw));
    1120             : 
    1121             :         // this' row now unflagged
    1122           1 :         spwcols.flagRow().put(ispw,false);
    1123             : 
    1124             :       }
    1125             :       else {
    1126             : 
    1127             :         try {
    1128             :         
    1129             :           // Assert equivalence in all meaningful rows
    1130          11 :           AlwaysAssert( spwcols.numChan()(ispw)==ospwcols.numChan()(ispw), AipsError);
    1131          11 :           AlwaysAssert( allEQ(spwcols.chanFreq()(ispw),ospwcols.chanFreq()(ispw)), AipsError);
    1132          11 :           AlwaysAssert( allEQ(spwcols.chanWidth()(ispw),ospwcols.chanWidth()(ispw)), AipsError);
    1133          11 :           AlwaysAssert( allEQ(spwcols.resolution()(ispw),ospwcols.resolution()(ispw)), AipsError);
    1134          11 :           AlwaysAssert( allEQ(spwcols.effectiveBW()(ispw),ospwcols.effectiveBW()(ispw)), AipsError);
    1135          11 :           AlwaysAssert( spwcols.refFrequency()(ispw)==ospwcols.refFrequency()(ispw), AipsError);
    1136          11 :           AlwaysAssert( spwcols.totalBandwidth()(ispw)==ospwcols.totalBandwidth()(ispw), AipsError);
    1137             :         }
    1138           0 :         catch ( AipsError err ) {
    1139           0 :           throw(AipsError("Error merging spw="+String::toString(ispw)+"'s meta info"));
    1140             :         }
    1141             :       }
    1142             :     } 
    1143             : 
    1144             :   } // ispw
    1145             : 
    1146             : 
    1147           6 : }
    1148             : 
    1149             : 
    1150             : 
    1151             : 
    1152           0 : void NewCalTable::addHistoryMessage(String app, String message) {
    1153             : 
    1154           0 :   Int row=this->history().nrow();
    1155           0 :   this->history().addRow(1);
    1156             : 
    1157           0 :   MSHistoryColumns hcol(this->history());
    1158             : 
    1159             :   // Add the current data
    1160           0 :   Time date;
    1161           0 :   MEpoch now(MVEpoch(date.modifiedJulianDay()),MEpoch::Ref(MEpoch::UTC));
    1162           0 :   hcol.timeMeas().put(row,now);
    1163             : 
    1164             :   // The application
    1165           0 :   hcol.application().put(row,app);
    1166             : 
    1167             :   // Write the message
    1168           0 :   hcol.message().put(row,message);
    1169             : 
    1170             :   // Fill in some other columns with emptiness
    1171           0 :   hcol.objectId().put(row,-1);
    1172           0 :   hcol.observationId().put(row,-1);
    1173             : 
    1174           0 : }
    1175             : 
    1176           8 : void NewCalTable::makeSpwSingleChan() {
    1177             : 
    1178          16 :   MSSpWindowColumns spwcol(this->spectralWindow());
    1179             : 
    1180             :   // Reset each spw to a single channel
    1181          18 :   for (uInt ispw=0;ispw<spwcol.nrow();++ispw) {
    1182             : 
    1183             :     Int nchan;
    1184          10 :     spwcol.numChan().get(ispw,nchan);
    1185          20 :     IPosition ip(1,1);
    1186          10 :     if (nchan>1) {
    1187           8 :       Vector<Double> midFreq;
    1188           4 :       spwcol.chanFreq().get(ispw,midFreq);
    1189           4 :       midFreq(0)=midFreq(nchan/2);
    1190           4 :       midFreq.resize(1,true);
    1191             :       Double totBW;
    1192           4 :       spwcol.totalBandwidth().get(ispw,totBW);
    1193           8 :       Vector<Double> totBWv(1,totBW);
    1194             :       
    1195           4 :       spwcol.numChan().put(ispw,1);
    1196             : 
    1197           4 :       spwcol.chanFreq().setShape(ispw,ip);
    1198           4 :       spwcol.chanFreq().put(ispw,midFreq);
    1199             : 
    1200           4 :       spwcol.chanWidth().setShape(ispw,ip);
    1201           4 :       spwcol.chanWidth().put(ispw,totBWv);
    1202           4 :       spwcol.effectiveBW().setShape(ispw,ip);
    1203           4 :       spwcol.effectiveBW().put(ispw,totBWv);
    1204           4 :       spwcol.resolution().setShape(ispw,ip);
    1205           4 :       spwcol.resolution().put(ispw,totBWv);
    1206             : 
    1207             :     }
    1208             :   }
    1209           8 : }
    1210             : 
    1211          23 : void NewCalTable::addPhoneyObs() {
    1212             : 
    1213          23 :   TableType ntype(this->tableType());
    1214             : 
    1215          46 :   ostringstream msg;
    1216          23 :   msg << "Found pre-v4.1 caltable (" << this->tableName() << "); attempting to update..." << endl;
    1217             : 
    1218             :   // If absent, add OBSERVATION_ID column and OBSERVATION
    1219             :   //  ONLY if caltable is writable (on disk) or a Memory table
    1220          23 :   if ( (ntype==Table::Plain && this->isWritable()) ||
    1221             :        (ntype==Table::Memory) ) {
    1222             : 
    1223             :     // Add phoney OBSERVATION_ID column and fill with zeros
    1224          23 :     if (!this->tableDesc().isColumn(NCT::fieldName(NCT::OBSERVATION_ID))) {
    1225          46 :       ScalarColumnDesc<Int> obscoldesc(NCT::fieldName (NCT::OBSERVATION_ID),ColumnDesc::Direct);
    1226          23 :       this->addColumn(obscoldesc,false);
    1227          23 :       CTMainColumns mc(*this);
    1228          23 :       mc.obsId().fillColumn(0);
    1229             :     }
    1230             : 
    1231             :     // Add dummy OBSERVATION subtable with 1 row
    1232          23 :     if (!this->keywordSet().isDefined("OBSERVATION")) {
    1233          46 :       String  calObsName=this->tableName()+"/OBSERVATION";
    1234          23 :       Table::TableOption access(Table::NewNoReplace);
    1235          46 :       SetupNewTable obstab(calObsName,CTObservation::requiredTableDesc(),access);
    1236          23 :       this->rwKeywordSet().defineTable("OBSERVATION", Table(obstab,ntype));  // same type as parent table
    1237          23 :       observation_p = CTObservation(this->keywordSet().asTable("OBSERVATION"));
    1238          23 :       fillGenericObs(1);
    1239             :     }
    1240             : 
    1241          23 :     msg << "SUCCEEDED: trivial OBSERVATION/OBSERVATION_ID have been added.";
    1242             : 
    1243          23 :     LogIO log;
    1244          23 :     log << msg.str() << LogIO::WARN;
    1245             : 
    1246             :   }
    1247             :   else {
    1248           0 :     msg << "FAILED: caltable is not writable.";
    1249           0 :     msg << " Please run cb.updatecaltable on this caltable, OR";
    1250           0 :     msg << "  regenerate this caltable in v4.1 or later.";
    1251           0 :     throw(AipsError(msg.str()));
    1252             :   }
    1253             : 
    1254          23 : }
    1255             : 
    1256             : 
    1257             : 
    1258             : } //# NAMESPACE CASA - END

Generated by: LCOV version 1.16