LCOV - code coverage report
Current view: top level - mstransform/MSTransform - MSTransformDataHandler.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 1889 2178 86.7 %
Date: 2024-12-11 20:54:31 Functions: 53 57 93.0 %

          Line data    Source code
       1             : //# MSTransformDataHandler.cc: This file contains the implementation of the MSTransformDataHandler 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/MSTransform/MSTransformDataHandler.h>
      24             : #include <casacore/tables/Tables/TableProxy.h>
      25             : #include <casacore/tables/TaQL/TableParse.h>
      26             : #include <casacore/ms/MSOper/MSMetaData.h>
      27             : #include <asdmstman/AsdmStMan.h>
      28             : 
      29             : 
      30             : using namespace casacore;
      31             : namespace casa { //# NAMESPACE CASA - BEGIN
      32             : 
      33             : /////////////////////////////////////////////
      34             : /// MSTransformDataHandler implementation ///
      35             : /////////////////////////////////////////////
      36             : 
      37             : // -----------------------------------------------------------------------
      38             : //
      39             : // -----------------------------------------------------------------------
      40        1890 :     MSTransformDataHandler::MSTransformDataHandler(const String& theMS, Table::TableOption option,
      41             :                                                    bool virtualModelCol,bool virtualCorrectedCol,
      42        1890 :                                                    bool reindex) :
      43        1890 :                   ms_p(MeasurementSet(theMS, option)),
      44        1890 :                   mssel_p(ms_p),
      45        1890 :                   msc_p(NULL),
      46        1890 :                   mscIn_p(NULL),
      47        1890 :                   keepShape_p(true),
      48        1890 :                   antennaSel_p(false),
      49        1890 :                   timeBin_p(-1.0),
      50        1890 :                   scanString_p(""),
      51        1890 :                   intentString_p(""),
      52        1890 :                   obsString_p(""),
      53        1890 :                   uvrangeString_p(""),
      54        1890 :                   taqlString_p(""),
      55        1890 :                   timeRange_p(""),
      56        1890 :                   arrayExpr_p(""),
      57        1890 :                   combine_p(""),
      58        1890 :                   fitorder_p(-1),
      59        1890 :                   fitspw_p("*"),
      60        1890 :                   fitoutspw_p("*"),
      61        1890 :                   virtualModelCol_p(virtualModelCol),
      62        1890 :                   virtualCorrectedCol_p(virtualCorrectedCol),
      63        5670 :                   reindex_p(reindex)
      64             : {
      65        1890 :         return;
      66           0 : }
      67             : 
      68             : // -----------------------------------------------------------------------
      69             : //
      70             : // -----------------------------------------------------------------------
      71           0 : MSTransformDataHandler::MSTransformDataHandler(const MeasurementSet& ms,
      72             :                                                bool virtualModelCol,bool virtualCorrectedCol,
      73           0 :                                                bool reindex) :
      74           0 :                    ms_p(ms),
      75           0 :                    mssel_p(ms_p),
      76           0 :                    msc_p(NULL),
      77           0 :                    mscIn_p(NULL),
      78           0 :                    keepShape_p(true),
      79           0 :                    antennaSel_p(false),
      80           0 :                    timeBin_p(-1.0),
      81           0 :                    scanString_p(""),
      82           0 :                    intentString_p(""),
      83           0 :                    obsString_p(""),
      84           0 :                    uvrangeString_p(""),
      85           0 :                    taqlString_p(""),
      86           0 :                    timeRange_p(""),
      87           0 :                    arrayExpr_p(""),
      88           0 :                    combine_p(""),
      89           0 :                    fitorder_p(-1),
      90           0 :                    fitspw_p("*"),
      91           0 :                    fitoutspw_p("*"),
      92           0 :                    virtualModelCol_p(virtualModelCol),
      93           0 :                    virtualCorrectedCol_p(virtualCorrectedCol),
      94           0 :                    reindex_p(reindex)
      95             : {
      96           0 :         return;
      97           0 : }
      98             : 
      99             : // -----------------------------------------------------------------------
     100             : //
     101             : // -----------------------------------------------------------------------
     102        1890 : MSTransformDataHandler::~MSTransformDataHandler()
     103             : {
     104        1890 :         if (msc_p) delete msc_p;
     105        1890 :         msc_p = nullptr;
     106             : 
     107        1890 :         if (mscIn_p) delete mscIn_p;
     108        1890 :         mscIn_p = nullptr;
     109             : 
     110        1890 :         msOut_p=MeasurementSet();
     111             : 
     112             :         // parseColumnNames unavoidably has a static String and Vector<MS::PredefinedColumns>.
     113             :         // Collapse them down to free most of that memory.
     114        1890 :         parseColumnNames("None");
     115             : 
     116        1890 :         return;
     117        1890 : }
     118             : 
     119             : // -----------------------------------------------------------------------
     120             : //
     121             : // -----------------------------------------------------------------------
     122        1890 : const Vector<MS::PredefinedColumns>& MSTransformDataHandler::parseColumnNames(String col)
     123             : {
     124             :         // Memorize both for efficiency and so that the info
     125             :         // message at the bottom isn't unnecessarily repeated.
     126        1890 :         static String my_colNameStr = "";
     127        1890 :         static Vector<MS::PredefinedColumns> my_colNameVect;
     128             : 
     129        1890 :         col.upcase();
     130        1890 :         if(col == my_colNameStr && col != "")
     131             :         {
     132           0 :                 return my_colNameVect;
     133             :         }
     134        1890 :         else if(col == "NONE")
     135             :         {
     136        1890 :                 my_colNameStr = "";
     137        1890 :                 my_colNameVect.resize(0);
     138        1890 :                 return my_colNameVect;
     139             :         }
     140             : 
     141             :         uInt nNames;
     142             : 
     143           0 :         if(col.contains("ALL"))
     144             :         {
     145           0 :                 nNames = 3;
     146           0 :                 my_colNameVect.resize(nNames);
     147           0 :                 my_colNameVect[0] = MS::DATA;
     148           0 :                 my_colNameVect[1] = MS::MODEL_DATA;
     149           0 :                 my_colNameVect[2] = MS::CORRECTED_DATA;
     150             :         }
     151             :         else
     152             :         {
     153           0 :                 nNames = dataColStrToEnums(col, my_colNameVect);
     154             :         }
     155             : 
     156             :         // Whether or not the MS has the columns is checked by verifyColumns().
     157             :         // Unfortunately it cannot be done here because this is a static method.
     158             : 
     159             : 
     160             :         /*
     161             :          * jagonzal: Redundant logging message (this info is already provided by MSTransformManager)
     162             :          *
     163             :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
     164             :         // "NONE" is used by the destructor
     165             :         if(col != "NONE")
     166             :         {
     167             :                 os << LogIO::NORMAL << "Using ";
     168             :                 for(uInt i = 0; i < nNames; ++i)
     169             :                 {
     170             :                         os << MS::columnName(my_colNameVect[i]) << " ";
     171             :                 }
     172             : 
     173             :                 os << " column" << (my_colNameVect.nelements() > 1 ? "s." : ".") << LogIO::POST;
     174             :         }
     175             :         */
     176             : 
     177           0 :         my_colNameStr = col;
     178           0 :         return my_colNameVect;
     179             : }
     180             : 
     181             : // -----------------------------------------------------------------------
     182             : //
     183             : // -----------------------------------------------------------------------
     184        1882 : const Vector<MS::PredefinedColumns>& MSTransformDataHandler::parseColumnNames(        String col,
     185             :                                                                                 bool produceModel,
     186             :                                                                                                                                                                 const MeasurementSet& msref,
     187             :                                                                                                                                                                 bool virtualModelCol,
     188             :                                                                                                                                                                 bool virtualCorrectedCol)
     189             : {
     190             :         // Memorize both for efficiency and so that the info
     191             :         // message at the bottom isn't unnecessarily repeated.
     192        1882 :         static String my_colNameStr = "";
     193        1882 :         static Vector<MS::PredefinedColumns> my_colNameVect;
     194             : 
     195             :         // Data columns to pick up if present.
     196        1882 :         Vector<MS::PredefinedColumns> wanted;
     197             : 
     198        1882 :         col.upcase();
     199             : 
     200             :         // This version of parseColumnNames does not reuse results of previous calls
     201             :         // but always checks the given columns because it cannot be certain that msref
     202             :         // refers to the same MS with every call.
     203             : 
     204        1882 :         if (col == "NONE")
     205             :         {
     206           0 :                 my_colNameStr = "";
     207           0 :                 my_colNameVect.resize(0);
     208           0 :                 return my_colNameVect;
     209             :         }
     210             : 
     211        3764 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
     212             : 
     213             :         // Are we choosy?
     214        1882 :         const bool doAny = col.contains("ALL") || col.contains("ANY");
     215             : 
     216             :         uInt nPoss;
     217        1882 :         if (doAny)
     218             :         {
     219         366 :                 nPoss = 5;
     220         366 :                 wanted.resize(nPoss);
     221         366 :                 wanted[0] = MS::DATA;
     222         366 :                 wanted[1] = MS::MODEL_DATA;
     223         366 :                 wanted[2] = MS::CORRECTED_DATA;
     224         366 :                 wanted[3] = MS::FLOAT_DATA;
     225         366 :                 wanted[4] = MS::LAG_DATA;
     226             :         }
     227             :         // split name string into individual names
     228             :         else
     229             :         {
     230        1516 :                 nPoss = dataColStrToEnums(col, wanted);
     231             :         }
     232             : 
     233             :         // Add MODEL_DATA separately from 'datacolumn' selection
     234        1882 :         if (produceModel) {
     235           3 :             const auto nelem = wanted.nelements();
     236           3 :             wanted.resize(nelem + 1, true);
     237           3 :             wanted[nelem] = MS::MODEL_DATA;
     238           3 :             ++nPoss;
     239             :             // When producing output MS with DATA,MODEL from CORRECTED, setupMS will have
     240             :             // to add MS::DATA to the output MS, not MS::CORRECTED_DATA.
     241             :             // An alternative would be to add a special case in setupMS, similar
     242             :             // to mustWriteOnlyToData, when wanted == CORRECTED_DATA, MODEL_DATA.
     243           3 :             if (MS::CORRECTED_DATA == wanted[0]) {
     244           2 :                 wanted[0] = MS::DATA;
     245             :             }
     246             :         }
     247             : 
     248        1882 :         uInt nFound = 0;
     249        1882 :         my_colNameVect.resize(0);
     250        5230 :         for (uInt i = 0; i < nPoss; ++i)
     251             :         {
     252        3355 :                 if (msref.tableDesc().isColumn(MS::columnName(wanted[i])))
     253             :                 {
     254        2235 :                         ++nFound;
     255        2235 :                         my_colNameVect.resize(nFound, true);
     256        2235 :                         my_colNameVect[nFound - 1] = wanted[i];
     257             :                 }
     258             :                 // CAS-5348 (jagonzal): Model parameters check is done at construction time
     259             :                 // (produceModel comes from uvcontsub, doesn't require MODEL in input MS)
     260        1120 :                 else if ((wanted[i] == MS::MODEL_DATA and virtualModelCol) or produceModel)
     261             :                 {
     262           3 :                         ++nFound;
     263           3 :                         my_colNameVect.resize(nFound, true);
     264           3 :                         my_colNameVect[nFound - 1] = wanted[i];
     265             :                 }
     266        1117 :                 else if (wanted[i] == MS::CORRECTED_DATA and virtualCorrectedCol)
     267             :                 {
     268           9 :                         ++nFound;
     269           9 :                         my_colNameVect.resize(nFound, true);
     270           9 :                         my_colNameVect[nFound - 1] = wanted[i];
     271             :                 }
     272        1108 :                 else if (!doAny)
     273             :                 {
     274           7 :                         ostringstream ostr;
     275           7 :                         ostr << "Desired column (" << MS::columnName(wanted[i])
     276           7 :                              << ") not found in the input MS (" << msref.tableName()
     277           7 :                              << ").";
     278           7 :                         throw(AipsError(ostr.str()));
     279           7 :                 }
     280             :         }
     281        1875 :         if (nFound == 0) throw(AipsError("Did not find and select any data columns."));
     282             : 
     283        1875 :         my_colNameStr = col;
     284        1875 :         return my_colNameVect;
     285        1889 : }
     286             : 
     287             : // -----------------------------------------------------------------------
     288             : //
     289             : // -----------------------------------------------------------------------
     290        1516 : uInt MSTransformDataHandler::dataColStrToEnums(const String& col, Vector<MS::PredefinedColumns>& colvec)
     291             : {
     292        3032 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
     293        1516 :         String tmpNames(col);
     294        1516 :         Vector<String> tokens;
     295        1516 :         tmpNames.upcase();
     296             : 
     297             :         // split name string into individual names
     298             :         char * pch;
     299        1516 :         Int it = 0;
     300        1516 :         pch = strtok((char*) tmpNames.c_str(), " ,");
     301        3038 :         while (pch != NULL)
     302             :         {
     303        1522 :                 tokens.resize(it + 1, true);
     304        1522 :                 tokens[it] = String(pch);
     305        1522 :                 ++it;
     306        1522 :                 pch = strtok(NULL, " ,");
     307             :         }
     308             : 
     309        1516 :         uInt nNames = tokens.nelements();
     310             : 
     311        1516 :         uInt nFound = 0;
     312        3038 :         for (uInt i = 0; i < nNames; ++i)
     313             :         {
     314        1522 :                 colvec.resize(nFound + 1, true);
     315        1522 :                 colvec[nFound] = MS::UNDEFINED_COLUMN;
     316             : 
     317        1522 :                 if (    tokens[i] == "OBSERVED"
     318        1522 :                                 || tokens[i] == "DATA"
     319        3044 :                                 || tokens[i] == MS::columnName(MS::DATA))
     320             :                 {
     321         822 :                         colvec[nFound++] = MS::DATA;
     322             :                 }
     323         700 :                 else if (       tokens[i] == "FLOAT"
     324         700 :                                         || tokens[i] == "FLOAT_DATA"
     325        1400 :                                         || tokens[i] == MS::columnName(MS::FLOAT_DATA))
     326             :                 {
     327         460 :                         colvec[nFound++] = MS::FLOAT_DATA;
     328             :                 }
     329         240 :                 else if (       tokens[i] == "LAG"
     330         240 :                                         || tokens[i] == "LAG_DATA"
     331         480 :                                         || tokens[i] == MS::columnName(MS::LAG_DATA))
     332             :                 {
     333           0 :                         colvec[nFound++] = MS::LAG_DATA;
     334             :                 }
     335         240 :                 else if (       tokens[i] == "MODEL"
     336         202 :                                         || tokens[i] == "MODEL_DATA"
     337         442 :                                         || tokens[i] == MS::columnName(MS::MODEL_DATA))
     338             :                 {
     339          38 :                         colvec[nFound++] = MS::MODEL_DATA;
     340             :                 }
     341         202 :                 else if (       tokens[i] == "CORRECTED"
     342           0 :                                         || tokens[i] == "CORRECTED_DATA"
     343         202 :                                         || tokens[i] == MS::columnName(MS::CORRECTED_DATA))
     344             :                 {
     345         202 :                         colvec[nFound++] = MS::CORRECTED_DATA;
     346             :                 }
     347             :                 // "NONE" is used by the destructor
     348           0 :                 else if (tmpNames != "NONE")
     349             :                 {
     350           0 :                         os << LogIO::SEVERE;
     351             : 
     352           0 :                         if (nFound == 0)
     353             :                         {
     354           0 :                                 colvec[0] = MS::DATA;
     355           0 :                                 os << "Unrecognized data column " << tokens[i] << "...trying DATA.";
     356             :                         }
     357             :                         else
     358             :                         {
     359           0 :                                 os << "Skipping unrecognized data column " << tokens[i];
     360             :                         }
     361             : 
     362           0 :                         os << LogIO::POST;
     363             :                 }
     364             :         }
     365        1516 :         return nFound;
     366        1516 : }
     367             : 
     368             : // -----------------------------------------------------------------------
     369             : //
     370             : // -----------------------------------------------------------------------
     371        1882 : bool MSTransformDataHandler::setmsselect(       const String& spw, const String& field,
     372             :                                                                 const String& baseline, const String& scan,
     373             :                                                                 const String& uvrange, const String& taql,
     374             :                                                                 const Vector<Int>& step, const String& subarray,
     375             :                                                                 const String& correlation, const String& intent,
     376             :                                                                 const String& obs, const String& feed)
     377             : {
     378        3764 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
     379             :         bool ok;
     380             : 
     381        1882 :         String myspwstr(spw == "" ? "*" : spw);
     382        3764 :         Record selrec = ms_p.msseltoindex(myspwstr, field);
     383             : 
     384        1882 :         ok = selectSource(selrec.asArrayInt("field"));
     385             : 
     386             :         // All of the requested selection functions will be tried, even if an
     387             :         // earlier one has indicated its failure.  This allows all of the selection
     388             :         // strings to be tested, yielding more complete feedback for the user
     389             :         // (fewer retries).  This is a matter of taste, though.  If the selections
     390             :         // turn out to be slow, this function should return on the first false.
     391             : 
     392        1882 :         if (!selectSpw(myspwstr, step))
     393             :         {
     394           0 :                 os << LogIO::SEVERE << "No channels selected." << LogIO::POST;
     395           0 :                 ok = false;
     396             :         }
     397             : 
     398        1882 :         if (baseline != "")
     399             :         {
     400         786 :                 Vector<Int> antid(0);
     401         786 :                 Vector<String> antstr(1, baseline);
     402         786 :                 selectAntenna(antid, antstr);
     403         786 :         }
     404             : 
     405        1882 :         scanString_p = scan;
     406        1882 :         intentString_p = intent;
     407        1882 :         obsString_p = obs;
     408        1882 :         uvrangeString_p = uvrange;
     409        1882 :         taqlString_p = taql;
     410        1882 :         feedString_p = feed;
     411             : 
     412        1882 :         if (subarray != "") selectArray(subarray);
     413             : 
     414        1882 :         if (!selectCorrelations(correlation))
     415             :         {
     416           0 :                 os << LogIO::SEVERE << "No correlations selected." << LogIO::POST;
     417           0 :                 ok = false;
     418             :         }
     419             : 
     420        1882 :         return ok;
     421        1882 : }
     422             : 
     423             : // -----------------------------------------------------------------------
     424             : //
     425             : // -----------------------------------------------------------------------
     426        1882 : bool MSTransformDataHandler::selectSource(const Vector<Int>& fieldid)
     427             : {
     428        3764 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
     429             : 
     430        1882 :         bool cando = true;
     431             : 
     432        1882 :         if (fieldid.nelements() < 1)
     433             :         {
     434        1806 :                 fieldid_p = Vector<Int> (1, -1);
     435             :         }
     436          76 :         else if (fieldid.nelements() > ms_p.field().nrow())
     437             :         {
     438           0 :                 os << LogIO::SEVERE << "More fields were requested than are in the input MS." << LogIO::POST;
     439           0 :                 cando = false;
     440             :         }
     441          76 :         else if (max(fieldid) >= static_cast<Int> (ms_p.field().nrow()))
     442             :         {
     443             :                 // Arriving here is very unlikely since if fieldid came from MSSelection
     444             :                 // bad fields were presumably already quietly dropped.
     445           0 :                 os << LogIO::SEVERE << "At least 1 field was requested that is not in the input MS." << LogIO::POST;
     446           0 :                 cando = false;
     447             :         }
     448             :         else
     449             :         {
     450          76 :                 fieldid_p = fieldid;
     451             :         }
     452             : 
     453        1882 :         if (fieldid_p.nelements() == 1 && fieldid_p[0] < 0)
     454             :         {
     455        1806 :                 fieldid_p.resize(ms_p.field().nrow());
     456        1806 :                 indgen(fieldid_p);
     457             :         }
     458             : 
     459        1882 :         return cando;
     460        1882 : }
     461             : 
     462             : // -----------------------------------------------------------------------
     463             : //
     464             : // -----------------------------------------------------------------------
     465        1882 : bool MSTransformDataHandler::selectSpw(const String& spwstr,const Vector<Int>& steps)
     466             : {
     467        3764 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
     468             : 
     469        1882 :         MSSelection mssel;
     470        1882 :         String myspwstr(spwstr == "" ? "*" : spwstr);
     471        1882 :         spwString_p = myspwstr; 
     472             :         
     473        1882 :         mssel.setSpwExpr(myspwstr);
     474             : 
     475        1882 :         widths_p = steps.copy();
     476        1882 :         if (widths_p.nelements() < 1)
     477             :         {
     478           0 :                 widths_p.resize(1);
     479           0 :                 widths_p[0] = 1;
     480             :         }
     481             :         else
     482             :         {
     483        5010 :                 for (uInt k = 0; k < widths_p.nelements(); ++k)
     484             :                 {
     485        3128 :                         if (widths_p[k] == 0)
     486             :                         {
     487           0 :                                 os << LogIO::WARN << "0 cannot be used for channel width...using 1 instead." << LogIO::POST;
     488           0 :                                 widths_p[k] = 1;
     489             :                         }
     490             :                 }
     491             :         }
     492             : 
     493             :         // Each row should have spw, start, stop, step
     494             :         // A single width is a default, but multiple widths should be used literally.
     495        1882 :         Matrix<Int> chansel = mssel.getChanList(&ms_p, 1);
     496             : 
     497        1882 :         if (chansel.nrow() > 0)
     498             :         {
     499             :                 // Use myspwstr if it selected anything...
     500        1882 :                 spw_p = chansel.column(0);
     501        1882 :                 chanStart_p = chansel.column(1);
     502        1882 :                 chanEnd_p = chansel.column(2);
     503        1882 :                 chanStep_p = chansel.column(3);
     504             : 
     505        1882 :                 uInt nspw = chanEnd_p.nelements();
     506        1882 :                 nchan_p.resize(nspw);
     507             : 
     508             :                 // A single width is a default, but multiple widths should be used literally.
     509        1882 :                 if (widths_p.nelements() > 1 && widths_p.nelements() != spw_p.nelements())
     510             :                 {
     511             :                         os              << LogIO::SEVERE
     512             :                                         << "Mismatch between the # of widths specified by width and the # of spws."
     513           0 :                                         << LogIO::POST;
     514           0 :                         return false;
     515             :                 }
     516             : 
     517             :                 // Copy the default width to all spws.
     518        1882 :                 if (widths_p.nelements() < nspw)
     519             :                 {
     520        1047 :                         widths_p.resize(nspw, true);
     521       10776 :                         for (uInt k = 1; k < nspw; ++k)
     522             :                         {
     523        9729 :                                 widths_p[k] = widths_p[0];
     524             :                         }
     525             :                 }
     526             : 
     527       14739 :                 for (uInt k = 0; k < nspw; ++k)
     528             :                 {
     529             :                         // CAS-2224, triggered by spw='0:2' (as opposed to '0:2~2').
     530       12857 :                         if (chanStep_p[k] == 0) chanStep_p[k] = 1;
     531             : 
     532       12857 :                         nchan_p[k] = 1 + (chanEnd_p[k] - chanStart_p[k]) / (chanStep_p[k]* widths_p[k]);
     533       12857 :                         if (nchan_p[k] < 1) nchan_p[k] = 1;
     534             :                 }
     535             :         }
     536             :         else
     537             :         {
     538             :                 // Select everything and rely on widths.
     539           0 :                 MSSpWindowColumns mySpwTab(ms_p.spectralWindow());
     540           0 :                 uInt nspw = mySpwTab.nrow();
     541             : 
     542           0 :                 nchan_p = mySpwTab.numChan().getColumn();
     543             : 
     544           0 :                 spw_p.resize(nspw);
     545           0 :                 indgen(spw_p);
     546             : 
     547           0 :                 chanStart_p.resize(nspw);
     548           0 :                 chanStep_p.resize(nspw);
     549           0 :                 for (uInt k = 0; k < nspw; ++k)
     550             :                 {
     551           0 :                         chanStart_p[k] = 0;
     552           0 :                         chanEnd_p[k] = nchan_p[k] - 1;
     553           0 :                         chanStep_p[k] = 1;
     554             :                 }
     555             : 
     556           0 :                 if (widths_p.nelements() != spw_p.nelements())
     557             :                 {
     558           0 :                         if (widths_p.nelements() == 1)
     559             :                         {
     560           0 :                                 widths_p.resize(spw_p.nelements(), true);
     561           0 :                                 for (uInt k = 1; k < spw_p.nelements(); ++k)
     562             :                                 {
     563           0 :                                         widths_p[k] = widths_p[0];
     564             :                                 }
     565             : 
     566             :                         }
     567             :                         else
     568             :                         {
     569             :                                 os              << LogIO::SEVERE
     570             :                                                 << "Mismatch between the # of widths specified by width and the # of spws."
     571           0 :                                                 << LogIO::POST;
     572           0 :                                 return false;
     573             :                         }
     574             :                 }
     575             : 
     576           0 :                 for (uInt k = 0; k < nspw; ++k)
     577             :                 {
     578           0 :                         nchan_p[k] = 1 + (nchan_p[k] - 1) / widths_p[k];
     579             :                 }
     580           0 :         }
     581             : 
     582             :         // Check for and filter out selected spws that aren't included in DATA_DESCRIPTION.
     583             :         // (See CAS-1673 for an example.)
     584        1882 :         std::set<Int> selectedSpwNotInDD(MSTransformDataHandler::findSpwsNotInDD(ms_p, spw_p));
     585        1882 :         uInt nSelectedSpwNotInDD = selectedSpwNotInDD.size();
     586        1882 :         if (nSelectedSpwNotInDD > 0)
     587             :         {
     588         122 :                 os << LogIO::NORMAL << "The following a priori selected input spw(s)\n";
     589         122 :                 for (std::set<Int>::iterator spwit = selectedSpwNotInDD.begin();
     590        2332 :                      spwit != selectedSpwNotInDD.end(); ++spwit)
     591             :                 {
     592        2210 :                         os << spw_p[*spwit] << " ";
     593             :                 }
     594             :                 os << "\nwere not found in DATA_DESCRIPTION (i. e. no rows in the main "
     595             :                       "table reference them) and therefore "
     596         122 :                       "are not included to the output." << LogIO::POST;
     597             : 
     598         122 :                 uInt nSelSpw = spw_p.nelements();
     599         122 :                 uInt ngoodSelSpwSlots = nSelSpw - nSelectedSpwNotInDD;
     600         122 :                 Vector<Int> spwc(ngoodSelSpwSlots);
     601         122 :                 Vector<Int> chanStartc(ngoodSelSpwSlots);
     602         122 :                 Vector<Int> chanEndc(ngoodSelSpwSlots);
     603         122 :                 Vector<Int> nchanc(ngoodSelSpwSlots);
     604         122 :                 Vector<Int> chanStepc(ngoodSelSpwSlots);
     605         122 :                 std::set<Int>::iterator spwNotDDEnd = selectedSpwNotInDD.end();
     606             : 
     607         122 :                 uInt j = 0;
     608        4854 :                 for (uInt k = 0; k < nSelSpw; ++k)
     609             :                 {
     610        4732 :                         if (selectedSpwNotInDD.find(k) == spwNotDDEnd)
     611             :                         {
     612        2522 :                                 spwc[j] = spw_p[k];
     613        2522 :                                 chanStartc[j] = chanStart_p[k];
     614        2522 :                                 chanEndc[j] = chanEnd_p[k];
     615        2522 :                                 nchanc[j] = nchan_p[k];
     616        2522 :                                 chanStepc[j] = chanStep_p[k];
     617        2522 :                                 ++j;
     618             :                         }
     619             :                 }
     620         122 :                 spw_p.resize(ngoodSelSpwSlots);
     621         122 :                 spw_p = spwc;
     622         122 :                 chanStart_p.resize(ngoodSelSpwSlots);
     623         122 :                 chanStart_p = chanStartc;
     624         122 :                 chanEnd_p.resize(ngoodSelSpwSlots);
     625         122 :                 chanEnd_p = chanEndc;
     626         122 :                 nchan_p.resize(ngoodSelSpwSlots);
     627         122 :                 nchan_p = nchanc;
     628         122 :                 chanStep_p.resize(ngoodSelSpwSlots);
     629         122 :                 chanStep_p = chanStepc;
     630         122 :         }
     631             : 
     632        1882 :         mssel.getChanSlices(chanSlices_p, &ms_p, 1);
     633        1882 :         return true;
     634        1882 : }
     635             : 
     636             : // -----------------------------------------------------------------------
     637             : //
     638             : // -----------------------------------------------------------------------
     639        1882 : std::set<Int> MSTransformDataHandler::findSpwsNotInDD(MeasurementSet& ms,Vector<Int> spwv)
     640             : {
     641        1882 :         ScalarColumn<Int> spws_in_dd(     ms.dataDescription(),
     642        1882 :                                                                         MSDataDescription::columnName(MSDataDescription::SPECTRAL_WINDOW_ID));
     643        1882 :         std::set<Int> uniqSpwsInDD;
     644        1882 :         uInt nspwsInDD = spws_in_dd.nrow();
     645             : 
     646       16963 :         for (uInt ddrow = 0; ddrow < nspwsInDD; ++ddrow)
     647             :         {
     648       15081 :                 uniqSpwsInDD.insert(spws_in_dd(ddrow));
     649             :         }
     650             : 
     651        1882 :         std::set<Int> badSelSpwSlots;
     652        1882 :         std::set<Int>::iterator ddend = uniqSpwsInDD.end();
     653       14739 :         for (uInt k = 0; k < spwv.nelements(); ++k)
     654             :         {
     655       12857 :                 if (uniqSpwsInDD.find(spwv[k]) == ddend)
     656             :                 {
     657        2210 :                         badSelSpwSlots.insert(k);
     658             :                 }
     659             :         }
     660             : 
     661        3764 :         return badSelSpwSlots;
     662        1882 : }
     663             : 
     664             : // -----------------------------------------------------------------------
     665             : //
     666             : // -----------------------------------------------------------------------
     667         786 : void MSTransformDataHandler::selectAntenna(const Vector<Int>& antennaids,const Vector<String>& antennaSel)
     668             : {
     669         786 :         antennaSel_p = MSTransformDataHandler::pickAntennas(antennaId_p, antennaSelStr_p, antennaids,antennaSel);
     670         786 :         return;
     671             : }
     672             : 
     673             : // -----------------------------------------------------------------------
     674             : //
     675             : // -----------------------------------------------------------------------
     676         786 : bool MSTransformDataHandler::pickAntennas(      Vector<Int>& selected_antennaids,
     677             :                                                                                         Vector<String>& selected_antenna_strs,
     678             :                                                                                         const Vector<Int>& antennaids,
     679             :                                                                                         const Vector<String>& antennaSel)
     680             : {
     681         786 :         bool didSelect = true;
     682             : 
     683         786 :         if ((antennaids.nelements() == 1) && (antennaids[0] == -1))
     684             :         {
     685           0 :                 if (antennaSel[0] == "")
     686             :                 {
     687           0 :                         didSelect = false;
     688             :                 }
     689             :                 else
     690             :                 {
     691           0 :                         selected_antennaids.resize();
     692             :                 }
     693             :         }
     694             :         else
     695             :         {
     696         786 :                 selected_antennaids = antennaids;
     697             :         }
     698             : 
     699         786 :         selected_antenna_strs = antennaSel;
     700             : 
     701         786 :         return didSelect;
     702             : }
     703             : 
     704             : // -----------------------------------------------------------------------
     705             : //
     706             : // -----------------------------------------------------------------------
     707           3 : void MSTransformDataHandler::selectArray(const String& subarray)
     708             : {
     709           3 :         arrayExpr_p = subarray;
     710           3 :         return;
     711             : }
     712             : 
     713             : // -----------------------------------------------------------------------
     714             : //
     715             : // -----------------------------------------------------------------------
     716        1882 : bool MSTransformDataHandler::selectCorrelations(const String& corrstr)
     717             : {
     718        3764 :     LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
     719             : 
     720        1882 :     corrString_p = corrstr;
     721        1882 :     const bool areSelecting = corrstr != "" && corrstr != "*";
     722             : 
     723             :     // Get correlation slices
     724        1882 :     MSSelection mssel1;
     725        1882 :     if (areSelecting) mssel1.setPolnExpr(corrstr.c_str());
     726        1882 :     mssel1.getCorrSlices(corrSlices_p, &ms_p);
     727             : 
     728             :     // Get correlation map
     729             :     // jagonzal (CAS-6951): We have to use another MSSelection because the first one corrupts the correlation
     730             :     //                      expression for instance "XX;YY" is turned into "XX" after calling getCorrSlices
     731        1882 :     MSSelection mssel2;
     732        1882 :     if (areSelecting) mssel2.setPolnExpr(corrstr.c_str());
     733        3764 :     return MSTransformDataHandler::getCorrMaps(mssel2, ms_p, inPolOutCorrToInCorrMap_p, areSelecting);
     734        1882 : }
     735             : 
     736             : // -----------------------------------------------------------------------
     737             : //
     738             : // -----------------------------------------------------------------------
     739        1882 : bool MSTransformDataHandler::getCorrMaps(MSSelection& mssel,
     740             :                                          const MeasurementSet& ms,
     741             :                                          Vector<Vector<Int> >& outToIn,
     742             :                                          const bool areSelecting)
     743             : {
     744             : 
     745             :     // ?? This always returns true!!!?!!
     746        1882 :     bool cando = true;
     747             : 
     748             :     // The total number of polids
     749        1882 :     uInt npol = ms.polarization().nrow();
     750             : 
     751             :     // Nominally empty selection for all polids
     752        1882 :     outToIn.resize(npol);
     753        1882 :     outToIn.set(Vector<Int> ());
     754        1882 :     if (areSelecting)
     755             :     {
     756             :         // Get the corr indices as an ordered map
     757          77 :         std::map<Int, Vector<Vector<Int> > > corrmap(mssel.getCorrMap(&ms));
     758             : 
     759             :         // Iterate over the ordered map to fill the vector maps
     760         176 :         for ( auto mi = corrmap.begin( ); mi != corrmap.end( ); ++mi)
     761             :         {
     762          99 :             Int pol = mi->first;
     763          99 :             std::vector<int> correlations_idx = mi->second[0].tovector();
     764          99 :             std::sort(correlations_idx.begin(), correlations_idx.end());
     765          99 :             outToIn[pol] = Vector<Int>(correlations_idx);
     766          99 :         }
     767          77 :     }
     768             :     else
     769             :     {   // Make outToIn an identity map.
     770        1805 :         ScalarColumn<Int> numCorr(ms.polarization(),MSPolarization::columnName(MSPolarization::NUM_CORR));
     771             : 
     772        3967 :         for (uInt polid = 0; polid < npol; ++polid)
     773             :         {
     774        2162 :             uInt ncorr = numCorr(polid);
     775        2162 :             outToIn[polid].resize(ncorr);
     776        6835 :             for (uInt cid = 0; cid < ncorr; ++cid)
     777             :             {
     778        4673 :                 outToIn[polid][cid] = cid;
     779             :             }
     780             :         }
     781        1805 :     }
     782             : 
     783        1882 :     return cando;
     784             : }
     785             : 
     786             : // -----------------------------------------------------------------------
     787             : //
     788             : // -----------------------------------------------------------------------
     789        1882 : void MSTransformDataHandler::selectTime(Double timeBin, String timerng)
     790             : {
     791        1882 :         timeBin_p   = timeBin;
     792        1882 :         timeRange_p = timerng;
     793        1882 : }
     794             : 
     795             : // -----------------------------------------------------------------------
     796             : //
     797             : // -----------------------------------------------------------------------
     798        1882 : bool MSTransformDataHandler::makeMSBasicStructure(String& msname,
     799             :                                                   String& colname,
     800             :                                                   bool produceModel,
     801             :                                                   bool createWeightSpectrumCols,
     802             :                                                   const Vector<Int>& tileShape,
     803             :                                                   const String& combine,
     804             :                                                   Table::TableOption option)
     805             : {
     806        3764 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
     807             :         os << LogIO::DEBUG1 << "Preparing to setup output MS with createWeightSpectrumCols: "
     808        1882 :            << createWeightSpectrumCols << LogIO::POST;;
     809             : 
     810        1882 :         if ((spw_p.nelements() > 0) && (max(spw_p) >= Int(ms_p.spectralWindow().nrow())))
     811             :         {
     812           0 :                 os << LogIO::SEVERE << "SpectralWindow selection contains elements that do not exist in this MS" << LogIO::POST;
     813           0 :                 ms_p = MeasurementSet();
     814           0 :                 return false;
     815             :         }
     816             : 
     817             :         // Watch out!  This throws an AipsError if ms_p doesn't have the requested columns.
     818             :         const Vector<MS::PredefinedColumns> colNamesTok =
     819        1889 :             parseColumnNames(colname,produceModel, ms_p,virtualModelCol_p,virtualCorrectedCol_p);
     820             : 
     821        1875 :         if (!makeSelection())
     822             :         {
     823           9 :                 ms_p = MeasurementSet();
     824           9 :                 throw(MSSelectionNullSelection("MSSelectionNullSelection : The selected table has zero rows."));
     825             :                 return false;
     826             :         }
     827             : 
     828        1864 :         mscIn_p = new MSColumns(mssel_p);
     829             : 
     830             :         // Note again the parseColumnNames() a few lines back that stops setupMS()
     831             :         // from being called if the MS doesn't have the requested columns.
     832        1864 :         MeasurementSet* outpointer = 0;
     833             : 
     834        1864 :         if (tileShape.nelements() == 3)
     835             :         {
     836           0 :                 outpointer = setupMS(msname, nchan_p[0], ncorr_p[0], colNamesTok,
     837             :                                      createWeightSpectrumCols, tileShape);
     838             :         }
     839             : 
     840             :         // the following calls MSTileLayout...  disabled for now because it
     841             :         // forces tiles to be the full spw bandwidth in width (gmoellen, 2010/11/07)
     842        1864 :         else if ((tileShape.nelements() == 1) && (tileShape[0] == 0 || tileShape[0]== 1))
     843             :         {
     844        1864 :                 outpointer = setupMS(msname, nchan_p[0], ncorr_p[0],
     845        3728 :                                      mscIn_p->observation().telescopeName()(0),
     846        1864 :                                      colNamesTok, createWeightSpectrumCols, tileShape[0]);
     847             :         }
     848             :         else {
     849             :                 // Sweep all other cases of bad tileshape to a default one.
     850             :                 // (this probably never happens)
     851           0 :                 outpointer = setupMS(msname, nchan_p[0], ncorr_p[0],
     852           0 :                                      mscIn_p->observation().telescopeName()(0),
     853             :                                      colNamesTok, createWeightSpectrumCols, 0);
     854             :         }
     855             : 
     856        1864 :         combine_p = combine;
     857             : 
     858        1864 :         msOut_p = *outpointer;
     859             : 
     860             :         // handle column keywords copy for CORRECTED_DATA -> DATA
     861        1864 :         if (colNamesTok.nelements() == 1 && colNamesTok[0] == MS::CORRECTED_DATA && mssel_p.isColumn(MS::CORRECTED_DATA)) {
     862         194 :             TableColumn outCol(msOut_p, "DATA");
     863         194 :             TableColumn inCol(mssel_p, "CORRECTED_DATA");
     864             :             // Copy the keywords CORRECTED_DATA -> DATA
     865         194 :             copyMainTableKeywords(outCol.rwKeywordSet(), inCol.keywordSet());
     866         194 :         }
     867             : 
     868        1864 :         bool ret = true;
     869             :         try
     870             :         {
     871        1864 :                 if (option == Table::Scratch)
     872             :                 {
     873             :                         // Set up pointing (has to be done in the copied MS)
     874           0 :                         SetupNewTable pointingSetup(msOut_p.pointingTableName(),MSPointing::requiredTableDesc(), Table::New);
     875           0 :                         msOut_p.rwKeywordSet().defineTable(MS::keywordName(MS::POINTING),Table(pointingSetup));
     876           0 :                         msOut_p.initRefs();
     877             : 
     878             :                         // Add additional columns to SPECTRAL_WINDOW sub-table
     879           0 :                         addOptionalColumns(mssel_p.spectralWindow(), msOut_p.spectralWindow(), true);
     880             : 
     881             :                         // Initialize output MS Columns
     882           0 :                         msc_p = new MSColumns(msOut_p);
     883             : 
     884             :                         // Write transformed SPECTRAL_WINDOW, DATA_DESCRIPTION_ID and POLARIZATION
     885           0 :                         ret &= fillDDTables();
     886           0 :                 }
     887             :                 else
     888             :                 {
     889        1864 :                         ret = fillSubTables(colNamesTok);
     890             :                 }
     891             :         }
     892           0 :         catch (AipsError ex)
     893             :         {
     894           0 :                 ret = false;
     895             :                 os      << LogIO::SEVERE
     896             :                         << "Exception filling the sub-tables: " << ex.getMesg() << endl
     897           0 :                         << "Stack Trace: " << ex.getStackTrace()
     898           0 :                         << LogIO::POST;
     899           0 :         }
     900             : 
     901        1864 :         if (!ret)
     902             :         {
     903           0 :                 delete outpointer;
     904           0 :                 ms_p = MeasurementSet();
     905           0 :                 msOut_p = MeasurementSet();
     906           0 :                 os << LogIO::SEVERE << msname << " left unfinished." << LogIO::POST;
     907           0 :                 return false;
     908             :         }
     909             : 
     910             :         //Detaching the selected part
     911        1864 :         ms_p = MeasurementSet();
     912             : 
     913        1864 :         delete outpointer;
     914        1864 :         return true;
     915        1893 : }
     916             : 
     917             : // -----------------------------------------------------------------------
     918             : //
     919             : // -----------------------------------------------------------------------
     920           0 : bool MSTransformDataHandler::isAllColumns(const Vector<MS::PredefinedColumns>& colNames)
     921             : {
     922           0 :         bool dCol = false, mCol = false, cCol = false;
     923           0 :         for (uInt i = 0; i < colNames.nelements(); i++)
     924             :         {
     925           0 :                 if (colNames[i] == MS::DATA) dCol = true;
     926           0 :                 else if (colNames[i] == MS::MODEL_DATA) mCol = true;
     927           0 :                 else if (colNames[i] == MS::CORRECTED_DATA) cCol = true;
     928             :                 // else turn off all?
     929             :         }
     930             : 
     931           0 :         return (dCol && mCol && cCol);
     932             : }
     933             : 
     934             : // -----------------------------------------------------------------------
     935             : // Modified version of makeSelection that uses the new getter methods
     936             : // MSS::getSPWDDIDList() and MSS::getDDIDList()
     937             : // -----------------------------------------------------------------------
     938        1875 : bool MSTransformDataHandler::makeSelection()
     939             : {
     940             : 
     941        3750 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
     942             : 
     943             :         // VisSet/MSIter will check if the SORTED exists
     944             :         // jagonzal (CAS-5327): Commenting this out, since this implies all sorts of memory leaks
     945             :         // Block<Int> sort;
     946             :         // ROVisibilityIterator(ms_p, sort);
     947             : 
     948             :         const MeasurementSet *elms;
     949        1875 :         elms = &ms_p;
     950        1875 :         MeasurementSet sorted;
     951        1875 :         if (ms_p.keywordSet().isDefined("SORTED_TABLE"))
     952             :         {
     953         590 :                 sorted = ms_p.keywordSet().asTable("SORTED_TABLE");
     954             : 
     955             :                 //If ms is not writable and sort is a subselection...use original ms
     956         590 :                 if (ms_p.nrow() == sorted.nrow()) elms = &sorted;
     957             :         }
     958             : 
     959        1875 :         MSSelection thisSelection;
     960        1875 :         if (fieldid_p.nelements() > 0)
     961             :         {
     962        1875 :                 thisSelection.setFieldExpr(MSSelection::indexExprStr(fieldid_p));
     963             :         }
     964             : 
     965        1875 :         if (spw_p.nelements() > 0)
     966             :         {
     967        1875 :                 thisSelection.setSpwExpr(spwString_p);
     968             :         }
     969             : 
     970        1875 :         if (antennaSel_p)
     971             :         {
     972         782 :                 if (antennaId_p.nelements() > 0)
     973             :                 {
     974           0 :                         thisSelection.setAntennaExpr(MSSelection::indexExprStr(antennaId_p));
     975             :                 }
     976         782 :                 if (antennaSelStr_p[0] != "")
     977             :                 {
     978         782 :                         thisSelection.setAntennaExpr(MSSelection::nameExprStr(antennaSelStr_p));
     979             :                 }
     980             : 
     981             :         }
     982             : 
     983        1875 :         if (timeRange_p != "")
     984             :         {
     985          39 :                 thisSelection.setTimeExpr(timeRange_p);
     986             :         }
     987             : 
     988             : 
     989        1875 :         thisSelection.setUvDistExpr(uvrangeString_p);
     990        1875 :         thisSelection.setScanExpr(scanString_p);
     991        1875 :         thisSelection.setStateExpr(intentString_p);
     992        1875 :         thisSelection.setObservationExpr(obsString_p);
     993             : 
     994        1875 :         if (arrayExpr_p != "")
     995             :         {
     996           3 :                 thisSelection.setArrayExpr(arrayExpr_p);
     997             :         }
     998             : 
     999        1875 :         if (corrString_p != "")
    1000             :         {
    1001          77 :                 thisSelection.setPolnExpr(corrString_p.c_str());
    1002             :         }
    1003             : 
    1004        1875 :         thisSelection.setTaQLExpr(taqlString_p);
    1005        1875 :         thisSelection.setFeedExpr(feedString_p);
    1006             : 
    1007        1875 :         TableExprNode exprNode = thisSelection.toTableExprNode(elms);
    1008        1873 :         selTimeRanges_p = thisSelection.getTimeList();
    1009        1873 :         selObsId_p = thisSelection.getObservationList();
    1010             : 
    1011             :         // Get the list of DDI for the selected spws
    1012        1873 :         spw2ddid_p = thisSelection.getSPWDDIDList(elms);
    1013             : 
    1014        1873 :         const MSDataDescription ddtable = elms->dataDescription();
    1015        1873 :         ScalarColumn<Int> polId(ddtable,MSDataDescription::columnName(MSDataDescription::POLARIZATION_ID));
    1016        1873 :         const MSPolarization poltable = elms->polarization();
    1017        1873 :         ArrayColumn<Int> pols(poltable,MSPolarization::columnName(MSPolarization::CORR_TYPE));
    1018             : 
    1019             :         // Get the list of DDI for the selected polarizations
    1020        1873 :         Vector<Int> polDDIList = thisSelection.getDDIDList(elms);
    1021             : 
    1022             :         // When polDDIList is empty, do not do an intersection
    1023        1873 :         bool doIntersection = true;
    1024             : 
    1025        1873 :         if (polDDIList.size() == 0){
    1026        1796 :                 doIntersection = false;
    1027             :         }
    1028             : 
    1029             :         // intersection between selected DDI from spw selection and
    1030             :         // selected DDI from polarization selection
    1031        1873 :         if (doIntersection) {
    1032          77 :                 Vector<Int> intersectedDDI = set_intersection(spw2ddid_p, polDDIList);
    1033          77 :                 uInt nddids = intersectedDDI.size();
    1034          77 :                 if (nddids > 0){
    1035          77 :                         spw2ddid_p.resize(nddids);
    1036         508 :                         for (uInt ii = 0; ii < nddids; ++ii){
    1037         431 :                                 spw2ddid_p[ii] = intersectedDDI[ii];
    1038             :                         }
    1039             :                 }
    1040             :                 else {
    1041             :                         os      << LogIO::SEVERE << "None of the selected correlations are in spectral window "
    1042           0 :                                 << LogIO::POST;
    1043             :                 }
    1044          77 :         }
    1045             : 
    1046             : 
    1047             :         // This is actually the number of selected DDI
    1048        1873 :         uInt nDDIs = spw2ddid_p.size();
    1049             : 
    1050        1873 :         inNumCorr_p.resize(nDDIs);
    1051        1873 :         ncorr_p.resize(nDDIs);
    1052             : 
    1053             :         // Map the correlations from input selected DDI to output
    1054       12481 :         for (uInt k = 0; k < nDDIs; ++k)
    1055             :         {
    1056       10608 :                 Int ddid = spw2ddid_p[k];
    1057             : 
    1058             :                 // Number of input correlations for each DDI
    1059             :                 // It reads the nelements of the CORR_TYPE column cell
    1060       10608 :                 inNumCorr_p[k] = pols(polId(ddid)).nelements();
    1061             : 
    1062             :                 // Corresponding number of output correlations for each DDI
    1063       10608 :                 ncorr_p[k] = inPolOutCorrToInCorrMap_p[polId(ddid)].nelements();
    1064       10608 :                 if (ncorr_p[k] == 0)
    1065             :                 {
    1066             :                         os              << LogIO::SEVERE
    1067             :                                         << "None of the selected correlations are in spectral window "
    1068           0 :                                         << spw_p[k] << LogIO::POST;
    1069           0 :                         return false;
    1070             :                 }
    1071             :         }
    1072             : 
    1073             : 
    1074             :         // Now remake the selected ms
    1075        1873 :         if (!(exprNode.isNull()))
    1076             :         {
    1077        1873 :                 mssel_p = MeasurementSet((*elms)(exprNode));
    1078             :         }
    1079             :         else
    1080             :         {
    1081             :                 // Null take all the ms ...setdata() blank means that
    1082           0 :                 mssel_p = MeasurementSet((*elms));
    1083             :         }
    1084             : 
    1085        1873 :         if (mssel_p.nrow() == 0) return false;
    1086             : 
    1087             :         // Setup antNewIndex_p now that mssel_p is ready.
    1088        1864 :         if (antennaSel_p and reindex_p)
    1089             :         {
    1090             :                 /*
    1091             :                 // Watch out! getAntenna*List() and getBaselineList() return negative numbers for negated antennas!
    1092             :                 ScalarColumn<Int> ant1c(mssel_p, MS::columnName(MS::ANTENNA1));
    1093             :                 ScalarColumn<Int> ant2c(mssel_p, MS::columnName(MS::ANTENNA2));
    1094             :                 Vector<Int> selAnts(ant1c.getColumn());
    1095             :                 uInt nAnts = selAnts.nelements();
    1096             : 
    1097             :                 selAnts.resize(2 * nAnts, true);
    1098             :                 selAnts(Slice(nAnts, nAnts)) = ant2c.getColumn();
    1099             :                 nAnts = GenSort<Int>::sort(selAnts, Sort::Ascending,Sort::NoDuplicates);
    1100             :                 selAnts.resize(nAnts, true);
    1101             :                 Int maxAnt = max(selAnts);
    1102             :                 */
    1103             : 
    1104             :                 // jagonzal: Scanning the main table is extremely inefficient, and depends on TaQL
    1105             :                 //           Therefore simply remove the negated antennas from getAntenna1List
    1106         744 :                 vector<Int> antsSel;
    1107             : 
    1108             :                 // Get antennas selected on position 1
    1109         744 :                 Vector<Int> ant1List = thisSelection.getAntenna1List();
    1110        1712 :                 for (uInt idx=0;idx<ant1List.size();idx++)
    1111             :                 {
    1112         968 :                         if (ant1List(idx) >= 0) antsSel.push_back(ant1List(idx));
    1113             :                 }
    1114             : 
    1115             :                 // Get antennas selected on position 2
    1116         744 :                 Vector<Int> ant2List = thisSelection.getAntenna2List();
    1117        1770 :                 for (uInt idx=0;idx<ant2List.size();idx++)
    1118             :                 {
    1119        1026 :                         if (ant2List(idx) >= 0) antsSel.push_back(ant2List(idx));
    1120             :                 }
    1121             : 
    1122             :                 // Sort and remove duplicates
    1123         744 :                 std::sort(antsSel.begin(), antsSel.end());
    1124         744 :                 antsSel.erase(std::unique(antsSel.begin(), antsSel.end()),antsSel.end());
    1125             : 
    1126         744 :                 Vector<Int> selAnts(antsSel);
    1127         744 :                 uInt nAnts = selAnts.size();
    1128         744 :                 Int maxAnt = max(selAnts);
    1129             : 
    1130         744 :                 if (maxAnt < 0)
    1131             :                 {
    1132             :                         os      << LogIO::SEVERE
    1133             :                                 << "The maximum selected antenna number, " << maxAnt
    1134             :                                 << ", seems to be < 0."
    1135           0 :                                 << LogIO::POST;
    1136           0 :                         return false;
    1137             :                 }
    1138             : 
    1139         744 :                 antNewIndex_p.resize(maxAnt + 1);
    1140             :                 //So if you see -1 in the main, feed, or pointing tables, fix it
    1141         744 :                 antNewIndex_p.set(-1);
    1142             : 
    1143        1791 :     for (uInt k = 0; k < nAnts; ++k)
    1144        1047 :       antNewIndex_p[selAnts[k]] = k;
    1145             : 
    1146             :     //If the total number of output antennas is the same as the input antennas
    1147             :     //this means that the selection of baselines includes at the end
    1148             :     //all the input antennas. Therefore setting antenna selection to false.
    1149             :     //See CAS-11111
    1150         744 :     if(nAnts == elms->antenna().nrow())
    1151         718 :       antennaSel_p = false;
    1152        1488 :         }
    1153             :         // This still gets tripped up by VLA:OUT.
    1154             :         else
    1155             :         {
    1156             :                 // Make a default antNewIndex_p.
    1157        1120 :                 antNewIndex_p.resize(mssel_p.antenna().nrow());
    1158        1120 :                 indgen(antNewIndex_p);
    1159             :         }
    1160             : 
    1161        1864 :         if (mssel_p.nrow() < ms_p.nrow())
    1162             :         {
    1163             :                 os              << LogIO::NORMAL
    1164             :                                 << mssel_p.nrow() << " out of " << ms_p.nrow()
    1165             :                                 << " rows are going to be considered due to the selection criteria."
    1166         766 :                                 << LogIO::POST;
    1167             :         }
    1168             : 
    1169        1864 :         return true;
    1170        1879 : }
    1171             : 
    1172             : 
    1173             : // -----------------------------------------------------------------------
    1174             : //
    1175             : // -----------------------------------------------------------------------
    1176        1864 : MeasurementSet* MSTransformDataHandler::setupMS(const String& MSFileName, const Int nchan,
    1177             :                                                 const Int nCorr, const String& telescop,
    1178             :                                                 const Vector<MS::PredefinedColumns>& colNames,
    1179             :                                                 bool createWeightSpectrumCols,
    1180             :                                                 const Int obstype, const bool compress,
    1181             :                                                 const asdmStManUseAlternatives asdmStManUse,
    1182             :                                                 Table::TableOption option)
    1183             :  {
    1184             :         //Choose an appropriate tileshape
    1185        1864 :         IPosition dataShape(2, nCorr, nchan);
    1186        1864 :         IPosition tileShape = MSTileLayout::tileShape(dataShape, obstype, telescop);
    1187        1864 :         return setupMS(MSFileName, nchan, nCorr, colNames, createWeightSpectrumCols,
    1188        5592 :                        tileShape.asVector(),compress, asdmStManUse,option);
    1189        1864 :  }
    1190             : 
    1191             : // -----------------------------------------------------------------------
    1192             : //
    1193             : // -----------------------------------------------------------------------
    1194        1864 :  MeasurementSet* MSTransformDataHandler::setupMS(const String& MSFileName, const Int nchan,
    1195             :                                                  const Int nCorr,
    1196             :                                                  const Vector<MS::PredefinedColumns>& colNamesTok,
    1197             :                                                  bool createWeightSpectrumCols,
    1198             :                                                  const Vector<Int>& tshape, const bool compress,
    1199             :                                                  const asdmStManUseAlternatives asdmStManUse,
    1200             :                                                  Table::TableOption option)
    1201             :  {
    1202        1864 :         if (tshape.nelements() != 3) throw(AipsError("TileShape has to have 3 elements "));
    1203             : 
    1204             :         // This is more to shush a compiler warning than to warn users.
    1205        3728 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    1206        1864 :         if (tshape[0] != nCorr)
    1207           0 :                 os << LogIO::DEBUG1 << "Warning: using " << tshape[0]
    1208             :                                 << " from the tileshape instead of " << nCorr
    1209           0 :                                 << " for the number of correlations." << LogIO::POST;
    1210        1864 :         if (tshape[1] != nchan)
    1211        1558 :                 os << LogIO::DEBUG1 << "Warning: using " << tshape[1]
    1212             :                                 << " from the tileshape instead of " << nchan
    1213         779 :                                 << " for the number of channels." << LogIO::POST;
    1214             : 
    1215             :         // Choose an appropriate tileshape //////////////////
    1216             : 
    1217        1864 :         IPosition tileShape(tshape);
    1218             : 
    1219             :         // Make the MS table
    1220        1864 :         TableDesc td = MS::requiredTableDesc();
    1221        1864 :         Vector<String> tiledDataNames;
    1222             : 
    1223        1864 :         if (option == Table::Scratch)
    1224             :         {
    1225           0 :                 SetupNewTable newtab(MSFileName, td, option);
    1226           0 :                 TableLock lock(TableLock::AutoLocking);
    1227           0 :                 MeasurementSet *ms = new MeasurementSet(newtab, lock);
    1228             : 
    1229             :                 // Set up default sub-tables for the MS
    1230           0 :                 SetupNewTable dataDescSetup(ms->dataDescriptionTableName(),MSDataDescription::requiredTableDesc(), option);
    1231           0 :                 ms->rwKeywordSet().defineTable(MS::keywordName(MS::DATA_DESCRIPTION),Table(dataDescSetup));
    1232           0 :                 SetupNewTable polarizationSetup(ms->polarizationTableName(),MSPolarization::requiredTableDesc(), option);
    1233           0 :                 ms->rwKeywordSet().defineTable(MS::keywordName(MS::POLARIZATION),Table(polarizationSetup));
    1234           0 :                 SetupNewTable spectralWindowSetup(ms->spectralWindowTableName(),MSSpectralWindow::requiredTableDesc(), option);
    1235           0 :                 ms->rwKeywordSet().defineTable(MS::keywordName(MS::SPECTRAL_WINDOW),Table(spectralWindowSetup));
    1236           0 :                 ms->initRefs();
    1237             : 
    1238           0 :                 return ms;
    1239           0 :         }
    1240             : 
    1241             :         // Even though we know the data is going to be the same shape throughout I'll
    1242             :         // still create a column that has a variable shape as this will permit MS's
    1243             :         // with other shapes to be appended.
    1244        1864 :         uInt ncols = colNamesTok.nelements();
    1245        1864 :         const bool mustWriteOnlyToData = mustConvertToData(ncols, colNamesTok);
    1246        1864 :         if (mustWriteOnlyToData)
    1247             :         {
    1248        1203 :                 MS::addColumnToDesc(td, MS::DATA, 2);
    1249        1203 :                 if (asdmStManUse == DONT)
    1250             :                 {
    1251        1203 :                         if (compress) MS::addColumnCompression(td, MS::DATA, true);
    1252        2406 :                         String hcolName = String("Tiled") + String("DATA");
    1253        1203 :                         td.defineHypercolumn(hcolName, 3, stringToVector("DATA"));
    1254        1203 :                         tiledDataNames.resize(1);
    1255        1203 :                         tiledDataNames[0] = hcolName;
    1256        1203 :                 }
    1257             :         }
    1258             :         else
    1259             :         {
    1260         661 :                 tiledDataNames.resize(ncols);
    1261        1694 :                 for (uInt i = 0; i < ncols; ++i)
    1262             :                 {
    1263             :                         // Unfortunately MS::PredefinedColumns aren't ordered so that
    1264             :                         // I can just check if colNamesTok[i] is in the "data range".
    1265        1033 :                         if (    colNamesTok[i] == MS::DATA
    1266         831 :                                         || colNamesTok[i] == MS::MODEL_DATA
    1267         653 :                                         || colNamesTok[i] == MS::CORRECTED_DATA
    1268         459 :                                         || colNamesTok[i] == MS::FLOAT_DATA
    1269        1864 :                                         || colNamesTok[i] == MS::LAG_DATA)
    1270             :                         {
    1271        1033 :                                 if (asdmStManUse == DONT || colNamesTok[i] != MS::DATA)
    1272             :                                 {
    1273        1033 :                                         MS::addColumnToDesc(td, colNamesTok[i], 2);
    1274        1033 :                                         if (compress) MS::addColumnCompression(td, colNamesTok[i], true);
    1275             :                                 }
    1276             :                         }
    1277             :                         else
    1278             :                         {
    1279           0 :                                 throw(AipsError( MS::columnName(colNamesTok[i]) + " is not a recognized data column "));
    1280             :                         }
    1281        1033 :                         if (asdmStManUse == DONT || colNamesTok[i] != MS::DATA)
    1282             :                         {
    1283        1033 :                                 String hcolName = String("Tiled") + MS::columnName(colNamesTok[i]);
    1284        1033 :                                 td.defineHypercolumn(hcolName, 3,stringToVector(MS::columnName(colNamesTok[i])));
    1285        1033 :                                 tiledDataNames[i] = hcolName;
    1286        1033 :                         }
    1287             :                 }
    1288             :         }
    1289             : 
    1290             :         //other cols for compression
    1291        1864 :         if (compress && asdmStManUse != USE_FOR_DATA_WEIGHT_SIGMA_FLAG)
    1292             :         {
    1293           0 :                 MS::addColumnCompression(td, MS::WEIGHT, true);
    1294           0 :                 MS::addColumnCompression(td, MS::SIGMA, true);
    1295             :         }
    1296             : 
    1297        1864 :         if (createWeightSpectrumCols) {
    1298         324 :             MS::addColumnToDesc(td, MS::WEIGHT_SPECTRUM, 2);
    1299         324 :             MS::addColumnToDesc(td, MS::SIGMA_SPECTRUM, 2);
    1300             : 
    1301         324 :             td.defineHypercolumn("TiledWgtSpectrum", 3,stringToVector(MS::columnName(MS::WEIGHT_SPECTRUM)));
    1302         324 :             td.defineHypercolumn("TiledSigmaSpectrum", 3,stringToVector(MS::columnName(MS::SIGMA_SPECTRUM)));
    1303             :         }
    1304             : 
    1305        1864 :         td.defineHypercolumn("TiledFlagCategory", 4,stringToVector(MS::columnName(MS::FLAG_CATEGORY)));
    1306        1864 :         td.defineHypercolumn("TiledUVW", 2, stringToVector(MS::columnName(MS::UVW)));
    1307             : 
    1308        1864 :         if (asdmStManUse != USE_FOR_DATA_WEIGHT_SIGMA_FLAG)
    1309             :         {
    1310        1864 :                 td.defineHypercolumn("TiledFlag", 3,stringToVector(MS::columnName(MS::FLAG)));
    1311        1864 :                 td.defineHypercolumn("TiledWgt", 2,stringToVector(MS::columnName(MS::WEIGHT)));
    1312        1864 :                 td.defineHypercolumn("TiledSigma", 2,stringToVector(MS::columnName(MS::SIGMA)));
    1313             :         }
    1314             : 
    1315        1864 :         SetupNewTable newtab(MSFileName, td, option);
    1316             : 
    1317        1864 :         uInt cache_val = 32768;
    1318             : 
    1319             :         // Set the default Storage Manager to be the Incr one
    1320        1864 :         IncrementalStMan incrStMan("ISMData", cache_val);
    1321        1864 :         newtab.bindAll(incrStMan, true);
    1322             : 
    1323             :         //Override the binding for specific columns
    1324        1864 :         IncrementalStMan incrStMan0("Array_ID", cache_val);
    1325        1864 :         newtab.bindColumn(MS::columnName(MS::ARRAY_ID), incrStMan0);
    1326        1864 :         IncrementalStMan incrStMan1("EXPOSURE", cache_val);
    1327        1864 :         newtab.bindColumn(MS::columnName(MS::EXPOSURE), incrStMan1);
    1328        1864 :         IncrementalStMan incrStMan2("FEED1", cache_val);
    1329        1864 :         newtab.bindColumn(MS::columnName(MS::FEED1), incrStMan2);
    1330        1864 :         IncrementalStMan incrStMan3("FEED2", cache_val);
    1331        1864 :         newtab.bindColumn(MS::columnName(MS::FEED2), incrStMan3);
    1332        1864 :         IncrementalStMan incrStMan4("FIELD_ID", cache_val);
    1333        1864 :         newtab.bindColumn(MS::columnName(MS::FIELD_ID), incrStMan4);
    1334             : 
    1335             :     // jagonzal (CAS-6746): Don't use IncrementalStMan with RW cols ///////////////////////////////////////////////////
    1336             :     // IncrementalStMan incrStMan5("FLAG_ROW",cache_val/4);
    1337             :     // newtab.bindColumn(MS::columnName(MS::FLAG_ROW), incrStMan5);
    1338        1864 :     StandardStMan aipsStManFlagRow("FLAG_ROW", cache_val/4);
    1339        1864 :     newtab.bindColumn(MS::columnName(MS::FLAG_ROW), aipsStManFlagRow);
    1340             :     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    1341             : 
    1342        1864 :         IncrementalStMan incrStMan6("INTERVAL", cache_val);
    1343        1864 :         newtab.bindColumn(MS::columnName(MS::INTERVAL), incrStMan6);
    1344        1864 :         IncrementalStMan incrStMan7("OBSERVATION_ID", cache_val);
    1345        1864 :         newtab.bindColumn(MS::columnName(MS::OBSERVATION_ID), incrStMan7);
    1346        1864 :         IncrementalStMan incrStMan8("PROCESSOR_ID", cache_val);
    1347        1864 :         newtab.bindColumn(MS::columnName(MS::PROCESSOR_ID), incrStMan8);
    1348        1864 :         IncrementalStMan incrStMan9("SCAN_NUMBER", cache_val);
    1349        1864 :         newtab.bindColumn(MS::columnName(MS::SCAN_NUMBER), incrStMan9);
    1350        1864 :         IncrementalStMan incrStMan10("STATE_ID", cache_val);
    1351        1864 :         newtab.bindColumn(MS::columnName(MS::STATE_ID), incrStMan10);
    1352        1864 :         IncrementalStMan incrStMan11("TIME", cache_val);
    1353        1864 :         newtab.bindColumn(MS::columnName(MS::TIME), incrStMan11);
    1354        1864 :         IncrementalStMan incrStMan12("TIME_CENTROID", cache_val);
    1355        1864 :         newtab.bindColumn(MS::columnName(MS::TIME_CENTROID), incrStMan12);
    1356             : 
    1357             :         // Bind ANTENNA1, ANTENNA2 and DATA_DESC_ID to the standardStMan
    1358             :         // as they may change sufficiently frequently to make the
    1359             :         // incremental storage manager inefficient for these columns.
    1360        1864 :         StandardStMan aipsStMan0("ANTENNA1", cache_val);
    1361        1864 :         newtab.bindColumn(MS::columnName(MS::ANTENNA1), aipsStMan0);
    1362        1864 :         StandardStMan aipsStMan1("ANTENNA2", cache_val);
    1363        1864 :         newtab.bindColumn(MS::columnName(MS::ANTENNA2), aipsStMan1);
    1364        1864 :         StandardStMan aipsStMan2("DATA_DESC_ID", cache_val);
    1365        1864 :         newtab.bindColumn(MS::columnName(MS::DATA_DESC_ID), aipsStMan2);
    1366             : 
    1367             :         // Bind the DATA, FLAG & WEIGHT/SIGMA_SPECTRUM columns to the tiled stman or
    1368             :         // asdmStMan
    1369        1864 :         AsdmStMan sm;
    1370             : 
    1371        1864 :         if (mustWriteOnlyToData)
    1372             :         {
    1373        1203 :                 if (asdmStManUse == DONT)
    1374             :                 {
    1375        1203 :                         TiledShapeStMan tiledStMan1Data("TiledDATA", tileShape);
    1376        1203 :                         newtab.bindColumn(MS::columnName(MS::DATA), tiledStMan1Data);
    1377        1203 :                 }
    1378             :                 else
    1379             :                 {
    1380           0 :                         newtab.bindColumn(MS::columnName(MS::DATA), sm);
    1381             :                 }
    1382             :         }
    1383             :         else
    1384             :         {
    1385        1694 :                 for (uInt i = 0; i < ncols; ++i)
    1386             :                 {
    1387        1033 :                         TiledShapeStMan tiledStMan1Data(tiledDataNames[i], tileShape);
    1388        1033 :                         newtab.bindColumn(MS::columnName(colNamesTok[i]), tiledStMan1Data);
    1389        1033 :                 }
    1390         661 :                 if (asdmStManUse != DONT)
    1391             :                 {
    1392           0 :                         newtab.bindColumn(MS::columnName(MS::DATA), sm);
    1393             :                 }
    1394             :         }
    1395             : 
    1396        3728 :         TiledShapeStMan tiledStMan1fc("TiledFlagCategory",IPosition(4, tileShape(0), tileShape(1), 1, tileShape(2)));
    1397        1864 :         newtab.bindColumn(MS::columnName(MS::FLAG_CATEGORY), tiledStMan1fc);
    1398             : 
    1399        1864 :         if (createWeightSpectrumCols) {
    1400         324 :             TiledShapeStMan tiledStMan2("TiledWgtSpectrum", tileShape);
    1401         324 :             TiledShapeStMan tiledStMan6("TiledSigmaSpectrum", tileShape);
    1402         324 :             newtab.bindColumn(MS::columnName(MS::WEIGHT_SPECTRUM), tiledStMan2);
    1403         324 :             newtab.bindColumn(MS::columnName(MS::SIGMA_SPECTRUM), tiledStMan6);
    1404         324 :         }
    1405             : 
    1406        3728 :         TiledColumnStMan tiledStMan3("TiledUVW",IPosition(2, 3, (tileShape(0) * tileShape(1) * tileShape(2)) / 3));
    1407        1864 :         newtab.bindColumn(MS::columnName(MS::UVW), tiledStMan3);
    1408        1864 :         if (asdmStManUse == USE_FOR_DATA_WEIGHT_SIGMA_FLAG)
    1409             :         {
    1410           0 :                 newtab.bindColumn(MS::columnName(MS::FLAG), sm);
    1411           0 :                 newtab.bindColumn(MS::columnName(MS::WEIGHT), sm);
    1412           0 :                 newtab.bindColumn(MS::columnName(MS::SIGMA), sm);
    1413             :         }
    1414             :         else
    1415             :         {
    1416        1864 :             TiledShapeStMan tiledStMan1f("TiledFlag", tileShape);
    1417        1864 :             TiledShapeStMan tiledStMan4("TiledWgt", IPosition(2, tileShape(0),
    1418        5592 :                                                               tileShape(1) * tileShape(2)));
    1419        1864 :             TiledShapeStMan tiledStMan5("TiledSigma",IPosition(2, tileShape(0),
    1420        5592 :                                                                tileShape(1) * tileShape(2)));
    1421             : 
    1422        1864 :             newtab.bindColumn(MS::columnName(MS::FLAG), tiledStMan1f);
    1423        1864 :             newtab.bindColumn(MS::columnName(MS::WEIGHT), tiledStMan4);
    1424        1864 :             newtab.bindColumn(MS::columnName(MS::SIGMA), tiledStMan5);
    1425        1864 :         }
    1426             : 
    1427             :         // Avoid lock overheads by locking the table permanently
    1428        1864 :         TableLock lock(TableLock::AutoLocking);
    1429        1864 :         MeasurementSet *ms = new MeasurementSet(newtab, lock);
    1430             : 
    1431             :         // Set up the sub-tables for the UVFITS MS (we make new tables with 0 rows)
    1432             :         // Table::TableOption option = Table::New;
    1433        1864 :         createSubtables(*ms, option);
    1434             : 
    1435             :         // Set the TableInfo
    1436        1864 :         TableInfo& info(ms->tableInfo());
    1437        1864 :         info.setType(TableInfo::type(TableInfo::MEASUREMENTSET));
    1438        1864 :         info.setSubType(String("UVFITS"));
    1439        1864 :         info.readmeAddLine("This is a measurement set Table holding astronomical observations");
    1440             : 
    1441        1864 :         return ms;
    1442        1864 : }
    1443             : 
    1444             : // -----------------------------------------------------------------------
    1445             : //
    1446             : // -----------------------------------------------------------------------
    1447        1864 : void MSTransformDataHandler::createSubtables(MeasurementSet& ms, Table::TableOption option)
    1448             : {
    1449        1864 :         SetupNewTable antennaSetup(ms.antennaTableName(),MSAntenna::requiredTableDesc(), option);
    1450        1864 :         ms.rwKeywordSet().defineTable(MS::keywordName(MS::ANTENNA),Table(antennaSetup));
    1451        1864 :         SetupNewTable dataDescSetup(ms.dataDescriptionTableName(),MSDataDescription::requiredTableDesc(), option);
    1452        1864 :         ms.rwKeywordSet().defineTable(MS::keywordName(MS::DATA_DESCRIPTION),Table(dataDescSetup));
    1453        1864 :         SetupNewTable feedSetup(ms.feedTableName(), MSFeed::requiredTableDesc(),option);
    1454        1864 :         ms.rwKeywordSet().defineTable(MS::keywordName(MS::FEED), Table(feedSetup));
    1455        1864 :         SetupNewTable flagCmdSetup(ms.flagCmdTableName(),MSFlagCmd::requiredTableDesc(), option);
    1456        1864 :         ms.rwKeywordSet().defineTable(MS::keywordName(MS::FLAG_CMD),Table(flagCmdSetup));
    1457        1864 :         SetupNewTable fieldSetup(ms.fieldTableName(), MSField::requiredTableDesc(),option);
    1458        1864 :         ms.rwKeywordSet().defineTable(MS::keywordName(MS::FIELD), Table(fieldSetup));
    1459        1864 :         SetupNewTable historySetup(ms.historyTableName(),MSHistory::requiredTableDesc(), option);
    1460        1864 :         ms.rwKeywordSet().defineTable(MS::keywordName(MS::HISTORY),Table(historySetup));
    1461        1864 :         SetupNewTable observationSetup(ms.observationTableName(),MSObservation::requiredTableDesc(), option);
    1462        1864 :         ms.rwKeywordSet().defineTable(MS::keywordName(MS::OBSERVATION),Table(observationSetup));
    1463        1864 :         SetupNewTable polarizationSetup(ms.polarizationTableName(),MSPolarization::requiredTableDesc(), option);
    1464        1864 :         ms.rwKeywordSet().defineTable(MS::keywordName(MS::POLARIZATION),Table(polarizationSetup));
    1465        1864 :         SetupNewTable processorSetup(ms.processorTableName(),MSProcessor::requiredTableDesc(), option);
    1466        1864 :         ms.rwKeywordSet().defineTable(MS::keywordName(MS::PROCESSOR),Table(processorSetup));
    1467        1864 :         SetupNewTable spectralWindowSetup(ms.spectralWindowTableName(),MSSpectralWindow::requiredTableDesc(), option);
    1468        1864 :         ms.rwKeywordSet().defineTable(MS::keywordName(MS::SPECTRAL_WINDOW),Table(spectralWindowSetup));
    1469        1864 :         SetupNewTable stateSetup(ms.stateTableName(), MSState::requiredTableDesc(),option);
    1470        1864 :         ms.rwKeywordSet().defineTable(MS::keywordName(MS::STATE), Table(stateSetup));
    1471             : 
    1472             :         // Add the optional Source sub table to allow for specification of the rest frequency
    1473        1864 :         SetupNewTable sourceSetup(ms.sourceTableName(),MSSource::requiredTableDesc(), option);
    1474        1864 :         ms.rwKeywordSet().defineTable(MS::keywordName(MS::SOURCE),Table(sourceSetup, 0));
    1475             : 
    1476             :         // Update the references to the sub-table keywords
    1477        1864 :         ms.initRefs();
    1478             : 
    1479        3728 :         return;
    1480        1864 : }
    1481             : 
    1482             : // -----------------------------------------------------------------------
    1483             : //
    1484             : // -----------------------------------------------------------------------
    1485        1864 : bool MSTransformDataHandler::fillSubTables(const Vector<MS::PredefinedColumns>&)
    1486             : {
    1487        3728 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    1488        1864 :         bool success = true;
    1489             : 
    1490             :         // Copy the sub-tables before doing anything with the main table.
    1491             :         // Otherwise MSColumns won't work.
    1492             : 
    1493             :         // fill or update
    1494        1864 :         Timer timer;
    1495             : 
    1496        1864 :         timer.mark();
    1497        1864 :         success &= copyPointing();
    1498        1864 :         os << LogIO::DEBUG1 << "copyPointing took " << timer.real() << "s." << LogIO::POST;
    1499             : 
    1500             :         // Optional columns should be set up before msc_p.
    1501        1864 :         addOptionalColumns(mssel_p.spectralWindow(), msOut_p.spectralWindow(), true);
    1502             : 
    1503             :         // Force the Measures frames for all the time type columns to
    1504             :         // have the same reference as the TIME column of the main table.
    1505             :         // Disable the empty table check (with false) because some of the
    1506             :         // sub-tables (like POINTING) might already have been written.
    1507             :         // However, empty tables are still empty after setting up the reference codes here.
    1508        1864 :         msc_p = new MSColumns(msOut_p);
    1509        1864 :         msc_p->setEpochRef(MEpoch::castType(mscIn_p->timeMeas().getMeasRef().getType()), false);
    1510             : 
    1511             :         // UVW is the only other Measures column in the main table.
    1512        1864 :         msc_p->uvwMeas().setDescRefCode(Muvw::castType(mscIn_p->uvwMeas().getMeasRef().getType()));
    1513             : 
    1514        1864 :         if (!mscIn_p->flagCategory().isNull() && mscIn_p->flagCategory().isDefined(0))
    1515             :         {
    1516         417 :                 msc_p->setFlagCategories(mscIn_p->flagCategories());
    1517             :         }
    1518             : 
    1519             : 
    1520        1864 :         timer.mark();
    1521        1864 :         if (!fillDDTables()) return false;
    1522        1864 :         os << LogIO::DEBUG1 << "fillDDTables took " << timer.real() << "s." << LogIO::POST;
    1523             : 
    1524             :         // SourceIDs need to be re-mapped around here
    1525             :         // (It cannot not be done in selectSource() because mssel_p is not set up yet)
    1526        1864 :         timer.mark();
    1527        1864 :         relabelSources();
    1528        1864 :         os << LogIO::DEBUG1 << "relabelSources took " << timer.real() << "s." << LogIO::POST;
    1529             : 
    1530        1864 :         success &= fillFieldTable();
    1531        1864 :         success &= copySource();
    1532             : 
    1533        1864 :         success &= copyAntenna();
    1534             :         // Feed table writing has to be after antenna
    1535        1864 :         if (!copyFeed()) return false;
    1536             : 
    1537        1864 :         success &= copyFlag_Cmd();
    1538        1864 :         success &= copyHistory();
    1539        1864 :         success &= copyObservation();
    1540        1864 :         success &= copyProcessor();
    1541        1864 :         success &= copyState();
    1542             : 
    1543        1864 :         timer.mark();
    1544        1864 :         success &= copySyscal();
    1545        1864 :         os << LogIO::DEBUG1 << "copySyscal took " << timer.real() << "s." << LogIO::POST;
    1546             : 
    1547        1864 :         timer.mark();
    1548        1864 :         success &= copyWeather();
    1549        1864 :         os << LogIO::DEBUG1 << "copyWeather took " << timer.real() << "s." << LogIO::POST;
    1550             : 
    1551        1864 :         timer.mark();
    1552        1864 :         success &= filterOptSubtable("CALDEVICE");
    1553        1864 :         os << LogIO::DEBUG1 << "CALDEVICE took " << timer.real() << "s." << LogIO::POST;
    1554             : 
    1555        1864 :         timer.mark();
    1556        1864 :         success &= filterOptSubtable("SYSPOWER");
    1557        1864 :         os << LogIO::DEBUG1 << "SYSPOWER took " << timer.real() << "s." << LogIO::POST;
    1558             : 
    1559             :         // Run this after running the other copy*()s.
    1560             :         // Maybe there should be an option to *not* run it.
    1561        1864 :         success &= copyGenericSubtables();
    1562        1864 :         return success;
    1563        1864 : }
    1564             : 
    1565             : // -----------------------------------------------------------------------
    1566             : //
    1567             : // -----------------------------------------------------------------------
    1568        1864 : bool MSTransformDataHandler::fillFieldTable()
    1569             : {
    1570        3728 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    1571             : 
    1572        1864 :         uInt nAddedCols = addOptionalColumns(mssel_p.field(), msOut_p.field(), true);
    1573             : 
    1574        1864 :         MSFieldColumns msField(msOut_p.field());
    1575             : 
    1576        1864 :         const MSFieldColumns& fieldIn = mscIn_p->field();
    1577        1864 :         ScalarColumn<String> code(fieldIn.code());
    1578        1864 :         ArrayColumn<Double> delayDir(fieldIn.delayDir());
    1579        1864 :         ScalarColumn<bool> flagRow(fieldIn.flagRow());
    1580        1864 :         ScalarColumn<String> name(fieldIn.name());
    1581        1864 :         ScalarColumn<Int> numPoly(fieldIn.numPoly());
    1582        1864 :         ArrayColumn<Double> phaseDir(fieldIn.phaseDir());
    1583        1864 :         ArrayColumn<Double> refDir(fieldIn.referenceDir());
    1584        1864 :         ScalarColumn<Int> sourceId(fieldIn.sourceId());
    1585        1864 :         ScalarColumn<Double> time(fieldIn.time());
    1586             : 
    1587        1864 :         String refstr;
    1588        1864 :         String nameVarRefColDelayDir, nameVarRefColPhaseDir, nameVarRefColRefDir;
    1589             : 
    1590             :         // Need to correctly define the direction measures.
    1591             : 
    1592             :         // DelayDir
    1593        1864 :         if (delayDir.keywordSet().asRecord("MEASINFO").isDefined("Ref"))
    1594             :         {
    1595        1480 :                 delayDir.keywordSet().asRecord("MEASINFO").get("Ref", refstr);
    1596        1480 :                 msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").define("Ref",refstr);
    1597             :         }
    1598             : 
    1599             :         // it's a variable ref. column
    1600        1864 :         if (delayDir.keywordSet().asRecord("MEASINFO").isDefined("VarRefCol"))
    1601             :         {
    1602         384 :                 delayDir.keywordSet().asRecord("MEASINFO").get("VarRefCol", refstr);
    1603         384 :                 msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").define("VarRefCol", refstr);
    1604         384 :                 nameVarRefColDelayDir = refstr;
    1605             : 
    1606         384 :                 Vector<String> refTypeV;
    1607         384 :                 delayDir.keywordSet().asRecord("MEASINFO").get("TabRefTypes", refTypeV);
    1608         384 :                 msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefTypes", refTypeV);
    1609             : 
    1610         384 :                 Vector<uInt> refCodeV;
    1611         384 :                 delayDir.keywordSet().asRecord("MEASINFO").get("TabRefCodes", refCodeV);
    1612         384 :                 msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefCodes", refCodeV);
    1613         384 :                 Int refid = msField.delayDir().keywordSet().asRecord("MEASINFO").fieldNumber("Ref");
    1614             : 
    1615             :                 // Erase the redundant Ref keyword
    1616         384 :                 if (refid >= 0)
    1617             :                 {
    1618         384 :                         msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").removeField(RecordFieldId(refid));
    1619             :                 }
    1620         384 :         }
    1621             : 
    1622             :         // PhaseDir
    1623        1864 :         if (phaseDir.keywordSet().asRecord("MEASINFO").isDefined("Ref"))
    1624             :         {
    1625        1480 :                 phaseDir.keywordSet().asRecord("MEASINFO").get("Ref", refstr);
    1626        1480 :                 msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").define("Ref",refstr);
    1627             :         }
    1628             : 
    1629             :         // It's a variable ref. column
    1630        1864 :         if (phaseDir.keywordSet().asRecord("MEASINFO").isDefined("VarRefCol"))
    1631             :         {
    1632         384 :                 phaseDir.keywordSet().asRecord("MEASINFO").get("VarRefCol", refstr);
    1633         384 :                 msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").define("VarRefCol", refstr);
    1634         384 :                 nameVarRefColPhaseDir = refstr;
    1635             : 
    1636         384 :                 Vector<String> refTypeV;
    1637         384 :                 phaseDir.keywordSet().asRecord("MEASINFO").get("TabRefTypes", refTypeV);
    1638         384 :                 msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefTypes", refTypeV);
    1639             : 
    1640         384 :                 Vector<uInt> refCodeV;
    1641         384 :                 phaseDir.keywordSet().asRecord("MEASINFO").get("TabRefCodes", refCodeV);
    1642         384 :                 msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefCodes", refCodeV);
    1643             : 
    1644         384 :                 Int refid = msField.phaseDir().keywordSet().asRecord("MEASINFO").fieldNumber("Ref");
    1645         384 :                 if (refid >= 0)
    1646             :                 {
    1647         384 :                         msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").removeField(RecordFieldId(refid));
    1648             :                 }
    1649         384 :         }
    1650             : 
    1651             :         // ReferenceDir
    1652        1864 :         if (refDir.keywordSet().asRecord("MEASINFO").isDefined("Ref"))
    1653             :         {
    1654        1480 :                 refDir.keywordSet().asRecord("MEASINFO").get("Ref", refstr);
    1655        1480 :                 msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").define(
    1656             :                                 "Ref", refstr);
    1657             :         }
    1658             : 
    1659             :         // It's a variable ref. column
    1660        1864 :         if (refDir.keywordSet().asRecord("MEASINFO").isDefined("VarRefCol"))
    1661             :         {
    1662         384 :                 refDir.keywordSet().asRecord("MEASINFO").get("VarRefCol", refstr);
    1663         384 :                 msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").define("VarRefCol", refstr);
    1664         384 :                 nameVarRefColRefDir = refstr;
    1665             : 
    1666         384 :                 Vector<String> refTypeV;
    1667         384 :                 refDir.keywordSet().asRecord("MEASINFO").get("TabRefTypes", refTypeV);
    1668         384 :                 msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefTypes", refTypeV);
    1669             : 
    1670         384 :                 Vector<uInt> refCodeV;
    1671         384 :                 refDir.keywordSet().asRecord("MEASINFO").get("TabRefCodes", refCodeV);
    1672         384 :                 msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefCodes", refCodeV);
    1673             : 
    1674         384 :                 Int refid = msField.referenceDir().keywordSet().asRecord("MEASINFO").fieldNumber("Ref");
    1675         384 :                 if (refid >= 0)
    1676             :                 {
    1677         384 :                         msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").removeField(RecordFieldId(refid));
    1678             :                 }
    1679         384 :         }
    1680             : 
    1681             :         // ...and the time measure...
    1682        1864 :         time.keywordSet().asRecord("MEASINFO").get("Ref", refstr);
    1683        1864 :         msField.time().rwKeywordSet().asrwRecord("MEASINFO").define("Ref", refstr);
    1684             : 
    1685        1864 :         if (!reindex_p)
    1686             :         {
    1687          95 :                 const MSField &inputField = mssel_p.field();
    1688          95 :                 MSField &outputField = msOut_p.field();
    1689          95 :                 TableCopy::copyRows(outputField, inputField);
    1690          95 :                 copyEphemerisTable(msField);
    1691          95 :                 return true;
    1692             :         }
    1693             : 
    1694             :         // fieldRelabel_p size: nrow of a input MS, -1 for unselected field ids
    1695        1769 :         fieldRelabel_p.resize(mscIn_p->field().nrow());
    1696        1769 :         fieldRelabel_p.set(-1);
    1697             : 
    1698             :         os      << LogIO::DEBUG1 << fieldid_p.nelements()
    1699        1769 :                 << " fields selected out of " << mscIn_p->field().nrow()
    1700        1769 :                 << LogIO::POST;
    1701             : 
    1702             :         try {
    1703             : 
    1704        1769 :                 msOut_p.field().addRow(fieldid_p.nelements());
    1705             : 
    1706        6362 :                 for (uInt k = 0; k < fieldid_p.nelements(); ++k)
    1707             :                 {
    1708        4593 :                         fieldRelabel_p[fieldid_p[k]] = k;
    1709             : 
    1710        4593 :                         msField.code().put(k, code(fieldid_p[k]));
    1711        4593 :                         msField.delayDir().put(k, delayDir(fieldid_p[k]));
    1712        4593 :                         msField.flagRow().put(k, flagRow(fieldid_p[k]));
    1713        4593 :                         msField.name().put(k, name(fieldid_p[k]));
    1714        4593 :                         msField.numPoly().put(k, numPoly(fieldid_p[k]));
    1715        4593 :                         msField.phaseDir().put(k, phaseDir(fieldid_p[k]));
    1716        4593 :                         msField.referenceDir().put(k, refDir(fieldid_p[k]));
    1717        4593 :                         msField.time().put(k, time(fieldid_p[k]));
    1718             : 
    1719        4593 :                         Int inSrcID = sourceId(fieldid_p[k]);
    1720        4593 :                         if (inSrcID < 0)
    1721             :                         {
    1722         519 :                                 msField.sourceId().put(k, -1);
    1723             :                         }
    1724             :                         else
    1725             :                         {
    1726        4074 :                                 msField.sourceId().put(k, sourceRelabel_p[inSrcID]);
    1727             :                         }
    1728             :                 }
    1729             : 
    1730        1769 :                 if (nAddedCols > 0)
    1731             :                 {
    1732         339 :                         copyEphemerisTable(msField);
    1733             : 
    1734             :                         // need to copy the reference column
    1735         339 :                         if (!nameVarRefColDelayDir.empty())
    1736             :                         {
    1737         335 :                                 ScalarColumn<Int> dM(mssel_p.field(), nameVarRefColDelayDir);
    1738         335 :                                 ScalarColumn<Int> cdMDirRef(msOut_p.field(),nameVarRefColDelayDir);
    1739        1658 :                                 for (uInt k = 0; k < fieldid_p.nelements(); ++k)
    1740             :                                 {
    1741        1323 :                                         cdMDirRef.put(k, dM(fieldid_p[k]));
    1742             :                                 }
    1743         335 :                         }
    1744             : 
    1745             :                         // need to copy the reference column
    1746         339 :                         if (!nameVarRefColPhaseDir.empty())
    1747             :                         {
    1748         335 :                                 ScalarColumn<Int> dM(mssel_p.field(), nameVarRefColPhaseDir);
    1749         335 :                                 ScalarColumn<Int> cdMDirRef(msOut_p.field(),nameVarRefColPhaseDir);
    1750        1658 :                                 for (uInt k = 0; k < fieldid_p.nelements(); ++k)
    1751             :                                 {
    1752        1323 :                                         cdMDirRef.put(k, dM(fieldid_p[k]));
    1753             :                                 }
    1754         335 :                         }
    1755             : 
    1756             :                         // need to copy the reference column
    1757         339 :                         if (!nameVarRefColRefDir.empty())
    1758             :                         {
    1759         335 :                                 ScalarColumn<Int> dM(mssel_p.field(), nameVarRefColRefDir);
    1760         335 :                                 ScalarColumn<Int> cdMDirRef(msOut_p.field(),nameVarRefColRefDir);
    1761        1658 :                                 for (uInt k = 0; k < fieldid_p.nelements(); ++k)
    1762             :                                 {
    1763        1323 :                                         cdMDirRef.put(k, dM(fieldid_p[k]));
    1764             :                                 }
    1765         335 :                         }
    1766             :                 }
    1767             : 
    1768             :         }
    1769           0 :         catch (AipsError x)
    1770             :         {
    1771           0 :                 os      << LogIO::EXCEPTION << "Error " << x.getMesg() << " setting up the output FIELD table." << LogIO::POST;
    1772           0 :         }
    1773           0 :         catch (...)
    1774             :         {
    1775           0 :                 throw(AipsError("Unknown exception caught and released in fillFieldTable()"));
    1776           0 :         }
    1777             : 
    1778        1769 :         return true;
    1779        1864 : }
    1780             : 
    1781         434 : bool MSTransformDataHandler::copyEphemerisTable(MSFieldColumns & msField)
    1782             : {
    1783         868 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    1784         434 :         const MSFieldColumns& fieldIn = mscIn_p->field();
    1785         434 :         ScalarColumn<Int> eID(fieldIn.ephemerisId());
    1786             : 
    1787         434 :         if (eID.hasContent())
    1788             :         {
    1789             :                 uInt nField;
    1790         321 :                 if (reindex_p)
    1791             :                 {
    1792         274 :                         nField = fieldid_p.nelements();
    1793             :                 }
    1794             :                 else
    1795             :                 {
    1796          47 :                         nField = eID.nrow();
    1797             :                 }
    1798             : 
    1799         321 :                 String destPathName = Path(msOut_p.field().tableName()).absoluteName();
    1800         321 :                 ScalarColumn<String> name(fieldIn.name());
    1801             : 
    1802        1649 :                 for (uInt k = 0; k < nField; ++k)
    1803             :                 {
    1804             :                         uInt fieldId;
    1805        1328 :                         if (reindex_p)
    1806             :                         {
    1807        1188 :                                 fieldId = fieldid_p[k];
    1808             :                         }
    1809             :                         else
    1810             :                         {
    1811         140 :                                 fieldId = k;
    1812             :                         }
    1813             : 
    1814        1328 :                         Int theEphId = eID(fieldId);
    1815             : 
    1816             :                         // There is an ephemeris attached to this field
    1817        1328 :                         if (theEphId > -1)
    1818             :                         {
    1819          50 :                                 Path ephPath = Path(fieldIn.ephemPath(fieldId));
    1820             : 
    1821             :                                 // Copy the ephemeris table over to the output FIELD table
    1822          50 :                                 if (ephPath.length() > 0)
    1823             :                                 {
    1824          50 :                                         Directory origEphemDir(ephPath);
    1825          50 :                                         origEphemDir.copy(destPathName + "/" + ephPath.baseName());
    1826             : 
    1827             :                                         os      << LogIO::NORMAL
    1828           0 :                                                         << "Transferring ephemeris " << ephPath.baseName()
    1829          50 :                                                         << " for output field " << name(fieldId)
    1830          50 :                                                         << LogIO::POST;
    1831          50 :                                 }
    1832          50 :                         }
    1833             : 
    1834        1328 :                         if (reindex_p)
    1835             :                         {
    1836        1188 :                                 msField.ephemerisId().put(k, theEphId);
    1837             :                         }
    1838             :                 }
    1839         321 :         }
    1840             : 
    1841         434 :         return true;
    1842         434 : }
    1843             : 
    1844             : // -----------------------------------------------------------------------
    1845             : //  Modified version of fillDDTables
    1846             : // -----------------------------------------------------------------------
    1847        1864 : bool MSTransformDataHandler::fillDDTables()
    1848             : {
    1849        1864 :         fillPolTable();
    1850        1864 :         fillDDITable();
    1851        1864 :         fillSPWTable();
    1852             : 
    1853        1864 :         return true;
    1854             : }
    1855             : 
    1856             : // -----------------------------------------------------------------------
    1857             : //
    1858             : // -----------------------------------------------------------------------
    1859        1864 : bool MSTransformDataHandler::fillPolTable()
    1860             : {
    1861        3728 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    1862             : 
    1863             :         // Input polarization table
    1864        1864 :         const MSPolarization &poltable = mssel_p.polarization();
    1865        1864 :         ScalarColumn<Int> numCorr(poltable,MSPolarization::columnName(MSPolarization::NUM_CORR));
    1866        1864 :         ArrayColumn<Int> corrType(poltable,MSPolarization::columnName(MSPolarization::CORR_TYPE));
    1867        1864 :         ArrayColumn<Int> corrProd(poltable,MSPolarization::columnName(MSPolarization::CORR_PRODUCT));
    1868        1864 :         ScalarColumn<bool> flagRow(poltable,MSPolarization::columnName(MSPolarization::FLAG_ROW));
    1869             : 
    1870             :         // Output polarization table
    1871        1864 :         MSPolarizationColumns& msPol(msc_p->polarization());
    1872             : 
    1873             :         // Fill output polarization table
    1874        1864 :         uInt nPol = poltable.nrow(); // nOutputPol = nInputPol (no PolId re-index)
    1875        1864 :         corrSlice_p.resize(nPol);
    1876        4119 :         for (uInt polId = 0; polId < nPol; polId++)
    1877             :         {
    1878        2255 :                 uInt ncorr = inPolOutCorrToInCorrMap_p[polId].nelements();
    1879        2255 :                 const Vector<Int> inCT(corrType(polId));
    1880             : 
    1881             :                 // Add row
    1882        2255 :                 msOut_p.polarization().addRow();
    1883        2255 :                 msPol.numCorr().put(polId, ncorr);
    1884        2255 :                 msPol.flagRow().put(polId, flagRow(polId));
    1885             : 
    1886             :                 // Setup correlation slices
    1887        2255 :                 if (ncorr > 0 && ncorr < inCT.nelements())
    1888             :                 {
    1889          78 :                         keepShape_p = false;
    1890             : 
    1891             :                         // Check whether the requested correlations can be accessed by slicing.
    1892             :                         // That means there must be a constant stride.  The most likely (only?)
    1893             :                         // way to violate that is to ask for 3 out of 4 correlations.
    1894          78 :                         if (ncorr > 2)
    1895             :                         {
    1896             :                                 os      << LogIO::SEVERE
    1897             :                                         << "Sorry, the requested correlation selection is not unsupported.\n"
    1898             :                                         << "Try selecting fewer or all of the correlations."
    1899           0 :                                         << LogIO::POST;
    1900           0 :                                 return false;
    1901             :                         }
    1902             : 
    1903          78 :                         size_t increment = 2;
    1904          78 :                         if (ncorr > 1)
    1905             :                         {
    1906          18 :                                 increment = inPolOutCorrToInCorrMap_p[polId][1] - inPolOutCorrToInCorrMap_p[polId][0];
    1907             :                         }
    1908          78 :                         corrSlice_p[polId] = Slice(inPolOutCorrToInCorrMap_p[polId][0],ncorr,increment);
    1909             :                 }
    1910             :                 else
    1911             :                 {
    1912        2177 :                         corrSlice_p[polId] = Slice(0, ncorr);
    1913             :                 }
    1914             : 
    1915             :                 // Apply slices to correlation type and product
    1916        2255 :                 Vector<Int> outCT;
    1917        2255 :                 const Matrix<Int> inCP(corrProd(polId));
    1918        2255 :                 Matrix<Int> outCP;
    1919        2255 :                 outCT.resize(ncorr);
    1920        2255 :                 outCP.resize(2, ncorr);
    1921        7000 :                 for (uInt k = 0; k < ncorr; ++k)
    1922             :                 {
    1923        4745 :                         Int inCorrInd = inPolOutCorrToInCorrMap_p[polId][k];
    1924             : 
    1925        4745 :                         outCT[k] = inCT[inCorrInd];
    1926       14235 :                         for (uInt feedind = 0; feedind < 2; ++feedind)
    1927             :                         {
    1928        9490 :                                 outCP(feedind, k) = inCP(feedind, inCorrInd);
    1929             :                         }
    1930             : 
    1931             :                 }
    1932             : 
    1933             :                 // Fill correlation type and product
    1934        2255 :                 msPol.corrType().put(polId, outCT);
    1935        2255 :                 msPol.corrProduct().put(polId, outCP);
    1936        2255 :         }
    1937             : 
    1938        1864 :         return true;
    1939        1864 : }
    1940             : 
    1941             : // -----------------------------------------------------------------------
    1942             : //
    1943             : // -----------------------------------------------------------------------
    1944        1864 : bool MSTransformDataHandler::fillDDITable()
    1945             : {
    1946        3728 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    1947             : 
    1948             :         // Input selected DDIs based on joint SPW-Pol selection
    1949        1864 :         uInt nddid = spw2ddid_p.size();
    1950             : 
    1951             :         // Input ddi table
    1952        1864 :         const MSDataDescription &inputDDI = mssel_p.dataDescription();
    1953             : 
    1954        1864 :         ScalarColumn<Int> polIdCol(inputDDI, MSDataDescription::columnName(MSDataDescription::POLARIZATION_ID));
    1955        1864 :         ScalarColumn<Int> spwIdCol(inputDDI,MSDataDescription::columnName(MSDataDescription::SPECTRAL_WINDOW_ID));
    1956             : 
    1957             :         // Get selected SPWs
    1958        1864 :         Vector<Int> selectedSpwIds(nddid);
    1959       12459 :         for (uInt row=0; row<spw2ddid_p.size(); ++row)
    1960             :         {
    1961       10595 :                 selectedSpwIds[row] = spwIdCol(spw2ddid_p[row]);
    1962             :         }
    1963             : 
    1964             :         // Get list of unique selected SPWs
    1965        1864 :         bool option(false);
    1966        1864 :         Sort sortSpws(spw_p.getStorage(option), sizeof(Int));
    1967        1864 :         sortSpws.sortKey((uInt) 0, TpInt);
    1968        1864 :         Vector<uInt> spwsortindex, spwuniqinds;
    1969        1864 :         sortSpws.sort(spwsortindex, spw_p.nelements());
    1970        1864 :         uInt nuniqSpws = sortSpws.unique(spwuniqinds, spwsortindex);
    1971        1864 :         spw_uniq_p.resize(nuniqSpws);
    1972             : 
    1973             :         // Make map from input to output SPWs
    1974        1864 :         spwRelabel_p.resize(mscIn_p->spectralWindow().nrow());
    1975        1864 :         spwRelabel_p.set(-1);
    1976       12430 :         for (uInt k = 0; k < nuniqSpws; ++k)
    1977             :         {
    1978       10566 :                 spw_uniq_p[k] = spw_p[spwuniqinds[k]];
    1979       10566 :                 spwRelabel_p[spw_uniq_p[k]] = k;
    1980             :         }
    1981             : 
    1982        1864 :         if (!reindex_p)
    1983             :         {
    1984          95 :                 MSDataDescription &outputDDI = msOut_p.dataDescription();
    1985          95 :                 TableCopy::copyRows(outputDDI, inputDDI);
    1986          95 :                 return true;
    1987             :         }
    1988             : 
    1989             :         // Output SPECTRAL_WINDOW_ID column
    1990        1769 :         Vector<Int> newSPWId(nddid);
    1991       11171 :         for (uInt ddi=0; ddi<nddid; ddi++)
    1992             :         {
    1993        9402 :                 newSPWId[ddi] = spwRelabel_p[spwIdCol(spw2ddid_p[ddi])];
    1994             :         }
    1995             : 
    1996             :         // Output POLARIZATION_ID column
    1997        1769 :         Vector<Int> newPolId(nddid);
    1998       11171 :         for (uInt ddi=0; ddi<nddid; ddi++)
    1999             :         {
    2000        9402 :                 newPolId[ddi] = polIdCol(spw2ddid_p[ddi]);
    2001             :         }
    2002             : 
    2003             :         // Fill output DDI table
    2004        1769 :         MSDataDescColumns& outputDDI(msc_p->dataDescription());
    2005       11171 :         for (uInt ddi=0; ddi<nddid; ddi++)
    2006             :         {
    2007        9402 :                 msOut_p.dataDescription().addRow();
    2008        9402 :                 outputDDI.flagRow().put(ddi, false);
    2009        9402 :                 outputDDI.polarizationId().put(ddi, newPolId[ddi]);
    2010        9402 :                 outputDDI.spectralWindowId().put(ddi, newSPWId[ddi]);
    2011             :         }
    2012             : 
    2013             : 
    2014        1769 :         return true;
    2015        1864 : }
    2016             : 
    2017             : // -----------------------------------------------------------------------
    2018             : //
    2019             : // -----------------------------------------------------------------------
    2020        1864 : bool MSTransformDataHandler::fillSPWTable()
    2021             : {
    2022        3728 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    2023             : 
    2024             :         // Selected input MS SPW Table Columns (read-only)
    2025        1864 :         MSSpWindowColumns inSpWCols(mssel_p.spectralWindow());
    2026             : 
    2027             :         // SPW Table Columns of output MS (read-write)
    2028        1864 :         MSSpWindowColumns& msSpW(msc_p->spectralWindow());
    2029             : 
    2030             :         // Detect which optional columns of SPECTRAL_WINDOW are present.
    2031             :         // inSpWCols and msSpW should agree because addOptionalColumns() was done for
    2032             :         // SPECTRAL_WINDOW in fillAllTables() before making msc_p or calling fillDDTables
    2033        1864 :         bool haveSpwAN = columnOk(inSpWCols.assocNature());
    2034        1864 :         bool haveSpwASI = columnOk(inSpWCols.assocSpwId());
    2035        1864 :         bool haveSpwBN = columnOk(inSpWCols.bbcNo());
    2036        1864 :         bool haveSpwBS = columnOk(inSpWCols.bbcSideband());
    2037        1864 :         bool haveSpwDI = columnOk(inSpWCols.dopplerId());
    2038        3864 :         bool haveSpwSWF = mssel_p.spectralWindow().tableDesc().isColumn("SDM_WINDOW_FUNCTION") &&
    2039        2000 :                           mssel_p.spectralWindow().tableDesc().columnDescSet().isDefined("SDM_WINDOW_FUNCTION");
    2040        3864 :         bool haveSpwSNB = mssel_p.spectralWindow().tableDesc().isColumn("SDM_NUM_BIN") &&
    2041        2000 :                           mssel_p.spectralWindow().tableDesc().columnDescSet().isDefined("SDM_NUM_BIN");
    2042        3824 :         bool haveSpwCorrBit = mssel_p.spectralWindow().tableDesc().isColumn("SDM_CORR_BIT") &&
    2043        1960 :                               mssel_p.spectralWindow().tableDesc().columnDescSet().isDefined("SDM_CORR_BIT");
    2044             : 
    2045        1864 :         uInt nuniqSpws = spw_uniq_p.size();
    2046             : 
    2047             :         // This sets the number of input channels for each spw. But
    2048             :         // it considers that a SPW ID contains only one set of channels.
    2049             :         // I hope this is true!!
    2050             :         // Write to SPECTRAL_WINDOW table
    2051        1864 :         inNumChan_p.resize(spw_p.nelements());
    2052       12437 :         for (uInt k = 0; k < spw_p.nelements(); ++k)
    2053             :         {
    2054       10573 :                 inNumChan_p[k] = inSpWCols.numChan()(spw_p[k]);
    2055             :         }
    2056             : 
    2057        1864 :         if (reindex_p)
    2058             :         {
    2059        1769 :                 msOut_p.spectralWindow().addRow(nuniqSpws);
    2060             :         }
    2061             :         else
    2062             :         {
    2063          95 :                 const MSSpectralWindow &inputSPW = mssel_p.spectralWindow();
    2064          95 :                 MSSpectralWindow &outputSPW = msOut_p.spectralWindow();
    2065          95 :                 TableCopy::copyRows(outputSPW, inputSPW);
    2066             :         }
    2067             : 
    2068             : 
    2069        1864 :         Vector<Vector<Int> > spwinds_of_uniq_spws(nuniqSpws);
    2070        1864 :         totnchan_p.resize(nuniqSpws);
    2071       12430 :         for (uInt k = 0; k < nuniqSpws; ++k)
    2072             :         {
    2073       10566 :                 Int maxchan = 0;
    2074       10566 :                 uInt j = 0;
    2075             : 
    2076       10566 :                 totnchan_p[k] = 0;
    2077       10566 :                 spwinds_of_uniq_spws[k].resize();
    2078      184259 :                 for (uInt spwind = 0; spwind < spw_p.nelements(); ++spwind)
    2079             :                 {
    2080      173693 :                         if (spw_p[spwind] == spw_uniq_p[k])
    2081             :                         {
    2082       10573 :                                 Int highchan = nchan_p[spwind] * chanStep_p[spwind] + chanStart_p[spwind];
    2083             : 
    2084       10573 :                                 if (highchan > maxchan) maxchan = highchan;
    2085             : 
    2086       10573 :                                 totnchan_p[k] += nchan_p[spwind];
    2087             : 
    2088             :                                 // The true is necessary to avoid scrambling previously assigned values.
    2089       10573 :                                 spwinds_of_uniq_spws[k].resize(j + 1, true);
    2090             : 
    2091             :                                 // Warning!  spwinds_of_uniq_spws[k][j] will compile without warning, but dump core at runtime.
    2092       10573 :                                 (spwinds_of_uniq_spws[k])[j] = spwind;
    2093             : 
    2094       10573 :                                 ++j;
    2095             :                         }
    2096             :                 }
    2097       10566 :                 if (maxchan > inSpWCols.numChan()(spw_uniq_p[k]))
    2098             :                 {
    2099             :                         os      << LogIO::SEVERE
    2100             :                                 << " Channel settings wrong; exceeding number of channels in spw "
    2101           0 :                                 << spw_uniq_p[k] << LogIO::POST;
    2102           0 :                         return false;
    2103             :                 }
    2104             :         }
    2105             : 
    2106             :         // min_k is an index for getting an spw index via spw_uniq_p[min_k].
    2107             :         // k is an index for getting an spw index via spw_p[k].
    2108       12430 :         for (uInt min_k = 0; min_k < nuniqSpws; ++min_k)
    2109             :         {
    2110       10566 :                 uInt k = spwinds_of_uniq_spws[min_k][0];
    2111       10566 :                 uInt outSPWId = reindex_p? min_k : spw_p[k];
    2112             : 
    2113       10566 :                 if (spwinds_of_uniq_spws[min_k].nelements() > 1 || nchan_p[k] != inSpWCols.numChan()(spw_p[k]))
    2114             :                 {
    2115        1453 :                         Vector<Double> effBWIn = inSpWCols.effectiveBW()(spw_uniq_p[min_k]);
    2116        1453 :                         Int nOutChan = totnchan_p[min_k];
    2117        1453 :                         Vector<Double> chanFreqOut(nOutChan);
    2118        1453 :                         Vector<Double> chanFreqIn = inSpWCols.chanFreq()(spw_uniq_p[min_k]);
    2119        1453 :                         Vector<Double> chanWidthOut(nOutChan);
    2120        1453 :                         Vector<Double> chanWidthIn = inSpWCols.chanWidth()(spw_uniq_p[min_k]);
    2121        1453 :                         Vector<Double> spwResolOut(nOutChan);
    2122        1453 :                         Vector<Double> spwResolIn = inSpWCols.resolution()(spw_uniq_p[min_k]);
    2123        1453 :                         Vector<Double> effBWOut(nOutChan);
    2124        1453 :                         Int outChan = 0;
    2125        1453 :                         Int outChanNotDropped = 0;
    2126             : 
    2127        1453 :                         keepShape_p = false;
    2128             : 
    2129             :                         // The sign of CHAN_WIDTH defaults to +.  Its determination assumes that
    2130             :                         // chanFreqIn is monotonic, but not that the sign of the chanWidthIn is correct.
    2131        1453 :                         bool neginc = chanFreqIn[chanFreqIn.nelements() - 1] < chanFreqIn[0];
    2132             : 
    2133        1453 :                         effBWOut.set(0.0);
    2134        1453 :                         Double totalBW = 0.0;
    2135        2913 :                         for (uInt rangeNum = 0; rangeNum < spwinds_of_uniq_spws[min_k].nelements(); ++rangeNum)
    2136             :                         {
    2137        1460 :                                 k = spwinds_of_uniq_spws[min_k][rangeNum];
    2138             : 
    2139        1460 :                                 Int span = chanStep_p[k] * widths_p[k];
    2140             : 
    2141       44468 :                                 for (Int j = 0; j < nchan_p[k]; ++j)
    2142             :                                 {
    2143       43008 :                                         Int inpChan = chanStart_p[k] + j * span;
    2144             : 
    2145       43008 :                                         if (span >= 1)
    2146             :                                         {
    2147       43008 :                                                 Int lastChan = inpChan + span - 1;
    2148             : 
    2149       43008 :                                                 if (lastChan > chanEnd_p[k])
    2150             :                                                 {
    2151             :                                                         // The averaging width is not a factor of the number of
    2152             :                                                         // selected input channels, so the last output bin receives
    2153             :                                                         // fewer input channels than the other bins.
    2154          14 :                                                         lastChan = chanEnd_p[k];
    2155             : 
    2156          14 :                                                         Int nchan = lastChan - inpChan + 1;
    2157             :                                                         os      << LogIO::NORMAL
    2158             :                                                                 << "The last output channel of spw "
    2159          28 :                                                                 << spw_p[k] << " has only " << nchan
    2160          14 :                                                                 << " input channel";
    2161          14 :                                                         if (nchan > 1) os << "s.";
    2162          14 :                                                         os << LogIO::POST;
    2163             : 
    2164             :                                                         // jagonzal (CAS-8618): We may have more than one channel dropped per SPW
    2165             :                                                         // due to multiple channel selections
    2166          14 :                                                         spwDropChannelMap_p[spw_p[k]].push_back(outChan);
    2167             :                                                 }
    2168             :                                                 else
    2169             :                                                 {
    2170      132819 :                                                         for (Int inputChan = inpChan;inputChan<=lastChan;inputChan++)
    2171             :                                                         {
    2172       89825 :                                                                 spwSelectedChannelMap_p[spw_p[k]][outChanNotDropped].push_back(inputChan);
    2173             :                                                         }
    2174       42994 :                                                         outChanNotDropped++;
    2175             :                                                 }
    2176             : 
    2177       43008 :                                                 chanFreqOut[outChan] = (chanFreqIn[inpChan]
    2178       43008 :                                                                 + chanFreqIn[lastChan]) / 2;
    2179             : 
    2180       43008 :                                                 Double sep = chanFreqIn[lastChan] - chanFreqIn[inpChan];
    2181             : 
    2182       43008 :                                                 if (neginc) sep = -sep;
    2183             : 
    2184             :                                                 // The internal abs is necessary because the sign of chanWidthIn may be wrong.
    2185       43008 :                                                 chanWidthOut[outChan] = sep + 0.5 * abs(chanWidthIn[inpChan] + chanWidthIn[lastChan]);
    2186       43008 :                                                 if (neginc) chanWidthOut[outChan] = -chanWidthOut[outChan];
    2187             : 
    2188       43008 :                                                 spwResolOut[outChan] = 0.5 * (spwResolIn[inpChan] + spwResolIn[lastChan]) + sep;
    2189             : 
    2190      132888 :                                                 for (Int avgChan = inpChan; avgChan <= lastChan; avgChan += chanStep_p[k])
    2191             :                                                 {
    2192       89880 :                                                         effBWOut[outChan] += effBWIn[avgChan];
    2193             :                                                 }
    2194             : 
    2195             :                                         }
    2196             :                                         else
    2197             :                                         {
    2198           0 :                                                 chanFreqOut[outChan] = chanFreqIn[inpChan];
    2199           0 :                                                 spwResolOut[outChan] = spwResolIn[inpChan];
    2200           0 :                                                 chanWidthOut[outChan] = chanWidthIn[inpChan];
    2201           0 :                                                 effBWOut[outChan] = effBWIn[inpChan];
    2202             :                                         }
    2203             :                                         // Use CHAN_WIDTH instead of EFFECTIVE_BW
    2204       43008 :                                         totalBW += abs(chanWidthOut[outChan]);
    2205       43008 :                                         ++outChan;
    2206             :                                 }
    2207             :                         }
    2208        1453 :                         --outChan;
    2209             : 
    2210        1453 :                         msSpW.chanFreq().put(outSPWId, chanFreqOut);
    2211        1453 :                         msSpW.refFrequency().put(outSPWId,min(chanFreqOut[0], chanFreqOut[chanFreqOut.size() - 1]));
    2212        1453 :                         msSpW.resolution().put(outSPWId, spwResolOut);
    2213        1453 :                         msSpW.numChan().put(outSPWId, nOutChan);
    2214        1453 :                         msSpW.chanWidth().put(outSPWId, chanWidthOut);
    2215        1453 :                         msSpW.effectiveBW().put(outSPWId, spwResolOut);
    2216        1453 :                         msSpW.totalBandwidth().put(outSPWId, totalBW);
    2217        1453 :                 }
    2218             :                 else
    2219             :                 {
    2220        9113 :                         msSpW.chanFreq().put(outSPWId, inSpWCols.chanFreq()(spw_p[k]));
    2221        9113 :                         msSpW.refFrequency().put(outSPWId, inSpWCols.refFrequency()(spw_p[k]));
    2222        9113 :                         msSpW.resolution().put(outSPWId, inSpWCols.resolution()(spw_p[k]));
    2223        9113 :                         msSpW.numChan().put(outSPWId, inSpWCols.numChan()(spw_p[k]));
    2224        9113 :                         msSpW.chanWidth().put(outSPWId, inSpWCols.chanWidth()(spw_p[k]));
    2225        9113 :                         msSpW.effectiveBW().put(outSPWId, inSpWCols.effectiveBW()(spw_p[k]));
    2226        9113 :                         msSpW.totalBandwidth().put(outSPWId,inSpWCols.totalBandwidth()(spw_p[k]));
    2227             :                 }
    2228             : 
    2229       10566 :                 msSpW.flagRow().put(outSPWId, inSpWCols.flagRow()(spw_p[k]));
    2230       10566 :                 msSpW.freqGroup().put(outSPWId, inSpWCols.freqGroup()(spw_p[k]));
    2231       10566 :                 msSpW.freqGroupName().put(outSPWId, inSpWCols.freqGroupName()(spw_p[k]));
    2232       10566 :                 msSpW.ifConvChain().put(outSPWId, inSpWCols.ifConvChain()(spw_p[k]));
    2233       10566 :                 msSpW.measFreqRef().put(outSPWId, inSpWCols.measFreqRef()(spw_p[k]));
    2234       10566 :                 msSpW.name().put(outSPWId, inSpWCols.name()(spw_p[k]));
    2235       10566 :                 msSpW.netSideband().put(outSPWId, inSpWCols.netSideband()(spw_p[k]));
    2236             : 
    2237             : 
    2238       10566 :                 if (haveSpwBN) msSpW.bbcNo().put(outSPWId, inSpWCols.bbcNo()(spw_p[k]));
    2239       10566 :                 if (haveSpwBS) msSpW.bbcSideband().put(outSPWId, inSpWCols.bbcSideband()(spw_p[k]));
    2240       10566 :         if (haveSpwDI) msSpW.dopplerId().put(outSPWId, inSpWCols.dopplerId()(spw_p[k]));
    2241       10566 :         if (haveSpwSWF) 
    2242             :         {
    2243        2879 :             ScalarColumn<String> inSwfCol(mssel_p.spectralWindow(), "SDM_WINDOW_FUNCTION");
    2244        2879 :             ScalarColumn<String> outSwfCol(msOut_p.spectralWindow(), "SDM_WINDOW_FUNCTION");
    2245        2879 :             outSwfCol.put(outSPWId, inSwfCol(spw_p[k]));
    2246        2879 :         }
    2247       10566 :         if (haveSpwSNB) 
    2248             :         {
    2249        2879 :             ScalarColumn<Int> inSnbCol(mssel_p.spectralWindow(), "SDM_NUM_BIN");
    2250        2879 :             ScalarColumn<Int> outSnbCol(msOut_p.spectralWindow(), "SDM_NUM_BIN");
    2251        2879 :             outSnbCol.put(outSPWId, inSnbCol(spw_p[k]));
    2252        2879 :         }
    2253       10566 :         if (haveSpwCorrBit) 
    2254             :         {
    2255        1868 :             ScalarColumn<String> inCorrBitCol(mssel_p.spectralWindow(), "SDM_CORR_BIT");
    2256        1868 :             ScalarColumn<String> outCorrBitCol(msOut_p.spectralWindow(), "SDM_CORR_BIT");
    2257        1868 :             outCorrBitCol.put(outSPWId, inCorrBitCol(spw_p[k]));
    2258        1868 :         }
    2259             : 
    2260       10566 :                 if (haveSpwASI)
    2261             :                 {
    2262        4035 :                         if (reindex_p)
    2263             :                         {
    2264             :                                 // Get list of SPWs associated to his one
    2265        3301 :                                 std::vector<Int> selectedSPWs = spw_p.tovector();
    2266             : 
    2267             :                                 // Get the list of selected SPWs and association nature
    2268        3301 :                                 Array<Int> assocSpwId = inSpWCols.assocSpwId()(spw_p[k]);
    2269        3301 :                                 Array<String> assocNature = inSpWCols.assocNature()(spw_p[k]);
    2270             : 
    2271             :                                 // Find which associated SPWs are selected, and store the transformed Id
    2272        3301 :                                 std::vector<Int>::iterator findIt;
    2273        3301 :                                 std::vector<Int> selectedAssocSpwId;
    2274        3301 :                                 std::vector<String> selectedAssocNature;
    2275       53953 :                                 for (uInt idx=0;idx<assocSpwId.size();idx++)
    2276             :                                 {
    2277       50652 :                                         IPosition pos(1,idx);
    2278       50652 :                                         Int spw = assocSpwId(pos);
    2279       50652 :                                         findIt = find (selectedSPWs.begin(), selectedSPWs.end(), spw);
    2280       50652 :                                         if (findIt != selectedSPWs.end())
    2281             :                                         {
    2282        5672 :                                                 selectedAssocSpwId.push_back(spwRelabel_p[spw]);
    2283        5672 :                                                 if (haveSpwAN) selectedAssocNature.push_back(assocNature(pos));
    2284             :                                         }
    2285       50652 :                                 }
    2286             : 
    2287             :                                 // Store selected associated SPW Ids
    2288        3301 :                                 Vector<Int> selectedAssocSpwIdVector(selectedAssocSpwId);
    2289        3301 :                                 msSpW.assocSpwId().put(min_k, selectedAssocSpwIdVector);
    2290             : 
    2291             :                                 // Store selected association nature
    2292        3301 :                                 if (haveSpwAN)
    2293             :                                 {
    2294        3301 :                                         Vector<String> selectedAssocNatureVector(selectedAssocNature);
    2295        3301 :                                         msSpW.assocNature().put(min_k, selectedAssocNatureVector);
    2296        3301 :                                 }
    2297        3301 :                         }
    2298             :                         else
    2299             :                         {
    2300         734 :                                 msSpW.assocNature().put(outSPWId, inSpWCols.assocNature()(outSPWId));
    2301             :                         }
    2302             :                 }
    2303             :         }
    2304             : 
    2305             : 
    2306        1864 :         return true;
    2307        1864 : }
    2308             : 
    2309             : // -----------------------------------------------------------------------
    2310             : //
    2311             : // -----------------------------------------------------------------------
    2312        9659 : uInt MSTransformDataHandler::addOptionalColumns(const Table& inTab, Table& outTab,const bool beLazy)
    2313             : {
    2314        9659 :         uInt nAdded = 0;
    2315        9659 :         const TableDesc& inTD = inTab.actualTableDesc();
    2316             : 
    2317             :         // Only rely on the # of columns if you are sure that inTab and outTab
    2318             :         // can't have the same # of columns without having _different_ columns,
    2319             :         // i.e. use beLazy if outTab.actualTableDesc() is in its default state.
    2320        9659 :         uInt nInCol = inTD.ncolumn();
    2321        9659 :         if (!beLazy || nInCol > outTab.actualTableDesc().ncolumn())
    2322             :         {
    2323        9116 :                 LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    2324             : 
    2325        4558 :                 Vector<String> oldColNames = inTD.columnNames();
    2326             : 
    2327       67683 :                 for (uInt k = 0; k < nInCol; ++k)
    2328             :                 {
    2329       63125 :                         if (!outTab.actualTableDesc().isColumn(oldColNames[k]))
    2330             :                         {
    2331             :                                 try
    2332             :                                 {
    2333       28229 :                                         outTab.addColumn(inTD.columnDesc(k), false);
    2334       28229 :                                         ++nAdded;
    2335             :                                 }
    2336             :                                 // NOT AipsError x
    2337           0 :                                 catch (...)
    2338             :                                 {
    2339             :                                         os      << LogIO::WARN << "Could not add column "
    2340           0 :                                                 << oldColNames[k] << " to " << outTab.tableName()
    2341           0 :                                                 << LogIO::POST;
    2342           0 :                                 }
    2343             :                         }
    2344             :                 }
    2345        4558 :         }
    2346             : 
    2347        9659 :         return nAdded;
    2348        9659 : }
    2349             : 
    2350             : // -----------------------------------------------------------------------
    2351             : //
    2352             : // -----------------------------------------------------------------------
    2353        1864 : void MSTransformDataHandler::relabelSources()
    2354             : {
    2355        3728 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    2356             : 
    2357             :         //Source is an optional table, so it may not exist
    2358        1864 :         if (Table::isReadable(mssel_p.sourceTableName()))
    2359             :         {
    2360             :                 // Note that mscIn_p->field().sourceId() has ALL of the
    2361             :                 // sourceIDs in the input MS, not just the selected ones.
    2362        1864 :                 const Vector<Int>& inSrcIDs = mscIn_p->field().sourceId().getColumn();
    2363             : 
    2364        1864 :                 Int highestInpSrc = max(inSrcIDs);
    2365             : 
    2366             :                 // Ensure space for -1.
    2367        1864 :                 if (highestInpSrc < 0) highestInpSrc = 0;
    2368             : 
    2369        1864 :                 sourceRelabel_p.resize(highestInpSrc + 1);
    2370             :                 // Default to "any".
    2371        1864 :                 sourceRelabel_p.set(-1);
    2372             : 
    2373             :                 // Enable sourceIDs that are actually referred
    2374             :                 // by selected fields, and remap them using j.
    2375        1864 :                 uInt j = 0;
    2376        6692 :                 for (uInt k = 0; k < fieldid_p.nelements(); ++k)
    2377             :                 {
    2378        4828 :                         Int fldInSrcID = inSrcIDs[fieldid_p[k]];
    2379             : 
    2380        4828 :                         if (fldInSrcID > -1)
    2381             :                         {
    2382             :                                 // Multiple fields can use the same
    2383        4309 :                                 if (sourceRelabel_p[fldInSrcID] == -1)
    2384             :                                 {
    2385             :                                         // source in a mosaic.
    2386        3827 :                                         sourceRelabel_p[fldInSrcID] = j;
    2387        3827 :                                         ++j;
    2388             :                                 }
    2389             :                         }
    2390             :                 }
    2391        1864 :         }
    2392             :         else
    2393             :         {
    2394             :                 // Default to "any".
    2395             :                 os      << LogIO::NORMAL
    2396             :                         << "The input MS does not have the optional SOURCE table.\n"
    2397           0 :                         << "-1 will be used as a generic source ID." << LogIO::POST;
    2398           0 :                 sourceRelabel_p.resize(1);
    2399           0 :                 sourceRelabel_p.set(-1);
    2400             :         }
    2401             : 
    2402        3728 :         return;
    2403        1864 : }
    2404             : 
    2405             : // -----------------------------------------------------------------------
    2406             : //
    2407             : // -----------------------------------------------------------------------
    2408        2216 : void MSTransformDataHandler::copySubtable(const String& tabName, const Table& inTab,const bool doFilter)
    2409             : {
    2410        2216 :         String outName(msOut_p.tableName() + '/' + tabName);
    2411             : 
    2412        2216 :         if (PlainTable::tableCache()(outName)) PlainTable::tableCache().remove(outName);
    2413        2216 :         inTab.deepCopy(outName, Table::New, false, Table::AipsrcEndian, doFilter);
    2414        2216 :         Table outTab(outName, Table::Update);
    2415        2216 :         msOut_p.rwKeywordSet().defineTable(tabName, outTab);
    2416        2216 :         msOut_p.initRefs();
    2417             : 
    2418        4432 :         return;
    2419        2216 : }
    2420             : 
    2421             : // -----------------------------------------------------------------------
    2422             : //
    2423             : // -----------------------------------------------------------------------
    2424           0 : void MSTransformDataHandler::make_map(std::map<Int, Int>& mapper, const Vector<Int>& inv)
    2425             : {
    2426           0 :   std::set<Int> valSet;
    2427             : 
    2428             :         // Strange, but slightly more efficient than going forward.
    2429           0 :         for (Int i = inv.nelements(); i--;)
    2430             :         {
    2431           0 :                 valSet.insert(inv[i]);
    2432             :         }
    2433             : 
    2434           0 :         uInt remaval = 0;
    2435           0 :         for (std::set<Int>::const_iterator vs_iter = valSet.begin(); vs_iter != valSet.end(); ++vs_iter)
    2436             :         {
    2437           0 :                 mapper[*vs_iter] = remaval;
    2438           0 :                 ++remaval;
    2439             :         }
    2440             : 
    2441           0 :         return;
    2442           0 : }
    2443             : 
    2444             : // -----------------------------------------------------------------------
    2445             : //
    2446             : // -----------------------------------------------------------------------
    2447        1864 : bool MSTransformDataHandler::copyPointing()
    2448             : {
    2449        3728 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    2450             : 
    2451             :         //Pointing is allowed to not exist
    2452        1864 :         if (Table::isReadable(mssel_p.pointingTableName()))
    2453             :         {
    2454        1864 :                 const MSPointing& oldPoint = mssel_p.pointing();
    2455             : 
    2456        1864 :                 if ((!antennaSel_p && timeRange_p == "") or !reindex_p)
    2457             :                 {
    2458             :                         // jagonzal: copySubtables works with POINTING because it
    2459             :                         // is not created by default in the method createSubtables
    2460        1816 :                         copySubtable(MS::keywordName(MS::POINTING), oldPoint);
    2461             :                 }
    2462             :                 else
    2463             :                 {
    2464          48 :                         setupNewPointing();
    2465             : 
    2466          48 :                         if (oldPoint.nrow() > 0)
    2467             :                         {
    2468             :                                 // Could be declared as Table&
    2469          22 :                                 MSPointing& newPoint = msOut_p.pointing();
    2470             : 
    2471             :                                 // Add optional columns if present in oldPoint.
    2472          22 :                                 uInt nAddedCols = addOptionalColumns(oldPoint, newPoint, true);
    2473          22 :                                 os << LogIO::DEBUG1 << "POINTING has " << nAddedCols << " optional columns." << LogIO::POST;
    2474             : 
    2475          22 :                                 const MSPointingColumns oldPCs(oldPoint);
    2476          22 :                                 MSPointingColumns newPCs(newPoint);
    2477          22 :                                 newPCs.setEpochRef(MEpoch::castType(oldPCs.timeMeas().getMeasRef().getType()));
    2478          22 :                                 newPCs.setDirectionRef(MDirection::castType(oldPCs.directionMeasCol().getMeasRef().getType()));
    2479          22 :                                 newPCs.setEncoderDirectionRef(MDirection::castType(oldPCs.encoderMeas().getMeasRef().getType()));
    2480             : 
    2481          22 :                                 const ScalarColumn<Int>& antIds = oldPCs.antennaId();
    2482          22 :                                 const ScalarColumn<Double>& time = oldPCs.time();
    2483          22 :                                 ScalarColumn<Int>& outants = newPCs.antennaId();
    2484             : 
    2485          22 :                                 uInt nTRanges = selTimeRanges_p.ncolumn();
    2486             : 
    2487          22 :                                 uInt outRow = 0;
    2488             : 
    2489             :                                 // Int for comparison
    2490          22 :                                 Int maxSelAntp1 = antNewIndex_p.nelements();
    2491             :                                 // with newAntInd.
    2492      122172 :                                 for (uInt inRow = 0; inRow < antIds.nrow(); ++inRow)
    2493             :                                 {
    2494      122150 :                                         Int newAntInd = antIds(inRow);
    2495      122150 :                                         if (antennaSel_p)
    2496             :                                         {
    2497           0 :                                                 newAntInd = newAntInd < maxSelAntp1 ? antNewIndex_p[newAntInd] : -1;
    2498             :                                         }
    2499             : 
    2500      122150 :                                         Double t = time(inRow);
    2501             : 
    2502      122150 :                                         if (newAntInd > -1)
    2503             :                                         {
    2504      122150 :                                                 bool matchT = false;
    2505      122150 :                                                 if (nTRanges == 0)
    2506             :                                                 {
    2507           0 :                                                         matchT = true;
    2508             :                                                 }
    2509             :                                                 else
    2510             :                                                 {
    2511      242222 :                                                         for (uInt tr = 0; tr < nTRanges; ++tr)
    2512             :                                                         {
    2513      122150 :                                                                 if (t >= selTimeRanges_p(0, tr) && t <= selTimeRanges_p(1, tr))
    2514             :                                                                 {
    2515        2078 :                                                                         matchT = true;
    2516        2078 :                                                                         break;
    2517             :                                                                 }
    2518             :                                                         }
    2519             :                                                 }
    2520             : 
    2521      122150 :                                                 if (matchT)
    2522             :                                                 {
    2523        2078 :                                                         TableCopy::copyRows(newPoint, oldPoint, outRow,inRow, 1, false);
    2524        2078 :                                                         outants.put(outRow, newAntInd);
    2525        2078 :                                                         ++outRow;
    2526             :                                                 }
    2527             :                                         }
    2528             :                                 }
    2529          22 :                         }
    2530             :                 }
    2531             :         }
    2532             :         else
    2533             :         {
    2534             :                 // Make an empty stub for MSColumns.
    2535           0 :                 setupNewPointing();
    2536             :         }
    2537             : 
    2538             : 
    2539        1864 :         return true;
    2540        1864 : }
    2541             : 
    2542             : // -----------------------------------------------------------------------
    2543             : //
    2544             : // -----------------------------------------------------------------------
    2545          48 : void MSTransformDataHandler::setupNewPointing()
    2546             : {
    2547           0 :         SetupNewTable pointingSetup(msOut_p.pointingTableName(),
    2548          48 :         MSPointing::requiredTableDesc(), Table::New);
    2549             : 
    2550             :         // POINTING can be large, set some sensible defaults for storageMgrs
    2551          48 :         IncrementalStMan ismPointing("ISMPointing");
    2552          48 :         StandardStMan ssmPointing("SSMPointing", 32768);
    2553          48 :         pointingSetup.bindAll(ismPointing, true);
    2554          48 :         pointingSetup.bindColumn(MSPointing::columnName(MSPointing::DIRECTION),ssmPointing);
    2555          48 :         pointingSetup.bindColumn(MSPointing::columnName(MSPointing::TARGET),ssmPointing);
    2556          48 :         pointingSetup.bindColumn(MSPointing::columnName(MSPointing::TIME),ssmPointing);
    2557          48 :         msOut_p.rwKeywordSet().defineTable(MS::keywordName(MS::POINTING),Table(pointingSetup));
    2558          48 :         msOut_p.initRefs();
    2559             : 
    2560          96 :         return;
    2561          48 : }
    2562             : 
    2563             : // -----------------------------------------------------------------------
    2564             : //
    2565             : // -----------------------------------------------------------------------
    2566        1864 : bool MSTransformDataHandler::copySource()
    2567             : {
    2568             :         //Source is an optional table, so it may not exist
    2569        1864 :         if (Table::isReadable(mssel_p.sourceTableName()))
    2570             :         {
    2571        3728 :                 LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    2572             : 
    2573        1864 :                 const MSSource& oldSource = mssel_p.source();
    2574        1864 :                 MSSource& newSource = msOut_p.source();
    2575             : 
    2576             :                 // Add optional columns if present in oldSource.
    2577        1864 :                 uInt nAddedCols = addOptionalColumns(oldSource, newSource, true);
    2578        1864 :                 os << LogIO::DEBUG1 << "SOURCE has " << nAddedCols << " optional columns." << LogIO::POST;
    2579             : 
    2580        1864 :                 const MSSourceColumns incols(oldSource);
    2581        1864 :                 MSSourceColumns outcols(newSource);
    2582             : 
    2583             :                 // Copy the Measures frame info.  This has to be done before filling the rows.
    2584        1864 :                 outcols.setEpochRef(MEpoch::castType(incols.timeMeas().getMeasRef().getType()));
    2585        1864 :                 outcols.setDirectionRef(MDirection::castType(incols.directionMeas().getMeasRef().getType()));
    2586        1864 :                 outcols.setPositionRef(MPosition::castType(incols.positionMeas().getMeasRef().getType()));
    2587        1864 :                 outcols.setFrequencyRef(MFrequency::castType(incols.restFrequencyMeas().getMeasRef().getType()));
    2588        1864 :                 outcols.setRadialVelocityRef(MRadialVelocity::castType(incols.sysvelMeas().getMeasRef().getType()));
    2589             : 
    2590        1864 :                 if (!reindex_p)
    2591             :                 {
    2592          95 :                         TableCopy::copyRows(newSource, oldSource);
    2593          95 :                         return true;
    2594             :                 }
    2595             : 
    2596        1769 :                 const ScalarColumn<Int>& inSId = incols.sourceId();
    2597        1769 :                 ScalarColumn<Int>& outSId = outcols.sourceId();
    2598        1769 :                 const ScalarColumn<Int>& inSPW = incols.spectralWindowId();
    2599        1769 :                 ScalarColumn<Int>& outSPW = outcols.spectralWindowId();
    2600             : 
    2601             :                 // row number in output.
    2602        1769 :                 uInt outrn = 0;
    2603        1769 :                 uInt nInputRows = inSId.nrow();
    2604             :                 // inSidVal is Int.
    2605        1769 :                 Int maxSId = sourceRelabel_p.nelements();
    2606        1769 :                 Int maxSPWId = spwRelabel_p.nelements();
    2607       51295 :                 for (uInt inrn = 0; inrn < nInputRows; ++inrn)
    2608             :                 {
    2609       49526 :                         Int inSidVal = inSId(inrn);
    2610             :                         // -1 means the source is valid for any SPW.
    2611       49526 :                         Int inSPWVal = inSPW(inrn);
    2612       49526 :                         if (inSidVal >= maxSId)
    2613             :                         {
    2614          47 :                                 os << LogIO::WARN << "Invalid SOURCE ID in SOURCE table row " << inrn << LogIO::POST;
    2615             :                         }
    2616       49526 :                         if (inSPWVal >= maxSPWId)
    2617             :                         {
    2618           3 :                                 os << LogIO::WARN << "Invalid SPW ID in SOURCE table row " << inrn << LogIO::POST;
    2619             :                         }
    2620             : 
    2621       49525 :                         if (    (inSidVal > -1) &&
    2622       49478 :                                         (inSidVal < maxSId) &&
    2623      146019 :                                         (sourceRelabel_p[inSidVal] > -1) &&
    2624       46968 :                                         ((inSPWVal == -1) || (inSPWVal < maxSPWId && spwRelabel_p[inSPWVal] > -1)))
    2625             :                         {
    2626             :                                 // Copy inrn to outrn.
    2627       20039 :                                 TableCopy::copyRows(newSource, oldSource, outrn, inrn, 1);
    2628       20039 :                                 outSId.put(outrn, sourceRelabel_p[inSidVal]);
    2629       20039 :                                 outSPW.put(outrn, inSPWVal > -1 ? spwRelabel_p[inSPWVal] : -1);
    2630       20039 :                                 ++outrn;
    2631             :                         }
    2632             :                 }
    2633             : 
    2634        2054 :         }
    2635             : 
    2636        1769 :         return true;
    2637             : }
    2638             : 
    2639             : // -----------------------------------------------------------------------
    2640             : //
    2641             : // -----------------------------------------------------------------------
    2642        1864 : bool MSTransformDataHandler::copyAntenna()
    2643             : {
    2644        1864 :         const MSAntenna& oldAnt = mssel_p.antenna();
    2645        1864 :         MSAntenna& newAnt = msOut_p.antenna();
    2646        1864 :         const MSAntennaColumns incols(oldAnt);
    2647        1864 :         MSAntennaColumns outcols(newAnt);
    2648        1864 :         bool retval = false;
    2649             : 
    2650        1864 :         outcols.setOffsetRef(MPosition::castType(incols.offsetMeas().getMeasRef().getType()));
    2651        1864 :         outcols.setPositionRef(MPosition::castType(incols.positionMeas().getMeasRef().getType()));
    2652             : 
    2653             :     //TableCopy::copyRows(newAnt, oldAnt);
    2654             :     //retval = true;
    2655             : 
    2656        1864 :         if (!antennaSel_p or !reindex_p)
    2657             :         {
    2658        1838 :                 TableCopy::copyRows(newAnt, oldAnt);
    2659        1838 :                 retval = true;
    2660             :         }
    2661             :         else
    2662             :         {
    2663          26 :                 uInt nAnt = antNewIndex_p.nelements();
    2664             :                 // Don't use min() here, it's too overloaded.
    2665          26 :                 if (nAnt > oldAnt.nrow()) nAnt = oldAnt.nrow();
    2666             : 
    2667          99 :                 for (uInt k = 0; k < nAnt; ++k)
    2668             :                 {
    2669          73 :                         if (antNewIndex_p[k] > -1) TableCopy::copyRows(newAnt, oldAnt, antNewIndex_p[k], k, 1, false);
    2670             :                 }
    2671          26 :                 retval = true;
    2672             :         }
    2673             : 
    2674        1864 :         return retval;
    2675        1864 : }
    2676             : 
    2677             : // -----------------------------------------------------------------------
    2678             : //
    2679             : // -----------------------------------------------------------------------
    2680        1864 : bool MSTransformDataHandler::copyFeed()
    2681             : {
    2682        3728 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    2683             : 
    2684        1864 :         const MSFeed& oldFeed = mssel_p.feed();
    2685        1864 :         MSFeed& newFeed = msOut_p.feed();
    2686        1864 :         const MSFeedColumns incols(oldFeed);
    2687        1864 :         MSFeedColumns outcols(newFeed);
    2688             : 
    2689        1864 :         outcols.setDirectionRef(MDirection::castType(incols.beamOffsetMeas().getMeasRef().getType()));
    2690        1864 :         outcols.setEpochRef(MEpoch::castType(incols.timeMeas().getMeasRef().getType()));
    2691        1864 :         outcols.setPositionRef(MPosition::castType(incols.positionMeas().getMeasRef().getType()));
    2692             : 
    2693        1864 :         if ((!antennaSel_p && allEQ(spwRelabel_p, spw_p)) or !reindex_p)
    2694             :         {
    2695        1406 :                 TableCopy::copyRows(newFeed, oldFeed);
    2696             :         }
    2697             :         else
    2698             :         {
    2699         458 :                 const Vector<Int>& antIds = incols.antennaId().getColumn();
    2700         458 :                 const Vector<Int>& spwIds = incols.spectralWindowId().getColumn();
    2701             : 
    2702             :                 // Copy selected rows.
    2703         458 :                 uInt totNFeeds = antIds.nelements();
    2704         458 :                 uInt totalSelFeeds = 0;
    2705         458 :                 Int maxSelAntp1 = antNewIndex_p.nelements();
    2706      146580 :                 for (uInt k = 0; k < totNFeeds; ++k)
    2707             :                 {
    2708             :                         // antenna must be selected, and spwId must be -1 (any) or selected.
    2709      146122 :                         if (    antIds[k] < maxSelAntp1 &&
    2710      291669 :                                         antNewIndex_p[antIds[k]] > -1 &&
    2711      145547 :                                         (spwIds[k] < 0 || spwRelabel_p[spwIds[k]] > -1)
    2712             :                                 )
    2713             :                         {
    2714       44585 :                                 TableCopy::copyRows(newFeed, oldFeed, totalSelFeeds, k, 1,false);
    2715       44585 :                                 ++totalSelFeeds;
    2716             :                         }
    2717             :                 }
    2718             : 
    2719             :                 // Remap antenna and spw #s.
    2720         458 :                 ScalarColumn<Int>& antCol = outcols.antennaId();
    2721         458 :                 ScalarColumn<Int>& spwCol = outcols.spectralWindowId();
    2722             : 
    2723       45043 :                 for (uInt k = 0; k < totalSelFeeds; ++k)
    2724             :                 {
    2725             : 
    2726       44585 :                         antCol.put(k, antNewIndex_p[antCol(k)]);
    2727       44585 :                         if (spwCol(k) > -1) spwCol.put(k, spwRelabel_p[spwCol(k)]);
    2728             :                 }
    2729         458 :         }
    2730             : 
    2731             :         // Check if selected spw is WVR data. WVR data does not have FEED data
    2732             :         // so it is not a failure if newFeed.nrow == 0
    2733        1864 :         if (newFeed.nrow() < 1 and spw_p.size() == 1){
    2734             :             // Using the MSMetaData class
    2735           0 :             MSMetaData msmeta(&mssel_p, 0);
    2736           0 :             std::set<uInt> wvrspw = msmeta.getWVRSpw();
    2737           0 :             for (std::set<uInt>::iterator bbit = wvrspw.begin(); bbit != wvrspw.end(); ++bbit){
    2738           0 :                 if ((uInt)spw_p[0] == *bbit){
    2739           0 :                     os << LogIO::DEBUG1 << "Skipping spw="<<*bbit<<" because it is WVR and has no FEED content" << LogIO::POST;
    2740           0 :                     return true;
    2741             :                 }
    2742             :             }
    2743           0 :         }
    2744             : 
    2745        1864 :         if (newFeed.nrow() < 1)
    2746             :         {
    2747             : //              LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    2748           0 :                 os << LogIO::SEVERE << "No feeds were selected." << LogIO::POST;
    2749           0 :                 return false;
    2750             :         }
    2751             : 
    2752        1864 :         return true;
    2753        1864 : }
    2754             : 
    2755             : // -----------------------------------------------------------------------
    2756             : //  Get the processorId corresponding to a given DDI
    2757             : // -----------------------------------------------------------------------
    2758           0 : Int MSTransformDataHandler::getProcessorId(Int dataDescriptionId, String msname)
    2759             : {
    2760           0 :     ostringstream taql;
    2761           0 :     taql << "SELECT PROCESSOR_ID from " << msname;
    2762           0 :     taql << " WHERE DATA_DESC_ID ==" << dataDescriptionId;
    2763           0 :     taql << " LIMIT 1";
    2764             : 
    2765           0 :     casacore::TableProxy *firstSelectedRow = new TableProxy(tableCommand(taql.str()).table());
    2766           0 :     Record colWrapper = firstSelectedRow->getVarColumn(String("PROCESSOR_ID"),0,1,1);
    2767           0 :     casacore::Vector<Int> processorId = colWrapper.asArrayInt("r1");
    2768             : 
    2769           0 :     delete firstSelectedRow;
    2770           0 :     return processorId[0];
    2771           0 : }
    2772             : 
    2773             : 
    2774             : // -----------------------------------------------------------------------
    2775             : //
    2776             : // -----------------------------------------------------------------------
    2777        1864 : bool MSTransformDataHandler::copyFlag_Cmd()
    2778             : {
    2779             : 
    2780             :         // Like POINTING, FLAG_CMD is supposed to exist but is allowed not to.
    2781        1864 :         if (Table::isReadable(mssel_p.flagCmdTableName()))
    2782             :         {
    2783        1864 :                 const MSFlagCmd& oldFlag_Cmd = mssel_p.flagCmd();
    2784             : 
    2785        1864 :                 if (oldFlag_Cmd.nrow() > 0)
    2786             :                 {
    2787             : 
    2788             :                         // Could be declared as Table&
    2789         297 :                         MSFlagCmd& newFlag_Cmd = msOut_p.flagCmd();
    2790             : 
    2791         594 :                         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    2792             : 
    2793             :                         // Add optional columns if present in oldFlag_Cmd.
    2794         297 :                         uInt nAddedCols = addOptionalColumns(oldFlag_Cmd, newFlag_Cmd, true);
    2795         297 :                         os << LogIO::DEBUG1 << "FLAG_CMD has " << nAddedCols << " optional columns." << LogIO::POST;
    2796             : 
    2797         297 :                         const MSFlagCmdColumns oldFCs(oldFlag_Cmd);
    2798         297 :                         MSFlagCmdColumns newFCs(newFlag_Cmd);
    2799         297 :                         newFCs.setEpochRef(MEpoch::castType(oldFCs.timeMeas().getMeasRef().getType()));
    2800             : 
    2801         297 :                         TableCopy::copyRows(newFlag_Cmd, oldFlag_Cmd);
    2802             : 
    2803         297 :                 }
    2804             :         }
    2805             : 
    2806        1864 :         return true;
    2807             : }
    2808             : 
    2809             : // -----------------------------------------------------------------------
    2810             : //
    2811             : // -----------------------------------------------------------------------
    2812        1864 : bool MSTransformDataHandler::copyHistory()
    2813             : {
    2814        3728 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    2815             : 
    2816        1864 :         const MSHistory& oldHistory = mssel_p.history();
    2817             : 
    2818             :         // Could be declared as Table&
    2819        1864 :         MSHistory& newHistory = msOut_p.history();
    2820             : 
    2821             :         // Add optional columns if present in oldHistory.
    2822        1864 :         uInt nAddedCols = addOptionalColumns(oldHistory, newHistory, true);
    2823        1864 :         os << LogIO::DEBUG1 << "HISTORY has " << nAddedCols << " optional columns." << LogIO::POST;
    2824             : 
    2825        1864 :         const MSHistoryColumns oldHCs(oldHistory);
    2826        1864 :         MSHistoryColumns newHCs(newHistory);
    2827        1864 :         newHCs.setEpochRef(MEpoch::castType(oldHCs.timeMeas().getMeasRef().getType()));
    2828             : 
    2829        1864 :         TableCopy::copyRows(newHistory, oldHistory);
    2830             : 
    2831        1864 :         return true;
    2832        1864 : }
    2833             : 
    2834             : // -----------------------------------------------------------------------
    2835             : //
    2836             : // -----------------------------------------------------------------------
    2837        1864 : bool MSTransformDataHandler::copyObservation()
    2838             : {
    2839        1864 :         const MSObservation& oldObs = mssel_p.observation();
    2840        1864 :         MSObservation& newObs = msOut_p.observation();
    2841        1864 :         const MSObservationColumns oldObsCols(oldObs);
    2842        1864 :         MSObservationColumns newObsCols(newObs);
    2843        1864 :         newObsCols.setEpochRef(MEpoch::castType(oldObsCols.releaseDateMeas().getMeasRef().getType()));
    2844             : 
    2845        1864 :         uInt nObs = selObsId_p.nelements();
    2846        1864 :         if (nObs > 0 and reindex_p)
    2847             :         {
    2848          21 :                 for (uInt outrn = 0; outrn < nObs; ++outrn)
    2849             :                 {
    2850          12 :                         TableCopy::copyRows(newObs, oldObs, outrn, selObsId_p[outrn], 1);
    2851             :                 }
    2852             : 
    2853           9 :         }
    2854             :         else
    2855             :         {
    2856        1855 :                 TableCopy::copyRows(newObs, oldObs);
    2857             :         }
    2858             : 
    2859        1864 :         return true;
    2860        1864 : }
    2861             : 
    2862             : // -----------------------------------------------------------------------
    2863             : //
    2864             : // -----------------------------------------------------------------------
    2865        1864 : bool MSTransformDataHandler::copyProcessor()
    2866             : {
    2867        1864 :         const MSProcessor& oldProc = mssel_p.processor();
    2868        1864 :         MSProcessor& newProc = msOut_p.processor();
    2869        1864 :         TableCopy::copyRows(newProc, oldProc);
    2870             : 
    2871        1864 :         return true;
    2872             : }
    2873             : 
    2874             : // -----------------------------------------------------------------------
    2875             : //
    2876             : // -----------------------------------------------------------------------
    2877        1864 : bool MSTransformDataHandler::copyState()
    2878             : {
    2879             :         // STATE is allowed to not exist, even though it is not optional in
    2880             :         // the MS def'n.  For one thing, split dropped it for quite a while.
    2881        1864 :         if (Table::isReadable(mssel_p.stateTableName()))
    2882             :         {
    2883        3728 :                 LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    2884        1864 :                 const MSState& oldState = mssel_p.state();
    2885             : 
    2886        1864 :                 if (oldState.nrow() > 0)
    2887             :                 {
    2888        1654 :                         if (!intentString_p.empty() and reindex_p)
    2889             :                         {
    2890         102 :                                 MSState& newState = msOut_p.state();
    2891         102 :                                 const MSStateColumns oldStateCols(oldState);
    2892         102 :                                 MSStateColumns newStateCols(newState);
    2893             : 
    2894             :                                 // Initialize stateRemapper_p if necessary.
    2895             :                                 // if (stateRemapper_p.size() < 1) make_map(stateRemapper_p, mscIn_p->stateId().getColumn());
    2896             : 
    2897             :                                 // jagonzal (CAS-6351): Do not apply implicit re-indexing //////////////////////////////////////////////////
    2898             :                                 //
    2899             :                                 // Get list of selected scan intent indexes
    2900         102 :                                 MSSelection mssel;
    2901         102 :                                 mssel.setStateExpr(intentString_p);
    2902         102 :                                 Vector<Int> scanIntentList = mssel.getStateObsModeList(getInputMS());
    2903             :                                 //
    2904             :                                 // Populate state re-mapper using all selected indexes (not only the implicit ones)
    2905         102 :                                 stateRemapper_p.clear();
    2906         342 :                                 for (uInt index=0; index < scanIntentList.size(); index++)
    2907             :                                 {
    2908         240 :                                         stateRemapper_p[scanIntentList(index)] = index;
    2909             :                                 }
    2910             :                                 ///////////////////////////////////////////////////////////////////////////////////////////////////////////
    2911             : 
    2912         102 :                                 uInt nStates = stateRemapper_p.size();
    2913             : 
    2914             :                                 // stateRemapper_p goes from input to output, as is wanted in most
    2915             :                                 // places.  Here we need a map going the other way, so make one.
    2916         102 :                                 Vector<Int> outStateToInState(nStates);
    2917         102 :                                 std::map<Int, Int>::iterator mit;
    2918             : 
    2919         342 :                                 for (mit = stateRemapper_p.begin(); mit != stateRemapper_p.end(); ++mit)
    2920             :                                 {
    2921         240 :                                         outStateToInState[(*mit).second] = (*mit).first;
    2922             :                                 }
    2923             : 
    2924             : 
    2925         342 :                                 for (uInt outrn = 0; outrn < nStates; ++outrn)
    2926             :                                 {
    2927         240 :                                         TableCopy::copyRows(newState, oldState, outrn,outStateToInState[outrn], 1);
    2928             :                                 }
    2929         102 :                         }
    2930             :                         // jagonzal (CAS-6351): Do not apply implicit re-indexing
    2931             :                         // Therefore just copy the input state sub-table to the output state sub-table
    2932             :                         else
    2933             :                         {
    2934        1552 :                                 MSState& newState = msOut_p.state();
    2935        1552 :                                 TableCopy::copyRows(newState, oldState);
    2936             :                         }
    2937             : 
    2938             :                 }
    2939        1864 :         }
    2940        1864 :         return true;
    2941             : }
    2942             : 
    2943             : // -----------------------------------------------------------------------
    2944             : //
    2945             : // -----------------------------------------------------------------------
    2946        1864 : bool MSTransformDataHandler::copySyscal()
    2947             : {
    2948             :         // SYSCAL is allowed to not exist.
    2949        1864 :         if (Table::isReadable(mssel_p.sysCalTableName()))
    2950             :         {
    2951        1268 :                 const MSSysCal& oldSysc = mssel_p.sysCal();
    2952             : 
    2953        1268 :                 if (oldSysc.nrow() > 0)
    2954             :                 {
    2955             :                         // Add a SYSCAL subtable to msOut_p with 0 rows for now.
    2956         625 :                         Table::TableOption option = Table::New;
    2957         625 :                         TableDesc sysCalTD = MSSysCal::requiredTableDesc();
    2958         625 :                         SetupNewTable sysCalSetup(msOut_p.sysCalTableName(), sysCalTD,option);
    2959         625 :                         msOut_p.rwKeywordSet().defineTable(MS::keywordName(MS::SYSCAL),Table(sysCalSetup, 0));
    2960             : 
    2961             :                         // update the references to the subtable keywords
    2962         625 :                         msOut_p.initRefs();
    2963             : 
    2964             :                         // Could be declared as Table&.
    2965         625 :                         MSSysCal& newSysc = msOut_p.sysCal();
    2966             : 
    2967        1250 :                         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    2968             : 
    2969         625 :                         uInt nAddedCols = addOptionalColumns(oldSysc, newSysc, true);
    2970         625 :                         os << LogIO::DEBUG1 << "SYSCAL has " << nAddedCols << " optional columns." << LogIO::POST;
    2971             : 
    2972         625 :                         const MSSysCalColumns incols(oldSysc);
    2973         625 :                         MSSysCalColumns outcols(newSysc);
    2974         625 :                         outcols.setEpochRef(MEpoch::castType(incols.timeMeas().getMeasRef().getType()));
    2975             : 
    2976         625 :                         if ((!antennaSel_p && allEQ(spwRelabel_p, spw_p)) or !reindex_p)
    2977             :                         {
    2978         464 :                                 TableCopy::copyRows(newSysc, oldSysc);
    2979             :                         }
    2980             :                         else
    2981             :                         {
    2982         161 :                                 const Vector<Int>& antIds = incols.antennaId().getColumn();
    2983         161 :                                 const Vector<Int>& spwIds = incols.spectralWindowId().getColumn();
    2984             : 
    2985             :                                 // Copy selected rows.
    2986         161 :                                 uInt totNSyscals = antIds.nelements();
    2987         161 :                                 uInt totalSelSyscals = 0;
    2988         161 :                                 Int maxSelAntp1 = antNewIndex_p.nelements(); // Int for comparison with antIds.
    2989       29846 :                                 for (uInt k = 0; k < totNSyscals; ++k)
    2990             :                                 {
    2991             :                                         // antenna must be selected, and spwId must be -1 (any) or selected.
    2992       29685 :                                         if (    antIds[k] < maxSelAntp1 &&
    2993       59370 :                                                         antNewIndex_p[antIds[k]] > -1 &&
    2994       29685 :                                                         (spwIds[k] < 0 || spwRelabel_p[spwIds[k]] > -1)
    2995             :                                                 )
    2996             :                                         {
    2997       22738 :                                                 TableCopy::copyRows(newSysc, oldSysc, totalSelSyscals,k, 1, false);
    2998       22738 :                                                 ++totalSelSyscals;
    2999             :                                         }
    3000             :                                 }
    3001             : 
    3002             :                                 // Remap antenna and spw #s.
    3003         161 :                                 ScalarColumn<Int>& antCol = outcols.antennaId();
    3004         161 :                                 ScalarColumn<Int>& spwCol = outcols.spectralWindowId();
    3005             : 
    3006       22899 :                                 for (uInt k = 0; k < totalSelSyscals; ++k)
    3007             :                                 {
    3008       22738 :                                         antCol.put(k, antNewIndex_p[antCol(k)]);
    3009       22738 :                                         if (spwCol(k) > -1) spwCol.put(k, spwRelabel_p[spwCol(k)]);
    3010             :                                 }
    3011         161 :                         }
    3012         625 :                 }
    3013             :         }
    3014             : 
    3015        1864 :         return true;
    3016             : }
    3017             : 
    3018        1864 : bool MSTransformDataHandler::copyWeather()
    3019             : {
    3020             :         // Weather is allowed to not exist.
    3021        1864 :         if (Table::isReadable(mssel_p.weatherTableName()))
    3022             :         {
    3023        1259 :                 const MSWeather& oldWeath = mssel_p.weather();
    3024             : 
    3025        1259 :                 if (oldWeath.nrow() > 0)
    3026             :                 {
    3027             :                         // Add a WEATHER subtable to msOut_p with 0 rows for now.
    3028        1259 :                         Table::TableOption option = Table::New;
    3029        1259 :                         TableDesc weatherTD = MSWeather::requiredTableDesc();
    3030        1259 :                         SetupNewTable weatherSetup(msOut_p.weatherTableName(), weatherTD,option);
    3031        1259 :                         msOut_p.rwKeywordSet().defineTable(MS::keywordName(MS::WEATHER),Table(weatherSetup, 0));
    3032             : 
    3033             :                         // update the references to the subtable keywords
    3034        1259 :                         msOut_p.initRefs();
    3035             : 
    3036        1259 :                         MSWeather& newWeath = msOut_p.weather(); // Could be declared as Table&
    3037             : 
    3038        2518 :                         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    3039             : 
    3040        1259 :                         uInt nAddedCols = addOptionalColumns(oldWeath, newWeath, true);
    3041        1259 :                         os << LogIO::DEBUG1 << "WEATHER has " << nAddedCols << " optional columns." << LogIO::POST;
    3042             : 
    3043        1259 :                         const MSWeatherColumns oldWCs(oldWeath);
    3044        1259 :                         MSWeatherColumns newWCs(newWeath);
    3045        1259 :                         newWCs.setEpochRef(MEpoch::castType(oldWCs.timeMeas().getMeasRef().getType()));
    3046             : 
    3047        1259 :                         if (!antennaSel_p or !reindex_p)
    3048             :                         {
    3049        1236 :                                 TableCopy::copyRows(newWeath, oldWeath);
    3050             :                         }
    3051             :                         else
    3052             :                         {
    3053          23 :                                 const Vector<Int>& antIds(oldWCs.antennaId().getColumn());
    3054          23 :                                 ScalarColumn<Int>& outants = newWCs.antennaId();
    3055             : 
    3056          23 :                                 uInt selRow = 0;
    3057          23 :                                 Int maxSelAntp1 = antNewIndex_p.nelements();
    3058             : 
    3059        1638 :                                 for (uInt k = 0; k < antIds.nelements(); ++k)
    3060             :                                 {
    3061             :                                         // Weather station is on antenna?
    3062        1615 :                                         if (antIds[k] > -1)
    3063             :                                         {
    3064             :                                                 // remap ant num
    3065           0 :                                                 if (antIds[k] < maxSelAntp1)
    3066             :                                                 {
    3067           0 :                                                         Int newAntInd = antNewIndex_p[antIds[k]];
    3068             : 
    3069             :                                                         // Ant selected?
    3070           0 :                                                         if (newAntInd > -1)
    3071             :                                                         {
    3072           0 :                                                                 TableCopy::copyRows(newWeath, oldWeath, selRow,k, 1);
    3073           0 :                                                                 outants.put(selRow, newAntInd);
    3074           0 :                                                                 ++selRow;
    3075             :                                                         }
    3076             :                                                 }
    3077             :                                         }
    3078             :                                         else
    3079             :                                         {
    3080             :                                                 // means valid for all antennas.
    3081        1615 :                                                 TableCopy::copyRows(newWeath, oldWeath, selRow, k, 1);
    3082        1615 :                                                 outants.put(selRow, -1);
    3083        1615 :                                                 ++selRow;
    3084             :                                         }
    3085             :                                 }
    3086          23 :                         }
    3087        1259 :                 }
    3088             :         }
    3089             : 
    3090        1864 :         return true;
    3091             : }
    3092             : 
    3093             : // -----------------------------------------------------------------------
    3094             : //
    3095             : // -----------------------------------------------------------------------
    3096        3728 : bool MSTransformDataHandler::filterOptSubtable(const String& subtabname)
    3097             : {
    3098        7456 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    3099             : 
    3100             :         // subtabname is allowed to not exist.  Use ms_p instead of mssel_p, because
    3101             :         // the latter has a random name which does NOT necessarily lead to
    3102             :         // subtabname.  (And if selection took care of subtables, we probably
    3103             :         // wouldn't have to do it here.)
    3104        3728 :         if (Table::isReadable(ms_p.tableName() + '/' + subtabname))
    3105             :         {
    3106        1536 :                 const Table intab(ms_p.tableName() + '/' + subtabname);
    3107             : 
    3108         768 :                 if (intab.nrow() > 0) {
    3109             : 
    3110             :                         // Add feed if selecting by it is ever added.
    3111         400 :                         bool doFilter = (antennaSel_p || !allEQ(spwRelabel_p, spw_p)) && reindex_p;
    3112             : 
    3113         400 :                         copySubtable(subtabname, intab, doFilter);
    3114             : 
    3115         400 :                         if (doFilter) {
    3116             : 
    3117             :                                 // At this point msOut_p has subtab with 0 rows.
    3118         380 :                                 Table outtab(msOut_p.tableName() + '/' + subtabname,Table::Update);
    3119         190 :                                 ScalarColumn<Int> inAntIdCol(intab, "ANTENNA_ID");
    3120         190 :                                 ScalarColumn<Int> inSpwIdCol(intab, "SPECTRAL_WINDOW_ID");
    3121         190 :                                 const Vector<Int>& antIds = inAntIdCol.getColumn();
    3122         190 :                                 const Vector<Int>& spwIds = inSpwIdCol.getColumn();
    3123             : 
    3124             :                                 // Copy selected rows.
    3125         190 :                                 uInt totNOuttabs = antIds.nelements();
    3126         190 :                                 uInt totalSelOuttabs = 0;
    3127             : 
    3128             :                                 // Int for comparison with antIds.
    3129         190 :                                 Int maxSelAntp1 = antNewIndex_p.nelements();
    3130             : 
    3131         190 :                                 bool haveRemappingProblem = false;
    3132     4423741 :                                 for (uInt inrow = 0; inrow < totNOuttabs; ++inrow)
    3133             :                                 {
    3134             :                                         // antenna must be selected, and spwId must be -1 (any) or selected.
    3135             :                                         // Extra care must be taken because for a while MSes had CALDEVICE
    3136             :                                         // and SYSPOWER, but the ANTENNA_ID and SPECTRAL_WINDOW_ID of those
    3137             :                                         // sub-tables were not being re-mapped by split.
    3138     4423551 :                                         if (antIds[inrow] < maxSelAntp1 && antNewIndex_p[antIds[inrow]] > -1)
    3139             :                                         {
    3140             : 
    3141     8807826 :                                                 if (spwIds[inrow] < 0 ||
    3142     4403913 :                                                                 (spwIds[inrow] < static_cast<Int> (spwRelabel_p.nelements()) &&
    3143     4401458 :                                                                                 spwRelabel_p[spwIds[inrow]] > -1))
    3144             :                                                 {
    3145      831136 :                                                         TableCopy::copyRows(outtab, intab, totalSelOuttabs,inrow, 1, false);
    3146      831136 :                                                         ++totalSelOuttabs;
    3147             :                                                 }
    3148             : 
    3149             :                                                 // Ideally we'd like to catch antenna errors too.  They are
    3150             :                                                 // avoided, but because of the way antNewIndex_p is made,
    3151             :                                                 // antIds[inrow] >= maxSelAntp1
    3152             :                                                 // is not necessarily an error.  It's not even possible to catch
    3153             :                                                 // all the spw errors, so we settle for catching the ones we can
    3154             :                                                 // and reliably avoiding segfaults.
    3155     3572777 :                                                 else if (spwIds[inrow] >= static_cast<Int> (spwRelabel_p.nelements()))
    3156             :                                                 {
    3157        2455 :                                                         haveRemappingProblem = true;
    3158             :                                                 }
    3159             : 
    3160             :                                         }
    3161             :                                 }
    3162             : 
    3163         190 :                                 if (haveRemappingProblem)
    3164             :                                 {
    3165             :                                         os      << LogIO::WARN << "At least one row of "
    3166             :                                                 << intab.tableName()
    3167             :                                                 << " has an antenna or spw mismatch.\n"
    3168             :                                                 << "(Presumably from an older split, sorry.)\n"
    3169             :                                                 << "If " << subtabname
    3170             :                                                 << " is important, it should be fixed with tb or browsetable,\n"
    3171             :                                                 << "or by redoing the split that made "
    3172             :                                                 << ms_p.tableName() << " (check its history)."
    3173           2 :                                                 << LogIO::POST;
    3174             :                                 }
    3175             : 
    3176             : 
    3177             :                                 // Remap antenna and spw #s.
    3178         190 :                                 ScalarColumn<Int> outAntCol(outtab, "ANTENNA_ID");
    3179         190 :                                 ScalarColumn<Int> outSpwCol(outtab, "SPECTRAL_WINDOW_ID");
    3180             : 
    3181      831326 :                                 for (uInt k = 0; k < totalSelOuttabs; ++k)
    3182             :                                 {
    3183      831136 :                                         outAntCol.put(k, antNewIndex_p[outAntCol(k)]);
    3184      831136 :                                         if (outSpwCol(k) > -1) outSpwCol.put(k, spwRelabel_p[outSpwCol(k)]);
    3185             :                                 }
    3186         190 :                         }
    3187             :                 }
    3188         768 :         }
    3189             : 
    3190        3728 :         return true;
    3191        3728 : }
    3192             : 
    3193             : // -----------------------------------------------------------------------
    3194             : //
    3195             : // -----------------------------------------------------------------------
    3196        1864 : bool MSTransformDataHandler::copyGenericSubtables()
    3197             : {
    3198        3728 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    3199             : 
    3200             :         // Already handled subtables will be removed from this,
    3201             :         // so a modifiable copy is needed.
    3202        1864 :         TableRecord inkws(mssel_p.keywordSet());
    3203             : 
    3204             :         // Some of the standard subtables need special handling,
    3205             :         // e.g. DATA_DESCRIPTION, SPECTRAL_WINDOW, and ANTENNA, so they are already
    3206             :         // defined in msOut_p.  Several more (e.g. FLAG_CMD) were also already
    3207             :         // created by MS::createDefaultSubtables().  Don't try to write over them - a
    3208             :         // locking error will result.
    3209        1864 :         const TableRecord& outkws = msOut_p.keywordSet();
    3210       30244 :         for (uInt i = 0; i < outkws.nfields(); ++i)
    3211             :         {
    3212       28380 :                 if (outkws.type(i) == TpTable && inkws.isDefined(outkws.name(i)))
    3213             :                 {
    3214       26516 :                         inkws.removeField(outkws.name(i));
    3215             :                 }
    3216             :         }
    3217             : 
    3218             :         // Find ephemerides files
    3219        1864 :         std::vector<String> ephemerides;
    3220        7364 :         for (uInt i = 0; i < inkws.nfields(); ++i)
    3221             :         {
    3222        5500 :                 if (inkws.type(i) == TpTable && inkws.name(i).contains("EPHEM"))
    3223             :                 {
    3224          25 :                         ephemerides.push_back(inkws.name(i));
    3225             :                 }
    3226             :         }
    3227             : 
    3228             :         // Remove ephemerides files
    3229        1889 :         for (uInt i = 0; i < ephemerides.size(); ++i)
    3230             :         {
    3231          25 :                 inkws.removeField(ephemerides.at(i));
    3232             :         }
    3233             : 
    3234             : 
    3235             :         // msOut_p.rwKeywordSet() (pass a reference, not a copy) will put a lock on msOut_p.
    3236        1864 :         TableCopy::copySubTables(msOut_p.rwKeywordSet(), inkws, msOut_p.tableName(), msOut_p.tableType(), mssel_p);
    3237             : 
    3238             :         // TableCopy::copySubTables(Table, Table, bool) includes this other code,
    3239             :         // which seems to be copying subtables at one level deeper, but not recursively?
    3240        1864 :         const TableDesc& inDesc = mssel_p.tableDesc();
    3241        1864 :         const TableDesc& outDesc = msOut_p.tableDesc();
    3242       43892 :         for (uInt i = 0; i < outDesc.ncolumn(); ++i)
    3243             :         {
    3244             :                 // Only writable cols can have keywords (and thus subtables) defined.
    3245       42028 :                 if (msOut_p.isColumnWritable(i))
    3246             :                 {
    3247       42028 :                         const String& name = outDesc[i].name();
    3248             : 
    3249       42028 :                         if (inDesc.isColumn(name))
    3250             :                         {
    3251       41695 :                             TableColumn outCol(msOut_p, name);
    3252       41695 :                             TableColumn inCol(mssel_p, name);
    3253             : 
    3254       41695 :                             TableCopy::copySubTables(outCol.rwKeywordSet(),
    3255             :                                                      inCol.keywordSet(),
    3256             :                                                      msOut_p.tableName(),
    3257             :                                                      msOut_p.tableType(),
    3258             :                                                      mssel_p);
    3259             :                             // Copy the keywords if column is [FLOAT_|CORRECTED_]DATA
    3260             :                             // KS NOTE CORRECTED_DATA -> DATA case should be handled separately.
    3261       41695 :                             if (name == "FLOAT_DATA" || name == "DATA" || name == "CORRECTED_DATA")
    3262        2019 :                                         copyMainTableKeywords(outCol.rwKeywordSet(), inCol.keywordSet());
    3263             : 
    3264       41695 :                         }
    3265             :                 }
    3266             :         }
    3267             : 
    3268        1864 :         return true;
    3269        1864 : }
    3270             : 
    3271             : // -----------------------------------------------------------------------
    3272             : // Method to merge SPW sub-tables from SubMSs to create the MMS level SPW sub-table
    3273             : // -----------------------------------------------------------------------
    3274          28 : bool MSTransformDataHandler::mergeSpwSubTables(Vector<String> filenames)
    3275             : {
    3276          56 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    3277             : 
    3278          28 :         String filename_0 = filenames(0);
    3279          28 :         MeasurementSet ms_0(filename_0,Table::Update);
    3280             : 
    3281          28 :         if (Table::isReadable(ms_0.spectralWindowTableName()) and !ms_0.spectralWindow().isNull())
    3282             :         {
    3283          28 :                 MSSpectralWindow spwTable_0 = ms_0.spectralWindow();
    3284             : 
    3285          28 :                 if (spwTable_0.nrow() > 0)
    3286             :                 {
    3287          56 :                 os << LogIO::NORMAL << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3288          56 :                                 << "Merging SPECTRAL_WINDOW sub-tables from all sub-MSs to form MMS-level SPECTRAL_WINDOW sub-table" << LogIO::POST;
    3289             : 
    3290          28 :                 MSSpWindowColumns spwCols_0(spwTable_0);
    3291             : 
    3292             :                         // Map subMS with spw_id to merge the FEED table later
    3293          28 :                         Vector<uInt> mapSubmsSpwid;
    3294             : 
    3295             :                         // subMS_0000 starts with spw 0
    3296          28 :                         uInt spwStart = 0;
    3297          28 :                         mapSubmsSpwid.resize(filenames.size());
    3298          28 :                         mapSubmsSpwid[0] = spwStart;
    3299             : 
    3300             :                         // for next subMS
    3301          28 :                         uInt rowIndex = spwTable_0.nrow();
    3302          28 :                         spwStart = spwStart + rowIndex;
    3303         100 :                         for (uInt subms_index=1;subms_index < filenames.size();subms_index++)
    3304             :                         {
    3305          72 :                                 String filename_i = filenames(subms_index);
    3306          72 :                                 MeasurementSet ms_i(filename_i);
    3307          72 :                                 MSSpectralWindow spwTable_i = ms_i.spectralWindow();
    3308             : 
    3309          72 :                                 if (spwTable_i.nrow() > 0)
    3310             :                                 {
    3311          72 :                                         MSSpWindowColumns spwCols_i(spwTable_i);
    3312             : 
    3313          72 :                                         uInt nrow = spwTable_i.nrow();
    3314          72 :                                         spwTable_0.addRow(nrow);
    3315             : 
    3316             :                                         // Map of this subMS to spw ID
    3317          72 :                                         mapSubmsSpwid[subms_index] = spwStart;
    3318             : 
    3319             :                                         // for next subMS
    3320          72 :                                         spwStart = spwStart + nrow;
    3321             : 
    3322         160 :                                         for (uInt subms_row_index=0;subms_row_index<spwTable_i.nrow();subms_row_index++)
    3323             :                                         {
    3324          88 :                                                 spwCols_0.measFreqRef().put(rowIndex,spwCols_i.measFreqRef()(subms_row_index));
    3325          88 :                                                 spwCols_0.chanFreq().put(rowIndex,spwCols_i.chanFreq()(subms_row_index));
    3326          88 :                                                 spwCols_0.refFrequency().put(rowIndex,spwCols_i.refFrequency()(subms_row_index));
    3327          88 :                                                 spwCols_0.chanWidth().put(rowIndex,spwCols_i.chanWidth()(subms_row_index));
    3328          88 :                                                 spwCols_0.effectiveBW().put(rowIndex,spwCols_i.effectiveBW()(subms_row_index));
    3329          88 :                                                 spwCols_0.resolution().put(rowIndex,spwCols_i.resolution()(subms_row_index));
    3330          88 :                                                 spwCols_0.flagRow().put(rowIndex,spwCols_i.flagRow()(subms_row_index));
    3331          88 :                                                 spwCols_0.freqGroup().put(rowIndex,spwCols_i.freqGroup()(subms_row_index));
    3332          88 :                                                 spwCols_0.freqGroupName().put(rowIndex,spwCols_i.freqGroupName()(subms_row_index));
    3333          88 :                                                 spwCols_0.ifConvChain().put(rowIndex,spwCols_i.ifConvChain()(subms_row_index));
    3334          88 :                                                 spwCols_0.name().put(rowIndex,spwCols_i.name()(subms_row_index));
    3335          88 :                                                 spwCols_0.netSideband().put(rowIndex,spwCols_i.netSideband()(subms_row_index));
    3336          88 :                                                 spwCols_0.numChan().put(rowIndex,spwCols_i.numChan()(subms_row_index));
    3337          88 :                                                 spwCols_0.totalBandwidth().put(rowIndex,spwCols_i.totalBandwidth()(subms_row_index));
    3338             : 
    3339             :                                                 // Optional columns
    3340          88 :                                                 if (columnOk(spwCols_i.bbcNo()))
    3341          26 :                                                         spwCols_0.bbcNo().put(rowIndex,spwCols_i.bbcNo()(subms_row_index));
    3342             : 
    3343          88 :                                                 if (columnOk(spwCols_i.assocSpwId()))
    3344           6 :                                                         spwCols_0.assocSpwId().put(rowIndex,spwCols_i.assocSpwId()(subms_row_index));
    3345             : 
    3346          88 :                                                 if(columnOk(spwCols_i.assocNature()))
    3347           6 :                                                         spwCols_0.assocNature().put(rowIndex,spwCols_i.assocNature()(subms_row_index));
    3348             : 
    3349          88 :                                                 if (columnOk(spwCols_i.bbcSideband()))
    3350           0 :                                                         spwCols_0.bbcSideband().put(rowIndex,spwCols_i.bbcSideband()(subms_row_index));
    3351             : 
    3352          88 :                                                 if (columnOk(spwCols_i.dopplerId()))
    3353           4 :                                                         spwCols_0.dopplerId().put(rowIndex,spwCols_i.dopplerId()(subms_row_index));
    3354             : 
    3355          88 :                                                 if (columnOk(spwCols_i.receiverId()))
    3356           0 :                                                         spwCols_0.receiverId().put(rowIndex,spwCols_i.receiverId()(subms_row_index));
    3357             : 
    3358         191 :                         if (spwTable_i.tableDesc().isColumn("SDM_WINDOW_FUNCTION") &&
    3359         103 :                             spwTable_i.tableDesc().columnDescSet().isDefined("SDM_WINDOW_FUNCTION"))
    3360             :                         {
    3361          15 :                             ScalarColumn<String> swfCol_i(spwTable_i, "SDM_WINDOW_FUNCTION");
    3362          15 :                             ScalarColumn<String> swfCol_0(spwTable_0, "SDM_WINDOW_FUNCTION");
    3363          15 :                             swfCol_0.put(rowIndex, swfCol_i(subms_row_index));
    3364          15 :                         }
    3365             : 
    3366         191 :                         if (spwTable_i.tableDesc().isColumn("SDM_NUM_BIN") &&
    3367         103 :                             spwTable_i.tableDesc().columnDescSet().isDefined("SDM_NUM_BIN"))
    3368             :                         {
    3369          15 :                             ScalarColumn<Int> snbCol_i(spwTable_i, "SDM_NUM_BIN");
    3370          15 :                             ScalarColumn<Int> snbCol_0(spwTable_0, "SDM_NUM_BIN");
    3371          15 :                             snbCol_0.put(rowIndex, snbCol_i(subms_row_index));
    3372          15 :                         }
    3373         191 :                         if (spwTable_i.tableDesc().isColumn("SDM_CORR_BIT") &&
    3374         103 :                             spwTable_i.tableDesc().columnDescSet().isDefined("SDM_CORR_BIT"))
    3375             :                         {
    3376          15 :                             ScalarColumn<String> corrBitCol_i(spwTable_i, "SDM_CORR_BIT");
    3377          15 :                             ScalarColumn<String> corrBitCol_0(spwTable_0, "SDM_CORR_BIT");
    3378          15 :                             corrBitCol_0.put(rowIndex, corrBitCol_i(subms_row_index));
    3379          15 :                         }
    3380             : 
    3381          88 :                                                 rowIndex += 1;
    3382             :                                         }
    3383          72 :                                 }
    3384          72 :                         }
    3385             : 
    3386             :                         // Merge the other sub-tables using SPW map generated here
    3387          28 :                         mergeDDISubTables(filenames);
    3388          28 :                         mergeFeedSubTables(filenames, mapSubmsSpwid);
    3389          28 :                         mergeSourceSubTables(filenames, mapSubmsSpwid);
    3390          28 :                         mergeFreqOffsetTables(filenames, mapSubmsSpwid);
    3391          28 :                         mergeCalDeviceSubtables(filenames, mapSubmsSpwid);
    3392          28 :                         mergeSysPowerSubtables(filenames, mapSubmsSpwid);
    3393          28 :                         mergeSyscalSubTables(filenames, mapSubmsSpwid);
    3394          28 :                 }
    3395             :                 else
    3396             :                 {
    3397           0 :                 os << LogIO::SEVERE << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3398           0 :                                 << "SPECTRAL_WINDOW sub-table found but has no valid content" << LogIO::POST;
    3399           0 :                 return false;
    3400             :                 }
    3401          28 :         }
    3402             :         else
    3403             :         {
    3404           0 :         os << LogIO::SEVERE << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3405           0 :                         << "SPECTRAL_WINDOW sub-table not found " << LogIO::POST;
    3406           0 :         return false;
    3407             :         }
    3408             : 
    3409          28 :         return true;
    3410          28 : }
    3411             : 
    3412             : // -----------------------------------------------------------------------
    3413             : // Method to merge DDI sub-tables from SubMSs to create the MMS-level DDI sub-table
    3414             : // -----------------------------------------------------------------------
    3415          28 : bool MSTransformDataHandler::mergeDDISubTables(Vector<String> filenames)
    3416             : {
    3417          56 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    3418             : 
    3419          28 :         String filename_0 = filenames(0);
    3420          28 :         MeasurementSet ms_0(filename_0,Table::Update);
    3421             : 
    3422          28 :     if (Table::isReadable(ms_0.dataDescriptionTableName()) and !ms_0.dataDescription().isNull())
    3423             :     {
    3424          28 :         MSDataDescription ddiTable_0 = ms_0.dataDescription();
    3425             : 
    3426          28 :         if (ddiTable_0.nrow() > 0)
    3427             :         {
    3428          56 :                 os << LogIO::NORMAL << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3429          56 :                                 << "Merging DDI sub-tables from all sub-MSs to form MMS-level DDI sub-table" << LogIO::POST;
    3430             : 
    3431          28 :                 MSDataDescColumns ddiCols_0(ddiTable_0);
    3432             : 
    3433          28 :                 uInt rowIndex = ddiTable_0.nrow();
    3434         100 :                 for (uInt subms_index=1;subms_index < filenames.size();subms_index++)
    3435             :                 {
    3436          72 :                         String filename_i = filenames(subms_index);
    3437          72 :                         MeasurementSet ms_i(filename_i);
    3438          72 :                         MSDataDescription dditable_i = ms_i.dataDescription();
    3439             : 
    3440          72 :                         if (dditable_i.nrow() > 0)
    3441             :                         {
    3442          72 :                         MSDataDescColumns ddicols_i(dditable_i);
    3443             : 
    3444          72 :                         ddiTable_0.addRow(dditable_i.nrow());
    3445             : 
    3446         162 :                         for (uInt subms_row_index=0;subms_row_index<dditable_i.nrow();subms_row_index++)
    3447             :                         {
    3448             :                                 // get the last spw id entered in the 0th DD table
    3449          90 :                                 uInt spwid = ddiCols_0.spectralWindowId().get(rowIndex-1);
    3450             : 
    3451          90 :                                 ddiCols_0.flagRow().put(rowIndex,ddicols_i.flagRow()(subms_row_index));
    3452          90 :                                 ddiCols_0.polarizationId().put(rowIndex,ddicols_i.polarizationId()(subms_row_index));
    3453             : 
    3454             :                                 // Take into account that some SPW may be pointed by several DDIs
    3455          90 :                                 uInt deltaDDI = 1;
    3456          90 :                                 if (subms_row_index>0)
    3457             :                                 {
    3458          18 :                                         deltaDDI = ddicols_i.spectralWindowId()(subms_row_index) - ddicols_i.spectralWindowId()(subms_row_index-1);
    3459             :                                 }
    3460             : 
    3461          90 :                                 ddiCols_0.spectralWindowId().put(rowIndex,spwid+deltaDDI);
    3462          90 :                                 rowIndex += 1;
    3463             :                         }
    3464          72 :                         }
    3465          72 :                 }
    3466          28 :         }
    3467             :                 else
    3468             :                 {
    3469           0 :                 os << LogIO::SEVERE << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3470           0 :                                 << "DDI sub-table found but has no valid content" << LogIO::POST;
    3471           0 :                 return false;
    3472             :                 }
    3473          28 :     }
    3474             :     else
    3475             :     {
    3476           0 :         os << LogIO::SEVERE << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3477           0 :                         << "DDI sub-table not found " << LogIO::POST;
    3478           0 :         return false;
    3479             :     }
    3480             : 
    3481          28 :         return true;
    3482          28 : }
    3483             : 
    3484             : 
    3485             : // -----------------------------------------------------------------------
    3486             : // Method to merge FEED sub-tables from SubMSs to create the MMS-level FEED sub-table
    3487             : // -----------------------------------------------------------------------
    3488          28 : bool MSTransformDataHandler::mergeFeedSubTables(Vector<String> filenames, Vector<uInt> mapSubmsSpwid)
    3489             : {
    3490          56 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    3491             : 
    3492          28 :         if (filenames.size() != mapSubmsSpwid.size())
    3493             :         {
    3494           0 :                 os      << LogIO::SEVERE << "List of Sub-MSs does not match size of SPW re-indexing map" << LogIO::POST;
    3495           0 :                 return false;
    3496             :         }
    3497             : 
    3498          28 :         String filename_0 = filenames(0);
    3499          28 :         MeasurementSet ms_0(filename_0,Table::Update);
    3500             : 
    3501          28 :     if (Table::isReadable(ms_0.feedTableName()) and !ms_0.feed().isNull())
    3502             :     {
    3503          28 :         MSFeed feedTable_0 = ms_0.feed();
    3504             : 
    3505             :         // CAS-7167. The WVR spw has no FEED content.
    3506             : //      if (feedTable_0.nrow() >= 0)
    3507             : //      {
    3508          56 :         os << LogIO::NORMAL << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3509          56 :                 << "Merging FEED sub-tables from all sub-MSs to form MMS-level FEED sub-table" << LogIO::POST;
    3510             : 
    3511          28 :         MSFeedColumns feedCols_0(feedTable_0);
    3512             : 
    3513          28 :         uInt rowIndex = feedTable_0.nrow();
    3514         100 :         for (uInt subms_index=1;subms_index < filenames.size();subms_index++)
    3515             :         {
    3516          72 :             String filename_i = filenames(subms_index);
    3517          72 :             MeasurementSet ms_i(filename_i);
    3518          72 :             MSFeed feedtable_i = ms_i.feed();
    3519             : 
    3520          72 :             if (feedtable_i.nrow() > 0)
    3521             :             {
    3522          72 :                 MSFeedColumns feedcols_i(feedtable_i);
    3523             : 
    3524          72 :                 feedTable_0.addRow(feedtable_i.nrow());
    3525             : 
    3526             :                 // Prepare row reference object
    3527          72 :                 RefRows refRow(rowIndex,rowIndex+feedtable_i.nrow()-1);
    3528             : 
    3529             :                 // Re-index SPW col
    3530          72 :                 Vector<Int> spectralWindowId_output(feedtable_i.nrow(),mapSubmsSpwid[subms_index]);
    3531          72 :                 spectralWindowId_output += feedcols_i.spectralWindowId().getColumn();
    3532          72 :                 feedCols_0.spectralWindowId().putColumnCells(refRow,spectralWindowId_output);
    3533             : 
    3534             :                 // Columns that can be just copied
    3535          72 :                 feedCols_0.position().putColumnCells(refRow,feedcols_i.position().getColumn());
    3536          72 :                 feedCols_0.beamOffset().putColumnCells(refRow,feedcols_i.beamOffset().getColumn());
    3537          72 :                 feedCols_0.polarizationType().putColumnCells(refRow,feedcols_i.polarizationType().getColumn());
    3538          72 :                 feedCols_0.polResponse().putColumnCells(refRow,feedcols_i.polResponse().getColumn());
    3539          72 :                 feedCols_0.receptorAngle().putColumnCells(refRow,feedcols_i.receptorAngle().getColumn());
    3540          72 :                 feedCols_0.antennaId().putColumnCells(refRow,feedcols_i.antennaId().getColumn());
    3541          72 :                 feedCols_0.beamId().putColumnCells(refRow,feedcols_i.beamId().getColumn());
    3542          72 :                 feedCols_0.feedId().putColumnCells(refRow,feedcols_i.feedId().getColumn());
    3543          72 :                 feedCols_0.interval().putColumnCells(refRow,feedcols_i.interval().getColumn());
    3544          72 :                 feedCols_0.numReceptors().putColumnCells(refRow,feedcols_i.numReceptors().getColumn());
    3545          72 :                 feedCols_0.time().putColumnCells(refRow,feedcols_i.time().getColumn());
    3546             : 
    3547             :                 // optional columns
    3548          72 :                 if (columnOk(feedcols_i.focusLength()))
    3549             :                 {
    3550           0 :                     feedCols_0.focusLength().putColumnCells(refRow,feedcols_i.focusLength().getColumn());
    3551             :                 }
    3552             : 
    3553          72 :                 if (columnOk(feedcols_i.phasedFeedId()))
    3554             :                 {
    3555           0 :                     feedCols_0.phasedFeedId().putColumnCells(refRow,feedcols_i.phasedFeedId().getColumn());
    3556             :                 }
    3557             : 
    3558             :                 // Increment row offset
    3559          72 :                 rowIndex += feedtable_i.nrow();
    3560          72 :             }
    3561          72 :         }
    3562             : 
    3563             : //      }
    3564             : /*
    3565             :                 else
    3566             :                 {
    3567             :                 os << LogIO::SEVERE << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3568             :                                 << "FEED sub-table found but has no valid content" << LogIO::POST;
    3569             :                 return false;
    3570             :                 }
    3571             : */
    3572          28 :     }
    3573             :     else
    3574             :     {
    3575           0 :         os << LogIO::SEVERE << LogOrigin("MSTransformDataHandler", __FUNCTION__) <<
    3576           0 :                          "FEED sub-table not found " << LogIO::POST;
    3577           0 :         return false;
    3578             :     }
    3579             : 
    3580          28 :         return true;
    3581          28 : }
    3582             : 
    3583             : // -----------------------------------------------------------------------
    3584             : // Method to merge Source sub-tables from SubMSs to create the MMS-level FEED sub-table
    3585             : // -----------------------------------------------------------------------
    3586          28 : bool MSTransformDataHandler::mergeSourceSubTables(Vector<String> filenames, Vector<uInt> mapSubmsSpwid)
    3587             : {
    3588          56 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    3589             : 
    3590          28 :         if (filenames.size() != mapSubmsSpwid.size())
    3591             :         {
    3592           0 :                 os      << LogIO::SEVERE << "List of Sub-MSs does not match size of SPW re-indexing map" << LogIO::POST;
    3593           0 :                 return false;
    3594             :         }
    3595             : 
    3596          28 :         String filename_0 = filenames(0);
    3597          28 :         MeasurementSet ms_0(filename_0,Table::Update);
    3598             : 
    3599          28 :         if (Table::isReadable(ms_0.sourceTableName()) and !ms_0.source().isNull())
    3600             :         {
    3601          28 :                 MSSource sourceTable_0 = ms_0.source();
    3602             : 
    3603          28 :                 if (sourceTable_0.nrow() > 0)
    3604             :                 {
    3605          54 :                 os << LogIO::NORMAL << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3606          54 :                                 << "Merging SOURCE sub-tables from all sub-MSs to form MMS-level SOURCE sub-table" << LogIO::POST;
    3607             : 
    3608          27 :                         MSSourceColumns sourceCols_0(sourceTable_0);
    3609             : 
    3610          27 :                         uInt rowIndex = sourceTable_0.nrow();
    3611          98 :                         for (uInt subms_index=1;subms_index < filenames.size();subms_index++)
    3612             :                         {
    3613          71 :                                 String filename_i = filenames(subms_index);
    3614          71 :                                 MeasurementSet ms_i(filename_i);
    3615          71 :                                 MSSource sourcetable_i = ms_i.source();
    3616             : 
    3617          71 :                                 if (sourcetable_i.nrow() > 0)
    3618             :                                 {
    3619          71 :                                         MSSourceColumns sourcecols_i(sourcetable_i);
    3620             : 
    3621          71 :                                         sourceTable_0.addRow(sourcetable_i.nrow());
    3622             : 
    3623             :                                 // Prepare row reference object
    3624          71 :                                 RefRows refRow(rowIndex,rowIndex+sourcetable_i.nrow()-1);
    3625             : 
    3626             :                                 // Re-index SPW col
    3627          71 :                                 Vector<Int> spectralWindowId_output(sourcetable_i.nrow(),mapSubmsSpwid[subms_index]);
    3628          71 :                                 spectralWindowId_output += sourcecols_i.spectralWindowId().getColumn();
    3629          71 :                                 sourceCols_0.spectralWindowId().putColumnCells(refRow,spectralWindowId_output);
    3630             : 
    3631             :                                 // Columns that can be just copied
    3632          71 :                                 sourceCols_0.direction().putColumnCells(refRow,sourcecols_i.direction().getColumn());
    3633          71 :                                 sourceCols_0.properMotion().putColumnCells(refRow,sourcecols_i.properMotion().getColumn());
    3634          71 :                                 sourceCols_0.calibrationGroup().putColumnCells(refRow,sourcecols_i.calibrationGroup().getColumn());
    3635          71 :                                 sourceCols_0.code().putColumnCells(refRow,sourcecols_i.code().getColumn());
    3636          71 :                                 sourceCols_0.interval().putColumnCells(refRow,sourcecols_i.interval().getColumn());
    3637          71 :                                 sourceCols_0.name().putColumnCells(refRow,sourcecols_i.name().getColumn());
    3638          71 :                                 sourceCols_0.numLines().putColumnCells(refRow,sourcecols_i.numLines().getColumn());
    3639          71 :                                 sourceCols_0.sourceId().putColumnCells(refRow,sourcecols_i.sourceId().getColumn());
    3640          71 :                                 sourceCols_0.time().putColumnCells(refRow,sourcecols_i.time().getColumn());
    3641             : 
    3642             :                                 // Optional columns
    3643          71 :                                 if (columnOk(sourcecols_i.position()))
    3644             :                                 {
    3645           4 :                                         sourceCols_0.position().putColumnCells(refRow,sourcecols_i.position().getColumn());
    3646             :                                 }
    3647             : 
    3648          71 :                                 if (columnOk(sourcecols_i.transition()))
    3649             :                                 {
    3650           6 :                                         sourceCols_0.transition().putColumnCells(refRow,sourcecols_i.transition().getColumn());
    3651             :                                 }
    3652             : 
    3653          71 :                                 if (columnOk(sourcecols_i.restFrequency()))
    3654             :                                 {
    3655           6 :                                         sourceCols_0.restFrequency().putColumnCells(refRow,sourcecols_i.restFrequency().getColumn());
    3656             :                                 }
    3657             : 
    3658          71 :                                 if (columnOk(sourcecols_i.sysvel()))
    3659             :                                 {
    3660           6 :                                         sourceCols_0.sysvel().putColumnCells(refRow,sourcecols_i.sysvel().getColumn());
    3661             :                                 }
    3662             : 
    3663          71 :                                 if (columnOk(sourcecols_i.pulsarId()))
    3664             :                                 {
    3665           0 :                                         sourceCols_0.pulsarId().putColumnCells(refRow,sourcecols_i.pulsarId().getColumn());
    3666             :                                 }
    3667             : 
    3668          71 :                                 if (columnOk(sourcecols_i.sourceModel()))
    3669             :                                 {
    3670           0 :                                         sourceCols_0.sourceModel().putColumnCells(refRow,sourcecols_i.sourceModel().getColumn());
    3671             :                                 }
    3672             : 
    3673             :                                 // Increment row offset
    3674          71 :                                 rowIndex += sourcetable_i.nrow();
    3675          71 :                                 }
    3676          71 :                         }
    3677             : 
    3678          27 :                 }
    3679             :                 else
    3680             :                 {
    3681           2 :                 os << LogIO::SEVERE << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3682           2 :                                 << "SOURCE sub-table found but has no valid content" << LogIO::POST;
    3683           1 :                 return false;
    3684             :                 }
    3685          28 :         }
    3686             :         else
    3687             :         {
    3688           0 :                 os << LogIO::SEVERE << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3689           0 :                         << "SOURCE sub-table not found " << LogIO::POST;
    3690           0 :         return false;
    3691             :         }
    3692             : 
    3693          27 :         return true;
    3694          28 : }
    3695             : 
    3696             : 
    3697             : // -----------------------------------------------------------------------
    3698             : // Method to merge Syscal sub-tables from SubMSs to create the MMS-level Syscal sub-table
    3699             : // -----------------------------------------------------------------------
    3700          28 : bool MSTransformDataHandler::mergeSyscalSubTables(Vector<String> filenames, Vector<uInt> mapSubmsSpwid)
    3701             : {
    3702          56 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    3703             : 
    3704          28 :         if (filenames.size() != mapSubmsSpwid.size())
    3705             :         {
    3706           0 :                 os      << LogIO::SEVERE << "List of Sub-MSs does not match size of SPW re-indexing map" << LogIO::POST;
    3707           0 :                 return false;
    3708             :         }
    3709             : 
    3710          28 :         String filename_0 = filenames(0);
    3711          28 :         MeasurementSet ms_0(filename_0,Table::Update);
    3712             : 
    3713          28 :         if(Table::isReadable(ms_0.sysCalTableName()) and !ms_0.sysCal().isNull())
    3714             :         {
    3715          25 :                 MSSysCal syscalTable_0 = ms_0.sysCal();
    3716             : 
    3717             :                 // CAS-7167. The WVR spw has no FEED content.
    3718             : //              if (syscalTable_0.nrow() >= 0)
    3719             : //              {
    3720          50 :         os << LogIO::NORMAL << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3721          50 :                 << "Merging SYSCAL sub-tables from all sub-MSs to form MMS-level SYSCAL sub-table" << LogIO::POST;
    3722             : 
    3723          25 :         MSSysCalColumns syscalCols_0(syscalTable_0);
    3724             : 
    3725          25 :         uInt rowIndex = syscalTable_0.nrow();
    3726          93 :         for (uInt subms_index=1;subms_index < filenames.size();subms_index++)
    3727             :         {
    3728          68 :             String filename_i = filenames(subms_index);
    3729          68 :             MeasurementSet ms_i(filename_i);
    3730          68 :             MSSysCal syscaltable_i = ms_i.sysCal();
    3731             : 
    3732          68 :             if (syscaltable_i.nrow() > 0)
    3733             :             {
    3734           3 :                 MSSysCalColumns syscalcols_i(syscaltable_i);
    3735             : 
    3736           3 :                 syscalTable_0.addRow(syscaltable_i.nrow());
    3737             : 
    3738             :                 // Prepare row reference object
    3739           3 :                 RefRows refRow(rowIndex,rowIndex+syscaltable_i.nrow()-1);
    3740             : 
    3741             :                 // Re-index SPW col
    3742           3 :                 Vector<Int> spectralWindowId_output(syscaltable_i.nrow(),mapSubmsSpwid[subms_index]);
    3743           3 :                 spectralWindowId_output += syscalcols_i.spectralWindowId().getColumn();
    3744           3 :                 syscalCols_0.spectralWindowId().putColumnCells(refRow,spectralWindowId_output);
    3745             : 
    3746             :                 // Columns that can be just copied
    3747           3 :                 syscalCols_0.antennaId().putColumnCells(refRow,syscalcols_i.antennaId().getColumn());
    3748           3 :                 syscalCols_0.feedId().putColumnCells(refRow,syscalcols_i.feedId().getColumn());
    3749           3 :                 syscalCols_0.interval().putColumnCells(refRow,syscalcols_i.interval().getColumn());
    3750           3 :                 syscalCols_0.time().putColumnCells(refRow,syscalcols_i.time().getColumn());
    3751             : 
    3752             :                 // Optional columns
    3753           3 :                 if (columnOk(syscalcols_i.phaseDiff()))
    3754             :                 {
    3755           0 :                     syscalCols_0.phaseDiff().putColumnCells(refRow,syscalcols_i.phaseDiff().getColumn());
    3756             :                 }
    3757             : 
    3758           3 :                 if (columnOk(syscalcols_i.phaseDiffFlag()))
    3759             :                 {
    3760           0 :                     syscalCols_0.phaseDiffFlag().putColumnCells(refRow,syscalcols_i.phaseDiffFlag().getColumn());
    3761             :                 }
    3762             : 
    3763           3 :                 if (columnOk(syscalcols_i.tant()))
    3764             :                 {
    3765           0 :                     syscalCols_0.tant().putColumnCells(refRow,syscalcols_i.tant().getColumn());
    3766             :                 }
    3767             : 
    3768           3 :                 if (columnOk(syscalcols_i.tantFlag()))
    3769             :                 {
    3770           3 :                     syscalCols_0.tantFlag().putColumnCells(refRow,syscalcols_i.tantFlag().getColumn());
    3771             :                 }
    3772             : 
    3773           3 :                 if (columnOk(syscalcols_i.tantSpectrum()))
    3774             :                 {
    3775           0 :                     syscalCols_0.tantSpectrum().putColumnCells(refRow,syscalcols_i.tantSpectrum().getColumn());
    3776             :                 }
    3777             : 
    3778           3 :                 if (columnOk(syscalcols_i.tantTsys()))
    3779             :                 {
    3780           0 :                     syscalCols_0.tantTsys().putColumnCells(refRow,syscalcols_i.tantTsys().getColumn());
    3781             :                 }
    3782             : 
    3783           3 :                 if (columnOk(syscalcols_i.tantTsysFlag()))
    3784             :                 {
    3785           3 :                     syscalCols_0.tantTsysFlag().putColumnCells(refRow,syscalcols_i.tantTsysFlag().getColumn());
    3786             :                 }
    3787             : 
    3788           3 :                 if (columnOk(syscalcols_i.tantTsysSpectrum()))
    3789             :                 {
    3790           0 :                     syscalCols_0.tantTsysSpectrum().putColumnCells(refRow,syscalcols_i.tantTsysSpectrum().getColumn());
    3791             :                 }
    3792             : 
    3793           3 :                 if (columnOk(syscalcols_i.tcal()))
    3794             :                 {
    3795           0 :                     syscalCols_0.tcal().putColumnCells(refRow,syscalcols_i.tcal().getColumn());
    3796             :                 }
    3797             : 
    3798           3 :                 if (columnOk(syscalcols_i.tcalFlag()))
    3799             :                 {
    3800           3 :                     syscalCols_0.tcalFlag().putColumnCells(refRow,syscalcols_i.tcalFlag().getColumn());
    3801             :                 }
    3802             : 
    3803           3 :                 if (columnOk(syscalcols_i.tcalSpectrum()))
    3804             :                 {
    3805           3 :                     syscalCols_0.tcalSpectrum().putColumnCells(refRow,syscalcols_i.tcalSpectrum().getColumn());
    3806             :                 }
    3807             : 
    3808           3 :                 if (columnOk(syscalcols_i.trx()))
    3809             :                 {
    3810           0 :                     syscalCols_0.trx().putColumnCells(refRow,syscalcols_i.trx().getColumn());
    3811             :                 }
    3812             : 
    3813           3 :                 if (columnOk(syscalcols_i.trxFlag()))
    3814             :                 {
    3815           3 :                     syscalCols_0.trxFlag().putColumnCells(refRow,syscalcols_i.trxFlag().getColumn());
    3816             :                 }
    3817             : 
    3818           3 :                 if (columnOk(syscalcols_i.trxSpectrum()))
    3819             :                 {
    3820           3 :                     syscalCols_0.trxSpectrum().putColumnCells(refRow,syscalcols_i.trxSpectrum().getColumn());
    3821             :                 }
    3822             : 
    3823           3 :                 if (columnOk(syscalcols_i.tsky()))
    3824             :                 {
    3825           0 :                     syscalCols_0.tsky().putColumnCells(refRow,syscalcols_i.tsky().getColumn());
    3826             :                 }
    3827             : 
    3828           3 :                 if (columnOk(syscalcols_i.tskyFlag()))
    3829             :                 {
    3830           3 :                     syscalCols_0.tskyFlag().putColumnCells(refRow,syscalcols_i.tskyFlag().getColumn());
    3831             :                 }
    3832             : 
    3833           3 :                 if (columnOk(syscalcols_i.tskySpectrum()))
    3834             :                 {
    3835           3 :                     syscalCols_0.tskySpectrum().putColumnCells(refRow,syscalcols_i.tskySpectrum().getColumn());
    3836             :                 }
    3837             : 
    3838           3 :                 if (columnOk(syscalcols_i.tsys()))
    3839             :                 {
    3840           0 :                     syscalCols_0.tsys().putColumnCells(refRow,syscalcols_i.tsys().getColumn());
    3841             :                 }
    3842             : 
    3843           3 :                 if (columnOk(syscalcols_i.tsysFlag()))
    3844             :                 {
    3845           3 :                     syscalCols_0.tsysFlag().putColumnCells(refRow,syscalcols_i.tsysFlag().getColumn());
    3846             :                 }
    3847             : 
    3848           3 :                 if (columnOk(syscalcols_i.tsysSpectrum()))
    3849             :                 {
    3850           3 :                     syscalCols_0.tsysSpectrum().putColumnCells(refRow,syscalcols_i.tsysSpectrum().getColumn());
    3851             :                 }
    3852             : 
    3853             :                 // Increment row offset
    3854           3 :                 rowIndex += syscalcols_i.nrow();
    3855           3 :             }
    3856          68 :         }
    3857             : 
    3858             : /*
    3859             :                 }
    3860             :                 else
    3861             :                 {
    3862             :                 os << LogIO::DEBUG1 << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3863             :                                 << "SYSCAL sub-table found but has no valid content" << LogIO::POST;
    3864             :                 return false;
    3865             :                 }
    3866             : */
    3867          25 :         }
    3868             :         else
    3869             :         {
    3870           6 :                 os << LogIO::DEBUG1 << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3871           6 :                         << "SYSCAL sub-table not found " << LogIO::POST;
    3872           3 :         return false;
    3873             :         }
    3874             : 
    3875          25 :         return true;
    3876          28 : }
    3877             : 
    3878             : 
    3879             : // -----------------------------------------------------------------------
    3880             : // Method to merge FreqOffset sub-tables from SubMSs to create the MMS-level FreqOffset sub-table
    3881             : // -----------------------------------------------------------------------
    3882          28 : bool MSTransformDataHandler::mergeFreqOffsetTables(Vector<String> filenames, Vector<uInt> mapSubmsSpwid)
    3883             : {
    3884          56 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    3885             : 
    3886          28 :         if (filenames.size() != mapSubmsSpwid.size())
    3887             :         {
    3888           0 :                 os      << LogIO::SEVERE << "List of Sub-MSs does not match size of SPW re-indexing map" << LogIO::POST;
    3889           0 :                 return false;
    3890             :         }
    3891             : 
    3892          28 :         String filename_0 = filenames(0);
    3893          28 :         MeasurementSet ms_0(filename_0,Table::Update);
    3894             : 
    3895          28 :         if (Table::isReadable(ms_0.freqOffsetTableName()) and !ms_0.freqOffset().isNull())
    3896             :         {
    3897           0 :                 MSFreqOffset freqoffsetTable_0 = ms_0.freqOffset();
    3898             : 
    3899           0 :                 if (freqoffsetTable_0.nrow() > 0)
    3900             :                 {
    3901           0 :                 os << LogIO::NORMAL << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3902           0 :                                 << "Merging FREQ_OFFSET sub-tables from all sub-MSs to form MMS-level FREQ_OFFSET sub-table" << LogIO::POST;
    3903             : 
    3904           0 :                         MSFreqOffsetColumns freqoffsetCols_0(freqoffsetTable_0);
    3905             : 
    3906           0 :                         uInt rowIndex = freqoffsetTable_0.nrow();
    3907           0 :                         for (uInt subms_index=1;subms_index < filenames.size();subms_index++)
    3908             :                         {
    3909           0 :                                 String filename_i = filenames(subms_index);
    3910           0 :                                 MeasurementSet ms_i(filename_i);
    3911           0 :                                 MSFreqOffset freqoffsettable_i = ms_i.freqOffset();
    3912             : 
    3913           0 :                                 if (freqoffsettable_i.nrow() > 0)
    3914             :                                 {
    3915           0 :                                         MSFreqOffsetColumns freqoffsetcols_i(freqoffsettable_i);
    3916             : 
    3917           0 :                                         freqoffsetTable_0.addRow(freqoffsettable_i.nrow());
    3918             : 
    3919             :                                 // Prepare row reference object
    3920           0 :                                 RefRows refRow(rowIndex,rowIndex+freqoffsettable_i.nrow()-1);
    3921             : 
    3922             :                                 // Re-index SPW col
    3923           0 :                                 Vector<Int> spectralWindowId_output(freqoffsettable_i.nrow(),mapSubmsSpwid[subms_index]);
    3924           0 :                                 spectralWindowId_output += freqoffsetcols_i.spectralWindowId().getColumn();
    3925           0 :                                 freqoffsetCols_0.spectralWindowId().putColumnCells(refRow,spectralWindowId_output);
    3926             : 
    3927             :                                 // Columns that can be just copied
    3928           0 :                                 freqoffsetCols_0.antenna1().putColumnCells(refRow,freqoffsetcols_i.antenna1().getColumn());
    3929           0 :                                 freqoffsetCols_0.antenna2().putColumnCells(refRow,freqoffsetcols_i.antenna2().getColumn());
    3930           0 :                                 freqoffsetCols_0.feedId().putColumnCells(refRow,freqoffsetcols_i.feedId().getColumn());
    3931           0 :                                 freqoffsetCols_0.interval().putColumnCells(refRow,freqoffsetcols_i.interval().getColumn());
    3932           0 :                                 freqoffsetCols_0.offset().putColumnCells(refRow,freqoffsetcols_i.offset().getColumn());
    3933           0 :                                 freqoffsetCols_0.time().putColumnCells(refRow,freqoffsetcols_i.time().getColumn());
    3934             : 
    3935             :                                 // NOTE (jagonzal): FreqOffset does not have optional columns
    3936             : 
    3937             :                                 // Increment row offset
    3938           0 :                                 rowIndex += freqoffsettable_i.nrow();
    3939           0 :                                 }
    3940           0 :                         }
    3941             : 
    3942           0 :                 }
    3943             :                 else
    3944             :                 {
    3945           0 :                 os << LogIO::DEBUG1 << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3946           0 :                                 << "FREQ_OFFSET sub-table found but has no valid content" << LogIO::POST;
    3947           0 :                 return false;
    3948             :                 }
    3949             : 
    3950           0 :         }
    3951             :         else
    3952             :         {
    3953          56 :                 os << LogIO::DEBUG1 << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3954          56 :                         << "FREQ_OFFSET sub-table not found " << LogIO::POST;
    3955          28 :         return false;
    3956             :         }
    3957             : 
    3958           0 :         return true;
    3959          28 : }
    3960             : 
    3961             : // -----------------------------------------------------------------------
    3962             : // Method to merge CalDevice sub-tables from SubMSs to create the MMS-level CalDevice sub-table
    3963             : // -----------------------------------------------------------------------
    3964          28 : bool MSTransformDataHandler::mergeCalDeviceSubtables(Vector<String> filenames, Vector<uInt> mapSubmsSpwid)
    3965             : {
    3966          56 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    3967             : 
    3968          28 :         if (filenames.size() != mapSubmsSpwid.size())
    3969             :         {
    3970           0 :                 os      << LogIO::SEVERE << "List of Sub-MSs does not match size of SPW re-indexing map" << LogIO::POST;
    3971           0 :                 return false;
    3972             :         }
    3973             : 
    3974          28 :         String filename_0 = filenames(0);
    3975          28 :         MeasurementSet ms_0(filename_0,Table::Update);
    3976             : 
    3977          28 :         if (Table::isReadable(ms_0.tableName() + "/CALDEVICE"))
    3978             :         {
    3979           8 :                 Table subtable_0(ms_0.tableName() + "/CALDEVICE", Table::Update);
    3980             : 
    3981           8 :                 if (subtable_0.nrow() > 0)
    3982             :                 {
    3983          16 :                 os << LogIO::NORMAL << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    3984          16 :                                 << "Merging CALDEVICE sub-tables from all sub-MSs to form MMS-level CALDEVICE sub-table" << LogIO::POST;
    3985             : 
    3986             :                 // Get RW access to columns
    3987           8 :                         ScalarColumn<Int> antennaIdCol_0(subtable_0, "ANTENNA_ID");
    3988           8 :                         ScalarColumn<Int> feedIdCol_0(subtable_0, "FEED_ID");
    3989           8 :                         ScalarColumn<Int> spectralWindowIdCol_0(subtable_0, "SPECTRAL_WINDOW_ID");
    3990           8 :                         ScalarColumn<Double> timeCol_0(subtable_0, "TIME");
    3991           8 :                         ScalarColumn<Double> intervalCol_0(subtable_0, "INTERVAL");
    3992             : 
    3993           8 :                         ScalarColumn<Int> numCalLoadCol_0(subtable_0, "NUM_CAL_LOAD");
    3994           8 :                         ArrayColumn<String> calLoadNamesCol_0(subtable_0, "CAL_LOAD_NAMES");
    3995           8 :                         ScalarColumn<Int> numReceptorCol_0(subtable_0, "NUM_RECEPTOR");
    3996           8 :                         ArrayColumn<Float> noiseCalCol_0(subtable_0, "NOISE_CAL");
    3997           8 :                         ArrayColumn<Float> calEffCol_0(subtable_0, "CAL_EFF");
    3998           8 :                         ArrayColumn<Double> temperatureLoadCol_0(subtable_0, "TEMPERATURE_LOAD");
    3999             : 
    4000             :                 // Get original content of columns
    4001           8 :                         Vector<Int> antennaId_0;
    4002           8 :                         if (columnOk(antennaIdCol_0)) antennaId_0 = antennaIdCol_0.getColumn();
    4003           8 :                         Vector<Int> feedId_0;
    4004           8 :                         if (columnOk(feedIdCol_0)) feedId_0 = feedIdCol_0.getColumn();
    4005           8 :                         Vector<Int> spectralWindowId_0;
    4006           8 :                         if (columnOk(spectralWindowIdCol_0)) spectralWindowId_0 = spectralWindowIdCol_0.getColumn();
    4007           8 :                         Vector<Double> time_0;
    4008           8 :                         if (columnOk(timeCol_0)) time_0 = timeCol_0.getColumn();
    4009           8 :                         Vector<Double> interval_0;
    4010           8 :                         if (columnOk(intervalCol_0)) interval_0 = intervalCol_0.getColumn();
    4011             : 
    4012           8 :                         Vector<Int> numCalLoad_0;
    4013           8 :                         if (columnOk(numCalLoadCol_0)) numCalLoad_0 = numCalLoadCol_0.getColumn();
    4014           8 :                         Array<String> calLoadNames_0;
    4015           8 :                         if (columnOk(calLoadNamesCol_0)) calLoadNames_0 = calLoadNamesCol_0.getColumn();
    4016           8 :                         Vector<Int> numReceptor_0;
    4017           8 :                         if (columnOk(numReceptorCol_0)) numReceptor_0 = numReceptorCol_0.getColumn();
    4018           8 :                         Array<Float> noiseCal_0;
    4019           8 :                         if (columnOk(noiseCalCol_0)) noiseCal_0 = noiseCalCol_0.getColumn();
    4020           8 :                         Array<Float> calEff_0;
    4021           8 :                         if (columnOk(calEffCol_0)) calEff_0 = calEffCol_0.getColumn();
    4022           8 :                         Array<Double> temperatureLoad_0;
    4023           8 :                         if (columnOk(temperatureLoadCol_0)) temperatureLoad_0 = temperatureLoadCol_0.getColumn();
    4024             : 
    4025           8 :                         uInt rowIndex = subtable_0.nrow();
    4026          26 :                         for (uInt subms_index=1;subms_index < filenames.size();subms_index++)
    4027             :                         {
    4028          18 :                                 String filename_i = filenames(subms_index);
    4029          18 :                                 MeasurementSet ms_i(filename_i);
    4030          18 :                                 Table subtable_i(ms_i.tableName() + "/CALDEVICE", Table::Update);
    4031             : 
    4032          18 :                                 if (subtable_i.nrow() > 0)
    4033             :                                 {
    4034             :                                 // Get RW access to columns
    4035          18 :                                         ScalarColumn<Int> antennaIdCol_i(subtable_i, "ANTENNA_ID");
    4036          18 :                                         ScalarColumn<Int> feedIdCol_i(subtable_i, "FEED_ID");
    4037          18 :                                         ScalarColumn<Int> spectralWindowIdCol_i(subtable_i, "SPECTRAL_WINDOW_ID");
    4038          18 :                                         ScalarColumn<Double> timeCol_i(subtable_i, "TIME");
    4039          18 :                                         ScalarColumn<Double> intervalCol_i(subtable_i, "INTERVAL");
    4040             : 
    4041          18 :                                         ScalarColumn<Int> numCalLoadCol_i(subtable_i, "NUM_CAL_LOAD");
    4042          18 :                                         ArrayColumn<String> calLoadNamesCol_i(subtable_i, "CAL_LOAD_NAMES");
    4043          18 :                                         ScalarColumn<Int> numReceptorCol_i(subtable_i, "NUM_RECEPTOR");
    4044          18 :                                         ArrayColumn<Float> noiseCalCol_i(subtable_i, "NOISE_CAL");
    4045          18 :                                         ArrayColumn<Float> calEffCol_i(subtable_i, "CAL_EFF");
    4046          18 :                                         ArrayColumn<Double> temperatureLoadCol_i(subtable_i, "TEMPERATURE_LOAD");
    4047             : 
    4048             :                                 // Get original content of columns
    4049          18 :                                         Vector<Int> antennaId_i;
    4050          18 :                                         if (columnOk(antennaIdCol_i)) antennaId_i = antennaIdCol_i.getColumn();
    4051          18 :                                         Vector<Int> feedId_i;
    4052          18 :                                         if (columnOk(feedIdCol_i)) feedId_i = feedIdCol_i.getColumn();
    4053          18 :                                         Vector<Int> spectralWindowId_i;
    4054          18 :                                         if (columnOk(spectralWindowIdCol_i)) spectralWindowId_i = spectralWindowIdCol_i.getColumn();
    4055          18 :                                         Vector<Double> time_i;
    4056          18 :                                         if (columnOk(timeCol_i)) time_i = timeCol_i.getColumn();
    4057          18 :                                         Vector<Double> interval_i;
    4058          18 :                                         if (columnOk(intervalCol_i)) interval_i = intervalCol_i.getColumn();
    4059             : 
    4060          18 :                                         Vector<Int> numCalLoad_i;
    4061          18 :                                         if (columnOk(numCalLoadCol_i)) numCalLoad_i = numCalLoadCol_i.getColumn();
    4062          18 :                                         Array<String> calLoadNames_i;
    4063          18 :                                         if (columnOk(calLoadNamesCol_i)) calLoadNames_i = calLoadNamesCol_i.getColumn();
    4064          18 :                                         Vector<Int> numReceptor_i;
    4065          18 :                                         if (columnOk(numReceptorCol_i)) numReceptor_i = numReceptorCol_i.getColumn();
    4066          18 :                                         Array<Float> noiseCal_i;
    4067          18 :                                         if (columnOk(noiseCalCol_i)) noiseCal_i = noiseCalCol_i.getColumn();
    4068          18 :                                         Array<Float> calEff_i;
    4069          18 :                                         if (columnOk(calEffCol_i)) calEff_i = calEffCol_i.getColumn();
    4070          18 :                                         Array<Double> temperatureLoad_i;
    4071          18 :                                         if (columnOk(temperatureLoadCol_i)) temperatureLoad_i = temperatureLoadCol_i.getColumn();
    4072             : 
    4073             :                                         // Add n# rows to subtable_i equivalent to n# rows from subtable_0
    4074          18 :                                         subtable_0.addRow(subtable_i.nrow());
    4075             : 
    4076             :                                 // Prepare row reference object
    4077          18 :                                 RefRows refRow(rowIndex,rowIndex+subtable_i.nrow()-1);
    4078             : 
    4079             :                                 // Re-index SPW col
    4080          18 :                                 Vector<Int> spectralWindowId_output(spectralWindowId_i.size(),mapSubmsSpwid[subms_index]);
    4081          18 :                                 spectralWindowId_output += spectralWindowId_i;
    4082          18 :                                 spectralWindowIdCol_0.putColumnCells(refRow,spectralWindowId_output);
    4083             : 
    4084             :                                 // Columns that can be just copied
    4085          18 :                                         if (columnOk(antennaIdCol_i))
    4086             :                                         {
    4087          18 :                                                 antennaIdCol_0.putColumnCells(refRow,antennaId_i);
    4088             :                                         }
    4089             : 
    4090          18 :                                         if (columnOk(feedIdCol_i))
    4091             :                                         {
    4092          18 :                                                 feedIdCol_0.putColumnCells(refRow,feedId_i);
    4093             :                                         }
    4094             : 
    4095          18 :                                         if (columnOk(timeCol_i))
    4096             :                                         {
    4097          18 :                                                 timeCol_0.putColumnCells(refRow,time_i);
    4098             :                                         }
    4099             : 
    4100          18 :                                         if (columnOk(intervalCol_i))
    4101             :                                         {
    4102          18 :                                                 intervalCol_0.putColumnCells(refRow,interval_i);
    4103             :                                         }
    4104             : 
    4105             : 
    4106          18 :                                         if (columnOk(numCalLoadCol_i))
    4107             :                                         {
    4108          18 :                                                 numCalLoadCol_0.putColumnCells(refRow,numCalLoad_i);
    4109             :                                         }
    4110             : 
    4111          18 :                                         if (columnOk(calLoadNamesCol_i))
    4112             :                                         {
    4113          18 :                                                 calLoadNamesCol_0.putColumnCells(refRow,calLoadNames_i);
    4114             :                                         }
    4115             : 
    4116          18 :                                         if (columnOk(numReceptorCol_i))
    4117             :                                         {
    4118          18 :                                                 numReceptorCol_0.putColumnCells(refRow,numReceptor_i);
    4119             :                                         }
    4120             : 
    4121          18 :                                         if (columnOk(noiseCalCol_i))
    4122             :                                         {
    4123           8 :                                                 noiseCalCol_0.putColumnCells(refRow,noiseCal_i);
    4124             :                                         }
    4125             : 
    4126          18 :                                         if (columnOk(calEffCol_i))
    4127             :                                         {
    4128           0 :                                                 calEffCol_0.putColumnCells(refRow,calEff_i);
    4129             :                                         }
    4130             : 
    4131          18 :                                         if (columnOk(temperatureLoadCol_i))
    4132             :                                         {
    4133          10 :                                                 temperatureLoadCol_0.putColumnCells(refRow,temperatureLoad_i);
    4134             :                                         }
    4135             : 
    4136             :                                 // Increment row offset
    4137          18 :                                 rowIndex += subtable_i.nrow();
    4138          18 :                                 }
    4139          18 :                         }
    4140             : 
    4141           8 :                 }
    4142             :                 else
    4143             :                 {
    4144           0 :                 os << LogIO::DEBUG1 << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    4145           0 :                                 << "CALDEVICE sub-table found but has no valid content" << LogIO::POST;
    4146           0 :                 return false;
    4147             :                 }
    4148           8 :         }
    4149             :         else
    4150             :         {
    4151          40 :                 os << LogIO::DEBUG1 << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    4152          40 :                         << "CALDEVICE sub-table not found " << LogIO::POST;
    4153          20 :         return false;
    4154             :         }
    4155             : 
    4156           8 :         return true;
    4157          28 : }
    4158             : 
    4159             : 
    4160             : // -----------------------------------------------------------------------
    4161             : // Method to merge SysPower sub-tables from SubMSs to create the MMS-level SysPower sub-table
    4162             : // -----------------------------------------------------------------------
    4163          28 : bool MSTransformDataHandler::mergeSysPowerSubtables(Vector<String> filenames, Vector<uInt> mapSubmsSpwid)
    4164             : {
    4165          56 :         LogIO os(LogOrigin("MSTransformDataHandler", __FUNCTION__));
    4166             : 
    4167          28 :         if (filenames.size() != mapSubmsSpwid.size())
    4168             :         {
    4169           0 :                 os      << LogIO::SEVERE << "List of Sub-MSs does not match size of SPW re-indexing map" << LogIO::POST;
    4170           0 :                 return false;
    4171             :         }
    4172             : 
    4173          28 :         String filename_0 = filenames(0);
    4174          28 :         MeasurementSet ms_0(filename_0,Table::Update);
    4175             : 
    4176          28 :         if (Table::isReadable(ms_0.tableName() + "/SYSPOWER"))
    4177             :         {
    4178           8 :                 Table subtable_0(ms_0.tableName() + "/SYSPOWER", Table::Update);
    4179             : 
    4180           8 :                 if (subtable_0.nrow() > 0)
    4181             :                 {
    4182          12 :                 os << LogIO::NORMAL << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    4183          12 :                                 << "Merging SYSPOWER sub-tables from all sub-MSs to form MMS-level SYSPOWER sub-table" << LogIO::POST;
    4184             : 
    4185             :                 // Get RW access to columns
    4186           6 :                         ScalarColumn<Int> antennaIdCol_0(subtable_0, "ANTENNA_ID");
    4187           6 :                         ScalarColumn<Int> feedIdCol_0(subtable_0, "FEED_ID");
    4188           6 :                         ScalarColumn<Int> spectralWindowIdCol_0(subtable_0, "SPECTRAL_WINDOW_ID");
    4189           6 :                         ScalarColumn<Double> timeCol_0(subtable_0, "TIME");
    4190           6 :                         ScalarColumn<Double> intervalCol_0(subtable_0, "INTERVAL");
    4191             : 
    4192           6 :                         ArrayColumn<Float> switchedDiffCol_0(subtable_0, "SWITCHED_DIFF");
    4193           6 :                         ArrayColumn<Float> switchedSumCol_0(subtable_0, "SWITCHED_SUM");
    4194           6 :                         ArrayColumn<Float> requantizerGainCol_0(subtable_0, "REQUANTIZER_GAIN");
    4195             : 
    4196             :                 // Get original content of columns
    4197           6 :                         Vector<Int> antennaId_0;
    4198           6 :                         if (columnOk(antennaIdCol_0)) antennaId_0 = antennaIdCol_0.getColumn();
    4199           6 :                         Vector<Int> feedId_0;
    4200           6 :                         if (columnOk(feedIdCol_0)) feedId_0 = feedIdCol_0.getColumn();
    4201           6 :                         Vector<Int> spectralWindowId_0;
    4202           6 :                         if (columnOk(spectralWindowIdCol_0)) spectralWindowId_0 = spectralWindowIdCol_0.getColumn();
    4203           6 :                         Vector<Double> time_0;
    4204           6 :                         if (columnOk(timeCol_0)) time_0 = timeCol_0.getColumn();
    4205           6 :                         Vector<Double> interval_0;
    4206           6 :                         if (columnOk(intervalCol_0)) interval_0 = intervalCol_0.getColumn();
    4207             : 
    4208           6 :                         Array<Float> switchedDiff_0;
    4209           6 :                         if (columnOk(switchedDiffCol_0)) switchedDiff_0 = switchedDiffCol_0.getColumn();
    4210           6 :                         Array<Float> switchedSum_0;
    4211           6 :                         if (columnOk(switchedSumCol_0)) switchedSum_0 = switchedSumCol_0.getColumn();
    4212           6 :                         Array<Float> requantizerGain_0;
    4213           6 :                         if (columnOk(requantizerGainCol_0)) requantizerGain_0 = requantizerGainCol_0.getColumn();
    4214             : 
    4215           6 :                         uInt rowIndex = subtable_0.nrow();
    4216          14 :                         for (uInt subms_index=1;subms_index < filenames.size();subms_index++)
    4217             :                         {
    4218           8 :                                 String filename_i = filenames(subms_index);
    4219           8 :                                 MeasurementSet ms_i(filename_i);
    4220           8 :                                 Table subtable_i(ms_i.tableName() + "/SYSPOWER", Table::Update);
    4221             : 
    4222           8 :                                 if (subtable_i.nrow() > 0)
    4223             :                                 {
    4224             :                                 // Get RW access to columns
    4225           8 :                                         ScalarColumn<Int> antennaIdCol_i(subtable_i, "ANTENNA_ID");
    4226           8 :                                         ScalarColumn<Int> feedIdCol_i(subtable_i, "FEED_ID");
    4227           8 :                                         ScalarColumn<Int> spectralWindowIdCol_i(subtable_i, "SPECTRAL_WINDOW_ID");
    4228           8 :                                         ScalarColumn<Double> timeCol_i(subtable_i, "TIME");
    4229           8 :                                         ScalarColumn<Double> intervalCol_i(subtable_i, "INTERVAL");
    4230             : 
    4231           8 :                                         ArrayColumn<Float> switchedDiffCol_i(subtable_i, "SWITCHED_DIFF");
    4232           8 :                                         ArrayColumn<Float> switchedSumCol_i(subtable_i, "SWITCHED_SUM");
    4233           8 :                                         ArrayColumn<Float> requantizerGainCol_i(subtable_i, "REQUANTIZER_GAIN");
    4234             : 
    4235             :                                 // Get original content of columns
    4236           8 :                                         Vector<Int> antennaId_i;
    4237           8 :                                         if (columnOk(antennaIdCol_i)) antennaId_i = antennaIdCol_i.getColumn();
    4238           8 :                                         Vector<Int> feedId_i;
    4239           8 :                                         if (columnOk(feedIdCol_i)) feedId_i = feedIdCol_i.getColumn();
    4240           8 :                                         Vector<Int> spectralWindowId_i;
    4241           8 :                                         if (columnOk(spectralWindowIdCol_i)) spectralWindowId_i = spectralWindowIdCol_i.getColumn();
    4242           8 :                                         Vector<Double> time_i;
    4243           8 :                                         if (columnOk(timeCol_i)) time_i = timeCol_i.getColumn();
    4244           8 :                                         Vector<Double> interval_i;
    4245           8 :                                         if (columnOk(intervalCol_i)) interval_i = intervalCol_i.getColumn();
    4246             : 
    4247           8 :                                         Array<Float> switchedDiff_i;
    4248           8 :                                         if (columnOk(switchedDiffCol_i)) switchedDiff_i = switchedDiffCol_i.getColumn();
    4249           8 :                                         Array<Float> switchedSum_i;
    4250           8 :                                         if (columnOk(switchedSumCol_i)) switchedSum_i = switchedSumCol_i.getColumn();
    4251           8 :                                         Array<Float> requantizerGain_i;
    4252           8 :                                         if (columnOk(requantizerGainCol_i)) requantizerGain_i = requantizerGainCol_i.getColumn();
    4253             : 
    4254             :                                         // Add n# rows to subtable_i equivalent to n# rows from subtable_0
    4255           8 :                                         subtable_0.addRow(subtable_i.nrow());
    4256             : 
    4257             :                                 // Prepare row reference object
    4258           8 :                                 RefRows refRow(rowIndex,rowIndex+subtable_i.nrow()-1);
    4259             : 
    4260             :                                 // Re-index SPW col
    4261           8 :                                 Vector<Int> spectralWindowId_output(spectralWindowId_i.size(),mapSubmsSpwid[subms_index]);
    4262           8 :                                 spectralWindowId_output += spectralWindowId_i;
    4263           8 :                                 spectralWindowIdCol_0.putColumnCells(refRow,spectralWindowId_output);
    4264             : 
    4265             :                                 // Columns that can be just copied
    4266           8 :                                 if (columnOk(antennaIdCol_i))
    4267             :                                         {
    4268           8 :                                                 antennaIdCol_0.putColumnCells(refRow,antennaId_i);
    4269             :                                         }
    4270             : 
    4271           8 :                                 if (columnOk(feedIdCol_i))
    4272             :                                         {
    4273           8 :                                                 feedIdCol_0.putColumnCells(refRow,feedId_i);
    4274             :                                         }
    4275             : 
    4276           8 :                                 if (columnOk(timeCol_i))
    4277             :                                         {
    4278           8 :                                                 timeCol_0.putColumnCells(refRow,time_i);
    4279             :                                         }
    4280             : 
    4281           8 :                                 if (columnOk(intervalCol_i))
    4282             :                                         {
    4283           8 :                                                 intervalCol_0.putColumnCells(refRow,interval_i);
    4284             :                                         }
    4285             : 
    4286             : 
    4287           8 :                                 if (columnOk(switchedDiffCol_i))
    4288             :                                         {
    4289           8 :                                                 switchedDiffCol_0.putColumnCells(refRow,switchedDiff_i);
    4290             :                                         }
    4291             : 
    4292           8 :                                 if (columnOk(switchedSumCol_i))
    4293             :                                         {
    4294           8 :                                                 switchedSumCol_0.putColumnCells(refRow,switchedSum_i);
    4295             :                                         }
    4296             : 
    4297           8 :                                 if (columnOk(requantizerGainCol_i))
    4298             :                                         {
    4299           8 :                                                 requantizerGainCol_0.putColumnCells(refRow,requantizerGain_i);
    4300             :                                         }
    4301             : 
    4302             :                                 // Increment row offset
    4303           8 :                                 rowIndex += subtable_i.nrow();
    4304           8 :                                 }
    4305           8 :                         }
    4306             : 
    4307           6 :                 }
    4308             :                 else
    4309             :                 {
    4310           4 :                 os << LogIO::DEBUG1 << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    4311           4 :                                 << "SYSPOWER sub-table found but has no valid content" << LogIO::POST;
    4312           2 :                 return false;
    4313             :                 }
    4314           8 :         }
    4315             :         else
    4316             :         {
    4317          40 :                 os << LogIO::DEBUG1 << LogOrigin("MSTransformDataHandler", __FUNCTION__)
    4318          40 :                         << "SYSPOWER sub-table not found " << LogIO::POST;
    4319          20 :         return false;
    4320             :         }
    4321             : 
    4322           6 :         return true;
    4323          28 : }
    4324             : 
    4325             : // -----------------------------------------------------------------------
    4326             : //
    4327             : // -----------------------------------------------------------------------
    4328             : // template <class T>  bool MSTransformDataHandler::columnOk (ArrayColumn<T> column)
    4329             : // {
    4330             : //      bool ret;
    4331             : //      if (column.isNull()==false and column.hasContent()==true and column.ndimColumn() > 0)
    4332             : //      {
    4333             : //              ret = true;
    4334             : //      }
    4335             : //      else
    4336             : //      {
    4337             : //              ret = false;
    4338             : //      }
    4339             : 
    4340             : //      return ret;
    4341             : // }
    4342             : 
    4343             : // // -----------------------------------------------------------------------
    4344             : // //
    4345             : // // -----------------------------------------------------------------------
    4346             : // template <class T>  bool MSTransformDataHandler::columnOk (ScalarColumn<T> column)
    4347             : // {
    4348             : //      bool ret;
    4349             : //      if (column.isNull()==false and column.hasContent()==true)
    4350             : //      {
    4351             : //              ret = true;
    4352             : //      }
    4353             : //      else
    4354             : //      {
    4355             : //              ret = false;
    4356             : //      }
    4357             : 
    4358             : //      return ret;
    4359             : // }
    4360             : 
    4361             : 
    4362             : // -----------------------------------------------------------------------
    4363             : // Work-around to copy the keywords of the FLOAT_DATA column to the output MS
    4364             : // -----------------------------------------------------------------------
    4365        2213 : void MSTransformDataHandler::copyMainTableKeywords (TableRecord& outKeys,
    4366             :                 const TableRecord& inKeys)
    4367             : {
    4368        2599 :         for (uInt i=0; i<inKeys.nfields(); i++) {
    4369         386 :                 if (inKeys.type(i) == TpString) {
    4370             :                         // Add keywords for MAIN table columns such as FLOAT_DATA
    4371         386 :                         String ikey = inKeys.name(i);
    4372         386 :                         if (!outKeys.isDefined (ikey)) {
    4373         384 :                                 String keyval;
    4374         384 :                                 inKeys.get(ikey, keyval);
    4375         384 :                                 outKeys.define(ikey,keyval);
    4376         384 :                         }
    4377             : 
    4378         386 :                 }
    4379             : 
    4380             :         }
    4381        2213 : }
    4382             : 
    4383             : 
    4384             : } //# NAMESPACE CASA - END

Generated by: LCOV version 1.16