LCOV - code coverage report
Current view: top level - synthesis/MeasurementComponents - FringeJones.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 0 1001 0.0 %
Date: 2024-10-04 16:51:10 Functions: 0 49 0.0 %

          Line data    Source code
       1             : //# FringeJones.cc: Implementation of FringeJones
       2             : //# Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003,2011
       3             : //# Associated Universities, Inc. Washington DC, USA.
       4             : //#
       5             : //# This library is free software; you can redistribute it and/or modify it
       6             : //# under the terms of the GNU Library General Public License as published by
       7             : //# the Free Software Foundation; either version 2 of the License, or (at your
       8             : //# option) any later version.
       9             : //#
      10             : //# This library is distributed in the hope that it will be useful, but WITHOUT
      11             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
      13             : //# License for more details.
      14             : //#
      15             : //# You should have received a copy of the GNU Library General Public License
      16             : //# along with this library; if not, write to the Free Software Foundation,
      17             : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
      18             : //#
      19             : //# Correspondence concerning AIPS++ should be addressed as follows:
      20             : //#        Internet email: casa-feedback@nrao.edu.
      21             : //#        Postal address: AIPS++ Project Office
      22             : //#                        National Radio Astronomy Observatory
      23             : //#                        520 Edgemont Road
      24             : //#                        Charlottesville, VA 22903-2475 USA
      25             : //#
      26             : 
      27             : #include <synthesis/MeasurementComponents/FringeJones.h>
      28             : #include <msvis/MSVis/VisBuffer.h>
      29             : #include <msvis/MSVis/VisBuffAccumulator.h>
      30             : #include <casacore/ms/MeasurementSets/MSColumns.h>
      31             : #include <synthesis/CalTables/CTIter.h>
      32             : #include <synthesis/MeasurementEquations/VisEquation.h>  // *
      33             : #include <synthesis/MeasurementComponents/SolveDataBuffer.h>
      34             : #include <synthesis/MeasurementComponents/MSMetaInfoForCal.h>
      35             : #include <casacore/lattices/Lattices/ArrayLattice.h>
      36             : #include <casacore/lattices/LatticeMath/LatticeFFT.h>
      37             : #include <casacore/scimath/Mathematics/FFTServer.h>
      38             : 
      39             : #include <casacore/casa/Arrays/ArrayMath.h>
      40             : #include <casacore/casa/Arrays/MatrixMath.h>
      41             : #include <casacore/casa/Arrays/ArrayLogical.h>
      42             : #include <casacore/casa/BasicSL/String.h>
      43             : #include <casacore/casa/Utilities/Assert.h>
      44             : #include <casacore/casa/Exceptions/Error.h>
      45             : #include <casacore/casa/System/Aipsrc.h>
      46             : 
      47             : #include <sstream>
      48             : 
      49             : #include <casacore/measures/Measures/MCBaseline.h>
      50             : #include <casacore/measures/Measures/MDirection.h>
      51             : #include <casacore/measures/Measures/MEpoch.h>
      52             : #include <casacore/measures/Measures/MeasTable.h>
      53             : 
      54             : #include <casacore/casa/Logging/LogMessage.h>
      55             : #include <casacore/casa/Logging/LogSink.h>
      56             : 
      57             : #include <casacore/casa/Arrays/MaskedArray.h>
      58             : #include <casacore/casa/Arrays/MaskArrMath.h>
      59             : 
      60             : #include <gsl/gsl_rng.h>
      61             : #include <gsl/gsl_randist.h>
      62             : #include <gsl/gsl_vector.h>
      63             : #include <gsl/gsl_blas.h>
      64             : #include <gsl/gsl_spblas.h>
      65             : #include <gsl/gsl_multilarge_nlinear.h>
      66             : #include <gsl/gsl_multimin.h>
      67             : #include <gsl/gsl_linalg.h>
      68             : #include <iomanip>                // needed for setprecision
      69             : 
      70             : // DEVDEBUG gates the development debugging information to standard
      71             : // error; it should be set to 0 for production.
      72             : #define DEVDEBUG false
      73             : #define KDISPSCALE 1e6
      74             : 
      75             : using namespace casa::vi;
      76             : using namespace casacore;
      77             : 
      78             : namespace casa { //# NAMESPACE CASA - BEGIN
      79             : 
      80             : // Start of GSL compliant solver
      81             : 
      82             : class AuxParamBundle {
      83             : public:
      84             :     SDBList &sdbs;    
      85             :     size_t nCalls;
      86             : private:
      87             :     // We make sure there are no copy or default constructors to
      88             :     // preserve the integrity of our reference member.
      89             :     AuxParamBundle();
      90             :     AuxParamBundle(AuxParamBundle const&);
      91             :     AuxParamBundle const& operator=(AuxParamBundle const&);
      92             : 
      93             :     size_t refant;
      94             :     size_t nCorrelations;
      95             :     size_t corrStep;
      96             :     Double t0;
      97             :     Double reftime;
      98             :     std::map< Int, std::set< Int > > activeAntennas;
      99             :     std::map< Int, Int > antennaIndexMap;
     100             :     // Can't I just have a vector, which maps indices to values anyway?
     101             :     std::vector<bool> parameterFlags;
     102             :     Int nParams;
     103             :     std::map< Int, Int > parameterMap;
     104             :     Int activeCorr;
     105             : public:
     106           0 :     AuxParamBundle(SDBList& sdbs_, size_t refant, const std::map< Int, std::set<Int> >& activeAntennas_, Vector<Bool> paramActive) :
     107           0 :         sdbs(sdbs_),
     108           0 :         nCalls(0),
     109           0 :         refant(refant),
     110           0 :         nCorrelations(sdbs.nCorrelations() > 1 ? 2 : 1),
     111           0 :         corrStep(sdbs.nCorrelations() > 2 ? 3 : 1),
     112           0 :         activeAntennas(activeAntennas_),
     113           0 :         parameterFlags(),
     114           0 :         parameterMap(),
     115           0 :         activeCorr(-1)
     116             :         // corrStep(3)
     117             :         {
     118           0 :             Int last_index = sdbs.nSDB() - 1 ;
     119           0 :             t0 = sdbs(0).time()(0);
     120           0 :             Double tlast = sdbs(last_index).time()(0);
     121           0 :             reftime = 0.5*(t0 + tlast);
     122             : 
     123           0 :             parameterFlags = paramActive.tovector();
     124           0 :             Int j = 0; // The CASA parameter index (0=peculiar phase, 1=delay, 2=rate, 3=dispersive)
     125           0 :             Int i = 0; // the Least Squares parameter vector index, depending on what's being solved for
     126           0 :             for (auto p=parameterFlags.begin(); p!=parameterFlags.end(); p++) {
     127           0 :                 if (*p) {
     128           0 :                     parameterMap.insert(std::pair<Int, Int>(j, i));
     129           0 :                     i++;
     130             :                 }
     131           0 :                 j++;
     132             :             }
     133           0 :             if (i==0) {
     134           0 :                 throw(AipsError("No parameters specified!"));
     135             :             }
     136           0 :             nParams = i; // There's always at least one parameter!
     137             :             // cerr << "AuxParamBundle reftime " << reftime << " t0 " << t0 <<" dt " << tlast - t0 << endl;
     138           0 :         }
     139             : 
     140           0 :     Int nParameters() {
     141           0 :         return nParams;
     142             :     }
     143           0 :     Double get_t0() {
     144           0 :         return t0;
     145             :     }
     146             :     Double
     147             :     get_ref_time() {
     148             :         return reftime;
     149             :     }
     150             :     size_t
     151           0 :     get_num_corrs() {
     152             :         //return sdbs.nCorrelations() > 1 ? 2 : 1;
     153           0 :         return nCorrelations;
     154             :     }
     155             :     size_t
     156           0 :     get_num_antennas() {
     157           0 :         if (activeCorr < 0) {
     158           0 :             throw(AipsError("Correlation out of range."));
     159             :         }
     160           0 :         std::set< Int > ants = activeAntennas.find(activeCorr)->second;
     161           0 :         return (size_t) ants.size();
     162           0 :     }
     163             :     size_t
     164           0 :     get_max_antenna_index() {
     165           0 :         if (activeCorr < 0) {
     166           0 :             throw(AipsError("Correlation out of range."));
     167             :         }
     168           0 :         return *(activeAntennas.find(activeCorr)->second.rbegin());
     169             :     }
     170             :     // Sometimes there is Int, sometimes size_t; the following ones are casacore::Int.
     171             :     Int
     172             :     get_num_data_points() {
     173             :         Int nTotalRows = 0;
     174             :         for (Int i = 0; i != sdbs.nSDB(); i++) {
     175             :             nTotalRows += sdbs(i).nRows();
     176             :         }
     177             :         return nTotalRows * sdbs.nChannels();
     178             :     }
     179             :     Int
     180           0 :     get_actual_num_data_points() {
     181           0 :         Int nTotalRows = 0;
     182           0 :         for (Int i = 0; i != sdbs.nSDB(); i++) {
     183           0 :             SolveDataBuffer& s (sdbs(i));
     184           0 :             for (Int irow=0; irow!=s.nRows(); irow++) {
     185           0 :                 if (s.flagRow()(irow)) continue;
     186           0 :                 nTotalRows++;
     187             :             }
     188             :         }
     189           0 :         return nTotalRows * sdbs.nChannels();
     190             :     }
     191             :     size_t 
     192           0 :     get_data_corr_index(size_t icorr) {
     193           0 :         if (icorr > nCorrelations) {
     194           0 :             throw(AipsError("Correlation out of range."));
     195             :         }
     196           0 :         size_t dcorr = icorr * corrStep;
     197           0 :         return dcorr;
     198             :     }
     199             :     bool
     200           0 :     isActive(size_t iant) {
     201           0 :         std::set<Int> ants = activeAntennas.find(activeCorr)->second;
     202           0 :         if (iant == refant) return true;
     203           0 :         else return (ants.find(iant) != ants.end());
     204           0 :     }
     205             :     Int
     206           0 :     get_param_corr_param_index(size_t iant0, size_t ipar) {
     207           0 :         if (iant0 == refant) return -1;
     208           0 :         int iant1 = antennaIndexMap[iant0];
     209           0 :         if (iant1 > antennaIndexMap[refant]) {
     210           0 :             iant1 -= 1;
     211             :         }
     212             :         int ipar1;
     213           0 :         auto p = parameterMap.find(ipar);
     214           0 :         if (p==parameterMap.end()) {
     215           0 :             ipar1 = -1;
     216             :         }
     217             :         else {
     218           0 :             ipar1 = (iant1 * nParameters()) + p->second;
     219             :         }
     220           0 :         return ipar1;
     221             :     }
     222             :     size_t
     223           0 :     get_active_corr() {
     224           0 :         return activeCorr;
     225             :     }
     226             :     void
     227           0 :     set_active_corr(size_t icorr) {
     228           0 :         activeCorr = icorr;
     229           0 :         antennaIndexMap.clear();
     230           0 :         Int i = 0;
     231           0 :         std::set<Int>::iterator it;
     232           0 :         std::set<Int> ants = activeAntennas.find(activeCorr)->second;
     233           0 :         for (it = ants.begin(); it != ants.end(); it++) {
     234           0 :             antennaIndexMap[*it] = i++;
     235             :         }
     236           0 :     }
     237             : };
     238             : 
     239             : 
     240             : 
     241             : void
     242           0 : print_baselines(std::set<std::pair< Int, Int > > baselines) {
     243           0 :     cerr << "Baselines encountered ";
     244           0 :     std::set<std::pair< Int, Int > >::iterator it;
     245           0 :     for (it=baselines.begin(); it != baselines.end(); ++it) {
     246           0 :         cerr << "(" << it->first << ", " << it->second << ") ";
     247             :     }
     248           0 :     cerr << endl;
     249           0 : }
     250             : 
     251             : 
     252             : int
     253           0 : expb_f(const gsl_vector *param, void *d, gsl_vector *f)
     254             : {
     255           0 :     AuxParamBundle *bundle = (AuxParamBundle *)d;
     256           0 :     SDBList& sdbs = bundle->sdbs;
     257           0 :     Double refTime = bundle->get_t0();
     258             :     
     259           0 :     gsl_vector_set_zero(f);
     260             :     //    Vector<Double> freqs = sdbs.freqs();
     261             : 
     262           0 :     const Double reffreq0=sdbs(0).freqs()(0);  // First freq in first SDB
     263             :     
     264           0 :     size_t count = 0; // This is the master index.
     265             : 
     266           0 :     Double sumwt = 0.0;
     267           0 :     Double xi_squared = 0.0;
     268             : 
     269           0 :     for (Int ibuf=0; ibuf < sdbs.nSDB(); ibuf++) {
     270           0 :         SolveDataBuffer& s (sdbs(ibuf));
     271           0 :         if (!s.Ok()) continue;
     272             : 
     273           0 :         const Vector<Double> freqs(s.freqs()); // This ibuf's freqs
     274           0 :         Float fmin_ = min(freqs);
     275           0 :         Float fmax = max(freqs);
     276             : 
     277           0 :         const Cube<Complex>& v(s.visCubeCorrected());
     278           0 :         const Cube<Bool>& fl(s.flagCube());
     279           0 :         const Cube<Float>& weights(s.weightSpectrum());
     280             :            
     281           0 :         for (Int irow=0; irow!=s.nRows(); irow++) {
     282           0 :             if (s.flagRow()(irow)) continue;
     283             : 
     284           0 :             Int ant1(s.antenna1()(irow));
     285           0 :             Int ant2(s.antenna2()(irow));
     286           0 :             if (!bundle->isActive(ant1) || !bundle->isActive(ant2))
     287           0 :                 continue;            
     288           0 :             if (ant1==ant2) continue;
     289             : 
     290             :             // VisBuffer.h seems to suggest that a vb.visCube may have shape
     291             :             // (nCorr(), nChannel(), nRow())
     292           0 :             size_t icorr0 = bundle->get_active_corr();
     293           0 :             size_t dcorr = bundle->get_data_corr_index(icorr0);
     294             :             // We also need to get the right parameters for this,
     295             :             // polarization (icorr is an encoding of the
     296             :             // polarization of the correlation products).
     297             :             
     298             :             Double phi0, tau, r, disp;
     299             :             {
     300             :                 Int i;
     301             :                 Double phi0_1, tau1, r1, disp1;
     302             :                 Double phi0_2, tau2, r2, disp2;
     303             :                 
     304           0 :                 phi0_1 = ((i = bundle->get_param_corr_param_index(ant1, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
     305           0 :                 tau1   = ((i = bundle->get_param_corr_param_index(ant1, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
     306           0 :                 r1     = ((i = bundle->get_param_corr_param_index(ant1, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
     307           0 :                 disp1  = ((i = bundle->get_param_corr_param_index(ant1, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
     308             :                 
     309           0 :                 phi0_2 = ((i = bundle->get_param_corr_param_index(ant2, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
     310           0 :                 tau2   = ((i = bundle->get_param_corr_param_index(ant2, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
     311           0 :                 r2     = ((i = bundle->get_param_corr_param_index(ant2, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
     312           0 :                 disp2  = ((i = bundle->get_param_corr_param_index(ant2, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
     313             :                 
     314           0 :                 phi0 = phi0_2 - phi0_1;
     315           0 :                 tau = tau2 - tau1;
     316           0 :                 r = r2-r1;
     317           0 :                 disp = disp2-disp1;
     318             :             }
     319             :             
     320           0 :             for (size_t ichan = 0; ichan != v.ncolumn(); ichan++) {
     321           0 :                 if (fl(dcorr, ichan, irow)) continue;
     322             : 
     323           0 :                 Float freq = freqs(ichan);
     324           0 :                 Float k_disp = KDISPSCALE*C::_2pi*(1.0/freq + (freq-fmin_-fmax)/(fmin_*fmax));
     325             : 
     326           0 :                 Complex vis = v(dcorr, ichan, irow);
     327           0 :                 Double w0 = weights(dcorr, ichan, irow);
     328             :                 // FIXME: what should we use to scale the weights?
     329             :                 // Double weightScale = norm(vis);
     330             :                 // Double weightScale = abs(vis);
     331             :                 // Double weightScale = 1;
     332             :                 // Double weightScale = 1/sqrt(w0); // Actually AIPS 0, not AIPS 1!
     333             :                 // Double weightScale = pow(w0, -0.75); // AIPS 2
     334             :                 //  Double weightScale = 1/w0; // AIPS 3
     335             :                 // Double weightScale = norm(vis); // Casa 1, I guess
     336           0 :                 Double w = sqrt(w0);
     337           0 :                 sumwt += w*w;
     338           0 :                 if (fabs(w) < FLT_EPSILON) continue;
     339             :                 // We have to turn the delay back into seconds from nanoseconds.
     340             :                 // Freq difference is in Hz, which comes out typically as 1e6 bands
     341             :                 //Double wDf = C::_2pi*(freqs(ichan) - freqs(0))*1e-9;
     342           0 :                 Double wDf = C::_2pi*(freqs(ichan) - reffreq0)*1e-9;
     343             :                 //
     344           0 :                 Double t1 = s.time()(0);
     345             :                 // FIXME: Remind me why we *do* scale wDf with 1e-9
     346             :                 // but do *not* do that with ref_freq?
     347             :                 // I have a theory which is mine:
     348             :                 // this is because tau is in nanoseconds.
     349             :                 //Double ref_freq = freqs(0);
     350             :                 //Double wDt = C::_2pi*(t1 - refTime) * ref_freq; 
     351           0 :                 Double wDt = C::_2pi*(t1 - refTime) * reffreq0; 
     352             : 
     353           0 :                 Double mtheta = -(phi0 + tau*wDf + r*wDt + disp*k_disp); 
     354           0 :                 Double vtheta = arg(vis);
     355             : 
     356           0 :                 Double c_r = w*(cos(mtheta) - cos(vtheta));
     357           0 :                 Double c_i = w*(sin(mtheta)  - sin(vtheta));
     358           0 :                 gsl_vector_set(f, count, c_r);
     359           0 :                 gsl_vector_set(f, count+1, c_i);
     360             : 
     361           0 :                 count += 2;
     362           0 :                 xi_squared += c_r*c_r + c_i*c_i;
     363             :             }
     364             :         }
     365           0 :     }
     366             :     // cerr << "Residual xi-squared = " << xi_squared << endl;
     367           0 :     return GSL_SUCCESS;
     368             : }
     369             : 
     370             :     
     371             : int
     372           0 : expb_df(CBLAS_TRANSPOSE_t TransJ, const gsl_vector* param, const gsl_vector *u, void *bundle_, gsl_vector *v, gsl_matrix *JTJ)
     373             : {
     374             : 
     375             :     // param is the current vector for which we're finding the jacobian.
     376             :     // if TransJ is true, evaluate J^T u and store in v.
     377             :     // Also store J^T . J in lower half of JTJ.
     378           0 :     std::set <std::pair < Int, Int> > baselines;
     379           0 :     AuxParamBundle *bundle = (AuxParamBundle *)bundle_;
     380             : 
     381           0 :     SDBList& sdbs = bundle->sdbs;
     382           0 :     const Double reffreq0=sdbs(0).freqs()(0);  // First freq in first SDB
     383             : 
     384           0 :     size_t count = 0; // This is the master index.
     385             : 
     386           0 :     gsl_vector_set_zero(v);
     387           0 :     gsl_matrix_set_zero(JTJ);
     388             :     
     389           0 :     Double refTime = bundle->get_t0();
     390             : 
     391           0 :     for (Int ibuf=0; ibuf < sdbs.nSDB(); ibuf++) {
     392           0 :         SolveDataBuffer& s (sdbs(ibuf));
     393           0 :         if (!s.Ok()) continue;
     394             : 
     395           0 :         const Vector<Double>& freqs(s.freqs()); // This ibuf's freqs
     396           0 :         Float fmin_ = min(freqs);
     397           0 :         Float fmax = max(freqs);
     398           0 :         const Cube<Complex>& vis(s.visCubeCorrected());
     399           0 :         const Cube<Bool>& fl(s.flagCube());
     400           0 :         const Cube<Float>& weights(s.weightSpectrum());
     401             : 
     402           0 :         Double t1 = s.time()(0);
     403           0 :         for (Int irow=0; irow!=s.nRows(); irow++) {
     404           0 :             if (s.flagRow()(irow)) continue;
     405             : 
     406           0 :             Int ant1(s.antenna1()(irow));
     407           0 :             Int ant2(s.antenna2()(irow));
     408             :             
     409           0 :             if (ant1==ant2) continue;
     410           0 :             if (!bundle->isActive(ant1) || !bundle->isActive(ant2)) {
     411           0 :                 continue;
     412             :             }
     413             : 
     414             :             // VisBuffer.h seems to suggest that a vb.visCube may have shape
     415             :             // (nCorr(), nChannel(), nRow()) 
     416             : 
     417           0 :             size_t icorr0 = bundle->get_active_corr();
     418           0 :             size_t dcorr = bundle->get_data_corr_index(icorr0);
     419             :             // We also need to get the right parameters for this
     420             :             // polarization (icorr is an encoding of the
     421             :             // polarization of the correlation products).
     422             :             
     423             :             Double phi0, tau, r, disp;
     424             :             {
     425             :                 Int i;
     426             :                 Double phi0_1, tau1, r1, disp1;
     427             :                 Double phi0_2, tau2, r2, disp2;
     428             :                 
     429           0 :                 phi0_1 = ((i = bundle->get_param_corr_param_index(ant1, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
     430           0 :                 tau1   = ((i = bundle->get_param_corr_param_index(ant1, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
     431           0 :                 r1     = ((i = bundle->get_param_corr_param_index(ant1, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
     432           0 :                 disp1  = ((i = bundle->get_param_corr_param_index(ant1, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
     433             :                 
     434           0 :                 phi0_2 = ((i = bundle->get_param_corr_param_index(ant2, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
     435           0 :                 tau2   = ((i = bundle->get_param_corr_param_index(ant2, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
     436           0 :                 r2     = ((i = bundle->get_param_corr_param_index(ant2, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
     437           0 :                 disp2  = ((i = bundle->get_param_corr_param_index(ant2, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
     438             :                 
     439           0 :                 phi0 = phi0_2 - phi0_1;
     440           0 :                 tau = tau2 - tau1;
     441           0 :                 r = r2-r1;
     442           0 :                 disp = disp2-disp1;
     443             :             }
     444             : 
     445             :                 
     446             :             //Double ref_freq = freqs(0); 
     447             :             //Double wDt = C::_2pi*(t1 - refTime) * ref_freq; 
     448           0 :             Double wDt = C::_2pi*(t1 - refTime) * reffreq0; 
     449           0 :             bool found_data = false;
     450             : 
     451           0 :             for (size_t ichan = 0; ichan != vis.ncolumn(); ichan++) {
     452           0 :                 if (fl(dcorr, ichan, irow)) continue;
     453           0 :                 Double w0 = weights(dcorr, ichan, irow);
     454           0 :                 Double w = sqrt(w0);
     455           0 :                 if (fabs(w) < FLT_EPSILON) continue;
     456           0 :                 found_data = true;
     457             : 
     458           0 :                 Float freq = freqs(ichan);
     459           0 :                 Float k_disp = KDISPSCALE*C::_2pi*(1.0/freq + (freq-fmin_-fmax)/(fmin_*fmax));
     460             :                     
     461             :                 // Add a 1e-9 factor because tau parameter is in nanoseconds.
     462             :                 //Double wDf = C::_2pi*(freqs(ichan) - freqs(0))*1e-9;
     463           0 :                 Double wDf = C::_2pi*(freqs(ichan) - reffreq0)*1e-9;
     464             :                 //
     465           0 :                 Double mtheta = -(phi0 + tau*wDf + r*wDt + disp*k_disp);
     466           0 :                 Double ws = sin(mtheta);
     467           0 :                 Double wc = cos(mtheta);
     468             : 
     469           0 :                 Double p0 = 1.0;
     470           0 :                 Double p1 = wDf;
     471           0 :                 Double p2 = wDt;
     472           0 :                 Double p3 = k_disp;
     473             :                 
     474           0 :                 Vector<Double> dterm2(4);
     475           0 :                 dterm2(0) = -p0;
     476           0 :                 dterm2(1) = -p1;
     477           0 :                 dterm2(2) = -p2;
     478           0 :                 dterm2(3) = -p3;
     479             : 
     480           0 :                 Vector<Double> dterm1(4);
     481           0 :                 dterm1(0) = p0;
     482           0 :                 dterm1(1) = p1;
     483           0 :                 dterm1(2) = p2;
     484           0 :                 dterm1(3) = p3;
     485             :                 
     486             :                 /* 
     487             :                    What we want to express is just:
     488             :                    J[count + 0, iparam2 + 0] = w*-ws*-1.0; 
     489             :                    J[count + 1, iparam2 + 0] = w*+wc*-1.0;
     490             :                    J[count + 0, iparam2 + 1] = w*-ws*-wDf;
     491             :                    J[count + 1, iparam2 + 1] = w*+wc*-wDf;
     492             :                    J[count + 0, iparam2 + 2] = w*-ws*-wDt;
     493             :                    J[count + 1, iparam2 + 2] = w*+wc*-wDt;
     494             :                    
     495             :                    But in the GSL multilarge framework we have to
     496             :                    be ready to calculate either J*u for a given u
     497             :                    or J^T*u, depending on the flag TransJ, and we also have to fill in the 
     498             :                    
     499             :                    v[iparam + ...] = J[count + ..., iparam + ...] * u[iparam + ...]
     500             :                    
     501             :                    or
     502             :                    
     503             :                    v[iparam + ...] = J^T[iparam + ..., count + ...] * u[count + ...]
     504             :                    
     505             :                    <https://www.gnu.org/software/gsl/doc/html/nls.html#c.gsl_multifit_nlinear_default_parameters>
     506             :                    
     507             :                    "Additionally, the normal equations matrix J^T J should be stored in the lower half of JTJ."
     508             :                    
     509             :                    So we should also use
     510             :                    JTJ[iparam + ..., iparam + ...] += J^T[iparam + ..., count + ...] J[count + ..., iparam + ...] 
     511             :                    
     512             :                 */
     513           0 :                 if (TransJ==CblasNoTrans) {
     514           0 :                     for (Int di=0; di<4; di++) {
     515             :                         Int i;
     516           0 :                         if ((i = bundle->get_param_corr_param_index(ant2, di))>=0) {
     517           0 :                             (*gsl_vector_ptr(v, count + 0)) += (w*-ws*dterm2(di)) * gsl_vector_get(u, i);
     518           0 :                             (*gsl_vector_ptr(v, count + 1)) += (w*+wc*dterm2(di)) * gsl_vector_get(u, i);
     519             :                         }
     520           0 :                         if ((i = bundle->get_param_corr_param_index(ant1, di))>=0) {
     521           0 :                             (*gsl_vector_ptr(v, count + 0)) += gsl_vector_get(u, i) * (w*-ws*dterm1(di));
     522           0 :                             (*gsl_vector_ptr(v, count + 1)) += gsl_vector_get(u, i) * (w*+wc*dterm1(di));
     523             :                         }
     524             :                     }
     525             :                 } else {
     526           0 :                     for (Int di=0; di<4; di++) {
     527             :                         Int i;
     528           0 :                         if ((i = bundle->get_param_corr_param_index(ant2, di))>=0) {
     529           0 :                             (*gsl_vector_ptr(v, i)) += (w*-ws*dterm2(di)) * gsl_vector_get(u, count + 0);
     530           0 :                             (*gsl_vector_ptr(v, i)) += (w*+wc*dterm2(di)) * gsl_vector_get(u, count + 1);
     531             :                         }
     532           0 :                         if ((i = bundle->get_param_corr_param_index(ant1, di))>=0) {
     533           0 :                             (*gsl_vector_ptr(v, i)) += gsl_vector_get(u, count + 0) * (w*-ws*dterm1(di));
     534           0 :                             (*gsl_vector_ptr(v, i)) += gsl_vector_get(u, count + 1) * (w*+wc*dterm1(di));
     535             :                         }
     536             :                     }
     537             :                 }
     538           0 :                 if (JTJ) {
     539             :                     Int i, j;
     540           0 :                     Double wterm = (-ws) * (-ws) + (+wc) * (+wc);
     541           0 :                     if (fabs(1-wterm) > 1e-15)
     542           0 :                         throw AipsError("Insufficiently at one");
     543           0 :                     for (Int di=0; di<4; di++) {
     544           0 :                         for (Int dj=0; dj<=di; dj++) {
     545           0 :                             if (((i = bundle->get_param_corr_param_index(ant2, di))>=0) &&
     546           0 :                                 ((j = bundle->get_param_corr_param_index(ant2, dj))>=0)) {
     547           0 :                                 (*gsl_matrix_ptr(JTJ, i, j)) += w0*dterm2(di)*dterm2(dj);
     548             :                             }
     549           0 :                             if (((i = bundle->get_param_corr_param_index(ant1, di))>=0) &&
     550           0 :                                 ((j = bundle->get_param_corr_param_index(ant1, dj))>=0)) {
     551           0 :                                 (*gsl_matrix_ptr(JTJ, i, j)) += w0*dterm1(di)*dterm1(dj);
     552             :                             }
     553             :                         }
     554             :                     }
     555             :                     // iant1 != iant2, so we don't have to worry about collisions
     556           0 :                     for (Int di=0; di<4; di++) {
     557           0 :                         for (Int dj=0; dj<4; dj++) {
     558             :                             Int i0, j0;
     559           0 :                             if (((i0 = bundle->get_param_corr_param_index(ant1, di))>=0) &&
     560           0 :                                 ((j0 = bundle->get_param_corr_param_index(ant2, dj))>=0)) {
     561           0 :                                 Int i1 = max(i0, j0);
     562           0 :                                 Int j1 = min(i0, j0);
     563           0 :                                 (*gsl_matrix_ptr(JTJ, i1, j1)) += w0*dterm2(di)*dterm1(dj);
     564             :                             }
     565             :                         }
     566             :                     }
     567           0 :                     count += 2;
     568             :                 } // if JTJ
     569           0 :             } // loop over channels
     570           0 :             if (found_data) {
     571           0 :                 std::pair<Int, Int> antpair = std::make_pair(ant1, ant2);
     572           0 :                 bool newBaseline = (baselines.find(antpair) == baselines.end());
     573           0 :                 if (newBaseline) {
     574           0 :                     baselines.insert(antpair);
     575             :                     // cerr << "paramFlagging for antenna "<< ant1 << ": ";
     576             :                     // for (size_t di=0; di<4; di++) {
     577             :                     //     cerr << (bundle->get_param_corr_param_index(ant1, di)>=0) << " ";
     578             :                     // }
     579             :                     // cerr << endl;
     580             :                     // cerr << "indices for antenna "<< ant1 << ": ";
     581             :                     // if (bundle->get_param_corr_param_index(ant1, 0) >= 0) { 
     582             :                     //     for (size_t di=0; di<4; di++) {
     583             :                     //         cerr << bundle->get_param_corr_param_index(ant1, di) << " ";
     584             :                     //     }                    
     585             :                     //     cerr << endl;
     586             :                     // }
     587             :                     // cerr << "phi0 " << phi0 << " tau " << tau << " r " << r << endl;
     588             :                 }
     589             :             }
     590             :         }
     591             :     }
     592             :     if (DEVDEBUG && 0) {
     593             :         print_baselines(baselines);
     594             :         cerr << "count " << count << endl;
     595             :         cerr << "v = ";
     596             :         for (size_t i=0; i!=v->size; i++) {
     597             :             cerr << gsl_vector_get(v, i) << " ";
     598             :         }
     599             :         cerr << endl;
     600             :         // if (JTJ) {
     601             :         //     cerr <<"JTJ " << std::scientific << endl;
     602             :         //     for (size_t i=0; i!=JTJ->size1; i++) {
     603             :         //         for (size_t j=0; j!=JTJ->size2; j++) {
     604             :         //             cerr << gsl_matrix_get(JTJ, i, j) << " ";
     605             :         //         }
     606             :         //         cerr << endl;
     607             :         //     }
     608             :         //     cerr << endl;
     609             :         // }
     610             :     }
     611           0 :     return GSL_SUCCESS;
     612           0 : }
     613             :     
     614             : 
     615             : 
     616             : int
     617           0 : expb_hess(gsl_vector *param, AuxParamBundle *bundle, gsl_matrix *hess, Double xi_squared, gsl_vector *snr_vector, LogIO& logSink)
     618             : {
     619             :     // We calculate the diagonal for the hessian as used by AIPS for
     620             :     // the signal to noise. The AIPS formulation, by Fred Schwab, is a
     621             :     // hand-rolled routine that solves a different problem to ours: by
     622             :     // using a triangular matrix for the Jacobian (requiring antenna i<
     623             :     // antenna j) the J^T * J term vanishes throughout and the Hessian
     624             :     // of the Xi^2 functional *only* includes the second-order
     625             :     // derivative terms, which are usually neglected.
     626             :     //
     627             :     // This is very clever, but it also means different covariance and
     628             :     // information matrices, and therefore a different SNR.  Here we
     629             :     // use a generic least squares solver but we cheat slightly and use
     630             :     // the AIPS form for the Hessian and SNR calculations.
     631             :     //
     632             :     // FIXME: Is there any compelling reason to use gsl_vectors for
     633             :     // this, given that we're not really hooked in to the gsl
     634             :     // least squares framework by the time we do this?
     635             :     
     636           0 :     SDBList& sdbs = bundle->sdbs;
     637           0 :     Double refTime = bundle->get_t0();
     638             : 
     639             :     // Dimensions of (num_antennas); is the same dimension as
     640             :     // param vector here.
     641           0 :     gsl_matrix_set_zero(hess);
     642             : 
     643           0 :     const Double reffreq0=sdbs(0).freqs()(0);  // First freq in first SDB
     644             : 
     645           0 :     size_t nobs = 0;
     646           0 :     Double sumwt = 0;
     647           0 :     size_t numpar = param->size;
     648             : 
     649           0 :     for (Int ibuf=0; ibuf < sdbs.nSDB(); ibuf++)
     650             :     {
     651           0 :         SolveDataBuffer& s (sdbs(ibuf));
     652           0 :         if (!s.Ok()) continue;
     653             : 
     654           0 :         const Vector<Double> freqs(s.freqs()); // This ibuf's freqs
     655           0 :         Float fmin_ = min(freqs);
     656           0 :         Float fmax = max(freqs);
     657             :             
     658           0 :         const Cube<Complex>& v(s.visCubeCorrected());
     659           0 :         const Cube<Bool>& fl(s.flagCube());
     660           0 :         const Cube<Float>& weights(s.weightSpectrum());
     661             :            
     662             :             
     663           0 :         for (Int irow=0; irow!=s.nRows(); irow++) {
     664           0 :             if (s.flagRow()(irow)) continue;
     665             : 
     666           0 :             Int ant1(s.antenna1()(irow));
     667           0 :             Int ant2(s.antenna2()(irow));
     668           0 :             if (!bundle->isActive(ant1) || !bundle->isActive(ant2))
     669           0 :                 continue;            
     670           0 :             if (ant1==ant2) continue;
     671             : 
     672             :             // VisBuffer.h seems to suggest that a vb.visCube may have shape
     673             :             // (nCorr(), nChannel(), nRow())
     674           0 :             size_t icorr0 = bundle->get_active_corr();
     675           0 :             size_t dcorr = bundle->get_data_corr_index(icorr0);
     676             :             // We also need to get the right parameters for this,
     677             :             // polarization (icorr is an encoding of the
     678             :             // polarization of the correlation products).
     679             :             
     680             :             Double phi0, tau, r, disp;
     681             :             {
     682             :                 Int i;
     683             :                 Double phi0_1, tau1, r1, disp1;
     684             :                 Double phi0_2, tau2, r2, disp2;
     685             :                 
     686           0 :                 phi0_1 = ((i = bundle->get_param_corr_param_index(ant1, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
     687           0 :                 tau1   = ((i = bundle->get_param_corr_param_index(ant1, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
     688           0 :                 r1     = ((i = bundle->get_param_corr_param_index(ant1, 2))>=0) ? gsl_vector_get(param, i) : 0.0;
     689           0 :                 disp1  = ((i = bundle->get_param_corr_param_index(ant1, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
     690             : 
     691             :                 
     692           0 :                 phi0_2 = ((i = bundle->get_param_corr_param_index(ant2, 0))>=0) ? gsl_vector_get(param, i) : 0.0;
     693           0 :                 tau2   = ((i = bundle->get_param_corr_param_index(ant2, 1))>=0) ? gsl_vector_get(param, i) : 0.0;
     694           0 :                 r2     = ((i = bundle->get_param_corr_param_index(ant2, 2))>=0) ? gsl_vector_get(param, i) : 0.0;  
     695           0 :                 disp2  = ((i = bundle->get_param_corr_param_index(ant2, 3))>=0) ? gsl_vector_get(param, i) : 0.0;
     696             :               
     697           0 :                 phi0 = phi0_2 - phi0_1;
     698           0 :                 tau = tau2 - tau1;
     699           0 :                 r = r2-r1;
     700           0 :                 disp = disp2-disp1;
     701             :             }
     702             : 
     703           0 :             for (size_t ichan = 0; ichan != v.ncolumn(); ichan++) {
     704           0 :                 if (fl(dcorr, ichan, irow)) continue;
     705           0 :                 Complex vis = v(dcorr, ichan, irow);
     706             :                 // Fixme: this isn't a square root.
     707           0 :                 Double w0 = weights(dcorr, ichan, irow);
     708           0 :                 sumwt += w0;
     709           0 :                 Double w = w0;
     710           0 :                 nobs++;
     711           0 :                 if (fabs(w) < FLT_EPSILON) continue;
     712             :                 
     713             :                 // We have to turn the delay back into seconds from nanoseconds.
     714             :                 // Freq difference is in Hz, which comes out typically as 1e6 bands
     715             :                 //Double wDf = C::_2pi*(freqs(ichan) - freqs(0))*1e-9;
     716           0 :                 Double wDf = C::_2pi*(freqs(ichan) - reffreq0)*1e-9;
     717             :                 //
     718           0 :                 Double t1 = s.time()(0);
     719             : 
     720             :                 //Double ref_freq = freqs(0);
     721             :                 //Double wDt = C::_2pi*(t1 - refTime) * ref_freq;
     722           0 :                 Double wDt = C::_2pi*(t1 - refTime) * reffreq0; 
     723             : 
     724           0 :                 Float freq = freqs(ichan);
     725           0 :                 Float k_disp = KDISPSCALE*C::_2pi*(1.0/freq + (freq-fmin_-fmax)/(fmin_*fmax));
     726             : 
     727           0 :                 Double mtheta = -(phi0 + tau*wDf + r*wDt + disp*k_disp); 
     728           0 :                 Double vtheta = arg(vis);
     729             : 
     730             :                 // Hold on a minute though! 
     731           0 :                 Double cx = w*cos(vtheta - mtheta);
     732             : 
     733           0 :                 Matrix<Double> dterm(4,4);
     734           0 :                 dterm(0, 0) = cx;
     735           0 :                 dterm(0, 1) = wDf*cx;
     736           0 :                 dterm(0, 2) = wDt*cx;
     737           0 :                 dterm(0, 3) = k_disp*dterm(0, 1);
     738           0 :                 dterm(1, 1) = wDf*dterm(0, 1);
     739           0 :                 dterm(1, 2) = wDt*dterm(0, 1);
     740           0 :                 dterm(1, 3) = wDf*dterm(0, 3);
     741           0 :                 dterm(2, 2) = wDt*dterm(1, 2);
     742           0 :                 dterm(2, 3) = wDt*dterm(1, 3);
     743           0 :                 dterm(3, 3) = k_disp*dterm(2, 3);
     744             : 
     745             :                 // Symmetry terms:
     746           0 :                 dterm(1, 0) = dterm(0, 1);
     747           0 :                 dterm(2, 0) = dterm(0, 2);
     748           0 :                 dterm(3, 0) = dterm(0, 3);
     749           0 :                 dterm(2, 1) = dterm(1, 2);
     750           0 :                 dterm(3, 1) = dterm(1, 3);
     751           0 :                 dterm(3, 2) = dterm(2, 3);
     752             :                 
     753             : 
     754             : 
     755           0 :                 for (Int di=0; di<4; di++) {
     756           0 :                     for (Int dj=0; dj<4; dj++) {
     757             :                         Int i, j;
     758           0 :                         if (((i = bundle->get_param_corr_param_index(ant1, di))>=0) &&
     759           0 :                             ((j = bundle->get_param_corr_param_index(ant1, dj))>=0)) {
     760           0 :                             *gsl_matrix_ptr(hess, i, j) += dterm(di, dj);
     761             :                         }
     762             :                         // Exactly the same logic, but with antenna2
     763           0 :                         if (((i = bundle->get_param_corr_param_index(ant2, di))>=0) &&
     764           0 :                             ((j = bundle->get_param_corr_param_index(ant2, dj))>=0)) {
     765           0 :                             *gsl_matrix_ptr(hess, i, j) += dterm(di, dj);
     766             :                         }
     767             :                     }
     768             :                 }
     769             :                 // FIXME: Not just diagonal terms any more!
     770             :                 // Note that some of these are not in the lower
     771             :                 // triangular part, even though they are copied
     772             :                 // faithfully from AIPS which thinks it is filling
     773             :                 // a triangular matrix and handles symmetry
     774             :                 // later. Unless I've missed something (again).
     775           0 :                 for (Int di=0;  di<4; di++) {
     776           0 :                     for (Int dj=0; dj<4; dj++) {
     777             :                         Int i, j;
     778           0 :                         if (((i = bundle->get_param_corr_param_index(ant1, di))>=0) &&
     779           0 :                             ((j = bundle->get_param_corr_param_index(ant2, dj))>=0)) {
     780           0 :                             *gsl_matrix_ptr(hess, i, j) -= dterm(di, dj);
     781           0 :                             *gsl_matrix_ptr(hess, j, i) -= dterm(dj, di);
     782             :                         } // if
     783             :                     } // dj
     784             :                 } // di
     785           0 :             } // ichan
     786             :         } // irow
     787           0 :     } // ibuff
     788             :     // s is more tricky: it is the xi^2 term from exp_f
     789             :     
     790           0 :     xi_squared = max(xi_squared, 1e-25);
     791             : 
     792             :     if (DEVDEBUG && 0) {
     793             :         cerr << "The matrix is" << endl;
     794             :         cerr << setprecision(3) << scientific;
     795             :         for (size_t i = 0; i != hess->size1; i++) {
     796             :             for (size_t j = 0; j < hess->size2; j++) {
     797             :                 cerr << gsl_matrix_get(hess,i,j) << " ";
     798             :             }
     799             :             cerr << endl;
     800             :         }
     801             :         cerr << endl;
     802             :         // str.unsetf(cerr:floatfield);
     803             :         cerr << std::defaultfloat;
     804             :     }
     805             :     //
     806           0 :     size_t hsize = hess->size1;
     807             :     int signum;
     808           0 :     gsl_permutation *perm = gsl_permutation_alloc (hsize);
     809           0 :     gsl_matrix *lu = gsl_matrix_alloc(hsize, hsize);
     810           0 :     gsl_matrix *inv_hess = gsl_matrix_alloc(hsize, hsize);
     811             : 
     812           0 :     gsl_linalg_LU_decomp(hess, perm, &signum);
     813           0 :     Double det = gsl_linalg_LU_det(hess, signum);
     814           0 :     if ((fabs(det) < GSL_DBL_EPSILON) || std::isnan(det)) {
     815           0 :         logSink << "Hessian matrix singular (determinant=" << det << "); setting signal-to-noise ratio to zero." << LogIO::POST;
     816             :        // Singular matrix; fill snrs with zero.
     817           0 :         for (size_t i=0; i < hess->size1; i+=bundle->nParameters()) {
     818           0 :             Double snr = 0;
     819           0 :             gsl_vector_set(snr_vector, i, snr);
     820             :         }
     821             :     }
     822             :     else {
     823           0 :         gsl_linalg_LU_invert(hess, perm, inv_hess);
     824             :     
     825           0 :         Double sigma2 = xi_squared / (nobs - numpar) * nobs / sumwt;
     826             :         // cerr << "xi_squared " << xi_squared << " Nobs " << nobs << " sumwt " << sumwt << " sigma2 " << sigma2 << endl;
     827           0 :         for (size_t i=0; i < hess->size1; i+=bundle->nParameters()) {
     828           0 :             Double h = gsl_matrix_get(inv_hess, i, i);
     829           0 :             Double snr0 = sqrt(sigma2*h*0.5);
     830           0 :             snr0 = min(snr0, 9999.999);
     831           0 :             Double snr = (snr0 > 1e-20) ? 1.0/snr0 : snr0;
     832           0 :             gsl_vector_set(snr_vector, i, snr);
     833             :         }
     834             :     }
     835           0 :     gsl_matrix_free(lu);
     836           0 :     gsl_matrix_free(inv_hess);
     837           0 :     gsl_permutation_free(perm);
     838             :     // SNR[i], according to aips, is 1/sqrt(sigma2*hess(i1,i1)*0.5);
     839             :     // Note that in AIPS i1 ranges over 1..NANT
     840             :     // We use 1 as a success code.
     841           0 :     return 1;
     842             : }
     843             : 
     844             : 
     845             : Int
     846           0 : findRefAntWithData(SDBList& sdbs, Vector<Int>& refAntList, Int prtlev) {
     847           0 :     std::set<Int> activeAntennas;
     848           0 :     for (Int ibuf=0; ibuf != sdbs.nSDB(); ibuf++) {
     849           0 :         SolveDataBuffer& s(sdbs(ibuf));
     850           0 :         if (!s.Ok())
     851           0 :             continue;
     852           0 :         Cube<Bool> fl = s.flagCube();
     853           0 :         for (Int irow=0; irow!=s.nRows(); irow++) {
     854           0 :             if (s.flagRow()(irow))
     855           0 :                 continue;
     856           0 :             Int a1(s.antenna1()(irow));
     857           0 :             Int a2(s.antenna2()(irow));
     858             :             // Not using irow
     859           0 :             Matrix<Bool> flr = fl.xyPlane(irow);
     860           0 :             if (!allTrue(flr)) {
     861           0 :                 activeAntennas.insert(a1);
     862           0 :                 activeAntennas.insert(a2);
     863             :             }
     864           0 :         }
     865           0 :     }
     866           0 :     if (prtlev > 2) {
     867           0 :         cout << "[FringeJones.cc::findRefAntWithData] refantlist " << refAntList << endl;
     868           0 :         cout << "[FringeJones.cc::findRefAntWithData] activeAntennas: ";
     869           0 :         std::copy(
     870             :             activeAntennas.begin(),
     871             :             activeAntennas.end(),
     872           0 :             std::ostream_iterator<Int>(std::cout, " ")
     873             :             );
     874           0 :         cout << endl;
     875             :     }
     876           0 :     Int refAnt = -1;
     877           0 :     for (Vector<Int>::ConstIteratorSTL a = refAntList.begin(); a != refAntList.end(); a++) {
     878           0 :         if (activeAntennas.find(*a) != activeAntennas.end()) {
     879           0 :             if (prtlev > 2)
     880           0 :                 cout << "[FringeJones.cc::findRefAntWithData] We are choosing refant " << *a << endl;
     881           0 :             refAnt = *a;
     882           0 :             break;
     883             :         } else {
     884           0 :             if (prtlev > 2)
     885           0 :                 cout << "[FringeJones.cc::findRefAntWithData] No data for refant " << *a << endl;
     886             :         }
     887           0 :     }
     888           0 :     return refAnt;
     889           0 : }
     890             : 
     891             : 
     892             : // Stolen from SolveDataBuffer
     893             : void
     894           0 : aggregateTimeCentroid(SDBList& sdbs, Int refAnt, std::map<Int, Double>& aggregateTime) {
     895             :     // Weighted average of SDBs' timeCentroids
     896           0 :     std::map<Int, Double> aggregateWeight;
     897           0 :     for (Int i=0; i < sdbs.nSDB(); ++i) {
     898           0 :         SolveDataBuffer& s = sdbs(i);
     899           0 :         Vector<Double> wtvD;
     900             :         // Sum over correlations and channels to get a vector of weights for each row
     901           0 :         Vector<Float> wtv(partialSums(s.weightSpectrum(), IPosition(2, 0, 1)));
     902           0 :         wtvD.resize(wtv.nelements());
     903           0 :         convertArray(wtvD, wtv);
     904           0 :         for (Int j=0; j<s.nRows(); j++) {
     905           0 :             Int a1 = s.antenna1()(j);
     906           0 :             Int a2 = s.antenna2()(j);
     907             :             Int ant;
     908           0 :             if (a1 == refAnt) { ant = a2; }
     909           0 :             else if (a2 == refAnt) { ant = a1; }
     910           0 :             else continue;
     911           0 :             Double w = wtv(j);
     912           0 :             aggregateTime[ant] += w*s.timeCentroid()(j);
     913           0 :             aggregateWeight[ant] += w;
     914             :         }
     915           0 :     }
     916           0 :     for (auto it=aggregateTime.begin(); it!=aggregateTime.end(); ++it) {
     917           0 :         Int a = it->first;
     918           0 :         it->second /= aggregateWeight[a];
     919             :     }
     920             : 
     921           0 : }
     922             : 
     923             : 
     924             : void
     925           0 : print_gsl_vector(gsl_vector *v)
     926             : {
     927           0 :     const size_t n = v->size;
     928           0 :     for (size_t i=0; i!=n; i++) {
     929           0 :         cerr << gsl_vector_get(v, i) << " ";
     930           0 :         if (i>0 && (i % 4)==3) cerr << endl;
     931             :     }
     932           0 :     cerr << endl;
     933           0 : }
     934             : 
     935             : void
     936           0 : print_max_gsl3(gsl_vector *v)
     937             : {
     938           0 :     double phi_max = 0.0;
     939           0 :     double del_max = 0.0;
     940           0 :     double rat_max = 0.0;
     941             :         
     942           0 :     const size_t n = v->size;
     943           0 :     for (size_t i=0; i!=n/3; i++) {
     944           0 :         if (fabs(gsl_vector_get(v, 3*i+0)) > fabs(phi_max)) phi_max = gsl_vector_get(v, 3*i+0);
     945           0 :         if (fabs(gsl_vector_get(v, 3*i+1)) > fabs(del_max)) del_max = gsl_vector_get(v, 3*i+1);
     946           0 :         if (fabs(gsl_vector_get(v, 3*i+2)) > fabs(rat_max)) rat_max = gsl_vector_get(v, 3*i+2);
     947             :     }
     948           0 :     cerr << "phi_max " << phi_max << " del_max " << del_max << " rat_max " << rat_max << endl;
     949           0 : }
     950             : 
     951             : 
     952             : 
     953             : /*
     954             : gsl-2.4/multilarge_nlinear/fdf.c defines gsl_multilarge_nlinear_driver,
     955             : which I have butchered for my purposes here into
     956             : not_gsl_multilarge_nlinear_driver(). We still iterate the nonlinear
     957             : least squares solver until completion, but we adopt a convergence
     958             : criterion copied from AIPS.
     959             : 
     960             : Inputs: maxiter  - maximum iterations to allow
     961             :         w        - workspace
     962             : 
     963             : Additionally I've removed the info parameter, and I may yet regret it.
     964             : 
     965             : Originally:
     966             :         info     - (output) info flag on why iteration terminated
     967             :                    1 = stopped due to small step size ||dx|
     968             :                    2 = stopped due to small gradient
     969             :                    3 = stopped due to small change in f
     970             :                    GSL_ETOLX = ||dx|| has converged to within machine
     971             :                                precision (and xtol is too small)
     972             :                    GSL_ETOLG = ||g||_inf is smaller than machine
     973             :                                precision (gtol is too small)
     974             :                    GSL_ETOLF = change in ||f|| is smaller than machine
     975             :                                precision (ftol is too small)
     976             : 
     977             : Return:
     978             : GSL_SUCCESS if converged
     979             : GSL_MAXITER if maxiter exceeded without converging
     980             : GSL_ENOPROG if no accepted step found on first iteration
     981             : */
     982             : 
     983             : int
     984           0 : least_squares_inner_driver (const size_t maxiter,
     985             :                             gsl_multilarge_nlinear_workspace * w,
     986             :                             AuxParamBundle *bundle)
     987             : {
     988             :   int status;
     989           0 :   size_t iter = 0;
     990             :   /* call user callback function prior to any iterations
     991             :    * with initial system state */
     992             :   Double s;
     993           0 :   Double last_s = 1.0e30;
     994           0 :   Bool converged = false;
     995             :   do  {
     996           0 :       status = gsl_multilarge_nlinear_iterate (w);
     997             :       /*
     998             :        * If the solver reports no progress on the first iteration,
     999             :        * then it didn't find a single step to reduce the
    1000             :        * cost function and more iterations won't help so return.
    1001             :        *
    1002             :        * If we get a no progress flag on subsequent iterations,
    1003             :        * it means we did find a good step in a previous iteration,
    1004             :        * so continue iterating since the solver has now reset
    1005             :        * mu to its initial value.
    1006             :        */
    1007           0 :       if (status == GSL_ENOPROG && iter == 0) {
    1008           0 :           return GSL_EMAXITER;
    1009             :       }
    1010             : 
    1011           0 :       Double fnorm = gsl_blas_dnrm2(w->f);      
    1012           0 :       s = 0.5 * fnorm * fnorm;
    1013             :       if (DEVDEBUG) {
    1014             :           cerr << "Iter: " << iter << " ";
    1015             :           cerr << "Parameters: " << endl;
    1016             :           print_gsl_vector(w->x);
    1017             :           print_max_gsl3(w->dx);
    1018             :           cerr << "1 - s/last_s=" << 1 - s/last_s << endl;
    1019             :       }
    1020           0 :       ++iter;
    1021           0 :       if ((1 - s/last_s < 5e-6) && (iter > 1)) converged = true;
    1022           0 :       last_s = s;
    1023             :       /* old test for convergence:
    1024             :          status = not_gsl_multilarge_nlinear_test(xtol, gtol, ftol, info, w); */
    1025           0 :   } while (!converged && iter < maxiter);
    1026             :   /*
    1027             :    * the following error codes mean that the solution has converged
    1028             :    * to within machine precision, so record the error code in info
    1029             :    * and return success
    1030             :    */
    1031           0 :   if (status == GSL_ETOLF || status == GSL_ETOLX || status == GSL_ETOLG)
    1032             :   {
    1033           0 :       status = GSL_SUCCESS;
    1034             :   }
    1035             :   /* check if max iterations reached */
    1036           0 :   if (iter >= maxiter && status != GSL_SUCCESS)
    1037           0 :       status = GSL_EMAXITER;  return status;
    1038             : } /* gsl_multilarge_nlinear_driver() */
    1039             : 
    1040             : 
    1041             : 
    1042             : 
    1043             : void
    1044           0 : least_squares_driver(SDBList& sdbs, Matrix<Float>& casa_param, Matrix<Bool>& casa_flags, Matrix<Float>& casa_snr, Int refant,
    1045             :                      const std::map< Int, std::set<Int> >& activeAntennas, Int maxits, Vector<Bool> paramActive, LogIO& logSink) {
    1046             :     // The variable casa_param is the Casa calibration framework's RParam matrix; we transcribe our results into it only at the end.
    1047             :     // n below is number of variables,
    1048             :     // p is number of parameters
    1049             : 
    1050             :     // We could pass in an AuxParamBundle instead I guess?
    1051           0 :     AuxParamBundle bundle(sdbs, refant, activeAntennas, paramActive);
    1052           0 :     for (size_t icor=0; icor != bundle.get_num_corrs(); icor++) {
    1053           0 :         bundle.set_active_corr(icor);
    1054           0 :         if (bundle.get_num_antennas() == 0) {
    1055           0 :             logSink << "No antennas for correlation " << icor << "; not running least-squares solver." << LogIO::POST;
    1056           0 :             continue;
    1057             :         }
    1058           0 :         if (bundle.get_num_antennas() == 1) {
    1059           0 :             logSink << "No baselines for correlation " << icor << "; not running least-squares solver." << LogIO::POST;
    1060           0 :             continue;
    1061             :         }
    1062             :         // Four parameters for every antenna, with dispersion
    1063           0 :         size_t p = bundle.nParameters() * (bundle.get_num_antennas() - 1);
    1064             :         // We need to store complex visibilities in a real matrix so we
    1065             :         // just store real and imaginary components separately.
    1066           0 :         size_t n = 2 * bundle.get_actual_num_data_points();
    1067             : 
    1068             :         if (DEVDEBUG) {
    1069             :             cerr << "bundle.nParameters() " << bundle.nParameters()
    1070             :                  << " bundle.get_num_antennas() " <<bundle.get_num_antennas() << endl;
    1071             :             cerr << "p " << p << " n " << n << endl;
    1072             :         }
    1073             :         // Parameters for the least-squares solver.
    1074             :         // param_tol sets roughly the number of decimal places accuracy you want in the answer;
    1075             :         // I feel that 3 is probably plenty for fringe fitting.
    1076             :         // param_tol is not used
    1077             :         //const double param_tol = 1.0e-3;
    1078             :         // gtol is not used
    1079             :         // const double gtol = pow(GSL_DBL_EPSILON, 1.0/3.0);
    1080             :         // ftol is not used
    1081             :         // const double ftol = 1.0e-20;   
    1082           0 :         const size_t max_iter = maxits ;
    1083             : 
    1084           0 :         const gsl_multilarge_nlinear_type *T = gsl_multilarge_nlinear_trust;
    1085           0 :         gsl_multilarge_nlinear_parameters params = gsl_multilarge_nlinear_default_parameters();
    1086             :         // the Moré scaling is the best equipped to handle very different scales;
    1087             :         //it should be the best choice to accommodate dispersive terms of O(f)
    1088           0 :         params.scale = gsl_multilarge_nlinear_scale_more;
    1089           0 :         params.trs = gsl_multilarge_nlinear_trs_lm;
    1090           0 :         params.solver = gsl_multilarge_nlinear_solver_cholesky;
    1091           0 :         gsl_multilarge_nlinear_workspace *w = gsl_multilarge_nlinear_alloc(T, &params, n, p);
    1092             :         gsl_multilarge_nlinear_fdf f;
    1093             : 
    1094           0 :         f.f = &expb_f;
    1095             :         /* Can't set to NULL for finite-difference Jacobian in multilarge case. */
    1096           0 :         f.df =  &expb_df;   
    1097           0 :         f.n = n;    /* number of data points */
    1098           0 :         f.p = p;    /* number of parameters */
    1099           0 :         f.params = &bundle;
    1100             : 
    1101             :         
    1102             :         // Our original param is a matrix of (3*nCorr, nElem).
    1103             :         // We have to transcribe it to a vector.
    1104             : 
    1105           0 :         gsl_vector *gp = gsl_vector_alloc(p);
    1106           0 :         gsl_vector_set_zero(gp);
    1107             : 
    1108             :         // We transcribe Casa parameters into gsl vector format, as required by the solver.
    1109           0 :         for (size_t iant=0; iant != bundle.get_max_antenna_index()+1; iant++) {
    1110           0 :             if (!bundle.isActive(iant)) {
    1111           0 :                 continue;
    1112             :             }
    1113           0 :             for (int di=0; di<4; di++) {
    1114           0 :                 Int param_ind = bundle.get_param_corr_param_index(iant, di);
    1115           0 :                 if (param_ind < 0) continue;
    1116           0 :                 gsl_vector_set(gp, param_ind, casa_param(4*icor + di, iant));
    1117             :             }
    1118             :         }
    1119           0 :         gsl_vector *gp_orig = gsl_vector_alloc(p);
    1120             :         // Keep a copy of original parameters
    1121           0 :         gsl_vector_memcpy (gp_orig, gp);
    1122             :         // initialise workspace
    1123           0 :         gsl_multilarge_nlinear_init(gp, &f, w);
    1124             :     
    1125             :         // compute initial residual norm */
    1126           0 :         gsl_vector *res_f = gsl_multilarge_nlinear_residual(w);
    1127             : 
    1128             :         int info;
    1129           0 :         int status = least_squares_inner_driver(max_iter, w, &bundle);
    1130           0 :         double chi1 = gsl_blas_dnrm2(res_f);
    1131             :         
    1132           0 :         gsl_vector_sub(gp_orig, w->x);
    1133           0 :         gsl_vector *res = gsl_multilarge_nlinear_position(w);
    1134             :         
    1135             :         // We transcribe values back from gsl_vector to the param matrix
    1136             :         
    1137           0 :         gsl_matrix *hess = gsl_matrix_alloc(p,p);
    1138           0 :         gsl_vector *snr_vector = gsl_vector_alloc(p);
    1139           0 :         gsl_matrix_set_zero(hess);
    1140           0 :         gsl_vector_set_zero(snr_vector);
    1141           0 :         expb_hess(gp, &bundle, hess, chi1*chi1, snr_vector, logSink);
    1142             :         
    1143             :         // Transcribe parameters back into CASA arrays
    1144           0 :         for (size_t iant=0; iant != bundle.get_max_antenna_index()+1; iant++) {
    1145           0 :             if (!bundle.isActive(iant)) continue;
    1146           0 :             Int iparam = bundle.get_param_corr_param_index(iant, 0);
    1147           0 :             if (iparam<0) {
    1148           0 :                 continue;
    1149             :             }
    1150             :             if (DEVDEBUG) {
    1151             :                 logSink << "iparam " << iparam << endl;
    1152             :                 logSink << "Old values for ant " << iant << " correlation " << icor 
    1153             :                         << " delay " << casa_param(4*icor + 1, iant) << " ns "
    1154             :                         << " rate " << casa_param(4*icor + 2, iant)
    1155             :                         << " angle " << casa_param(4*icor + 0, iant)
    1156             :                         << endl;
    1157             :                 logSink << "New values for ant " << iant << " correlation " << icor << ":";
    1158             :                 int i;
    1159             :                 if ((i=bundle.get_param_corr_param_index(iant, 0))>=0) {
    1160             :                     logSink << " Angle " << gsl_vector_get(res, i);
    1161             :                 }
    1162             :                 if ((i=bundle.get_param_corr_param_index(iant, 1))>=0) {
    1163             :                     logSink << " delay " << gsl_vector_get(res, i) << " ns ";
    1164             :                 }
    1165             :                 if ((i=bundle.get_param_corr_param_index(iant, 2))>=0) {
    1166             :                     logSink << " rate " << gsl_vector_get(res, i);
    1167             :                 }
    1168             :                 logSink << "." << LogIO::POST;
    1169             :             }
    1170           0 :             if (status==GSL_SUCCESS || status==GSL_EMAXITER) {
    1171             :                 // Current policy is to assume that exceeding max
    1172             :                 // number of iterations is not a deal-breaker, leave it
    1173             :                 // to SNR calculation to decide if the results are
    1174             :                 // useful.
    1175           0 :                 for (size_t di=0; di<4; di++) {
    1176           0 :                     int i=bundle.get_param_corr_param_index(iant, di);
    1177           0 :                     int i0 = bundle.get_param_corr_param_index(iant, 0);
    1178           0 :                     if (i>=0) {
    1179           0 :                         casa_param(4*icor + di, iant) = gsl_vector_get(res, i);
    1180           0 :                         casa_snr(4*icor + di, iant) = gsl_vector_get(snr_vector, i0);
    1181             :                     } else {
    1182           0 :                         casa_param(4*icor + di, iant) = 0.0;
    1183           0 :                         casa_snr(4*icor + di, iant) = 0.0;
    1184             :                     }
    1185             :                 }
    1186           0 :             } else { // gsl solver failed; flag data
    1187           0 :                 logSink << "Least-squares solver failed to converge; flagging" << endl;
    1188           0 :                 for (size_t di=0; di<4; di++) {
    1189           0 :                     casa_flags(4*icor + di, iant) = false;
    1190             :                 }
    1191             :             }
    1192             :         }
    1193             : 
    1194             :         logSink <<  "Least squares complete for correlation " << icor
    1195           0 :                 << " after " <<  gsl_multilarge_nlinear_niter(w) << " iterations." << LogIO::POST;
    1196             : 
    1197             :             // << "reason for stopping: " << ((info == 1) ? "small step size" : "small gradient") << endl
    1198             :             // << "initial |f(x)| = " << chi0 << endl
    1199             :             // << "final   |f(x)| = " << chi1 << endl
    1200             :             // << "final step taken = " << diffsize 
    1201             : 
    1202             :         if (DEVDEBUG) {
    1203             :             cerr << "casa_param " << casa_param << endl;
    1204             : 
    1205             :             switch (info) {
    1206             :             case 1:
    1207             :                 logSink << "Small step size." << endl;
    1208             :                 break;
    1209             :             case 2:
    1210             :                 logSink << "Flatness." << endl;
    1211             :             }
    1212             :             logSink << LogIO::POST;
    1213             :         }
    1214           0 :         gsl_vector_free(gp);
    1215           0 :         gsl_vector_free(gp_orig);
    1216           0 :         gsl_vector_free(snr_vector);
    1217           0 :         gsl_matrix_free(hess);
    1218           0 :         gsl_multilarge_nlinear_free(w);
    1219             :     }
    1220           0 : }
    1221             : 
    1222             :     
    1223             : 
    1224             : 
    1225             : // **********************************************************
    1226             : //  CTRateAwareTimeInterp1 Implementations
    1227             : //
    1228             : 
    1229           0 : CTRateAwareTimeInterp1::CTRateAwareTimeInterp1(NewCalTable& ct,
    1230             :                                                const casacore::String& timetype,
    1231             :                                                casacore::Array<Float>& result,
    1232           0 :                                                casacore::Array<Bool>& rflag) :
    1233           0 :   CTTimeInterp1(ct,timetype,result,rflag)
    1234           0 : {}
    1235             : 
    1236             : // Destructor (nothing to do locally)
    1237           0 : CTRateAwareTimeInterp1::~CTRateAwareTimeInterp1() {}
    1238             : 
    1239           0 : Bool CTRateAwareTimeInterp1::interpolate(Double newtime) {
    1240             :   // Call generic first
    1241           0 :   if (CTTimeInterp1::interpolate(newtime)) {
    1242             :     // Only if generic yields new calibration
    1243             :     // NB: lastWasExact_=exact in generic
    1244           0 :     applyPhaseRate(timeType().contains("nearest") || lastWasExact_);
    1245           0 :     return true;
    1246             :   }
    1247             :   else
    1248             :     // No change
    1249           0 :     return false;
    1250             : 
    1251             : }
    1252             : 
    1253             : // Do the phase rate math
    1254           0 : void CTRateAwareTimeInterp1::applyPhaseRate(Bool single)
    1255             : {
    1256             : 
    1257           0 :   Int ispw=mcols_p->spwId()(0);  // should only be one (sliced ct_)!
    1258           0 :   MSSpectralWindow msSpw(ct_.spectralWindow());
    1259           0 :   MSSpWindowColumns msCol(msSpw);
    1260             :   //Vector<Double> refFreqs;
    1261             :   //msCol.refFrequency().getColumn(refFreqs,True);
    1262             : 
    1263           0 :   Vector<Double> freqs;
    1264           0 :   msCol.chanFreq().get(ispw,freqs,True);  // should only be 1
    1265           0 :   Double centroidFreq=freqs(0);
    1266             : 
    1267             :   // cout << "time = " << (currTime_ - timeRef_) << endl;
    1268             : 
    1269           0 :   if (single) {
    1270           0 :     for (Int ipol=0;ipol<2;ipol++) {
    1271           0 :       Double dtime=(currTime_-timeRef_)-timelist_(currIdx_);
    1272           0 :       Double phase=result_(IPosition(2,ipol*4,0));
    1273           0 :       Double rate=result_(IPosition(2,ipol*4+2,0));
    1274           0 :       phase+=2.0*C::pi*rate*centroidFreq*dtime;
    1275           0 :       result_(IPosition(2,ipol*4,0))=phase;
    1276             :     }
    1277             :   } else {
    1278           0 :     Vector<uInt> rows(2); indgen(rows); rows+=uInt(currIdx_);
    1279           0 :     Cube<Float> r(mcols_p->fparamArray("",rows));
    1280             : 
    1281           0 :     Vector<Double> dtime(2);
    1282           0 :     dtime(0)=(currTime_-timeRef_)-timelist_(currIdx_);
    1283           0 :     dtime(1)=(currTime_-timeRef_)-timelist_(currIdx_+1);
    1284           0 :     Double wt=dtime(1) / (dtime(1)-dtime(0));
    1285             : 
    1286             : 
    1287           0 :     for (Int ipol=0;ipol<2;ipol++) {
    1288           0 :       Vector<Double> phase(2), rate(2);
    1289           0 :       phase(0)=r.xyPlane(0)(IPosition(2,ipol*4,0));
    1290           0 :       phase(1)=r.xyPlane(1)(IPosition(2,ipol*4,0));
    1291           0 :       rate(0)=r.xyPlane(0)(IPosition(2,ipol*4+2,0));
    1292           0 :       rate(1)=r.xyPlane(1)(IPosition(2,ipol*4+2,0));
    1293             : 
    1294           0 :       phase(0)+=2.0*C::pi*rate(0)*centroidFreq*dtime(0);
    1295           0 :       phase(1)+=2.0*C::pi*rate(1)*centroidFreq*dtime(1);
    1296             : 
    1297           0 :       Vector<Complex> ph(2);
    1298           0 :       ph(0)=Complex(cos(phase(0)),sin(phase(0)));
    1299           0 :       ph(1)=Complex(cos(phase(1)),sin(phase(1)));
    1300           0 :       ph(0)=Float(wt)*ph(0) + Float(1.0-wt)*ph(1);
    1301           0 :       result_(IPosition(2,ipol*4,0))=arg(ph(0));
    1302           0 :     }
    1303           0 :   }
    1304           0 : }
    1305             : 
    1306             : 
    1307             : 
    1308             : 
    1309             : // **********************************************************
    1310             : //  FringeJones Implementations
    1311             : //
    1312           0 : FringeJones::FringeJones(VisSet& vs) :
    1313             :     VisCal(vs),             // virtual base
    1314             :     VisMueller(vs),         // virtual base
    1315           0 :     GJones(vs)       // immediate parent
    1316             : {
    1317           0 :     if (prtlev()>2) cout << "FringeJones::FringeJones(vs)" << endl;
    1318           0 : }
    1319             : 
    1320           0 : FringeJones::FringeJones(String msname,Int MSnAnt,Int MSnSpw) :
    1321             :     VisCal(msname,MSnAnt,MSnSpw),             // virtual base
    1322             :     VisMueller(msname,MSnAnt,MSnSpw),         // virtual base
    1323           0 :     GJones(msname,MSnAnt,MSnSpw)    // immediate parent
    1324             : {
    1325           0 :     if (prtlev()>2) cout << "FringeJones::FringeJones(msname,MSnAnt,MSnSpw)" << endl;
    1326           0 : }
    1327             : 
    1328           0 : FringeJones::FringeJones(const MSMetaInfoForCal& msmc) :
    1329             :     VisCal(msmc),             // virtual base
    1330             :     VisMueller(msmc),         // virtual base
    1331           0 :     GJones(msmc)    // immediate parent
    1332             : {
    1333           0 :     if (prtlev()>2) cout << "FringeJones::FringeJones(msmc)" << endl;
    1334           0 : }
    1335             : 
    1336           0 : FringeJones::FringeJones(Int nAnt) :
    1337             :     VisCal(nAnt), 
    1338             :     VisMueller(nAnt),
    1339           0 :     GJones(nAnt)
    1340             : {
    1341           0 :     if (prtlev()>2) cout << "FringeJones::FringeJones(nAnt)" << endl;
    1342           0 : }
    1343             : 
    1344           0 : FringeJones::~FringeJones() {
    1345           0 :     if (prtlev()>2) cout << "FringeJones::~FringeJones()" << endl;
    1346           0 : }
    1347             : 
    1348           0 : void FringeJones::setApply(const Record& apply) {
    1349             :     // Call parent to do conventional things
    1350           0 :     GJones::setApply(apply);
    1351             : 
    1352           0 :     if (calWt()) 
    1353           0 :         logSink() << " (" << this->typeName() << ": Enforcing calWt()=false for phase/delay-like terms)" << LogIO::POST;
    1354             : 
    1355             :    // Enforce calWt() = false for delays
    1356           0 :     calWt()=false;
    1357             : 
    1358             :     /*
    1359             :     // Extract per-spw ref Freq for phase(delay) calculation
    1360             :     //  from the CalTable
    1361             :     // TBD:  revise as per refFreq decisions
    1362             :     MSSpectralWindow msSpw(ct_->spectralWindow());
    1363             :     MSSpWindowColumns msCol(msSpw);
    1364             :     msCol.refFrequency().getColumn(KrefFreqs_,true);
    1365             :     KrefFreqs_/=1.0e9;  // in GHz
    1366             : 
    1367             :     /// Re-assign KrefFreq_ according spwmap (if any)
    1368             :     if (spwMap().nelements()>0) {
    1369             :         Vector<Double> tmpfreqs;
    1370             :         tmpfreqs.assign(KrefFreqs_);
    1371             :         for (uInt ispw=0;ispw<spwMap().nelements();++ispw)
    1372             :             if (spwMap()(ispw)>-1)
    1373             :                 KrefFreqs_(ispw)=tmpfreqs(spwMap()(ispw));
    1374             :     }
    1375             :     */
    1376             : 
    1377             :     // Use the "physical" (centroid) frequency, per spw 
    1378           0 :     MSSpectralWindow msSpw(ct_->spectralWindow());
    1379           0 :     MSSpWindowColumns msCol(msSpw);
    1380           0 :     Vector<Double> tmpfreqs;
    1381           0 :     Vector<Double> chanfreq;
    1382           0 :     tmpfreqs.resize(msSpw.nrow());
    1383           0 :     for (rownr_t ispw=0;ispw<msSpw.nrow();++ispw) {
    1384           0 :       if (ispw < msSpw.nrow()) {
    1385           0 :         msCol.chanFreq().get(ispw,chanfreq,true);  // reshape, if nec.
    1386           0 :         Int nch=chanfreq.nelements();
    1387           0 :         tmpfreqs(ispw)=chanfreq(nch/2);
    1388             :       }
    1389             :     }
    1390             : 
    1391           0 :     KrefFreqs_.resize(nSpw()); KrefFreqs_.set(0.0);
    1392           0 :     for (rownr_t ispw=0;ispw<(rownr_t)nSpw();++ispw) {
    1393           0 :         if (ispw < tmpfreqs.nelements())
    1394           0 :             KrefFreqs_(ispw)=tmpfreqs(ispw);
    1395             :     }
    1396             : 
    1397             :     /// Re-assign KrefFreq_ according spwmap (if any)
    1398           0 :     if (spwMap().nelements()>0) {
    1399           0 :       for (uInt ispw=0;ispw<spwMap().nelements();++ispw)
    1400           0 :         if (spwMap()(ispw)>-1 && ispw < tmpfreqs.nelements())
    1401           0 :           KrefFreqs_(ispw)=tmpfreqs(spwMap()(ispw));
    1402             :     }
    1403             : 
    1404           0 :     KrefFreqs_/=1.0e9;  // in GHz
    1405           0 : }
    1406             : 
    1407           0 : void FringeJones::setApply() {
    1408             :   // This was omitted in copying KJones. It shouldn't have been.
    1409             :     
    1410             :   // Call parent to do conventional things
    1411           0 :   GJones::setApply();
    1412             : 
    1413             :   // Enforce calWt() = false for delays
    1414           0 :   calWt()=false;
    1415             : 
    1416             :   // Set the ref freqs to something usable
    1417           0 :   KrefFreqs_.resize(nSpw());
    1418           0 :   KrefFreqs_.set(5.0);
    1419             : 
    1420           0 : }
    1421             : 
    1422             : 
    1423           0 : void FringeJones::setCallib(const Record& callib,
    1424             :                             const MeasurementSet& selms) {
    1425             : 
    1426             :     // Call parent to do conventional things
    1427           0 :     SolvableVisCal::setCallib(callib,selms);
    1428             : 
    1429             :     /*
    1430             :     if (calWt()) 
    1431             :         logSink() << " (" << this->typeName() << ": Enforcing calWt()=false for phase/delay-like terms)" << LogIO::POST;
    1432             :     */
    1433             :     // Enforce calWt() = false for delays
    1434           0 :     calWt()=false;
    1435             : 
    1436             :     /*
    1437             :     // Extract per-spw ref Freq for phase(delay) calculation
    1438             :     //  from the CalTable 
    1439             :    KrefFreqs_.assign(cpp_->refFreqIn());
    1440             :     KrefFreqs_/=1.0e9;  // in GHz
    1441             : 
    1442             :     // Re-assign KrefFreq_ according spwmap (if any)
    1443             :     if (spwMap().nelements()>0) {
    1444             :         Vector<Double> tmpfreqs;
    1445             :         tmpfreqs.assign(KrefFreqs_);
    1446             :         for (uInt ispw=0;ispw<spwMap().nelements();++ispw)
    1447             :             if (spwMap()(ispw)>-1)
    1448             :                 KrefFreqs_(ispw)=tmpfreqs(spwMap()(ispw));
    1449             :     }
    1450             :     */
    1451             : 
    1452             :     // Use the "physical" (centroid) frequency, per spw 
    1453           0 :     KrefFreqs_.resize(nSpw());
    1454           0 :     for (Int ispw=0;ispw<nSpw();++ispw) {
    1455           0 :       const Vector<Double>& f(cpp_->freqIn(ispw));
    1456           0 :       Int nf=f.nelements();
    1457           0 :       KrefFreqs_[ispw]=f[nf/2];  // center (usually this will be same as [0])
    1458             :     }
    1459           0 :     KrefFreqs_/=1.0e9;  // In GHz
    1460             : 
    1461             :     // Re-assign KrefFreq_ according spwmap (if any)
    1462           0 :     if (spwMap().nelements()>0) {
    1463           0 :       Vector<Double> tmpfreqs;
    1464           0 :       tmpfreqs.assign(KrefFreqs_);
    1465           0 :       for (uInt ispw=0;ispw<spwMap().nelements();++ispw)
    1466           0 :         if (spwMap()(ispw)>-1)
    1467           0 :           KrefFreqs_(ispw)=tmpfreqs(spwMap()(ispw));
    1468           0 :     }
    1469             :     
    1470           0 : }
    1471             : 
    1472           0 : void FringeJones::setSolve(const Record& solve) {
    1473             : 
    1474             :     // Call parent to do conventional things
    1475           0 :     GJones::setSolve(solve);
    1476           0 :     preavg() = -DBL_MAX;
    1477             : 
    1478             :     // refant isn't properly set until selfSolveOne.  We set it to a
    1479             :     // known value here so that it can be checked in debugging code.
    1480           0 :     refant() = -1;
    1481           0 :     if (prtlev() > 2) {
    1482           0 :         cout << "Before GJones::setSolve" << endl
    1483           0 :              << "FringeJones::setSolve()" <<endl
    1484           0 :              << "FringeJones::refant() = "<< refant() <<endl
    1485           0 :              << "FringeJones::refantlist() = "<< refantlist() <<endl;
    1486             :     }
    1487           0 :     if (solve.isDefined("zerorates")) {
    1488           0 :         zeroRates() = solve.asBool("zerorates");
    1489             :     }
    1490           0 :     if (solve.isDefined("globalsolve")) {
    1491           0 :         globalSolve() = solve.asBool("globalsolve");
    1492             :     }
    1493           0 :     if (solve.isDefined("delaywindow")) {
    1494           0 :         Array<Double> dw = solve.asArrayDouble("delaywindow");
    1495           0 :         delayWindow() = dw;
    1496           0 :     } else {
    1497           0 :         cerr << "No delay window!" << endl;
    1498             :     }
    1499           0 :     if (solve.isDefined("ratewindow")) {
    1500           0 :         rateWindow() = solve.asArrayDouble("ratewindow");
    1501             :     } else {
    1502           0 :         cerr << "No rate window!" << endl;
    1503             :     }
    1504           0 :     if (solve.isDefined("niter")) {
    1505           0 :         maxits() = solve.asInt("niter");
    1506             :     }
    1507           0 :     if (solve.isDefined("paramactive")) {
    1508           0 :         paramActive() = solve.asArrayBool("paramactive");
    1509             :     }
    1510           0 :     if (solve.isDefined("concatspws")) {
    1511           0 :         concatSPWs() = solve.asBool("concatspws");
    1512             :     }
    1513           0 :     if (solve.isDefined("corrcomb")) {
    1514             :       //cerr << "FringeJones::setsolve() Corrcomb is set! To:"
    1515             :       //     << solve.asString("corrcomb")
    1516             :       //     << endl;
    1517           0 :         corrcomb() = solve.asString("corrcomb");
    1518             :     }
    1519           0 : }
    1520             : 
    1521             : // Note: this was previously omitted
    1522           0 : void FringeJones::specify(const Record& specify) {
    1523             : 
    1524           0 :   return SolvableVisCal::specify(specify);
    1525             : 
    1526             : }
    1527             : 
    1528           0 : void FringeJones::calcAllJones() {
    1529             : 
    1530           0 :   if (prtlev()>6) cout << "       FringeJones::calcAllJones()" << endl;
    1531             : 
    1532             :   // Should handle OK flags in this method, and only
    1533             :   //  do Jones calc if OK
    1534             : 
    1535           0 :   Vector<Complex> oneJones;
    1536           0 :   Vector<Bool> oneJOK;
    1537           0 :   Vector<Float> onePar;
    1538           0 :   Vector<Bool> onePOK;
    1539             : 
    1540           0 :   ArrayIterator<Complex> Jiter(currJElem(),1);
    1541           0 :   ArrayIterator<Bool>    JOKiter(currJElemOK(),1);
    1542           0 :   ArrayIterator<Float>   Piter(currRPar(),1);
    1543           0 :   ArrayIterator<Bool>    POKiter(currParOK(),1);
    1544             : 
    1545             :   Double phase;
    1546             : 
    1547           0 :   for (Int iant=0; iant<nAnt(); iant++) {
    1548           0 :     onePar.reference(Piter.array());
    1549           0 :     onePOK.reference(POKiter.array());
    1550             : 
    1551           0 :     Float fmin_ = min(currFreq());
    1552           0 :     Float fmax = max(currFreq());
    1553           0 :     for (Int ich=0; ich<nChanMat(); ich++) {
    1554             :       
    1555           0 :       oneJones.reference(Jiter.array());
    1556           0 :       oneJOK.reference(JOKiter.array());
    1557             : 
    1558           0 :       for (Int ipar=0;ipar<nPar();ipar+=4) {
    1559           0 :         if (onePOK(ipar)) {
    1560           0 :           Float freq = currFreq()(ich);
    1561           0 :           Float k_disp = 1e-9*KDISPSCALE*C::_2pi*(1.0/freq + (freq-fmin_-fmax)/(fmin_*fmax));
    1562             :                           
    1563           0 :           phase=onePar(ipar);
    1564           0 :           phase+=2.0*C::pi*onePar(ipar+1)*
    1565           0 :             (currFreq()(ich)-KrefFreqs_(currSpw()));
    1566           0 :           phase+=2.0*C::pi*onePar(ipar+2)*KrefFreqs_(currSpw())*1e9*
    1567           0 :             (currTime() - refTime());
    1568           0 :           Float dph_d = onePar(ipar+3) * k_disp;
    1569             :           if (DEVDEBUG && 0) {
    1570             :               cerr << "fmin_ " << fmin_ << " fmax " << fmax << " k_disp " << k_disp
    1571             :                    << " param " << onePar(ipar+3) << " dph_d " << dph_d << endl;
    1572             :           }
    1573           0 :           phase+=dph_d;
    1574           0 :           oneJones(ipar/4)=Complex(cos(phase),sin(phase));
    1575           0 :           oneJOK(ipar/4)=True;
    1576             :         } else {
    1577           0 :           oneJOK(ipar/4)=False;
    1578             :         }
    1579             :       }
    1580             :       // Advance iterators
    1581           0 :       Jiter.next();
    1582           0 :       JOKiter.next();
    1583             :     }
    1584             :     // Step to next antenns's pars
    1585           0 :     Piter.next();
    1586           0 :     POKiter.next();
    1587             :   }
    1588           0 : }
    1589             : 
    1590             : 
    1591             : void
    1592           0 : FringeJones::calculateSNR(Int nCorr, DelayRateFFT& drf) {
    1593           0 :     Matrix<Float> sRP(solveRPar().nonDegenerate(1));
    1594           0 :     Matrix<Bool> sPok(solveParOK().nonDegenerate(1));
    1595           0 :     Matrix<Float> sSNR(solveParSNR().nonDegenerate(1));
    1596             :     
    1597           0 :     for (size_t icor=0; icor != (size_t) nCorr; icor++) {
    1598           0 :         const set<Int>& activeAntennas = drf.getActiveAntennasCorrelation(icor);
    1599           0 :         for (Int iant=0; iant != nAnt(); iant++) {
    1600           0 :             if (iant == refant()) {
    1601           0 :                 Double maxsnr = 999.0;
    1602           0 :                 sSNR(4*icor + 0, iant) = maxsnr;
    1603           0 :                 sSNR(4*icor + 1, iant) = maxsnr;
    1604           0 :                 sSNR(4*icor + 2, iant) = maxsnr;
    1605           0 :                 sSNR(4*icor + 3, iant) = maxsnr;
    1606             :             }
    1607           0 :             else if (activeAntennas.find(iant) != activeAntennas.end()) {
    1608           0 :                 Double delay = sRP(4*icor + 1, iant);
    1609           0 :                 Double rate = sRP(4*icor + 2, iant);
    1610             :                 // Note that DelayRateFFT::snr is also used to calculate SNRs for the least square values!
    1611           0 :                 Float snrval = drf.snr(icor, iant, delay, rate);
    1612           0 :                 sSNR(4*icor + 0, iant) = snrval;
    1613           0 :                 sSNR(4*icor + 1, iant) = snrval;
    1614           0 :                 sSNR(4*icor + 2, iant) = snrval;
    1615           0 :                 sSNR(4*icor + 3, iant) = snrval;
    1616             :             } else {
    1617           0 :                 sPok(4*icor + 0, iant) = false;
    1618           0 :                 sPok(4*icor + 1, iant) = false;
    1619           0 :                 sPok(4*icor + 2, iant) = false;
    1620           0 :                 sPok(4*icor + 3, iant) = false;
    1621             :             }
    1622             :         }
    1623             :     }
    1624           0 : }
    1625             : 
    1626             : 
    1627             : 
    1628             : 
    1629             : void
    1630           0 : FringeJones::selfSolveOne(SDBList& sdbs) {
    1631           0 :     solveRPar()=0.0;
    1632           0 :     solveParOK()=false; 
    1633           0 :     solveParErr()=1.0; // Does nothing?
    1634             :     // Maybe we put refFreq, refTime stuff in here?
    1635           0 :     Vector<Double> myRefFreqs;
    1636             :     // Cannot assume we have a calibration table (ct_) in this method.
    1637             :     // MSSpectralWindow msSpw(ct_->spectralWindow());
    1638             :     /// MSSpWindowColumns spwCol(msSpw);
    1639             :     // spwCol.refFrequency().getColumn(myRefFreqs, true);
    1640             :     //Double ref_freq = myRefFreqs(currSpw());
    1641             :     //Double ref_freq = sdbs.freqs()(0);
    1642             :     if (DEVDEBUG) {
    1643             :         cerr << "Solving for fringes for spw=" << currSpw() << endl
    1644             :              << "Valid spws are " << freqMetaData_.validSpws() << endl;
    1645             :     }
    1646           0 :     Int spw = currSpw();
    1647           0 :     Double reffreq = freqMetaData_.freq(spw)(0); 
    1648           0 :     Double t0 = sdbs(0).time()(0);
    1649           0 :     Double dt0 = refTime() - t0;
    1650             :     //Double df0 = ref_freq - sdbs.freqs()(0);
    1651             :     //Double df0 = 0; 
    1652           0 :     Double df0 = reffreq - sdbs(0).freqs()(0);  // global center to global edge
    1653             : 
    1654           0 :     logSink() << "Solving for fringes for spw=" << currSpw() << " at t="
    1655           0 :               << MVTime(refTime()/C::day).string(MVTime::YMD,7)  << LogIO::POST;
    1656             : 
    1657           0 :     std::map<Int, Double> aggregateTime;
    1658             :     // Set the refant to the first choice that has data!
    1659           0 :     refant() = findRefAntWithData(sdbs, refantlist(), prtlev());
    1660           0 :     if (refant()<0) {
    1661           0 :         logSink() << "Antennas " << refantlist() << LogIO::POST;
    1662             :         logSink() << "dt0 " << dt0 
    1663             :                   << " nSDB() " << sdbs.nSDB()
    1664           0 :                   << LogIO::POST; 
    1665           0 :         throw(AipsError("No valid reference antenna supplied."));
    1666             :     }
    1667             :     else {
    1668           0 :         logSink() << "Using reference antenna " << refant() << LogIO::POST;
    1669             :     }
    1670           0 :     aggregateTimeCentroid(sdbs, refant(), aggregateTime);
    1671             : 
    1672             :     if (DEVDEBUG) {
    1673             :         std::cerr << "Weighted time centroids" << endl; 
    1674             :         for (auto it=aggregateTime.begin(); it!=aggregateTime.end(); ++it)
    1675             :             std::cerr << it->first << " => " << it->second - t0 << std::endl;
    1676             :     }
    1677             : 
    1678             :     // We arrange that we can use either the DelayRateFFT based on concatenation
    1679             :     // or the new one that combines spectral windows after the FFT
    1680             :     if (DEVDEBUG) {
    1681             :         std::cerr << "Making a DelayRateFFT" << endl;
    1682             :     }
    1683           0 :     DelayRateFFT *drfp = DelayRateFFT::makeAChild(concatSPWs(), sdbs, refant(), delayWindow(), rateWindow());
    1684             :     // DelayRateFFT *drfp = new DelayRateFFTConcat(sdbs, refant(), delayWindow(), rateWindow());
    1685             :     // DelayRateFFT *drfp = new DelayRateFFTConcat(sdbs, refant(), delayWindow(), rateWindow());
    1686             :     if (DEVDEBUG) {
    1687             :         cerr << "Made a DelayRateFFT of some kind!" << endl;
    1688             :     }
    1689           0 :     drfp->FFT();
    1690           0 :     drfp->searchPeak();
    1691           0 :     Matrix<Float> sRP(solveRPar().nonDegenerate(1));
    1692           0 :     Matrix<Bool> sPok(solveParOK().nonDegenerate(1));
    1693           0 :     Matrix<Float> sSNR(solveParSNR().nonDegenerate(1));
    1694           0 :     logSink() << "sPok " << sPok.shape() << LogIO::POST;
    1695             :     
    1696             :     // Map from MS antenna number to index
    1697             :     // transcribe fft results to sRP
    1698           0 :     Int ncol = drfp->param().ncolumn();
    1699           0 :     Int nrow = drfp->param().nrow();
    1700             :     if (DEVDEBUG) {
    1701             :         std::cerr << "nrow " << nrow << ", ncol " << ncol << endl; 
    1702             :         std::cerr << "drfp->flag() " << drfp->flag() << endl; 
    1703             :     }
    1704             : 
    1705           0 :     for (Int i=0; i!=ncol; i++) { // i==iant
    1706           0 :         for (Int j=0; j!=nrow; j++) { // j is parameter number
    1707           0 :             Int oj = (j>=3) ? j+1 : j;
    1708           0 :             sRP(IPosition(2, oj, i)) = drfp->param()(IPosition(2, j, i));
    1709           0 :             sPok(IPosition(2, oj, i)) = !(drfp->flag()(IPosition(2, j, i)));
    1710             :         }
    1711             :         // Our estimate for dispersion is zero, unconditionally, and we stand by it.
    1712           0 :         sPok(IPosition(2, 3, i)) = true;
    1713           0 :         if (nrow > 3)
    1714           0 :             sPok(IPosition(2, 7, i)) = true;
    1715             :     }
    1716           0 :     size_t nCorrOrig(sdbs(0).nCorrelations());
    1717           0 :     size_t nCorr = (nCorrOrig> 1 ? 2 : 1); // number of p-hands
    1718           0 :     calculateSNR(nCorr, *drfp);
    1719           0 :     set<Int> belowThreshold;
    1720           0 :     Float threshold = minSNR();
    1721             :     
    1722           0 :     for (size_t icor=0; icor != nCorr; icor++) {
    1723           0 :         const set<Int>& activeAntennas = drfp->getActiveAntennasCorrelation(icor);
    1724           0 :         for (Int iant=0; iant != nAnt(); iant++) {
    1725           0 :             if (iant != refant() && (activeAntennas.find(iant) != activeAntennas.end())) {
    1726           0 :                 Float s = sSNR(4*icor + 0, iant);
    1727             :                 // Start the log message; finished below
    1728           0 :                 logSink() << "Antenna " << iant << " correlation " << icor << " has (FFT) SNR of " << s;
    1729           0 :                 if (s < threshold) {
    1730           0 :                     belowThreshold.insert(iant);
    1731           0 :                     logSink() << " below threshold (" << threshold << ")";
    1732             :                     // Don't assume these will be flagged later; do it right away.
    1733             :                     // (The least squares routine will eventually become optional.)
    1734           0 :                     sPok(4*icor + 0, iant) = false;
    1735           0 :                     sPok(4*icor + 1, iant) = false;
    1736           0 :                     sPok(4*icor + 2, iant) = false;
    1737           0 :                     sPok(4*icor + 3, iant) = false;
    1738             :                 }
    1739             :                 // Finish the log message
    1740           0 :                 logSink() << "." << LogIO::POST;
    1741             :             }
    1742             :         }
    1743             :         // We currently remove the antennas below SNR threshold from
    1744             :         // the object used to handle the FFT fringe search.
    1745           0 :         drfp->removeAntennasCorrelation(icor, belowThreshold);
    1746             :         if (DEVDEBUG) {
    1747             :             drfp->printActive();
    1748             :         }
    1749             :     }
    1750           0 :     if (globalSolve()) {
    1751           0 :         logSink() << "Starting least squares optimization." << LogIO::POST;
    1752             :         // Note that least_squares_driver is *not* a method of
    1753             :         // FringeJones so we pass everything in, including the logSink
    1754             :         // reference.  Note also that sRP is passed by reference and
    1755             :         // altered in place.
    1756           0 :         least_squares_driver(sdbs, sRP, sPok, sSNR, refant(), drfp->getActiveAntennas(), maxits(),
    1757           0 :                              paramActive(), logSink());
    1758             :     }
    1759             :     else {
    1760           0 :         logSink() << "Skipping least squares optimisation." << LogIO::POST;
    1761             :     }
    1762             : 
    1763             :     if (DEVDEBUG) {
    1764             :         cerr << "Ref time " << MVTime(refTime()/C::day).string(MVTime::YMD,7) << endl;
    1765             :         cerr << "df0 " << df0 << " dt0 " << dt0 << " reffreq*dt0 " << reffreq*dt0 << endl;
    1766             :         cerr << "reffreq " << reffreq << endl;
    1767             :         cerr << "df0 " << df0 << " dt0 " << dt0 << " reffreq*dt0 " << reffreq*dt0 << endl;
    1768             :         cerr << "sRP " << sRP << endl; 
    1769             :     }
    1770             : 
    1771           0 :     for (Int iant=0; iant != nAnt(); iant++) {
    1772           0 :         for (size_t icor=0; icor != nCorr; icor++) {
    1773           0 :             const set<Int>& activeAntennas = drfp->getActiveAntennasCorrelation(icor);
    1774           0 :             if (activeAntennas.find(iant) == activeAntennas.end()) {
    1775           0 :                 continue;
    1776             :             }
    1777           0 :             Double phi0 = sRP(4*icor + 0, iant);
    1778           0 :             Double delay = sRP(4*icor + 1, iant);
    1779           0 :             Double rate = sRP(4*icor + 2, iant);
    1780           0 :             Double k_disp = sRP(4*icor + 3, iant);
    1781           0 :             aggregateTime.find(iant);
    1782             :             // We assume the reference frequency for fringe fitting
    1783             :             // (which is NOT the one stored in the SPECTRAL_WINDOW
    1784             :             // table) is the left-hand edge of the frequency grid.
    1785           0 :             Double delta1 = df0*delay/1e9;
    1786           0 :             Double delta2 = reffreq*dt0*rate;
    1787           0 :             Double delta3 = C::_2pi*(delta1+delta2);
    1788             :             Double dt;
    1789           0 :             auto p = aggregateTime.find(iant);
    1790           0 :             if (zeroRates() && p != aggregateTime.end()) {
    1791           0 :                 dt = p->second - t0;
    1792             :             } else {
    1793           0 :                 dt = refTime() - t0;
    1794             :             }
    1795             :             if (DEVDEBUG) {
    1796             :                 cerr << "Antenna " << iant << ": phi0 " << phi0 << " delay " << delay << " rate " << rate << " dt " << dt << endl
    1797             :                      << "k_disp " << k_disp << endl
    1798             :                      << "reffreq "<< reffreq << " Adding corrections for frequency (" << 360*delta1 << ")" 
    1799             :                      << " and time (" << 360*delta2 << ") degrees." << endl;
    1800             :             }
    1801           0 :             sRP(4*icor + 0, iant) += delta3;
    1802             :          }
    1803             :     }
    1804             :     
    1805             :     // We can zero the rates here (if needed) whether we did least squares or not.
    1806           0 :     if (zeroRates()) {
    1807           0 :         logSink() << "Zeroing delay rates in calibration table." << LogIO::POST;
    1808             :         
    1809           0 :         for (size_t icor=0; icor != nCorr; icor++) {
    1810           0 :             for (Int iant=0; iant != nAnt(); iant++) {
    1811           0 :                 sRP(4*icor + 2, iant) = 0.0;
    1812             :             }
    1813             :         }
    1814             :     }
    1815             :     // Copy the results to the second polarisation for combined pols
    1816           0 :     if (corrcomb()=="all") { 
    1817           0 :         logSink() << "Correlations combined: Copying results to other correlation" << LogIO::POST;
    1818           0 :         for (Int iant=0; iant != nAnt(); iant++) {
    1819           0 :             for (Int i=0; i !=4; i++) {
    1820           0 :                 sRP(4+i, iant) = sRP(i, iant);
    1821           0 :                 sPok(4+i, iant) = sPok(i, iant);            
    1822           0 :                 sSNR(4+i, iant) = sSNR(i, iant);
    1823             :             }
    1824             :         }
    1825             :     } 
    1826             :     if (DEVDEBUG) {
    1827             :         std::cerr << "sPok " << sPok << endl;
    1828             :     }
    1829           0 :     delete drfp;
    1830           0 : }
    1831             : 
    1832             : void
    1833           0 : FringeJones::solveOneVB(const VisBuffer&) {
    1834           0 :     throw(AipsError("VisBuffer interface not supported!"));
    1835             : }
    1836             : 
    1837             : 
    1838           0 : void FringeJones::globalPostSolveTinker() {
    1839             : 
    1840             :   // Re-reference the phase, if requested
    1841           0 :   if (refantlist()(0)>-1) applyRefAnt();
    1842           0 : }
    1843             : 
    1844           0 : void FringeJones::applyRefAnt() {
    1845             : 
    1846             :   // TBD:
    1847             :   // 1. Synchronize refant changes on par axis
    1848             :   // 2. Implement minimum mean deviation algorithm
    1849             : 
    1850           0 :   if (refantlist()(0)<0) 
    1851           0 :     throw(AipsError("No refant specified."));
    1852             : 
    1853           0 :   Int nUserRefant=refantlist().nelements();
    1854             : 
    1855             :   // Get the preferred refant names from the MS
    1856           0 :   String refantName(msmc().antennaName(refantlist()(0)));
    1857           0 :   if (nUserRefant>1) {
    1858           0 :     refantName+=" (";
    1859           0 :     for (Int i=1;i<nUserRefant;++i) {
    1860           0 :       refantName+=msmc().antennaName(refantlist()(i));
    1861           0 :       if (i<nUserRefant-1) refantName+=",";
    1862             :     }
    1863           0 :     refantName+=")";
    1864             :   }
    1865             : 
    1866             :   logSink() << "Applying refant: " << refantName
    1867           0 :             << " refantmode = " << refantmode();
    1868           0 :   if (refantmode()=="flex")
    1869           0 :     logSink() << " (hold alternate refants' phase constant) when refant flagged";
    1870           0 :   if (refantmode()=="strict")
    1871           0 :     logSink() << " (flag all antennas when refant flagged)";
    1872           0 :   logSink() << LogIO::POST;
    1873             : 
    1874             :   // Generate a prioritized refant choice list
    1875             :   //  The first entry in this list is the user's primary refant,
    1876             :   //   the second entry is the refant used on the previous interval,
    1877             :   //   and the rest is a prioritized list of alternate refants,
    1878             :   //   starting with the user's secondary (if provided) refants,
    1879             :   //   followed by the rest of the array, in distance order.   This
    1880             :   //   makes the priorities correct all the time, and prevents
    1881             :   //   a semi-stochastic alternation (by preferring the last-used
    1882             :   //   alternate, even if nominally higher-priority refants become
    1883             :   //   available)
    1884             : 
    1885             : 
    1886             :   // Extract antenna positions
    1887           0 :   Matrix<Double> xyz;
    1888           0 :   if (msName()!="<noms>") {
    1889           0 :     MeasurementSet ms(msName());
    1890           0 :     MSAntennaColumns msant(ms.antenna());
    1891           0 :     msant.position().getColumn(xyz);
    1892           0 :   }
    1893             :   else {
    1894             :     // TBD RO*
    1895           0 :     CTColumns ctcol(*ct_);
    1896           0 :     CTAntennaColumns& antcol(ctcol.antenna());
    1897           0 :     antcol.position().getColumn(xyz);
    1898           0 :   }
    1899             : 
    1900             :   // Calculate (squared) antenna distances, relative
    1901             :   //  to last preferred antenna
    1902           0 :   Vector<Double> dist2(xyz.ncolumn(),0.0);
    1903           0 :   for (Int i=0;i<3;++i) {
    1904           0 :     Vector<Double> row=xyz.row(i);
    1905           0 :     row-=row(refantlist()(nUserRefant-1));
    1906           0 :     dist2+=square(row);
    1907           0 :   }
    1908             :   // Move preferred antennas to a large distance
    1909           0 :   for (Int i=0;i<nUserRefant;++i)
    1910           0 :     dist2(refantlist()(i))=DBL_MAX;
    1911             : 
    1912             :   // Generated sorted index
    1913           0 :   Vector<uInt> ord;
    1914           0 :   genSort(ord,dist2);
    1915             : 
    1916             :   // Assemble the whole choices list
    1917           0 :   Int nchoices=nUserRefant+1+ord.nelements();
    1918           0 :   Vector<Int> refantchoices(nchoices,0);
    1919           0 :   Vector<Int> r(refantchoices(IPosition(1,nUserRefant+1),IPosition(1,refantchoices.nelements()-1)));
    1920           0 :   convertArray(r,ord);
    1921             : 
    1922             :   // set first two to primary preferred refant
    1923           0 :   refantchoices(0)=refantchoices(1)=refantlist()(0);
    1924             : 
    1925             :   // set user's secondary refants (if any)
    1926           0 :   if (nUserRefant>1) 
    1927           0 :     refantchoices(IPosition(1,2),IPosition(1,nUserRefant))=
    1928           0 :       refantlist()(IPosition(1,1),IPosition(1,nUserRefant-1));
    1929             : 
    1930             :   //cout << "refantchoices = " << refantchoices << endl;
    1931             : 
    1932             : 
    1933           0 :   if (refantmode()=="strict") {
    1934           0 :     nchoices=1;
    1935           0 :     refantchoices.resize(1,True);
    1936             :   }
    1937             : 
    1938           0 :   Vector<Int> nPol(nSpw(),2);  // TBD:or 1, if data was single pol
    1939             : 
    1940           0 :   if (nPar()==8) {
    1941             :     // Verify that 2nd poln has unflagged solutions, PER SPW
    1942           0 :     ROCTMainColumns ctmc(*ct_);
    1943             : 
    1944           0 :     Block<String> cols(1);
    1945           0 :     cols[0]="SPECTRAL_WINDOW_ID";
    1946           0 :     CTIter ctiter(*ct_,cols);
    1947           0 :     Cube<Bool> fl;
    1948             : 
    1949           0 :     while (!ctiter.pastEnd()) {
    1950             : 
    1951           0 :       Int ispw=ctiter.thisSpw();
    1952           0 :       fl.assign(ctiter.flag());
    1953             : 
    1954           0 :       IPosition blc(3,0,0,0), trc(fl.shape());
    1955           0 :       trc-=1; blc(0)=nPar()/2;
    1956             :       
    1957             :       //      cout << "ispw = " << ispw << " nfalse(fl(1,:,:)) = " << nfalse(fl(blc,trc)) << endl;
    1958             :       
    1959             :       // If there are no unflagged solutions in 2nd pol, 
    1960             :       //   avoid it in refant calculations
    1961           0 :       if (nfalse(fl(blc,trc))==0)
    1962           0 :         nPol(ispw)=1;
    1963             : 
    1964           0 :       ctiter.next();      
    1965           0 :     }
    1966           0 :   }
    1967             :   //  cout << "nPol = " << nPol << endl;
    1968             : 
    1969           0 :   Bool usedaltrefant(false);
    1970           0 :   Int currrefant(refantchoices(0)), lastrefant(-1);
    1971             : 
    1972           0 :   Block<String> cols(2);
    1973           0 :   cols[0]="SPECTRAL_WINDOW_ID";
    1974           0 :   cols[1]="TIME";
    1975           0 :   CTIter ctiter(*ct_,cols);
    1976             : 
    1977             :   // Arrays to hold per-timestamp solutions
    1978           0 :   Cube<Float> solA, solB;
    1979           0 :   Cube<Bool> flA, flB;
    1980           0 :   Vector<Int> ant1A, ant1B, ant2B;
    1981           0 :   Matrix<Complex> refPhsr;  // the reference phasor [npol,nchan] 
    1982           0 :   Int lastspw(-1);
    1983           0 :   Bool first(true);
    1984           0 :   while (!ctiter.pastEnd()) {
    1985           0 :     Int ispw=ctiter.thisSpw();
    1986           0 :     if (ispw!=lastspw) first=true;  // spw changed, start over
    1987             : 
    1988             :     // Read in the current sol, fl, ant1:
    1989           0 :     solB.assign(ctiter.fparam());
    1990           0 :     flB.assign(ctiter.flag());
    1991           0 :     ant1B.assign(ctiter.antenna1());
    1992           0 :     ant2B.assign(ctiter.antenna2()); 
    1993             : 
    1994             :     // First time thru, 'previous' solution same as 'current'
    1995           0 :     if (first) {
    1996           0 :       solA.reference(solB);
    1997           0 :       flA.reference(flB);
    1998           0 :       ant1A.reference(ant1B);
    1999             :     }
    2000           0 :     IPosition shB(solB.shape());
    2001           0 :     IPosition shA(solA.shape());
    2002             : 
    2003             :     // Find a good refant at this time
    2004             :     //  A good refant is one that is unflagged in all polarizations
    2005             :     //     in the current(B) and previous(A) intervals (so they can be connected)
    2006           0 :     Int irefA(0),irefB(0);  // index on 3rd axis of solution arrays
    2007           0 :     Int ichoice(0);  // index in refantchoicelist
    2008           0 :     Bool found(false);
    2009           0 :     IPosition blcA(3,0,0,0),trcA(shA),blcB(3,0,0,0),trcB(shB);
    2010           0 :     trcA-=1; trcA(0)=trcA(2)=0;
    2011           0 :     trcB-=1; trcB(0)=trcB(2)=0;
    2012           0 :     ichoice=0;
    2013           0 :     while (!found && ichoice<nchoices) { 
    2014             :       // Find index of current refant choice
    2015           0 :       irefA=irefB=0;
    2016           0 :       while (ant1A(irefA)!=refantchoices(ichoice) && irefA<shA(2)) ++irefA;
    2017           0 :       while (ant1B(irefB)!=refantchoices(ichoice) && irefB<shB(2)) ++irefB;
    2018             : 
    2019           0 :       if (irefA<shA(2) && irefB<shB(2)) {
    2020             : 
    2021             :         //      cout << " Trial irefA,irefB: " << irefA << "," << irefB 
    2022             :         //           << "   Ants=" << ant1A(irefA) << "," << ant1B(irefB) << endl;
    2023             : 
    2024           0 :         blcA(2)=trcA(2)=irefA;
    2025           0 :         blcB(2)=trcB(2)=irefB;
    2026           0 :         found=true;  // maybe
    2027           0 :         for (Int ipol=0;ipol<nPol(ispw);++ipol) {
    2028           0 :           blcA(0)=blcB(0)=ipol*nPar()/2;
    2029           0 :           trcA(0)=trcB(0)=(ipol+1)*nPar()/2-1;
    2030           0 :           found &= (nfalse(flA(blcA,trcA))>0);  // previous interval
    2031           0 :           found &= (nfalse(flB(blcB,trcB))>0);  // current interval
    2032             :         } 
    2033             :       }
    2034             :       else
    2035             :         // irefA or irefB out-of-range
    2036           0 :         found=false;  // Just to be sure
    2037             : 
    2038           0 :       if (!found) ++ichoice;  // try next choice next round
    2039             : 
    2040             :     }
    2041             : 
    2042           0 :     if (found) {
    2043             :       // at this point, irefA/irefB point to a good refant
    2044             :       
    2045             :       // Keep track
    2046           0 :       usedaltrefant|=(ichoice>0);
    2047           0 :       currrefant=refantchoices(ichoice);
    2048           0 :       refantchoices(1)=currrefant;  // 2nd priorty next time
    2049             : 
    2050             :       //      cout << " currrefant = " << currrefant << " (" << ichoice << ")" << endl;
    2051             : 
    2052             :       //      cout << " Final irefA,irefB: " << irefA << "," << irefB 
    2053             :       //           << "   Ants=" << ant1A(irefA) << "," << ant1B(irefB) << endl;
    2054             : 
    2055             : 
    2056             :       // Only report if using an alternate refant
    2057           0 :       if (currrefant!=lastrefant && ichoice>0) {
    2058             :         logSink() 
    2059             :           << "At " 
    2060           0 :           << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7) 
    2061             :           << " ("
    2062             :           << "Spw=" << ctiter.thisSpw()
    2063             :           << ", Fld=" << ctiter.thisField()
    2064             :           << ")"
    2065           0 :           << ", using refant " << msmc().antennaName(currrefant)
    2066             :           << " (id=" << currrefant 
    2067             :           << ")" << " (alternate)"
    2068           0 :           << LogIO::POST;
    2069             :       }  
    2070             : 
    2071             :       // Form reference phasor [nPar,nChan]
    2072           0 :       Matrix<Float> rA,rB;
    2073           0 :       Matrix<Bool> rflA,rflB;
    2074           0 :       rB.assign(solB.xyPlane(irefB));
    2075           0 :       rflB.assign(flB.xyPlane(irefB));
    2076             :       
    2077           0 :       if (!first) {
    2078             :         // Get and condition previous phasor for the current refant
    2079           0 :         rA.assign(solA.xyPlane(irefA));
    2080           0 :         rflA.assign(flA.xyPlane(irefA));
    2081           0 :         rB-=rA;
    2082             : 
    2083             :         // Accumulate flags
    2084           0 :         rflB&=rflA;
    2085             :       }
    2086             :       
    2087             :       //      cout << " rB = " << rB << endl;
    2088             :       //      cout << boolalpha << " rflB = " << rflB << endl;
    2089             :       // TBD: fillChanGaps?
    2090             :       
    2091             :       // Now apply reference phasor to all antennas
    2092           0 :       Matrix<Float> thissol;
    2093           0 :       for (Int iant=0;iant<shB(2);++iant) {
    2094           0 :         thissol.reference(solB.xyPlane(iant));
    2095           0 :         thissol-=rB;
    2096             :       }
    2097             :       
    2098             :       // Set refant, so we can put it back
    2099           0 :       ant2B=currrefant;
    2100             :       
    2101             :       // put back referenced solutions
    2102           0 :       ctiter.setfparam(solB);
    2103           0 :       ctiter.setantenna2(ant2B);
    2104             : 
    2105             :       // Next time thru, solB is previous
    2106           0 :       solA.reference(solB);
    2107           0 :       flA.reference(flB);
    2108           0 :       ant1A.reference(ant1B);
    2109           0 :       solB.resize();  // (break references)
    2110           0 :       flB.resize();
    2111           0 :       ant1B.resize();
    2112             :         
    2113           0 :       lastrefant=currrefant;
    2114           0 :       first=false;  // avoid first-pass stuff from now on
    2115             :       
    2116           0 :     } // found
    2117             :     else {
    2118             :       logSink() 
    2119             :         << "At " 
    2120           0 :         << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7) 
    2121             :         << " ("
    2122             :         << "Spw=" << ctiter.thisSpw()
    2123             :         << ", Fld=" << ctiter.thisField()
    2124             :         << ")"
    2125             :         << ", refant (id=" << currrefant 
    2126             :         << ") was flagged; flagging all antennas strictly."
    2127           0 :         << LogIO::POST;
    2128             :       // Flag all solutions in this interval
    2129           0 :       flB.set(True);
    2130           0 :       ctiter.setflag(flB);
    2131           0 :       if (ichoice == nchoices){
    2132             :           logSink() << LogIO::WARN
    2133             :           << "From time: "
    2134           0 :           << MVTime(ctiter.thisTime()/C::day).string(MVTime::YMD,7)
    2135             :           << "in Spw: "
    2136             :           << ctiter.thisSpw()
    2137             :           << " refant list exhausted, flagging all solutions"
    2138           0 :           << LogIO::POST; 
    2139             :       }
    2140             :     }
    2141             : 
    2142             :     // advance to the next interval
    2143           0 :     lastspw=ispw;
    2144           0 :     ctiter.next();
    2145           0 :   }
    2146             : 
    2147           0 :   if (usedaltrefant)
    2148             :     logSink() << LogIO::NORMAL
    2149             :               << " NB: An alternate refant was used at least once to maintain" << endl
    2150             :               << "  phase continuity where the user's preferred refant drops out." << endl
    2151             :               << "  Alternate refants are held constant in phase (_not_ zeroed)" << endl
    2152             :               << "  during these periods, and the preferred refant may return at" << endl
    2153             :               << "  a non-zero phase.  This is generally harmless."
    2154           0 :               << LogIO::POST;
    2155             : 
    2156           0 :   return;
    2157             : 
    2158           0 : }
    2159             : 
    2160             : } //# NAMESPACE CASA - END
    2161             : 
    2162             : 
    2163             : /*
    2164             : Example of use in at Python level:
    2165             : 
    2166             : fringefit(vis="n14c2.ms", caltable="fail.fj", field="",spw="1",intent="",
    2167             :           selectdata=True, timerange="", antenna="", scan="5", observation="",
    2168             :           msselect="", solint="inf", refant="EF", minsnr=3.0, append=False,
    2169             :           gaintable=['n14c2.gcal'], parang=False)
    2170             : */
    2171             : 

Generated by: LCOV version 1.16