LCOV - code coverage report
Current view: top level - mstransform/TVI - UVContSubTVI.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 0 641 0.0 %
Date: 2024-10-09 13:55:54 Functions: 0 75 0.0 %

          Line data    Source code
       1             : //# UVContSubTVI.h: This file contains the implementation of the UVContSubTVI class.
       2             : //#
       3             : //#  CASA - Common Astronomy Software Applications (http://casa.nrao.edu/)
       4             : //#  Copyright (C) Associated Universities, Inc. Washington DC, USA 2011, All rights reserved.
       5             : //#  Copyright (C) European Southern Observatory, 2011, All rights reserved.
       6             : //#
       7             : //#  This library is free software; you can redistribute it and/or
       8             : //#  modify it under the terms of the GNU Lesser General Public
       9             : //#  License as published by the Free software Foundation; either
      10             : //#  version 2.1 of the License, or (at your option) any later version.
      11             : //#
      12             : //#  This library is distributed in the hope that it will be useful,
      13             : //#  but WITHOUT ANY WARRANTY, without even the implied warranty of
      14             : //#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             : //#  Lesser General Public License for more details.
      16             : //#
      17             : //#  You should have received a copy of the GNU Lesser General Public
      18             : //#  License along with this library; if not, write to the Free Software
      19             : //#  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
      20             : //#  MA 02111-1307  USA
      21             : //# $Id: $
      22             : 
      23             : #include <mstransform/TVI/UVContSubTVI.h>
      24             : #include <casacore/ms/MeasurementSets/MSFieldColumns.h>
      25             : 
      26             : // OpenMP
      27             : #ifdef _OPENMP
      28             : #include <omp.h>
      29             : #endif
      30             : 
      31             : using namespace casacore;
      32             : 
      33             : namespace casa { //# NAMESPACE CASA - BEGIN
      34             : 
      35             : namespace vi { //# NAMESPACE VI - BEGIN
      36             : 
      37           0 : FitSpec:: FitSpec(Vector<bool> mask, unsigned int order){
      38           0 :     lineFreeChannelMask = mask;
      39           0 :     fitOrder = order;
      40           0 : };
      41             : 
      42             : //////////////////////////////////////////////////////////////////////////
      43             : // UVContSubTVI class
      44             : //////////////////////////////////////////////////////////////////////////
      45             : 
      46             : // -----------------------------------------------------------------------
      47             : //
      48             : // -----------------------------------------------------------------------
      49           0 : UVContSubTVI::UVContSubTVI(     ViImplementation2 * inputVii,
      50           0 :                                                                 const Record &configuration):
      51           0 :                                                                 FreqAxisTVI (inputVii)
      52             : {
      53           0 :         fitOrder_p = 0;
      54           0 :         want_cont_p = False;
      55           0 :         withDenoisingLib_p = true;
      56           0 :         nThreads_p = 1;
      57           0 :         niter_p = 1;
      58             : 
      59           0 :         inputFrequencyMap_p.clear();
      60             : 
      61             :         // Parse and check configuration parameters
      62             :         // Note: if a constructor finishes by throwing an exception, the memory
      63             :         // associated with the object itself is cleaned up — there is no memory leak.
      64           0 :         const auto fitspec = parseConfiguration(configuration);
      65             : 
      66           0 :         initialize(fitspec);
      67           0 : }
      68             : 
      69           0 : UVContSubTVI::~UVContSubTVI()
      70             : {
      71           0 :     inputFrequencyMap_p.clear();
      72           0 : }
      73             : 
      74             : 
      75             : /**
      76             :  * Check if this is a valid field index
      77             :  *
      78             :  * @param str string from a (multi)field spec string
      79             :  *
      80             :  * @return whether this is a valid field index
      81             :  */
      82           0 : bool isFieldIndex(const std::string &str) {
      83           0 :     return !str.empty() && std::all_of(str.begin(), str.end(), ::isdigit);
      84             : }
      85             : 
      86             : /**
      87             :  * For a field string (example: '3', '0,1,4') get the integer indices
      88             :  * specified in the string.
      89             :  * Tokenizes the string by ',' separator and trims spaces.
      90             :  *
      91             :  * @param a string with field indices as used in uvcontsub/fitspec parameter
      92             :  *
      93             :  * @return vector of field indices
      94             :  */
      95           0 : std::vector<int> stringToFieldIdxs(const std::string &str)
      96             : {
      97           0 :     stringstream stream(str);
      98           0 :     vector<int> result;
      99           0 :     while(stream.good()) {
     100           0 :         string token;
     101           0 :         getline(stream, token, ',' );
     102           0 :         token.erase(std::remove(token.begin(), token.end(), ' '), token.end());
     103           0 :         if (!isFieldIndex(token)) {
     104           0 :             throw AipsError("Invalid field index: " + token + " (in " + str + ").");
     105             : 
     106             :         }
     107             :         try {
     108           0 :             auto idx = std::stoi(token);
     109           0 :             result.push_back(idx);
     110           0 :         } catch (const std::exception &exc) {
     111           0 :             throw AipsError("Error trying to parse field ID: " + token + ", " + exc.what());
     112           0 :         }
     113           0 :     }
     114           0 :     return result;
     115           0 : }
     116             : 
     117           0 : InFitSpecMap UVContSubTVI::parseFitSpec(const Record &configuration) const
     118             : {
     119           0 :     InFitSpecMap fitspec;
     120             : 
     121           0 :     const auto exists = configuration.fieldNumber ("fitspec");
     122           0 :     if (exists < 0) {
     123           0 :         return fitspec;
     124             :     }
     125             : 
     126             :     try {
     127             :         // fitspec is a simple string (spw:chan MSSelection syntax)
     128           0 :         String specStr;
     129           0 :         configuration.get(exists, specStr);
     130             : 
     131           0 :         std::vector <InFitSpec> specs = { InFitSpec(specStr, fitOrder_p) };
     132             :         // -1 (all fields): global fit spw:chan string and global fitOrder
     133           0 :         fitspec.insert({-1, specs});
     134           0 :     } catch(AipsError &exc) {
     135             :         // alternatively, fitspec must be a record with field/spw specs
     136           0 :         fitspec = parseDictFitSpec(configuration);
     137           0 :     }
     138           0 :     return fitspec;
     139           0 : }
     140             : 
     141             : /**
     142             :  * For an spw string given in a fitspec per-field subdictionary
     143             :  * (example: '0', '1,2') get the integer indices specified in the
     144             :  * string. Tokenizes the string by ',' separator and trims
     145             :  * spaces. Similar to stringToFieldIDxs but with spw-specific checks.
     146             :  *
     147             :  * @param a string with SPW indices as used in uvcontsub/fitspec parameter
     148             :  * @param allowSemicolon whether to accept the ':' spw:chan separator
     149             :  *
     150             :  * @return vector of SPW indices
     151             :  */
     152           0 : std::vector<unsigned int> stringToSPWIdxs(const std::string &spwStr,
     153             :                                           bool allowSemicolon=false) {
     154           0 :     if (0 == spwStr.length()) {
     155           0 :         throw AipsError("Unexpected empty SPW IDs string");
     156             :     }
     157           0 :     if (!allowSemicolon && spwStr.find(':') != std::string::npos) {
     158           0 :         throw AipsError("Unexpected spw:chan separator character ':' found in SPW: " +
     159           0 :                         spwStr + ". Not allowed in fitspec dictionaries");
     160             :     }
     161             : 
     162           0 :     vector<unsigned int> result;
     163           0 :     stringstream stream(spwStr);
     164           0 :     while(stream.good()) {
     165           0 :         string token;
     166           0 :         getline(stream, token, ',' );
     167           0 :         token.erase(std::remove(token.begin(), token.end(), ' '), token.end());
     168           0 :         if (!allowSemicolon && !isFieldIndex(token)) {
     169           0 :             throw AipsError("Invalid SPW index: " + token + " (in " + spwStr + ")");
     170             :         }
     171             :         try {
     172           0 :             auto idx = std::stoi(token);
     173           0 :             result.push_back(idx);
     174           0 :         } catch (const std::exception &exc) {
     175           0 :             throw AipsError("Error trying to parse SPW: " + token + ", " + exc.what());
     176           0 :         }
     177           0 :     }
     178           0 :     return result;
     179           0 : }
     180             : 
     181             : /**
     182             :  * Get max valid FIELD IDs for this iterator. MSv2 uses the FIELD
     183             :  * table row index as FIELD ID.
     184             :  */
     185           0 : rownr_t UVContSubTVI::getMaxMSFieldID() const
     186             : {
     187           0 :     const auto &fieldsTable = getVii()->fieldSubtablecols();
     188           0 :     return fieldsTable.nrow() - 1;
     189             : }
     190             : 
     191           0 : void UVContSubTVI::insertToFieldSpecMap(const std::vector<int> &fieldIdxs,
     192             :                                         const InFitSpec &spec,
     193             :                                         InFitSpecMap &fitspec) const
     194             : {
     195           0 :     for (const auto fid: fieldIdxs) {
     196           0 :         const auto fieldFound = fitspec.find(fid);
     197           0 :         if (fieldFound == fitspec.end()) {
     198           0 :             std::vector<InFitSpec> firstSpw = { spec };
     199           0 :             fitspec[fid] = firstSpw;
     200           0 :         } else {
     201           0 :             fitspec[fid].emplace_back(spec);
     202             :         }
     203             : 
     204             :     }
     205           0 : }
     206             : 
     207             : /**
     208             :  * Takes one per-field subdict, parses it and populates a map field IDs->fit specs.
     209             :  *
     210             :  * @param fieldRec subdict from the configuration dict/record passed from the task/tool
     211             :  *        interface, with uvcontsub task parameters
     212             :  * @param fieldIdx IDs of the fields this spec applies to
     213             :  * @param fitspec spec map to populate for this(ese) field(s)
     214             :  */
     215           0 : void UVContSubTVI::parseFieldSubDict(const Record &fieldRec,
     216             :                                      const std::vector<int> &fieldIdxs,
     217             :                                      InFitSpecMap &fitspec) const
     218             : {
     219           0 :     std::set<unsigned int> spwsSeen;
     220           0 :     for (unsigned int spw=0; spw < fieldRec.nfields(); ++spw) {
     221           0 :         const auto spwRec = fieldRec.subRecord(RecordFieldId(spw));
     222           0 :         std::string spwStr  = fieldRec.name(RecordFieldId(spw));
     223           0 :         const auto spwIdxs = stringToSPWIdxs(spwStr, false);
     224           0 :         for (const auto sid : spwIdxs) {
     225           0 :             if (spwsSeen.insert(sid).second == false) {
     226           0 :                 throw AipsError("Error in fitspec. SPW " + to_string(sid) + " is given "
     227           0 :                                 "multiple times. Found for SPW subdict '" + spwStr +
     228           0 :                                 "' and other subdicts(s).");
     229             :             }
     230             :         }
     231             :         try {
     232           0 :             const std::string chanStr = spwRec.asString(RecordFieldId("chan"));
     233           0 :             if (!chanStr.empty()) {
     234           0 :                 spwStr = "";
     235           0 :                 for (const auto sid : spwIdxs) {
     236           0 :                     const auto spw_chan = to_string(sid) + ":" + chanStr;
     237           0 :                     if (spwStr.empty()) {
     238           0 :                         spwStr = spw_chan;
     239             :                     } else {
     240           0 :                         spwStr += "," + spw_chan;
     241             :                     }
     242           0 :                 }
     243             :             }
     244           0 :         } catch (const AipsError &exc) {
     245           0 :             throw AipsError("Error trying to get chan value in subdict for spw "
     246           0 :                             + spwStr + ", " + exc.what());
     247           0 :         }
     248             : 
     249           0 :         int polOrder = fitOrder_p;
     250             :         try {
     251           0 :             polOrder  = spwRec.asInt(RecordFieldId("fitorder"));
     252           0 :         } catch (const AipsError &exc) {
     253           0 :             throw AipsError("Error trying to get fitorder value in subdict for spw "
     254           0 :                             + spwStr + ", " + exc.what());
     255           0 :         }
     256           0 :         if (polOrder < 0) {
     257           0 :             throw AipsError("Fit order cannot be negative. Value given: " +
     258           0 :                             to_string(polOrder));
     259             :         }
     260             : 
     261           0 :         const auto spec = std::make_pair(spwStr, polOrder);
     262           0 :         insertToFieldSpecMap(fieldIdxs, spec, fitspec);
     263           0 :     }
     264           0 : }
     265             : 
     266             : /**
     267             :  * Takes the input dict of fieldID: SPW: {chan/fitorder}, parses it
     268             :  * and populates a map that is returned.
     269             :  *
     270             :  * @param configuration dictionary/record passed from the task/tool interface, with
     271             :  *        uvcontsub task parameters
     272             :  *
     273             :  * @return InFitSpecMap map populated from an input dict
     274             :  */
     275           0 : InFitSpecMap UVContSubTVI::parseDictFitSpec(const Record &configuration) const
     276             : {
     277           0 :     const Record rawFieldFitspec = configuration.asRecord("fitspec");
     278           0 :     if (rawFieldFitspec.empty()) {
     279           0 :         throw AipsError("The dictionary 'fitspec' of fit specifications is empty!");
     280             :     }
     281             : 
     282           0 :     const auto maxMSField = getMaxMSFieldID();
     283           0 :     InFitSpecMap fitspec;
     284           0 :     std::set<unsigned int> fieldsSeen;
     285             :     // iterate through fields given in fitspec
     286           0 :     for (unsigned int rid=0; rid < rawFieldFitspec.nfields(); ++rid) {
     287           0 :         const std::string fieldsStr = rawFieldFitspec.name(RecordFieldId(rid));
     288           0 :         const auto fieldIdxs = stringToFieldIdxs(fieldsStr);
     289           0 :         for (const auto fid: fieldIdxs) {
     290             :             // check that the field is in the MS
     291           0 :             if (fid < 0 || static_cast<unsigned int>(fid) > maxMSField) {
     292           0 :                 throw AipsError("Wrong field ID given: " +
     293           0 :                                 std::to_string(fid) +
     294             :                                 ". This MeasurementSet has field IDs between"
     295           0 :                                 " 0 and " + std::to_string(maxMSField));
     296             :             }
     297           0 :             if (fieldsSeen.insert(fid).second == false) {
     298           0 :                 throw AipsError("Error in fitspec. Field " + to_string(fid) + " is given "
     299           0 :                                 "multiple times. Found for field subdict '" + fieldsStr +
     300           0 :                                 "' and other subdict(s).");
     301             :             }
     302             :         }
     303             : 
     304           0 :         std::string noneStr;
     305           0 :         bool subRecordIsString = true;
     306             :         try {
     307           0 :             noneStr = rawFieldFitspec.asString(RecordFieldId(rid));
     308           0 :         } catch (const AipsError &exc) {
     309           0 :             subRecordIsString = false;
     310           0 :         }
     311           0 :         if (subRecordIsString){
     312           0 :             if (noneStr != "NONE") {
     313           0 :                 throw AipsError("Wrong value found in fitspec, field subdict for field: '"
     314           0 :                                 + fieldsStr + "', value: '" +
     315           0 :                                 noneStr + "'. Only 'NONE' is accepted (= do not fit for " +
     316           0 :                                 "any SPW).");
     317             :             }
     318             :         } else {
     319           0 :             const Record fieldRec = rawFieldFitspec.subRecord(RecordFieldId(rid));
     320           0 :             parseFieldSubDict(fieldRec, fieldIdxs, fitspec);
     321           0 :         }
     322           0 :     }
     323             : 
     324           0 :     return fitspec;
     325           0 : }
     326             : 
     327           0 : std::string fieldTextFromId(int idx)
     328             : {
     329           0 :     std::string name;
     330           0 :     if (idx >= 0) {
     331           0 :         name = std::to_string(idx);
     332             :     } else {
     333           0 :         name = "all fields";
     334             :     }
     335           0 :     return name;
     336           0 : }
     337             : 
     338           0 : void UVContSubTVI::printInputFitSpec(const InFitSpecMap &fitspec) const
     339             : {
     340           0 :     if (fitspec.size() > 0) {
     341           0 :         logger_p << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     342             :                  << "Fitspec (order and spw:line-free channel) specification is: "
     343           0 :                  << LogIO::POST;
     344             : 
     345           0 :         for (const auto &elem: fitspec) {
     346           0 :             const auto &specs = elem.second;
     347           0 :             for (const auto &oneSpw : specs) {
     348           0 :                 logger_p << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     349           0 :                          << "   field: " << fieldTextFromId(elem.first)
     350           0 :                          << ". " << oneSpw.second << ", '" << oneSpw.first << "'"
     351           0 :                          << LogIO::POST;
     352             :             }
     353             :         }
     354             :     } else {
     355           0 :         logger_p << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     356           0 :                  << "Line-free channel selection: not given" << LogIO::POST;
     357             :     }
     358           0 : }
     359             : 
     360             : // -----------------------------------------------------------------------
     361             : //
     362             : // -----------------------------------------------------------------------
     363           0 : InFitSpecMap UVContSubTVI::parseConfiguration(const Record &configuration)
     364             : {
     365           0 :         auto exists = configuration.fieldNumber ("fitorder");
     366           0 :         if (exists >= 0)
     367             :         {
     368           0 :                 configuration.get (exists, fitOrder_p);
     369             : 
     370           0 :                 if (fitOrder_p > 0)
     371             :                 {
     372           0 :                         logger_p        << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     373           0 :                                                 << "Global/default fit order is " << fitOrder_p << LogIO::POST;
     374             :                 }
     375             :         }
     376             : 
     377           0 :         exists = configuration.fieldNumber ("want_cont");
     378           0 :         if (exists >= 0)
     379             :         {
     380           0 :                 configuration.get (exists, want_cont_p);
     381             : 
     382           0 :                 if (want_cont_p)
     383             :                 {
     384           0 :                         logger_p        << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     385             :                                                 << "Producing continuum estimate instead of continuum subtracted data "
     386           0 :                                                 << LogIO::POST;
     387             :                 }
     388             :         }
     389             : 
     390           0 :         const auto fitspec = parseFitSpec(configuration);
     391           0 :         printInputFitSpec(fitspec);
     392             : 
     393           0 :         exists = configuration.fieldNumber ("writemodel");
     394           0 :         if (exists >= 0)
     395             :         {
     396           0 :             configuration.get(exists, precalcModel_p);
     397           0 :             if (precalcModel_p)
     398             :             {
     399           0 :                 logger_p        << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     400             :                                 << "Producing continuum estimate in the MODEL_DATA column"
     401           0 :                                 << LogIO::POST;
     402             :             }
     403             :         }
     404             : 
     405           0 :         exists = configuration.fieldNumber ("denoising_lib");
     406           0 :         if (exists >= 0)
     407             :         {
     408           0 :                 configuration.get (exists, withDenoisingLib_p);
     409             : 
     410           0 :                 if (withDenoisingLib_p)
     411             :                 {
     412           0 :                         logger_p << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     413             :                                  << "Using GSL based multiparameter regression with linear "
     414           0 :                                  << "least-squares fitting" << LogIO::POST;
     415             :                 }
     416             :         }
     417             : 
     418           0 :         exists = configuration.fieldNumber ("nthreads");
     419           0 :         if (exists >= 0)
     420             :         {
     421           0 :                 configuration.get (exists, nThreads_p);
     422             : 
     423           0 :                 if (nThreads_p > 1)
     424             :                 {
     425             : #ifdef _OPENMP
     426           0 :                         if (omp_get_max_threads() < (int)nThreads_p)
     427             :                         {
     428           0 :                             logger_p << LogIO::WARN << LogOrigin("UVContSubTVI", __FUNCTION__)
     429             :                                      << "Requested " <<  nThreads_p
     430             :                                      << " OMP threads but maximum possible is " << omp_get_max_threads()<< endl
     431             :                                      << "Setting number of OMP threads to " << omp_get_max_threads() << endl
     432             :                                      << "Check OMP_NUM_THREADS environmental variable and number of cores in your system"
     433           0 :                                      << LogIO::POST;
     434           0 :                             nThreads_p = omp_get_max_threads();
     435             :                         }
     436             :                         else
     437             :                         {
     438           0 :                             logger_p << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     439           0 :                                      << "Numer of OMP threads set to " << nThreads_p << LogIO::POST;
     440             :                         }
     441             : #else
     442             :                         logger_p << LogIO::WARN << LogOrigin("UVContSubTVI", __FUNCTION__)
     443             :                                         << "Requested " <<  nThreads_p << " threads but OMP is not available in your system"
     444             :                                         << LogIO::POST;
     445             :                         nThreads_p = 1;
     446             : #endif
     447             :                 }
     448             :         }
     449             : 
     450           0 :         exists = configuration.fieldNumber ("niter");
     451           0 :         if (exists >= 0)
     452             :         {
     453           0 :                 configuration.get (exists, niter_p);
     454             : 
     455           0 :                 if (niter_p > 1)
     456             :                 {
     457           0 :                         logger_p        << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     458           0 :                                                 << "Number of iterations for re-weighted linear fit: " << niter_p << LogIO::POST;
     459             :                 }
     460             :         }
     461             : 
     462             :         // If the user gives SPWs in fitspec that are not in this list, give a warning
     463           0 :         exists = configuration.fieldNumber ("allowed_spws");
     464           0 :         if (exists >= 0)
     465             :         {
     466           0 :                 String allowed;
     467           0 :                 configuration.get (exists, allowed);
     468           0 :                 allowedSpws_p = allowed;
     469           0 :         }
     470             : 
     471           0 :         return fitspec;
     472           0 : }
     473             : 
     474             : /**
     475             :  * Check consistency of spw related parameters (spw and fitspec). Prints a warning
     476             :  * if there is an spw selection and fitspec uses SPWs not included in the selection.
     477             :  * This condition was found to be confusing for users trying to set parameters as
     478             :  * in the old uvcontsub with combine='spw'.
     479             :  *
     480             :  * @param msVii MS object attached to the Vi (remember - not the right
     481             :  *              thing to use in a TVI)
     482             :  * @param spwChan MSSelection with the spw/chan (spwExpr) selection set
     483             :  */
     484           0 : void UVContSubTVI::spwInputChecks(const MeasurementSet *msVii,
     485             :                                   MSSelection &spwChan) const {
     486             :     // note: spwChan should be const (if getSpwList() were const)
     487           0 :     if (!allowedSpws_p.empty()) {
     488           0 :         const auto usedSpws = spwChan.getSpwList(msVii).tovector();
     489           0 :         MSSelection checker;
     490           0 :         checker.setSpwExpr(allowedSpws_p);
     491           0 :         const auto allowed = checker.getSpwList(msVii).tovector();
     492           0 :         for (const auto spw : usedSpws ) {
     493           0 :             if (std::find(allowed.begin(), allowed.end(), spw) == allowed.end()) {
     494           0 :                 logger_p << LogIO::WARN << LogOrigin("UVContSubTVI", __FUNCTION__)
     495             :                          << "SPW " << spw << " is used in fitspec but is not included in "
     496           0 :                          << "the SPW selection ('" << allowedSpws_p <<  "'), please "
     497           0 :                          << "double-check the spw and fitspec parameters." << LogIO::POST;
     498             :             }
     499             :         }
     500           0 :     }
     501           0 : }
     502             : 
     503             : /**
     504             :  * Produces a map spw -> vector of selected channels, to be used as an
     505             :  * intermediate step to produce a channel mask for the fitting
     506             :  * routines.
     507             :  *
     508             :  * @param spwChanStr An SPW:chan selection string (MSSelection syntax)
     509             :  *
     510             :  * @return Map from spw (int ID) -> vector of channel indices
     511             :  */
     512           0 : unordered_map<int, vector<int>> UVContSubTVI::makeLineFreeChannelSelMap(std::string
     513             :                                                                         spwChanStr) const
     514             : {
     515           0 :     MSSelection mssel;
     516           0 :     mssel.setSpwExpr(spwChanStr);
     517             :     // This will access the MS directly: far from ideal (CAS-11638) but no easy solution
     518           0 :     const auto msVii = &(inputVii_p->ms());
     519             : 
     520           0 :     spwInputChecks(msVii, mssel);
     521             : 
     522             :     // Create line-free channel map based on MSSelection channel ranges
     523           0 :     const auto spwchan = mssel.getChanList(msVii);
     524           0 :     const auto nSelections = spwchan.shape()[0];
     525           0 :     unordered_map<int,vector<int>>  lineFreeChannelSelMap;
     526           0 :     for (uInt selection_i=0; selection_i<nSelections; ++selection_i)
     527             :     {
     528           0 :         auto spw = spwchan(selection_i, 0);
     529           0 :         if (lineFreeChannelSelMap.find(spw) == lineFreeChannelSelMap.end())
     530             :         {
     531           0 :             lineFreeChannelSelMap[spw].clear(); // Accessing the vector creates it
     532             :         }
     533             : 
     534           0 :         const auto channelStart = spwchan(selection_i, 1);
     535           0 :         const auto channelStop = spwchan(selection_i, 2);
     536           0 :         const auto channelStep = spwchan(selection_i, 3);
     537           0 :         for (auto inpChan=channelStart; inpChan<=channelStop; inpChan += channelStep)
     538             :         {
     539           0 :             lineFreeChannelSelMap[spw].push_back(inpChan);
     540             :         }
     541             :     }
     542             : 
     543           0 :     return lineFreeChannelSelMap;
     544           0 : }
     545             : 
     546             : // -----------------------------------------------------------------------
     547             : //
     548             : // -----------------------------------------------------------------------
     549           0 : void UVContSubTVI::populatePerFieldSpec(int fieldID,
     550             :                                         const std::vector<InFitSpec> &fitSpecs)
     551             : {
     552           0 :     std::unordered_map<int, int> perSpwFitOrder;
     553           0 :     std::string fullSpwStr = "";
     554           0 :     for (const auto &spec : fitSpecs) {
     555           0 :         if (fullSpwStr == "NONE") {
     556           0 :             break;
     557           0 :         } else if (fullSpwStr.length() == 0) {
     558           0 :             fullSpwStr = spec.first;
     559             :         } else {
     560             :             // MSSelection syntax spw:chan, SPWs separated by commas
     561           0 :             fullSpwStr += "," + spec.first;
     562             :         }
     563           0 :         auto spws = stringToSPWIdxs(spec.first, true);
     564           0 :         for (const auto sid : spws) {
     565           0 :             perSpwFitOrder[sid] = spec.second;
     566             :         }
     567           0 :     }
     568             : 
     569           0 :     auto lineFreeChannelSelMap = makeLineFreeChannelSelMap(fullSpwStr);
     570             : 
     571             :     // Create line-free channel mask, spw->(channel_mask, fit_order)
     572           0 :     unordered_map<int, FitSpec> lineFreeChannelMaskMap;   // rename: fitSpecMap
     573           0 :     for (auto const spwInp: spwInpChanIdxMap_p)
     574             :     {
     575           0 :         const auto spw = spwInp.first;
     576           0 :         if (lineFreeChannelMaskMap.find(spw) == lineFreeChannelMaskMap.end())
     577             :         {
     578           0 :             if (lineFreeChannelSelMap.size() > 0 && 0 == lineFreeChannelSelMap[spw].size()) {
     579             :                 // Some SPWs have been selected, but this SPW doesn't have any selection
     580             :                 //   => a 0-elements mask says there is nothing to mask or fit here, or
     581             :                 // otherwise we'd make the effort to prepare and call the fit routine for an
     582             :                 // "all masked/True" channel mask which will not even start minimizing
     583           0 :                 lineFreeChannelMaskMap[spw].lineFreeChannelMask = Vector<bool>();
     584             :             } else {
     585           0 :                 auto &mask = lineFreeChannelMaskMap[spw].lineFreeChannelMask;
     586           0 :                 mask = Vector<bool>(spwInp.second.size(), true);
     587           0 :                 for (uInt selChanIdx=0; selChanIdx<lineFreeChannelSelMap[spw].size();
     588             :                      ++selChanIdx)
     589             :                 {
     590           0 :                     const auto selChan = lineFreeChannelSelMap[spw][selChanIdx];
     591           0 :                     mask(selChan) = False;
     592             :                 }
     593             :             }
     594             : 
     595           0 :             unsigned int fitOrder = fitOrder_p;
     596           0 :             const auto find = perSpwFitOrder.find(spw);
     597           0 :             if (find != perSpwFitOrder.end()) {
     598           0 :                 fitOrder = find->second;
     599             :             }
     600           0 :             lineFreeChannelMaskMap[spw].fitOrder = fitOrder;
     601             :         }
     602           0 :     }
     603             : 
     604             :     // Poppulate per field map: field -> spw -> fit spec
     605             :     // emplace struct (linefreechannelmaskmap, + fitorder)
     606           0 :     perFieldSpecMap_p.emplace(fieldID, lineFreeChannelMaskMap);
     607           0 : }
     608             : 
     609             : /**
     610             :  * Takes the map from fitspec and produces the per field map to be
     611             :  * used in the iteration, with channel masks and fitorder per field
     612             :  * per SPW.
     613             :  */
     614           0 : void UVContSubTVI::fitSpecToPerFieldMap(const InFitSpecMap &fitspec)
     615             : {
     616             :      // Process line-free channel specifications
     617           0 :     for (const auto item: fitspec) {
     618           0 :         unordered_map<int, FitSpec> fieldSpecMap;
     619             :         // Parse line-free channel selection using MSSelection syntax
     620           0 :         const auto fieldID = item.first;
     621           0 :         const auto &specs = item.second;
     622           0 :         bool noneFound = false;
     623           0 :         for (const auto spwSpec : specs) {
     624           0 :             const auto spwStr = spwSpec.first;
     625           0 :             const auto order = spwSpec.second;
     626           0 :             const auto fieldName = fieldTextFromId(fieldID);
     627           0 :             logger_p << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     628             :                      << "Parsing fit spw:chan string and order for field: " << fieldName
     629           0 :                      << ", spw/chan: '" << spwStr << "', order: " << order << LogIO::POST;
     630           0 :             if (spwStr == "NONE") {
     631           0 :                 noneFound = true;
     632           0 :                 if (specs.size() != 1) {
     633           0 :                 throw AipsError("For field '" + fieldName + "' A \"NONE\" fit specification "
     634           0 :                                 "has been given but additional fit specs have been given");
     635             :                 }
     636             :             }
     637           0 :         }
     638             : 
     639           0 :         if (noneFound) {
     640             :             // Not inserting any entries in perFieldSpecMap_p[fieldID]
     641             :             // implies no transformation for that field (inputVis -> outputVis)
     642           0 :             continue;
     643             :         }
     644             : 
     645           0 :         if (1 == specs.size() && specs[0].first.empty()) {
     646             :             // -1 is the "all-fields-included" field pseudo-index
     647             :             // empty fieldSpecMap string -> all SPW, channels, leave all SPW masks unset
     648           0 :             if (-1 == fieldID) {
     649           0 :                 perFieldSpecMap_p.emplace(fieldID, fieldSpecMap);
     650             :             }
     651           0 :             continue;
     652             :         }
     653             : 
     654           0 :         populatePerFieldSpec(fieldID, specs);
     655           0 :     }
     656           0 : }
     657             : 
     658             : // -----------------------------------------------------------------------
     659             : //
     660             : // -----------------------------------------------------------------------
     661           0 : void UVContSubTVI::initialize(const InFitSpecMap &fitspec)
     662             : {
     663             :     // Populate nchan input-output maps
     664           0 :     for (auto spwInp: spwInpChanIdxMap_p)
     665             :     {
     666           0 :         auto spw = spwInp.first;
     667           0 :         spwOutChanNumMap_p[spw] = spwInp.second.size();
     668           0 :     }
     669             : 
     670           0 :     fitSpecToPerFieldMap(fitspec);
     671           0 : }
     672             : 
     673             : // -----------------------------------------------------------------------
     674             : //
     675             : // -----------------------------------------------------------------------
     676           0 : void UVContSubTVI::floatData (Cube<Float> & vis) const
     677             : {
     678             :         // Get input VisBuffer
     679           0 :         VisBuffer2 *vb = getVii()->getVisBuffer();
     680             : 
     681             :         // Transform data
     682           0 :         transformDataCube(vb->visCubeFloat(),vb->weightSpectrum(),vis);
     683             : 
     684           0 :         return;
     685             : }
     686             : 
     687             : /**
     688             :  * To save the original_data - continumm_subtracted_data as model data
     689             :  * for visibilityModel.
     690             :  *
     691             :  * @param origVis visibilities before continuum subtraction
     692             :  * @param contSubvis visibilities after being cont-subtracted
     693             :  */
     694           0 : void UVContSubTVI::savePrecalcModel(const Cube<Complex> & origVis,
     695             :                                     const Cube<Complex> & contSubVis) const
     696             : {
     697             :     // save it for visibilityModel
     698           0 :     if (precalcModel_p) {
     699             :         // Or otherwise the next assignment would fail a conform check
     700           0 :         if (precalcModelVis_p.shape() != contSubVis.shape()) {
     701           0 :             precalcModelVis_p.resize(contSubVis.shape());
     702             :         }
     703             : 
     704           0 :         precalcModelVis_p = origVis - contSubVis;
     705             :     }
     706           0 : }
     707             : 
     708             : // -----------------------------------------------------------------------
     709             : //
     710             : // -----------------------------------------------------------------------
     711           0 : void UVContSubTVI::visibilityObserved (Cube<Complex> & vis) const
     712             : {
     713             :     // Get input VisBuffer
     714           0 :     VisBuffer2 *vb = getVii()->getVisBuffer();
     715             : 
     716             :     // Get weightSpectrum from sigmaSpectrum
     717           0 :     Cube<Float> weightSpFromSigmaSp;
     718           0 :     weightSpFromSigmaSp.resize(vb->sigmaSpectrum().shape(),False);
     719           0 :     weightSpFromSigmaSp = vb->sigmaSpectrum(); // = Operator makes a copy
     720           0 :     arrayTransformInPlace (weightSpFromSigmaSp,sigmaToWeight);
     721             : 
     722             :     // Transform data
     723           0 :     transformDataCube(vb->visCube(),weightSpFromSigmaSp,vis);
     724             : 
     725           0 :     savePrecalcModel(vb->visCube(), vis);
     726           0 : }
     727             : 
     728             : // -----------------------------------------------------------------------
     729             : //
     730             : // -----------------------------------------------------------------------
     731           0 : void UVContSubTVI::visibilityCorrected (Cube<Complex> & vis) const
     732             : {
     733             :     // Get input VisBuffer
     734           0 :     VisBuffer2 *vb = getVii()->getVisBuffer();
     735             : 
     736             :     // Transform data
     737           0 :     transformDataCube(vb->visCubeCorrected(),vb->weightSpectrum(),vis);
     738             : 
     739           0 :     savePrecalcModel(vb->visCubeCorrected(), vis);
     740           0 : }
     741             : 
     742             : // -----------------------------------------------------------------------
     743             : //
     744             : // -----------------------------------------------------------------------
     745           0 : void UVContSubTVI::visibilityModel (Cube<Complex> & vis) const
     746             : {
     747             :         // Get input VisBuffer
     748           0 :         VisBuffer2 *vb = getVii()->getVisBuffer();
     749             : 
     750             :         // from visiblityObserved we have calculated the polynomial subtraction
     751           0 :         if (precalcModel_p && precalcModelVis_p.shape() == vb->visCubeModel().shape()) {
     752           0 :             vis = precalcModelVis_p;
     753           0 :             return;
     754             :         }
     755             : 
     756             :         // Transform data
     757           0 :         transformDataCube(vb->visCubeModel(),vb->weightSpectrum(),vis);
     758             : 
     759           0 :         return;
     760             : }
     761             : 
     762             : // -----------------------------------------------------------------------
     763             : //
     764             : // -----------------------------------------------------------------------
     765           0 : void UVContSubTVI::result(Record &res) const
     766             : {
     767           0 :     auto acc = result_p.getAccumulatedResult();
     768           0 :     res.defineRecord("uvcontsub", acc);
     769           0 : }
     770             : 
     771             : // -----------------------------------------------------------------------
     772             : //
     773             : // -----------------------------------------------------------------------
     774           0 : template<class T> void UVContSubTVI::transformDataCube(   const Cube<T> &inputVis,
     775             :                                                                                                                 const Cube<Float> &inputWeight,
     776             :                                                                                                                 Cube<T> &outputVis) const
     777             : {
     778             :     // Get input VisBuffer
     779           0 :     VisBuffer2 *vb = getVii()->getVisBuffer();
     780             : 
     781           0 :     auto fieldID = vb->fieldId()[0];
     782             :     // First check the "all fields" (no per-individual field list in fitspec)
     783           0 :     auto fieldMapIt = perFieldSpecMap_p.find(-1);
     784           0 :     if (fieldMapIt == perFieldSpecMap_p.end()) {
     785             :         // otherwise, check for individual fields (coming from a fitspec list)
     786           0 :         fieldMapIt = perFieldSpecMap_p.find(fieldID);
     787           0 :         if (fieldMapIt == perFieldSpecMap_p.end()) {
     788             :             // This was a "NONE" = no-subtraction for this field ==> no-op
     789           0 :             outputVis = inputVis;
     790           0 :             return;
     791             :         }
     792             :     }
     793             : 
     794           0 :     Int spwId = vb->spectralWindows()(0);
     795             : 
     796             :     // Get input line-free channel mask and fitorder
     797           0 :     Vector<bool> *lineFreeChannelMask = nullptr;
     798           0 :     auto fitOrder = fitOrder_p;
     799           0 :     auto spwMap = fieldMapIt->second;
     800           0 :     auto maskLookup = spwMap.find(spwId);
     801           0 :     if (maskLookup != spwMap.end())
     802             :     {
     803           0 :         if (maskLookup->second.lineFreeChannelMask.nelements() == 0) {
     804             :             // This was a non-selected SPW in a non-empty SPW selection string ==> no-op
     805           0 :             outputVis = inputVis;
     806           0 :             return;
     807             :         } else {
     808           0 :             lineFreeChannelMask = &(maskLookup->second.lineFreeChannelMask);
     809           0 :             fitOrder = maskLookup->second.fitOrder;
     810             :         }
     811             :     }
     812             : 
     813             :     // Get polynomial model for this SPW (depends on number of channels and gridding)
     814           0 :     const auto freqIter = inputFrequencyMap_p.find(spwId);
     815           0 :     const Vector<Double> &inputFrequencies = vb->getFrequencies(0);
     816             :     // Could perhaps have a per field-spw pair map to avoid re-allocations - But can be big
     817             :     // (n_fields X n_spws X n_chans) for many fields, many SPWs MSs
     818             :     inputFrequencyMap_p[spwId].
     819           0 :         reset(new denoising::GslPolynomialModel<double>(inputFrequencies, fitOrder));
     820             : 
     821             :     // Reshape output data before passing it to the DataCubeHolder
     822           0 :     outputVis.resize(getVisBuffer()->getShape(),False);
     823             : 
     824             :     // Get input flag Cube
     825           0 :     const Cube<bool> &flagCube = vb->flagCube();
     826             : 
     827             :     // Transform data
     828           0 :     if (nThreads_p > 1)
     829             :     {
     830             : #ifdef _OPENMP
     831             : 
     832           0 :         uInt nCorrs = vb->getShape()(0);
     833           0 :         if (nCorrs < nThreads_p)
     834             :         {
     835           0 :             omp_set_num_threads(nCorrs);
     836             :         }
     837             :         else
     838             :         {
     839           0 :             omp_set_num_threads(nThreads_p);
     840             :         }
     841             : 
     842           0 : #pragma omp parallel for
     843             :         for (uInt corrIdx=0; corrIdx < nCorrs; corrIdx++)
     844             :         {
     845             :             transformDataCore(inputFrequencyMap_p[spwId].get(),lineFreeChannelMask,
     846             :                               inputVis,flagCube,inputWeight,outputVis,corrIdx);
     847             :         }
     848             : 
     849           0 :         omp_set_num_threads(nThreads_p);
     850             : #endif
     851             :     }
     852             :     else
     853             :     {
     854           0 :         auto scanID = vb->scan()[0];
     855           0 :         uInt nCorrs = vb->getShape()(0);
     856           0 :         for (uInt corrIdx=0; corrIdx < nCorrs; corrIdx++)
     857             :         {
     858             :             Complex chisq =
     859           0 :                 transformDataCore(inputFrequencyMap_p[spwId].get(), lineFreeChannelMask,
     860             :                                   inputVis, flagCube, inputWeight, outputVis, corrIdx);
     861           0 :             result_p.addOneFit(fieldID, scanID, spwId, (int)corrIdx, chisq);
     862             :         }
     863             :     }
     864           0 : }
     865             : 
     866             : // -----------------------------------------------------------------------
     867             : //
     868             : // -----------------------------------------------------------------------
     869           0 : template<class T> Complex UVContSubTVI::transformDataCore(denoising::GslPolynomialModel<Double>* model,
     870             :                                                           Vector<bool> *lineFreeChannelMask,
     871             :                                                           const Cube<T> &inputVis,
     872             :                                                           const Cube<bool> &inputFlags,
     873             :                                                           const Cube<Float> &inputWeight,
     874             :                                                           Cube<T> &outputVis,
     875             :                                                           Int parallelCorrAxis) const
     876             : {
     877             :     // Gather input data
     878           0 :     DataCubeMap inputData;
     879           0 :     DataCubeHolder<T> inputVisCubeHolder(inputVis);
     880           0 :     DataCubeHolder<bool> inputFlagCubeHolder(inputFlags);
     881           0 :     DataCubeHolder<Float> inputWeightsCubeHolder(inputWeight);
     882           0 :     inputData.add(MS::DATA,inputVisCubeHolder);
     883           0 :     inputData.add(MS::FLAG,inputFlagCubeHolder);
     884           0 :     inputData.add(MS::WEIGHT_SPECTRUM,inputWeightsCubeHolder);
     885             : 
     886             :     // Gather output data
     887           0 :     DataCubeMap outputData;
     888           0 :     DataCubeHolder<T> outputVisCubeHolder(outputVis);
     889           0 :     outputData.add(MS::DATA,outputVisCubeHolder);
     890             : 
     891           0 :     Complex chisq;
     892           0 :     if (want_cont_p)
     893             :     {
     894           0 :         if (withDenoisingLib_p)
     895             :         {
     896           0 :             UVContEstimationDenoisingKernel<T> kernel(model,niter_p,lineFreeChannelMask);
     897           0 :             UVContSubTransformEngine<T> transformer(&kernel,&inputData,&outputData);
     898           0 :             transformFreqAxis2(inputVis.shape(),transformer,parallelCorrAxis);
     899           0 :             chisq = kernel.getChiSquared();
     900           0 :         }
     901             :         else
     902             :         {
     903           0 :             UVContEstimationKernel<T> kernel(model,lineFreeChannelMask);
     904           0 :             UVContSubTransformEngine<T> transformer(&kernel,&inputData,&outputData);
     905           0 :             transformFreqAxis2(inputVis.shape(),transformer,parallelCorrAxis);
     906           0 :             chisq = kernel.getChiSquared();
     907           0 :         }
     908             :     }
     909             :     else
     910             :     {
     911           0 :         if (withDenoisingLib_p)
     912             :         {
     913           0 :             UVContSubtractionDenoisingKernel<T> kernel(model,niter_p,lineFreeChannelMask);
     914           0 :             UVContSubTransformEngine<T> transformer(&kernel,&inputData,&outputData);
     915           0 :             transformFreqAxis2(inputVis.shape(),transformer,parallelCorrAxis);
     916           0 :             chisq = kernel.getChiSquared();
     917           0 :         }
     918             :         else
     919             :         {
     920           0 :             UVContSubtractionKernel<T> kernel(model,lineFreeChannelMask);
     921           0 :             UVContSubTransformEngine<T> transformer(&kernel,&inputData,&outputData);
     922           0 :             transformFreqAxis2(inputVis.shape(),transformer,parallelCorrAxis);
     923           0 :             chisq = kernel.getChiSquared();
     924           0 :         }
     925             :     }
     926             : 
     927           0 :     return chisq;
     928           0 : }
     929             : 
     930             : //////////////////////////////////////////////////////////////////////////
     931             : // UVContSubTVIFactory class
     932             : //////////////////////////////////////////////////////////////////////////
     933             : 
     934             : // -----------------------------------------------------------------------
     935             : //
     936             : // -----------------------------------------------------------------------
     937           0 : UVContSubTVIFactory::UVContSubTVIFactory (      Record &configuration,
     938           0 :                                                                                         ViImplementation2 *inputVii)
     939             : {
     940           0 :         inputVii_p = inputVii;
     941           0 :         configuration_p = configuration;
     942           0 : }
     943             : 
     944             : // -----------------------------------------------------------------------
     945             : //
     946             : // -----------------------------------------------------------------------
     947           0 : vi::ViImplementation2 * UVContSubTVIFactory::createVi(VisibilityIterator2 *) const
     948             : {
     949           0 :         return new UVContSubTVI(inputVii_p,configuration_p);
     950             : }
     951             : 
     952             : // -----------------------------------------------------------------------
     953             : //
     954             : // -----------------------------------------------------------------------
     955           0 : vi::ViImplementation2 * UVContSubTVIFactory::createVi() const
     956             : {
     957           0 :         return new UVContSubTVI(inputVii_p,configuration_p);
     958             : }
     959             : 
     960             : //////////////////////////////////////////////////////////////////////////
     961             : // UVContSubTVILayerFactory class
     962             : //////////////////////////////////////////////////////////////////////////
     963             : 
     964           0 : UVContSubTVILayerFactory::UVContSubTVILayerFactory(Record &configuration) :
     965           0 :         ViiLayerFactory()
     966             : {
     967           0 :         configuration_p = configuration;
     968           0 : }
     969             : 
     970             : ViImplementation2*
     971           0 : UVContSubTVILayerFactory::createInstance(ViImplementation2* vii0) const
     972             : {
     973             :         // Make the UVContSubTVI, using supplied ViImplementation2, and return it
     974           0 :         ViImplementation2 *vii = new UVContSubTVI(vii0, configuration_p);
     975           0 :         return vii;
     976             : }
     977             : 
     978             : //////////////////////////////////////////////////////////////////////////
     979             : // UVContSubTransformEngine class
     980             : //////////////////////////////////////////////////////////////////////////
     981             : 
     982             : // -----------------------------------------------------------------------
     983             : //
     984             : // -----------------------------------------------------------------------
     985           0 : template<class T> UVContSubTransformEngine<T>::UVContSubTransformEngine(    UVContSubKernel<T> *kernel,
     986             :                                                                                                                                                         DataCubeMap *inputData,
     987             :                                                                                                                                                         DataCubeMap *outputData):
     988           0 :                                                                                                                         FreqAxisTransformEngine2<T>(inputData,outputData)
     989             : {
     990           0 :         uvContSubKernel_p = kernel;
     991           0 : }
     992             : 
     993             : // -----------------------------------------------------------------------
     994             : //
     995             : // -----------------------------------------------------------------------
     996           0 : template<class T> void UVContSubTransformEngine<T>::transform(      )
     997             : {
     998           0 :         uvContSubKernel_p->setDebug(debug_p);
     999           0 :         uvContSubKernel_p->kernel(inputData_p,outputData_p);
    1000           0 : }
    1001             : 
    1002             : //////////////////////////////////////////////////////////////////////////
    1003             : // UVContSubKernel class
    1004             : //////////////////////////////////////////////////////////////////////////
    1005             : 
    1006             : // -----------------------------------------------------------------------
    1007             : //
    1008             : // -----------------------------------------------------------------------
    1009           0 : template<class T> UVContSubKernel<T>::UVContSubKernel(      denoising::GslPolynomialModel<Double> *model,
    1010           0 :                                                                                                                 Vector<bool> *lineFreeChannelMask)
    1011             : {
    1012           0 :         model_p = model;
    1013           0 :         fitOrder_p = model_p->ncomponents()-1;
    1014           0 :         freqPows_p.reference(model_p->getModelMatrix());
    1015           0 :         frequencies_p.reference(model_p->getLinearComponentFloat());
    1016             : 
    1017           0 :         lineFreeChannelMask_p = lineFreeChannelMask ? lineFreeChannelMask : nullptr;
    1018           0 :         debug_p = False;
    1019           0 : }
    1020             : 
    1021             : // -----------------------------------------------------------------------
    1022             : //
    1023             : // -----------------------------------------------------------------------
    1024           0 : template<class T> void UVContSubKernel<T>::kernel(DataCubeMap *inputData,
    1025             :                                                   DataCubeMap *outputData)
    1026             : {
    1027             :         // Get input/output data
    1028           0 :         Vector<T> &outputVector = outputData->getVector<T>(MS::DATA);
    1029           0 :         Vector<T> &inputVector = inputData->getVector<T>(MS::DATA);
    1030             : 
    1031             :         // Apply line-free channel mask
    1032           0 :         Vector<bool> &inputFlags = inputData->getVector<bool>(MS::FLAG);
    1033           0 :         if (lineFreeChannelMask_p != nullptr)
    1034           0 :             inputFlags |= *lineFreeChannelMask_p;
    1035             : 
    1036             :         // Calculate number of valid data points and adapt fit
    1037           0 :         size_t validPoints = nfalse(inputFlags);
    1038           0 :         if (validPoints > 0)
    1039             :         {
    1040           0 :                 bool restoreDefaultPoly = False;
    1041           0 :                 uInt tmpFitOrder = fitOrder_p;
    1042             : 
    1043             :                 // Reduce fit order to match number of valid points
    1044           0 :                 if (validPoints <= fitOrder_p)
    1045             :                 {
    1046           0 :                         changeFitOrder(validPoints-1);
    1047           0 :                         restoreDefaultPoly = true;
    1048             :                 }
    1049             : 
    1050             :                 // Get weights
    1051           0 :                 Vector<Float> &inputWeight = inputData->getVector<Float>(MS::WEIGHT_SPECTRUM);
    1052             : 
    1053             :                 // Convert flags to mask
    1054           0 :                 Vector<bool> mask = !inputFlags;
    1055             : 
    1056             :                 // Calculate and subtract continuum
    1057           0 :                 chisq_p = kernelCore(inputVector,mask,inputWeight,outputVector);
    1058             : 
    1059             :                 // Go back to default fit order to match number of valid points
    1060           0 :                 if (restoreDefaultPoly)
    1061             :                 {
    1062           0 :                         changeFitOrder(tmpFitOrder);
    1063             :                 }
    1064           0 :         }
    1065             :         else
    1066             :         {
    1067           0 :                 defaultKernel(inputVector,outputVector);
    1068             :         }
    1069           0 : }
    1070             : 
    1071             : 
    1072             : //////////////////////////////////////////////////////////////////////////
    1073             : // UVContSubtractionKernel class
    1074             : //////////////////////////////////////////////////////////////////////////
    1075             : 
    1076             : // -----------------------------------------------------------------------
    1077             : //
    1078             : // -----------------------------------------------------------------------
    1079           0 : template<class T> UVContSubtractionKernel<T>::UVContSubtractionKernel(      denoising::GslPolynomialModel<Double>* model,
    1080             :                                                                                                                                                 Vector<bool> *lineFreeChannelMask):
    1081           0 :                                                                                                                                                 UVContSubKernel<T>(model,lineFreeChannelMask)
    1082             : {
    1083           0 :         changeFitOrder(fitOrder_p);
    1084           0 : }
    1085             : 
    1086             : // -----------------------------------------------------------------------
    1087             : //
    1088             : // -----------------------------------------------------------------------
    1089           0 : template<class T> void UVContSubtractionKernel<T>::changeFitOrder(size_t order)
    1090             : {
    1091           0 :         fitOrder_p = order;
    1092           0 :         Polynomial<AutoDiff<Float> > poly(order);
    1093           0 :         fitter_p.setFunction(poly); // poly It is cloned
    1094           0 :         fitter_p.asWeight(true);
    1095             : 
    1096           0 :         return;
    1097           0 : }
    1098             : 
    1099             : 
    1100             : // -----------------------------------------------------------------------
    1101             : //
    1102             : // -----------------------------------------------------------------------
    1103           0 : template<class T> void UVContSubtractionKernel<T>::defaultKernel(   Vector<Complex> &inputVector,
    1104             :                                                                                                                                         Vector<Complex> &outputVector)
    1105             : {
    1106           0 :         outputVector = inputVector;
    1107           0 :         return;
    1108             : }
    1109             : 
    1110             : // -----------------------------------------------------------------------
    1111             : //
    1112             : // -----------------------------------------------------------------------
    1113           0 : template<class T> void UVContSubtractionKernel<T>::defaultKernel(   Vector<Float> &inputVector,
    1114             :                                                                                                                                         Vector<Float> &outputVector)
    1115             : {
    1116           0 :         outputVector = inputVector;
    1117           0 :         return;
    1118             : }
    1119             : 
    1120             : // -----------------------------------------------------------------------
    1121             : //
    1122             : // -----------------------------------------------------------------------
    1123           0 : template<class T> Complex UVContSubtractionKernel<T>::kernelCore(   Vector<Complex> &inputVector,
    1124             :                                                                                                                                 Vector<bool> &inputFlags,
    1125             :                                                                                                                                 Vector<Float> &inputWeights,
    1126             :                                                                                                                                 Vector<Complex> &outputVector)
    1127             : {
    1128             :         // Fit for imaginary and real components separately
    1129           0 :         Vector<Float> realCoeff;
    1130           0 :         Vector<Float> imagCoeff;
    1131           0 :         realCoeff = fitter_p.fit(frequencies_p, real(inputVector), inputWeights, &inputFlags);
    1132           0 :         double realChisq = fitter_p.chiSquare();
    1133           0 :         imagCoeff = fitter_p.fit(frequencies_p, imag(inputVector), inputWeights, &inputFlags);
    1134           0 :         double imagChisq = fitter_p.chiSquare();
    1135             : 
    1136             :         // Fill output data
    1137           0 :         outputVector = inputVector;
    1138           0 :         outputVector -= Complex(realCoeff(0),imagCoeff(0));
    1139           0 :         for (uInt order_idx = 1; order_idx <= fitOrder_p; order_idx++)
    1140             :         {
    1141           0 :                 Complex coeff(realCoeff(order_idx),imagCoeff(order_idx));
    1142           0 :                 for (uInt chan_idx=0; chan_idx < outputVector.size(); chan_idx++)
    1143             :                 {
    1144           0 :                         outputVector(chan_idx) -= (freqPows_p(order_idx,chan_idx))*coeff;
    1145             :                 }
    1146             :         }
    1147             : 
    1148           0 :         if (debug_p)
    1149             :         {
    1150           0 :                 LogIO logger;
    1151           0 :                 logger << "fit order = " << fitOrder_p << LogIO::POST;
    1152           0 :                 logger << "realCoeff =" << realCoeff << LogIO::POST;
    1153           0 :                 logger << "imagCoeff =" << imagCoeff << LogIO::POST;
    1154           0 :                 logger << "inputFlags =" << inputFlags << LogIO::POST;
    1155           0 :                 logger << "inputWeights =" << inputWeights << LogIO::POST;
    1156           0 :                 logger << "inputVector =" << inputVector << LogIO::POST;
    1157           0 :                 logger << "outputVector =" << outputVector << LogIO::POST;
    1158           0 :         }
    1159             : 
    1160           0 :         return Complex(realChisq, imagChisq);
    1161           0 : }
    1162             : 
    1163             : // -----------------------------------------------------------------------
    1164             : //
    1165             : // -----------------------------------------------------------------------
    1166           0 : template<class T> Complex UVContSubtractionKernel<T>::kernelCore(   Vector<Float> &inputVector,
    1167             :                                                                                                                                 Vector<bool> &inputFlags,
    1168             :                                                                                                                                 Vector<Float> &inputWeights,
    1169             :                                                                                                                                 Vector<Float> &outputVector)
    1170             : {
    1171             :         // Fit model
    1172           0 :         Vector<Float> coeff;
    1173           0 :         coeff = fitter_p.fit(frequencies_p, inputVector, inputWeights, &inputFlags);
    1174           0 :         const double chisq = fitter_p.chiSquare();
    1175             : 
    1176             :         // Fill output data
    1177           0 :         outputVector = inputVector;
    1178           0 :         outputVector -= coeff(0);
    1179           0 :         for (uInt order_idx = 1; order_idx <= fitOrder_p; order_idx++)
    1180             :         {
    1181           0 :                 for (uInt chan_idx=0; chan_idx < outputVector.size(); chan_idx++)
    1182             :                 {
    1183           0 :                         outputVector(chan_idx) -= (freqPows_p(order_idx,chan_idx))*coeff(order_idx);
    1184             :                 }
    1185             :         }
    1186             : 
    1187           0 :         if (debug_p)
    1188             :         {
    1189           0 :                 LogIO logger;
    1190           0 :                 logger << "fit order = " << fitOrder_p << LogIO::POST;
    1191           0 :                 logger << "coeff =" << coeff << LogIO::POST;
    1192           0 :                 logger << "inputFlags =" << inputFlags << LogIO::POST;
    1193           0 :                 logger << "inputWeights =" << inputWeights << LogIO::POST;
    1194           0 :                 logger << "inputVector =" << inputVector << LogIO::POST;
    1195           0 :                 logger << "outputVector =" << outputVector << LogIO::POST;
    1196           0 :         }
    1197             : 
    1198           0 :         return Complex(chisq, chisq);
    1199           0 : }
    1200             : 
    1201             : 
    1202             : //////////////////////////////////////////////////////////////////////////
    1203             : // UVContEstimationKernel class
    1204             : //////////////////////////////////////////////////////////////////////////
    1205             : 
    1206             : // -----------------------------------------------------------------------
    1207             : //
    1208             : // -----------------------------------------------------------------------
    1209           0 : template<class T> UVContEstimationKernel<T>::UVContEstimationKernel(        denoising::GslPolynomialModel<Double>* model,
    1210             :                                                                                                                                                 Vector<bool> *lineFreeChannelMask):
    1211           0 :                                                                                                                                                 UVContSubKernel<T>(model,lineFreeChannelMask)
    1212             : {
    1213           0 :         changeFitOrder(fitOrder_p);
    1214           0 : }
    1215             : 
    1216             : // -----------------------------------------------------------------------
    1217             : //
    1218             : // -----------------------------------------------------------------------
    1219           0 : template<class T> void UVContEstimationKernel<T>::changeFitOrder(size_t order)
    1220             : {
    1221           0 :         fitOrder_p = order;
    1222           0 :         Polynomial<AutoDiff<Float> > poly(order);
    1223           0 :         fitter_p.setFunction(poly); // poly It is cloned
    1224           0 :         fitter_p.asWeight(true);
    1225             : 
    1226           0 :         return;
    1227           0 : }
    1228             : 
    1229             : // -----------------------------------------------------------------------
    1230             : //
    1231             : // -----------------------------------------------------------------------
    1232           0 : template<class T> void UVContEstimationKernel<T>::defaultKernel(Vector<Complex> &,
    1233             :                                                                                                                                 Vector<Complex> &outputVector)
    1234             : {
    1235           0 :         outputVector = 0;
    1236           0 :         return;
    1237             : }
    1238             : 
    1239             : // -----------------------------------------------------------------------
    1240             : //
    1241             : // -----------------------------------------------------------------------
    1242           0 : template<class T> void UVContEstimationKernel<T>::defaultKernel(Vector<Float> &,
    1243             :                                                                                                                                 Vector<Float> &outputVector)
    1244             : {
    1245           0 :         outputVector = 0;
    1246           0 :         return;
    1247             : }
    1248             : 
    1249             : // -----------------------------------------------------------------------
    1250             : //
    1251             : // -----------------------------------------------------------------------
    1252           0 : template<class T> Complex UVContEstimationKernel<T>::kernelCore(Vector<Complex> &inputVector,
    1253             :                                                                 Vector<bool> &inputFlags,
    1254             :                                                                 Vector<Float> &inputWeights,
    1255             :                                                                 Vector<Complex> &outputVector
    1256             :                                                                 )
    1257             : {
    1258             :         // Fit for imaginary and real components separately
    1259           0 :         Vector<Float> realCoeff;
    1260           0 :         Vector<Float> imagCoeff;
    1261           0 :         realCoeff = fitter_p.fit(frequencies_p, real(inputVector), inputWeights, &inputFlags);
    1262           0 :         double realChisq = fitter_p.chiSquare();
    1263             : 
    1264           0 :         imagCoeff = fitter_p.fit(frequencies_p, imag(inputVector), inputWeights, &inputFlags);
    1265           0 :         double imagChisq = fitter_p.chiSquare();
    1266             : 
    1267             :         // Fill output data
    1268           0 :         outputVector = Complex(realCoeff(0),imagCoeff(0));
    1269           0 :         for (uInt order_idx = 1; order_idx <= fitOrder_p; order_idx++)
    1270             :         {
    1271           0 :                 Complex coeff(realCoeff(order_idx),imagCoeff(order_idx));
    1272           0 :                 for (uInt chan_idx=0; chan_idx < outputVector.size(); chan_idx++)
    1273             :                 {
    1274           0 :                         outputVector(chan_idx) += (freqPows_p(order_idx,chan_idx))*coeff;
    1275             :                 }
    1276             :         }
    1277             : 
    1278           0 :         return Complex(realChisq, imagChisq);
    1279           0 : }
    1280             : 
    1281             : // -----------------------------------------------------------------------
    1282             : //
    1283             : // -----------------------------------------------------------------------
    1284           0 : template<class T> Complex UVContEstimationKernel<T>::kernelCore(    Vector<Float> &inputVector,
    1285             :                                                                                                                                 Vector<bool> &inputFlags,
    1286             :                                                                                                                                 Vector<Float> &inputWeights,
    1287             :                                                                                                                                 Vector<Float> &outputVector)
    1288             : {
    1289             :         // Fit model
    1290           0 :         Vector<Float> coeff;
    1291           0 :         coeff = fitter_p.fit(frequencies_p, inputVector, inputWeights, &inputFlags);
    1292           0 :         double chisq = fitter_p.chiSquare();
    1293             : 
    1294             :         // Fill output data
    1295           0 :         outputVector = coeff(0);
    1296           0 :         for (uInt order_idx = 1; order_idx <= fitOrder_p; order_idx++)
    1297             :         {
    1298           0 :                 for (uInt chan_idx=0; chan_idx < outputVector.size(); chan_idx++)
    1299             :                 {
    1300           0 :                         outputVector(chan_idx) += (freqPows_p(order_idx,chan_idx))*coeff(order_idx);
    1301             :                 }
    1302             :         }
    1303             : 
    1304           0 :         return Complex(chisq, chisq);
    1305           0 : }
    1306             : 
    1307             : //////////////////////////////////////////////////////////////////////////
    1308             : // UVContSubtractionDenoisingKernel class
    1309             : //////////////////////////////////////////////////////////////////////////
    1310             : 
    1311             : // -----------------------------------------------------------------------
    1312             : //
    1313             : // -----------------------------------------------------------------------
    1314           0 : template<class T> UVContSubtractionDenoisingKernel<T>::UVContSubtractionDenoisingKernel(denoising::GslPolynomialModel<Double>* model,
    1315             :                                                                                                                                                                                 size_t nIter,
    1316             :                                                                                                                                                                                 Vector<bool> *lineFreeChannelMask):
    1317           0 :                                                                                                                                                                                 UVContSubKernel<T>(model,lineFreeChannelMask)
    1318             : {
    1319           0 :         fitter_p.resetModel(*model);
    1320           0 :         fitter_p.setNIter(nIter);
    1321           0 : }
    1322             : 
    1323             : // -----------------------------------------------------------------------
    1324             : //
    1325             : // -----------------------------------------------------------------------
    1326           0 : template<class T> void UVContSubtractionDenoisingKernel<T>::changeFitOrder(size_t order)
    1327             : {
    1328           0 :         fitOrder_p = order;
    1329           0 :         fitter_p.resetNComponents(order+1);
    1330           0 :         return;
    1331             : }
    1332             : 
    1333             : 
    1334             : // -----------------------------------------------------------------------
    1335             : //
    1336             : // -----------------------------------------------------------------------
    1337           0 : template<class T> void UVContSubtractionDenoisingKernel<T>::defaultKernel(  Vector<T> &inputVector,
    1338             :                                                                                                                                                         Vector<T> &outputVector)
    1339             : {
    1340           0 :         outputVector = inputVector;
    1341           0 :         return;
    1342             : }
    1343             : 
    1344             : // -----------------------------------------------------------------------
    1345             : //
    1346             : // -----------------------------------------------------------------------
    1347           0 : template<class T> Complex UVContSubtractionDenoisingKernel<T>::kernelCore(  Vector<T> &inputVector,
    1348             :                                                                                                                                                 Vector<bool> &inputFlags,
    1349             :                                                                                                                                                 Vector<Float> &inputWeights,
    1350             :                                                                                                                                                 Vector<T> &outputVector)
    1351           0 : {       fitter_p.setWeightsAndFlags(inputWeights,inputFlags);
    1352           0 :     vector<T> coeff;
    1353           0 :     Complex chisq;
    1354           0 :     tie(coeff, chisq) = fitter_p.calcFitCoeff(inputVector);
    1355             : 
    1356           0 :         Vector<T> model(outputVector.size());
    1357           0 :         fitter_p.calcFitModel(model);
    1358             : 
    1359           0 :         outputVector = inputVector;
    1360           0 :         outputVector -= model;
    1361             : 
    1362             :         /*
    1363             :         fitter_p.setWeightsAndFlags(inputWeights,inputFlags);
    1364             :         Vector<T> coeff = fitter_p.calcFitCoeff(inputVector);
    1365             : 
    1366             :         // Fill output data
    1367             :         outputVector = inputVector;
    1368             :         outputVector -= coeff(0);
    1369             :         for (uInt order_idx = 1; order_idx <= fitOrder_p; order_idx++)
    1370             :         {
    1371             :                 for (uInt chan_idx=0; chan_idx < outputVector.size(); chan_idx++)
    1372             :                 {
    1373             :                         outputVector(chan_idx) -= (freqPows_p(order_idx,chan_idx))*coeff(order_idx);
    1374             :                 }
    1375             :         }
    1376             :         */
    1377             : 
    1378             :         /*
    1379             :         if (debug_p)
    1380             :         {
    1381             :                 LogIO logger;
    1382             :                 logger << "freqPows_p =" << freqPows_p << LogIO::POST;
    1383             :                 logger << "fit order = " << fitOrder_p << LogIO::POST;
    1384             :                 logger << "coeff =" << coeff << LogIO::POST;
    1385             :                 logger << "inputFlags =" << inputFlags << LogIO::POST;
    1386             :                 logger << "inputWeights =" << inputWeights << LogIO::POST;
    1387             :                 logger << "inputVector =" << inputVector << LogIO::POST;
    1388             :                 logger << "outputVector =" << outputVector << LogIO::POST;
    1389             :         }
    1390             :         */
    1391             : 
    1392           0 :         return chisq;
    1393           0 : }
    1394             : 
    1395             : //////////////////////////////////////////////////////////////////////////
    1396             : // UVContEstimationDenoisingKernel class
    1397             : //////////////////////////////////////////////////////////////////////////
    1398             : 
    1399             : // -----------------------------------------------------------------------
    1400             : //
    1401             : // -----------------------------------------------------------------------
    1402           0 : template<class T> UVContEstimationDenoisingKernel<T>::UVContEstimationDenoisingKernel(      denoising::GslPolynomialModel<Double>* model,
    1403             :                                                                                                                                                                                 size_t nIter,
    1404             :                                                                                                                                                                                 Vector<bool> *lineFreeChannelMask):
    1405           0 :                                                                                                                                                                                 UVContSubKernel<T>(model,lineFreeChannelMask)
    1406             : {
    1407           0 :         fitter_p.resetModel(*model);
    1408           0 :         fitter_p.setNIter(nIter);
    1409           0 : }
    1410             : 
    1411             : // -----------------------------------------------------------------------
    1412             : //
    1413             : // -----------------------------------------------------------------------
    1414           0 : template<class T> void UVContEstimationDenoisingKernel<T>::changeFitOrder(size_t order)
    1415             : {
    1416           0 :         fitOrder_p = order;
    1417           0 :         fitter_p.resetNComponents(order+1);
    1418           0 :         return;
    1419             : }
    1420             : 
    1421             : // -----------------------------------------------------------------------
    1422             : //
    1423             : // -----------------------------------------------------------------------
    1424           0 : template<class T> void UVContEstimationDenoisingKernel<T>::defaultKernel(   Vector<T> &,
    1425             :                                                                                                                                                         Vector<T> &outputVector)
    1426             : {
    1427           0 :         outputVector = 0;
    1428           0 :         return;
    1429             : }
    1430             : 
    1431             : // -----------------------------------------------------------------------
    1432             : //
    1433             : // -----------------------------------------------------------------------
    1434           0 : template<class T> Complex UVContEstimationDenoisingKernel<T>::kernelCore(   Vector<T> &inputVector,
    1435             :                                                                                                                                                 Vector<bool> &inputFlags,
    1436             :                                                                                                                                                 Vector<Float> &inputWeights,
    1437             :                                                                                                                                                 Vector<T> &outputVector)
    1438             : {
    1439           0 :         fitter_p.setWeightsAndFlags(inputWeights,inputFlags);
    1440           0 :     std::vector<T> coeff;
    1441           0 :     Complex chisq;
    1442           0 :     tie(coeff, chisq) = fitter_p.calcFitCoeff(inputVector);
    1443           0 :         fitter_p.calcFitModel(outputVector);
    1444             : 
    1445             :         /*
    1446             :         fitter_p.setWeightsAndFlags(inputWeights,inputFlags);
    1447             :         Vector<T> coeff = fitter_p.calcFitCoeff(inputVector);
    1448             : 
    1449             :         // Fill output data
    1450             :         outputVector = coeff(0);
    1451             :         for (uInt order_idx = 1; order_idx <= fitOrder_p; order_idx++)
    1452             :         {
    1453             :                 for (uInt chan_idx=0; chan_idx < outputVector.size(); chan_idx++)
    1454             :                 {
    1455             :                         outputVector(chan_idx) += (freqPows_p(order_idx,chan_idx))*coeff(order_idx);
    1456             :                 }
    1457             :         }
    1458             :         */
    1459             : 
    1460           0 :         return chisq;
    1461           0 : }
    1462             : 
    1463             : } //# NAMESPACE VI - END
    1464             : 
    1465             : } //# NAMESPACE CASA - END
    1466             : 
    1467             : 

Generated by: LCOV version 1.16