LCOV - code coverage report
Current view: top level - mstransform/TVI - UVContSubTVI.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 470 641 73.3 %
Date: 2024-12-11 20:54:31 Functions: 39 75 52.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          54 : UVContSubTVI::UVContSubTVI(     ViImplementation2 * inputVii,
      50          54 :                                                                 const Record &configuration):
      51          54 :                                                                 FreqAxisTVI (inputVii)
      52             : {
      53          54 :         fitOrder_p = 0;
      54          54 :         want_cont_p = False;
      55          54 :         withDenoisingLib_p = true;
      56          54 :         nThreads_p = 1;
      57          54 :         niter_p = 1;
      58             : 
      59          54 :         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          54 :         const auto fitspec = parseConfiguration(configuration);
      65             : 
      66          44 :         initialize(fitspec);
      67         104 : }
      68             : 
      69          88 : UVContSubTVI::~UVContSubTVI()
      70             : {
      71          44 :     inputFrequencyMap_p.clear();
      72          88 : }
      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          74 : bool isFieldIndex(const std::string &str) {
      83          74 :     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          38 : std::vector<int> stringToFieldIdxs(const std::string &str)
      96             : {
      97          38 :     stringstream stream(str);
      98          38 :     vector<int> result;
      99          77 :     while(stream.good()) {
     100          41 :         string token;
     101          41 :         getline(stream, token, ',' );
     102          41 :         token.erase(std::remove(token.begin(), token.end(), ' '), token.end());
     103          41 :         if (!isFieldIndex(token)) {
     104           2 :             throw AipsError("Invalid field index: " + token + " (in " + str + ").");
     105             : 
     106             :         }
     107             :         try {
     108          39 :             auto idx = std::stoi(token);
     109          39 :             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          41 :     }
     114          72 :     return result;
     115          40 : }
     116             : 
     117          54 : InFitSpecMap UVContSubTVI::parseFitSpec(const Record &configuration) const
     118             : {
     119          54 :     InFitSpecMap fitspec;
     120             : 
     121          54 :     const auto exists = configuration.fieldNumber ("fitspec");
     122          54 :     if (exists < 0) {
     123           0 :         return fitspec;
     124             :     }
     125             : 
     126             :     try {
     127             :         // fitspec is a simple string (spw:chan MSSelection syntax)
     128          54 :         String specStr;
     129          75 :         configuration.get(exists, specStr);
     130             : 
     131          99 :         std::vector <InFitSpec> specs = { InFitSpec(specStr, fitOrder_p) };
     132             :         // -1 (all fields): global fit spw:chan string and global fitOrder
     133          33 :         fitspec.insert({-1, specs});
     134          75 :     } catch(AipsError &exc) {
     135             :         // alternatively, fitspec must be a record with field/spw specs
     136          21 :         fitspec = parseDictFitSpec(configuration);
     137          21 :     }
     138          44 :     return fitspec;
     139          10 : }
     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          75 : std::vector<unsigned int> stringToSPWIdxs(const std::string &spwStr,
     153             :                                           bool allowSemicolon=false) {
     154          75 :     if (0 == spwStr.length()) {
     155           0 :         throw AipsError("Unexpected empty SPW IDs string");
     156             :     }
     157          75 :     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          75 :     vector<unsigned int> result;
     163          75 :     stringstream stream(spwStr);
     164         150 :     while(stream.good()) {
     165          76 :         string token;
     166          76 :         getline(stream, token, ',' );
     167          76 :         token.erase(std::remove(token.begin(), token.end(), ' '), token.end());
     168          76 :         if (!allowSemicolon && !isFieldIndex(token)) {
     169           1 :             throw AipsError("Invalid SPW index: " + token + " (in " + spwStr + ")");
     170             :         }
     171             :         try {
     172          75 :             auto idx = std::stoi(token);
     173          75 :             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          76 :     }
     178         148 :     return result;
     179          76 : }
     180             : 
     181             : /**
     182             :  * Get max valid FIELD IDs for this iterator. MSv2 uses the FIELD
     183             :  * table row index as FIELD ID.
     184             :  */
     185          21 : rownr_t UVContSubTVI::getMaxMSFieldID() const
     186             : {
     187          21 :     const auto &fieldsTable = getVii()->fieldSubtablecols();
     188          21 :     return fieldsTable.nrow() - 1;
     189             : }
     190             : 
     191          28 : void UVContSubTVI::insertToFieldSpecMap(const std::vector<int> &fieldIdxs,
     192             :                                         const InFitSpec &spec,
     193             :                                         InFitSpecMap &fitspec) const
     194             : {
     195          57 :     for (const auto fid: fieldIdxs) {
     196          29 :         const auto fieldFound = fitspec.find(fid);
     197          29 :         if (fieldFound == fitspec.end()) {
     198          69 :             std::vector<InFitSpec> firstSpw = { spec };
     199          23 :             fitspec[fid] = firstSpw;
     200          23 :         } else {
     201           6 :             fitspec[fid].emplace_back(spec);
     202             :         }
     203             : 
     204             :     }
     205          28 : }
     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          24 : void UVContSubTVI::parseFieldSubDict(const Record &fieldRec,
     216             :                                      const std::vector<int> &fieldIdxs,
     217             :                                      InFitSpecMap &fitspec) const
     218             : {
     219          24 :     std::set<unsigned int> spwsSeen;
     220          52 :     for (unsigned int spw=0; spw < fieldRec.nfields(); ++spw) {
     221          32 :         const auto spwRec = fieldRec.subRecord(RecordFieldId(spw));
     222          64 :         std::string spwStr  = fieldRec.name(RecordFieldId(spw));
     223          32 :         const auto spwIdxs = stringToSPWIdxs(spwStr, false);
     224          61 :         for (const auto sid : spwIdxs) {
     225          31 :             if (spwsSeen.insert(sid).second == false) {
     226           3 :                 throw AipsError("Error in fitspec. SPW " + to_string(sid) + " is given "
     227           2 :                                 "multiple times. Found for SPW subdict '" + spwStr +
     228           2 :                                 "' and other subdicts(s).");
     229             :             }
     230             :         }
     231             :         try {
     232          31 :             const std::string chanStr = spwRec.asString(RecordFieldId("chan"));
     233          29 :             if (!chanStr.empty()) {
     234          26 :                 spwStr = "";
     235          52 :                 for (const auto sid : spwIdxs) {
     236          52 :                     const auto spw_chan = to_string(sid) + ":" + chanStr;
     237          26 :                     if (spwStr.empty()) {
     238          26 :                         spwStr = spw_chan;
     239             :                     } else {
     240           0 :                         spwStr += "," + spw_chan;
     241             :                     }
     242          26 :                 }
     243             :             }
     244          30 :         } catch (const AipsError &exc) {
     245           1 :             throw AipsError("Error trying to get chan value in subdict for spw "
     246           2 :                             + spwStr + ", " + exc.what());
     247           1 :         }
     248             : 
     249          29 :         int polOrder = fitOrder_p;
     250             :         try {
     251          30 :             polOrder  = spwRec.asInt(RecordFieldId("fitorder"));
     252           1 :         } catch (const AipsError &exc) {
     253           1 :             throw AipsError("Error trying to get fitorder value in subdict for spw "
     254           2 :                             + spwStr + ", " + exc.what());
     255           1 :         }
     256          28 :         if (polOrder < 0) {
     257           0 :             throw AipsError("Fit order cannot be negative. Value given: " +
     258           0 :                             to_string(polOrder));
     259             :         }
     260             : 
     261          28 :         const auto spec = std::make_pair(spwStr, polOrder);
     262          28 :         insertToFieldSpecMap(fieldIdxs, spec, fitspec);
     263          39 :     }
     264          24 : }
     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          21 : InFitSpecMap UVContSubTVI::parseDictFitSpec(const Record &configuration) const
     276             : {
     277          21 :     const Record rawFieldFitspec = configuration.asRecord("fitspec");
     278          21 :     if (rawFieldFitspec.empty()) {
     279           0 :         throw AipsError("The dictionary 'fitspec' of fit specifications is empty!");
     280             :     }
     281             : 
     282          21 :     const auto maxMSField = getMaxMSFieldID();
     283          21 :     InFitSpecMap fitspec;
     284          21 :     std::set<unsigned int> fieldsSeen;
     285             :     // iterate through fields given in fitspec
     286          49 :     for (unsigned int rid=0; rid < rawFieldFitspec.nfields(); ++rid) {
     287          76 :         const std::string fieldsStr = rawFieldFitspec.name(RecordFieldId(rid));
     288          38 :         const auto fieldIdxs = stringToFieldIdxs(fieldsStr);
     289          72 :         for (const auto fid: fieldIdxs) {
     290             :             // check that the field is in the MS
     291          39 :             if (fid < 0 || static_cast<unsigned int>(fid) > maxMSField) {
     292           4 :                 throw AipsError("Wrong field ID given: " +
     293           6 :                                 std::to_string(fid) +
     294             :                                 ". This MeasurementSet has field IDs between"
     295           8 :                                 " 0 and " + std::to_string(maxMSField));
     296             :             }
     297          37 :             if (fieldsSeen.insert(fid).second == false) {
     298           3 :                 throw AipsError("Error in fitspec. Field " + to_string(fid) + " is given "
     299           2 :                                 "multiple times. Found for field subdict '" + fieldsStr +
     300           2 :                                 "' and other subdict(s).");
     301             :             }
     302             :         }
     303             : 
     304          33 :         std::string noneStr;
     305          33 :         bool subRecordIsString = true;
     306             :         try {
     307          57 :             noneStr = rawFieldFitspec.asString(RecordFieldId(rid));
     308          24 :         } catch (const AipsError &exc) {
     309          24 :             subRecordIsString = false;
     310          24 :         }
     311          33 :         if (subRecordIsString){
     312           9 :             if (noneStr != "NONE") {
     313           1 :                 throw AipsError("Wrong value found in fitspec, field subdict for field: '"
     314           2 :                                 + fieldsStr + "', value: '" +
     315           2 :                                 noneStr + "'. Only 'NONE' is accepted (= do not fit for " +
     316           2 :                                 "any SPW).");
     317             :             }
     318             :         } else {
     319          24 :             const Record fieldRec = rawFieldFitspec.subRecord(RecordFieldId(rid));
     320          24 :             parseFieldSubDict(fieldRec, fieldIdxs, fitspec);
     321          24 :         }
     322          51 :     }
     323             : 
     324          22 :     return fitspec;
     325          41 : }
     326             : 
     327         118 : std::string fieldTextFromId(int idx)
     328             : {
     329         118 :     std::string name;
     330         118 :     if (idx >= 0) {
     331          52 :         name = std::to_string(idx);
     332             :     } else {
     333          66 :         name = "all fields";
     334             :     }
     335         118 :     return name;
     336           0 : }
     337             : 
     338          44 : void UVContSubTVI::printInputFitSpec(const InFitSpecMap &fitspec) const
     339             : {
     340          44 :     if (fitspec.size() > 0) {
     341          88 :         logger_p << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     342             :                  << "Fitspec (order and spw:line-free channel) specification is: "
     343          88 :                  << LogIO::POST;
     344             : 
     345          97 :         for (const auto &elem: fitspec) {
     346          53 :             const auto &specs = elem.second;
     347         112 :             for (const auto &oneSpw : specs) {
     348         118 :                 logger_p << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     349          59 :                          << "   field: " << fieldTextFromId(elem.first)
     350         118 :                          << ". " << oneSpw.second << ", '" << oneSpw.first << "'"
     351         118 :                          << 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          44 : }
     359             : 
     360             : // -----------------------------------------------------------------------
     361             : //
     362             : // -----------------------------------------------------------------------
     363          54 : InFitSpecMap UVContSubTVI::parseConfiguration(const Record &configuration)
     364             : {
     365          54 :         auto exists = configuration.fieldNumber ("fitorder");
     366          54 :         if (exists >= 0)
     367             :         {
     368          54 :                 configuration.get (exists, fitOrder_p);
     369             : 
     370          54 :                 if (fitOrder_p > 0)
     371             :                 {
     372          18 :                         logger_p        << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     373          18 :                                                 << "Global/default fit order is " << fitOrder_p << LogIO::POST;
     374             :                 }
     375             :         }
     376             : 
     377          54 :         exists = configuration.fieldNumber ("want_cont");
     378          54 :         if (exists >= 0)
     379             :         {
     380          54 :                 configuration.get (exists, want_cont_p);
     381             : 
     382          54 :                 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          54 :         const auto fitspec = parseFitSpec(configuration);
     391          44 :         printInputFitSpec(fitspec);
     392             : 
     393          44 :         exists = configuration.fieldNumber ("writemodel");
     394          44 :         if (exists >= 0)
     395             :         {
     396          44 :             configuration.get(exists, precalcModel_p);
     397          44 :             if (precalcModel_p)
     398             :             {
     399           6 :                 logger_p        << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     400             :                                 << "Producing continuum estimate in the MODEL_DATA column"
     401           6 :                                 << LogIO::POST;
     402             :             }
     403             :         }
     404             : 
     405          44 :         exists = configuration.fieldNumber ("denoising_lib");
     406          44 :         if (exists >= 0)
     407             :         {
     408          44 :                 configuration.get (exists, withDenoisingLib_p);
     409             : 
     410          44 :                 if (withDenoisingLib_p)
     411             :                 {
     412          86 :                         logger_p << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     413             :                                  << "Using GSL based multiparameter regression with linear "
     414          86 :                                  << "least-squares fitting" << LogIO::POST;
     415             :                 }
     416             :         }
     417             : 
     418          44 :         exists = configuration.fieldNumber ("nthreads");
     419          44 :         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          44 :         exists = configuration.fieldNumber ("niter");
     451          44 :         if (exists >= 0)
     452             :         {
     453          44 :                 configuration.get (exists, niter_p);
     454             : 
     455          44 :                 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          44 :         exists = configuration.fieldNumber ("allowed_spws");
     464          44 :         if (exists >= 0)
     465             :         {
     466          44 :                 String allowed;
     467          44 :                 configuration.get (exists, allowed);
     468          44 :                 allowedSpws_p = allowed;
     469          44 :         }
     470             : 
     471          44 :         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          37 : void UVContSubTVI::spwInputChecks(const MeasurementSet *msVii,
     485             :                                   MSSelection &spwChan) const {
     486             :     // note: spwChan should be const (if getSpwList() were const)
     487          37 :     if (!allowedSpws_p.empty()) {
     488           5 :         const auto usedSpws = spwChan.getSpwList(msVii).tovector();
     489           5 :         MSSelection checker;
     490           5 :         checker.setSpwExpr(allowedSpws_p);
     491           5 :         const auto allowed = checker.getSpwList(msVii).tovector();
     492          10 :         for (const auto spw : usedSpws ) {
     493           5 :             if (std::find(allowed.begin(), allowed.end(), spw) == allowed.end()) {
     494           8 :                 logger_p << LogIO::WARN << LogOrigin("UVContSubTVI", __FUNCTION__)
     495             :                          << "SPW " << spw << " is used in fitspec but is not included in "
     496           4 :                          << "the SPW selection ('" << allowedSpws_p <<  "'), please "
     497           8 :                          << "double-check the spw and fitspec parameters." << LogIO::POST;
     498             :             }
     499             :         }
     500           5 :     }
     501          37 : }
     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          37 : unordered_map<int, vector<int>> UVContSubTVI::makeLineFreeChannelSelMap(std::string
     513             :                                                                         spwChanStr) const
     514             : {
     515          37 :     MSSelection mssel;
     516          37 :     mssel.setSpwExpr(spwChanStr);
     517             :     // This will access the MS directly: far from ideal (CAS-11638) but no easy solution
     518          37 :     const auto msVii = &(inputVii_p->ms());
     519             : 
     520          37 :     spwInputChecks(msVii, mssel);
     521             : 
     522             :     // Create line-free channel map based on MSSelection channel ranges
     523          37 :     const auto spwchan = mssel.getChanList(msVii);
     524          37 :     const auto nSelections = spwchan.shape()[0];
     525          37 :     unordered_map<int,vector<int>>  lineFreeChannelSelMap;
     526         109 :     for (uInt selection_i=0; selection_i<nSelections; ++selection_i)
     527             :     {
     528          72 :         auto spw = spwchan(selection_i, 0);
     529          72 :         if (lineFreeChannelSelMap.find(spw) == lineFreeChannelSelMap.end())
     530             :         {
     531          43 :             lineFreeChannelSelMap[spw].clear(); // Accessing the vector creates it
     532             :         }
     533             : 
     534          72 :         const auto channelStart = spwchan(selection_i, 1);
     535          72 :         const auto channelStop = spwchan(selection_i, 2);
     536          72 :         const auto channelStep = spwchan(selection_i, 3);
     537       28128 :         for (auto inpChan=channelStart; inpChan<=channelStop; inpChan += channelStep)
     538             :         {
     539       28056 :             lineFreeChannelSelMap[spw].push_back(inpChan);
     540             :         }
     541             :     }
     542             : 
     543          74 :     return lineFreeChannelSelMap;
     544          37 : }
     545             : 
     546             : // -----------------------------------------------------------------------
     547             : //
     548             : // -----------------------------------------------------------------------
     549          37 : void UVContSubTVI::populatePerFieldSpec(int fieldID,
     550             :                                         const std::vector<InFitSpec> &fitSpecs)
     551             : {
     552          37 :     std::unordered_map<int, int> perSpwFitOrder;
     553          37 :     std::string fullSpwStr = "";
     554          80 :     for (const auto &spec : fitSpecs) {
     555          43 :         if (fullSpwStr == "NONE") {
     556           0 :             break;
     557          43 :         } else if (fullSpwStr.length() == 0) {
     558          37 :             fullSpwStr = spec.first;
     559             :         } else {
     560             :             // MSSelection syntax spw:chan, SPWs separated by commas
     561           6 :             fullSpwStr += "," + spec.first;
     562             :         }
     563          43 :         auto spws = stringToSPWIdxs(spec.first, true);
     564          86 :         for (const auto sid : spws) {
     565          43 :             perSpwFitOrder[sid] = spec.second;
     566             :         }
     567          43 :     }
     568             : 
     569          37 :     auto lineFreeChannelSelMap = makeLineFreeChannelSelMap(fullSpwStr);
     570             : 
     571             :     // Create line-free channel mask, spw->(channel_mask, fit_order)
     572          37 :     unordered_map<int, FitSpec> lineFreeChannelMaskMap;   // rename: fitSpecMap
     573         410 :     for (auto const spwInp: spwInpChanIdxMap_p)
     574             :     {
     575         373 :         const auto spw = spwInp.first;
     576         373 :         if (lineFreeChannelMaskMap.find(spw) == lineFreeChannelMaskMap.end())
     577             :         {
     578         373 :             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         330 :                 lineFreeChannelMaskMap[spw].lineFreeChannelMask = Vector<bool>();
     584             :             } else {
     585          43 :                 auto &mask = lineFreeChannelMaskMap[spw].lineFreeChannelMask;
     586          43 :                 mask = Vector<bool>(spwInp.second.size(), true);
     587       28099 :                 for (uInt selChanIdx=0; selChanIdx<lineFreeChannelSelMap[spw].size();
     588             :                      ++selChanIdx)
     589             :                 {
     590       28056 :                     const auto selChan = lineFreeChannelSelMap[spw][selChanIdx];
     591       28056 :                     mask(selChan) = False;
     592             :                 }
     593             :             }
     594             : 
     595         373 :             unsigned int fitOrder = fitOrder_p;
     596         373 :             const auto find = perSpwFitOrder.find(spw);
     597         373 :             if (find != perSpwFitOrder.end()) {
     598          43 :                 fitOrder = find->second;
     599             :             }
     600         373 :             lineFreeChannelMaskMap[spw].fitOrder = fitOrder;
     601             :         }
     602         373 :     }
     603             : 
     604             :     // Poppulate per field map: field -> spw -> fit spec
     605             :     // emplace struct (linefreechannelmaskmap, + fitorder)
     606          37 :     perFieldSpecMap_p.emplace(fieldID, lineFreeChannelMaskMap);
     607          37 : }
     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          44 : void UVContSubTVI::fitSpecToPerFieldMap(const InFitSpecMap &fitspec)
     615             : {
     616             :      // Process line-free channel specifications
     617          97 :     for (const auto item: fitspec) {
     618          53 :         unordered_map<int, FitSpec> fieldSpecMap;
     619             :         // Parse line-free channel selection using MSSelection syntax
     620          53 :         const auto fieldID = item.first;
     621          53 :         const auto &specs = item.second;
     622          53 :         bool noneFound = false;
     623         112 :         for (const auto spwSpec : specs) {
     624          59 :             const auto spwStr = spwSpec.first;
     625          59 :             const auto order = spwSpec.second;
     626          59 :             const auto fieldName = fieldTextFromId(fieldID);
     627         118 :             logger_p << LogIO::NORMAL << LogOrigin("UVContSubTVI", __FUNCTION__)
     628             :                      << "Parsing fit spw:chan string and order for field: " << fieldName
     629         118 :                      << ", spw/chan: '" << spwStr << "', order: " << order << LogIO::POST;
     630          59 :             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          59 :         }
     638             : 
     639          53 :         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          53 :         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          16 :             if (-1 == fieldID) {
     649          16 :                 perFieldSpecMap_p.emplace(fieldID, fieldSpecMap);
     650             :             }
     651          16 :             continue;
     652             :         }
     653             : 
     654          37 :         populatePerFieldSpec(fieldID, specs);
     655          69 :     }
     656          44 : }
     657             : 
     658             : // -----------------------------------------------------------------------
     659             : //
     660             : // -----------------------------------------------------------------------
     661          44 : void UVContSubTVI::initialize(const InFitSpecMap &fitspec)
     662             : {
     663             :     // Populate nchan input-output maps
     664         490 :     for (auto spwInp: spwInpChanIdxMap_p)
     665             :     {
     666         446 :         auto spw = spwInp.first;
     667         446 :         spwOutChanNumMap_p[spw] = spwInp.second.size();
     668         446 :     }
     669             : 
     670          44 :     fitSpecToPerFieldMap(fitspec);
     671          44 : }
     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        2875 : void UVContSubTVI::savePrecalcModel(const Cube<Complex> & origVis,
     695             :                                     const Cube<Complex> & contSubVis) const
     696             : {
     697             :     // save it for visibilityModel
     698        2875 :     if (precalcModel_p) {
     699             :         // Or otherwise the next assignment would fail a conform check
     700          53 :         if (precalcModelVis_p.shape() != contSubVis.shape()) {
     701           3 :             precalcModelVis_p.resize(contSubVis.shape());
     702             :         }
     703             : 
     704          53 :         precalcModelVis_p = origVis - contSubVis;
     705             :     }
     706        2875 : }
     707             : 
     708             : // -----------------------------------------------------------------------
     709             : //
     710             : // -----------------------------------------------------------------------
     711        2855 : void UVContSubTVI::visibilityObserved (Cube<Complex> & vis) const
     712             : {
     713             :     // Get input VisBuffer
     714        2855 :     VisBuffer2 *vb = getVii()->getVisBuffer();
     715             : 
     716             :     // Get weightSpectrum from sigmaSpectrum
     717        2855 :     Cube<Float> weightSpFromSigmaSp;
     718        2855 :     weightSpFromSigmaSp.resize(vb->sigmaSpectrum().shape(),False);
     719        2855 :     weightSpFromSigmaSp = vb->sigmaSpectrum(); // = Operator makes a copy
     720        2855 :     arrayTransformInPlace (weightSpFromSigmaSp,sigmaToWeight);
     721             : 
     722             :     // Transform data
     723        2855 :     transformDataCube(vb->visCube(),weightSpFromSigmaSp,vis);
     724             : 
     725        2855 :     savePrecalcModel(vb->visCube(), vis);
     726        2855 : }
     727             : 
     728             : // -----------------------------------------------------------------------
     729             : //
     730             : // -----------------------------------------------------------------------
     731          20 : void UVContSubTVI::visibilityCorrected (Cube<Complex> & vis) const
     732             : {
     733             :     // Get input VisBuffer
     734          20 :     VisBuffer2 *vb = getVii()->getVisBuffer();
     735             : 
     736             :     // Transform data
     737          20 :     transformDataCube(vb->visCubeCorrected(),vb->weightSpectrum(),vis);
     738             : 
     739          20 :     savePrecalcModel(vb->visCubeCorrected(), vis);
     740          20 : }
     741             : 
     742             : // -----------------------------------------------------------------------
     743             : //
     744             : // -----------------------------------------------------------------------
     745          53 : void UVContSubTVI::visibilityModel (Cube<Complex> & vis) const
     746             : {
     747             :         // Get input VisBuffer
     748          53 :         VisBuffer2 *vb = getVii()->getVisBuffer();
     749             : 
     750             :         // from visiblityObserved we have calculated the polynomial subtraction
     751          53 :         if (precalcModel_p && precalcModelVis_p.shape() == vb->visCubeModel().shape()) {
     752          53 :             vis = precalcModelVis_p;
     753          53 :             return;
     754             :         }
     755             : 
     756             :         // Transform data
     757           0 :         transformDataCube(vb->visCubeModel(),vb->weightSpectrum(),vis);
     758             : 
     759           0 :         return;
     760             : }
     761             : 
     762             : // -----------------------------------------------------------------------
     763             : //
     764             : // -----------------------------------------------------------------------
     765          44 : void UVContSubTVI::result(Record &res) const
     766             : {
     767          44 :     auto acc = result_p.getAccumulatedResult();
     768          44 :     res.defineRecord("uvcontsub", acc);
     769          44 : }
     770             : 
     771             : // -----------------------------------------------------------------------
     772             : //
     773             : // -----------------------------------------------------------------------
     774        2875 : 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        2875 :     VisBuffer2 *vb = getVii()->getVisBuffer();
     780             : 
     781        2875 :     auto fieldID = vb->fieldId()[0];
     782             :     // First check the "all fields" (no per-individual field list in fitspec)
     783        2875 :     auto fieldMapIt = perFieldSpecMap_p.find(-1);
     784        2875 :     if (fieldMapIt == perFieldSpecMap_p.end()) {
     785             :         // otherwise, check for individual fields (coming from a fitspec list)
     786        1205 :         fieldMapIt = perFieldSpecMap_p.find(fieldID);
     787        1205 :         if (fieldMapIt == perFieldSpecMap_p.end()) {
     788             :             // This was a "NONE" = no-subtraction for this field ==> no-op
     789         120 :             outputVis = inputVis;
     790        1201 :             return;
     791             :         }
     792             :     }
     793             : 
     794        2755 :     Int spwId = vb->spectralWindows()(0);
     795             : 
     796             :     // Get input line-free channel mask and fitorder
     797        2755 :     Vector<bool> *lineFreeChannelMask = nullptr;
     798        2755 :     auto fitOrder = fitOrder_p;
     799        2755 :     auto spwMap = fieldMapIt->second;
     800        2755 :     auto maskLookup = spwMap.find(spwId);
     801        2755 :     if (maskLookup != spwMap.end())
     802             :     {
     803        1834 :         if (maskLookup->second.lineFreeChannelMask.nelements() == 0) {
     804             :             // This was a non-selected SPW in a non-empty SPW selection string ==> no-op
     805        1081 :             outputVis = inputVis;
     806        1081 :             return;
     807             :         } else {
     808         753 :             lineFreeChannelMask = &(maskLookup->second.lineFreeChannelMask);
     809         753 :             fitOrder = maskLookup->second.fitOrder;
     810             :         }
     811             :     }
     812             : 
     813             :     // Get polynomial model for this SPW (depends on number of channels and gridding)
     814        1674 :     const auto freqIter = inputFrequencyMap_p.find(spwId);
     815        1674 :     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        1674 :         reset(new denoising::GslPolynomialModel<double>(inputFrequencies, fitOrder));
     820             : 
     821             :     // Reshape output data before passing it to the DataCubeHolder
     822        1674 :     outputVis.resize(getVisBuffer()->getShape(),False);
     823             : 
     824             :     // Get input flag Cube
     825        1674 :     const Cube<bool> &flagCube = vb->flagCube();
     826             : 
     827             :     // Transform data
     828        1674 :     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        1674 :         auto scanID = vb->scan()[0];
     855        1674 :         uInt nCorrs = vb->getShape()(0);
     856        5096 :         for (uInt corrIdx=0; corrIdx < nCorrs; corrIdx++)
     857             :         {
     858             :             Complex chisq =
     859        3422 :                 transformDataCore(inputFrequencyMap_p[spwId].get(), lineFreeChannelMask,
     860             :                                   inputVis, flagCube, inputWeight, outputVis, corrIdx);
     861        3422 :             result_p.addOneFit(fieldID, scanID, spwId, (int)corrIdx, chisq);
     862             :         }
     863             :     }
     864        2755 : }
     865             : 
     866             : // -----------------------------------------------------------------------
     867             : //
     868             : // -----------------------------------------------------------------------
     869        3422 : 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        3422 :     DataCubeMap inputData;
     879        3422 :     DataCubeHolder<T> inputVisCubeHolder(inputVis);
     880        3422 :     DataCubeHolder<bool> inputFlagCubeHolder(inputFlags);
     881        3422 :     DataCubeHolder<Float> inputWeightsCubeHolder(inputWeight);
     882        3422 :     inputData.add(MS::DATA,inputVisCubeHolder);
     883        3422 :     inputData.add(MS::FLAG,inputFlagCubeHolder);
     884        3422 :     inputData.add(MS::WEIGHT_SPECTRUM,inputWeightsCubeHolder);
     885             : 
     886             :     // Gather output data
     887        3422 :     DataCubeMap outputData;
     888        3422 :     DataCubeHolder<T> outputVisCubeHolder(outputVis);
     889        3422 :     outputData.add(MS::DATA,outputVisCubeHolder);
     890             : 
     891        3422 :     Complex chisq;
     892        3422 :     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        3422 :         if (withDenoisingLib_p)
     912             :         {
     913        3354 :             UVContSubtractionDenoisingKernel<T> kernel(model,niter_p,lineFreeChannelMask);
     914        3354 :             UVContSubTransformEngine<T> transformer(&kernel,&inputData,&outputData);
     915        3354 :             transformFreqAxis2(inputVis.shape(),transformer,parallelCorrAxis);
     916        3354 :             chisq = kernel.getChiSquared();
     917        3354 :         }
     918             :         else
     919             :         {
     920          68 :             UVContSubtractionKernel<T> kernel(model,lineFreeChannelMask);
     921          68 :             UVContSubTransformEngine<T> transformer(&kernel,&inputData,&outputData);
     922          68 :             transformFreqAxis2(inputVis.shape(),transformer,parallelCorrAxis);
     923          68 :             chisq = kernel.getChiSquared();
     924          68 :         }
     925             :     }
     926             : 
     927        3422 :     return chisq;
     928        3422 : }
     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          54 : UVContSubTVILayerFactory::UVContSubTVILayerFactory(Record &configuration) :
     965          54 :         ViiLayerFactory()
     966             : {
     967          54 :         configuration_p = configuration;
     968          54 : }
     969             : 
     970             : ViImplementation2*
     971          54 : UVContSubTVILayerFactory::createInstance(ViImplementation2* vii0) const
     972             : {
     973             :         // Make the UVContSubTVI, using supplied ViImplementation2, and return it
     974          54 :         ViImplementation2 *vii = new UVContSubTVI(vii0, configuration_p);
     975          44 :         return vii;
     976             : }
     977             : 
     978             : //////////////////////////////////////////////////////////////////////////
     979             : // UVContSubTransformEngine class
     980             : //////////////////////////////////////////////////////////////////////////
     981             : 
     982             : // -----------------------------------------------------------------------
     983             : //
     984             : // -----------------------------------------------------------------------
     985        3422 : template<class T> UVContSubTransformEngine<T>::UVContSubTransformEngine(    UVContSubKernel<T> *kernel,
     986             :                                                                                                                                                         DataCubeMap *inputData,
     987             :                                                                                                                                                         DataCubeMap *outputData):
     988        3422 :                                                                                                                         FreqAxisTransformEngine2<T>(inputData,outputData)
     989             : {
     990        3422 :         uvContSubKernel_p = kernel;
     991        3422 : }
     992             : 
     993             : // -----------------------------------------------------------------------
     994             : //
     995             : // -----------------------------------------------------------------------
     996       69280 : template<class T> void UVContSubTransformEngine<T>::transform(      )
     997             : {
     998       69280 :         uvContSubKernel_p->setDebug(debug_p);
     999       69280 :         uvContSubKernel_p->kernel(inputData_p,outputData_p);
    1000       69280 : }
    1001             : 
    1002             : //////////////////////////////////////////////////////////////////////////
    1003             : // UVContSubKernel class
    1004             : //////////////////////////////////////////////////////////////////////////
    1005             : 
    1006             : // -----------------------------------------------------------------------
    1007             : //
    1008             : // -----------------------------------------------------------------------
    1009        3422 : template<class T> UVContSubKernel<T>::UVContSubKernel(      denoising::GslPolynomialModel<Double> *model,
    1010        3422 :                                                                                                                 Vector<bool> *lineFreeChannelMask)
    1011             : {
    1012        3422 :         model_p = model;
    1013        3422 :         fitOrder_p = model_p->ncomponents()-1;
    1014        3422 :         freqPows_p.reference(model_p->getModelMatrix());
    1015        3422 :         frequencies_p.reference(model_p->getLinearComponentFloat());
    1016             : 
    1017        3422 :         lineFreeChannelMask_p = lineFreeChannelMask ? lineFreeChannelMask : nullptr;
    1018        3422 :         debug_p = False;
    1019        3422 : }
    1020             : 
    1021             : // -----------------------------------------------------------------------
    1022             : //
    1023             : // -----------------------------------------------------------------------
    1024       69280 : template<class T> void UVContSubKernel<T>::kernel(DataCubeMap *inputData,
    1025             :                                                   DataCubeMap *outputData)
    1026             : {
    1027             :         // Get input/output data
    1028       69280 :         Vector<T> &outputVector = outputData->getVector<T>(MS::DATA);
    1029       69280 :         Vector<T> &inputVector = inputData->getVector<T>(MS::DATA);
    1030             : 
    1031             :         // Apply line-free channel mask
    1032       69280 :         Vector<bool> &inputFlags = inputData->getVector<bool>(MS::FLAG);
    1033       69280 :         if (lineFreeChannelMask_p != nullptr)
    1034       40186 :             inputFlags |= *lineFreeChannelMask_p;
    1035             : 
    1036             :         // Calculate number of valid data points and adapt fit
    1037       69280 :         size_t validPoints = nfalse(inputFlags);
    1038       69280 :         if (validPoints > 0)
    1039             :         {
    1040       68782 :                 bool restoreDefaultPoly = False;
    1041       68782 :                 uInt tmpFitOrder = fitOrder_p;
    1042             : 
    1043             :                 // Reduce fit order to match number of valid points
    1044       68782 :                 if (validPoints <= fitOrder_p)
    1045             :                 {
    1046        1800 :                         changeFitOrder(validPoints-1);
    1047        1800 :                         restoreDefaultPoly = true;
    1048             :                 }
    1049             : 
    1050             :                 // Get weights
    1051       68782 :                 Vector<Float> &inputWeight = inputData->getVector<Float>(MS::WEIGHT_SPECTRUM);
    1052             : 
    1053             :                 // Convert flags to mask
    1054       68782 :                 Vector<bool> mask = !inputFlags;
    1055             : 
    1056             :                 // Calculate and subtract continuum
    1057       68782 :                 chisq_p = kernelCore(inputVector,mask,inputWeight,outputVector);
    1058             : 
    1059             :                 // Go back to default fit order to match number of valid points
    1060       68782 :                 if (restoreDefaultPoly)
    1061             :                 {
    1062        1800 :                         changeFitOrder(tmpFitOrder);
    1063             :                 }
    1064       68782 :         }
    1065             :         else
    1066             :         {
    1067         498 :                 defaultKernel(inputVector,outputVector);
    1068             :         }
    1069       69280 : }
    1070             : 
    1071             : 
    1072             : //////////////////////////////////////////////////////////////////////////
    1073             : // UVContSubtractionKernel class
    1074             : //////////////////////////////////////////////////////////////////////////
    1075             : 
    1076             : // -----------------------------------------------------------------------
    1077             : //
    1078             : // -----------------------------------------------------------------------
    1079          68 : template<class T> UVContSubtractionKernel<T>::UVContSubtractionKernel(      denoising::GslPolynomialModel<Double>* model,
    1080             :                                                                                                                                                 Vector<bool> *lineFreeChannelMask):
    1081          68 :                                                                                                                                                 UVContSubKernel<T>(model,lineFreeChannelMask)
    1082             : {
    1083          68 :         changeFitOrder(fitOrder_p);
    1084          68 : }
    1085             : 
    1086             : // -----------------------------------------------------------------------
    1087             : //
    1088             : // -----------------------------------------------------------------------
    1089          68 : template<class T> void UVContSubtractionKernel<T>::changeFitOrder(size_t order)
    1090             : {
    1091          68 :         fitOrder_p = order;
    1092          68 :         Polynomial<AutoDiff<Float> > poly(order);
    1093          68 :         fitter_p.setFunction(poly); // poly It is cloned
    1094          68 :         fitter_p.asWeight(true);
    1095             : 
    1096         136 :         return;
    1097          68 : }
    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         680 : 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         680 :         Vector<Float> realCoeff;
    1130         680 :         Vector<Float> imagCoeff;
    1131         680 :         realCoeff = fitter_p.fit(frequencies_p, real(inputVector), inputWeights, &inputFlags);
    1132         680 :         double realChisq = fitter_p.chiSquare();
    1133         680 :         imagCoeff = fitter_p.fit(frequencies_p, imag(inputVector), inputWeights, &inputFlags);
    1134         680 :         double imagChisq = fitter_p.chiSquare();
    1135             : 
    1136             :         // Fill output data
    1137         680 :         outputVector = inputVector;
    1138         680 :         outputVector -= Complex(realCoeff(0),imagCoeff(0));
    1139         680 :         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         680 :         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        1360 :         return Complex(realChisq, imagChisq);
    1161         680 : }
    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        3354 : template<class T> UVContSubtractionDenoisingKernel<T>::UVContSubtractionDenoisingKernel(denoising::GslPolynomialModel<Double>* model,
    1315             :                                                                                                                                                                                 size_t nIter,
    1316             :                                                                                                                                                                                 Vector<bool> *lineFreeChannelMask):
    1317        3354 :                                                                                                                                                                                 UVContSubKernel<T>(model,lineFreeChannelMask)
    1318             : {
    1319        3354 :         fitter_p.resetModel(*model);
    1320        3354 :         fitter_p.setNIter(nIter);
    1321        3354 : }
    1322             : 
    1323             : // -----------------------------------------------------------------------
    1324             : //
    1325             : // -----------------------------------------------------------------------
    1326        3600 : template<class T> void UVContSubtractionDenoisingKernel<T>::changeFitOrder(size_t order)
    1327             : {
    1328        3600 :         fitOrder_p = order;
    1329        3600 :         fitter_p.resetNComponents(order+1);
    1330        3600 :         return;
    1331             : }
    1332             : 
    1333             : 
    1334             : // -----------------------------------------------------------------------
    1335             : //
    1336             : // -----------------------------------------------------------------------
    1337         498 : template<class T> void UVContSubtractionDenoisingKernel<T>::defaultKernel(  Vector<T> &inputVector,
    1338             :                                                                                                                                                         Vector<T> &outputVector)
    1339             : {
    1340         498 :         outputVector = inputVector;
    1341         498 :         return;
    1342             : }
    1343             : 
    1344             : // -----------------------------------------------------------------------
    1345             : //
    1346             : // -----------------------------------------------------------------------
    1347       68102 : template<class T> Complex UVContSubtractionDenoisingKernel<T>::kernelCore(  Vector<T> &inputVector,
    1348             :                                                                                                                                                 Vector<bool> &inputFlags,
    1349             :                                                                                                                                                 Vector<Float> &inputWeights,
    1350             :                                                                                                                                                 Vector<T> &outputVector)
    1351       68102 : {       fitter_p.setWeightsAndFlags(inputWeights,inputFlags);
    1352       68102 :     vector<T> coeff;
    1353       68102 :     Complex chisq;
    1354       68102 :     tie(coeff, chisq) = fitter_p.calcFitCoeff(inputVector);
    1355             : 
    1356       68102 :         Vector<T> model(outputVector.size());
    1357       68102 :         fitter_p.calcFitModel(model);
    1358             : 
    1359       68102 :         outputVector = inputVector;
    1360       68102 :         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       68102 :         return chisq;
    1393       68102 : }
    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