LCOV - code coverage report
Current view: top level - synthesis/MeasurementComponents - SolvableVisCal.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 2995 4380 68.4 %
Date: 2024-11-06 17:42:47 Functions: 97 156 62.2 %

          Line data    Source code
       1             : //# SolvableVisCal.cc: Implementation of SolvableVisCal classes/Users/nschweig/CASA6/CASR-539/SolvableVisCal.cc
       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 addressed as follows:
      20             : //#        Internet email: casa-feedback@nrao.edu.
      21             : //#        Postal address: AIPS++ Project Office
      22             : //#                        National Radio Astronomy Observatory
      23             : //#                        520 Edgemont Road
      24             : //#                        Charlottesville, VA 22903-2475 USA
      25             : //#
      26             : //# $Id: VisCal.cc,v 1.15 2006/02/06 19:23:11 gmoellen Exp $
      27             : 
      28             : #include <synthesis/MeasurementComponents/CalCorruptor.h>
      29             : #include <synthesis/MeasurementComponents/SolvableVisCal.h>
      30             : #include <synthesis/MeasurementComponents/MSMetaInfoForCal.h>
      31             : 
      32             : #include <msvis/MSVis/VisBuffer.h>
      33             : 
      34             : #include <casacore/casa/Arrays/ArrayMath.h>
      35             : #include <casacore/casa/Arrays/MaskArrMath.h>
      36             : #include <casacore/casa/Arrays/ArrayIter.h>
      37             : #include <casacore/scimath/Mathematics/MatrixMathLA.h>
      38             : #include <casacore/scimath/Fitting/LinearFit.h>
      39             : #include <casacore/scimath/Functionals/Polynomial.h>
      40             : #include <casacore/casa/BasicSL/String.h>
      41             : #include <casacore/casa/Utilities/Assert.h>
      42             : #include <casacore/casa/Quanta/MVTime.h>
      43             : #include <casacore/casa/Exceptions/Error.h>
      44             : #include <casacore/casa/OS/Memory.h>
      45             : #include <casacore/casa/OS/File.h>
      46             : #include <casacore/casa/Utilities/GenSort.h>
      47             : #include <casacore/casa/Quanta/Quantum.h>
      48             : #include <casacore/casa/Quanta/QuantumHolder.h>
      49             : #include <casacore/tables/Tables/TableCopy.h>
      50             : #include <casacore/tables/Tables/TableUtil.h>
      51             : #include <casacore/ms/MeasurementSets/MSAntennaColumns.h>
      52             : #include <casacore/ms/MeasurementSets/MSSpWindowColumns.h>
      53             : #include <casacore/ms/MeasurementSets/MSFieldColumns.h>
      54             : #include <casacore/ms/MSOper/MSMetaData.h>
      55             : #include <synthesis/CalTables/CTMainColumns.h>
      56             : #include <synthesis/CalTables/CTColumns.h>
      57             : #include <synthesis/CalTables/CTGlobals.h>
      58             : #include <synthesis/CalTables/CTIter.h>
      59             : #include <synthesis/CalTables/CTInterface.h>
      60             : #include <synthesis/MeasurementComponents/SolveDataBuffer.h>
      61             : #include <casacore/ms/MSSel/MSSelection.h>
      62             : #include <casacore/ms/MSSel/MSSelectionTools.h>
      63             : #include <sstream>
      64             : #include <iostream>
      65             : #include <iomanip>
      66             : #include <casacore/casa/Containers/RecordField.h>
      67             : 
      68             : #include <casacore/casa/Logging/LogMessage.h>
      69             : #include <casacore/casa/Logging/LogSink.h>
      70             : #include <casacore/casa/System/Aipsrc.h>
      71             : #include <casacore/casa/System/ProgressMeter.h>
      72             : 
      73             : #include <fstream>
      74             : 
      75             : using namespace casacore;
      76             : namespace casa { //# NAMESPACE CASA - BEGIN
      77             : 
      78             : 
      79         931 : SolNorm::SolNorm(Bool donorm, String type) :
      80         931 :   donorm_(donorm),
      81         931 :   normtype_(normTypeFromString(type))
      82             : {
      83             :   //  report();
      84         931 : }
      85             : 
      86           0 : SolNorm::SolNorm(const SolNorm& other) : 
      87           0 :   donorm_(other.donorm_),
      88           0 :   normtype_(other.normtype_)
      89           0 : {}
      90             : 
      91           0 : void SolNorm::report() {
      92           0 :   cout << "Forming SolNorm object:" << endl;
      93           0 :   cout << " donorm=" << boolalpha << donorm_ << endl
      94           0 :        << " normtype=" << normtypeString() << endl;
      95           0 : }
      96             :  
      97           7 : String SolNorm::normTypeAsString(Type type) {
      98           7 :   switch (type) {
      99           7 :   case MEAN: {
     100           7 :     return String("MEAN");
     101             :   }
     102           0 :   case MEDIAN: { 
     103           0 :     return String("MEDIAN");
     104             :   }
     105           0 :   default: {
     106           0 :     return String("UNKNOWN");
     107             :   }
     108             :   }
     109             :   return String("UNKNOWN");
     110             : }
     111             :   
     112         931 : SolNorm::Type SolNorm::normTypeFromString(String type) {
     113             : 
     114         931 :   String uptype=upcase(type);
     115         931 :   if (uptype.contains("MEAN")) return SolNorm::MEAN;
     116           0 :   else if (uptype.contains("MED")) return SolNorm::MEDIAN;
     117             :   else {
     118           0 :     throw(AipsError("Invalid normalization type specifiec!"));
     119             :   }                                             
     120             :   // Shouldn't reach here  return SolNorm::UNKNOWN;
     121             : 
     122         931 : }
     123             : 
     124             : 
     125             : 
     126             : 
     127             : 
     128             : // **********************************************************
     129             : //  FreqMetaData Implementations
     130             : //
     131             : 
     132         725 : FreqMetaData::FreqMetaData() : 
     133         725 :   ok_(False),   // ok requires running calcFreqMeta later
     134         725 :   validspws_(),
     135         725 :   freq_(Vector< Vector<Double> >()),
     136         725 :   width_(Vector< Vector<Double> >()),
     137         725 :   effBW_(Vector< Vector<Double> >()),
     138         725 :   spwfanin_()
     139         725 : {}
     140             : 
     141             : 
     142         168 : void FreqMetaData::calcFreqMeta(const Vector< Vector<Double> >& msfreq,
     143             :                                 const Vector< Vector<Double> >& mswidth,
     144             :                                 const Vector<uInt>& selspw,
     145             :                                 Bool freqdep,Bool combspw,
     146             :                                 const Vector<Int>& spwfanin) {
     147             : 
     148             :   // Max number of spws
     149         168 :   uInt nspw(msfreq.nelements());
     150             : 
     151             :   // We will keep track of which spws get set
     152         168 :   Vector<Bool> validspw(nspw,false);
     153             : 
     154             :   // Size up the Vector of spw freq Vectors
     155         168 :   freq_.resize(nspw);
     156         168 :   width_.resize(nspw);
     157         168 :   effBW_.resize(nspw);
     158             : 
     159             :   // We will log some pertinent info
     160         168 :   LogIO log;
     161         168 :   log << LogOrigin("FreqMetaData","calcFreqMeta") << LogIO::NORMAL << "Derived frequency meta-info for solutions:" << LogIO::POST;
     162             : 
     163             :   // Gather MS freq info
     164         649 :   for (uInt i=0;i<selspw.nelements();++i) {
     165         481 :     uInt ispw=selspw(i);
     166         481 :     uInt nchan=msfreq(ispw).nelements();
     167             : 
     168             :     // This ensures msfreq/mswidth consistent with selspw
     169             :     //   (each selspw has at least one channel of freq info)
     170         481 :     if (nchan<1)
     171           0 :       throw(AipsError("No frequency information for a selected spw!"));
     172             : 
     173             : 
     174             :     // Set nominal per-spw solution frequencies
     175         481 :     if (!freqdep && nchan>1) {
     176             : 
     177             :       //      cout << "Not freqdep and multi-chan data..." 
     178             :       //           << "Soln freqs will be collapsed to single channel."  << endl;
     179             : 
     180             : 
     181             :       //  solutions NOT freq dep but  more than one MS channel to solve from
     182             :       //    --> Average chan freqs to single fiducial value
     183             :       //   (this is a parameterized solution, like delay or fringefit...)
     184             : 
     185             : 
     186             :       // Manage value scale, to avoid loss of precision
     187         112 :       Double freq0=msfreq(ispw)(0);  // Lop off large freq value
     188         112 :       Double width1=mswidth(ispw)(0);  // Divide widths by typical value (also ensures abs)
     189         112 :       Vector<Double> f=msfreq(ispw)-freq0;               // relative freq
     190         112 :       Vector<Double> w=mswidth(ispw)/width1;  // width-weights
     191             : 
     192             :       // output info will be single-channel
     193         112 :       freq_(ispw).resize(1);
     194         112 :       width_(ispw).resize(1);
     195             : 
     196             :       // calculate
     197         112 :       freq_(ispw).set(sum( (Array<Double>) f*w));   // weighed rel freq sum 
     198         112 :       width_(ispw).set(sum(w));     // sum of norm'd width weights
     199         112 :       freq_(ispw)/=width_(ispw);    // divide by weight sum
     200             : 
     201             :       // Restore offsets to final values
     202         112 :       freq_(ispw)+=freq0;         // add offset back in
     203         112 :       width_(ispw)*=width1;       // mult by width norm
     204             : 
     205         112 :     } else {
     206             :       // Solutions ARE freq-dep, or only one channel, 
     207             :       //     so just adopt MS frequencies (NB: possibly already decimated by VI2)
     208             :       //  TBD: could use reference here (only if ~combspw)?
     209             :       //cout << "Soln is freqdep, or only one channel..." 
     210             :       //<< "Soln freqs are just the VI2 data freqs" << endl;
     211         369 :       freq_(ispw).assign(msfreq(ispw));
     212         369 :       width_(ispw).assign(mswidth(ispw));
     213             :     }
     214             : 
     215             :     { 
     216             :       // Report spw freq-metadetails....
     217         481 :       ostringstream os;
     218         481 :       os.precision(15);
     219         481 :       os << " Selected spw=" << ispw << " (nchan=" << freq_(ispw).nelements() << ") has centroid freq = " << mean(freq_(ispw));
     220         481 :       log << LogIO::NORMAL << os  << LogIO::POST;
     221             :       //log << LogOrigin("FreqMetaData","calcFreqMeta") << LogIO::NORMAL << os  << LogIO::POST;
     222         481 :     }
     223             : 
     224             : 
     225             :     // Assume effective BW is just the width
     226         481 :     effBW_(ispw).reference(width_(ispw));
     227             : 
     228             :     // Remember we set this spw
     229         481 :     validspw(ispw)=true;
     230             : 
     231             :   }
     232             : 
     233             :   // Collapse over spws if combining them...
     234         168 :   if (combspw && spwfanin.nelements()>1) {
     235             : 
     236             :     //    cout << "Combining spws!" << endl;
     237             : 
     238             :     // Remember the fan-in vector
     239          13 :     spwfanin_.resize();
     240          13 :     spwfanin_.assign(spwfanin);
     241             : 
     242             : 
     243             :     // Keep track of which spws are aggregate spws
     244             :     //  (none are yet)
     245          13 :     Vector<Bool> isAggspw(nspw,false);
     246             : 
     247             :     // Keep track of fanned-in spws per agg spw
     248          13 :     Vector< Vector<Int> > fannedin(nspw,Vector<Int>(0));
     249             : 
     250             : 
     251          13 :     Vector<Double> freq0(nspw,0);
     252          13 :     Vector<Double> width1(nspw,0);
     253             : 
     254          63 :     for (uInt ispw=0;ispw<spwfanin.nelements();++ispw) {
     255             : 
     256             :       // Step over unmapped spws...
     257          50 :       if (spwfanin(ispw)<0)
     258           9 :         continue; 
     259             : 
     260             :       //  The following assumes fan-in is always to lowest spw id in group 
     261          41 :       if (Int(ispw)==spwfanin(ispw)) {  
     262             : 
     263             :         //cout << "Aggregate spw = " << ispw << endl;
     264             :         
     265          13 :         isAggspw(ispw)=true;
     266             : 
     267             :         // Just to be sure...
     268          13 :         validspw(ispw)=true;
     269             : 
     270             :         // Add this (agg) spw to fanned in list
     271          13 :         uInt nfanin=fannedin(ispw).nelements();
     272          13 :         fannedin(ispw).resize(nfanin+1,true);  // copies elements
     273          13 :         fannedin(ispw)(nfanin)=ispw;
     274             : 
     275             :         // This is a spw in which we'll accumulate
     276             :         
     277             :         // Offsets for precision 
     278          13 :         freq0(ispw)=freq_(ispw)(0);
     279          13 :         width1(ispw)=width_(ispw)(0);
     280             : 
     281          13 :         freq_(ispw)-=freq0(ispw);
     282          13 :         width_(ispw)/=width1(ispw);
     283             : 
     284             :         // begin to accumulate effBW
     285          13 :         effBW_(ispw).resize();    // break prior reference to width_
     286          13 :         effBW_(ispw).assign(width_(ispw));   // copy in this spw's width_
     287             : 
     288             :         // weight the freqs with widths
     289          13 :         freq_(ispw)*=width_(ispw);
     290             : 
     291             :         // weight the widths with the widths
     292             :         //  (we will end up with a width-weighted width over spws)
     293          13 :         width_(ispw)*=width_(ispw);
     294             : 
     295             :       }
     296             :       else {
     297          28 :         uInt aggspw(spwfanin(ispw));
     298             : 
     299          28 :         uInt nfanin=fannedin(aggspw).nelements();
     300          28 :         fannedin(aggspw).resize(nfanin+1,true);  // copies elements
     301          28 :         fannedin(aggspw)(nfanin)=ispw;
     302             : 
     303          28 :         if (ispw<=aggspw) 
     304           0 :           throw(AipsError("Cannot accumulate into spw with a lower spw id."));
     305             : 
     306             : 
     307             :         //      cout << "Accumulating spw=" << ispw << " into aggspw="<< aggspw << endl;
     308             : 
     309             :         // Trap incompatible spws
     310          28 :         if (freq_(ispw).nelements()!=freq_(aggspw).nelements())
     311           0 :           throw(AipsError("Cannont combine spws with differing nchan!"));
     312             : 
     313             :         //  TBD: recognize/handle sideband and width variation if nchan>1 ?
     314             :         //  (at the moment, there is no SB info in the sign of the width)
     315             : 
     316             :         // Offsets for precision (from aggspw!)
     317          28 :         Vector<Double> f(freq_(ispw)-freq0(aggspw));
     318          28 :         Vector<Double> w(width_(ispw)/width1(aggspw));
     319             : 
     320             :         // accumulate
     321          28 :         freq_(aggspw)+= ( (Array<Double>) f*w);
     322          28 :         width_(aggspw)+= ( (Array<Double>) w*w);
     323          28 :         effBW_(aggspw)+= w;
     324             :         
     325             :         // This acculated spw now refers to aggspw:
     326          28 :         freq_(ispw).reference(freq_(aggspw));
     327          28 :         width_(ispw).reference(width_(aggspw));
     328          28 :         effBW_(ispw).reference(effBW_(aggspw));
     329             : 
     330             :         // This spw no longer autonomously "valid"
     331             :         //   (aggspw is the relevant valid one)
     332          28 :         validspw(ispw)=false;
     333             :         
     334          28 :       }
     335             :     }
     336             : 
     337             :     // Finish weighted mean calculation
     338          63 :     for (uInt ispw=0;ispw<spwfanin.nelements();++ispw) {
     339             :       
     340             :       // Step over non-agg spws
     341          50 :       if (!isAggspw(ispw))
     342          37 :         continue;
     343             : 
     344             :       //      cout << "Finalizing freq averages for agg spw = " << ispw << endl;
     345             : 
     346          13 :       if (freq0(ispw)>0.0 && effBW_(ispw).nelements()>0 && allGT(effBW_(ispw),0.0)) {
     347          13 :         freq_(ispw)/=effBW_(ispw);
     348          13 :         width_(ispw)/=effBW_(ispw);
     349             : 
     350             :         // put offsets back in
     351          13 :         freq_(ispw)+=freq0(ispw);
     352          13 :         width_(ispw)*=width1(ispw);
     353          13 :         effBW_(ispw)*=width1(ispw);
     354             : 
     355             :         { 
     356             :           // Report fanin details....
     357          13 :           ostringstream os;
     358          13 :           os.precision(15);
     359          13 :           os << " Combining spws=" << fannedin(ispw) << " into (aggregate) spw=" << ispw << " (nchan=" << freq_(ispw).nelements() << ") at centroid freq = " << mean(freq_(ispw));
     360          13 :           log << LogIO::NORMAL << os << LogIO::POST;
     361             :           //log << LogOrigin("FreqMetaData","calcFreqMeta") << LogIO::NORMAL << os << LogIO::POST;
     362          13 :         }
     363             : 
     364             :       }
     365             :       else {
     366           0 :         throw(AipsError("Problem completing combspw freq average."));
     367             :       }
     368             :     } // ispw (fanin spws only)
     369             :     //    cout << "Finished combining spws." << endl;
     370             : 
     371          13 :   } // combspw? 
     372             :   else {
     373             : 
     374             :     // For safety, make spwfanin the identity vector
     375         155 :     spwfanin_.resize(nspw);
     376         155 :     indgen(spwfanin_);
     377             : 
     378             :   }
     379             : 
     380             :   // Fill validspws_ vector    
     381         168 :   Vector<Int> spwlist(nspw);
     382         168 :   indgen(spwlist);
     383         168 :   validspws_.assign(spwlist(validspw).getCompressedArray());
     384             : 
     385             :   // If we get here, we should be ok!
     386         168 :   ok_=true;
     387             : 
     388         168 : }
     389             : 
     390             : 
     391       20733 : Bool FreqMetaData::ok() const {
     392       20733 :   if (ok_)
     393       20733 :     return true;
     394             :   else
     395           0 :     throw(AipsError("FreqMetaData not initialized!"));
     396             :   return false;
     397             : 
     398             : }
     399             : 
     400           8 : const Vector<Int>& FreqMetaData::validSpws() const {
     401             : 
     402           8 :   if (ok() && validspws_.nelements()>0)
     403           8 :     return validspws_;
     404             :   else
     405           0 :     throw(AipsError("No valid spws in FreqMetaData!"));
     406             : 
     407             : }
     408             : 
     409             : 
     410       19804 : const Vector<Double>& FreqMetaData::freq(Int spw) const {
     411       19804 :   if (ok() && freq_(spw).nelements()>0) 
     412       19804 :     return freq_(spw);
     413             :   else
     414           0 :     throw(AipsError("Bad spw in FreqMetaData!"));
     415             : 
     416             : }
     417         441 : const Vector<Double>& FreqMetaData::width(Int spw) const {
     418         441 :   if (ok() && width_(spw).nelements()>0) 
     419         441 :     return width_(spw);
     420             :   else
     421           0 :     throw(AipsError("Bad spw in FreqMetaData!"));
     422             : 
     423             : }
     424         441 : const Vector<Double>& FreqMetaData::effBW(Int spw) const {
     425         441 :   if (ok() && effBW_(spw).nelements()>0) 
     426         441 :     return effBW_(spw);
     427             :   else
     428           0 :     throw(AipsError("Bad spw in FreqMetaData!"));
     429             : 
     430             : }
     431             : 
     432          39 : Int FreqMetaData::fannedInSpw(Int spw) const {
     433             : 
     434          39 :   if (ok() && Int(spwfanin_.nelements())>spw && spwfanin_(spw)>-1)
     435          39 :     return spwfanin_(spw);
     436             :   else
     437           0 :     throw(AipsError("Bad spw fan-in in FreqMetaData::faninoutspw."));
     438             : 
     439             : }
     440             : 
     441             : 
     442             : // **********************************************************
     443             : //  SolvableVisCal Implementations
     444             : //
     445             : 
     446         124 : SolvableVisCal::SolvableVisCal(VisSet& vs) :
     447             :   VisCal(vs),
     448         124 :   corruptor_p(NULL),
     449         124 :   ct_(NULL),
     450         124 :   ci_(NULL),
     451         124 :   cpp_(NULL),
     452         124 :   spwOK_(vs.numberSpw(),false),
     453         124 :   maxTimePerSolution_p(0), 
     454         124 :   minTimePerSolution_p(10000000), 
     455         124 :   avgTimePerSolution_p(0),
     456         124 :   timer_p(),
     457         124 :   freqMetaData_(),
     458         124 :   calTableName_(""),
     459         124 :   calTableSelect_(""),
     460         124 :   append_(false),
     461         124 :   tInterpType_(""),
     462         124 :   fInterpType_(""),
     463         124 :   spwMap_(1,-1),
     464         124 :   refantmode_("flex"),
     465         124 :   urefantlist_(1,-1),
     466         124 :   minblperant_(4),
     467         124 :   solved_(false),
     468         124 :   byCallib_(false),
     469         124 :   apmode_(""),
     470         124 :   solmode_(""),
     471         124 :   rmsthresh_(0),
     472         124 :   usolint_("inf"),
     473         124 :   solint_("inf"),
     474         124 :   solTimeInterval_(DBL_MAX),
     475         124 :   fsolint_("none"),
     476         124 :   fintervalHz_(-1.0),
     477         124 :   fintervalCh_(vs.numberSpw(),0.0),
     478         124 :   chanAveBounds_(vs.numberSpw(),Matrix<Int>()),
     479         124 :   solnorm_(false,"mean"),
     480         124 :   minSNR_(0.0f),
     481         124 :   combine_(""),
     482         124 :   corrcomb_("none"),
     483         124 :   focusChan_(0),
     484         124 :   dataInterval_(0.0),
     485         124 :   fitWt_(0.0),
     486         124 :   fit_(0.0),
     487         124 :   antennaMap_(),
     488         124 :   refantMap_(),
     489         124 :   solveCPar_(vs.numberSpw(),NULL),  // TBD: move inflation into ctor body
     490         124 :   solveRPar_(vs.numberSpw(),NULL),
     491         124 :   solveParOK_(vs.numberSpw(),NULL),
     492         124 :   solveParErr_(vs.numberSpw(),NULL),
     493         124 :   solveParSNR_(vs.numberSpw(),NULL),
     494         124 :   solveAllCPar_(vs.numberSpw(),NULL),
     495         124 :   solveAllRPar_(vs.numberSpw(),NULL),
     496         124 :   solveAllParOK_(vs.numberSpw(),NULL),
     497         124 :   solveAllParErr_(vs.numberSpw(),NULL),
     498         124 :   solveAllParSNR_(vs.numberSpw(),NULL),
     499         124 :   srcPolPar_(),
     500         124 :   chanmask_(NULL),
     501         124 :   simulated_(false),
     502         124 :   simint_("integration"),
     503         248 :   onthefly_(false)
     504             : {
     505         124 :   if (prtlev()>2) cout << "SVC::SVC(vs)" << endl;
     506             : 
     507         124 :   caiRC_p = Aipsrc::registerRC("calibrater.activity.interval", "3600.0");
     508         124 :   cafRC_p = Aipsrc::registerRC("calibrater.activity.fraction", "0.00001");
     509         124 :   String ca_str = Aipsrc::get(caiRC_p);
     510         124 :   std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityInterval_p);
     511         124 :   userPrintActivityInterval_p = abs(userPrintActivityInterval_p);
     512             : 
     513         124 :   ca_str = Aipsrc::get(cafRC_p);
     514         124 :   std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityFraction_p);
     515         124 :   userPrintActivityFraction_p = abs(userPrintActivityFraction_p);
     516             : 
     517         124 :   initSVC();
     518             : 
     519         124 : };
     520             : 
     521          27 : SolvableVisCal::SolvableVisCal(String msname,Int MSnAnt,Int MSnSpw) :
     522             :   VisCal(msname,MSnAnt,MSnSpw),
     523          27 :   corruptor_p(NULL),
     524          27 :   ct_(NULL),
     525          27 :   ci_(NULL),
     526          27 :   cpp_(NULL),
     527           0 :   spwOK_(MSnSpw,false),
     528          27 :   maxTimePerSolution_p(0), 
     529          27 :   minTimePerSolution_p(10000000), 
     530          27 :   avgTimePerSolution_p(0),
     531          27 :   timer_p(),
     532          27 :   calTableName_(""),
     533          27 :   calTableSelect_(""),
     534          27 :   append_(false),
     535          27 :   tInterpType_(""),
     536          27 :   fInterpType_(""),
     537          27 :   spwMap_(1,-1),
     538          27 :   refantmode_("flex"),
     539          27 :   urefantlist_(1,-1),
     540          27 :   minblperant_(4),
     541          27 :   solved_(false),
     542          27 :   byCallib_(false),
     543          27 :   apmode_(""),
     544          27 :   solmode_(""),
     545          27 :   rmsthresh_(0),
     546          27 :   usolint_("inf"),
     547          27 :   solint_("inf"),
     548          27 :   solTimeInterval_(DBL_MAX),
     549          27 :   fsolint_("none"),
     550          27 :   fintervalHz_(-1.0),
     551          27 :   fintervalCh_(MSnSpw,0.0),
     552          27 :   chanAveBounds_(MSnSpw,Matrix<Int>()),
     553          27 :   solnorm_(false,"mean"),
     554          27 :   minSNR_(0.0f),
     555          27 :   combine_(""),
     556          27 :   focusChan_(0),
     557          27 :   dataInterval_(0.0),
     558          27 :   fitWt_(0.0),
     559          27 :   fit_(0.0),
     560          27 :   solveCPar_(MSnSpw,NULL),  // TBD: move inflation into ctor body
     561          27 :   solveRPar_(MSnSpw,NULL),
     562          27 :   solveParOK_(MSnSpw,NULL),
     563          27 :   solveParErr_(MSnSpw,NULL),
     564          27 :   solveParSNR_(MSnSpw,NULL),
     565          27 :   solveAllCPar_(MSnSpw,NULL),
     566          27 :   solveAllRPar_(MSnSpw,NULL),
     567          27 :   solveAllParOK_(MSnSpw,NULL),
     568          27 :   solveAllParErr_(MSnSpw,NULL),
     569          27 :   solveAllParSNR_(MSnSpw,NULL),
     570          27 :   srcPolPar_(),
     571          27 :   chanmask_(NULL),
     572          27 :   simulated_(false),
     573          27 :   simint_("integration"),
     574         108 :   onthefly_(false)
     575             : {
     576          27 :   if (prtlev()>2) cout << "SVC::SVC(msname,MSnAnt,MSnSpw)" << endl;
     577             : 
     578          27 :   caiRC_p = Aipsrc::registerRC("calibrater.activity.interval", "3600.0");
     579          27 :   cafRC_p = Aipsrc::registerRC("calibrater.activity.fraction", "0.00001");
     580          27 :   String ca_str = Aipsrc::get(caiRC_p);
     581          27 :   std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityInterval_p);
     582          27 :   userPrintActivityInterval_p = abs(userPrintActivityInterval_p);
     583             : 
     584          27 :   ca_str = Aipsrc::get(cafRC_p);
     585          27 :   std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityFraction_p);
     586          27 :   userPrintActivityFraction_p = abs(userPrintActivityFraction_p);
     587             : 
     588          27 :   initSVC();
     589             : 
     590          27 : };
     591             : 
     592             :   
     593             : 
     594         574 : SolvableVisCal::SolvableVisCal(const MSMetaInfoForCal& msmc) :
     595             :   VisCal(msmc),
     596         574 :   corruptor_p(NULL),
     597         574 :   ct_(NULL),
     598         574 :   ci_(NULL),
     599         574 :   cpp_(NULL),
     600         574 :   spwOK_(nSpw(),False),
     601         574 :   maxTimePerSolution_p(0), 
     602         574 :   minTimePerSolution_p(10000000), 
     603         574 :   avgTimePerSolution_p(0),
     604         574 :   timer_p(),
     605         574 :   calTableName_(""),
     606         574 :   calTableSelect_(""),
     607         574 :   append_(False),
     608         574 :   tInterpType_(""),
     609         574 :   fInterpType_(""),
     610         574 :   spwMap_(1,-1),
     611         574 :   refantmode_("flex"),
     612         574 :   urefantlist_(1,-1),
     613         574 :   minblperant_(4),
     614         574 :   solved_(False),
     615         574 :   byCallib_(False),
     616         574 :   apmode_(""),
     617         574 :   solmode_(""),
     618         574 :   rmsthresh_(0),
     619         574 :   usolint_("inf"),
     620         574 :   solint_("inf"),
     621         574 :   solTimeInterval_(DBL_MAX),
     622         574 :   fsolint_("none"),
     623         574 :   fintervalHz_(-1.0),
     624         574 :   fintervalCh_(nSpw(),0.0),
     625         574 :   chanAveBounds_(nSpw(),Matrix<Int>()),
     626         574 :   solnorm_(false,"mean"),
     627         574 :   minSNR_(0.0f),
     628         574 :   combine_(""),
     629         574 :   focusChan_(0),
     630         574 :   dataInterval_(0.0),
     631         574 :   fitWt_(0.0),
     632         574 :   fit_(0.0),
     633         574 :   solveCPar_(nSpw(),NULL),  // TBD: move inflation into ctor body
     634         574 :   solveRPar_(nSpw(),NULL),
     635         574 :   solveParOK_(nSpw(),NULL),
     636         574 :   solveParErr_(nSpw(),NULL),
     637         574 :   solveParSNR_(nSpw(),NULL),
     638         574 :   solveAllCPar_(nSpw(),NULL),
     639         574 :   solveAllRPar_(nSpw(),NULL),
     640         574 :   solveAllParOK_(nSpw(),NULL),
     641         574 :   solveAllParErr_(nSpw(),NULL),
     642         574 :   solveAllParSNR_(nSpw(),NULL),
     643         574 :   srcPolPar_(),
     644         574 :   chanmask_(NULL),
     645         574 :   simulated_(False),
     646         574 :   simint_("integration"),
     647        2296 :   onthefly_(False)
     648             : {
     649         574 :   if (prtlev()>2) cout << "SVC::SVC(msmc)" << endl;
     650             : 
     651         574 :   caiRC_p = Aipsrc::registerRC("calibrater.activity.interval", "3600.0");
     652         574 :   cafRC_p = Aipsrc::registerRC("calibrater.activity.fraction", "0.00001");
     653         574 :   String ca_str = Aipsrc::get(caiRC_p);
     654         574 :   std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityInterval_p);
     655         574 :   userPrintActivityInterval_p = abs(userPrintActivityInterval_p);
     656             : 
     657         574 :   ca_str = Aipsrc::get(cafRC_p);
     658         574 :   std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityFraction_p);
     659         574 :   userPrintActivityFraction_p = abs(userPrintActivityFraction_p);
     660             : 
     661         574 :   initSVC();
     662             : 
     663         574 : };
     664             : 
     665             : 
     666             : 
     667           0 : SolvableVisCal::SolvableVisCal(const Int& nAnt) :
     668             :   VisCal(nAnt),
     669           0 :   corruptor_p(NULL),
     670           0 :   maxTimePerSolution_p(0), 
     671           0 :   minTimePerSolution_p(10000000), 
     672           0 :   avgTimePerSolution_p(0),
     673           0 :   timer_p(),
     674           0 :   calTableName_(""),
     675           0 :   calTableSelect_(""),
     676           0 :   append_(false),
     677           0 :   tInterpType_(""),
     678           0 :   fInterpType_(""),
     679           0 :   spwMap_(1,-1),
     680           0 :   refantmode_("flex"),
     681           0 :   urefantlist_(1,-1),
     682           0 :   minblperant_(4),
     683           0 :   solved_(false),
     684           0 :   apmode_(""),
     685           0 :   solmode_(""),
     686           0 :   rmsthresh_(0),
     687           0 :   usolint_("inf"),
     688           0 :   solint_("inf"),
     689           0 :   solTimeInterval_(DBL_MAX),
     690           0 :   fsolint_("none"),
     691           0 :   solnorm_(false,"mean"),
     692           0 :   minSNR_(0.0),
     693           0 :   combine_(""),
     694           0 :   focusChan_(0),
     695           0 :   dataInterval_(0.0),
     696           0 :   fitWt_(0.0),
     697           0 :   fit_(0.0),
     698           0 :   solveCPar_(1,NULL),
     699           0 :   solveRPar_(1,NULL),
     700           0 :   solveParOK_(1,NULL),
     701           0 :   solveParErr_(1,NULL),
     702           0 :   solveParSNR_(1,NULL),
     703           0 :   srcPolPar_(),
     704           0 :   chanmask_(NULL),
     705           0 :   simulated_(false),
     706           0 :   simint_("inf"),
     707           0 :   onthefly_(false)
     708             : {  
     709           0 :   if (prtlev()>2) cout << "SVC::SVC(i,j,k)" << endl;
     710             : 
     711           0 :   caiRC_p = Aipsrc::registerRC("calibrater.activity.interval", "3600.0");
     712           0 :   cafRC_p = Aipsrc::registerRC("calibrater.activity.fraction", "0.00001");
     713           0 :   String ca_str = Aipsrc::get(caiRC_p);
     714           0 :   std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityInterval_p);
     715           0 :   userPrintActivityInterval_p = abs(userPrintActivityInterval_p);
     716             : 
     717           0 :   ca_str = Aipsrc::get(cafRC_p);
     718           0 :   std::sscanf(std::string(ca_str).c_str(), "%f", &userPrintActivityFraction_p);
     719           0 :   userPrintActivityFraction_p = abs(userPrintActivityFraction_p);
     720             : 
     721           0 :   initSVC();
     722             : 
     723           0 : }
     724             : 
     725         725 : SolvableVisCal::~SolvableVisCal() {
     726             : 
     727         725 :   if (prtlev()>2) cout << "SVC::~SVC()" << endl;
     728             :   
     729             :   // TODO RI do we ever have the same corruptor working on multiple VCs?  then we need some kind of 
     730             :   // multiuse locking...
     731         725 :   if (corruptor_p) delete corruptor_p;  
     732             : 
     733         725 :   deleteSVC();
     734             : 
     735         725 :   if (ci_)   delete ci_;   ci_=NULL;
     736         725 :   if (cpp_)  delete cpp_;  cpp_=NULL;
     737         725 :   if (ct_)   delete ct_;   ct_=NULL;
     738             : 
     739         725 : }
     740             : 
     741             : 
     742             : // Generic setapply
     743           0 : void SolvableVisCal::setApply() {
     744             : 
     745           0 :   if (prtlev()>2) cout << "SVC::setApply()" << endl;
     746             : 
     747             :   // Generic settings
     748           0 :   calTableName()="<none>";
     749           0 :   calTableSelect()="<none>";
     750           0 :   tInterpType()="nearest";
     751           0 :   indgen(spwMap());
     752           0 :   interval()=DBL_MAX;
     753             : 
     754             :   // This is apply context  
     755           0 :   setApplied(true);
     756           0 :   setSolved(false);
     757             : 
     758           0 : }
     759             : 
     760             : 
     761             : 
     762             : // Setapply from a Cal Table, etc.
     763         217 : void SolvableVisCal::setApply(const Record& apply) {
     764             :   //  Inputs:
     765             :   //    apply           Record&       Contains application params
     766             :   //    
     767             : 
     768         217 :   if (prtlev()>2) 
     769           0 :     cout << "SVC::setApply(apply)" << endl;
     770             : 
     771             :   // Call VisCal version for generic stuff
     772         217 :   VisCal::setApply(apply);
     773             : 
     774             :   // Collect Cal table parameters
     775         217 :   if (apply.isDefined("table")) {
     776         217 :     calTableName()=apply.asString("table");
     777             :     // Verify that CalTable is of correct type
     778         217 :     verifyCalTable(calTableName());
     779             :   }
     780             : 
     781             :   // Collect interpolation parameters
     782         217 :   if (apply.isDefined("interp")) {
     783         163 :     String interp=apply.asString("interp");
     784         163 :     if (interp.contains(',')) {
     785          47 :       tInterpType()=String(interp.before(','));
     786          47 :       fInterpType() = interp.after(',');
     787             :     }
     788             :     else
     789         116 :       tInterpType()=interp;
     790         163 :   }
     791             : 
     792             :   // Protect against non-specific interp
     793         217 :   if (tInterpType()=="")
     794          75 :     tInterpType()="linear";
     795         217 :   if (fInterpType()=="" && this->freqDepPar()) // only if we are freq-dep
     796          22 :     fInterpType()="linear";
     797             : 
     798             :   // Catch use of deprecated 'aipslin' interpolation
     799         217 :   if (tInterpType().contains("aips") || fInterpType().contains("aips") )
     800           0 :     throw(AipsError("The (peculiar) 'aipslin' interpolation type was deprecated in CASA v3.4; use 'linear'."));
     801             : 
     802             : 
     803             :   //  cout << "SVC::setApply(apply) is not yet supporting CalSelection." << endl;
     804             : 
     805             :   /*
     806             :   if (apply.isDefined("select"))
     807             :     calTableSelect()=apply.asString("select");
     808             : 
     809             :   else {
     810             :     
     811             :     calTableSelect()="";
     812             :     //    String spwsel("");
     813             :     //    if (apply.isDefined("spw")) {
     814             :     //      ostringstream os;
     815             :     //      os << Vector<Int>(apply.asArrayInt("spw"));
     816             :     //      spwsel = os.str();
     817             :     //    }
     818             :     //    cout << "spwsel = " << spwsel << endl;
     819             : 
     820             :     String fldsel("");
     821             :     if (apply.isDefined("field")) {
     822             :       ostringstream os;
     823             :       os << Vector<Int>(apply.asArrayInt("field"));
     824             :       if (os.str()!="[]")
     825             :         fldsel = os.str();
     826             :     }
     827             : 
     828             :     if (fldsel.length()>0) {
     829             :       ostringstream os;
     830             :       os << "(FIELD_ID IN " << fldsel << ")";
     831             :       calTableSelect() = os.str();
     832             :     }
     833             :   }
     834             :   */
     835             : 
     836         217 :   String fieldstr;
     837         217 :   String fieldtype("");
     838         217 :   if (apply.isDefined("fieldstr")) {
     839         163 :     fieldstr=apply.asString("fieldstr");
     840             :     //    cout << "SVC::setApply: fieldstr=" << fieldstr  << endl;
     841         163 :     if (fieldstr=="nearest") {
     842          15 :       fieldtype="nearest";
     843          15 :       fieldstr="";
     844             :     }
     845             :   }
     846             :   //cout << "SVC::setApply: fieldstr=" << fieldstr  << endl;
     847             :   //cout << "SVC::setApply: fieldtype=" << fieldtype  << endl;
     848             : 
     849         217 :   if (apply.isDefined("spwmap")) 
     850         163 :     spwMap().assign(apply.asArrayInt("spwmap"));
     851             : 
     852             :   // Catch spwmap that is too long
     853         217 :   if (spwMap().nelements()>uInt(nSpw()))
     854           0 :     throw(AipsError("Specified spwmap has more elements ("+String::toString(spwMap().nelements())+") than the number of spectral windows in the MS ("+String::toString(nSpw())+")."));
     855             : 
     856             :   // TBD: move interval to VisCal version?
     857             :   // TBD: change to "reach"
     858         217 :   if (apply.isDefined("t"))
     859         163 :     interval()=apply.asFloat("t");
     860             : 
     861             :   // This is apply context  
     862         217 :   setApplied(true);
     863         217 :   setSolved(false);
     864             : 
     865             :   //  TBD:  "Arranging to apply...."
     866             : 
     867             :   // TBD:  Move the following so as to be triggered
     868             :   //       when actual application starts?  E.g., SVC::initApply()...
     869             : 
     870             :   // Open the caltable
     871         217 :   loadMemCalTable(calTableName(),fieldstr);
     872             : 
     873             :   // Make the interpolation engine
     874         217 :   MeasurementSet ms(msName());
     875         219 :   ci_ = new CTPatchedInterp(*ct_,matrixType(),nPar(),tInterpType(),fInterpType(),fieldtype,ms,msmc(),spwMap(),cttifactoryptr());
     876             : 
     877             :   // Channel counting info 
     878             :   //  (soon will deprecate, I think, because there will be no need
     879             :   //    to do channel registration in the apply)
     880         216 :   startChanList()=0;  // all zero
     881             : 
     882             :   //  cout << "End of SVC::setApply" << endl;
     883             : 
     884         219 : }
     885             : 
     886             : // Setapply from a Cal Table, etc.
     887          43 : void SolvableVisCal::setCallib(const Record& callib,
     888             :                                const MeasurementSet& selms) {
     889             : 
     890          43 :   if (prtlev()>2) 
     891           0 :     cout << "SVC::setCallib(callib)" << endl;
     892             : 
     893             : 
     894         129 :   if (typeName().contains("BPOLY") ||
     895          86 :       typeName().contains("GSPLINE"))
     896           0 :     throw(AipsError(typeName()+" not yet supported for apply by cal library."));
     897             : 
     898             :   // Call VisCal version for generic stuff
     899          43 :   VisCal::setCallib(callib,selms);
     900             : 
     901             :   // signal that we are using a callib
     902          43 :   byCallib_=true;
     903             : 
     904             :   // Collect Cal table parameters
     905          43 :   if (callib.isDefined("tablename")) {
     906          43 :     calTableName()=callib.asString("tablename");
     907             :     // Verify that CalTable is of correct type
     908          43 :     verifyCalTable(calTableName());
     909             :   }
     910             : 
     911             :   // This is apply context  
     912          43 :   setApplied(true);
     913          43 :   setSolved(false);
     914             : 
     915             :   logSink() << LogIO::NORMAL << ".   "
     916          43 :             << this->applyinfo()
     917          43 :             << LogIO::POST;
     918             : 
     919             :   // Make the interpolation engine
     920          43 :   cpp_ = new CLPatchPanel(calTableName(),selms,callib,matrixType(),nPar(),cttifactoryptr());
     921             :   //cpp_->listmappings();
     922             : 
     923             :   // Setup ct_ in SVC private data, because some derived classes need this
     924             :   //  NB:  Not loaded into memory in the callib context (CLPatchPanel has that)
     925          43 :   ct_= new NewCalTable(calTableName(),Table::Old,Table::Plain);
     926             : 
     927          43 : }
     928             : 
     929             : 
     930             : // ===================================================
     931             : 
     932          32 : void SolvableVisCal::createCorruptor(const VisIter& vi,const Record& simpar, const Int nSim) {
     933          64 :   LogIO os(LogOrigin("SVC", "createCorruptor", WHERE));
     934             : 
     935          32 :   if (prtlev()>3) cout << "  SVC::createCorruptor:" << endl;
     936             : 
     937             :   // this is the generic create and init 
     938             :   // ** specialists should call this after createing their corruptor
     939             :   // and before initializing
     940             : 
     941          32 :   if (!corruptor_p) {
     942           0 :     corruptor_p = new CalCorruptor(nSim);  
     943           0 :     os << LogIO::WARN << "creating generic CalCorruptor" << LogIO::POST;
     944             :   }
     945             : 
     946             :   // would be nice to reduce the amount of stuff passed down to the corruptor; 
     947             :   // fnChan is used in AtmosCorruptor, currAnt and curr Spw are used generically
     948             : 
     949          32 :   corruptor_p->prtlev()=prtlev();
     950          32 :   corruptor_p->freqDepPar()=freqDepPar();
     951          32 :   corruptor_p->simpar()=simpar;
     952             :   // initialize is supposed to be called in a specialization, but 
     953             :   // if we end up only using the generic CalCorruptor and this generic 
     954             :   // createCorruptor, we still want amplitude to be passed on.
     955          32 :   if (simpar.isDefined("amplitude")) 
     956          32 :     corruptor_p->amp()=simpar.asFloat("amplitude");
     957             : 
     958          32 :   if (simpar.isDefined("mode")) 
     959          32 :     corruptor_p->mode()=simpar.asString("mode");
     960             : 
     961             : //  corruptor_p->nCorr()=vi.nCorr();
     962             : //  if (prtlev()>3) 
     963             : //    os << LogIO::POST << "nCorr= " << vi.nCorr() << LogIO::POST;      
     964             :   // what matters is nPar not nCorr - then apply uses coridx
     965          32 :   corruptor_p->nPar()=nPar();
     966             : 
     967          32 :   const MSSpWindowColumns& spwcols = vi.msColumns().spectralWindow();  
     968             :   //  if (prtlev()>3) cout << " SpwCols accessed:" << endl;
     969             :   //if (prtlev()>3) cout << "   nSpw()= " << nSpw() << " spwcols= " << nSpw() << endl;
     970             :   //if (prtlev()>3) cout << "   spwcols.nrow()= " << spwcols.nrow() << endl;  
     971          32 :   AlwaysAssert(uInt(nSpw())==spwcols.nrow(),AipsError);
     972             :   // there's a member variable in Simulator nSpw, should we verify that 
     973             :   // this is the same? probably.
     974             : 
     975             :   // things will break if spw mapping, ie not in same order as in vs
     976          32 :   corruptor_p->nSpw()=nSpw();
     977          32 :   corruptor_p->nAnt()=nAnt();
     978          32 :   corruptor_p->currAnt()=0;
     979          32 :   corruptor_p->currSpw()=0;
     980          32 :   corruptor_p->fRefFreq().resize(nSpw());
     981          32 :   corruptor_p->fnChan().resize(nSpw());
     982          32 :   corruptor_p->fWidth().resize(nSpw());
     983          32 :   corruptor_p->currChans().resize(nSpw());
     984             :   
     985          64 :   for (Int irow=0;irow<nSpw();++irow) { 
     986          32 :     corruptor_p->currChans()[irow]=0;
     987          32 :     corruptor_p->fRefFreq()[irow]=spwcols.refFrequency()(irow);
     988             :     // don't need to change fnChan to 1 if not freqDepPar()
     989             :     // because fnChan is only used in AtmosCorruptor if 
     990             :     // freqDepPar() is set i.e. in initAtm().
     991          32 :     corruptor_p->fnChan()[irow]=spwcols.numChan()(irow);    
     992          32 :     corruptor_p->fWidth()[irow]=spwcols.totalBandwidth()(irow); 
     993             :     // totalBandwidthQuant ?  in other places its assumed to be in Hz
     994             :   }
     995             :   // see MSsummary.cc for more info/examples
     996          32 :   if (prtlev()>3) 
     997           0 :     cout << "   SVC::fnChan = "<<corruptor_p->fnChan()<<" reffreq = "<<corruptor_p->fRefFreq()<<" fWidth = "<<corruptor_p->fWidth()<<endl;
     998             : 
     999          32 :   if (prtlev()>3) cout << "  ~SVC::createCorruptor:" << endl;
    1000             : 
    1001          32 : }
    1002             : 
    1003             : 
    1004             : 
    1005          32 : void SolvableVisCal::setSimulate(VisSet& vs, Record& simpar, Vector<Double>& solTimes) {
    1006             : 
    1007          64 :   LogIO os(LogOrigin("SVC["+typeName()+"]", "setSimulate()", WHERE));
    1008          32 :   if (prtlev()>2) cout << " SVC::setSimulate(simpar)" << endl;
    1009             : 
    1010             :   //  cout << "SVC::setSimulate" << endl;
    1011             : 
    1012             :   // Extract calWt
    1013          32 :   if (simpar.isDefined("calwt"))
    1014           0 :     calWt()=simpar.asBool("calwt");
    1015             :   
    1016             :   // (copied from SolvableVisCal::setSolve)
    1017          32 :   if (simpar.isDefined("simint"))
    1018           0 :     simint()=simpar.asString("simint");
    1019             :   
    1020          32 :   if (upcase(simint()).contains("INF") || simint()=="") {
    1021           0 :     simint()="infinite";
    1022           0 :     interval()=-1.0;
    1023          32 :   } else if (upcase(simint()).contains("INT")) {
    1024          32 :     simint()="integration";
    1025          32 :     interval()=0.0;
    1026             :   } else {
    1027           0 :     QuantumHolder qhsimint;
    1028           0 :     String error;
    1029           0 :     Quantity qsimint;
    1030           0 :     qhsimint.fromString(error,simint());
    1031           0 :     if (error.length()!=0)
    1032           0 :       throw(AipsError("Unrecognized units for simint."));
    1033           0 :     qsimint=qhsimint.asQuantumDouble();
    1034             :     
    1035           0 :     if (qsimint.isConform("s"))
    1036           0 :       interval()=qsimint.get("s").getValue();
    1037             :     else {
    1038           0 :       if (qsimint.getUnit().length()==0) {
    1039             :         // when no units specified, assume seconds
    1040             :         // assume seconds
    1041           0 :         interval()=qsimint.getValue();
    1042           0 :         simint()=simint()+"s";
    1043             :       }
    1044             :       else
    1045             :         // unrecognized units:
    1046           0 :         throw(AipsError("Unrecognized units for simint (e.g., use 'min', not 'm', for minutes)"));
    1047             :     }
    1048           0 :   }
    1049             : 
    1050             :   // check if want to write a table:
    1051          32 :   if (simpar.isDefined("caltable")) {
    1052          32 :     calTableName()=simpar.asString("caltable");
    1053             :     // RI todo SVC::setSimulate deal with over-writing existing caltables
    1054             :     // verifyCalTable(calTableName());
    1055          32 :     append()=false;
    1056             :   } else {
    1057           0 :     calTableName()="<none>";
    1058             :   }
    1059          32 :   if (calTableName().length()==0)
    1060          12 :     calTableName()="<none>";
    1061             :    
    1062             :   // on the fly (only implemented for ANoise 20100817)
    1063          32 :   simOnTheFly()=false;
    1064          32 :   if (simpar.isDefined("onthefly")) {
    1065          32 :     if (simpar.asBool("onthefly")) {
    1066          16 :       if (type() != VisCal::ANoise) {
    1067           0 :         throw(AipsError("Logic Error: onthefly simulation not available for type "+typeName()));
    1068             :       } else {
    1069          16 :         simOnTheFly()=true;
    1070          16 :         os << LogIO::DEBUG1 << " using OTF simulation" << LogIO::POST;  
    1071          16 :         calTableName()="<none>";
    1072             :       }
    1073             :     }
    1074             :   }
    1075             : 
    1076          32 :   setSolved(false);
    1077             :   // this has to be true for some of George's VE stuff 
    1078             :   // but be careful about VC structure and inflation!
    1079          32 :   setApplied(true); 
    1080          32 :   setSimulated(true);
    1081             : 
    1082             :   // without this, CI gets created without a sensible time
    1083             :   // interpolation, and ends up bombing
    1084          32 :   tInterpType()="nearest";
    1085             : 
    1086             : 
    1087             :   // ----------------
    1088             :   // assess size of ms:
    1089             : 
    1090             :   // how to combine data in sizeUp e.g. SPW,SCAN
    1091          32 :   if (simpar.isDefined("combine"))
    1092          32 :     combine()=simpar.asString("combine");
    1093             :   else
    1094           0 :     throw(AipsError("MS combination information not set"));
    1095             : 
    1096             :   // GM: organize calibration correction/corruption according to 
    1097             :   // multi-spw consistency; e.g. move time ahead of data_desc_id so that 
    1098             :   // data_desc_id (spw) changes faster than time, even within scans.
    1099             : 
    1100             :   // RI todo double-check logic in case of spwmap and multi-spw
    1101             :   
    1102             :   // Arrange for iteration over data
    1103          32 :   Block<Int> columns;
    1104             :   // include scan iteration
    1105          32 :   columns.resize(5);
    1106          32 :   columns[0]=MS::ARRAY_ID;
    1107          32 :   columns[1]=MS::SCAN_NUMBER;
    1108          32 :   columns[2]=MS::FIELD_ID;
    1109             :   // GM's order:
    1110             :   //columns[3]=MS::DATA_DESC_ID;
    1111             :   //columns[4]=MS::TIME;
    1112             :   // RI put spw after time
    1113          32 :   columns[4]=MS::DATA_DESC_ID;
    1114          32 :   columns[3]=MS::TIME;
    1115             :   
    1116             : 
    1117             :   // drop chunking time interval down to the simulation interval, else will 
    1118             :   // chunk by entire scans.
    1119          32 :   Double iterInterval(max(interval(),DBL_MIN));
    1120          32 :   if (interval() < 0.0) {   // means no interval (infinite solint)
    1121           0 :     iterInterval=0.0;
    1122           0 :     interval()=DBL_MAX;   
    1123             :   }
    1124          32 :   vs.resetVisIter(columns,iterInterval);
    1125             : 
    1126          32 :   Vector<Int> nChunkPerSol;
    1127          32 :   Int nSim = 1;
    1128             :   // independent of simpar details
    1129             : 
    1130          32 :   nSim=sizeUpSim(vs,nChunkPerSol,solTimes);
    1131          32 :   if (prtlev()>1 and prtlev()<=4) cout << "  VisCal sized for Simulation with " << nSim << " slots." << endl;
    1132          32 :   if (prtlev()>4) cout << "  solTimes = " << solTimes-solTimes[0] << endl;  
    1133             :   
    1134          32 :   if (!(simpar.isDefined("startTime"))) {    
    1135           0 :     throw(AipsError("can't add startTime field to Record"));
    1136             :     // Record seems to have been designed strangely, so this doesn't work:
    1137             :     //    RecordDesc simParDesc = simpar.description();
    1138             :     //    simParDesc.addField("startTime",TpDouble);
    1139             :     //    simpar.restructure(simParDesc);
    1140             :   }
    1141          32 :   simpar.define("startTime",min(solTimes));
    1142          32 :   if (!(simpar.isDefined("stopTime"))) {    
    1143           0 :     throw(AipsError("can't add stopTime field to Record"));
    1144             :   }
    1145          32 :   simpar.define("stopTime",max(solTimes));
    1146             :   
    1147             :   // assume only one ms attached to the VI. need vi for mscolumns in createCorruptor
    1148             :   // note - sizeUpSim seems to break the reference to mscolumns inside of VI, 
    1149             :   // so we're better off resetting it here, I think, just to make sure?
    1150          32 :   VisIter& vi(vs.iter());
    1151             :   os << LogIO::DEBUG1 << " number of spw in VI (checking validity of mscolumns) = " 
    1152          32 :      << vi.numberSpw() << LogIO::POST;  
    1153          32 :   vi.origin();
    1154             :   os << LogIO::DEBUG1 << " number of spw in VI (after resetting to origin = " 
    1155          32 :      << vi.numberSpw() << LogIO::POST;  
    1156             : 
    1157             :   // -------------------
    1158             :   // create (and initialize) a corruptor in a VC-specific way - 
    1159             :   // specializations need to call the generic SVC::createCorruptor to get 
    1160             :   // spw etc information passed down.
    1161          32 :   createCorruptor(vi,simpar,nSim);
    1162             :   
    1163             :   // set times in the corruptor if createCorruptor didn't:
    1164          32 :   if (!corruptor_p->times_initialized()) {
    1165          32 :     corruptor_p->curr_slot()=0;
    1166          32 :     corruptor_p->slot_times().resize(nSim);
    1167          32 :     corruptor_p->slot_times()=solTimes;
    1168          32 :     corruptor_p->startTime()=min(solTimes);
    1169          32 :     corruptor_p->stopTime()=max(solTimes);
    1170          32 :     corruptor_p->times_initialized()=true;
    1171             :   }
    1172             : 
    1173          32 :   if (simOnTheFly()) {
    1174             : 
    1175          16 :     calTableName()="<none>";
    1176             : 
    1177             :   } else {
    1178             :    
    1179          16 :     if (prtlev()>5) 
    1180           0 :       cout << "  slot_times= " 
    1181           0 :            << corruptor_p->slot_time(1)-corruptor_p->slot_time(0) << " " 
    1182           0 :            << corruptor_p->slot_time(2)-corruptor_p->slot_time(0) << " " 
    1183           0 :            << corruptor_p->slot_time(3)-corruptor_p->slot_time(0) << " " 
    1184           0 :            << corruptor_p->slot_time(4)-corruptor_p->slot_time(0) << " " 
    1185           0 :            << corruptor_p->slot_time(5)-corruptor_p->slot_time(0) << " " 
    1186           0 :            << corruptor_p->slot_time(6)-corruptor_p->slot_time(0) << " " 
    1187           0 :            << corruptor_p->slot_time(7)-corruptor_p->slot_time(0) << " " 
    1188           0 :            << endl;  
    1189             :  
    1190          16 :     os << LogIO::NORMAL << "Calculating corruption terms for " << siminfo() << LogIO::POST;
    1191             :     //-------------------
    1192             :     // actually calculate the calset
    1193             :     // which was inflated by sizeupSim to the right size
    1194             :     
    1195          16 :     Vector<Int> slotidx(nSpw(),-1);
    1196             :     
    1197          16 :     vi.originChunks();
    1198             :     
    1199          16 :     Vector<Int> a1;
    1200          16 :     Vector<Int> a2;
    1201          16 :     Matrix<Bool> flags;
    1202             :     
    1203          32 :     ProgressMeter meter(0.,1. , "Simulating "+nameOfType(type())+" ", "", "", "", true, 1);
    1204             : 
    1205             :     // check if it's possible to simulate ACs
    1206          16 :     Bool knownACtype(false);
    1207          16 :     String mode(corruptor_p->mode());
    1208          16 :     if (type()==VisCal::ANoise)
    1209           0 :      knownACtype = true;
    1210          16 :     else if (type()==VisCal::T && (mode=="tsys-manual" || mode=="tsys-atm"))
    1211          16 :       knownACtype = true;
    1212             :     
    1213        4548 :     for (Int isim=0;isim<nSim && vi.moreChunks();++isim) {      
    1214             :     
    1215        4532 :       Int thisSpw=spwMap()(vi.spectralWindow());
    1216        4532 :       currSpw()=thisSpw;
    1217        4532 :       corruptor_p->currSpw()=thisSpw;
    1218        4532 :       slotidx(thisSpw)++;
    1219             :     
    1220        4532 :       IPosition cparshape=solveCPar().shape();
    1221             : 
    1222        4532 :       Vector<Double> timevec;
    1223             :       Double starttime,stoptime;
    1224        4532 :       starttime=vi.time(timevec)[0];
    1225             :       
    1226             :       //IPosition blc(3,0,       0,0); // par,chan=focuschan,elem=ant
    1227             :       //IPosition trc(3,nPar()-1,0,0);
    1228        4532 :       IPosition blc(3,0,       0,           0); // par,chan=focuschan,elem=ant
    1229        4532 :       IPosition trc(3,nPar()-1,nChanPar()-1,0);
    1230        4532 :       IPosition gpos(3,0,0,0);
    1231             :       
    1232        4532 :       Bool useBase(false);
    1233        4532 :       if (nElem()==nBln()) useBase=true;
    1234             :     
    1235        9064 :       for (Int ichunk=0;ichunk<nChunkPerSol[isim];++ichunk) {
    1236             :         // RI todo: SVC:setSim deal with spwmap and spwcomb() here
    1237             :     
    1238        9064 :         for (vi.origin(); vi.more(); vi++) {
    1239             :     
    1240        4532 :         if (prtlev()>5) cout << "  vi++"<<endl;
    1241        4532 :         vi.antenna1(a1);
    1242        4532 :           vi.antenna2(a2);
    1243        4532 :           vi.flag(flags);
    1244        4532 :           vi.time(timevec);
    1245             :         // assume that the corruptor slot i.e. time is the same for all rows.
    1246             :         // (to the accuracy of simint())
    1247             :         
    1248             :         // set things for SVC::keep:
    1249             :         Int tvsize;
    1250        4532 :         timevec.shape(tvsize);
    1251        4532 :         stoptime=timevec[tvsize-1];
    1252        4532 :         refTime() = 0.5*(starttime+stoptime);
    1253        4532 :         interval() = (stoptime-starttime);
    1254        4532 :         currField() = vi.fieldId();
    1255             :     
    1256             :         // make sure we have the right slot in the corruptor 
    1257             :         // RI todo can the corruptor slot be the same for all chunks?
    1258             :         // were setting curr_time() to timevec[0], but I think refTime is more 
    1259             :         // accurate
    1260             :         // 20100831 make corruptor->setCurrtime() which does slot if ness, 
    1261             :         // and * invalidates any aux matrices like airmass in atmcorr, 
    1262             :         // if ness *
    1263             : 
    1264        4532 :         if (corruptor_p->curr_time()!=refTime()) 
    1265        4532 :           corruptor_p->setCurrTime(refTime());
    1266             :         
    1267        4532 :         solveCPar()=Complex(0.0);
    1268        4532 :         solveParOK()=false;
    1269             :         
    1270       18507 :         for (Int irow=0;irow<vi.nRow();++irow) {
    1271             :           
    1272       13975 :           if (nfalse(flags.column(irow))> 0 ) {
    1273             :             
    1274       13975 :             corruptor_p->currAnt()=a1(irow);
    1275             :             // only used for baseline-based SVCs
    1276       13975 :             corruptor_p->currAnt2()=a2(irow);
    1277             :             
    1278             :             // baseline or antenna-based?
    1279       13975 :             if (useBase) {
    1280        4500 :               gpos(2)=blnidx(a1(irow),a2(irow));
    1281             :             } else {
    1282        9475 :               gpos(2)=a1(irow);
    1283             :             }
    1284             :             
    1285             :             // RI TODO make some freqDepPar VCs return all ch at once
    1286             :             //if not freqDepPar, then nChanPar=1 
    1287       27950 :             for (Int ich=nChanPar()-1;ich>-1;--ich) {                
    1288       13975 :               focusChan()=ich;
    1289       13975 :               corruptor_p->setFocusChan(ich);
    1290       13975 :               gpos(1)=ich;
    1291             : 
    1292             :               // gpos is (ipar, ich, iant|ibln)
    1293       27950 :               for (Int ipar=0;ipar<nPar();ipar++) {
    1294       13975 :                 gpos(0)=ipar;
    1295       13975 :                 if ( a1(irow)==a2(irow) ) {
    1296             :                   // autocorrels should get 1. for multiplicative VC
    1297             : //                if (type()==VisCal::ANoise or type()==VisCal::A)
    1298        4500 :                   if (type()==VisCal::A)
    1299           0 :                     solveCPar()(gpos)=0.0;
    1300        4500 :                   else if (knownACtype)
    1301        4500 :                     solveCPar()(gpos) = corruptor_p->simPar(vi,type(),ipar);
    1302             :                   else
    1303           0 :                     solveCPar()(gpos)=1.0;
    1304        4500 :                   solveParOK()(gpos)=true;                   
    1305             :                 } else {
    1306             :                   // specialized simPar for each VC - may depend on mode etc
    1307        9475 :                   solveCPar()(gpos) = corruptor_p->simPar(vi,type(),ipar); 
    1308        9475 :                   solveParOK()(gpos)=true;            
    1309             : 
    1310             :                   // if MS doesn't have ACs we need to fill ant2 b/c it'll 
    1311             :                   // never get selected in this loop over ant1
    1312             :                   // TODO clean this up
    1313        9475 :                   if (not useBase) {
    1314        9475 :                     gpos(2)=a2(irow);
    1315        9475 :                     if (solveCPar()(gpos)==Complex(0.0)) {
    1316         543 :                       corruptor_p->currAnt()=a2(irow);
    1317         543 :                       solveCPar()(gpos) = corruptor_p->simPar(vi,type(),ipar); 
    1318         543 :                       solveParOK()(gpos)=true;        
    1319         543 :                       corruptor_p->currAnt()=a1(irow);                     
    1320             :                     }
    1321        9475 :                     gpos(2)=a1(irow);
    1322             :                   }
    1323             :                 }
    1324             :               }
    1325             : 
    1326             : 
    1327             : // 20101006 
    1328             : //            if ( a1(irow)==a2(irow) ) {
    1329             : //              // autocorrels should get 1. for multiplicative VC
    1330             : //              if (type()==VisCal::ANoise or type()==VisCal::A)
    1331             : //                solveCPar()(blc,trc)=0.0;
    1332             : //              else
    1333             : //                solveCPar()(blc,trc)=1.0;
    1334             : //            } else {
    1335             : //              // specialized simPar for each VC - may depend on mode etc
    1336             : //              for (Int ipar=0;ipar<nPar();ipar++) 
    1337             : //                // RI TODO left-hand operand of comma has no effect:
    1338             : //                (solveCPar()(blc,trc))[ipar,0,0] = corruptor_p->simPar(vi,type(),ipar);            
    1339             : //            }
    1340             : 
    1341             :             } //ich
    1342             : 
    1343             : //          if (prtlev()>5) cout << "  row "<<irow<< " set; cparshape="<<solveCPar().shape()<<endl;
    1344             :             // if using gpos and not changing these then they stay set this way
    1345             :             //blc(1)=0;
    1346             :             //trc(1)=nChanPar()-1;
    1347             :             //              blc(2)=gpos(2);
    1348             :             //              trc(2)=gpos(2);
    1349             :             //solveParOK()(blc,trc)=true;
    1350             :           }// if not flagged
    1351             :         }// row
    1352             : 
    1353             :         // Reference solveCPar, etc. for keepNCT
    1354        4532 :         solveAllCPar().reference(solveCPar());
    1355        4532 :         solveAllParOK().reference(solveParOK());
    1356        4532 :         solveAllParErr().reference(solveParErr());
    1357        4532 :         solveAllParSNR().reference(solveParSNR());
    1358        4532 :         currScan()=-1;
    1359        4532 :         currObs()=0;
    1360             : 
    1361        4532 :         keepNCT();
    1362             : 
    1363             :         }// vi
    1364        4532 :         if (vi.moreChunks()) vi.nextChunk();
    1365             :       } // chunk loop
    1366             :     
    1367             :       // progress indicator
    1368        4532 :       meter.update(Double(isim)/nSim);
    1369             :       
    1370        4532 :     }// nsim loop
    1371          16 :   }
    1372             : 
    1373          32 :   if (calTableName()!="<none>") {      
    1374             :     // RI todo SVC::setSimulate check if user wants to overwrite calTable
    1375             :     os << LogIO::NORMAL 
    1376          20 :        << "Writing calTable = "+calTableName()+" ("+typeName()+")" 
    1377          20 :        << endl << LogIO::POST;      
    1378             :     // write the table
    1379          10 :     append()=false; 
    1380          10 :     storeNCT();
    1381             :   } else {
    1382             :     os << LogIO::NORMAL 
    1383          22 :        << "calTable name not set - not writing to disk (note: ";
    1384          22 :     if (simOnTheFly()) 
    1385          16 :       os << "OTF sim - not creating Calset either)";
    1386             :     else
    1387           6 :       os << "NOT OTF sim - still creating Calset)";  
    1388          22 :     os << LogIO::POST;
    1389             :   }  
    1390             : 
    1391             : 
    1392             : 
    1393          32 :   if (not simOnTheFly()) {
    1394             : 
    1395             :     // Create the interpolator
    1396          16 :     if (ci_)
    1397           0 :       delete ci_;
    1398             : 
    1399          16 :     MeasurementSet ms(msName());
    1400          16 :     ci_=new CTPatchedInterp(*ct_,matrixType(),nPar(),tInterpType(),"linear","",ms,spwMap(),cttifactoryptr());
    1401             : 
    1402          16 :   }
    1403             : 
    1404             :   //  cout << "End of SVC::setSimulate" << endl;
    1405             : 
    1406             : 
    1407          32 :   if (prtlev()>2) cout << " ~SVC::setSimulate(simpar)" << endl;
    1408          32 : }
    1409             : 
    1410             : 
    1411             : 
    1412             : 
    1413             : 
    1414             : 
    1415             : 
    1416          48 : String SolvableVisCal::siminfo() {
    1417             : 
    1418          48 :   ostringstream o;
    1419          96 :   o << "simulated " << typeName() 
    1420          48 :     << ": output table="      << calTableName()
    1421          48 :     << " simint="     << simint()
    1422          48 :     << " t="          << interval();
    1423          96 :   return String(o);
    1424          48 : }
    1425             : 
    1426             : // ===================================================
    1427             : 
    1428             : 
    1429             : 
    1430             : 
    1431             : 
    1432             : 
    1433         402 : String SolvableVisCal::applyinfo() {
    1434             : 
    1435         402 :   ostringstream o;
    1436         804 :   o << typeName()
    1437         402 :     << ": table="  << calTableName();
    1438             : 
    1439         402 :   if (byCallib_)
    1440          86 :     o << " (by cal library)";
    1441             :   else {
    1442         316 :     o << " select=" << calTableSelect()
    1443         316 :       << " interp=" << tInterpType();
    1444         316 :     if (this->freqDepPar())
    1445         112 :       o << "," << fInterpType();
    1446         316 :     o << " spwmap=" << spwMap();
    1447             :       
    1448             :   }
    1449             : 
    1450         402 :   o << boolalpha << " calWt=" << calWt();
    1451             :     //    << " t="      << interval();
    1452             : 
    1453         804 :   return String(o);
    1454             : 
    1455         402 : }
    1456             : 
    1457             : // NEWCALTABLE ?????
    1458           0 : void SolvableVisCal::setSolve() {
    1459             : 
    1460           0 :   if (prtlev()>2) cout << "SVC::setSolve()" << endl;
    1461             : 
    1462           0 :   interval()=10.0;
    1463           0 :   urefantlist_.resize(1);
    1464           0 :   urefantlist_(0)=-1;
    1465           0 :   apmode()="AP";
    1466           0 :   calTableName()="<none>";
    1467           0 :   solnorm_=SolNorm(false,String("mean"));
    1468           0 :   minSNR()=0.0f;
    1469             : 
    1470             :   // This is the solve context
    1471           0 :   setSolved(true);
    1472           0 :   setApplied(false);
    1473           0 :   setSimulated(false);
    1474             : 
    1475           0 : }
    1476             : 
    1477         207 : void SolvableVisCal::setSolve(const Record& solve) 
    1478             : {
    1479             : 
    1480         207 :   if (prtlev()>2) cout << "SVC::setSolve(solve)" << endl;
    1481             : 
    1482             :   // Collect parameters
    1483         207 :   if (solve.isDefined("table"))
    1484         207 :     calTableName()=solve.asString("table");
    1485             : 
    1486         207 :   if (calTableName().length()==0)
    1487           0 :     throw(AipsError("Please specify a name for the output calibration table!"));
    1488             : 
    1489             :   // Internal default solint 
    1490         207 :   solint()="inf";
    1491         207 :   fsolint()="none";
    1492         207 :   if (solve.isDefined("solint")) {
    1493         206 :     usolint_=solve.asString("solint");
    1494         206 :     if (usolint_.contains(',')) {
    1495             :       // both time and freq solint specified
    1496           3 :       solint()=usolint_.before(',');
    1497           3 :       fsolint()=usolint_.after(',');
    1498             :     }
    1499             :     else
    1500             :       // interpret as only time-dep solint
    1501         203 :       solint()=usolint_;
    1502             :   }
    1503             : 
    1504             :   // Handle solint format
    1505         207 :   if (upcase(solint()).contains("INF") || solint()=="") {
    1506         190 :     solint()="inf";
    1507         190 :     interval()=-1.0;
    1508             :   }
    1509          17 :   else if (upcase(solint()).contains("INT"))
    1510          10 :     interval()=0.0;
    1511             :   else {
    1512           7 :     QuantumHolder qhsolint;
    1513           7 :     String error;
    1514           7 :     Quantity qsolint;
    1515           7 :     qhsolint.fromString(error,solint());
    1516           7 :     if (error.length()!=0)
    1517           0 :       throw(AipsError("Unrecognized units for time-dep solint."));
    1518           7 :     qsolint=qhsolint.asQuantumDouble();
    1519             :     
    1520           7 :     if (qsolint.isConform("s"))
    1521           5 :       interval()=qsolint.get("s").getValue();
    1522             :     else {
    1523           2 :       if (qsolint.getUnit().length()==0) {
    1524             :         // when no units specified, assume seconds
    1525           2 :         interval()=qsolint.getValue();
    1526           2 :         solint()=solint()+"s";
    1527             :       }
    1528             :       else
    1529             :         // unrecognized units:
    1530           0 :         throw(AipsError("Unrecognized units for solint (e.g., use 'min', not 'm', for minutes)"));
    1531             :     }
    1532           7 :   }
    1533             : 
    1534             :   // Handle fsolint format
    1535         207 :   if (upcase(fsolint()).contains("NONE") || !freqDepPar()) {
    1536         204 :     fsolint()="none";
    1537         204 :     fintervalCh_.set(0.0); 
    1538         204 :     fintervalHz_=-1.0;
    1539             :   }
    1540             :   else {
    1541           3 :     if (freqDepPar()) {
    1542             :       // Try to parse it
    1543           3 :       if (upcase(fsolint()).contains("CH")) {
    1544           3 :         String fsolintstr=upcase(fsolint());
    1545           3 :         fintervalCh_.set(String::toDouble(upcase(fsolint()).before("CH")));
    1546           3 :         fintervalHz_=-1.0;  // Don't know in Hz, and don't really care
    1547           3 :         fsolint()=downcase(fsolint());
    1548           3 :       }
    1549             :       else {
    1550           0 :         QuantumHolder qhFsolint;
    1551           0 :         String error;
    1552           0 :         qhFsolint.fromString(error,fsolint());
    1553           0 :         if (error.length()!=0)
    1554           0 :           throw(AipsError("Unrecognized units for freq-dep solint."));
    1555           0 :         Quantity qFsolint;
    1556           0 :         qFsolint=qhFsolint.asQuantumDouble();
    1557             :         
    1558           0 :         if (qFsolint.isConform("Hz")) {
    1559           0 :           fintervalHz_=qFsolint.get("Hz").getValue();
    1560           0 :           fintervalCh_.set(-1.0);
    1561             :           //      throw(AipsError("Not able to convert freq-dep solint from Hz to channel yet."));
    1562             :         }
    1563             :         else {
    1564           0 :           if (qFsolint.getUnit().length()==0) {
    1565             :             // when no units specified, assume channel
    1566           0 :             fintervalCh_.set(qFsolint.getValue());
    1567           0 :             fsolint()=fsolint()+"ch";
    1568             :           }
    1569             :           else
    1570             :             // unrecognized units:
    1571           0 :             throw(AipsError("Unrecognized units for freq-dep solint"));
    1572             :         } // Hz vs. Ch via Quantum
    1573           0 :       } // parse by Quantum
    1574             :     } // freqDepPar
    1575             :     /*
    1576             :     cout << "Freq-dep solint: " << fsolint() 
    1577             :          << " Ch=" << fintervalCh_ 
    1578             :          << " Hz=" << fintervalHz() 
    1579             :          << endl;
    1580             :     */
    1581             :   } // user set something
    1582             : 
    1583         207 :   if (solve.isDefined("preavg"))
    1584         207 :     preavg()=solve.asFloat("preavg");
    1585             : 
    1586         207 :   if (solve.isDefined("refantmode")) {
    1587         206 :     refantmode_=solve.asString("refantmode");
    1588             :   }
    1589         207 :   if (solve.isDefined("refant")) {
    1590         207 :     refantlist().resize();
    1591         207 :     refantlist()=solve.asArrayInt("refant");
    1592             :   }
    1593         207 :   if (solve.isDefined("minblperant"))
    1594         206 :     minblperant()=solve.asInt("minblperant");
    1595             : 
    1596         207 :   if (solve.isDefined("apmode"))
    1597         207 :     apmode()=solve.asString("apmode");
    1598         207 :   apmode().upcase();
    1599             : 
    1600         207 :   if (solve.isDefined("append"))
    1601         207 :     append()=solve.asBool("append");
    1602             : 
    1603         207 :   if (solve.isDefined("solnorm")) {
    1604         206 :     Bool solnorm=solve.asBool("solnorm");
    1605             : 
    1606             :     // normtype="mean" if not specified
    1607         206 :     String normtype("mean");
    1608         206 :     if (solve.isDefined("normtype")) 
    1609         206 :       normtype=solve.asString("normtype");
    1610             : 
    1611             :     // Set the SolNorm object
    1612         206 :     solnorm_=SolNorm(solnorm,normtype);
    1613             : 
    1614         206 :   }
    1615             : 
    1616         207 :   if (solve.isDefined("minsnr"))
    1617         206 :     minSNR()=solve.asFloat("minsnr");
    1618             : 
    1619         207 :   if (solve.isDefined("combine"))
    1620         206 :     combine()=solve.asString("combine");
    1621             :   //  cout << "SVC::setsolve: minSNR() = " << minSNR() << endl;
    1622             : 
    1623             :   // TBD: Warn if table exists (and append=F)!
    1624             : 
    1625             :   // If normalizable & preavg<0, use full pre-averaging
    1626             :   //  (or handle this per type, e.g. D)
    1627             :   // TBD: make a nice log message concerning preavg
    1628         207 :   if (normalizable() && preavg()<0.0)
    1629         108 :     preavg()=DBL_MAX;
    1630             : 
    1631             :   // This is the solve context
    1632         207 :   setSolved(true);
    1633         207 :   setApplied(false);
    1634             : 
    1635             :   //  state();
    1636             : 
    1637         207 : }
    1638             : 
    1639         449 : String SolvableVisCal::solveinfo() {
    1640             : 
    1641             :   // Get the refant name from the MS
    1642         449 :   String refantNames("none");
    1643         449 :   if (refant()>-1) {
    1644         170 :     refantNames="";
    1645         170 :     Int nra=refantlist().nelements();
    1646         340 :     for (Int i=0;i<nra;++i) {
    1647         170 :       refantNames+=msmc().antennaName(refantlist()(i));
    1648         170 :       if (i<nra-1) refantNames+=",";
    1649             :     }
    1650             :   }
    1651             : 
    1652         449 :   ostringstream o;
    1653         449 :   o << boolalpha
    1654         449 :     << typeName()
    1655         449 :     << ": table="      << calTableName()
    1656         449 :     << " append="     << append()
    1657         449 :     << " solint="     << solint()
    1658         898 :     << (freqDepPar() ? (","+fsolint()) : "")
    1659             :     //    << " t="          << interval()
    1660             :     //    << " preavg="     << preavg()
    1661         449 :     << " refantmode="     << "'" << refantmode_ << "'"
    1662         449 :     << " refant="     << "'" << refantNames << "'" // (id=" << refant() << ")"
    1663         449 :     << " minsnr=" << minSNR()
    1664         449 :     << " apmode="  << apmode()
    1665         449 :     << " solnorm=" << solnorm()
    1666         449 :     << (solnorm() ? " normtype="+solNorm().normtypeString() : "");
    1667         898 :   return String(o);
    1668             : 
    1669         449 : }
    1670             : 
    1671             : 
    1672           0 : void SolvableVisCal::setAccumulate(VisSet& vs,
    1673             :                                    const String& table,
    1674             :                                    const String& select,
    1675             :                                    const Double& t,
    1676             :                                    const Int&) {
    1677             : 
    1678             : 
    1679           0 :   LogMessage message(LogOrigin("SolvableVisCal","setAccumulate"));
    1680             : 
    1681             :   // meta-info
    1682           0 :   calTableName()=table;
    1683           0 :   calTableSelect()=select;
    1684           0 :   interval()=t;
    1685             : 
    1686             :   // Not actually applying or solving
    1687           0 :   setSolved(false);
    1688           0 :   setApplied(false);
    1689             : 
    1690             :   // If interval<0, this signals an existing input cumulative table
    1691           0 :   if (interval()<0.0) {
    1692             : 
    1693             :     //    throw(AipsError("Accum is temporarily disabled."));
    1694             :   
    1695           0 :     logSink() << "Loading existing " << typeName()
    1696             :               << " table: " << table
    1697             :               << " for accumulation."
    1698           0 :               << LogIO::POST;
    1699             : 
    1700             : 
    1701             :     // Load the exiting table
    1702           0 :     loadMemCalTable(calTableName(),"");
    1703             : 
    1704             :     // The following should be for trivial types only!    
    1705           0 :     nChanMatList()=nChanParList();
    1706             : 
    1707             : 
    1708             :   }
    1709             : 
    1710             :   // else, we are creating a cumulative table from scratch (the VisSet)
    1711             :   else {
    1712             : 
    1713           0 :     logSink() << "Creating " << typeName()
    1714             :               << " table for accumulation."
    1715           0 :               << LogIO::POST;
    1716             : 
    1717             :     // Creat an empty caltable
    1718           0 :     createMemCalTable();
    1719             : 
    1720             :     // Setup channelization (as if solving)
    1721           0 :     setSolveChannelization(vs);
    1722           0 :     nChanMatList()=nChanParList();
    1723             : 
    1724             :     // Initialize solvePar shapes
    1725           0 :     initSolvePar();
    1726             : 
    1727             :     // Inflate it by iteratin over the dataset
    1728           0 :     inflateNCTwithMetaData(vs);
    1729             : 
    1730             :   }
    1731             : 
    1732           0 : }
    1733             : 
    1734             : 
    1735         208 : void SolvableVisCal::setSpecify(const Record& specify) {
    1736             : 
    1737         416 :   LogMessage message(LogOrigin("SolvableVisCal","setSpecify"));
    1738             : 
    1739             :   // Not actually applying or solving
    1740         208 :   setSolved(false);
    1741         208 :   setApplied(false);
    1742             : 
    1743             :   // Collect Cal table parameters
    1744         208 :   Bool tableExists(false);
    1745         208 :   if (specify.isDefined("caltable")) {
    1746         208 :     calTableName()=specify.asString("caltable");
    1747             : 
    1748             :     // Detect existence of the table
    1749         208 :     tableExists=Table::isReadable(calTableName());
    1750             : 
    1751             :   }
    1752             : 
    1753         208 :   if (tableExists) {
    1754             : 
    1755             :     // Verify table has correct type
    1756         188 :     verifyCalTable(calTableName());
    1757             : 
    1758         188 :     logSink() << "Loading existing " << typeName()
    1759         188 :               << " table: " << calTableName()
    1760             :               << " (to be updated)."
    1761         188 :               << LogIO::POST;
    1762             : 
    1763             :     // Open it
    1764         188 :     loadMemCalTable(calTableName());
    1765             : 
    1766             :     // Fill solveParArrays
    1767             : 
    1768         188 :     Block<String> sortcols(1);
    1769         188 :     sortcols[0]="SPECTRAL_WINDOW_ID";
    1770         188 :     ROCTIter ctiter(*ct_,sortcols);
    1771        5453 :     while (!ctiter.pastEnd()) {
    1772        5265 :       currSpw()=ctiter.thisSpw();
    1773        5265 :       nChanPar()=ctiter.nchan();
    1774        5265 :       switch(parType()) {
    1775        5265 :       case VisCalEnum::COMPLEX: {
    1776        5265 :         ctiter.cparam(solveAllCPar());
    1777        5265 :         break;
    1778             :       }
    1779           0 :       case VisCalEnum::REAL: {
    1780           0 :         ctiter.fparam(solveAllRPar());
    1781           0 :         break;
    1782             :       }
    1783           0 :       default: {
    1784           0 :         throw(AipsError("Internal SVC::setSpecify(...) error: Got invalid VisCalEnum"));
    1785             :         break;
    1786             :       }
    1787             :       }
    1788        5265 :       ctiter.paramErr(solveAllParErr());
    1789        5265 :       ctiter.snr(solveAllParSNR());
    1790        5265 :       solveAllParOK().assign(!ctiter.flag());
    1791             : 
    1792             :       // Advance iterator
    1793        5265 :       ctiter.next();
    1794             :     }
    1795             : 
    1796             :     // Delete old mem caltable (it will be replaced)
    1797         188 :     if (ct_) delete ct_;
    1798           0 :     else throw(AipsError("SVC::setSpecify: unknown error on caltable delete"));
    1799         188 :     ct_=NULL;
    1800             : 
    1801         188 :   } // tableExists
    1802             :   else {
    1803             : 
    1804          20 :     nChanParList()=Vector<Int>(nSpw(),1);
    1805          20 :     startChanList()=Vector<Int>(nSpw(),0);
    1806             : 
    1807             :     // we are creating a table from scratch
    1808          20 :     logSink() << "Creating " << typeName()
    1809             :               << " table from specified parameters."
    1810          20 :               << LogIO::POST;
    1811             :   
    1812             :     // Size up the solve arrays
    1813          20 :     initSolvePar();
    1814             : 
    1815         212 :     for (Int ispw=0;ispw<nSpw();++ispw) {
    1816         192 :       currSpw()=ispw;
    1817         192 :       refTime()=0.0;
    1818         192 :       currField()=-1;
    1819         192 :       currScan()=-1;
    1820         192 :       currObs()=0;
    1821             : 
    1822         192 :       switch(parType()) {
    1823         175 :       case VisCalEnum::COMPLEX: {
    1824         175 :         solveAllCPar().set(defaultCPar());
    1825         175 :         break;
    1826             :       }
    1827          17 :       case VisCalEnum::REAL: {
    1828          17 :         solveAllRPar().set(defaultRPar());
    1829          17 :         break;
    1830             :       }
    1831           0 :       default: {
    1832           0 :         throw(AipsError("Internal SVC::setAccumulate(...) error: Got invalid VisCalEnum"));
    1833             :       }
    1834             :       }
    1835         192 :       solveAllParOK().set(true);
    1836         192 :       solveAllParSNR().set(1.0);
    1837         192 :       solveAllParErr().set(0.0);
    1838             :       
    1839             :     } // ispw
    1840             :   } // !tableExists
    1841             : 
    1842             :   // Create the caltable
    1843         208 :   createMemCalTable();
    1844             : 
    1845         208 : }
    1846             : 
    1847         214 : void SolvableVisCal::specify(const Record& specify) {
    1848             : 
    1849         428 :   LogMessage message(LogOrigin("SolvableVisCal","specify"));
    1850             : 
    1851         214 :   Vector<Int> spws;
    1852         214 :   Vector<Int> antennas;
    1853         214 :   Vector<Int> pols;
    1854         214 :   Vector<Double> parameters;
    1855             : 
    1856         214 :   Int nUserSpw(1);
    1857         214 :   Int Ntime(1);
    1858         214 :   Int Nant(0);
    1859         214 :   Int Npol(1);
    1860             :   
    1861         214 :   Bool repspw(false);
    1862             :   
    1863         214 :   IPosition ip0(3,0,0,0);
    1864         214 :   IPosition ip1(3,0,0,0);
    1865             : 
    1866         214 :   if (specify.isDefined("caltype")) {
    1867         214 :     String caltype=specify.asString("caltype");
    1868         214 :     logSink() << "Generating '" << caltype << "' corrections." << LogIO::POST;
    1869         214 :     if (upcase(caltype).contains("PH"))
    1870           0 :       apmode()="P";
    1871             :     else
    1872         214 :       apmode()="A";
    1873         214 :   }
    1874             : 
    1875             :  /*
    1876             :   if (specify.isDefined("time")) {
    1877             :     // TBD: the time label
    1878             :     cout << "time = " << specify.asString("time") << endl;
    1879             :     cout << "refTime() = " << refTime() << endl;
    1880             :   }
    1881             :  */
    1882             : /**
    1883             :   if (specify.isDefined("time")) {
    1884             :     // TBD: the time label
    1885             :     //cout << "time = " << specify.asString("time") << endl;
    1886             :     cout << "refTime() = " << refTime() << endl;
    1887             :     currTime()=specify.asDouble("time");
    1888             :   }
    1889             : **/
    1890             : 
    1891         214 :   if (specify.isDefined("spw")) {
    1892             :     // TBD: the spws (in order) identifying the solutions
    1893         214 :     spws=specify.asArrayInt("spw");
    1894         214 :     nUserSpw=spws.nelements();
    1895         214 :     if (nUserSpw<1) {
    1896             :       // None specified, so loop over all, repetitively
    1897             :       //  (We ought to optimize this...)
    1898             :       logSink() << 
    1899             :         "Specified parameter(s) (per antenna and pol) repeated on all spws." 
    1900           0 :                 << LogIO::POST;
    1901           0 :       repspw=true;
    1902           0 :       nUserSpw=nSpw();
    1903           0 :       spws.resize(nUserSpw);
    1904           0 :       indgen(spws);
    1905             :     }
    1906             :   }
    1907             : 
    1908             : 
    1909         214 :   if (specify.isDefined("antenna")) {
    1910             :     // TBD: the antennas (in order) identifying the solutions
    1911         214 :     antennas=specify.asArrayInt("antenna");
    1912             :     //    cout << "antenna indices = " << antennas << endl;
    1913         214 :     Nant=antennas.nelements();
    1914         214 :     if (Nant<1) {
    1915             :       // Use specified values for _all_ antennas implicitly
    1916             :       logSink() << 
    1917             :         "Specified parameter(s) (per spw and pol) repeated on all antennas." 
    1918          20 :                 << LogIO::POST;
    1919          20 :       Nant=1;   // For the antenna loop below
    1920          20 :       ip0(2)=0;
    1921          20 :       ip1(2)=nAnt()-1;
    1922             :     }
    1923             :     else {
    1924             :       // Point to first antenna
    1925         194 :       ip0(2)=antennas(0);
    1926         194 :       ip1(2)=ip0(2);
    1927             :     }
    1928             :   }
    1929         214 :   if (specify.isDefined("pol")) {
    1930             :     // TBD: the pols (in order) identifying the solutions
    1931         214 :     String polstr=specify.asString("pol");
    1932             :     //    cout << "pol = " << polstr << endl;
    1933         214 :     if (polstr=="R" || polstr=="X") 
    1934             :       // Fill in only first pol
    1935          12 :       pols=Vector<Int>(1,0);
    1936         202 :     else if (polstr=="L" || polstr=="Y") 
    1937             :       // Fill in only second pol
    1938          12 :       pols=Vector<Int>(1,1);
    1939         190 :     else if (polstr=="R,L" || polstr=="X,Y") {
    1940             :       // Fill in both pols explicity
    1941           2 :       pols=Vector<Int>(2,0);
    1942           2 :       pols(1)=1;
    1943             :     }
    1944         188 :     else if (polstr=="L,R" || polstr=="Y,X") {
    1945             :       // Fill in both pols explicity
    1946           0 :       pols=Vector<Int>(2,0);
    1947           0 :       pols(0)=1;
    1948             :     }
    1949         188 :     else if (polstr=="")
    1950             :       // Fill in both pols implicitly
    1951         188 :       pols=Vector<Int>();
    1952             :     else
    1953           0 :       throw(AipsError("Invalid pol specification"));
    1954             :     
    1955         214 :     Npol=pols.nelements();
    1956         214 :     if (Npol<1) {
    1957             :       // No pol axis specified
    1958             :       logSink() << 
    1959             :         "Specified parameter(s) (per spw and antenna) repeated on all polarizations." 
    1960         188 :                 << LogIO::POST;
    1961         188 :       Npol=1;
    1962         188 :       ip0(0)=0;
    1963         188 :       ip1(0)=nPar()-1;
    1964             :     }
    1965             :     else {
    1966             :       // Point to the first polarization
    1967          26 :       ip0(0)=pols(0);
    1968          26 :       ip1(0)=ip0(0);
    1969             :     }
    1970         214 :   }
    1971         214 :   if (specify.isDefined("parameter")) {
    1972             :     // TBD: the actual cal values
    1973         214 :     parameters=specify.asArrayDouble("parameter");
    1974             :   }
    1975         214 :   Int nparam=parameters.nelements();
    1976             : 
    1977             :   // Test for correct number of specified parameters
    1978             :   //  Either all params are enumerated, or one is specified
    1979             :   //  for all, [TBD:or a polarization pair is specified for all]
    1980             :   //  else throw
    1981         214 :   if (nparam!=(repspw ? (Ntime*Nant*Npol) : (nUserSpw*Ntime*Nant*Npol)) && 
    1982             :       nparam!=1 )                // one for all
    1983             :     //      (Npol==2 && nparam%2!=0) )  // poln pair for all
    1984           0 :     throw(AipsError("Inconsistent number of parameters specified."));
    1985             : 
    1986             : 
    1987             :   // Fill in user-specifed parameters in order
    1988         214 :   Int ipar(0);
    1989         432 :   for (Int iUspw=0;iUspw<nUserSpw;++iUspw) {
    1990             : 
    1991         218 :     currSpw()=spws(iUspw);
    1992             : 
    1993             :     // reset par index if we are repeating for all spws
    1994         218 :     if (repspw) ipar=0;
    1995             :     
    1996             :     // Loop over specified antennas
    1997         490 :     for (Int iant=0;iant<Nant;++iant) {
    1998         272 :       if (Nant>1)
    1999          60 :         ip1(2)=ip0(2)=antennas(iant);
    2000             :       
    2001             :       // Loop over specified polarizations
    2002         604 :       for (Int ipol=0;ipol<Npol;++ipol) {
    2003         332 :         if (Npol>1)
    2004         120 :           ip1(0)=ip0(0)=pols(ipol);
    2005             :         
    2006             :         // Report details as compactly as possible
    2007         332 :         if (!repspw || iUspw==0)
    2008             :           logSink() << "spwId=" 
    2009         664 :                     << (repspw ? "<all>" : String::toString(currSpw()) )
    2010             :                     << " antId=" 
    2011         664 :                     << (antennas.nelements()>0 ? String::toString(antennas(iant)) : "<all>")
    2012             :                     << " polId=" 
    2013         664 :                     << (pols.nelements()>0 ? String::toString(pols(ipol)) : "<all>")
    2014         664 :                     << " parameter= " << parameters(ipar)
    2015             :                     << "   (ip0,ip1 = " << ip0 << "," << ip1 << ")"
    2016        1328 :                     << LogIO::POST;
    2017             : 
    2018         332 :         switch(parType()) {
    2019         212 :         case VisCalEnum::COMPLEX: {
    2020         212 :           Array<Complex> sl(solveAllCPar()(ip0,ip1));
    2021             :           // Multiply ipar-th parameter onto the selecte slice
    2022         212 :           if (apmode()=="P") {
    2023             :             // Phases have been specified
    2024           0 :             Double phase=parameters(ipar)*C::pi/180.0;
    2025           0 :             sl*=Complex(cos(phase),sin(phase));
    2026             :           }
    2027             :           else
    2028             :             // Assume amplitude
    2029         212 :             sl*=Complex(parameters(ipar));
    2030         212 :           break;
    2031         212 :         }
    2032         120 :         case VisCalEnum::REAL: {
    2033             :           // Add ipar-th parameter onto the selected slice
    2034         120 :           Array<Float> sl(solveAllRPar()(ip0,ip1));
    2035         120 :           sl+=Float(parameters(ipar));
    2036         120 :           break;
    2037         120 :         }
    2038           0 :         default: {
    2039           0 :           throw(AipsError("Internal SVC::setAccumulate(...) error: Got invalid VisCalEnum"));
    2040             :           break;
    2041             :         }
    2042             :         }
    2043             : 
    2044             :         // increment ipar, but be sure not to run off the end
    2045         332 :         ++ipar;
    2046         332 :         ipar = ipar%nparam;
    2047             : 
    2048             : 
    2049             :       } // ipol
    2050             :     } // iant
    2051             : 
    2052             :   } // iUspw
    2053             : 
    2054             : 
    2055             :   // Now write keep _all_ spws
    2056        5672 :   for (Int ispw=0;ispw<nSpw();++ispw) {
    2057             :     // Keep this result
    2058        5458 :     currSpw()=ispw;
    2059        5458 :     keepNCT();
    2060             :   }
    2061             : 
    2062         214 : }
    2063             : 
    2064           7 : Int SolvableVisCal::sizeUpSolve(VisSet& vs, Vector<Int>& nChunkPerSol) {
    2065             : 
    2066             :   // New version that counts solutions (which may overlap in 
    2067             :   //   field and/or ddid) rather than chunks
    2068             : 
    2069           7 :   Bool verby(false);
    2070             : 
    2071             :   // Set Nominal per-spw channelization
    2072           7 :   setSolveChannelization(vs);
    2073             : 
    2074           7 :   sortVisSet(vs, verby);
    2075             :   
    2076             :   // Number of VisIter chunks per spw
    2077           7 :   Vector<Int> nChunkPerSpw(vs.numberSpw(),0);
    2078             : 
    2079           7 :   Vector<Int> nSolPerSpw(vs.numberSpw(),0);
    2080             : 
    2081             :   // Number of VisIter chunks per solution
    2082           7 :   nChunkPerSol.resize(100);
    2083           7 :   nChunkPerSol=0;
    2084             : 
    2085           7 :   VisIter& vi(vs.iter());
    2086             : 
    2087             :   /*
    2088             :   Block< Vector<Int> > g,st,nch,icr,spw;
    2089             :   vi.getChannelSelection(g,st,nch,icr,spw);
    2090             :   for (uInt isel=0;isel<spw.nelements();++isel)
    2091             :     cout << isel << ":" << endl
    2092             :          << " " << "nGrp =" << g[isel]
    2093             :          << " " << "start=" << st[isel]
    2094             :          << " " << "nchan=" << nch[isel]
    2095             :          << " " << "icrem=" << icr[isel]
    2096             :          << " " << "spw  =" << spw[isel]
    2097             :          << endl;
    2098             :   */
    2099             : 
    2100           7 :   VisBuffer vb(vi);
    2101           7 :   vi.originChunks();
    2102           7 :   vi.origin();
    2103             :     
    2104           7 :   Double time0(86400.0*floor(vb.time()(0)/86400.0));
    2105           7 :   Double time1(0.0),time(0.0);
    2106             : 
    2107           7 :   Int thisobs(-1),lastobs(-1);
    2108           7 :   Int thisscan(-1),lastscan(-1);
    2109           7 :   Int thisfld(-1),lastfld(-1);
    2110           7 :   Int thisspw(-1),lastspw(-1);
    2111           7 :   Int chunk(0);
    2112           7 :   Int sol(-1);
    2113           7 :   Double soltime1(-1.0);
    2114         338 :   for (vi.originChunks(); vi.moreChunks(); vi.nextChunk(),chunk++) {
    2115         331 :     vi.origin();
    2116         331 :     time1=vb.time()(0);  // first time in this chunk
    2117         331 :     thisobs=vb.observationId()(0);
    2118         331 :     thisscan=vb.scan()(0);
    2119         331 :     thisfld=vb.fieldId();
    2120         331 :     thisspw=vb.spectralWindow();
    2121             :     
    2122         331 :     nChunkPerSpw(thisspw)++;
    2123             : 
    2124             :     // New chunk means new sol interval, IF....
    2125         662 :     if ( (!combfld() && !combspw()) ||              // not combing fld nor spw, OR
    2126         180 :          ((time1-soltime1)>interval()) ||           // (combing fld and/or spw) and solint exceeded, OR
    2127         170 :          ((time1-soltime1)<0.0) ||                  // a negative time step occurs, OR
    2128         170 :          (!combobs() && (thisobs!=lastobs)) ||      // not combing obs, and new obs encountered OR
    2129         170 :          (!combscan() && (thisscan!=lastscan)) ||   // not combing scans, and new scan encountered OR
    2130         170 :          (!combspw() && (thisspw!=lastspw)) ||      // not combing spws, and new spw encountered  OR
    2131         662 :          (!combfld() && (thisfld!=lastfld)) ||      // not combing fields, and new field encountered OR 
    2132             :          (sol==-1))  {                              // this is the first interval
    2133         161 :       soltime1=time1;
    2134         161 :       sol++;
    2135             : 
    2136             :       // Increment solution count per spw
    2137         161 :       nSolPerSpw(thisspw)++;
    2138             : 
    2139         161 :       if (verby) {
    2140           0 :         cout << "--------------------------------" << endl;
    2141           0 :         cout << "sol = " << sol << endl;
    2142             :       }
    2143             :       // increase size of nChunkPerSol array, if needed
    2144         161 :       if (nChunkPerSol.nelements()<uInt(sol+1))
    2145           0 :         nChunkPerSol.resize(nChunkPerSol.nelements()+100,true);
    2146         161 :       nChunkPerSol(sol)=0;
    2147             :     }
    2148             : 
    2149             :     // Increment chunk-per-sol count for current solution
    2150         331 :     nChunkPerSol(sol)++;
    2151             : 
    2152         331 :     if (verby) {
    2153           0 :       cout << "          ck=" << chunk << " " << soltime1-time0 << endl;
    2154             :       
    2155           0 :       Int iter(0);
    2156           0 :       for (vi.origin(); vi.more();vi++,iter++) {
    2157           0 :         time=vb.time()(0);
    2158           0 :         cout  << "                 " << "vb=" << iter << " ";
    2159           0 :         cout << "ob=" << vb.observationId()(0) << " ";
    2160           0 :         cout << "ar=" << vb.arrayId() << " ";
    2161           0 :         cout << "ob=" << vb.observationId()(0) << " ";
    2162           0 :         cout << "sc=" << vb.scan()(0) << " ";
    2163           0 :         if (!combfld()) cout << "fl=" << vb.fieldId() << " ";
    2164           0 :         if (!combspw()) cout << "sp=" << vb.spectralWindow() << " ";
    2165           0 :         cout << "t=" << floor(time-time0)  << " (" << floor(time-soltime1) << ") ";
    2166           0 :         if (combfld()) cout << "fl=" << vb.fieldId() << " ";
    2167           0 :         if (combspw()) cout << "sp=" << vb.spectralWindow() << " ";
    2168           0 :         cout << endl;
    2169             :       }
    2170             :     }
    2171             :     
    2172         331 :     lastobs=thisobs;
    2173         331 :     lastscan=thisscan;
    2174         331 :     lastfld=thisfld;
    2175         331 :     lastspw=thisspw;
    2176             :     
    2177             :   }
    2178             :   
    2179           7 :   if (verby) {
    2180           0 :     cout << "nSolPerSpw = " << nSolPerSpw << endl;
    2181           0 :     cout << "nChunkPerSpw = " << nChunkPerSpw << " " << sum(nChunkPerSpw) << endl;
    2182           0 :     cout << "nchunk = " << chunk << endl;
    2183             :   }
    2184             : 
    2185           7 :   Int nSol(sol+1);
    2186             :   
    2187           7 :   nChunkPerSol.resize(nSol,true);
    2188             :   
    2189           7 :   spwMap().resize(vs.numberSpw());
    2190           7 :   indgen(spwMap());
    2191          14 :   Vector<Int> spwlist=spwMap()(nChunkPerSpw>0).getCompressedArray();
    2192           7 :   Int spwlab=0;
    2193           7 :   if (combspw()) {
    2194           2 :     while (nChunkPerSpw(spwlab)<1) spwlab++;
    2195           2 :     if (verby) cout << "Obtaining " << nSol << " solutions, labelled as spw=" << spwlab  << endl;
    2196           2 :     spwMap()=-1;  // TBD: needed?
    2197           2 :     spwMap()(nChunkPerSpw>0)=spwlab;
    2198             : 
    2199           2 :     if (verby)
    2200           0 :       cout << "nChanParList = " << nChanParList()(nChunkPerSpw>0).getCompressedArray() 
    2201           0 :            << "==" << nChanParList()(spwlab) <<  endl;
    2202             : 
    2203             :     // Verify that all spws have same number of channels (so they can be combined!)
    2204           2 :     if (!allEQ(nChanParList()(spwMap()>-1).getCompressedArray(),nChanParList()(spwlab)))
    2205           0 :       throw(AipsError("Spws with different selected channelizations cannot be combined."));
    2206             : 
    2207             :     //    nChunkPerSpw = 0;
    2208             :     //    nChunkPerSpw(spwlab)=nSol;
    2209             : 
    2210           2 :     nSolPerSpw=0;
    2211           2 :     nSolPerSpw(spwlab)=nSol;
    2212             : 
    2213             :   }
    2214             : 
    2215           7 :   if (verby) {
    2216           0 :     cout << " spwMap()  = " << spwMap() << endl;
    2217           0 :     cout << " spwlist = " << spwlist << endl;
    2218           0 :     cout << "nSolPerSpw = " << nSolPerSpw << endl;
    2219           0 :     cout << "nChunkPerSpw = " << nChunkPerSpw << " " << sum(nChunkPerSpw) << endl;
    2220           0 :     cout << "Total solutions = " << nSol << endl;
    2221           0 :     cout << "nChunkPerSol = " << nChunkPerSol << endl;
    2222             :   }
    2223             : 
    2224           7 :   if (combobs())
    2225           0 :     logSink() << "Combining observation Ids." << LogIO::POST;
    2226           7 :   if (combscan())
    2227           0 :     logSink() << "Combining scans." << LogIO::POST;
    2228           7 :   if (combspw()) 
    2229           2 :     logSink() << "Combining spws: " << spwlist << " -> " << spwlab << LogIO::POST;
    2230           7 :   if (combfld()) 
    2231           0 :     logSink() << "Combining fields." << LogIO::POST;
    2232             :   
    2233             : 
    2234             :   //if (!isSimulated()) {
    2235           7 :   logSink() << "For solint = " << solint() << ", found "
    2236             :             <<  nSol << " solution intervals."
    2237           7 :             << LogIO::POST;
    2238             :   //}
    2239             : 
    2240             :   // Size the solvePar arrays
    2241           7 :   initSolvePar();
    2242             : 
    2243             :   // Return the total number of solution intervals
    2244           7 :   return nSol;
    2245             : 
    2246           7 : }
    2247             : 
    2248          46 : void SolvableVisCal::sortVisSet(VisSet& vs, const Bool verbose)
    2249             : {
    2250             :   // Interpret solution interval for the VisIter
    2251          46 :   Double iterInterval(max(interval(),DBL_MIN));
    2252          46 :   if (interval() < 0.0) {   // means no interval (infinite solint)
    2253           0 :     iterInterval=0.0;
    2254           0 :     interval()=DBL_MAX;
    2255             :   }
    2256             : 
    2257          46 :   if (verbose) {
    2258           0 :     cout << "   interval() = " << interval() ;
    2259           0 :     cout << boolalpha << "   combobs()  = " << combobs();
    2260           0 :     cout << boolalpha << "   combscan() = " << combscan();
    2261           0 :     cout << boolalpha << "   combfld()  = " << combfld() ;
    2262           0 :     cout << boolalpha << "   combspw()  = " << combspw() ;
    2263             :   }
    2264             : 
    2265          46 :   Int nsortcol(4+(combscan()?0:1)+(combobs()?0:1) );  // include room for scan,obs
    2266          46 :   Block<Int> columns(nsortcol);
    2267          46 :   Int i(0);
    2268          46 :   columns[i++]=MS::ARRAY_ID;
    2269          46 :   if (!combobs()) columns[i++]=MS::OBSERVATION_ID;  // force obsid boundaries
    2270          46 :   if (!combscan()) columns[i++]=MS::SCAN_NUMBER;  // force scan boundaries
    2271          46 :   if (!combfld()) columns[i++]=MS::FIELD_ID;      // force field boundaries
    2272          46 :   if (!combspw()) columns[i++]=MS::DATA_DESC_ID;  // force spw boundaries
    2273          46 :   columns[i++]=MS::TIME;
    2274          46 :   if (combspw() || combfld()) iterInterval=DBL_MIN;  // force per-timestamp chunks
    2275          46 :   if (combfld()) columns[i++]=MS::FIELD_ID;      // effectively ignore field boundaries
    2276          46 :   if (combspw()) columns[i++]=MS::DATA_DESC_ID;  // effectively ignore spw boundaries
    2277             :   
    2278          46 :   if (verbose) {
    2279           0 :     cout << " sort columns: ";
    2280           0 :     for (Int i=0;i<nsortcol;++i) 
    2281           0 :       cout << columns[i] << " ";
    2282           0 :     cout << endl;
    2283             :   }
    2284             : 
    2285             :   // this sets the vi to send chunks by iterInterval (e.g. integration time)
    2286             :   // instead of default which would go until the scan changed
    2287          46 :   vs.resetVisIter(columns,iterInterval);  
    2288          46 : }
    2289             : 
    2290          32 : Int SolvableVisCal::sizeUpSim(VisSet& vs, Vector<Int>& nChunkPerSol, Vector<Double>& solTimes) {
    2291             : 
    2292             :   // New version that counts solutions (which may overlap in 
    2293             :   //   field and/or ddid) rather than chunks
    2294          64 :   LogIO os(LogOrigin("SVC", "sizeUpSim()", WHERE));
    2295             : 
    2296          32 :   if (prtlev()>2) cout << "  SVC::sizeUpSim" << endl;
    2297             :   
    2298          32 :   sortVisSet(vs, prtlev() > 2);
    2299             : 
    2300          32 :   VisIter& vi(vs.iter());
    2301          32 :   vi.originChunks();
    2302          32 :   vi.origin();
    2303          32 :   VisBuffer vb(vi);
    2304             : 
    2305             :   // Number of VisIter chunks per spw
    2306          32 :   Vector<Int> nChunkPerSpw(vs.numberSpw(),0);
    2307             : 
    2308          32 :   Int nSol(1);
    2309             : 
    2310          32 :   if (simOnTheFly()) {
    2311          16 :     nChunkPerSol.resize(1);
    2312          16 :     nChunkPerSol=1;
    2313             : 
    2314          16 :     vi.origin();
    2315          16 :     solTimes.resize(1);
    2316          16 :     solTimes(0)=vb.time()(0);  // first time in this chunk
    2317             : 
    2318             :   } else {
    2319             : 
    2320             : 
    2321             :   // Number of VisIter chunks per solution
    2322          16 :   nChunkPerSol.resize(100);
    2323          16 :   nChunkPerSol=0;
    2324             :     
    2325          16 :   Double time0(86400.0*floor(vb.time()(0)/86400.0));
    2326          16 :   Double time1(0.0),time(0.0);
    2327             : 
    2328          16 :   Int thisscan(-1),lastscan(-1);
    2329          16 :   Int thisfld(-1),lastfld(-1);
    2330          16 :   Int thisspw(-1),lastspw(-1);
    2331          16 :   Int chunk(0);
    2332          16 :   Int sol(-1);
    2333          16 :   Double soltime1(-1.0);
    2334        4548 :   for (vi.originChunks(); vi.moreChunks(); vi.nextChunk(),chunk++) {
    2335        4532 :     vi.origin();
    2336        4532 :     time1=vb.time()(0);  // first time in this chunk
    2337        4532 :     thisscan=vb.scan()(0);
    2338        4532 :     thisfld=vb.fieldId();
    2339        4532 :     thisspw=vb.spectralWindow();
    2340             :     
    2341        4532 :     nChunkPerSpw(thisspw)++;
    2342             : 
    2343             :     // New chunk means new sol interval, IF....
    2344        9064 :     if ( (!combfld() && !combspw()) ||              // not combing fld nor spw, OR
    2345           0 :          ((time1-soltime1)>interval()) ||           // (combing fld and/or spw) and solint exceeded, OR
    2346           0 :          ((time1-soltime1)<0.0) ||                  // a negative time step occurs, OR
    2347           0 :          (!combscan() && (thisscan!=lastscan)) ||   // not combing scans, and new scan encountered OR
    2348           0 :          (!combspw() && (thisspw!=lastspw)) ||      // not combing spws, and new spw encountered  OR
    2349        9064 :          (!combfld() && (thisfld!=lastfld)) ||      // not combing fields, and new field encountered OR 
    2350             :          (sol==-1))  {                              // this is the first interval
    2351        4532 :       soltime1=time1;
    2352        4532 :       sol++;
    2353        4532 :       if (prtlev()>5) {
    2354           0 :         cout << "--------------------------------" << endl;
    2355           0 :         cout << "   sol = " << sol << endl;
    2356             :       }
    2357             :       // increase size of nChunkPerSol array, if needed
    2358        4532 :       if (nChunkPerSol.nelements()<uInt(sol+1))
    2359          40 :         nChunkPerSol.resize(nChunkPerSol.nelements()+100,true);
    2360        4532 :       nChunkPerSol(sol)=0;
    2361             :       // keep the times!
    2362        4532 :       if (solTimes.nelements()<uInt(sol+1))
    2363          56 :         solTimes.resize(solTimes.nelements()+100,true);
    2364        4532 :       solTimes(sol)=soltime1;
    2365             :     }
    2366             : 
    2367             :     // Increment chunk-per-sol count for current solution
    2368        4532 :     nChunkPerSol(sol)++;
    2369             : 
    2370        4532 :     if (prtlev()>5) {
    2371           0 :       cout << "          ck=" << chunk << " " << soltime1-time0 << endl;
    2372             :       
    2373           0 :       Int iter(0);
    2374           0 :       for (vi.origin(); vi.more();vi++,iter++) {
    2375           0 :         time=vb.time()(0);
    2376           0 :         cout  << "                 " << "vb=" << iter << " ";
    2377           0 :         cout << "ar=" << vb.arrayId() << " ";
    2378           0 :         cout << "sc=" << vb.scan()(0) << " ";
    2379           0 :         if (!combfld()) cout << "fl=" << vb.fieldId() << " ";
    2380           0 :         if (!combspw()) cout << "sp=" << vb.spectralWindow() << " ";
    2381           0 :         cout << "t=" << floor(time-time0)  << " (" << floor(time-soltime1) << ") ";
    2382           0 :         if (combfld()) cout << "fl=" << vb.fieldId() << " ";
    2383           0 :         if (combspw()) cout << "sp=" << vb.spectralWindow() << " ";
    2384           0 :         cout << endl;
    2385             :       }
    2386             :     }
    2387             :     
    2388        4532 :     lastscan=thisscan;
    2389        4532 :     lastfld=thisfld;
    2390        4532 :     lastspw=thisspw;
    2391             :     
    2392             :   }
    2393             :   
    2394          16 :   nSol = sol+1;
    2395             : 
    2396          16 :   nChunkPerSol.resize(nSol,true);
    2397          16 :   solTimes.resize(nSol,true);
    2398             : 
    2399          16 :   if (prtlev()>5) {
    2400           0 :     cout << "   solTimes = " << solTimes-solTimes[0] << endl;
    2401           0 :     cout << "   nChunkPerSol = " << nChunkPerSol << " " << sum(nChunkPerSol) << endl;
    2402             :   }
    2403             :   } // if not inTheFly
    2404             : 
    2405             :   // Set Nominal per-spw channelization - this does set chanParList to full
    2406             :   // # chans
    2407          32 :   setSolveChannelization(vs);
    2408          32 :   if (prtlev()>3) cout<<"   freqDepPar="<<freqDepPar()<<endl;
    2409          32 :   if (prtlev()>2) cout<<"   nSpw()="<<nSpw()
    2410           0 :                       <<" nPar()="<<nPar()<<" nChanParList="<<nChanParList()
    2411           0 :                       <<" nElem()="<<nElem()<<" nSol="<<nSol
    2412           0 :                       <<" approx size = "<<(nSpw()*(nChanParList().size())*nElem()*nSol*nPar())
    2413           0 :                       <<"x size(complex)"<<endl;
    2414             :   
    2415          32 :   if (not simOnTheFly()) {
    2416             : 
    2417          16 :     if (ct_) 
    2418           0 :       delete ct_;
    2419             : 
    2420             :     // Make a caltable into which simulated solutions will be deposited
    2421             :     // !freqDepPar controls channelization in SPW subtable  (T == single channel)
    2422          16 :     ct_=new NewCalTable(calTableName()+"_sim_temp",parType(),typeName(),msName(),!freqDepPar());
    2423             : 
    2424             :   }
    2425             : 
    2426             : 
    2427          32 :   spwMap().resize(vs.numberSpw());
    2428          32 :   indgen(spwMap());
    2429          64 :   Vector<Int> spwlist=spwMap()(nChunkPerSpw>0).getCompressedArray();
    2430          32 :   Int spwlab=0;
    2431          32 :   if (combspw()) {
    2432           0 :     while (nChunkPerSpw(spwlab)<1) spwlab++;
    2433           0 :     if (prtlev()>2) cout << "   obtaining " << nSol << " solutions, labelled as spw=" << spwlab  << endl;
    2434           0 :     spwMap()=-1;  // TBD: needed?
    2435           0 :     spwMap()(nChunkPerSpw>0)=spwlab;
    2436             : 
    2437           0 :     if (prtlev()>2)
    2438           0 :       cout << "   nChanParList = " << nChanParList()(nChunkPerSpw>0).getCompressedArray() 
    2439           0 :            << "==" << nChanParList()(spwlab) <<  endl;
    2440             : 
    2441             :     // Verify that all spws have same number of channels (so they can be combined!)
    2442           0 :     if (!allEQ(nChanParList()(spwMap()>-1).getCompressedArray(),nChanParList()(spwlab)))
    2443           0 :       throw(AipsError("Spws with different selected channelizations cannot be combined."));
    2444             : 
    2445           0 :     nChunkPerSpw = 0;
    2446           0 :     nChunkPerSpw(spwlab)=nSol;
    2447             :   }
    2448             : 
    2449          32 :   if (prtlev()>2) {
    2450           0 :     cout << "   spwMap()  = " << spwMap() ;
    2451           0 :     cout << " spwlist = " << spwlist ;
    2452           0 :     cout << " nChunkPerSpw = " << nChunkPerSpw << " " << sum(nChunkPerSpw) << " = " << nSol << endl;
    2453             :     //cout << "Total solutions = " << nSol << endl;
    2454             :   }
    2455          32 :   if (prtlev()>5) 
    2456           0 :     cout << "   nChunkPerSim = " << nChunkPerSol << endl;
    2457             :   
    2458             :   
    2459          32 :   if (combscan())
    2460           0 :     os << "Combining scans." << LogIO::POST;
    2461          32 :   if (combspw()) 
    2462           0 :     os << "Combining spws: " << spwlist << " -> " << spwlab << LogIO::POST;
    2463          32 :   if (combfld()) 
    2464           0 :     os << "Combining fields." << LogIO::POST;
    2465             :   
    2466          32 :   os << "For simint = " << simint() << ", found "
    2467             :      <<  nSol << " solution intervals."
    2468          32 :      << LogIO::POST;
    2469             :   
    2470             :   // Size the solvePar arrays
    2471             :   // Jones' insists on having 1 channel, but mullers have lots.  
    2472             :   // initSolvePar();
    2473             :   // so i have to copy this from initsolvepar and make it all chans
    2474             : 
    2475          64 :   for (Int ispw=0;ispw<nSpw();++ispw) {
    2476             :     
    2477          32 :     currSpw()=ispw;
    2478             : 
    2479          32 :     switch(parType())
    2480             :       {
    2481          32 :       case VisCalEnum::COMPLEX:
    2482             :         {
    2483          32 :           os << LogIO::DEBUG1 << "spw " << currSpw() 
    2484          96 :              << " nPar=" << nPar() << "nChanPar=" << nChanPar() 
    2485          32 :              << " nElem=" << nElem() << LogIO::POST;
    2486             :           
    2487          32 :             solveCPar().resize(nPar(),nChanPar(),nElem());
    2488          32 :            solveParOK().resize(nPar(),nChanPar(),nElem());
    2489          32 :           solveParErr().resize(nPar(),nChanPar(),nElem());
    2490          32 :           solveParSNR().resize(nPar(),nChanPar(),nElem());
    2491             :                   
    2492          32 :           solveCPar()=Complex(1.0);
    2493          32 :           solveParOK()=true;
    2494          32 :           solveParErr()=0.0;
    2495          32 :           solveParSNR()=0.0;
    2496          32 :           break;
    2497             :         }
    2498           0 :       case VisCalEnum::REAL:
    2499             :         {
    2500           0 :             solveRPar().resize(nPar(),nChanPar(),nElem());
    2501           0 :            solveParOK().resize(nPar(),nChanPar(),nElem());
    2502           0 :           solveParErr().resize(nPar(),nChanPar(),nElem());
    2503           0 :           solveParSNR().resize(nPar(),nChanPar(),nElem());
    2504             :           
    2505           0 :           solveRPar()=0.0;
    2506           0 :           solveParOK()=true;
    2507           0 :           solveParErr()=0.0;
    2508           0 :           solveParSNR()=0.0;
    2509           0 :           break;
    2510             :         }
    2511           0 :       case VisCalEnum::COMPLEXREAL:
    2512           0 :          throw(AipsError("Internal error(Calibrater Module): Unsupported parameter type COMPLEXREAL found"));
    2513             :          break;
    2514             :       }
    2515             :   }
    2516             : 
    2517             :   
    2518          32 :   if (not simOnTheFly()) {
    2519             :     os << LogIO::DEBUG1 
    2520             :       //       << "calset shape = " << cs().shape(0) 
    2521          32 :        << " solveCPar shape = " << solveCPar().shape() 
    2522          16 :        << LogIO::POST;
    2523             :   }
    2524             : 
    2525          32 :   if (prtlev()>2) cout << "  ~SVC::sizeUpSim" << endl;
    2526             : 
    2527             :   // Return the total number of solution intervals
    2528          32 :   return nSol;
    2529             : 
    2530          32 : }
    2531             : 
    2532             : //  VI2-related refactorings------------------
    2533             : 
    2534       19605 : void SolvableVisCal::setMeta(Int obs, Int scan, Double time,
    2535             :                              Int spw, const Vector<Double>& freq,
    2536             :                              Int fld) {
    2537             : 
    2538       19605 :   VisCal::setMeta(obs,scan,time,spw,freq,fld);
    2539             : 
    2540       19605 :   refTime()=time;  // current time for solving is _refTime()_
    2541             :   
    2542             :   //  refFreq()=???
    2543             : 
    2544       19605 : }
    2545             : 
    2546             : 
    2547             : // Setup solvePar shape for a spw
    2548       19774 : Int SolvableVisCal::sizeSolveParCurrSpw(Int nVisChan) {
    2549             : 
    2550             :   // Sizes the solvePar arrays for the currSpw()
    2551             :   
    2552       19774 :   if (prtlev()>3) cout << " SVJ::sizeSolveParCurrSpw()" << endl;
    2553             : 
    2554             :   // Use nVisChan only for freqDepPar() types
    2555       19774 :   Int nChan = ( freqDepPar() ? nVisChan : 1);
    2556             : 
    2557             :   // Keep old way informed (needed?)
    2558       19774 :   nChanPar()=nChan;
    2559             : 
    2560             :   // Now, size the arrays:
    2561             : 
    2562       19774 :   IPosition parsh(3,nPar(),nChan,nElem());  // multi-chan
    2563       19774 :   IPosition parsh1(3,nPar(),1,nElem());     // single-chan
    2564       19774 :   switch (parType()) {
    2565       19517 :   case VisCalEnum::COMPLEX: {
    2566       19517 :     solveAllCPar().resize(parsh);
    2567       19517 :     solveAllCPar()=Complex(1.0);
    2568       19517 :     if (nChan==1)
    2569       19357 :       solveCPar().reference(solveAllCPar());
    2570             :     else {
    2571         160 :       solveCPar().resize(parsh1);
    2572         160 :       solveCPar()=Complex(1.0);
    2573             :     }
    2574       19517 :     break;
    2575             :   }
    2576         257 :   case VisCalEnum::REAL: {
    2577         257 :     solveAllRPar().resize(parsh);
    2578         257 :     solveAllRPar()=0.0;
    2579         257 :     if (nChanPar()==1)
    2580         235 :       solveRPar().reference(solveAllRPar());
    2581             :     else {
    2582          22 :       solveRPar().resize(parsh1);
    2583          22 :       solveRPar()=0.0;
    2584             :     }
    2585         257 :     break;
    2586             :   }
    2587           0 :   default:
    2588           0 :     throw(AipsError("Internal error(Calibrater Module): Unsupported parameter type "
    2589           0 :                     "COMPLEXREAL found in SVC::sizeSolveParCurrSpw"));
    2590             :   }
    2591             :     
    2592       19774 :   solveAllParOK().resize(parsh);
    2593       19774 :   solveAllParErr().resize(parsh);
    2594       19774 :   solveAllParSNR().resize(parsh);
    2595       19774 :   solveAllParOK()=True;
    2596       19774 :   solveAllParErr()=0.0;
    2597       19774 :   solveAllParSNR()=0.0;
    2598       19774 :   if (nChan==1) {
    2599       19592 :       solveParOK().reference(solveAllParOK());
    2600       19592 :       solveParErr().reference(solveAllParErr());
    2601       19592 :       solveParSNR().reference(solveAllParSNR());
    2602             :   }
    2603             :   else {
    2604             :     // solving many channels, one at a time
    2605         182 :     solveParOK().resize(parsh1);
    2606         182 :     solveParErr().resize(parsh1);
    2607         182 :     solveParSNR().resize(parsh1);
    2608         182 :     solveParOK()=True;
    2609         182 :     solveParErr()=0.0;
    2610         182 :     solveParSNR()=0.0;
    2611             :   }
    2612             : 
    2613             :   // return the realized nChan
    2614       19774 :   return nChan;
    2615             : 
    2616       19774 : }
    2617             : 
    2618           0 : void SolvableVisCal::setDefSolveParCurrSpw(Bool sync) {
    2619             : 
    2620             :   // TBD: generalize for type-dep def values, etc.
    2621             : 
    2622           0 :   switch (parType()) {
    2623           0 :   case VisCalEnum::COMPLEX: {
    2624           0 :     AlwaysAssert(solveCPar().nelements()>0,AipsError);
    2625           0 :     solveCPar().set(1.0);  //  def=1+0j
    2626           0 :     break;
    2627             :   }
    2628           0 :   case VisCalEnum::REAL: {
    2629           0 :     AlwaysAssert(solveRPar().nelements()>0,AipsError);
    2630           0 :     solveRPar().set(0.0);  //  def=0
    2631           0 :     break;
    2632             :   }
    2633           0 :   default:
    2634           0 :     throw(AipsError("Internal error(Calibrater Module): Unsupported parameter type "
    2635           0 :                     "COMPLEXREAL found in SVC::setDefSolveParCurrSpw"));
    2636             :   }
    2637           0 :   solveParOK().set(True);
    2638             : 
    2639           0 :   if (sync)
    2640           0 :     syncSolveCal();
    2641             : 
    2642           0 : }
    2643             : 
    2644             : // Parse solint in VI2 context
    2645         168 : void SolvableVisCal::reParseSolintForVI2() {
    2646             : 
    2647             :   // Internal default solint 
    2648         168 :   solint()="inf";
    2649         168 :   fsolint()="none";
    2650         168 :   if (usolint_.contains(',')) {
    2651             :     // both time and freq solint specified
    2652           3 :     solint()=usolint_.before(',');
    2653           3 :     fsolint()=usolint_.after(',');
    2654             :   }
    2655             :   else
    2656             :     // interpret as only time-dep solint
    2657         165 :     solint()=usolint_;
    2658             : 
    2659             :   // solint is always "int" for single dish calibration
    2660         168 :   if (longTypeName().startsWith("SDGAIN_OTFD")) {
    2661             :     //return;
    2662           9 :     solint() = "int";
    2663             :   }
    2664             : 
    2665             :   // Handle solint format
    2666         168 :   if (upcase(solint()).contains("INF") || solint()=="") {
    2667         149 :     solint()="inf";
    2668         149 :     solTimeInterval_=DBL_MAX;
    2669             :   }
    2670          19 :   else if (upcase(solint()).contains("INT"))
    2671          12 :     solTimeInterval_=FLT_MIN;  // implausibly small; forces chunk boundaries at integrations
    2672             :   else {
    2673           7 :     QuantumHolder qhsolint;
    2674           7 :     String error;
    2675           7 :     Quantity qsolint;
    2676           7 :     qhsolint.fromString(error,solint());
    2677           7 :     if (error.length()!=0)
    2678           0 :       throw(AipsError("Unrecognized units for time-dep solint."));
    2679           7 :     qsolint=qhsolint.asQuantumDouble();
    2680             :     
    2681           7 :     if (qsolint.isConform("s"))
    2682           5 :       solTimeInterval_=qsolint.get("s").getValue();
    2683             :     else {
    2684           2 :       if (qsolint.getUnit().length()==0) {
    2685             :         // when no units specified, assume seconds
    2686           2 :         solTimeInterval_=qsolint.getValue();
    2687           2 :         solint()=solint()+"s";
    2688             :       }
    2689             :       else
    2690             :         // unrecognized units:
    2691           0 :         throw(AipsError("Unrecognized units for solint (e.g., use 'min', not 'm', for minutes)"));
    2692             :     }
    2693           7 :   }
    2694             : 
    2695             :   //  cout << "******* VI2: Review fsolint parsing..." << endl;
    2696             : 
    2697             :   // Maybe should just parse it, and then work out logic re freqDepPar, etc.
    2698             : 
    2699             :   // Handle fsolint format
    2700             :   // TBD:  compare to logic in Calibrater::genericGatherAndSolve (line ~2298)
    2701         171 :   if (upcase(fsolint()).contains("NONE") ||   // unspecified  OR  
    2702           3 :       !freqDepMat()) {                        // cal is entirely unchannelizedb 
    2703         165 :     fsolint()="none";
    2704         165 :     fintervalCh_.set(-1.0);    // signals full averaging (this is different from old way)
    2705         165 :     fintervalHz_=-1.0;      // don't care
    2706             :   }
    2707             :   else {
    2708             :     // something specified OR freqDepMat
    2709             :     //   if pars are freq-dep, specification indicates desired soln resolution
    2710           3 :     if (freqDepPar()) {
    2711             :       // Try to parse it
    2712           3 :       if (upcase(fsolint()).contains("CH")) {
    2713           3 :         String fsolintstr=upcase(fsolint());
    2714           3 :         fintervalCh_.set(String::toDouble(upcase(fsolint()).before("CH")));
    2715           3 :         fintervalHz_=-1.0;  // Don't know in Hz, and don't really care
    2716           3 :         fsolint()=downcase(fsolint());
    2717           3 :       }
    2718             :       else {
    2719           0 :         QuantumHolder qhFsolint;
    2720           0 :         String error;
    2721           0 :         qhFsolint.fromString(error,fsolint());
    2722           0 :         if (error.length()!=0)
    2723           0 :           throw(AipsError("Unrecognized units for freq-dep solint."));
    2724           0 :         Quantity qFsolint;
    2725           0 :         qFsolint=qhFsolint.asQuantumDouble();
    2726             :         
    2727           0 :         if (qFsolint.isConform("Hz")) {
    2728           0 :           fintervalHz_=qFsolint.get("Hz").getValue();
    2729           0 :           convertHzToCh();
    2730             :         }
    2731             :         else {
    2732           0 :           if (qFsolint.getUnit().length()==0) {
    2733             :             // when no units specified, assume channel
    2734           0 :             fintervalCh_.set(qFsolint.getValue());
    2735           0 :             fsolint()=fsolint()+"ch";
    2736             :           }
    2737             :           else
    2738             :             // unrecognized units:
    2739           0 :             throw(AipsError("Unrecognized units for freq-dep solint"));
    2740             :         } // Hz vs. Ch via Quantum
    2741           0 :       } // parse by Quantum
    2742             :     } // freqDepPar
    2743             :   } // user set something
    2744             :   /*
    2745             :   cout << "Freq-dep solint: " << fsolint() 
    2746             :        << " Ch=" << fintervalCh_ 
    2747             :        << " Hz=" << fintervalHz() 
    2748             :        << endl;
    2749             :   //*/
    2750             : 
    2751         168 : }
    2752             : 
    2753             : 
    2754             : // Generate the in-memory caltable (empty)
    2755             : //  NB: no subtable revisions
    2756         165 : void SolvableVisCal::createMemCalTable2() {
    2757             : 
    2758             :   //  cout << "createMemCalTable" << endl;
    2759             : 
    2760             :   // Set up description
    2761         165 :   String partype = ((parType()==VisCalEnum::COMPLEX) ? "Complex" : "Float");
    2762         330 :   CTDesc caltabdesc(partype,Path(msName()).baseName(),typeName(),"unknown");
    2763         165 :   ct_ = new NewCalTable("tempNCT.tab",caltabdesc,Table::Scratch,Table::Memory);
    2764             : 
    2765         165 :   if (msmc().msOk())
    2766         165 :     ct_->setMetaInfo(msName());
    2767             :   else {
    2768           0 :     ct_->fillGenericObs(1);
    2769           0 :     ct_->fillGenericField(msmc().nFld());
    2770           0 :     ct_->fillGenericAntenna(msmc().nAnt());
    2771           0 :     Vector<Int> nchan(msmc().nSpw(),1);
    2772           0 :     ct_->fillGenericSpw(msmc().nSpw(),nchan);
    2773           0 :   }
    2774             : 
    2775             :   // Flag all SPW subtable rows; we'll set them OTF
    2776         165 :   CTColumns ncc(*ct_);
    2777             : 
    2778             :   // Set FLAG_ROW in SPW subtable
    2779         165 :   Vector<Bool> flr=ncc.spectralWindow().flagRow().getColumn();
    2780         165 :   flr.set(True);
    2781         165 :   ncc.spectralWindow().flagRow().putColumn(flr);
    2782             : 
    2783             :   // Collapse channel axis info in all rows for unchan'd 
    2784             :   //  calibration, so columns are "clean" (uniform shape)
    2785             :   // NB: some of this info will be revised during data iteration
    2786         165 :   CTSpWindowColumns& spwcol(ncc.spectralWindow());
    2787         165 :   if (!freqDepPar()) {
    2788         118 :     Int nspw=ncc.spectralWindow().nrow();
    2789         521 :     for (Int ispw=0;ispw<nspw;++ispw) {
    2790         403 :       Vector<Double> chfr,chwid,chres,cheff;
    2791             : 
    2792         403 :       spwcol.chanFreq().get(ispw,chfr);
    2793         403 :       spwcol.chanWidth().get(ispw,chwid);
    2794         403 :       spwcol.resolution().get(ispw,chres);
    2795         403 :       spwcol.effectiveBW().get(ispw,cheff);
    2796             : 
    2797         403 :       spwcol.chanFreq().put(ispw,Vector<Double>(1,mean(chfr)));
    2798         403 :       spwcol.chanWidth().put(ispw,Vector<Double>(1,sum(chwid)));
    2799         403 :       spwcol.resolution().put(ispw,Vector<Double>(1,sum(chres)));
    2800         403 :       spwcol.effectiveBW().put(ispw,Vector<Double>(1,sum(cheff)));
    2801         403 :     }
    2802             :     
    2803             :     // One channel per spw
    2804         118 :     spwcol.numChan().putColumn(Vector<Int>(nspw,1));
    2805             :   }
    2806             : 
    2807         165 : }
    2808             : 
    2809           0 : void SolvableVisCal::setOrVerifyCTFrequencies(Int spw) {
    2810             : 
    2811             :   //  cout << "SVC::setOrVerifyCTFrequencies......." << endl;
    2812             : 
    2813             : 
    2814             :   // Assumes currFreq() is set properly (see syncSolveMeta)
    2815             : 
    2816             :   // Access SPW subtable columns
    2817           0 :   CTColumns ctcol(*ct_);
    2818           0 :   CTSpWindowColumns& spwcol(ctcol.spectralWindow());
    2819             : 
    2820             :   // If row is flagged, then it hasn't been set yet...
    2821           0 :   Bool needToSet(spwcol.flagRow().get(spw));
    2822             : 
    2823             :   // How many solution channels?
    2824           0 :   Int nChan=currFreq().nelements();
    2825             : 
    2826           0 :   Vector<Double> currFreqHz;
    2827           0 :   currFreqHz.assign(currFreq());  // currFreq is in GHz!!
    2828           0 :   currFreqHz*=1e9;                // currFreqHz is in Hz
    2829             : 
    2830           0 :   if (needToSet) {
    2831             : 
    2832             :     //cout << "Setting freqs in spw=" << spw << endl;
    2833             :     
    2834             :     // Existing values (from the _unaveraged_ MS)
    2835           0 :     Vector<Double> chfr,chwid,chres,cheff;
    2836             :     Double totbw;
    2837           0 :     spwcol.chanFreq().get(spw,chfr);
    2838           0 :     spwcol.chanWidth().get(spw,chwid);
    2839           0 :     spwcol.resolution().get(spw,chres);
    2840           0 :     spwcol.effectiveBW().get(spw,cheff);
    2841           0 :     totbw=spwcol.totalBandwidth().get(spw);
    2842             : 
    2843             :     // Setup freq info for caltable accordingly
    2844           0 :     if (nChan>1) {
    2845             :       // Incoming data is channelized...
    2846           0 :       Double df=currFreqHz(1)-currFreqHz(0); // apparent width
    2847           0 :       totbw=(currFreqHz(nChan-1)-currFreqHz(0))+df;  // total span (ignoring gaps!)
    2848           0 :       if (freqDepPar()) {
    2849             :         // solution is channelized
    2850             :         
    2851             :         // Assumes uniform width
    2852             :         // TBD: do better job here for quirky non-gridded cases!
    2853           0 :         chfr.resize(nChan); chfr.assign(currFreqHz);
    2854           0 :         chwid.resize(nChan); chwid.set(df);
    2855           0 :         chres.resize(nChan); chres.set(df);
    2856           0 :         cheff.resize(nChan); cheff.set(df);
    2857             :       }
    2858             :       else {
    2859             :         // Data channelized, but solution is not  (e.g., delays)
    2860           0 :         chfr.resize(1); chfr.set(mean(currFreqHz));  // The ~centroid freq
    2861           0 :         chwid.resize(1); chwid.set(totbw);
    2862           0 :         chres.resize(1); chres.set(totbw);
    2863           0 :         cheff.resize(1); cheff.set(totbw);
    2864             :       }
    2865             :     }
    2866             :     else {
    2867             :       // Incoming data has only one channel
    2868             : 
    2869             :       // Assume full collapse of existing freq axis
    2870             :       // NB: Using UN-SELECTED MS total bandwidth here!!
    2871             :       // TBD:  this is wrong for partially selected channels....
    2872           0 :       AlwaysAssert(currFreqHz.nelements()==1,AipsError);
    2873           0 :       chfr.resize(1);   chfr.assign(currFreqHz);
    2874           0 :       chwid.resize(1);  chwid.set(totbw);
    2875           0 :       chres.resize(1);  chres.set(totbw);
    2876           0 :       cheff.resize(1);  cheff.set(totbw);
    2877             :     }
    2878             : 
    2879             :     // Export revised values to the table
    2880           0 :     spwcol.chanFreq().put(spw,chfr);
    2881           0 :     spwcol.chanWidth().put(spw,chwid);
    2882           0 :     spwcol.resolution().put(spw,chres);
    2883           0 :     spwcol.effectiveBW().put(spw,cheff);
    2884           0 :     spwcol.numChan().put(spw,(freqDepPar()?nChan:1)); // handles unchan'd par case
    2885           0 :     spwcol.totalBandwidth().put(spw,totbw);
    2886           0 :     spwcol.flagRow().put(spw,False);
    2887             : 
    2888           0 :   }
    2889             :   else {
    2890             :     // Only verify that freqs haven't changed
    2891             : 
    2892             :     //cout << "Verifying freqs in spw=" << spw << endl;
    2893             : 
    2894           0 :     Vector<Double> currCTFreq;
    2895           0 :     spwcol.chanFreq().get(spw,currCTFreq);
    2896             : 
    2897             : 
    2898           0 :     if (!freqDepPar()) {
    2899           0 :       Double currFreqHz1=mean(currFreqHz);
    2900           0 :       currFreqHz.resize(1);
    2901           0 :       currFreqHz.set(currFreqHz1);
    2902             :     }
    2903             : 
    2904           0 :     Vector<Float> fcurrCTFreq(currCTFreq.size());
    2905           0 :     for (size_t i=0; i!=currCTFreq.size(); i++) {
    2906           0 :         fcurrCTFreq[i] = float(currCTFreq[i]);
    2907             :     }
    2908           0 :     Vector<Float> fcurrFreqHz(currFreqHz.size());
    2909           0 :     for (size_t i=0; i!=currCTFreq.size(); i++) {
    2910           0 :         fcurrFreqHz[i] = float(currFreqHz[i]);
    2911             :     }
    2912             : 
    2913             :     // cout << "Diff (currFreqHz) = " << (currFreqHz - fcurrFreqHz) << endl;
    2914             :     // cout << "Diff (currCTFreq) = " << (currCTFreq - fcurrCTFreq) << endl;
    2915             :     // cout << "currFreqHz  = " << currFreqHz << endl;
    2916             :     // cout << "fcurrFreqHz  = " << fcurrFreqHz << endl;
    2917             :     // cout << "currCTFreq  = " << currCTFreq << endl;
    2918             :     // cout << "fcurrCTFreq  = " << fcurrCTFreq << endl;
    2919             : 
    2920             :     
    2921             :     //    if (!allEQ(float(currCTFreq),float(currFreqHz))) {
    2922           0 :     if (!allEQ(fcurrCTFreq,fcurrFreqHz)) {
    2923           0 :       cout << "For spw=" << spw << ":" << endl;
    2924           0 :       cout << "Current CalTable nchan= " << currCTFreq.nelements() << endl;
    2925           0 :       cout << "Current CalTable freq = " << currCTFreq << endl;
    2926           0 :       cout << "Current Solution nchan= " << (freqDepPar() ? nChan : 1) << endl;
    2927           0 :       cout << "Current Solution freq = " << currFreqHz << endl;
    2928           0 :       cout << "Diff = " << currFreqHz-currCTFreq << endl;
    2929             : 
    2930             :       
    2931           0 :       throw(AipsError("Mismatch between Solution frequencies and existing CalTable frequencies for spw="+String::toString(spw)));
    2932             :     }
    2933           0 :   }
    2934           0 : }
    2935             : 
    2936       19570 : void SolvableVisCal::setCTFrequencies(Int spw) {
    2937             : 
    2938             :   //  cout << "SVC::setCTFrequencies......." << endl;
    2939             : 
    2940             : 
    2941             :   // Discern spw to which to write
    2942       19570 :   Int outspw=spw;
    2943             :   // If combining spws, freqMetaData_ knows the fan-in
    2944       19570 :   if (combspw())
    2945          39 :     outspw=freqMetaData_.fannedInSpw(spw);
    2946             : 
    2947             :   // Access SPW subtable columns
    2948       19570 :   CTColumns ctcol(*ct_);
    2949       19570 :   CTSpWindowColumns& spwcol(ctcol.spectralWindow());
    2950             : 
    2951             :   // If row is flagged, then it hasn't been set yet (in this execution or any prior)
    2952       19570 :   Bool needToSet(spwcol.flagRow().get(outspw));
    2953             : 
    2954             : 
    2955             :   //  cout << "needToSet = " << boolalpha << needToSet << endl;
    2956             : 
    2957             : 
    2958       19570 :   if (needToSet) {
    2959             : 
    2960             :     //cout << "Setting freqs for spw=" << outspw << endl;
    2961             : 
    2962             :     // const references to freq info from freqMetaData_
    2963         441 :     const Vector<Double>& chfr(freqMetaData_.freq(outspw));
    2964         441 :     const Vector<Double>& chwid(freqMetaData_.width(outspw));
    2965         441 :     const Vector<Double>& cheff(freqMetaData_.effBW(outspw));
    2966             : 
    2967             :     // Derived info
    2968         441 :     const Vector<Double>& chres(chfr);   // resolution same as freq
    2969         441 :     Int numChan=chfr.nelements();
    2970         441 :     Double totbw=sum(chfr);
    2971             : 
    2972             :     // TBD: add some sanity checks, e.g., numChan==1 if !freqDepPar, etc.
    2973             : 
    2974             :     // Set freq info in the table
    2975         441 :     spwcol.chanFreq().put(outspw,chfr);
    2976         441 :     spwcol.chanWidth().put(outspw,chwid);
    2977         441 :     spwcol.resolution().put(outspw,chres);
    2978         441 :     spwcol.effectiveBW().put(outspw,cheff);
    2979         441 :     spwcol.numChan().put(outspw,numChan);
    2980         441 :     spwcol.totalBandwidth().put(outspw,totbw);
    2981         441 :     spwcol.flagRow().put(outspw,False);
    2982             : 
    2983             : 
    2984             :   }
    2985             :   else {
    2986             : 
    2987             :     // outspw already set (not yet written to disk, unless (possibly) append=True; checked elsewhere)
    2988             :     //  Verify that info matches...  this shouldn't be necessary, in general,
    2989             :     //  as discernAndSetSolutionFrequencies sets the rigorously....
    2990             :     // TBD: test against _apparent_ frequencies in this soluton interval, e.g.,
    2991             :     //   are available spws consistent....  (and merely warn)
    2992             : 
    2993             :     //cout << "Verifying freqs for spw=" << outspw << endl;
    2994             : 
    2995             :     // Existing freqs in table...
    2996       19129 :     Vector<Double> currCTFreq;
    2997       19129 :     spwcol.chanFreq().get(outspw,currCTFreq);
    2998             :     Int numChan;
    2999       19129 :     spwcol.numChan().get(outspw,numChan);
    3000             : 
    3001             :     // Current solution freqs
    3002       19129 :     const Vector<Double>& chfr(freqMetaData_.freq(outspw));
    3003       19129 :     const Int numChanOut(chfr.nelements());
    3004             : 
    3005             :     // If values mismatch, we need to abort
    3006       19129 :     if (numChan!=numChanOut || !allEQ(currCTFreq,chfr)) {
    3007           0 :       cout << "For spw=" << outspw << ":" << endl;
    3008           0 :       cout << "Current CalTable nchan= " << numChan << endl;
    3009           0 :       cout << "Current CalTable freq = " << currCTFreq << endl;
    3010           0 :       cout << "Current Solution nchan= " << numChan << endl;
    3011           0 :       cout << "Current Solution freq = " << chfr << endl;
    3012           0 :       cout << "Diff = " << chfr-currCTFreq << endl;
    3013             :       
    3014           0 :       throw(AipsError("Mismatch between Solution frequencies and existing CalTable frequencies for spw="+String::toString(spw)));
    3015             :     }
    3016             : 
    3017       19129 :   } // !needToSet
    3018             : 
    3019       19570 : }
    3020             : 
    3021             : // Discern detailed frequency meta info for solutions (solve context)
    3022         168 : void SolvableVisCal::discernAndSetSolnFrequencies(const vi::VisibilityIterator2& vi, const Vector<uInt>& selspws) {
    3023             : 
    3024             :   //  cout << endl << "SVC::discernAndSetSolnFrequencies---------------------------" << endl;
    3025             : 
    3026             :   // TBD:  When aggregating, we should verify that all frames are consistent
    3027         168 :   Vector<Int> frames(vi.spectralWindowSubtablecols().measFreqRef().getColumn());
    3028             :   //cout << "vi.spectralWindowSubtablecols().measFreqRef() = " << frames << endl;
    3029             : 
    3030             :   // Gather MS freq info
    3031         336 :   Vector< Vector<Double> > MSfreq(nSpw(),Vector<Double>()), MSwidth(nSpw(),Vector<Double>());
    3032         649 :   for (uInt i=0;i<selspws.nelements();++i) {
    3033         481 :     uInt ispw=selspws(i);
    3034             : 
    3035         481 :     MSfreq(ispw).assign(vi.getImpl()->getFrequencies(-1.0e0,frames(ispw),ispw,0));
    3036         481 :     MSwidth(ispw).assign(vi.getImpl()->getChanWidths(-1.0e0,frames(ispw),ispw,0));
    3037             : 
    3038             :     //    cout << "Spw=" << ispw << ":" << endl 
    3039             :     //   << " MSfreq=" << MSfreq(ispw) << endl
    3040             :     //   << " MSwidth=" << MSwidth(ispw) << endl;
    3041             :   }
    3042             : 
    3043             :   // Nominally empty spwFanIn...
    3044         168 :   Vector<Int> spwFanIn;
    3045             : 
    3046             :   // Work out spwFanIn from selecte spws, if we are combining spws...
    3047         168 :   if (combspw()) {
    3048             : 
    3049             :     // We're combining, so set up the "spwmap" for spw fan-in
    3050          13 :     spwFanIn.resize(nSpw());
    3051          13 :     spwFanIn.set(-1);  // -1 means not included
    3052             : 
    3053             :     // Use the MINIMUM spwid from selection for the aggregate
    3054          13 :     Int aggSpw=min(selspws);
    3055          54 :     for (uInt iselspw=0;iselspw<selspws.nelements();++iselspw) 
    3056          41 :       spwFanIn(selspws(iselspw))=aggSpw;
    3057             : 
    3058             :   }
    3059             : 
    3060             :   // Now delegate the freq meta calculation to the FreqMetaData object
    3061         168 :   freqMetaData_.calcFreqMeta(MSfreq,MSwidth,selspws,freqDepPar(),combspw(),spwFanIn);
    3062             : 
    3063             : 
    3064             :   // If appending, check current/pending freq meta data againt existing info on disk
    3065         168 :   if (append()) {
    3066           8 :     const CTSpectralWindow ctspw(calTableName()+"/SPECTRAL_WINDOW");
    3067           8 :     const CTSpWindowColumns& spwcol(ctspw);
    3068             : 
    3069             :     // Which spws are we procssing now?
    3070           8 :     Vector<Int> validfMDspws(freqMetaData_.validSpws());
    3071             : 
    3072             :     // If current spws already in disk table, freq meta must match!
    3073          22 :     for (uInt i=0;i<validfMDspws.nelements();++i) {
    3074          17 :       const Int& ispw(validfMDspws(i));
    3075             : 
    3076             :       // If disk table already has this spw set (not flagged), we need to check for a match
    3077          17 :       if (!spwcol.flagRow().get(ispw)) {
    3078             :         
    3079             :         // disk table info
    3080          15 :         const uInt numChan(spwcol.numChan().get(ispw));
    3081          15 :         const Vector<Double> currCTFreq(spwcol.chanFreq().get(ispw));
    3082             : 
    3083             :         // current pending freq info
    3084          15 :         const Vector<Double>& fMDfreq(freqMetaData_.freq(ispw));
    3085             : 
    3086             :         // TBD: check other freq meta info (width, resoln, effBW)?
    3087             : 
    3088             :         // Insist nchan and freq(s) match!
    3089          15 :         if (numChan!=fMDfreq.nelements() || !allEQ(currCTFreq,fMDfreq))
    3090           6 :           throw(AipsError("Mismatch with frequency meta-data in append to "+
    3091           9 :                           calTableName()+" detected in spw="+String::toString(ispw)+". Check spw selection."));
    3092             : 
    3093          15 :       } // !flagged in disk table
    3094             : 
    3095             :     } // validfMDspws(i}
    3096             : 
    3097          14 :   } // append?
    3098             : 
    3099             : 
    3100             : 
    3101             :   // TBD: Add more log info, probably inside FreqMetaData...
    3102             : 
    3103         177 : }
    3104             : 
    3105             : 
    3106             : 
    3107             : //  VI2------------------------^
    3108             : 
    3109             : 
    3110             : 
    3111             : // The inflate methods will soon deprecate (gmoellen, 20121212)
    3112             : //   (the are assumed to exist only by LJJones and EPJones, which
    3113             : //    are not yet NewCalTable-compliant)
    3114             : 
    3115             : // Inflate the internal CalSet according to VisSet info
    3116           0 : void SolvableVisCal::inflate(VisSet& vs, const Bool& /* fillMeta */) {
    3117             : 
    3118           0 :   if (prtlev()>3) cout << " SVC::inflate(vs)" << endl;
    3119             : 
    3120             :   // This method sets up various shape parameters
    3121             :   //  according to the current VisSet.  It is necessary
    3122             :   //  to run this after Calibrater::setdata and before
    3123             :   //  the main part of the solve.  (In case the setdata
    3124             :   //  was run after the setsolve.)  This method calls
    3125             :   //  a generic version to interpret the data shapes
    3126             :   //  in the proper context-dependent way and size
    3127             :   //  the CalSet.
    3128             : 
    3129             :   //  TBD: Move this slot counting exercise out to Calibrater?
    3130             :   //   --> Not clear we should do this...
    3131             : 
    3132             :   //  TBD: How do we generalize this to create bracketing
    3133             :   //   slots at scan start/stop (for accumulation context)?
    3134             : 
    3135             :   // Count slots in the VisIter
    3136           0 :   Vector<Int> nSlot(nSpw(),0);
    3137             :   {
    3138           0 :     VisIter& vi(vs.iter());
    3139           0 :     for (vi.originChunks(); vi.moreChunks(); vi.nextChunk())
    3140           0 :       nSlot(vi.spectralWindow())++;
    3141           0 :     vi.originChunks();
    3142             : 
    3143           0 :     logSink() << "For interval of "<<interval()<<" seconds, found "
    3144             :               <<  sum(nSlot)<<" slots"
    3145           0 :               << LogIO::POST;
    3146             :   }
    3147             : 
    3148             :   // Call generic version to actually inflate the CalSet
    3149             :   //  (assumes nChanParList()/startChanList() already valid!)
    3150           0 :   inflate(nChanParList(),startChanList(),nSlot);
    3151             : 
    3152           0 : }
    3153             : 
    3154             : 
    3155             : // Inflate the internal CalSet generically
    3156           0 : void SolvableVisCal::inflate(const Vector<Int>& /*nChan*/,
    3157             :                              const Vector<Int>& /*startChan*/,
    3158             :                              const Vector<Int>& /*nSlot*/) {
    3159             : 
    3160           0 :   if (prtlev()>3) cout << "  SVC::inflate(,,)" << endl;
    3161             : 
    3162           0 :   throw(AipsError("Attempt to use deprecated SVC::inflate method."));
    3163             : 
    3164             : }
    3165             : 
    3166          32 : void SolvableVisCal::setSolveChannelization(VisSet& vs) {
    3167             : 
    3168             :   //  TBD: include anticipated decimation when partial freq ave supported?
    3169             :   //      (NB: note difference between chan-ave on selection [VisSet] and
    3170             :   //       chan-ave on-the-fly with vb.freqAve())
    3171             : 
    3172             : 
    3173          32 :   Vector<Int> nDatChan(vs.numberChan());
    3174          32 :   Vector<Int> startDatChan(vs.startChan());
    3175             : 
    3176             :   // Figure out channel axis shapes (solve context!):
    3177             : 
    3178             :   // If multi-channel pars, this is a frequency-sampled calibration (e.g., B)
    3179          32 :   if (freqDepPar()) {
    3180             :     // Overall par shape follows data shape
    3181          26 :     nChanParList() = nDatChan;
    3182          26 :     startChanList() = startDatChan;
    3183             : 
    3184             :     // Handle partial freq average
    3185          26 :     if (fsolint()!="none" && (allGT(fintervalCh_,0.0)||fintervalHz_>0.0))
    3186           0 :       setFracChanAve();
    3187             :     
    3188             :     // However, for solving, we will only consider one channel at a time:
    3189          26 :     nChanMatList() = 1;
    3190             : 
    3191             :   }
    3192             :   else {
    3193             :     // Pars are not themselves channel-dependent
    3194           6 :     nChanParList() = 1;
    3195             : 
    3196             :     // Check if matrices may still be freq-dep:
    3197           6 :     if (freqDepMat()) {
    3198             :       // cal is an explicit f(freq) (e.g., like delay)
    3199           0 :       nChanMatList()  = nDatChan;
    3200           0 :       startChanList() = startDatChan;
    3201             :     } else {
    3202             :       // cal has no freq dep at all
    3203           6 :       nChanMatList()  = Vector<Int>(nSpw(),1);
    3204           6 :       startChanList() = Vector<Int>(nSpw(),0);
    3205             :     }
    3206             : 
    3207             :   }
    3208             : 
    3209             :   // At this point:
    3210             :   //  1. nChanParList() represents the (per-Spw) overall length of the
    3211             :   //     output parameter channel axis, appropriate for shaping the
    3212             :   //     output NewCalTable.  This value is irrelevant during the solve, since
    3213             :   //     we will only solve for one parameter channel at a time (or 
    3214             :   //     there is only one channel to solver for).
    3215             :   //  2. nChanMatList() represents the per-Spw  matrix channel axis length to
    3216             :   //     be used during the solve, independent of the parameter channel
    3217             :   //     axis length.  In the solve context, nChanMat()>1 when there is
    3218             :   //     more than one channel of data upon which the (single channel)
    3219             :   //     solve parameters depend (e.g., delay, polynomial bandpass, etc.)
    3220             : 
    3221          32 : }
    3222             : 
    3223             : 
    3224             : 
    3225             : 
    3226           0 : void SolvableVisCal::convertHzToCh() {
    3227             : 
    3228             :   //  cout << "convertHzToCh!" << endl;
    3229             : 
    3230             :   // Access the channel widths vis msmc, etc.
    3231           0 :   vector<QVD> chanwidths=msmc().msmd().getChanWidths();
    3232             : 
    3233           0 :   logSink() << LogIO::NORMAL;
    3234           0 :   logSink() << " Frequency solint parsing:" << LogIO::POST;
    3235           0 :   for (Int ispw=0;ispw<nSpw();++ispw) {
    3236           0 :     currSpw()=ispw;
    3237             :     // Calculate channel increment from Hz
    3238           0 :     if (fintervalCh()<0.0 && fintervalHz()>0.0) {
    3239             :       // Assumes constant chan width in each spw!
    3240           0 :       Double datawidthHz=abs(chanwidths[ispw][0].get("Hz").getValue()); 
    3241           0 :       fintervalCh()=floor(fintervalHz()/datawidthHz);
    3242           0 :       if (fintervalCh()<1.0) fintervalCh()=1.0;  // nothing fractional <1.0
    3243             : 
    3244             :       logSink() << ".  Spw " << ispw << ": "
    3245           0 :                 << " (freq solint: " << fintervalHz() << " Hz) / (data width: " << datawidthHz << " Hz)"
    3246           0 :                 << " = " << fintervalCh() << " data channels per solution channel."
    3247           0 :                 << LogIO::POST;
    3248             :     }
    3249             :   } // ispw  
    3250             : 
    3251           0 : }
    3252             : 
    3253             : 
    3254             : 
    3255             : 
    3256           0 : void SolvableVisCal::setFracChanAve() {
    3257             : 
    3258             :   // TBD: calculate fintervalCh from fintervalHz
    3259           0 :   MeasurementSet ms(msName());
    3260           0 :   MSSpWindowColumns spwcol(ms.spectralWindow());
    3261             : 
    3262             :   //  cout << "setFracChanAve!" << endl;
    3263           0 :   for (Int ispw=0;ispw<nSpw();++ispw) {
    3264             :     //    cout << "ispw=" << ispw << ":" << endl;
    3265             :     //    cout << " nChanData      = " << nChanPar() << endl;
    3266             :     //    cout << " startChan()    = " << startChan() << endl;
    3267           0 :     currSpw()=ispw;
    3268             : 
    3269             :     // Calculate channel increment from Hz
    3270           0 :     if (fintervalCh()<0.0 && fintervalHz()>0.0) {
    3271           0 :       Double datawidth=abs(spwcol.chanWidth()(ispw)(IPosition(1,0)));
    3272           0 :       cout << "ispw=" << ispw << " datawidth=" << datawidth << flush;
    3273           0 :       fintervalCh()=floor(fintervalHz()/datawidth);
    3274           0 :       if (fintervalCh()<1.0) fintervalCh()=1.0;
    3275           0 :       cout << " dHz=" << fintervalHz() << " --> " << fintervalCh() << " channels." << endl;
    3276             :     }
    3277             : 
    3278           0 :     Int extrach=nChanPar()%Int(fintervalCh());
    3279           0 :     Int nChanOut=nChanPar()/Int(fintervalCh()) + (extrach > 0 ? 1 : 0);
    3280             : 
    3281             :     //    cout << " fintervalCh()  = " << fintervalCh() << endl;
    3282             :     //    cout << " extrach        = " << extrach << endl;
    3283             :     //    cout << " nChanOut       = " << nChanOut << endl;
    3284             :     
    3285           0 :     chanAveBounds_(ispw).resize(nChanOut,2);
    3286           0 :     Matrix<Int> bounds(chanAveBounds_(ispw));
    3287           0 :     bounds.column(0).set(startChan());
    3288           0 :     bounds.column(1).set(startChan()+Int(fintervalCh()-1));
    3289           0 :     for (Int ochan=1;ochan<nChanOut;++ochan) {
    3290           0 :       Vector<Int> col(bounds.row(ochan));
    3291           0 :       col+=Int(ochan*fintervalCh());
    3292           0 :     }
    3293           0 :     if (extrach>0) bounds(nChanOut-1,1)+=(extrach-Int(fintervalCh()));
    3294             :     
    3295             :     //    for (int ochan=0;ochan<nChanOut;++ochan) 
    3296             :     //      cout << "    ochan="<<ochan<< " bounds=" 
    3297             :     //     << bounds.row(ochan) 
    3298             :     //     << " n=" << bounds(ochan,1)-bounds(ochan,0)+1
    3299             :     //     << endl;
    3300             : 
    3301             :     // Revise nChanPar()
    3302           0 :     nChanPar()=nChanOut;
    3303           0 :   }
    3304           0 :   currSpw()=0;
    3305             :   //  cout << "nChanParList() = " << nChanParList() << endl;
    3306             :   //  cout << "chanAveBounds_ = " << chanAveBounds_ << endl;
    3307           0 : }
    3308             : 
    3309             : // Inflate an empty Caltable w/ meta-data from a VisSet
    3310           0 : void SolvableVisCal::inflateNCTwithMetaData(VisSet& vs) {
    3311             : 
    3312           0 :   if (prtlev()>3) cout << "  SVC::inflateNCTwithMetaData(vs)" << endl;
    3313             : 
    3314             :   // NB: Currently, this is only used for the accumulate
    3315             :   //     context; in solve, meta-data is filled on-the-fly
    3316             :   //     (this ensures more accurate timestamps, etc.)
    3317             : 
    3318             :   // Fill the Calset with meta info
    3319           0 :   VisIter& vi(vs.iter());
    3320           0 :   vi.originChunks();
    3321           0 :   VisBuffer vb(vi);
    3322           0 :   Vector<Int> islot(nSpw(),0);
    3323           0 :   for (vi.originChunks(); vi.moreChunks(); vi.nextChunk()) {
    3324             : 
    3325           0 :     vi.origin();
    3326           0 :     currSpw()=vi.spectralWindow();
    3327           0 :     currField()=vi.fieldId();
    3328           0 :     currScan()=vb.scan0();
    3329           0 :     currObs()=vb.observationId()(0);
    3330             :     
    3331             :     // Derive average time info
    3332           0 :     Double timeStamp(0.0);
    3333           0 :     Int ntime(0);
    3334           0 :     for (vi.origin(); vi.more(); vi++,++ntime) timeStamp+=vb.time()(0);
    3335           0 :     if (ntime>0)
    3336           0 :       refTime()=timeStamp/Double(ntime);
    3337             :     else
    3338           0 :       refTime()=0.0;
    3339             : 
    3340             :     // Initialize parameters
    3341           0 :     switch(parType()) {
    3342           0 :     case VisCalEnum::COMPLEX: {
    3343           0 :       solveAllCPar().set(defaultPar());
    3344           0 :       break;
    3345             :     }
    3346           0 :     case VisCalEnum::REAL: {
    3347           0 :       solveAllCPar().set(defaultPar());
    3348           0 :       break;
    3349             :     }
    3350           0 :     default:
    3351           0 :       break;
    3352             :     }
    3353           0 :     solveAllParOK().set(true);
    3354           0 :     solveAllParErr().set(Float(0.0));
    3355           0 :     solveAllParSNR().set(1.0);
    3356             : 
    3357             :     /*
    3358             :     cout << "Spw=" << currSpw()
    3359             :          << " Fld=" << currField()
    3360             :          << " Scan=" << currScan()
    3361             :          << " Time=" << MVTime(refTime()/C::day).string(MVTime::YMD,7)
    3362             :          << endl;
    3363             :     */
    3364             : 
    3365             :     // Add this interval to the NCT
    3366           0 :     if (refTime()>0.0)
    3367           0 :       keepNCT();
    3368             : 
    3369             :   }
    3370             : 
    3371           0 : }
    3372             : 
    3373          39 : Bool SolvableVisCal::syncSolveMeta(VisBuffGroupAcc& vbga) {
    3374             : 
    3375             :   // Adopt meta data from FIRST CalVisBuffer in the VBGA, for now
    3376          39 :   currSpw()=spwMap()(vbga(0).spectralWindow());
    3377          39 :   currField()=vbga(0).fieldId();
    3378             : 
    3379             :   // The timestamp really is global, in any case
    3380          39 :   Double& rTime(vbga.globalTimeStamp());
    3381          39 :   if (rTime > 0.0) {
    3382          39 :     refTime()=rTime;
    3383          39 :     return true;
    3384             :   }
    3385             :   else
    3386           0 :     return false;
    3387             : 
    3388             : }
    3389             : 
    3390       19605 : void SolvableVisCal::syncSolveMeta(SDBList& sdbs) {  // VI2
    3391             :   
    3392             :   //  cout << "spwMap() = " << spwMap() << endl;
    3393             : 
    3394             :   // Ask the sdbs
    3395       19605 :   Vector<Double> freqs;
    3396       19605 :   if (freqDepPar()) 
    3397             :     // nominally channelized
    3398        1848 :     freqs.reference(sdbs.freqs());
    3399             :   else
    3400             :     // a single aggregate frequency (as a Vector)
    3401       17757 :     freqs.reference(Vector<Double>(1,sdbs.aggregateCentroidFreq()));
    3402             : 
    3403       19605 :   setMeta(sdbs.aggregateObsId(),
    3404             :           sdbs.aggregateScan(),
    3405             :           //sdbs.aggregateTime(),   
    3406             :           sdbs.aggregateTimeCentroid(),
    3407             :           sdbs.aggregateSpw(),
    3408             :           freqs,        
    3409             :           sdbs.aggregateFld());
    3410       19605 : }
    3411             : 
    3412             : 
    3413             : 
    3414         122 : Bool SolvableVisCal::syncSolveMeta(VisBuffer& vb, 
    3415             :                                    const Int&) {
    3416             : 
    3417         122 :   if (prtlev()>2) cout << "SVC::syncSolveMeta(,,)" << endl;
    3418             : 
    3419             :   // Returns true, only if sum of weights is positive,
    3420             :   //  i.e., there is data to solve with
    3421             : 
    3422             :   // TBD: freq info, etc.
    3423             : 
    3424         122 :   currSpw()=spwMap()(vb.spectralWindow());
    3425         122 :   currField()=vb.fieldId();
    3426         122 :   currScan()=vb.scan0();
    3427         122 :   currObs()=vb.observationId()(0);
    3428             : 
    3429             :   // Row weights as a Doubles
    3430         122 :   Vector<Double> dWts;
    3431         122 :   dWts.resize(vb.weight().shape());
    3432         122 :   convertArray(dWts,vb.weight());
    3433         122 :   Vector<Double> times;
    3434         122 :   times = vb.time();
    3435             :   
    3436             :   // The following assumes flagRow is accurate
    3437         122 :   LogicalArray gRows(!vb.flagRow());
    3438         122 :   Double sumWts(0.0);
    3439         122 :   MaskedArray<Double> gTimes(times,gRows);
    3440         122 :   MaskedArray<Double> gWts(dWts,gRows);
    3441             : 
    3442         122 :   if (sum(gRows)>0) {
    3443         122 :     sumWts=sum(gWts);
    3444             :   }
    3445             : 
    3446         122 :   if (sumWts>0.0) {
    3447         122 :     gTimes*=gWts;
    3448         122 :     refTime()=sum(gTimes);
    3449         122 :     refTime()/=sumWts;
    3450         122 :     return true;
    3451             :   }
    3452             :   else
    3453           0 :     return false;
    3454             : 
    3455         122 : }
    3456             : 
    3457          39 : void SolvableVisCal::overrideObsScan(Int obs,Int scan) {
    3458          39 :   currObs()=obs;
    3459          39 :   currScan()=scan;
    3460          39 : }
    3461             : 
    3462         122 : void SolvableVisCal::enforceAPonData(VisBuffer& vb) {
    3463             : 
    3464             :   // TBD: migrate this to VisEquation?
    3465             : 
    3466             :   // ONLY if something to do
    3467         122 :   if (apmode()=="A" || apmode()=="P") {
    3468           0 :     Int nCorr(vb.corrType().nelements());
    3469           0 :     Float amp(1.0);
    3470           0 :     Complex cor(1.0);
    3471           0 :     Bool *flR=vb.flagRow().data();
    3472           0 :     Bool *fl =vb.flag().data();
    3473           0 :     Vector<Float> ampCorr(nCorr);
    3474           0 :     Vector<Int> n(nCorr,0);
    3475           0 :     for (Int irow=0;irow<vb.nRow();++irow,++flR) {
    3476           0 :       if (!vb.flagRow()(irow)) {
    3477           0 :         ampCorr=0.0f;
    3478           0 :         n=0;
    3479           0 :         for (Int ich=0;ich<vb.nChannel();++ich,++fl) {
    3480           0 :           if (!vb.flag()(ich,irow)) {
    3481           0 :             for (Int icorr=0;icorr<nCorr;icorr++) {
    3482             :               
    3483           0 :               amp=abs(vb.visCube()(icorr,ich,irow));
    3484           0 :               if (amp>0.0f) {
    3485           0 :                 if (apmode()=="P") {
    3486             :                   // we will scale by amp to make data phase-only
    3487           0 :                   cor=Complex(amp,0.0);
    3488             :                   // keep track for weight adjustment
    3489           0 :                   ampCorr(icorr)+=abs(cor); // amp;
    3490           0 :                   n(icorr)++;
    3491             :                 }
    3492           0 :                 else if (apmode()=="A")
    3493             :                   // we will scale by "phase" to make data amp-only
    3494           0 :                   cor=vb.visCube()(icorr,ich,irow)/amp;
    3495             :                 
    3496             :                 // Apply the complex scaling
    3497           0 :                 vb.visCube()(icorr,ich,irow)/=cor;
    3498             :               }
    3499             :             } // icorr
    3500             :           } // !*fl
    3501             :         } // ich
    3502             :         // Make appropriate weight adjustment
    3503             :         //  Only for phase-only since only it rescales data
    3504           0 :         if (apmode()=="P") {
    3505           0 :           for (Int icorr=0;icorr<nCorr;icorr++)
    3506           0 :             if (n(icorr)>0)
    3507             :               // weights adjusted by square of the mean(amp)
    3508           0 :               vb.weightMat()(icorr,irow)*=square(ampCorr(icorr)/Float(n(icorr)));
    3509             :             else
    3510             :               // weights now zero
    3511           0 :               vb.weightMat()(icorr,irow)=0.0f;
    3512             :         }
    3513             :       } // !*flR
    3514             :     } // irow
    3515             : 
    3516           0 :   } // phase- or amp-only
    3517             : 
    3518             :   //  cout << "amp(vb.visCube())=" << amplitude(vb.visCube().reform(IPosition(1,vb.visCube().nelements()))) << endl;
    3519             : 
    3520             : 
    3521         122 : }
    3522             : 
    3523           0 : void SolvableVisCal::setUpForPolSolve(VisBuffer& vb) {
    3524             : 
    3525             :   // TBD: migrate this to VisEquation?
    3526             : 
    3527             :   // NB (2016Nov29, gmoellen): No, should actually move this very specific
    3528             :   //   activity into DJones where it is specifically relevant.
    3529             :   //   VB2 version has done this.
    3530             :   
    3531             :   // Divide model and data by (scalar) stokes I (which may be resolved!), 
    3532             :   //  and set model cross-hands to (1,0) so we can solve for fractional
    3533             :   //  pol factors.
    3534             : 
    3535             :   // Only if solving for Q an U
    3536             :   //  (leave cross-hands alone if just solving for X)
    3537           0 :   if (solvePol()>1) {
    3538             : 
    3539           0 :     Int nCorr(vb.corrType().nelements());
    3540           0 :     Bool *flR=vb.flagRow().data();
    3541           0 :     Bool *fl =vb.flag().data();
    3542           0 :     Vector<Float> ampCorr(nCorr);
    3543           0 :     Vector<Int> n(nCorr,0);
    3544           0 :     Complex sI(0.0);
    3545           0 :     for (Int irow=0;irow<vb.nRow();++irow,++flR) {
    3546           0 :       if (!vb.flagRow()(irow)) {
    3547           0 :         ampCorr=0.0f;
    3548           0 :         n=0;
    3549           0 :         for (Int ich=0;ich<vb.nChannel();++ich,++fl) {
    3550           0 :           if (!vb.flag()(ich,irow)) {
    3551             :             
    3552           0 :             sI=(vb.modelVisCube()(0,ich,irow)+vb.modelVisCube()(3,ich,irow))/Complex(2.0);
    3553           0 :             if (abs(sI)>0.0) {
    3554           0 :               for (Int icorr=0;icorr<nCorr;icorr++) {
    3555           0 :                 vb.visCube()(icorr,ich,irow)/=sI;
    3556           0 :                 ampCorr(icorr)+=abs(sI);
    3557           0 :                 n(icorr)++;
    3558             :               } // icorr
    3559             :             }
    3560             :             else
    3561           0 :               vb.flag()(ich,irow)=true;
    3562             :             
    3563             :           } // !*fl
    3564             :         } // ich
    3565             :         // Make appropriate weight adjustment
    3566           0 :         for (Int icorr=0;icorr<nCorr;icorr++)
    3567           0 :           if (n(icorr)>0)
    3568             :             // weights adjusted by square of the mean(amp)
    3569           0 :             vb.weightMat()(icorr,irow)*=square(ampCorr(icorr)/Float(n(icorr)));
    3570             :           else
    3571             :             // weights now zero
    3572           0 :             vb.weightMat()(icorr,irow)=0.0f;
    3573             :       } // !*flR
    3574             :     } // irow
    3575             :     
    3576             :     // Model is now all unity  (Is this ok for flagged data? Probably.)
    3577           0 :     vb.modelVisCube()=Complex(1.0);
    3578             : 
    3579           0 :   }
    3580             : 
    3581           0 : }
    3582             : 
    3583           0 : Bool SolvableVisCal::verifyConstraints(VisBuffGroupAcc& vbag) {
    3584             : 
    3585             :   // TBD: handle multi-channel infocusFlag properly
    3586             :   // TBD: optimize array access
    3587             :   
    3588             :   // Assemble nominal baseline weights distribution
    3589           0 :   Matrix<Double> blwtsum(nAnt(),nAnt(),0.0);
    3590           0 :   for (Int ivb=0;ivb<vbag.nBuf();++ivb) {
    3591           0 :     CalVisBuffer& cvb(vbag(ivb));
    3592             : 
    3593           0 :     cvb.setFocusChan(focusChan());
    3594             : 
    3595           0 :     for (Int irow=0;irow<cvb.nRow();++irow) {
    3596           0 :       Int& a1(cvb.antenna1()(irow));
    3597           0 :       Int& a2(cvb.antenna2()(irow));
    3598           0 :       if (!cvb.flagRow()(irow) && a1!=a2) {
    3599           0 :         if (!cvb.infocusFlag()(0,irow)) {
    3600           0 :           Double wt=Double(sum(cvb.weightMat().column(irow)));
    3601           0 :           blwtsum(a2,a1)+=wt;
    3602           0 :           blwtsum(a1,a2)+=wt;
    3603             :         } // flag
    3604             :       } // flagRow 
    3605             :     } // irow
    3606             :   } // ivb
    3607             : 
    3608             :   // Recursively apply threshold on baselines per antenna
    3609             :   //  Currently, we insist on at least 3 baselines per antenna
    3610             :   //  (This will eventually be a user-specified parameter: blperant)
    3611           0 :   Vector<Bool> antOK(nAnt(),true);  // nominally OK
    3612           0 :   Vector<Int> blperant(nAnt(),0);
    3613           0 :   Int iant=0;
    3614           0 :   while (iant<nAnt()) {
    3615           0 :     if (antOK(iant)) {   // avoid reconsidering already bad ones
    3616           0 :       Int nbl=ntrue(blwtsum.column(iant)>0.0);
    3617           0 :       blperant(iant)=nbl;
    3618           0 :       if (nbl<minblperant()) {
    3619             :         // some baselines available, but not enough
    3620             :         //  so eliminate this antenna 
    3621           0 :         antOK(iant)=false;
    3622           0 :         blwtsum.row(iant)=0.0;
    3623           0 :         blwtsum.column(iant)=0.0;
    3624           0 :         blperant(iant)=0;
    3625             :         // ensure we begin recount at first antenna again
    3626           0 :         iant=-1;
    3627             :       }
    3628             :     }      
    3629           0 :     ++iant;
    3630             :   }
    3631             : 
    3632             :   //  cout << "  blperant = " << blperant << " (minblperant = " << minblperant() << endl;
    3633             :   //  cout << "  antOK    = " << antOK << endl;
    3634             :   //  cout << "  ntrue(antOK) = " << ntrue(antOK) << endl;
    3635             : 
    3636             :   // Apply constraints results to solutions and data
    3637           0 :   solveParOK()=false;   // Solutions nominally bad
    3638           0 :   for (Int iant=0;iant<nAnt();++iant) {
    3639           0 :     if (antOK(iant)) {
    3640             :       // set solution good
    3641           0 :       solveParOK().xyPlane(iant) = true;
    3642             :     }
    3643             :     else {
    3644             :       // This ant not ok, set soln to zero
    3645           0 :       if (parType()==VisCalEnum::COMPLEX)
    3646           0 :         solveCPar().xyPlane(iant)=1.0;
    3647           0 :       else if (parType()==VisCalEnum::REAL)
    3648           0 :         solveRPar().xyPlane(iant)=0.0;
    3649             : 
    3650             :       // Flag corresponding data
    3651           0 :       for (Int ivb=0;ivb<vbag.nBuf();++ivb) {
    3652           0 :         CalVisBuffer& cvb(vbag(ivb));
    3653           0 :         Vector<Int>& a1(cvb.antenna1());
    3654           0 :         Vector<Int>& a2(cvb.antenna2());
    3655           0 :         for (Int irow=0;irow<cvb.nRow();++irow) {
    3656           0 :           if (a1(irow)==iant || a2(irow)==iant)
    3657           0 :             cvb.infocusFlag()(0,irow)=true;
    3658             :         }
    3659             :         // the following didn't work because row(0) behaved
    3660             :         //  as contiguous and set the wrong flags for multi-chan data!
    3661             :         //      cvb.infocusFlag().row(0)(a1==iant)=true;
    3662             :         //      cvb.infocusFlag().row(0)(a2==iant)=true;
    3663             :       } // ivb
    3664             : 
    3665             :     } // antOK
    3666             :   } // iant
    3667             :   
    3668             :   // We return sum(antOK)>0 here because it is not how many 
    3669             :   //  good ants there are, but rather how many good baselines 
    3670             :   //  per ant there are.  The above counting exercise will 
    3671             :   //  reduce sum(antOK) to zero when the baseline counts 
    3672             :   //  constraint is violated over enough of the whole array.  
    3673             :   //  so as to make the solution impossible.  Otherwise
    3674             :   //  there will be at least blperant+1 (>0) good antennas.
    3675             : 
    3676           0 :   return (ntrue(antOK)>0);
    3677             : 
    3678           0 : }
    3679             : 
    3680       19605 : void SolvableVisCal::clearMap() {
    3681             :     // Clear or initalize values for the antennaMap_
    3682       19605 :     Vector<Int> initVector(nPar(), 0);
    3683       19605 :     Vector<Int> singleVector(1, 0);
    3684             :     
    3685      201590 :     for (Int iant=0; iant<nAnt(); ++iant) {
    3686      181985 :         antennaMap_[iant]["expected"] = initVector;
    3687      181985 :         antennaMap_[iant]["data_unflagged"] = initVector;
    3688      181985 :         antennaMap_[iant]["above_minblperant"] = initVector;
    3689      181985 :         antennaMap_[iant]["above_minsnr"] = initVector;
    3690      181985 :         antennaMap_[iant]["used_as_refant"] = singleVector;
    3691             :     }
    3692             :     
    3693       19605 : }
    3694             : 
    3695         160 : void SolvableVisCal::clearRefantMap() {
    3696             :     // Clear or initialize values for refantMap_
    3697         760 :     for (Int ispw=0; ispw<nSpw(); ++ispw) {
    3698        6012 :         for (Int iant=0; iant<nAnt(); ++iant) {
    3699        5412 :             refantMap_[ispw][iant] = 0;
    3700             :         }
    3701             :     }
    3702         160 : }
    3703             : 
    3704       19605 : void SolvableVisCal::expectedUnflagged(SDBList& sdbs) {
    3705             :     // Iterate over sdbs and add values to expected and data unflagged
    3706       66801 :     for (Int isdb=0;isdb<sdbs.nSDB();++isdb) {
    3707       47196 :         SolveDataBuffer& sdb(sdbs(isdb));
    3708             :         
    3709       47196 :         Int nRow(sdb.nRows());
    3710       47196 :         Int nCorr(sdb.nCorrelations());
    3711     1152046 :         for (Int irow=0;irow<nRow;++irow) {
    3712     1104850 :             const Int& a1(sdb.antenna1()(irow));
    3713     1104850 :             const Int& a2(sdb.antenna2()(irow));
    3714             :             
    3715     1104850 :             if (a1!=a2) {
    3716     5289408 :                 for (int par=0;par<nPar();par++) {
    3717     4241132 :                   antennaMap_[a1]["expected"][par] = 1;
    3718     4241132 :                   antennaMap_[a2]["expected"][par] = 1;
    3719             :                 }
    3720             :             }
    3721             :             // Do cal type-dependent setting of "data_unflagged" counts
    3722             :             
    3723     1104850 :             switch (this->type()) {
    3724      656136 :             case VisCal::G:
    3725             :             case VisCal::K:
    3726             :             case VisCal::B: {  // nPar=2 (gain-like)
    3727             :                 // Set each pol by flags from appropriate parallel-hand corr
    3728      656136 :                 if (nfalse(sdb.flagCube()(0,Slice(),irow))>0) {
    3729      614095 :                   antennaMap_[a1]["data_unflagged"][0] =
    3730     1228190 :                   antennaMap_[a2]["data_unflagged"][0] = 1;
    3731             :                 }
    3732      656136 :                 if (nfalse(sdb.flagCube()(nCorr-1,Slice(),irow))>0) {
    3733      614095 :                   antennaMap_[a1]["data_unflagged"][1] =
    3734     1228190 :                   antennaMap_[a2]["data_unflagged"][1] = 1;
    3735             :                 }
    3736      656136 :                 break;
    3737             :             }
    3738      330840 :             case VisCal::T: {  // nPar=1 (gain-like)
    3739             :                 // Set single pol by flags from all parallel-hand correlations
    3740      330840 :                 Int nsl(nCorr>1?2:1), isl(nCorr>2?3:1);
    3741      330840 :                 if (nfalse(sdb.flagCube()(Slice(0,nsl,isl),Slice(),irow))>0) {
    3742      330840 :                   antennaMap_[a1]["data_unflagged"][0] =
    3743      661680 :                   antennaMap_[a2]["data_unflagged"][0] = 1;
    3744             :                 }
    3745      330840 :                 break;
    3746             :             }
    3747      117874 :             default: {
    3748             :                 // Set all pols by flags from all correlations (any unflagged is ok)
    3749      117874 :                 if (nfalse(sdb.flagCube()(Slice(),Slice(),irow))>0) {
    3750      117874 :                   antennaMap_[a1]["data_unflagged"].set(1);
    3751      117874 :                   antennaMap_[a2]["data_unflagged"].set(1);
    3752             :                 }
    3753             :             }
    3754             :             }
    3755             :         }
    3756             :     }
    3757       19605 : }
    3758             : 
    3759       17184 : Bool SolvableVisCal::verifyConstraints(SDBList& sdbs) {  // VI2
    3760             : 
    3761             :   // TBD: handle multi-channel infocusFlag properly
    3762             :   // TBD: optimize array access
    3763             :   
    3764             :   // Assemble nominal baseline weights distribution
    3765       17184 :   Matrix<Double> blwtsum(nAnt(),nAnt(),0.0);
    3766       36233 :   for (Int isdb=0;isdb<sdbs.nSDB();++isdb) {
    3767       19049 :     SolveDataBuffer& sdb(sdbs(isdb));
    3768             : 
    3769       19049 :     sdb.setFocusChan(focusChan());
    3770             : 
    3771             :     // TBD: do this per cal parameter, rather than just per ant
    3772             : 
    3773       19049 :     Int nRow(sdb.nRows());
    3774       19049 :     Int nCorr(sdb.nCorrelations());
    3775             : 
    3776     1028428 :     for (Int irow=0;irow<nRow;++irow) {
    3777     1009379 :       const Int& a1(sdb.antenna1()(irow));
    3778     1009379 :       const Int& a2(sdb.antenna2()(irow));
    3779     1009379 :       if (!sdb.flagRow()(irow) && a1!=a2) {
    3780             :         // Currently insist _any_ unflagged correlations; need to refine!
    3781     1009379 :         if (sum(sdb.infocusFlagCube()(Slice(),Slice(),irow))<nCorr) {
    3782     1009345 :           Double wt=Double(sum(sdb.infocusWtSpec()(Slice(),Slice(),irow)));
    3783     1009345 :           blwtsum(a2,a1)+=wt;
    3784     1009345 :           blwtsum(a1,a2)+=wt;
    3785             :         } // flag
    3786             :       } // flagRow 
    3787             :     } // irow
    3788             :   } // ivb
    3789             : 
    3790             :   // Recursively apply threshold on baselines per antenna
    3791       17184 :   Vector<Bool> antOK(nAnt(),True);  // nominally OK
    3792       17184 :   Vector<Int> blperant(nAnt(),0);
    3793       17184 :   Vector<Int> initVector(nPar(), 0);
    3794             :     
    3795       17184 :   Int iant=0;
    3796      791213 :   while (iant<nAnt()) {
    3797      774029 :     if (antOK(iant)) {   // avoid reconsidering already bad ones
    3798      212206 :       Int nbl=ntrue(blwtsum.column(iant)>0.0);
    3799      212206 :       blperant(iant)=nbl;
    3800      212206 :       if (nbl<minblperant()) {
    3801             :         // some baselines available, but not enough
    3802             :         //  so eliminate this antenna 
    3803       85872 :         antOK(iant)=False;
    3804       85872 :         blwtsum.row(iant)=0.0;
    3805       85872 :         blwtsum.column(iant)=0.0;
    3806       85872 :         blperant(iant)=0;
    3807             :         // ensure we begin recount at first antenna again
    3808       85872 :         iant=-1;
    3809             :       }
    3810             :     }      
    3811      774029 :     ++iant;
    3812             :   }
    3813             : 
    3814             :   //  cout << "  blperant = " << blperant << " (minblperant = " << minblperant() << endl;
    3815             :   //  cout << "  antOK    = " << antOK << endl;
    3816             :   //  cout << "  ntrue(antOK) = " << ntrue(antOK) << endl;
    3817             : 
    3818             :   // Apply constraints results to solutions and data
    3819       17184 :   solveParOK()=False;   // Solutions nominally bad
    3820      210912 :   for (Int iant=0;iant<nAnt();++iant) {
    3821      193728 :     if (antOK(iant)) {
    3822             :       // set solution good
    3823      107856 :       solveParOK().xyPlane(iant) = True;
    3824      250048 :       for (Int ipar=0; ipar<nPar();++ipar) {
    3825      142192 :         antennaMap_[iant]["above_minblperant"][ipar] = 1;
    3826             :       }
    3827             :     }
    3828             :     else {
    3829             :       // This ant not ok, set soln to zero
    3830       85872 :       if (parType()==VisCalEnum::COMPLEX)
    3831       85872 :         solveCPar().xyPlane(iant)=1.0;
    3832           0 :       else if (parType()==VisCalEnum::REAL)
    3833           0 :         solveRPar().xyPlane(iant)=0.0;
    3834             : 
    3835             :       // Flag corresponding data
    3836      171744 :       for (Int isdb=0;isdb<sdbs.nSDB();++isdb) {
    3837       85872 :         SolveDataBuffer& sdb(sdbs(isdb));
    3838       85872 :         const Vector<Int>& a1(sdb.antenna1());
    3839       85872 :         const Vector<Int>& a2(sdb.antenna2());
    3840     5367214 :         for (Int irow=0;irow<sdb.nRows();++irow) {
    3841     5281342 :           if (a1(irow)==iant || a2(irow)==iant)
    3842      502821 :             sdb.infocusFlagCube()(Slice(),Slice(),irow)=True;
    3843             :         }
    3844             :         // the following didn't work because row(0) behaved
    3845             :         //  as contiguous and set the wrong flags for multi-chan data!
    3846             :         //      cvb.infocusFlag().row(0)(a1==iant)=True;
    3847             :         //      cvb.infocusFlag().row(0)(a2==iant)=True;
    3848             :       } // ivb
    3849             : 
    3850             :     } // antOK
    3851             :   } // iant
    3852             :   
    3853             :   // We return sum(antOK)>0 here because it is not how many 
    3854             :   //  good ants there are, but rather how many good baselines 
    3855             :   //  per ant there are.  The above counting exercise will 
    3856             :   //  reduce sum(antOK) to zero when the baseline counts 
    3857             :   //  constraint is violated over enough of the whole array.  
    3858             :   //  so as to make the solution impossible.  Otherwise
    3859             :   //  there will be at least blperant+1 (>0) good antennas.
    3860             : 
    3861       34368 :   return (ntrue(antOK)>0);
    3862             : 
    3863       17184 : }
    3864             : 
    3865             : 
    3866             : 
    3867             : // Verify VisBuffer data sufficient for solving (wts, etc.)
    3868           0 : Bool SolvableVisCal::verifyForSolve(VisBuffer& vb) {
    3869             : 
    3870             :   //  cout << "verifyForSolve..." << endl;
    3871             : 
    3872           0 :   Int nAntForSolveFinal(-1);
    3873           0 :   Int nAntForSolve(0);
    3874             : 
    3875             :   // We will count baselines and weights per ant
    3876             :   //   and set solveParOK accordingly
    3877           0 :   Vector<Int> blperant(nAnt(),0);
    3878           0 :   Vector<Double> wtperant(nAnt(),0.0);
    3879           0 :   Vector<Bool> antOK(nAnt(),false);
    3880             :     
    3881           0 :   while (nAntForSolve!=nAntForSolveFinal) {
    3882             : 
    3883           0 :     nAntForSolveFinal=nAntForSolve;
    3884           0 :     nAntForSolve=0;
    3885             : 
    3886             : 
    3887             :     // TBD: optimize indexing with pointers in the following
    3888           0 :     blperant=0;
    3889           0 :     wtperant=0.0;
    3890             : 
    3891           0 :     for (Int irow=0;irow<vb.nRow();++irow) {
    3892           0 :       Int a1=vb.antenna1()(irow);
    3893           0 :       Int a2=vb.antenna2()(irow);
    3894           0 :       if (!vb.flagRow()(irow) && a1!=a2) {
    3895             :         
    3896           0 :         if (!vb.flag()(focusChan(),irow)) {
    3897             :           
    3898           0 :           blperant(a1)+=1;
    3899           0 :           blperant(a2)+=1;
    3900             :           
    3901           0 :           wtperant(a1)+=Double(sum(vb.weightMat().column(irow)));
    3902           0 :           wtperant(a2)+=Double(sum(vb.weightMat().column(irow)));
    3903             :           
    3904             :         }
    3905             :       }
    3906             :     }
    3907             :     
    3908           0 :     antOK=false;
    3909           0 :     for (Int iant=0;iant<nAnt();++iant) {
    3910           0 :       if (blperant(iant)>3 &&
    3911           0 :           wtperant(iant)>0.0) {
    3912             :         // This antenna is good, keep it
    3913           0 :         nAntForSolve+=1;
    3914           0 :         antOK(iant)=true;
    3915             :       }
    3916             :       else {
    3917             :         // This antenna under-represented; flag it
    3918           0 :         vb.flag().row(focusChan())(vb.antenna1()==iant)=true;
    3919           0 :         vb.flag().row(focusChan())(vb.antenna2()==iant)=true;
    3920             :         //      vb.flagRow()(vb.antenna1()==iant)=true;
    3921             :         //      vb.flagRow()(vb.antenna2()==iant)=true;
    3922             :       }
    3923             :     }
    3924             : 
    3925             :     //    cout << "blperant     = " << blperant << endl;
    3926             :     //    cout << "wtperant = " << wtperant << endl;
    3927             :     //    cout << "nAntForSolve = " << nAntForSolve << " " << antOK << endl;
    3928             : 
    3929             :   }
    3930             : 
    3931             :   // We've converged on the correct good antenna count
    3932           0 :   nAntForSolveFinal=nAntForSolve;
    3933             : 
    3934             :   // Set a priori solution flags  
    3935           0 :   solveParOK() = false;
    3936           0 :   for (Int iant=0;iant<nAnt();++iant)
    3937           0 :     if (antOK(iant))
    3938             :       // This ant ok
    3939           0 :       solveParOK().xyPlane(iant) = true;
    3940             :     else
    3941             :       // This ant not ok, set soln to zero
    3942           0 :       if (parType()==VisCalEnum::COMPLEX)
    3943           0 :         solveCPar().xyPlane(iant)=1.0;
    3944           0 :       else if (parType()==VisCalEnum::REAL)
    3945           0 :         solveRPar().xyPlane(iant)=0.0;
    3946             :   //  cout << "antOK = " << antOK << endl;
    3947             :   //  cout << "solveParOK() = " << solveParOK() << endl;
    3948             :   //  cout << "amp(solveCPar()) = " << amplitude(solveCPar()) << endl;
    3949             : 
    3950           0 :   if (nAntForSolve<4) cout << "Only " << nAntForSolve 
    3951           0 :                            << "/" << nAnt() 
    3952           0 :                            << " antennas (" 
    3953           0 :                            << floor(100*Float(nAntForSolve/nAnt()))
    3954           0 :                            << "%) have sufficient baselines at " 
    3955           0 :                            << MVTime(refTime()/C::day).string(MVTime::YMD,7)
    3956           0 :                            << endl;
    3957           0 :   return (nAntForSolve>3);
    3958             :     
    3959           0 : }
    3960             : 
    3961           0 : void SolvableVisCal::selfGatherAndSolve(VisSet&, VisEquation&) {
    3962             :     
    3963           0 :   if (useGenericGatherForSolve())
    3964           0 :     throw(AipsError("Spurious call to selfGatherAndSolve() with useGenericGatherForSolve()=T."));
    3965             :   else
    3966           0 :     throw(AipsError("Attempt to call un-implemented selfGatherAndSolve()"));
    3967             : 
    3968             : }
    3969           0 : void SolvableVisCal::selfSolveOne(VisBuffGroupAcc&) {
    3970             :     
    3971           0 :   if (useGenericSolveOne())
    3972           0 :     throw(AipsError("Spurious call to selfSolveOne() with useGenericSolveOne()=T."));
    3973             :   else
    3974           0 :     throw(AipsError("Attempt to call un-implemented selfSolveOne()"));
    3975             : 
    3976             : }
    3977             : 
    3978             :      
    3979           0 : void SolvableVisCal::updatePar(const Vector<Complex> dCalPar,const Vector<Complex> dSrcPar) {
    3980             : 
    3981           0 :   AlwaysAssert((solveCPar().nelements()==dCalPar.nelements()),AipsError);
    3982             : 
    3983           0 :   Cube<Complex> dparcube(dCalPar.reform(solveCPar().shape()));
    3984             : 
    3985             :   // zero flagged increments
    3986           0 :   dparcube(!solveParOK())=Complex(0.0);
    3987             :   
    3988             :   // Add the increment
    3989           0 :   solveCPar()+=dparcube;
    3990             : 
    3991             :   // Update source params
    3992           0 :   if (solvePol()) {
    3993           0 :     srcPolPar()+=dSrcPar;
    3994             :     //    cout << "Updated Q,U = " << real(srcPolPar()) << endl;
    3995             :   }
    3996             : 
    3997             :   // The matrices are nominally out-of-sync now
    3998           0 :   invalidateCalMat();
    3999             : 
    4000             :   // Ensure phaseonly-ness, if necessary
    4001             :   //  if (apmode()=='P') {   
    4002             :   //  NB: Disable this, for the moment (07May24); testing a fix for
    4003             :   //      a problem Kumar noticed.  See VC::makeSolnPhaseOnly(), etc.
    4004             :   if (false) {
    4005             :     Float amp(0.0);
    4006             :     for (Int iant=0;iant<nAnt();++iant) {
    4007             :       for (Int ipar=0;ipar<nPar();++ipar) {
    4008             :         if (solveParOK()(ipar,0,iant)) {
    4009             :           amp=abs(solveCPar()(ipar,0,iant));
    4010             :           if (amp>0.0)
    4011             :             solveCPar()(ipar,0,iant)/=amp;
    4012             :         }
    4013             :       }
    4014             :     }
    4015             :   }
    4016           0 : }
    4017             : 
    4018       67731 : void SolvableVisCal::updatePar(const Vector<Complex> dPar) { // VI2
    4019             : 
    4020       67731 :   AlwaysAssert((solveCPar().nelements()==dPar.nelements()),AipsError);
    4021             : 
    4022       67731 :   Cube<Complex> dparcube(dPar.reform(solveCPar().shape()));
    4023             : 
    4024             :   // zero flagged increments
    4025       67731 :   dparcube(!solveParOK())=Complex(0.0);
    4026             :   
    4027             :   // Add the increment
    4028       67731 :   solveCPar()+=dparcube;
    4029             : 
    4030             :   // The matrices are nominally out-of-sync now
    4031       67731 :   invalidateCalMat();
    4032             : 
    4033             :   // Ensure phaseonly-ness, if necessary
    4034             :   //  if (apmode()=='P') {   
    4035             :   //  NB: Disable this, for the moment (07May24); testing a fix for
    4036             :   //      a problem Kumar noticed.  See VC::makeSolnPhaseOnly(), etc.
    4037             :   if (False) {
    4038             :     Float amp(0.0);
    4039             :     for (Int iant=0;iant<nAnt();++iant) {
    4040             :       for (Int ipar=0;ipar<nPar();++ipar) {
    4041             :         if (solveParOK()(ipar,0,iant)) {
    4042             :           amp=abs(solveCPar()(ipar,0,iant));
    4043             :           if (amp>0.0)
    4044             :             solveCPar()(ipar,0,iant)/=amp;
    4045             :         }
    4046             :       }
    4047             :     }
    4048             :   }
    4049       67731 : }
    4050             : 
    4051             : 
    4052        9334 : void SolvableVisCal::formSolveSNR() {
    4053             : 
    4054             :   // Nominally zero
    4055        9334 :   solveParSNR()=0.0;
    4056             : 
    4057      117758 :   for (Int iant=0;iant<nAnt();++iant) {
    4058      251752 :     for (Int ipar=0;ipar<nPar();++ipar) {
    4059      143328 :       if (solveParOK()(ipar,0,iant)) {
    4060      140572 :         if (solveParErr()(ipar,0,iant)>0.0f) 
    4061      140572 :           solveParSNR()(ipar,0,iant)=abs(solveCPar()(ipar,0,iant))/solveParErr()(ipar,0,iant);
    4062             :         else 
    4063             :           // if error is zero, SNR is officially infinite; use a (large) special value here
    4064           0 :           solveParSNR()(ipar,0,iant)=9999999.0;
    4065             :       } // ok
    4066             :     } // ipar
    4067             :   } // iant
    4068             : 
    4069        9334 : }
    4070             : 
    4071        9414 : void SolvableVisCal::applySNRThreshold() {
    4072             : 
    4073        9414 :   Int nOk1(ntrue(solveParOK()));
    4074             :     
    4075        9414 :   std::map<casacore::Int, std::map<casacore::String, casacore::Vector<casacore::Int>>> resultMap;
    4076        9414 :   Vector<Int> initVector(nPar(), 0);
    4077        9414 :   Vector<Int> initVectorSingle(1, 0);
    4078             :   
    4079      118638 :   for (Int iant=0;iant<nAnt();++iant) {
    4080             :     //if (refant() == iant) {
    4081             :     //  antennaMap_[iant]["used_as_refant"][0] += 1;
    4082             :     //}
    4083      254152 :     for (Int ipar=0;ipar<nPar();++ipar) {
    4084             :       //antennaMap_[iant]["expected"][ipar] += 1;
    4085      144928 :       if (solveParOK()(ipar,0,iant)){
    4086      142172 :             solveParOK()(ipar,0,iant)=(solveParSNR()(ipar,0,iant)>minSNR());
    4087             :         //antennaMap_[iant]["data_unflagged"][ipar] += 1;
    4088      142172 :         if (solveParOK()(ipar,0,iant)) {antennaMap_[iant]["above_minsnr"][ipar] = 1;};
    4089             :       }
    4090             :     }
    4091             :   }
    4092             :   
    4093             :   //cout << pexp << endl;
    4094             :     
    4095        9414 :   Int nOk2(ntrue(solveParOK()));
    4096        9414 :   Int nFail=nOk1-nOk2;
    4097             :   
    4098             :   if (false) {
    4099             :     // Report some stuff re SNR
    4100             :     cout << endl 
    4101             :          << "Time = " << MVTime(refTime()/C::day).string(MVTime::YMD,7) << endl;
    4102             :     cout << "SNR      = " << solveParSNR() << endl;
    4103             :     cout << nOk1 << " " << nOk2 << " " << nFail << endl;
    4104             :     Float meansnr(0.0f);
    4105             :     if (ntrue(solveParOK())>0) {
    4106             :       meansnr=mean(solveParSNR()(solveParOK()));
    4107             :       cout << "mean solution SNR = " << meansnr
    4108             :            << " (passing threshold)."
    4109             :            << endl;
    4110             :     }
    4111             :   }
    4112             :   
    4113        9414 :   if (nFail>0) {
    4114         676 :     cout << nFail << " of " << nOk1
    4115         676 :          << " solutions flagged due to SNR < " << minSNR() 
    4116         676 :          << " in spw=" << currSpw();
    4117             :     // if multi-chan, report channel
    4118         676 :     if (freqDepPar())
    4119         236 :       cout << " (chan="<<focusChan()<<")";
    4120             : 
    4121        1352 :     cout << " at " << MVTime(refTime()/C::day).string(MVTime::YMD,7)
    4122         676 :          << endl;
    4123             :   }
    4124             : 
    4125        9414 : }
    4126             : 
    4127             : // Return the cal flag record, with tableName included
    4128         104 : Record SolvableVisCal::actionRec() {
    4129         104 :   Record cf;
    4130         104 :   cf.define("table",calTableName());
    4131         104 :   cf.merge(VisCal::actionRec());
    4132         104 :   return cf;
    4133           0 : }
    4134             : 
    4135         167 : Record SolvableVisCal::solveActionRec() {
    4136             : 
    4137             :   // Return empty record
    4138             :   //  TBD: consider returning various _generic_ info
    4139             :   //  NB: specialization may add particulars via merge
    4140         167 :   Record r;
    4141         167 :   return r;
    4142             : }
    4143             : 
    4144             : 
    4145             : 
    4146             : 
    4147             : 
    4148           8 : void SolvableVisCal::smooth(Vector<Int>& fields,
    4149             :                             const String& smtype,
    4150             :                             const Double& smtime) {
    4151             : 
    4152           8 :   if (smoothable()) 
    4153             :     // Call NewCalTable's global smooth method
    4154           8 :     casa::smoothCT(*ct_,smtype,smtime,fields);
    4155             :   else
    4156           0 :     throw(AipsError("This type "+this->typeName()+" does not support smoothing!"));
    4157             : 
    4158           8 : }
    4159             : 
    4160      329767 : void SolvableVisCal::syncSolveCal() {
    4161             : 
    4162      329767 :   if (prtlev()>4) cout << "    SVC::syncSolveCal()" << endl;
    4163             :   
    4164             :   // Ensure parameters are ready
    4165      329767 :   syncSolvePar();
    4166             : 
    4167      329767 :   if (!PValid())
    4168           0 :     throw(AipsError("No valid parameters in syncSolveCal"));
    4169             : 
    4170             :   // Sync up matrices using current params
    4171      329767 :   syncCalMat(false);    // NEVER invert in solve context
    4172      329767 :   syncDiffMat();
    4173             : 
    4174      329767 : }
    4175      334299 : void SolvableVisCal::syncSolvePar() {
    4176             : 
    4177      334299 :   if (prtlev()>5) cout << "      SVC::syncSolvePar()" << endl;
    4178             : 
    4179             :   // In solve context, reference solveCPar(), etc.
    4180      334299 :   AlwaysAssert((solveCPar().nelements()>0 || solveRPar().nelements()>0),AipsError);
    4181      334299 :   currCPar().reference(solveCPar());
    4182      334299 :   currRPar().reference(solveRPar());
    4183      334299 :   currParOK().reference(solveParOK());
    4184      334299 :   validateP();
    4185             : 
    4186      334299 : }
    4187             : 
    4188      297261 : void SolvableVisCal::calcPar() {
    4189             : 
    4190      297261 :   if (simOnTheFly() and isSimulated()) {
    4191        4532 :     if (prtlev()>3) cout << "SVC:calcPar triggered simOTF with isSolved=" << isSolved()
    4192           0 :          << " isApplied=" << isApplied() << " isSimulated=" << isSimulated() << endl;
    4193        4532 :     syncSolvePar(); // OTF simulation context RI 20100831    
    4194             :   } else { 
    4195             : 
    4196      292729 :   if (prtlev()>6) cout << "      SVC::calcPar()" << endl;
    4197             : 
    4198             :   // This method is relevant only to the apply (& simulate) context
    4199             : 
    4200             :   // If we have a CLPatchPanel, use it
    4201      292729 :   if (cpp_)
    4202       30582 :     this->calcParByCLPP();
    4203             :   else { // use CTPatchedInterp
    4204             : 
    4205      262147 :   Bool newcal(false);
    4206             : 
    4207             :   // Interpolate solution   (CTPatchedInterp)
    4208      262147 :   if (freqDepPar()) {
    4209             : 
    4210             :     //cout << "currFreq() = " << currFreq().shape() << " " << currFreq() << endl;
    4211             : 
    4212             :     // Call w/ freq-dep
    4213       11845 :     if (fInterpType().contains("rel")) {
    4214             :       // Relative freq
    4215           0 :       Double freqOff(msmc().centerFreq(currSpw()));
    4216           0 :       Double SBfactor(1.0);
    4217           0 :       if (currFreq().nelements()>1 && currFreq()(0)>currFreq()(1))
    4218           0 :         SBfactor=-1.0f;
    4219             :       //cout << "freqOff=" << freqOff << " SBfactor=" << SBfactor << " netSB=" << msmc().msmd().getNetSidebands()[currSpw()] << endl;
    4220           0 :       newcal=ci_->interpolate(currObs(),currScan(),currField(),currSpw(),currTime(),(currFreq()-freqOff)*SBfactor);
    4221             :     }
    4222             :     else
    4223             :       // absolute freq
    4224       11845 :       newcal=ci_->interpolate(currObs(),currScan(),currField(),currSpw(),currTime(),currFreq());
    4225             : 
    4226             :     //    cout.precision(12);
    4227             :     //    cout << typeName() << " t="<< currTime() << " newcal=" << boolalpha << newcal << endl;
    4228             :   }
    4229             :   else {
    4230      250302 :     if (parType()==VisCalEnum::COMPLEX)
    4231             :       // Call w/ fiducial freq for phase-delay correction
    4232             :       // TBD: improve freq spec, e.g., use spw center freq rather than _selected_ center
    4233      245654 :       newcal=ci_->interpolate(currObs(),currScan(),currField(),currSpw(),currTime(),1.0e9*currFreq()(currFreq().nelements()/2));
    4234             :     else
    4235             :       // No freq info at all
    4236        4648 :       newcal=ci_->interpolate(currObs(),currScan(),currField(),currSpw(),currTime());
    4237             :   }
    4238             : 
    4239             :   // TBD: signal failure to find calibration??  (e.g., for a spw?)
    4240             : 
    4241             :   // Parameters now (or still) valid (independent of newcal!!)
    4242      262147 :   validateP();
    4243             : 
    4244             :   // If new cal parameters, use them 
    4245      262147 :   if (newcal) {
    4246             : 
    4247             :     //    cout << "Found new cal!" << endl;
    4248             :     
    4249             :     // Reference result
    4250       63957 :     if (parType()==VisCalEnum::COMPLEX) 
    4251       58735 :       currCPar().reference(ci_->resultC(currObs(),currScan(),currField(),currSpw()));
    4252        5222 :     else if (parType()==VisCalEnum::REAL) 
    4253        5222 :       currRPar().reference(ci_->resultF(currObs(),currScan(),currField(),currSpw()));
    4254             :     else
    4255           0 :       throw(AipsError("Bad parType() in SVC::calcPar"));
    4256             : 
    4257             :     // Assign _inverse_ of parameter flags
    4258       63957 :     currParOK().reference(!ci_->rflag(currObs(),currScan(),currField(),currSpw()));
    4259             : 
    4260             :     // Ensure shapes recorded correctly
    4261             :     // (New interpolation generates cal samples for all data channels...revisit?
    4262       63957 :     IPosition ip=currCPar().shape();
    4263       63957 :     nChanPar()=ip(1);
    4264       63957 :     startChan()=0;
    4265             : 
    4266             :     // In case we need solution timestamp
    4267             :     // NB: w/ new caltables, we use currTime() here.
    4268       63957 :     refTime() = currTime();
    4269             : 
    4270             :     // If new parameters, matrices (generically) are necessarily invalid now
    4271       63957 :     invalidateCalMat();
    4272       63957 :   }
    4273             :   }
    4274             :   }
    4275             : 
    4276      297261 : }
    4277             : 
    4278       30582 : void SolvableVisCal::calcParByCLPP() {
    4279             : 
    4280       30582 :   Bool newcal(false);
    4281       30582 :   Cube<Bool> resFlag;
    4282             : 
    4283             :   // Interpolate solution   
    4284       30582 :   switch (parType()) {
    4285       28182 :   case VisCalEnum::COMPLEX: {
    4286             : 
    4287       28182 :     if (freqDepPar()) {
    4288             :       // Call w/ freq-dep
    4289         240 :       newcal=cpp_->interpolate(currCPar(),resFlag,currObs(),currScan(),currField(),currIntent(),currSpw(),currTime(),currFreq());
    4290             :     }
    4291             :     else {
    4292             :       // Call w/ fiducial freq for phase-delay correction
    4293       27942 :       Double freq=1.0e9*currFreq()(currFreq().nelements()/2);
    4294       27942 :       newcal=cpp_->interpolate(currCPar(),resFlag,currObs(),currScan(),currField(),currIntent(),currSpw(),currTime(),freq);
    4295             :     }
    4296       28182 :     break;
    4297             :   }
    4298        2400 :   case VisCalEnum::REAL: {
    4299             :     // Interpolate solution   
    4300        2400 :     if (freqDepPar()) {
    4301             :       // Call w/ freq-dep
    4302           0 :       newcal=cpp_->interpolate(currRPar(),resFlag,currObs(),currScan(),currField(),currIntent(),currSpw(),currTime(),currFreq());
    4303             :     }
    4304             :     else {
    4305        2400 :       newcal=cpp_->interpolate(currRPar(),resFlag,currObs(),currScan(),currField(),currIntent(),currSpw(),currTime(),-1.0);
    4306             :     }
    4307        2400 :     break;
    4308             :   }
    4309           0 :   default:
    4310           0 :     throw(AipsError("Unhandled parType()")); // users should never see this
    4311             :     break;
    4312             :   }
    4313             : 
    4314             :   // TBD: signal failure to find calibration??  (e.g., for a spw?)
    4315             : 
    4316             :   // Parameters now (or still) valid (independent of newcal!!)
    4317       30582 :   validateP();
    4318             : 
    4319       30582 :   if (newcal) {
    4320             :  
    4321             :     // Assign _inverse_ of parameter flags
    4322       27088 :     currParOK().reference(!resFlag);
    4323             : 
    4324             :     // Ensure shapes recorded correctly
    4325             :     // (New interpolation generates cal samples for all data channels...revisit?
    4326             :     //  IS THIS NEEDED?
    4327       27088 :     IPosition ip=currCPar().shape();
    4328       27088 :     nChanPar()=ip(1);
    4329       27088 :     startChan()=0;
    4330             : 
    4331             :     // In case we need solution timestamp
    4332             :     // NB: w/ new caltables, we use currTime() here.
    4333       27088 :     refTime() = currTime();
    4334             : 
    4335             :     // If new parameters, matrices (generically) are necessarily invalid now
    4336       27088 :     invalidateCalMat();
    4337       27088 :   }
    4338             : 
    4339       30582 : }
    4340             : 
    4341             : 
    4342             : // Report solved-for QU
    4343           7 : void SolvableVisCal::reportSolvedQU() {
    4344             : 
    4345           7 :   String fldname(msmc().fieldName(currField()));
    4346             : 
    4347           7 :   if (solvePol()==2) {
    4348           7 :     Float Q=real(srcPolPar()(0));
    4349           7 :     Float U=real(srcPolPar()(1));
    4350           7 :     Float P=sqrt(Q*Q + U*U);
    4351           7 :     Float X=atan2(U,Q)/2.0*180.0/C::pi;
    4352             : 
    4353             :     logSink() << "Fractional polarization solution for " << fldname
    4354           7 :               << " (spw = " << currSpw() << "): "
    4355             :               << ": Q = " << Q
    4356             :               << ", U = " << U
    4357             :               << "  (P = " << P
    4358             :               << ", X = " << X << " deg)"
    4359           7 :               << LogIO::POST;
    4360             :   }
    4361           0 :   else if (solvePol()==1) {
    4362             :     logSink() << "Position angle offset solution for " << fldname
    4363           0 :               << " (spw = " << currSpw() << ") = "
    4364           0 :               << real(srcPolPar()(0))*180.0/C::pi/2.0
    4365             :               << " deg."
    4366           0 :               << LogIO::POST;
    4367             :   }
    4368           7 : }
    4369             : 
    4370         268 : void SolvableVisCal::createMemCalTable() {
    4371             : 
    4372             :   //  cout << "createMemCalTable" << endl;
    4373             : 
    4374             :   // Set up description
    4375         268 :   String partype = ((parType()==VisCalEnum::COMPLEX) ? "Complex" : "Float");
    4376             : 
    4377         268 :   if (msName()!="<noms>") {
    4378         536 :     CTDesc caltabdesc(partype,Path(msName()).baseName(),typeName(),"unknown");
    4379         268 :     ct_ = new NewCalTable("tempNCT.tab",caltabdesc,Table::Scratch,Table::Memory)
    4380             : ;
    4381         268 :     ct_->setMetaInfo(msName());
    4382         268 :   }
    4383             :   else {
    4384           0 :     ct_ = new NewCalTable("tempNCT.tab",partype,typeName(),msmc().ssp(),
    4385           0 :                           false,true);
    4386             :   }
    4387             : 
    4388         268 :   CTColumns ncc(*ct_);
    4389             : 
    4390             :   // Revise SPW frequencies
    4391        6495 :   for (Int ispw=0;ispw<nSpw();++ispw) {
    4392             : 
    4393        6227 :     currSpw()=ispw;
    4394             : 
    4395             :     // MS freqs
    4396        6227 :     Vector<Double> chfr,chwid,chres,cheff;
    4397        6227 :     ncc.spectralWindow().chanFreq().get(ispw,chfr);
    4398        6227 :     ncc.spectralWindow().chanWidth().get(ispw,chwid);
    4399        6227 :     ncc.spectralWindow().resolution().get(ispw,chres);
    4400        6227 :     ncc.spectralWindow().effectiveBW().get(ispw,cheff);
    4401             : 
    4402        6227 :     Int nchan=0;
    4403        6227 :     Vector<Double> calfreq,calwid,calres,caleff;
    4404        6227 :     if (startChan()>-1 && nChanPar()>0) {
    4405             : 
    4406        6227 :       if (freqDepPar()) { 
    4407         701 :         if (fsolint()!="none") {
    4408           0 :           IPosition blc(1,0),trc(1,0);
    4409           0 :           Matrix<Int> bounds(chanAveBounds());
    4410           0 :           nchan=bounds.nrow();
    4411           0 :           calfreq.resize(nchan);
    4412           0 :           calwid.resize(nchan);
    4413           0 :           calres.resize(nchan);
    4414           0 :           caleff.resize(nchan);
    4415           0 :           cout.precision(12);
    4416           0 :           for (Int ochan=0;ochan<nchan;++ochan) {
    4417           0 :             blc(0)=bounds(ochan,0);
    4418           0 :             trc(0)=bounds(ochan,1);
    4419           0 :             calfreq(ochan)=mean(chfr(blc,trc));
    4420           0 :             calwid(ochan)=sum(chwid(blc,trc));
    4421           0 :             calres(ochan)=sum(chres(blc,trc));
    4422           0 :             caleff(ochan)=sum(cheff(blc,trc));
    4423             :           }
    4424           0 :         }
    4425             :         else {
    4426         701 :           nchan=nChanPar();
    4427         701 :           if (nChanPar()<Int(chfr.nelements())) {
    4428           0 :             calfreq=chfr(Slice(startChan(),nChanPar()));
    4429           0 :             calwid=chwid(Slice(startChan(),nChanPar()));
    4430           0 :             calres=chres(Slice(startChan(),nChanPar()));
    4431           0 :             caleff=cheff(Slice(startChan(),nChanPar()));
    4432             :           }
    4433             :           else {
    4434         701 :             calfreq.reference(chfr);
    4435         701 :             calwid.reference(chwid);
    4436         701 :             calres.reference(chres);
    4437         701 :             caleff.reference(cheff);
    4438             :           }
    4439             :         }
    4440             :       }
    4441             :       else {
    4442        5526 :         nchan=1;
    4443        5526 :         calfreq.resize(1);
    4444        5526 :         calwid.resize(1);
    4445        5526 :         calres.resize(1);
    4446        5526 :         caleff.resize(1);
    4447             :         // Use simple mean freq, and aggregate bandwidth
    4448        5526 :         calfreq(0)=mean(chfr);
    4449        5526 :         calwid(0)=sum(chwid);
    4450        5526 :         calres(0)=sum(chres);
    4451        5526 :         caleff(0)=sum(cheff);
    4452             :       }
    4453             :     }
    4454             :     //    cout << "nchan=" << nchan << " calfreq.nelements() = " << calfreq.nelements() << " " << calfreq << endl;
    4455        6227 :     if (nchan>0) {
    4456        6227 :       ncc.spectralWindow().chanFreq().setShape(ispw,IPosition(1,nchan));
    4457             :       //      cout << "ncc.spectralWindow().chanFreq().shape(ispw)         = " << ncc.spectralWindow().chanFreq().shape(ispw) << endl;
    4458        6227 :       ncc.spectralWindow().chanFreq().put(ispw,calfreq);
    4459        6227 :       ncc.spectralWindow().chanWidth().put(ispw,calwid);
    4460        6227 :       ncc.spectralWindow().resolution().put(ispw,calres);  // same as chanWidth, for now
    4461        6227 :       ncc.spectralWindow().effectiveBW().put(ispw,caleff);  // same as chanWidth, for now
    4462        6227 :       ncc.spectralWindow().numChan().put(ispw,nchan);
    4463        6227 :       ncc.spectralWindow().totalBandwidth().put(ispw,abs(sum(calwid)));
    4464             :     }
    4465             :     else
    4466           0 :       ncc.spectralWindow().flagRow().put(ispw,true);
    4467        6227 :   }
    4468             : 
    4469             :   // When combining in spw, further revise freq info to average over combined spws
    4470             :   //  Only for freqDepPar()=false types, for now (nothing bandpass-like)
    4471             :   //  NB: Currently, this will only handle a single aggregation..., e.g., not CAS-5687
    4472         268 :   if (combspw() && !freqDepPar()) {
    4473             : 
    4474             :     try {
    4475             : 
    4476           2 :     Matrix<Double> chanFreq,chanWidth,effectiveBW;
    4477           2 :     ncc.spectralWindow().chanFreq().getColumn(chanFreq,true);
    4478           2 :     ncc.spectralWindow().chanWidth().getColumn(chanWidth,true);
    4479           2 :     ncc.spectralWindow().effectiveBW().getColumn(effectiveBW,true);
    4480             : 
    4481             :     // Insist on a single channel!   (NO BANDPASS-LIKE TYPES!)
    4482           2 :     Int nChan=chanFreq.shape()[0];
    4483           2 :     AlwaysAssert(nChan==1,AipsError);
    4484             : 
    4485           2 :     Vector<Bool> spwmask=(spwMap()>-1);
    4486           2 :     Int outSpw=Vector<Int>(spwMap()(spwmask).getCompressedArray())[0];
    4487             : 
    4488             :     // If only one chan, then the chanWidth should span the the whole spw range
    4489             :     //  NB: this is done before the chanFreq are revised, below
    4490             :     //  NB: Disabled for now, since centroid freq +/- wid/2 doesn't actually
    4491             :     //      cover the input spw range, in general....more thought necessary here
    4492             :     //      So keep the single spw width, for now, for which there remains
    4493             :     //      a reasonable argument (the phase correction is ~appropriate over this
    4494             :     //      limited range without further refinement...)  (the width isn't used
    4495             :     //      decisively anywhere yet, in any case)
    4496             :     if (false) {
    4497             :       
    4498             :       Vector<Double> f(chanFreq.row(0));
    4499             :       Vector<Double> chW(chanWidth.row(0));
    4500             :       Vector<Double> flo=f-chW/2.0;
    4501             :       Vector<Double> fhi=f+chW/2.0;
    4502             : 
    4503             :       if (allGT(fhi,flo))
    4504             :         // USB  (positive result)
    4505             :         chW(outSpw)=max(fhi(spwmask))-min(flo(spwmask));
    4506             :       else
    4507             :         // LSB  (negative result)
    4508             :         chW(outSpw)=min(fhi(spwmask))-max(flo(spwmask));
    4509             : 
    4510             :     }
    4511             : 
    4512             :     // Assumes single channel!
    4513           2 :     Vector<Double> f(chanFreq.row(0));
    4514           2 :     Vector<Double> ebw(effectiveBW.row(0));
    4515           2 :     Double meanfreq=sum(f(spwmask)*ebw(spwmask));
    4516           2 :     Double sumebw=sum(ebw(spwmask));
    4517           2 :     meanfreq/=sumebw;
    4518             :     
    4519           2 :     f(outSpw)=meanfreq;
    4520           2 :     ebw(outSpw)=sumebw;
    4521             : 
    4522             :     /*
    4523             :     cout << "spwmask = " << boolalpha << spwmask << endl;
    4524             :     cout << "chanFreq(:,outSpw)    = " << chanFreq.column(outSpw) << endl;
    4525             :     cout << "chanWidth(:,outSpw)   = " << chanWidth.column(outSpw) << endl;
    4526             :     cout << "effectiveBW(:,outSpw) = " << effectiveBW.column(outSpw) << endl;
    4527             :     */
    4528             : 
    4529             : 
    4530           2 :     ncc.spectralWindow().chanFreq().putColumn(chanFreq);
    4531           2 :     ncc.spectralWindow().chanWidth().putColumn(chanWidth);
    4532           2 :     ncc.spectralWindow().effectiveBW().putColumn(effectiveBW);
    4533           2 :     }
    4534           0 :     catch (...) {
    4535           0 :       throw(AipsError("Error calculating solution frequencies w/ combine='spw'"));
    4536           0 :     }
    4537             :   }
    4538             : 
    4539         268 : }
    4540             : 
    4541             : // File a single-channel solved solution into the multi-channel space for it
    4542        1278 : void SolvableVisCal::keep1(Int ichan) {
    4543        1278 :   if (parType()==VisCalEnum::COMPLEX)
    4544        1278 :     solveAllCPar()(Slice(),Slice(ichan,1),Slice())=solveCPar();
    4545           0 :   else if (parType()==VisCalEnum::REAL)
    4546           0 :     solveAllRPar()(Slice(),Slice(ichan,1),Slice())=solveRPar();
    4547             : 
    4548        1278 :   solveAllParOK()(Slice(),Slice(ichan,1),Slice())=solveParOK();
    4549        1278 :   solveAllParErr()(Slice(),Slice(ichan,1),Slice())=solveParErr();
    4550        1278 :   solveAllParSNR()(Slice(),Slice(ichan,1),Slice())=solveParSNR();
    4551        1278 : }
    4552             : 
    4553         668 : Bool SolvableVisCal::spwOK(Int ispw) {
    4554             : 
    4555         668 :   if (isSolved())
    4556           0 :     return spwOK_(ispw);
    4557             : 
    4558         668 :   if (isApplied() && ci_)
    4559             :     // Get it from the interpolator (w/ spwmap)
    4560         650 :     return spwOK_(ispw)=ci_->spwOK(ispw);
    4561             :   else {
    4562             :     // Assume ok (e.g., non-ci_ types like TOpac, GainCurve)
    4563             :     // TBD: be more careful by specializing this method
    4564          18 :     return true;
    4565             :   }
    4566             : }
    4567             : 
    4568             : // Is the data in this VB calibrate-able?  This replaces the old spwOK and
    4569             : //   is more specific as regards obs, fld, intent.  Used at wide scopes
    4570             : //   (Calibrater/VisEquation) to control entering expensive loops.
    4571             : // "OK for Cal" or "Calibrate-able" here means:
    4572             : //   a) this SVC can actually calibrate the data within the VB because
    4573             : //       there are solutions explicitly available to do it (see
    4574             : //       SVC::calAvailable(vb) below)
    4575             : // OR
    4576             : //   b) that this SVC is agnostic about the data within the VB according
    4577             : //       to arrangements made by CalLibrary specifictions and
    4578             : //       embodied within the CLPatchPanel (cpp_).  Agnosticism is
    4579             : //       supported ONLY when using the CalLibrary and CLPatchPanel
    4580      287363 : Bool SolvableVisCal::VBOKforCalApply(vi::VisBuffer2& vb) {
    4581             : 
    4582             :   // Current spw
    4583             :   //  TBD: Use syncMeta2?
    4584      287363 :   const Int& ispw(vb.spectralWindows()(0));
    4585             : 
    4586      287363 :   if (isSolved())
    4587           0 :     return spwOK_(ispw);
    4588             : 
    4589      287363 :   if (isApplied()) {
    4590             : 
    4591      287363 :     if (ci_)
    4592             :       // Get it from the old-fashioned CTPatchedInterp
    4593      257321 :       return spwOK_(ispw)=ci_->spwOK(ispw);
    4594             : 
    4595       30042 :     else if (cpp_) {
    4596             :       // Get it from the new CLPatchPanel, which has
    4597             :       //  obs, fld, intent specificity, too!
    4598       30042 :       const Int& iobs(vb.observationId()(0));
    4599       30042 :       const Int& iscan(vb.scan()(0));
    4600       30042 :       const Int& ifld(vb.fieldId()(0));
    4601       30042 :       const Int& ient(vb.stateId()(0));
    4602       30042 :       return cpp_->MSIndicesOK(iobs,iscan,ifld,ient,ispw,-1); // all ants
    4603             :     }
    4604             :     else
    4605             :       // Assume ok for non-interpolable types
    4606           0 :       return true;
    4607             :   }
    4608             : 
    4609             :   // Shouldn't reach here, assume true (could trigger failure elsewhere)
    4610           0 :   return true;
    4611             : 
    4612             : }
    4613             : 
    4614             : // Is calibration for the specified VB actually available?
    4615             : //  This returns true when condition "a" described above
    4616             : //  is true.  If the CLPatchPanel is agnostic, this returns
    4617             : //  false.  This is used by VisCal::correct2 control whether
    4618             : //  calibration update and algebraic apply can/should be done. 
    4619             : //  In the CalLibrary context, this enables agnosticism (when
    4620             : //  false)
    4621             : //  The implementation here is almost the same as VBOKforCal,
    4622             : //   differing only in the call to cpp_->calAvailable.
    4623      288061 : Bool SolvableVisCal::calAvailable(vi::VisBuffer2& vb) {
    4624             : 
    4625             :   // Current spw
    4626             :   //  TBD: Use syncMeta2?
    4627      288061 :   const Int& ispw(vb.spectralWindows()(0));
    4628             : 
    4629      288061 :   if (isSolved())
    4630           0 :     return spwOK_(ispw);
    4631             : 
    4632      288061 :   if (isApplied()) {
    4633             : 
    4634      288061 :     if (ci_)
    4635             :       // Get it from the old-fashioned CTPatchedInterp
    4636      257479 :       return spwOK_(ispw)=ci_->spwOK(ispw);
    4637             : 
    4638       30582 :     else if (cpp_) {
    4639             :       // Get it from the new CLPatchPanel, which has
    4640             :       //  obs, fld, intent specificity, too!
    4641       30582 :       const Int& iobs(vb.observationId()(0));
    4642       30582 :       const Int& iscan(vb.scan()(0));
    4643       30582 :       const Int& ifld(vb.fieldId()(0));
    4644       30582 :       const Int& ient(vb.stateId()(0));
    4645       30582 :       return cpp_->calAvailable(iobs,iscan,ifld,ient,ispw,-1); // all ants
    4646             :     }
    4647             :     else
    4648             :       // Assume ok for non-interpolable types
    4649           0 :       return true;
    4650             :   }
    4651             : 
    4652             :   // Shouldn't reach here, assume true (could trigger failure elsewhere)
    4653           0 :   return true;
    4654             : 
    4655             : }
    4656             : 
    4657             : 
    4658             : 
    4659             : // File a solved solution (and meta-data) into the in-memory Caltable
    4660       27720 : void SolvableVisCal::keepNCT() {
    4661             : 
    4662             :   // TBD: set CalTable freq info here
    4663             :   //  if (!spwOK(currSpw()))
    4664             :   //    setSpwFreqInCT(currSpw(),currFreq());
    4665             : 
    4666       27720 :   if (prtlev()>4) 
    4667           0 :     cout << " SVC::keepNCT" << endl;    
    4668             : 
    4669             :   // Add some rows to fill 
    4670             :   //  nElem() gets it right for both baseline- and antenna-based
    4671       27720 :   ct_->addRow(nElem());
    4672             : 
    4673       27720 :   CTMainColumns ncmc(*ct_);
    4674             : 
    4675             :   // We are adding to the most-recently added rows
    4676       27720 :   RefRows rows(ct_->nrow()-nElem(),ct_->nrow()-1,1); 
    4677             : 
    4678             :   // Meta-info
    4679       27720 :   ncmc.time().putColumnCells(rows,Vector<Double>(nElem(),refTime()));
    4680       27720 :   ncmc.fieldId().putColumnCells(rows,Vector<Int>(nElem(),currField()));
    4681       27720 :   ncmc.spwId().putColumnCells(rows,Vector<Int>(nElem(),currSpw()));
    4682       27720 :   ncmc.scanNo().putColumnCells(rows,Vector<Int>(nElem(),currScan()));
    4683       27720 :   ncmc.obsId().putColumnCells(rows,Vector<Int>(nElem(),currObs()));
    4684       27720 :   ncmc.interval().putColumnCells(rows,Vector<Double>(nElem(),0.0));
    4685             : 
    4686             :   // Params
    4687       27720 :   if (parType()==VisCalEnum::COMPLEX)
    4688             :     // Fill Complex column
    4689       21787 :     ncmc.cparam().putColumnCells(rows,solveAllCPar());
    4690        5933 :   else if (parType()==VisCalEnum::REAL)
    4691             :     // Fill Float column
    4692        5933 :     ncmc.fparam().putColumnCells(rows,solveAllRPar());
    4693             : 
    4694             :   // Stats
    4695       27720 :   ncmc.paramerr().putColumnCells(rows,solveAllParErr());
    4696       27720 :   ncmc.snr().putColumnCells(rows,solveAllParSNR());
    4697       27720 :   ncmc.flag().putColumnCells(rows,!solveAllParOK());
    4698             : 
    4699             :   // This spw now has some solutions in it
    4700       27720 :   spwOK_(currSpw())=true;
    4701             : 
    4702       27720 : }
    4703             : 
    4704         108 : void SolvableVisCal::globalPostSolveTinker() {
    4705             : 
    4706             :   // Make solutions phase- or amp-only, if required
    4707         108 :   if (apmode()!="AP") enforceAPonSoln();
    4708             :   
    4709             :   // Apply normalization
    4710         108 :   if (solnorm()) normalize();
    4711             : 
    4712         108 : }
    4713             : 
    4714             : // Divide all solutions by their amplitudes to make them "phase-only"
    4715           2 : void SolvableVisCal::enforceAPonSoln() {
    4716             : 
    4717             :   // VI2: review initializatin of apmode!  (and similar!)
    4718           2 :   if (apmode()=="") return;
    4719             : 
    4720             :   // Only if we have a CalTable, and it is not empty
    4721           2 :   if (ct_ && ct_->nrow()>0) {
    4722             : 
    4723             :     // TBD: trap attempts to enforceAPonSoln a caltable containing FPARAM (non-Complex)?
    4724             : 
    4725             :     logSink() << "Enforcing apmode on solutions." 
    4726           2 :               << LogIO::POST;
    4727             : 
    4728             :     // In this generic version, one normalization factor per spw
    4729           2 :     Block<String> col(3);
    4730           2 :     col[0]="SPECTRAL_WINDOW_ID";
    4731           2 :     col[1]="TIME";
    4732           2 :     col[2]="ANTENNA1";
    4733           2 :     CTIter ctiter(*ct_,col);
    4734             : 
    4735          82 :     while (!ctiter.pastEnd()) {
    4736             : 
    4737          80 :       Array<Complex> par(ctiter.cparam());
    4738          80 :       Array<Bool> fl(ctiter.flag());
    4739          80 :       Array<Float> amps(amplitude(par));
    4740          80 :       par(amps==0.0f)=Complex(1.0);
    4741          80 :       par(fl)=Complex(1.0);
    4742          80 :       amps(amps==0.0f)=1.0f;
    4743          80 :       amps(fl)=1.0f;
    4744             : 
    4745          80 :       Array<Complex> cor(amps.shape());
    4746          80 :       if (apmode()=='P')
    4747             :         // we will scale solns by amp to make them phase-only
    4748          40 :         convertArray(cor,amps);
    4749          40 :       else if (apmode()=='A') {
    4750             :         // we will scale solns by "phase" to make them amp-only
    4751          40 :         cor=par;
    4752          40 :         cor/=amps;
    4753             :       }
    4754             :       
    4755          80 :       if (ntrue(amplitude(cor)==0.0f)==0)
    4756          80 :         par/=cor;
    4757             :       else
    4758           0 :         throw(AipsError("enforceAPonSoln divide-by-zero error."));
    4759             :       
    4760             :       // put result back
    4761          80 :       ctiter.setcparam(par);
    4762             : 
    4763             :       // advance iterator
    4764          80 :       ctiter.next();
    4765          80 :     }
    4766             : 
    4767             : 
    4768           2 :   }
    4769             :   else 
    4770           0 :     throw(AipsError("Solution apmode enforcement not supported."));
    4771             : 
    4772             : }
    4773             : 
    4774           1 : void SolvableVisCal::normalize() {
    4775             : 
    4776             :   // Only if we have a CalTable, and it is not empty
    4777           1 :   if (ct_ && ct_->nrow()>0) {
    4778             : 
    4779             :     // TBD: trap attempts to normalize a caltable containing FPARAM (non-Complex)?
    4780             : 
    4781           2 :     logSink() << "Normalizing solution amplitudes per spw with " << solNorm().normtypeString()
    4782           2 :               << LogIO::POST;
    4783             : 
    4784             :     // In this generic version, one normalization factor per spw
    4785           1 :     Block<String> col(1);
    4786           1 :     col[0]="SPECTRAL_WINDOW_ID";
    4787           1 :     CTIter ctiter(*ct_,col);
    4788             : 
    4789           5 :     while (!ctiter.pastEnd()) {
    4790           4 :       Cube<Complex> p(ctiter.cparam());
    4791           4 :       Cube<Bool> fl(ctiter.flag());
    4792           4 :       if (nfalse(fl)>0) {
    4793           4 :         Complex normfactor=normSolnArray(p,!fl,false);  // don't do phase
    4794           8 :         logSink() << " Normalization factor (" << solNorm().normtypeString() << ") for spw " << ctiter.thisSpw() << " = " << abs(normfactor)
    4795           8 :               << LogIO::POST;
    4796             : 
    4797             :         // record result...
    4798           4 :         ctiter.setcparam(p);
    4799             :       }
    4800           4 :       ctiter.next();
    4801           4 :     }
    4802             : 
    4803           1 :   }
    4804           1 : }
    4805             : 
    4806         473 : void SolvableVisCal::storeNCT() {
    4807             : 
    4808         473 :   if (prtlev()>3) cout << " SVC::storeNCT()" << endl;
    4809             : 
    4810             :   // Escape from attempt to write to an empty name,
    4811             :   //  because this may delete more than one wants
    4812         473 :   if (calTableName().empty())
    4813           0 :     throw(AipsError("Empty string provided for caltable name; this is not allowed."));
    4814             : 
    4815             :   // Flag spws that didn't occur (should do for other meta-info!)
    4816         473 :   ct_->flagAbsentSpws();
    4817             : 
    4818             :   // If append=T and the specified table exists...
    4819         473 :   if (append() && Table::isReadable(calTableName())) {
    4820             : 
    4821             :     // Verify the same type
    4822           6 :     verifyCalTable(calTableName());
    4823             :     
    4824           6 :     logSink() << "Appending solutions to table: " << calTableName()
    4825           6 :               << LogIO::POST;
    4826             :     
    4827             :     // Keep the new in-memory caltable locally
    4828           6 :     NewCalTable *newct=ct_;
    4829           6 :     ct_=NULL;
    4830             : 
    4831             :     // Load the existing table (ct_)
    4832           6 :     loadMemCalTable(calTableName());
    4833             :     
    4834             :     // Verify that both caltables come from the same MS
    4835             :     try {
    4836           6 :       String msn0=ct_->keywordSet().asString("MSName");
    4837           6 :       String msn1=newct->keywordSet().asString("MSName");
    4838           6 :       AlwaysAssert( msn0==msn1, AipsError);
    4839           6 :     }
    4840           0 :     catch ( AipsError err ) {
    4841           0 :       delete newct;  // ct_ will be deleted in dtor
    4842           0 :       throw(AipsError("Cannot append solutions from different MS."));
    4843           0 :     }
    4844             : 
    4845             :     // Merge spw info (carefully) from newct to ct_
    4846             :     try {
    4847           6 :       ct_->mergeSpwMetaInfo(*newct);
    4848             :     }
    4849           0 :     catch ( AipsError err ) {
    4850           0 :       logSink() << err.getMesg() << LogIO::SEVERE;
    4851           0 :       throw(AipsError("Error attempting append=T"));
    4852           0 :     }
    4853             :     
    4854             :     // copy the new onto the existing...
    4855           6 :     TableCopy::copyRows(*ct_,*newct,ct_->nrow(),0,newct->nrow());
    4856             :     
    4857             :     // Delete the local pointer to the new solutions
    4858             :     //  NB: ct_ will be deleted by dtor (after writeToDisk below)
    4859           6 :     delete newct;
    4860             :    
    4861             :     // At this point, ct_ contains old and new solutions in memory
    4862             : 
    4863             :   }
    4864             :   else
    4865         467 :     logSink() << "Writing solutions to table: " << calTableName()
    4866         467 :               << LogIO::POST;
    4867             :   
    4868             :   // Write out the table to disk (regardless of what happened above)
    4869             :   //  (this will sort)
    4870         473 :   ct_->writeToDisk(calTableName());
    4871             : 
    4872         473 : }
    4873             : 
    4874          29 : void SolvableVisCal::storeNCT(const String& table,const Bool& append) {
    4875             : 
    4876          29 :   if (prtlev()>3) cout << " SVC::store(table,append)" << endl;
    4877             : 
    4878             :   // Override tablename
    4879          29 :   calTableName()=table;
    4880          29 :   SolvableVisCal::append()=append;
    4881             : 
    4882             :   // Call conventional store
    4883          29 :   storeNCT();
    4884             : 
    4885          29 : }
    4886             : 
    4887         411 : void SolvableVisCal::loadMemCalTable(String ctname,String field) {
    4888         411 :   if (field.length()>0) {
    4889             :     // Open whole table (on disk);
    4890          12 :     NewCalTable wholect(NewCalTable::createCT(ctname,Table::Old,Table::Memory)); 
    4891          12 :     ct_ = new NewCalTable(wholect);  // Make sure ct_ contains a real object
    4892             : 
    4893             :     // Prepare to select on it
    4894          12 :     CTInterface cti(wholect);
    4895          12 :     MSSelection mss;
    4896             :     //    mss.reset(cti,MSSelection::PARSE_LATE,"","",field);
    4897          12 :     mss.setFieldExpr(field);
    4898          12 :     TableExprNode ten=mss.toTableExprNode(&cti);
    4899             :     //cout << "Selected field list: " << mss.getFieldList() << endl;
    4900             : 
    4901             :     // Apply selection to table
    4902             :     try {
    4903          12 :       getSelectedTable(*ct_,wholect,ten,"");
    4904           0 :     } catch (AipsError x) {
    4905           0 :       logSink() << x.getMesg() << LogIO::SEVERE;
    4906           0 :       throw(AipsError("Error selecting on caltable: "+ctname+"... "));
    4907           0 :     }
    4908             : 
    4909          12 :   }
    4910             :   else
    4911             :     // No selection
    4912         399 :     ct_ = new NewCalTable(NewCalTable::createCT(ctname,Table::Old,Table::Memory)); 
    4913             : 
    4914             : 
    4915             : 
    4916             :   // Fill nChanParList from the Caltable
    4917             :   //   (this may be revised by calcPar)
    4918             : 
    4919             :   // This should not be needed anymore (and it breaks portability)
    4920             :   //  MSSpWindowColumns spwcol(ct_->spectralWindow());
    4921             :   //  nChanParList().assign(spwcol.numChan().getColumn());
    4922             : 
    4923         411 : }
    4924             : 
    4925           0 : void SolvableVisCal::stateSVC(const Bool& doVC) {
    4926             :   
    4927             :   // If requested, report VisCal state
    4928           0 :   if (doVC) VisCal::state();
    4929             : 
    4930           0 :   if (prtlev()>3) cout << "SVC::stateSVC():" << endl;
    4931           0 :   cout << boolalpha;
    4932             : 
    4933             :   // Now SVC-specific stuff:
    4934           0 :   cout << "  isSolved() = " << isSolved() << endl;
    4935           0 :   cout << "  calTableName() = " << calTableName() << endl;
    4936           0 :   cout << "  calTableSelect() = " << calTableSelect() << endl;
    4937           0 :   cout << "  apmode() = " << apmode() << endl;
    4938           0 :   cout << "  phandonly() = " << phandonly() << endl;
    4939           0 :   cout << "  tInterpType() = " << tInterpType() << endl;
    4940           0 :   cout << "  fInterpType() = " << fInterpType() << endl;
    4941           0 :   cout << "  spwMap() = " << spwMap() << endl;
    4942           0 :   cout << "  refantmode() = " << refantmode() << endl;
    4943           0 :   cout << "  refant() = " << refant() << endl;
    4944           0 :   cout << "  refantlist() = " << refantlist() << endl;
    4945           0 :   cout << "  solmode = " << solmode() << endl;
    4946           0 :   cout << "  rmsthresh = " << rmsthresh() << endl;
    4947             : 
    4948           0 :   cout << "  solveCPar().shape()   = " << solveCPar().shape() 
    4949           0 :        << " (" << solveCPar().data() << ")" << endl;
    4950           0 :   cout << "  solveRPar().shape()   = " << solveRPar().shape() 
    4951           0 :        << " (" << solveRPar().data() << ")" << endl;
    4952           0 :   cout << "  solveParOK().shape() = " << solveParOK().shape()
    4953           0 :        << " (" << solveParOK().data() << ") "
    4954           0 :        << " (ntrue=" << ntrue(solveParOK()) << ")" << endl;
    4955             : 
    4956           0 :   cout << "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" << endl;
    4957             : 
    4958           0 : }
    4959             : 
    4960           4 : Complex SolvableVisCal::normSolnArray(Array<Complex>& sol, 
    4961             :                                       const Array<Bool>& solOK,
    4962             :                                       const Bool doPhase) {
    4963             : 
    4964             :   // Only do something if 2 or more good solutions
    4965           4 :   Complex factor(1.0);
    4966           4 :   if (ntrue(solOK)>1) {
    4967             : 
    4968             :     
    4969           4 :     Array<Float> amp(amplitude(sol));
    4970             : 
    4971             :     // If desired, determine phase part of the normalization
    4972           4 :     if (doPhase) {
    4973             :       // Prepare to divide by amplitudes indiscriminately
    4974           0 :       amp(!solOK)=1.0f;
    4975           0 :       Array<Complex> sol1=sol/amp;
    4976           0 :       sol1(!solOK)=Complex(0.0);
    4977           0 :       factor=sum(sol1);
    4978           0 :       factor/=abs(factor);
    4979           0 :     }
    4980             : 
    4981             :     // Determine amplitude normalization factor
    4982           4 :     factor*=calcPowerNorm(amp,solOK);
    4983             :     
    4984             :     // Apply the normalization factor, if non-zero
    4985           4 :     if (abs(factor) > 0.0)
    4986           4 :       sol/=factor;
    4987             :     
    4988           4 :   } // ntrue > 0
    4989             : 
    4990             :   // Return the net normlization factor
    4991           4 :   return factor;
    4992             :   
    4993             : }
    4994             : 
    4995             : 
    4996             : 
    4997        7805 : void SolvableVisCal::currMetaNote() {
    4998             : 
    4999             :   cout << "   ("
    5000       15610 :        << "time=" << MVTime(refTime()/C::day).string(MVTime::YMD,7)
    5001        7805 :        << " field=" << currField()
    5002        7805 :        << " spw=" << currSpw()
    5003        7805 :        << " chan=" << focusChan()
    5004        7805 :        << ")"
    5005        7805 :        << endl;
    5006             : 
    5007        7805 : }
    5008             : 
    5009         725 : void SolvableVisCal::initSVC() {
    5010             : 
    5011         725 :   if (prtlev()>2) cout << " SVC::initSVC()" << endl;
    5012             : 
    5013        9170 :   for (Int ispw=0;ispw<nSpw(); ispw++) {
    5014             : 
    5015             :     // TBD: Would like to make this parType()-dependent,
    5016             :     //  but parType() isn't initialized yet...
    5017             :   
    5018             :     //    if (parType()==VisCalEnum::COMPLEX) {
    5019        8445 :       solveCPar_[ispw] = new Cube<Complex>();
    5020        8445 :       solveAllCPar_[ispw] = new Cube<Complex>();
    5021             :     //    }
    5022             :     //   else if (parType()==VisCalEnum::REAL) {
    5023        8445 :       solveRPar_[ispw] = new Cube<Float>();
    5024        8445 :       solveAllRPar_[ispw] = new Cube<Float>();
    5025             :     //    }
    5026        8445 :     solveParOK_[ispw] = new Cube<Bool>();
    5027        8445 :     solveParErr_[ispw] = new Cube<Float>();
    5028        8445 :     solveParSNR_[ispw] = new Cube<Float>();
    5029        8445 :     solveAllParOK_[ispw] = new Cube<Bool>();
    5030        8445 :     solveAllParErr_[ispw] = new Cube<Float>();
    5031        8445 :     solveAllParSNR_[ispw] = new Cube<Float>();
    5032             :   }
    5033             :   
    5034         725 :   parType_=VisCalEnum::COMPLEX;
    5035             : 
    5036         725 : }
    5037             : 
    5038         725 : void SolvableVisCal::deleteSVC() {
    5039             : 
    5040         725 :   if (prtlev()>2) cout << " SVC::deleteSVC()" << endl;
    5041             : 
    5042        9170 :   for (Int ispw=0; ispw<nSpw(); ispw++) {
    5043        8445 :     if (solveCPar_[ispw])  delete solveCPar_[ispw];
    5044        8445 :     if (solveRPar_[ispw])  delete solveRPar_[ispw];
    5045        8445 :     if (solveParOK_[ispw]) delete solveParOK_[ispw];
    5046        8445 :     if (solveParErr_[ispw]) delete solveParErr_[ispw];
    5047        8445 :     if (solveParSNR_[ispw]) delete solveParSNR_[ispw];
    5048        8445 :     if (solveAllCPar_[ispw])  delete solveAllCPar_[ispw];
    5049        8445 :     if (solveAllRPar_[ispw])  delete solveAllRPar_[ispw];
    5050        8445 :     if (solveAllParOK_[ispw]) delete solveAllParOK_[ispw];
    5051        8445 :     if (solveAllParErr_[ispw]) delete solveAllParErr_[ispw];
    5052        8445 :     if (solveAllParSNR_[ispw]) delete solveAllParSNR_[ispw];
    5053             :   }
    5054         725 :   solveCPar_=NULL;
    5055         725 :   solveRPar_=NULL;
    5056         725 :   solveParOK_=NULL;
    5057         725 :   solveParErr_=NULL;
    5058         725 :   solveParSNR_=NULL;
    5059         725 :   solveAllCPar_=NULL;
    5060         725 :   solveAllRPar_=NULL;
    5061         725 :   solveAllParOK_=NULL;
    5062         725 :   solveAllParErr_=NULL;
    5063         725 :   solveAllParSNR_=NULL;
    5064         725 : }
    5065             : 
    5066         461 : void SolvableVisCal::verifyCalTable(const String& caltablename) {
    5067             : 
    5068             :   // Call external method to get type (will throw if bad table)
    5069         461 :   String calType=calTableType(caltablename);
    5070             : 
    5071             :   // Check if proper Calibration type...
    5072         461 :   if (calType!=typeName()) {
    5073           0 :     ostringstream o;
    5074           0 :     o << "Table " << caltablename 
    5075           0 :       << " has wrong Calibration type: " << calType
    5076           0 :       << " (expected: " << typeName() << ")";
    5077           0 :     throw(AipsError(String(o)));
    5078           0 :   }
    5079         461 : }
    5080             : 
    5081         331 : void SolvableVisCal::applyChanMask(VisBuffer& vb) {
    5082             : 
    5083         331 :   if (chanmask_) {
    5084             : 
    5085             :     // A reference to de-referenced pointer
    5086         331 :     PtrBlock<Vector<Bool>*>& chmask(*chanmask_);
    5087             :   
    5088         331 :     Int spw=vb.spectralWindow();
    5089         331 :     Int chan0=vb.channel()(0);
    5090         331 :     Int nchan=vb.nChannel();
    5091         331 :     if (chmask.nelements()==uInt(nSpw()) &&
    5092         993 :         chmask[spw] &&
    5093         662 :         sum((*chmask[spw])(Slice(chan0,nchan))) > 0 ) {
    5094             :       // There are some channels to mask...
    5095         151 :       Vector<Bool> fr(vb.flagRow());
    5096         151 :       Matrix<Bool> f(vb.flag());
    5097         151 :       Vector<Bool> fc;
    5098         151 :       Vector<Bool> chm((*(*chanmask_)[spw])(Slice(chan0,nchan)));
    5099        1826 :       for (Int irow=0;irow<vb.nRow();++irow)
    5100        1675 :         if (!fr(irow)) {
    5101        1675 :           fc.reference(f.column(irow));
    5102        1675 :           fc = fc||chm;
    5103             :           
    5104             :           //    cout << irow << ": ";
    5105             :           //    for (Int j=0;j<nchan;++j) cout << fc(j);
    5106             :           //    cout << endl;
    5107             :           
    5108             :         }
    5109         151 :     }
    5110             :   }
    5111             : 
    5112         331 : }
    5113             :   //
    5114             :   //-----------------------------------------------------------------------
    5115             :   //  
    5116           0 :   void SolvableVisCal::printActivity(const Int nSlots, const Int slotNo, 
    5117             :                                      const Int fieldId, const Int spw, 
    5118             :                                      const Int nSolutions)
    5119             :   {
    5120             :     Int nMesg;
    5121             : 
    5122             :     //    nSlots = rcs().nTime(spw);
    5123             :     
    5124           0 :     Double timeTaken = timer_p.all();
    5125           0 :     if (maxTimePerSolution_p < timeTaken) maxTimePerSolution_p = timeTaken;
    5126           0 :     if (minTimePerSolution_p > timeTaken) minTimePerSolution_p = timeTaken;
    5127           0 :     avgTimePerSolution_p += timeTaken;
    5128           0 :     Double avgT =  avgTimePerSolution_p/(nSolutions>0?nSolutions:1);
    5129             :     //
    5130             :     // Boost the no. of messages printed if the next message, based on
    5131             :     // the average time per solution, is going to appear after a time
    5132             :     // longer than your patience would permit!  The limit of
    5133             :     // patience defaults to 1h.
    5134             :     //
    5135           0 :     Float boost = userPrintActivityInterval_p/avgT;
    5136           0 :     boost = userPrintActivityInterval_p/avgT;
    5137           0 :     boost = (boost < 1.0)? 1.0 : nSlots*userPrintActivityFraction_p;
    5138           0 :     nMesg = (Int)boost;
    5139             :     
    5140           0 :     Int tmp=abs(nSlots-slotNo); Bool print;
    5141           0 :     print = false;
    5142           0 :     if (nMesg <= 0) print=false;
    5143           0 :     else if ((slotNo == 0) || (slotNo == nSlots-1))  print=true;
    5144           0 :     else if ((tmp > 0 ) && ((slotNo+1)%nMesg ==0)) print=true;
    5145           0 :     else print=false;
    5146             : 
    5147           0 :     if (print)
    5148             :       {
    5149           0 :         Int f = (Int)(100*(slotNo+1)/(nSlots>0?nSlots:1));
    5150             :         logSink()<< LogIO::NORMAL 
    5151             :                  << "Spw=" << spw << " slot=" << slotNo << "/" << nSlots
    5152             :                  << " field=" << fieldId << ". Done " << f << "%"
    5153             :                  << " Time taken per solution (max/min/avg): "
    5154             :                  << maxTimePerSolution_p << "/" 
    5155           0 :                  << (minTimePerSolution_p<0?1:minTimePerSolution_p) << "/"
    5156           0 :                  << avgT << " sec" << LogIO::POST;
    5157             :       }
    5158           0 :   }
    5159             :   
    5160             : // **********************************************************
    5161             : //  SolvableVisMueller Implementations
    5162             : //
    5163             : 
    5164             : 
    5165          73 : SolvableVisMueller::SolvableVisMueller(VisSet& vs) :
    5166             :   VisCal(vs),
    5167             :   VisMueller(vs),
    5168             :   SolvableVisCal(vs),
    5169          73 :   dM_(NULL),
    5170          73 :   diffMElem_(),
    5171          73 :   DMValid_(false)
    5172             : {
    5173          73 :   if (prtlev()>2) cout << "SVM::SVM(vs)" << endl;
    5174          73 : }
    5175             : 
    5176          27 : SolvableVisMueller::SolvableVisMueller(String msname,Int MSnAnt,Int MSnSpw) :
    5177             :   VisCal(msname,MSnAnt,MSnSpw),
    5178             :   VisMueller(msname,MSnAnt,MSnSpw),
    5179             :   SolvableVisCal(msname,MSnAnt,MSnSpw),
    5180          27 :   dM_(NULL),
    5181          27 :   diffMElem_(),
    5182          27 :   DMValid_(false)
    5183             : {
    5184          27 :   if (prtlev()>2) cout << "SVM::SVM(msname,MSnAnt,MSnSpw)" << endl;
    5185          27 : }
    5186             : 
    5187         571 : SolvableVisMueller::SolvableVisMueller(const MSMetaInfoForCal& msmc) :
    5188             :   VisCal(msmc),
    5189             :   VisMueller(msmc),
    5190             :   SolvableVisCal(msmc),
    5191         571 :   dM_(NULL),
    5192         571 :   diffMElem_(),
    5193         571 :   DMValid_(False)
    5194             : {
    5195         571 :   if (prtlev()>2) cout << "SVM::SVM(msmc)" << endl;
    5196         571 : }
    5197             : 
    5198           0 : SolvableVisMueller::SolvableVisMueller(const Int& nAnt) :
    5199             :   VisCal(nAnt),
    5200             :   VisMueller(nAnt),
    5201             :   SolvableVisCal(nAnt),
    5202           0 :   dM_(NULL),
    5203           0 :   diffMElem_(),
    5204           0 :   DMValid_(false)
    5205             : {
    5206           0 :   if (prtlev()>2) cout << "SVM::SVM(i,j,k)" << endl;
    5207           0 : }
    5208             : 
    5209         671 : SolvableVisMueller::~SolvableVisMueller() {
    5210             : 
    5211         671 :   if (prtlev()>2) cout << "SVM::~SVM()" << endl;
    5212             : 
    5213         671 : }
    5214             : 
    5215             : // Setup solvePar shape (Mueller version)
    5216           7 : void SolvableVisMueller::initSolvePar() {
    5217             : 
    5218             :   // TBD: NCT: attention to solveAllPar
    5219             : 
    5220           7 :   if (prtlev()>3) cout << " SVM::initSolvePar()" << endl;
    5221             :   
    5222          58 :   for (Int ispw=0;ispw<nSpw();++ispw) {
    5223             :     
    5224          51 :     currSpw()=ispw;
    5225             : 
    5226          51 :     switch(parType()) {
    5227          51 :     case VisCalEnum::COMPLEX: {
    5228          51 :       solveAllCPar().resize(nPar(),nChanPar(),nBln());
    5229          51 :       solveAllCPar()=Complex(1.0);
    5230          51 :       solveCPar().reference(solveAllCPar());
    5231          51 :       break;
    5232             :     }
    5233           0 :     case VisCalEnum::REAL: {
    5234           0 :       solveAllRPar().resize(nPar(),nChanPar(),nBln());
    5235           0 :       solveAllRPar()=0.0;
    5236           0 :       solveRPar().reference(solveAllRPar());
    5237           0 :       break;
    5238             :     }
    5239           0 :     case VisCalEnum::COMPLEXREAL: {
    5240           0 :       throw(AipsError("Internal error(Calibrater Module): Unsupported parameter type "
    5241           0 :                       "COMPLEXREAL found in SolvableVisMueller::initSolvePar()"));
    5242             :       break;
    5243             :     }
    5244             :     }//switch
    5245             : 
    5246          51 :     solveAllParOK().resize(nPar(),nChanPar(),nBln());
    5247          51 :     solveAllParErr().resize(nPar(),nChanPar(),nBln());
    5248          51 :     solveAllParSNR().resize(nPar(),nChanPar(),nBln());
    5249          51 :     solveAllParOK()=true;
    5250          51 :     solveAllParErr()=0.0;
    5251          51 :     solveAllParSNR()=0.0;
    5252          51 :     solveParOK().reference(solveAllParOK());
    5253          51 :     solveParErr().reference(solveAllParErr());
    5254          51 :     solveParSNR().reference(solveAllParSNR());
    5255             :   }
    5256           7 :   currSpw()=0;
    5257           7 : }
    5258             : 
    5259           0 : void SolvableVisMueller::syncDiffMat() {
    5260             : 
    5261           0 :   if (prtlev()>5) cout << "     SVM::syncDiffMat()" 
    5262           0 :                        << " (DMValid()=" << DMValid() << ")" << endl;
    5263             : 
    5264             :   // Sync the diff'd Mueller matrices
    5265           0 :   if (!DMValid()) syncDiffMueller();
    5266             : 
    5267           0 : }
    5268             : 
    5269           0 : void SolvableVisMueller::syncDiffMueller() {
    5270             : 
    5271           0 :   if (prtlev()>6) cout << "      SVM::syncDiffMueller()" << endl;
    5272             : 
    5273             :   // TBD:  validateDM() for trivialMuellerElem()=true??
    5274             :   //    (cf. where does invalidateDM() occur?)
    5275             : 
    5276           0 :   if (trivialDM())
    5277             :     // Ensure trivial matrices ready
    5278           0 :     initTrivDM();
    5279             :   else {
    5280           0 :     diffMElem().resize(IPosition(4,muellerNPar(muellerType()),nPar(),nChanMat(),nCalMat()));
    5281           0 :     diffMElem().unique();
    5282           0 :     invalidateDM();
    5283             : 
    5284             :     // Calculate for all blns/chans
    5285           0 :     calcAllDiffMueller();
    5286             : 
    5287             :   }
    5288             : 
    5289             :   // Ensure diff'd Mueller matrix renders are OK
    5290           0 :   createDiffMueller();
    5291             : 
    5292             :   // diff'd Mueller matrices now valid
    5293           0 :   validateDM();
    5294             : 
    5295           0 : }
    5296             : 
    5297           0 : void SolvableVisMueller::calcAllDiffMueller() {
    5298             : 
    5299           0 :   if (prtlev()>6) cout << "       SVM::calcAllDiffMueller" << endl;
    5300             : 
    5301             :   // Should handle OK flags in this method, and only
    5302             :   //  do  calc if OK
    5303             : 
    5304             :   // Sanity check on parameter channel axis
    5305           0 :   AlwaysAssert((solveCPar().shape()(1)==1),AipsError);
    5306             : 
    5307             :   // Referencing arrays, per baseline
    5308           0 :   Matrix<Complex> oneDM;       //  (nElem,nPar)
    5309           0 :   Vector<Complex> onePar;      //  (nPar)
    5310             : 
    5311           0 :   ArrayIterator<Complex> dMiter(diffMElem(),2);
    5312           0 :   ArrayIterator<Complex> Piter(solveCPar(),1);
    5313             :   
    5314           0 :   for (Int ibln=0; ibln<nCalMat(); ++ibln) {
    5315             : 
    5316             :     // Solving parameters are NEVER channel-dependent
    5317             :     //  (even if data & matrices are)
    5318           0 :     onePar.reference(Piter.array());
    5319             :       
    5320           0 :     for (Int ich=0; ich<nChanMat(); ich++) {
    5321             :       
    5322           0 :       oneDM.reference(dMiter.array());
    5323             : 
    5324             :       // Calculate the DM matrices for each par on this bln/chan
    5325           0 :       calcOneDiffMueller(oneDM,onePar);
    5326             : 
    5327             :       // Advance iterators
    5328           0 :       dMiter.next();
    5329             : 
    5330             :     }
    5331           0 :     Piter.next();
    5332             :   }
    5333             : 
    5334           0 : }
    5335             : 
    5336           0 : void SolvableVisMueller::calcOneDiffMueller(Matrix<Complex>&, 
    5337             :                                             const Vector<Complex>&) {
    5338             : 
    5339           0 :   if (prtlev()>10) cout << "        SVM::calcOneDiffMueller()" << endl;
    5340             : 
    5341             :   // If Mueller matrix is trivial, shouldn't get here
    5342           0 :   if (trivialMuellerElem()) 
    5343           0 :     throw(AipsError("Trivial Mueller Matrix logic error."));
    5344             : 
    5345             :   // Otherwise, this method apparently hasn't been specialized, as required
    5346             :   else
    5347           0 :     throw(AipsError("Unknown non-trivial dMueller-from-parameter calculation requested."));
    5348             : 
    5349             : }
    5350             : 
    5351           0 : void SolvableVisMueller::createDiffMueller() {
    5352             : 
    5353           0 :   if (prtlev()>6) cout << "       SVM::createDiffMueller()" << endl;
    5354             : 
    5355           0 :   Mueller::MuellerType mtype(muellerType());
    5356             : 
    5357             :   // Delete if wrong type
    5358           0 :   if (dM_ && dM().type() != mtype) delete dM_;
    5359             :   
    5360             :   // If needed, construct the correct diff Mueller
    5361           0 :   if (!dM_) dM_ = casa::createMueller(mtype);
    5362             :       
    5363           0 : }
    5364             : 
    5365           0 : void SolvableVisMueller::initTrivDM() {
    5366             : 
    5367           0 :   if (prtlev()>7) cout << "        SVM::initTrivDM()" << endl;
    5368             : 
    5369             :   // If DM matrice not trivial, shouldn't get here
    5370           0 :   if (!trivialDM()) 
    5371           0 :     throw(AipsError("Trivial Mueller Matrix logic error."));
    5372             : 
    5373             :   // Otherwise, this method apparently hasn't been specialized, as required
    5374             :   else
    5375           0 :     throw(AipsError("Unknown trivial dM initialization requested."));
    5376             : 
    5377             : }
    5378             : 
    5379             : // File a solved solution (and meta-data) into the in-memory Caltable
    5380        1555 : void SolvableVisMueller::keepNCT() {
    5381             :   
    5382             :   // Call parent to do general stuff
    5383             :   //  This adds nElem() rows
    5384        1555 :   SolvableVisCal::keepNCT();
    5385             : 
    5386        1555 :   if (prtlev()>4) 
    5387           0 :     cout << " SVM::keepNCT" << endl;
    5388             : 
    5389             :   // Form antenna pairs
    5390        1555 :   Vector<Int> a1(nElem()),a2(nElem());
    5391        1555 :   Int k=0;
    5392       16375 :   for (Int i=0;i<nAnt();++i)
    5393       94430 :     for (Int j=i;j<nAnt();++j) {
    5394       79610 :       a1(k)=i;
    5395       79610 :       a2(k)=j;
    5396       79610 :       ++k;
    5397             :     }
    5398             : 
    5399             :   // We are adding to the most-recently added rows
    5400        1555 :   RefRows rows(ct_->nrow()-nElem(),ct_->nrow()-1,1); 
    5401             : 
    5402             :   // Write to table
    5403        1555 :   CTMainColumns ncmc(*ct_);
    5404        1555 :   ncmc.antenna1().putColumnCells(rows,a1);
    5405        1555 :   ncmc.antenna2().putColumnCells(rows,a2);
    5406             : 
    5407        1555 : }
    5408             : 
    5409             : 
    5410           0 : void SolvableVisMueller::stateSVM(const Bool& doVC) {
    5411             :   
    5412             :   // If requested, report VisCal state
    5413           0 :   if (doVC) VisMueller::state();
    5414             :   
    5415             :   // Get parent's state (w/out VC):
    5416           0 :   SolvableVisCal::stateSVC(false);
    5417             : 
    5418           0 :   if (applyByMueller()) {
    5419           0 :     if (prtlev()>3) cout << "SVM::stateSVM()" << endl;
    5420           0 :     cout << boolalpha;
    5421             : 
    5422             :   // Now SVM-specific stuff:
    5423           0 :     cout << "DMValid() = " << DMValid() << endl;
    5424           0 :     cout << "diffMElem().shape() = " << diffMElem().shape() 
    5425           0 :          << " (" << diffMElem().data() << ")" << endl;
    5426             :     
    5427           0 :     cout << "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" << endl;
    5428             :   }
    5429           0 : }
    5430             : 
    5431           4 : Float SolvableVisMueller::calcPowerNorm(Array<Float>& amp, const Array<Bool>& ok) {
    5432             : 
    5433             :   // SVM version assumes amp already in power units
    5434           4 :   Array<Float> a2;
    5435           4 :   a2.assign(amp);
    5436           4 :   a2(!ok)=0.0; // zero flagged samples
    5437             : 
    5438           4 :   Float norm(1.0);
    5439           4 :   switch (solNorm().normtype()) {
    5440           4 :   case SolNorm::MEAN: {
    5441           4 :     Float n=Float(ntrue(ok));
    5442           4 :     if (n>0.0)
    5443           4 :       norm=sum(a2)/n;
    5444           4 :     break;
    5445             :   }
    5446           0 :   case SolNorm::MEDIAN: {
    5447           0 :     MaskedArray<Float> a2masked(a2,ok);
    5448           0 :     norm=median(a2masked,false,true);  // unsorted, do mean when even
    5449           0 :     break;
    5450           0 :   }
    5451           0 :   default:
    5452           0 :     throw(AipsError("Proper normalization type not specified."));
    5453             :     break;
    5454             :   }
    5455           4 :   return norm;
    5456           4 : }
    5457             : 
    5458             : 
    5459             : // **********************************************************
    5460             : //  SolvableVisJones Implementations
    5461             : //
    5462             : 
    5463             : 
    5464          43 : SolvableVisJones::SolvableVisJones(VisSet& vs) :
    5465             :   VisCal(vs),                           // virtual base
    5466             :   VisMueller(vs),                       // virtual base
    5467             :   SolvableVisMueller(vs),               // immediate parent
    5468             :   VisJones(vs),                         // immediate parent
    5469          43 :   dJ1_(NULL),                           // data...
    5470          43 :   dJ2_(NULL),
    5471          43 :   diffJElem_(),
    5472          43 :   DJValid_(false)
    5473             : {
    5474          43 :   if (prtlev()>2) cout << "SVJ::SVJ(vs)" << endl;
    5475          43 : }
    5476             : 
    5477          27 : SolvableVisJones::SolvableVisJones(String msname,Int MSnAnt,Int MSnSpw) :
    5478             :   VisCal(msname,MSnAnt,MSnSpw),             // virtual base
    5479             :   VisMueller(msname,MSnAnt,MSnSpw),         // virtual base
    5480             :   SolvableVisMueller(msname,MSnAnt,MSnSpw), // immediate parent
    5481             :   VisJones(msname,MSnAnt,MSnSpw),           // immediate parent
    5482          27 :   dJ1_(NULL),                           // data...
    5483          27 :   dJ2_(NULL),
    5484          27 :   diffJElem_(),
    5485          27 :   DJValid_(false)
    5486             : {
    5487          27 :   if (prtlev()>2) cout << "SVJ::SVJ(msname,MSnAnt,MSnSpw)" << endl;
    5488          27 : }
    5489             : 
    5490         555 : SolvableVisJones::SolvableVisJones(const MSMetaInfoForCal& msmc) :
    5491             :   VisCal(msmc),             // virtual base
    5492             :   VisMueller(msmc),         // virtual base
    5493             :   SolvableVisMueller(msmc), // immediate parent
    5494             :   VisJones(msmc),           // immediate parent
    5495         555 :   dJ1_(NULL),               // data...
    5496         555 :   dJ2_(NULL),
    5497         555 :   diffJElem_(),
    5498         555 :   DJValid_(False)
    5499             : {
    5500         555 :   if (prtlev()>2) cout << "SVJ::SVJ(msmc)" << endl;
    5501         555 : }
    5502             : 
    5503             : 
    5504           0 : SolvableVisJones::SolvableVisJones(const Int& nAnt) : 
    5505             :   VisCal(nAnt),               // virtual base
    5506             :   VisMueller(nAnt),           // virtual base
    5507             :   SolvableVisMueller(nAnt),   // immediate parent
    5508             :   VisJones(nAnt),             // immediate parent
    5509           0 :   dJ1_(NULL),                 // data...
    5510           0 :   dJ2_(NULL),
    5511           0 :   diffJElem_(),
    5512           0 :   DJValid_(false)
    5513             : {
    5514           0 :   if (prtlev()>2) cout << "SVJ::SVJ(i,j,k)" << endl;
    5515           0 : }
    5516             : 
    5517         625 : SolvableVisJones::~SolvableVisJones() {
    5518             : 
    5519         625 :   if (prtlev()>2) cout << "SVJ::~SVJ()" << endl;
    5520         625 :   if (dJ1_)
    5521          46 :       delete dJ1_;
    5522         625 :   if (dJ2_)
    5523          46 :       delete dJ2_;
    5524         625 : }
    5525             : 
    5526           0 : void SolvableVisJones::reReference() {
    5527             : 
    5528             :   // TBD: Handle single-poln referencing
    5529             :   // TBD: Handle missing refant
    5530             : 
    5531             :   // Generic version for trivial types
    5532           0 :   if (trivialJonesElem()) {
    5533             : 
    5534             :     // Determine multiplicative complex phase
    5535           0 :     Matrix<Complex> refgain;
    5536           0 :     refgain=solveCPar().xyPlane(refant());
    5537             : 
    5538             :     //    cout << "refgain add:  " << refgain.data() << " " << solveCPar().xyPlane(refant()).data() << endl;
    5539             : 
    5540           0 :     Float amp(1.0);
    5541           0 :     Complex* rg=refgain.data();
    5542             :     // TBD: clean this up: there is only 1 solvePar chan!
    5543             :     //    for (Int ich=0;ich<nChanPar();++ich) {
    5544           0 :       for (Int ip=0;ip<nPar();++ip,++rg) {
    5545           0 :         amp=abs(*rg);
    5546           0 :         if (amp>0.0) {
    5547           0 :           *rg/=amp;
    5548           0 :           *rg=conj(*rg);
    5549             :         }
    5550             :         else
    5551           0 :           *rg=Complex(1.0);
    5552             :       }
    5553             :       //    }
    5554             : 
    5555             :       //      cout << "amp(refgain) = " << amplitude(refgain) << endl;
    5556             : 
    5557             : 
    5558             :     // Apply complex phase to each ant
    5559           0 :     Matrix<Complex> antgain;
    5560           0 :     for (Int ia=0;ia<nAnt();++ia) {
    5561           0 :       antgain.reference(solveCPar().xyPlane(ia));
    5562           0 :       antgain*=refgain;
    5563             :     }
    5564           0 :   }
    5565             :   else 
    5566           0 :     throw(AipsError("Attempt to reference non-trivial calibration type."));
    5567             : 
    5568             : 
    5569           0 : }
    5570             : 
    5571             : 
    5572           0 : void SolvableVisJones::differentiate(CalVisBuffer& cvb) {
    5573             : 
    5574           0 :   if (prtlev()>3) cout << "  SVJ::differentiate(CVB)" << endl;
    5575             : 
    5576             :   // NB: For freqDepPar()=true, the data and solutions are
    5577             :   //     multi-channel, but nChanMat()=1 because we only 
    5578             :   //     consider one channel at a time.  In this case,
    5579             :   //     focusChan is the specific channel under consideration.
    5580             :   //     Otherwise, we will use all channels in the vb 
    5581             :   //     simultaneously
    5582             : 
    5583             :   // Some vb shape info
    5584           0 :   Int& nRow(cvb.nRow());
    5585           0 :   Int& nCorr(cvb.nCorr());
    5586             : 
    5587             :   // Size (diff)residuals workspace in the CVB
    5588           0 :   cvb.setFocusChan(focusChan());
    5589           0 :   cvb.sizeResiduals(nPar(),2);    // 2 sets of nPar() derivatives per baseline
    5590             : 
    5591             :   // Copy in-focus model to residual workspace
    5592           0 :   cvb.initResidWithModel();
    5593             : 
    5594             : 
    5595             :   // References to workspaces
    5596           0 :   Cube<Complex>& Vout(cvb.residuals());
    5597           0 :   Array<Complex>& dVout(cvb.diffResiduals());
    5598           0 :   Matrix<Bool>& Vflg(cvb.residFlag());
    5599             :   
    5600             :   // "Apply" the current Q,U or X estimates to the crosshand model
    5601           0 :   if (solvePol()>0) {
    5602           0 :     Complex pol(1.0);
    5603             : 
    5604           0 :     if (solvePol()==2)  // pol = Q+iU
    5605           0 :       pol=Complex(real(srcPolPar()(0)),real(srcPolPar()(1)));
    5606           0 :     else if (solvePol()==1)   // pol = exp(iX)
    5607           0 :       pol=exp(Complex(0.0,real(srcPolPar()(0))));
    5608             :     
    5609           0 :     IPosition blc(3,1,0,0), trc(3,1,nChanMat()-1,nRow-1);
    5610           0 :     Array<Complex> RL(Vout(blc,trc));
    5611           0 :     RL*=pol;
    5612           0 :     blc(0)=trc(0)=2;
    5613           0 :     Array<Complex> LR(Vout(blc,trc));
    5614           0 :     LR*=conj(pol);
    5615           0 :   }
    5616             :   
    5617             :   // Visibility vector renderers
    5618           0 :   VisVector::VisType vt(visType(nCorr));
    5619           0 :   VisVector cVm(vt);  // The model data corrupted by trial solution
    5620           0 :   VisVector dV1(vt);  // The deriv of V wrt pars of 1st ant in bln 
    5621           0 :   VisVector dV2(vt);  // The deriv of V wrt pars of 2nd ant in bln 
    5622             : 
    5623             :   // Temporary non-iterating VisVectors to hold partial applies
    5624           0 :   VisVector J1V(vt,true);
    5625           0 :   VisVector VJ2(vt,true);
    5626             : 
    5627             :   // Starting synchronization for output visibility data
    5628           0 :   cVm.sync(Vout(0,0,0));
    5629           0 :   dV1.sync(dVout(IPosition(5,0,0,0,0,0)));
    5630           0 :   dV2.sync(dVout(IPosition(5,0,0,0,0,1)));
    5631             : 
    5632             :   // Synchronize current calibration pars/matrices
    5633           0 :   syncSolveCal();
    5634             : 
    5635             :   // Nominal synchronization of dJs
    5636           0 :   dJ1().sync(diffJElem()(IPosition(4,0,0,0,0)));
    5637           0 :   dJ2().sync(diffJElem()(IPosition(4,0,0,0,0)));
    5638             : 
    5639             :   // Inform Jones matrices if data is scalar
    5640           0 :   Bool scalar(vt==VisVector::One);
    5641           0 :   J1().setScalarData(scalar);
    5642           0 :   J2().setScalarData(scalar);
    5643           0 :   dJ1().setScalarData(scalar);
    5644           0 :   dJ2().setScalarData(scalar);
    5645             : 
    5646             :   // VisBuffer indices
    5647           0 :   Double* time=  cvb.time().data();
    5648           0 :   Int*    a1=    cvb.antenna1().data();
    5649           0 :   Int*    a2=    cvb.antenna2().data();
    5650           0 :   Bool*   flagR= cvb.flagRow().data();
    5651           0 :   Bool*   flag=  Vflg.data();            // via local reference
    5652             :   
    5653             :   // TBD: set weights according to flags??
    5654             : 
    5655             :   // iterate rows
    5656           0 :   for (Int irow=0; irow<nRow; irow++,flagR++,a1++,a2++,time++) {
    5657             :     
    5658             :     // Avoid ACs
    5659           0 :     if (*a1==*a2) *flagR=true;
    5660             : 
    5661           0 :     if (!*flagR) {  // if this row unflagged
    5662             :         
    5663             :       // Re-update matrices if time changes
    5664           0 :       if (timeDepMat() && *time != lastTime()) {
    5665           0 :         currTime()=*time;
    5666           0 :         invalidateDiffCalMat();
    5667           0 :         syncCalMat();
    5668           0 :         syncDiffMat();
    5669           0 :         lastTime()=currTime();
    5670             :       }
    5671             : 
    5672             :       // Synchronize Jones renderers for the ants on this baseline
    5673           0 :       J1().sync(currJElem()(0,0,*a1),currJElemOK()(0,0,*a1));
    5674           0 :       J2().sync(currJElem()(0,0,*a2),currJElemOK()(0,0,*a2));
    5675             : 
    5676             :       // Synchronize differentiated Jones renderers for this baseline
    5677           0 :       if (trivialDJ()) {
    5678           0 :         dJ1().origin();
    5679           0 :         dJ2().origin();
    5680             :       } else {
    5681           0 :         dJ1().sync(diffJElem()(IPosition(4,0,0,0,*a1)));
    5682           0 :         dJ2().sync(diffJElem()(IPosition(4,0,0,0,*a2)));
    5683             :       }
    5684             : 
    5685             :       // Assumes all iterating quantities have nChanMat() channelization
    5686           0 :       for (Int ich=0; ich<nChanMat();ich++,flag++,
    5687           0 :              cVm++, J1()++, J2()++) {
    5688             :              
    5689             :         // if channel unflagged an cal ok
    5690             :         //      if (!*flag && (*J1Ok && *J2Ok) ) {  
    5691           0 :         if (!*flag) { 
    5692             :           
    5693             :           // Partial applies for repeated use below
    5694           0 :           VJ2=cVm;                    
    5695           0 :           J2().applyLeft(VJ2,*flag);      // VJ2 = Vm*J2, used below
    5696             : 
    5697           0 :           J1().applyRight(cVm,*flag);     
    5698           0 :           J1V=cVm;                        // J1V = J1*Vm, used below
    5699             : 
    5700             :           // Finish trial corruption
    5701           0 :           J2().applyLeft(cVm,*flag);      // cVm = (J1*Vm)*J2
    5702             : 
    5703             :         }
    5704             : 
    5705             :         // Only continue with diff-ing, if we aren't flagged yet
    5706           0 :         if (!*flag) {
    5707             : 
    5708             :           // Differentiation per par
    5709           0 :           for (Int ip=0;ip<nPar();ip++,
    5710           0 :                  dV1++,dJ1()++,
    5711           0 :                  dV2++,dJ2()++) {
    5712             :             
    5713           0 :             dV1=VJ2;
    5714           0 :             dJ1().applyRight(dV1);  // dV1 = dJ1(ip)*(Vm*J2)
    5715             :             
    5716           0 :             dV2=J1V;
    5717           0 :             dJ2().applyLeft(dV2);   // dV2 = (J1*Vm)*dJ2(ip)
    5718             :           }
    5719             :           
    5720             :         } // (!*flag)
    5721             :         else {
    5722             :           // set trial corruption to zero
    5723           0 :           cVm.zero();
    5724             :           
    5725             :           // Advance all par-dep pointers over flagged channel
    5726           0 :           dV1.advance(nPar());
    5727           0 :           dV2.advance(nPar());
    5728           0 :           dJ1().advance(nPar());
    5729           0 :           dJ2().advance(nPar());
    5730             :         }
    5731             : 
    5732             :       } // chn
    5733             :                 
    5734             :     } // !*flagR
    5735             :     else {
    5736             :       // Must advance all chan-, par-dep pointers over flagged row
    5737           0 :       flag+=nChanMat(); 
    5738           0 :       cVm.advance(nChanMat());
    5739           0 :       J1().advance(nChanMat());
    5740           0 :       J2().advance(nChanMat());
    5741           0 :       Int chpar(nChanMat()*nPar());
    5742           0 :       dV1.advance(chpar);
    5743           0 :       dV2.advance(chpar);
    5744           0 :       dJ1().advance(chpar);
    5745           0 :       dJ2().advance(chpar);
    5746             :     }
    5747             :   }
    5748             : 
    5749             :   // Subtract the obs'd data from the trial-corrupted model
    5750             :   //  to form residuals
    5751           0 :   cvb.finalizeResiduals();
    5752             : 
    5753           0 : }
    5754             : 
    5755      329767 : void SolvableVisJones::differentiate(SolveDataBuffer& sdb) {  // VI2
    5756             : 
    5757      329767 :   if (prtlev()>3) cout << "  SVJ::differentiate(SDB)" << endl;
    5758             : 
    5759             :   // NB: For freqDepPar()=True, the data and solutions are
    5760             :   //     multi-channel, but nChanMat()=1 because we only 
    5761             :   //     consider one channel at a time.  In this case,
    5762             :   //     focusChan is the specific channel under consideration.
    5763             :   //     Otherwise, we will use all channels in the vb 
    5764             :   //     simultaneously
    5765             : 
    5766             :   // Some vb shape info
    5767      329767 :   const Int& nRow(sdb.nRows());
    5768      329767 :   const Int& nCorr(sdb.nCorrelations());
    5769             : 
    5770             :   // Size (diff)residuals workspace in the CVB
    5771      329767 :   sdb.setFocusChan(focusChan());
    5772      329767 :   sdb.sizeResiduals(nPar(),2);    // 2 sets of nPar() derivatives per baseline
    5773             : 
    5774             :   // Copy in-focus model to residual workspace
    5775      329767 :   sdb.initResidWithModel();
    5776             : 
    5777             :   // References to workspaces
    5778      329767 :   Cube<Complex>& Vout(sdb.residuals());
    5779      329767 :   Array<Complex>& dVout(sdb.diffResiduals());
    5780             :   
    5781             :   // "Apply" the current Q,U or X estimates to the crosshand model
    5782             :   // NB:  This is circular-basis specific!!
    5783             : 
    5784             :   /*   2016Nov29 (gmoellen):  MOVED TO DJones::guessPar(SDBList)
    5785             : 
    5786             :   if (solvePol()>0) {
    5787             :     Complex pol(1.0);
    5788             : 
    5789             :     if (solvePol()==2)  // pol = Q+iU
    5790             :       pol=Complex(real(srcPolPar()(0)),real(srcPolPar()(1)));
    5791             :     else if (solvePol()==1)   // pol = exp(iX)
    5792             :       pol=exp(Complex(0.0,real(srcPolPar()(0))));
    5793             :     
    5794             :     IPosition blc(3,1,0,0), trc(3,1,nChanMat()-1,nRow-1);
    5795             :     Array<Complex> RL(Vout(blc,trc));
    5796             :     RL*=pol;
    5797             :     blc(0)=trc(0)=2;
    5798             :     Array<Complex> LR(Vout(blc,trc));
    5799             :     LR*=conj(pol);
    5800             :   }
    5801             :   */  
    5802             : 
    5803             : 
    5804             :   // Visibility vector renderers
    5805      329767 :   VisVector::VisType vt(visType(nCorr));
    5806      329767 :   VisVector cVm(vt);  // The model data corrupted by trial solution
    5807      329767 :   VisVector dV1(vt);  // The deriv of V wrt pars of 1st ant in bln 
    5808      329767 :   VisVector dV2(vt);  // The deriv of V wrt pars of 2nd ant in bln 
    5809             : 
    5810             :   // Temporary non-iterating VisVectors to hold partial applies
    5811      329767 :   VisVector J1V(vt,True);
    5812      329767 :   VisVector VJ2(vt,True);
    5813             : 
    5814             :   // Starting synchronization for output visibility data
    5815      329767 :   cVm.sync(Vout(0,0,0));
    5816      329767 :   dV1.sync(dVout(IPosition(5,0,0,0,0,0)));
    5817      329767 :   dV2.sync(dVout(IPosition(5,0,0,0,0,1)));
    5818             : 
    5819             :   // Synchronize current calibration pars/matrices
    5820      329767 :   syncSolveCal();
    5821             : 
    5822             :   // Nominal synchronization of dJs
    5823      329767 :   dJ1().sync(diffJElem()(IPosition(4,0,0,0,0)));
    5824      329767 :   dJ2().sync(diffJElem()(IPosition(4,0,0,0,0)));
    5825             : 
    5826             :   // Inform Jones matrices if data is scalar
    5827      329767 :   Bool scalar(vt==VisVector::One);
    5828      329767 :   J1().setScalarData(scalar);
    5829      329767 :   J2().setScalarData(scalar);
    5830      329767 :   dJ1().setScalarData(scalar);
    5831      329767 :   dJ2().setScalarData(scalar);
    5832             : 
    5833             :   // VisBuffer indices
    5834      329767 :   const Double* time=  sdb.time().data();
    5835      329767 :   const Int*    a1=    sdb.antenna1().data();
    5836      329767 :   const Int*    a2=    sdb.antenna2().data();
    5837      329767 :   const Bool*   flagR= sdb.flagRow().data();
    5838             :   
    5839             :   // TBD: set weights according to flags??
    5840             : 
    5841             :   // iterate rows
    5842    21809974 :   for (Int irow=0; irow<nRow; irow++,flagR++,a1++,a2++,time++) {
    5843             :     
    5844             :     // Avoid ACs and flagged rows
    5845    21480207 :     if (*a1!=*a2 && !*flagR) {  
    5846             :         
    5847             :       // Re-update matrices if time changes
    5848             :       //  E.g.?
    5849    21480207 :       if (timeDepMat() && *time != lastTime()) {
    5850           0 :         currTime()=*time;
    5851           0 :         invalidateDiffCalMat();
    5852           0 :         syncCalMat();
    5853           0 :         syncDiffMat();
    5854           0 :         lastTime()=currTime();
    5855             :       }
    5856             : 
    5857             :       // Synchronize Jones renderers for the ants on this baseline
    5858    21480207 :       J1().sync(currJElem()(0,0,*a1),currJElemOK()(0,0,*a1));
    5859    21480207 :       J2().sync(currJElem()(0,0,*a2),currJElemOK()(0,0,*a2));
    5860             : 
    5861             :       // Synchronize differentiated Jones renderers for this baseline
    5862    21480207 :       if (trivialDJ()) {
    5863    21480207 :         dJ1().origin();
    5864    21480207 :         dJ2().origin();
    5865             :       } else {
    5866           0 :         dJ1().sync(diffJElem()(IPosition(4,0,0,0,*a1)));
    5867           0 :         dJ2().sync(diffJElem()(IPosition(4,0,0,0,*a2)));
    5868             :       }
    5869             : 
    5870             :       // Assumes all iterating quantities have nChanMat() channelization
    5871    42960414 :       for (Int ich=0; ich<nChanMat();ich++,
    5872    21480207 :              cVm++, J1()++, J2()++) {
    5873             :              
    5874             :         // NB: Ignoring vis flag state  (OK?)
    5875             :           
    5876             :         // Partial applies for repeated use below
    5877    21480207 :         VJ2=cVm;                    
    5878    21480207 :         J2().applyLeft(VJ2);      // VJ2 = Vm*J2, used below
    5879             : 
    5880    21480207 :         J1().applyRight(cVm);     
    5881    21480207 :         J1V=cVm;                        // J1V = J1*Vm, used below
    5882             : 
    5883             :         // Finish trial corruption
    5884    21480207 :         J2().applyLeft(cVm);      // cVm = (J1*Vm)*J2
    5885             : 
    5886             :         // Differentiation per par
    5887    55832886 :         for (Int ip=0;ip<nPar();ip++,
    5888    34352679 :                dV1++,dJ1()++,
    5889    68705358 :                dV2++,dJ2()++) {
    5890             :           
    5891    34352679 :           dV1=VJ2;
    5892    34352679 :           dJ1().applyRight(dV1);  // dV1 = dJ1(ip)*(Vm*J2)
    5893             :           
    5894    34352679 :           dV2=J1V;
    5895    34352679 :           dJ2().applyLeft(dV2);   // dV2 = (J1*Vm)*dJ2(ip)
    5896             :         }
    5897             :           
    5898             :       } // chn
    5899             :                 
    5900    21480207 :     } // !*flagR
    5901             :     else {
    5902             :       // Must advance all chan-, par-dep pointers over flagged row
    5903           0 :       cVm.advance(nChanMat());
    5904           0 :       J1().advance(nChanMat());
    5905           0 :       J2().advance(nChanMat());
    5906           0 :       Int chpar(nChanMat()*nPar());
    5907           0 :       dV1.advance(chpar);
    5908           0 :       dV2.advance(chpar);
    5909           0 :       dJ1().advance(chpar);
    5910           0 :       dJ2().advance(chpar);
    5911             :     }
    5912             :   }
    5913             : 
    5914             :   // Subtract the obs'd data from the trial-corrupted model
    5915             :   //  to form residuals
    5916      329767 :   sdb.finalizeResiduals();
    5917             : 
    5918      329767 : }
    5919             : 
    5920             : 
    5921           0 : void SolvableVisJones::differentiate(VisBuffer& vb,
    5922             :                                      Cube<Complex>& Vout, 
    5923             :                                      Array<Complex>& dVout,
    5924             :                                      Matrix<Bool>& Vflg) {
    5925             :     
    5926           0 :   if (prtlev()>3) cout << "  SVJ::differentiate()" << endl;
    5927             : 
    5928             :   // NB: For freqDepPar()=true, the data and solutions are
    5929             :   //     multi-channel, but nChanMat()=1 because we only 
    5930             :   //     consider one channel at a time.  In this case,
    5931             :   //     focusChan is the specific channel under consideration.
    5932             :   //     Otherwise, we will use all channels in the vb 
    5933             :   //     simultaneously
    5934             : 
    5935             :   // Some vb shape info
    5936           0 :   Int& nRow(vb.nRow());
    5937           0 :   Int nCorr(vb.corrType().nelements());
    5938             : 
    5939             :   // Size up the output data arrays
    5940             :   // Vout = [nCorr,nChan,nRow]
    5941             :   // dVout = [nCorr,nPar,nChan,nRow,2]   (1 set of dV for both ants on baseline)
    5942           0 :   Vout.resize(IPosition(3,nCorr,nChanMat(),nRow));
    5943           0 :   Vout.unique();             // ensure unique storage
    5944             : 
    5945           0 :   dVout.resize(IPosition(5,nCorr,nPar(),nChanMat(),nRow,2));
    5946           0 :   dVout.unique();
    5947           0 :   dVout=Complex(0.0);
    5948             :   
    5949             :   // Copy the input model data from the VisBuffer to Vout
    5950             :   //  for in-place application (do this according to focusChan)
    5951             :   //  (also flags)
    5952           0 :   Matrix<Bool> fl;
    5953           0 :   if (freqDepPar()) {
    5954             :     // Copy just the focusChan; all work below is single-channel
    5955           0 :     AlwaysAssert((nChanMat()==1),AipsError);  // sanity
    5956           0 :     AlwaysAssert((focusChan()>-1),AipsError);       // sanity
    5957             : 
    5958           0 :     Vout = vb.modelVisCube()(IPosition(3,0,      focusChan(),0     ),
    5959           0 :                              IPosition(3,nCorr-1,focusChan(),nRow-1));
    5960             : 
    5961           0 :     Vflg.resize(IPosition(2,1,nRow));   // proper single channel size
    5962           0 :     Vflg.unique();                      // unique storage
    5963           0 :     Vflg = vb.flag()(IPosition(2,focusChan(),0     ),
    5964           0 :                      IPosition(2,focusChan(),nRow-1));
    5965             :   }
    5966             :   else {
    5967             :     // Copy all channels in the vb
    5968           0 :     Vout = vb.modelVisCube();
    5969           0 :     Vflg.reference(vb.flag());   // Just reference whole flag array
    5970             :   }
    5971             : 
    5972             :   // "Apply" the current Q,U or X estimates to the crosshand model
    5973           0 :   if (solvePol()>0) {
    5974           0 :     Complex pol(1.0);
    5975             : 
    5976           0 :     if (solvePol()==2)  // pol = Q+iU
    5977           0 :       pol=Complex(real(srcPolPar()(0)),real(srcPolPar()(1)));
    5978           0 :     else if (solvePol()==1)   // pol = exp(iX)
    5979           0 :       pol=exp(Complex(0.0,real(srcPolPar()(0))));
    5980             :     
    5981           0 :     IPosition blc(3,1,0,0), trc(3,1,nChanMat()-1,nRow-1);
    5982           0 :     Array<Complex> RL(Vout(blc,trc));
    5983           0 :     RL*=pol;
    5984           0 :     blc(0)=trc(0)=2;
    5985           0 :     Array<Complex> LR(Vout(blc,trc));
    5986           0 :     LR*=conj(pol);
    5987           0 :   }
    5988             :   
    5989             :   // Visibility vector renderers
    5990           0 :   VisVector::VisType vt(visType(nCorr));
    5991           0 :   VisVector cVm(vt);  // The model data corrupted by trial solution
    5992           0 :   VisVector dV1(vt);  // The deriv of V wrt pars of 1st ant in bln 
    5993           0 :   VisVector dV2(vt);  // The deriv of V wrt pars of 2nd ant in bln 
    5994             : 
    5995             :   // Temporary non-iterating VisVectors to hold partial applies
    5996           0 :   VisVector J1V(vt,true);
    5997           0 :   VisVector VJ2(vt,true);
    5998             : 
    5999             :   // Starting synchronization for output visibility data
    6000           0 :   cVm.sync(Vout(0,0,0));
    6001           0 :   dV1.sync(dVout(IPosition(5,0,0,0,0,0)));
    6002           0 :   dV2.sync(dVout(IPosition(5,0,0,0,0,1)));
    6003             : 
    6004             :   // Synchronize current calibration pars/matrices
    6005           0 :   syncSolveCal();
    6006             : 
    6007             :   // Nominal synchronization of dJs
    6008           0 :   dJ1().sync(diffJElem()(IPosition(4,0,0,0,0)));
    6009           0 :   dJ2().sync(diffJElem()(IPosition(4,0,0,0,0)));
    6010             : 
    6011             :   // Inform Jones matrices if data is scalar
    6012           0 :   Bool scalar(vt==VisVector::One);
    6013           0 :   J1().setScalarData(scalar);
    6014           0 :   J2().setScalarData(scalar);
    6015           0 :   dJ1().setScalarData(scalar);
    6016           0 :   dJ2().setScalarData(scalar);
    6017             : 
    6018             :   // VisBuffer indices
    6019           0 :   Double* time=  vb.time().data();
    6020           0 :   Int*    a1=    vb.antenna1().data();
    6021           0 :   Int*    a2=    vb.antenna2().data();
    6022           0 :   Bool*   flagR= vb.flagRow().data();
    6023           0 :   Bool*   flag=  Vflg.data();            // via local reference
    6024             :   
    6025             :   // TBD: set weights according to flags??
    6026             : 
    6027             :   // iterate rows
    6028           0 :   for (Int irow=0; irow<nRow; irow++,flagR++,a1++,a2++,time++) {
    6029             :     
    6030             :     // Avoid ACs
    6031           0 :     if (*a1==*a2) *flagR=true;
    6032             : 
    6033           0 :     if (!*flagR) {  // if this row unflagged
    6034             :         
    6035             :       // Re-update matrices if time changes
    6036           0 :       if (timeDepMat() && *time != lastTime()) {
    6037           0 :         currTime()=*time;
    6038           0 :         invalidateDiffCalMat();
    6039           0 :         syncCalMat();
    6040           0 :         syncDiffMat();
    6041           0 :         lastTime()=currTime();
    6042             :       }
    6043             : 
    6044             :       // Synchronize Jones renderers for the ants on this baseline
    6045           0 :       J1().sync(currJElem()(0,0,*a1),currJElemOK()(0,0,*a1));
    6046           0 :       J2().sync(currJElem()(0,0,*a2),currJElemOK()(0,0,*a2));
    6047             : 
    6048             :       // Synchronize differentiated Jones renderers for this baseline
    6049           0 :       if (trivialDJ()) {
    6050           0 :         dJ1().origin();
    6051           0 :         dJ2().origin();
    6052             :       } else {
    6053           0 :         dJ1().sync(diffJElem()(IPosition(4,0,0,0,*a1)));
    6054           0 :         dJ2().sync(diffJElem()(IPosition(4,0,0,0,*a2)));
    6055             :       }
    6056             : 
    6057             :       // Assumes all iterating quantities have nChanMat() channelization
    6058           0 :       for (Int ich=0; ich<nChanMat();ich++,flag++,
    6059           0 :              cVm++, J1()++, J2()++) {
    6060             :              
    6061             :         // if channel unflagged an cal ok
    6062             :         //      if (!*flag && (*J1Ok && *J2Ok) ) {  
    6063           0 :         if (!*flag) { 
    6064             :           
    6065             :           // Partial applies for repeated use below
    6066           0 :           VJ2=cVm;                    
    6067           0 :           J2().applyLeft(VJ2,*flag);      // VJ2 = Vm*J2, used below
    6068             : 
    6069           0 :           J1().applyRight(cVm,*flag);     
    6070           0 :           J1V=cVm;                        // J1V = J1*Vm, used below
    6071             : 
    6072             :           // Finish trial corruption
    6073           0 :           J2().applyLeft(cVm,*flag);      // cVm = (J1*Vm)*J2
    6074             : 
    6075             :         }
    6076             : 
    6077             :         // Only continue with diff-ing, if we aren't flagged yet
    6078           0 :         if (!*flag) {
    6079             : 
    6080             :           // Differentiation per par
    6081           0 :           for (Int ip=0;ip<nPar();ip++,
    6082           0 :                  dV1++,dJ1()++,
    6083           0 :                  dV2++,dJ2()++) {
    6084             :             
    6085           0 :             dV1=VJ2;
    6086           0 :             dJ1().applyRight(dV1);  // dV1 = dJ1(ip)*(Vm*J2)
    6087             :             
    6088           0 :             dV2=J1V;
    6089           0 :             dJ2().applyLeft(dV2);   // dV2 = (J1*Vm)*dJ2(ip)
    6090             :           }
    6091             :           
    6092             :         } // (!*flag)
    6093             :         else {
    6094             :           // set trial corruption to zero
    6095           0 :           cVm.zero();
    6096             :           
    6097             :           // Advance all par-dep pointers over flagged channel
    6098           0 :           dV1.advance(nPar());
    6099           0 :           dV2.advance(nPar());
    6100           0 :           dJ1().advance(nPar());
    6101           0 :           dJ2().advance(nPar());
    6102             :         }
    6103             : 
    6104             :       } // chn
    6105             :                 
    6106             :     } // !*flagR
    6107             :     else {
    6108             :       // Must advance all chan-, par-dep pointers over flagged row
    6109           0 :       flag+=nChanMat(); 
    6110           0 :       cVm.advance(nChanMat());
    6111           0 :       J1().advance(nChanMat());
    6112           0 :       J2().advance(nChanMat());
    6113           0 :       Int chpar(nChanMat()*nPar());
    6114           0 :       dV1.advance(chpar);
    6115           0 :       dV2.advance(chpar);
    6116           0 :       dJ1().advance(chpar);
    6117           0 :       dJ2().advance(chpar);
    6118             :     }
    6119             :   }
    6120             : 
    6121           0 : }
    6122             : 
    6123           0 : void SolvableVisJones::diffSrc(VisBuffer& vb,
    6124             :                                Array<Complex>& dVout) {
    6125             :     
    6126           0 :   if (prtlev()>3) cout << "  SVJ::diffSrc()" << endl;
    6127             : 
    6128             :   // Some vb shape info
    6129           0 :   Int& nRow(vb.nRow());
    6130           0 :   Int nCorr(vb.corrType().nelements());
    6131             : 
    6132             :   // Size up the output data arrays
    6133           0 :   dVout.resize(IPosition(4,nCorr,nChanMat(),nRow,solvePol()));
    6134           0 :   dVout.unique();
    6135           0 :   dVout=Complex(0.0);
    6136             :   
    6137             :   // For now, we don't actually need gradients w.r.t. the source
    6138           0 :   return;
    6139             : 
    6140             :   IPosition blc(4,0,0,0,0), trc(4,0,nChanMat()-1,nRow-1,0);
    6141             : 
    6142             :   if (solvePol()==2) {
    6143             :     blc(3)=trc(3)=0;
    6144             :     blc(0)=1;trc(0)=2;
    6145             :     dVout(blc,trc)=Complex(1.0);   // Q part (both RL & LR)
    6146             :     blc(3)=trc(3)=1;
    6147             :     blc(0)=trc(0)=1;
    6148             :     dVout(blc,trc)=Complex(0.0,1.0);  // U part (in RL)
    6149             :     blc(0)=trc(0)=2;
    6150             :     dVout(blc,trc)=Complex(0.0,-1.0); // U part (in LR)
    6151             :   }
    6152             :   else if (solvePol()==1) {
    6153             :     Complex dX=Complex(0.0,1.0)*exp(Complex(0.0,real(srcPolPar()(0))));
    6154             :     blc(3)=trc(3)=0;
    6155             :     blc(0)=trc(0)=1;
    6156             :     dVout(blc,trc)=dX;  // multiplying RL
    6157             :     blc(0)=trc(0)=2;
    6158             :     dVout(blc,trc)=conj(dX); // multiplying LR
    6159             :   }
    6160             : 
    6161             :   // Visibility vector renderers
    6162             :   VisVector::VisType vt(visType(nCorr));
    6163             :   VisVector dSm1(vt);  // The model data corrupted by trial solution
    6164             :   VisVector dSm2(vt);  // The model data corrupted by trial solution
    6165             : 
    6166             :   // Starting synchronization for output visibility data
    6167             :   dSm1.sync(dVout(IPosition(4,0,0,0,0)));
    6168             :   if (solvePol()>1)
    6169             :     dSm2.sync(dVout(IPosition(4,0,0,0,1)));
    6170             : 
    6171             :   // Synchronize current calibration pars/matrices
    6172             :   syncSolveCal();
    6173             : 
    6174             :   // Nominal synchronization of dJs
    6175             :   dJ1().sync(diffJElem()(IPosition(4,0,0,0,0)));
    6176             :   dJ2().sync(diffJElem()(IPosition(4,0,0,0,0)));
    6177             : 
    6178             :   // Inform Jones matrices if data is scalar
    6179             :   Bool scalar(vt==VisVector::One);
    6180             :   J1().setScalarData(scalar);
    6181             :   J2().setScalarData(scalar);
    6182             :   dJ1().setScalarData(scalar);
    6183             :   dJ2().setScalarData(scalar);
    6184             : 
    6185             :   // VisBuffer indices
    6186             :   Double* time=  vb.time().data();
    6187             :   Int*    a1=    vb.antenna1().data();
    6188             :   Int*    a2=    vb.antenna2().data();
    6189             :   Bool*   flagR= vb.flagRow().data();
    6190             :   Bool*   flag=  vb.flag().data();
    6191             :   
    6192             :   // TBD: set weights according to flags??
    6193             : 
    6194             :   // iterate rows
    6195             :   for (Int irow=0; irow<nRow; irow++,flagR++,a1++,a2++,time++) {
    6196             :     
    6197             :     // Avoid ACs
    6198             :     if (*a1==*a2) *flagR=true;
    6199             : 
    6200             :     if (!*flagR) {  // if this row unflagged
    6201             :         
    6202             :       // Re-update matrices if time changes
    6203             :       if (timeDepMat() && *time != lastTime()) {
    6204             :         currTime()=*time;
    6205             :         invalidateDiffCalMat();
    6206             :         syncCalMat();
    6207             :         syncDiffMat();
    6208             :         lastTime()=currTime();
    6209             :       }
    6210             : 
    6211             :       // Synchronize Jones renderers for the ants on this baseline
    6212             :       J1().sync(currJElem()(0,0,*a1),currJElemOK()(0,0,*a1));
    6213             :       J2().sync(currJElem()(0,0,*a2),currJElemOK()(0,0,*a2));
    6214             : 
    6215             :       // Assumes all iterating quantities have nChanMat() channelization
    6216             :       for (Int ich=0; ich<nChanMat();ich++,flag++,
    6217             :              dSm1++, dSm2++, J1()++, J2()++) {
    6218             :              
    6219             :         // if channel unflagged an cal ok
    6220             :         if (!*flag) { 
    6221             :           
    6222             :           J1().applyRight(dSm1);
    6223             :           J2().applyLeft(dSm1);
    6224             :           if (solvePol()>1) {
    6225             :             J1().applyRight(dSm2);
    6226             :             J2().applyLeft(dSm2);
    6227             :           }
    6228             :         }
    6229             : 
    6230             :       } // chn
    6231             :                 
    6232             :     } // !*flagR
    6233             :     else {
    6234             :       // Must advance all chan-, par-dep pointers over flagged row
    6235             :       flag+=nChanMat(); 
    6236             :       dSm1.advance(nChanMat());
    6237             :       dSm2.advance(nChanMat());
    6238             :       J1().advance(nChanMat());
    6239             :       J2().advance(nChanMat());
    6240             :     }
    6241             :   }
    6242             : 
    6243             : }
    6244             : 
    6245           0 : void SolvableVisJones::accumulate(SolvableVisCal* incr,
    6246             :                                   const Vector<Int>& fields) {
    6247             : 
    6248             :   // Use SVJ interface for the incremental component
    6249             :   //  (this should always be safe at this point?)
    6250           0 :   SolvableVisJones* svj = dynamic_cast<SolvableVisJones*>(incr);
    6251             : 
    6252             :   // Catch bad SVJ conversion or fundamental type mismatch
    6253           0 :   if (svj==NULL || svj->type() != this->type())
    6254           0 :     throw(AipsError("Incremental calibration is not of compatible type."));
    6255             : 
    6256           0 :   Int nfield(fields.nelements());
    6257             : 
    6258           0 :   Bool fldok(true);
    6259             : 
    6260             :   // TBD: Iterate over the ct_
    6261           0 :   Block<String> cols(2);
    6262           0 :   cols[0]="SPECTRAL_WINDOW_ID";
    6263           0 :   cols[1]="TIME";
    6264           0 :   CTIter ctiter(*ct_,cols);
    6265             : 
    6266           0 :   cout << boolalpha;
    6267           0 :   Int piter(0);
    6268           0 :   Int prow(0);
    6269           0 :   while (!ctiter.pastEnd()) {
    6270             :     
    6271           0 :     currSpw()=ctiter.thisSpw();
    6272           0 :     currTime()=ctiter.thisTime();
    6273             : 
    6274             :     /*    
    6275             :     cout << "Spw=" << currSpw() << " spwok=" << svj->spwOK(currSpw());
    6276             :     cout << " Time=" << MVTime(currTime()/C::day).string(MVTime::YMD,7);
    6277             :     cout << " nrow=" << ctiter.nrow();
    6278             :     */
    6279             : 
    6280             :     // Only update spws which are available in the incr table:
    6281           0 :     if (svj->spwOK(currSpw())) {
    6282             :         
    6283           0 :       currField()=ctiter.thisField();
    6284             : 
    6285             :       // Is current field among those we need to update?
    6286           0 :       fldok = (nfield==0 || anyEQ(fields,currField())); 
    6287             : 
    6288             :       //      cout << " Fld=" << currField() << " fldok=" << fldok;
    6289             : 
    6290           0 :       if (fldok) {
    6291             : 
    6292           0 :         currFreq()=ctiter.freq();
    6293             : 
    6294           0 :         currCPar().assign(ctiter.cparam());
    6295           0 :         currParOK().assign(!ctiter.flag());
    6296             : 
    6297           0 :         syncCalMat(false);  // a reference!!
    6298             :           
    6299             :         // Sync svj with this
    6300           0 :         svj->syncCal(*this);
    6301             : 
    6302           0 :         AlwaysAssert( (nChanMat()==svj->nChanMat()), AipsError);
    6303             :           
    6304             :         // Do the multiplication each ant, chan
    6305           0 :         for (Int iant=0; iant<nAnt(); iant++) {
    6306           0 :           for (Int ichan=0; ichan<svj->nChanMat(); ichan++) {
    6307           0 :             J1()*=(svj->J1());
    6308           0 :             J1()++;
    6309           0 :             svj->J1()++;
    6310             :           } // ichan
    6311             :         } // iant
    6312             : 
    6313             :         //cout << "  keep";
    6314             :         
    6315           0 :         ctiter.setcparam(currCPar());  // assumes matrices are references
    6316           0 :         ctiter.setflag(!currParOK());
    6317             : 
    6318           0 :         piter+=1;
    6319           0 :         prow+=ctiter.nrow();
    6320             : 
    6321             :       } // fldok
    6322             :     } // spwOK
    6323             : 
    6324             :     //    cout << endl;
    6325             : 
    6326             :     // Advance iterator
    6327           0 :     ctiter.next();
    6328             :     
    6329             :   } // ispw
    6330             : 
    6331             :   //  cout << "Processed " << prow << " rows in " << piter << " iterations." << endl;
    6332             : 
    6333           0 : }
    6334             : 
    6335             : 
    6336             : 
    6337             : // Setup solvePar shape (Jones version)
    6338          60 : void SolvableVisJones::initSolvePar() {
    6339             : 
    6340          60 :   if (prtlev()>3) cout << " SVJ::initSolvePar()" << endl;
    6341             : 
    6342         552 :   for (Int ispw=0;ispw<nSpw();++ispw) {
    6343             : 
    6344         492 :     currSpw()=ispw;
    6345             : 
    6346         492 :     switch (parType()) {
    6347         193 :     case VisCalEnum::COMPLEX: {
    6348         193 :       solveAllCPar().resize(nPar(),nChanPar(),nAnt());
    6349         193 :       solveAllCPar()=Complex(1.0);
    6350         193 :       if (nChanPar()==1)
    6351         193 :         solveCPar().reference(solveAllCPar());
    6352             :       else {
    6353           0 :         solveCPar().resize(nPar(),1,nAnt());
    6354           0 :         solveCPar()=Complex(1.0);
    6355             :       }
    6356         193 :       break;
    6357             :     }
    6358         299 :     case VisCalEnum::REAL: {
    6359         299 :       solveAllRPar().resize(nPar(),nChanPar(),nAnt());
    6360         299 :       solveAllRPar()=0.0;
    6361         299 :       if (nChanPar()==1)
    6362         160 :         solveRPar().reference(solveAllRPar());
    6363             :       else {
    6364         139 :         solveRPar().resize(nPar(),1,nAnt());
    6365         139 :         solveRPar()=0.0;
    6366             :       }
    6367         299 :       break;
    6368             :     }
    6369           0 :     default:
    6370           0 :       throw(AipsError("Internal error(Calibrater Module): Unsupported parameter type "
    6371           0 :                       "COMPLEXREAL found in SolvableVisJones::initSolvePar()"));
    6372             :     }
    6373             :     
    6374         492 :     solveAllParOK().resize(nPar(),nChanPar(),nAnt());
    6375         492 :     solveAllParErr().resize(nPar(),nChanPar(),nAnt());
    6376         492 :     solveAllParSNR().resize(nPar(),nChanPar(),nAnt());
    6377         492 :     solveAllParOK()=true;
    6378         492 :     solveAllParErr()=0.0;
    6379         492 :     solveAllParSNR()=0.0;
    6380         492 :     if (nChanPar()==1) {
    6381         353 :       solveParOK().reference(solveAllParOK());
    6382         353 :       solveParErr().reference(solveAllParErr());
    6383         353 :       solveParSNR().reference(solveAllParSNR());
    6384             :     }
    6385             :     else {
    6386             :       // solving many channels, one at a time
    6387         139 :       solveParOK().resize(nPar(),1,nAnt());
    6388         139 :       solveParErr().resize(nPar(),1,nAnt());
    6389         139 :       solveParSNR().resize(nPar(),1,nAnt());
    6390         139 :       solveParOK()=true;
    6391         139 :       solveParErr()=0.0;
    6392         139 :       solveParSNR()=0.0;
    6393             :     }
    6394             :   }
    6395          60 :   currSpw()=0;
    6396             : 
    6397          60 : }
    6398             : 
    6399      329767 : void SolvableVisJones::syncDiffMat() {
    6400             : 
    6401      329767 :   if (prtlev()>5) cout << "     SVJ::syncDiffMat()" 
    6402           0 :                        << " (DJValid()=" << DJValid() << ")" << endl;
    6403             : 
    6404             :   // Sync the diff'd Jones matrices
    6405      329767 :   if (!DJValid()) syncDiffJones();
    6406             : 
    6407             :   // Sync up Muellers, if necessary
    6408             :   //  if (applyByMueller()) 
    6409             :       // Do nothing for now!  --All dJ applied directly in differentiate
    6410             :       // if (!DMValid()) syncDiffMueller();
    6411             : 
    6412      329767 : }
    6413             : 
    6414          46 : void SolvableVisJones::syncDiffJones() {
    6415             : 
    6416          46 :   if (prtlev()>6) cout << "      SVJ::syncDiffJones()" << endl;
    6417             : 
    6418             :   // If differentiated Jones are trivial, we are
    6419             :   // already referencing the type-dep trivial versions
    6420             :   //  TBD: Review this for D, where trivialJonesElem()=false,
    6421             :   //   but diffJ is "trivial-ish"!!!  (Probably need trivDiffJonesElem(),
    6422             :   //   or override this method in D to make it no-op)
    6423             : 
    6424          46 :   if (trivialDJ())
    6425             :     // Ensure trivial matrices ready
    6426          46 :     initTrivDJ();
    6427             :   else {
    6428           0 :     diffJElem().resize(IPosition(4,jonesNPar(jonesType()),nPar(),nChanMat(),nCalMat()));
    6429           0 :     diffJElem().unique();
    6430           0 :     invalidateDJ();
    6431             : 
    6432             :     // Calculate for all ants/chans
    6433           0 :     calcAllDiffJones();
    6434             : 
    6435             :   }
    6436             : 
    6437             :   // Ensure diff'd Jones matrix renders are OK
    6438          46 :   createDiffJones();
    6439             : 
    6440             :   // diff'd Jones matrices now valid
    6441          46 :   validateDJ();
    6442          46 :   invalidateDM();   // dMs still invalid, probably forever
    6443             : 
    6444          46 : }
    6445             : 
    6446           0 : void SolvableVisJones::calcAllDiffJones() {
    6447             : 
    6448           0 :   if (prtlev()>6) cout << "       SVJ::calcAllDiffJones" << endl;
    6449             : 
    6450             :   // Should handle OK flags in this method, and only
    6451             :   //  do  calc if OK
    6452             : 
    6453           0 :   Matrix<Complex> oneDJ;   //  (nElem,nPar)
    6454           0 :   Vector<Complex> onePar;      //  (nPar)
    6455             : 
    6456           0 :   ArrayIterator<Complex> dJiter(diffJElem(),2);
    6457           0 :   ArrayIterator<Complex> Piter(currCPar(),1);
    6458             :   
    6459           0 :   for (Int iant=0; iant<nCalMat(); iant++) {
    6460             : 
    6461             :     // Solving parameters are NEVER channel-dependent
    6462             :     //  (even if data & matrices are)
    6463           0 :     onePar.reference(Piter.array());
    6464             :       
    6465           0 :     for (Int ich=0; ich<nChanMat(); ich++) {
    6466             :       
    6467           0 :       oneDJ.reference(dJiter.array());
    6468             : 
    6469             :       // Calculate the DJ matrices w.r.t. each par on this ant/chan
    6470           0 :       calcOneDiffJones(oneDJ,onePar);
    6471             : 
    6472             :       // Advance iterators
    6473           0 :       dJiter.next();
    6474             : 
    6475             :     }
    6476           0 :     Piter.next();
    6477             :   }
    6478             : 
    6479           0 : }
    6480             : 
    6481           0 : void SolvableVisJones::calcOneDiffJones(Matrix<Complex>&, 
    6482             :                                         const Vector<Complex>&) {
    6483             : 
    6484           0 :   if (prtlev()>10) cout << "        SVJ::calcOneDiffJones()" << endl;
    6485             : 
    6486             :   // If Jones matrix is trivial, shouldn't get here
    6487           0 :   if (trivialJonesElem()) 
    6488           0 :     throw(AipsError("Trivial Jones Matrix logic error."));
    6489             : 
    6490             :   // Otherwise, this method apparently hasn't been specialized, as required
    6491             :   else
    6492           0 :     throw(AipsError("Unknown non-trivial dJones-from-parameter calculation requested."));
    6493             : 
    6494             : }
    6495             : 
    6496          46 : void SolvableVisJones::createDiffJones() {
    6497             : 
    6498          46 :   if (prtlev()>6) cout << "       SVJ::createDiffJones()" << endl;
    6499             : 
    6500          46 :   Jones::JonesType jtype(jonesType());
    6501             : 
    6502             :   // Delete if wrong type
    6503          46 :   if (dJ1_ && dJ1().type() != jtype) delete dJ1_;
    6504          46 :   if (dJ2_ && dJ2().type() != jtype) delete dJ2_;
    6505             :   
    6506             :   // If needed, construct the correct diff Jones
    6507          46 :   if (!dJ1_) dJ1_ = casa::createJones(jtype);
    6508          46 :   if (!dJ2_) dJ2_ = casa::createJones(jtype);
    6509             :       
    6510          46 : }
    6511             : 
    6512           0 : void SolvableVisJones::initTrivDJ() {
    6513             : 
    6514           0 :   if (prtlev()>7) cout << "        SVJ::initTrivDJ()" << endl;
    6515             : 
    6516             :   // If DJ matrice not trivial, shouldn't get here
    6517           0 :   if (!trivialDJ()) 
    6518           0 :     throw(AipsError("Trivial Jones Matrix logic error."));
    6519             : 
    6520             :   // Otherwise, this method apparently hasn't been specialized, as required
    6521             :   else
    6522           0 :     throw(AipsError("Unknown trivial dJ initialization requested."));
    6523             : 
    6524             : }
    6525             : 
    6526             : // File a solved solution (and meta-data) into the in-memory Caltable
    6527       25597 : void SolvableVisJones::keepNCT() {
    6528             :   
    6529             :   // Call parent to do general stuff
    6530       25597 :   SolvableVisCal::keepNCT();
    6531             : 
    6532       25597 :   if (prtlev()>4) 
    6533           0 :     cout << " SVJ::keepNCT" << endl;
    6534             : 
    6535             :   // Antenna id sequence
    6536       25597 :   Vector<Int> a1(nAnt());
    6537       25597 :   indgen(a1);
    6538             : 
    6539             :   // We are adding to the most-recently added rows
    6540       25597 :   RefRows rows(ct_->nrow()-nElem(),ct_->nrow()-1,1); 
    6541             : 
    6542             :   // Write to table
    6543       25597 :   CTMainColumns ncmc(*ct_);
    6544       25597 :   ncmc.antenna1().putColumnCells(rows,a1);
    6545       25597 :   ncmc.antenna2().putColumnCells(rows,Vector<Int>(nAnt(),-1));  // Unknown but nominally unform
    6546             :  
    6547             :   // NB: a2 will be set separately, e.g., by applyRefAnt
    6548             : 
    6549       25597 : }
    6550             : 
    6551           0 : void SolvableVisJones::stateSVJ(const Bool& doVC) {
    6552             :   
    6553             :   // If requested, report VisCal state
    6554           0 :   if (doVC) VisJones::state();
    6555             : 
    6556             :   // Get parent's state (w/out VC):
    6557           0 :   SolvableVisMueller::stateSVM(false);
    6558             : 
    6559           0 :   if (applyByJones()) {
    6560           0 :     if (prtlev()>3) cout << "SVJ::stateSVJ()" << endl;
    6561           0 :     cout << boolalpha;
    6562             :     
    6563             :     // Now SVJ-specific stuff:
    6564           0 :     cout << "  DJValid() = " << DJValid() << endl;
    6565             :     
    6566           0 :     cout << "  diffJElem().shape() = " << diffJElem().shape() 
    6567           0 :          << " (" << diffJElem().data() << ")" << endl;
    6568           0 :     cout << "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" << endl;
    6569             :   }
    6570           0 : }
    6571             : 
    6572         952 : Float SolvableVisJones::calcPowerNorm(Array<Float>& amp, const Array<Bool>& ok) {
    6573             : 
    6574             :   // SVJ version asumes amps are voltages, so square them
    6575         952 :   Array<Float> a2(square(amp));
    6576         952 :   a2(!ok)=0.0; // zero flagged samples
    6577             : 
    6578             : 
    6579         952 :   Float norm2(1.0);
    6580         952 :   switch (solNorm().normtype()) {
    6581         952 :   case SolNorm::MEAN: {
    6582         952 :     Float n=Float(ntrue(ok));
    6583         952 :     if (n>0.0)
    6584         918 :       norm2=sum(a2)/n;
    6585         952 :     break;
    6586             :   }
    6587           0 :   case SolNorm::MEDIAN: {
    6588           0 :     MaskedArray<Float> a2masked(a2,ok);
    6589           0 :     norm2=median(a2masked,false,true);  // unsorted, do mean when even
    6590           0 :     break;
    6591           0 :   }
    6592           0 :   default:
    6593           0 :     throw(AipsError("Proper normalization type not specified."));
    6594             :     break;
    6595             :   }
    6596             : 
    6597             :   // Return sqrt, because Jones are voltages
    6598        1904 :   return sqrt(norm2); 
    6599         952 : }
    6600             : 
    6601          99 : void SolvableVisJones::globalPostSolveTinker() {
    6602             : 
    6603             :   // Re-reference the phase, if requested
    6604          99 :   if (refantlist()(0)>-1) applyRefAnt();
    6605             : 
    6606             :   // Apply more general post-solve stuff
    6607          99 :   SolvableVisCal::globalPostSolveTinker();
    6608             : 
    6609          99 : }
    6610             : 
    6611          41 : void SolvableVisJones::applyRefAnt() {
    6612             : 
    6613             :   // TBD:
    6614             :   // 1. Synchronize refant changes on par axis
    6615             :   // 2. Implement minimum mean deviation algorithm
    6616             : 
    6617          41 :   if (refantlist()(0)<0) 
    6618           0 :     throw(AipsError("No refant specified."));
    6619             : 
    6620          41 :   Int nUserRefant=refantlist().nelements();
    6621             : 
    6622             :   // Get the preferred refant names from the MS
    6623          41 :   String refantName(msmc().antennaName(refantlist()(0)));
    6624          41 :   if (nUserRefant>1) {
    6625           3 :     refantName+=" (";
    6626           6 :     for (Int i=1;i<nUserRefant;++i) {
    6627           3 :       refantName+=msmc().antennaName(refantlist()(i));
    6628           3 :       if (i<nUserRefant-1) refantName+=",";
    6629             :     }
    6630           3 :     refantName+=")";
    6631             :   }
    6632             : 
    6633             :   logSink() << "Applying refant: " << refantName
    6634          41 :             << " refantmode = " << refantmode();
    6635          41 :   if (refantmode()=="flex")
    6636          38 :     logSink() << " (hold alternate refants' phase constant) when refant flagged";
    6637          41 :   if (refantmode()=="strict")
    6638           3 :     logSink() << " (flag all antennas when refant flagged)";
    6639          41 :   logSink() << LogIO::POST;
    6640             : 
    6641             :   // Generate a prioritized refant choice list
    6642             :   //  The first entry in this list is the user's primary refant,
    6643             :   //   the second entry is the refant used on the previous interval,
    6644             :   //   and the rest is a prioritized list of alternate refants,
    6645             :   //   starting with the user's secondary (if provided) refants,
    6646             :   //   followed by the rest of the array, in distance order.   This
    6647             :   //   makes the priorities correct all the time, and prevents
    6648             :   //   a semi-stochastic alternation (by preferring the last-used
    6649             :   //   alternate, even if nominally higher-priority refants become
    6650             :   //   available)
    6651             : 
    6652             : 
    6653             :   // Extract antenna positions
    6654          41 :   Matrix<Double> xyz;
    6655          41 :   if (msName()!="<noms>") {
    6656          41 :     MeasurementSet ms(msName());
    6657          41 :     MSAntennaColumns msant(ms.antenna());
    6658          41 :     msant.position().getColumn(xyz);
    6659          41 :   }
    6660             :   else {
    6661             :     // TBD RO*
    6662           0 :     CTColumns ctcol(*ct_);
    6663           0 :     CTAntennaColumns& antcol(ctcol.antenna());
    6664           0 :     antcol.position().getColumn(xyz);
    6665           0 :   }
    6666             : 
    6667             :   // Calculate (squared) antenna distances, relative
    6668             :   //  to last preferred antenna
    6669          41 :   Vector<Double> dist2(xyz.ncolumn(),0.0);
    6670         164 :   for (Int i=0;i<3;++i) {
    6671         123 :     Vector<Double> row=xyz.row(i);
    6672         123 :     row-=row(refantlist()(nUserRefant-1));
    6673         123 :     dist2+=square(row);
    6674         123 :   }
    6675             :   // Move preferred antennas to a large distance
    6676          85 :   for (Int i=0;i<nUserRefant;++i)
    6677          44 :     dist2(refantlist()(i))=DBL_MAX;
    6678             : 
    6679             :   // Generated sorted index
    6680          41 :   Vector<uInt> ord;
    6681          41 :   genSort(ord,dist2);
    6682             : 
    6683             :   // Assemble the whole choices list
    6684          41 :   Int nchoices=nUserRefant+1+ord.nelements();
    6685          41 :   Vector<Int> refantchoices(nchoices,0);
    6686          82 :   Vector<Int> r(refantchoices(IPosition(1,nUserRefant+1),IPosition(1,refantchoices.nelements()-1)));
    6687          41 :   convertArray(r,ord);
    6688             : 
    6689             :   // set first two to primary preferred refant
    6690          41 :   refantchoices(0)=refantchoices(1)=refantlist()(0);
    6691             : 
    6692             :   // set user's secondary refants (if any)
    6693          41 :   if (nUserRefant>1) 
    6694           6 :     refantchoices(IPosition(1,2),IPosition(1,nUserRefant))=
    6695           9 :       refantlist()(IPosition(1,1),IPosition(1,nUserRefant-1));
    6696             : 
    6697             :   //cout << "refantchoices = " << refantchoices << endl;
    6698             : 
    6699             : 
    6700          41 :   if (refantmode()=="strict") {
    6701           3 :     nchoices=1;
    6702           3 :     refantchoices.resize(1,True);
    6703             :   }
    6704             : 
    6705          41 :   Vector<Int> nPol(nSpw(),nPar());  // TBD:or 1, if data was single pol
    6706             : 
    6707          41 :   if (nPar()==2) {
    6708             :     // Verify that 2nd poln has unflagged solutions, PER SPW
    6709          39 :     ROCTMainColumns ctmc(*ct_);
    6710             : 
    6711          39 :     Block<String> cols(1);
    6712          39 :     cols[0]="SPECTRAL_WINDOW_ID";
    6713          39 :     CTIter ctiter(*ct_,cols);
    6714          39 :     Cube<Bool> fl;
    6715             : 
    6716         134 :     while (!ctiter.pastEnd()) {
    6717             : 
    6718          95 :       Int ispw=ctiter.thisSpw();
    6719          95 :       fl.assign(ctiter.flag());
    6720             : 
    6721          95 :       IPosition blc(3,0,0,0), trc(fl.shape());
    6722          95 :       trc-=1; trc(0)=blc(0)=1;
    6723             :       
    6724             :       //      cout << "ispw = " << ispw << " nfalse(fl(1,:,:)) = " << nfalse(fl(blc,trc)) << endl;
    6725             :       
    6726             :       // If there are no unflagged solutions in 2nd pol, 
    6727             :       //   avoid it in refant calculations
    6728          95 :       if (nfalse(fl(blc,trc))==0)
    6729           6 :         nPol(ispw)=1;
    6730             : 
    6731          95 :       ctiter.next();      
    6732          95 :     }
    6733          39 :   }
    6734             :   //  cout << "nPol = " << nPol << endl;
    6735             : 
    6736          41 :   Bool usedaltrefant(false);
    6737          41 :   Int currrefant(refantchoices(0)), lastrefant(-1);
    6738             : 
    6739          41 :   Block<String> cols(2);
    6740          41 :   cols[0]="SPECTRAL_WINDOW_ID";
    6741          41 :   cols[1]="TIME";
    6742          41 :   CTIter ctiter(*ct_,cols);
    6743             : 
    6744             :   // Arrays to hold per-timestamp solutions
    6745          41 :   Cube<Complex> solA, solB;
    6746          41 :   Cube<Bool> flA, flB;
    6747          41 :   Vector<Int> ant1A, ant1B, ant2B;
    6748          41 :   Matrix<Complex> refPhsr;  // the reference phasor [npol,nchan] 
    6749          41 :   Int lastspw(-1);
    6750          41 :   Bool first(true);
    6751        8326 :   while (!ctiter.pastEnd()) {
    6752        8285 :     Int ispw=ctiter.thisSpw();
    6753        8285 :     if (ispw!=lastspw) first=true;  // spw changed, start over
    6754             : 
    6755             :     // Read in the current sol, fl, ant1:
    6756        8285 :     solB.assign(ctiter.cparam());
    6757        8285 :     flB.assign(ctiter.flag());
    6758        8285 :     ant1B.assign(ctiter.antenna1());
    6759        8285 :     ant2B.assign(ctiter.antenna2()); 
    6760             : 
    6761             :     // First time thru, 'previous' solution same as 'current'
    6762        8285 :     if (first) {
    6763         551 :       solA.reference(solB);
    6764         551 :       flA.reference(flB);
    6765         551 :       ant1A.reference(ant1B);
    6766             :     }
    6767        8285 :     IPosition shB(solB.shape());
    6768        8285 :     IPosition shA(solA.shape());
    6769             : 
    6770             :     // Find a good refant at this time
    6771             :     //  A good refant is one that is unflagged in all polarizations
    6772             :     //     in the current(B) and previous(A) intervals (so they can be connected)
    6773        8285 :     Int irefA(0),irefB(0);  // index on 3rd axis of solution arrays
    6774        8285 :     Int ichoice(0);  // index in refantchoicelist
    6775        8285 :     Bool found(false);
    6776        8285 :     IPosition blcA(3,0,0,0),trcA(shA),blcB(3,0,0,0),trcB(shB);
    6777        8285 :     trcA-=1; trcA(0)=trcA(2)=0;
    6778        8285 :     trcB-=1; trcB(0)=trcB(2)=0;
    6779        8285 :     ichoice=0;
    6780       21423 :     while (!found && ichoice<nchoices) { 
    6781             :       // Find index of current refant choice
    6782       13138 :       irefA=irefB=0;
    6783       33197 :       while (ant1A(irefA)!=refantchoices(ichoice) && irefA<shA(2)) ++irefA;
    6784       33197 :       while (ant1B(irefB)!=refantchoices(ichoice) && irefB<shB(2)) ++irefB;
    6785             : 
    6786       13138 :       if (irefA<shA(2) && irefB<shB(2)) {
    6787             : 
    6788             :         //      cout << " Trial irefA,irefB: " << irefA << "," << irefB 
    6789             :         //           << "   Ants=" << ant1A(irefA) << "," << ant1B(irefB) << endl;
    6790             : 
    6791       13138 :         blcA(2)=trcA(2)=irefA;
    6792       13138 :         blcB(2)=trcB(2)=irefB;
    6793       13138 :         found=true;  // maybe
    6794       26780 :         for (Int ipol=0;ipol<nPol(ispw);++ipol) {
    6795       13642 :           blcA(0)=trcA(0)=blcB(0)=trcB(0)=ipol;
    6796       13642 :           found &= (nfalse(flA(blcA,trcA))>0);  // previous interval
    6797       13642 :           found &= (nfalse(flB(blcB,trcB))>0);  // current interval
    6798             :         } 
    6799             :       }
    6800             :       else
    6801             :         // irefA or irefB out-of-range
    6802           0 :         found=false;  // Just to be sure
    6803             : 
    6804       13138 :       if (!found) ++ichoice;  // try next choice next round
    6805             : 
    6806             :     }
    6807             : 
    6808        8285 :     if (found) {
    6809             :       // at this point, irefA/irefB point to a good refant
    6810             :       
    6811             :       // Keep track
    6812        7831 :       usedaltrefant|=(ichoice>0);
    6813        7831 :       currrefant=refantchoices(ichoice);
    6814        7831 :       refantchoices(1)=currrefant;  // 2nd priorty next time
    6815             :         
    6816             :       // Mark refant in activity rec
    6817        7831 :       refantMap_[ctiter.thisSpw()][currrefant] += 1;
    6818             : 
    6819             :       //      cout << " currrefant = " << currrefant << " (" << ichoice << ")" << endl;
    6820             : 
    6821             :       //      cout << " Final irefA,irefB: " << irefA << "," << irefB 
    6822             :       //           << "   Ants=" << ant1A(irefA) << "," << ant1B(irefB) << endl;
    6823             : 
    6824             : 
    6825             :       // Only report if using an alternate refant
    6826        7831 :       if (currrefant!=lastrefant && ichoice>0) {
    6827             :         logSink() 
    6828             :           << "At " 
    6829           4 :           << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7) 
    6830             :           << " ("
    6831             :           << "Spw=" << ctiter.thisSpw()
    6832             :           << ", Fld=" << ctiter.thisField()
    6833             :           << ")"
    6834           4 :           << ", using refant " << msmc().antennaName(currrefant)
    6835             :           << " (id=" << currrefant 
    6836             :           << ")" << " (alternate)"
    6837           6 :           << LogIO::POST;
    6838             :       }  
    6839             : 
    6840             :       // Form reference phasor [nPar,nChan]
    6841        7831 :       Matrix<Complex> rA,rB;
    6842        7831 :       Matrix<Float> ampA,ampB;
    6843        7831 :       Matrix<Bool> rflA,rflB;
    6844        7831 :       rB.assign(solB.xyPlane(irefB));
    6845        7831 :       rflB.assign(flB.xyPlane(irefB));
    6846        7831 :       switch (this->type()) {
    6847        7813 :       case VisCal::G:
    6848             :       case VisCal::B:
    6849             :       case VisCal::T: {
    6850        7813 :         ampB=amplitude(rB);
    6851        7813 :         rflB(ampB<FLT_EPSILON)=true; // flag... 
    6852        7813 :         rB(rflB)=Complex(1.0);       //  ...and reset zeros
    6853        7813 :         ampB(rflB)=1.0;
    6854        7813 :         rB/=ampB;  // rB now normalized ("phase"-only)
    6855        7813 :         break;
    6856             :       }
    6857          18 :       case VisCal::D: {
    6858             :         // Fill 2nd pol with negative conj of 1st pol
    6859          18 :         rB.row(1)=-conj(rB.row(0));
    6860          18 :         break;
    6861             :       }
    6862           0 :       default:
    6863           0 :         throw(AipsError("SVC::applyRefAnt attempted for inapplicable type"));
    6864             :       }
    6865             : 
    6866        7831 :       if (!first) {
    6867             :         // Get and condition previous phasor for the current refant
    6868        7734 :         rA.assign(solA.xyPlane(irefA));
    6869        7734 :         rflA.assign(flA.xyPlane(irefA));
    6870        7734 :         switch (this->type()) {
    6871        7734 :         case VisCal::G:
    6872             :         case VisCal::B:
    6873             :         case VisCal::T: {
    6874        7734 :           ampA=amplitude(rA);
    6875        7734 :           rflA(ampA<FLT_EPSILON)=true;  // flag...
    6876        7734 :           rA(rflA)=Complex(1.0);        // ...and reset zeros
    6877        7734 :           ampA(rflA)=1.0;
    6878        7734 :           rA/=ampA; // rA now normalized ("phase"-only)
    6879             :         
    6880             :           // Phase difference (as complex) relative to last
    6881        7734 :           rB/=rA;
    6882        7734 :           break;
    6883             :         }
    6884           0 :         case VisCal::D: {
    6885             :           // 
    6886           0 :           rA.row(1)=-conj(rA.row(0));
    6887             : 
    6888             :           // Complex difference relative to last
    6889           0 :           rB-=rA;
    6890           0 :           break;
    6891             :         }
    6892           0 :         default:
    6893           0 :           throw(AipsError("SVC::applyRefAnt attempted for inapplicable type"));
    6894             :         }
    6895             : 
    6896             :         // Accumulate flags
    6897        7734 :         rflB&=rflA;
    6898             :       }
    6899             :       
    6900             :       //      cout << " rB = " << rB << endl;
    6901             :       //      cout << boolalpha << " rflB = " << rflB << endl;
    6902             :       // TBD: fillChanGaps?
    6903             :       
    6904             :       // Now apply reference phasor to all antennas
    6905        7831 :       Matrix<Complex> thissol;
    6906       86879 :       for (Int iant=0;iant<shB(2);++iant) {
    6907       79048 :         thissol.reference(solB.xyPlane(iant));
    6908       79048 :         switch (this->type()) {
    6909       78868 :         case VisCal::G:
    6910             :         case VisCal::B:
    6911             :         case VisCal::T: {
    6912             :           // Complex division == phase subtraction
    6913       78868 :           thissol/=rB;
    6914       78868 :           break;
    6915             :         }
    6916         180 :         case VisCal::D: {
    6917             :           // Complex subtraction
    6918         180 :           thissol-=rB;
    6919         180 :           break;
    6920             :         }
    6921           0 :         default:
    6922           0 :           throw(AipsError("SVC::applyRefAnt attempted for inapplicable type"));
    6923             :         }
    6924             :       }
    6925             :       
    6926             :       // Set refant, so we can put it back
    6927        7831 :       ant2B=currrefant;
    6928             :       
    6929             :       // put back referenced solutions
    6930        7831 :       ctiter.setcparam(solB);
    6931        7831 :       ctiter.setantenna2(ant2B);
    6932             : 
    6933             :       // Next time thru, solB is previous
    6934        7831 :       solA.reference(solB);
    6935        7831 :       flA.reference(flB);
    6936        7831 :       ant1A.reference(ant1B);
    6937        7831 :       solB.resize();  // (break references)
    6938        7831 :       flB.resize();
    6939        7831 :       ant1B.resize();
    6940             :         
    6941        7831 :       lastrefant=currrefant;
    6942        7831 :       first=false;  // avoid first-pass stuff from now on
    6943             :       
    6944        7831 :     } // found
    6945             :     else {
    6946             :       logSink() 
    6947             :         << "At " 
    6948         908 :         << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7) 
    6949             :         << " ("
    6950             :         << "Spw=" << ctiter.thisSpw()
    6951             :         << ", Fld=" << ctiter.thisField()
    6952             :         << ")"
    6953             :         << ", refant (id=" << currrefant 
    6954             :         << ") was flagged; flagging all antennas strictly." 
    6955         908 :         << LogIO::POST;
    6956             :       // Flag all solutions in this interval
    6957         454 :       flB.set(True);
    6958         454 :       ctiter.setflag(flB);
    6959             :     }
    6960             : 
    6961             :     // advance to the next interval
    6962        8285 :     lastspw=ispw;
    6963        8285 :     ctiter.next();
    6964        8285 :   }
    6965             : 
    6966          41 :   if (usedaltrefant)
    6967             :     logSink() << LogIO::NORMAL
    6968             :               << " NB: An alternate refant was used at least once to maintain" << endl
    6969             :               << "  phase continuity where the user's preferred refant drops out." << endl
    6970             :               << "  Alternate refants are held constant in phase (_not_ zeroed)" << endl
    6971             :               << "  during these periods, and the preferred refant may return at" << endl
    6972             :               << "  a non-zero phase.  This is generally harmless."
    6973           2 :               << LogIO::POST;
    6974             : 
    6975          82 :   return;
    6976             : 
    6977          41 : }
    6978             : 
    6979             : 
    6980          29 : void SolvableVisJones::fluxscale(const String& outfile,
    6981             :                                  const Vector<Int>& refFieldIn,
    6982             :                                  const Vector<Int>& tranFieldIn,
    6983             :                                  const Vector<Int>& inRefSpwMap,
    6984             :                                  const Vector<String>& fldNames,
    6985             :                                  const Float& inGainThres,
    6986             :                                  const String& antSel,
    6987             :                                  const String& timerangeSel,
    6988             :                                  const String& scanSel,
    6989             :                                  fluxScaleStruct& oFluxScaleStruct,
    6990             :                                  const String& oListFile,
    6991             :                                  const Bool& incremental,
    6992             :                                  const Int& fitorder, 
    6993             :                                  const Bool& display) {
    6994             : 
    6995             :   //String outCalTabName="_tmp_testfluxscaletab";
    6996          29 :   String outCalTabName=outfile;
    6997             : 
    6998             :   //timerange
    6999             :   //String timerange("");
    7000             :   //String scanSel("");
    7001             :   // turn on incremental caltable mode
    7002             :   //Bool incremental = true;
    7003             :   //Bool fitperchan = true;
    7004             : 
    7005             :   // threshold for gain (amplitude) to be used in 
    7006             :   // fluxscale determination
    7007             :   // -1: no threshold
    7008             :   // plot histogram of gain ratio
    7009          29 :   Bool report_p=display;
    7010             : 
    7011          29 :   if (incremental) {
    7012             :     logSink() << LogIO::NORMAL
    7013             :               << "Generating an incremental caltable"
    7014           6 :               << LogIO::POST;
    7015             :   }
    7016             : 
    7017          29 :   if (!ct_ || ct_->nrow()<1)
    7018           0 :     throw(AipsError("SVJ:fluxscale: Empty or absent caltable specified"));
    7019             : 
    7020             :   // For updating the MS History Table
    7021             :   //  LogSink logSink_p = LogSink(LogMessage::NORMAL, false);
    7022             :   //  logSink_p.clearLocally();
    7023             :   //  LogIO oss(LogOrigin("calibrater", "fluxscale()"), logSink_p);
    7024             : 
    7025             :   // PtrBlocks to hold mean gain moduli and related
    7026          29 :   PtrBlock< Cube<Bool>* >   MGOK;
    7027          29 :   PtrBlock< Cube<Double>* > MG;
    7028          29 :   PtrBlock< Cube<Double>* > MG2;
    7029          29 :   PtrBlock< Cube<Double>* > MGWT;
    7030          29 :   PtrBlock< Cube<Double>* > MGVAR;
    7031          29 :   PtrBlock< Cube<Int>* >    MGN;
    7032          29 :   PtrBlock< Cube<Int>* >    MGNALL;
    7033             : 
    7034          29 :   Int nMSFld; fldNames.shape(nMSFld);
    7035             : 
    7036             :   // Assemble available field list from the NewCalTable
    7037          29 :   ROCTMainColumns mcols(*ct_);
    7038          29 :   Vector<Int> fldList;
    7039          29 :   mcols.fieldId().getColumn(fldList);
    7040          29 :   Int nFldList=genSort(fldList,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
    7041          29 :   fldList.resize(nFldList,true);
    7042             : 
    7043          29 :   Int nFld=max(fldList)+1;
    7044             : 
    7045             :   //get Antenna names
    7046          29 :   MSAntennaColumns antcol(ct_->antenna());
    7047          29 :   Vector<String> antNames(antcol.name().getColumn());
    7048             : 
    7049          29 :   Vector<Double> solFreq(nSpw(),-1.0);
    7050          29 :   Vector<Double> mgreft(nFld,0);
    7051             :  
    7052             : 
    7053             :   try {
    7054             : 
    7055             :     // Resize, NULL-initialize PtrBlocks
    7056          29 :     MGOK.resize(nFld);   MGOK=NULL;
    7057          29 :     MG.resize(nFld);     MG=NULL;
    7058          29 :     MG2.resize(nFld);    MG2=NULL;
    7059          29 :     MGWT.resize(nFld);   MGWT=NULL;
    7060          29 :     MGVAR.resize(nFld);  MGVAR=NULL;
    7061          29 :     MGN.resize(nFld);    MGN=NULL;
    7062          29 :     MGNALL.resize(nFld); MGNALL=NULL;
    7063             : 
    7064             :     // sort user-specified fields
    7065          29 :     Vector<Int> refField; refField = refFieldIn;
    7066             :     Int nRef,nTran;
    7067          29 :     nRef=genSort(refField,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
    7068             :     // temp copy of tranFieldIn
    7069          29 :     std::vector<Int> tmpTranField;
    7070          29 :     tranFieldIn.tovector(tmpTranField);
    7071          62 :     for (Int iRef=0; iRef<nRef; iRef++) {
    7072          33 :         auto iidx = std::find(tmpTranField.begin(),tmpTranField.end(),refField(iRef));
    7073          33 :         if (iidx != tmpTranField.end()) { 
    7074           4 :           logSink() << "The reference field, "<<fldNames(*iidx)
    7075             :                     << " , is also listed in the transfer fields. "
    7076             :                     <<" It will be ignored for further scaling process."
    7077           2 :                      << LogIO::POST;
    7078           2 :           tmpTranField.erase(iidx);
    7079             :         }
    7080             :     }
    7081             :     //Vector<Int> tranField; tranField = tranFieldIn;
    7082          29 :     Vector<Int> tranField(tmpTranField);
    7083          29 :     nTran=genSort(tranField,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
    7084             : 
    7085             :     // make masks for ref/tran among available fields
    7086          29 :     Vector<Bool> tranmask(nFldList,true);
    7087          29 :     Vector<Bool> refmask(nFldList,false);
    7088         107 :     for (Int iFld=0; iFld<nFldList; iFld++) {
    7089          78 :       if ( anyEQ(refField,fldList(iFld)) ) {
    7090             :         // this is a ref field
    7091          33 :         refmask(iFld)=true;
    7092          33 :         tranmask(iFld)=false;
    7093             :       }
    7094             :     }
    7095             : 
    7096             :     // Check availability of all ref fields
    7097          29 :     if (ntrue(refmask)==0) {
    7098           0 :       throw(AipsError(" Cannot find specified reference field(s)"));
    7099             :     }
    7100             :     // Any fields present other than ref fields?
    7101          29 :     if (ntrue(tranmask)==0) {
    7102           0 :       throw(AipsError(" Cannot find solutions for transfer field(s)"));
    7103             :     }
    7104             : 
    7105             :     // make implicit reference field list
    7106          29 :     MaskedArray<Int> mRefFldList(fldList,LogicalArray(refmask));
    7107          29 :     Vector<Int> implRefField(mRefFldList.getCompressedArray());
    7108             : 
    7109             :     // Check for missing reference fields
    7110          29 :     if (Int(ntrue(refmask)) < nRef) {
    7111           0 :       ostringstream x;
    7112           0 :       for (Int iRef=0; iRef<nRef; iRef++) {
    7113           0 :         if ( !anyEQ(fldList,refField(iRef)) ) {
    7114           0 :           if (refField(iRef)>-1 && refField(iRef) < nMSFld) x << fldNames(refField(iRef)) << " ";
    7115           0 :           else x << "Index="<<refField(iRef)+1<<"=out-of-range ";
    7116             :         }
    7117             :       }
    7118           0 :       String noRefSol=x.str();
    7119             :       logSink() << LogIO::WARN
    7120             :                 << " The following reference fields have no solutions available: "
    7121             :                 << noRefSol
    7122           0 :                 << LogIO::POST;
    7123           0 :       refField.reference(implRefField);
    7124           0 :     }
    7125          29 :     refField.shape(nRef);
    7126             : 
    7127             :     // make implicit tranfer field list
    7128          29 :     MaskedArray<Int> mTranFldList(fldList,LogicalArray(tranmask));
    7129          29 :     Vector<Int> implTranField(mTranFldList.getCompressedArray());
    7130          29 :     Int nImplTran; implTranField.shape(nImplTran);
    7131             : 
    7132             :     //    cout << "implTranField = " << implTranField << endl;
    7133             : 
    7134             :     // Check availability of transfer fields
    7135             : 
    7136             :     // If user specified no transfer fields, use implicit 
    7137             :     //  transfer field list, ELSE check for missing tran fields
    7138             :     //  among those they specified
    7139          29 :     if (nTran==0) {
    7140          17 :       tranField.reference(implTranField);
    7141             :       logSink() << LogIO::NORMAL
    7142             :                 << " Assuming all non-reference fields are transfer fields."
    7143          17 :                 << LogIO::POST;
    7144             :     } else {
    7145          15 :       if ( !(nTran==nImplTran &&
    7146           3 :              allEQ(tranField,implTranField)) ) {
    7147           9 :         ostringstream x;
    7148          18 :         for (Int iTran=0; iTran<nTran; iTran++) {
    7149           9 :           if ( !anyEQ(implTranField,tranField(iTran)) ) {
    7150           0 :             if (tranField(iTran)>-1 && tranField(iTran) < nMSFld) x << fldNames(tranField(iTran)) << " ";
    7151           0 :             else x << "Index="<<tranField(iTran)+1<<"=out-of-range ";
    7152             :           }
    7153             :         }
    7154           9 :         String noTranSol=x.str();
    7155           9 :         if (x!="") {
    7156             :         logSink() << LogIO::WARN
    7157             :                   << " The following transfer fields have no solutions available: "
    7158             :                   << noTranSol
    7159           0 :                   << LogIO::POST;
    7160             :         }
    7161             :         //tranField.reference(implTranField);
    7162           9 :       }
    7163             :     }
    7164          29 :     tranField.shape(nTran);
    7165             :   
    7166             :     // make a combined field list 
    7167          58 :     std::vector<Int> allfields(refField.begin(), refField.end());
    7168          29 :     allfields.insert(allfields.end(), tranField.begin(), tranField.end());
    7169             :     
    7170             :     // Report ref, tran field info
    7171          29 :     String refNames(fldNames(refField(0)));
    7172          33 :     for (Int iRef=1; iRef<nRef; iRef++) {
    7173           4 :       refNames+=" ";
    7174           4 :       refNames+=fldNames(refField(iRef));
    7175             :     }
    7176             :     logSink() << " Found reference field(s): " << refNames 
    7177          29 :               << LogIO::POST;
    7178          29 :     String tranNames(fldNames(tranField(0)));
    7179          35 :     for (Int iTran=1; iTran<nTran; iTran++) {
    7180           6 :       tranNames+=" ";
    7181           6 :       tranNames+=fldNames(tranField(iTran));
    7182             :     }
    7183             :     logSink() << " Found transfer field(s):  " << tranNames 
    7184          29 :               << LogIO::POST;
    7185             : 
    7186             :     // Handle spw referencing
    7187          29 :     Vector<Int> refSpwMap;
    7188          29 :     refSpwMap.resize(nSpw());
    7189          29 :     indgen(refSpwMap);
    7190             : 
    7191          29 :     if (inRefSpwMap(0)>-1) {
    7192           5 :       if (inRefSpwMap.nelements()==1) {
    7193           0 :         refSpwMap=inRefSpwMap(0);
    7194           0 :         logSink() << " All spectral windows will be referenced to spw=" << inRefSpwMap(0) 
    7195           0 :                   << LogIO::POST;
    7196             :       } else {
    7197          23 :         for (Int i=0; i<Int(inRefSpwMap.nelements()); i++) {
    7198          18 :           if (inRefSpwMap(i)>-1 && inRefSpwMap(i)!=i) {
    7199           9 :             refSpwMap(i)=inRefSpwMap(i);
    7200          18 :             logSink() << " Spw=" << i << " will be referenced to spw=" << inRefSpwMap(i) 
    7201           9 :                       << LogIO::POST;
    7202             :           }
    7203             :         }
    7204             :       }
    7205             :     }
    7206             :  
    7207             :     // Field names for log messages
    7208             : 
    7209             :     //    cout << "Filling mgnorms....";
    7210             : 
    7211          29 :     Matrix<Float> medianGains(nFld,nSpw(),0.0); //keeps median (amplitude) gains for each field for each spw
    7212             :     { // make an inner scope
    7213          29 :     Block<String> cols(4);
    7214          29 :     cols[0]="SPECTRAL_WINDOW_ID";
    7215          29 :     cols[1]="TIME";
    7216          29 :     cols[2]="FIELD_ID"; // should usually be degenerate with TIME?
    7217          29 :     cols[3]="ANTENNA1";
    7218             :     //ROCTIter ctiter(*ct_,cols);
    7219             : 
    7220             :     // Loop over solutions and fill the calculation
    7221          29 :     Cube<Bool>   mgok;   // For referencing PtrBlocks...
    7222          29 :     Cube<Double> mg;  
    7223          29 :     Cube<Double> mg2; 
    7224          29 :     Cube<Double> mgwt;   
    7225          29 :     Cube<Int>    mgn;    
    7226          29 :     Cube<Int>    mgnall;    
    7227          29 :     Int prevFld(-1);
    7228             : 
    7229          29 :     Int lastFld(-1);
    7230             : 
    7231             :     // determine median gain amplitude for each field 
    7232             :     // use CTinterface to appy selection with MSSelection syntax
    7233          29 :     NewCalTable selct(*ct_);
    7234          29 :     CTInterface cti(*ct_);
    7235          29 :     Vector<Int> selAntList;
    7236          29 :     Vector<Int> deselAntList;
    7237          29 :     Vector<Int> allAntList(nElem());
    7238          29 :     indgen(allAntList);
    7239          58 :     vector<Int> tmpAllAntList(allAntList.begin(),allAntList.end());
    7240             :     // 
    7241             :     // Check if antenna specific time/scan selection is needed.
    7242             :     // If so get selected time col for later use to flag the data. 
    7243             :     // The negation '!' is used as a keyword to trigger such a selection mode. 
    7244          29 :     Bool doPerAntSel(false);
    7245          29 :     Vector<Double> selTime;
    7246          29 :     if (antSel!="" ) {
    7247           4 :       if (antSel.contains(casacore::Regex("^!")) && (timerangeSel!="" || scanSel!="")) {
    7248           2 :         doPerAntSel = true;
    7249             :       // if doPerAntSel time/scan sel only applied to deselected ant in antSel
    7250             :       // so need to construct selected table based on that
    7251           2 :         MSSelection msssub;
    7252           2 :         String antsel=antSel;
    7253           2 :         antsel.ltrim('!');
    7254           2 :         msssub.setAntennaExpr(antsel);
    7255           2 :         if (timerangeSel != "") msssub.setTimeExpr(timerangeSel);
    7256           2 :         if (scanSel != "") msssub.setScanExpr(scanSel);
    7257           2 :         TableExprNode tensub=msssub.toTableExprNode(&cti);
    7258           2 :         getSelectedTable(selct,*ct_,tensub,"");
    7259           2 :         ROCTMainColumns ctmc(selct);
    7260           2 :         selTime=ctmc.time().getColumn();
    7261           2 :         deselAntList=ctmc.antenna1().getColumn();
    7262           2 :         Int ndeselAnt=genSort(deselAntList,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
    7263           2 :         deselAntList.resize(ndeselAnt,true);
    7264           2 :       }
    7265             :     }         
    7266             : 
    7267          29 :     Bool firstpass(true);
    7268         113 :     for (Int iFld=0; iFld<nFld; iFld++) {
    7269             : 
    7270          84 :       MSSelection mss;
    7271             :       //String antSel("!ea25");
    7272             :       //String antSel("0~26");
    7273             :       //String antSel("");
    7274          84 :       mss.setFieldExpr(String::toString(iFld));     
    7275          84 :       if (antSel!="") {
    7276          11 :         if (!doPerAntSel) {
    7277             :           // applied selections globally 
    7278           5 :           mss.setAntennaExpr(antSel);
    7279           5 :           if (timerangeSel!="")  mss.setTimeExpr(timerangeSel);
    7280           5 :           if (scanSel!="") mss.setScanExpr(scanSel);
    7281             :         }
    7282             :       } else {
    7283          73 :         selAntList=allAntList;
    7284             :       } 
    7285          84 :       std::vector<Int> tmpSelAntList;
    7286          84 :       Vector<Bool> validSels(nSpw(),true);
    7287         292 :       for (Int iSpw=0; iSpw<nSpw(); iSpw++) {
    7288             :         //reset MSSelection
    7289         208 :         mss.clear(MSSelection::SPW_EXPR);
    7290             :         //mss.setFieldExpr(String::toString(iFld));     
    7291         208 :         mss.setSpwExpr(String::toString(iSpw));     
    7292             :         try {
    7293         208 :           TableExprNode ten=mss.toTableExprNode(&cti);
    7294         230 :           getSelectedTable(selct,*ct_,ten,"");
    7295         186 :           ROCTMainColumns ctmc(selct);
    7296         186 :           Array<Float> outparams;
    7297         186 :           Array<Bool> flagcol=ctmc.flag().getColumn();
    7298         186 :           Vector<Double> timecol=ctmc.time().getColumn();
    7299         186 :           Vector<Int> antenna1=ctmc.antenna1().getColumn();
    7300             :           // Do antenna-specific the selections in time 
    7301         186 :           IPosition flshp = flagcol.shape();
    7302         186 :           if (doPerAntSel && selTime.nelements()!=0) {
    7303         398 :             for (uInt ifg = 0; ifg < flshp(2); ifg++) {
    7304        1176 :               for (Int ipar = 0; ipar < nPar(); ipar++) {
    7305         784 :                 if (anyEQ(deselAntList, antenna1(ifg)) && !anyEQ(selTime, timecol(ifg)))
    7306             :                   //outflag(IPosition(3,ipar,0,ifg))=false;
    7307           8 :                   flagcol(IPosition(3,ipar,0,ifg))=true;
    7308             :               }
    7309             :             }
    7310             :           }
    7311             :           // reverse the flag for a masked array
    7312         186 :           LogicalArray outflag(!flagcol);
    7313             :           //cerr<<"ntrue outflag ="<<ntrue(outflag)<<endl;
    7314         186 :           ctmc.fparamArray(outparams,"AP");
    7315             :           // get subset (amp only) of the array
    7316         186 :           IPosition arshp = outparams.shape();
    7317         186 :           IPosition start(3,0,0,0);
    7318         186 :           Int pinc = nPar()!=1 ? 2: 1;
    7319         186 :           Int pshp = arshp(0)!=1 ? Int(arshp(0)/2) : 1; 
    7320             :           //IPosition length(3,Int(arshp(0)/pinc),1,arshp(arshp.nelements()-1));
    7321         186 :           IPosition length(3,pshp,1,arshp(arshp.nelements()-1));
    7322         186 :           IPosition stride(3,pinc,1,1);
    7323         186 :           Slicer slicer(start,length,stride);
    7324         186 :           Array<Float> subarr=outparams(slicer);
    7325         186 :           MaskedArray<Float> moutparams(subarr,outflag);
    7326             :           //Vector<Float> subarr2 = moutparams.getCompressedArray();
    7327             :           // Get selected antenna list in ant ids.
    7328             :           // While it is applied to all fields and spws
    7329             :           // the actual selections happen per spw. So we do it here but only for the first
    7330             :           // successful selection for the data and use it for the rest of the process.
    7331         186 :           if (antSel!="" && firstpass) {
    7332           4 :             Vector<Int> selantlist=ctmc.antenna1().getColumn();
    7333           4 :             Int nSelAnt=genSort(selantlist,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
    7334           4 :             selantlist.resize(nSelAnt,true);
    7335           4 :             selAntList=selantlist;
    7336             :             //cerr<<"selantlist.nelements()="<<selantlist.nelements()<<endl;
    7337           4 :             String oMsg( "" );
    7338           4 :             if ( doPerAntSel ) {
    7339           2 :               oMsg+="Selected data range for antenna(s): "+String::toString(deselAntList)+",";
    7340           2 :               if ( timerangeSel!="") oMsg+= " time range:"+timerangeSel;
    7341           2 :               if ( scanSel!="") oMsg+= " scan(s):"+scanSel;
    7342             :             }
    7343             :             else { 
    7344           2 :               oMsg+=" Selected antennas: "+String::toString(selAntList);
    7345             :             }
    7346           4 :             logSink() << oMsg << LogIO::POST;
    7347           4 :             firstpass=false;
    7348           4 :           }
    7349             : 
    7350             :           //medianGains(iFld,iSpw)=median(subarr2);
    7351         186 :           medianGains(iFld,iSpw)=median(moutparams);
    7352         185 :           String oMsg( "" );
    7353         370 :           oMsg+="median(field="+String::toString(iFld)+",spw="+String::toString(iSpw)+")="+\
    7354         555 :              String::toString(medianGains(iFld,iSpw));
    7355         185 :           logSink() << LogIO::NORMAL3<< oMsg << LogIO::POST;
    7356         245 :         } catch (...) {
    7357          23 :          if (anyEQ(tranField,iFld)) validSels[iSpw]=false;
    7358          23 :         }
    7359             :       }
    7360          84 :       if (!ntrue(validSels)) 
    7361           0 :             throw(AipsError("The input selections results in empy data selection for the transfer field="
    7362           0 :                   +String::toString(iFld)));
    7363          84 :     } //for-iFld 
    7364          29 :     NewCalTable selct2(*ct_);
    7365          29 :     CTInterface cti2(*ct_);
    7366          29 :     MSSelection mss2;
    7367          29 :     String fieldstr;
    7368          97 :     for (uInt iselfld=0; iselfld<allfields.size();iselfld++) {
    7369          68 :       fieldstr+=String::toString(allfields[iselfld]);
    7370          68 :       if (iselfld!=allfields.size()-1) fieldstr+=',';
    7371             :     } 
    7372          29 :     mss2.setFieldExpr(fieldstr);
    7373          29 :     if (!doPerAntSel) {
    7374          27 :       mss2.setAntennaExpr(antSel);
    7375          27 :       mss2.setTimeExpr(timerangeSel);
    7376          27 :       mss2.setScanExpr(scanSel);
    7377             :     }
    7378          29 :     TableExprNode ten2=mss2.toTableExprNode(&cti2);
    7379          29 :     getSelectedTable(selct2,*ct_,ten2,"");
    7380             : 
    7381          29 :     ROCTIter ctiter(selct2,cols);
    7382       13935 :     while (!ctiter.pastEnd()) {
    7383       13906 :       Int iSpw(ctiter.thisSpw());
    7384       13906 :       Int iFld(ctiter.thisField());
    7385       13906 :       Int iAnt(ctiter.thisAntenna1());
    7386             :       //refTime_ = ctiter.thisTime();
    7387       13906 :       if (iFld > prevFld) {
    7388         586 :         mgreft = ctiter.thisTime();
    7389             :       }
    7390       13906 :       prevFld = iFld;
    7391             : 
    7392       13906 :       if (solFreq(iSpw)<0.0) {
    7393          78 :         Vector<Double> freq;
    7394          78 :         ctiter.freq(freq);
    7395          78 :         uInt nFrq=freq.nelements();
    7396          78 :         solFreq(iSpw)=freq(nFrq/2);
    7397          78 :       }
    7398             :         
    7399       13906 :       if (MGOK[iFld]==NULL) {
    7400             :         // First time this field, allocate ant/spw matrices
    7401          68 :         MGOK[iFld]   = new Cube<Bool>(nPar(),nElem(),nSpw(),false);
    7402          68 :         MG[iFld]     = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
    7403          68 :         MG2[iFld]    = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
    7404          68 :         MGWT[iFld]   = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
    7405          68 :         MGVAR[iFld]  = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
    7406          68 :         MGN[iFld]    = new Cube<Int>(nPar(),nElem(),nSpw(),0);
    7407             :         // for reporting numbers of solution used
    7408          68 :         MGNALL[iFld] = new Cube<Int>(nPar(),nElem(),nSpw(),0);
    7409             :         
    7410             :       }
    7411             :       // References to PBs for syntactical convenience
    7412             :       //  TBD: should need to do this for each iteration (nAnt times redundant!)
    7413       13906 :       if (iFld!=lastFld) {
    7414        1125 :         mgok.reference(*(MGOK[iFld]));
    7415        1125 :         mg.reference(*(MG[iFld]));
    7416        1125 :         mg2.reference(*(MG2[iFld]));
    7417        1125 :         mgwt.reference(*(MGWT[iFld]));
    7418        1125 :         mgn.reference(*(MGN[iFld]));
    7419        1125 :         mgnall.reference(*(MGNALL[iFld]));
    7420             :       }
    7421             : 
    7422             :       // References to PBs for syntactical convenience
    7423             :       // TBD: Handle "iFitwt" from NewCalTable?
    7424             :       // Double wt=cs().iFitwt(iSpw)(iAnt,islot);
    7425       13906 :       Double wt=1;
    7426             :               
    7427             :       // amps, flags  [npar]  (one channel, one antenna)
    7428             :       // check for data shape (e.g. duplicated entries)
    7429       13906 :       Cube<Complex> CParam(ctiter.cparam());
    7430       13906 :       IPosition testShape=CParam.shape();
    7431       13906 :       if (testShape[2]!=1) {
    7432           0 :         if (testShape[2]>1) { 
    7433             :           // possible cause: append=true in gaincal
    7434           0 :           throw(AipsError("Found multiple gain solutions in a single timestamp for fieldid="+String::toString(iFld)+". Please check the input Caltable."));
    7435             :         }
    7436             :         else {
    7437           0 :           throw(AipsError("Found gain solution array shape, "+String::toString(testShape)+" while expected [2,1,1]. Please check the input Caltable."));
    7438             :         }
    7439             :       } 
    7440             :       //Vector<Float> amp(amplitude(ctiter.cparam())[0]);
    7441       13906 :       Vector<Float> amp(amplitude(CParam));
    7442       13906 :       Vector<Bool> fl(ctiter.flag());
    7443       41718 :       for (Int ipar=0; ipar<nPar(); ipar++) {
    7444       27812 :         if (!fl(ipar)) {
    7445       26700 :           Double gn=amp(ipar); // converts to Double
    7446             :           // evaluate input gain to be within the threshold
    7447       26700 :           Float lowbound= (inGainThres >0 and inGainThres <1.0)? 1.0 - inGainThres : 0.0;
    7448       26700 :           if (inGainThres==0) lowbound=1.0;
    7449             :           //if ((anyEQ(selAntList,iAnt) &&  && (inGainThres < 0 || 
    7450       26970 :           if (inGainThres < 0 || 
    7451             :            //     (gn >= lowbound*medianGains(iFld,iSpw)))  { 
    7452             :            // take both lower and upper bounds
    7453         270 :               (gn >= lowbound*medianGains(iFld,iSpw)  and 
    7454         265 :                gn <= (1.0 + inGainThres) * medianGains(iFld,iSpw)))  {
    7455             :               
    7456       26650 :             if (doPerAntSel && selTime.nelements() != 0) {
    7457         540 :                if (anyEQ(deselAntList,iAnt) && !anyEQ(selTime,ctiter.thisTime())) {
    7458           6 :                   logSink()<<LogIO::NORMAL3<<"skipped "<<ctiter.thisTime()<<" for iAnt="<<iAnt<<LogIO::POST;
    7459           6 :                   continue;
    7460             :                }
    7461             :             } 
    7462             :             //cerr<<"fld="<<iFld<<" spw="<<iSpw<<" ant="<<iAnt<<" gn="<<gn<<" median="<<medianGains(iFld,iSpw)<<endl;
    7463       26644 :             mgok(ipar,iAnt,iSpw)=true;
    7464       26644 :             mg(ipar,iAnt,iSpw) += (wt*gn);
    7465       26644 :             mg2(ipar,iAnt,iSpw)+= (wt*gn*gn);
    7466       26644 :             mgn(ipar,iAnt,iSpw)++;
    7467       26644 :             mgwt(ipar,iAnt,iSpw)+=wt;
    7468             :           }
    7469             :           else {
    7470          50 :             String debugMsg( "" ); 
    7471         100 :             debugMsg+="Rejected field="+String::toString(iFld)+" spw="+String::toString(iSpw)+" antenna="+String::toString(iAnt)+
    7472         200 :                       "; gain(amp)="+String::toString(gn)+" is outside the accepted range:"+String::toString(lowbound*medianGains(iFld,iSpw))+
    7473         150 :                       " ~ "+String::toString((1.0 + inGainThres) * medianGains(iFld,iSpw));
    7474          50 :             logSink() << LogIO::DEBUG1 << debugMsg << LogIO::POST;
    7475          50 :           }
    7476       26694 :           mgnall(ipar,iAnt,iSpw)++;
    7477             :         }
    7478             :       }
    7479       13906 :       lastFld=iFld;
    7480       13906 :       ctiter.next();
    7481       13906 :     }//end of while
    7482          29 :     } // end inner scope 
    7483             :    
    7484             :     //for reporting only
    7485          29 :     if (inGainThres>=0.0) {
    7486           1 :       String oMsg( "" );
    7487           1 :       oMsg+=" Applying gain threshold="+String::toString(inGainThres);
    7488           1 :       logSink() << oMsg << LogIO::POST;
    7489           1 :       Bool hasFlaggedData(false);
    7490             :       //for (Int iFld=0; iFld<nFld; iFld++) {
    7491             :       Int iFld;
    7492           3 :       for (int idx=0; idx < (int) allfields.size(); idx++) {
    7493           2 :         iFld = allfields[idx];
    7494           2 :         if (MGOK[iFld]!=NULL) {
    7495           2 :           Cube<Bool>    mgok;   mgok.reference(*(MGOK[iFld]));
    7496           2 :           Cube<Int>    mgn;    mgn.reference(*(MGN[iFld]));
    7497           2 :           Cube<Int>    mgnall;    mgnall.reference(*(MGNALL[iFld]));
    7498             :           //cerr<<"ntrue="<<ntrue(mgok)<< " shape="<<mgok.shape()<<endl;
    7499             :           //cerr<<"mgn shape="<<mgn.shape()<<endl;
    7500             :           //cerr<<"mgnall shape="<<mgnall.shape()<<endl;
    7501           4 :           for (Int iSpw=0; iSpw<nSpw(); iSpw++) {
    7502             :             //cerr<<"median gain="<<medianGains(iFld,iSpw)<<endl;
    7503          58 :             for (Int iAnt=0; iAnt<nElem(); iAnt++) {
    7504          56 :               IPosition start(3,0,iAnt,iSpw);
    7505          56 :               IPosition length(3,nPar(),1,1);
    7506          56 :               IPosition stride(3,1,1,1);
    7507          56 :               Slicer slicer(start,length,stride);
    7508             :               //if (ntrue(mgok(slicer))) {
    7509          56 :               if ( sum(mgn(slicer))<sum(mgnall(slicer)) ) {
    7510             :                 //cerr<<"iFld:"<<iFld<<" iAnt:"<<iAnt<<"  sum(mgn)="<<sum(mgn(slicer))<<" sum(mgnall(slicer))="<<sum(mgnall(slicer))<<endl;
    7511          14 :                 Float frac=Float (sum(mgn(slicer)))/Float (sum(mgnall(slicer)));
    7512          14 :                 ostringstream fracstream;
    7513          14 :                 fracstream.precision(3);
    7514          14 :                 if (frac<1.0) {
    7515             :                   // report a fraction flagged
    7516          14 :                   fracstream << (1.0-frac)*100.0;
    7517          14 :                   oMsg="";
    7518             :                   //cerr<<"iFld="<<iFld<<" iAnt="<<iAnt<<": "<<frac*100.0<<"% of "<<sum(mgnall(slicer))<<" will be excluded"<<endl;
    7519             :                   //oMsg+="  Field ID="+String::toString(tranField(iFld))+" Antenna ID="+String::toString(iAnt)+": ";
    7520             :                   //oMsg+="  Field ID="+String::toString(allfields[idx])+" Antenna ID="+String::toString(iAnt)+": ";
    7521          14 :                   oMsg+="  "+fldNames(allfields[idx])+"(id="+String::toString(allfields[idx])+") Antenna:"+antNames(iAnt)+"(id="+String::toString(iAnt)+"): ";
    7522          14 :                   oMsg+=fracstream.str()+" % of ";
    7523             :                   //oMsg+=String::toString(sum(mgnall(slicer)) )+" solutions will be used";
    7524          14 :                   oMsg+=String::toString(sum(mgnall(slicer)) )+" solution(s) will be excluded";
    7525          14 :                   logSink() << oMsg << LogIO::POST;
    7526             :                 }
    7527          14 :                 hasFlaggedData=true;
    7528          14 :               }//ntrue()
    7529          56 :             } //iAnt 
    7530             :           } //iSpw
    7531           2 :         }
    7532             :       }//iFld
    7533           1 :       if (!hasFlaggedData) {
    7534           0 :         oMsg=" None of the gains were exceeded the threshold.";
    7535           0 :         logSink() << oMsg << LogIO::POST;
    7536             :       }
    7537           1 :     }//gainthreshold 
    7538             :   /*
    7539             : 
    7540             :     // fill per-ant -fld, -spw  mean gain moduli
    7541             :     for (Int iSpw=0; iSpw<nSpw(); iSpw++) {
    7542             : 
    7543             :       if (cs().nTime(iSpw) > 0 ) {
    7544             : 
    7545             :         for (Int islot=0; islot<cs().nTime(iSpw); islot++) {
    7546             :           Int iFld=cs().fieldId(iSpw)(islot);
    7547             :           if (MGOK[iFld]==NULL) {
    7548             :             // First time this field, allocate ant/spw matrices
    7549             :             MGOK[iFld]   = new Cube<Bool>(nPar(),nElem(),nSpw(),false);
    7550             :             MG[iFld]     = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
    7551             :             MG2[iFld]    = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
    7552             :             MGWT[iFld]   = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
    7553             :             MGVAR[iFld]  = new Cube<Double>(nPar(),nElem(),nSpw(),0.0);
    7554             :             MGN[iFld]    = new Cube<Int>(nPar(),nElem(),nSpw(),0);
    7555             : 
    7556             :           }
    7557             :           // References to PBs for syntactical convenience
    7558             :           Cube<Bool>   mgok;   mgok.reference(*(MGOK[iFld]));
    7559             :           Cube<Double> mg;  mg.reference(*(MG[iFld]));
    7560             :           Cube<Double> mg2; mg2.reference(*(MG2[iFld]));
    7561             :           Cube<Double> mgwt;   mgwt.reference(*(MGWT[iFld]));
    7562             :           Cube<Int>    mgn;    mgn.reference(*(MGN[iFld]));
    7563             : 
    7564             :           for (Int iAnt=0; iAnt<nElem(); iAnt++) {
    7565             :             if (true) { // || antmask(iAnt)) {
    7566             :               Double wt=cs().iFitwt(iSpw)(iAnt,islot);
    7567             :               
    7568             :               for (Int ipar=0; ipar<nPar(); ipar++) {
    7569             :                 IPosition ip(4,ipar,0,iAnt,islot);
    7570             :                 if (cs().parOK(iSpw)(ip)) {
    7571             :                   Double gn=abs( cs().par(iSpw)(ip) );
    7572             :                   mgok(ipar,iAnt,iSpw)=true;
    7573             :                   mg(ipar,iAnt,iSpw) += (wt*gn);
    7574             :                   mg2(ipar,iAnt,iSpw)+= (wt*gn*gn);
    7575             :                   mgn(ipar,iAnt,iSpw)++;
    7576             :                   mgwt(ipar,iAnt,iSpw)+=wt;
    7577             :                 }
    7578             :               }
    7579             :             }
    7580             :           }
    7581             :         }
    7582             :       }
    7583             :     }
    7584             :   */
    7585             : 
    7586             :     //    cout << "done." << endl;
    7587             : 
    7588             :     //    cout << "Normalizing mgs...";
    7589             : 
    7590             : 
    7591             :     // normalize mg
    7592         113 :     for (Int iFld=0; iFld<nFld; iFld++) {
    7593             : 
    7594             :       //      cout << "iFld = " << iFld << " " << MGOK[iFld]->column(0) << endl;
    7595             : 
    7596             :       // Have data for this field?
    7597          84 :       if (MGOK[iFld]!=NULL) {
    7598             :         // References to PBs for syntactical convenience
    7599          68 :         Cube<Bool>   mgok;   mgok.reference(*(MGOK[iFld]));
    7600          68 :         Cube<Double> mg;  mg.reference(*(MG[iFld]));
    7601          68 :         Cube<Double> mg2; mg2.reference(*(MG2[iFld]));
    7602          68 :         Cube<Double> mgwt;   mgwt.reference(*(MGWT[iFld]));
    7603          68 :         Cube<Double> mgvar;  mgvar.reference(*(MGVAR[iFld]));
    7604          68 :         Cube<Int>    mgn;    mgn.reference(*(MGN[iFld]));
    7605             : 
    7606         254 :         for (Int iSpw=0; iSpw<nSpw(); iSpw++) {
    7607        2624 :           for (Int iAnt=0; iAnt<nElem(); iAnt++) {
    7608        7314 :             for (Int ipar=0;ipar<nPar(); ++ipar) {
    7609        4876 :               if ( mgok(ipar,iAnt,iSpw) && mgwt(ipar,iAnt,iSpw)>0.0 ) {
    7610        4159 :                 mg(ipar,iAnt,iSpw)/=mgwt(ipar,iAnt,iSpw);
    7611        4159 :                 mg2(ipar,iAnt,iSpw)/=mgwt(ipar,iAnt,iSpw);
    7612             :                 // Per-ant, per-spw variance (non-zero only if sufficient data)
    7613        4159 :                 if (mgn(ipar,iAnt,iSpw) > 2) {
    7614        2922 :                   mgvar(ipar,iAnt,iSpw) = (mg2(ipar,iAnt,iSpw) - pow(mg(ipar,iAnt,iSpw),2.0))/(mgn(ipar,iAnt,iSpw)-1);
    7615             :                 }
    7616             :               } else {
    7617         717 :                 mg(ipar,iAnt,iSpw)=0.0;
    7618         717 :                 mgwt(ipar,iAnt,iSpw)=0.0;
    7619         717 :                 mgok(ipar,iAnt,iSpw)=false;
    7620             :               }
    7621             :             }
    7622             :    /*
    7623             :             cout << " iSpw = " << iSpw << " iFld = " << iFld;
    7624             :             cout << " iAnt = " << iAnt;
    7625             :             cout << " mg = " << mg(iAnt,iSpw);
    7626             :             cout << " +/- " << sqrt(1.0/mgwt(iAnt,iSpw));
    7627             :             cout << " SNR = " << mg(iAnt,iSpw)/sqrt(1.0/mgwt(iAnt,iSpw));
    7628             :             cout << "  " << mgn(iAnt,iSpw);
    7629             :             cout << endl;
    7630             :    */
    7631             :           }
    7632             :         }
    7633             : 
    7634          68 :       } //if-MGOK end
    7635             :     } 
    7636             : 
    7637             : 
    7638             :     //    cout << "done." << endl;
    7639             :     //    cout << "nTran = " << nTran << endl;
    7640             : 
    7641             :     //    cout << "Calculating scale factors...";
    7642             : 
    7643             :     // Collapse ref field mg's into a single ref
    7644          29 :     Cube<Double> mgref;
    7645          29 :     Cube<Bool>  mgrefok;
    7646          29 :     mgref.reference(*MG[refField(0)]);
    7647          29 :     mgrefok.reference(*MGOK[refField(0)]);
    7648             : 
    7649          29 :     if (nRef>1) {
    7650             :       //Store no. of fields that is not flagged per pol,ant,and spw
    7651           2 :       Cube<Double> nokref(nPar(),nElem(),nSpw(),0);
    7652             :       // Add on additional ref fields
    7653           6 :       for (Int iref=1;iref<nRef;++iref) {
    7654             : 
    7655           4 :         Cube<Bool> mgokR; mgokR.reference(*MGOK[refField(iref)]);
    7656           4 :         Cube<Double> mgR;   mgR.reference(*MG[refField(iref)]);
    7657             : 
    7658           8 :         for (Int ispw=0;ispw<nSpw();++ispw) {
    7659         112 :           for (Int iant=0;iant<nAnt();++iant) {
    7660         324 :             for (Int ipar=0;ipar<nPar();++ipar) {
    7661         216 :               if (iref==1) {
    7662         108 :                 if (mgrefok(ipar,iant,ispw)) {
    7663          54 :                   nokref(ipar,iant,ispw)+=1.0;   
    7664             :                 }
    7665             :                 else {// the first ref field of this gain is flagged
    7666          54 :                   mgref(ipar,iant,ispw)=0.0;
    7667             :                 }
    7668             :               }
    7669             : 
    7670         216 :               if (mgokR(ipar,iant,ispw)) {
    7671         211 :                 mgref(ipar,iant,ispw)+=mgR(ipar,iant,ispw);
    7672         211 :                 nokref(ipar,iant,ispw)+=1.0;   
    7673             :               }
    7674             : 
    7675             :               // at the last ref field...
    7676         216 :               if(iref==nRef-1 ) {
    7677         108 :                 if (nokref(ipar,iant,ispw)==0.0) {
    7678           0 :                   mgrefok(ipar,iant,ispw)=false;
    7679           0 :                   mgref(ipar,iant,ispw)=0.0;
    7680             :                 } 
    7681             :                 else {
    7682             :                   // overwrite to turn to true for the case of mgrefok=false for refField(0)
    7683         108 :                   mgrefok(ipar,iant,ispw)=true;
    7684             :                 }
    7685             :               }
    7686             : 
    7687             :               // Replaced this with above to support flagged ref field case(CAS-4758) - TT
    7688             :               //if (mgrefok(ipar,iant,ispw) && mgokR(ipar,iant,ispw))
    7689             :               //  mgref(ipar,iant,ispw)+=mgR(ipar,iant,ispw);
    7690             :               // else {
    7691             :               //  mgrefok(ipar,iant,ispw)=false;
    7692             :               //  mgref(ipar,iant,ispw)=0.0;
    7693             :               //} 
    7694             : 
    7695             :             } // ipar
    7696             :           } // iant
    7697             :         } // ispw
    7698           4 :       } // iref
    7699             :       // Complete the average:
    7700             :       //mgref/=Double(nRef);
    7701           2 :       mgref/=nokref; // only count unflagged ones
    7702           2 :     } // nRef > 1
    7703             : 
    7704             :     // Scale factor calculation, per trans fld, per spw
    7705          29 :     Matrix<Double> fd( nSpw(), nFld, -1.0 );
    7706          29 :     Matrix<Double> fderr( nSpw(), nFld, -1.0 );
    7707          29 :     Matrix<Double> fdrms(nSpw(),nFld,-1.0);
    7708          29 :     Matrix<Int> numSol( nSpw(), nFld, -1 );
    7709             : //    fd.resize(nSpw(),nFld);
    7710             : //    fd.set(-1.0);
    7711             : //    fderr.resize( nSpw(), nFld );
    7712             : //    fderr.set( -1.0 );
    7713             : //    numSol.resize( nSpw() );
    7714             : //    numSol.set( -1 );
    7715             : 
    7716          29 :     Matrix<Bool> scaleOK(nSpw(),nFld,false);
    7717          29 :     Matrix<Double> mgratio(nSpw(),nFld,-1.0);
    7718          29 :     Matrix<Double> mgrms(nSpw(),nFld,-1.0);
    7719          29 :     Matrix<Double> mgerr(nSpw(),nFld,-1.0);
    7720             : 
    7721          64 :     for (Int iTran=0; iTran<nTran; iTran++) {
    7722             :       
    7723          35 :       Int tranidx=tranField(iTran);
    7724          35 :       if (MGOK[tranidx]!=NULL) {
    7725             :       // References to PBs for syntactical convenience
    7726          35 :       Cube<Bool>   mgokT;  mgokT.reference(*(MGOK[tranidx]));
    7727          35 :       Cube<Double> mgT;    mgT.reference(*(MG[tranidx]));
    7728          35 :       Cube<Double> mgvarT; mgvarT.reference(*(MGVAR[tranidx]));
    7729          35 :       Cube<Double> mgwtT;  mgwtT.reference(*(MGWT[tranidx]));
    7730          35 :       if (report_p) {
    7731           0 :         setupPlotter();
    7732             :       }
    7733          35 :       int countvalidspw = 0;
    7734         135 :       for (Int ispw=0; ispw<nSpw(); ispw++) {
    7735             :         // Reference spw may be different
    7736         100 :         Int refSpw(refSpwMap(ispw));
    7737             :         
    7738             :         // Only if anything good for this spw
    7739         100 :         if (ntrue(mgokT.xyPlane(ispw)) > 0) {
    7740             : 
    7741        1323 :           for (Int iant=0;iant<nAnt();++iant) {
    7742        3684 :             for (Int ipar=0;ipar<nPar();++ipar) {
    7743        2456 :               if (mgokT(ipar,iant,ispw) && 
    7744        4600 :                   mgrefok(ipar,iant,refSpw) &&
    7745        2144 :                   mgref(ipar,iant,refSpw)>0.0 ) {
    7746        2144 :                 mgT(ipar,iant,ispw)/=mgref(ipar,iant,refSpw);
    7747             :               }
    7748             :               else {
    7749         312 :                 mgT(ipar,iant,ispw)=0.0;
    7750         312 :                 mgokT(ipar,iant,ispw)=false;
    7751             :               }
    7752             :             } // ipar
    7753             :           } // iant
    7754             :         } // ntrue>0
    7755             : 
    7756             :         // Form the mean gain ratio
    7757         100 :         Matrix<Double> mgTspw(mgT.xyPlane(ispw));
    7758         100 :         Matrix<Bool> mgokTspw(mgokT.xyPlane(ispw));
    7759         100 :         cout.precision(6);
    7760         100 :         cout.setf(ios::fixed,ios::floatfield);
    7761         100 :         Int nPA=ntrue(mgokTspw);
    7762         100 :         if (nPA>0) {
    7763             : 
    7764             :           // for plotting
    7765          95 :           if (report_p) {
    7766             :             //cerr<<"plotting for each spw..."<<endl;
    7767           0 :             String hlab = "Fld:"+String::toString(tranidx)+" Spw:"+String::toString(ispw)+
    7768           0 :                           " median="+String::toString(medianGains(tranidx,ispw));
    7769           0 :             Vector<Double> tempvec;
    7770           0 :             tempvec=mgTspw(mgokTspw).getCompressedArray();
    7771             :             // determine nbins by Scott's rule
    7772             :             Double minv, maxv;
    7773           0 :             minMax(minv,maxv,tempvec);
    7774           0 :             Double binw = 3.49*stddev(tempvec)/pow(Double (tempvec.nelements()), 1./3.);
    7775           0 :             Int inNbins = Int (ceil ((maxv-minv)/binw));
    7776           0 :             plotHistogram(hlab,countvalidspw,tempvec,inNbins);
    7777           0 :             countvalidspw++;
    7778           0 :           }
    7779             : 
    7780             :           //      cout << "mgTspw = " << mgTspw << endl;
    7781          95 :           scaleOK(ispw,tranidx)=true;
    7782             :           //mgratio(ispw,tranidx)=mean(mgTspw(mgokTspw));
    7783          95 :           mgratio(ispw,tranidx)=median(mgTspw(mgokTspw));
    7784          95 :           if (nPA==1) { // flux scaling based on a single gain ratio... 
    7785           0 :             mgrms(ispw,tranidx)=0.0;
    7786           0 :             mgerr(ispw,tranidx)=0.0;
    7787             :           }
    7788             :           else {
    7789          95 :             mgrms(ispw,tranidx)=stddev(mgTspw(mgokTspw));
    7790          95 :             mgerr(ispw,tranidx)=mgrms(ispw,tranidx)/sqrt(Double(nPA-1));
    7791             :           }
    7792             :           // ...and flux density estimate
    7793          95 :           fd(ispw,tranidx)=mgratio(ispw,tranidx)*mgratio(ispw,tranidx);
    7794          95 :           fdrms(ispw,tranidx)=2.0*mgrms(ispw,tranidx);
    7795          95 :           if (nPA==1) {
    7796           0 :             fderr(ispw,tranidx)=0.0;
    7797             :           }
    7798             :           else {
    7799          95 :             fderr(ispw,tranidx)=fdrms(ispw,tranidx)/sqrt(Double(nPA-1));
    7800             :           }
    7801          95 :           numSol(ispw,tranidx) = nPA;
    7802             :         }
    7803             : 
    7804             :         // Compose the fit message for the list file and the log
    7805             : 
    7806         100 :         String oMsg( "" );
    7807             : 
    7808         100 :         oMsg += " Flux density for ";
    7809         100 :         oMsg += fldNames(tranidx);
    7810         100 :         oMsg += " in SpW=";
    7811         100 :         oMsg += String::toString<Int>( ispw );
    7812         100 :         if (scaleOK(ispw,tranidx)) {
    7813          95 :           oMsg += " (freq=";
    7814          95 :           oMsg += String::toString<Double>(solFreq(ispw));
    7815          95 :           oMsg += " Hz)";
    7816             :         }
    7817             : 
    7818         100 :         if ( refSpw != ispw ) {
    7819          13 :           oMsg += " (ref SpW=";
    7820          13 :           oMsg += String::toString<Int>( refSpw );
    7821          13 :           oMsg += ")";
    7822             :         }
    7823             : 
    7824         100 :         oMsg += " is: ";
    7825             : 
    7826         100 :         if ( scaleOK(ispw,tranidx) ) {
    7827          95 :           oMsg += String::toString<Double>( fd(ispw,tranidx) );
    7828          95 :           oMsg += " +/- ";
    7829          95 :           oMsg += String::toString<Double>( fderr(ispw,tranidx) );
    7830          95 :           oMsg += " (SNR = ";
    7831          95 :           oMsg += String::toString<Double>( fd(ispw,tranidx)/fderr(ispw,tranidx) );
    7832          95 :           oMsg += ", N = ";
    7833          95 :           oMsg += String::toString<Int>( nPA );
    7834          95 :           oMsg += ")";
    7835             :         } else {
    7836           5 :           oMsg += " INSUFFICIENT DATA ";
    7837             :         }
    7838             : 
    7839             :         // Write the fit message to the output list file if the file name is
    7840             :         // non-null.  In the first iteration (first transfer field and spw),
    7841             :         // open the list file and truncate any previous version.  In subsequent
    7842             :         // iterations, append the messages.
    7843             : 
    7844         100 :         if ( oListFile != "" ) {
    7845          28 :           ofstream oStream;
    7846          28 :           if ( iTran == 0 && ispw == 0 ) {
    7847           3 :             oStream.open( oListFile.chars(), ios::out|ios::trunc );
    7848             :           } else {
    7849          25 :             oStream.open( oListFile.chars(), ios::out|ios::app );
    7850             :           }
    7851          28 :           oStream << "#" << oMsg << endl << flush;
    7852          28 :           oStream.close();
    7853          28 :         }
    7854             : 
    7855             : 
    7856             :         // Write the fit message to the logger
    7857             : 
    7858         100 :         logSink() << oMsg << LogIO::POST;
    7859             : 
    7860             : /*
    7861             :         // Report flux densities to logger
    7862             :         logSink() << " Flux density for " << fldNames(tranidx)
    7863             :                   << " in SpW=" << ispw;
    7864             :         if (refSpw!=ispw) 
    7865             :           logSink() << " (ref SpW=" << refSpw << ")";
    7866             :         
    7867             :         logSink() << " is: ";
    7868             :         if (scaleOK(ispw,tranidx)) {
    7869             :           logSink() << fd(ispw,tranidx)
    7870             :                     << " +/- " << fderr(ispw,tranidx)
    7871             :                     << " (SNR = " << fd(ispw,tranidx)/fderr(ispw,tranidx)
    7872             :                     << ", N= " << nPA << ")";
    7873             :         }
    7874             :         else
    7875             :           logSink() << " INSUFFICIENT DATA ";
    7876             : 
    7877             :         logSink() << LogIO::POST;
    7878             : */
    7879         100 :       } // ispw
    7880          35 :       }           
    7881             :     } // iTran
    7882             :     // max 3 coefficients
    7883             :     //Matrix<Double> spidx(nFld,3,0.0);
    7884             :     //Matrix<Double> spidxerr(nFld,3,0.0);
    7885          29 :     Matrix<Double> spidx(nFld,fitorder+1,0.0);
    7886          29 :     Matrix<Double> spidxerr(nFld,fitorder+1,0.0);
    7887          29 :     Matrix<Double> covar;
    7888          29 :     Vector<Double> fitFluxD(nFld,0.0);
    7889          29 :     Vector<Double> fitFluxDErr(nFld,0.0);
    7890          29 :     Vector<Double> fitRefFreq(nFld,0.0); 
    7891             :     //PtrBlock<Matrix<Double> *> covarList(nFld);
    7892          29 :     Vector<Matrix<Double> > covarList(nFld);
    7893             :     //Vector<Double> refFreq(nFld,0.0);
    7894             :    
    7895          64 :     for (Int iTran=0; iTran<nTran; iTran++) {
    7896          35 :       uInt tranidx=tranField(iTran);
    7897          35 :       Int nValidFlux=ntrue(scaleOK.column(tranidx));
    7898             : 
    7899          35 :       String oFitMsg;
    7900          35 :       logSink()<<LogIO::DEBUG1<<"nValidFLux="<<nValidFlux<<LogIO::POST;
    7901             : 
    7902             :       //if (nValidFlux>1) { 
    7903          35 :       if (nValidFlux>0) { 
    7904             : 
    7905             :         // Make fd and freq lists
    7906          35 :         Vector<Double> fds;
    7907          35 :         fds=fd.column(tranidx)(scaleOK.column(tranidx)).getCompressedArray();
    7908          35 :         Vector<Double> fderrs;
    7909          35 :         fderrs=fderr.column(tranidx)(scaleOK.column(tranidx)).getCompressedArray();
    7910          35 :         Vector<Double> freqs;
    7911          35 :         freqs=solFreq(scaleOK.column(tranidx)).getCompressedArray();
    7912             : 
    7913             :         // shift mean(log(freq)) later
    7914             :         // Reference frequency is first in the list
    7915             :         //refFreq(tranidx)=freqs[0];
    7916             :         //freqs/=refFreq(tranidx);
    7917             :         //
    7918             :         // calculate spectral index
    7919             :         // fit the per-spw fluxes to get spectral index
    7920          35 :         if (nValidFlux==1) {
    7921          15 :           fitFluxD(tranidx) = fds(0);  
    7922          15 :           fitRefFreq(tranidx) = freqs(0);  
    7923             :         }
    7924             :         else {
    7925             :           // single spw so no fitting is performed, just fill flux and frequency 
    7926             :           // to fit result record
    7927          20 :         LinearFit<Double> fitter;
    7928          20 :         uInt myfitorder = 0; 
    7929          20 :         if (fitorder < 0) {
    7930             :           logSink() << LogIO::WARN
    7931             :                     << "fitorder=" << fitorder 
    7932             :                     << " not supported. Using fitorder=1" 
    7933           0 :                     << LogIO::POST;    
    7934           0 :           myfitorder = 1;
    7935             :          }
    7936          20 :          else if (nValidFlux==2 && fitorder>1) {
    7937             :              // note that myfitorder does not get set in this conditional branch, is that 
    7938             :              // the correct thing not to do? (myfitorder was prevously unitialized at this point).
    7939             :           logSink() << LogIO::WARN
    7940             :                    << "Not enough number of valid flux density data for the requested fitorder:"<<fitorder
    7941           0 :                    << ". Use fitorder=1." <<LogIO::POST;
    7942             :          } 
    7943             :          else {
    7944          20 :           myfitorder = (uInt)fitorder;
    7945             :           
    7946             :           //if (fitorder < nValidFlux) {
    7947             :           //  myfitorder = (uInt)fitorder;
    7948             :           //}
    7949             :           //else {
    7950             :           //if (fitorder > nValidFlux) {
    7951             :           //  myfitorder = (uInt)(nValidFlux-1);
    7952             :           //  logSink() << LogIO::WARN
    7953             :           //            << "Not enough number of valid flux density data for the requested fitorder:"<<fitorder
    7954             :           //            <<". Using a lower fitorder="<<myfitorder<<LogIO::POST;
    7955             :         }
    7956             :         // set fitting for spectral index, alpha and beta(curvature)
    7957             :         // with S = S_o*f/f0^(alpha+beta*log(f/fo))
    7958             :         // fitting y = c + alpha*x + beta*x^2
    7959             :         // log(S/S0)=alpha*log(f/f0) + beta*log(f/f0)**2
    7960          20 :         Polynomial< AutoDiff<Double> > bp(myfitorder);
    7961          20 :         fitter.setFunction(bp);
    7962             : 
    7963             :         // shift the zero point to the mean of log(freq)
    7964          20 :         Double meanLogFreq=mean(log10(freqs));
    7965          40 :         Vector<Double> log_relsolFreq=log10(freqs)-meanLogFreq;
    7966             :         //Vector<Double> log_relsolFreq=log10(freqs);
    7967          20 :         Vector<Double> log_fd=log10(fds);
    7968             :         
    7969             :         // The error in the log of fds is fderrs/fds
    7970          40 :         Vector<Double> soln=fitter.fit(log_relsolFreq, log_fd, fderrs/fds);
    7971          20 :         Vector<Double> errs=fitter.errors();
    7972          20 :         Matrix<Double> covar=fitter.compuCovariance();
    7973             : 
    7974         105 :         for (uInt i=0; i<soln.nelements(); i++) {
    7975          85 :            spidx(tranidx,i) = soln(i);
    7976          85 :            spidxerr(tranidx,i) = errs(i);
    7977             :         } 
    7978          20 :         fitFluxD(tranidx) = pow(10.0,(soln(0)));
    7979             : //      correct for the proper propagation of error
    7980          20 :         fitFluxDErr(tranidx) = (errs(0)>0.0 ? log(10)*pow(10.0,(soln(0)))*errs(0) : 0.0);
    7981          20 :         fitRefFreq(tranidx) = pow(10.0,meanLogFreq);
    7982             :         //covarList[tranidx] = &covar;
    7983          20 :         covarList(tranidx) = covar;
    7984          20 :         oFitMsg =" Fitted spectrum for ";
    7985          20 :         oFitMsg += fldNames(tranidx);
    7986          20 :         oFitMsg += " with fitorder="+String::toString<Int>(myfitorder)+": ";
    7987             : //      oFitMsg += "Flux density = "+String::toString<Double>(pow(10.0,(soln(0))));
    7988          20 :         oFitMsg += "Flux density = "+String::toString<Double>(fitFluxD(tranidx));
    7989             : //      Double ferr=(errs(0)>0.0 ? exp10(errs(0)) : 0.0);
    7990             : //      Double ferr=(errs(0)>0.0 ? pow(10.0,(errs(0))) : 0.0);
    7991          20 :         oFitMsg += " +/- "+String::toString<Double>(fitFluxDErr(tranidx)); 
    7992             : //      oFitMsg += " (freq="+String::toString<Double>(refFreq(tranidx)/1.0e9)+" GHz)";
    7993             : //      oFitMsg += " (freq="+String::toString<Double>(pow(10.0,meanLogFreq)/1.0e9)+" GHz)";
    7994          20 :         oFitMsg += " (freq="+String::toString<Double>(fitRefFreq(tranidx)/1.0e9)+" GHz)";
    7995             :         //oFitMsg += " soln.nelements="+String::toString<Int>(soln.nelements()); 
    7996          20 :         oFitMsg += " spidx:";
    7997          85 :         for (uInt j=1; j<soln.nelements();j++) {
    7998          65 :           String coefname=" a_"+String::toString<Int>(j);
    7999          65 :           if (j==1) coefname += " (spectral index) "; 
    8000          65 :           oFitMsg += coefname+"="+String::toString<Double>(soln(j)); 
    8001          65 :           oFitMsg += " +/- "+String::toString<Double>(errs(j)); 
    8002             :           //if (nValidFlux > (Int)(j+1)) {
    8003             :           //    oFitMsg += " +/- "+String::toString<Double>(errs(j)); 
    8004             :           //}
    8005             :           //else {
    8006             :           //    oFitMsg += " (degenerate)";
    8007             :           //}
    8008          65 :         }
    8009             :         Int sh1, sh2;
    8010          20 :         covar.shape(sh1,sh2);
    8011          20 :         if (sh1 > 1) {
    8012          20 :           oFitMsg += " covariance matrix for the fit: ";
    8013         105 :           for (Int i=0;i<sh1; i++) {
    8014        1878 :             for (Int j=0;j<sh2; j++) {
    8015        1793 :               oFitMsg += " covar("+String::toString(i)+","+String::toString(j)+")="+String::toString<Double>(covar(i,j));
    8016             :             }
    8017             :          }
    8018             :         }
    8019          20 :         if ( oListFile != "" ) {
    8020           7 :           ofstream oStream;
    8021           7 :           oStream.open( oListFile.chars(), ios::out|ios::app );
    8022           7 :           oStream << "#" << oFitMsg << endl << flush;
    8023           7 :           oStream.close();
    8024           7 :         }
    8025          20 :         logSink() << oFitMsg << LogIO::POST;
    8026          20 :       }
    8027          35 :       }// nValidFlux
    8028             :       /**
    8029             :       Int sh1, sh2;
    8030             :       covar->shape(sh1,sh2);
    8031             : 
    8032             :       for (Int i=0;i<sh1; i++) {
    8033             :         for (Int j=0;j<sh2; j++) {
    8034             :           logSink() << LogIO::DEBUG1 
    8035             :             <<"covar("<<i<<","<<j<<")="<<*covar(i,j) << LogIO::POST;
    8036             :         }
    8037             :       }
    8038             :       **/
    8039          35 :     }//iTran
    8040             : 
    8041             :     //store determined quantities for returned output
    8042          29 :     oFluxScaleStruct.fd = fd.copy();
    8043          29 :     oFluxScaleStruct.fderr = fderr.copy();
    8044          29 :     oFluxScaleStruct.numSol = numSol.copy();
    8045          29 :     oFluxScaleStruct.freq = solFreq.copy();
    8046          29 :     oFluxScaleStruct.spidx  = spidx.copy();
    8047          29 :     oFluxScaleStruct.spidxerr  = spidxerr.copy();
    8048          29 :     oFluxScaleStruct.fitfd = fitFluxD.copy();
    8049          29 :     oFluxScaleStruct.fitfderr = fitFluxDErr.copy();
    8050          29 :     oFluxScaleStruct.fitreffreq = fitRefFreq.copy();
    8051             :     //oFluxScaleStruct.covarmat = covarList;
    8052          29 :     oFluxScaleStruct.covarmat = covarList.copy();
    8053             :     // quit if no scale factors found
    8054          29 :     if (ntrue(scaleOK) == 0) throw(AipsError("No scale factors determined!"));
    8055             : 
    8056             :     //    cout << "done." << endl;
    8057             : 
    8058             :     //    cout << "Adjusting gains...";
    8059             : 
    8060             :     // Adjust tran field's gains here
    8061             : 
    8062             :     //create incremental caltable
    8063          29 :     if (incremental) {
    8064             :       //MSSpWindowColumns spwcol(ct_->spectralWindow());
    8065             :       //Vector<Int> NCHAN=spwcol.numChan().getColumn();
    8066             :       //nChanPar()=NCHAN(0);
    8067             : 
    8068           6 :       delete ct_;
    8069             :       // setup and fill a record
    8070             :       // set record description
    8071           6 :       Vector<Int> spwlist(nSpw());
    8072           6 :       indgen(spwlist);
    8073             : 
    8074           6 :       RecordDesc fsparDesc;
    8075           6 :       fsparDesc.addField ("caltable", TpString);
    8076           6 :       fsparDesc.addField ("time", TpDouble);
    8077           6 :       fsparDesc.addField ("spw", TpArrayInt);
    8078           6 :       fsparDesc.addField ("antenna", TpArrayInt);
    8079           6 :       fsparDesc.addField ("pol", TpString);
    8080           6 :       fsparDesc.addField ("parameter", TpArrayDouble);
    8081           6 :       fsparDesc.addField ("paramerr", TpArrayDouble);
    8082           6 :       fsparDesc.addField ("caltype", TpString);
    8083             : 
    8084             :       // create record with field values
    8085           6 :       Record fspar(fsparDesc);
    8086           6 :       fspar.define("caltable",outCalTabName);
    8087             :       //fspar.define("time",tc(0));
    8088           6 :       fspar.define("spw", spwlist);
    8089           6 :       fspar.define("caltype", "G Cal");
    8090           6 :       setSpecify(fspar);
    8091             :         //
    8092             :       { // generate per chan factor taking account for spectral index
    8093             :           // for(Int ich=0;ich<nchan;ich++); fl = soln(0) + alpha*chanf(ich) * beta*chanf(ich)*chanf(ich)
    8094             :           // fact = sqrt(fl) at each ich for each spw and each field
    8095             :           // and store 1/fact in bcal-like table 
    8096             :       }
    8097             : 
    8098             :       // Only do fields that occurred in the input caltable
    8099          24 :       for (uInt ifld=0;ifld<fldList.nelements();ifld++) {
    8100          18 :         Int iFld=fldList(ifld);
    8101          18 :         setCurrField(iFld);
    8102             :         //
    8103          18 :         initSolvePar(); // somewhat redundant but needed to reset solveCPar
    8104             : 
    8105             :         //currField()=iFld; 
    8106             :         //refTime()=tc(0);
    8107             :         //currTime()=tc(0);  
    8108          18 :         refTime()=mgreft(iFld);
    8109             :         // for future time support in specify
    8110          18 :         fspar.define("time",mgreft(iFld)); 
    8111             : 
    8112             :          // for only looping thru field id (set all spw for each field)
    8113          18 :         fspar.define("parameter", abs(1./mgratio.column(iFld)));
    8114          18 :         fspar.define("paramerr", 1./mgerr.column(iFld));
    8115             :         //
    8116          18 :         specify(fspar);
    8117             :       }
    8118             : /***
    8119             :       Block<String> cols(3);
    8120             :       cols[0]="SPECTRAL_WINDOW_ID";
    8121             :       cols[1]="TIME";
    8122             :       cols[2]="FIELD_ID";
    8123             :       CTIter ctiter(*ct_,cols);
    8124             :       while (!ctiter.pastEnd()) {
    8125             :         Int iSpw(ctiter.thisSpw());
    8126             :         Int iFld(ctiter.thisField());
    8127             :         cerr<<"iFld last="<<iFld<<endl;
    8128             :         //Cube<Complex> cpar(ctiter.cparam());
    8129             :         Cube<Float> fpar(ctiter.fparam());
    8130             :         //cpar = Complex(Float(mgratio(iSpw,iFld)));
    8131             :         fpar = Float(mgratio(iSpw,iFld));
    8132             :         //ctiter.setcparam(cpar);
    8133             :         ctiter.setfparam(fpar);
    8134             :         ctiter.next(); 
    8135             :       }
    8136             :       storeNCT(outfile,false);
    8137             : ***/
    8138           6 :     }
    8139             :     else {
    8140             :       // older behavior
    8141          23 :       Block<String> cols(3);
    8142          23 :       cols[0]="SPECTRAL_WINDOW_ID";
    8143          23 :       cols[1]="TIME";
    8144          23 :       cols[2]="FIELD_ID";
    8145          23 :       CTIter ctiter(*ct_,cols);
    8146             : 
    8147        1364 :       while (!ctiter.pastEnd()) {
    8148        1341 :         Int iSpw(ctiter.thisSpw());
    8149        1341 :         Int iFld(ctiter.thisField());
    8150             : 
    8151        1341 :         if (scaleOK(iSpw,iFld)) {
    8152         701 :           Cube<Complex> cpar(ctiter.cparam());
    8153         701 :           cpar/=Complex(Float(mgratio(iSpw,iFld)));
    8154         701 :           ctiter.setcparam(cpar);
    8155         701 :         }
    8156        1341 :         ctiter.next();
    8157             :       }
    8158          23 :     } // scope
    8159             : 
    8160             :     //    cout << "done." << endl;
    8161             : 
    8162             :     //    cout << "Cleaning up...";
    8163             : 
    8164             :     // Clean up PtrBlocks
    8165         113 :     for (Int iFld=0; iFld<nFld; iFld++) {
    8166          84 :       if (MGOK[iFld]!=NULL) {
    8167          68 :         delete MGOK[iFld];
    8168          68 :         delete MG[iFld];
    8169          68 :         delete MG2[iFld];
    8170          68 :         delete MGWT[iFld];
    8171          68 :         delete MGVAR[iFld];
    8172          68 :         delete MGN[iFld];
    8173          68 :         delete MGNALL[iFld];
    8174             :       }
    8175             :     } 
    8176             : 
    8177             :     //    cout << "done." << endl;
    8178             : 
    8179             :     // Avoid this since problem with <msname>/SELECTED_TABLE (06Feb02 gmoellen)
    8180             :     /*
    8181             :     {
    8182             : 
    8183             :       MeasurementSet ms(vs_->msName().before("/SELECTED"));
    8184             :       Table historytab = Table(ms.historyTableName(),
    8185             :                                TableLock(TableLock::UserNoReadLocking),
    8186             :                                Table::Update);
    8187             :       MSHistoryHandler hist = MSHistoryHandler(ms, "calibrater");
    8188             :       historytab.lock(true);
    8189             :       oss.postLocally();
    8190             :       hist.addMessage(oss);
    8191             :       historytab.unlock();
    8192             :     }
    8193             :     */
    8194          29 :   }
    8195           0 :   catch (AipsError x) {
    8196             : 
    8197             :     // Clean up PtrBlocks
    8198           0 :     for (Int iFld=0; iFld<nFld; iFld++) {
    8199           0 :       if (MGOK[iFld]!=NULL) {
    8200           0 :         delete MGOK[iFld];
    8201           0 :         delete MG[iFld];
    8202           0 :         delete MG2[iFld];
    8203           0 :         delete MGWT[iFld];
    8204           0 :         delete MGVAR[iFld];
    8205           0 :         delete MGN[iFld];
    8206           0 :         delete MGNALL[iFld];
    8207             :       }
    8208             :     }
    8209             : 
    8210           0 :     throw(x);
    8211             : 
    8212           0 :   }
    8213             : 
    8214          58 :   return;
    8215             : 
    8216          29 : }
    8217             : 
    8218           0 : void SolvableVisJones::setupPlotter() {
    8219           0 : }
    8220             : 
    8221           0 : void SolvableVisJones::plotHistogram(const String& title,
    8222             :                                      const Int index,
    8223             :                                      const Vector<Double>& data,
    8224             :                                      const Int nbins) {
    8225             : // construct histogram in multiple panels 
    8226           0 :   std::string legendloc = "bottom";
    8227           0 :   std::string zoomloc = "";
    8228           0 :   if (index==0) {
    8229           0 :     std::vector<std::string> loc;
    8230           0 :     loc.push_back("top");
    8231             :     //plotter_->loaddock( dock_xml_p, "bottom", loc, panels_id_[0].getInt());
    8232           0 :   }
    8233             :   else {
    8234             :      
    8235             :     // multirow panels
    8236             :     /***
    8237             :     if (index<3) {
    8238             :       //cerr<<"panels_id[index-1].getInt()="<<panels_id_[index-1].getInt()<<endl;
    8239             :       panels_id_[index] = plotter_->panel( title, "ratio", "N", "",
    8240             :       std::vector<int>( ), legendloc,zoomloc,panels_id_[index-1].getInt(),false,false);
    8241             :     }       
    8242             :     else {
    8243             :       if (index==3) {
    8244             :         panels_id_[index] = plotter_->panel( title, "ratio", "N", "",
    8245             :                        std::vector<int>( ), legendloc,zoomloc,panels_id_[0].getInt(),true,false);
    8246             :       }
    8247             :       else {
    8248             :         panels_id_[index] = plotter_->panel( title, "ratio", "N", "",
    8249             :                                      std::vector<int>( ), legendloc,zoomloc,panels_id_[index-1].getInt(),false,false);
    8250             :       } 
    8251             :     }
    8252             :     ***/
    8253             :   }
    8254             :   // plot histogram
    8255             : 
    8256           0 : }
    8257             : 
    8258           9 : void SolvableVisJones::listCal(const Vector<Int> ufldids,
    8259             :                                   const Vector<Int> uantids,
    8260             :                                   const Matrix<Int> uchanids, 
    8261             :                                   const String& listfile,
    8262             :                                   const Int& maxScrRows) {
    8263             : 
    8264             :   //  cout << "listcal disabled for the moment." << endl;
    8265             : 
    8266             :   //  return;
    8267             : 
    8268          27 :   if (typeName().contains("BPOLY") ||
    8269          18 :       typeName().contains("GSPLINE"))
    8270           0 :     throw(AipsError(typeName()+" not yet supported."));
    8271             : 
    8272           9 :     char cfill = cout.fill(' '); // Set fill character for terminal output
    8273             :     
    8274             :     //Int uSpwID = uchanids(0,0);
    8275             :     //Int chan = uchanids(0,1);
    8276             :     
    8277             :     // The number of spws; that is, the number of rows in matrix uchanids.
    8278             :     // Actually, this is the number of spw/channel selections made in the
    8279             :     // spw selection parameter.  The rows of uchanids may contain the same
    8280             :     // spw.
    8281           9 :     uInt nSpws = uchanids.nrow();
    8282             :     
    8283             :     // Prep for listing
    8284           9 :     Bool endOutput = false; // if true, end output immediately
    8285           9 :     Bool prompt = true; // if true, issue prompt
    8286           9 :     Int isol = 0; // total solution counter
    8287           9 :     Int scrRows=0; // screen row counter, reset after continue prompt
    8288             :     
    8289             :     // Redirect cout to listfile
    8290           9 :     ofstream file;
    8291           9 :     streambuf* sbuf = cout.rdbuf();
    8292           9 :     if(listfile!="") { // non-interactive
    8293           9 :         prompt = false;
    8294             :         // Guard against trampling existing file
    8295           9 :         File diskfile(listfile);
    8296           9 :         if (diskfile.exists()) {
    8297           0 :             String errmsg = "File: " + listfile + 
    8298           0 :                 " already exists; delete it or choose a different name.";
    8299           0 :             throw(AipsError(errmsg));
    8300           0 :         }
    8301             :         else
    8302           9 :             cout << "Writing output to file: " << listfile << endl;
    8303             :         logSink() << LogIO::NORMAL2 << "Redirecting output to "
    8304           9 :                   << diskfile.path().originalName().data() << LogIO::POST;
    8305           9 :         file.open(diskfile.path().originalName().data());
    8306           9 :         cout.rdbuf(file.rdbuf());
    8307           9 :     } else { 
    8308             :         logSink() << LogIO::DEBUG1 
    8309             :                   << "Not redirecting output: cout remains untouched."
    8310           0 :                   << LogIO::POST;
    8311             :     }
    8312             :     
    8313           9 :     Vector<String> antname;
    8314           9 :     msmc().antennaNames(antname);
    8315           9 :     Vector<String> fldname;
    8316           9 :     msmc().fieldNames(fldname);
    8317             : 
    8318             :     // Default header info.
    8319           9 :     logSink() << LogIO::NORMAL1 << "MS name = " << msName() << LogIO::POST;        
    8320             :         
    8321             :     logSink() << LogIO::DEBUG1 << "Number of spectral window selections (may not be unique) = " 
    8322           9 :               << nSpws << LogIO::POST;
    8323             :     logSink() << LogIO::DEBUG1 << "Number of (unique) spws in cal table = "
    8324           9 :               << ct_->spectralWindow().nrow() << LogIO::POST;
    8325             : 
    8326             : 
    8327             : 
    8328             :     // Get nchan from the subtable
    8329           9 :     MSSpWindowColumns spwcol(ct_->spectralWindow());
    8330           9 :     Vector<Int> NCHAN=spwcol.numChan().getColumn();
    8331             : 
    8332           9 :     Int NANT=ct_->antenna().nrow();
    8333             : 
    8334             : 
    8335           9 :     Block<String> cols(1);
    8336           9 :     cols[0]="SPECTRAL_WINDOW_ID";
    8337           9 :     ROCTIter ctiter(*ct_,cols);
    8338             : 
    8339             : 
    8340          33 :     while (!ctiter.pastEnd()) {
    8341             : 
    8342          24 :       Int spwID=ctiter.thisSpw();
    8343          24 :       if (anyEQ(uchanids.column(0),spwID)) {
    8344             :         // spwID among selected spws
    8345          21 :         uInt iUchanids=0;
    8346          45 :         while (uchanids(iUchanids,0)!=spwID) ++iUchanids;
    8347          21 :         Vector<Int> RowUchanids = uchanids.row(iUchanids);
    8348             :         
    8349          21 :         if (ctiter.nrow()<1) {
    8350             :           // shouldn't happen
    8351           0 :             String errMsg;
    8352             :             errMsg = "Nothing to list for selected SpwID: " 
    8353           0 :                             + errMsg.toString(spwID);
    8354           0 :             logSink() << LogIO::NORMAL1 << errMsg << LogIO::POST;
    8355           0 :         } else { // we have something to list
    8356             : 
    8357             :             // Handle channel selection here.
    8358          21 :           const uInt nchan= NCHAN(spwID);
    8359             :             logSink() << LogIO::DEBUG1 << "For Spw ID " << spwID 
    8360             :                       << ": Number of spectral channels in calibration table = "
    8361          21 :                       << nchan << LogIO::POST;
    8362             : 
    8363             :             // Extract channel selection info from uchanids
    8364          21 :             Int stepChan   = RowUchanids(3);
    8365          21 :             if (stepChan == 0) { stepChan = 1; } // one channel at a time (default)
    8366          21 :             else if (stepChan < 0) {
    8367           0 :                 throw(AipsError("Stepping backwards through channels not supported."));
    8368             :             }
    8369             :             // Cal table channels are a subset of the MS channels.
    8370             :             // MS indices of channels in cal table.
    8371          21 :             const uInt msCalStartChan = 0;
    8372          21 :             const uInt msCalStopChan  = nchan-1;
    8373             :             // MS indices of selected channels
    8374          21 :             uInt msSelStartChan = RowUchanids(1);
    8375          21 :             uInt msSelStopChan  = RowUchanids(2);
    8376             :             // Cal table indices of selected channels
    8377          21 :             Int startChan = msSelStartChan - msCalStartChan;
    8378          21 :             Int stopChan  = msSelStopChan - msCalStartChan;
    8379          21 :             if (startChan > stopChan) { 
    8380           0 :                 throw(AipsError("Start channel must be less than or equal to stop channel."));
    8381          21 :             } else if ((stopChan < 0) || (startChan > (Int)nchan - 1)) { 
    8382             :                 // All selected channels out of range
    8383           0 :                 String errMsg = "None of the selected channels are present in cal table.";
    8384             :                 logSink() << LogIO::SEVERE << errMsg
    8385             :                           << endl << "Selected channel range = [" 
    8386             :                           << msSelStartChan << "," << msSelStopChan << "]" << endl
    8387             :                           << "Cal table channel range = [" 
    8388           0 :                           << msCalStartChan << "," << msCalStopChan << "]" << LogIO::POST;
    8389           0 :                 throw(AipsError(errMsg));
    8390           0 :             } 
    8391          21 :             if (startChan < 0) {
    8392             :                 logSink() << LogIO::NORMAL1 << "Start channel ( " << msSelStartChan
    8393             :                           << " ) below allowed range." << endl
    8394             :                           << "Increasing start channel to " << msCalStartChan
    8395           0 :                           << LogIO::POST;
    8396           0 :                 startChan = 0;
    8397             :             }
    8398          21 :             if (stopChan > (Int)nchan - 1) {
    8399             :                 logSink() << LogIO::NORMAL1 << "Stop channel ( " << msSelStopChan
    8400             :                           << " ) above allowed range." << endl
    8401             :                           << "Decreasing stop channel to " << msCalStopChan
    8402          21 :                           << LogIO::POST;
    8403          21 :                 stopChan = (Int)nchan - 1;
    8404             :             }
    8405             :             // Number of channels selected
    8406          21 :             Int numChans = ((stopChan - startChan) / stepChan) + 1; 
    8407          21 :             if (numChans > Int(nchan)) {
    8408             :                 logSink() << LogIO::NORMAL1 
    8409             :                           << "More channels requested than are present in the cal table."
    8410             :                           << endl << "Cal table channels for this spw: "
    8411             :                           << msCalStartChan << " to " << msCalStopChan
    8412           0 :                           << LogIO::POST;
    8413             :             } 
    8414             :             
    8415             :             logSink() << LogIO::DEBUG1 << "For spwID " << spwID << endl
    8416             :                       << "  startChan = " << startChan << endl
    8417             :                       << "  stopChan = " << stopChan << endl
    8418             :                       << "  stepChan = " << stepChan << endl
    8419             :                       << "  Number of channels to list: numChans = " << numChans
    8420          21 :                       << LogIO::POST;
    8421             :             
    8422             :             // Setup the column widths.  Check width of each string.        
    8423             :             uInt precAmp, precPhase; // Column precision
    8424             :             uInt oAmp, oPhase; // Column order
    8425             :             
    8426          21 :             wTime_p = 10; // set width of time column
    8427             :             // set the field column width (looking at the whole cal table)
    8428          21 :             wField_p = 0; 
    8429             : 
    8430          21 :             Vector<Int> fldids;
    8431          21 :             fldids=ctiter.field();
    8432          21 :             Int nUniqFlds=genSort(fldids,Sort::Ascending,(Sort::QuickSort | Sort::NoDuplicates));
    8433          21 :             fldids.resize(nUniqFlds,true);  // shrink the Vector
    8434             : 
    8435          50 :             for (Int ifld=0;ifld<nUniqFlds;++ifld) {
    8436          29 :               String fldstr=(fldname(ifld)); 
    8437          29 :               uInt fldstrLength = fldstr.length();
    8438          29 :               if (wField_p < fldstrLength) { wField_p = fldstrLength; }
    8439          29 :             }
    8440             : 
    8441          21 :             wChan_p = (uInt)max(3,(Int)rint(log10(nchan)+0.5));
    8442          21 :             wPreAnt_p = wTime_p + 1 + wField_p + 1 + wChan_p; // do not count final pipe ("|")
    8443             :             logSink() << LogIO::DEBUG1 << "Column widths:" << endl
    8444             :                       << "  time = "    << wTime_p  << endl
    8445             :                       << "  field = "   << wField_p << endl
    8446          21 :                       << "  channel = " << wChan_p << LogIO::POST;
    8447             :             
    8448             :             // For multiple channels, I think I will need to write a method that 
    8449             :             // looks through all spws to determine the necessary order for the 
    8450             :             // Amplitude and Phase.
    8451             : 
    8452          21 :             if (ct_->isComplex()) {
    8453          21 :               oAmp = 1;
    8454          21 :               precAmp = 3; 
    8455          21 :               oPhase = 4;
    8456          21 :               precPhase = 1; 
    8457             :             }
    8458             :             else {
    8459             :               // only "amp" column matters (and may have -ve sign)
    8460           0 :               oAmp = 4;
    8461           0 :               precAmp = 5; 
    8462           0 :               oPhase = 0;
    8463           0 :               precPhase = 0; 
    8464             :             }
    8465             :             
    8466             :             // set width of amplitude column
    8467          21 :             wAmp_p = oAmp + precAmp + 1; // order + precision + decimal point
    8468             :             
    8469             :             // set width of phase column
    8470          21 :             wPhase_p = oPhase + precPhase + 1; // order + precision + decimal point
    8471             :             
    8472          21 :             wFlag_p=1;
    8473          21 :             wPol_p = wAmp_p + 1 + wPhase_p + 1 + wFlag_p + 1; 
    8474          21 :             wAntCol_p = wPol_p*nPar();
    8475             :             //cerr << "wAntCol_p = " <<wAntCol_p << endl;
    8476             :             
    8477             :             logSink() << LogIO::DEBUG1 << "oAmp = " << oAmp 
    8478             :                 << ", precAmp = " << precAmp 
    8479             :                 << ", wAmp_p = " << wAmp_p << endl
    8480             :                 << "oPhase = " << oPhase 
    8481             :                 << ", precPhase = " << precPhase 
    8482             :                 << ", wPhase_p = " << wPhase_p
    8483          21 :                 << LogIO::POST;
    8484             :             
    8485             :             //uInt numAntCols = 4; // Number of antenna columns
    8486          21 :             uInt numAntCols = 8/nPar(); // Number of antenna columns
    8487          21 :             wTotal_p = wPreAnt_p + 1 + wAntCol_p*numAntCols;
    8488             : 
    8489             :             //cerr << "wTotal_p = " << wTotal_p << endl;
    8490             :             
    8491             :             // Construct the horizontal separator
    8492          21 :             String hSeparator=replicate('-',wTotal_p); 
    8493          21 :             uInt colPos=0;
    8494          21 :             colPos+=wPreAnt_p; hSeparator[colPos]='|'; colPos++;
    8495         189 :             for(uInt iPol=0; iPol<numAntCols*nPar(); iPol++) {
    8496         168 :                 colPos+=wPol_p-1;
    8497         168 :                 hSeparator[colPos]='|';
    8498         168 :                 colPos++;
    8499             :             }
    8500             :             
    8501             :             logSink() << LogIO::DEBUG1
    8502          21 :                 << "Listing CalTable: " << calTableName()
    8503          21 :                 << "   (" << typeName() << ") "
    8504          21 :                 << LogIO::POST;
    8505             :             
    8506          21 :             String dateTimeStr0=MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7);
    8507          21 :             String dateStr0=dateTimeStr0.substr(0,10);
    8508             :             
    8509          42 :             String headLine = "SpwID = " + String::toString(spwID) + ", "
    8510          42 :                               "Date = " + dateStr0 + ",  " +
    8511          63 :                               "CalTable = " + calTableName() + " (" + typeName() + "), " +
    8512          42 :                               "MS name = " + msName();
    8513          21 :             cout.setf(ios::left,ios::adjustfield);
    8514             :             //            cout << setw(wTotal_p) << headLine << endl
    8515          21 :             cout << headLine << endl
    8516          21 :                  << replicate('-',wTotal_p) << endl;
    8517          21 :             scrRows+=2;
    8518             :             
    8519             :             // labels for flagged solutions
    8520          21 :             Vector<String> flagstr(2); 
    8521          21 :             flagstr(0)="F";
    8522          21 :             flagstr(1)=" ";
    8523             :             
    8524             :             // The following is a klugey way to 
    8525             :             // make the times, fields, and gains look like
    8526             :             // what the CalTable's used to be
    8527             : 
    8528          21 :             Int NTIME=ctiter.nrow()/NANT;
    8529          21 :             Vector<Double> timelist;
    8530          21 :             timelist=ctiter.time();
    8531          21 :             Vector<Int> fieldlist;
    8532          21 :             fieldlist=ctiter.field();
    8533          45 :             for (Int i=1;i<NTIME;++i) {
    8534          24 :               timelist(i)=timelist(i*NANT);
    8535          24 :               fieldlist(i)=fieldlist(i*NANT);
    8536             :             }
    8537          21 :             timelist.resize(NTIME,true);
    8538          21 :             fieldlist.resize(NTIME,true);
    8539             : 
    8540          21 :             Array<Float> v1,v2;
    8541          21 :             Array<Bool> vok;
    8542          21 :             Int npar=nPar();
    8543          21 :             if (ct_->isComplex()) {
    8544          21 :               Cube<Complex> cparam;
    8545          21 :               ctiter.cparam(cparam);
    8546          21 :               IPosition sh(cparam.shape());
    8547          21 :               sh.append(IPosition(1,NTIME));
    8548          21 :               sh(2)=NANT;
    8549          21 :               Array<Complex> calGains;
    8550          21 :               calGains.reference(cparam.reform(sh));
    8551          21 :               v1.assign(amplitude(calGains));
    8552          21 :               v2.assign(phase(calGains)*180.0/C::pi);
    8553          21 :               Cube<Bool> sok;
    8554          21 :               sok=!ctiter.flag();
    8555          21 :               Array<Bool> calGainOK;
    8556          21 :               calGainOK.reference(sok.reform(sh));
    8557          21 :               vok.reference(calGainOK);
    8558          21 :             }
    8559             :             else {
    8560           0 :               Cube<Float> fparam;
    8561           0 :               Array<Float> fparam4;
    8562           0 :               ctiter.fparam(fparam);
    8563           0 :               IPosition sh(fparam.shape());
    8564           0 :               Cube<Bool> sok;
    8565           0 :               Array<Bool> sok4;
    8566           0 :               sok=!ctiter.flag();
    8567           0 :               sh.append(IPosition(1,NTIME));
    8568           0 :               sh(2)=NANT;
    8569           0 :               fparam4.reference(fparam.reform(sh));
    8570           0 :               sok4.reference(sok.reform(sh));
    8571             : 
    8572             :               // only one val per par
    8573           0 :               sh.append(IPosition(1,NTIME));
    8574           0 :               sh(2)=NANT;
    8575           0 :               v1.reference(fparam4);
    8576           0 :               v2.resize();
    8577           0 :               vok.reference(sok4);
    8578           0 :             }
    8579             : 
    8580          21 :             IPosition gidx(4,0,0,0,0); // 4-element IPosition, all zeros
    8581             :             
    8582             :             // Setup a Vector of antenna ID's to ease the process of printing 
    8583             :             // multiple antenna columns per row.
    8584             :             uInt numAnts; // Hold number of antennas to be output.
    8585          21 :             Vector<Int> pAntids(NANT); // Vector of antenna ID's.
    8586          21 :             if (uantids.nelements()==0) { // Print all antennas.
    8587          19 :                 numAnts = NANT; 
    8588         245 :                 for(uInt i=0; i< numAnts; i++) { // Fill pAntids with all antenna IDs.
    8589         226 :                     pAntids[i] = i;
    8590             :                 }
    8591             :             } else { // Use the user-specified antenna ID's.
    8592           2 :                 numAnts = uantids.nelements(); 
    8593           2 :                 pAntids.resize(numAnts);
    8594           2 :                 pAntids = uantids;
    8595             :             }
    8596             :             
    8597             :             // loop over antenna elements
    8598          88 :             for (uInt iElem=0;iElem<numAnts;iElem+=numAntCols) { 
    8599          67 :                 gidx(2)=pAntids(iElem);
    8600             :                 
    8601          67 :                 Bool header=true; // New antenna, require print header
    8602             :                 
    8603             :                 // If antenna element is among selected antennas, print it
    8604          67 :                 if (uantids.nelements()==0 || anyEQ(uantids,pAntids(iElem))) {
    8605             : 
    8606             :                     // Begin loop over time
    8607         230 :                     for (Int itime=0;itime<NTIME;++itime) { 
    8608         163 :                         gidx(3)=itime;
    8609             :                         
    8610         163 :                         Int fldid(fieldlist(itime));
    8611             :                         
    8612             :                         // Get date-time string
    8613         163 :                         String dateTimeStr=MVTime(timelist(itime)/C::day).string(MVTime::YMD,7);
    8614         163 :                         String dateStr=dateTimeStr.substr(0,10);
    8615         163 :                         String timeStr=dateTimeStr.substr(11,10);
    8616             :                         // Get field string
    8617         163 :                         String fldStr="";
    8618         163 :                         if (fldid>-1)
    8619         163 :                           fldStr=(fldname(fldid));
    8620             :                         
    8621         163 :                         String tmp_timestr = timeStr; // tmp_ variables get reset during the loop
    8622         163 :                         String tmp_fldstr = fldStr; //
    8623             :                         
    8624             :                         // If no user-specified fields, or fldid is in user's list
    8625         163 :                         if (ufldids.nelements()==0 || anyEQ(ufldids,fldid) ) {
    8626             :                             
    8627             :                             // Set i/o flags for writing data
    8628         128 :                             cout << setiosflags(ios::fixed) << setiosflags(ios::right);
    8629             :                             
    8630             :                             // Loop over channels
    8631         256 :                             for (uInt iChan=startChan; iChan<=uInt(stopChan); iChan+=stepChan) {
    8632             :                                 
    8633             :                                 // If beginning new screen, print the header
    8634         128 :                                 if (scrRows == 0 || header) {
    8635          68 :                                     header=false;
    8636             :                                     // Write Antenna line (put spaces over the time, field cols)
    8637        1853 :                                     for(uInt k=0; k<(wPreAnt_p); k++) { cout<<" "; }
    8638          68 :                                     cout << "|";
    8639         300 :                                     for(uInt k=0; (k<numAntCols) and (iElem+k<=numAnts-1); k++) {
    8640         232 :                                         String tAntName = " Ant = " + String(antname(pAntids(iElem+k)));
    8641         232 :                                         cout.setf(ios::left,ios::adjustfield);
    8642         232 :                                         cout << setw(wAntCol_p-1) << tAntName << "|";
    8643         232 :                                     }
    8644          68 :                                     cout << endl;    scrRows++;
    8645             :                                     
    8646             :                                     // Write part of header with no data
    8647          68 :                                     scrRows += writeHeader(numAntCols, numAnts, iElem);
    8648             :                                 }
    8649             :                                 
    8650             :                                 
    8651         128 :                                 gidx(1)=iChan;
    8652             :                                 // Write the Time, Field, and Channel for each row
    8653         128 :                                 cout << setw(wTime_p) << timeStr << " "
    8654         128 :                                      << setw(wField_p) << fldStr << " "
    8655         128 :                                      << setw(wChan_p) << msCalStartChan + iChan << "|";
    8656             : 
    8657             :                                 // Write data for each antenna column
    8658         564 :                                 for (uInt kelem=iElem; (kelem<iElem+numAntCols) and (kelem<=numAnts-1); 
    8659             :                                      kelem++) {
    8660         436 :                                     gidx(2)=pAntids(kelem);
    8661             :                                     // Loop over polarization
    8662        1308 :                                     for (Int ipar=0;ipar<npar;++ipar) {
    8663         872 :                                         gidx(0)=ipar; 
    8664             :                                         
    8665             :                                         // WRITE THE DATA
    8666             :                                              // amplitude
    8667         872 :                                         cout << setprecision(precAmp) << setw(wAmp_p) << v1(gidx) << " ";
    8668             : 
    8669         872 :                                         if (v2.nelements()>0)
    8670             :                                              // phase
    8671         872 :                                           cout<< setprecision(precPhase) << setw(wPhase_p) << v2(gidx) << " ";
    8672             :                                         else
    8673           0 :                                           cout<< setprecision(precPhase) << setw(wPhase_p) << replicate(" ",wPhase_p) << " ";
    8674             :                                         // flag
    8675         872 :                                         cout << flagstr(Int(vok(gidx))) << " ";
    8676             :                                     } // end ipar loop
    8677             :                                     
    8678             :                                 } // end kelem loop
    8679             :                                 
    8680         128 :                                 cout << resetiosflags(ios::right) << endl;
    8681         128 :                                 isol=isol+numAntCols; scrRows++;
    8682             :                                 
    8683             :                                 // If at end of screen prompt user or new header
    8684         128 :                                 if (maxScrRows>0 && (scrRows >= maxScrRows-1) ) { // scrRows counts from 0
    8685           5 :                                     scrRows = 0; // signal a new page
    8686           5 :                                     if (prompt) { // query the user, if we are interactive
    8687           0 :                                         string contStr;
    8688           0 :                                         cout << "Type Q to quit, A to list all, or RETURN to continue [continue]: ";
    8689           0 :                                         getline(cin,contStr);
    8690           0 :                                         if ( (contStr.compare(0,1,"q") == 0) or 
    8691           0 :                                              (contStr.compare(0,1,"Q") == 0) ) { endOutput=true; }
    8692           0 :                                         if ( (contStr.compare(0,1,"a") == 0) or 
    8693           0 :                                              (contStr.compare(0,1,"A") == 0) ) { prompt = false; }
    8694           0 :                                     }
    8695             :                                 }
    8696             :                             } // end iChan loop
    8697             :                             
    8698             :                         } // end if (field)
    8699             :                         
    8700         163 :                         if (endOutput) {break;} // break out of itime loop
    8701             :                         
    8702         163 :                     } // itime
    8703             :                     
    8704             :                 } // end if (antenna)
    8705             :                 
    8706          67 :                 if (endOutput) {break;} // break out of ielem loop
    8707             :                 
    8708             :             } // end iElem loop
    8709             :             
    8710          21 :             if (endOutput) {break;} // break out of spw loop
    8711             : 
    8712          21 :         } // end spw if (verification) block
    8713             :         
    8714          21 :       } // end spw loop   
    8715             :     
    8716             :       // advance iterator (spw)
    8717          24 :       ctiter.next();
    8718             :     } // ctiter
    8719             : 
    8720           9 :     cout << endl
    8721           9 :          << "Listed " << isol << " antenna solutions." 
    8722           9 :          << endl << endl;
    8723             :          
    8724           9 :     if (listfile!="") cout.rdbuf(sbuf); // restore cout
    8725           9 :     cout.fill(cfill);
    8726             : 
    8727           9 : }// end function listCal
    8728             : 
    8729          68 : int SolvableVisJones::writeHeader(const uInt numAntCols, 
    8730             :                                   const uInt numAnts,
    8731             :                                   const uInt iElem) {
    8732          68 :     uInt lineCount=0;
    8733             :     // Write time and field headings (only once)
    8734             :     cout << setiosflags(ios::left)
    8735          68 :          << setw(wTime_p) << "Time"  << " "
    8736          68 :          << setw(wField_p) << "Field" << " "
    8737          68 :          << setw(wChan_p) << "Chn" << "|";
    8738             :     
    8739             :     // Write Amp and Phase headings for each antenna column
    8740          68 :     Int nh(2);
    8741          68 :     Vector<String> vh(nh);
    8742          68 :     vh[0]="Amp ";
    8743          68 :     vh[1]="Phs ";
    8744          68 :     if (this->typeName().contains("EVLAGAIN")) {
    8745           0 :       nh=8;
    8746           0 :       vh.resize(nh);
    8747           0 :       vh[0]=vh[4]="Gain";
    8748           0 :       vh[2]=vh[6]="Tsys";
    8749           0 :       vh[1]=vh[3]=vh[5]=vh[7]=" ";
    8750             :     }
    8751          68 :     else if (this->typeName()=="K Jones") {
    8752           0 :       vh[0]="Delay ";
    8753           0 :       vh[1]=" ";
    8754             :     }
    8755          68 :     else if (this->typeName().contains("Opac")) {
    8756           0 :       vh[0]="Opac ";
    8757           0 :       vh[1]=" ";
    8758             :     }
    8759          68 :     else if (this->typeName().contains("KAntPos")) {
    8760           0 :       nh=6;
    8761           0 :       vh.resize(nh);
    8762           0 :       vh[0]="dX m";
    8763           0 :       vh[2]="dY m";
    8764           0 :       vh[4]="dZ m";
    8765           0 :       vh[1]=vh[3]=vh[5]=" ";
    8766             :     }
    8767          68 :     else if (this->typeName().contains("EGainCurve")) {
    8768           0 :       nh=8;
    8769           0 :       vh.resize(nh);
    8770           0 :       vh[0]="c[0]";
    8771           0 :       vh[2]="c[1]";
    8772           0 :       vh[4]="c[2]";
    8773           0 :       vh[6]="c[3]";
    8774           0 :       vh[1]=vh[3]=vh[5]=vh[7]=" ";
    8775             :     }
    8776          68 :     else if (this->typeName().contains("TSYS")) {
    8777           0 :       vh[0]="Tsys";
    8778           0 :       vh[1]=" ";
    8779             :     }
    8780             : 
    8781          68 :     cout.setf(ios::right, ios::adjustfield);
    8782         300 :     for(uInt k=0; (k<numAntCols) and (iElem+k<=numAnts-1); k++) {
    8783         696 :       for (Int ip=0;ip<nPar();++ip) {
    8784         464 :         if (ip>0) cout << " ";
    8785         464 :         cout << setw(wAmp_p)   << vh[(2*ip)%nh] << " " 
    8786         464 :              << setw(wPhase_p) << vh[(2*ip+1)%nh] << " " 
    8787         464 :              << "F";
    8788             :       }
    8789         232 :       cout << "|";
    8790             :     }
    8791          68 :     cout << endl;    lineCount++;
    8792             :     // Construct the horizontal separator
    8793          68 :     String hSeparator=replicate('-',wTotal_p); 
    8794          68 :     uInt colPos=0;
    8795          68 :     colPos+=wTime_p; hSeparator[colPos]='|'; colPos++;
    8796          68 :     colPos+=wField_p; hSeparator[colPos]='|'; colPos++;
    8797          68 :     colPos+=wChan_p; hSeparator[colPos]='|'; colPos++;
    8798         612 :     for(uInt iPol=0; iPol<numAntCols*nPar(); iPol++) {
    8799         544 :         colPos+=wPol_p-1;
    8800         544 :         hSeparator[colPos]='|';
    8801         544 :         colPos++;
    8802             :     }
    8803             :     // Write horizontal separator
    8804          68 :     cout << hSeparator << endl;   lineCount++;
    8805          68 :     return lineCount;
    8806          68 : } // end writeHeader
    8807             : 
    8808             : // Globals
    8809             : 
    8810             : // Return a cal table's type, verifying its existence
    8811         712 : String calTableType(const String& tablename) {
    8812             : 
    8813             :   // Check existence...
    8814         712 :   if (!Table::isReadable(tablename)) {
    8815           0 :     ostringstream o;
    8816           0 :     o << "Table " << tablename
    8817           0 :       << " does not exist.";
    8818           0 :     throw(AipsError(String(o)));
    8819           0 :   }
    8820             : 
    8821             :   // Table exists...
    8822             :   
    8823         712 :   TableInfo ti(TableUtil::tableInfo(tablename));
    8824             :   
    8825             :   // ...Check if Calibration table....
    8826         712 :   if (ti.type()!="Calibration") {
    8827           0 :     ostringstream o;
    8828           0 :     o << "Table " << tablename
    8829             :       << " is not a valid Calibration table."
    8830           0 :       << " (expected type = \"Calibration\"; type found = \""
    8831           0 :       << ti.type() << "\")";
    8832           0 :     throw(AipsError(String(o)));
    8833             :     
    8834           0 :   }
    8835             :   
    8836             :   // If we get here, we have a calibration table,
    8837             :   //  so return its type
    8838        1424 :   return ti.subType();
    8839             : 
    8840         712 : }
    8841             : 
    8842             : 
    8843             : } //# NAMESPACE CASA - END

Generated by: LCOV version 1.16