LCOV - code coverage report
Current view: top level - msvis/MSVis - VBContinuumSubtractor.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 223 297 75.1 %
Date: 2024-12-11 20:54:31 Functions: 13 15 86.7 %

          Line data    Source code
       1             : //# VBContinuumSubtractor.cc:  Subtract continuum from spectral line data
       2             : //# Copyright (C) 2004
       3             : //# Associated Universities, Inc. Washington DC, USA.
       4             : //#
       5             : //# This library is free software; you can redistribute it and/or modify it
       6             : //# under the terms of the GNU Library General Public License as published by
       7             : //# the Free Software Foundation; either version 2 of the License, or (at your
       8             : //# option) any later version.
       9             : //#
      10             : //# This library is distributed in the hope that it will be useful, but WITHOUT
      11             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
      13             : //# License for more details.
      14             : //#
      15             : //# You should have received a copy of the GNU Library General Public License
      16             : //# along with this library; if not, write to the Free Software Foundation,
      17             : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
      18             : //#
      19             : //# Correspondence concerning AIPS++ should be addressed as follows:
      20             : //#        Internet email: casa-feedback@nrao.edu.
      21             : //#        Postal address: AIPS++ Project Office
      22             : //#                        National Radio Astronomy Observatory
      23             : //#                        520 Edgemont Road
      24             : //#                        Charlottesville, VA 22903-2475 USA
      25             : //#
      26             : //# $Id$
      27             : //#
      28             : //#include <casa/Arrays/ArrayLogical.h>
      29             : //#include <casa/Arrays/ArrayMath.h>
      30             : //#include <casa/Arrays/ArrayUtil.h>
      31             : #include <casacore/casa/Arrays/Cube.h>
      32             : //#include <casa/Arrays/MaskedArray.h>
      33             : //#include <casa/Arrays/MaskArrMath.h>
      34             : //#include <casa/Containers/Record.h>
      35             : //#include <casa/Containers/RecordFieldId.h>
      36             : //#include <casa/Exceptions/Error.h>
      37             : #include <casacore/casa/Logging/LogIO.h>
      38             : //#include <casa/Quanta/MVTime.h>
      39             : //#include <casa/Quanta/QuantumHolder.h>
      40             : #include <casacore/ms/MeasurementSets/MeasurementSet.h>
      41             : #include <casacore/ms/MeasurementSets/MSColumns.h>
      42             : #include <msvis/MSVis/VBContinuumSubtractor.h>
      43             : #include <msvis/MSVis/VisBuffGroupAcc.h>
      44             : #include <msvis/MSVis/VisBuffer.h>
      45             : #include <casacore/scimath/Fitting/LinearFitSVD.h>
      46             : #include <casacore/scimath/Functionals/Polynomial.h>
      47             : 
      48             : #include <msvis/MSVis/VisBuffer2.h>
      49             : 
      50             : //#include <algorithm>
      51             : 
      52             : using namespace casacore;
      53             : using namespace casa::vi;
      54             : 
      55             : namespace casa { //# NAMESPACE CASA - BEGIN
      56             : 
      57         152 : VBContinuumSubtractor::VBContinuumSubtractor():
      58         152 :   fitorder_p(-1),
      59         152 :   lofreq_p(-1.0),
      60         152 :   hifreq_p(-1.0),
      61         152 :   midfreq_p(-1.0),
      62         152 :   freqscale_p(1.0),
      63         152 :   maxAnt_p(-1),
      64         152 :   nHashes_p(0),
      65         152 :   ncorr_p(0),
      66         152 :   totnumchan_p(0),
      67         152 :   tvi_debug(False)
      68             : {
      69         152 : }
      70             : 
      71           0 : VBContinuumSubtractor::VBContinuumSubtractor(const Double lofreq,
      72           0 :                                              const Double hifreq):
      73           0 :   fitorder_p(-1),
      74           0 :   lofreq_p(lofreq),
      75           0 :   hifreq_p(hifreq),
      76           0 :   midfreq_p(-1.0),
      77           0 :   freqscale_p(1.0),
      78           0 :   maxAnt_p(-1),
      79           0 :   nHashes_p(0),
      80           0 :   ncorr_p(0),
      81           0 :   totnumchan_p(0),
      82           0 :   tvi_debug(False)
      83             : {
      84           0 :   midfreq_p = 0.5 * (lofreq + hifreq);
      85           0 :   freqscale_p = calcFreqScale();
      86           0 : }
      87             : 
      88           0 : void VBContinuumSubtractor::resize(Cube<Complex>& coeffs,
      89             :                                    Cube<Bool>& coeffsOK) const
      90             : {
      91           0 :   if(maxAnt_p < 0 || fitorder_p < 0 || ncorr_p < 1)
      92           0 :     throw(AipsError("The fit order, # of corrs, and/or max antenna # must be set."));
      93             : 
      94             :   // An nth order polynomial has n + 1 coefficients.
      95           0 :   coeffs.resize(ncorr_p, fitorder_p + 1, nHashes_p);
      96             :   // Calibrater wants coeffsOK to be a Cube, even though a Matrix would do for
      97             :   // VBContinuumSubtractor.  Unfortunately problems arise (worse, quietly) in
      98             :   // SolvableVisCal::keep() and store() if one tries to get away with
      99             :   //coeffsOK.resize(ncorr_p, 1, nHashes_p);
     100           0 :   coeffsOK.resize(ncorr_p, fitorder_p + 1, nHashes_p);
     101           0 : }
     102             : 
     103         150 : void VBContinuumSubtractor::init(const IPosition& shp, const uInt maxAnt,
     104             :                                  const uInt totnumchan,
     105             :                                  const Double lof, const Double hif)
     106             : {
     107         150 :   ncorr_p    = shp[0];
     108         150 :   fitorder_p = shp[1] - 1;
     109             : 
     110             :   //// Going from the number of baselines to the number of antennas is a little
     111             :   //// backwards, but so is this function.
     112             :   // uInt nAnt = round((-1 + sqrt(1 + 8 * shp[2])) / 2);
     113         150 :   setNAnt(maxAnt + 1);
     114             :   
     115         150 :   totnumchan_p = totnumchan;
     116         150 :   setScalingFreqs(lof, hif);
     117         150 : }
     118             : 
     119           2 : Bool VBContinuumSubtractor::initFromVBGA(VisBuffGroupAcc& vbga)
     120             : {
     121           2 :   Bool retval = true;
     122             : 
     123           2 :   if(vbga.nBuf() > 0){
     124           2 :     ncorr_p = vbga(0).nCorr();
     125           2 :     setNAnt(vbga.nAnt());
     126             :   
     127             :     // Count the total number of channels, and get the minimum and maximum
     128             :     // frequencies for scaling.
     129           2 :     totnumchan_p = 0;
     130           2 :     hifreq_p = -1.0;
     131           2 :     lofreq_p = DBL_MAX;
     132          21 :     for(Int ibuf = 0; ibuf < vbga.nBuf(); ++ibuf){
     133          19 :       VisBuffer& vb(vbga(ibuf));
     134             : 
     135          19 :       totnumchan_p += vb.nChannel();
     136          19 :       getMinMaxFreq(vb, lofreq_p, hifreq_p, false);
     137             :     }
     138           2 :     midfreq_p = 0.5 * (lofreq_p + hifreq_p);
     139           2 :     freqscale_p = calcFreqScale();
     140             :   }
     141             :   else
     142           0 :     retval = false;
     143           2 :   return retval;
     144             : }
     145             : 
     146         152 : VBContinuumSubtractor::~VBContinuumSubtractor()
     147         152 : {}
     148             : 
     149          39 : void VBContinuumSubtractor::fit(VisBuffGroupAcc& vbga, const Int fitorder,
     150             :                                 MS::PredefinedColumns whichcol,
     151             :                                 Cube<Complex>& coeffs,
     152             :                                 Cube<Bool>& coeffsOK, const Bool doInit,
     153             :                                 const Bool doResize,
     154             :                                 const Bool squawk)
     155             : {
     156          78 :   LogIO os(LogOrigin("VBContinuumSubtractor", "fit()", WHERE));
     157             : 
     158             :   // jagonzal: Debug code
     159             :   /*
     160             :   uInt row_debug = 0;
     161             :   uInt corr_debug = 0;
     162             :   */
     163             : 
     164          39 :   fitorder_p = fitorder;
     165             : 
     166          39 :   if(!(whichcol == MS::DATA || whichcol == MS::MODEL_DATA ||
     167             :        whichcol == MS::CORRECTED_DATA)){
     168           0 :     if(squawk)
     169             :       os << LogIO::SEVERE
     170             :          << MS::columnName(whichcol) << " is not supported.\n"
     171             :          << MS::columnName(MS::DATA) << " will be used instead."
     172           0 :          << LogIO::POST;
     173           0 :     whichcol = MS::DATA;
     174             :   }
     175             : 
     176          39 :   if(doInit)
     177           0 :     initFromVBGA(vbga);
     178             : 
     179          39 :   if(maxAnt_p < 0 || fitorder_p < 0 || ncorr_p < 1 || totnumchan_p < 1
     180          39 :      || lofreq_p < 0.0 || hifreq_p < 0.0)
     181           0 :     throw(AipsError("The continuum fitter must first be initialized."));
     182             : 
     183          39 :   if(doResize)
     184           0 :     resize(coeffs, coeffsOK);
     185             : 
     186          39 :   if(!checkSize(coeffs, coeffsOK))
     187           0 :     throw(AipsError("Shape mismatch in the coefficient storage cubes."));
     188             : 
     189             :   // Make the estimate
     190          39 :   LinearFitSVD<Float> fitter;
     191          39 :   fitter.asWeight(true);        // Makes the "sigma" arg = w = 1/sig**2
     192             : 
     193          39 :   coeffsOK.set(false);
     194             : 
     195             :   // Translate vbga to arrays for use by LinearFitSVD.
     196             : 
     197             :   // The fitorder will actually be clamped on a baseline-by-baseline basis
     198             :   // because of flagging, but a summary note is in order here.
     199          39 :   if(static_cast<Int>(totnumchan_p) < fitorder_p)
     200             :     os << LogIO::WARN
     201             :        << "fitorder = " << fitorder_p
     202             :        << ", but only " << totnumchan_p << " channels were selected.\n"
     203             :        << "The polynomial order will be lowered accordingly."
     204           0 :        << LogIO::POST;
     205             :   // Scale frequencies to [-1, 1].
     206          39 :   midfreq_p = 0.5 * (lofreq_p + hifreq_p);
     207          39 :   freqscale_p = calcFreqScale();
     208          39 :   Vector<Float> freqs(totnumchan_p);
     209          39 :   uInt totchan = 0;
     210         163 :   for(Int ibuf = 0; ibuf < vbga.nBuf(); ++ibuf){
     211         124 :     VisBuffer& vb(vbga(ibuf));
     212         124 :     Vector<Double> freq(vb.frequency());
     213         124 :     uInt nchan = vb.nChannel();
     214             : 
     215       11560 :     for(uInt c = 0; c < nchan; ++c){
     216       11436 :       freqs[totchan] = freqscale_p * (freq[c] - midfreq_p);
     217       11436 :       ++totchan;
     218             :     }
     219         124 :   }
     220             : 
     221          39 :   Vector<Float> wt(totnumchan_p);
     222          39 :   Vector<Float> unflaggedfreqs(totnumchan_p);
     223          39 :   Vector<Complex> vizzes(totnumchan_p);
     224          39 :   Vector<Float> floatvs(totnumchan_p);
     225          39 :   Vector<Float> realsolution(fitorder_p + 1);
     226          39 :   Vector<Float> imagsolution(fitorder_p + 1);
     227             : 
     228         112 :   for(uInt corrind = 0; corrind < ncorr_p; ++corrind){
     229        1273 :     for(uInt blind = 0; blind < nHashes_p; ++blind){
     230        1200 :       uInt totchan = 0;
     231        1200 :       uInt totunflaggedchan = 0;
     232             : 
     233             :       // Fill wt, unflaggedfreqs, and vizzes with the baseline's values for
     234             :       // all channels being used in the fit.
     235        1200 :       wt.resize(totnumchan_p);
     236        1200 :       vizzes.resize(totnumchan_p);
     237        1200 :       unflaggedfreqs.resize(totnumchan_p);
     238             : 
     239        5460 :       for(Int ibuf = 0; ibuf < vbga.nBuf(); ++ibuf){
     240        4260 :         VisBuffer& vb(vbga(ibuf));
     241        4260 :         uInt nchan = vb.nChannel();
     242             :         //Int vbrow = vbga.outToInRow(ibuf, false)[blind];
     243             : 
     244        4260 :         if(!vb.flagRow()[blind]){
     245        2570 :           Cube<Complex>& viscube(vb.dataCube(whichcol));
     246             :           Float w;
     247             : 
     248             :           // 2/24/2011: VisBuffer doesn't (yet) have sigmaSpectrum, and I have
     249             :           // never seen it in an MS anyway.  Settle for 1/sqrt(weightSpectrum)
     250             :           // if it is available or sigmaMat otherwise.
     251             :           //const Bool haveWS = vb.existsWeightSpectrum();
     252             :           // 5/13/2011: Sigh.  VisBuffAccumulator doesn't even handle
     253             :           // WeightSpectrum, let alone sigma.
     254             :           //const Bool haveWS = false;
     255             : 
     256             :           //if(!haveWS) // w is needed either way, in case ws == 0.0.
     257        2570 :           w = vb.weightMat()(corrind, blind);
     258             : 
     259             :           // w needs a sanity check, because a VisBuffer from vbga is not
     260             :           // necessarily still attached to the MS and sigmaMat() is not one
     261             :           // of the accumulated quantities.  This caused problems for
     262             :           // the last integration in CAS-3135.  checkVisIter() didn't do the
     263             :           // trick in that case.  Fortunately w isn't all that important; if
     264             :           // all the channels have the same weight the only consequence of
     265             :           // setting w to 1 is that the estimated errors (which we don't yet
     266             :           // use) will be wrong.
     267             :           //
     268             :           // 5e-45 ended up getting squared in the fitter and producing a NaN.
     269        2570 :           if(isnan(w) || w < 1.0e-20 || w > 1.0e20)
     270           0 :             w = 1.0;  // Emit a warning?
     271             : 
     272             :           Bool chanFlag;
     273      241910 :           for(uInt c = 0; c < nchan; ++c){
     274             :             // AAARRGGGHHH!!  With Calibrater you have to use vb.flag(), not
     275             :             // flagCube(), to get the channel selection!
     276             :             //if(!vb.flagCube()(corrind, c, vbrow)){0
     277      239340 :                   if (!tvi_debug)
     278             :                   {
     279      239340 :                           chanFlag = vb.flag()(c, blind);
     280             :                   }
     281             :                   else
     282             :                   {
     283             :                           // jagonzal: Use flagCube, meaning that each correlation is fit
     284             :                           // independently even if the other correlations are fully flagged
     285           0 :                           chanFlag = vb.flagCube()(corrind, c, blind);
     286             :                           // jagonzal: Apparently line-free chan mask is contained in vb.flag()
     287           0 :                           chanFlag = vb.flagCube()(corrind, c, blind) |  vb.flag()(c, blind);
     288             :                   }
     289             :             //if(!vb.flag()(c, blind)){
     290             :                 // if(!vb.flagCube()(corrind, c, blind)){
     291      239340 :                   if (!chanFlag) {
     292      227391 :               unflaggedfreqs[totunflaggedchan] = freqs[totchan];
     293             :               // if(haveWS){
     294             :               //   Double ws = vb.weightSpectrum()(corrind, c, vbrow);
     295             : 
     296             :               //   wt[totunflaggedchan] = ws;
     297             :               // }
     298             :               // else
     299      227391 :                 wt[totunflaggedchan] = w / nchan;
     300      227391 :               vizzes[totunflaggedchan] = viscube(corrind, c, blind);
     301      227391 :               ++totunflaggedchan;
     302             :             }
     303      239340 :             ++totchan;
     304             :           }
     305             :         }
     306             :         else
     307        1690 :           totchan += nchan;
     308             :       }
     309             : 
     310             :       // jagonzal: Debug code
     311             :       /*
     312             :       if (tvi_debug)
     313             :       {
     314             :           VisBuffer& vb(vbga(0));
     315             :           uInt rowId = vb.rowIds()[blind];
     316             :           if (rowId == row_debug and corrind == corr_debug and totunflaggedchan <= 0)
     317             :           {
     318             :                 os << LogIO::WARN << "All channels flagged" << LogIO::POST;
     319             :           }
     320             :       }
     321             :       */
     322             : 
     323        1200 :       if(totunflaggedchan > 0){                 // OK, try a fit.
     324             :         // Truncate the Vectors.
     325         785 :         wt.resize(totunflaggedchan, true);
     326             :         //vizzes.resize(totunflaggedchan, true);
     327         785 :         floatvs.resize(totunflaggedchan);
     328         785 :         unflaggedfreqs.resize(totunflaggedchan, true);
     329             : 
     330             :         // perform least-squares fit of a polynomial.
     331             :         // Don't try to solve for more coefficients than valid channels.
     332         785 :         Int locFitOrd = min(fitorder_p, static_cast<Int>(totunflaggedchan) - 1);
     333             : 
     334             :         // if(locFitOrd < 1)
     335             :         //   os << LogIO::DEBUG1
     336             :         //      << "locFitOrd = " << locFitOrd
     337             :         //      << LogIO::POST;
     338             : 
     339         785 :         Polynomial<AutoDiff<Float> > pnom(locFitOrd);
     340             : 
     341             :         // The way LinearFit is templated, "y" can be Complex, but at the cost
     342             :         // of "x" being Complex as well, and worse, wt too.  It is better to
     343             :         // separately fit the reals and imags.
     344             :         // Do reals.
     345        4395 :         for(Int ordind = 0; ordind <= locFitOrd; ++ordind)       // Note <=.
     346        3610 :           pnom.setCoefficient(ordind, 1.0);
     347             : 
     348      228176 :         for(uInt c = 0; c < totunflaggedchan; ++c)
     349      227391 :           floatvs[c] = vizzes[c].real();
     350             : 
     351         785 :         fitter.setFunction(pnom);
     352         785 :         realsolution(Slice(0,locFitOrd+1,1)) = fitter.fit(unflaggedfreqs, floatvs, wt);
     353             : 
     354             :         // jagonzal: Debug code
     355             :         /*
     356             :         if (tvi_debug)
     357             :         {
     358             :             VisBuffer& vb(vbga(0));
     359             :             uInt rowId = vb.rowIds()[blind];
     360             :             if (rowId == row_debug and corrind == corr_debug)
     361             :             {
     362             :                 os << "locFitOrd=" << locFitOrd << LogIO::POST;
     363             :                 os << "flag=" << vb.flag().column(blind) << LogIO::POST;
     364             :                 os << "flagCube=" << vb.flagCube().xyPlane(blind).row(corrind) << LogIO::POST;
     365             :                         os << "unflaggedfreqs=" << unflaggedfreqs << LogIO::POST;
     366             :                         os << "wt=" << wt<< LogIO::POST;
     367             :                         os << "real floatvs=" << floatvs << LogIO::POST;
     368             :                         os << "real realsolution=" << realsolution << LogIO::POST;
     369             :             }
     370             :         }
     371             :         */
     372             : 
     373             :         // if(isnan(realsolution[0])){
     374             :         //   os << LogIO::DEBUG1 << "NaN found." << LogIO::POST;
     375             :         //   for(uInt c = 0; c < totunflaggedchan; ++c){
     376             :         //     if(isnan(unflaggedfreqs[c]))
     377             :         //       os << LogIO::DEBUG1
     378             :         //          << "unflaggedfreqs[" << c << "] is a NaN."
     379             :         //          << LogIO::POST;
     380             :         //     if(isnan(floatvs[c]))
     381             :         //       os << LogIO::DEBUG1
     382             :         //          << "floatvs[" << c << "] is a NaN."
     383             :         //          << LogIO::POST;
     384             :         //     if(isnan(wt[c]))
     385             :         //       os << LogIO::DEBUG1
     386             :         //          << "wt[" << c << "] is a NaN."
     387             :         //          << LogIO::POST;
     388             :         //     else if(wt[c] <= 0.0)
     389             :         //       os << LogIO::DEBUG1
     390             :         //          << "wt[" << c << "] = " << wt[c]
     391             :         //          << LogIO::POST;
     392             :         //   }
     393             :         // }
     394             : 
     395             :         // Do imags.
     396        4395 :         for(Int ordind = 0; ordind <= locFitOrd; ++ordind)       // Note <=.
     397        3610 :           pnom.setCoefficient(ordind, 1.0);
     398             : 
     399      228176 :         for(uInt c = 0; c < totunflaggedchan; ++c)
     400      227391 :           floatvs[c] = vizzes[c].imag();
     401             : 
     402         785 :         fitter.setFunction(pnom);
     403         785 :         imagsolution(Slice(0,locFitOrd+1,1)) = fitter.fit(unflaggedfreqs, floatvs, wt);
     404             : 
     405             :         // jagonzal: Debug code
     406             :         /*
     407             :         if (tvi_debug)
     408             :         {
     409             :             VisBuffer& vb(vbga(0));
     410             :             uInt rowId = vb.rowIds()[blind];
     411             :             if (rowId == row_debug and corrind == corr_debug)
     412             :             {
     413             :                 os << "imag floatvs=" << floatvs << LogIO::POST;
     414             :                         os << "imag solution=" << imagsolution << LogIO::POST;
     415             :             }
     416             :         }
     417             :         */
     418             :           
     419             : 
     420        4395 :         for(Int ordind = 0; ordind <= locFitOrd; ++ordind){      // Note <=.
     421        3610 :           coeffs(corrind, ordind, blind) = Complex(realsolution[ordind],
     422        3610 :                                                    imagsolution[ordind]);
     423        3610 :           coeffsOK(corrind, ordind, blind) = true;
     424             :         }
     425             : 
     426             :         // Pad remaining orders (if any) with 0.0.  Note <=.
     427         785 :         for(Int ordind = locFitOrd + 1; ordind <= fitorder_p; ++ordind){
     428           0 :           coeffs(corrind, ordind, blind) = 0.0;
     429             : 
     430             :           // Since coeffs(corrind, ordind, blind) == 0, it isn't necessary to
     431             :           // pay attention to coeffsOK(corrind, ordind, blind) (especially?) if
     432             :           // ordind > 0.  But Calibrater's SolvableVisCal::keep() and store()
     433             :           // quietly go awry if you try coeffsOK.resize(ncorr_p, 1, nHashes_p);
     434           0 :           coeffsOK(corrind, ordind, blind) = false;
     435             :         }
     436             : 
     437             :         // TODO: store uncertainties
     438         785 :       }
     439             :     }
     440             :   }
     441          39 : }
     442             : 
     443          53 : void VBContinuumSubtractor::getMinMaxFreq(VisBuffer& vb,
     444             :                                           Double& minfreq,
     445             :                                           Double& maxfreq,
     446             :                                           const Bool initialize)
     447             : {
     448          53 :   const Vector<Double>& freq(vb.frequency());
     449          53 :   Int hichan = vb.nChannel() - 1;
     450          53 :   Int lochan = 0;
     451             : 
     452          53 :   if(initialize){
     453          34 :     maxfreq = -1.0;
     454          34 :     minfreq = DBL_MAX;
     455             :   }
     456             :   
     457          53 :   if(freq[hichan] < freq[lochan]){
     458          18 :     lochan = hichan;
     459          18 :     hichan = 0;
     460             :   }
     461          53 :   if(freq[hichan] > maxfreq)
     462          36 :     maxfreq = freq[hichan];
     463          53 :   if(freq[lochan] < minfreq)
     464          53 :     minfreq = freq[lochan];
     465          53 : }
     466             : 
     467          34 : Bool VBContinuumSubtractor::areFreqsInBounds(VisBuffer& vb,
     468             :                                              const Bool squawk) const
     469             : {
     470             :   Double maxfreq, minfreq;
     471             :   
     472          34 :   getMinMaxFreq(vb, minfreq, maxfreq);
     473          34 :   Bool result = minfreq >= lofreq_p && maxfreq <= hifreq_p;
     474             : 
     475          34 :   if(squawk && !result){
     476             :     // The truth was considered too alarming (CAS-1968).
     477             :     // LogIO os(LogOrigin("VBContinuumSubtractor", "areFreqsInBounds"));
     478           0 :     LogIO os(LogOrigin("VBContinuumSubtractor", "apply"));
     479             : 
     480             :     os << LogIO::WARN
     481             :        << "Extrapolating to cover [" << 1.0e-9 * minfreq << ", "
     482             :        << 1.0e-9 * maxfreq << "] (GHz).\n"
     483             :        << "The frequency range used for the continuum fit was ["
     484           0 :        << 1.0e-9 * lofreq_p << ", "
     485           0 :        << 1.0e-9 * hifreq_p << "] (GHz)."
     486           0 :        << LogIO::POST;
     487           0 :   }
     488          34 :   return result;
     489             : }
     490             : 
     491          34 : Bool VBContinuumSubtractor::doShapesMatch(VisBuffer& vb,
     492             :                                           LogIO& os, const Bool squawk) const
     493             : {
     494          34 :   Bool theydo = true;
     495             : 
     496          34 :   if(vb.nCorr() != static_cast<Int>(ncorr_p)){
     497           0 :     theydo = false;
     498           0 :     if(squawk)
     499             :       os << LogIO::SEVERE
     500           0 :          << "The supplied number of correlations, " << vb.nCorr()
     501           0 :          << ", does not match the expected " << ncorr_p
     502           0 :          << LogIO::POST;
     503             :   }
     504             :   // It's no longer the # of rows that matter but the maximum antenna #.
     505             :   // if(vb.nRow() != nrow_p){
     506          34 :   if(max(vb.antenna2()) > maxAnt_p){
     507           0 :     theydo = false;             // Should it just flag unknown baselines?
     508           0 :     if(squawk)
     509             :       os << LogIO::SEVERE
     510           0 :          << "The fit is only valid for antennas with indices <= " << maxAnt_p
     511           0 :          << LogIO::POST;
     512             :   }
     513          34 :   return theydo;
     514             : }
     515             : 
     516             : // Do the subtraction
     517          34 : Bool VBContinuumSubtractor::apply(VisBuffer& vb,
     518             :                                   const MS::PredefinedColumns whichcol,
     519             :                                   const Cube<Complex>& coeffs,
     520             :                                   const Cube<Bool>& coeffsOK,
     521             :                                   const Bool doSubtraction,
     522             :                                   const Bool squawk)
     523             : {
     524             :     using casacore::operator*;
     525             : 
     526          68 :   LogIO os(LogOrigin("VBContinuumSubtractor", "apply"));
     527             : 
     528          34 :   if(!doShapesMatch(vb, os, squawk))
     529           0 :     return false;
     530             :     
     531          34 :   Bool ok = areFreqsInBounds(vb, squawk); // A Bool might be too Boolean here.
     532          34 :   ok = true;                              // Yep, returning false for a slight
     533             :                                           // extrapolation is too harsh.
     534             : 
     535          34 :   if(!(whichcol == MS::DATA || whichcol == MS::MODEL_DATA ||
     536             :        whichcol == MS::CORRECTED_DATA)){
     537           0 :     if(squawk)
     538             :       os << LogIO::SEVERE
     539             :          << MS::columnName(whichcol) << " is not supported."
     540           0 :          << LogIO::POST;
     541           0 :     return false;
     542             :   }
     543          34 :   Cube<Complex>& viscube(vb.dataCube(whichcol));
     544             :   
     545          34 :   uInt nchan = vb.nChannel();
     546          34 :   uInt nvbrow = vb.nRow();
     547             : 
     548             :   // DEBUGGING
     549             :   // os << LogIO::DEBUG1
     550             :   //    << "nvbrow: " << nvbrow << ", nchan: " << nchan
     551             :   //    << LogIO::POST;
     552             :   // // Check coeffs.
     553             :   // for(uInt vbrow = 0; vbrow < nvbrow; ++vbrow){
     554             :   //   uInt blind = hashFunction(vb.antenna1()[vbrow],
     555             :   //                             vb.antenna2()[vbrow]);
     556             : 
     557             :   //   for(uInt corrind = 0; corrind < ncorr_p; ++corrind){
     558             :   //     if(coeffsOK(corrind, 0, blind)){
     559             :   //       Complex cont = coeffs(corrind, 0, blind);
     560             :     
     561             :   //       if(fabs(cont) < 0.001)
     562             :   //         os << LogIO::WARN
     563             :   //            << "cont(" << corrind << ", 0, " << blind << ") = "
     564             :   //            << cont
     565             :   //            << LogIO::POST;
     566             :   //     }
     567             :   //   }
     568             :   // }
     569             :   // END DEBUGGING
     570             : 
     571          34 :   Vector<Double> freqpow(fitorder_p + 1);           // sf**ordind
     572          34 :   freqpow[0] = 1.0;
     573          34 :   Vector<Double>& freq(vb.frequency());
     574             : 
     575         850 :   for(uInt c = 0; c < nchan; ++c){
     576         816 :     Double sf = freqscale_p * (freq[c] - midfreq_p);      // scaled frequency
     577             :   
     578        4080 :     for(Int ordind = 1; ordind <= fitorder_p; ++ordind)
     579        3264 :       freqpow[ordind] = sf * freqpow[ordind - 1];
     580             : 
     581        8976 :     for(uInt vbrow = 0; vbrow < nvbrow; ++vbrow){
     582        8160 :       uInt blind = hashFunction(vb.antenna1()[vbrow],
     583        8160 :                                 vb.antenna2()[vbrow]);
     584             : 
     585       24480 :       for(uInt corrind = 0; corrind < ncorr_p; ++corrind){
     586       16320 :         if(coeffsOK(corrind, 0, blind)){
     587       16320 :           Complex cont = coeffs(corrind, 0, blind);
     588             : 
     589       81600 :           for(Int ordind = 1; ordind <= fitorder_p; ++ordind)
     590       65280 :             cont += coeffs(corrind, ordind, blind) * freqpow[ordind];
     591       16320 :           if(doSubtraction)
     592           0 :             viscube(corrind, c, vbrow) -= cont;
     593             :           else
     594       16320 :             viscube(corrind, c, vbrow) = cont;            
     595             : 
     596             :           // TODO: Adjust WEIGHT_SPECTRUM (create if necessary?), WEIGHT, and
     597             :           // SIGMA.
     598             :         }
     599             :         else
     600             :         {
     601             :             // jagonzal: Do not flag data in case of not successful
     602             :             // sfit because it might be cause by the line-free mask
     603             :                 // and we may end up flagging 'good' line channels
     604           0 :             if (!tvi_debug) vb.flagCube()(corrind, c, vbrow) = true;
     605             :             // jagonzal: When returning the continuum, in case of not
     606             :             // successful fit we should return 0, not the input data
     607           0 :             if (tvi_debug and !doSubtraction) viscube(corrind, c, vbrow) = 0;
     608             :         }
     609             :         //vb.flag()(c, vbrow) = true;
     610             :       }
     611             :     }
     612             :   }
     613          34 :   return ok;
     614          34 : }
     615             : 
     616             : 
     617             : // Do the subtraction  VB2 version
     618          79 : Bool VBContinuumSubtractor::apply2(VisBuffer2& vb,
     619             :                                    Cube<Complex>& Vout,
     620             :                                    //const MS::PredefinedColumns whichcol,
     621             :                                    const Cube<Complex>& coeffs,
     622             :                                    const Cube<Bool>& coeffsOK,
     623             :                                    const Bool doSubtraction,
     624             :                                    const Bool squawk)
     625             : {
     626             :     using casacore::operator*;
     627             : 
     628         158 :   LogIO os(LogOrigin("VBContinuumSubtractor", "apply2"));
     629             : 
     630          79 :   if(!doShapesMatch(vb, os, squawk))
     631           0 :     return false;
     632             :     
     633          79 :   Bool ok = areFreqsInBounds(vb, squawk); // A Bool might be too Boolean here.
     634          79 :   ok = true;                              // Yep, returning false for a slight
     635             :                                           // extrapolation is too harsh.
     636             : 
     637          79 :   Cube<Complex>& viscube(Vout);
     638             :   
     639          79 :   Cube<Bool> fC;
     640          79 :   fC.reference(vb.flagCube());
     641             : 
     642          79 :   uInt nchan = vb.nChannels();
     643          79 :   uInt nvbrow = vb.nRows();
     644             : 
     645          79 :   Vector<Double> freqpow(fitorder_p + 1);           // sf**ordind
     646          79 :   freqpow[0] = 1.0;
     647          79 :   const Vector<Double>& freq(vb.getFrequencies(0));
     648             : 
     649        6655 :   for(uInt c = 0; c < nchan; ++c){
     650        6576 :     Double sf = freqscale_p * (freq[c] - midfreq_p);      // scaled frequency
     651             :   
     652       15600 :     for(Int ordind = 1; ordind <= fitorder_p; ++ordind)
     653        9024 :       freqpow[ordind] = sf * freqpow[ordind - 1];
     654             : 
     655      135696 :     for(uInt vbrow = 0; vbrow < nvbrow; ++vbrow){
     656      129120 :       uInt blind = hashFunction(vb.antenna1()(vbrow),
     657      129120 :                                 vb.antenna2()(vbrow));
     658             : 
     659      266400 :       for(uInt corrind = 0; corrind < ncorr_p; ++corrind){
     660      137280 :         if(coeffsOK(corrind, 0, blind)){
     661      137280 :           Complex cont = coeffs(corrind, 0, blind);
     662             : 
     663      323520 :           for(Int ordind = 1; ordind <= fitorder_p; ++ordind)
     664      186240 :             cont += coeffs(corrind, ordind, blind) * freqpow[ordind];
     665      137280 :           if(doSubtraction)
     666      137280 :             viscube(corrind, c, vbrow) -= cont;
     667             :           else
     668           0 :             viscube(corrind, c, vbrow) = cont;            
     669             : 
     670             :           // TODO: Adjust WEIGHT_SPECTRUM (create if necessary?), WEIGHT, and
     671             :           // SIGMA.
     672             :         }
     673             :         else
     674             :         {
     675             :             // jagonzal: Do not flag data in case of not successful
     676             :             // sfit because it might be cause by the line-free mask
     677             :                 // and we may end up flagging 'good' line channels
     678           0 :             if (!tvi_debug) fC(corrind, c, vbrow) = true;
     679             :             // jagonzal: When returning the continuum, in case of not
     680             :             // successful fit we should return 0, not the input data
     681           0 :             if (tvi_debug and !doSubtraction) viscube(corrind, c, vbrow) = 0;
     682             :         }
     683             :         //vb.flag()(c, vbrow) = true;
     684             :       }
     685             :     }
     686             :   }
     687          79 :   return ok;
     688          79 : }
     689             : 
     690          79 : Bool VBContinuumSubtractor::doShapesMatch(VisBuffer2& vb,
     691             :                                           LogIO& os, const Bool squawk) const
     692             : {
     693          79 :   Bool theydo = true;
     694             : 
     695          79 :   if(vb.nCorrelations() != static_cast<Int>(ncorr_p)){
     696           0 :     theydo = false;
     697           0 :     if(squawk)
     698             :       os << LogIO::SEVERE
     699           0 :          << "The supplied number of correlations, " << vb.nCorrelations()
     700           0 :          << ", does not match the expected " << ncorr_p
     701           0 :          << LogIO::POST;
     702             :   }
     703          79 :   if(max(vb.antenna2()) > maxAnt_p){
     704           0 :     theydo = false;             // Should it just flag unknown baselines?
     705           0 :     if(squawk)
     706             :       os << LogIO::SEVERE
     707           0 :          << "The fit is only valid for antennas with indices <= " << maxAnt_p
     708           0 :          << LogIO::POST;
     709             :   }
     710          79 :   return theydo;
     711             : }
     712             : 
     713          79 : void VBContinuumSubtractor::getMinMaxFreq(VisBuffer2& vb,
     714             :                                           Double& minfreq,
     715             :                                           Double& maxfreq,
     716             :                                           const Bool initialize)
     717             : {
     718          79 :   const Vector<Double>& freq(vb.getFrequencies(0));  // row=0, assumed uniform in VB2
     719          79 :   Int hichan = vb.nChannels() - 1;
     720          79 :   Int lochan = 0;
     721             : 
     722          79 :   if(initialize){
     723          79 :     maxfreq = -1.0;
     724          79 :     minfreq = DBL_MAX;
     725             :   }
     726             :   
     727          79 :   if(freq[hichan] < freq[lochan]){
     728          45 :     lochan = hichan;
     729          45 :     hichan = 0;
     730             :   }
     731          79 :   if(freq[hichan] > maxfreq)
     732          79 :     maxfreq = freq[hichan];
     733          79 :   if(freq[lochan] < minfreq)
     734          79 :     minfreq = freq[lochan];
     735          79 : }
     736             : 
     737             : 
     738          79 : Bool VBContinuumSubtractor::areFreqsInBounds(VisBuffer2& vb,
     739             :                                              const Bool squawk) const
     740             : {
     741             :   Double maxfreq, minfreq;
     742             :   
     743          79 :   getMinMaxFreq(vb, minfreq, maxfreq);
     744          79 :   Bool result = minfreq >= lofreq_p && maxfreq <= hifreq_p;
     745             : 
     746          79 :   if(squawk && !result){
     747             :     // The truth was considered too alarming (CAS-1968).
     748             :     // LogIO os(LogOrigin("VBContinuumSubtractor", "areFreqsInBounds"));
     749           0 :     LogIO os(LogOrigin("VBContinuumSubtractor", "apply"));
     750             : 
     751             :     os << LogIO::WARN
     752             :        << "Extrapolating to cover [" << 1.0e-9 * minfreq << ", "
     753             :        << 1.0e-9 * maxfreq << "] (GHz).\n"
     754             :        << "The frequency range used for the continuum fit was ["
     755           0 :        << 1.0e-9 * lofreq_p << ", "
     756           0 :        << 1.0e-9 * hifreq_p << "] (GHz)."
     757           0 :        << LogIO::POST;
     758           0 :   }
     759          79 :   return result;
     760             : }
     761             : 
     762             : 
     763             : 
     764             : } //# NAMESPACE CASA - END
     765             : 

Generated by: LCOV version 1.16