LCOV - code coverage report
Current view: top level - synthesis/CalTables - CTPatchedInterp.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 0 1027 0.0 %
Date: 2024-10-10 15:00:01 Functions: 0 22 0.0 %

          Line data    Source code
       1             : //# CTPatchedInterp.cc: Implementation of CTPatchedInterp.h
       2             : //# Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003
       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 adressed 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             : //#
      27             : 
      28             : #include <synthesis/CalTables/CTPatchedInterp.h>
      29             : #include <synthesis/CalTables/CTIter.h>
      30             : 
      31             : #include <casacore/scimath/Mathematics/InterpolateArray1D.h>
      32             : #include <casacore/casa/OS/Path.h>
      33             : #include <casacore/casa/Utilities/GenSort.h>
      34             : #include <casacore/casa/aips.h>
      35             : 
      36             : #define CTPATCHEDINTERPVERB false
      37             : 
      38             : #define NEAREST InterpolateArray1D<Double,Float>::nearestNeighbour
      39             : #define LINEAR InterpolateArray1D<Double,Float>::linear
      40             : #define CUBIC InterpolateArray1D<Double,Float>::cubic
      41             : #define SPLINE InterpolateArray1D<Double,Float>::spline
      42             : 
      43             : #include <casacore/ms/MSOper/MSMetaData.h>
      44             : #include <synthesis/MeasurementComponents/MSMetaInfoForCal.h>
      45             : #include <casacore/casa/Logging/LogMessage.h>
      46             : #include <casacore/casa/Logging/LogIO.h>
      47             : 
      48             : using namespace casacore;
      49             : namespace casa { //# NAMESPACE CASA - BEGIN
      50             : 
      51             : // Ctor
      52           0 : CTPatchedInterp::CTPatchedInterp(NewCalTable& ct,
      53             :                                  VisCalEnum::MatrixType mtype,
      54             :                                  Int nPar,
      55             :                                  const String& timetype,
      56             :                                  const String& freqtype,
      57             :                                  const String& fieldtype,
      58             :                                  Vector<Int> spwmap,
      59             :                                  Vector<Int> fldmap,
      60           0 :                                  const CTTIFactoryPtr cttifactoryptr) :
      61           0 :   ct_(ct),
      62           0 :   ctname_(),
      63           0 :   msmc_(NULL),
      64           0 :   mtype_(mtype),
      65           0 :   isCmplx_(false),
      66           0 :   nPar_(nPar),
      67           0 :   nFPar_(nPar),
      68           0 :   timeType_(timetype),
      69           0 :   freqTypeStr_(freqtype),
      70           0 :   relativeFreq_(freqtype.contains("rel")),
      71           0 :   freqInterpMethod0_(ftype(freqTypeStr_)),
      72           0 :   freqInterpMethod_(freqInterpMethod0_),
      73           0 :   freqInterpMethodVec_(),
      74           0 :   byObs_(timetype.contains("perobs")), // detect slicing by obs
      75           0 :   byScan_(timetype.contains("perscan")), // detect slicing by scan
      76           0 :   byField_(fieldtype=="nearest" || fieldtype=="map"), 
      77           0 :   nChanIn_(),
      78           0 :   freqIn_(),
      79           0 :   nMSTimeSeg_(1), // byObs_?ct.observation().nrow():1),  // assume CT shapes for MS shapes
      80           0 :   nMSFld_(ct.field().nrow()),                 
      81           0 :   nMSSpw_(ct.spectralWindow().nrow()),
      82           0 :   nMSAnt_(ct.antenna().nrow()),
      83           0 :   altFld_(),
      84           0 :   nCTTimeSeg_(1), // byObs_?ct.observation().nrow():1),
      85           0 :   nCTFld_(byField_?ct.field().nrow():1),
      86           0 :   nCTSpw_(ct.spectralWindow().nrow()),
      87           0 :   nCTAnt_(ct.antenna().nrow()),
      88           0 :   nCTElem_(0),
      89           0 :   spwInOK_(),
      90           0 :   fldMap_(),
      91           0 :   spwMap_(),
      92           0 :   antMap_(),
      93           0 :   elemMap_(),
      94           0 :   conjTab_(),
      95           0 :   result_(),
      96           0 :   resFlag_(),
      97           0 :   tI_(),
      98           0 :   tIdel_(),
      99           0 :   tIMissingLogged_(),
     100           0 :   lastFld_(ct.spectralWindow().nrow(),-1),
     101           0 :   lastObs_(ct.spectralWindow().nrow(),-1),
     102           0 :   lastScan_(ct.spectralWindow().nrow(),-1),
     103           0 :   cttifactoryptr_(cttifactoryptr)
     104             : {
     105             :   if (CTPATCHEDINTERPVERB) cout << "CTPatchedInterp::CTPatchedInterp(<no MS>)" << endl;
     106             : 
     107             :   //  cout << "freqInterpMethod_ = " << freqInterpMethod_ << endl;
     108             : 
     109           0 :   freqInterpMethodVec_.resize(nMSSpw_);
     110           0 :   freqInterpMethodVec_.set(freqInterpMethod0_);
     111             :     
     112           0 :   switch(mtype_) {
     113           0 :   case VisCalEnum::GLOBAL: {
     114             : 
     115           0 :     throw(AipsError("CTPatchedInterp::ctor: No non-Mueller/Jones yet."));
     116             : 
     117             :     nCTElem_=1;
     118             :     nMSElem_=1;
     119             :     break;
     120             :   }
     121           0 :   case VisCalEnum::MUELLER: {
     122           0 :     nCTElem_=nCTAnt_*(nCTAnt_+1)/2;
     123           0 :     nMSElem_=nMSAnt_*(nMSAnt_+1)/2;
     124           0 :     break;
     125             :   }
     126           0 :   case VisCalEnum::JONES: {
     127           0 :     nCTElem_=nCTAnt_;
     128           0 :     nMSElem_=nMSAnt_;
     129           0 :     break;
     130             :   }
     131             :   }
     132             : 
     133             :   // How many _Float_ parameters?
     134           0 :   isCmplx_=(ct_.keywordSet().asString("ParType")=="Complex");
     135           0 :   if (isCmplx_)  // Complex input
     136           0 :     nFPar_*=2;  // interpolating 2X as many Float values
     137             : 
     138             : 
     139             :   // Set channel/freq info
     140           0 :   CTSpWindowColumns ctspw(ct_.spectralWindow());
     141           0 :   ctspw.numChan().getColumn(nChanIn_);
     142           0 :   freqIn_.resize(nCTSpw_);
     143           0 :   for (uInt iCTspw=0;iCTspw<ctspw.nrow();++iCTspw) {
     144           0 :     ctspw.chanFreq().get(iCTspw,freqIn_(iCTspw),true);
     145           0 :     if (relativeFreq_) {
     146           0 :       Vector<Double>& fIn(freqIn_(iCTspw));
     147           0 :       fIn-=mean(fIn); //  assume mean freq is center, and apply offset
     148             :       // Flip LSB
     149           0 :       if (fIn.nelements()>1 && fIn(0)>fIn(1)) {
     150             :         //cout << " spw=" << iCTspw << " LSB!" << endl;
     151           0 :         fIn*=Double(-1.0);
     152             :       }
     153             :     }
     154             :     //cout << " freqIn_(" << iCTspw << ")=" << freqIn_(iCTspw) << endl;
     155             :   }
     156             : 
     157             :   // byScan_ supercedes byObs_, so turn OFF byObs_, if necessary
     158           0 :   if (byObs_ && byScan_) {
     159           0 :     byObs_=false;
     160           0 :     LogIO log;
     161           0 :     ostringstream msg;
     162           0 :     msg << "For " << Path(ct_.tableName()).baseName().before(".tempMemCal")
     163           0 :         << " 'perscan' interpolation supercedes 'perobs' interpolation. ";
     164           0 :     log << msg.str() << LogIO::WARN;
     165           0 :   }
     166             :   
     167             :   // Manage 'byObs_' carefully
     168           0 :   if (byObs_) {
     169             : 
     170           0 :     Int nMSObs=ct_.observation().nrow(); // assume CT shapes for MS shapes
     171           0 :     Int nCTObs=ct_.observation().nrow();
     172             : 
     173             :     // Count _available_ obsids in caltable
     174           0 :     ROCTMainColumns ctmc(ct_);
     175           0 :     Vector<Int> obsid;
     176           0 :     ctmc.obsId().getColumn(obsid);
     177           0 :     Int nctobsavail=genSort(obsid,Sort::Ascending,
     178           0 :                             (Sort::QuickSort | Sort::NoDuplicates));
     179             : 
     180             : 
     181           0 :     LogIO log;
     182           0 :     ostringstream msg;
     183             :     
     184           0 :     if (nctobsavail==1) {
     185           0 :       byObs_=false;
     186           0 :       msg << "Only one ObsId found in "
     187           0 :           << Path(ct_.tableName()).baseName().before(".tempMemCal")
     188           0 :           << "; ignoring 'perobs' interpolation.";
     189           0 :       log << msg.str() << LogIO::WARN;
     190             :     }
     191             :     else {
     192             : 
     193             :       // Verify consistency between CT and MS
     194           0 :       if (nctobsavail==nCTObs &&
     195             :           nctobsavail==nMSObs) {
     196             :         // Everything ok
     197           0 :         nCTTimeSeg_=nCTObs;
     198           0 :         nMSTimeSeg_=nMSObs;
     199             :       }
     200             :       else {
     201             :         // only 1 obs, or available nobs doesn't match MS
     202           0 :         byObs_=false;
     203           0 :         msg << "Multiple ObsIds found in "
     204           0 :             << Path(ct_.tableName()).baseName().before(".tempMemCal")
     205             :             << ", but they do not match the MS ObsIds;"
     206           0 :             << " turning off 'perobs'.";
     207           0 :         log << msg.str() << LogIO::WARN;
     208             :       }
     209             :     }
     210             : 
     211           0 :   }
     212             : 
     213             :   // Manage 'byScan_' even more carefully
     214           0 :   if (byScan_) {
     215             : 
     216           0 :     LogIO log;
     217           0 :     ostringstream msg;
     218             : 
     219             :     // Count _availale_ scan numbers in caltable
     220           0 :     ROCTMainColumns ctmc(ct_);
     221           0 :     Vector<Int> scan;
     222             :     Int minScan, maxScan;
     223           0 :     ctmc.scanNo().getColumn(scan);
     224           0 :     minMax(minScan, maxScan, scan);
     225           0 :     if (minScan == -1) {
     226           0 :       byScan_=false;
     227           0 :       msg << "No scan numbers found in "
     228           0 :           << Path(ct_.tableName()).baseName().before(".tempMemCal")
     229           0 :           << "; ignoring 'perscan' interpolation.";
     230           0 :       log << msg.str() << LogIO::WARN;
     231             :     } else {
     232           0 :       nCTTimeSeg_=maxScan+1;
     233           0 :       nMSTimeSeg_=maxScan+1; // assume CT shapes for MS shapes
     234             :     }
     235           0 :   }
     236             : 
     237             :   // Initialize caltable slices
     238           0 :   sliceTable();
     239             : 
     240             :   // Set spwmap
     241           0 :   setSpwMap(spwmap);
     242             : 
     243             :   // Set fldmap
     244           0 :   if (byField_) {
     245           0 :     if (fieldtype=="map")
     246           0 :       setFldMap(fldmap);  // Use specified map
     247             :     else
     248           0 :       setFldMap(ct.field());  // Use CalTable's fields ('nearest')
     249             :   }
     250             :   else
     251           0 :     setDefFldMap();
     252             : 
     253             :   // Set defaultmaps
     254           0 :   setDefAntMap();
     255           0 :   setElemMap();
     256             : 
     257             :   // Resize working arrays
     258           0 :   result_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     259           0 :   resFlag_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     260           0 :   timeResult_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     261           0 :   timeResFlag_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     262           0 :   freqResult_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     263           0 :   freqResFlag_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     264             : 
     265             :   // Figure out where we can duplicate field interpolators
     266           0 :   calcAltFld();
     267             : 
     268             :   // Setup mapped interpolators
     269             :   // TBD: defer this to later, so that spwmap, etc. can be revised
     270             :   //   before committing to the interpolation engines
     271           0 :   makeInterpolators();
     272             : 
     273             :   //  state();
     274           0 : }
     275             : 
     276           0 : CTPatchedInterp::CTPatchedInterp(NewCalTable& ct,
     277             :                                  VisCalEnum::MatrixType mtype,
     278             :                                  Int nPar,
     279             :                                  const String& timetype,
     280             :                                  const String& freqtype,
     281             :                                  const String& fieldtype,
     282             :                                  const MeasurementSet& ms,
     283             :                  const MSMetaInfoForCal& msmc,
     284             :                                  Vector<Int> spwmap,
     285           0 :                                  const CTTIFactoryPtr cttifactoryptr) :
     286           0 :   ct_(ct),
     287           0 :   ctname_(),
     288           0 :   msmc_(&msmc),
     289           0 :   mtype_(mtype),
     290           0 :   isCmplx_(false),
     291           0 :   nPar_(nPar),
     292           0 :   nFPar_(nPar),
     293           0 :   timeType_(timetype),
     294           0 :   freqTypeStr_(freqtype),
     295           0 :   relativeFreq_(freqtype.contains("rel")),
     296           0 :   freqInterpMethod0_(ftype(freqTypeStr_)),
     297           0 :   freqInterpMethod_(freqInterpMethod0_),
     298           0 :   freqInterpMethodVec_(),
     299           0 :   byObs_(timetype.contains("perobs")), // detect slicing by obs
     300           0 :   byScan_(timetype.contains("perscan")), // detect slicing by scan
     301           0 :   byField_(fieldtype=="nearest"),  // for now we are NOT slicing by field
     302           0 :   nChanIn_(),
     303           0 :   freqIn_(),
     304           0 :   nMSTimeSeg_(1), // byObs_?ms.observation().nrow():1),
     305           0 :   nMSFld_(ms.field().nrow()),  
     306           0 :   nMSSpw_(ms.spectralWindow().nrow()),
     307           0 :   nMSAnt_(ms.antenna().nrow()),
     308           0 :   altFld_(),
     309           0 :   nCTTimeSeg_(1),  // byObs_?ct.observation().nrow():1),
     310           0 :   nCTFld_(byField_?ct.field().nrow():1),
     311           0 :   nCTSpw_(ct.spectralWindow().nrow()),
     312           0 :   nCTAnt_(ct.antenna().nrow()),
     313           0 :   nCTElem_(0),
     314           0 :   spwInOK_(),
     315           0 :   fldMap_(),
     316           0 :   spwMap_(),
     317           0 :   antMap_(),
     318           0 :   elemMap_(),
     319           0 :   conjTab_(),
     320           0 :   result_(),
     321           0 :   resFlag_(),
     322           0 :   tI_(),
     323           0 :   tIdel_(),
     324           0 :   tIMissingLogged_(),
     325           0 :   lastFld_(ms.spectralWindow().nrow(),-1),
     326           0 :   lastObs_(ms.spectralWindow().nrow(),-1),
     327           0 :   lastScan_(ms.spectralWindow().nrow(),-1),
     328           0 :   cttifactoryptr_(cttifactoryptr)
     329             : {
     330             : 
     331             :   if (CTPATCHEDINTERPVERB) cout << "CTPatchedInterp::CTPatchedInterp(CT,MS)" << endl;
     332             : 
     333             :   //freqInterpMethod_=ftype(freqTypeStr_);
     334             : 
     335           0 :   freqInterpMethodVec_.resize(nMSSpw_);
     336           0 :   freqInterpMethodVec_.set(freqInterpMethod0_);
     337             : 
     338             :   //  cout << "freqInterpMethod_ = " << freqInterpMethod_ << endl;
     339             : 
     340           0 :   switch(mtype_) {
     341           0 :   case VisCalEnum::GLOBAL: {
     342             : 
     343           0 :     throw(AipsError("CTPatchedInterp::ctor: No non-Mueller/Jones yet."));
     344             : 
     345             :     nCTElem_=1;
     346             :     nMSElem_=1;
     347             :     break;
     348             :   }
     349           0 :   case VisCalEnum::MUELLER: {
     350           0 :     nCTElem_=nCTAnt_*(nCTAnt_+1)/2;
     351           0 :     nMSElem_=nMSAnt_*(nMSAnt_+1)/2;
     352           0 :     break;
     353             :   }
     354           0 :   case VisCalEnum::JONES: {
     355           0 :     nCTElem_=nCTAnt_;
     356           0 :     nMSElem_=nMSAnt_;
     357           0 :     break;
     358             :   }
     359             :   }
     360             : 
     361             :   // How many _Float_ parameters?
     362           0 :   isCmplx_=(ct_.keywordSet().asString("ParType")=="Complex");  // Complex input
     363           0 :   if (isCmplx_)
     364           0 :     nFPar_*=2;  // interpolating 2X as many Float values
     365             : 
     366             :   // Set channel/freq info
     367           0 :   CTSpWindowColumns ctspw(ct_.spectralWindow());
     368           0 :   ctspw.numChan().getColumn(nChanIn_);
     369           0 :   freqIn_.resize(nCTSpw_);
     370           0 :   for (uInt iCTspw=0;iCTspw<ctspw.nrow();++iCTspw) {
     371           0 :     ctspw.chanFreq().get(iCTspw,freqIn_(iCTspw),true);
     372           0 :     if (relativeFreq_) {
     373           0 :       Vector<Double>& fIn(freqIn_(iCTspw));
     374           0 :       fIn-=mean(fIn); //  assume mean freq is center, and apply offset
     375             :       // Flip LSB
     376           0 :       if (fIn.nelements()>1 && fIn(0)>fIn(1)) {
     377             :         //cout << " spw=" << iCTspw << " LSB!" << endl;
     378           0 :         fIn*=Double(-1.0);
     379             :       }
     380             :     }
     381             :     //cout << " freqIn_(" << iCTspw << ")=" << freqIn_(iCTspw) << endl;
     382             :   }
     383             : 
     384             :   // byScan_ supercedes byObs_, so turn OFF byObs_, if necessary
     385           0 :   if (byObs_ && byScan_) {
     386           0 :     byObs_=false;
     387           0 :     LogIO log;
     388           0 :     ostringstream msg;
     389           0 :     msg << "For " << Path(ct_.tableName()).baseName().before(".tempMemCal")
     390           0 :         << " 'perscan' interpolation supercedes 'perobs' interpolation. ";
     391           0 :     log << msg.str() << LogIO::WARN;
     392           0 :   }
     393             :     
     394             :   // Manage 'byObs_' carefully
     395           0 :   if (byObs_) {
     396           0 :     Int nMSObs=ms.observation().nrow();
     397           0 :     Int nCTObs=ct_.observation().nrow();
     398             : 
     399             :     // Count _available_ obsids in caltable
     400           0 :     ROCTMainColumns ctmc(ct_);
     401           0 :     Vector<Int> obsid;
     402           0 :     ctmc.obsId().getColumn(obsid);
     403           0 :     Int nctobsavail=genSort(obsid,Sort::Ascending,
     404           0 :                             (Sort::QuickSort | Sort::NoDuplicates));
     405             : 
     406             : 
     407           0 :     LogIO log;
     408           0 :     ostringstream msg;
     409             :     
     410           0 :     if (nctobsavail==1) {
     411           0 :       byObs_=false;
     412           0 :       msg << "Only one ObsId found in "
     413           0 :           << Path(ct_.tableName()).baseName().before(".tempMemCal")
     414           0 :           << "; ignoring 'perobs' interpolation.";
     415           0 :       log << msg.str() << LogIO::WARN;
     416             :     }
     417             :     else {
     418             : 
     419             :       // Verify consistency between CT and MS
     420           0 :       if (nctobsavail==nCTObs &&
     421             :           nctobsavail==nMSObs) {
     422             :         // Everything ok
     423           0 :         nCTTimeSeg_=nCTObs;
     424           0 :         nMSTimeSeg_=nMSObs;
     425             :       }
     426             :       else {
     427             :         // only 1 obs, or available nobs doesn't match MS
     428           0 :         byObs_=false;
     429           0 :         msg << "Multiple ObsIds found in "
     430           0 :             << Path(ct_.tableName()).baseName().before(".tempMemCal")
     431             :             << ", but they do not match the MS ObsIds;"
     432           0 :             << " turning off 'perobs'.";
     433           0 :         log << msg.str() << LogIO::WARN;
     434             :       }
     435             :     }
     436           0 :   }
     437             : 
     438             :   // Manage 'byScan_' even more carefully
     439           0 :   if (byScan_) {
     440             : 
     441           0 :     LogIO log;
     442           0 :     ostringstream msg;
     443             : 
     444             :     // Count _availale_ scan numbers in caltable
     445           0 :     ROCTMainColumns ctmc(ct_);
     446           0 :     Vector<Int> scan;
     447             :     Int minScan, maxScan;
     448           0 :     ctmc.scanNo().getColumn(scan);
     449           0 :     minMax(minScan, maxScan, scan);
     450           0 :     if (minScan == -1) {
     451           0 :       byScan_=false;
     452           0 :       msg << "No scan numbers found in "
     453           0 :           << Path(ct_.tableName()).baseName().before(".tempMemCal")
     454           0 :           << "; ignoring 'perscan' interpolation.";
     455           0 :       log << msg.str() << LogIO::WARN;
     456             :     } else {
     457           0 :       std::set<Int> scanNumbers = msmc.msmd().getScanNumbers(0,0);
     458           0 :       nCTTimeSeg_=maxScan+1;
     459           0 :       nMSTimeSeg_=*scanNumbers.rbegin()+1;
     460             : 
     461           0 :     }
     462           0 :   }
     463             :   
     464             :   // Initialize caltable slices
     465           0 :   sliceTable();
     466             : 
     467             :   // Set spwmap
     468           0 :   setSpwMap(spwmap);
     469             : 
     470             :   // Set fldmap
     471           0 :   if (byField_)
     472           0 :     setFldMap(ms.field());  // on a trial basis
     473             :   else
     474           0 :     setDefFldMap();
     475             : 
     476             :   // Set defaultmaps
     477           0 :   setDefAntMap();
     478           0 :   setElemMap();
     479             : 
     480             :   // Resize working arrays
     481           0 :   result_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     482           0 :   resFlag_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     483           0 :   timeResult_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     484           0 :   timeResFlag_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     485           0 :   freqResult_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     486           0 :   freqResFlag_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     487             : 
     488             :   // Figure out where we can duplicate field interpolators
     489           0 :   calcAltFld();
     490             :   
     491             :   // Setup mapped interpolators
     492             :   // TBD: defer this to later, so that spwmap, etc. can be revised
     493             :   //   before committing to the interpolation engines
     494           0 :   makeInterpolators();
     495             : 
     496             :   //  state();
     497             : 
     498           0 : }
     499             : 
     500           0 : CTPatchedInterp::CTPatchedInterp(NewCalTable& ct,
     501             :                                  VisCalEnum::MatrixType mtype,
     502             :                                  Int nPar,
     503             :                                  const String& timetype,
     504             :                                  const String& freqtype,
     505             :                                  const String& fieldtype,
     506             :                                  const MSColumns& mscol,
     507             :                                  Vector<Int> spwmap,
     508           0 :                                  const CTTIFactoryPtr cttifactoryptr) :
     509           0 :   ct_(ct),
     510           0 :   ctname_(),
     511           0 :   msmc_(NULL),
     512           0 :   mtype_(mtype),
     513           0 :   isCmplx_(false),
     514           0 :   nPar_(nPar),
     515           0 :   nFPar_(nPar),
     516           0 :   timeType_(timetype),
     517           0 :   freqTypeStr_(freqtype),
     518           0 :   relativeFreq_(freqtype.contains("rel")),
     519           0 :   freqInterpMethod0_(ftype(freqTypeStr_)),
     520           0 :   freqInterpMethod_(freqInterpMethod0_),
     521           0 :   freqInterpMethodVec_(),
     522           0 :   byObs_(false),                // turn off for old-fashioned
     523           0 :   byScan_(false),               // turn off for old-fashioned
     524           0 :   byField_(fieldtype=="nearest"),  // for now we are NOT slicing by field
     525           0 :   nChanIn_(),
     526           0 :   freqIn_(),
     527           0 :   nMSFld_(mscol.field().nrow()),  
     528           0 :   nMSSpw_(mscol.spectralWindow().nrow()),
     529           0 :   nMSAnt_(mscol.antenna().nrow()),
     530           0 :   altFld_(),
     531           0 :   nCTFld_(byField_?ct.field().nrow():1),
     532           0 :   nCTSpw_(ct.spectralWindow().nrow()),
     533           0 :   nCTAnt_(ct.antenna().nrow()),
     534           0 :   nCTElem_(0),
     535           0 :   spwInOK_(),
     536           0 :   fldMap_(),
     537           0 :   spwMap_(),
     538           0 :   antMap_(),
     539           0 :   elemMap_(),
     540           0 :   conjTab_(),
     541           0 :   result_(),
     542           0 :   resFlag_(),
     543           0 :   tI_(),
     544           0 :   tIdel_(),
     545           0 :   tIMissingLogged_(),
     546           0 :   lastFld_(mscol.spectralWindow().nrow(),-1),
     547           0 :   lastObs_(mscol.spectralWindow().nrow(),-1),
     548           0 :   lastScan_(mscol.spectralWindow().nrow(),-1),
     549           0 :   cttifactoryptr_(cttifactoryptr)
     550             : {
     551             :   if (CTPATCHEDINTERPVERB) cout << "CTPatchedInterp::CTPatchedInterp(mscol)" << endl;
     552             : 
     553             :   //  cout << "freqInterpMethod_ = " << freqInterpMethod_ << endl;
     554           0 :   freqInterpMethodVec_.resize(nMSSpw_);
     555           0 :   freqInterpMethodVec_.set(freqInterpMethod0_);
     556             : 
     557           0 :   switch(mtype_) {
     558           0 :   case VisCalEnum::GLOBAL: {
     559             : 
     560           0 :     throw(AipsError("CTPatchedInterp::ctor: No non-Mueller/Jones yet."));
     561             : 
     562             :     nCTElem_=1;
     563             :     nMSElem_=1;
     564             :     break;
     565             :   }
     566           0 :   case VisCalEnum::MUELLER: {
     567           0 :     nCTElem_=nCTAnt_*(nCTAnt_+1)/2;
     568           0 :     nMSElem_=nMSAnt_*(nMSAnt_+1)/2;
     569           0 :     break;
     570             :   }
     571           0 :   case VisCalEnum::JONES: {
     572           0 :     nCTElem_=nCTAnt_;
     573           0 :     nMSElem_=nMSAnt_;
     574           0 :     break;
     575             :   }
     576             :   }
     577             : 
     578             :   // How many _Float_ parameters?
     579           0 :   isCmplx_=(ct_.keywordSet().asString("ParType")=="Complex");
     580           0 :   if (isCmplx_)  // Complex input
     581           0 :     nFPar_*=2;  // interpolating 2X as many Float values
     582             : 
     583             :   // Set channel/freq info
     584           0 :   CTSpWindowColumns ctspw(ct_.spectralWindow());
     585           0 :   ctspw.numChan().getColumn(nChanIn_);
     586           0 :   freqIn_.resize(nCTSpw_);
     587           0 :   for (uInt iCTspw=0;iCTspw<ctspw.nrow();++iCTspw) {
     588           0 :     ctspw.chanFreq().get(iCTspw,freqIn_(iCTspw),true);
     589           0 :     if (relativeFreq_) {
     590           0 :       Vector<Double>& fIn(freqIn_(iCTspw));
     591           0 :       fIn-=mean(fIn); //  assume mean freq is center, and apply offset
     592             :       // Flip LSB
     593           0 :       if (fIn.nelements()>1 && fIn(0)>fIn(1)) {
     594             :         //cout << " spw=" << iCTspw << " LSB!" << endl;
     595           0 :         fIn*=Double(-1.0);
     596             :       }
     597             :     }
     598             :     //    cout << " freqIn_(" << iCTspw << ")=" << freqIn_(iCTspw) << endl;
     599             :   }
     600             : 
     601             :   // Initialize caltable slices
     602           0 :   sliceTable();
     603             : 
     604             :   // Set spwmap
     605           0 :   setSpwMap(spwmap);
     606             : 
     607             :   // Set fldmap
     608           0 :   if (byField_)
     609           0 :     setFldMap(mscol.field());  // on a trial basis
     610             :   else
     611           0 :     setDefFldMap();
     612             : 
     613             : 
     614             :   // Set defaultmaps
     615           0 :   setDefAntMap();
     616           0 :   setElemMap();
     617             : 
     618             :   // Resize working arrays
     619           0 :   result_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     620           0 :   resFlag_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     621           0 :   timeResult_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     622           0 :   timeResFlag_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     623           0 :   freqResult_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     624           0 :   freqResFlag_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     625             : 
     626             :   // Figure out where we can duplicate field interpolators
     627           0 :   calcAltFld();
     628             : 
     629             :   // Setup mapped interpolators
     630             :   // TBD: defer this to later, so that spwmap, etc. can be revised
     631             :   //   before committing to the interpolation engines
     632           0 :   makeInterpolators();
     633             : 
     634             :   //  state();
     635             : 
     636           0 : }
     637             :     
     638           0 : CTPatchedInterp::CTPatchedInterp(NewCalTable& ct,
     639             :                  VisCalEnum::MatrixType mtype,
     640             :                  Int nPar,
     641             :                  const String& timetype,
     642             :                  const String& freqtype,
     643             :                  const String& fieldtype,
     644             :                  const MeasurementSet& ms,
     645             :                  Vector<Int> spwmap,
     646           0 :                  const CTTIFactoryPtr cttifactoryptr) :
     647           0 :   ct_(ct),
     648           0 :   ctname_(),
     649           0 :   msmc_(NULL),
     650           0 :   mtype_(mtype),
     651           0 :   isCmplx_(false),
     652           0 :   nPar_(nPar),
     653           0 :   nFPar_(nPar),
     654           0 :   timeType_(timetype),
     655           0 :   freqTypeStr_(freqtype),
     656           0 :   relativeFreq_(freqtype.contains("rel")),
     657           0 :   freqInterpMethod0_(ftype(freqTypeStr_)),
     658           0 :   freqInterpMethod_(freqInterpMethod0_),
     659           0 :   freqInterpMethodVec_(),
     660           0 :   byObs_(timetype.contains("perobs")), // detect slicing by obs
     661           0 :   byScan_(timetype.contains("perscan")), // detect slicing by scan
     662           0 :   byField_(fieldtype=="nearest"),  // for now we are NOT slicing by field
     663           0 :   nChanIn_(),
     664           0 :   freqIn_(),
     665           0 :   nMSTimeSeg_(1), // byObs_?ms.observation().nrow():1),
     666           0 :   nMSFld_(ms.field().nrow()),
     667           0 :   nMSSpw_(ms.spectralWindow().nrow()),
     668           0 :   nMSAnt_(ms.antenna().nrow()),
     669           0 :   altFld_(),
     670           0 :   nCTTimeSeg_(1),  // byObs_?ct.observation().nrow():1),
     671           0 :   nCTFld_(byField_?ct.field().nrow():1),
     672           0 :   nCTSpw_(ct.spectralWindow().nrow()),
     673           0 :   nCTAnt_(ct.antenna().nrow()),
     674           0 :   nCTElem_(0),
     675           0 :   spwInOK_(),
     676           0 :   fldMap_(),
     677           0 :   spwMap_(),
     678           0 :   antMap_(),
     679           0 :   elemMap_(),
     680           0 :   conjTab_(),
     681           0 :   result_(),
     682           0 :   resFlag_(),
     683           0 :   tI_(),
     684           0 :   tIdel_(),
     685           0 :   tIMissingLogged_(),
     686           0 :   lastFld_(ms.spectralWindow().nrow(),-1),
     687           0 :   lastObs_(ms.spectralWindow().nrow(),-1),
     688           0 :   lastScan_(ms.spectralWindow().nrow(),-1),
     689           0 :   cttifactoryptr_(cttifactoryptr)
     690             : {
     691             :     
     692             :   if (CTPATCHEDINTERPVERB) cout << "CTPatchedInterp::CTPatchedInterp(CT,MS)" << endl;
     693             :     
     694             :   //freqInterpMethod_=ftype(freqTypeStr_);
     695             :     
     696           0 :   freqInterpMethodVec_.resize(nMSSpw_);
     697           0 :   freqInterpMethodVec_.set(freqInterpMethod0_);
     698             :     
     699             :   //  cout << "freqInterpMethod_ = " << freqInterpMethod_ << endl;
     700             :     
     701           0 :   switch(mtype_) {
     702           0 :     case VisCalEnum::GLOBAL: {
     703             :             
     704           0 :       throw(AipsError("CTPatchedInterp::ctor: No non-Mueller/Jones yet."));
     705             :             
     706             :       nCTElem_=1;
     707             :       nMSElem_=1;
     708             :       break;
     709             :     }
     710           0 :     case VisCalEnum::MUELLER: {
     711           0 :       nCTElem_=nCTAnt_*(nCTAnt_+1)/2;
     712           0 :       nMSElem_=nMSAnt_*(nMSAnt_+1)/2;
     713           0 :       break;
     714             :     }
     715           0 :     case VisCalEnum::JONES: {
     716           0 :       nCTElem_=nCTAnt_;
     717           0 :       nMSElem_=nMSAnt_;
     718           0 :       break;
     719             :     }
     720             :     }
     721             :     
     722             :     // How many _Float_ parameters?
     723           0 :     isCmplx_=(ct_.keywordSet().asString("ParType")=="Complex");  // Complex input
     724           0 :     if (isCmplx_)
     725           0 :         nFPar_*=2;  // interpolating 2X as many Float values
     726             :     
     727             :     // Set channel/freq info
     728           0 :     CTSpWindowColumns ctspw(ct_.spectralWindow());
     729           0 :     ctspw.numChan().getColumn(nChanIn_);
     730           0 :     freqIn_.resize(nCTSpw_);
     731           0 :     for (uInt iCTspw=0;iCTspw<ctspw.nrow();++iCTspw) {
     732           0 :         ctspw.chanFreq().get(iCTspw,freqIn_(iCTspw),true);
     733           0 :         if (relativeFreq_) {
     734           0 :             Vector<Double>& fIn(freqIn_(iCTspw));
     735           0 :             fIn-=mean(fIn); //  assume mean freq is center, and apply offset
     736             :             // Flip LSB
     737           0 :             if (fIn.nelements()>1 && fIn(0)>fIn(1)) {
     738             :                 //cout << " spw=" << iCTspw << " LSB!" << endl;
     739           0 :                 fIn*=Double(-1.0);
     740             :             }
     741             :         }
     742             :         //cout << " freqIn_(" << iCTspw << ")=" << freqIn_(iCTspw) << endl;
     743             :     }
     744             :     
     745             :     // Manage 'byObs_' carefully
     746           0 :     if (byObs_) {
     747           0 :         Int nMSObs=ms.observation().nrow();
     748           0 :         Int nCTObs=ct_.observation().nrow();
     749             :         
     750             :         // Count _available_ obsids in caltable
     751           0 :         ROCTMainColumns ctmc(ct_);
     752           0 :         Vector<Int> obsid;
     753           0 :         ctmc.obsId().getColumn(obsid);
     754           0 :         Int nctobsavail=genSort(obsid,Sort::Ascending,
     755           0 :                                 (Sort::QuickSort | Sort::NoDuplicates));
     756             :         
     757             :         
     758           0 :         LogIO log;
     759           0 :         ostringstream msg;
     760             :         
     761           0 :         if (nctobsavail==1) {
     762           0 :             byObs_=false;
     763           0 :             msg << "Only one ObsId found in "
     764           0 :             << Path(ct_.tableName()).baseName().before(".tempMemCal")
     765           0 :             << "; ignoring 'perobs' interpolation.";
     766           0 :             log << msg.str() << LogIO::WARN;
     767             :         }
     768             :         else {
     769             :             
     770             :             // Verify consistency between CT and MS
     771           0 :             if (nctobsavail==nCTObs &&
     772             :                 nctobsavail==nMSObs) {
     773             :                 // Everything ok
     774           0 :                 nCTTimeSeg_=nCTObs;
     775           0 :                 nMSTimeSeg_=nMSObs;
     776             :             }
     777             :             else {
     778             :                 // only 1 obs, or available nobs doesn't match MS
     779           0 :                 byObs_=false;
     780           0 :                 msg << "Multiple ObsIds found in "
     781           0 :                 << Path(ct_.tableName()).baseName().before(".tempMemCal")
     782             :                 << ", but they do not match the MS ObsIds;"
     783           0 :                 << " turning off 'perobs'.";
     784           0 :                 log << msg.str() << LogIO::WARN;
     785             :             }
     786             :         }
     787           0 :     }
     788             :     
     789             :     // Initialize caltable slices
     790           0 :     sliceTable();
     791             :     
     792             :     // Set spwmap
     793           0 :     setSpwMap(spwmap);
     794             :     
     795             :     // Set fldmap
     796           0 :     if (byField_)
     797           0 :         setFldMap(ms.field());  // on a trial basis
     798             :     else
     799           0 :         setDefFldMap();
     800             :     
     801             :     // Set defaultmaps
     802           0 :     setDefAntMap();
     803           0 :     setElemMap();
     804             :     
     805             :     // Resize working arrays
     806           0 :     result_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     807           0 :     resFlag_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     808           0 :     timeResult_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     809           0 :     timeResFlag_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     810           0 :     freqResult_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     811           0 :     freqResFlag_.resize(nMSSpw_,nMSFld_,nMSTimeSeg_);
     812             :     
     813             :     // Figure out where we can duplicate field interpolators
     814           0 :     calcAltFld();
     815             : 
     816             :     // Setup mapped interpolators
     817             :     // TBD: defer this to later, so that spwmap, etc. can be revised
     818             :     //   before committing to the interpolation engines
     819           0 :     makeInterpolators();
     820             : 
     821             :     //state();
     822             :     
     823           0 : }
     824             : 
     825             : 
     826             : // Destructor
     827           0 : CTPatchedInterp::~CTPatchedInterp() {
     828             : 
     829             :   if (CTPATCHEDINTERPVERB) cout << "CTPatchedInterp::~CTPatchedInterp()" << endl;
     830             : 
     831             :   {  
     832           0 :     IPosition sh(tI_.shape());
     833           0 :     for (Int l=0;l<sh(3);++l)
     834           0 :       for (Int k=0;k<sh(2);++k)
     835           0 :         for (Int j=0;j<sh(1);++j)
     836           0 :           for (Int i=0;i<sh(0);++i) {
     837           0 :             IPosition ip(4,i,j,k,l);
     838           0 :             if (tIdel_(ip))
     839           0 :               delete tI_(ip);
     840           0 :           }
     841           0 :     tI_.resize();
     842           0 :   }
     843             :   {
     844           0 :     IPosition sh(ctSlices_.shape());
     845           0 :     for (Int l=0;l<sh(3);++l)
     846           0 :       for (Int k=0;k<sh(2);++k)
     847           0 :         for (Int j=0;j<sh(1);++j)
     848           0 :           for (Int i=0;i<sh(0);++i) {
     849           0 :             IPosition ip(4,i,j,k,l);
     850           0 :             if (ctSlices_(ip)) 
     851           0 :               delete ctSlices_(ip);
     852           0 :           }
     853           0 :     ctSlices_.resize();
     854           0 :   }
     855           0 : }
     856             : 
     857           0 : Bool CTPatchedInterp::interpolate(Int msobs, Int msscan, Int msfld, Int msspw, Double time, Double freq) {
     858             : 
     859             :   if (CTPATCHEDINTERPVERB) cout << "CTPatchedInterp::interpolate(...)" << endl;
     860             : 
     861           0 :   Bool newcal(false);
     862           0 :   Int scanOrObsInt=thisTimeSeg(msobs,msscan);
     863           0 :   IPosition ip(4,0,msspw,msfld,scanOrObsInt);
     864             : 
     865             :   // Loop over _output_ elements
     866           0 :   for (Int iMSElem=0;iMSElem<nMSElem_;++iMSElem) {
     867             :     // Call fully _patched_ time-interpolator, keeping track of 'newness'
     868             :     //  fills timeResult_/timeResFlag_ implicitly
     869           0 :     ip(0)=iMSElem;
     870             :     
     871           0 :     if (!tI_(ip)) {
     872             :       //if (iMSElem==0) cout << "Flagging: " << ip << endl;
     873             : 
     874             :       // casa log post
     875           0 :       if (!tIMissingLogged_(ip)) {  // only if these coords not logged before
     876           0 :         LogIO log;
     877           0 :         ostringstream msg;
     878           0 :         String scanOrObsStr=(byScan_ ? "scan" : "obs");
     879           0 :         msg  << "MS " << scanOrObsStr << "=" << scanOrObsInt;
     880           0 :         if (byField_) msg << " in fld=" << msfld;
     881           0 :         msg << ",spw=" << msspw
     882           0 :             << ",ant=" << iMSElem
     883           0 :             << " is selected for processing, but has no available calibration in " << ctname_
     884           0 :             << " as mapped, and will be flagged.";
     885           0 :         log << msg.str() << LogIO::WARN;
     886           0 :         tIMissingLogged_(ip)=true;
     887           0 :       }
     888           0 :       newcal=true;
     889             :     }
     890             :     else {
     891           0 :       if (freq>0.0)
     892           0 :         newcal|=tI_(ip)->interpolate(time,freq);
     893             :       else
     894           0 :         newcal|=tI_(ip)->interpolate(time);
     895             :     }
     896             :   }
     897             : 
     898             :   // Whole result referred to time result:
     899           0 :   result_(msspw,msfld,scanOrObsInt).reference(timeResult_(msspw,msfld,scanOrObsInt));
     900           0 :   resFlag_(msspw,msfld,scanOrObsInt).reference(timeResFlag_(msspw,msfld,scanOrObsInt));
     901             : 
     902             :   // Detect if obs or fld changed, and cal is obs- or fld-dep
     903           0 :   Bool diffobsfld(false);
     904           0 :   diffobsfld|=(byField_ && msfld!=lastFld_(msspw));   // field-dep, and field changed
     905           0 :   diffobsfld|=(byObs_ && msobs!=lastObs_(msspw));     // obs-dep, and obs changed
     906           0 :   diffobsfld|=(byScan_ && msscan!=lastScan_(msspw));  // scan-dep, and scan changed
     907           0 :   newcal|=diffobsfld;  // update newcal for return
     908             : 
     909             :   // Remember for next pass
     910           0 :   lastFld_(msspw)=msfld;
     911           0 :   lastObs_(msspw)=msobs;
     912           0 :   lastScan_(msspw)=msscan;
     913             : 
     914           0 :   return newcal;
     915           0 : }
     916             : 
     917           0 : Bool CTPatchedInterp::interpolate(Int msobs, Int msscan, Int msfld, Int msspw, Double time, const Vector<Double>& freq) {
     918             : 
     919             :   if (CTPATCHEDINTERPVERB) cout << "CTPatchedInterp::interpolate(...,freq)" << endl;
     920             : 
     921             :   // obsid non-degenerate only if byObs_
     922             : 
     923             :   // The number of requested channels
     924           0 :   uInt nMSChan=freq.nelements();
     925             : 
     926             :   // Ensure freq result Array is properly sized
     927           0 :   if (freqResult_(msspw,msfld,thisTimeSeg(msobs,msscan)).nelements()==0) {
     928           0 :      Int thisAltFld=altFld_(msfld);
     929           0 :      if (freqResult_(msspw,thisAltFld,thisTimeSeg(msobs,msscan)).nelements()==0) {
     930           0 :        freqResult_(msspw,thisAltFld,thisTimeSeg(msobs,msscan)).resize(nFPar_,nMSChan,nMSElem_);
     931           0 :        freqResFlag_(msspw,thisAltFld,thisTimeSeg(msobs,msscan)).resize(nPar_,nMSChan,nMSElem_);
     932           0 :        freqResFlag_(msspw,thisAltFld,thisTimeSeg(msobs,msscan)).set(true);
     933             :      }
     934           0 :      if (thisAltFld!=msfld) {
     935           0 :        freqResult_(msspw,msfld,thisTimeSeg(msobs,msscan)).reference(freqResult_(msspw,thisAltFld,thisTimeSeg(msobs,msscan)));
     936           0 :        freqResFlag_(msspw,msfld,thisTimeSeg(msobs,msscan)).reference(freqResFlag_(msspw,thisAltFld,thisTimeSeg(msobs,msscan)));
     937             :      }
     938             :   }
     939             : 
     940             : 
     941             :   
     942             :   
     943             :   {
     944             : 
     945             :     // CAS-11744
     946             :     // In the following, we verify that there are sufficient soln channels to 
     947             :     // do the requested freq-dep interpolation.  If there are not, we
     948             :     // change the freq-dep interp mode to one that will work (linear or
     949             :     // nearest, for nchan=2 or 1, respectively), and issue a logger warning.
     950             :     // This is necessary specifically for the current _flag_ interpolation code.
     951             :     // The warning is thought warranted since freq-dep calibration (B, Tsys)
     952             :     // usually has adequate nchan, and if it does not, this may be unexpected
     953             :     // (e.g., use of too large a freq solint).
     954             :     
     955             :     // Check freq sampling adequate for specified freq interpolation
     956           0 :     Int nSolChan=timeResult_(msspw,msfld,thisTimeSeg(msobs,msscan)).shape()(1);
     957           0 :     LogIO log;
     958           0 :     ostringstream msg;
     959             : 
     960           0 :     switch (freqInterpMethod0_) {
     961           0 :     case LINEAR: {
     962           0 :       if (nSolChan<2 && freqInterpMethodVec_(msspw)!=NEAREST) {
     963           0 :         freqInterpMethodVec_(msspw)=NEAREST;  // change to nearest for this msspw
     964           0 :         ostringstream spwmapstr;
     965           0 :         spwmapstr << " (mapped to CT spw=" << spwMap_(msspw) << ")";
     966           0 :         msg << "In caltable "
     967           0 :             << Path(ct_.tableName()).baseName().before(".tempMemCal")
     968           0 :             << " (" << ct_.keywordSet().asString("VisCal") << ")"
     969           0 :             << ":" << endl
     970           0 :             << " Insufficient solution channel sampling (nchan=" << nSolChan << ") for frequency-dependent LINEAR interpolation " << endl
     971           0 :             << " of calibration for MS spw=" << msspw
     972           0 :             << ( msspw!=spwMap_(msspw) ? String(spwmapstr) : "" ) 
     973           0 :             << "; using NEAREST instead.";
     974           0 :         log << LogOrigin("CTPatchedInterp","interpolate") << msg.str() << LogIO::WARN;
     975           0 :       }
     976           0 :       break;
     977             :     }
     978           0 :     case CUBIC:
     979             :     case SPLINE: {
     980           0 :       if (nSolChan<2 && freqInterpMethodVec_(msspw)>NEAREST) {
     981           0 :         freqInterpMethodVec_(msspw)=NEAREST;  // change to nearest for this msspw
     982           0 :         ostringstream spwmapstr;
     983           0 :         spwmapstr << " (mapped to CT spw=" << spwMap_(msspw) << ")";
     984           0 :         msg << "In caltable "
     985           0 :             << Path(ct_.tableName()).baseName().before(".tempMemCal")
     986           0 :             << " (" << ct_.keywordSet().asString("VisCal") << ")"
     987           0 :             << ":" << endl
     988           0 :             << " Insufficient solution channel sampling (nchan=" << nSolChan << ") for frequency-dependent CUBIC/SPLINE interpolation " << endl
     989           0 :             << " of calibration for MS spw=" << msspw
     990           0 :             << ( msspw!=spwMap_(msspw) ? String(spwmapstr) : "" ) 
     991           0 :             << "; using NEAREST instead.";
     992           0 :         log << LogOrigin("CTPatchedInterp","interpolate") << msg.str() << LogIO::WARN;
     993           0 :       }
     994           0 :       else if (nSolChan<4 && freqInterpMethodVec_(msspw)>LINEAR) {
     995           0 :         freqInterpMethodVec_(msspw)=LINEAR;  // change to nearest for this msspw
     996           0 :         ostringstream spwmapstr;
     997           0 :         spwmapstr << " (mapped to CT spw=" << spwMap_(msspw) << ")";
     998           0 :         msg << "In caltable "
     999           0 :             << Path(ct_.tableName()).baseName().before(".tempMemCal")
    1000           0 :             << " (" << ct_.keywordSet().asString("VisCal") << ")"
    1001           0 :             << ":" << endl
    1002           0 :             << " Insufficient solution channel sampling (nchan=" << nSolChan << ") for frequency-dependent CUBIC/SPLINE interpolation " << endl
    1003           0 :             << " of calibration for MS spw=" << msspw
    1004           0 :             << ( msspw!=spwMap_(msspw) ? String(spwmapstr) : "" ) 
    1005           0 :             << "; using LINEAR instead.";
    1006           0 :         log << LogOrigin("CTPatchedInterp","interpolate") << msg.str() << LogIO::WARN;
    1007           0 :       }
    1008           0 :       break;
    1009             :     }
    1010           0 :     default: {
    1011           0 :       break;
    1012             :     }
    1013             :     }
    1014           0 :   }
    1015             : 
    1016             :   // Use the msspw-specific one!
    1017           0 :   freqInterpMethod_=freqInterpMethodVec_(msspw);
    1018             : 
    1019           0 :   Bool newcal(false);
    1020           0 :   Int scanOrObsInt=thisTimeSeg(msobs,msscan);
    1021           0 :   IPosition ip(4,0,msspw,msfld,scanOrObsInt);
    1022             : 
    1023             :   // Loop over _output_ antennas
    1024           0 :   for (Int iMSElem=0;iMSElem<nMSElem_;++iMSElem) {
    1025             :     // Call time interpolation calculation; resample in freq if new
    1026             :     //   (fills timeResult_/timeResFlag_ implicitly)
    1027           0 :     ip(0)=iMSElem;
    1028           0 :     if (!tI_(ip)) {
    1029             :       //if (iMSElem==0) cout << "Flagging: " << ip << endl;
    1030             : 
    1031             :       // casa log post
    1032           0 :       if (!tIMissingLogged_(ip)) {  // only if these coords not logged before
    1033           0 :         LogIO log;
    1034           0 :         ostringstream msg;
    1035           0 :         String scanOrObsStr=(byScan_ ? "scan" : "obs");
    1036           0 :         msg  << "MS " << scanOrObsStr << "=" << scanOrObsInt;
    1037           0 :         if (byField_) msg << " in fld=" << msfld;
    1038           0 :         msg << ",spw=" << msspw
    1039           0 :             << ",ant=" << iMSElem
    1040           0 :             << " is selected for processing, but has no available calibration in " << ctname_
    1041           0 :             << " as mapped, and will be flagged.";
    1042           0 :         log << msg.str() << LogIO::WARN;
    1043           0 :         tIMissingLogged_(ip)=true;
    1044           0 :       }
    1045             :       
    1046             :       
    1047           0 :       newcal=true;
    1048             :     }
    1049             :     else {
    1050             :       
    1051           0 :       if (tI_(ip)->interpolate(time)) { 
    1052             :         // Resample in frequency
    1053           0 :         Matrix<Float> fR(freqResult_(msspw,msfld,scanOrObsInt).xyPlane(iMSElem));
    1054           0 :         Matrix<Bool> fRflg(freqResFlag_(msspw,msfld,scanOrObsInt).xyPlane(iMSElem));
    1055           0 :         Matrix<Float> tR(timeResult_(msspw,msfld,scanOrObsInt).xyPlane(iMSElem));
    1056           0 :         Matrix<Bool> tRflg(timeResFlag_(msspw,msfld,scanOrObsInt).xyPlane(iMSElem));
    1057           0 :         resampleInFreq(fR,fRflg,freq,tR,tRflg,freqIn_(spwMap_(msspw)));
    1058             :         
    1059             :         // Calibration is new
    1060           0 :         newcal=true;
    1061           0 :       }
    1062             :     }
    1063             :   }
    1064             : 
    1065             :   // Whole result referred to freq result:
    1066           0 :   result_(msspw,msfld,scanOrObsInt).reference(freqResult_(msspw,msfld,scanOrObsInt));
    1067           0 :   resFlag_(msspw,msfld,scanOrObsInt).reference(freqResFlag_(msspw,msfld,scanOrObsInt));
    1068             : 
    1069             :   // Detect if obs or fld changed, and cal is obs- or fld-dep
    1070           0 :   Bool diffobsfld(false);
    1071           0 :   diffobsfld|=(byField_ && msfld!=lastFld_(msspw));   // field-dep, and field changed
    1072           0 :   diffobsfld|=(byObs_ && msobs!=lastObs_(msspw));     // obs-dep, and obs changed
    1073           0 :   diffobsfld|=(byScan_ && msscan!=lastScan_(msspw));  // scan-dep, and scan changed
    1074           0 :   newcal|=diffobsfld;  //  update newcal for return
    1075             : 
    1076             :   /*
    1077             :   if (newcal) {
    1078             :     Double t0(86400.0*floor(time/86400.0));
    1079             :     cout << boolalpha
    1080             :          << "fld="<<msfld
    1081             :          << " obs="<<scanOrObsInt
    1082             :          << " spw="<<msspw
    1083             :          << " time="<< time-t0
    1084             :          << " diffobsfld=" << diffobsfld
    1085             :          << " new=" << newcal
    1086             :          << " tI_(ip)=" << tI_(ip)
    1087             :          << " chan="<< nMSChan/2
    1088             :          << " result=" << result_(msspw,msfld,scanOrObsInt)(0,nMSChan/2,0)
    1089             :          << " addr=" << &result_(msspw,msfld,scanOrObsInt)(0,nMSChan/2,0)
    1090             :          << endl;
    1091             :   }
    1092             :   */
    1093             :   // Remember for next pass
    1094           0 :   lastFld_(msspw)=msfld;
    1095           0 :   lastObs_(msspw)=msobs;
    1096           0 :   lastScan_(msspw)=msscan;
    1097             : 
    1098           0 :   return newcal;
    1099             : }
    1100             : 
    1101             : // spwOK info for users
    1102           0 : Bool CTPatchedInterp::spwOK(Int spw) const {
    1103             : 
    1104           0 :   if (spw<Int(spwMap_.nelements()))
    1105           0 :     return this->spwInOK(spwMap_(spw));
    1106             : 
    1107             :   // Something wrong...
    1108           0 :   return false;
    1109             : 
    1110             : }
    1111           0 : Bool CTPatchedInterp::spwInOK(Int spw) const {
    1112             : 
    1113           0 :   if (spw<Int(spwInOK_.nelements()))
    1114           0 :     return spwInOK_(spw);
    1115             : 
    1116             :   // Something wrong
    1117           0 :   return false;
    1118             : 
    1119             : }
    1120             : 
    1121             : 
    1122             :   // Report state
    1123           0 : void CTPatchedInterp::state() {
    1124             : 
    1125             :   if (CTPATCHEDINTERPVERB) cout << "CTPatchedInterp::state()" << endl;
    1126             : 
    1127           0 :   cout << "-state--------" << endl;
    1128           0 :   cout << " ct_      = " << Path(ct_.tableName()).baseName().before(".tempMemCal") << endl;
    1129           0 :   cout << boolalpha;
    1130           0 :   cout << " isCmplx_ = " << isCmplx_ << endl;
    1131           0 :   cout << " nPar_    = " << nPar_ << endl;
    1132           0 :   cout << " nFPar_   = " << nFPar_ << endl;
    1133           0 :   cout << " nMSTimeSeg_  = " << nMSTimeSeg_ << endl;
    1134           0 :   cout << " nMSFld_  = " << nMSFld_ << endl;
    1135           0 :   cout << " nMSSpw_  = " << nMSSpw_ << endl;
    1136           0 :   cout << " nMSAnt_  = " << nMSAnt_ << endl;
    1137           0 :   cout << " nMSElem_ = " << nMSElem_ << endl;
    1138           0 :   cout << " nCTTimeSeg_  = " << nCTTimeSeg_ << endl;
    1139           0 :   cout << " nCTFld_  = " << nCTFld_ << endl;
    1140           0 :   cout << " nCTSpw_  = " << nCTSpw_ << endl;
    1141           0 :   cout << " nCTAnt_  = " << nCTAnt_ << endl;
    1142           0 :   cout << " nCTElem_ = " << nCTElem_ << endl;
    1143           0 :   cout << " fldMap_  = " << fldMap_ << endl;
    1144           0 :   cout << " spwMap_  = " << spwMap_ << endl;
    1145           0 :   cout << " antMap_  = " << antMap_ << endl;
    1146           0 :   cout << " byObs_   = " << byObs_ << endl;
    1147           0 :   cout << " byScan_  = " << byScan_ << endl;
    1148           0 :   cout << " byField_ = " << byField_ << endl;
    1149           0 :   cout << " altFld_  = " << altFld_ << endl;
    1150           0 :   cout << " timeType_ = " << timeType_ << endl;
    1151           0 :   cout << " freqTypeStr_ = " << freqTypeStr_ << endl;
    1152           0 :   cout << " freqInterpMethod0_ = " << freqInterpMethod0_ << endl;
    1153           0 :   cout << " freqInterpMethodVec_ = " << freqInterpMethodVec_ << endl;
    1154           0 :   cout << " spwInOK_ = " << spwInOK_ << endl;
    1155           0 : }
    1156             : 
    1157           0 : void CTPatchedInterp::sliceTable() {
    1158             : 
    1159             :   if (CTPATCHEDINTERPVERB) cout << "  CTPatchedInterp::sliceTable()" << endl;
    1160             : 
    1161             :   // This method generates per-spw, per-antenna (and eventually per-field?)
    1162             :   //   caltables.  
    1163             : 
    1164             :   // Ensure time sort of input table
    1165             :   //  TBD (here or inside loop?)
    1166             : 
    1167             :   // Indexed by the fields, spws, ants in the cal table (pre-mapped)
    1168           0 :   ctSlices_.resize(IPosition(4,nCTElem_,nCTSpw_,nCTFld_,nCTTimeSeg_));
    1169           0 :   ctSlices_.set(NULL);
    1170             : 
    1171             :   // Initialize spwInOK_
    1172           0 :   spwInOK_.resize(nCTSpw_);
    1173           0 :   spwInOK_.set(false);
    1174             : 
    1175             :   // Set up iterator
    1176             :   //  TBD: handle baseline-based case!
    1177           0 :   Block<String> sortcol;
    1178           0 :   Int addobs( (byObs_ ? 1 : 0) ); // slicing by obs?
    1179           0 :   Int addscan( (byScan_ ? 1 : 0) ); // slicing by scan?
    1180           0 :   Int addfld( (byField_ ? 1 : 0) ); // slicing by field?
    1181             : 
    1182           0 :   switch(mtype_) {
    1183           0 :   case VisCalEnum::GLOBAL: {
    1184             : 
    1185           0 :     throw(AipsError("CTPatchedInterp::sliceTable: No non-Mueller/Jones yet."));
    1186             : 
    1187             :     sortcol.resize(1+addobs+addscan+addfld);
    1188             :     if (byObs_) sortcol[0]="OBSERVATION_ID";  // slicing by obs
    1189             :     if (byScan_) sortcol[0+addobs]="SCAN_NUMBER";  // slicing by scan
    1190             :     if (byField_) sortcol[0+addobs+addscan]="FIELD_ID";  // slicing by field
    1191             :     sortcol[0+addobs+addscan+addfld]="SPECTRAL_WINDOW_ID";
    1192             :     ROCTIter ctiter(ct_,sortcol);
    1193             :     while (!ctiter.pastEnd()) {
    1194             :       Int ispw=ctiter.thisSpw();
    1195             :       Int ifld = (byField_ ? ctiter.thisField() : 0); // use 0 if not slicing by field
    1196             :       Int iobs = (byObs_ ? ctiter.thisObs() : 0); // use 0 if not slicing by obs
    1197             :       iobs = (byScan_ ? ctiter.thisScan() : iobs); // XXX perscan overrides perobs?
    1198             :       IPosition ip(4,0,ispw,ifld,iobs);
    1199             :       ctSlices_(ip)= new NewCalTable(ctiter.table());
    1200             :       spwInOK_(ispw)=(spwInOK_(ispw) || ctSlices_(ip)->nrow()>0);
    1201             :       ctiter.next();
    1202             :     }
    1203             :     break;
    1204             :   }
    1205           0 :   case VisCalEnum::MUELLER: {
    1206           0 :     sortcol.resize(3+addobs+addscan+addfld);
    1207           0 :     if (byObs_) sortcol[0]="OBSERVATION_ID";  // slicing by obs
    1208           0 :     if (byScan_) sortcol[0+addobs]="SCAN_NUMBER";  // slicing by scan
    1209           0 :     if (byField_) sortcol[0+addobs+addscan]="FIELD_ID";  // slicing by field
    1210           0 :     sortcol[0+addobs+addscan+addfld]="SPECTRAL_WINDOW_ID";
    1211           0 :     sortcol[1+addobs+addscan+addfld]="ANTENNA1";
    1212           0 :     sortcol[2+addobs+addscan+addfld]="ANTENNA2";
    1213           0 :     ROCTIter ctiter(ct_,sortcol);
    1214           0 :     while (!ctiter.pastEnd()) {
    1215           0 :       Int ispw=ctiter.thisSpw();
    1216           0 :       Int iant1=ctiter.thisAntenna1();
    1217           0 :       Int iant2=ctiter.thisAntenna2();
    1218           0 :       Int ibln=blnidx(iant1,iant2,nCTAnt_);
    1219           0 :       Int ifld = (byField_ ? ctiter.thisField() : 0); // use 0 if not slicing by field
    1220           0 :       Int iobs = (byObs_ ? ctiter.thisObs() : 0); // use 0 if not slicing by obs
    1221           0 :       iobs = (byScan_ ? ctiter.thisScan() : iobs); // XXX perscan overrides perobs?
    1222           0 :       IPosition ip(4,ibln,ispw,ifld,iobs);
    1223           0 :       ctSlices_(ip)=new NewCalTable(ctiter.table());
    1224           0 :       spwInOK_(ispw)=(spwInOK_(ispw) || ctSlices_(ip)->nrow()>0);
    1225           0 :       ctiter.next();
    1226           0 :     }    
    1227           0 :     break;
    1228           0 :   }
    1229           0 :   case VisCalEnum::JONES: {
    1230           0 :     sortcol.resize(2+addobs+addscan+addfld);
    1231           0 :     if (byObs_) sortcol[0]="OBSERVATION_ID";  // slicing by obs
    1232           0 :     if (byScan_) sortcol[0+addobs]="SCAN_NUMBER";  // slicing by scan
    1233           0 :     if (byField_) sortcol[0+addobs+addscan]="FIELD_ID";  // slicing by field
    1234           0 :     sortcol[0+addobs+addscan+addfld]="SPECTRAL_WINDOW_ID";
    1235           0 :     sortcol[1+addobs+addscan+addfld]="ANTENNA1";
    1236           0 :     ROCTIter ctiter(ct_,sortcol);
    1237           0 :     while (!ctiter.pastEnd()) {
    1238           0 :       Int ispw=ctiter.thisSpw();
    1239           0 :       Int iant=ctiter.thisAntenna1();
    1240           0 :       Int ifld = (byField_ ? ctiter.thisField() : 0); // use 0 if not slicing by field
    1241           0 :       Int iobs = (byObs_ ? ctiter.thisObs() : 0); // use 0 if not slicing by obs
    1242           0 :       iobs = (byScan_ ? ctiter.thisScan() : iobs); // XXX perscan overrides perobs?
    1243           0 :       IPosition ip(4,iant,ispw,ifld,iobs);
    1244           0 :       ctSlices_(ip)= new NewCalTable(ctiter.table());
    1245           0 :       spwInOK_(ispw)=(spwInOK_(ispw) || ctSlices_(ip)->nrow()>0);
    1246           0 :       ctiter.next();
    1247           0 :     }    
    1248           0 :     break;
    1249           0 :   }
    1250             :   }
    1251             :   
    1252           0 : }
    1253             : 
    1254             : // Initialize by iterating over the supplied table
    1255           0 : void CTPatchedInterp::makeInterpolators() {
    1256             : 
    1257             :   if (CTPATCHEDINTERPVERB) cout << "  CTPatchedInterp::initialize()" << endl;
    1258             : 
    1259             :   // Save caltable name for log messages
    1260           0 :   ctname_=Path(ct_.antenna().tableName().before(".tempMem")).baseName();
    1261             :   
    1262             :   // Size/initialize interpolation engines
    1263           0 :   IPosition tIsize(4,nMSElem_,nMSSpw_,nMSFld_,nMSTimeSeg_);
    1264           0 :   tI_.resize(tIsize);
    1265           0 :   tI_.set(NULL);
    1266           0 :   tIdel_.resize(tIsize);
    1267           0 :   tIdel_.set(false);
    1268           0 :   tIMissingLogged_.resize(tIsize);
    1269           0 :   tIMissingLogged_.set(false);
    1270             : 
    1271           0 :   Bool reportBadSpw(false);
    1272           0 :   for (Int iMSTimeSeg=0;iMSTimeSeg<nMSTimeSeg_;++iMSTimeSeg) {
    1273           0 :   for (Int iMSFld=0;iMSFld<nMSFld_;++iMSFld) {
    1274             : 
    1275           0 :     if (altFld_(iMSFld)==iMSFld) {  // i.e., this field has its own solutions
    1276             : 
    1277             :       //      cout << "Making  interpolators for        " << iMSFld << " (mapped from " << fldMap_(iMSFld) << ")" << endl;
    1278             : 
    1279           0 :       std::set<uInt> spws;
    1280           0 :       if (msmc_)
    1281           0 :         spws = msmc_->msmd().getSpwsForField(iMSFld);
    1282             : 
    1283           0 :       for (Int iMSSpw=0;iMSSpw<nMSSpw_;++iMSSpw) { 
    1284             :         
    1285             :         // Only if the required CT spw is available
    1286             :         //  (spwmap applied in spwOK method)
    1287           0 :         if (this->spwOK(iMSSpw)) {
    1288             :           
    1289             :           // Size up the timeResult_ Cube (NB: channel shape matches Cal Table)
    1290           0 :           if (timeResult_(iMSSpw,iMSFld,iMSTimeSeg).nelements()==0) {
    1291           0 :             timeResult_(iMSSpw,iMSFld,iMSTimeSeg).resize(nFPar_,nChanIn_(spwMap_(iMSSpw)),nMSElem_);
    1292           0 :             timeResFlag_(iMSSpw,iMSFld,iMSTimeSeg).resize(nPar_,nChanIn_(spwMap_(iMSSpw)),nMSElem_);
    1293           0 :             timeResFlag_(iMSSpw,iMSFld,iMSTimeSeg).set(true);
    1294             :           }
    1295           0 :           for (Int iMSElem=0;iMSElem<nMSElem_;++iMSElem) {
    1296             :             // Realize the mapping 
    1297           0 :             IPosition ictip(4,elemMap_(iMSElem),spwMap_(iMSSpw),fldMap_(iMSFld),iMSTimeSeg);
    1298           0 :             IPosition tIip(4,iMSElem,iMSSpw,iMSFld,iMSTimeSeg);
    1299           0 :             Matrix<Float> tR(timeResult_(iMSSpw,iMSFld,iMSTimeSeg).xyPlane(iMSElem));
    1300           0 :             Matrix<Bool> tRf(timeResFlag_(iMSSpw,iMSFld,iMSTimeSeg).xyPlane(iMSElem));
    1301             : 
    1302             :             // If the ct slice exists, set up an interpolator
    1303           0 :             if (ictip(0) >= 0 && ictip(0) < nCTElem_ &&
    1304           0 :                 ictip(1) >= 0 && ictip(1) < nCTSpw_ &&
    1305           0 :                 ictip(2) >= 0 && ictip(2) < nCTFld_ &&
    1306           0 :                 ictip(3) >= 0 && ictip(3) < nCTTimeSeg_ &&
    1307           0 :                 ctSlices_(ictip)) {
    1308           0 :               NewCalTable& ict(*ctSlices_(ictip));
    1309           0 :               if (!ict.isNull()) {
    1310           0 :                 tI_(tIip)=(*cttifactoryptr_)(ict,timeType_,tR,tRf);
    1311           0 :                 tIdel_(tIip)=true;
    1312             :               }
    1313             :             }
    1314             :             else {
    1315             :               // the required ct slice is empty, so arrange to flag it
    1316           0 :               tI_(tIip)=NULL; 
    1317           0 :               tR.set(0.0);
    1318           0 :               tRf.set(true);
    1319             :             }
    1320           0 :           } // iMSElem
    1321             :         } // spwOK
    1322             :         else
    1323           0 :           reportBadSpw=true;
    1324             :       } // iMSSpw
    1325             : 
    1326           0 :     } // not re-using
    1327             :     else {  // re-using
    1328             :       // Point to an existing interpolator group
    1329           0 :       Int thisAltFld=altFld_(iMSFld);
    1330             : 
    1331             :       //      cout << "Reusing interpolators from " << thisAltFld << " for " << iMSFld << " (mapped to   " << fldMap_(iMSFld) << ")" << endl;
    1332             : 
    1333           0 :       for (Int iMSSpw=0;iMSSpw<nMSSpw_;++iMSSpw) { 
    1334           0 :         timeResult_(iMSSpw,iMSFld,iMSTimeSeg).reference(timeResult_(iMSSpw,thisAltFld,iMSTimeSeg));
    1335           0 :         timeResFlag_(iMSSpw,iMSFld,iMSTimeSeg).reference(timeResFlag_(iMSSpw,thisAltFld,iMSTimeSeg));
    1336           0 :         for (Int iMSElem=0;iMSElem<nMSElem_;++iMSElem) {
    1337           0 :           IPosition tIip0(4,iMSElem,iMSSpw,iMSFld,iMSTimeSeg),tIip1(4,iMSElem,iMSSpw,thisAltFld,iMSTimeSeg);
    1338           0 :           tI_(tIip0)=tI_(tIip1);
    1339             :           //      if (!tI_(tIip0) && iMSElem==0)  cout << "ouch---------------------" << "iMSTimeSeg="<<iMSTimeSeg<<" iMSFld="<<iMSFld<<" spw="<< iMSSpw << " ant="<<iMSElem<< endl;
    1340           0 :         }
    1341             :       }
    1342             :     }
    1343             :   } // iMSFld
    1344             :   } // iMSTimeSeg
    1345             : 
    1346             : 
    1347           0 :   if (reportBadSpw) {
    1348           0 :     cout << "The following MS spws have no corresponding cal spws in " << ctname_ << ": ";
    1349           0 :     for (Int iMSSpw=0;iMSSpw<nMSSpw_;++iMSSpw)
    1350             :       //  (spwmap applied in spwOK method)
    1351           0 :       if (!this->spwOK(iMSSpw)) cout << iMSSpw << " ";
    1352           0 :     cout << endl;
    1353             :   }
    1354             : 
    1355           0 : }
    1356             : 
    1357             : 
    1358             : 
    1359           0 : void CTPatchedInterp::setFldMap(const MSField& msfld) {
    1360             :   
    1361           0 :   MSFieldColumns fcol(msfld);
    1362           0 :   setFldMap(fcol);
    1363             : 
    1364           0 : }
    1365             : 
    1366           0 : void CTPatchedInterp::setFldMap(const MSFieldColumns& fcol) {
    1367             : 
    1368             :    // Set the default fldmap
    1369           0 :    setDefFldMap();
    1370             :    //   cout << "Nominal fldMap_ = " << fldMap_ << endl;
    1371             : 
    1372           0 :    ROCTColumns ctcol(ct_);
    1373             : 
    1374             :    // Discern _available_ fields in the CT
    1375           0 :    Vector<Int> ctFlds;
    1376           0 :    ctcol.fieldId().getColumn(ctFlds);
    1377           0 :    Int nAvFlds=genSort(ctFlds,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
    1378           0 :    ctFlds.resize(nAvFlds,true);
    1379             : 
    1380             :    //cout << "nAvFlds = " << nAvFlds << endl;
    1381             :    //cout << "ctFlds  = " << ctFlds << endl;
    1382             : 
    1383             :    // If only one CT field, just use it
    1384             : 
    1385           0 :    Vector<Double> fseps(0);
    1386           0 :    if (nAvFlds==1) 
    1387           0 :      fldMap_.set(ctFlds(0));
    1388             :    else {
    1389             :      // For each MS field, find the nearest available CT field 
    1390           0 :      Int nMSFlds=fcol.nrow();
    1391           0 :      fseps.resize(nMSFlds);
    1392           0 :      fseps.set(0.0);
    1393           0 :      MDirection msdir,ctdir;
    1394           0 :      Vector<Double> sep(nAvFlds);
    1395           0 :      IPosition ipos(1,0);  // get the first direction stored (no poly yet)
    1396           0 :      for (Int iMSFld=0;iMSFld<nMSFlds;++iMSFld) {
    1397           0 :        msdir=fcol.phaseDirMeas(iMSFld);
    1398             :        //cout << iMSFld << ":" << msdir.getValue() << endl;
    1399           0 :        sep.set(DBL_MAX);
    1400           0 :        for (Int iCTFld=0;iCTFld<nAvFlds;++iCTFld) {
    1401             :          // Get cal field direction, converted to ms field frame
    1402           0 :          ctdir=ctcol.field().phaseDirMeas(ctFlds(iCTFld));
    1403           0 :          MDirection::Convert(ctdir,msdir.getRef());
    1404             :          //cout << "   c:" << ctFlds(iCTFld) << ":" << ctdir.getValue() << endl;
    1405           0 :          sep(iCTFld)=ctdir.getValue().separation(msdir.getValue());
    1406             :        }
    1407             :        // Sort separations
    1408           0 :        Vector<uInt> ord;
    1409           0 :        Int nsep=genSort(ord,sep,Sort::Ascending,(Sort::QuickSort | Sort::Ascending));
    1410             : 
    1411             :        /*
    1412             :        cout << "    ord=" << ord << endl;
    1413             :        cout << "   nsep=" << nsep << endl;
    1414             :        cout << "    sep=" << sep << " " << sep*(180.0/C::pi)<< endl;
    1415             :        */
    1416             : 
    1417             :        // Trap case of duplication of nearest separation
    1418           0 :        if (nsep>1 && sep(ord(1))==sep(ord(0)))
    1419           0 :          throw(AipsError("Found more than one field at minimum distance, can't decide!"));
    1420             :        
    1421           0 :        fseps(iMSFld)=sep(ord(0));
    1422           0 :        fldMap_(iMSFld)=ctFlds(ord(0));
    1423           0 :      }   
    1424           0 :    }
    1425           0 :    fseps*=(180.0/C::pi);
    1426           0 :    LogIO log;
    1427           0 :    ostringstream msg;
    1428           0 :    msg << "Calibration field mapping for "
    1429           0 :        << Path(ct_.tableName()).baseName().before(".tempMemCal")
    1430           0 :        << " (via gainfield='nearest'): "
    1431           0 :        << fldMap_ << endl
    1432           0 :        << " Separations (deg): " << fseps;
    1433           0 :    log << msg.str() << LogIO::POST;
    1434             : 
    1435             :    //   cout << ct_.tableName() << ": fldMap_ = " << fldMap_ << endl;
    1436           0 : }   
    1437             : 
    1438           0 : void CTPatchedInterp::setFldMap(Vector<Int>& fldmap) {
    1439             : 
    1440             :   // Set the default spwmap first, then we'll ammend it
    1441           0 :   setDefFldMap();
    1442             : 
    1443           0 :   Int nfld=fldmap.nelements();
    1444             : 
    1445             :   // Must specify no more than needed, but at least one
    1446           0 :   AlwaysAssert(nfld>0,AipsError);
    1447           0 :   AlwaysAssert(nfld<=nMSFld_,AipsError);
    1448             : 
    1449             :   // Discern _available_ fields in the CT
    1450           0 :   ROCTColumns ctcol(ct_);
    1451           0 :   Vector<Int> ctFlds;
    1452           0 :   ctcol.fieldId().getColumn(ctFlds);
    1453           0 :   Int nAvFlds=genSort(ctFlds,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
    1454           0 :   ctFlds.resize(nAvFlds,true);
    1455             :   
    1456           0 :   for (Int i=0;i<nfld;++i) {
    1457           0 :     if (!anyEQ(ctFlds,fldmap(i)))
    1458           0 :       throw(AipsError("Specified fldmap contains an unavailable field: "+String(fldmap(i))));
    1459             :     else
    1460           0 :       fldMap_(i)=fldmap(i);
    1461             :   }
    1462           0 :   if (nfld<nMSFld_)
    1463             :   // Fill in the rest with last-specified
    1464           0 :     fldMap_(Slice(nfld,nMSFld_-nfld,1))=fldMap_(nfld-1);
    1465             : 
    1466             : 
    1467           0 :    LogIO log;
    1468           0 :    ostringstream msg;
    1469           0 :    msg << "Calibration field mapping for "
    1470           0 :        << Path(ct_.tableName()).baseName().before(".tempMemCal")
    1471           0 :        << " (via user specification): "
    1472           0 :        << fldMap_;
    1473           0 :    log << msg.str() << LogIO::POST;
    1474             : 
    1475           0 : }
    1476             : 
    1477             : // Calculate fldmap redundancy
    1478           0 : void CTPatchedInterp::calcAltFld() {
    1479             : 
    1480           0 :   altFld_.resize(nMSFld_);
    1481           0 :   for (Int iMSFld=0;iMSFld<nMSFld_;++iMSFld) {
    1482           0 :      altFld_(iMSFld)=iMSFld;  // nominally
    1483           0 :      for (Int ifld=0;ifld<iMSFld;++ifld) 
    1484           0 :        if (fldMap_(ifld)==fldMap_(iMSFld))
    1485             :          //altFld_(iMSFld)=ifld;  
    1486           0 :          altFld_(iMSFld)=altFld_(ifld);
    1487             :   }
    1488             :   /*
    1489             :   cout << "------------" << endl;
    1490             :   cout << "fldMap_ = " << fldMap_ << endl;
    1491             :   cout << "altFld_ = " << altFld_ << endl;
    1492             :   */
    1493           0 : }
    1494             : 
    1495             : 
    1496             : 
    1497           0 : void CTPatchedInterp::setSpwMap(Vector<Int>& spwmap) {
    1498             : 
    1499             :   // Set the default spwmap first, then we'll ammend it
    1500           0 :   setDefSpwMap();
    1501             : 
    1502           0 :   Int nspec=spwmap.nelements();
    1503             : 
    1504             :   // Do nothing, if nothing specified (and rely on default)
    1505           0 :   if (nspec==0) return;
    1506             : 
    1507             :   // Do nothing f a single -1 is specified
    1508           0 :   if (nspec==1 && spwmap(0)==-1) return;
    1509             : 
    1510             : 
    1511             :   // Alert user if too many spws specified
    1512           0 :   if (spwmap.nelements()>uInt(nMSSpw_))
    1513           0 :     throw(AipsError("Specified spwmap has more elements ("+String::toString(spwmap.nelements())+") than the number of spectral windows in the MS ("+String::toString(nMSSpw_)+")."));
    1514             :     
    1515             :   // Handle auto-fanout
    1516           0 :   if (spwmap(0)==-999) {
    1517             :     // Use first OK spw for all MS spws
    1518           0 :     Int gspw(0);
    1519           0 :     while (!spwInOK(gspw)) ++gspw;
    1520           0 :     spwMap_.set(gspw);
    1521             :   }
    1522             :   else {
    1523             :     // First trap out-of-range values
    1524           0 :     if (anyLT(spwmap,0))
    1525           0 :       throw(AipsError("Please specify positive indices in spwmap."));
    1526           0 :     if (anyGE(spwmap,nCTSpw_)) {
    1527           0 :       ostringstream o;
    1528           0 :       o << "Please specify spw indices <= maximum available ("
    1529           0 :         << (nCTSpw_-1) << " in " << Path(ct_.tableName()).baseName().before(".tempMemCal") << ")";
    1530           0 :       throw(AipsError(o.str()));
    1531           0 :     }
    1532             : 
    1533             :     // Now fill from spwmap
    1534           0 :     if (nspec==1)
    1535             :       // Use one value for all
    1536           0 :       spwMap_.set(spwmap(0));
    1537             :     else {
    1538             :       // set as many as are specified
    1539           0 :       IPosition blc(1,0);
    1540           0 :       IPosition trc(1,min(nspec-1,nMSSpw_-1));
    1541           0 :       spwMap_(blc,trc)=spwmap(blc,trc);
    1542           0 :     }
    1543             :   }
    1544             : 
    1545             :   //cout << "CTPatchedInterp::setSpwMap: Realized spwMap_ = " << spwMap_ << endl;
    1546             : 
    1547             : }
    1548             : 
    1549             : 
    1550             : // Resample in frequency
    1551           0 : void CTPatchedInterp::resampleInFreq(Matrix<Float>& fres,Matrix<Bool>& fflg,const Vector<Double>& fout,
    1552             :                                      Matrix<Float>& tres,Matrix<Bool>& tflg,const Vector<Double>& fin) {
    1553             : 
    1554             :   if (CTPATCHEDINTERPVERB) cout << "  CTPatchedInterp::resampleInFreq(...)" << endl;
    1555             : 
    1556             :   // if no good solutions coming in, return flagged
    1557           0 :   if (nfalse(tflg)==0) {
    1558           0 :     fflg.set(true);
    1559           0 :     return;
    1560             :   }
    1561             : 
    1562             : 
    1563           0 :   Int flparmod=nFPar_/nPar_;    // for indexing the flag Matrices on the par axis
    1564             : 
    1565           0 :   Bool unWrapPhase=flparmod>1;
    1566             : 
    1567             :   //  cout << "nFPar_,nPar_,flparmod = " << nFPar_ << "," << nPar_ << "," << flparmod << endl;
    1568             : 
    1569           0 :   fres=0.0;
    1570             : 
    1571           0 :   for (Int ifpar=0;ifpar<nFPar_;++ifpar) {
    1572             : 
    1573             :     // Slice by par (each Matrix row)
    1574           0 :     Vector<Float> fresi(fres.row(ifpar)), tresi(tres.row(ifpar));
    1575           0 :     Vector<Bool> fflgi(fflg.row(ifpar/flparmod)), tflgi(tflg.row(ifpar/flparmod));
    1576             : 
    1577             :     // Mask time result by flags
    1578           0 :     Vector<Double> mfin=fin(!tflgi).getCompressedArray();
    1579             : 
    1580           0 :     if (mfin.nelements()==0) {
    1581             :       //   cout << ifpar << " All chans flagged!" << endl;
    1582             :       // Everything flagged this par
    1583             :       //  Just flag, zero and go on to the next one
    1584           0 :       fflgi.set(true);
    1585           0 :       fresi.set(0.0);
    1586           0 :       continue;
    1587             :     }
    1588             : 
    1589           0 :     mfin/=1.0e9; // in GHz
    1590           0 :     Vector<Float> mtresi=tresi(!tflgi).getCompressedArray();
    1591             : 
    1592             :     // Trap case of same in/out frequencies
    1593           0 :     if (fout.nelements()==mfin.nelements() && allNear(fout,mfin,1.e-10)) {
    1594             :       // Just copy
    1595           0 :       fresi=mtresi;
    1596           0 :       fflgi.set(false);  // none are flagged
    1597           0 :       continue;
    1598             :     }
    1599             : 
    1600           0 :     if (ifpar%2==1 && unWrapPhase) {
    1601           0 :       for (uInt i=1;i<mtresi.nelements();++i) {
    1602           0 :         while ( (mtresi(i)-mtresi(i-1))>C::pi ) mtresi(i)-=C::_2pi;
    1603           0 :         while ( (mtresi(i)-mtresi(i-1))<-C::pi ) mtresi(i)+=C::_2pi;
    1604             :       }
    1605             :     }
    1606             : 
    1607             :     // Set flags carefully
    1608           0 :     resampleFlagsInFreq(fflgi,fout,tflgi,fin);
    1609             : 
    1610             : 
    1611             :     // Always use nearest on edges
    1612             :     // TBD: trap cases where frequencies don't overlap at all
    1613             :     //     (fout(hi)<mfin(0) || fout(lo)> mfin(ihi))..... already OK (lo>hi)?
    1614             :     // TBD: optimize the following by forming Slices in the
    1615             :     //     while loops and doing Array assignment once afterwords
    1616             : 
    1617           0 :     Int nfreq=fout.nelements();
    1618           0 :     Int lo=0;
    1619           0 :     Int hi=fresi.nelements()-1;
    1620           0 :     Double inlo(mfin(0));
    1621           0 :     Int ihi=mtresi.nelements()-1;
    1622           0 :     Double inhi(mfin(ihi));
    1623             : 
    1624             :     // Handle 'nearest' extrapolation in sideband-dep way
    1625           0 :     Bool inUSB(inhi>inlo);
    1626           0 :     Bool outUSB(fout(hi)>fout(lo));
    1627           0 :     if (inUSB) {
    1628           0 :       if (outUSB) {
    1629           0 :         while (lo<nfreq && fout(lo)<=inlo) fresi(lo++)=mtresi(0);
    1630           0 :         while (hi>-1 && fout(hi)>=inhi) fresi(hi--)=mtresi(ihi);
    1631             :       }
    1632             :       else { // "outLSB"
    1633           0 :         while (lo<nfreq && fout(lo)>=inhi) fresi(lo++)=mtresi(ihi);
    1634           0 :         while (hi>-1 && fout(hi)<=inlo) fresi(hi--)=mtresi(0);
    1635             :       }
    1636             :     }
    1637             :     else {  // "inLSB"
    1638           0 :       if (outUSB) {
    1639           0 :         while (lo<nfreq && fout(lo)<=inhi) fresi(lo++)=mtresi(ihi);
    1640           0 :         while (hi>-1 && fout(hi)>=inlo) fresi(hi--)=mtresi(0);
    1641             :       }
    1642             :       else {  // "outLSB"
    1643           0 :         while (lo<nfreq && fout(lo)>=inlo) fresi(lo++)=mtresi(0);
    1644           0 :         while (hi>-1 && fout(hi)<=inhi) fresi(hi--)=mtresi(ihi);
    1645             :       }
    1646             :     }
    1647             : 
    1648             :     //    cout << "lo, hi = " << lo << ","<<hi << endl;
    1649             : 
    1650           0 :     if (lo>hi) continue; // Frequencies didn't overlap, nearest was used
    1651             : 
    1652             :     // Use InterpolateArray1D to fill in the middle
    1653           0 :     IPosition blc(1,lo), trc(1,hi);
    1654           0 :     Vector<Float> slfresi(fresi(blc,trc));
    1655           0 :     Vector<Double> slfout(fout(blc,trc));
    1656             : 
    1657           0 :     InterpolateArray1D<Double,Float>::interpolate(slfresi,slfout,mfin,mtresi,freqInterpMethod_);
    1658             : 
    1659           0 :   }
    1660             : }
    1661             : 
    1662           0 : void CTPatchedInterp::resampleFlagsInFreq(Vector<Bool>& flgout,const Vector<Double>& fout,
    1663             :                                           Vector<Bool>& flgin,const Vector<Double>& fin) {
    1664             : 
    1665             :   //  cout << "resampleFlagsInFreq" << endl;
    1666             : 
    1667           0 :   Vector<Double> finGHz=fin/1e9;
    1668             : 
    1669             :   // Handle chan-dep flags
    1670           0 :   if (freqTypeStr_.contains("flag")) {
    1671             :     
    1672             :     // Determine implied mode-dep flags indexed by channel registration
    1673           0 :     uInt nflg=flgin.nelements();
    1674           0 :     Vector<Bool> flreg(nflg,false);
    1675           0 :     switch (freqInterpMethod_) {
    1676           0 :     case NEAREST: {
    1677             :       // Just use input flags
    1678           0 :       flreg.reference(flgin);
    1679           0 :       break;
    1680             :     }
    1681           0 :     case LINEAR: {
    1682           0 :       for (uInt i=0;i<nflg-1;++i)
    1683           0 :         flreg[i]=(flgin[i] || flgin[i+1]);
    1684           0 :       flreg[nflg-1]=flreg[nflg-2];
    1685           0 :       break;
    1686             :     }
    1687           0 :     case CUBIC:
    1688             :     case SPLINE: {
    1689           0 :       for (uInt i=1;i<nflg-2;++i)
    1690           0 :         flreg[i]=(flgin[i-1] || flgin[i] || flgin[i+1] || flgin[i+2]);
    1691           0 :       flreg[0]=flreg[1];
    1692           0 :       flreg[nflg-2]=flreg[nflg-3];
    1693           0 :       flreg[nflg-1]=flreg[nflg-3];
    1694           0 :       break;
    1695             :     }
    1696             :     }
    1697             :     
    1698             :     // Now step through requested chans, setting flags
    1699           0 :     uInt ireg=0;
    1700           0 :     uInt nflgout=flgout.nelements();
    1701           0 :     for (uInt iflgout=0;iflgout<nflgout;++iflgout) {
    1702             :       
    1703             :       // Find nominal registration (the _index_ just left)
    1704           0 :       Bool exact(false);
    1705           0 :       ireg=binarySearch(exact,finGHz,fout(iflgout),nflg,0);
    1706             : 
    1707             :       // If registration is exact, assign verbatim
    1708             :       // NB: the calibration value calculation occurs agnostically w.r.t. flags,
    1709             :       //     so the calculated value should also match
    1710             :       // TBD: Add "|| near(finGHz[ireg],fout(iflgout),1e-10) in case "exact" has
    1711             :       //      precision issues?
    1712           0 :       if (exact) {
    1713           0 :         flgout[iflgout]=flgin[ireg];
    1714           0 :         continue;
    1715             :       }
    1716             : 
    1717             :       // Not exact, so carefully handle bracketing
    1718           0 :       if (ireg>0)
    1719           0 :         ireg-=1;
    1720           0 :       ireg=min(ireg,nflg-1);
    1721             : 
    1722             :       //while (finGHz(ireg)<=fout(iflgout) && ireg<nflg-1) {
    1723             :       //  ireg+=1;  // USB specific!
    1724             :       //}
    1725             :       //if (ireg>0 && finGHz(ireg)!=fout(iflgout)) --ireg;  // registration is one sample prior
    1726             : 
    1727             :       // refine registration by interp type
    1728           0 :       switch (freqInterpMethod_) {
    1729           0 :       case NEAREST: {
    1730             :         // nearest might be forward sample
    1731           0 :         if ( ireg<(nflg-1) &&
    1732           0 :              abs(fout[iflgout]-finGHz[ireg])>abs(finGHz[ireg+1]-fout[iflgout]) )
    1733           0 :           ireg+=1;
    1734           0 :         break;
    1735             :       }
    1736           0 :       case LINEAR: {
    1737           0 :         if (ireg==(nflg-1)) // need one more sample to the right
    1738           0 :           ireg-=1;
    1739           0 :         break;
    1740             :       }
    1741           0 :       case CUBIC:
    1742             :       case SPLINE: {
    1743           0 :         if (ireg==0) ireg+=1;  // need one more sample to the left
    1744           0 :         if (ireg>(nflg-3)) ireg=nflg-3;  // need two more samples to the right
    1745           0 :         break;
    1746             :       }
    1747             :       }
    1748             :         
    1749             :       // Assign effective flag
    1750           0 :       flgout[iflgout]=flreg[ireg];
    1751             : 
    1752             :       /*
    1753             :       cout << iflgout << " "
    1754             :            << ireg << " "
    1755             :            << flreg[ireg] 
    1756             :            << endl;
    1757             :       */
    1758             : 
    1759             :     }
    1760             : 
    1761           0 :   }
    1762             :   else 
    1763             :     // We are interp/extrap-olating gaps absolutely
    1764           0 :     flgout.set(false);
    1765             : 
    1766           0 : }
    1767             : 
    1768           0 : void CTPatchedInterp::setElemMap() {
    1769             :  
    1770             :   // Ensure the antMap_ is set
    1771           0 :   if (antMap_.nelements()!=uInt(nMSAnt_))
    1772           0 :     setDefAntMap();
    1773             : 
    1774             :   // Handle cases
    1775           0 :   switch(mtype_) {
    1776           0 :   case VisCalEnum::GLOBAL: {
    1777             : 
    1778           0 :     throw(AipsError("CTPatchedInterp::sliceTable: No non-Mueller/Jones yet."));
    1779             : 
    1780             :     // There is only 1
    1781             :     AlwaysAssert(nMSElem_==1,AipsError);
    1782             :     elemMap_.resize(nMSElem_);
    1783             :     elemMap_.set(0);
    1784             : 
    1785             :     break;
    1786             :   }
    1787           0 :   case VisCalEnum::MUELLER: {
    1788           0 :     elemMap_.resize(nMSElem_);
    1789           0 :     conjTab_.resize(nMSElem_);
    1790           0 :     conjTab_.set(false);
    1791           0 :     Int iMSElem(0),a1in(0),a2in(0);
    1792           0 :     for (Int iMSAnt=0;iMSAnt<nMSAnt_;++iMSAnt) {
    1793           0 :       a1in=antMap_(iMSAnt);
    1794           0 :       for (Int jAntOut=iMSAnt;jAntOut<nMSAnt_;++jAntOut) {
    1795           0 :         a2in=antMap_(jAntOut);
    1796           0 :         if (a1in<=a2in)
    1797           0 :           elemMap_(iMSElem)=blnidx(a1in,a2in,nMSAnt_);
    1798             :         else {
    1799           0 :           elemMap_(iMSElem)=blnidx(a2in,a1in,nMSAnt_);
    1800           0 :           conjTab_(iMSElem)=true;  // we must conjugate Complex params!
    1801             :         }
    1802           0 :         ++iMSElem;
    1803             :       } // jAntOut
    1804             :     } // iMSAnt
    1805           0 :     break;
    1806             :   }    
    1807           0 :   case VisCalEnum::JONES: {
    1808             :     // Just reference the antMap_
    1809           0 :     elemMap_.reference(antMap_);
    1810           0 :     break;
    1811             :   }
    1812             :   } // switch
    1813           0 : }
    1814             : 
    1815             : 
    1816           0 : InterpolateArray1D<Double,Float>::InterpolationMethod CTPatchedInterp::ftype(String& strtype) {
    1817           0 :   if (strtype.contains("nearest"))
    1818           0 :     return InterpolateArray1D<Double,Float>::nearestNeighbour;
    1819           0 :   if (strtype.contains("linear"))
    1820           0 :     return InterpolateArray1D<Double,Float>::linear;
    1821           0 :   if (strtype.contains("cubic"))
    1822           0 :     return InterpolateArray1D<Double,Float>::cubic;
    1823           0 :   if (strtype.contains("spline"))
    1824           0 :     return InterpolateArray1D<Double,Float>::spline;
    1825             : 
    1826             :   //  cout << "Using linear for freq interpolation as last resort." << endl;
    1827           0 :   return InterpolateArray1D<Double,Float>::linear;
    1828             : 
    1829             : 
    1830             : }
    1831             : 
    1832             : 
    1833             : } //# NAMESPACE CASA - END

Generated by: LCOV version 1.16