LCOV - code coverage report
Current view: top level - synthesis/CalTables - NewCalTable.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 272 649 41.9 %
Date: 2024-10-12 00:35:29 Functions: 23 50 46.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: casa-feedback@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         507 : NewCalTable::NewCalTable() :
      53         507 :   Table()
      54             : {
      55             :   // Form CTDesc from parameters
      56         507 :   String parTypeStr("Complex");
      57             : 
      58        1014 :   CTDesc nctd(parTypeStr,"unknown","unknown","unknown");
      59             : 
      60             :   // Form underlying generic Table according to the CTDesc
      61        1014 :   SetupNewTable calMainTab("nullNewCalTable.tempMemCalTable",nctd.calMainDesc(),Table::New);
      62         507 :   Table tab(calMainTab, Table::Memory, 0, false); 
      63         507 :   *this = tab;
      64             :   
      65             :   // Set the table info record
      66         507 :   this->setTableInfo();
      67         507 : };
      68             : 
      69             : //----------------------------------------------------------------------------
      70             : 
      71       40618 : NewCalTable::~NewCalTable()
      72             : {
      73             : // Default desctructor
      74       40618 : };
      75             : 
      76             : //----------------------------------------------------------------------------
      77           0 : NewCalTable::NewCalTable (const String& tableName, CTDesc& ctableDesc,
      78           0 :                           Table::TableOption access, Table::TableType ttype):
      79           0 :               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           0 :   if (access == Table::New || access == Table::NewNoReplace ||
      91             :       access == Table::Scratch) {
      92             : 
      93             :     // Form underlying generic Table according to the supplied desc
      94           0 :     SetupNewTable calMainTab(tableName,ctableDesc.calMainDesc(),access);
      95           0 :     Table tab(calMainTab, ttype, 0, false); 
      96           0 :     *this = tab;
      97             : 
      98             :     // Set the table info record
      99           0 :     this->setTableInfo();
     100             : 
     101             :     // Form (empty) subtables
     102           0 :     this->createSubTables();
     103           0 :   }
     104             :   else
     105           0 :     throw(AipsError("Creating NewCalTable from scratch must use access=Table::New or TableNewNoReplace or Table::Scratch"));
     106           0 : };
     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           0 : NewCalTable::NewCalTable(String tableName,VisCalEnum::VCParType parType,
     125           0 :                          String typeName,String msName,Bool doSingleChan) : 
     126           0 :   Table()
     127             : {
     128             :   // Form CTDesc from parameters
     129           0 :   String parTypeStr = ((parType==VisCalEnum::COMPLEX) ? "Complex" : "Float");
     130             : 
     131           0 :   CTDesc nctd(parTypeStr,msName,typeName,"unknown");
     132             : 
     133             :   // Form underlying generic Table according to the CTDesc
     134           0 :   SetupNewTable calMainTab(tableName+".tempMemCalTable",nctd.calMainDesc(),Table::New);
     135           0 :   Table tab(calMainTab, Table::Memory, 0, false); 
     136           0 :   *this = tab;
     137             :   
     138             :   // Set the table info record
     139           0 :   this->setTableInfo();
     140             : 
     141             :   // Add (empty) subtables
     142           0 :   this->createSubTables();
     143             : 
     144             :   // Copy subtables from the supplied MS
     145           0 :   this->setMetaInfo(msName);
     146             : 
     147             :   // Reset Spw channelization, if nec.
     148             :   //  (very basic, uses chan n/2 freq)
     149           0 :   if (doSingleChan)
     150           0 :     this->makeSpwSingleChan();
     151             : 
     152           0 : }
     153             : 
     154             : //----------------------------------------------------------------------------
     155         182 : NewCalTable::NewCalTable (const String& tableName, Table::TableOption access, 
     156         182 :                           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         182 :   if (ttype==Table::Memory) 
     168           0 :     *this = this->copyToMemoryTable(tableName+".tempMemCalTable");
     169             :  
     170         544 :   if (!this->tableDesc().isColumn(NCT::fieldName(NCT::OBSERVATION_ID)) ||
     171         362 :       !this->keywordSet().isDefined("OBSERVATION")) 
     172           2 :     addPhoneyObs();
     173             : 
     174             :   // Attach subtable accessors
     175         182 :   attachSubTables();
     176             : 
     177         182 : };
     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           0 : NewCalTable NewCalTable::createCT(const String& tableName, 
     196             :                                   Table::TableOption access, 
     197             :                                   Table::TableType ttype, 
     198             :                                   Bool doBackCompat) {
     199             :   // Handle back compat
     200           0 :   if (doBackCompat)
     201           0 :     NewCalTable::CTBackCompat(tableName);
     202             : 
     203             :   // Ordinary ctor
     204           0 :   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           2 : 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           2 :                          Bool disk, Bool verbose) :
     228           2 :   Table()
     229             : {
     230             : 
     231           2 :   String caltype("");
     232           2 :   if (CorF=="Complex")
     233           2 :     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           4 :   CTDesc nctd(CorF,"none",caltype,"circ");
     240             : 
     241             :   // Form underlying generic Table according to the supplied desc
     242           4 :   SetupNewTable calMainTab(tableName+".tempMemCalTable",nctd.calMainDesc(),Table::New);
     243           2 :   Table tab(calMainTab, Table::Memory, 0, false); 
     244           2 :   *this = tab;
     245             :   
     246             :   // Set the table info record
     247           2 :   this->setTableInfo();
     248             : 
     249             :   // Add (empty) subtables
     250           2 :   this->createSubTables();
     251             : 
     252             :   // Fill it generically
     253           2 :   this->fillGenericContents(nObs,nScanPerObs,nTimePerScan,
     254             :                             nAnt,nSpw,nChan,
     255             :                             nFld,rTime,tint,verbose);
     256             : 
     257           2 :   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           2 : }
     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       19796 : 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       19796 :   attachSubTables();
     312       19796 : };
     313             : 
     314             : //----------------------------------------------------------------------------
     315             : 
     316         660 : 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         660 :    copyMemCalSubtables(other);
     324         660 :    attachSubTables();
     325         660 : };
     326             : 
     327             : //----------------------------------------------------------------------------
     328             : 
     329         837 : 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         837 :   if (this != &other) {
     337         837 :     clearSubtables();
     338         837 :     Table::operator=(other);
     339         837 :     if (!conformant(this->tableDesc()))
     340           0 :         throw (AipsError("NewCalTable( const NewCalTable&) - "
     341           0 :                          "table is not a valid caltable"));
     342         837 :     attachSubTables();
     343             :   }
     344         837 :   return *this;
     345             : };
     346             : 
     347             : 
     348             : //----------------------------------------------------------------------------
     349             : 
     350             : // Handle backward compatibility
     351           0 : Bool NewCalTable::CTBackCompat(const String& caltable) {
     352             :   
     353           0 :   Bool doBC(false);
     354             : 
     355             :   // Detect backward compatibility issues 
     356           0 :   Table tab(caltable,Table::Old);
     357             : 
     358             :   // pre-v41 had no OBSERVATION/OBSERVATION_ID
     359           0 :   doBC=(!tab.tableDesc().isColumn(NCT::fieldName(NCT::OBSERVATION_ID)) ||
     360           0 :         !tab.keywordSet().isDefined("OBSERVATION"));
     361             : 
     362           0 :   if (doBC)
     363           0 :     NewCalTable backcompat(caltable,Table::Update,Table::Plain);
     364             : 
     365           0 :   return true;
     366             : 
     367           0 : }
     368             : 
     369             : 
     370             : //----------------------------------------------------------------------------
     371         509 : void NewCalTable::setTableInfo() {
     372         509 :       this->tableInfo().setType(TableInfo::type(TableInfo::ME_CALIBRATION));
     373         509 :       this->tableInfo().setSubType(this->tableDesc().getType());
     374         509 : }
     375             : 
     376             : //----------------------------------------------------------------------------
     377           2 : void NewCalTable::createSubTables() {
     378             :       
     379             :   // Names
     380           2 :   String  calObsName=this->tableName()+"/OBSERVATION";
     381           2 :   String  calAntennaName=this->tableName()+"/ANTENNA";
     382           2 :   String  calFieldName=this->tableName()+"/FIELD";
     383           2 :   String  calSpectralWindowName=this->tableName()+"/SPECTRAL_WINDOW";
     384           2 :   String  calHistoryName=this->tableName()+"/HISTORY";
     385             :   
     386           2 :   Table::TableOption access(Table::TableOption(this->tableOption()));
     387           2 :   Table::TableType type(this->tableType());
     388             : 
     389             :   // Assign them to keywords
     390           2 :   SetupNewTable obstab(calObsName,CTObservation::requiredTableDesc(),access); 
     391           2 :   this->rwKeywordSet().defineTable("OBSERVATION", Table(obstab,type));
     392           2 :   observation_p = CTObservation(this->keywordSet().asTable("OBSERVATION"));
     393             : 
     394           2 :   SetupNewTable antennatab(calAntennaName,CTAntenna::requiredTableDesc(),access); 
     395           2 :   this->rwKeywordSet().defineTable("ANTENNA", Table(antennatab,type));
     396           2 :   antenna_p = CTAntenna(this->keywordSet().asTable("ANTENNA"));
     397             : 
     398           2 :   SetupNewTable fieldtab(calFieldName,CTField::requiredTableDesc(),access); 
     399           2 :   this->rwKeywordSet().defineTable("FIELD", Table(fieldtab,type));
     400           2 :   field_p = CTField(this->keywordSet().asTable("FIELD"));
     401             : 
     402           2 :   SetupNewTable spwtab(calSpectralWindowName,CTSpectralWindow::requiredTableDesc(),access); 
     403           2 :   this->rwKeywordSet().defineTable("SPECTRAL_WINDOW", Table(spwtab,type));
     404           2 :   spectralWindow_p = CTSpectralWindow(this->keywordSet().asTable("SPECTRAL_WINDOW"));
     405             :   
     406           2 :   SetupNewTable histab(calHistoryName,CTHistory::requiredTableDesc(),access); 
     407           2 :   this->rwKeywordSet().defineTable("HISTORY", Table(histab,type));
     408           2 :   history_p = CTHistory(this->keywordSet().asTable("HISTORY"));
     409           2 : };
     410             : 
     411             : 
     412             : //----------------------------------------------------------------------------
     413       21475 : void NewCalTable::attachSubTables()
     414             : {
     415             : 
     416       21475 :   if (this->keywordSet().isDefined("OBSERVATION"))
     417       20457 :     observation_p = CTObservation(this->keywordSet().asTable("OBSERVATION"));
     418             : 
     419       21475 :   if (this->keywordSet().isDefined("ANTENNA"))
     420       20457 :     antenna_p = CTAntenna(this->keywordSet().asTable("ANTENNA"));
     421             : 
     422       21475 :   if (this->keywordSet().isDefined("FIELD"))
     423       20457 :     field_p = CTField(this->keywordSet().asTable("FIELD"));
     424             : 
     425       21475 :   if (this->keywordSet().isDefined("SPECTRAL_WINDOW"))
     426       20457 :     spectralWindow_p = CTSpectralWindow(this->keywordSet().asTable("SPECTRAL_WINDOW"));
     427             : 
     428       21475 :   if (this->keywordSet().isDefined("HISTORY"))
     429       20457 :     history_p = CTHistory(this->keywordSet().asTable("HISTORY"));
     430             : 
     431       21475 : }
     432             : 
     433             : //----------------------------------------------------------------------------
     434         837 : void NewCalTable::clearSubtables()
     435             : {
     436         837 :    observation_p=CTObservation();
     437         837 :    antenna_p=CTAntenna();
     438         837 :    field_p=CTField();
     439         837 :    spectralWindow_p=CTSpectralWindow();
     440         837 :    history_p = CTHistory();
     441         837 : }
     442             : //----------------------------------------------------------------------------
     443         660 : void NewCalTable::copyMemCalSubtables(const NewCalTable & other)
     444             : {
     445         660 :    copyMemCalSubtable(other.observation_p, observation_p);
     446         660 :    copyMemCalSubtable(other.antenna_p, antenna_p);
     447         660 :    copyMemCalSubtable(other.field_p, field_p);
     448         660 :    copyMemCalSubtable(other.spectralWindow_p, spectralWindow_p);
     449         660 :    copyMemCalSubtable(other.history_p, history_p);
     450         660 : }
     451             : //----------------------------------------------------------------------------
     452        3300 : void NewCalTable::copyMemCalSubtable(const Table & otherCalsubtable, Table & calSubtable )
     453             : {
     454             :   //if (! otherCalsubtable.isNull () && otherCalsubtable.tableType() == Table::Memory){
     455        3300 :   if (! otherCalsubtable.isNull ()){
     456        3175 :         calSubtable = otherCalsubtable;
     457             :     }
     458        3300 : }
     459             : 
     460             : //----------------------------------------------------------------------------
     461          78 : Bool NewCalTable::isComplex() {
     462          78 :   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           0 : String NewCalTable::CASAvers() {
     472           0 :   if (this->keywordSet().fieldNumber("CASA_Version")==-1)
     473             :     // Handle non-existent keyword
     474           0 :     return String("Unknown");
     475             :   else
     476           0 :     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           0 : };
     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           0 : 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           0 :   MeasurementSet inms(msName);
     521           0 :   const MSObservation msobstab = inms.observation();
     522           0 :   const MSAntenna msantab = inms.antenna();
     523           0 :   const MSField msfldtab = inms.field();
     524           0 :   const MSSpectralWindow msspwtab = inms.spectralWindow();
     525             : 
     526             :   // deep copy subtables from an MS to NCT 
     527             :   // by TableCopy::copyRows
     528             :   //copy obs table
     529           0 :   CTObservation calobstab(this->observation());
     530           0 :   TableCopy::copyRows(calobstab,msobstab);
     531             :   //copy antenna table
     532           0 :   CTAntenna calantab(this->antenna());
     533           0 :   TableCopy::copyRows(calantab,msantab);
     534             : 
     535             :   //copy field table
     536           0 :   CTField calfldtab(this->field());
     537           0 :   TableCopy::copyRows(calfldtab,msfldtab);
     538             : 
     539             :   // copy nominal Eph object directions into CTField
     540           0 :   handleEphObj(msfldtab,msName);
     541             : 
     542             :   //copy spectralWindow table
     543           0 :   CTSpectralWindow calspwtab(this->spectralWindow());
     544           0 :   TableCopy::copyRows(calspwtab,msspwtab);
     545             : 
     546             :   // Record only the basename of the MS 
     547           0 :   this->rwKeywordSet().define(RecordFieldId("MSName"),Path(msName).baseName());
     548           0 : }
     549             : 
     550           0 : 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           0 :   const String ephColName = MSField::columnName(MSField::EPHEMERIS_ID);
     555           0 :   if (msfldtab.actualTableDesc().isColumn(ephColName)) {
     556           0 :     MSFieldColumns msfcol(msfldtab);
     557           0 :     Vector<Int> ephid=msfcol.ephemerisId().getColumn();
     558             : 
     559             :     // Do nothing if no eph objects
     560           0 :     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           0 :       }
     575             :     }
     576           0 :   }
     577           0 : }
     578             : 
     579             : 
     580             : //----------------------------------------------------------------------------
     581         837 : 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         837 :   Bool eqDType=false;
     587         837 :   CTDesc calTD = CTDesc(false);  // opt out of OBS_ID, because we aren't insisting on it yet
     588         837 :   TableDesc requiredCalTD = calTD.calMainDesc();
     589         837 :   Bool isCalTableDesc = tabDesc.columnDescSet().isSuperset(requiredCalTD.columnDescSet(), eqDType);
     590         837 :   if (!isCalTableDesc) {
     591           0 :     cerr<<"NewCalTable::conformant: tabDesc is not superset of requiredCalMain"<<endl;
     592             :   };
     593         837 :   Vector<String> colNames(requiredCalTD.columnNames());
     594         837 :   Vector<String> incolNames(tabDesc.columnNames());
     595         837 :   uInt ncols = colNames.nelements();
     596       10044 :   for (uInt j=0; j < ncols; j++) {
     597             :   }
     598         837 :   Bool check = true;
     599       10044 :   for (uInt i=0; i < ncols; i++) {
     600        9207 :     TableRecord keySet = tabDesc[colNames(i)].keywordSet();
     601        9207 :     TableRecord reqKeySet = requiredCalTD[colNames(i)].keywordSet();
     602        9207 :     if (reqKeySet.isDefined("QuantumUnits")) {
     603        1674 :       check = keySet.isDefined("QuantumUnits");
     604        1674 :       if (!check) {
     605           0 :         cerr<<"NewCalTable::conformant: column:"<<colNames(i)<<" does not have a unit"<<endl;
     606             :       }
     607             :       else {
     608        1674 :         check =  allEQ(keySet.asArrayString("QuantumUnits"), reqKeySet.asArrayString("QuantumUnits"));
     609        1674 :         if (!check) {
     610           0 :           cerr<<"NewCalTable::conformant column:"<<colNames(i)
     611           0 :                <<" has an invalid QuantumUnits:"<<keySet.asArrayString("QuantumUnits")<<endl;
     612             :         }
     613             :       }
     614             :     }
     615        9207 :   }
     616        1674 :   return isCalTableDesc && check;
     617         837 : };
     618             : 
     619             : //----------------------------------------------------------------------------
     620           0 : void NewCalTable::writeToDisk(const String& outTableName)
     621             : {
     622           0 :   Block<String> sortcols(4);
     623           0 :   sortcols[0]="SPECTRAL_WINDOW_ID"; 
     624           0 :   sortcols[1]="TIME"; 
     625           0 :   sortcols[2]="ANTENNA1"; 
     626           0 :   sortcols[3]="ANTENNA2"; 
     627           0 :   Table sorted = this->sort(sortcols,Sort::Ascending,Sort::HeapSort);
     628           0 :   sorted.deepCopy(outTableName,Table::New);
     629           0 : };
     630             : 
     631         780 : Complex NewCalTable::NCTtestvalueC(Int iant,Int ispw,Double ich,Double time,Double refTime,Double tint) {
     632             : 
     633         780 :   Double a=1.0 + Double(iant)/10.0 + Double(ispw)/100.0 + ich/10000.0;
     634         780 :   Double dt=(time-refTime)/tint;
     635         780 :   Double p=dt+ich/100.0; 
     636         780 :   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           2 : 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           2 :   if (rTime==0.0) rTime=4832568000.0;
     658           2 :   if (tint==0.0) tint=60.0;
     659             : 
     660           2 :   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           2 :   fillGenericObs(nObs);
     674           2 :   fillGenericField(nFld);
     675           2 :   fillGenericAntenna(nAnt);
     676           2 :   fillGenericSpw(nSpw,nChan);
     677             : 
     678             :   // The per-solution antenna indices
     679           2 :   Vector<Int> antlist(nAnt);
     680           2 :   indgen(antlist);
     681           2 :   Int refant=0;  // for ANTENNA2
     682             : 
     683             :   // T-like
     684           2 :   Int nPar(1);
     685             : 
     686           2 :   Double thistime(rTime-tint);  // first sample will be at rTime
     687             : 
     688           2 :   CTMainColumns ncmc(*this);
     689             : 
     690           2 :   Int thisscan(0);
     691           7 :   for (Int iobs=0;iobs<nObs;++iobs) {
     692           5 :     if (verbose) cout << "Obs=" << iobs << endl;
     693           5 :     Int thisfield(-1);
     694          14 :     for (Int iscan=0;iscan<nScanPerObs;++iscan) {
     695           9 :       thisscan+=1;    //  unique scans
     696           9 :       thisfield+=1;   // each scan is a new field
     697           9 :       thisfield=thisfield%nFld;   // never more than nFld-1
     698           9 :       if (verbose) cout << " Scan=" << thisscan << "  Field=" <<thisfield << endl; 
     699          36 :       for (Int itime=0;itime<nTimePerScan;++itime) {
     700          27 :         thistime+=tint; // every tint
     701          27 :         if (verbose) cout << "  Time="<< thistime << endl;
     702             : 
     703         105 :         for (Int ispw=0;ispw<nSpw;++ispw) {
     704             : 
     705          78 :           if (verbose) cout << "   Spw=" << ispw << endl;
     706             :           
     707             :           // add rows
     708          78 :           Int nAddRows=nAnt;
     709          78 :           RefRows rows(this->nrow(),this->nrow()+nAddRows-1,1); 
     710          78 :           this->addRow(nAddRows);
     711             : 
     712          78 :           if (verbose) cout << "    Adding " << nAnt << " rows; total=" << this->nrow() << endl;
     713             :           
     714             :           // fill columns in new rows
     715          78 :           ncmc.time().putColumnCells(rows,Vector<Double>(nAddRows,thistime));
     716          78 :           ncmc.interval().putColumnCells(rows,Vector<Double>(nAddRows,tint));
     717          78 :           ncmc.fieldId().putColumnCells(rows,Vector<Int>(nAddRows,thisfield));
     718          78 :           ncmc.spwId().putColumnCells(rows,Vector<Int>(nAddRows,ispw));
     719          78 :           ncmc.antenna1().putColumnCells(rows,antlist);
     720          78 :           ncmc.antenna2().putColumnCells(rows,Vector<Int>(nAddRows,refant));
     721          78 :           ncmc.obsId().putColumnCells(rows,Vector<Int>(nAddRows,iobs));
     722          78 :           ncmc.scanNo().putColumnCells(rows,Vector<Int>(nAddRows,thisscan));
     723             : 
     724             : 
     725          78 :           if (isComplex()) {
     726          78 :             Cube<Complex> par(nPar,nChan(ispw),nAddRows);
     727         858 :             for (Int iant=0;iant<nAnt;++iant) {
     728        1560 :               for (Int ich=0;ich<nChan(ispw);++ich) {
     729         780 :                 par.xyPlane(iant).column(ich)=NCTtestvalueC(iant,ispw,ich,thistime,rTime,tint);
     730             :               }
     731             :             }
     732          78 :             ncmc.cparam().putColumnCells(rows,par);
     733          78 :           }
     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           0 :           }
     743             : 
     744          78 :           Cube<Float> parerr(nPar,nChan(ispw),nAddRows);
     745          78 :           parerr=0.001;
     746          78 :           ncmc.paramerr().putColumnCells(rows,parerr);
     747          78 :           Cube<Float> snr(nPar,nChan(ispw),nAddRows);
     748          78 :           snr=999.0;
     749          78 :           ncmc.snr().putColumnCells(rows,snr);
     750          78 :           Cube<Float> wt(nPar,nChan(ispw),nAddRows);
     751          78 :           wt=1.0;
     752          78 :           ncmc.weight().putColumnCells(rows,wt);
     753          78 :           Cube<Bool> flag(nPar,nChan(ispw),nAddRows);
     754          78 :           flag=false;
     755          78 :           ncmc.flag().putColumnCells(rows,flag);
     756          78 :         }
     757             :       }
     758             :     }
     759             :   }
     760             :   
     761           2 : }
     762             : 
     763             : //----------------------------------------------------------------------------
     764           4 : void NewCalTable::fillGenericObs(Int nObs) { 
     765             : 
     766           4 :   this->observation().addRow(nObs);
     767           4 :   MSObservationColumns oc(this->observation());
     768           4 :   Vector<Double> tr(2,0.0);
     769           4 :   tr(1)=7609161600.0;  // the year 2100 (forever-ish)
     770          11 :   for (Int iobs=0;iobs<nObs;++iobs) {
     771           7 :     oc.timeRange().put(iobs,tr);
     772           7 :     oc.observer().put(iobs,String("unknown"));
     773           7 :     oc.project().put(iobs,String("unknown"));
     774           7 :     oc.telescopeName().put(iobs,String("unknown"));
     775           7 :     oc.flagRow().put(iobs,false);
     776             :   }
     777           4 : }
     778             : 
     779             : //----------------------------------------------------------------------------
     780           2 : void NewCalTable::fillGenericField(Int nFld) { 
     781             : 
     782           2 :   this->field().addRow(nFld);
     783           2 :   MSFieldColumns fc(this->field());
     784           5 :   for (Int ifld=0;ifld<nFld;++ifld) {
     785           3 :     fc.name().put(ifld,("Field_"+String::toString(ifld)));
     786           3 :     fc.flagRow().put(ifld,false);
     787             :   }
     788           2 : }
     789             : 
     790             : 
     791             : 
     792             : //----------------------------------------------------------------------------
     793           2 : void NewCalTable::fillGenericAntenna(Int nAnt) {
     794             : 
     795           2 :   this->antenna().addRow(nAnt);
     796           2 :   MSAntennaColumns ac(this->antenna());
     797          22 :   for (Int iant=0;iant<nAnt;++iant) {
     798          20 :     ac.name().put(iant,("Antenna_"+String::toString(iant)));
     799          20 :     ac.station().put(iant,("Station_"+String::toString(iant)));
     800          20 :     ac.type().put(iant,"GROUND-BASED");
     801          20 :     ac.mount().put(iant,"ALT-AZ");
     802          20 :     ac.dishDiameter().put(iant,25.0);
     803          20 :     ac.offset().put(iant,Vector<Double>(3,0.0));
     804          20 :     ac.position().put(iant,Vector<Double>(3,0.0));
     805          20 :     ac.flagRow().put(iant,false);
     806             :   }
     807             : 
     808           2 : }
     809             : 
     810             : 
     811             : //----------------------------------------------------------------------------
     812           2 : void NewCalTable::fillGenericSpw(Int nSpw,Vector<Int>& nChan) {
     813             : 
     814           2 :   this->spectralWindow().addRow(nSpw);
     815           2 :   MSSpWindowColumns sc(this->spectralWindow());
     816           7 :   for (Int ispw=0;ispw<nSpw;++ispw) {
     817           5 :     Double refFreq(60.0e9+Double(ispw)*1.0e9);  // Every GHz
     818           5 :     Double width(1.0e6);  // 1 MHz channels
     819           5 :     Vector<Double> chanfreq(nChan(ispw),refFreq);
     820          10 :     for (Int ich=0;ich<nChan(ispw);++ich) chanfreq(ich)+=(Double(ich)+0.5)*width;
     821             : 
     822           5 :     sc.name().put(ispw,("SPW_"+String::toString(ispw)));
     823           5 :     sc.refFrequency().put(ispw,refFreq);
     824           5 :     sc.numChan().put(ispw,nChan(ispw));
     825           5 :     sc.chanFreq().put(ispw,chanfreq);
     826             :     
     827           5 :     Vector<Double> res(nChan(ispw),width);
     828             : 
     829           5 :     sc.chanWidth().put(ispw,res);
     830           5 :     sc.effectiveBW().put(ispw,res);
     831           5 :     sc.resolution().put(ispw,res);
     832           5 :     sc.totalBandwidth().put(ispw,sum(res));
     833           5 :     sc.flagRow().put(ispw,false);
     834           5 :   }
     835           2 : }
     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           0 :   }
     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           0 :     }
    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           0 : void NewCalTable::flagAbsentSpws() {
    1041             : 
    1042           0 :   CTColumns ctcol(*this);
    1043             : 
    1044             :   // Extract unique spws in MAIN
    1045           0 :   Vector<Int> spwids;
    1046           0 :   ctcol.spwId().getColumn(spwids);
    1047           0 :   Int nspw=genSort(spwids,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
    1048           0 :   spwids.resize(nspw,true);
    1049             : 
    1050             :   // Revise SPW FLAG_ROW
    1051           0 :   Vector<Bool> spwfr;
    1052           0 :   ctcol.spectralWindow().flagRow().getColumn(spwfr);
    1053           0 :   spwfr.set(true);
    1054           0 :   for (Int ispw=0;ispw<nspw;++ispw) {
    1055           0 :     uInt thisspw=spwids(ispw);
    1056           0 :     if (thisspw<spwfr.nelements()) 
    1057           0 :       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           0 :   ctcol.spectralWindow().flagRow().putColumn(spwfr);
    1064             : 
    1065           0 : }
    1066             : // Merge SPW subtable rows from another NewCalTable
    1067           0 : void NewCalTable::mergeSpwMetaInfo(const NewCalTable& other) {
    1068             : 
    1069             :   // Access this' SPW subtable
    1070           0 :   CTSpWindowColumns spwcols(this->spectralWindow());
    1071             : 
    1072             :   // Access other's SPW subtable
    1073           0 :   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           0 :   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           0 :   uInt onspw=ospwcols.nrow();
    1082           0 :   for (uInt ispw=0;ispw<onspw;++ispw) {
    1083             : 
    1084             :     // Only if other's ispw is not flagged...
    1085           0 :     if (!ospwcols.flagRow()(ispw)) {
    1086             : 
    1087             :       try {
    1088             : 
    1089             :         // Certain meta info must already be equivalent
    1090           0 :         AlwaysAssert( spwcols.name()(ispw)==ospwcols.name()(ispw), AipsError);
    1091           0 :         AlwaysAssert( spwcols.measFreqRef()(ispw)==ospwcols.measFreqRef()(ispw), AipsError);
    1092           0 :         AlwaysAssert( spwcols.netSideband()(ispw)==ospwcols.netSideband()(ispw), AipsError);
    1093           0 :         AlwaysAssert( spwcols.ifConvChain()(ispw)==ospwcols.ifConvChain()(ispw), AipsError);
    1094           0 :         AlwaysAssert( spwcols.freqGroup()(ispw)==ospwcols.freqGroup()(ispw), AipsError);
    1095           0 :         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           0 :       }
    1100             : 
    1101             :       // ...and this' ispw _is_ flagged
    1102           0 :       if (spwcols.flagRow()(ispw)) {
    1103             : 
    1104             :         // Copy from other to this:
    1105           0 :         Int nchan=ospwcols.numChan()(ispw);
    1106           0 :         IPosition sh(1,nchan);
    1107             : 
    1108           0 :         spwcols.numChan().put(ispw,nchan);
    1109           0 :         spwcols.chanFreq().setShape(ispw,sh);
    1110           0 :         spwcols.chanFreq().put(ispw,ospwcols.chanFreq()(ispw));
    1111           0 :         spwcols.chanWidth().setShape(ispw,sh);
    1112           0 :         spwcols.chanWidth().put(ispw,ospwcols.chanWidth()(ispw));
    1113           0 :         spwcols.resolution().setShape(ispw,sh);
    1114           0 :         spwcols.resolution().put(ispw,ospwcols.resolution()(ispw));
    1115           0 :         spwcols.effectiveBW().setShape(ispw,sh);
    1116           0 :         spwcols.effectiveBW().put(ispw,ospwcols.effectiveBW()(ispw));
    1117             : 
    1118           0 :         spwcols.refFrequency().put(ispw,ospwcols.refFrequency()(ispw));
    1119           0 :         spwcols.totalBandwidth().put(ispw,ospwcols.totalBandwidth()(ispw));
    1120             : 
    1121             :         // this' row now unflagged
    1122           0 :         spwcols.flagRow().put(ispw,false);
    1123             : 
    1124           0 :       }
    1125             :       else {
    1126             : 
    1127             :         try {
    1128             :         
    1129             :           // Assert equivalence in all meaningful rows
    1130           0 :           AlwaysAssert( spwcols.numChan()(ispw)==ospwcols.numChan()(ispw), AipsError);
    1131           0 :           AlwaysAssert( allEQ(spwcols.chanFreq()(ispw),ospwcols.chanFreq()(ispw)), AipsError);
    1132           0 :           AlwaysAssert( allEQ(spwcols.chanWidth()(ispw),ospwcols.chanWidth()(ispw)), AipsError);
    1133           0 :           AlwaysAssert( allEQ(spwcols.resolution()(ispw),ospwcols.resolution()(ispw)), AipsError);
    1134           0 :           AlwaysAssert( allEQ(spwcols.effectiveBW()(ispw),ospwcols.effectiveBW()(ispw)), AipsError);
    1135           0 :           AlwaysAssert( spwcols.refFrequency()(ispw)==ospwcols.refFrequency()(ispw), AipsError);
    1136           0 :           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           0 :         }
    1141             :       }
    1142             :     } 
    1143             : 
    1144             :   } // ispw
    1145             : 
    1146             : 
    1147           0 : }
    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           0 : void NewCalTable::makeSpwSingleChan() {
    1177             : 
    1178           0 :   MSSpWindowColumns spwcol(this->spectralWindow());
    1179             : 
    1180             :   // Reset each spw to a single channel
    1181           0 :   for (uInt ispw=0;ispw<spwcol.nrow();++ispw) {
    1182             : 
    1183             :     Int nchan;
    1184           0 :     spwcol.numChan().get(ispw,nchan);
    1185           0 :     IPosition ip(1,1);
    1186           0 :     if (nchan>1) {
    1187           0 :       Vector<Double> midFreq;
    1188           0 :       spwcol.chanFreq().get(ispw,midFreq);
    1189           0 :       midFreq(0)=midFreq(nchan/2);
    1190           0 :       midFreq.resize(1,true);
    1191             :       Double totBW;
    1192           0 :       spwcol.totalBandwidth().get(ispw,totBW);
    1193           0 :       Vector<Double> totBWv(1,totBW);
    1194             :       
    1195           0 :       spwcol.numChan().put(ispw,1);
    1196             : 
    1197           0 :       spwcol.chanFreq().setShape(ispw,ip);
    1198           0 :       spwcol.chanFreq().put(ispw,midFreq);
    1199             : 
    1200           0 :       spwcol.chanWidth().setShape(ispw,ip);
    1201           0 :       spwcol.chanWidth().put(ispw,totBWv);
    1202           0 :       spwcol.effectiveBW().setShape(ispw,ip);
    1203           0 :       spwcol.effectiveBW().put(ispw,totBWv);
    1204           0 :       spwcol.resolution().setShape(ispw,ip);
    1205           0 :       spwcol.resolution().put(ispw,totBWv);
    1206             : 
    1207           0 :     }
    1208           0 :   }
    1209           0 : }
    1210             : 
    1211           2 : void NewCalTable::addPhoneyObs() {
    1212             : 
    1213           2 :   TableType ntype(this->tableType());
    1214             : 
    1215           2 :   ostringstream msg;
    1216           2 :   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           2 :   if ( (ntype==Table::Plain && this->isWritable()) ||
    1221             :        (ntype==Table::Memory) ) {
    1222             : 
    1223             :     // Add phoney OBSERVATION_ID column and fill with zeros
    1224           2 :     if (!this->tableDesc().isColumn(NCT::fieldName(NCT::OBSERVATION_ID))) {
    1225           2 :       ScalarColumnDesc<Int> obscoldesc(NCT::fieldName (NCT::OBSERVATION_ID),ColumnDesc::Direct);
    1226           2 :       this->addColumn(obscoldesc,false);
    1227           2 :       CTMainColumns mc(*this);
    1228           2 :       mc.obsId().fillColumn(0);
    1229           2 :     }
    1230             : 
    1231             :     // Add dummy OBSERVATION subtable with 1 row
    1232           2 :     if (!this->keywordSet().isDefined("OBSERVATION")) {
    1233           2 :       String  calObsName=this->tableName()+"/OBSERVATION";
    1234           2 :       Table::TableOption access(Table::NewNoReplace);
    1235           2 :       SetupNewTable obstab(calObsName,CTObservation::requiredTableDesc(),access);
    1236           2 :       this->rwKeywordSet().defineTable("OBSERVATION", Table(obstab,ntype));  // same type as parent table
    1237           2 :       observation_p = CTObservation(this->keywordSet().asTable("OBSERVATION"));
    1238           2 :       fillGenericObs(1);
    1239           2 :     }
    1240             : 
    1241           2 :     msg << "SUCCEEDED: trivial OBSERVATION/OBSERVATION_ID have been added.";
    1242             : 
    1243           2 :     LogIO log;
    1244           2 :     log << msg.str() << LogIO::WARN;
    1245             : 
    1246           2 :   }
    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           2 : }
    1255             : 
    1256             : 
    1257             : 
    1258             : } //# NAMESPACE CASA - END

Generated by: LCOV version 1.16