LCOV - code coverage report
Current view: top level - msvis/MSVis - SubMS.cc (source / functions) Hit Total Coverage
Test: casacpp_coverage.info Lines: 3433 5018 68.4 %
Date: 2024-12-11 20:54:31 Functions: 58 88 65.9 %

          Line data    Source code
       1             : //# SubMS.cc 
       2             : //# Copyright (C) 1996-2007
       3             : //# Associated Universities, Inc. Washington DC, USA.
       4             : //#
       5             : //# This library is free software; you can redistribute it and/or modify
       6             : //# it under the terms of the GNU General Public License as published by
       7             : //# the Free Software Foundation; either version 2 of the License, or
       8             : //# (at your option) any later version.
       9             : //#
      10             : //# This library is distributed in the hope that it will be useful,
      11             : //# but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : //# GNU General Public License for more details.
      14             : //# 
      15             : //# You should have received a copy of the GNU General Public License
      16             : //# along with this library; if not, write to the Free Software
      17             : //# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
      18             : //#
      19             : //# Correspondence concerning AIPS++ should be addressed as follows:
      20             : //#        Internet email: casa-feedback@nrao.edu.
      21             : //#        Postal address: AIPS++ Project Office
      22             : //#                        National Radio Astronomy Observatory
      23             : //#                        520 Edgemont Road
      24             : //#                        Charlottesville, VA 22903-2475 USA
      25             : //#
      26             : //# $Id: $
      27             : 
      28             : // To make Timer reports in the inner loop of the simple copy,
      29             : // uncomment the following line:
      30             : //#define COPYTIMER
      31             : 
      32             : #include <msvis/MSVis/SubMS.h>
      33             : #include <asdmstman/AsdmStMan.h>
      34             : #include <casacore/ms/MSSel/MSSelection.h>
      35             : //#include <ms/MSSel/MSTimeGram.h>
      36             : //#include <tables/TaQL/ExprNode.h>
      37             : #include <casacore/tables/Tables/RefRows.h>
      38             : #include <casacore/ms/MeasurementSets/MSColumns.h>
      39             : #include <casacore/coordinates/Coordinates/CoordinateUtil.h>
      40             : #include <casacore/casa/Arrays/Matrix.h>
      41             : #include <casacore/casa/Arrays/Cube.h>
      42             : #include <casacore/casa/Arrays/ArrayMath.h>
      43             : #include <casacore/casa/Arrays/ArrayOpsDiffShapes.h>
      44             : #include <casacore/casa/Arrays/ArrayLogical.h>
      45             : #include <casacore/casa/Arrays/ArrayUtil.h>
      46             : #include <casacore/casa/Arrays/IPosition.h>
      47             : #include <casacore/casa/Arrays/Slice.h>
      48             : #include <casacore/casa/BasicSL/Complex.h>
      49             : #include <casacore/casa/Logging/LogIO.h>
      50             : #include <casacore/casa/OS/File.h>
      51             : #include <casacore/casa/OS/Directory.h>
      52             : #include <casacore/casa/OS/HostInfo.h>
      53             : #include <casacore/casa/OS/Memory.h>              // Can be commented out along with
      54             : //                                         // Memory:: calls.
      55             : 
      56             : //#ifdef COPYTIMER
      57             : #include <casacore/casa/OS/Timer.h>
      58             : //#endif
      59             : 
      60             : #include <casacore/casa/Containers/Record.h>
      61             : #include <casacore/casa/BasicSL/String.h>
      62             : #include <casacore/casa/Utilities/Assert.h>
      63             : #include <casacore/casa/Utilities/GenSort.h>
      64             : #include <casacore/casa/System/AppInfo.h>
      65             : #include <casacore/casa/System/ProgressMeter.h>
      66             : #include <casacore/casa/Quanta/QuantumHolder.h>
      67             : #include <msvis/MSVis/GroupProcessor.h>
      68             : //#include <msvis/MSVis/VisSet.h>
      69             : #include <msvis/MSVis/VisBuffer.h>
      70             : #include <msvis/MSVis/VisBufferComponents.h>
      71             : #include <msvis/MSVis/VBGContinuumSubtractor.h>
      72             : #include <msvis/MSVis/VBRemapper.h>
      73             : #include <msvis/MSVis/VisChunkAverager.h>
      74             : #include <msvis/MSVis/VisIterator.h>
      75             : //#include <msvis/MSVis/VisibilityIterator.h>
      76             : #include <casacore/tables/DataMan/IncrementalStMan.h>
      77             : #include <casacore/tables/Tables/ScalarColumn.h>
      78             : #include <casacore/tables/Tables/ScaColDesc.h>
      79             : #include <casacore/tables/Tables/SetupNewTab.h>
      80             : #include <casacore/tables/DataMan/StandardStMan.h>
      81             : #include <casacore/tables/Tables/Table.h>
      82             : #include <casacore/tables/Tables/PlainTable.h>
      83             : #include <casacore/tables/Tables/TableDesc.h>
      84             : #include <casacore/tables/Tables/TableInfo.h>
      85             : #include <casacore/tables/Tables/TableLock.h>
      86             : #include <casacore/tables/Tables/TableRecord.h>
      87             : #include <casacore/tables/Tables/TableCopy.h>
      88             : #include <casacore/tables/Tables/TableRow.h>
      89             : #include <casacore/tables/DataMan/TiledColumnStMan.h>
      90             : #include <casacore/tables/DataMan/TiledShapeStMan.h>
      91             : #include <casacore/tables/DataMan/TiledDataStMan.h>
      92             : #include <casacore/tables/DataMan/TiledStManAccessor.h>
      93             : #include <casacore/ms/MeasurementSets/MSTileLayout.h>
      94             : #include <casacore/scimath/Mathematics/InterpolateArray1D.h>
      95             : #include <casacore/scimath/Mathematics/FFTServer.h>
      96             : #include <sstream>
      97             : #include <iomanip>
      98             : #include <functional>
      99             : #include <map>
     100             : #include <set>
     101             : #include <casacore/measures/Measures/MeasTable.h>
     102             : #include <casacore/scimath/Mathematics/Smooth.h>
     103             : #include <casacore/casa/Quanta/MVTime.h>
     104             : 
     105             : 
     106             : using namespace casacore;
     107             : 
     108             : 
     109             : namespace casa {
     110             : 
     111             : typedef ROVisibilityIterator ROVisIter;
     112             : typedef VisibilityIterator VisIter;
     113             : 
     114             : namespace subms {
     115             : 
     116             : 
     117             : // Weight <-> Sigma routines
     118             : //   A value in zero in either will be interpretted as 
     119             : //    practically zero weight (~inf noise), w/out generating
     120             : //    inf or NaN
     121        4925 : Double wtToSigma(Double wt)
     122             : {
     123             :   // sig = 1/sqrt(wt)
     124        4925 :   return wt > 0.0 ? 1.0 / sqrt(wt) : FLT_MAX;
     125             : }
     126     2987511 : Double sigToWeight(Double sig)
     127             : {
     128             :   // wt = 1/square(sig)
     129     2987511 :   return sig > 0.0 ? 1.0 / square(sig) : FLT_EPSILON;
     130             : }
     131             : 
     132             : } // end namespace subms
     133             : 
     134             : //#warning "Debugging kluge here"
     135             : //inline Complex operator*(const Complex& val, Double f) { return val*Float(f); }
     136             : //
     137             : 
     138          54 :   SubMS::SubMS(String& theMS, Table::TableOption option) :
     139          54 :     ms_p(MeasurementSet(theMS, option)),
     140          54 :     mssel_p(ms_p),
     141          54 :     msc_p(NULL),
     142          54 :     mscIn_p(NULL),
     143          54 :     keepShape_p(true),
     144             :     //    sameShape_p(true),
     145          54 :     antennaSel_p(false),
     146          54 :     timeBin_p(-1.0),
     147          54 :     scanString_p(""),
     148          54 :     intentString_p(""),
     149          54 :     obsString_p(""),
     150          54 :     uvrangeString_p(""),
     151          54 :     taqlString_p(""),
     152          54 :     timeRange_p(""),
     153          54 :     arrayExpr_p(""),
     154          54 :     combine_p(""),
     155          54 :     fitorder_p(-1),
     156          54 :     fitspw_p("*"),
     157          54 :     fitoutspw_p("*"),
     158          54 :     fillMainTable_p(True),
     159          54 :     tvi_debug(False),
     160         162 :     want_cont_p(False)
     161             :   {
     162          54 :   }
     163             :   
     164         196 :   SubMS::SubMS(MeasurementSet& ms) :
     165         196 :     ms_p(ms),
     166         196 :     mssel_p(ms_p),
     167         196 :     msc_p(NULL),
     168         196 :     mscIn_p(NULL),
     169         196 :     keepShape_p(true),
     170             :     //sameShape_p(true),
     171         196 :     antennaSel_p(false),
     172         196 :     timeBin_p(-1.0),
     173         196 :     scanString_p(""),
     174         196 :     intentString_p(""),
     175         196 :     obsString_p(""),
     176         196 :     uvrangeString_p(""),
     177         196 :     taqlString_p(""),
     178         196 :     timeRange_p(""),
     179         196 :     arrayExpr_p(""),
     180         196 :     combine_p(""),
     181         196 :     fitorder_p(-1),
     182         196 :     fitspw_p("*"),
     183         196 :     fitoutspw_p("*"),
     184         196 :     fillMainTable_p(true),
     185         196 :     tvi_debug(False),
     186         588 :     want_cont_p(False)
     187             :   {
     188         196 :   }
     189             :   
     190         348 :   SubMS::~SubMS()
     191             :   {
     192         250 :     delete msc_p;
     193         250 :     msc_p = nullptr;
     194             :     
     195         250 :     delete mscIn_p;
     196         250 :     mscIn_p = nullptr;
     197             : 
     198         250 :     msOut_p=MeasurementSet();
     199             : 
     200             :     // parseColumnNames unavoidably has a static String and Vector<MS::PredefinedColumns>.
     201             :     // Collapse them down to free most of that memory.
     202         250 :     parseColumnNames("None");
     203             : 
     204         348 :   }
     205             : 
     206          44 : std::set<Int> SubMS::findBadSpws(MeasurementSet& ms, Vector<Int> spwv)
     207             : {
     208          44 :   ScalarColumn<Int> spws_in_dd(ms.dataDescription(), 
     209          44 :                                  MSDataDescription::columnName(MSDataDescription::SPECTRAL_WINDOW_ID));
     210          44 :   std::set<Int> uniqSpwsInDD;
     211          44 :   uInt nspwsInDD = spws_in_dd.nrow();
     212         443 :   for(uInt ddrow = 0; ddrow < nspwsInDD; ++ddrow)
     213         399 :     uniqSpwsInDD.insert(spws_in_dd(ddrow));
     214          44 :   std::set<Int>::iterator ddend = uniqSpwsInDD.end();
     215          44 :   std::set<Int> badSelSpwSlots;
     216         171 :   for(uInt k = 0; k < spwv.nelements(); ++k){
     217         127 :     if(uniqSpwsInDD.find(spwv[k]) == ddend){
     218           0 :       badSelSpwSlots.insert(k);
     219             :     }
     220             :   }
     221          88 :   return badSelSpwSlots;
     222          44 : }
     223             :   
     224             :   // This is the version used by split.
     225          44 :   Bool SubMS::selectSpw(const String& spwstr, const Vector<Int>& steps)
     226             :   {
     227          88 :     LogIO os(LogOrigin("SubMS", "selectSpw()"));
     228             : 
     229          44 :     MSSelection mssel;
     230          44 :     String myspwstr(spwstr == "" ? "*" : spwstr);
     231             : 
     232          44 :     mssel.setSpwExpr(myspwstr);
     233             : 
     234          44 :     widths_p = steps.copy();
     235          44 :     if(widths_p.nelements() < 1){
     236           0 :       widths_p.resize(1);
     237           0 :       widths_p[0] = 1;
     238             :     }
     239             :     else{
     240          88 :       for(uInt k = 0; k < widths_p.nelements(); ++k){
     241          44 :         if(widths_p[k] == 0){
     242             :           os << LogIO::WARN
     243             :              << "0 cannot be used for channel width...using 1 instead."
     244           0 :              << LogIO::POST;
     245           0 :           widths_p[k] = 1;
     246             :         }
     247             :       }
     248             :     }
     249             : 
     250             :     // Each row should have spw, start, stop, step
     251             :     // A single width is a default, but multiple widths should be used
     252             :     // literally.
     253          44 :     Matrix<Int> chansel = mssel.getChanList(&ms_p, 1);
     254             : 
     255          44 :     if(chansel.nrow() > 0) {         // Use myspwstr if it selected anything...
     256          44 :       spw_p       = chansel.column(0);
     257          44 :       chanStart_p = chansel.column(1);
     258          44 :       chanEnd_p   = chansel.column(2);
     259          44 :       chanStep_p  = chansel.column(3);
     260             : 
     261          44 :       uInt nspw = chanEnd_p.nelements();
     262          44 :       nchan_p.resize(nspw);
     263             : 
     264             :       // A single width is a default, but multiple widths should be used
     265             :       // literally.
     266          44 :       if(widths_p.nelements() > 1 && widths_p.nelements() != spw_p.nelements()){
     267             :         os << LogIO::SEVERE
     268             :            << "Mismatch between the # of widths specified by width and the # of spws."
     269           0 :            << LogIO::POST;
     270           0 :         return false;
     271             :       }
     272             : 
     273             :       // Copy the default width to all spws.
     274          44 :       if(widths_p.nelements() < nspw){
     275          25 :         widths_p.resize(nspw, true);
     276         108 :         for(uInt k = 1; k < nspw; ++k)
     277          83 :           widths_p[k] = widths_p[0];
     278             :       }
     279             : 
     280         171 :       for(uInt k = 0; k < nspw; ++k){
     281         127 :         if(chanStep_p[k] == 0)  // CAS-2224, triggered by spw='0:2'
     282           0 :           chanStep_p[k] = 1;    // (as opposed to '0:2~2').
     283             :         
     284             :         // if((nchan_p[k] - chanStart_p[k] + 1) % (chanStep_p[k] * widths_p[k]) != 0)
     285             :         //   os << LogIO::WARN
     286             :         //      << "The number of selected channels, " << nchan_p[k]
     287             :         //      << ", for spw " << spw_p[k] << " is not a multiple of the increment, "
     288             :         //      << chanStep_p[k] * widths_p[k] << ".\n"
     289             :         //      << "The reported width and frequency of the final channel may be"
     290             :         //      << "\noff by a fraction of a channel width.\n"
     291             :         //      << "(This is being worked on.)"
     292             :         //      << LogIO::POST;
     293             : 
     294         127 :         nchan_p[k] = 1 + (chanEnd_p[k] -
     295         127 :                           chanStart_p[k]) / (chanStep_p[k] * widths_p[k]);
     296         127 :         if(nchan_p[k] < 1)
     297           0 :           nchan_p[k] = 1;
     298             :       }
     299             :     }
     300             :     else{                            // select everything and rely on widths.
     301           0 :       MSSpWindowColumns mySpwTab(ms_p.spectralWindow());
     302           0 :       uInt nspw = mySpwTab.nrow();
     303             : 
     304           0 :       nchan_p = mySpwTab.numChan().getColumn();
     305             :       
     306           0 :       spw_p.resize(nspw);
     307           0 :       indgen(spw_p);
     308             :       
     309           0 :       chanStart_p.resize(nspw);
     310           0 :       chanStep_p.resize(nspw);
     311           0 :       for(uInt k = 0; k < nspw; ++k){
     312           0 :         chanStart_p[k] = 0;
     313           0 :         chanEnd_p[k]   = nchan_p[k] - 1;
     314           0 :         chanStep_p[k]  = 1;
     315             :       }
     316             : 
     317           0 :       if(widths_p.nelements() != spw_p.nelements()){
     318           0 :         if(widths_p.nelements() == 1){
     319           0 :           widths_p.resize(spw_p.nelements(), true);
     320           0 :           for(uInt k = 1; k < spw_p.nelements(); ++k)
     321           0 :             widths_p[k] = widths_p[0];
     322             :         }
     323             :         else{
     324             :           os << LogIO::SEVERE
     325             :              << "Mismatch between the # of widths specified by width and the # of spws."
     326           0 :              << LogIO::POST;
     327           0 :           return false;
     328             :         }
     329             :       }
     330             : 
     331           0 :       for(uInt k = 0; k < nspw; ++k){
     332             :         // if((nchan_p[k] + 1) % (chanStep_p[k] * widths_p[k]) != 0)
     333             :         //   os << LogIO::WARN
     334             :         //      << "The number of selected channels, " << nchan_p[k]
     335             :         //      << ", for spw " << spw_p[k] << " is not a multiple of the increment, "
     336             :         //      << chanStep_p[k] * widths_p[k] << ".\n"
     337             :         //      << "The reported width and frequency of the final channel may be"
     338             :         //      << "\noff by a fraction of a channel width.\n"
     339             :         //      << "(This is being worked on.)"
     340             :         //      << LogIO::POST;
     341             : 
     342           0 :         nchan_p[k] = 1 + (nchan_p[k] - 1) / widths_p[k];
     343             :       }
     344           0 :     }
     345             :     
     346             :     // Check for and filter out selected spws that aren't included in
     347             :     // DATA_DESCRIPTION.  (See CAS-1673 for an example.)
     348          44 :     std::set<Int> badSelSpwSlots(SubMS::findBadSpws(ms_p, spw_p));
     349          44 :     uInt nbadSelSpwSlots = badSelSpwSlots.size();
     350          44 :     if(nbadSelSpwSlots > 0){
     351           0 :       os << LogIO::WARN << "Selected input spw(s)\n";
     352           0 :       for(std::set<Int>::iterator bbit = badSelSpwSlots.begin();
     353           0 :           bbit != badSelSpwSlots.end(); ++bbit)
     354           0 :         os << spw_p[*bbit] << " ";
     355             :       os << "\nwere not found in DATA_DESCRIPTION and are being excluded."
     356           0 :          << LogIO::POST;
     357             : 
     358           0 :       uInt nSelSpw = spw_p.nelements();
     359           0 :       uInt ngoodSelSpwSlots = nSelSpw - nbadSelSpwSlots;
     360           0 :       Vector<Int> spwc(ngoodSelSpwSlots);
     361           0 :       Vector<Int> chanStartc(ngoodSelSpwSlots);
     362           0 :       Vector<Int> chanEndc(ngoodSelSpwSlots);
     363           0 :       Vector<Int> nchanc(ngoodSelSpwSlots);
     364           0 :       Vector<Int> chanStepc(ngoodSelSpwSlots);
     365           0 :       std::set<Int>::iterator bsend = badSelSpwSlots.end();
     366             :       
     367           0 :       uInt j = 0;
     368           0 :       for(uInt k = 0; k < nSelSpw; ++k){
     369           0 :         if(badSelSpwSlots.find(k) == bsend){
     370           0 :           spwc[j]       = spw_p[k];
     371           0 :           chanStartc[j] = chanStart_p[k];
     372           0 :           chanEndc[j]   = chanEnd_p[k];
     373           0 :           nchanc[j]     = nchan_p[k];
     374           0 :           chanStepc[j]  = chanStep_p[k];
     375           0 :           ++j;
     376             :         }
     377             :       }
     378           0 :       spw_p.resize(ngoodSelSpwSlots);
     379           0 :       spw_p = spwc;
     380           0 :       chanStart_p.resize(ngoodSelSpwSlots);
     381           0 :       chanStart_p = chanStartc;
     382           0 :       chanEnd_p.resize(ngoodSelSpwSlots);
     383           0 :       chanEnd_p = chanEndc;
     384           0 :       nchan_p.resize(ngoodSelSpwSlots);
     385           0 :       nchan_p = nchanc;
     386           0 :       chanStep_p.resize(ngoodSelSpwSlots);
     387           0 :       chanStep_p = chanStepc;
     388           0 :     }
     389             :     
     390          44 :     mssel.getChanSlices(chanSlices_p, &ms_p, 1);
     391          44 :     return true;
     392          44 :   }
     393             :   
     394             :   // This older version is used elsewhere.
     395           0 :   void SubMS::selectSpw(Vector<Int> spw, Vector<Int> nchan, Vector<Int> start, 
     396             :                         Vector<Int> step)
     397             :   {
     398           0 :     spw_p.resize();
     399           0 :     spw_p = spw;
     400             :     
     401             :     //check for default
     402           0 :     if(spw_p.nelements() == 1 && spw_p[0] < 0){
     403           0 :       spw_p.resize(ms_p.spectralWindow().nrow());
     404           0 :       indgen(spw_p);
     405             : 
     406             :       //no may be we have to redo the chan selection
     407             :       
     408           0 :       if (nchan.nelements() != spw_p.nelements()){
     409           0 :         nchan.resize(spw_p.nelements(), true);
     410           0 :         for(uInt k = 1; k < spw_p.nelements(); ++k){
     411           0 :           nchan[k] = nchan[0];
     412             :         }
     413             :       }
     414           0 :       if (start.nelements() != spw_p.nelements()){
     415           0 :         start.resize(spw_p.nelements(), true);
     416           0 :         for(uInt k = 1; k < spw_p.nelements(); ++k){
     417           0 :           start[k] = start[0];
     418             :         }
     419             :       }
     420           0 :       if (step.nelements() != spw_p.nelements()){
     421           0 :         step.resize(spw_p.nelements(), true);
     422           0 :         for(uInt k = 1; k < spw_p.nelements(); ++k){
     423           0 :           step[k] = step[0];
     424             :         }
     425             :       }
     426             :     }
     427             :         
     428           0 :     nchan_p.resize();
     429           0 :     nchan_p = nchan;
     430           0 :     chanStart_p.resize();
     431           0 :     chanStart_p = start;
     432           0 :     chanEnd_p.resize(spw_p.nelements());
     433           0 :     for(uInt k =0; k < spw_p.nelements(); ++k)
     434           0 :       chanEnd_p[k] = nchan[k] - 1;
     435           0 :     chanStep_p.resize();
     436           0 :     chanStep_p = step;
     437             :     // check for defaults
     438           0 :     if(nchan_p[0]<=0 || (nchan_p.nelements() != spw_p.nelements())){
     439           0 :       nchan_p.resize(spw_p.nelements());
     440           0 :       MSSpWindowColumns mySpwTab(ms_p.spectralWindow());
     441           0 :       for (uInt k =0; k < spw_p.nelements(); ++k){
     442           0 :         if(nchan[0]<=0)
     443           0 :           nchan_p[k]=mySpwTab.numChan()(spw_p[k]);
     444             :         else
     445           0 :           nchan_p[k]=nchan[0];
     446           0 :         chanEnd_p[k] = nchan_p[k] - 1;
     447             :       }
     448           0 :       chanStart_p.resize(spw_p.nelements());
     449           0 :       chanStep_p.resize(spw_p.nelements());
     450           0 :       if(chanStart_p.nelements() == start.nelements()){
     451           0 :         chanStart_p=start;
     452             :       }
     453             :       else{
     454           0 :         chanStart_p.set(start[0]);
     455             :       }
     456           0 :       if(chanStep_p.nelements() == step.nelements()){
     457           0 :         chanStep_p=step;
     458             :       }
     459             :       else{
     460           0 :         chanStep_p.set(step[0]);
     461             :       } 
     462           0 :     }    
     463           0 :   }
     464             : 
     465             :   // selectSpw must be called first because this uses spwRelabel_p!
     466          44 :   Bool SubMS::selectCorrelations(const String& corrstr)
     467             :   {
     468          88 :     LogIO os(LogOrigin("SubMS", "selectCorrelations()"));
     469          44 :     MSSelection mssel;
     470          44 :     const Bool areSelecting = corrstr != "" && corrstr != "*";
     471             : 
     472          44 :     if(areSelecting)
     473           0 :       mssel.setPolnExpr(corrstr);
     474          44 :     corrString_p = corrstr;
     475          44 :     mssel.getCorrSlices(corrSlices_p, &ms_p);
     476          88 :     return getCorrMaps(mssel, ms_p, inPolOutCorrToInCorrMap_p, areSelecting);
     477          44 :   }
     478             : 
     479          44 : Bool SubMS::getCorrMaps(MSSelection& mssel, const MeasurementSet& ms,
     480             :                         Vector<Vector<Int> >& outToIn, const Bool areSelecting)
     481             : {
     482          44 :   Bool cando = true;
     483             : 
     484          44 :   uInt npol = ms.polarization().nrow();  // The total number of polids
     485             :     
     486             :   // Nominally empty selection for all polids
     487          44 :   outToIn.resize(npol);
     488          44 :   outToIn.set(Vector<Int>());
     489             :     
     490          44 :   if(areSelecting){
     491             :     // Get the corr indices as an ordered map
     492           0 :     std::map<Int, Vector<Vector<Int> > > corrmap(mssel.getCorrMap(&ms));
     493             : 
     494             :     // Iterate over the ordered map to fill the vector maps
     495           0 :     for( auto mi = corrmap.begin( ); mi != corrmap.end( ); ++mi ) {
     496           0 :       Int pol = mi->first;
     497           0 :       outToIn[pol] = mi->second[0];
     498             :     }
     499           0 :   }
     500             :   else{ // Make outToIn an identity map.
     501          44 :     ScalarColumn<Int> numCorr(ms.polarization(), 
     502          44 :                                 MSPolarization::columnName(MSPolarization::NUM_CORR));
     503             :     
     504          89 :     for(uInt polid = 0; polid < npol; ++polid){
     505          45 :       uInt ncorr = numCorr(polid);
     506             :       
     507          45 :       outToIn[polid].resize(ncorr);
     508         134 :       for(uInt cid = 0; cid < ncorr; ++cid)
     509          89 :         outToIn[polid][cid] = cid;
     510             :     }
     511          44 :   }
     512          44 :   return cando;
     513             : }
     514             : 
     515             :   // This is the one used by split.
     516          44 :   Bool SubMS::setmsselect(const String& spw, const String& field,
     517             :                           const String& baseline, const String& scan,
     518             :                           const String& uvrange, const String& taql,
     519             :                           const Vector<Int>& step, const String& subarray,
     520             :                           const String& correlation, const String& intent,
     521             :                           const String& obs)
     522             :   {
     523          88 :     LogIO os(LogOrigin("SubMS", "setmsselect()"));
     524             :     Bool  ok;
     525             :     
     526          44 :     String myspwstr(spw == "" ? "*" : spw);
     527          88 :     Record selrec = ms_p.msseltoindex(myspwstr, field);
     528             : 
     529          44 :     ok = selectSource(selrec.asArrayInt("field"));
     530             : 
     531             :     // All of the requested selection functions will be tried, even if an
     532             :     // earlier one has indicated its failure.  This allows all of the selection
     533             :     // strings to be tested, yielding more complete feedback for the user
     534             :     // (fewer retries).  This is a matter of taste, though.  If the selections
     535             :     // turn out to be slow, this function should return on the first false.
     536             : 
     537          44 :     if(!selectSpw(myspwstr, step)){
     538           0 :       os << LogIO::SEVERE << "No channels selected." << LogIO::POST;
     539           0 :       ok = false;
     540             :     }
     541             :     
     542          44 :     if(baseline != ""){
     543           0 :       Vector<Int> antid(0);
     544           0 :       Vector<String> antstr(1,baseline);
     545           0 :       selectAntenna(antid, antstr);
     546           0 :     }
     547          44 :     scanString_p    = scan;
     548          44 :     intentString_p  = intent;
     549          44 :     obsString_p     = obs;
     550          44 :     uvrangeString_p = uvrange;
     551          44 :     taqlString_p    = taql;
     552             : 
     553          44 :     if(subarray != "")
     554           0 :       selectArray(subarray);
     555             : 
     556          44 :     if(!selectCorrelations(correlation)){
     557           0 :       os << LogIO::SEVERE << "No correlations selected." << LogIO::POST;
     558           0 :       ok = false;
     559             :     }
     560             : 
     561          44 :     return ok;
     562          44 :   }
     563             : 
     564             :   // This is the older version, used elsewhere.
     565           0 :   void SubMS::setmsselect(const String& spw, const String& field, 
     566             :                           const String& baseline, const String& scan,
     567             :                           const String& obs, const String& uvrange, 
     568             :                           const String& taql, const Vector<Int>& nchan, 
     569             :                           const Vector<Int>& start, const Vector<Int>& step,
     570             :                           const String& subarray, const String& intent)
     571             :   {
     572           0 :     Vector<Int> inchan(1, -1);
     573           0 :     Vector<Int> istart(1, 0);
     574           0 :     Vector<Int> istep(1, 1);
     575           0 :     Record      selrec = ms_p.msseltoindex(spw, field);
     576           0 :     Vector<Int> spwids = selrec.asArrayInt("spw");
     577             : 
     578           0 :     selectSource(selrec.asArrayInt("field"));
     579           0 :     if(spwids.nelements() < 1)
     580           0 :       spwids=Vector<Int>(1, -1);
     581             : 
     582             :     //use nchan if defined else use caret-column syntax of  msselection 
     583           0 :     if((nchan.nelements()>0) && nchan[0] > 0){
     584           0 :       inchan.resize(); inchan=nchan;
     585           0 :       if((step.nelements() >0 ) && (step.nelements() != nchan.nelements()) && (nchan.nelements() >1)){
     586           0 :         istep[0]=step[0];
     587             :       }
     588           0 :       if(step.nelements() != nchan.nelements()){
     589           0 :         istep.resize(nchan.nelements(), true);
     590           0 :         istep.set(istep[0]);
     591             :       }
     592             :       else{
     593           0 :         istep.resize(); istep=step;
     594             :       }
     595           0 :       if((start.nelements() >0 ) && (start.nelements() != nchan.nelements()) && (nchan.nelements() >1)){
     596           0 :         istart[0]=start[0];
     597             :       }
     598           0 :       if(start.nelements() != nchan.nelements()){
     599           0 :         istart.resize(nchan.nelements(), true);
     600           0 :         istart.set(istart[0]);
     601             :       }
     602             :       else{
     603           0 :         istart.resize(); istart=start;
     604             :       }
     605             :     }
     606             :     else{
     607           0 :       Matrix<Int> chansel=selrec.asArrayInt("channel");
     608           0 :       if(chansel.nelements() != 0){
     609           0 :         inchan.resize(chansel.nrow());
     610           0 :         istep.resize(chansel.nrow());
     611           0 :         istart.resize(chansel.nrow());
     612             :         // if the vector step is used ..for averaging ..let's use it
     613           0 :         Bool stepused=false;
     614           0 :         if( (step.nelements() >= 1) && (max(step) > 1))
     615           0 :           stepused=true;
     616           0 :         for (uInt k =0 ; k < chansel.nrow(); ++k){
     617           0 :           if(stepused){
     618           0 :             if(step.nelements() == 1)
     619           0 :               istep[k] = step[0];
     620           0 :             else if(step.nelements() == istep.nelements())
     621           0 :               istep[k] = step[k];
     622             :             else //confused at this stage
     623           0 :               istep[k] = 1;
     624             :           }
     625             :           else{
     626           0 :             istep[k] = chansel.row(k)(3);
     627           0 :             if(istep[k] < 1)
     628           0 :               istep[k] = 1;
     629             :           }
     630           0 :           istart[k] = chansel.row(k)(1);
     631           0 :           inchan[k] = (chansel.row(k)(2) - istart[k] + 1) / istep[k];
     632           0 :           if(inchan[k] < 1)
     633           0 :             inchan[k] = 1;
     634             :         }
     635             :       } 
     636           0 :     }
     637           0 :     selectSpw(spwids, inchan, istart, istep);
     638             :     
     639           0 :     if(baseline != ""){
     640           0 :       Vector<Int> antid(0);
     641           0 :       Vector<String> antstr(1,baseline);
     642           0 :       selectAntenna(antid, antstr);
     643           0 :     }
     644           0 :     scanString_p    = scan;
     645           0 :     obsString_p    = obs;
     646           0 :     uvrangeString_p = uvrange;
     647           0 :     taqlString_p    = taql;
     648           0 :     intentString_p  = intent;
     649             : 
     650           0 :     if(subarray != "")
     651           0 :       selectArray(subarray);
     652           0 :   }  
     653             : 
     654             :   
     655          44 :   Bool SubMS::selectSource(const Vector<Int>& fieldid)
     656             :   {
     657          88 :     LogIO os(LogOrigin("SubMS", "selectSource()"));
     658          44 :     Bool cando = true;
     659             : 
     660          44 :     if(fieldid.nelements() < 1){
     661          12 :       fieldid_p = Vector<Int>(1, -1);
     662             :     }
     663          32 :     else if(fieldid.nelements() > ms_p.field().nrow()){
     664             :       os << LogIO::SEVERE
     665             :          << "More fields were requested than are in the input MS.\n"
     666           0 :          << LogIO::POST;
     667           0 :       cando = false;
     668             :     }
     669          32 :     else if(max(fieldid) >= static_cast<Int>(ms_p.field().nrow())){
     670             :       // Arriving here is very unlikely since if fieldid came from MSSelection
     671             :       // bad fields were presumably already quietly dropped.
     672             :       os << LogIO::SEVERE
     673             :          << "At least 1 field was requested that is not in the input MS.\n"
     674           0 :          << LogIO::POST;      
     675           0 :       cando = false;
     676             :     }
     677             :     else{
     678          32 :       fieldid_p = fieldid;
     679             :     }
     680             : 
     681          44 :     if(fieldid_p.nelements() == 1 && fieldid_p[0] < 0){
     682          12 :       fieldid_p.resize(ms_p.field().nrow());
     683          12 :       indgen(fieldid_p);
     684             :     }
     685          44 :     return cando;
     686          44 :   }
     687             :   
     688           0 : Bool SubMS::pickAntennas(Vector<Int>& selected_antennaids,
     689             :                          Vector<String>& selected_antenna_strs,
     690             :                          const Vector<Int>& antennaids,
     691             :                          const Vector<String>& antennaSel)
     692             : {
     693           0 :   Bool didSelect = true;
     694           0 :   if((antennaids.nelements() == 1) && (antennaids[0] == -1)){
     695           0 :     if(antennaSel[0] == "")
     696           0 :       didSelect = false;
     697             :     else
     698           0 :       selected_antennaids.resize();
     699             :   }
     700             :   else
     701           0 :     selected_antennaids = antennaids;
     702           0 :   selected_antenna_strs = antennaSel;
     703           0 :   return didSelect;
     704             : }
     705             :   
     706          44 :   void SubMS::selectTime(Double timeBin, String timerng)
     707             :   {  
     708          44 :     timeBin_p   = timeBin;
     709          44 :     timeRange_p = timerng;
     710          44 :   }  
     711             :   
     712          44 :   Bool SubMS::makeSubMS(String& msname, String& colname,
     713             :                         const Vector<Int>& tileShape, const String& combine)
     714             :   {
     715          88 :     LogIO os(LogOrigin("SubMS", "makeSubMS()"));
     716             : 
     717             :     /*
     718             :     try{
     719             :     */
     720             : 
     721          44 :       if((spw_p.nelements()>0) && (max(spw_p) >= Int(ms_p.spectralWindow().nrow()))){
     722             :         os << LogIO::SEVERE 
     723             :            << "SpectralWindow selection contains elements that do not exist in "
     724             :            << "this MS"
     725           0 :            << LogIO::POST;
     726           0 :         ms_p=MeasurementSet();
     727           0 :         return false;   
     728             :       }
     729             :       
     730             :       // Watch out!  This throws an AipsError if ms_p doesn't have the
     731             :       // requested columns.
     732          44 :       const Vector<MS::PredefinedColumns> colNamesTok = parseColumnNames(colname, ms_p);
     733             : 
     734          44 :       if(!makeSelection()){
     735             :         //os << LogIO::WARN 
     736             :         //   << "Failed on selection: the combination of spw, field, antenna, correlation, "
     737             :         //   << "and timerange may be invalid." 
     738             :         //   << LogIO::POST;
     739           0 :         ms_p=MeasurementSet();
     740           0 :         return false;
     741             :       }
     742          44 :       mscIn_p=new MSColumns(mssel_p);
     743             :       // Note again the parseColumnNames() a few lines back that stops setupMS()
     744             :       // from being called if the MS doesn't have the requested columns.
     745          44 :       MeasurementSet* outpointer=0;
     746             : 
     747          44 :       if(tileShape.nelements() == 3){
     748           0 :         outpointer = setupMS(msname, nchan_p[0], ncorr_p[0],  
     749             :                              colNamesTok, tileShape);
     750             :       }
     751             : 
     752             :       // the following calls MSTileLayout...  disabled for now because it
     753             :       // forces tiles to be the full spw bandwidth in width (gmoellen, 2010/11/07)
     754             :   
     755          44 :       else if((tileShape.nelements()==1) && (tileShape[0]==0 || tileShape[0]==1)){
     756          44 :         outpointer = setupMS(msname, nchan_p[0], ncorr_p[0],
     757          88 :                              mscIn_p->observation().telescopeName()(0),
     758          44 :                              colNamesTok, tileShape[0]);
     759             :       }
     760             :       /* 
     761             :       else{
     762             :         // Derive tile shape based on input dataset's tiles, borrowed
     763             :         //  from VisSet's scr col tile shape derivation
     764             :         //  (this may need some tweaking for averaging cases)
     765             :         TableDesc td = mssel_p.actualTableDesc();
     766             : 
     767             :         // If a non-DATA column, i.e. CORRECTED_DATA, is being written to DATA,
     768             :         // datacolname must be set to DATA because the tile management in
     769             :         // setupMS() will look for "TiledDATA", not "TiledCorrectedData".
     770             :         String datacolname = MS::columnName(MS::DATA);
     771             :         // But if DATA is not present in the input MS, using it would cause a
     772             :         // segfault.
     773             :         if(!td.isColumn(datacolname))
     774             :           // This is could be any other kind of *DATA column, including
     775             :           // FLOAT_DATA or LAG_DATA, but it is guaranteed to be something.
     776             :           datacolname = MS::columnName(colNamesTok[0]);
     777             : 
     778             :         const ColumnDesc& cdesc = td[datacolname];
     779             : 
     780             :         String dataManType = cdesc.dataManagerType();
     781             :         String dataManGroup = cdesc.dataManagerGroup();
     782             : 
     783             :         Bool tiled = (dataManType.contains("Tiled"));
     784             : 
     785             :         if (tiled) {
     786             :             ROTiledStManAccessor tsm(mssel_p, dataManGroup);
     787             :             uInt nHyper = tsm.nhypercubes();
     788             : 
     789             :             // Test clause
     790             :             if(1){
     791             :               os << LogIO::DEBUG1
     792             :                  << datacolname << "'s max cache size: "
     793             :                  << tsm.maximumCacheSize() << " bytes.\n"
     794             :                  << "\tnhypercubes: " << nHyper << ".\n"
     795             :                  << "\ttshp of row 0: " << tsm.tileShape(0)
     796             :                  << "\n\thypercube shape of row 0: " << tsm.hypercubeShape(0)
     797             :                  << LogIO::POST;
     798             :             }
     799             :     
     800             : 
     801             :             // Find smallest tile shape
     802             :             Int highestProduct=-INT_MAX;
     803             :             Int highestId=0;
     804             :             for (uInt id=0; id < nHyper; id++) {
     805             :               IPosition tshp(tsm.getTileShape(id));
     806             :               Int product = tshp.product();
     807             : 
     808             :               os << LogIO::DEBUG2
     809             :                  << "\thypercube " << id << ":\n"
     810             :                  << "\t\ttshp: " << tshp << "\n"
     811             :                  << "\t\thypercube shape: " << tsm.getHypercubeShape(id)
     812             :                  << ".\n\t\tcache size: " << tsm.getCacheSize(id)
     813             :                  << " buckets.\n\t\tBucket size: " << tsm.getBucketSize(id)
     814             :                  << " bytes."
     815             :                  << LogIO::POST;
     816             : 
     817             :               if (product > 0 && (product > highestProduct)) {
     818             :                 highestProduct = product;
     819             :                 highestId = id;
     820             :               }
     821             :             }
     822             :             Vector<Int> dataTileShape = tsm.getTileShape(highestId).asVector();
     823             : 
     824             :             outpointer = setupMS(msname, nchan_p[0], ncorr_p[0],  
     825             :                                  colNamesTok, dataTileShape);
     826             : 
     827             :         }
     828             :       */
     829             :       else{
     830             :           //Sweep all other cases of bad tileshape to a default one.
     831             :           //  (this probably never happens)
     832           0 :           outpointer = setupMS(msname, nchan_p[0], ncorr_p[0],
     833           0 :                                mscIn_p->observation().telescopeName()(0),  
     834             :                                colNamesTok, 0);
     835             :         
     836             :       }
     837             :       
     838          44 :       combine_p = combine;
     839             : 
     840          44 :       msOut_p= *outpointer;
     841             :       
     842          44 :       if(!fillAllTables(colNamesTok)){
     843           0 :         delete outpointer;
     844           0 :         os << LogIO::WARN << msname << " left unfinished." << LogIO::POST;
     845           0 :         ms_p=MeasurementSet();
     846           0 :         return false;
     847             :       }
     848             :       
     849             :       //  msOut_p.relinquishAutoLocks (true);
     850             :       //  msOut_p.unlock();
     851             :       //Detaching the selected part
     852          44 :       ms_p=MeasurementSet();
     853             :       
     854          44 :       delete outpointer;
     855          44 :       return true;
     856             : 
     857             :     /*
     858             :     }
     859             :     catch(AipsError x){
     860             :       ms_p=MeasurementSet();
     861             :       throw(x);
     862             :     }
     863             :     catch(...){
     864             :       ms_p=MeasurementSet();
     865             :       throw(AipsError("Unknown exception caught"));
     866             :     }
     867             :     */
     868             : 
     869          44 :   }
     870             :   
     871           0 :   MeasurementSet* SubMS::makeScratchSubMS(const String& colname,
     872             :                                           const Bool forceInMemory)
     873             :   {
     874           0 :     return makeScratchSubMS(parseColumnNames(colname, ms_p), forceInMemory);
     875             :   }
     876             :   
     877           0 :   MeasurementSet* SubMS::makeScratchSubMS(const Vector<MS::PredefinedColumns>& whichDataCols,
     878             :                                           const Bool forceInMemory)
     879             :   {
     880           0 :     LogIO os(LogOrigin("SubMS", "makeScratchSubMS()"));
     881             :     
     882           0 :     if(max(fieldid_p) >= Int(ms_p.field().nrow())){
     883             :       os << LogIO::SEVERE 
     884             :          << "Field selection contains elements that do not exist in "
     885             :          << "this MS"
     886           0 :          << LogIO::POST;
     887           0 :       ms_p=MeasurementSet();
     888           0 :       return 0;  
     889             :     }
     890           0 :     if(max(spw_p) >= Int(ms_p.spectralWindow().nrow())){
     891             :       os << LogIO::SEVERE 
     892             :          << "SpectralWindow selection contains elements that do not exist in "
     893             :          << "this MS"
     894           0 :          << LogIO::POST;
     895           0 :       ms_p=MeasurementSet();
     896           0 :       return 0;
     897             :     }
     898             :     
     899           0 :     if(!makeSelection()){
     900             :       os << LogIO::SEVERE 
     901             :          << "Failed on selection: combination of spw and/or field and/or time "
     902             :          << "chosen may be invalid."
     903           0 :          << LogIO::POST;
     904           0 :       ms_p=MeasurementSet();
     905           0 :       return 0;
     906             :     }
     907           0 :     mscIn_p=new MSColumns(mssel_p);
     908           0 :     Double sizeInMB= 1.5 * n_bytes() / (1024.0 * 1024.0);
     909           0 :     String msname=AppInfo::workFileName(uInt(sizeInMB), "TempSubMS");
     910             :     
     911           0 :     MeasurementSet* outpointer=setupMS(msname, nchan_p[0], ncorr_p[0],  
     912           0 :                                        mscIn_p->observation().telescopeName()(0),
     913             :                                        whichDataCols);
     914             :     
     915           0 :     outpointer->markForDelete();
     916             :     //Hmmmmmm....memory...... 
     917           0 :     if(sizeInMB <  (Double)(HostInfo::memoryTotal(true))/(2048.0) 
     918           0 :        || forceInMemory){
     919           0 :       MeasurementSet* a = outpointer;
     920           0 :       outpointer= new MeasurementSet(a->copyToMemoryTable("TmpMemoryMS"));
     921           0 :       outpointer->initRefs();
     922           0 :       delete a;
     923             :     }
     924             :     
     925           0 :     msOut_p = *outpointer;
     926             :     
     927           0 :     if(!fillAllTables(whichDataCols)){
     928           0 :       delete outpointer;
     929           0 :       outpointer = 0;
     930           0 :       ms_p = MeasurementSet();
     931           0 :       return 0;
     932             :     }
     933             :     //Detaching the selected part
     934           0 :     ms_p=MeasurementSet();
     935           0 :     return outpointer;
     936           0 :   }
     937             : 
     938             :   
     939          44 : Bool SubMS::fillAllTables(const Vector<MS::PredefinedColumns>& datacols)
     940             : {
     941             : 
     942          88 :   LogIO os(LogOrigin("SubMS", "fillAllTables()"));
     943          44 :   Bool success = true;
     944             : 
     945             :   // Copy the subtables before doing anything with the main table.  Otherwise
     946             :   // MSColumns won't work.
     947             : 
     948             :   // fill or update
     949          44 :   Timer timer;
     950             : 
     951          44 :   timer.mark();
     952          44 :   success &= copyPointing();
     953             :   os << LogIO::DEBUG1
     954             :      << "copyPointing took " << timer.real() << "s."
     955          44 :      << LogIO::POST;
     956             : 
     957             :   // Optional columns should be set up before msc_p.
     958          44 :   addOptionalColumns(mssel_p.spectralWindow(), msOut_p.spectralWindow(), true);
     959             : 
     960             :   // Force the Measures frames for all the time type columns to have the same
     961             :   // reference as the TIME column of the main table.
     962             :   // Disable the empty table check (with false) because some of the subtables
     963             :   // (like POINTING) might already have been written.
     964             :   // However, empty tables are still empty after setting up the reference codes
     965             :   // here.
     966          44 :   msc_p = new MSColumns(msOut_p);
     967          44 :   msc_p->setEpochRef(MEpoch::castType(mscIn_p->timeMeas().getMeasRef().getType()),
     968             :                      false);
     969             : 
     970             :   // UVW is the only other Measures column in the main table.
     971          44 :   msc_p->uvwMeas().setDescRefCode(Muvw::castType(mscIn_p->uvwMeas().getMeasRef().getType()));
     972             : 
     973          44 :   if(!mscIn_p->flagCategory().isNull() && mscIn_p->flagCategory().isDefined(0))
     974           0 :     msc_p->setFlagCategories(mscIn_p->flagCategories());
     975             : 
     976          44 :   timer.mark();
     977          44 :   if(!fillDDTables())
     978           0 :     return false;
     979             :   os << LogIO::DEBUG1
     980             :      << "fillDDTables took " << timer.real() << "s."
     981          44 :      << LogIO::POST;
     982             : 
     983             :   // SourceIDs need to be remapped around here.  It could not be done in
     984             :   // selectSource() because mssel_p was not setup yet.
     985          44 :   timer.mark();
     986          44 :   relabelSources();
     987             :   os << LogIO::DEBUG1
     988             :      << "relabelSources took " << timer.real() << "s."
     989          44 :      << LogIO::POST;
     990             : 
     991          44 :   success &= fillFieldTable();
     992          44 :   success &= copySource();
     993             : 
     994          44 :   success &= copyAntenna();
     995          44 :   if(!copyFeed())         // Feed table writing has to be after antenna 
     996           0 :     return false;
     997             : 
     998          44 :   success &= copyFlag_Cmd();
     999          44 :   success &= copyHistory();
    1000          44 :   success &= copyObservation();
    1001          44 :   success &= copyProcessor();
    1002          44 :   success &= copyState();
    1003             : 
    1004          44 :   timer.mark();
    1005          44 :   success &= copySyscal();
    1006             :   os << LogIO::DEBUG1
    1007             :      << "copySyscal took " << timer.real() << "s."
    1008          44 :      << LogIO::POST;
    1009             : 
    1010          44 :   timer.mark();
    1011          44 :   success &= copyWeather();
    1012             :   os << LogIO::DEBUG1
    1013             :      << "copyWeather took " << timer.real() << "s."
    1014          44 :      << LogIO::POST;
    1015             :   
    1016          44 :   timer.mark();
    1017          44 :   success &= filterOptSubtable("CALDEVICE");
    1018             :   os << LogIO::DEBUG1
    1019             :      << "CALDEVICE took " << timer.real() << "s."
    1020          44 :      << LogIO::POST;
    1021             : 
    1022          44 :   timer.mark();
    1023          44 :   success &= filterOptSubtable("SYSPOWER");
    1024             :   os << LogIO::DEBUG1
    1025             :      << "SYSPOWER took " << timer.real() << "s."
    1026          44 :      << LogIO::POST;
    1027             : 
    1028             :   // Run this after running the other copy*()s.  Maybe there should be an
    1029             :   // option to *not* run it.
    1030          44 :   success &= copyGenericSubtables();
    1031             : 
    1032             :   //sameShape_p = areDataShapesConstant();
    1033             : 
    1034             :   // jagonzal: Allow main table to be left empty, so that it can be filled by another layer.
    1035          44 :   if (fillMainTable_p)
    1036             :   {
    1037          44 :           if(fitorder_p < 0 && timeBin_p <= 0.0)
    1038          44 :             success &= writeAllMainRows(datacols);
    1039             :           else
    1040           0 :             success &= writeSomeMainRows(datacols);
    1041          44 :           return success;
    1042             :   }
    1043             :   else
    1044             :   {
    1045           0 :           return success;
    1046             :   }
    1047          44 : }
    1048             :   
    1049             :   
    1050          44 :   Bool SubMS::makeSelection(){
    1051             :     
    1052          88 :     LogIO os(LogOrigin("SubMS", "makeSelection()"));
    1053             :     
    1054             :     //VisSet/MSIter will check if the SORTED exists
    1055             :     //and resort if necessary
    1056             :     {
    1057             :       // Matrix<Int> noselection;
    1058             :       // VisSet vs(ms_p, noselection);
    1059          44 :       Block<Int> sort;
    1060          44 :       ROVisibilityIterator(ms_p, sort);
    1061          44 :     }
    1062             :    
    1063             :     const MeasurementSet *elms;
    1064          44 :     elms=&ms_p;
    1065          44 :     MeasurementSet sorted;
    1066          44 :     if (ms_p.keywordSet().isDefined("SORTED_TABLE")) {
    1067          14 :       sorted=ms_p.keywordSet().asTable("SORTED_TABLE");
    1068             :       //If ms is not writable and sort is a subselection...use original ms
    1069          14 :       if( ms_p.nrow() == sorted.nrow())
    1070          14 :         elms=&sorted;
    1071             :     }
    1072             :  
    1073          44 :     MSSelection thisSelection;
    1074          44 :     if(fieldid_p.nelements() > 0)
    1075          44 :       thisSelection.setFieldExpr(MSSelection::indexExprStr(fieldid_p));
    1076          44 :     if(spw_p.nelements() > 0)
    1077          44 :       thisSelection.setSpwExpr(MSSelection::indexExprStr(spw_p));
    1078          44 :     if(antennaSel_p){
    1079           0 :       if(antennaId_p.nelements() > 0){
    1080           0 :         thisSelection.setAntennaExpr(MSSelection::indexExprStr( antennaId_p ));
    1081             :       }
    1082           0 :       if(antennaSelStr_p[0] != "")
    1083           0 :         thisSelection.setAntennaExpr(MSSelection::nameExprStr( antennaSelStr_p));
    1084             :     }
    1085          44 :     if(timeRange_p != "")
    1086           0 :       thisSelection.setTimeExpr(timeRange_p);
    1087             :     
    1088          44 :     thisSelection.setUvDistExpr(uvrangeString_p);
    1089          44 :     thisSelection.setScanExpr(scanString_p);
    1090          44 :     thisSelection.setStateExpr(intentString_p);
    1091          44 :     thisSelection.setObservationExpr(obsString_p);
    1092          44 :     if(arrayExpr_p != "")
    1093           0 :       thisSelection.setArrayExpr(arrayExpr_p);
    1094          44 :     if(corrString_p != "")
    1095           0 :       thisSelection.setPolnExpr(corrString_p);
    1096          44 :     thisSelection.setTaQLExpr(taqlString_p);
    1097             :     
    1098          44 :     TableExprNode exprNode=thisSelection.toTableExprNode(elms);
    1099          44 :     selTimeRanges_p = thisSelection.getTimeList();
    1100          44 :     selObsId_p = thisSelection.getObservationList();
    1101             : 
    1102             :     {      
    1103          44 :       const MSDataDescription ddtable = elms->dataDescription();
    1104             :       ScalarColumn<Int> polId(ddtable, 
    1105          44 :                                 MSDataDescription::columnName(MSDataDescription::POLARIZATION_ID));
    1106          44 :       const MSPolarization poltable = elms->polarization();
    1107             :       ArrayColumn<Int> pols(poltable, 
    1108          44 :                               MSPolarization::columnName(MSPolarization::CORR_TYPE));
    1109             :       
    1110             :       ScalarColumn<Int> spwId(ddtable, 
    1111          44 :                                 MSDataDescription::columnName(MSDataDescription::SPECTRAL_WINDOW_ID));
    1112             : 
    1113          44 :       uInt nddids = polId.nrow();
    1114          44 :       uInt nSpws = spw_p.nelements();
    1115             : 
    1116             :       // # of distinct channel ranges or pol setups (!#pols) per spw.
    1117          44 :       Vector<uInt> nuses_per_spw;
    1118             : 
    1119          44 :       Int highestSpw = max(spw_p);
    1120          44 :       if(highestSpw < 0)
    1121           0 :         highestSpw = 0;
    1122          44 :       spw2ddid_p.resize(highestSpw + 1);
    1123          44 :       nuses_per_spw.resize(highestSpw + 1);
    1124          44 :       spw2ddid_p.set(0);                 // This is a row #, so must be >= 0.
    1125          44 :       nuses_per_spw.set(0);
    1126          44 :       Bool ddidprob = false;
    1127         443 :       for(uInt j = 0; j < nddids; ++j){
    1128         399 :         Int spw = spwId(j);
    1129        2497 :         for(uInt k = 0; k < nSpws; ++k){
    1130        2098 :           if(spw == spw_p[k]){
    1131         127 :             ++nuses_per_spw[spw];
    1132         127 :             if(nuses_per_spw[spw_p[k]] == 2){
    1133           0 :               ddidprob = true;
    1134             :               os << LogIO::SEVERE
    1135           0 :                  << "Input spw " << spw_p[k] << " was selected for > 1 "
    1136           0 :                  << "channel ranges or polarization setups." << LogIO::POST;
    1137             :             }
    1138         127 :             spw2ddid_p[spw] = j;
    1139             :           }
    1140             :         }
    1141             :       }
    1142             : 
    1143          44 :       if(ddidprob){
    1144             :         os << LogIO::SEVERE
    1145             :            << "split does not yet support more than 1 channel range (';' in spw)"
    1146             :            << "\nor polarization setup per spectral window."
    1147           0 :            << LogIO::POST;
    1148           0 :         return false;
    1149             :       }
    1150             : 
    1151          44 :       Vector<Int> ddids;
    1152          44 :       ddids.resize(nSpws);
    1153             : 
    1154          44 :       inNumCorr_p.resize(nSpws);
    1155          44 :       ncorr_p.resize(nSpws);
    1156         171 :       for(uInt k = 0; k < nSpws; ++k){
    1157         127 :         Int ddid = spw2ddid_p[spw_p[k]];
    1158             :         
    1159         127 :         inNumCorr_p[k] = pols(polId(ddid)).nelements();
    1160         127 :         ncorr_p[k] = inPolOutCorrToInCorrMap_p[polId(ddid)].nelements();
    1161         127 :         if(ncorr_p[k] == 0){
    1162             :           os << LogIO::SEVERE
    1163             :              << "None of the selected correlations are in spectral window "
    1164           0 :              << spw_p[k]
    1165           0 :              << LogIO::POST;
    1166           0 :           return false;
    1167             :         }
    1168             :       }
    1169          44 :     }
    1170             :     
    1171             :     // Now remake the selected ms
    1172          44 :     if(!(exprNode.isNull())){
    1173          44 :       mssel_p = MeasurementSet((*elms)(exprNode));
    1174             :     }
    1175             :     else{
    1176             :       // Null take all the ms ...setdata() blank means that
    1177           0 :       mssel_p = MeasurementSet((*elms));
    1178             :     }
    1179             :     //mssel_p.rename(ms_p.tableName()+"/SELECTED_TABLE", Table::Scratch);
    1180          44 :     if(mssel_p.nrow() == 0)
    1181           0 :       return false;
    1182             : 
    1183             :     // Setup antNewIndex_p now that mssel_p is ready.
    1184          44 :     if(antennaSel_p){
    1185             :       // Watch out! getAntenna*List() and getBaselineList() return negative
    1186             :       // numbers for negated antennas!
    1187             :       //Vector<Int> selAnt1s(thisSelection.getAntenna1List());
    1188             :       //Vector<Int> selAnt2s(thisSelection.getAntenna2List());
    1189           0 :       ScalarColumn<Int> ant1c(mssel_p, MS::columnName(MS::ANTENNA1));
    1190           0 :       ScalarColumn<Int> ant2c(mssel_p, MS::columnName(MS::ANTENNA2));
    1191           0 :       Vector<Int> selAnts(ant1c.getColumn());
    1192           0 :       uInt nAnts = selAnts.nelements();
    1193             : 
    1194           0 :       selAnts.resize(2 * nAnts, true);
    1195           0 :       selAnts(Slice(nAnts, nAnts)) = ant2c.getColumn();
    1196           0 :       nAnts = GenSort<Int>::sort(selAnts, Sort::Ascending, Sort::NoDuplicates);
    1197           0 :       selAnts.resize(nAnts, true);
    1198           0 :       Int maxAnt = max(selAnts);
    1199             : 
    1200           0 :       if(maxAnt < 0){
    1201             :         os << LogIO::SEVERE
    1202             :            << "The maximum selected antenna number, " << maxAnt
    1203             :            << ", seems to be < 0."
    1204           0 :            << LogIO::POST;
    1205           0 :         return false;
    1206             :       }
    1207           0 :       antNewIndex_p.resize(maxAnt + 1);
    1208           0 :       antNewIndex_p.set(-1); //So if you see -1 in the main, feed, or pointing
    1209             :                              //tables, fix it
    1210           0 :       Bool trivial = true;
    1211           0 :       for(uInt k = 0; k < nAnts; ++k){
    1212           0 :         trivial &= (selAnts[k] == static_cast<Int>(k));   // trivial = selAnts == indgen(nAnts)
    1213           0 :         antNewIndex_p[selAnts[k]] = k;
    1214             :       }                                  // It is possible to exclude baselines
    1215           0 :       antennaSel_p = !trivial;           // without excluding any antennas.
    1216           0 :     }                                    // This still gets tripped up by VLA:OUT.
    1217             :     else{        // Make a default antNewIndex_p.
    1218          44 :       antNewIndex_p.resize(mssel_p.antenna().nrow());
    1219          44 :       indgen(antNewIndex_p);
    1220             :     }
    1221             :       
    1222          44 :     if(mssel_p.nrow() < ms_p.nrow()){
    1223             :       os << LogIO::NORMAL
    1224             :          << mssel_p.nrow() << " out of " << ms_p.nrow() << " rows are going to be" 
    1225             :          << " considered due to the selection criteria." 
    1226          34 :          << LogIO::POST;
    1227             :     }
    1228          44 :     return true;
    1229          44 :   }
    1230             : 
    1231         122 :   MeasurementSet* SubMS::setupMS(const String& MSFileName, const Int nchan,
    1232             :                                  const Int nCorr, const String& telescop,
    1233             :                                  const Vector<MS::PredefinedColumns>& colNames,
    1234             :                                  const Int obstype,
    1235             :                                  const Bool compress,
    1236             :                                  const asdmStManUseAlternatives asdmStManUse)
    1237             :   {
    1238             :     //Choose an appropriate tileshape
    1239         122 :     IPosition dataShape(2, nCorr, nchan);
    1240         122 :     IPosition tileShape = MSTileLayout::tileShape(dataShape, obstype, telescop);
    1241         244 :     return setupMS(MSFileName, nchan, nCorr, colNames, tileShape.asVector(),
    1242         244 :                    compress, asdmStManUse);
    1243             :     //return setupMS(MSFileName, nchan, nCorr, colNames, tileShape.asVector());
    1244         122 :   }
    1245         122 :   MeasurementSet* SubMS::setupMS(const String& MSFileName, const Int nchan,
    1246             :                                  const Int nCorr, 
    1247             :                                  const Vector<MS::PredefinedColumns>& colNamesTok,
    1248             :                                  const Vector<Int>& tshape, const Bool compress,
    1249             :                                  const asdmStManUseAlternatives asdmStManUse)
    1250             :   {
    1251         122 :     if(tshape.nelements() != 3)
    1252           0 :       throw(AipsError("TileShape has to have 3 elements ") );
    1253             : 
    1254             :     // This is more to shush a compiler warning than to warn users.
    1255         244 :     LogIO os(LogOrigin("SubMS", "setupMS()"));
    1256         122 :     if(tshape[0] != nCorr)
    1257             :       os << LogIO::DEBUG1
    1258           0 :          << "Warning: using " << tshape[0] << " from the tileshape instead of "
    1259             :          << nCorr << " for the number of correlations."
    1260           0 :          << LogIO::POST;
    1261         122 :     if(tshape[1] != nchan)
    1262             :       os << LogIO::DEBUG1
    1263          92 :          << "Warning: using " << tshape[1] << " from the tileshape instead of "
    1264             :          << nchan << " for the number of channels."
    1265          46 :          << LogIO::POST;
    1266             : 
    1267             :     // Choose an appropriate tileshape
    1268             :     //IPosition dataShape(2,nCorr,nchan);
    1269             :     //IPosition tileShape = MSTileLayout::tileShape(dataShape,obsType, telescop);
    1270             :     //////////////////
    1271             :     
    1272         122 :     IPosition tileShape(tshape);
    1273             : 
    1274             :     // Make the MS table
    1275         122 :     TableDesc td = MS::requiredTableDesc();
    1276         122 :     Vector<String> tiledDataNames;
    1277             : 
    1278             :     // Even though we know the data is going to be the same shape throughout I'll
    1279             :     // still create a column that has a variable shape as this will permit MS's
    1280             :     // with other shapes to be appended.
    1281         122 :     uInt ncols = colNamesTok.nelements();
    1282         122 :     const Bool mustWriteOnlyToData = mustConvertToData(ncols, colNamesTok);
    1283         122 :     Bool hasFloatData = False;
    1284             : 
    1285         122 :     if (mustWriteOnlyToData)
    1286             :       {
    1287          95 :         MS::addColumnToDesc(td, MS::DATA, 2);
    1288          95 :         if(asdmStManUse==DONT){
    1289          68 :           if (compress) MS::addColumnCompression(td,MS::DATA,true);
    1290         136 :           String hcolName=String("Tiled")+String("DATA");
    1291          68 :           td.defineHypercolumn(hcolName, 3,
    1292         136 :                                stringToVector("DATA"));
    1293          68 :           tiledDataNames.resize(1);
    1294          68 :           tiledDataNames[0] = hcolName;
    1295          68 :         }
    1296             :       }
    1297             :     else{
    1298          27 :       tiledDataNames.resize(ncols);
    1299          75 :       for(uInt i = 0; i < ncols; ++i){
    1300             :         // only add data-like columns here
    1301             :         // Unfortunately MS::PredefinedColumns aren't ordered so that I can just check if
    1302             :         // colNamesTok[i] is in the "data range".
    1303          48 :         if(colNamesTok[i] == MS::DATA ||
    1304          37 :            colNamesTok[i] == MS::MODEL_DATA ||
    1305          27 :            colNamesTok[i] == MS::CORRECTED_DATA ||
    1306          85 :            colNamesTok[i] == MS::FLOAT_DATA ||
    1307           0 :            colNamesTok[i] == MS::LAG_DATA) {
    1308          48 :           MS::addColumnToDesc(td, colNamesTok[i], 2);
    1309             :           // compress them unless they are DATA or FLOAT_DATA and the AsdmStMan is in use
    1310          52 :           if(asdmStManUse==DONT ||
    1311           4 :              (colNamesTok[i] != MS::DATA && colNamesTok[i] != MS::FLOAT_DATA)){
    1312          44 :             if (compress) MS::addColumnCompression(td,colNamesTok[i],true);
    1313             :           }
    1314          48 :           if (colNamesTok[i] == MS::FLOAT_DATA) {
    1315             :             // make a note that FLOAT_DATA is being used, for later.
    1316          16 :             hasFloatData = True;
    1317             :           }
    1318             :         }
    1319             :         else {
    1320           0 :           throw(AipsError(MS::columnName(colNamesTok[i]) +
    1321           0 :                           " is not a recognized data column "));
    1322             :         }
    1323             :         //  Add tiled versions for these columns except for DATA and FLOAT_DATA when AsdmStMan is in use.
    1324          52 :         if(asdmStManUse==DONT ||
    1325           4 :            (colNamesTok[i] != MS::DATA && colNamesTok[i] != MS::FLOAT_DATA)){
    1326          44 :           String hcolName = String("Tiled") + MS::columnName(colNamesTok[i]);
    1327          44 :           td.defineHypercolumn(hcolName, 3,
    1328          88 :                                stringToVector(MS::columnName(colNamesTok[i])));
    1329          44 :           tiledDataNames[i] = hcolName;
    1330          44 :         }
    1331             :       }
    1332             :     }
    1333             : 
    1334             :     //other cols for compression
    1335         122 :     if (compress && asdmStManUse!=USE_FOR_DATA_WEIGHT_SIGMA_FLAG) {
    1336           0 :       MS::addColumnCompression(td, MS::WEIGHT, true);
    1337           0 :       MS::addColumnCompression(td, MS::SIGMA, true);
    1338             :     }
    1339             :     
    1340             :     // add this optional column because random group fits has a
    1341             :     // weight per visibility
    1342         122 :     MS::addColumnToDesc(td, MS::WEIGHT_SPECTRUM, 2);
    1343             : 
    1344             :     // if(asdmStManUse==DONT){
    1345             :     //     td.defineHypercolumn("TiledDATA",3,
    1346             :     //                           stringToVector(MS::columnName(MS::DATA)));
    1347             :     // }
    1348         122 :     td.defineHypercolumn("TiledFlagCategory",4,
    1349         244 :                          stringToVector(MS::columnName(MS::FLAG_CATEGORY)));
    1350         122 :     td.defineHypercolumn("TiledWgtSpectrum",3,
    1351         244 :                          stringToVector(MS::columnName(MS::WEIGHT_SPECTRUM)));
    1352         122 :     td.defineHypercolumn("TiledUVW",2,
    1353         244 :                          stringToVector(MS::columnName(MS::UVW)));
    1354         122 :     if(asdmStManUse!=USE_FOR_DATA_WEIGHT_SIGMA_FLAG){
    1355         122 :       td.defineHypercolumn("TiledFlag",3,
    1356         244 :                            stringToVector(MS::columnName(MS::FLAG)));
    1357         122 :       td.defineHypercolumn("TiledWgt",2,
    1358         244 :                            stringToVector(MS::columnName(MS::WEIGHT)));
    1359         122 :       td.defineHypercolumn("TiledSigma", 2,
    1360         244 :                            stringToVector(MS::columnName(MS::SIGMA)));
    1361             :     }
    1362             : 
    1363         122 :     SetupNewTable newtab(MSFileName, td, Table::New);
    1364             :     
    1365         122 :     uInt cache_val=32768;
    1366             :     // Set the default Storage Manager to be the Incr one
    1367         122 :     IncrementalStMan incrStMan ("ISMData",cache_val);
    1368         122 :     newtab.bindAll(incrStMan, true);
    1369             :     //Override the binding for specific columns
    1370             :     
    1371         122 :     IncrementalStMan incrStMan0("Array_ID",cache_val);
    1372         122 :     newtab.bindColumn(MS::columnName(MS::ARRAY_ID), incrStMan0);
    1373         122 :     IncrementalStMan incrStMan1("EXPOSURE",cache_val);
    1374         122 :     newtab.bindColumn(MS::columnName(MS::EXPOSURE), incrStMan1);
    1375         122 :     IncrementalStMan incrStMan2("FEED1",cache_val);
    1376         122 :     newtab.bindColumn(MS::columnName(MS::FEED1), incrStMan2);
    1377         122 :     IncrementalStMan incrStMan3("FEED2",cache_val);
    1378         122 :     newtab.bindColumn(MS::columnName(MS::FEED2), incrStMan3);
    1379         122 :     IncrementalStMan incrStMan4("FIELD_ID",cache_val);
    1380         122 :     newtab.bindColumn(MS::columnName(MS::FIELD_ID), incrStMan4);
    1381             : 
    1382             :     // jagonzal (CAS-6746): Don't use IncrementalStMan with RW cols ///////////////////////////////////////////////////
    1383             :     //IncrementalStMan incrStMan5("FLAG_ROW",cache_val/4);
    1384             :     //newtab.bindColumn(MS::columnName(MS::FLAG_ROW), incrStMan5);
    1385         122 :     StandardStMan aipsStManFlagRow("FLAG_ROW", cache_val/4);
    1386         122 :     newtab.bindColumn(MS::columnName(MS::FLAG_ROW), aipsStManFlagRow);
    1387             :     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    1388             : 
    1389         122 :     IncrementalStMan incrStMan6("INTERVAL",cache_val);
    1390         122 :     newtab.bindColumn(MS::columnName(MS::INTERVAL), incrStMan6);
    1391         122 :     IncrementalStMan incrStMan7("OBSERVATION_ID",cache_val);
    1392         122 :     newtab.bindColumn(MS::columnName(MS::OBSERVATION_ID), incrStMan7);
    1393         122 :     IncrementalStMan incrStMan8("PROCESSOR_ID",cache_val);
    1394         122 :     newtab.bindColumn(MS::columnName(MS::PROCESSOR_ID), incrStMan8);
    1395         122 :     IncrementalStMan incrStMan9("SCAN_NUMBER",cache_val);
    1396         122 :     newtab.bindColumn(MS::columnName(MS::SCAN_NUMBER), incrStMan9);
    1397         122 :     IncrementalStMan incrStMan10("STATE_ID",cache_val);
    1398         122 :     newtab.bindColumn(MS::columnName(MS::STATE_ID), incrStMan10);
    1399         122 :     IncrementalStMan incrStMan11("TIME",cache_val);
    1400         122 :     newtab.bindColumn(MS::columnName(MS::TIME), incrStMan11);
    1401         122 :     IncrementalStMan incrStMan12("TIME_CENTROID",cache_val);
    1402         122 :     newtab.bindColumn(MS::columnName(MS::TIME_CENTROID), incrStMan12);
    1403             :     
    1404             :     // Bind ANTENNA1, ANTENNA2 and DATA_DESC_ID to the standardStMan 
    1405             :     // as they may change sufficiently frequently to make the
    1406             :     // incremental storage manager inefficient for these columns.
    1407             :     
    1408             :       
    1409         122 :     StandardStMan aipsStMan0("ANTENNA1", cache_val);
    1410         122 :     newtab.bindColumn(MS::columnName(MS::ANTENNA1), aipsStMan0);
    1411         122 :     StandardStMan aipsStMan1("ANTENNA2", cache_val);
    1412         122 :     newtab.bindColumn(MS::columnName(MS::ANTENNA2), aipsStMan1);
    1413         122 :     StandardStMan aipsStMan2("DATA_DESC_ID", cache_val);
    1414         122 :     newtab.bindColumn(MS::columnName(MS::DATA_DESC_ID), aipsStMan2);
    1415             :     
    1416             :      
    1417             :     //    itsLog << LogOrigin("MSFitsInput", "setupMeasurementSet");
    1418             :     //itsLog << LogIO::NORMAL << "Using tile shape "<<tileShape <<" for "<<
    1419             :     //  array_p<<" with obstype="<< obsType<<LogIO::POST;
    1420             :     
    1421             :     //    TiledShapeStMan tiledStMan1("TiledData",tileShape);
    1422         122 :     TiledShapeStMan tiledStMan1f("TiledFlag",tileShape);
    1423             :     TiledShapeStMan tiledStMan1fc("TiledFlagCategory",
    1424         122 :                                   IPosition(4,tileShape(0),tileShape(1),1,
    1425         366 :                                             tileShape(2)));
    1426         122 :     TiledShapeStMan tiledStMan2("TiledWgtSpectrum",tileShape);
    1427         244 :     TiledColumnStMan tiledStMan3("TiledUVW",IPosition(2, 3, (tileShape(0) * tileShape(1) * tileShape(2)) / 3));
    1428             :     TiledShapeStMan tiledStMan4("TiledWgt", 
    1429         244 :                                 IPosition(2,tileShape(0), tileShape(1) * tileShape(2)));
    1430             :     TiledShapeStMan tiledStMan5("TiledSigma", 
    1431         244 :                                 IPosition(2,tileShape(0), tileShape(1) * tileShape(2)));
    1432             :     
    1433             :     // Bind the DATA or FLOAT_DATA, FLAG & WEIGHT_SPECTRUM columns to the tiled stman or asdmStMan
    1434             : 
    1435         122 :     AsdmStMan sm;
    1436             : 
    1437         122 :     if (mustWriteOnlyToData){
    1438          95 :       if(asdmStManUse==DONT){
    1439          68 :         TiledShapeStMan tiledStMan1Data("TiledDATA",tileShape);
    1440             :       
    1441          68 :         newtab.bindColumn(MS::columnName(MS::DATA), tiledStMan1Data);
    1442          68 :       }
    1443             :       else{
    1444          27 :         if (hasFloatData) {
    1445           0 :           newtab.bindColumn(MS::columnName(MS::FLOAT_DATA), sm);
    1446             :         } else{
    1447          27 :           newtab.bindColumn(MS::columnName(MS::DATA), sm);
    1448             :         }
    1449             :       }
    1450             :     }
    1451             :     else{
    1452          75 :       for(uInt i = 0; i < ncols; ++i){
    1453          48 :         TiledShapeStMan tiledStMan1Data(tiledDataNames[i], tileShape);
    1454             :         
    1455          48 :         newtab.bindColumn(MS::columnName(colNamesTok[i]), tiledStMan1Data);
    1456          48 :       }
    1457          27 :       if(asdmStManUse!=DONT){
    1458           4 :         if (hasFloatData) {
    1459           4 :           newtab.bindColumn(MS::columnName(MS::FLOAT_DATA), sm);
    1460             :         } else {
    1461           0 :           newtab.bindColumn(MS::columnName(MS::DATA), sm);
    1462             :         }
    1463             :       }
    1464             :     }
    1465         122 :     newtab.bindColumn(MS::columnName(MS::FLAG_CATEGORY),tiledStMan1fc);
    1466         122 :     newtab.bindColumn(MS::columnName(MS::WEIGHT_SPECTRUM),tiledStMan2);
    1467             :     
    1468         122 :     newtab.bindColumn(MS::columnName(MS::UVW),tiledStMan3);
    1469         122 :     if(asdmStManUse==USE_FOR_DATA_WEIGHT_SIGMA_FLAG){
    1470           0 :       newtab.bindColumn(MS::columnName(MS::FLAG),sm);
    1471           0 :       newtab.bindColumn(MS::columnName(MS::WEIGHT),sm);
    1472           0 :       newtab.bindColumn(MS::columnName(MS::SIGMA),sm);      
    1473             :     }
    1474             :     else{
    1475         122 :       newtab.bindColumn(MS::columnName(MS::FLAG),tiledStMan1f);
    1476         122 :       newtab.bindColumn(MS::columnName(MS::WEIGHT),tiledStMan4);
    1477         122 :       newtab.bindColumn(MS::columnName(MS::SIGMA),tiledStMan5);
    1478             :     }
    1479             :       
    1480             : 
    1481             :     // avoid lock overheads by locking the table permanently
    1482         122 :     TableLock lock(TableLock::AutoLocking);
    1483         122 :     MeasurementSet *ms = new MeasurementSet (newtab,lock);
    1484             :     
    1485             :     // Set up the subtables for the UVFITS MS
    1486             :     // we make new tables with 0 rows
    1487         122 :     Table::TableOption option=Table::New;
    1488         122 :     createSubtables(*ms, option); 
    1489             : 
    1490             :     { // Set the TableInfo
    1491         122 :       TableInfo& info(ms->tableInfo());
    1492         122 :       info.setType(TableInfo::type(TableInfo::MEASUREMENTSET));
    1493         122 :       info.setSubType(String("UVFITS"));
    1494             :       info.readmeAddLine
    1495         122 :         ("This is a measurement set Table holding astronomical observations");
    1496             :     }
    1497         122 :     return ms;
    1498         122 :   }
    1499             :   
    1500             :   
    1501          44 :   Bool SubMS::fillDDTables()
    1502             :   {  
    1503          88 :     LogIO os(LogOrigin("SubMS", "fillDDTables()"));
    1504             :     
    1505          44 :     MSSpWindowColumns inSpWCols(mssel_p.spectralWindow());
    1506          44 :     MSSpWindowColumns& msSpW(msc_p->spectralWindow());
    1507             :     // Detect which optional columns of SPECTRAL_WINDOW are present.
    1508             :     // inSpWCols and msSpW should agree because addOptionalColumns() was done
    1509             :     // for SPECTRAL_WINDOW in fillAllTables() before making msc_p or calling
    1510             :     // fillDDTables.
    1511          44 :     Bool haveSpwAN  = inSpWCols.assocNature().hasContent();
    1512          44 :     Bool haveSpwASI = inSpWCols.assocSpwId().hasContent();
    1513          44 :     Bool haveSpwBN  = inSpWCols.bbcNo().hasContent();
    1514          44 :     Bool haveSpwBS  = inSpWCols.bbcSideband().hasContent();
    1515          44 :     Bool haveSpwDI  = inSpWCols.dopplerId().hasContent();
    1516             : 
    1517          44 :     MSDataDescColumns& msDD(msc_p->dataDescription());
    1518          44 :     MSPolarizationColumns& msPol(msc_p->polarization());
    1519             :     
    1520             :     //DD table
    1521          44 :     const MSDataDescription ddtable = mssel_p.dataDescription();
    1522             :     ScalarColumn<Int> polId(ddtable, 
    1523          44 :                               MSDataDescription::columnName(MSDataDescription::POLARIZATION_ID));
    1524             :     
    1525             :     //Fill in matching spw to datadesc in old ms 
    1526             :     {
    1527          44 :       MSDataDescColumns msOldDD(ddtable);
    1528          44 :       oldDDSpwMatch_p=msOldDD.spectralWindowId().getColumn();
    1529          44 :     }
    1530             : 
    1531             :     //POLARIZATION table    
    1532          44 :     const MSPolarization poltable= mssel_p.polarization();
    1533             :     ScalarColumn<Int> numCorr (poltable, 
    1534          44 :                                  MSPolarization::columnName(MSPolarization::NUM_CORR));
    1535             :     ArrayColumn<Int> corrType(poltable, 
    1536          44 :                                 MSPolarization::columnName(MSPolarization::CORR_TYPE));
    1537          44 :     ArrayColumn<Int> corrProd(poltable, MSPolarization::columnName(MSPolarization::CORR_PRODUCT));
    1538          44 :     ScalarColumn<Bool> polFlagRow(poltable, MSPolarization::columnName(MSPolarization::FLAG_ROW));
    1539             :     
    1540          44 :     spwRelabel_p.resize(mscIn_p->spectralWindow().nrow());
    1541          44 :     spwRelabel_p.set(-1);
    1542             :     
    1543          44 :     inNumChan_p.resize(spw_p.nelements()); 
    1544             :     
    1545          44 :     polID_p = polId.getColumn();
    1546             :     Bool dum;
    1547          44 :     Sort sort( polID_p.getStorage(dum),sizeof(Int) );
    1548          44 :     sort.sortKey((uInt)0,TpInt);
    1549          44 :     Vector<uInt> index,uniq;
    1550          44 :     sort.sort(index,polID_p.nelements());
    1551          44 :     uInt nPol = sort.unique(uniq,index);
    1552          44 :     Vector<Int> selectedPolId(nPol);      // Map from output polID to input polID.
    1553          89 :     for(uInt k = 0; k < nPol; ++k)
    1554          45 :       selectedPolId[k] = polID_p[index[uniq[k]]];
    1555             :     
    1556             :     // Make map from input to output spws.
    1557          44 :     Sort sortSpws(spw_p.getStorage(dum), sizeof(Int));
    1558          44 :     sortSpws.sortKey((uInt)0, TpInt);
    1559          44 :     Vector<uInt> spwsortindex, spwuniqinds;
    1560          44 :     sortSpws.sort(spwsortindex, spw_p.nelements());
    1561          44 :     uInt nuniqSpws = sortSpws.unique(spwuniqinds, spwsortindex);
    1562          44 :     spw_uniq_p.resize(nuniqSpws);
    1563         171 :     for(uInt k = 0; k < nuniqSpws; ++k){
    1564         127 :       spw_uniq_p[k] = spw_p[spwuniqinds[k]];
    1565         127 :       spwRelabel_p[spw_uniq_p[k]] = k;
    1566             :     }
    1567          44 :     if(nuniqSpws < spw_p.nelements()){
    1568             :       os << LogIO::WARN
    1569             :          << "Multiple channel ranges within an spw may not work.  SOME DATA MAY BE OMITTED!"
    1570             :          << "\nConsider splitting them individually and optionally combining the output MSes with concat."
    1571             :          << "\nEven then, expect problems if exporting to uvfits."
    1572           0 :          << LogIO::POST;
    1573             :     }
    1574             : 
    1575          44 :     Vector<Int> newPolId(nuniqSpws);
    1576         171 :     for(uInt k = 0; k < nuniqSpws; ++k){
    1577         127 :       Bool found = false;
    1578             :       
    1579         127 :       for(uInt j = 0; j < nPol; ++j){ 
    1580         127 :         if(selectedPolId[j] == polID_p[spw2ddid_p[spw_uniq_p[k]]]){
    1581         127 :           newPolId[k] = j;
    1582         127 :           found = true;
    1583         127 :           break;
    1584             :         }
    1585             :       }
    1586         127 :       if(!found){
    1587             :         os << LogIO::SEVERE
    1588             :            << "No polarization ID found for output polarization setup " << k
    1589           0 :            << LogIO::POST;
    1590           0 :         return false;
    1591             :       }
    1592             :     }
    1593          44 :     corrSlice_p.resize(nPol);
    1594          89 :     for(uInt outpid = 0; outpid < nPol; ++outpid){
    1595          45 :       uInt inpid = selectedPolId[outpid];
    1596          45 :       uInt ncorr = inPolOutCorrToInCorrMap_p[inpid].nelements();
    1597          45 :       const Vector<Int> inCT(corrType(inpid));
    1598             :       
    1599             :       // ncorr will be 0 if none of the selected spws have this pid. 
    1600          45 :       if(ncorr > 0 && ncorr < inCT.nelements()){
    1601           0 :         keepShape_p = false;
    1602             : 
    1603             :         // Check whether the requested correlations can be accessed by slicing.
    1604             :         // That means there must be a constant stride.  The most likely (only?)
    1605             :         // way to violate that is to ask for 3 out of 4 correlations.
    1606           0 :         if(ncorr > 2){
    1607             :           os << LogIO::SEVERE
    1608             :              << "Sorry, the requested correlation selection is not unsupported.\n"
    1609             :              << "Try selecting fewer or all of the correlations."
    1610           0 :              << LogIO::POST;
    1611           0 :           return false;
    1612             :         }
    1613             : 
    1614           0 :         corrSlice_p[outpid] = Slice(inPolOutCorrToInCorrMap_p[inpid][0],
    1615             :                                ncorr,
    1616           0 :                                ncorr > 1 ? inPolOutCorrToInCorrMap_p[inpid][1] -
    1617           0 :                                            inPolOutCorrToInCorrMap_p[inpid][0] :
    1618             :                                1);
    1619             :       }
    1620             :       else
    1621          45 :         corrSlice_p[outpid] = Slice(0, ncorr);
    1622             :       
    1623          45 :       msOut_p.polarization().addRow();
    1624          45 :       msPol.numCorr().put(outpid, ncorr);
    1625          45 :       msPol.flagRow().put(outpid, polFlagRow(inpid));
    1626             : 
    1627          45 :       Vector<Int> outCT;
    1628          45 :       const Matrix<Int> inCP(corrProd(inpid));
    1629          45 :       Matrix<Int> outCP;
    1630          45 :       outCT.resize(ncorr);
    1631          45 :       outCP.resize(2, ncorr);
    1632         134 :       for(uInt k = 0; k < ncorr; ++k){
    1633          89 :         Int inCorrInd = inPolOutCorrToInCorrMap_p[inpid][k];
    1634             :         
    1635          89 :         outCT[k] = inCT[inCorrInd];
    1636         267 :         for(uInt feedind = 0; feedind < 2; ++feedind)
    1637         178 :           outCP(feedind, k) = inCP(feedind, inCorrInd);
    1638             :       }
    1639          45 :       msPol.corrType().put(outpid, outCT);
    1640          45 :       msPol.corrProduct().put(outpid, outCP);
    1641          45 :     }
    1642             : 
    1643         171 :     for(uInt k = 0; k < spw_p.nelements(); ++k)
    1644         127 :       inNumChan_p[k] = inSpWCols.numChan()(spw_p[k]);
    1645             :     
    1646          44 :     Vector<Vector<Int> > spwinds_of_uniq_spws(nuniqSpws);
    1647             : 
    1648          44 :     totnchan_p.resize(nuniqSpws);
    1649         171 :     for(uInt k = 0; k < nuniqSpws; ++k){
    1650         127 :       Int maxchan = 0;
    1651         127 :       uInt j = 0;
    1652             : 
    1653         127 :       msOut_p.spectralWindow().addRow();
    1654         127 :       msOut_p.dataDescription().addRow();
    1655             : 
    1656         127 :       totnchan_p[k] = 0;
    1657         127 :       spwinds_of_uniq_spws[k].resize();
    1658        1382 :       for(uInt spwind = 0; spwind < spw_p.nelements(); ++spwind){
    1659        1255 :         if(spw_p[spwind] == spw_uniq_p[k]){
    1660         127 :           Int highchan = nchan_p[spwind] * chanStep_p[spwind]
    1661         127 :             + chanStart_p[spwind];
    1662             : 
    1663         127 :           if(highchan > maxchan)
    1664         127 :             maxchan = highchan;
    1665             : 
    1666         127 :           totnchan_p[k] += nchan_p[spwind];
    1667             : 
    1668             :           // The true is necessary to avoid scrambling previously assigned
    1669             :           // values.
    1670         127 :           spwinds_of_uniq_spws[k].resize(j + 1, true);
    1671             : 
    1672             :           // Warning!  spwinds_of_uniq_spws[k][j] will compile without warning,
    1673             :           // but dump core at runtime.
    1674         127 :           (spwinds_of_uniq_spws[k])[j] = spwind;
    1675         127 :           ++j;
    1676             :         }
    1677             :       }
    1678         127 :       if(maxchan > inSpWCols.numChan()(spw_uniq_p[k])){
    1679             :         os << LogIO::SEVERE
    1680             :            << " Channel settings wrong; exceeding number of channels in spw "
    1681           0 :            << spw_uniq_p[k] << LogIO::POST;
    1682           0 :         return false;
    1683             :       }
    1684             :     }
    1685             : 
    1686             :     // min_k is an index for getting an spw index via spw_uniq_p[min_k].
    1687             :     // k is an index for getting an spw index via spw_p[k].
    1688         171 :     for(uInt min_k = 0; min_k < nuniqSpws; ++min_k){
    1689         127 :       uInt k = spwinds_of_uniq_spws[min_k][0];
    1690             : 
    1691         254 :       if(spwinds_of_uniq_spws[min_k].nelements() > 1 ||
    1692         127 :          nchan_p[k] != inSpWCols.numChan()(spw_p[k])){
    1693           6 :         Vector<Double> effBWIn = inSpWCols.effectiveBW()(spw_uniq_p[min_k]);
    1694           6 :         Int nOutChan = totnchan_p[min_k];
    1695           6 :         Vector<Double> chanFreqOut(nOutChan);
    1696           6 :         Vector<Double> chanFreqIn = inSpWCols.chanFreq()(spw_uniq_p[min_k]);
    1697           6 :         Vector<Double> chanWidthOut(nOutChan);
    1698           6 :         Vector<Double> chanWidthIn = inSpWCols.chanWidth()(spw_uniq_p[min_k]);
    1699           6 :         Vector<Double> spwResolOut(nOutChan);
    1700           6 :         Vector<Double> spwResolIn = inSpWCols.resolution()(spw_uniq_p[min_k]);
    1701           6 :         Vector<Double> effBWOut(nOutChan);
    1702           6 :         Int outChan = 0;
    1703             : 
    1704           6 :         keepShape_p = false;
    1705             : 
    1706             :         // The sign of CHAN_WIDTH defaults to +.  Its determination assumes
    1707             :         // that chanFreqIn is monotonic, but not that the sign of the
    1708             :         // chanWidthIn is correct.
    1709           6 :         Bool neginc = chanFreqIn[chanFreqIn.nelements() - 1] < chanFreqIn[0];
    1710             : 
    1711           6 :         effBWOut.set(0.0);
    1712           6 :         Double totalBW = 0.0;
    1713          12 :         for(uInt rangeNum = 0;
    1714          12 :             rangeNum < spwinds_of_uniq_spws[min_k].nelements(); ++rangeNum){
    1715           6 :           k = spwinds_of_uniq_spws[min_k][rangeNum];
    1716             : 
    1717           6 :           Int span = chanStep_p[k] * widths_p[k];
    1718             : 
    1719          30 :           for(Int j = 0; j < nchan_p[k]; ++j){
    1720          24 :             Int inpChan = chanStart_p[k] + j * span;
    1721             : 
    1722          24 :             if(span > 1){
    1723           0 :               Int lastChan = inpChan + span - 1;
    1724             : 
    1725           0 :               if(lastChan > chanEnd_p[k]){
    1726             :                 // The averaging width is not a factor of the number of
    1727             :                 // selected input channels, so the last output bin receives
    1728             :                 // fewer input channels than the other bins.
    1729           0 :                 lastChan = chanEnd_p[k];
    1730             : 
    1731           0 :                 Int nchan = lastChan - inpChan + 1;
    1732             :                 os << LogIO::NORMAL
    1733           0 :                    << "The last output channel of spw " << spw_p[k]
    1734           0 :                    << " has only " << nchan << " input channel";
    1735           0 :                 if(nchan > 1)
    1736           0 :                   os << "s.";
    1737             :                 //else
    1738             :                 //  os << ".\nRemember that MS selection ranges (unlike Python), *include* the last number.";
    1739           0 :                 os << LogIO::POST;
    1740             :                 //os << LogIO::WARN
    1741             :                 //   << "You will not be able to export an MS where the width varies by channel to UVFITS!"
    1742             :                 //   << LogIO::POST;
    1743             :               }
    1744             : 
    1745           0 :               chanFreqOut[outChan] = (chanFreqIn[inpChan] +
    1746           0 :                                       chanFreqIn[lastChan]) / 2;
    1747             : 
    1748           0 :               Double sep = chanFreqIn[lastChan] - chanFreqIn[inpChan];
    1749             : 
    1750           0 :               if(neginc)
    1751           0 :                 sep = -sep;
    1752             : 
    1753             :               // The internal abs is necessary because the sign of chanWidthIn
    1754             :               // may be wrong.
    1755           0 :               chanWidthOut[outChan] = sep + 0.5 * abs(chanWidthIn[inpChan] +
    1756           0 :                                                       chanWidthIn[lastChan]);
    1757           0 :               if(neginc)
    1758           0 :                 chanWidthOut[outChan] = -chanWidthOut[outChan];
    1759             :             
    1760           0 :               spwResolOut[outChan] = 0.5 * (spwResolIn[inpChan] +
    1761           0 :                                             spwResolIn[lastChan])
    1762           0 :                                      + sep;
    1763             : 
    1764           0 :               for(Int avgChan = inpChan; avgChan <= lastChan;
    1765           0 :                   avgChan += chanStep_p[k])
    1766           0 :                 effBWOut[outChan] += effBWIn[avgChan];
    1767             :             }
    1768             :             else{
    1769          24 :               chanFreqOut[outChan] = chanFreqIn[inpChan];
    1770          24 :               spwResolOut[outChan] = spwResolIn[inpChan];
    1771          24 :               chanWidthOut[outChan] = chanWidthIn[inpChan];
    1772          24 :               effBWOut[outChan]    = effBWIn[inpChan];
    1773             :             }
    1774          24 :             totalBW += effBWOut[outChan];
    1775          24 :             ++outChan;
    1776             :           }
    1777             :         }
    1778           6 :         --outChan;
    1779             : 
    1780           6 :         msSpW.chanFreq().put(min_k, chanFreqOut);
    1781           6 :         msSpW.refFrequency().put(min_k, min(chanFreqOut[0],chanFreqOut[chanFreqOut.size()-1]));
    1782           6 :         msSpW.resolution().put(min_k, spwResolOut);
    1783           6 :         msSpW.numChan().put(min_k, nOutChan);
    1784           6 :         msSpW.chanWidth().put(min_k, chanWidthOut);
    1785           6 :         msSpW.effectiveBW().put(min_k, spwResolOut);
    1786           6 :         msSpW.totalBandwidth().put(min_k, totalBW);
    1787           6 :       }
    1788             :       else{
    1789         121 :         msSpW.chanFreq().put(min_k, inSpWCols.chanFreq()(spw_p[k]));
    1790         121 :         msSpW.refFrequency().put(min_k, inSpWCols.refFrequency()(spw_p[k]));
    1791         121 :         msSpW.resolution().put(min_k, inSpWCols.resolution()(spw_p[k]));
    1792         121 :         msSpW.numChan().put(min_k, inSpWCols.numChan()(spw_p[k]));    
    1793         121 :         msSpW.chanWidth().put(min_k, inSpWCols.chanWidth()(spw_p[k]));
    1794         121 :         msSpW.effectiveBW().put(min_k, inSpWCols.effectiveBW()(spw_p[k]));
    1795         121 :         msSpW.totalBandwidth().put(min_k, inSpWCols.totalBandwidth()(spw_p[k]));
    1796             :       }
    1797             :       
    1798         127 :       msSpW.flagRow().put(min_k, inSpWCols.flagRow()(spw_p[k]));
    1799         127 :       msSpW.freqGroup().put(min_k, inSpWCols.freqGroup()(spw_p[k]));
    1800         127 :       msSpW.freqGroupName().put(min_k, inSpWCols.freqGroupName()(spw_p[k]));
    1801         127 :       msSpW.ifConvChain().put(min_k, inSpWCols.ifConvChain()(spw_p[k]));
    1802         127 :       msSpW.measFreqRef().put(min_k, inSpWCols.measFreqRef()(spw_p[k]));
    1803         127 :       msSpW.name().put(min_k, inSpWCols.name()(spw_p[k]));
    1804         127 :       msSpW.netSideband().put(min_k, inSpWCols.netSideband()(spw_p[k]));
    1805         127 :       if(haveSpwAN)
    1806           5 :         msSpW.assocNature().put(min_k, inSpWCols.assocNature()(spw_p[k]));
    1807         127 :       if(haveSpwASI)
    1808           5 :         msSpW.assocSpwId().put(min_k, inSpWCols.assocSpwId()(spw_p[k]));
    1809         127 :       if(haveSpwBN)
    1810           5 :         msSpW.bbcNo().put(min_k, inSpWCols.bbcNo()(spw_p[k]));
    1811         127 :       if(haveSpwBS)
    1812           0 :         msSpW.bbcSideband().put(min_k, inSpWCols.bbcSideband()(spw_p[k]));
    1813         127 :       if(haveSpwDI)
    1814           2 :         msSpW.dopplerId().put(min_k, inSpWCols.dopplerId()(spw_p[k]));
    1815             : 
    1816         127 :       msDD.flagRow().put(min_k, false);
    1817         127 :       msDD.polarizationId().put(min_k, newPolId[min_k]);
    1818         127 :       msDD.spectralWindowId().put(min_k, min_k);
    1819             :     }
    1820          44 :     return true;
    1821          44 :   }
    1822             :   
    1823          44 :   Bool SubMS::fillFieldTable() 
    1824             :   {  
    1825          88 :     LogIO os(LogOrigin("SubMS", "fillFieldTable()"));
    1826             :     
    1827             :     //MSField fieldtable= mssel_p.field();
    1828             :     // optionalCols[0] = "EPHEMERIS_ID";
    1829          44 :     uInt nAddedCols = addOptionalColumns(mssel_p.field(), msOut_p.field(),
    1830             :                                          true);
    1831             : 
    1832          44 :     MSFieldColumns msField(msOut_p.field());
    1833             : 
    1834          44 :     const MSFieldColumns& fieldIn = mscIn_p->field(); 
    1835          44 :     ScalarColumn<String> code(fieldIn.code());
    1836          44 :     ArrayColumn<Double>  delayDir(fieldIn.delayDir());
    1837          44 :     ScalarColumn<Bool>   flagRow(fieldIn.flagRow());
    1838          44 :     ScalarColumn<String> name(fieldIn.name());
    1839          44 :     ScalarColumn<Int>    numPoly(fieldIn.numPoly());
    1840          44 :     ArrayColumn<Double>  phaseDir(fieldIn.phaseDir());
    1841          44 :     ArrayColumn<Double>  refDir(fieldIn.referenceDir());
    1842          44 :     ScalarColumn<Int>    sourceId(fieldIn.sourceId());
    1843          44 :     ScalarColumn<Double> time(fieldIn.time());
    1844             :     
    1845          44 :     String refstr;
    1846          44 :     String nameVarRefColDelayDir, nameVarRefColPhaseDir, nameVarRefColRefDir;
    1847             : 
    1848             :     // Need to correctly define the direction measures.
    1849             :     // DelayDir
    1850          44 :     if(delayDir.keywordSet().asRecord("MEASINFO").isDefined("Ref")){
    1851          42 :       delayDir.keywordSet().asRecord("MEASINFO").get("Ref", refstr);
    1852             :       //  MDirection::getType(dir1, refstr);
    1853          42 :       msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").define("Ref",refstr);
    1854             :     }
    1855          44 :     if(delayDir.keywordSet().asRecord("MEASINFO").isDefined("VarRefCol")){ // it's a variable ref. column
    1856           2 :       delayDir.keywordSet().asRecord("MEASINFO").get("VarRefCol", refstr);
    1857           2 :       msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").define("VarRefCol",refstr);
    1858           2 :       nameVarRefColDelayDir = refstr;
    1859           2 :       Vector<String> refTypeV;
    1860           2 :       delayDir.keywordSet().asRecord("MEASINFO").get("TabRefTypes", refTypeV);
    1861           2 :       msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefTypes",refTypeV);      
    1862           2 :       Vector<uInt> refCodeV;
    1863           2 :       delayDir.keywordSet().asRecord("MEASINFO").get("TabRefCodes", refCodeV);
    1864           2 :       msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefCodes",refCodeV);      
    1865           2 :       Int refid=msField.delayDir().keywordSet().asRecord("MEASINFO").fieldNumber("Ref");
    1866           2 :       if(refid>=0){ // erase the redundant Ref keyword
    1867           2 :         msField.delayDir().rwKeywordSet().asrwRecord("MEASINFO").removeField(RecordFieldId(refid));
    1868             :       }
    1869           2 :     }
    1870             :     // PhaseDir
    1871          44 :     if(phaseDir.keywordSet().asRecord("MEASINFO").isDefined("Ref")){
    1872          42 :       phaseDir.keywordSet().asRecord("MEASINFO").get("Ref", refstr);
    1873          42 :       msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").define("Ref", refstr);
    1874             :     }
    1875          44 :     if(phaseDir.keywordSet().asRecord("MEASINFO").isDefined("VarRefCol")){ // it's a variable ref. column
    1876           2 :       phaseDir.keywordSet().asRecord("MEASINFO").get("VarRefCol", refstr);
    1877           2 :       msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").define("VarRefCol",refstr);
    1878           2 :       nameVarRefColPhaseDir = refstr;
    1879           2 :       Vector<String> refTypeV;
    1880           2 :       phaseDir.keywordSet().asRecord("MEASINFO").get("TabRefTypes", refTypeV);
    1881           2 :       msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefTypes",refTypeV);      
    1882           2 :       Vector<uInt> refCodeV;
    1883           2 :       phaseDir.keywordSet().asRecord("MEASINFO").get("TabRefCodes", refCodeV);
    1884           2 :       msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefCodes",refCodeV);      
    1885           2 :       Int refid=msField.phaseDir().keywordSet().asRecord("MEASINFO").fieldNumber("Ref");
    1886           2 :       if(refid>=0){
    1887           2 :         msField.phaseDir().rwKeywordSet().asrwRecord("MEASINFO").removeField(RecordFieldId(refid));
    1888             :       }
    1889           2 :     }
    1890             :     // ReferenceDir
    1891          44 :     if(refDir.keywordSet().asRecord("MEASINFO").isDefined("Ref")){
    1892          42 :       refDir.keywordSet().asRecord("MEASINFO").get("Ref", refstr);
    1893          42 :       msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").define("Ref",refstr);
    1894             :     }
    1895          44 :     if(refDir.keywordSet().asRecord("MEASINFO").isDefined("VarRefCol")){ // it's a variable ref. column
    1896           2 :       refDir.keywordSet().asRecord("MEASINFO").get("VarRefCol", refstr);
    1897           2 :       msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").define("VarRefCol",refstr);
    1898           2 :       nameVarRefColRefDir = refstr;
    1899           2 :       Vector<String> refTypeV;
    1900           2 :       refDir.keywordSet().asRecord("MEASINFO").get("TabRefTypes", refTypeV);
    1901           2 :       msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefTypes",refTypeV);      
    1902           2 :       Vector<uInt> refCodeV;
    1903           2 :       refDir.keywordSet().asRecord("MEASINFO").get("TabRefCodes", refCodeV);
    1904           2 :       msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").define("TabRefCodes",refCodeV);
    1905           2 :       Int refid=msField.referenceDir().keywordSet().asRecord("MEASINFO").fieldNumber("Ref");
    1906           2 :       if(refid>=0){
    1907           2 :         msField.referenceDir().rwKeywordSet().asrwRecord("MEASINFO").removeField(RecordFieldId(refid));
    1908             :       }
    1909           2 :     }
    1910             : 
    1911             :     // ...and the time measure...
    1912          44 :     time.keywordSet().asRecord("MEASINFO").get("Ref", refstr);
    1913          44 :     msField.time().rwKeywordSet().asrwRecord("MEASINFO").define("Ref", refstr);
    1914             : 
    1915             :     // fieldRelabel_p size: nrow of a input MS, -1 for unselected field ids 
    1916          44 :     fieldRelabel_p.resize(mscIn_p->field().nrow());
    1917          44 :     fieldRelabel_p.set(-1);
    1918             : 
    1919             :     os << LogIO::DEBUG1
    1920             :        << fieldid_p.nelements() << " fields selected out of "
    1921          44 :        << mscIn_p->field().nrow()
    1922          44 :        << LogIO::POST;
    1923             : 
    1924             :     try{
    1925          44 :       msOut_p.field().addRow(fieldid_p.nelements());
    1926         153 :       for(uInt k = 0; k < fieldid_p.nelements(); ++k){
    1927         109 :         fieldRelabel_p[fieldid_p[k]] = k;
    1928             :       
    1929         109 :         msField.code().put(k, code(fieldid_p[k]));
    1930         109 :         msField.delayDir().put(k, delayDir(fieldid_p[k]));
    1931         109 :         msField.flagRow().put(k, flagRow(fieldid_p[k]));
    1932         109 :         msField.name().put(k, name(fieldid_p[k]));
    1933         109 :         msField.numPoly().put(k, numPoly(fieldid_p[k]));
    1934         109 :         msField.phaseDir().put(k, phaseDir(fieldid_p[k]));
    1935         109 :         msField.referenceDir().put(k, refDir(fieldid_p[k]));
    1936         109 :         msField.time().put(k, time(fieldid_p[k]));
    1937             : 
    1938         109 :         Int inSrcID = sourceId(fieldid_p[k]);
    1939         109 :         if(inSrcID < 0)
    1940           9 :           msField.sourceId().put(k, -1);
    1941             :         else
    1942         100 :           msField.sourceId().put(k, sourceRelabel_p[inSrcID]);
    1943             :       }
    1944             : 
    1945          44 :       if(nAddedCols > 0){
    1946             : 
    1947           2 :         ScalarColumn<Int> eID(fieldIn.ephemerisId());
    1948           2 :         if(eID.hasContent()){
    1949           1 :           String destPathName = Path(msOut_p.field().tableName()).absoluteName();
    1950           9 :           for(uInt k = 0; k < fieldid_p.nelements(); ++k){
    1951             : 
    1952           8 :             Int theEphId = eID(fieldid_p[k]);
    1953             : 
    1954           8 :             if(theEphId>-1){ // there is an ephemeris attached to this field
    1955           0 :               Path ephPath = Path(fieldIn.ephemPath(fieldid_p[k]));
    1956           0 :               if(ephPath.length()>0){ // copy the ephemeris table over to the output FIELD table
    1957           0 :                 Directory origEphemDir(ephPath);
    1958           0 :                 origEphemDir.copy(destPathName+"/"+ephPath.baseName());
    1959           0 :                 os << LogIO::NORMAL << "Transferring ephemeris " << ephPath.baseName() 
    1960           0 :                    << " for output field " << name(fieldid_p[k]) << LogIO::POST;
    1961           0 :               }
    1962           0 :             } 
    1963           8 :             msField.ephemerisId().put(k, theEphId);
    1964             :           }
    1965           1 :         }
    1966             : 
    1967           2 :         if(!nameVarRefColDelayDir.empty()){ // need to copy the reference column
    1968           2 :           ScalarColumn<Int>  dM(mssel_p.field(), nameVarRefColDelayDir);
    1969           2 :           ScalarColumn<Int> cdMDirRef(msOut_p.field(), nameVarRefColDelayDir);
    1970          11 :           for(uInt k = 0; k < fieldid_p.nelements(); ++k){
    1971           9 :             cdMDirRef.put(k, dM(fieldid_p[k]));
    1972             :           }
    1973           2 :         }
    1974           2 :         if(!nameVarRefColPhaseDir.empty()){ // need to copy the reference column
    1975           2 :           ScalarColumn<Int>  dM(mssel_p.field(), nameVarRefColPhaseDir);
    1976           2 :           ScalarColumn<Int> cdMDirRef(msOut_p.field(), nameVarRefColPhaseDir);
    1977          11 :           for(uInt k = 0; k < fieldid_p.nelements(); ++k){
    1978           9 :             cdMDirRef.put(k, dM(fieldid_p[k]));
    1979             :           }
    1980           2 :         }
    1981           2 :         if(!nameVarRefColRefDir.empty()){ // need to copy the reference column
    1982           2 :           ScalarColumn<Int>  dM(mssel_p.field(), nameVarRefColRefDir);
    1983           2 :           ScalarColumn<Int> cdMDirRef(msOut_p.field(), nameVarRefColRefDir);
    1984          11 :           for(uInt k = 0; k < fieldid_p.nelements(); ++k){
    1985           9 :             cdMDirRef.put(k, dM(fieldid_p[k]));
    1986             :           }
    1987           2 :         }
    1988           2 :       }
    1989             : 
    1990             :     }
    1991           0 :     catch(AipsError x){
    1992             :       os << LogIO::EXCEPTION
    1993             :          << "Error " << x.getMesg() << " setting up the output FIELD table."
    1994           0 :          << LogIO::POST;
    1995           0 :     }
    1996           0 :     catch(...){
    1997           0 :       throw(AipsError("Unknown exception caught and released in fillFieldTable()"));
    1998           0 :     }
    1999             :     
    2000          44 :     return true;    
    2001          44 :   }
    2002             : 
    2003             :   // Sets up sourceRelabel_p for mapping input SourceIDs (if any) to output
    2004             :   // ones.  Must be called after fieldid_p is set and before calling
    2005             :   // fillFieldTable() or copySource().
    2006          44 :   void SubMS::relabelSources()
    2007             :   {
    2008          88 :     LogIO os(LogOrigin("SubMS", "relabelSources()"));
    2009             : 
    2010             :     //Source is an optional table, so it may not exist
    2011          44 :     if(Table::isReadable(mssel_p.sourceTableName())){
    2012             :       // Note that mscIn_p->field().sourceId() has ALL of the sourceIDs in
    2013             :       // the input MS, not just the selected ones.
    2014          44 :       const Vector<Int>& inSrcIDs = mscIn_p->field().sourceId().getColumn();
    2015             : 
    2016          44 :       Int highestInpSrc = max(inSrcIDs);
    2017             :     
    2018          44 :       if(highestInpSrc < 0)                   // Ensure space for -1.
    2019           8 :         highestInpSrc = 0;
    2020          44 :       sourceRelabel_p.resize(highestInpSrc + 1);
    2021          44 :       sourceRelabel_p.set(-1);                    // Default to "any".
    2022             : 
    2023             :       // Enable sourceIDs that are actually referred to by selected fields, and
    2024             :       // remap them using j.
    2025          44 :       uInt j = 0;
    2026         153 :       for(uInt k = 0; k < fieldid_p.nelements(); ++k){
    2027         109 :         Int fldInSrcID = inSrcIDs[fieldid_p[k]];
    2028             :         
    2029         109 :         if(fldInSrcID > -1){
    2030         100 :           if(sourceRelabel_p[fldInSrcID] == -1){ // Multiple fields can use the same
    2031         100 :             sourceRelabel_p[fldInSrcID] = j;     // source in a mosaic.
    2032         100 :             ++j;
    2033             :           }
    2034             :         }
    2035             :       }
    2036          44 :     }
    2037             :     else{
    2038             :       os << LogIO::NORMAL
    2039             :          << "The input MS does not have the optional SOURCE table.\n"
    2040             :          << "-1 will be used as a generic source ID."
    2041           0 :          << LogIO::POST;
    2042           0 :       sourceRelabel_p.resize(1);
    2043           0 :       sourceRelabel_p.set(-1);                    // Default to "any".      
    2044             :     }
    2045          44 :   }
    2046             : 
    2047             :   // This method is currently not called in SubMS.  It should really be called
    2048             :   // in setupMS, but that has been made into a static method and it cannot be
    2049             :   // called there.  The ms argument is unused, but it is there to preserve the
    2050             :   // signature, and is commented to prevent a compiler warning.
    2051             :   //
    2052           0 :   void SubMS::verifyColumns(const MeasurementSet&, // ms,
    2053             :                             const Vector<MS::PredefinedColumns>& colNames)
    2054             :   {
    2055           0 :     LogIO os(LogOrigin("SubMS", "verifyColumns()"));
    2056           0 :     for(uInt i=0;i<colNames.nelements();i++)
    2057           0 :       if (!ms_p.tableDesc().isColumn(MS::columnName(colNames[i])))
    2058             :         {
    2059           0 :           ostringstream ostr;
    2060           0 :           ostr << "Desired column (" << MS::columnName(colNames[i])
    2061           0 :                << ") not found in the input MS (" << ms_p.tableName() << ").";
    2062           0 :           throw(AipsError(ostr.str()));
    2063           0 :         }
    2064           0 :   }
    2065             : 
    2066          54 :   Int SubMS::regridSpw(String& regridMessage,
    2067             :                        const String& outframe,
    2068             :                        const String& regridQuant,
    2069             :                        const Double regridVeloRestfrq,
    2070             :                        const String& regridInterpMeth,
    2071             :                        const Double regridCenter, 
    2072             :                        const Double regridBandwidth, 
    2073             :                        const Double regridChanWidth,
    2074             :                        const Bool doHanningSmooth,
    2075             :                        const Int phaseCenterFieldId,
    2076             :                        MDirection phaseCenter,
    2077             :                        const Bool centerIsStart,
    2078             :                        const Bool startIsEnd,
    2079             :                        const Int nchan,
    2080             :                        const Int width,
    2081             :                        const Int start
    2082             :                   ){
    2083             :     
    2084         108 :     LogIO os(LogOrigin("SubMS", "regridSpw()"));
    2085             : 
    2086          54 :     Int rval = -1; // return values: -1 = MS not modified, 1 = MS modified and OK, 
    2087             :                    // 0 = MS modified but not OK 
    2088             : 
    2089             :     // get the original table description of the MS 
    2090          54 :     TableDesc origMSTD(ms_p.actualTableDesc());
    2091          88 :     if(!origMSTD.isColumn("CORRECTED_DATA") &&  !origMSTD.isColumn("DATA") 
    2092          88 :        && !origMSTD.isColumn("FLOAT_DATA") && !origMSTD.isColumn("MODEL_DATA")){ 
    2093           0 :       os << LogIO::WARN << "MS has no DATA columns. Nothing to regrid." << LogIO::POST;
    2094             :     }     
    2095             : 
    2096             :     // Set up a little database to keep track of which pairs (FieldId, SPWId) have already
    2097             :     // been dealt with and what parameters were used
    2098             : 
    2099          54 :     vector<Int> oldSpwId;
    2100          54 :     vector<Int> oldFieldId;
    2101          54 :     vector<Int> newDataDescId;
    2102          54 :     vector<Bool> regrid;
    2103          54 :     vector<Bool> transform;
    2104          54 :     vector<MDirection> theFieldDirV;
    2105          54 :     vector<MPosition> mObsPosV;
    2106          54 :     vector<MFrequency::Types> fromFrameTypeV; // original ref frame of the SPW
    2107          54 :     vector<MFrequency::Ref> outFrameV; // new ref frame
    2108          54 :     vector<MRadialVelocity> outRadVelV; // radial velocity correction applied to the new ref frame
    2109          54 :     vector<Double> weightScaleV; // the scaling factor for the WEIGHTs
    2110          54 :     vector< Vector<Double> > xold; // the frequencies of the original SPW in the old ref frame
    2111          54 :     vector< Vector<Double> > xout; // the frequencies of the new SPW in the new ref frame
    2112          54 :     vector< Vector<Double> > xin;  // the frequencies of the old SPW in the new ref frame
    2113          54 :     vector< Int > method; // interpolation method cast to Int
    2114             :     
    2115             : 
    2116          54 :     Bool msModified = false;
    2117             : 
    2118          54 :     String oframe = outframe;
    2119          54 :     oframe.upcase();
    2120          54 :     Bool doRadVelCorr = (oframe=="SOURCE");
    2121             : 
    2122             :     // Loop 1: Verify the input parameters, no modification of the MS
    2123          54 :     if(!setRegridParameters(oldSpwId,
    2124             :                             oldFieldId,
    2125             :                             newDataDescId,
    2126             :                             regrid,
    2127             :                             transform,
    2128             :                             theFieldDirV,
    2129             :                             mObsPosV,
    2130             :                             fromFrameTypeV,
    2131             :                             outFrameV,
    2132             :                             outRadVelV,
    2133             :                             weightScaleV,
    2134             :                             xold,
    2135             :                             xout, 
    2136             :                             xin, 
    2137             :                             method,
    2138             :                             msModified,
    2139             :                             outframe,
    2140             :                             regridQuant,
    2141             :                             regridVeloRestfrq,
    2142             :                             regridInterpMeth,
    2143             :                             regridCenter,
    2144             :                             regridBandwidth, 
    2145             :                             regridChanWidth,
    2146             :                             phaseCenterFieldId,
    2147             :                             phaseCenter,
    2148             :                             false, // <-----
    2149             :                             os,
    2150             :                             regridMessage,
    2151             :                             centerIsStart,
    2152             :                             startIsEnd,
    2153             :                             nchan,
    2154             :                             width,
    2155             :                             start
    2156             :                             )){ // an error occured
    2157           1 :       return -1;
    2158             :     }
    2159             : 
    2160          53 :     if(oframe=="SOURCE" || oframe=="GEO"){
    2161             :       os << LogIO::NORMAL
    2162             :          << "Note: with outframe==GEO or outframe==SOURCE, the resulting spectral windows with be labeled as having reference frame REST.\n"
    2163             :          << "      All integrations will be Doppler-tracked to correspond to the GEO frame at the beginning of the observation\n"
    2164             :          << "      (with radial velocity corrections in the case of outframe==SOURCE).\n"
    2165             :          << "      No subsequent regridding to other reference frames will be possible."
    2166           3 :          << LogIO::POST;
    2167             :     }
    2168             : 
    2169          53 :     vector<Double> sigmaScaleV(weightScaleV.size());
    2170         106 :     for(uInt i=0; i<weightScaleV.size(); i++){
    2171          53 :       if(weightScaleV[i]<=0.){
    2172           0 :         os << LogIO::WARN << "Internal error: Encountered non-positive weight scaling factor " << weightScaleV[i] <<endl
    2173           0 :            << "Aborting." << LogIO::POST;
    2174           0 :         return -1;
    2175             :       }
    2176          53 :       else if(doHanningSmooth){
    2177           3 :         weightScaleV[i] *= 1.32;
    2178             :       }
    2179          53 :       sigmaScaleV[i] = 1./sqrt(weightScaleV[i]);
    2180             :     }
    2181             : 
    2182             :     // Loop 2: Write modified DD, SPW, and SOURCE tables
    2183             : 
    2184          53 :     if(!setRegridParameters(oldSpwId,
    2185             :                             oldFieldId,
    2186             :                             newDataDescId,
    2187             :                             regrid,
    2188             :                             transform,
    2189             :                             theFieldDirV,
    2190             :                             mObsPosV,
    2191             :                             fromFrameTypeV,
    2192             :                             outFrameV,
    2193             :                             outRadVelV,
    2194             :                             weightScaleV,
    2195             :                             xold,
    2196             :                             xout, 
    2197             :                             xin, 
    2198             :                             method,
    2199             :                             msModified,
    2200             :                             outframe,
    2201             :                             regridQuant,
    2202             :                             regridVeloRestfrq,
    2203             :                             regridInterpMeth,
    2204             :                             regridCenter,
    2205             :                             regridBandwidth, 
    2206             :                             regridChanWidth,
    2207             :                             phaseCenterFieldId,
    2208             :                             phaseCenter,
    2209             :                             true, // <-----
    2210             :                             os,
    2211             :                             regridMessage,
    2212             :                             centerIsStart,
    2213             :                             startIsEnd,
    2214             :                             nchan,
    2215             :                             width,
    2216             :                             start
    2217             :                             )){ // an error occured
    2218           0 :       if(msModified){
    2219           0 :         return 0;
    2220             :       }
    2221             :       else{
    2222           0 :         return -1;
    2223             :       }
    2224             :     }
    2225             :     
    2226          53 :     if(!msModified){ // nothing to be done in terms of regridding
    2227           8 :       if(doHanningSmooth){ // but we still need to Hanning smooth
    2228           1 :         os << LogIO::NORMAL << "Hanning smoothing not applied in regridding step since no regridding was necessary." <<  LogIO::POST;
    2229             :       }
    2230           8 :       return -1;
    2231             :     }
    2232             :     
    2233             :     // now we need to modify the main table ...
    2234             : 
    2235          45 :     Bool needRegridding = false;
    2236          90 :     for(uInt i=0; i<regrid.size(); i++){
    2237          45 :       if(regrid[i]){
    2238          45 :         needRegridding = true;
    2239             :       }
    2240             :     }
    2241             : 
    2242          45 :     if(needRegridding){
    2243             : 
    2244          45 :       os << LogIO::NORMAL << "Main table data array columns will be rewritten." <<  LogIO::POST;        
    2245             : 
    2246             :       // create the "partner" columns, i.e. rename the old array columns to old...
    2247             :       // and create new empty columns with the original names to hold the regridded values
    2248             : 
    2249          45 :       MSMainColumns mCols(ms_p);
    2250          45 :       Int nCorr = mCols.data().shape(0)(0); // the first dimension of DATA
    2251          45 :       IPosition dataShape(2, nCorr, xout[0].size());
    2252          45 :       Int obstype = 0; // default
    2253          45 :       MSObservationColumns obsCols(ms_p.observation());
    2254          45 :       String telescop = obsCols.telescopeName()(mCols.observationId()(0));
    2255          45 :       IPosition tileShape = MSTileLayout::tileShape(dataShape, obstype, telescop);
    2256             : 
    2257          45 :       createPartnerColumn(origMSTD, "CORRECTED_DATA", "oldCORRECTED_DATA", 3, tileShape);
    2258          45 :       createPartnerColumn(origMSTD, "DATA", "oldDATA", 3, tileShape);
    2259          45 :       createPartnerColumn(origMSTD, "FLOAT_DATA", "oldFLOAT_DATA", 3, tileShape);
    2260          45 :       createPartnerColumn(origMSTD, "LAG_DATA", "oldLAG_DATA", 3, tileShape);
    2261          45 :       createPartnerColumn(origMSTD, "MODEL_DATA", "oldMODEL_DATA", 3, tileShape);
    2262          45 :       createPartnerColumn(origMSTD, "SIGMA_SPECTRUM", "oldSIGMA_SPECTRUM", 3, tileShape);
    2263          45 :       createPartnerColumn(origMSTD, "WEIGHT_SPECTRUM", "oldWEIGHT_SPECTRUM", 3, tileShape);
    2264          45 :       createPartnerColumn(origMSTD, "FLAG", "oldFLAG", 3, tileShape);
    2265             : 
    2266          45 :       createPartnerColumn(origMSTD, "FLAG_CATEGORY", "oldFLAG_CATEGORY", 4,
    2267          90 :                           IPosition(4,tileShape(0),tileShape(1),1, tileShape(2)));
    2268          45 :     }
    2269             : 
    2270          45 :     MSMainColumns mainCols(ms_p);
    2271             : 
    2272             :     // columns which depend on the number of frequency channels and may need to be regridded:
    2273             :     // DATA, FLOAT_DATA, CORRECTED_DATA, MODEL_DATA, LAG_DATA, SIGMA_SPECTRUM,
    2274             :     // WEIGHT_SPECTRUM, FLAG, and FLAG_CATEGORY    
    2275          45 :     ArrayColumn<Complex> CORRECTED_DATACol =  mainCols.correctedData();
    2276          45 :     ArrayColumn<Complex>* oldCORRECTED_DATAColP  = 0;
    2277          45 :     ArrayColumn<Complex>  DATACol =  mainCols.data();
    2278          45 :     ArrayColumn<Complex>* oldDATAColP = 0;
    2279          45 :     ArrayColumn<Float> FLOAT_DATACol =  mainCols.floatData();
    2280          45 :     ArrayColumn<Float>* oldFLOAT_DATAColP = 0;
    2281          45 :     ArrayColumn<Complex> LAG_DATACol =  mainCols.lagData();
    2282          45 :     ArrayColumn<Complex>* oldLAG_DATAColP = 0;
    2283          45 :     ArrayColumn<Complex> MODEL_DATACol =  mainCols.modelData();
    2284          45 :     ArrayColumn<Complex>* oldMODEL_DATAColP = 0;
    2285          45 :     ArrayColumn<Float> SIGMA_SPECTRUMCol =  mainCols.sigmaSpectrum();
    2286          45 :     ArrayColumn<Float>* oldSIGMA_SPECTRUMColP = 0;
    2287          45 :     ArrayColumn<Float> WEIGHT_SPECTRUMCol =  mainCols.weightSpectrum();
    2288          45 :     ArrayColumn<Float>* oldWEIGHT_SPECTRUMColP = 0;
    2289          45 :     ArrayColumn<Bool> FLAGCol =  mainCols.flag();
    2290          45 :     ArrayColumn<Bool>* oldFLAGColP = 0;
    2291          45 :     ArrayColumn<Bool> FLAG_CATEGORYCol =  mainCols.flagCategory();
    2292          45 :     ArrayColumn<Bool>* oldFLAG_CATEGORYColP = 0;
    2293             : 
    2294             :     // WEIGHT and SIGMA will possibly need to be modified (these are also arrays but only for corr. product)
    2295          45 :     ArrayColumn<Float> SIGMACol = mainCols.sigma();
    2296          45 :     ArrayColumn<Float> WEIGHTCol = mainCols.weight();
    2297             : 
    2298          45 :     if(needRegridding){
    2299             : 
    2300          45 :       if(doHanningSmooth){
    2301           2 :         os << LogIO::NORMAL << "The following columns will be Hanning-smoothed before regridding: " <<  LogIO::POST;
    2302           2 :         if(!DATACol.isNull()){
    2303           2 :           os << LogIO::NORMAL << " DATA ";
    2304             :         }
    2305           2 :         if(!CORRECTED_DATACol.isNull()){
    2306           2 :           os << LogIO::NORMAL << " CORRECTED_DATA " <<  LogIO::POST;
    2307             :         }
    2308           2 :         if(!LAG_DATACol.isNull()){
    2309           0 :           os << LogIO::NORMAL << " LAG_DATA ";
    2310             :         }
    2311           2 :         if(!FLOAT_DATACol.isNull()){
    2312           0 :           os << LogIO::NORMAL << " FLOAT_DATA ";
    2313             :         }
    2314           2 :         os << LogIO::POST;
    2315             :       }
    2316             : 
    2317             :       // (create column objects for all "partners" of the array columns to be modified)
    2318          45 :       if(!CORRECTED_DATACol.isNull()){
    2319          18 :         oldCORRECTED_DATAColP = new ArrayColumn<Complex>(ms_p, "oldCORRECTED_DATA");
    2320             :       }
    2321          45 :       if(!DATACol.isNull()){
    2322          45 :         oldDATAColP = new ArrayColumn<Complex>(ms_p, "oldDATA");
    2323             :       }
    2324          45 :       if(!FLOAT_DATACol.isNull()){
    2325           0 :         oldFLOAT_DATAColP = new ArrayColumn<Float>(ms_p, "oldFLOAT_DATA");
    2326             :       }
    2327          45 :       if(!LAG_DATACol.isNull()){
    2328           0 :         oldLAG_DATAColP = new ArrayColumn<Complex>(ms_p, "oldLAG_DATA");
    2329             :       }
    2330          45 :       if(!MODEL_DATACol.isNull()){
    2331          17 :         oldMODEL_DATAColP = new ArrayColumn<Complex>(ms_p, "oldMODEL_DATA");
    2332             :       }
    2333          45 :       if(!SIGMA_SPECTRUMCol.isNull()){
    2334           2 :         oldSIGMA_SPECTRUMColP = new ArrayColumn<Float>(ms_p, "oldSIGMA_SPECTRUM");
    2335             :       }
    2336          45 :       if(!WEIGHT_SPECTRUMCol.isNull()){
    2337          45 :         oldWEIGHT_SPECTRUMColP = new ArrayColumn<Float>(ms_p, "oldWEIGHT_SPECTRUM");
    2338             :       }
    2339          45 :       if(!FLAGCol.isNull()){
    2340          45 :         oldFLAGColP = new ArrayColumn<Bool>(ms_p, "oldFLAG"); 
    2341             :       }
    2342          45 :       if(!FLAG_CATEGORYCol.isNull()){
    2343          45 :         oldFLAG_CATEGORYColP = new ArrayColumn<Bool>(ms_p, "oldFLAG_CATEGORY");
    2344             :       }
    2345             :     } // end if needRegridding
    2346             : 
    2347             :     // administrational columns needed from the main table
    2348          45 :     ScalarColumn<Int> fieldIdCol = mainCols.fieldId();
    2349          45 :     ScalarColumn<Int> DDIdCol = mainCols.dataDescId();
    2350          45 :     ScalarMeasColumn<MEpoch> mainTimeMeasCol = mainCols.timeMeas();
    2351             :    
    2352             :     // columns needed from subtables
    2353          45 :     MSDataDescription ddtable=ms_p.dataDescription();
    2354          45 :     MSDataDescColumns DDCols(ddtable);
    2355          45 :     ScalarColumn<Int> SPWIdCol = DDCols.spectralWindowId(); 
    2356          45 :     MSFieldColumns fldCols(ms_p.field());
    2357             : 
    2358             :     // Loop 3: Apply to MAIN table rows
    2359             :     
    2360             :     //    cout << "Modifying main table ..." << endl;
    2361             : 
    2362          45 :     uInt nMainTabRows = ms_p.nrow();
    2363             : 
    2364             :     // create time-sorted index for main table access
    2365          45 :     Vector<uInt> sortedI(nMainTabRows);
    2366             : 
    2367          45 :     Vector<Double> mainTimesV = mainCols.time().getColumn();
    2368          45 :     GenSortIndirect<Double>::sort(sortedI,mainTimesV);
    2369             : 
    2370             :     // prepare progress meter
    2371          45 :     Float progress = 0.2;
    2372          45 :     Float progressStep = 0.2;
    2373          45 :     if(ms_p.nrow()>100000){
    2374           0 :       progress = 0.1;
    2375           0 :       progressStep = 0.1;
    2376             :     }
    2377             : 
    2378             :     // prepare some regridding prerequisites
    2379          45 :     FFTServer<Float, Complex> fFFTServer; // for fftshift, if needed
    2380             :  
    2381             :     // start loop over main table
    2382      427358 :     for(uInt mainTabRowI=0; mainTabRowI<nMainTabRows; mainTabRowI++){
    2383             :       
    2384      427313 :       uInt mainTabRow = sortedI(mainTabRowI); // i.e. mainTabRow is sorted in time
    2385             : 
    2386             :       //if(mainTabRow!=mainTabRowI){
    2387             :       //  cout << "processing row " << mainTabRow << ", index " << mainTabRowI << endl;
    2388             :       //}
    2389             : 
    2390             :       // For each MAIN table row, the FIELD_ID cell and the DATA_DESC_ID cell are read 
    2391      427313 :       Int theFieldId = fieldIdCol(mainTabRow);
    2392      427313 :       Int theDataDescId = DDIdCol(mainTabRow);
    2393             :       // and the SPW_ID extracted from the corresponding row in the DATA_DESCRIPTION table.
    2394      427313 :       Int theSPWId = SPWIdCol(theDataDescId);
    2395             : 
    2396      427313 :       MEpoch theObsTime = mainTimeMeasCol(mainTabRow);
    2397             :       
    2398             :       //  The pair (theFieldId, theSPWId) is looked up in the "done table". 
    2399      427313 :       Int iDone = -1;
    2400      427313 :       for (uInt i=0; i<oldSpwId.size(); i++){
    2401      427313 :         if(oldSpwId[i]==theSPWId && (oldFieldId[i]==theFieldId || phaseCenterFieldId>=-1)){
    2402             :           // if common phase center is given, treat all fields the same
    2403      427313 :           iDone = i;
    2404      427313 :           break;
    2405             :         }
    2406             :       }
    2407      427313 :       if(iDone<0){ // should not occur
    2408             :         os << LogIO::SEVERE << "Internal error: Did not find regrid parameters for field ==" 
    2409           0 :            << theFieldId << " spw ==" <<  theSPWId << LogIO::POST;
    2410           0 :         return 0;
    2411             :       }
    2412             :       
    2413             :       
    2414      427313 :       if (DDIdCol(mainTabRow)!=newDataDescId[iDone]){
    2415             :         // If the data description actually changed, then DATA_DESC_ID 
    2416             :         //      of this main table row is set to the new value given in the "done" table
    2417           0 :         DDIdCol.put(mainTabRow, newDataDescId[iDone]);
    2418             :         
    2419             :       }
    2420             :       
    2421             :       //Furthermore, if regrid[iDone] is true, the visibilities and all 
    2422             :       // channel-number-dependent arrays need to be regridded.
    2423      427313 :       if(regrid[iDone]){
    2424             : 
    2425      427313 :         Bool doExtrapolate = false;
    2426             : 
    2427             :         // regrid the complex columns
    2428      427313 :         Array<Complex> yout;
    2429      427313 :         Array<Bool> youtFlags;
    2430      427313 :         Bool youtFlagsWritten(false);
    2431      427313 :         Array<Complex> yin;
    2432      427313 :         Array<Bool> yinFlags((*oldFLAGColP)(mainTabRow));
    2433      427313 :         Array<Bool> yinFlagsUnsmoothed;
    2434      427313 :         Array<Complex> yinIntermediate;
    2435      427313 :         Array<Bool> yinFlagsIntermediate;
    2436      427313 :         if(doHanningSmooth){
    2437         660 :           yinFlagsUnsmoothed.assign(yinFlags);
    2438             :         }
    2439             : 
    2440      427313 :         Vector<Double> xindd(xold[iDone].size());
    2441      427313 :         Double theShift = 0.;
    2442             : 
    2443      427313 :         if(transform[iDone]){
    2444             : 
    2445             :           // create frequency machine for this time stamp
    2446      115999 :           MDirection fldDir = fldCols.phaseDirMeas(theFieldId, mainTimesV(mainTabRow));
    2447             : 
    2448             : 
    2449      115999 :           MFrequency::Ref fromFrame = MFrequency::Ref(fromFrameTypeV[iDone], MeasFrame(fldDir, mObsPosV[iDone], theObsTime));
    2450      115999 :           Unit unit(String("Hz"));
    2451      115999 :           MFrequency::Convert freqTrans2(unit, fromFrame, outFrameV[iDone]);
    2452             : 
    2453      115999 :           MDoppler radVelCorr; // no correction
    2454      115999 :           Bool radVelSignificant = false;
    2455             : 
    2456             :           // prepare correction for radial velocity if requested and possible
    2457      115999 :           if(doRadVelCorr && fldCols.needInterTime(theFieldId)){
    2458       58741 :             MRadialVelocity mRV = fldCols.radVelMeas(theFieldId, mainTimesV(mainTabRow));
    2459       58741 :             MRadialVelocity::Ref mRVR = mRV.getRef();
    2460       58741 :             if(mRVR.getType() == MRadialVelocity::GEO){
    2461       58741 :               Quantity mrv = mRV.get("m/s");
    2462       58741 :               Quantity offsetMrv = outRadVelV[iDone].get("m/s"); // the radvel by which the out SPW def was shifted 
    2463       58741 :               radVelCorr = MDoppler(mrv-(2.*offsetMrv)); 
    2464       58741 :               if(fabs(mrv.getValue())>1E-6){
    2465       58741 :                 radVelSignificant = true;
    2466             :               }
    2467       58741 :             }
    2468             :             else{
    2469             :               os << LogIO::SEVERE << "Cannot perform radial velocity correction with ephemerides of type "  
    2470           0 :                  << MRadialVelocity::showType(mRVR.getType()) << ".\nType needs to be GEO." << LogIO::POST;
    2471           0 :               return 0;
    2472             :             }
    2473       58741 :           } 
    2474             :         
    2475             :           // prepare fftshift if necessary
    2476      115999 :           if(method[iDone]==(Int)useFFTShift || method[iDone]==(Int)useLinIntThenFFTShift){
    2477         990 :             uInt centerChan = xold[iDone].size()/2;
    2478         990 :             Vector<Double> newFreq(1);
    2479         990 :             newFreq[0] = freqTrans2(xold[iDone][centerChan]).get(unit).getValue();
    2480         990 :             if(radVelSignificant){
    2481           0 :               newFreq = radVelCorr.shiftFrequency(newFreq);
    2482             :             }
    2483             : 
    2484         990 :             theShift = newFreq[0] - xin[iDone][centerChan];
    2485             : 
    2486             :             //cout << "the shift " << theShift << endl;
    2487      254430 :             for(uInt i=0; i<xin[iDone].size(); i++){ // cannot use assign due to different data type
    2488      253440 :               xindd[i] = xin[iDone][i];
    2489             :             }
    2490         990 :           }
    2491             :           else{
    2492             :             // transform from this timestamp to the one of the output SPW
    2493     3062663 :             for(uInt i=0; i<xindd.size(); i++){
    2494     2947654 :               xindd[i] = freqTrans2(xold[iDone][i]).get(unit).getValue();
    2495             :             }
    2496      115009 :             if(radVelSignificant){
    2497       58741 :               xindd = radVelCorr.shiftFrequency(xindd);
    2498             :             }
    2499             :             //    if(mainTabRow==0){ // debug output
    2500             :             //      Int i = 25;
    2501             :             //      cout << "i " << i << " xin " << setprecision(9) << xin[iDone][i] << " xindd " << setprecision(9) << xindd[i] 
    2502             :             //           << " xout " << setprecision(9) << xout[iDone][i] << endl;
    2503             :             //      cout << "i " << i << " vradxin " << setprecision(9) << vrad(xin[iDone][i], regridVeloRestfrq) 
    2504             :             //           << " vradxindd " << setprecision(9) << vrad(xindd[i], regridVeloRestfrq)  
    2505             :             //           << " xout " << setprecision(9) << vrad(xout[iDone][i], regridVeloRestfrq) << endl;
    2506             :             //    }
    2507             :           }
    2508      115999 :         }
    2509             :         else{ // no additional transformation of input grid
    2510    20144406 :           for(uInt i=0; i<xin[iDone].size(); i++){ // cannot use assign due to different data type
    2511    19833092 :             xindd[i] = xin[iDone][i];
    2512             :           }
    2513             :         }
    2514             : 
    2515             : 
    2516      427313 :         Double relShift = 0.;
    2517      427313 :         InterpolateArray1D<Double,Complex>::InterpolationMethod  methodC = InterpolateArray1D<Double,Complex>::linear; // the default
    2518      427313 :         InterpolateArray1D<Double,Float>::InterpolationMethod  methodF = InterpolateArray1D<Double,Float>::linear;
    2519             : 
    2520      427643 :         if(fabs(theShift)>0. && 
    2521         330 :            (method[iDone]==(Int)useFFTShift || method[iDone]==(Int)useLinIntThenFFTShift)
    2522             :            ){
    2523         330 :           Int endChan = xout[iDone].size()-1;
    2524         330 :           if(endChan<=0){
    2525           0 :             os << LogIO::SEVERE << "Internal error: Cannot regrid a single-channel SPW using FFTshift" << LogIO::POST;
    2526           0 :             return 0;
    2527             :           }
    2528         330 :           Double chanWidth = xout[iDone][1] - xout[iDone][0];
    2529         330 :           relShift = -theShift/(xout[iDone][endChan] - xout[iDone][0] + chanWidth);
    2530             :           //cout << "the relshift " << relShift << endl;
    2531             :         }
    2532             :         else{
    2533      426983 :           methodC = (InterpolateArray1D<Double,Complex>::InterpolationMethod) method[iDone];
    2534      426983 :           methodF = (InterpolateArray1D<Double,Float>::InterpolationMethod) method[iDone];
    2535             :         }
    2536             : 
    2537      427313 :         if(!CORRECTED_DATACol.isNull()){
    2538        7843 :           yin.assign((*oldCORRECTED_DATAColP)(mainTabRow));
    2539             : 
    2540             :           // hanning smooth if requested
    2541        7843 :           if(doHanningSmooth){
    2542             : 
    2543             :             // copy yin to yinUnsmoothed 
    2544         660 :             Array<Complex> yinUnsmoothed;
    2545         660 :             yinUnsmoothed.assign(yin);
    2546             : 
    2547         660 :             Smooth<Complex>::hanning(yin, // the output
    2548             :                                      yinFlags, // the output flags
    2549             :                                      yinUnsmoothed, // the input
    2550             :                                      yinFlagsUnsmoothed, // the input flags
    2551             :                                      false);  // for flagging: good is not true
    2552         660 :           }
    2553             :           
    2554        7843 :           if(method[iDone]==(Int)useLinIntThenFFTShift){
    2555             :             // first interpolate to equidistant grid at initial timestamp
    2556         990 :             InterpolateArray1D<Double,Complex>::interpolate(yinIntermediate, // the new visibilities
    2557             :                                                             yinFlagsIntermediate, // the new flags
    2558         990 :                                                             xout[iDone], // the new channel centers (for the output SPW timestamp)
    2559             :                                                             xindd, // the old channel centers 
    2560             :                                                             yin, // the old visibilities 
    2561             :                                                             yinFlags,// the old flags
    2562             :                                                             InterpolateArray1D<Double,Complex>::linear, // the interpol method
    2563             :                                                             false, // for flagging: good is not true
    2564             :                                                             doExtrapolate // do not extrapolate
    2565             :                                                             );      
    2566             :             // shift from this timestamp to the output SPW timestamp
    2567         990 :             fFFTServer.fftshift(yout, youtFlags, yinIntermediate, yinFlagsIntermediate, 
    2568         990 :                                 1, // axis 1 of the array is the polarisation axis 
    2569             :                                 relShift, 
    2570             :                                 false, // for flagging: good is not true 
    2571             :                                 false);
    2572             : 
    2573             :           }
    2574        6853 :           else if(method[iDone]==(Int)useFFTShift){
    2575             :             // shift from this timestamp to the output SPW timestamp
    2576           0 :             fFFTServer.fftshift(yout, youtFlags, yin, yinFlags, 
    2577           0 :                                 1, // axis 1 of the array is the polarisation axis 
    2578             :                                 relShift, 
    2579             :                                 false, // for flagging: good is not true 
    2580             :                                 false);
    2581             :           }
    2582             :           else{
    2583        6853 :             InterpolateArray1D<Double,Complex>::interpolate(yout, // the new visibilities
    2584             :                                                             youtFlags, // the new flags
    2585        6853 :                                                             xout[iDone], // the new channel centers
    2586             :                                                             xindd, // the old channel centers
    2587             :                                                             yin, // the old visibilities 
    2588             :                                                             yinFlags,// the old flags
    2589             :                                                             methodC, // the interpol method
    2590             :                                                             false, // for flagging: good is not true
    2591             :                                                             doExtrapolate // do not extrapolate
    2592             :                                                             );
    2593             :           }
    2594             : 
    2595        7843 :           CORRECTED_DATACol.put(mainTabRow, yout);
    2596        7843 :           if(!youtFlagsWritten){ 
    2597        7843 :             FLAGCol.put(mainTabRow, youtFlags);
    2598        7843 :             youtFlagsWritten = true;
    2599             :           }
    2600             :         }
    2601      427313 :         if(!DATACol.isNull()){
    2602      427313 :           yin.assign((*oldDATAColP)(mainTabRow));
    2603      427313 :           if(doHanningSmooth){
    2604         660 :             Array<Complex> yinUnsmoothed;
    2605         660 :             yinUnsmoothed.assign(yin);
    2606             : 
    2607         660 :             Smooth<Complex>::hanning(yin, yinFlags, yinUnsmoothed, yinFlagsUnsmoothed, false);  
    2608         660 :           }
    2609             : 
    2610      427313 :           if(method[iDone]==(Int)useLinIntThenFFTShift){
    2611       28710 :             InterpolateArray1D<Double,Complex>::interpolate(yinIntermediate, yinFlagsIntermediate, xout[iDone], 
    2612             :                                                             xindd, yin, yinFlags,
    2613             :                                                             InterpolateArray1D<Double,Complex>::linear, 
    2614             :                                                             false, doExtrapolate);          
    2615       28710 :             fFFTServer.fftshift(yout, youtFlags, yinIntermediate, yinFlagsIntermediate, 
    2616       28710 :                                 1, relShift, false, false);
    2617             : 
    2618             :           }
    2619      398603 :           else if(method[iDone]==(Int)useFFTShift){
    2620           0 :             fFFTServer.fftshift(yout, youtFlags, yin, yinFlags, 
    2621           0 :                                 1, relShift, false, false);
    2622             :           }
    2623             :           else{
    2624      398603 :             InterpolateArray1D<Double,Complex>::interpolate(yout, youtFlags, xout[iDone], 
    2625             :                                                             xindd, yin, yinFlags,
    2626             :                                                             methodC, false, doExtrapolate);
    2627             :           }
    2628             : 
    2629      427313 :           DATACol.put(mainTabRow, yout);
    2630      427313 :           if(!youtFlagsWritten){ 
    2631      419470 :             FLAGCol.put(mainTabRow, youtFlags);
    2632      419470 :             youtFlagsWritten = true;
    2633             :           }       
    2634             :         }
    2635      427313 :         if(!LAG_DATACol.isNull()){
    2636           0 :           yin.assign((*oldLAG_DATAColP)(mainTabRow));
    2637           0 :           if(doHanningSmooth){ 
    2638           0 :             Array<Complex> yinUnsmoothed;
    2639           0 :             yinUnsmoothed.assign(yin);
    2640             : 
    2641           0 :             Smooth<Complex>::hanning(yin, yinFlags, yinUnsmoothed, yinFlagsUnsmoothed, false);  
    2642           0 :           }
    2643           0 :           if(method[iDone]==(Int)useLinIntThenFFTShift){
    2644           0 :             InterpolateArray1D<Double,Complex>::interpolate(yinIntermediate, yinFlagsIntermediate, xout[iDone], 
    2645             :                                                             xindd, yin, yinFlags,
    2646             :                                                             InterpolateArray1D<Double,Complex>::linear, 
    2647             :                                                             false, doExtrapolate);          
    2648           0 :             fFFTServer.fftshift(yout, youtFlags, yinIntermediate, yinFlagsIntermediate, 
    2649           0 :                                 1, relShift, false, false);
    2650             : 
    2651             :           }
    2652           0 :           else if(method[iDone]==(Int)useFFTShift){
    2653           0 :             fFFTServer.fftshift(yout, youtFlags, yin, yinFlags, 
    2654           0 :                                 1, relShift, false, false);
    2655             :           }
    2656             :           else{
    2657           0 :             InterpolateArray1D<Double,Complex>::interpolate(yout, youtFlags, xout[iDone], 
    2658             :                                                             xindd, yin, yinFlags,
    2659             :                                                             methodC, false, doExtrapolate);
    2660             :           }
    2661             : 
    2662           0 :           LAG_DATACol.put(mainTabRow, yout);
    2663             :         }
    2664      427313 :         if(!MODEL_DATACol.isNull()){
    2665        7842 :           yin.assign((*oldMODEL_DATAColP)(mainTabRow));
    2666             : 
    2667        7842 :           if(method[iDone]==(Int)useLinIntThenFFTShift){
    2668         990 :             InterpolateArray1D<Double,Complex>::interpolate(yinIntermediate, yinFlagsIntermediate, xout[iDone], 
    2669             :                                                             xindd, yin, yinFlags,
    2670             :                                                             InterpolateArray1D<Double,Complex>::linear, 
    2671             :                                                             false, doExtrapolate);          
    2672         990 :             fFFTServer.fftshift(yout, youtFlags, yinIntermediate, yinFlagsIntermediate, 
    2673         990 :                                 1, relShift, false, false);
    2674             : 
    2675             :           }
    2676        6852 :           else if(method[iDone]==(Int)useFFTShift){
    2677           0 :             fFFTServer.fftshift(yout, youtFlags, yin, yinFlags, 
    2678           0 :                                 1, relShift, false, false);
    2679             :           }
    2680             :           else{
    2681        6852 :             InterpolateArray1D<Double,Complex>::interpolate(yout, youtFlags, xout[iDone], 
    2682             :                                                             xindd, yin, yinFlags,
    2683             :                                                             methodC, false, doExtrapolate);
    2684             :           }
    2685             : 
    2686        7842 :           MODEL_DATACol.put(mainTabRow, yout);
    2687        7842 :           if(!youtFlagsWritten){ 
    2688           0 :             FLAGCol.put(mainTabRow, youtFlags);
    2689           0 :             youtFlagsWritten = true;
    2690             :           }
    2691             :         }
    2692             :         
    2693             :         // regrid the Float columns
    2694      427313 :         Array<Float> yinf;
    2695      427313 :         Array<Float> youtf;
    2696      427313 :         Array<Float> fYinIntermediate;
    2697      427313 :         if(!FLOAT_DATACol.isNull()){
    2698           0 :           yinf.assign((*oldFLOAT_DATAColP)(mainTabRow));
    2699           0 :           if(doHanningSmooth){
    2700           0 :             Array<Float> yinfUnsmoothed;
    2701           0 :             yinfUnsmoothed.assign(yinf);
    2702             : 
    2703           0 :             Smooth<Float>::hanning(yinf, yinFlags, yinfUnsmoothed, yinFlagsUnsmoothed, false);  
    2704           0 :           }
    2705             : 
    2706           0 :           if(method[iDone]==(Int)useLinIntThenFFTShift){
    2707           0 :             InterpolateArray1D<Double,Float>::interpolate(fYinIntermediate, yinFlagsIntermediate, xout[iDone], 
    2708             :                                                           xindd, yinf, yinFlags,
    2709             :                                                           InterpolateArray1D<Double,Float>::linear, 
    2710             :                                                           false, doExtrapolate);            
    2711           0 :             fFFTServer.fftshift(youtf, youtFlags, fYinIntermediate, yinFlagsIntermediate, 
    2712           0 :                                 1, relShift, false);
    2713             : 
    2714             :           }
    2715           0 :           else if(method[iDone]==(Int)useFFTShift){
    2716           0 :             fFFTServer.fftshift(youtf, youtFlags, yinf, yinFlags, 
    2717           0 :                                 1, relShift, false);
    2718             :           }
    2719             :           else{
    2720           0 :             InterpolateArray1D<Double, Float>::interpolate(youtf, youtFlags, xout[iDone], xindd, 
    2721             :                                                            yinf, yinFlags, methodF, false, doExtrapolate);
    2722             :           }
    2723             : 
    2724           0 :           FLOAT_DATACol.put(mainTabRow, youtf);
    2725           0 :           if(!youtFlagsWritten){ 
    2726           0 :             FLAGCol.put(mainTabRow, youtFlags);
    2727           0 :             youtFlagsWritten = true;
    2728             :           }
    2729             :         }
    2730             : 
    2731      427313 :         if(!SIGMA_SPECTRUMCol.isNull()){
    2732       58740 :           yinf.assign((*oldSIGMA_SPECTRUMColP)(mainTabRow));
    2733       58740 :           InterpolateArray1D<Double, Float>::interpolate(youtf, youtFlags, xout[iDone], xindd, 
    2734             :                                                          yinf, yinFlags, methodF, false, doExtrapolate);
    2735       58740 :           SIGMA_SPECTRUMCol.put(mainTabRow, youtf * sigmaScaleV[iDone]); //  an approximation
    2736             :         }
    2737      427313 :         if(!WEIGHT_SPECTRUMCol.isNull() && oldWEIGHT_SPECTRUMColP->isDefined(mainTabRow)){ // required column, but can be empty
    2738      405278 :           yinf.assign((*oldWEIGHT_SPECTRUMColP)(mainTabRow));
    2739      405278 :           InterpolateArray1D<Double, Float>::interpolate(youtf, youtFlags, xout[iDone],
    2740             :                                                          xindd, yinf, yinFlags,
    2741             :                                                          methodF, false, doExtrapolate);
    2742      405278 :           WEIGHT_SPECTRUMCol.put(mainTabRow, youtf * weightScaleV[iDone]); // an approximation
    2743             :         }
    2744             :         
    2745             : 
    2746      427313 :         SIGMACol.put(mainTabRow, SIGMACol(mainTabRow)*sigmaScaleV[iDone]);
    2747      427313 :         WEIGHTCol.put(mainTabRow, WEIGHTCol(mainTabRow)*weightScaleV[iDone]);
    2748             : 
    2749             : 
    2750             :         // deal with FLAG_CATEGORY
    2751             :         // note: FLAG_CATEGORY is a required column, but it can be undefined (empty)
    2752             :         
    2753      427313 :         if(FLAG_CATEGORYCol.isDefined(mainTabRow)){
    2754           0 :           Array<Bool> flagCat((*oldFLAG_CATEGORYColP)(mainTabRow));  
    2755           0 :           IPosition flagCatShape = (*oldFLAG_CATEGORYColP).shape(mainTabRow);
    2756           0 :           Int nCorrelations = flagCatShape(0); // get the dimension of the first axis
    2757           0 :           Int nChannels = flagCatShape(1); // get the dimension of the second axis
    2758           0 :           Int nCat = flagCatShape(2); // the dimension of the third axis ==
    2759             :                                       // number of categories
    2760           0 :           Int nOutChannels = xout[iDone].size();
    2761             :           
    2762           0 :           Vector<Float> dummyYin(nChannels);
    2763           0 :           Vector<Float> dummyYout(nOutChannels);
    2764           0 :           Array<Bool> flagCatOut(IPosition(3, nCorrelations, nOutChannels, nCat)); 
    2765             :           
    2766           0 :           for(Int i=0; i<nCat; i++){
    2767           0 :             IPosition start(0,0,i), length (nCorrelations,nChannels,i), stride (1,1,0);
    2768           0 :             Slicer slicer (start, length, stride, Slicer::endIsLast);
    2769           0 :             yinFlags.assign(flagCat(slicer));
    2770           0 :             InterpolateArray1D<Double, Float>::interpolate(dummyYout, youtFlags,
    2771           0 :                                                            xout[iDone], xindd, 
    2772             :                                                            dummyYin, yinFlags,
    2773             :                                                            methodF, false, false);
    2774             :             // write the slice to the array flagCatOut
    2775           0 :             for(Int j=0; j<nCorrelations; j++){
    2776           0 :               for(Int k=0; k<nOutChannels; k++){
    2777           0 :                 flagCatOut(IPosition(3, j, k, i)) = youtFlags(IPosition(2,j,k));
    2778             :               }
    2779             :             }
    2780           0 :           }
    2781             :           
    2782           0 :           FLAG_CATEGORYCol.put(mainTabRow, flagCatOut);
    2783             :           
    2784           0 :         }
    2785             :         
    2786      427313 :         msModified = true;
    2787             :         
    2788      427313 :       } // end if regridding necessary
    2789             : 
    2790      427313 :       if(mainTabRow>nMainTabRows*progress){
    2791         172 :         cout << "regridSpw progress: " << progress*100 << "% processed ... " << endl;
    2792         172 :         progress += progressStep;
    2793             :       }
    2794             :       
    2795      427313 :     } // end loop over main table rows
    2796          45 :     cout << "regridSpw progress: 100% processed." << endl;
    2797             : 
    2798          45 :     if(msModified){
    2799          45 :       if(needRegridding){
    2800             : 
    2801             :         // remove the "partner" columns
    2802          45 :         if(!CORRECTED_DATACol.isNull()){
    2803          18 :           ms_p.removeColumn("oldCORRECTED_DATA");
    2804             :         }
    2805          45 :         if(!DATACol.isNull()){
    2806          45 :           ms_p.removeColumn("oldDATA");
    2807             :         }
    2808          45 :         if(!FLOAT_DATACol.isNull()){
    2809           0 :           ms_p.removeColumn("oldFLOAT_DATA");
    2810             :         }
    2811          45 :         if(!LAG_DATACol.isNull()){
    2812           0 :           ms_p.removeColumn("oldLAG_DATA");
    2813             :         }
    2814          45 :         if(!MODEL_DATACol.isNull()){
    2815          17 :           ms_p.removeColumn("oldMODEL_DATA");
    2816             :         }
    2817          45 :         if(!SIGMA_SPECTRUMCol.isNull()){
    2818           2 :           ms_p.removeColumn("oldSIGMA_SPECTRUM");
    2819             :         }
    2820          45 :         if(!WEIGHT_SPECTRUMCol.isNull()){
    2821          45 :           ms_p.removeColumn("oldWEIGHT_SPECTRUM");
    2822             :         }
    2823          45 :         if(!FLAGCol.isNull()){
    2824          45 :           ms_p.removeColumn("oldFLAG");
    2825             :         } 
    2826          45 :         if(!FLAG_CATEGORYCol.isNull()){
    2827          45 :           ms_p.removeColumn("oldFLAG_CATEGORY");
    2828             :         }
    2829             :       }
    2830             :       
    2831          45 :       rval = 1; // successful modification
    2832             :     }
    2833          45 :     return rval;
    2834             : 
    2835          54 :   }
    2836             : 
    2837             : 
    2838         405 :   Bool SubMS::createPartnerColumn(TableDesc& modMSTD,
    2839             :                                   const String& oldName, 
    2840             :                                   const String& newName,
    2841             :                                   const Int& hypercolumnDim,
    2842             :                                   const IPosition& tileShape
    2843             :                                   ){
    2844         405 :     Bool rval = false;
    2845         405 :     if(modMSTD.isColumn(oldName)){
    2846             :       // get the old column desc
    2847         217 :       ColumnDesc myColDesc(modMSTD.columnDesc(oldName));
    2848             :       // move the column away
    2849         217 :       ms_p.renameColumn(newName, oldName);
    2850             :       // rename the hypercolumn
    2851         217 :       String hcName(myColDesc.dataManagerGroup());
    2852         217 :       String oldHcName = hcName;
    2853         217 :       String newHcName = hcName + "B";
    2854         217 :       if(!oldHcName.empty() && ms_p.actualTableDesc().isHypercolumn(oldHcName)){
    2855         203 :         ms_p.renameHypercolumn(newHcName, oldHcName);
    2856             :       }
    2857             :       // rename the datamanager
    2858         217 :       DataManager* myDM = ms_p.findDataManager(oldHcName);
    2859         217 :       ((TiledStMan*) myDM)->setDataManagerName(newHcName);
    2860             :       // create new hypercolumn and a new column with new data manager
    2861         217 :       TiledShapeStMan*  tiledStMan = new TiledShapeStMan(oldHcName, tileShape);
    2862         217 :       ms_p.addColumn(myColDesc, *tiledStMan);
    2863         217 :       modMSTD.defineHypercolumn(oldHcName, hypercolumnDim, stringToVector(oldName));
    2864             : 
    2865         217 :       rval = true;
    2866         217 :     }
    2867         405 :     return rval;
    2868             :   }
    2869             : 
    2870             : 
    2871        1356 :   Bool SubMS::regridChanBounds(Vector<Double>& newChanLoBound, 
    2872             :                                Vector<Double>& newChanHiBound,
    2873             :                                const Double regridCenterC,
    2874             :                                const Double regridBandwidth, 
    2875             :                                const Double regridChanWidthC, 
    2876             :                                const Double regridVeloRestfrq, 
    2877             :                                const String regridQuant,
    2878             :                                const Vector<Double>& transNewXinC, 
    2879             :                                const Vector<Double>& transCHAN_WIDTHC,
    2880             :                                String& message,
    2881             :                                const Bool centerIsStartC,
    2882             :                                const Bool startIsEndC,
    2883             :                                const Int nchanC,
    2884             :                                const Int width,
    2885             :                                const Int startC
    2886             :                                ){
    2887        1356 :     ostringstream oss;
    2888             : 
    2889             : //     cout << "regridCenterC " <<  regridCenterC << " regridBandwidth " << regridBandwidth 
    2890             : //       << " regridChanWidthC " << regridChanWidthC << endl;
    2891             : //     cout << " nchanC " << nchanC << " width " << width << " startC " << startC << endl;
    2892             : //     cout << " regridQuant " << regridQuant << " centerIsStartC " <<  centerIsStartC << " startIsEndC " << startIsEndC << endl;
    2893             :     
    2894             : 
    2895        1356 :     Vector<Double> transNewXin(transNewXinC);
    2896        1356 :     Vector<Double> transCHAN_WIDTH(transCHAN_WIDTHC);
    2897        1356 :     Bool centerIsStart = centerIsStartC;
    2898        1356 :     Bool startIsEnd = startIsEndC;
    2899        1356 :     Double regridChanWidth = regridChanWidthC;
    2900        1356 :     Double regridCenter = regridCenterC;
    2901        1356 :     Int nchan = nchanC;
    2902        1356 :     Int start = startC;
    2903             : 
    2904        1356 :     Int oldNUM_CHAN = transNewXin.size();
    2905             : 
    2906             : 
    2907             :     // detect spectral windows defined with descending frequency
    2908        1356 :     Bool isDescending=false;
    2909      397234 :     for(uInt i=1; i<transNewXin.size(); i++){
    2910      395878 :       if(transNewXin(i)<transNewXin(i-1)){
    2911       18404 :         isDescending = true;
    2912             :       }
    2913      377474 :       else if(isDescending){ // i.e. descending was detected but now we encounter ascending
    2914           0 :         oss << "Channel frequencies are neither in ascending nor in descending order. Cannot process.";
    2915           0 :         message = oss.str();
    2916           0 :         return false;  
    2917             :       } 
    2918             :     }
    2919             : 
    2920        1356 :     if(isDescending){ // need to reverse the order for processing and later reverse the result
    2921             :       //cout << "SPW has descending order ..." << endl;
    2922          28 :       uInt n = transNewXin.size();
    2923          28 :       Vector<Double> tempF, tempW;
    2924          28 :       tempF.assign(transNewXin);
    2925          28 :       tempW.assign(transCHAN_WIDTH);
    2926       18460 :       for(uInt i=0; i<n; i++){
    2927       18432 :         transNewXin(i) = tempF(n-1-i);
    2928       18432 :         transCHAN_WIDTH(i) = tempW(n-1-i);
    2929             :         //cout << "i f w " << i << " " << transNewXin(i) << " " << transCHAN_WIDTH(i) << endl;
    2930             :       }
    2931             :       // also need to adjust the start values 
    2932          28 :       if(startC>=0){
    2933          25 :         start = n-1-startC;
    2934          25 :         if(centerIsStartC){
    2935          25 :           startIsEnd = !startIsEnd;
    2936             :         }
    2937             :       }
    2938             :       //}
    2939          28 :     }
    2940             : 
    2941             :     // verify regridCenter, regridBandwidth, and regridChanWidth 
    2942             :     // Note: these are in the units corresponding to regridQuant!
    2943             :     
    2944        1356 :     if(regridQuant=="chan"){ ////////////////////////
    2945             :       // channel numbers ...
    2946           3 :       Int regridCenterChan = -1;
    2947           3 :       Int regridBandwidthChan = -1;
    2948           3 :       Int regridChanWidthChan = -1;
    2949             : 
    2950           3 :       if(regridCenter<-1E30){ // not set
    2951             :         // find channel center closest to center of bandwidth
    2952           0 :         lDouble BWCenterF = (transNewXin[0]+transNewXin[oldNUM_CHAN-1])/2.;
    2953           0 :         for(Int i=0; i<oldNUM_CHAN; i++){
    2954           0 :           if(transNewXin[i] >= BWCenterF){
    2955           0 :             regridCenterChan = i;
    2956           0 :             break;
    2957             :           }
    2958             :         }
    2959           0 :         centerIsStart = false;
    2960             :       }
    2961           3 :       else if(0. <= regridCenter && regridCenter < Double(oldNUM_CHAN)){ // valid input
    2962           3 :         regridCenterChan = (Int) floor(regridCenter);  
    2963             :       }
    2964             :       else { // invalid
    2965           0 :         if(centerIsStart){
    2966           0 :           oss << "SPW start ";
    2967             :         }
    2968             :         else{
    2969           0 :           oss << "SPW center ";
    2970             :         }
    2971           0 :         oss << regridCenter << " outside valid range which is "
    2972           0 :             << 0 << " - " << oldNUM_CHAN-1 <<".";
    2973           0 :         message = oss.str();
    2974           0 :         return false;  
    2975             :       }  
    2976             :       
    2977           3 :       if(regridBandwidth<=0.|| nchan>0){ // not set or nchan set
    2978           3 :         if(nchan>0){
    2979           0 :           regridBandwidthChan = nchan;
    2980             :         }
    2981             :         else{
    2982           3 :           regridBandwidthChan = oldNUM_CHAN;
    2983             :         }
    2984             :       }
    2985             :       else{
    2986           0 :         regridBandwidthChan = (Int) floor(regridBandwidth);
    2987             :       }
    2988             : 
    2989           3 :       if(centerIsStart){
    2990           3 :         if(startIsEnd){
    2991           0 :           regridCenterChan = regridCenterChan - regridBandwidthChan/2;
    2992             :         }
    2993             :         else{
    2994           3 :           regridCenterChan = regridCenterChan + regridBandwidthChan/2;
    2995             :         }
    2996           3 :         centerIsStart = false;
    2997             :       }
    2998             : 
    2999           3 :       if(regridCenterChan-regridBandwidthChan/2 < 0) { // center too close to lower edge
    3000           0 :         regridBandwidthChan = 2 * regridCenterChan + 1;
    3001           0 :         oss << " *** Requested output SPW width too large." << endl;
    3002             :       }
    3003           3 :       if( oldNUM_CHAN < regridCenterChan+regridBandwidthChan/2){  // center too close to upper edge
    3004           0 :         regridBandwidthChan = 2*(oldNUM_CHAN - regridCenterChan);
    3005           0 :         oss << " *** Requested output SPW width too large." << endl;
    3006             :       } 
    3007             :       
    3008           3 :       if(regridChanWidth < 1.){
    3009           0 :         regridChanWidthChan = 1;
    3010             :       }
    3011           3 :       else if(regridChanWidth > Double(regridBandwidthChan)){
    3012           0 :         regridChanWidthChan = regridBandwidthChan; // i.e. SPW = a single channel
    3013           0 :         oss << " *** Requested output channel width too large. Adjusted to maximum possible value." << endl;
    3014             :       }
    3015             :       else { // valid input
    3016           3 :         regridChanWidthChan = (Int) floor(regridChanWidth);
    3017           3 :         if(nchan>0){
    3018           0 :           regridBandwidthChan = nchan * regridChanWidthChan;
    3019             :         }
    3020             :       }
    3021             :       
    3022           3 :       if(regridBandwidthChan != floor(regridBandwidth)){
    3023           3 :         oss << " *** Output SPW width set to " << regridBandwidthChan << " original channels" << endl;
    3024           3 :         oss << "     in an attempt to keep center of output SPW close to center of requested SPW." << endl;
    3025             :       } 
    3026             :       
    3027             :       // calculate newChanLoBound and newChanHiBound from regridCenterChan, regridBandwidthChan, and regridChanWidthChan
    3028           3 :       Int bwLowerEndChan = regridCenterChan - regridBandwidthChan/2;
    3029           3 :       Int bwUpperEndChan = bwLowerEndChan + regridBandwidthChan - 1;
    3030           3 :       Int numNewChanDown = 0;
    3031           3 :       Int numNewChanUp = 0;
    3032             :       
    3033           3 :       if(regridChanWidthChan == regridBandwidthChan){ // only one new channel
    3034           0 :         newChanLoBound.resize(1);
    3035           0 :         newChanHiBound.resize(1);
    3036           0 :         newChanLoBound[0] = transNewXin[bwLowerEndChan]-transCHAN_WIDTH[bwLowerEndChan]/2.;
    3037           0 :         newChanHiBound[0] = transNewXin[bwUpperEndChan]+transCHAN_WIDTH[bwUpperEndChan]/2.;
    3038           0 :         numNewChanUp = 1;
    3039             :       }
    3040             :       else { // have more than one new channel
    3041             :         // Need to accomodate the possibility that the original channels are
    3042             :         // not contiguous!
    3043             : 
    3044             :         // the numbers of the Channels from which the lower bounds will be taken for the new channels 
    3045           3 :         vector<Int> loNCBup;
    3046             :         // starting from the central channel going up
    3047           3 :         vector<Int> hiNCBup; // the numbers of the Channels from which the high
    3048             :                              // bounds will be taken for the new channels
    3049             :         // starting from the central channel going up
    3050           3 :         vector<Int> loNCBdown; // the numbers of the Channels from which the
    3051             :                                // lower bounds will be taken for the new
    3052             :                                // channels
    3053             :         // starting from the central channel going down
    3054           3 :         vector<Int> hiNCBdown; // the numbers of the Channels from which the
    3055             :                                // high bounds will be taken for the new
    3056             :                                // channels
    3057             :         // starting from the central channel going down
    3058             :         //    Want to keep the center of the center channel at the center of
    3059             :         //    the new center channel if the bandwidth is an odd multiple of the
    3060             :         //    new channel width 
    3061             :         //    otherwise the center channel is the lower edge of the new center channel
    3062             :         Int startChan;
    3063           3 :         lDouble tnumChan = regridBandwidthChan/regridChanWidthChan;
    3064           3 :         if((Int)tnumChan % 2 != 0 ){
    3065             :           // odd multiple 
    3066           3 :           startChan = regridCenterChan-regridChanWidthChan/2;
    3067             :         }
    3068             :         else{
    3069           0 :           startChan = regridCenterChan;
    3070             :         }
    3071        3642 :         for(Int i=startChan; i<=bwUpperEndChan; i+=regridChanWidthChan){ // upper half
    3072        3639 :           loNCBup.push_back(i);
    3073        3639 :           if(i+regridChanWidthChan-1<=bwUpperEndChan){
    3074             :             // can go one more normal step up
    3075        3639 :             hiNCBup.push_back(i+regridChanWidthChan-1);
    3076             :           }
    3077             :           else{
    3078             :             // create narrower channels at the edges if necessary
    3079           0 :             oss << " *** Last channel at upper edge of new SPW made only " << bwUpperEndChan-i+1 
    3080           0 :                 << " original channels wide to fit given total bandwidth." << endl;
    3081           0 :             hiNCBup.push_back(bwUpperEndChan);
    3082             :           }
    3083             :         }
    3084             : 
    3085             :         // lower half
    3086        3639 :         for(Int i=startChan - 1; i>=bwLowerEndChan; i-=regridChanWidthChan){ 
    3087        3636 :           hiNCBdown.push_back(i);
    3088        3636 :           if(i-regridChanWidthChan+1>=bwLowerEndChan){
    3089             :             // can go one more normal step down
    3090        3636 :             loNCBdown.push_back(i-regridChanWidthChan+1);
    3091             :           }
    3092             :           else{
    3093             :             // create narrower channels at the edges if necessary
    3094           0 :             oss << " *** First channel at lower edge of new SPW made only " << i-bwLowerEndChan+1 
    3095           0 :                 << " original channels wide to fit given total bandwidth." << endl;
    3096           0 :             loNCBdown.push_back(bwLowerEndChan);
    3097             :           }
    3098             :         }
    3099             : 
    3100             :         // the number of channels below the central one
    3101           3 :         numNewChanDown = loNCBdown.size();
    3102             : 
    3103             :         // the number of channels above and including the central one
    3104           3 :         numNewChanUp = loNCBup.size();
    3105             : 
    3106           3 :         newChanLoBound.resize(numNewChanDown+numNewChanUp);
    3107           3 :         newChanHiBound.resize(numNewChanDown+numNewChanUp);
    3108        3639 :         for(Int i=0; i<numNewChanDown; i++){
    3109        3636 :           Int k = numNewChanDown-i-1; // need to assign in reverse
    3110        3636 :           newChanLoBound[i] = transNewXin[loNCBdown[k]] -
    3111        3636 :             transCHAN_WIDTH[loNCBdown[k]]/2.; 
    3112        7272 :           newChanHiBound[i] = transNewXin[hiNCBdown[k]] +
    3113        3636 :             transCHAN_WIDTH[hiNCBdown[k]]/2.;
    3114             :         }
    3115        3642 :         for(Int i=0; i<numNewChanUp; i++){
    3116        3639 :           newChanLoBound[i+numNewChanDown] = transNewXin[loNCBup[i]] -
    3117        3639 :             transCHAN_WIDTH[loNCBup[i]]/2.;
    3118        7278 :           newChanHiBound[i+numNewChanDown] = transNewXin[hiNCBup[i]] +
    3119        3639 :             transCHAN_WIDTH[hiNCBup[i]]/2.;
    3120             :         }
    3121           3 :       } // end if 
    3122             : 
    3123           3 :       oss << " New channels defined based on original channels" << endl
    3124           3 :           << " Central channel contains original channel " <<  regridCenterChan << endl 
    3125           3 :           << " Channel width = " << regridChanWidthChan
    3126           3 :           << " original channels" << endl
    3127           3 :           << " Total width of SPW = " <<  regridBandwidthChan << " original channels == " 
    3128           3 :           << numNewChanDown + numNewChanUp << " new channels" << endl;
    3129             : 
    3130           3 :       uInt nc = newChanLoBound.size();
    3131           3 :       oss << " Total width of SPW (in output frame) = " << newChanHiBound[nc-1] - newChanLoBound[0] 
    3132           3 :           << " Hz" << endl;
    3133           3 :       oss << " Lower edge = " << newChanLoBound[0] << " Hz,"
    3134           3 :           << " upper edge = " << newChanHiBound[nc-1] << " Hz" << endl;
    3135             : 
    3136           3 :       if(isDescending){ 
    3137           0 :         Vector<Double> tempL, tempU;
    3138           0 :         tempL.assign(newChanLoBound);
    3139           0 :         tempU.assign(newChanHiBound);
    3140           0 :         for(uInt i=0; i<nc; i++){
    3141           0 :           newChanLoBound(i) = tempL(nc-1-i);
    3142           0 :           newChanHiBound(i) = tempU(nc-1-i);
    3143             :         }
    3144           0 :       }
    3145             : 
    3146           3 :       message = oss.str();
    3147             : 
    3148           3 :       return true;
    3149             :     }
    3150             :     else { // we operate on real numbers /////////////////
    3151             :       // first transform them to frequencies
    3152        1353 :       lDouble regridCenterF = -1.; // initialize as "not set"
    3153        1353 :       lDouble regridBandwidthF = -1.;
    3154        1353 :       lDouble regridChanWidthF = -1.;
    3155             : 
    3156        1353 :       if(regridQuant=="vrad"){ ///////////////
    3157             :         // radio velocity ...
    3158             :         // need restfrq
    3159          66 :         if(regridVeloRestfrq<-1E30){ // means "not set"
    3160           0 :           oss << "Parameter \"restfreq\" needs to be set if regrid_quantity==vrad. Cannot proceed with regridSpw ..."; 
    3161           0 :           message = oss.str();
    3162           0 :           return false;
    3163             :         }
    3164          66 :         else if(regridVeloRestfrq < 0. || regridVeloRestfrq > 1E30){
    3165           0 :           oss << "Parameter \"restfreq\" value " << regridVeloRestfrq << " is invalid.";
    3166           0 :           message = oss.str();
    3167           0 :           return false;
    3168             :         }         
    3169             :         lDouble regridCenterVel; 
    3170          66 :         if(regridCenter>-C::c){
    3171             :           // (we deal with invalid values later)
    3172          54 :           if(centerIsStart){
    3173             :             Double tcWidth;
    3174          54 :             if(regridChanWidth > 0.){
    3175          54 :               tcWidth = regridChanWidth;
    3176             :             }
    3177             :             else{
    3178           0 :               tcWidth = vrad(transNewXin[0]-transCHAN_WIDTH[0]/2.,regridVeloRestfrq)
    3179           0 :                 - vrad(transNewXin[0]+transCHAN_WIDTH[0]/2.,regridVeloRestfrq);
    3180             :             }
    3181          54 :             if(startIsEnd){ // start is the center of the last channel (in freq)
    3182          51 :               regridCenter -= tcWidth/2.;
    3183             :             }
    3184             :             else{ // start is the center of the first channel (in freq)
    3185           3 :               regridCenter += tcWidth/2.;
    3186             :             }
    3187             :           }
    3188             : 
    3189          54 :           regridCenterF = freq_from_vrad(regridCenter,regridVeloRestfrq);
    3190             : 
    3191          54 :           regridCenterVel = regridCenter;
    3192             :         }
    3193             :         else{ // center was not specified
    3194          12 :           regridCenterF = (transNewXin[0]+transNewXin[oldNUM_CHAN-1])/2.;
    3195          12 :           regridCenterVel = vrad(regridCenterF,regridVeloRestfrq);
    3196          12 :           centerIsStart = false;
    3197             :         }
    3198          66 :         if(nchan>0){
    3199          60 :           if(regridChanWidth > 0.){
    3200          54 :             lDouble chanUpperEdgeF = freq_from_vrad(regridCenterVel - regridChanWidth/2.,
    3201             :                                                    regridVeloRestfrq);
    3202          54 :             regridChanWidthF = 2.* (chanUpperEdgeF - regridCenterF); 
    3203             :           }
    3204             :           else{ // take channel width from first channel
    3205           6 :             regridChanWidthF = transCHAN_WIDTH[0];
    3206             :           }
    3207          60 :           regridBandwidthF = nchan*regridChanWidthF;
    3208             :           // can convert start to center
    3209          60 :           if(centerIsStart){
    3210          54 :             if(startIsEnd){
    3211          51 :               regridCenterF = regridCenterF - regridBandwidthF/2.;
    3212             :             }
    3213             :             else{
    3214           3 :               regridCenterF = regridCenterF + regridBandwidthF/2.;
    3215             :             }
    3216          54 :             centerIsStart = false;
    3217             :           }
    3218             :         }
    3219           6 :         else if(regridBandwidth > 0.){
    3220             :           // can convert start to center
    3221           0 :           if(centerIsStart){
    3222           0 :             if(startIsEnd){
    3223           0 :               regridCenterVel = regridCenter + regridBandwidth/2.;
    3224             :             }
    3225             :             else{
    3226           0 :               regridCenterVel = regridCenter - regridBandwidth/2.;
    3227             :             }
    3228           0 :             regridCenterF = freq_from_vrad(regridCenterVel,regridVeloRestfrq);
    3229           0 :             centerIsStart = false;
    3230             :           }
    3231           0 :           lDouble bwUpperEndF = freq_from_vrad(regridCenterVel - regridBandwidth/2.,
    3232             :                                               regridVeloRestfrq);
    3233           0 :           regridBandwidthF = 2.* (bwUpperEndF - regridCenterF); 
    3234             :         }
    3235          66 :         if(regridChanWidth > 0. && regridChanWidthF<0.){
    3236           3 :           lDouble chanUpperEdgeF = freq_from_vrad(regridCenterVel - regridChanWidth/2.,
    3237             :                                                   regridVeloRestfrq);
    3238           3 :           regridChanWidthF = 2.* (chanUpperEdgeF - freq_from_vrad(regridCenterVel, regridVeloRestfrq));
    3239             :         }
    3240             :       }
    3241        1287 :       else if(regridQuant=="vopt"){ ///////////
    3242             :         // optical velocity ...
    3243             :         // need restfrq
    3244          13 :         if(regridVeloRestfrq < -1E30){ // means "not set"
    3245           0 :           oss << "Parameter \"restfreq\" needs to be set if regrid_quantity==vopt. Cannot proceed with regridSpw ...";
    3246           0 :           message = oss.str();
    3247           0 :           return false;
    3248             :         }
    3249          13 :         else if(regridVeloRestfrq <= 0. || regridVeloRestfrq > 1E30){
    3250           0 :           oss << "Parameter \"restfreq\" value " << regridVeloRestfrq
    3251           0 :               << " is invalid."; 
    3252           0 :           message = oss.str();
    3253           0 :           return false;
    3254             :         }
    3255             :         lDouble regridCenterVel; 
    3256          13 :         if(regridCenter > -C::c){
    3257          12 :           if(centerIsStart){
    3258             :             Double tcWidth;
    3259          12 :             if(regridChanWidth > 0.){
    3260          12 :               tcWidth = regridChanWidth;
    3261             :             }
    3262             :             else{
    3263           0 :               tcWidth = vopt(transNewXin[0]-transCHAN_WIDTH[0]/2.,regridVeloRestfrq)
    3264           0 :                 - vopt(transNewXin[0]+transCHAN_WIDTH[0]/2.,regridVeloRestfrq);
    3265             :             }
    3266          12 :             if(startIsEnd){ // start is the center of the last channel (in freq)
    3267           9 :               regridCenter -= tcWidth/2.;
    3268             :             }
    3269             :             else{ // start is the center of the first channel (in freq)
    3270           3 :               regridCenter += tcWidth/2.;
    3271             :             }
    3272             :           }
    3273             :           // (we deal with invalid values later)
    3274          12 :           regridCenterF = freq_from_vopt(regridCenter,regridVeloRestfrq);
    3275          12 :           regridCenterVel = regridCenter;
    3276             :         }
    3277             :         else{ // center was not specified
    3278           1 :           regridCenterF = (transNewXin[0]-transCHAN_WIDTH[0]+transNewXin[oldNUM_CHAN-1]+transCHAN_WIDTH[oldNUM_CHAN-1])/2.;
    3279           1 :           regridCenterVel = vopt(regridCenterF,regridVeloRestfrq);
    3280           1 :           centerIsStart = false;
    3281             :         }
    3282          13 :         if(nchan>0){
    3283             :           lDouble cw;
    3284          12 :           lDouble divbytwo = 0.5;
    3285          12 :           if(centerIsStart){
    3286          12 :             divbytwo = 1.;
    3287             :           }
    3288          12 :           if(regridChanWidth > 0.){
    3289          12 :             cw = regridChanWidth;
    3290             :           }
    3291             :           else{ // determine channel width from first channel
    3292           0 :             lDouble upEdge = vopt(transNewXin[0]-transCHAN_WIDTH[0],regridVeloRestfrq);
    3293           0 :             lDouble loEdge = vopt(transNewXin[0]+transCHAN_WIDTH[0],regridVeloRestfrq);
    3294           0 :             cw = abs(upEdge-loEdge); 
    3295             :           }
    3296          12 :           lDouble bwUpperEndF = 0.;
    3297          12 :           if(centerIsStart && !startIsEnd){ // start is end in velocity
    3298           3 :             bwUpperEndF = freq_from_vopt(regridCenterVel - (lDouble)nchan*cw*divbytwo,
    3299             :                                          regridVeloRestfrq);
    3300             :           }
    3301             :           else{
    3302           9 :             bwUpperEndF = freq_from_vopt(regridCenterVel + (lDouble)nchan*cw*divbytwo,
    3303             :                                          regridVeloRestfrq);
    3304             :           }
    3305          12 :           regridBandwidthF = abs(bwUpperEndF-regridCenterF)/divbytwo; 
    3306             :           // can convert start to center
    3307          12 :           if(centerIsStart){
    3308          12 :             if(startIsEnd){
    3309           9 :               regridCenterVel = regridCenterVel + (lDouble)nchan*cw/2.;
    3310             :             }
    3311             :             else{
    3312           3 :               regridCenterVel = regridCenterVel - (lDouble)nchan*cw/2.;
    3313             :             }
    3314          12 :             regridCenterF = freq_from_vopt(regridCenterVel,regridVeloRestfrq);
    3315          12 :             centerIsStart = false;
    3316             :           }
    3317          12 :           nchan=0; // indicate that nchan should not be used in the following
    3318             :         }
    3319           1 :         else if(regridBandwidth > 0.){
    3320             :           // can convert start to center
    3321           0 :           if(centerIsStart){
    3322           0 :             if(startIsEnd){
    3323           0 :               regridCenterVel = regridCenter + regridBandwidth/2.;
    3324             :             }
    3325             :             else{
    3326           0 :               regridCenterVel = regridCenter - regridBandwidth/2.;
    3327             :             }
    3328           0 :             regridCenterF = freq_from_vopt(regridCenterVel,regridVeloRestfrq);
    3329           0 :             centerIsStart = false;
    3330             :           }
    3331           0 :           lDouble bwUpperEndF =  freq_from_vopt(regridCenterVel - regridBandwidth/2.,
    3332             :                                                regridVeloRestfrq);
    3333           0 :           regridBandwidthF = 2.* (bwUpperEndF- regridCenterF); 
    3334             :         }
    3335          13 :         if(regridChanWidth > 0. && regridChanWidthF<0.){
    3336          12 :           lDouble chanUpperEdgeF = freq_from_vopt(regridCenterVel - regridChanWidth/2.,
    3337             :                                                  regridVeloRestfrq);
    3338          12 :           regridChanWidthF = 2.* (chanUpperEdgeF - freq_from_vopt(regridCenterVel,regridVeloRestfrq)); 
    3339             :         }
    3340             :       } 
    3341        1274 :       else if(regridQuant=="freq"){ ////////////////////////
    3342        1274 :         if(width>0){ // width parameter overrides regridChanWidth
    3343        1194 :           regridChanWidth = width*transCHAN_WIDTH[0];
    3344             :         }
    3345        1274 :         if(start>=0){
    3346        1206 :           Int firstChan = start;
    3347        1206 :           if(start >= (Int)transNewXin.size()){
    3348           0 :             oss << " *** Parameter start exceeds total number of channels which is "
    3349           0 :                 << transNewXin.size() << ". Set to 0." << endl;
    3350           0 :             firstChan = 0;
    3351           0 :             startIsEnd = false;
    3352             :           }
    3353        1206 :           if(startIsEnd){
    3354          28 :             regridCenter = transNewXin[firstChan]+transCHAN_WIDTH[firstChan]/2.;
    3355             :           }
    3356             :           else{
    3357        1178 :             regridCenter = transNewXin[firstChan]-transCHAN_WIDTH[firstChan]/2.;
    3358             :           }
    3359        1206 :           centerIsStart = true;
    3360             :         }
    3361             :         else{
    3362          68 :           if(centerIsStart){ // start is the center of the first channel
    3363             :             Double tcWidth;
    3364          68 :             if(regridChanWidth > 0.){ 
    3365          61 :               tcWidth = regridChanWidth;
    3366             :             }
    3367             :             else{
    3368           7 :               tcWidth = transCHAN_WIDTH[0];
    3369             :             }
    3370          68 :             if(startIsEnd){
    3371           6 :               regridCenter += tcWidth/2.;
    3372             :             }
    3373             :             else{
    3374          62 :               regridCenter -= tcWidth/2.;
    3375             :             }
    3376             :           }
    3377             :         }
    3378        1274 :         regridCenterF = regridCenter;
    3379        1274 :         regridBandwidthF = regridBandwidth;
    3380        1274 :         regridChanWidthF = regridChanWidth;
    3381             :       }
    3382           0 :       else if(regridQuant=="wave"){ ///////////////////////
    3383             :         // wavelength ...
    3384             :         lDouble regridCenterWav; 
    3385           0 :         if(regridCenter > 0.){
    3386           0 :           if(centerIsStart){
    3387             :             Double tcWidth;
    3388           0 :             if(regridChanWidth > 0.){
    3389           0 :               tcWidth = regridChanWidth;
    3390             :             }
    3391             :             else{
    3392           0 :               tcWidth = lambda(transNewXin[0]-transCHAN_WIDTH[0]/2.)
    3393           0 :                 - lambda(transNewXin[0]+transCHAN_WIDTH[0]/2.);
    3394             :             }
    3395           0 :             if(startIsEnd){ // start is the center of the last channel (in freq)
    3396           0 :               regridCenter -= tcWidth/2.;
    3397             :             }
    3398             :             else{ // start is the center of the first channel (in freq)
    3399           0 :               regridCenter += tcWidth/2.;
    3400             :             }
    3401             :           }
    3402           0 :           regridCenterF = freq_from_lambda(regridCenter); 
    3403           0 :           regridCenterWav = regridCenter;
    3404             :         }
    3405             :         else{ // center was not specified
    3406           0 :           regridCenterF = (transNewXin[0] + transNewXin[oldNUM_CHAN-1])/2.;
    3407           0 :           regridCenterWav = lambda(regridCenterF);
    3408           0 :           centerIsStart = false;
    3409             :         }
    3410           0 :         if(nchan>0){
    3411             :           lDouble cw;
    3412           0 :           lDouble divbytwo = 0.5;
    3413           0 :           if(centerIsStart){
    3414           0 :             divbytwo = 1.;
    3415             :           }
    3416           0 :           if(regridChanWidth > 0.){
    3417           0 :             cw = regridChanWidth;
    3418             :           }
    3419             :           else{ // determine channel width from first channel
    3420           0 :             lDouble upEdge = lambda(transNewXin[0]-transCHAN_WIDTH[0]);
    3421           0 :             lDouble loEdge = lambda(transNewXin[0]+transCHAN_WIDTH[0]);
    3422           0 :             cw = abs(upEdge-loEdge); 
    3423             :           }
    3424           0 :           lDouble bwUpperEndF = 0.;
    3425           0 :           if(centerIsStart && !startIsEnd){
    3426           0 :             bwUpperEndF = freq_from_lambda(regridCenterWav - (lDouble)nchan*cw*divbytwo);           
    3427             :           }
    3428             :           else{
    3429           0 :             bwUpperEndF = freq_from_lambda(regridCenterWav + (lDouble)nchan*cw*divbytwo);
    3430             :           }
    3431           0 :           regridBandwidthF = (bwUpperEndF-regridCenterF)/divbytwo; 
    3432             :           // can convert start to center
    3433           0 :           if(centerIsStart){
    3434           0 :             if(startIsEnd){
    3435           0 :               regridCenterWav = regridCenterWav + (lDouble)nchan*cw/2.;
    3436             :             }
    3437             :             else{
    3438           0 :               regridCenterWav = regridCenterWav - (lDouble)nchan*cw/2.;
    3439             :             }
    3440           0 :             regridCenterF = freq_from_lambda(regridCenterWav);
    3441           0 :             centerIsStart = false;
    3442             :           }
    3443           0 :           nchan=0; // indicate that nchan should not be used in the following
    3444             :         }
    3445           0 :         else if(regridBandwidth > 0. && regridBandwidth/2. < regridCenterWav){
    3446             :           // can convert start to center
    3447           0 :           if(centerIsStart){
    3448           0 :             if(startIsEnd){
    3449           0 :               regridCenterWav = regridCenter + regridBandwidth/2.;
    3450             :             }
    3451             :             else{
    3452           0 :               regridCenterWav = regridCenter - regridBandwidth/2.;
    3453             :             }
    3454           0 :             regridCenterF = freq_from_lambda(regridCenterWav);
    3455           0 :             centerIsStart = false;
    3456             :           }
    3457           0 :           lDouble bwUpperEndF =  lambda(regridCenterWav - regridBandwidth/2.);
    3458           0 :           regridBandwidthF = 2.* (bwUpperEndF - regridCenterF); 
    3459             :         }
    3460           0 :         if(regridChanWidth>0. && regridChanWidth/2.< regridCenterWav){
    3461           0 :           lDouble chanUpperEdgeF =  lambda(regridCenterWav - regridChanWidth/2.);
    3462           0 :           regridChanWidthF = 2.* (chanUpperEdgeF - regridCenterF); 
    3463             :         }
    3464             :       }
    3465             :       else{
    3466           0 :         oss << "Invalid value " << regridQuant << " for parameter \"mode\".";
    3467           0 :         message = oss.str();
    3468           0 :         return false;
    3469             :       }
    3470             :       // (transformation of regrid parameters to frequencies completed)
    3471             :       
    3472             :       // then determine the actually possible parameters
    3473             :       lDouble theRegridCenterF;
    3474             :       lDouble theRegridBWF;
    3475             :       lDouble theCentralChanWidthF;
    3476             :       
    3477             :       // for vrad and vopt also need to keep this adjusted value
    3478        1353 :       lDouble theChanWidthX = -1.;
    3479             : 
    3480        1353 :       if(regridCenterF < 0.){ //  means "not set"
    3481             :         // keep regrid center as it is in the data
    3482           7 :         theRegridCenterF = (transNewXin[0] - transCHAN_WIDTH[0]/2. 
    3483           7 :                             + transNewXin[oldNUM_CHAN-1]+transCHAN_WIDTH[oldNUM_CHAN-1]/2.)/2.;
    3484           7 :         centerIsStart = false;
    3485             :       }
    3486             :       else { // regridCenterF was set
    3487             :         // keep center in limits
    3488        1346 :         theRegridCenterF = regridCenterF;
    3489        1346 :         if( (theRegridCenterF - (transNewXin[oldNUM_CHAN-1]+transCHAN_WIDTH[oldNUM_CHAN-1]/2.)) > 1. ){ // 1 Hz tolerance
    3490           0 :           oss << "*** Requested center of SPW " << theRegridCenterF << " Hz is too large by "
    3491           0 :               << theRegridCenterF - transNewXin[oldNUM_CHAN-1]+transCHAN_WIDTH[oldNUM_CHAN-1]/2. << " Hz\n";
    3492           0 :           theRegridCenterF = transNewXin[oldNUM_CHAN-1]+transCHAN_WIDTH[oldNUM_CHAN-1]/2.;
    3493           0 :           oss << "*** Reset to maximum possible value " <<  theRegridCenterF  << " Hz";
    3494             :         }
    3495        1346 :         else if( theRegridCenterF < (transNewXin[0]-transCHAN_WIDTH[0]/2.)  ){ 
    3496          15 :           Double diff = (transNewXin[0]-transCHAN_WIDTH[0]/2.) - theRegridCenterF;
    3497             :           // cope with numerical accuracy problems
    3498          15 :           if(diff>1.){
    3499           6 :             oss << "*** Requested center of SPW " << theRegridCenterF << " Hz is smaller than minimum possible value";
    3500           6 :             oss << " by " << diff << " Hz";
    3501             :           }  
    3502          15 :           theRegridCenterF = transNewXin[0]-transCHAN_WIDTH[0]/2.;
    3503          15 :           if(diff>1.){
    3504           6 :             oss << "\n*** Reset to minimum possible value " <<  theRegridCenterF  << " Hz";
    3505             :           }
    3506             :         }
    3507             :       }
    3508        1353 :       if(regridBandwidthF<=0.|| nchan!=0){ // "not set" or use nchan instead
    3509             :         // keep bandwidth as is
    3510        1341 :         theRegridBWF = transNewXin[oldNUM_CHAN-1] - transNewXin[0] 
    3511        1341 :           + transCHAN_WIDTH[0]/2. + transCHAN_WIDTH[oldNUM_CHAN-1]/2.;
    3512        1341 :         if(nchan!=0){ // use nchan parameter if available
    3513        1341 :           if(nchan<0){
    3514         437 :             if(regridQuant=="freq" || regridQuant=="vrad"){ // i.e. equidistant in freq
    3515             :               // define via width of first channel to avoid numerical problems
    3516         436 :               if(regridChanWidthF <= 0.){ // channel width not set
    3517           4 :                 theRegridBWF = transCHAN_WIDTH[0]*floor((theRegridBWF+transCHAN_WIDTH[0]*0.01)/transCHAN_WIDTH[0]);
    3518             :               }
    3519             :               else{
    3520         432 :                 theRegridBWF = regridChanWidthF*floor((theRegridBWF+regridChanWidthF*0.01)/regridChanWidthF);
    3521             :               }
    3522             :             }
    3523             :           }
    3524         904 :           else if(regridChanWidthF <= 0.){ // channel width not set
    3525          18 :             theRegridBWF = transCHAN_WIDTH[0]*nchan;
    3526             :           }
    3527             :           else{ 
    3528         886 :             theRegridBWF = regridChanWidthF*nchan;
    3529             :           }
    3530             : 
    3531        1341 :           if(regridCenterF <= 0.|| regridCenter <-C::c ){ // center was not set by user but calculated
    3532             :             // need to update
    3533          20 :             theRegridCenterF = transNewXin[0] - transCHAN_WIDTH[0]/2. + theRegridBWF/2.;
    3534          20 :             centerIsStart = false;
    3535             :           }
    3536        1321 :           else if(nchan<0){ // center but not nchan was set by user
    3537             :             // verify that the bandwidth is correct
    3538         429 :             if(centerIsStart){
    3539         429 :               if(startIsEnd){
    3540          25 :                 theRegridBWF = theRegridCenterF - transNewXin[0] + transCHAN_WIDTH[0]/2.;
    3541             :               }
    3542             :               else{ // start is start
    3543         404 :                 theRegridBWF = transNewXin[oldNUM_CHAN-1] + transCHAN_WIDTH[oldNUM_CHAN-1]/2. - theRegridCenterF;
    3544             :               }
    3545         429 :               if(regridQuant=="freq" || regridQuant=="vrad"){ // i.e. equidistant in freq
    3546             :                 // define via width of first channel to avoid numerical problems
    3547         429 :                 if(regridChanWidthF <= 0.){ // channel width not set
    3548           0 :                   theRegridBWF = transCHAN_WIDTH[0]*floor((theRegridBWF+transCHAN_WIDTH[0]*0.01)/transCHAN_WIDTH[0]);
    3549             :                 }
    3550             :                 else{
    3551         429 :                   theRegridBWF = regridChanWidthF*floor((theRegridBWF+regridChanWidthF*0.01)/regridChanWidthF);
    3552             :                 }
    3553             :               }
    3554             :             }
    3555             :             else{ // center is center
    3556           0 :               theRegridBWF = 2. * min((Double)(theRegridCenterF - transNewXin[0] - transCHAN_WIDTH[0]), 
    3557           0 :                                       (Double)(transNewXin[oldNUM_CHAN-1] + transCHAN_WIDTH[oldNUM_CHAN-1] 
    3558           0 :                                                - theRegridCenterF));
    3559             :             }
    3560             :           }
    3561             :         }
    3562             :         // now can convert start to center
    3563        1341 :         if(centerIsStart){
    3564        1267 :           if(startIsEnd){
    3565          34 :             theRegridCenterF = theRegridCenterF - theRegridBWF/2.;
    3566             :           }
    3567             :           else{
    3568        1233 :             theRegridCenterF = theRegridCenterF + theRegridBWF/2.;
    3569             :           }
    3570        1267 :           centerIsStart = false;
    3571             :         }
    3572             :       }
    3573             :       else { // regridBandwidthF was set
    3574             :         // determine actually possible bandwidth:
    3575             :         // width will be truncated to the maximum width possible symmetrically
    3576             :         // around the value given by "regrid_center"
    3577          12 :         theRegridBWF = regridBandwidthF;
    3578             :         // now can convert start to center
    3579          12 :         if(centerIsStart){
    3580           0 :           if(startIsEnd){
    3581           0 :             theRegridCenterF = theRegridCenterF - theRegridBWF/2.;
    3582             :           }
    3583             :           else{
    3584           0 :             theRegridCenterF = theRegridCenterF + theRegridBWF/2.;
    3585             :           }
    3586           0 :           centerIsStart = false;
    3587             :         }
    3588             :         {
    3589          12 :           Double rangeTol = 1.; // Hz
    3590          12 :           if((regridQuant=="vopt" || regridQuant=="wave")){ // i.e. if the center is the center w.r.t. wavelength
    3591          12 :             rangeTol = transCHAN_WIDTH[0];
    3592             :           }
    3593          12 :           if((theRegridCenterF + theRegridBWF / 2.) -  (transNewXin[oldNUM_CHAN-1] + transCHAN_WIDTH[oldNUM_CHAN-1]/2.) > rangeTol ){
    3594           0 :             oss << " *** Input spectral window exceeds upper end of original window. Adjusting to max. possible value." << endl;    
    3595           0 :             theRegridBWF = min((Double)fabs(transNewXin[oldNUM_CHAN-1] + transCHAN_WIDTH[oldNUM_CHAN-1]/2. - theRegridCenterF),
    3596           0 :                                (Double)fabs(theRegridCenterF - transNewXin[0] + transCHAN_WIDTH[0]/2.)) * 2.;
    3597           0 :             if(theRegridBWF<transCHAN_WIDTH[0]){
    3598           0 :               theRegridCenterF = (transNewXin[0]+transCHAN_WIDTH[oldNUM_CHAN-1]+transCHAN_WIDTH[oldNUM_CHAN-1]/2.-transCHAN_WIDTH[0]/2.)/2.;
    3599           0 :               theRegridBWF = transCHAN_WIDTH[oldNUM_CHAN-1]-transNewXin[0]
    3600           0 :                 +transCHAN_WIDTH[oldNUM_CHAN-1]/2. + transCHAN_WIDTH[0]/2.;
    3601             :             }
    3602             :           }
    3603          12 :           if((theRegridCenterF - theRegridBWF/2.) - (transNewXin[0] - transCHAN_WIDTH[0]/2.) < -rangeTol ){
    3604           0 :             oss << " *** Input spectral window exceeds lower end of original window. Adjusting to max. possible value." << endl;
    3605           0 :             theRegridBWF = min((Double)fabs(transNewXin[oldNUM_CHAN-1] + transCHAN_WIDTH[oldNUM_CHAN-1]/2. - theRegridCenterF),
    3606           0 :                                (Double)fabs(theRegridCenterF - transNewXin[0] + transCHAN_WIDTH[0]/2.)) * 2.;
    3607           0 :             if(theRegridBWF<transCHAN_WIDTH[0]){
    3608           0 :               theRegridCenterF = (transNewXin[0]+transCHAN_WIDTH[oldNUM_CHAN-1]+transCHAN_WIDTH[oldNUM_CHAN-1]/2.-transCHAN_WIDTH[0]/2.)/2.;
    3609           0 :               theRegridBWF = transCHAN_WIDTH[oldNUM_CHAN-1]-transNewXin[0]
    3610           0 :                 +transCHAN_WIDTH[oldNUM_CHAN-1]/2. + transCHAN_WIDTH[0]/2.;
    3611             :             }
    3612             :           }
    3613             :         }
    3614             :       }
    3615        1353 :       if(regridChanWidthF <= 0.){ // "not set"
    3616          23 :         if(nchan!=0 || centerIsStartC){ // use first channel
    3617          23 :           theCentralChanWidthF = transCHAN_WIDTH[0];
    3618             :         }
    3619             :         else{
    3620             :           // keep channel width similar to the old one 
    3621           0 :           theCentralChanWidthF = transCHAN_WIDTH[oldNUM_CHAN/2]; // use channel width from
    3622             :                                                                  // near central channel
    3623             :         }
    3624             :       }
    3625             :       else { // regridChanWidthF was set
    3626             :         // keep in limits
    3627        1330 :         theCentralChanWidthF = regridChanWidthF;
    3628        1330 :         if(theCentralChanWidthF>theRegridBWF){ // too large => make a single channel
    3629           0 :           theCentralChanWidthF = theRegridBWF;
    3630           0 :           oss << " *** Requested new channel width exceeds defined SPW width." << endl
    3631           0 :               << "     Creating a single channel with the defined SPW width." << endl;
    3632             :         }
    3633        1330 :         else if(theCentralChanWidthF<transCHAN_WIDTH[0]){ // check if too small
    3634             :           // determine smallest channel width
    3635          10 :           lDouble smallestChanWidth = 1E30;
    3636          10 :           Int ii = 0;
    3637        1610 :           for(Int i=0; i<oldNUM_CHAN; i++){
    3638        1600 :             if(transCHAN_WIDTH[i] < smallestChanWidth){ 
    3639          10 :               smallestChanWidth = transCHAN_WIDTH[i];
    3640          10 :               ii = i;
    3641             :             }
    3642             :           }
    3643          10 :           if(theCentralChanWidthF < smallestChanWidth - 1.){ // 1 Hz tolerance to cope with numerical accuracy problems
    3644           1 :             oss << " *** Requested new channel width is smaller than smallest original channel width" << endl;
    3645           1 :             oss << "     which is " << smallestChanWidth << " Hz" << endl;
    3646           1 :             if(regridQuant == "vrad"){
    3647           0 :               oss << "     or " << (vrad(transNewXin[ii],regridVeloRestfrq) 
    3648           0 :                                     - vrad(transNewXin[ii]+transCHAN_WIDTH[ii]/2.,regridVeloRestfrq)) * 2. << " m/s";
    3649             :             }
    3650           1 :             if(regridQuant == "vopt"){
    3651           0 :               oss << "     or " << (vopt(transNewXin[ii],regridVeloRestfrq) 
    3652           0 :                                     - vopt(transNewXin[ii]+transCHAN_WIDTH[ii]/2.,regridVeloRestfrq)) * 2. << " m/s";
    3653             :             }
    3654           1 :             message = oss.str();
    3655           1 :             return false;  
    3656             :           }
    3657             :           else { // input channel width was OK, memorize
    3658           9 :             theChanWidthX = regridChanWidth;
    3659             :           }
    3660             :         }           
    3661             :       }
    3662             : 
    3663        1352 :       oss << " Channels equidistant in " << regridQuant << endl
    3664        1352 :           << " Central frequency (in output frame) = " << theRegridCenterF
    3665        1352 :           << " Hz";
    3666        1352 :       if(regridQuant == "vrad"){
    3667          66 :         oss << " == " << vrad(theRegridCenterF, regridVeloRestfrq) << " m/s radio velocity";
    3668             :       }
    3669        1286 :       else if(regridQuant == "vopt"){
    3670          13 :         oss << " == " << vopt(theRegridCenterF, regridVeloRestfrq) << " m/s optical velocity";
    3671             :       }      
    3672        1273 :       else if(regridQuant == "wave"){
    3673           0 :         oss << " == " << lambda(theRegridCenterF) << " m wavelength";
    3674             :       }
    3675        1352 :       oss << endl;
    3676             : 
    3677        1352 :       if(isDescending){
    3678          28 :         oss << " Channel central frequency is decreasing with increasing channel number." << endl;
    3679             :       }
    3680             : 
    3681        1352 :       oss << " Width of central channel (in output frame) = "
    3682        1352 :           << theCentralChanWidthF << " Hz";
    3683        1352 :       if(regridQuant == "vrad"){
    3684          66 :         oss << " == " << vrad(theRegridCenterF - theCentralChanWidthF, regridVeloRestfrq) 
    3685          66 :           -  vrad(theRegridCenterF, regridVeloRestfrq) << " m/s radio velocity";
    3686             :       }
    3687        1286 :       else if(regridQuant == "vopt"){
    3688          13 :         oss << " == " << vopt(theRegridCenterF - theCentralChanWidthF, regridVeloRestfrq) 
    3689          13 :           - vopt(theRegridCenterF, regridVeloRestfrq) << " m/s optical velocity";
    3690             :       }      
    3691        1273 :       else if(regridQuant == "wave"){
    3692           0 :         oss << " == " << lambda(theRegridCenterF - theCentralChanWidthF) - lambda(theRegridCenterF) << " m wavelength";
    3693             :       }
    3694        1352 :       oss << endl;
    3695             :        
    3696             :       // now calculate newChanLoBound, and newChanHiBound from
    3697             :       // theRegridCenterF, theRegridBWF, theCentralChanWidthF
    3698        1352 :       vector<lDouble> loFBup; // the lower bounds for the new channels 
    3699             :                              // starting from the central channel going up
    3700        1352 :       vector<lDouble> hiFBup; // the lower bounds for the new channels 
    3701             :                              // starting from the central channel going up
    3702        1352 :       vector<lDouble> loFBdown; // the lower bounds for the new channels
    3703             :                                // starting from the central channel going down
    3704        1352 :       vector<lDouble> hiFBdown; // the lower bounds for the new channels
    3705             :                                // starting from the central channel going down
    3706             :       
    3707        1352 :       lDouble edgeTolerance = theCentralChanWidthF*0.01; // needed to avoid numerical accuracy problems
    3708             : 
    3709        1352 :       if(regridQuant=="vrad"){
    3710             :         // regridding in radio velocity ...
    3711             :         
    3712             :         // create freq boundaries equidistant and contiguous in radio velocity
    3713          66 :         lDouble upperEndF = theRegridCenterF + theRegridBWF/2.;
    3714          66 :         lDouble lowerEndF = theRegridCenterF - theRegridBWF/2.;
    3715          66 :         lDouble upperEndV = vrad(upperEndF,regridVeloRestfrq);
    3716          66 :         lDouble lowerEndV = vrad(lowerEndF,regridVeloRestfrq);
    3717             :         lDouble velLo;
    3718             :         lDouble velHi;
    3719             : 
    3720             : 
    3721             :         //    Want to keep the center of the center channel at the center of
    3722             :         //    the new center channel if the bandwidth is an odd multiple of the
    3723             :         //    new channel width,
    3724             :         //    otherwise the center channel is the lower edge of the new center channel
    3725          66 :         lDouble tnumChan = floor((theRegridBWF+edgeTolerance)/theCentralChanWidthF);
    3726          66 :         if((Int)tnumChan % 2 != 0 ){
    3727             :           // odd multiple 
    3728          25 :           loFBup.push_back(theRegridCenterF-theCentralChanWidthF/2.);
    3729          25 :           hiFBup.push_back(theRegridCenterF+theCentralChanWidthF/2.);
    3730          25 :           loFBdown.push_back(theRegridCenterF-theCentralChanWidthF/2.);
    3731          25 :           hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF/2.);
    3732             :         }
    3733             :         else{
    3734          41 :           loFBup.push_back(theRegridCenterF);
    3735          41 :           hiFBup.push_back(theRegridCenterF+theCentralChanWidthF);
    3736          41 :           loFBdown.push_back(theRegridCenterF);
    3737          41 :           hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF);
    3738             :         }
    3739             : 
    3740          66 :         if(theChanWidthX<0){ // cannot use original channel width in velocity units
    3741             :           // need to calculate back from central channel width in Hz
    3742         114 :           theChanWidthX = vrad(loFBup[0],
    3743          57 :                                regridVeloRestfrq) - vrad(hiFBup[0],
    3744             :                                                          regridVeloRestfrq);
    3745             :         }
    3746             :         // calc velocity corresponding to the upper end (in freq) of the last
    3747             :         // added channel which is the lower end of the next channel
    3748          66 :         velLo = vrad(hiFBup[0],regridVeloRestfrq);
    3749             :         // calc velocity corresponding to the upper end (in freq) of the next channel
    3750          66 :         velHi = velLo - theChanWidthX; // vrad goes down as freq goes up!
    3751        5351 :         while(upperEndV - theChanWidthX/10. < velHi){ // (preventing accuracy problems)
    3752             :           // calc frequency of the upper end (in freq) of the next channel
    3753        5285 :           lDouble freqHi = freq_from_vrad(velHi,regridVeloRestfrq);
    3754        5285 :           if(freqHi<=upperEndF+edgeTolerance){ // end of bandwidth not yet reached
    3755        5285 :             loFBup.push_back(hiFBup.back());
    3756        5285 :             hiFBup.push_back(freqHi);
    3757             :           }
    3758           0 :           else if(freqHi<upperEndF+edgeTolerance){ 
    3759           0 :             loFBup.push_back(hiFBup.back());
    3760           0 :             hiFBup.push_back(upperEndF);
    3761           0 :             break;
    3762             :           }
    3763             :           else{
    3764           0 :             break;
    3765             :           }
    3766             :           // calc velocity corresponding to the upper end (in freq) of the added channel
    3767        5285 :           velLo = vrad(hiFBup.back(),regridVeloRestfrq);
    3768             :           // calc velocity corresponding to the upper end (in freq) of the next channel
    3769        5285 :           velHi = velLo - theChanWidthX; // vrad goes down as freq goes up
    3770             :         }
    3771             : 
    3772             :         // calc velocity corresponding to the lower end (in freq) of the last
    3773             :         // added channel which is the upper end of the next channel
    3774          66 :         velHi = vrad(loFBdown[0],regridVeloRestfrq);
    3775             :         // calc velocity corresponding to the lower end (in freq) of the next channel
    3776          66 :         velLo = velHi + theChanWidthX; // vrad goes up as freq goes down!
    3777        5392 :         while(velLo < lowerEndV + theChanWidthX/10.){ // (preventing accuracy problems)  
    3778             :           // calc frequency of the lower end (in freq) of the next channel
    3779        5326 :           lDouble freqLo = freq_from_vrad(velLo,regridVeloRestfrq);
    3780        5326 :           if(freqLo>=lowerEndF-edgeTolerance){ // end of bandwidth not yet reached
    3781        5326 :             hiFBdown.push_back(loFBdown.back());
    3782        5326 :             loFBdown.push_back(freqLo);
    3783             :           }
    3784           0 :           else if(freqLo>lowerEndF-edgeTolerance){ 
    3785           0 :             hiFBdown.push_back(loFBdown.back());
    3786           0 :             loFBdown.push_back(lowerEndF);
    3787           0 :             break;
    3788             :           }
    3789             :           else {
    3790           0 :             break;
    3791             :           }
    3792             :           // calc velocity corresponding to the upper end of the next channel
    3793        5326 :           velHi = vrad(loFBdown.back(),regridVeloRestfrq);
    3794             :           // calc velocity corresponding to the lower end (in freq) of the next channel
    3795        5326 :           velLo = velHi + theChanWidthX; // vrad goes up as freq goes down
    3796             :         }         
    3797             :       }
    3798        1286 :       else if(regridQuant=="vopt"){
    3799             :         // regridding in optical velocity ...
    3800             :         
    3801             :         // create freq boundaries equidistant and contiguous in optical velocity
    3802          13 :         lDouble upperEndF = theRegridCenterF + theRegridBWF/2.;
    3803          13 :         lDouble lowerEndF = theRegridCenterF - theRegridBWF/2.;
    3804          13 :         lDouble upperEndV = vopt(upperEndF,regridVeloRestfrq);
    3805          13 :         lDouble lowerEndV = vopt(lowerEndF,regridVeloRestfrq);
    3806             :         lDouble velLo;
    3807             :         lDouble velHi;
    3808             : 
    3809             :         //    Want to keep the center of the center channel at the center of
    3810             :         //    the new center channel if the bandwidth is an odd multiple of the
    3811             :         //    new channel width,
    3812             :         //    otherwise the center channel is the lower edge of the new center
    3813             :         //    channel
    3814             : 
    3815             :         // enlarged edge tolerance since channels non-equidistant in freq
    3816          13 :         lDouble tnumChan = floor((theRegridBWF+edgeTolerance)/theCentralChanWidthF); 
    3817          13 :         if((Int)tnumChan % 2 != 0 ){
    3818             :           // odd multiple 
    3819           9 :           loFBup.push_back(theRegridCenterF-theCentralChanWidthF/2.);
    3820           9 :           hiFBup.push_back(theRegridCenterF+theCentralChanWidthF/2.);
    3821           9 :           loFBdown.push_back(theRegridCenterF-theCentralChanWidthF/2.);
    3822           9 :           hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF/2.);
    3823             :         }
    3824             :         else{
    3825           4 :           loFBup.push_back(theRegridCenterF);
    3826           4 :           hiFBup.push_back(theRegridCenterF+theCentralChanWidthF);
    3827           4 :           loFBdown.push_back(theRegridCenterF);
    3828           4 :           hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF);
    3829             :         }
    3830             : 
    3831          13 :         if(theChanWidthX<0){ // cannot use original channel width in velocity units
    3832             :           // need to calculate back from central channel width in Hz
    3833          26 :           theChanWidthX = vopt(loFBup[0],
    3834          13 :                                regridVeloRestfrq) - vopt(hiFBup[0],regridVeloRestfrq);
    3835             :         }
    3836             :         // calc velocity corresponding to the upper end (in freq) of the last
    3837             :         // added channel which is the lower end of the next channel
    3838          13 :         velLo = vopt(hiFBup[0],regridVeloRestfrq);
    3839             :         // calc velocity corresponding to the upper end (in freq) of the next channel
    3840          13 :         velHi = velLo - theChanWidthX; // vopt goes down as freq goes up!
    3841         166 :         while(upperEndV - velHi < theChanWidthX/10.){ // (preventing accuracy problems)
    3842             :           // calc frequency of the upper end (in freq) of the next channel
    3843         154 :           lDouble freqHi = freq_from_vopt(velHi,regridVeloRestfrq);
    3844         154 :           if(freqHi<=upperEndF+edgeTolerance){ // end of bandwidth not yet reached
    3845         153 :             loFBup.push_back(hiFBup.back());
    3846         153 :             hiFBup.push_back(freqHi);
    3847             :           }
    3848           1 :           else if(freqHi<upperEndF+edgeTolerance){ 
    3849           0 :             loFBup.push_back(hiFBup.back());
    3850           0 :             hiFBup.push_back(upperEndF);
    3851           1 :             break;
    3852             :           }
    3853             :           else{
    3854           1 :             break;
    3855             :           }
    3856             :           // calc velocity corresponding to the upper end (in freq) of the added channel
    3857         153 :           velLo = vopt(hiFBup.back(),regridVeloRestfrq);
    3858             :           // calc velocity corresponding to the upper end (in freq) of the next channel
    3859         153 :           velHi = velLo - theChanWidthX; // vopt goes down as freq goes up
    3860             :         }
    3861             : 
    3862             :         // calc velocity corresponding to the lower end (in freq) of the last
    3863             :         // added channel which is the upper end of the next channel
    3864          13 :         velHi = vopt(loFBdown[0],regridVeloRestfrq);
    3865             :         // calc velocity corresponding to the lower end (in freq) of the next channel
    3866          13 :         velLo = velHi + theChanWidthX; // vopt goes up as freq goes down!
    3867         171 :         while(velLo - lowerEndV < theChanWidthX/10.){ // (preventing accuracy problems)  
    3868             :           // calc frequency of the lower end (in freq) of the next channel
    3869         158 :           lDouble freqLo = freq_from_vopt(velLo,regridVeloRestfrq);
    3870         158 :           if(freqLo>=lowerEndF-edgeTolerance){ // end of bandwidth not yet reached
    3871         158 :             hiFBdown.push_back(loFBdown.back());
    3872         158 :             loFBdown.push_back(freqLo);
    3873             :           }
    3874           0 :           else if(freqLo>lowerEndF-edgeTolerance){ 
    3875           0 :             hiFBdown.push_back(loFBdown.back());
    3876           0 :             loFBdown.push_back(lowerEndF);
    3877           0 :             break;
    3878             :           }
    3879             :           else {
    3880           0 :             break;
    3881             :           }
    3882             :           // calc velocity corresponding to the upper end of the next channel
    3883         158 :           velHi = vopt(loFBdown.back(),regridVeloRestfrq);
    3884             :           // calc velocity corresponding to the lower end (in freq) of the next channel
    3885         158 :           velLo = velHi + theChanWidthX; // vopt goes up as freq goes down
    3886             :         }         
    3887             :       }
    3888        1273 :       else if(regridQuant=="freq"){
    3889             :         // regridding in frequency  ...
    3890             :         
    3891             :         // create freq boundaries equidistant and contiguous in frequency
    3892        1273 :         lDouble upperEndF = theRegridCenterF + theRegridBWF/2.;
    3893        1273 :         lDouble lowerEndF = theRegridCenterF - theRegridBWF/2.;
    3894             : 
    3895             :         //    Want to keep the center of the center channel at the center of
    3896             :         //    the new center channel if the bandwidth is an odd multiple of the
    3897             :         //    new channel width, 
    3898             :         //    otherwise the center channel is the lower edge of the new center channel
    3899        1273 :         lDouble tnumChan = floor((theRegridBWF+edgeTolerance)/theCentralChanWidthF);
    3900             : 
    3901             :         //cout << "theRegridBWF " << theRegridBWF << " upperEndF " << upperEndF << " lowerEndF " << lowerEndF << " tnumChan " << tnumChan << endl;
    3902             : 
    3903        1273 :         if((Int) tnumChan % 2 != 0){
    3904             :           // odd multiple 
    3905         587 :           loFBup.push_back(theRegridCenterF-theCentralChanWidthF/2.);
    3906         587 :           hiFBup.push_back(theRegridCenterF+theCentralChanWidthF/2.);
    3907         587 :           loFBdown.push_back(theRegridCenterF-theCentralChanWidthF/2.);
    3908         587 :           hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF/2.);
    3909             :         }
    3910             :         else{
    3911         686 :           loFBup.push_back(theRegridCenterF);
    3912         686 :           hiFBup.push_back(theRegridCenterF+theCentralChanWidthF);
    3913         686 :           loFBdown.push_back(theRegridCenterF);
    3914         686 :           hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF);
    3915             :         }
    3916             : 
    3917       66050 :         while(hiFBup.back()< upperEndF+edgeTolerance){
    3918             :           // calc frequency of the upper end of the next channel
    3919       66050 :           lDouble freqHi = hiFBup.back() + theCentralChanWidthF;
    3920       66050 :           if(freqHi<=upperEndF+edgeTolerance){ // end of bandwidth not yet reached
    3921       64777 :             loFBup.push_back(hiFBup.back());
    3922       64777 :             hiFBup.push_back(freqHi);
    3923             :           }
    3924             :           else{
    3925        1273 :             break;
    3926             :           }
    3927             :         }
    3928             : 
    3929       66736 :         while(loFBdown.back() > lowerEndF-edgeTolerance){
    3930             :           // calc frequency of the lower end of the next channel
    3931       66736 :           lDouble freqLo = loFBdown.back() - theCentralChanWidthF;
    3932       66736 :           if(freqLo>=lowerEndF-edgeTolerance){ // end of bandwidth not yet reached
    3933       65463 :             hiFBdown.push_back(loFBdown.back());
    3934       65463 :             loFBdown.push_back(freqLo);
    3935             :           }
    3936             :           else {
    3937        1273 :             break;
    3938             :           }
    3939             :         }         
    3940             :       }
    3941           0 :       else if(regridQuant=="wave"){
    3942             :         // regridding in wavelength  ...
    3943             :         
    3944             :         // create freq boundaries equidistant and contiguous in wavelength
    3945           0 :         lDouble upperEndF = theRegridCenterF + theRegridBWF/2.;
    3946           0 :         lDouble lowerEndF = theRegridCenterF - theRegridBWF/2.;
    3947           0 :         lDouble upperEndL = lambda(upperEndF);
    3948           0 :         lDouble lowerEndL = lambda(lowerEndF);
    3949             :         lDouble lambdaLo;
    3950             :         lDouble lambdaHi;
    3951             : 
    3952             :         //    Want to keep the center of the center channel at the center of
    3953             :         //    the new center channel if the bandwidth is an odd multiple of the
    3954             :         //    new channel width, 
    3955             :         //    otherwise the center channel is the lower edge of the new center
    3956             :         //    channel
    3957           0 :         lDouble tnumChan = floor((theRegridBWF+edgeTolerance)/theCentralChanWidthF);
    3958           0 :         if((Int)tnumChan % 2 != 0){
    3959             :           // odd multiple 
    3960           0 :           loFBup.push_back(theRegridCenterF-theCentralChanWidthF/2.);
    3961           0 :           hiFBup.push_back(theRegridCenterF+theCentralChanWidthF/2.);
    3962           0 :           loFBdown.push_back(theRegridCenterF-theCentralChanWidthF/2.);
    3963           0 :           hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF/2.);
    3964             :         }
    3965             :         else{
    3966           0 :           loFBup.push_back(theRegridCenterF);
    3967           0 :           hiFBup.push_back(theRegridCenterF+theCentralChanWidthF);
    3968           0 :           loFBdown.push_back(theRegridCenterF);
    3969           0 :           hiFBdown.push_back(theRegridCenterF+theCentralChanWidthF);
    3970             :         }
    3971             : 
    3972           0 :         if(theChanWidthX<0){ // cannot use original channel width in wavelength units
    3973             :           // need to calculate back from central channel width in Hz
    3974           0 :           theChanWidthX = lambda(loFBup[0]) - lambda(hiFBup[0]);
    3975             :         }
    3976             :         // calc wavelength corresponding to the upper end (in freq) of the last
    3977             :         // added channel which is the lower end of the next channel
    3978           0 :         lambdaLo = lambda(hiFBup[0]);
    3979             :         // calc wavelength corresponding to the upper end (in freq) of the next channel
    3980           0 :         lambdaHi = lambdaLo - theChanWidthX; // lambda goes down as freq goes up!
    3981           0 :         while(upperEndL - lambdaHi < theChanWidthX/10.){ // (preventing accuracy problems)
    3982             :           // calc frequency of the upper end (in freq) of the next channel
    3983           0 :           lDouble freqHi = freq_from_lambda(lambdaHi);
    3984           0 :           if(freqHi<=upperEndF+edgeTolerance){ // end of bandwidth not yet reached
    3985           0 :             loFBup.push_back(hiFBup.back());
    3986           0 :             hiFBup.push_back(freqHi);
    3987             :           }
    3988           0 :           else if(freqHi<upperEndF+edgeTolerance){ 
    3989           0 :             loFBup.push_back(hiFBup.back());
    3990           0 :             hiFBup.push_back(upperEndF);
    3991           0 :             break;
    3992             :           }
    3993             :           else{
    3994           0 :             break;
    3995             :           }
    3996             :           // calc wavelength corresponding to the upper end (in freq) of the
    3997             :           // added channel
    3998           0 :           lambdaLo = lambda(hiFBup.back());
    3999             :           // calc wavelength corresponding to the upper end (in freq) of the next channel
    4000           0 :           lambdaHi = lambdaLo - theChanWidthX; // lambda goes down as freq goes up
    4001             :         }
    4002             : 
    4003             :         // calc wavelength corresponding to the lower end (in freq) of the last
    4004             :         // added channel which is the upper end of the next channel
    4005           0 :         lambdaHi = lambda(loFBdown[0]);
    4006             :         // calc wavelength corresponding to the lower end (in freq) of the next channel
    4007           0 :         lambdaLo = lambdaHi + theChanWidthX; // lambda goes up as freq goes down!
    4008           0 :         while(lambdaLo - lowerEndL < theChanWidthX/10.){  // (preventing accuracy problems) 
    4009             :           // calc frequency of the lower end (in freq) of the next channel
    4010           0 :           lDouble freqLo = freq_from_lambda(lambdaLo);
    4011           0 :           if(freqLo>=lowerEndF-edgeTolerance){ // end of bandwidth not yet reached
    4012           0 :             hiFBdown.push_back(loFBdown.back());
    4013           0 :             loFBdown.push_back(freqLo);
    4014             :           }
    4015           0 :           else if(freqLo>lowerEndF-edgeTolerance){ 
    4016           0 :             hiFBdown.push_back(loFBdown.back());
    4017           0 :             loFBdown.push_back(lowerEndF);
    4018           0 :             break;
    4019             :           }
    4020             :           else {
    4021           0 :             break;
    4022             :           }
    4023             :           // calc wavelength corresponding to the upper end of the next channel
    4024           0 :           lambdaHi = lambda(loFBdown.back());
    4025             :           // calc wavelength corresponding to the lower end (in freq) of the next channel
    4026           0 :           lambdaLo = lambdaHi + theChanWidthX; // wavelength goes up as freq goes down
    4027             :         }         
    4028             : 
    4029             :       }
    4030             :       else{ // should not get here
    4031           0 :         oss << "Invalid value " << regridQuant << " for parameter \"mode\".";
    4032           0 :         message = oss.str();
    4033           0 :         return false;
    4034             :       }
    4035             : 
    4036        1352 :       Int numNewChanDown = loFBdown.size();
    4037        1352 :       Int numNewChanUp = loFBup.size();
    4038             : 
    4039             :       // central channel contained in both vectors
    4040        1352 :       newChanLoBound.resize(numNewChanDown+numNewChanUp - 1);
    4041             : 
    4042        1352 :       newChanHiBound.resize(numNewChanDown+numNewChanUp - 1);
    4043       73651 :       for(Int i=0; i<numNewChanDown; i++){ 
    4044       72299 :         Int k = numNewChanDown-i-1; // need to assign in reverse
    4045       72299 :         newChanLoBound[i] = loFBdown[k];
    4046       72299 :         newChanHiBound[i] = hiFBdown[k];
    4047             :       }
    4048       71567 :       for(Int i=1; i<numNewChanUp; i++){ // start at 1 to omit the central channel here
    4049       70215 :         newChanLoBound[i+numNewChanDown-1] = loFBup[i];
    4050       70215 :         newChanHiBound[i+numNewChanDown-1] = hiFBup[i];
    4051             :       }
    4052             :       
    4053        1352 :       uInt nc = newChanLoBound.size();
    4054        1352 :       oss << " Number of channels = " << nc << endl;
    4055        1352 :       oss << " Total width of SPW (in output frame) = " << newChanHiBound[nc-1] - newChanLoBound[0] 
    4056        1352 :           << " Hz" << endl;
    4057        1352 :       oss << " Lower edge = " << newChanLoBound[0] << " Hz,"
    4058        1352 :           << " upper edge = " << newChanHiBound[nc-1] << " Hz" << endl;
    4059             : 
    4060        1352 :       if(isDescending){ // original SPW was in reverse order; need to restore that
    4061          28 :         Vector<Double> tempL, tempU;
    4062          28 :         tempL.assign(newChanLoBound);
    4063          28 :         tempU.assign(newChanHiBound);
    4064       18430 :         for(uInt i=0; i<nc; i++){
    4065       18402 :           newChanLoBound(i) = tempL(nc-1-i);
    4066       18402 :           newChanHiBound(i) = tempU(nc-1-i);
    4067             :         }
    4068          28 :       }
    4069             : 
    4070        1352 :       message = oss.str();
    4071             : 
    4072        1352 :       return true;
    4073             :       
    4074        1352 :     } // end if (regridQuant== ...
    4075             : 
    4076        1356 :   }
    4077             : 
    4078        1304 :   Bool SubMS::convertGridPars(LogIO& os,
    4079             :                               const String& mode, 
    4080             :                               const int nchan, 
    4081             :                               const String& start, 
    4082             :                               const String& width,
    4083             :                               const String& interp, 
    4084             :                               const String& restfreq, 
    4085             :                               const String& outframe,
    4086             :                               const String& veltype,
    4087             :                               String& t_mode,
    4088             :                               String& t_outframe,
    4089             :                               String& t_regridQuantity,
    4090             :                               Double& t_restfreq,
    4091             :                               String& t_regridInterpMeth,
    4092             :                               Double& t_cstart, 
    4093             :                               Double& t_bandwidth,
    4094             :                               Double& t_cwidth,
    4095             :                               Bool& t_centerIsStart, 
    4096             :                               Bool& t_startIsEnd,                         
    4097             :                               Int& t_nchan,
    4098             :                               Int& t_width,
    4099             :                               Int& t_start
    4100             :                               ){
    4101        1304 :     Bool rstat(false);
    4102             :     
    4103             :     try {
    4104             :       
    4105        1304 :       os << LogOrigin("SubMS", "convertGridPars");
    4106             :       
    4107        1304 :       casacore::QuantumHolder qh;
    4108        1304 :       String error;
    4109             : 
    4110        1304 :       t_mode = mode;
    4111        1304 :       t_restfreq = 0.; 
    4112        1304 :       if(!restfreq.empty() && !(restfreq=="[]")){
    4113        1014 :         if(qh.fromString(error, restfreq)){
    4114        1014 :           t_restfreq = qh.asQuantity().getValue("Hz");
    4115             :         }
    4116             :         else{
    4117           0 :           os << LogIO::SEVERE  << "restfreq: " << error << LogIO::POST;         
    4118           0 :           return false;
    4119             :         }
    4120             :       }
    4121             :       
    4122             :       // Determine grid
    4123        1304 :       t_cstart = -9e99; // default value indicating that the original start of the SPW should be used
    4124        1304 :       t_bandwidth = -1.; // default value indicating that the original width of the SPW should be used
    4125        1304 :       t_cwidth = -1.; // default value indicating that the original channel width of the SPW should be used
    4126        1304 :       t_nchan = -1; 
    4127        1304 :       t_width = 0;
    4128        1304 :       t_start = -1;
    4129        1304 :       t_startIsEnd = false; // false means that start specifies the lower end in frequency (default)
    4130             :       // true means that start specifies the upper end in frequency
    4131             : 
    4132        1304 :       if(!start.empty() && !(start=="[]")){ // start was set
    4133        1289 :         if(t_mode == "channel"){
    4134        1180 :           t_start = atoi(start.c_str());
    4135             :         }
    4136        1289 :         if(t_mode == "channel_b"){
    4137           2 :           t_cstart = Double(atoi(start.c_str()));
    4138             :         }
    4139        1287 :         else if(t_mode == "frequency"){
    4140          50 :           if(qh.fromString(error, start)){
    4141          50 :             t_cstart = qh.asQuantity().getValue("Hz");
    4142             :           }
    4143             :           else{
    4144           0 :             os << LogIO::SEVERE  << "start: " << error << LogIO::POST;          
    4145           0 :             return false;
    4146             :           }     
    4147             :         }
    4148        1237 :         else if(t_mode == "velocity"){
    4149          57 :           if(qh.fromString(error, start)){
    4150          57 :             t_cstart = qh.asQuantity().getValue("m/s");
    4151             :           }
    4152             :           else{
    4153           0 :             os << LogIO::SEVERE << "start: " << error << LogIO::POST;           
    4154           0 :             return false;
    4155             :           }     
    4156             :         }
    4157             :       }
    4158        1304 :       if(!width.empty() && !(width=="[]")){ // channel width was set
    4159        1291 :         if(t_mode == "channel"){
    4160        1180 :           Int w = atoi(width.c_str());
    4161        1180 :           t_width = abs(w);
    4162        1180 :           if(w<0){
    4163           2 :             t_startIsEnd = true;
    4164             :           }
    4165             :         }
    4166         111 :         else if(t_mode == "channel_b"){
    4167           2 :           Double w = atoi(width.c_str());
    4168           2 :           t_cwidth = abs(w);
    4169           2 :           if(w<0){
    4170           0 :             t_startIsEnd = true;
    4171             :           }     
    4172             :         }
    4173         109 :         else if(t_mode == "frequency"){
    4174          50 :           if(qh.fromString(error, width)){
    4175          50 :             Double w = qh.asQuantity().getValue("Hz");
    4176          50 :             t_cwidth = abs(w);
    4177          50 :             if(w<0){
    4178           4 :               t_startIsEnd = true;
    4179             :             }   
    4180             :           }
    4181             :           else{
    4182           0 :             os << LogIO::SEVERE << "width: " << error << LogIO::POST;           
    4183           0 :             return false;
    4184             :           }     
    4185             :         }
    4186          59 :         else if(t_mode == "velocity"){
    4187          59 :           if(qh.fromString(error, width)){
    4188          59 :             Double w = qh.asQuantity().getValue("m/s");
    4189          59 :             t_cwidth = abs(w);
    4190          59 :             if(w>=0){
    4191          55 :               t_startIsEnd = true; 
    4192             :             }           
    4193             :           }
    4194             :           else{
    4195           0 :             os << LogIO::SEVERE << "width: " << error << LogIO::POST;           
    4196           0 :             return false;           
    4197             :           }
    4198             :         }
    4199             :       }
    4200             :       else{ // width was not set
    4201             :         // for the velocity mode the default t_startIsEnd is true if the sign of width is not known
    4202          13 :         if(t_mode == "velocity"){
    4203           8 :           t_startIsEnd = true;
    4204             :         }
    4205             :       }
    4206             : 
    4207        1304 :       if(nchan > 0){ // number of output channels was set
    4208         880 :         if(t_mode == "channel_b"){
    4209           0 :           if(t_cwidth>0){
    4210           0 :             t_bandwidth = Double(nchan*t_cwidth);
    4211             :           }
    4212             :           else{
    4213           0 :             t_bandwidth = Double(nchan);          
    4214             :           }
    4215             :         }
    4216             :         else{
    4217         880 :           t_nchan = nchan;
    4218             :         }
    4219             :       }
    4220             :       
    4221        1304 :       if(t_mode == "channel"){
    4222        1180 :         t_regridQuantity = "freq";
    4223             :       }
    4224         124 :       else if(t_mode == "channel_b"){
    4225           2 :         t_regridQuantity = "chan";
    4226             :       }
    4227         122 :       else if(t_mode == "frequency"){
    4228          55 :         t_regridQuantity = "freq";
    4229             :       }
    4230          67 :       else if(t_mode == "velocity"){
    4231          67 :         if(t_restfreq == 0.){
    4232           0 :           os << LogIO::SEVERE << "Need to set restfreq in velocity mode." << LogIO::POST; 
    4233           0 :           return false;
    4234             :         }       
    4235          67 :         t_regridQuantity = "vrad";
    4236          67 :         if(veltype == "optical"){
    4237          10 :           t_regridQuantity = "vopt";
    4238             :         }
    4239          57 :         else if(veltype != "radio"){
    4240             :           os << LogIO::WARN << "Invalid velocity type "<< veltype 
    4241           2 :              << ", setting type to \"radio\"" << LogIO::POST; 
    4242             :         }
    4243             :       }   
    4244             :       else{
    4245           0 :         os << LogIO::WARN << "Invalid mode " << t_mode << LogIO::POST;
    4246           0 :         return false;
    4247             :       }
    4248             :       
    4249        1304 :       t_outframe=outframe;
    4250        1304 :       t_regridInterpMeth=interp;
    4251        1304 :       t_centerIsStart = true;
    4252             :             
    4253             :       // end prepare regridding parameters
    4254             :       
    4255        1304 :       rstat = true;
    4256             : 
    4257        1304 :     } catch (AipsError x) {
    4258           0 :       os << LogIO::SEVERE << "Exception Reported: " << x.getMesg() << LogIO::POST;
    4259           0 :       rstat = false;
    4260           0 :     }
    4261        1304 :     return rstat;
    4262             :   }
    4263             : 
    4264             : 
    4265        1250 :   Bool SubMS::calcChanFreqs(LogIO& os,
    4266             :                             Vector<Double>& newCHAN_FREQ, 
    4267             :                             Vector<Double>& newCHAN_WIDTH,
    4268             :                             const Vector<Double>& oldCHAN_FREQ, 
    4269             :                             const Vector<Double>& oldCHAN_WIDTH,
    4270             :                             const MDirection  phaseCenter,
    4271             :                             const MFrequency::Types theOldRefFrame,
    4272             :                             const MEpoch theObsTime,
    4273             :                             const MPosition mObsPos,
    4274             :                             const String& mode, 
    4275             :                             const int nchan, 
    4276             :                             const String& start, 
    4277             :                             const String& width,
    4278             :                             const String& restfreq, 
    4279             :                             const String& outframe,
    4280             :                             const String& veltype,
    4281             :                             const Bool verbose,
    4282             :                             const MRadialVelocity mRV // only used for outframe=="SOURCE"
    4283             :                             ){
    4284             : 
    4285             :     Double weightScale;
    4286        2500 :     return calcChanFreqs(os,
    4287             :                          newCHAN_FREQ, 
    4288             :                          newCHAN_WIDTH,
    4289             :                          weightScale,
    4290             :                          oldCHAN_FREQ, 
    4291             :                          oldCHAN_WIDTH,
    4292             :                          phaseCenter,
    4293             :                          theOldRefFrame,
    4294             :                          theObsTime,
    4295             :                          mObsPos,
    4296             :                          mode, 
    4297             :                          nchan, 
    4298             :                          start, 
    4299             :                          width,
    4300             :                          restfreq, 
    4301             :                          outframe,
    4302             :                          veltype,
    4303             :                          verbose,
    4304             :                          mRV // only used for outframe=="SOURCE"
    4305        2500 :                          );
    4306             :   }
    4307             : 
    4308             : 
    4309        1250 :   Bool SubMS::calcChanFreqs(LogIO& os,
    4310             :                             Vector<Double>& newCHAN_FREQ, 
    4311             :                             Vector<Double>& newCHAN_WIDTH,
    4312             :                             Double& weightScale,
    4313             :                             const Vector<Double>& oldCHAN_FREQ, 
    4314             :                             const Vector<Double>& oldCHAN_WIDTH,
    4315             :                             const MDirection  phaseCenter,
    4316             :                             const MFrequency::Types theOldRefFrame,
    4317             :                             const MEpoch theObsTime,
    4318             :                             const MPosition mObsPos,
    4319             :                             const String& mode, 
    4320             :                             const int nchan, 
    4321             :                             const String& start, 
    4322             :                             const String& width,
    4323             :                             const String& restfreq, 
    4324             :                             const String& outframe,
    4325             :                             const String& veltype,
    4326             :                             const Bool verbose,
    4327             :                             const MRadialVelocity mRV // only used for outframe=="SOURCE"
    4328             :                             ){
    4329             : 
    4330        1250 :     Vector<Double> newChanLoBound; 
    4331        1250 :     Vector<Double> newChanHiBound;
    4332        1250 :     String t_phasec;
    4333             : 
    4334        1250 :     String t_mode;
    4335        1250 :     String t_outframe;
    4336        1250 :     String t_regridQuantity;
    4337             :     Double t_restfreq;
    4338        1250 :     String t_regridInterpMeth;
    4339             :     Double t_cstart;
    4340             :     Double t_bandwidth;
    4341             :     Double t_cwidth;
    4342             :     Bool t_centerIsStart;
    4343             :     Bool t_startIsEnd;
    4344             :     Int t_nchan;
    4345             :     Int t_width;
    4346             :     Int t_start;
    4347             : 
    4348        1250 :     if(!convertGridPars(os,
    4349             :                         mode, 
    4350             :                         nchan, 
    4351             :                         start, 
    4352             :                         width,
    4353             :                         "linear", // a dummy value in this context
    4354             :                         restfreq, 
    4355             :                         outframe,
    4356             :                         veltype,
    4357             :                         ////// output ////
    4358             :                         t_mode,
    4359             :                         t_outframe,
    4360             :                         t_regridQuantity,
    4361             :                         t_restfreq,
    4362             :                         t_regridInterpMeth,
    4363             :                         t_cstart, 
    4364             :                         t_bandwidth,
    4365             :                         t_cwidth,
    4366             :                         t_centerIsStart, 
    4367             :                         t_startIsEnd,                         
    4368             :                         t_nchan,
    4369             :                         t_width,
    4370             :                         t_start
    4371             :                         )
    4372             :        ){
    4373             :       // an error occured
    4374           0 :       return false;
    4375             :     }
    4376             : 
    4377             :     // reference frame transformation
    4378        1250 :     Bool needTransform = true;
    4379        1250 :     Bool doRadVelCorr = false;
    4380             :     MFrequency::Types theFrame;
    4381        1250 :     String oframe = outframe;
    4382        1250 :     oframe.upcase();
    4383        1250 :     if(outframe==""){ // no ref frame given 
    4384             :       // keep the reference frame as is
    4385         901 :       theFrame = theOldRefFrame;
    4386         901 :       needTransform = false;
    4387             :     }
    4388         349 :     else if(oframe=="SOURCE"){ // GEO trafo + radial velocity correction
    4389           8 :       theFrame = MFrequency::GEO;
    4390           8 :       doRadVelCorr = true;
    4391             :     }
    4392         341 :     else if(!MFrequency::getType(theFrame, outframe)){
    4393             :       os << LogIO::SEVERE
    4394             :          << "Parameter \"outframe\" value " << outframe << " is invalid." 
    4395           0 :          << LogIO::POST;
    4396           0 :       return false;
    4397             :     }
    4398         341 :     else if (theFrame == theOldRefFrame){
    4399         110 :       needTransform = false;
    4400             :     }
    4401             : 
    4402        1250 :     uInt oldNUM_CHAN = oldCHAN_FREQ.size();
    4403        1250 :     if(oldNUM_CHAN == 0){
    4404           0 :       newCHAN_FREQ.resize(0);
    4405           0 :       newCHAN_WIDTH.resize(0);
    4406           0 :       return true;
    4407             :     }
    4408             : 
    4409        1250 :     if(oldNUM_CHAN != oldCHAN_WIDTH.size()){
    4410             :       os << LogIO::SEVERE
    4411             :          << "Internal error: inconsistent dimensions of input channel freq and width arrays." 
    4412           0 :          << LogIO::POST;
    4413           0 :       return false;
    4414             :     }      
    4415             : 
    4416        1250 :     Vector<Double> absOldCHAN_WIDTH;
    4417        1250 :     absOldCHAN_WIDTH.assign(oldCHAN_WIDTH);
    4418             :     {
    4419        1250 :       Bool negativeWidths = false;
    4420      332770 :       for(uInt i=0; i<oldCHAN_WIDTH.size(); i++){
    4421      331520 :         if(oldCHAN_WIDTH(i) < 0.){
    4422       10773 :           negativeWidths = true;
    4423       10773 :           absOldCHAN_WIDTH(i) = -oldCHAN_WIDTH(i);
    4424             :         }
    4425             :       }
    4426        1250 :       if(negativeWidths && verbose){
    4427             :         os << LogIO::NORMAL
    4428             :            << " *** Encountered negative channel widths in input spectral window."
    4429           3 :            << LogIO::POST;
    4430             :       }
    4431             :     }
    4432             : 
    4433        1250 :     Vector<Double> transNewXin;
    4434        1250 :     Vector<Double> transCHAN_WIDTH(oldNUM_CHAN);
    4435             : 
    4436        1250 :     if(needTransform){
    4437         239 :       transNewXin.resize(oldNUM_CHAN);
    4438             :       // set up conversion
    4439         239 :       Unit unit(String("Hz"));
    4440         239 :       MFrequency::Ref fromFrame = MFrequency::Ref(theOldRefFrame, MeasFrame(phaseCenter, mObsPos, theObsTime));
    4441         239 :       MFrequency::Ref toFrame = MFrequency::Ref(theFrame, MeasFrame(phaseCenter, mObsPos, theObsTime));
    4442         239 :       MFrequency::Convert freqTrans(unit, fromFrame, toFrame);
    4443             :       
    4444         239 :       MDoppler radVelCorr; // no correction
    4445         239 :       Bool radVelSignificant = false; // is the radial velocity large enough to warrant a shift?
    4446             :       // prepare correction for radial velocity if requested and possible
    4447         239 :       if(doRadVelCorr){
    4448           8 :         Quantity mrv = mRV.get("m/s"); // (const)
    4449           8 :         radVelCorr = MDoppler(-mrv); // NOTE: opposite sign to achieve correction!
    4450           8 :         Double mRVVal = mrv.getValue();
    4451           8 :         if(fabs(mRVVal)>1E-6){
    4452           8 :           radVelSignificant = true;
    4453           8 :           if(verbose){
    4454             :             os << LogIO::NORMAL
    4455             :                << "Note: The given additional radial velocity of " << mRVVal << " m/s will be taken into account."
    4456           0 :                << LogIO::POST;
    4457             :           }
    4458             :         }
    4459           0 :         else if(verbose){
    4460             :           os << LogIO::NORMAL
    4461             :              << "Note: The given additional radial velocity is less than 1E-6 m/s and will not be taken into account."
    4462           0 :              << LogIO::POST;
    4463             :         }
    4464           8 :       } 
    4465             : 
    4466       30465 :       for(uInt i=0; i<oldNUM_CHAN; i++){
    4467       30226 :         transNewXin[i] = freqTrans(oldCHAN_FREQ[i]).get(unit).getValue();
    4468       30226 :         transCHAN_WIDTH[i] = freqTrans(oldCHAN_FREQ[i] +
    4469       60452 :                                        absOldCHAN_WIDTH[i]/2.).get(unit).getValue()
    4470       30226 :           - freqTrans(oldCHAN_FREQ[i] -
    4471       30226 :                       absOldCHAN_WIDTH[i]/2.).get(unit).getValue(); // eliminate possible offsets
    4472             :       }
    4473             : 
    4474         239 :       if(radVelSignificant){ // correct in addition for radial velocity
    4475           8 :         transNewXin  = radVelCorr.shiftFrequency(transNewXin);
    4476           8 :         transCHAN_WIDTH = radVelCorr.shiftFrequency(transCHAN_WIDTH); //shiftFrequency is a scaling, so chan widths scale as well
    4477             :       }
    4478             : 
    4479         239 :     }
    4480             :     else {
    4481             :       // just copy
    4482        1011 :       transNewXin.assign(oldCHAN_FREQ);
    4483        1011 :       transCHAN_WIDTH.assign(absOldCHAN_WIDTH);
    4484             :     }
    4485             : 
    4486             :     // calculate new grid
    4487             : 
    4488        1250 :     String message;
    4489             : 
    4490        1250 :     if(!regridChanBounds(newChanLoBound, 
    4491             :                          newChanHiBound,
    4492             :                          t_cstart,  
    4493             :                          t_bandwidth, 
    4494             :                          t_cwidth, 
    4495             :                          t_restfreq,
    4496             :                          t_regridQuantity,
    4497             :                          transNewXin, 
    4498             :                          transCHAN_WIDTH,
    4499             :                          message,
    4500             :                          t_centerIsStart,
    4501             :                          t_startIsEnd,
    4502             :                          t_nchan,
    4503             :                          t_width,
    4504             :                          t_start
    4505             :                          )
    4506             :        ){ // there was an error
    4507           1 :       os << LogIO::WARN << message << LogIO::POST;
    4508           1 :       return false;
    4509             :     }
    4510             :     
    4511        1249 :     if(verbose){
    4512         124 :       os << LogIO::NORMAL << message << LogIO::POST;
    4513             :     }
    4514             : 
    4515             :     // we have a useful set of channel boundaries
    4516        1249 :     uInt newNUM_CHAN = newChanLoBound.size();
    4517             :     
    4518             :     // complete the calculation of the new channel centers and widths
    4519             :     // from newNUM_CHAN, newChanLoBound, and newChanHiBound 
    4520        1249 :     newCHAN_FREQ.resize(newNUM_CHAN);
    4521        1249 :     newCHAN_WIDTH.resize(newNUM_CHAN);
    4522      115528 :     for(uInt i=0; i<newNUM_CHAN; i++){
    4523      114279 :       newCHAN_FREQ[i] = (newChanLoBound[i]+newChanHiBound[i])/2.;
    4524      114279 :       newCHAN_WIDTH[i] = newChanHiBound[i]-newChanLoBound[i];
    4525             :       //cout << "new lo hi freq width " << newChanLoBound[i] << " " << newChanHiBound[i] << " " << newCHAN_FREQ[i] << " " << newCHAN_WIDTH[i] << endl;
    4526             :     }
    4527             : 
    4528        1249 :     weightScale = newCHAN_WIDTH[0]/transCHAN_WIDTH[0];
    4529             :     
    4530        1249 :     return true;
    4531             : 
    4532        1250 :   }
    4533             :   
    4534             : 
    4535         107 :   Bool SubMS::setRegridParameters(vector<Int>& oldSpwId,
    4536             :                                   vector<Int>& oldFieldId,
    4537             :                                   vector<Int>& newDataDescId,
    4538             :                                   vector<Bool>& regrid,
    4539             :                                   vector<Bool>& transform,
    4540             :                                   vector<MDirection>& theFieldDirV,
    4541             :                                   vector<MPosition>& mObsPosV,
    4542             :                                   vector<MFrequency::Types>& fromFrameTypeV,
    4543             :                                   vector<MFrequency::Ref>& outFrameV,
    4544             :                                   vector<MRadialVelocity>& outRadVelV,
    4545             :                                   vector< Double >& weightScaleV, 
    4546             :                                   vector< Vector<Double> >& xold, 
    4547             :                                   vector< Vector<Double> >& xout, 
    4548             :                                   vector< Vector<Double> >& xin, 
    4549             :                                   vector<Int>& method,
    4550             :                                   Bool& msModified,
    4551             :                                   const String& outframe,
    4552             :                                   const String& regridQuant,
    4553             :                                   const Double regridVeloRestfrq,
    4554             :                                   const String& regridInterpMeth,
    4555             :                                   const Double regridCenter, 
    4556             :                                   const Double regridBandwidth, 
    4557             :                                   const Double regridChanWidth,
    4558             :                                   const Int regridPhaseCenterFieldId,
    4559             :                                   const MDirection regridPhaseCenter,
    4560             :                                   const Bool writeTables,
    4561             :                                   LogIO& os,
    4562             :                                   String& regridMessage,
    4563             :                                   const Bool centerIsStart,
    4564             :                                   const Bool startIsEnd,
    4565             :                                   const Int nchan,
    4566             :                                   const Int width,
    4567             :                                   const Int start
    4568             :                                   )
    4569             :   {
    4570         107 :     Bool rval = true;
    4571             : 
    4572             :     // reset the "done" table.
    4573         107 :     newDataDescId.resize(0);
    4574         107 :     oldSpwId.resize(0);
    4575         107 :     oldFieldId.resize(0);
    4576         107 :     xold.resize(0);
    4577         107 :     xin.resize(0);
    4578         107 :     xout.resize(0);
    4579         107 :     theFieldDirV.resize(0);
    4580         107 :     mObsPosV.resize(0);
    4581         107 :     fromFrameTypeV.resize(0);
    4582         107 :     outFrameV.resize(0);
    4583         107 :     outRadVelV.resize(0);
    4584         107 :     weightScaleV.resize(0);
    4585         107 :     MFrequency::Ref outFrame;
    4586         214 :     MRadialVelocity outRadVel(Quantity(0, "m/s"), MRadialVelocity::GEO);
    4587         107 :     method.resize(0);
    4588         107 :     regrid.resize(0);   
    4589         107 :     transform.resize(0);        
    4590             :     
    4591             :     // Determine the highest data_desc_id from the DATA_DESCRIPTION table
    4592         107 :     MSDataDescription ddtable = ms_p.dataDescription();
    4593         107 :     Int origNumDataDescs = ddtable.nrow();
    4594         107 :     Int nextDataDescId = origNumDataDescs - 1;
    4595         107 :     Int numNewDataDesc = 0;
    4596             : 
    4597             :     // Determine the highest spw_id in the SPW table
    4598         107 :     MSSpectralWindow spwtable = ms_p.spectralWindow();
    4599         107 :     Int origNumSPWs = spwtable.nrow();
    4600         107 :     Int nextSPWId = origNumSPWs - 1;
    4601         107 :     Int numNewSPWIds = 0;
    4602             : 
    4603             :     // Determine the highest row number in the SOURCE table
    4604         107 :     Int origNumSourceRows = 0;
    4605         107 :     Int nextSourceRow = -1;
    4606         107 :     Int numNewSourceRows = 0;
    4607         107 :     vector<Int> newSourceIds;
    4608         107 :     vector<Int> newSourceSPWIds;
    4609         107 :     MSSource* p_sourcetable = NULL;
    4610         107 :     MSSourceColumns* p_sourceCol = NULL;
    4611         107 :     if(Table::isReadable(ms_p.sourceTableName())){
    4612         107 :       p_sourcetable = &(ms_p.source());
    4613         107 :       p_sourceCol = new MSSourceColumns(*p_sourcetable);
    4614         107 :       origNumSourceRows = p_sourcetable->nrow();
    4615         107 :       nextSourceRow = origNumSourceRows - 1;
    4616             :     }
    4617           0 :     else if(!writeTables) { // there is no source table
    4618           0 :       os << LogIO::NORMAL << "Note: MS does not contain a SOURCE table ..." << LogIO::POST;
    4619           0 :       nextSourceRow = -1;
    4620             :     }
    4621             : 
    4622         107 :     MSMainColumns mainCols(ms_p);
    4623         107 :     ScalarColumn<Int> fieldIdCol = mainCols.fieldId();
    4624         107 :     ScalarColumn<Int> DDIdCol = mainCols.dataDescId();
    4625         107 :     ScalarMeasColumn<MEpoch> mainTimeMeasCol = mainCols.timeMeas();
    4626             :     // other administrational tables
    4627             : 
    4628         107 :     MSDataDescColumns DDCols(ddtable);
    4629         107 :     ScalarColumn<Int> SPWIdCol = DDCols.spectralWindowId(); 
    4630             : 
    4631         107 :     MSSpWindowColumns SPWCols(spwtable);
    4632         107 :     ScalarColumn<Int> numChanCol = SPWCols.numChan(); 
    4633         107 :     ArrayColumn<Double> chanFreqCol = SPWCols.chanFreq(); 
    4634         107 :     ArrayMeasColumn<MFrequency> chanFreqMeasCol = SPWCols.chanFreqMeas();
    4635         107 :     ScalarColumn<Int> measFreqRefCol = SPWCols.measFreqRef();
    4636         107 :     ArrayColumn<Double> chanWidthCol = SPWCols.chanWidth(); 
    4637         107 :     ArrayColumn<Double> effectiveBWCol = SPWCols.effectiveBW();   
    4638         107 :     ScalarColumn<Double> refFrequencyCol = SPWCols.refFrequency(); 
    4639         107 :     ScalarMeasColumn<MFrequency> refFrequencyMeasCol = SPWCols.refFrequencyMeas(); 
    4640         107 :     ArrayColumn<Double> resolutionCol = SPWCols.resolution(); 
    4641         107 :     ScalarColumn<Double> totalBandwidthCol = SPWCols.totalBandwidth();
    4642             : 
    4643         107 :     MSField fieldtable = ms_p.field();
    4644         107 :     MSFieldColumns FIELDCols(fieldtable);
    4645             :     //ArrayMeasColumn<MDirection> referenceDirMeasCol = FIELDCols.referenceDirMeasCol(); 
    4646             :     //ScalarMeasColumn<MEpoch>& timeMeasCol = FIELDCols.timeMeas();
    4647         107 :     ScalarColumn<Int> FIELDsourceIdCol = FIELDCols.sourceId(); 
    4648             : 
    4649             :     // calculate mean antenna position for TOPO transformation
    4650         107 :     MSAntenna anttable = ms_p.antenna();
    4651         107 :     MSAntennaColumns ANTCols(anttable);
    4652         107 :     ROScalarMeasColumn<MPosition> ANTPositionMeasCol = ANTCols.positionMeas(); 
    4653         107 :     ScalarColumn<Bool> ANTflagRowCol = ANTCols.flagRow();
    4654         107 :     Int nAnt = 0;
    4655         107 :     Vector<Double> pos(3); pos=0;
    4656        1605 :     for (uInt i=0; i<anttable.nrow(); i++) {
    4657        1498 :       if(!ANTflagRowCol(i)){
    4658        1496 :         pos+=ANTPositionMeasCol(i).getValue().get();
    4659        1496 :         nAnt++;
    4660             :       }
    4661             :     }
    4662         107 :     if(nAnt>0){
    4663         107 :       pos /= Double(nAnt);
    4664             :     }
    4665             :     else {
    4666             :       os << LogIO::WARN << "No unflagged antennas in this MS. Cannot proceed with regridSpw ..." 
    4667           0 :          << LogIO::POST;
    4668           0 :       return rval; 
    4669             :     }
    4670             : 
    4671         107 :     MPosition mObsPos = ANTPositionMeasCol(0); // transfer reference frame
    4672         107 :     mObsPos.set(MVPosition(pos)); // set coordinates
    4673             : 
    4674             :     // but use a tabulated version if available (as in clean)
    4675             :     {
    4676         107 :       MPosition Xpos;
    4677         107 :       String Xobservatory;
    4678         107 :       MSObservationColumns XObsCols(ms_p.observation());
    4679         107 :       if (ms_p.observation().nrow() > 0) {
    4680         107 :         Xobservatory = XObsCols.telescopeName()(mainCols.observationId()(0));
    4681             :       }
    4682         214 :       if (Xobservatory.length() == 0 || 
    4683         107 :           !MeasTable::Observatory(Xpos,Xobservatory)) {
    4684             :         // unknown observatory, use the above calculated centroid position
    4685           0 :         if(!writeTables){
    4686             :           os << LogIO::WARN << "Unknown observatory: \"" << Xobservatory 
    4687           0 :              << "\". Determining observatory position from antenna 0." << LogIO::POST;
    4688             :         }
    4689           0 :         Xpos=MPosition::Convert(ANTPositionMeasCol(0), MPosition::ITRF)();
    4690             :       }
    4691             :       else{
    4692         107 :         if(!writeTables){
    4693             :           os << LogIO::NORMAL << "Using tabulated observatory position for " << Xobservatory << ":"
    4694          54 :              << LogIO::POST;
    4695          54 :           Xpos=MPosition::Convert(Xpos, MPosition::ITRF)();
    4696             :         }
    4697             :       }
    4698         107 :       mObsPos = Xpos;
    4699         107 :       if(!writeTables){
    4700          54 :         ostringstream oss;
    4701          54 :         oss <<  "   " << mObsPos << " (ITRF)";
    4702          54 :         os << LogIO::NORMAL << oss.str() << LogIO::POST;
    4703          54 :       }
    4704         107 :     }
    4705             :     
    4706             :     // create time-sorted index for main table access
    4707         107 :     uInt nMainTabRows = ms_p.nrow();
    4708         107 :     Vector<uInt> sortedI(nMainTabRows);
    4709             :     {
    4710         107 :       Vector<Double> mainTimesV = mainCols.time().getColumn();
    4711         107 :       GenSortIndirect<Double>::sort(sortedI,mainTimesV);
    4712         107 :     }
    4713             :     
    4714     1291361 :     for(uInt mainTabRowI=0; mainTabRowI<nMainTabRows; mainTabRowI++){
    4715             :     
    4716     1291255 :       uInt mainTabRow = sortedI(mainTabRowI); // i.e. mainTabRow is sorted in Time
    4717             : 
    4718             :       // For each MAIN table row, the FIELD_ID cell and the DATA_DESC_ID cell are read 
    4719     1291255 :       Int theFieldId = fieldIdCol(mainTabRow);
    4720     1291255 :       Int theDataDescId = DDIdCol(mainTabRow);
    4721             :       // and the SPW_ID extracted from the corresponding row in the
    4722             :       // DATA_DESCRIPTION table.
    4723     1291255 :       Int theSPWId = -2;
    4724     1291255 :       if (theDataDescId < origNumDataDescs){
    4725     1291255 :         theSPWId = SPWIdCol(theDataDescId);
    4726             :       }
    4727             :       else {
    4728             :         os << LogIO::SEVERE
    4729             :            << "Incoherent MS: Found at main table row " << mainTabRow
    4730             :            << " reference to non-existing DATA_DESCRIPTION table entry "
    4731             :            << theDataDescId
    4732           0 :            << LogIO::POST;
    4733           0 :         rval = false;
    4734           1 :         return rval;
    4735             :       }
    4736             : 
    4737             :       // variables saying what has to be done for this row
    4738     1291255 :       Bool needTransform = false;
    4739     1291255 :       Bool doRegrid = false;
    4740     1291255 :       Int equivalentSpwFieldPair = -1;
    4741             : 
    4742     1291255 :       String message;
    4743             : 
    4744             :       //  The pair (theFieldId, theSPWId) is looked up in the "done table". 
    4745     1291255 :       Int iDone = -1;
    4746     1291255 :       for (uInt i=0; i<oldSpwId.size(); i++){
    4747     1291148 :         if(oldSpwId[i]==theSPWId && (oldFieldId[i]==theFieldId || regridPhaseCenterFieldId>=-1)){ 
    4748             :           // if common phase center is given, treat all fields the same
    4749     1291148 :           iDone = i;
    4750     1291148 :           break;
    4751             :         }
    4752             :       }
    4753             : 
    4754     1291255 :       if(iDone<0){ // this (theFieldId, theSPWId) pair was not yet encountered 
    4755             : 
    4756             :         // Determine information for new row in "done" table
    4757             :         //   The information necessary for the transformation is extracted:  
    4758             :         //   1) center frequency of each channel (taken from the CHAN_FREQ cell
    4759             :         //      corresponding to theSPWId in the SPW table)
    4760         107 :         Vector<Double> newXin;
    4761         107 :         newXin.assign(chanFreqCol(theSPWId));
    4762             :         //      -> store in  xin (further below)
    4763             :         //   2) reference frame for these frequencies (taken from the
    4764             :         //      MEAS_FREQ_REF cell corresponding to theSPWId in the SPW table)
    4765         107 :         MFrequency::Types theOldRefFrame = MFrequency::castType(measFreqRefCol(theSPWId));
    4766             :         //      -> store in oldRefFrame[numNewDataDesc] (further below)
    4767             :         //   3) in case either the original or the destination reference frame
    4768             :         //      is TOPO or GEO, we need the observation time
    4769             :         //      (taken from the time of the first integration for this (theFieldId, theSPWId) pair)
    4770             :         //      -> store in obsTime[numNewDataDesc] (further below)
    4771         107 :         MEpoch theObsTime = mainTimeMeasCol(mainTabRow);
    4772             :           ////      (taken uniformly for the whole MS from the first row of the MS
    4773             :           ////      which is also the earliest row because it is time-sorted)
    4774             :           //MEpoch theObsTime = mainTimeMeasCol(0);
    4775             : 
    4776             :         // Determine if a reference frame transformation is necessary
    4777             :         // Bool         getType (MFrequency::Types &tp, const String &in)
    4778         107 :         needTransform = true;
    4779         107 :         Bool doRadVelCorr = false;
    4780             :         MFrequency::Types theFrame;
    4781         107 :         String oframe = outframe;
    4782         107 :         oframe.upcase();
    4783         107 :         if(outframe==""){ // no ref frame given 
    4784             :           // keep the reference frame as is
    4785          70 :           theFrame = theOldRefFrame;
    4786          70 :           needTransform = false;
    4787             :         }
    4788          37 :         else if(oframe=="SOURCE"){ // GEO trafo + radial velocity correction
    4789           6 :           theFrame = MFrequency::GEO;
    4790           6 :           doRadVelCorr = true;
    4791             :         }
    4792          31 :         else if(!MFrequency::getType(theFrame, outframe)){
    4793             :           os << LogIO::SEVERE
    4794             :              << "Parameter \"outframe\" value " << outframe << " is invalid." 
    4795           0 :              << LogIO::POST;
    4796           0 :           return false;
    4797             :         }
    4798          31 :         else if (theFrame == theOldRefFrame){
    4799           2 :           needTransform = false;
    4800             :         }
    4801             : 
    4802         107 :         Double weightScale = 1.;
    4803             : 
    4804             :         //   4) direction of the field, i.e. the phase center
    4805         107 :         MDirection theFieldDir;
    4806         107 :         uInt theFieldIdToUse = theFieldId;
    4807         107 :         if(regridPhaseCenterFieldId<-1){ // take it from the PHASE_DIR cell
    4808             :                                          // corresponding to theFieldId in the FIELD table)
    4809           0 :           theFieldDir = FIELDCols.phaseDirMeas(theFieldId, mainCols.time()(mainTabRow));
    4810             : 
    4811           0 :           if(FIELDCols.needInterTime(theFieldId)){
    4812           0 :             String ephPath = FIELDCols.ephemPath(theFieldId);
    4813           0 :             os << LogIO::NORMAL << "Note: Field with id " << theFieldId; 
    4814           0 :             if(ephPath.size()>0){
    4815           0 :               os << ", uses ephemeris " << ephPath << LogIO::POST;
    4816             :             }
    4817             :             else{
    4818           0 :               os << ", has a time-dependent position described by a polynomial." << LogIO::POST;
    4819             :             }
    4820           0 :           }
    4821             : 
    4822             :         }
    4823         107 :         else if(regridPhaseCenterFieldId==-1){ // use the given direction
    4824          14 :           theFieldDir = regridPhaseCenter;
    4825          14 :           doRadVelCorr = false;
    4826             :         }
    4827          93 :         else if((uInt)regridPhaseCenterFieldId < fieldtable.nrow()){ // use this valid field ID
    4828          93 :           theFieldDir = FIELDCols.phaseDirMeas(regridPhaseCenterFieldId, mainCols.time()(mainTabRow));
    4829          93 :           theFieldIdToUse = regridPhaseCenterFieldId;
    4830          93 :           if(FIELDCols.needInterTime(regridPhaseCenterFieldId)){
    4831           6 :             String ephPath = FIELDCols.ephemPath(regridPhaseCenterFieldId);
    4832           6 :             os << LogIO::NORMAL << "Note: Field to be used as phase center, id " << regridPhaseCenterFieldId; 
    4833           6 :             if(ephPath.size()>0){
    4834           6 :               os << ", uses ephemeris " << ephPath << LogIO::POST;
    4835             :             }
    4836             :             else{
    4837           0 :               os << ", has a time-dependent position described by a polynomial." << LogIO::POST;
    4838             :             }
    4839           6 :           }
    4840             : 
    4841             :         }
    4842             :         else{
    4843             :           os << LogIO::SEVERE << "Field to be used as phase center, id " 
    4844             :              << regridPhaseCenterFieldId 
    4845           0 :              << ", does not exist." << LogIO::POST;
    4846           0 :           return false;
    4847             :         }
    4848             : 
    4849             :         //      cout << "theFieldId = " << theFieldId << ", theObsTime = " << theObsTime
    4850             :         //           << ", theFieldDir = " << theFieldDir.getAngle() << endl;
    4851             : 
    4852             :         //      -> store in fieldDir[numNewDataDesc] (further below)
    4853             :         //   5) in case either the original or the destination reference frame
    4854             :         //      (but not both) are TOPO, we need the observatory position
    4855             :         //      (from the mean antenna position calculated above) 
    4856             :         //      -> store in obsPos[numNewDataDesc] (further below)
    4857             : 
    4858             :         // Perform the pure frequency transformation (no regridding yet)
    4859         107 :         Vector<Double> transNewXin;
    4860             :         // also take care of the other parameters of the spectral window
    4861         107 :         Int oldNUM_CHAN = numChanCol(theSPWId); 
    4862         107 :         Vector<Double> oldCHAN_WIDTH = chanWidthCol(theSPWId);
    4863             :         {
    4864         107 :           Bool negativeWidths = false;
    4865       65885 :           for(uInt i=0; i<oldCHAN_WIDTH.nelements(); i++){
    4866       65778 :             if(oldCHAN_WIDTH(i) < 0.){
    4867        7680 :               negativeWidths = true;
    4868        7680 :               oldCHAN_WIDTH(i) = -oldCHAN_WIDTH(i);
    4869             :             }
    4870             :           }
    4871         107 :           if(negativeWidths){
    4872             :             os << LogIO::NORMAL
    4873             :                << " *** Encountered negative channel widths in SPECTRAL_WINDOW table."
    4874           2 :                << LogIO::POST;
    4875             :           }
    4876             :         }
    4877         107 :         MFrequency oldREF_FREQUENCY = refFrequencyMeasCol(theSPWId);
    4878         107 :         Double oldTOTAL_BANDWIDTH = totalBandwidthCol(theSPWId);
    4879         107 :         Vector<Double> oldEFFECTIVE_BW = effectiveBWCol(theSPWId);   
    4880         107 :         Vector<Double> oldRESOLUTION = resolutionCol(theSPWId);
    4881             : 
    4882             :         // storage for values with pure freq trafo applied
    4883         107 :         Vector<Double> transCHAN_WIDTH(oldNUM_CHAN);
    4884         107 :         MFrequency transREF_FREQUENCY;
    4885             :         Double transTOTAL_BANDWIDTH;
    4886         107 :         Vector<Double> transRESOLUTION(oldNUM_CHAN);;
    4887             : 
    4888         107 :         if(needTransform){
    4889             : 
    4890          35 :           transNewXin.resize(oldNUM_CHAN);
    4891             :           // set up conversion
    4892          35 :           Unit unit(String("Hz"));
    4893          35 :           MFrequency::Ref fromFrame = MFrequency::Ref(theOldRefFrame, MeasFrame(theFieldDir, mObsPos, theObsTime));
    4894          35 :           MFrequency::Ref toFrame = MFrequency::Ref(theFrame, MeasFrame(theFieldDir, mObsPos, theObsTime));
    4895          35 :           MFrequency::Convert freqTrans(unit, fromFrame, toFrame);
    4896             :           
    4897          35 :           MDoppler radVelCorr; // no correction
    4898          35 :           Bool radVelSignificant = false; // is the radial velocity large enough to warrant a shift?
    4899             :           // prepare correction for radial velocity if requested and possible
    4900          35 :           if(doRadVelCorr && FIELDCols.needInterTime(theFieldIdToUse)){
    4901           6 :             MRadialVelocity mRV = FIELDCols.radVelMeas(theFieldIdToUse, mainCols.time()(mainTabRow));
    4902           6 :             Quantity mrv = mRV.get("m/s");
    4903           6 :             radVelCorr = MDoppler(-mrv); // NOTE: opposite sign to achieve correction
    4904           6 :             if(fabs(mrv.getValue())>1E-6){
    4905           6 :               radVelSignificant = true;
    4906           6 :               outRadVel = mRV;
    4907             :               os << LogIO::NORMAL
    4908          12 :                  << "Note: The geocentric radial velocity information (ca. " << mrv.getValue()
    4909             :                  << "m/s) from the ephemeris for field " << theFieldIdToUse << " will be taken into account."
    4910           6 :                  << LogIO::POST;
    4911             :             }
    4912             :             else{
    4913           0 :               outRadVel = MRadialVelocity(Quantity(0, "m/s"), MRadialVelocity::GEO);
    4914             :               os << LogIO::NORMAL
    4915             :                  << "Note: The geocentric radial velocity from the ephemeris for field " << theFieldIdToUse 
    4916             :                  << " is less than 1E-6 m/s and will not be taken into account."
    4917           0 :                  << LogIO::POST;
    4918             : 
    4919             :             }
    4920           6 :           } 
    4921             : 
    4922             :           // also create the reference for storage in the "Done" table
    4923          35 :           outFrame = MFrequency::Ref(theFrame, MeasFrame(theFieldDir, mObsPos, theObsTime));
    4924             :           
    4925             : 
    4926       28755 :           for(Int i=0; i<oldNUM_CHAN; i++){
    4927       28720 :             transNewXin[i] = freqTrans(newXin[i]).get(unit).getValue();
    4928       28720 :             transCHAN_WIDTH[i] = freqTrans(newXin[i] +
    4929       28720 :                                            oldCHAN_WIDTH[i]/2.).get(unit).getValue()
    4930       28720 :               - freqTrans(newXin[i] -
    4931       28720 :                           oldCHAN_WIDTH[i]/2.).get(unit).getValue(); // eliminate possible offsets
    4932       28720 :             transRESOLUTION[i] = freqTrans(newXin[i] +
    4933       57440 :                                            oldRESOLUTION[i]/2.).get(unit).getValue() 
    4934       28720 :               - freqTrans(newXin[i]
    4935       28720 :                           - oldRESOLUTION[i] / 2.0).get(unit).getValue(); // eliminate possible offsets
    4936             :           }
    4937          35 :           transREF_FREQUENCY = freqTrans(oldREF_FREQUENCY);
    4938          35 :           transTOTAL_BANDWIDTH = fabs(transNewXin[oldNUM_CHAN-1] - transNewXin[0]) +
    4939          35 :             fabs(transCHAN_WIDTH[oldNUM_CHAN-1])/2.  + fabs(transCHAN_WIDTH[0])/2.;
    4940             : 
    4941          35 :           if(radVelSignificant){ // correct in addition for radial velocity
    4942           6 :             transNewXin  = radVelCorr.shiftFrequency(transNewXin);
    4943           6 :             transCHAN_WIDTH = radVelCorr.shiftFrequency(transCHAN_WIDTH); //shiftFrequency is a scaling, so chan widths scale as well
    4944           6 :             transRESOLUTION = radVelCorr.shiftFrequency(transRESOLUTION);
    4945           6 :             Vector<Double> tmpV(1);
    4946           6 :             tmpV(0) = transREF_FREQUENCY.get("Hz").getValue();
    4947           6 :             transREF_FREQUENCY.set( MVFrequency( radVelCorr.shiftFrequency(tmpV)(0) ) );
    4948           6 :             tmpV(0) = transTOTAL_BANDWIDTH;
    4949           6 :             transTOTAL_BANDWIDTH = radVelCorr.shiftFrequency(tmpV)(0);
    4950           6 :           }
    4951             : 
    4952          35 :         }
    4953             :         else {
    4954             :           // just copy
    4955          72 :           transNewXin.assign(newXin);
    4956          72 :           transCHAN_WIDTH.assign(oldCHAN_WIDTH);
    4957          72 :           transRESOLUTION.assign(oldRESOLUTION);
    4958          72 :           transREF_FREQUENCY = oldREF_FREQUENCY;
    4959          72 :           transTOTAL_BANDWIDTH = oldTOTAL_BANDWIDTH;
    4960             :         }
    4961             : 
    4962             :         // (reference frame transformation completed)
    4963             : 
    4964             : 
    4965             :         // storage for values with complete freq trafo + regridding applied
    4966             :         // (set to default values for the case of no regridding)
    4967         107 :         Vector<Double> newXout;
    4968         107 :         newXout.assign(transNewXin);
    4969         107 :         Int newNUM_CHAN = oldNUM_CHAN;
    4970         107 :         Vector<Double> newCHAN_WIDTH;
    4971         107 :         newCHAN_WIDTH.assign(transCHAN_WIDTH);
    4972         107 :         MFrequency newREF_FREQUENCY = transREF_FREQUENCY;
    4973         107 :         Vector<Double> newRESOLUTION;
    4974         107 :         newRESOLUTION.assign(transRESOLUTION);
    4975         107 :         Double newTOTAL_BANDWIDTH = transTOTAL_BANDWIDTH;
    4976         107 :         Vector<Double> newEFFECTIVE_BW;
    4977         107 :         newEFFECTIVE_BW.assign(oldEFFECTIVE_BW);
    4978             :         Int theMethod;
    4979             : 
    4980             :         // check if theSPWId was already handled
    4981         107 :         Int iDone2 = -1;
    4982         107 :         for (uInt i=0; i<oldSpwId.size(); i++){
    4983           0 :           if(oldSpwId[i]==theSPWId){
    4984           0 :             iDone2 = i;
    4985           0 :             break;
    4986             :           }
    4987             :         }
    4988         107 :         equivalentSpwFieldPair = iDone2;
    4989             : 
    4990         107 :         if(equivalentSpwFieldPair>=0 && !needTransform){ 
    4991             :           // a transformation was not needed, 
    4992             :           // i.e. the operation on this SPW is independent of the FIELD
    4993             :           // and (since equivalentSpwFieldPair>=0) this SPW was already processed
    4994             :           // so we can reuse a previous SpwFieldPair
    4995             : 
    4996             :           // get the parameters from the "done table"
    4997           0 :           theSPWId = oldSpwId[equivalentSpwFieldPair];
    4998             :           // don't get the field id!
    4999           0 :           theDataDescId = newDataDescId[equivalentSpwFieldPair] + origNumDataDescs; 
    5000           0 :           transNewXin.assign(xin[equivalentSpwFieldPair]);
    5001           0 :           newXout.assign(xout[equivalentSpwFieldPair]);
    5002           0 :           theMethod = method[equivalentSpwFieldPair];
    5003           0 :           doRegrid = regrid[equivalentSpwFieldPair];
    5004             : 
    5005             :         }
    5006             :         else {
    5007             :           // Determine if regridding is necessary and set the parameters (at
    5008             :           // the same time, determine if the transformation is non-linear. If
    5009             :           // so set trafoNonlin (further below).)
    5010             :           
    5011         107 :           String methodName;
    5012             :           
    5013         172 :           if(regridQuant=="" ||
    5014          65 :              (regridCenter<-1E30 &&  regridBandwidth <= 0. && regridChanWidth <= 1. 
    5015          63 :               && regridQuant=="chan")
    5016             :              ){
    5017             :             // No regridding will take place.
    5018             :             // Set the interpol methods to some dummy value
    5019           0 :             theMethod = (Int) InterpolateArray1D<Double,Complex>::linear;
    5020           0 :             methodName = "linear";
    5021           0 :             message = " output frame = " + MFrequency::showType(theFrame) + " (pure transformation of the channel definition)";
    5022             :             // cout <<  regridQuant << " " << regridCenter << " " << regridBandwidth << " " << regridChanWidth << endl;
    5023             :           }
    5024             :           else { // a regrid quantity was chosen
    5025             :             // determine interpolation method (this is common for all possible
    5026             :             // values of regridQuant)
    5027         107 :             String meth=regridInterpMeth;
    5028         107 :             meth.downcase();
    5029         107 :             if(meth.contains("nearest")){
    5030           0 :               theMethod = (Int) InterpolateArray1D<Double,Complex>::nearestNeighbour;
    5031           0 :               methodName = "nearestNeighbour";
    5032             :             }
    5033         107 :             else if(meth.contains("splin")){
    5034           0 :               theMethod = (Int) InterpolateArray1D<Double,Complex>::spline;
    5035           0 :               methodName = "spline";
    5036             :             }       
    5037         107 :             else if(meth.contains("cub")){
    5038           0 :               theMethod = (Int) InterpolateArray1D<Double,Complex>::cubic;
    5039           0 :               methodName = "cubic spline";
    5040             :             }
    5041         107 :             else if(meth.contains("fft")){
    5042             :               // check if input grid is equidistant in frequency
    5043          11 :               Bool isEquidistant = true;
    5044          11 :               Double sep = fabs(transCHAN_WIDTH(0));
    5045        1088 :               for(uInt i=1; i<transCHAN_WIDTH.size(); i++){
    5046        1083 :                 if((fabs(transCHAN_WIDTH(i)-transCHAN_WIDTH(i-1))>0.1)
    5047        1083 :                    || fabs(fabs(transNewXin(i)-transNewXin(i-1))-sep)>0.1 ){
    5048           6 :                   isEquidistant = false;
    5049           6 :                   break;
    5050             :                 }
    5051        1077 :                 sep = fabs(transNewXin(i)-transNewXin(i-1));
    5052             :               }
    5053             : 
    5054          11 :               if(isEquidistant){
    5055           5 :                 theMethod = (Int) useFFTShift;
    5056           5 :                 methodName = "fftshift";
    5057             :               }
    5058             :               else{
    5059           6 :                 theMethod = (Int) useLinIntThenFFTShift;
    5060           6 :                 methodName = "fftshift (preceeded by a linear transform to make grid equidistant)";
    5061             :               }
    5062             :               // for this method to work, the output grid needs to be equidistant in frequency
    5063          12 :               if(!(regridQuant=="freq" || regridQuant=="vrad" 
    5064           1 :                    || (regridQuant=="chan" && isEquidistant) // (chan equidistance depends on input grid) 
    5065             :                    )){
    5066             :                 os << LogIO::SEVERE
    5067             :                    << "Parameter \"interpolation\" value \"" << meth << "\" requires an output grid equidistant in frequency."
    5068             :                    << endl << "Cannot proceed." 
    5069           1 :                    << LogIO::POST;
    5070           1 :                 return false;
    5071             :               }
    5072             :             }
    5073             :             else {
    5074          96 :               if(!meth.contains("linear") && meth!=""){
    5075             :                 os << LogIO::WARN
    5076             :                    << "Parameter \"interpolation\" value \"" << meth << "\" is invalid." 
    5077           0 :                    << LogIO::POST;
    5078           0 :                 return false;
    5079             :               }
    5080          96 :               theMethod = (Int) InterpolateArray1D<Double,Complex>::linear;
    5081          96 :               methodName = "linear";
    5082             :             }
    5083             :             
    5084         106 :             Vector<Double> newChanLoBound; 
    5085         106 :             Vector<Double> newChanHiBound;
    5086             :             
    5087         106 :             if(!regridChanBounds(newChanLoBound, 
    5088             :                                  newChanHiBound,
    5089             :                                  regridCenter,  
    5090             :                                  regridBandwidth, 
    5091             :                                  regridChanWidth, 
    5092             :                                  regridVeloRestfrq,
    5093             :                                  regridQuant,
    5094             :                                  transNewXin, 
    5095             :                                  transCHAN_WIDTH,
    5096             :                                  message,
    5097             :                                  centerIsStart,
    5098             :                                  startIsEnd,
    5099             :                                  nchan,
    5100             :                                  width,
    5101             :                                  start
    5102             :                                  )
    5103             :                ){ // there was an error
    5104           0 :               os << LogIO::SEVERE << message << LogIO::POST;
    5105           0 :               throw(AipsError("Regridding failed."));
    5106             :               //return false;
    5107             :             }
    5108             :             
    5109             :             // we have a useful set of channel boundaries
    5110         106 :             newNUM_CHAN = newChanLoBound.size();
    5111             :             
    5112         106 :             if(theMethod==(Int) useFFTShift
    5113           4 :                && newNUM_CHAN != oldNUM_CHAN){ // need to precede by lin. interpol. after all
    5114           4 :               theMethod = (Int) useLinIntThenFFTShift;
    5115             :             }
    5116             : 
    5117         106 :             message = "input frame = " + MFrequency::showType(theOldRefFrame) 
    5118         318 :               + ", output frame = " + MFrequency::showType(theFrame)
    5119         106 :               + "\n" + message + " Interpolation Method = " + methodName;
    5120             :             
    5121             :             // complete the calculation of the new spectral window parameters
    5122             :             // from newNUM_CHAN, newChanLoBound, and newChanHiBound 
    5123         106 :             newXout.resize(newNUM_CHAN);
    5124         106 :             newCHAN_WIDTH.resize(newNUM_CHAN);
    5125         106 :             newRESOLUTION.resize(newNUM_CHAN);
    5126         106 :             newEFFECTIVE_BW.resize(newNUM_CHAN);
    5127       35616 :             for(Int i=0; i<newNUM_CHAN; i++){
    5128       35510 :               newXout[i] = (newChanLoBound[i]+newChanHiBound[i])/2.;
    5129       35510 :               newCHAN_WIDTH[i] = newChanHiBound[i]-newChanLoBound[i];
    5130       35510 :               newRESOLUTION[i] = newCHAN_WIDTH[i]; // to be revisited
    5131       35510 :               newEFFECTIVE_BW[i] = newCHAN_WIDTH[i]; // to be revisited
    5132             :             }
    5133             :             // set the reference frequency to the central frequency of the first channel,
    5134             :             // keeping the already changed frame
    5135         106 :             MVFrequency mvf(newXout[0]);
    5136         106 :             newREF_FREQUENCY.set(mvf);
    5137             :             
    5138             :             // trivial definition of the bandwidth (taking into account possibility of descending freqs)
    5139         106 :             newTOTAL_BANDWIDTH = max(newChanHiBound[newNUM_CHAN-1], newChanHiBound[0])
    5140         106 :               -min(newChanLoBound[0],newChanLoBound[newNUM_CHAN-1]);
    5141             : 
    5142             : //          // effective bandwidth needs to be interpolated in quadrature
    5143             : //          Vector<Double> newEffBWSquared(newNUM_CHAN);
    5144             : //          Vector<Double> oldEffBWSquared(oldEFFECTIVE_BW);
    5145             : //          for(Int i=0; i<oldNUM_CHAN; i++){
    5146             : //            oldEffBWSquared[i] *= oldEffBWSquared[i];
    5147             : //          }
    5148             : //          InterpolateArray1D<Double, Double>::interpolate(newEffBWSquared, newXout,
    5149             : //                                                             transNewXin,
    5150             : //                                                             oldEffBWSquared,
    5151             : //                                                             InterpolateArray1D<Double,Double>::linear);
    5152             : //          for(uInt i=0; i<newNUM_CHAN; i++){
    5153             : //            newEFFECTIVE_BW[i] = sqrt(newEffBWSquared[i]);
    5154             : //          }
    5155             : 
    5156         106 :             if(!allEQ(newXout, transNewXin)){ // grids are different
    5157          90 :               doRegrid = true;
    5158             :             }
    5159             :             
    5160         107 :           } // end if (regridQuant=="" ... 
    5161             :           
    5162         106 :           if(writeTables && (needTransform || doRegrid)){
    5163             :             // new SPW amd DD table rows may need to be created
    5164             :             
    5165             :             // Create new row in the SPW table (with ID nextSPWId) by copying
    5166             :             // all information from row theSPWId
    5167          45 :             if(!spwtable.canAddRow()){
    5168             :               os << LogIO::WARN
    5169             :                  << "Unable to add new row to SPECTRAL_WINDOW table. Cannot proceed with regridSpw ..." 
    5170           0 :                  << LogIO::POST;
    5171           0 :               return false; 
    5172             :             }
    5173             :             
    5174          45 :             numNewSPWIds++;
    5175          45 :             nextSPWId++;
    5176             :             
    5177             :             // prepare parameter string for later entry into MS history and report to logger
    5178             :             {    
    5179          45 :               ostringstream param;
    5180          45 :               param << "Regridded spectral window "
    5181          45 :                     << nextSPWId - origNumSPWs << " will be created for field " 
    5182          45 :                     << theFieldId << " with parameters " << endl
    5183          45 :                     << message << endl;
    5184          45 :               regridMessage += param.str(); // append
    5185          45 :               os << LogIO::NORMAL << param.str() << LogIO::POST;
    5186          45 :             }
    5187             :             
    5188          45 :             spwtable.addRow();
    5189          45 :             TableRow SPWRow(spwtable);
    5190          45 :             TableRecord spwRecord = SPWRow.get(theSPWId);
    5191             :             // TODO        Warn if the original channels are not contiguous or overlap!
    5192          45 :             SPWRow.putMatchingFields(nextSPWId, spwRecord);
    5193             :             
    5194             :             // and replacing the following columns with updated information:
    5195             :             // Store xout as new value of CHAN_FREQ.
    5196          45 :             chanFreqCol.put(nextSPWId, newXout);
    5197          45 :             numChanCol.put(nextSPWId, newNUM_CHAN);
    5198          45 :             chanWidthCol.put(nextSPWId,  newCHAN_WIDTH);
    5199          45 :             refFrequencyCol.put(nextSPWId, newREF_FREQUENCY.getValue());
    5200          45 :             if(theFrame==MFrequency::GEO){ // i.e. outframe was GEO or SOURCE
    5201           3 :               measFreqRefCol.put(nextSPWId, (Int)MFrequency::REST);
    5202             :             }
    5203             :             else{
    5204          42 :               measFreqRefCol.put(nextSPWId, (Int)theFrame);
    5205             :             }
    5206             : 
    5207          45 :             totalBandwidthCol.put(nextSPWId, newTOTAL_BANDWIDTH);
    5208          45 :             effectiveBWCol.put(nextSPWId, newEFFECTIVE_BW);
    5209          45 :             resolutionCol.put(nextSPWId, newRESOLUTION);
    5210             :             
    5211          45 :             msModified = true;
    5212             :             //   Create a new row in the DATA_DESCRIPTION table and enter
    5213             :             //   nextSPWId in the SPW_ID column, copy the polarization id and
    5214             :             //   the flag_row content from the old DATA_DESCRIPTION row.
    5215          45 :             if(!ddtable.canAddRow()){
    5216             :               os << LogIO::WARN
    5217             :                  << "Unable to add new row to DATA_DESCRIPTION table.  Cannot proceed with regridSpw ..." 
    5218           0 :                  << LogIO::POST;
    5219           0 :               return false; 
    5220             :             }
    5221          45 :             numNewDataDesc++;
    5222          45 :             nextDataDescId++;
    5223          45 :             ddtable.addRow();
    5224          45 :             TableRow DDRow(ddtable);
    5225          45 :             TableRecord DDRecord = DDRow.get(theDataDescId);
    5226          45 :             DDRow.putMatchingFields(nextDataDescId, DDRecord);
    5227             : 
    5228             :             // anticipate the deletion of the original SPW table rows
    5229          45 :             SPWIdCol.put(nextDataDescId, nextSPWId - origNumSPWs); 
    5230             :             
    5231             :             // writing the value of nextDataDescId into the DATA_DESC_ID cell
    5232             :             // of the present MAIN table row.  will be done in the main regridSpw
    5233             :             // method
    5234          45 :             theDataDescId = nextDataDescId;
    5235             :           
    5236          45 :           } // end if(writeTables && (needTransform || doRegrid)
    5237             : 
    5238         107 :         } // end if there is a reusable SPW row
    5239             : 
    5240         106 :         if(writeTables && (needTransform || doRegrid)){
    5241             :           // a new SOURCE table row has to be created
    5242             : 
    5243             :           // Add a row to the SOURCE table by copying the contents from the row
    5244             :           // identified by the SOURCE_ID cell in the row theFieldId from the
    5245             :           // FIELD table. Set the value of the cell SPECTRAL_WINDOW_ID in this
    5246             :           // new row to the value nextSPWId.
    5247          45 :           if(nextSourceRow>=0){ // there is a source table
    5248          38 :             if(!p_sourcetable->canAddRow()){
    5249             :               os << LogIO::WARN
    5250             :                  << "Unable to add new row to SOURCE table. Cannot proceed with regridSpw ..." 
    5251           0 :                  << LogIO::POST;
    5252           0 :               return false; 
    5253             :             }
    5254          38 :             numNewSourceRows++;
    5255          38 :             nextSourceRow++;
    5256             :             // find the row in the SOURCE table which has
    5257             :             // SOURCE_ID==theSOURCEId and SPW_ID==theSPWId
    5258          38 :             Int theSOURCEId = FIELDsourceIdCol(theFieldId);
    5259          38 :             ScalarColumn<Int> SOURCEsourceIdCol = p_sourceCol->sourceId();
    5260          38 :             ScalarColumn<Int> SOURCESPWIdCol = p_sourceCol->spectralWindowId();
    5261          38 :             Int foundRow = -1;
    5262          68 :             for(int i=0; i<nextSourceRow; i++){
    5263          68 :               if(SOURCEsourceIdCol(i) == theSOURCEId && (SOURCESPWIdCol(i)==theSPWId || SOURCESPWIdCol(i)==-1)){
    5264          38 :                 foundRow = i;
    5265          38 :                 break;
    5266             :               }
    5267             :             }
    5268          38 :             if(foundRow<0){ 
    5269             :               os << LogIO::SEVERE << "Incoherent MS: Did not find SOURCE table entry with SOURCE_ID == " 
    5270             :                  << theSOURCEId << " and  SPECTRAL_WINDOW_ID == " << theSPWId << endl
    5271             :                  <<" even though the FIELD and the DATA_DESCRIPTION table entries for main table row " 
    5272             :                  << mainTabRow << " refer to it." 
    5273           0 :                  << LogIO::POST;
    5274           0 :               return false;
    5275             :             }
    5276             :             else { // found matching row
    5277          38 :               p_sourcetable->addRow();
    5278          38 :               TableRow SOURCERow(*p_sourcetable);
    5279          38 :               TableRecord SOURCERecord = SOURCERow.get(foundRow);
    5280          38 :               SOURCERow.putMatchingFields(nextSourceRow, SOURCERecord);
    5281             : 
    5282             :               // anticipate the deletion of the original SPW rows
    5283          38 :               SOURCESPWIdCol.put(nextSourceRow, nextSPWId - origNumSPWs);
    5284          38 :               newSourceIds.push_back(theSOURCEId);
    5285          38 :               newSourceSPWIds.push_back(nextSPWId - origNumSPWs);
    5286          38 :             }
    5287             :               
    5288          38 :           } // end if there is a source table
    5289             :         }
    5290             : 
    5291         106 :         weightScale = newCHAN_WIDTH[0]/transCHAN_WIDTH[0]; // = deltaNuNew/deltaNuOld (both in outframe)
    5292             : 
    5293             :         //Put a new row into the "done" table.
    5294             :         // (do all the push_backs in one place)
    5295         106 :         oldSpwId.push_back(theSPWId);
    5296         106 :         oldFieldId.push_back(theFieldId);
    5297             : 
    5298             :         // anticipate the deletion of the original DD rows
    5299         106 :         newDataDescId.push_back(theDataDescId - origNumDataDescs);
    5300             : 
    5301         106 :         weightScaleV.push_back(weightScale);
    5302         106 :         xold.push_back(newXin);
    5303         106 :         xin.push_back(transNewXin);
    5304         106 :         xout.push_back(newXout);
    5305         106 :         method.push_back(theMethod);
    5306         106 :         regrid.push_back(doRegrid);
    5307         106 :         transform.push_back(needTransform);
    5308         106 :         theFieldDirV.push_back(theFieldDir);
    5309         106 :         mObsPosV.push_back(mObsPos);
    5310         106 :         fromFrameTypeV.push_back(theOldRefFrame);
    5311         106 :         outFrameV.push_back(outFrame);
    5312         106 :         outRadVelV.push_back(outRadVel);
    5313             : 
    5314         123 :       } // end if(!alreadyDone)
    5315             :       // reference frame transformation and regridding of channel definition completed
    5316             :       ////////////////////
    5317             : 
    5318     1291255 :     } // end loop over main table
    5319             : 
    5320         106 :     if(writeTables && msModified){
    5321             :       // delete the original rows in DD, SPW, and SOURCE if necessary
    5322          45 :       if(numNewDataDesc>0){
    5323          90 :         for(Int i=0; i<origNumDataDescs; i++){
    5324          45 :           ddtable.removeRow(0);
    5325             :         }
    5326             :       }
    5327          45 :       if(numNewSPWIds>0){
    5328          90 :         for(Int i=0; i<origNumSPWs; i++){
    5329          45 :           spwtable.removeRow(0);
    5330             :         }
    5331             :       }
    5332          45 :       if(numNewSourceRows>0){
    5333          38 :         ScalarColumn<Int> sourceIdCol = p_sourceCol->sourceId();
    5334          38 :         ScalarColumn<Int> spwIdCol = p_sourceCol->spectralWindowId();
    5335             :         // delete duplicate rows among the original Source rows
    5336          38 :         vector<Bool> tBRemRows(origNumSourceRows, false);
    5337        1236 :         for(Int i=0; i<origNumSourceRows-1; i++){
    5338        1198 :           if(tBRemRows[i]){
    5339        1037 :             continue;
    5340             :           }
    5341         161 :           Int tSId = sourceIdCol(i);
    5342         161 :           Int tSpwId = spwIdCol(i);
    5343        6700 :           for(Int j=i+1; j<origNumSourceRows; j++){
    5344        6539 :             if(sourceIdCol(j)==tSId && spwIdCol(j)==tSpwId){
    5345        1055 :               tBRemRows[j]=true;
    5346             :             }
    5347             :           }
    5348             :         }
    5349        1236 :         for(Int i=origNumSourceRows-1; i>0; i--){
    5350        1198 :           if(tBRemRows[i]){
    5351        1055 :             p_sourcetable->removeRow(i);
    5352        1055 :             origNumSourceRows--; 
    5353             :           }
    5354             :         }
    5355             : 
    5356             :         // delete those original Source rows with Source/SPW ID pairs also present among the new ones
    5357          38 :         uInt sIndex=0;
    5358         219 :         for(Int i=0; i<origNumSourceRows; i++){
    5359         181 :           Bool sFound=false;
    5360         325 :           for(uInt j=0; j<newSourceIds.size(); j++){
    5361         181 :             if(sourceIdCol(sIndex)==newSourceIds[j] && spwIdCol(sIndex)==newSourceSPWIds[j]){
    5362          37 :               sFound=true;
    5363          37 :               break;
    5364             :             }
    5365             :           }
    5366         181 :           if(sFound){
    5367          37 :             p_sourcetable->removeRow(sIndex);
    5368             :           }
    5369             :           else{
    5370         144 :             sIndex++;
    5371             :           }
    5372             :         }
    5373          38 :       }
    5374             : 
    5375             :       // prepare parameter string for later entry into MS history
    5376          45 :       ostringstream param;
    5377          45 :       param << "Added " << numNewDataDesc
    5378          45 :             << " new rows to the DATA_DESCRIPTION table and deleted "
    5379          45 :             << origNumDataDescs << " old ones." << endl
    5380          45 :             << "Added " << numNewSPWIds
    5381          45 :             << " rows to the SPECTRAL_WINDOW table and deleted " << origNumSPWs 
    5382          45 :             << " old ones." << endl
    5383          45 :             << "Added " << numNewSourceRows
    5384          45 :             << " rows to the SOURCE table and deleted " << origNumSourceRows
    5385          45 :             << " old ones.";
    5386          45 :       regridMessage += param.str() + "\n"; // append
    5387             : 
    5388          45 :       os << LogIO::NORMAL << param.str() <<  LogIO::POST;
    5389          45 :     }
    5390             : 
    5391         106 :     delete p_sourceCol;
    5392             : 
    5393         106 :     return rval;
    5394         107 :   }
    5395             : 
    5396             : 
    5397         206 :   Bool SubMS::combineSpws(const Vector<Int>& spwids,
    5398             :                           const Bool noModify,
    5399             :                           Vector<Double>& newCHAN_FREQ,
    5400             :                           Vector<Double>& newCHAN_WIDTH,
    5401             :                           Bool verbose){
    5402             : 
    5403             : 
    5404             :     using casacore::operator*;
    5405             :     
    5406         412 :     LogIO os(LogOrigin("SubMS", "combineSpws()"));
    5407             :       
    5408             :     // Analyse spwids
    5409             : 
    5410         206 :     if(spwids.nelements()==0){
    5411           0 :       os << LogIO::WARN << "No SPWs selected for combination ..." <<  LogIO::POST;
    5412           0 :       return true;
    5413             :     }
    5414             : 
    5415         206 :     String tempNewName = ms_p.tableName()+".spwCombined"; // temporary name for the MS to store the result
    5416             : 
    5417             :     { // begin scope for MS related objects
    5418             : 
    5419             :       // find all existing spws, 
    5420         206 :       MSSpectralWindow spwtable = ms_p.spectralWindow();
    5421         206 :       Int origNumSPWs = spwtable.nrow();
    5422         206 :       Int newSPWId = origNumSPWs;
    5423             : 
    5424         206 :       vector<Int> spwsToCombine;
    5425         206 :       Vector<Bool> includeIt(origNumSPWs, false);
    5426             : 
    5427             :       // jagonzal: This covers for the case when we want to combine all the input SPWs
    5428         206 :       if(spwids(0) == -1)
    5429             :       {
    5430         336 :           for(Int i=0; i<origNumSPWs; i++)
    5431             :           {
    5432         282 :                   spwsToCombine.push_back(i);
    5433         282 :                   includeIt(i) = true;
    5434             :           }
    5435             :       }
    5436             :       // jagonzal: Nominal case when we want to combine a sub-set of the input SPWs
    5437             :       else
    5438             :       {
    5439         760 :           for(uInt i=0; i<spwids.nelements(); i++)
    5440             :           {
    5441         608 :                   if(spwids(i)<origNumSPWs && spwids(i)>=0)
    5442             :                   {
    5443         608 :                           spwsToCombine.push_back(spwids(i));
    5444         608 :                           includeIt(spwids(i)) = true;
    5445             :                   }
    5446             :                   else
    5447             :                   {
    5448           0 :                           os << LogIO::SEVERE << "Invalid SPW ID selected for combination " << spwids(i)
    5449           0 :                                           << "valid range is 0 - " << origNumSPWs-1 << ")" << LogIO::POST;
    5450           0 :                           return false;
    5451             :                   }
    5452             :           }
    5453             :       }
    5454             :       // jagonzal: Marginal case when there is no actual SPW combination
    5455         206 :       if(spwsToCombine.size()<=1)
    5456             :       {
    5457          24 :           if(verbose)
    5458             :           {
    5459          24 :                   os << LogIO::NORMAL << "Less than two SPWs selected. No combination necessary." << LogIO::POST;
    5460             :           }
    5461          24 :           return true;
    5462             :       }
    5463             :       
    5464             :       // sort the spwids
    5465         182 :       std::sort(spwsToCombine.begin(), spwsToCombine.end());
    5466             : 
    5467         182 :       uInt nSpwsToCombine = spwsToCombine.size();
    5468             : 
    5469             :       // prepare access to the SPW table
    5470         182 :       MSSpWindowColumns SPWColrs(spwtable);
    5471         182 :       ScalarColumn<Int> numChanColr = SPWColrs.numChan(); 
    5472         182 :       ArrayColumn<Double> chanFreqColr = SPWColrs.chanFreq(); 
    5473         182 :       ArrayColumn<Double> chanWidthColr = SPWColrs.chanWidth(); 
    5474             :       //    ArrayMeasColumn<MFrequency> chanFreqMeasColr = SPWColrs.chanFreqMeas();
    5475         182 :       ScalarColumn<Int> measFreqRefColr = SPWColrs.measFreqRef();
    5476         182 :       ArrayColumn<Double> effectiveBWColr = SPWColrs.effectiveBW();   
    5477         182 :       ScalarColumn<Double> refFrequencyColr = SPWColrs.refFrequency(); 
    5478             :       //    ScalarMeasColumn<MFrequency> refFrequencyMeasColr = SPWColrs.refFrequencyMeas(); 
    5479         182 :       ArrayColumn<Double> resolutionColr = SPWColrs.resolution(); 
    5480         182 :       ScalarColumn<Double> totalBandwidthColr = SPWColrs.totalBandwidth();
    5481             : 
    5482             :       // create a list of the spw ids sorted by first (lowest) channel frequency
    5483         182 :       vector<Int> spwsSorted(nSpwsToCombine);
    5484         182 :       Vector<Bool> isDescending(origNumSPWs, false);
    5485         182 :       Bool negChanWidthWarned = false;
    5486             :       {
    5487         182 :         Double* firstFreq = new Double[nSpwsToCombine];
    5488         182 :         uInt count = 0;
    5489        1259 :         for(uInt i=0; (Int)i<origNumSPWs; i++){
    5490        1077 :           if(includeIt(i)){
    5491         857 :             Vector<Double> CHAN_FREQ(chanFreqColr(i));
    5492             :             // if frequencies are ascending, take the first channel, otherwise the last
    5493         857 :             uInt nCh = CHAN_FREQ.nelements();
    5494         857 :             if(CHAN_FREQ(0)<=CHAN_FREQ(nCh-1)){
    5495         809 :               firstFreq[count] = CHAN_FREQ(0);
    5496             :             }
    5497             :             else{
    5498          48 :               firstFreq[count] = CHAN_FREQ(nCh-1);
    5499          48 :               isDescending(i) = true;
    5500             :             }      
    5501         857 :             count++;
    5502         857 :           }
    5503             :         }
    5504         182 :         Sort sort;
    5505         182 :         sort.sortKey (firstFreq, TpDouble); // define sort key
    5506         182 :         Vector<uInt> inx(nSpwsToCombine);
    5507         182 :         sort.sort(inx, nSpwsToCombine);
    5508        1048 :         for (uInt i=0; i<nSpwsToCombine; i++) {
    5509         866 :           spwsSorted[i] = spwsToCombine[inx(i)];
    5510             :         }
    5511         182 :         delete[] firstFreq;
    5512         182 :       }
    5513             : 
    5514         182 :       Int id0 = spwsSorted[0];
    5515             : 
    5516         182 :       uInt newNUM_CHAN = numChanColr(id0);
    5517         182 :       newCHAN_FREQ.assign(chanFreqColr(id0));
    5518         182 :       newCHAN_WIDTH.assign(chanWidthColr(id0));
    5519         182 :       Bool newIsDescending = isDescending(id0);
    5520             :       {
    5521         182 :         Bool negativeWidths = false;
    5522        6222 :         for(uInt i=0; i<newNUM_CHAN; i++){
    5523        6040 :           if(newCHAN_WIDTH(i) < 0.){
    5524         256 :             negativeWidths = true;
    5525         256 :             newCHAN_WIDTH(i) = -newCHAN_WIDTH(i);
    5526             :           }
    5527             :         }
    5528         182 :         if(negativeWidths && verbose){
    5529             :           os << LogIO::NORMAL
    5530             :              << " *** Encountered negative channel widths in SPECTRAL_WINDOW table."
    5531           1 :              << LogIO::POST;
    5532           1 :           negChanWidthWarned = true;
    5533             :         }
    5534             :       }
    5535             : 
    5536         182 :       if(newIsDescending){ // need to reverse the order for processing 
    5537           2 :         Vector<Double> tempF, tempW;
    5538           2 :         tempF.assign(newCHAN_FREQ);
    5539           2 :         tempW.assign(newCHAN_WIDTH);
    5540         258 :         for(uInt i=0; i<newNUM_CHAN; i++){
    5541         256 :           newCHAN_FREQ(i) = tempF(newNUM_CHAN-1-i);
    5542         256 :           newCHAN_WIDTH(i) = tempW(newNUM_CHAN-1-i);
    5543             :         }
    5544           2 :       }
    5545             : 
    5546         182 :       Vector<Double> newEFFECTIVE_BW(effectiveBWColr(id0));
    5547         182 :       Double newREF_FREQUENCY(refFrequencyColr(id0));
    5548             :       //MFrequency newREF_FREQUENCY = refFrequencyMeasColr(id0);
    5549         182 :       Int newMEAS_FREQ_REF = measFreqRefColr(id0);
    5550         182 :       Vector<Double> newRESOLUTION(resolutionColr(id0));
    5551         182 :       Double newTOTAL_BANDWIDTH = totalBandwidthColr(id0);
    5552             : 
    5553         182 :       vector<Int> averageN; // for each new channel store the number of old channels to average over
    5554         182 :       vector<vector<Int> > averageWhichSPW; // for each new channel store the
    5555             :       // (old) SPWs to average over  
    5556         182 :       vector<vector<Int> > averageWhichChan; // for each new channel store the
    5557             :       // channel numbers to av. over
    5558         182 :       vector<vector<Double> > averageChanFrac; // for each new channel store the
    5559             :       // channel fraction for each old channel
    5560             : 
    5561             :       // initialise the averaging vectors
    5562        6222 :       for(uInt i=0; i<newNUM_CHAN; i++){
    5563        6040 :         averageN.push_back(1);
    5564        6040 :         vector<Int> tv; // just a temporary auxiliary vector
    5565        6040 :         tv.push_back(id0);
    5566        6040 :         averageWhichSPW.push_back(tv);
    5567        6040 :         if(newIsDescending){
    5568         256 :           tv[0] = newNUM_CHAN-1-i;
    5569             :         }
    5570             :         else{
    5571        5784 :           tv[0] = i;
    5572             :         }
    5573        6040 :         averageWhichChan.push_back(tv);
    5574        6040 :         vector<Double> tvd; // another one
    5575        6040 :         tvd.push_back(1.); 
    5576        6040 :         averageChanFrac.push_back(tvd);
    5577        6040 :       }
    5578             : 
    5579         182 :       if(verbose){
    5580          49 :         os << LogIO::NORMAL << "Input SPWs sorted by first (lowest) channel frequency:" << LogIO::POST;
    5581             : 
    5582          49 :         ostringstream oss; // needed for iomanip functions
    5583          49 :         oss << "   SPW " << std::setw(3) << id0 << ": " << std::setw(5) << newNUM_CHAN 
    5584          49 :             << " channels, first channel = " << std::setprecision(9) << std::setw(14) << std::scientific << newCHAN_FREQ(0) << " Hz";
    5585          49 :         if(newNUM_CHAN>1){
    5586          39 :           oss << ", last channel = " << std::setprecision(9) << std::setw(14) << std::scientific << newCHAN_FREQ(newNUM_CHAN-1) << " Hz";
    5587             :         }
    5588          49 :         os << LogIO::NORMAL << oss.str() << LogIO::POST;
    5589          49 :       }
    5590             : 
    5591             :       // loop over remaining given spws
    5592         866 :       for(uInt i=1; i<nSpwsToCombine; i++){
    5593         684 :         Int idi = spwsSorted[i];
    5594             :       
    5595         684 :         uInt newNUM_CHANi = numChanColr(idi);
    5596         684 :         Vector<Double> newCHAN_FREQi(chanFreqColr(idi));
    5597         684 :         Vector<Double> newCHAN_WIDTHi(chanWidthColr(idi));
    5598         684 :         Bool newIsDescendingI = isDescending(idi);
    5599             :         {
    5600         684 :           Bool negativeWidths = false;
    5601       61068 :           for(uInt ii=0; ii<newNUM_CHANi; ii++){
    5602       60384 :             if(newCHAN_WIDTHi(ii) < 0.){
    5603        5888 :               negativeWidths = true;
    5604        5888 :               newCHAN_WIDTHi(ii) = -newCHAN_WIDTHi(ii);
    5605             :             }
    5606             :           }
    5607         684 :           if(negativeWidths && !negChanWidthWarned && verbose){
    5608             :             os << LogIO::NORMAL
    5609             :                << " *** Encountered negative channel widths in SPECTRAL_WINDOW table."
    5610           0 :                << LogIO::POST;
    5611           0 :             negChanWidthWarned = true;
    5612             :           }
    5613             :         }
    5614         684 :         if(newIsDescendingI){ // need to reverse the order for processing 
    5615          46 :           Vector<Double> tempF, tempW;
    5616          46 :           tempF.assign(newCHAN_FREQi);
    5617          46 :           tempW.assign(newCHAN_WIDTHi);
    5618        5934 :           for(uInt ii=0; ii<newNUM_CHANi; ii++){
    5619        5888 :             newCHAN_FREQi(ii) = tempF(newNUM_CHANi-1-ii);
    5620        5888 :             newCHAN_WIDTHi(ii) = tempW(newNUM_CHANi-1-ii);
    5621             :           }
    5622          46 :         }
    5623             : 
    5624         684 :         Vector<Double> newEFFECTIVE_BWi(effectiveBWColr(idi));
    5625             :         //Double newREF_FREQUENCYi(refFrequencyColr(idi));
    5626             :         //MFrequency newREF_FREQUENCYi = refFrequencyMeasColr(idi);
    5627         684 :         Int newMEAS_FREQ_REFi = measFreqRefColr(idi);
    5628         684 :         Vector<Double> newRESOLUTIONi(resolutionColr(idi));
    5629             :         //Double newTOTAL_BANDWIDTHi = totalBandwidthColr(idi);
    5630             : 
    5631         684 :         if(verbose){
    5632         265 :           ostringstream oss; // needed for iomanip functions
    5633         265 :           oss << "   SPW " << std::setw(3) << idi << ": " << std::setw(5) << newNUM_CHANi 
    5634         265 :               << " channels, first channel = " << std::setprecision(9) << std::setw(14) << std::scientific << newCHAN_FREQi(0) << " Hz";
    5635         265 :           if(newNUM_CHANi>1){
    5636         255 :             oss << ", last channel = " << std::setprecision(9) << std::setw(14) << std::scientific << newCHAN_FREQi(newNUM_CHANi-1) << " Hz";
    5637             :           }
    5638         265 :           os << LogIO::NORMAL << oss.str() << LogIO::POST;
    5639         265 :         }
    5640             : 
    5641         684 :         vector<Double> mergedChanFreq;
    5642         684 :         vector<Double> mergedChanWidth;
    5643         684 :         vector<Double> mergedEffBW;
    5644         684 :         vector<Double> mergedRes;
    5645         684 :         vector<Int> mergedAverageN;
    5646         684 :         vector<vector<Int> > mergedAverageWhichSPW;
    5647         684 :         vector<vector<Int> > mergedAverageWhichChan;
    5648         684 :         vector<vector<Double> > mergedAverageChanFrac;
    5649             : 
    5650             :         // check for compatibility
    5651         684 :         if(newMEAS_FREQ_REFi != newMEAS_FREQ_REF){
    5652             :           os << LogIO::WARN
    5653             :              << "SPW " << idi << " cannot be combined with SPW " << id0 << ". Non-matching ref. frame."
    5654           0 :              << LogIO::POST;
    5655           0 :           return false; 
    5656             :         }
    5657             : 
    5658             :         // append or prepend spw to new spw
    5659             :         // overlap at all?
    5660         684 :         if(newCHAN_FREQ(newNUM_CHAN-1) + newCHAN_WIDTH(newNUM_CHAN-1)/2. 
    5661         684 :            < newCHAN_FREQi(0) - newCHAN_WIDTHi(0)/2.) {
    5662             :           // no overlap, and need to append
    5663        1563 :           for(uInt j=0; j<newNUM_CHAN; j++){
    5664        1548 :             mergedChanFreq.push_back(newCHAN_FREQ(j));
    5665        1548 :             mergedChanWidth.push_back(newCHAN_WIDTH(j));
    5666        1548 :             mergedEffBW.push_back(newEFFECTIVE_BW(j));
    5667        1548 :             mergedRes.push_back(newRESOLUTION(j));
    5668        1548 :             mergedAverageN.push_back(averageN[j]);
    5669        1548 :             mergedAverageWhichSPW.push_back(averageWhichSPW[j]);
    5670        1548 :             mergedAverageWhichChan.push_back(averageWhichChan[j]);
    5671        1548 :             mergedAverageChanFrac.push_back(averageChanFrac[j]);
    5672             :           }
    5673          15 :           vector<Int> tv;
    5674          15 :           tv.push_back(idi); // origin is spw idi
    5675          15 :           vector<Int> tv2;
    5676          15 :           tv2.push_back(0);
    5677          15 :           vector<Double> tvd;
    5678          15 :           tvd.push_back(1.); // fraction is 1.
    5679        1563 :           for(uInt j=0; j<newNUM_CHANi; j++){
    5680        1548 :             mergedChanFreq.push_back(newCHAN_FREQi(j));
    5681        1548 :             mergedChanWidth.push_back(newCHAN_WIDTHi(j));
    5682        1548 :             mergedEffBW.push_back(newEFFECTIVE_BWi(j));
    5683        1548 :             mergedRes.push_back(newRESOLUTIONi(j));
    5684        1548 :             mergedAverageN.push_back(1); // so far only one channel
    5685        1548 :             mergedAverageWhichSPW.push_back(tv);
    5686        1548 :             if(newIsDescendingI){
    5687           0 :               tv2[0] = newNUM_CHANi-1-j;
    5688             :             }
    5689             :             else{
    5690        1548 :               tv2[0] = j;
    5691             :             }
    5692        1548 :             mergedAverageWhichChan.push_back(tv2); // channel number is j
    5693        1548 :             mergedAverageChanFrac.push_back(tvd);
    5694             :           }
    5695          15 :         }
    5696         669 :         else if( newCHAN_FREQ(0) - newCHAN_WIDTH(0)/2. 
    5697         669 :                  > newCHAN_FREQi(newNUM_CHANi-1) + newCHAN_WIDTHi(newNUM_CHANi-1)/2.){ 
    5698             :           // no overlap, need to prepend
    5699           0 :           vector<Int> tv;
    5700           0 :           tv.push_back(idi); // origin is spw idi
    5701           0 :           vector<Int> tv2;
    5702           0 :           tv2.push_back(0);
    5703           0 :           vector<Double> tvd;
    5704           0 :           tvd.push_back(1.); // fraction is 1.
    5705           0 :           for(uInt j=0; j<newNUM_CHANi; j++){
    5706           0 :             mergedChanFreq.push_back(newCHAN_FREQi(j));
    5707           0 :             mergedChanWidth.push_back(newCHAN_WIDTHi(j));
    5708           0 :             mergedEffBW.push_back(newEFFECTIVE_BWi(j));
    5709           0 :             mergedRes.push_back(newRESOLUTIONi(j));
    5710           0 :             mergedAverageN.push_back(1); // so far only one channel
    5711           0 :             mergedAverageWhichSPW.push_back(tv);
    5712           0 :             if(newIsDescendingI){
    5713           0 :               tv2[0] = newNUM_CHANi-1-j;
    5714             :             }
    5715             :             else{
    5716           0 :               tv2[0] = j;
    5717             :             }
    5718           0 :             mergedAverageWhichChan.push_back(tv2); // channel number is j
    5719           0 :             mergedAverageChanFrac.push_back(tvd);
    5720             :           }
    5721           0 :           for(uInt j=0; j<newNUM_CHAN; j++){
    5722           0 :             mergedChanFreq.push_back(newCHAN_FREQ(j));
    5723           0 :             mergedChanWidth.push_back(newCHAN_WIDTH(j));
    5724           0 :             mergedEffBW.push_back(newEFFECTIVE_BW(j));
    5725           0 :             mergedRes.push_back(newRESOLUTION(j));
    5726           0 :             mergedAverageN.push_back(averageN[j]);
    5727           0 :             mergedAverageWhichSPW.push_back(averageWhichSPW[j]);
    5728           0 :             mergedAverageWhichChan.push_back(averageWhichChan[j]);
    5729           0 :             mergedAverageChanFrac.push_back(averageChanFrac[j]);
    5730             :           }
    5731           0 :         }
    5732             :         else{ // there is overlap
    5733         669 :           Int id0StartChan = 0;
    5734         669 :           if(newCHAN_FREQi(0) - newCHAN_WIDTHi(0)/2. < 
    5735         669 :              newCHAN_FREQ(newNUM_CHAN-1) - newCHAN_WIDTH(newNUM_CHAN-1)/2.){
    5736             :             // spw idi starts before spw id0
    5737             : 
    5738             :             // some utilities for the averaging info
    5739         646 :             vector<Int> tv; // temporary vector
    5740         646 :             tv.push_back(idi); // origin is spw idi
    5741         646 :             vector<Int> tv2;
    5742         646 :             tv2.push_back(0);
    5743         646 :             vector<Double> tvd;
    5744         646 :             tvd.push_back(1.); // fraction is 1.
    5745             : 
    5746             :             // find the first overlapping channel and prepend non-overlapping channels
    5747         646 :             Double ubound0 = newCHAN_FREQ(0) + newCHAN_WIDTH(0)/2.;
    5748         646 :             Double lbound0 = newCHAN_FREQ(0) - newCHAN_WIDTH(0)/2.;
    5749         646 :             Double uboundk = 0.;
    5750         646 :             Double lboundk = 0.;              
    5751             :             uInt k;
    5752         646 :             for(k=0; k<newNUM_CHANi; k++){
    5753         646 :               uboundk = newCHAN_FREQi(k) + newCHAN_WIDTHi(k)/2.;
    5754         646 :               lboundk = newCHAN_FREQi(k) - newCHAN_WIDTHi(k)/2.;              
    5755         646 :               if(lbound0 < uboundk){
    5756         646 :                 break;
    5757             :               }
    5758           0 :               mergedChanFreq.push_back(newCHAN_FREQi(k));
    5759           0 :               mergedChanWidth.push_back(newCHAN_WIDTHi(k));
    5760           0 :               mergedEffBW.push_back(newEFFECTIVE_BWi(k));
    5761           0 :               mergedRes.push_back(newRESOLUTIONi(k));
    5762           0 :               mergedAverageN.push_back(1); // so far only one channel
    5763           0 :               mergedAverageWhichSPW.push_back(tv);
    5764           0 :               if(newIsDescendingI){
    5765           0 :                 tv2[0] = newNUM_CHANi-1-k;
    5766             :               }
    5767             :               else{
    5768           0 :                 tv2[0] = k;
    5769             :               }
    5770           0 :               mergedAverageWhichChan.push_back(tv2); // channel number is k
    5771           0 :               mergedAverageChanFrac.push_back(tvd);         
    5772             :             }
    5773             :             // k's the one
    5774         646 :             if(lbound0 < uboundk && lboundk < lbound0){ // actual overlap, need to merge channel k with channel 0
    5775           0 :               Double newWidth = ubound0 - lboundk;
    5776           0 :               Double newCenter = lboundk + newWidth/2.;
    5777           0 :               mergedChanFreq.push_back(newCenter);
    5778           0 :               mergedChanWidth.push_back(newWidth);
    5779           0 :               mergedEffBW.push_back(newWidth); 
    5780           0 :               mergedRes.push_back(newWidth); 
    5781           0 :               mergedAverageN.push_back(averageN[0]+1); // one more channel contributes
    5782             :               // channel k is from spw idi
    5783           0 :               if(newIsDescendingI){
    5784           0 :                 tv2[0] = newNUM_CHANi-1-k;
    5785             :               }
    5786             :               else{
    5787           0 :                 tv2[0] = k;
    5788             :               }
    5789           0 :               for(int j=0; j<averageN[0]; j++){
    5790           0 :                 tv.push_back(averageWhichSPW[0][j]); // additional contributors
    5791           0 :                 tv2.push_back(averageWhichChan[0][j]); // channel 0 from spw id0
    5792           0 :                 tvd.push_back(averageChanFrac[0][j]);
    5793             :               }
    5794           0 :               mergedAverageWhichSPW.push_back(tv);
    5795           0 :               mergedAverageWhichChan.push_back(tv2); 
    5796           0 :               mergedAverageChanFrac.push_back(tvd);
    5797           0 :               id0StartChan = 1;
    5798             :             }
    5799         646 :           }
    5800             :           // now move along SPW id0 and merge until end of id0 is reached, then just copy
    5801      539600 :           for(uInt j=id0StartChan; j<newNUM_CHAN; j++){
    5802      538931 :             mergedChanFreq.push_back(newCHAN_FREQ(j));
    5803      538931 :             mergedChanWidth.push_back(newCHAN_WIDTH(j));
    5804      538931 :             mergedEffBW.push_back(newEFFECTIVE_BW(j));
    5805      538931 :             mergedRes.push_back(newRESOLUTION(j));
    5806    69322717 :             for(uInt k=0; k<newNUM_CHANi; k++){
    5807    68783786 :               Double overlap_frac = 0.;
    5808             :               // does channel j in spw id0 overlap with channel k in spw idi?
    5809    68783786 :               Double uboundj = newCHAN_FREQ(j) + newCHAN_WIDTH(j)/2.;
    5810    68783786 :               Double uboundk = newCHAN_FREQi(k) + newCHAN_WIDTHi(k)/2.;
    5811    68783786 :               Double lboundj = newCHAN_FREQ(j) - newCHAN_WIDTH(j)/2.;
    5812    68783786 :               Double lboundk = newCHAN_FREQi(k) - newCHAN_WIDTHi(k)/2.;
    5813             :               // determine fraction 
    5814    68783786 :               if(lboundj <= lboundk && uboundk <= uboundj){ // chan k is completely covered by chan j
    5815        2050 :                 overlap_frac = 1.;
    5816             :                 //cout << "j " << j << " k " << k << " case 1" << endl;
    5817             :                 //cout << "overlap " << overlap_frac << endl;
    5818             :               }
    5819    68781736 :               else if(lboundk <= lboundj && uboundj <= uboundk){ // chan j is completely covered by chan k 
    5820           0 :                 overlap_frac = newCHAN_WIDTH(j)/newCHAN_WIDTHi(k);
    5821             :                 //cout << "j " << j << " k " << k << " case 2" << endl;
    5822             :                 //cout << "overlap " << overlap_frac << endl;
    5823             :               }
    5824    68781736 :               else if(lboundj < lboundk && lboundk < uboundj && uboundj < uboundk){ // lower end of k is overlapping with j
    5825       12841 :                 overlap_frac = (uboundj - lboundk)/newCHAN_WIDTHi(k);
    5826             :                 //cout << "j " << j << " k " << k << " case 3" << endl;
    5827             :                 //cout << "overlap " << overlap_frac << endl;
    5828             :               }
    5829    68768895 :               else if(lboundk < lboundj && lboundj < uboundk && lboundj < uboundk){ // upper end of k is overlapping with j 
    5830       12400 :                 overlap_frac = (uboundk - lboundj)/newCHAN_WIDTHi(k);
    5831             :                 //cout << "j " << j << " k " << k << " case 4" << endl;
    5832             :                 //cout << "overlap " << overlap_frac << endl;
    5833             :               }
    5834    68783786 :               if(overlap_frac > 0.){ // update averaging info
    5835       27291 :                 averageN[j] += 1;
    5836       27291 :                 averageWhichSPW[j].push_back(idi);
    5837       27291 :                 if(newIsDescendingI){
    5838        2538 :                   averageWhichChan[j].push_back(newNUM_CHANi-1-k);
    5839             :                 }
    5840             :                 else{
    5841       24753 :                   averageWhichChan[j].push_back(k);
    5842             :                 }
    5843       27291 :                 averageChanFrac[j].push_back(overlap_frac);
    5844             :               }
    5845             :             } // end loop over spw idi
    5846             :             // append this channel with updated averaging info
    5847      538931 :             mergedAverageN.push_back(averageN[j]);
    5848      538931 :             mergedAverageWhichSPW.push_back(averageWhichSPW[j]);
    5849      538931 :             mergedAverageWhichChan.push_back(averageWhichChan[j]);
    5850      538931 :             mergedAverageChanFrac.push_back(averageChanFrac[j]);  
    5851             :           } // end loop over spw id0
    5852         669 :           if(newCHAN_FREQ(newNUM_CHAN-1) + newCHAN_WIDTH(newNUM_CHAN-1)/2.
    5853         669 :              < newCHAN_FREQi(newNUM_CHANi-1) + newCHAN_WIDTHi(newNUM_CHANi-1)/2.){// spw idi still continues!
    5854             :             // find the last overlapping channel
    5855         464 :             Int j = newNUM_CHAN-1;
    5856         464 :             Double uboundj = newCHAN_FREQ(j) + newCHAN_WIDTH(j)/2.;
    5857         464 :             Double lboundj = newCHAN_FREQ(j) - newCHAN_WIDTH(j)/2.;
    5858         464 :             Double uboundk = 0;
    5859         464 :             Double lboundk = 0;       
    5860             :             Int k;
    5861       44386 :             for(k=newNUM_CHANi-1; k>=0; k--){
    5862       44386 :               uboundk = newCHAN_FREQi(k) + newCHAN_WIDTHi(k)/2.;
    5863       44386 :               lboundk = newCHAN_FREQi(k) - newCHAN_WIDTHi(k)/2.;              
    5864       44386 :               if(lboundk <= uboundj){
    5865         464 :                 break;
    5866             :               }
    5867             :             }
    5868             :             // k's the one 
    5869         464 :             if(lboundk < uboundj && uboundj < uboundk ){ // actual overlap
    5870         441 :               Double overlap_frac = (uboundj - lboundk)/newCHAN_WIDTHi(k);
    5871         441 :               if(overlap_frac>0.01){ // merge channel k completely with channel j 
    5872         439 :                 Double newWidth = uboundk - lboundj;
    5873         439 :                 Double newCenter = (lboundj+uboundk)/2.;
    5874         439 :                 mergedChanFreq[j] =  newCenter;
    5875         439 :                 mergedChanWidth[j] = newWidth;
    5876         439 :                 mergedEffBW[j] = newWidth; 
    5877         439 :                 mergedRes[j] = newWidth; 
    5878         439 :                 mergedAverageChanFrac[j][mergedAverageN[j]-1] = 1.; 
    5879             :               }
    5880             :               else{ // create separate, (slightly) more narrow channel
    5881           2 :                 Double newWidth = uboundk - uboundj;
    5882           2 :                 Double newCenter = (uboundj+uboundk)/2.;
    5883           2 :                 vector<Int> tv;
    5884           2 :                 tv.push_back(idi); // origin is spw idi
    5885           2 :                 vector<Int> tv2;
    5886           2 :                 tv2.push_back(0);
    5887           2 :                 vector<Double> tvd;
    5888           2 :                 tvd.push_back(1.); // fraction is 1.
    5889           2 :                 mergedChanFreq.push_back(newCenter);
    5890           2 :                 mergedChanWidth.push_back(newWidth);
    5891           2 :                 mergedEffBW.push_back(newWidth);
    5892           2 :                 mergedRes.push_back(newWidth);
    5893           2 :                 mergedAverageN.push_back(1); // so far only one channel
    5894           2 :                 mergedAverageWhichSPW.push_back(tv);
    5895           2 :                 if(newIsDescendingI){
    5896           0 :                   tv2[0] = newNUM_CHANi-1-k;
    5897             :                 }
    5898             :                 else{
    5899           2 :                   tv2[0] = k;
    5900             :                 }
    5901           2 :                 mergedAverageWhichChan.push_back(tv2); // channel number is k
    5902           2 :                 mergedAverageChanFrac.push_back(tvd);
    5903           2 :               }
    5904         441 :               k++; // start appending remaining channels after k
    5905             :             }
    5906             :             // append the remaining channels
    5907         464 :             vector<Int> tv;
    5908         464 :             tv.push_back(idi); // origin is spw idi
    5909         464 :             vector<Int> tv2;
    5910         464 :             tv2.push_back(0);
    5911         464 :             vector<Double> tvd;
    5912         464 :             tvd.push_back(1.); // fraction is 1.
    5913       44409 :             for(uInt m=k; m<newNUM_CHANi; m++){
    5914       43945 :               mergedChanFreq.push_back(newCHAN_FREQi(m));
    5915       43945 :               mergedChanWidth.push_back(newCHAN_WIDTHi(m));
    5916       43945 :               mergedEffBW.push_back(newEFFECTIVE_BWi(m));
    5917       43945 :               mergedRes.push_back(newRESOLUTIONi(m));
    5918       43945 :               mergedAverageN.push_back(1); // so far only one channel
    5919       43945 :               mergedAverageWhichSPW.push_back(tv);
    5920       43945 :                 if(newIsDescendingI){
    5921        4596 :                   tv2[0] = newNUM_CHANi-1-m;
    5922             :                 }
    5923             :                 else{
    5924       39349 :                   tv2[0] = m;
    5925             :                 }
    5926       43945 :               mergedAverageWhichChan.push_back(tv2); // channel number is m
    5927       43945 :               mergedAverageChanFrac.push_back(tvd);
    5928             :             }
    5929         464 :           } // end if spw idi still continues
    5930             :         } // end if there is overlap    
    5931             : 
    5932             : 
    5933         684 :         newNUM_CHAN = mergedChanFreq.size();
    5934         684 :         newCHAN_FREQ.assign(Vector<Double>(mergedChanFreq));
    5935         684 :         newCHAN_WIDTH.assign(Vector<Double>(mergedChanWidth));
    5936         684 :         newEFFECTIVE_BW.assign(Vector<Double>(mergedEffBW));
    5937         684 :         newREF_FREQUENCY = newCHAN_FREQ(0); 
    5938         684 :         newTOTAL_BANDWIDTH = fabs(newCHAN_FREQ(newNUM_CHAN-1) - newCHAN_FREQ(0))
    5939         684 :           + fabs(newCHAN_WIDTH(newNUM_CHAN-1)/2.) + fabs(newCHAN_WIDTH(0)/2.);
    5940         684 :         newRESOLUTION.assign(Vector<Double>(mergedRes));
    5941         684 :         averageN = mergedAverageN;
    5942         684 :         averageWhichSPW = mergedAverageWhichSPW;
    5943         684 :         averageWhichChan = mergedAverageWhichChan;
    5944         684 :         averageChanFrac = mergedAverageChanFrac;
    5945             : 
    5946         684 :       } // end loop over SPWs
    5947             : 
    5948             :       // print channel fractions for debugging
    5949             : //       vector< vector<bool> > wasprinted;
    5950             : //       for(uInt i=0; i<newNUM_CHAN; i++){
    5951             : //      vector<bool> tboolv;
    5952             : //      cout << "i freq width " << i << " " << newCHAN_FREQ(i) << " " << newCHAN_WIDTH(i) << endl;
    5953             : //      for(Int j=0; j<averageN[i]; j++){
    5954             : //        cout << " i, j " << i << ", " << j << " averageWhichChan[i][j] " << averageWhichChan[i][j]
    5955             : //             << " averageWhichSPW[i][j] " << averageWhichSPW[i][j] << endl;
    5956             : //        cout << " averageChanFrac[i][j] " << averageChanFrac[i][j] << endl;
    5957             : //        tboolv.push_back(false);
    5958             : //      }
    5959             : //      wasprinted.push_back(tboolv);
    5960             : //       }
    5961             :       
    5962             :       
    5963         182 :       if(noModify){ // newCHAN_FREQ and newCHAN_WIDTH have been determined now
    5964         152 :         return true;
    5965             :       }
    5966             : 
    5967             :       // now need write access
    5968          30 :       MSSpWindowColumns SPWCols(spwtable);
    5969          30 :       ScalarColumn<Int> numChanCol = SPWCols.numChan(); 
    5970          30 :       ArrayColumn<Double> chanFreqCol = SPWCols.chanFreq(); 
    5971          30 :       ArrayColumn<Double> chanWidthCol = SPWCols.chanWidth(); 
    5972             :       //    ArrayMeasColumn<MFrequency> chanFreqMeasCol = SPWCols.chanFreqMeas();
    5973          30 :       ScalarColumn<Int> measFreqRefCol = SPWCols.measFreqRef();
    5974          30 :       ArrayColumn<Double> effectiveBWCol = SPWCols.effectiveBW();   
    5975          30 :       ScalarColumn<Double> refFrequencyCol = SPWCols.refFrequency(); 
    5976             :       //    ScalarMeasColumn<MFrequency> refFrequencyMeasCol = SPWCols.refFrequencyMeas(); 
    5977          30 :       ArrayColumn<Double> resolutionCol = SPWCols.resolution(); 
    5978          30 :       ScalarColumn<Double> totalBandwidthCol = SPWCols.totalBandwidth();
    5979             : 
    5980          30 :       if(verbose){
    5981             :         os << LogIO::NORMAL << "Combined SPW will have " << newNUM_CHAN 
    5982          30 :            << " channels. May change in later regridding." << LogIO::POST;
    5983             :       }
    5984             : 
    5985             :       // Create new row in the SPW table (with ID nextSPWId) by copying
    5986             :       // all information from row theSPWId
    5987          30 :       if(!spwtable.canAddRow()){
    5988             :         os << LogIO::WARN
    5989             :            << "Unable to add new row to SPECTRAL_WINDOW table. Cannot proceed with spwCombine ..." 
    5990           0 :            << LogIO::POST;
    5991           0 :         return false; 
    5992             :       }
    5993             : 
    5994          30 :       TableRow SPWRow(spwtable);
    5995          30 :       TableRecord spwRecord = SPWRow.get(id0);
    5996             : 
    5997             :       // write new spw to spw table (ID =  newSpwId)
    5998          30 :       spwtable.addRow();
    5999          30 :       SPWRow.putMatchingFields(newSPWId, spwRecord);
    6000             : 
    6001          30 :       chanFreqCol.put(newSPWId, newCHAN_FREQ);
    6002          30 :       numChanCol.put(newSPWId, newNUM_CHAN);
    6003          30 :       chanWidthCol.put(newSPWId,  newCHAN_WIDTH);
    6004          30 :       refFrequencyCol.put(newSPWId, newREF_FREQUENCY);
    6005          30 :       totalBandwidthCol.put(newSPWId, newTOTAL_BANDWIDTH);
    6006          30 :       effectiveBWCol.put(newSPWId, newEFFECTIVE_BW);
    6007          30 :       resolutionCol.put(newSPWId, newRESOLUTION);
    6008             : 
    6009             :       // delete unwanted spws and memorize the new ID of the new merged one.
    6010             :       // (remember the IDs were sorted above)
    6011         288 :       for(int i=nSpwsToCombine-1; i>=0; i--){ // remove highest row numbers first
    6012         258 :         spwtable.removeRow(spwsToCombine[i]);
    6013             :       }
    6014          30 :       newSPWId -= nSpwsToCombine; 
    6015             : 
    6016             :       // other tables to correct: MAIN, FREQ_OFFSET, SYSCAL, FEED, DATA_DESCRIPTION, SOURCE
    6017             : 
    6018             :       // 1) SOURCE (an optional table)
    6019          30 :       uInt numSourceRows = 0;
    6020          30 :       MSSource* p_sourcetable = NULL;
    6021          30 :       MSSourceColumns* p_sourceCol = NULL;
    6022          30 :       if(Table::isReadable(ms_p.sourceTableName())){
    6023          30 :         p_sourcetable = &(ms_p.source());
    6024          30 :         p_sourceCol = new MSSourceColumns(*p_sourcetable);
    6025          30 :         numSourceRows = p_sourcetable->nrow();
    6026          30 :         ScalarColumn<Int> SOURCESPWIdCol = p_sourceCol->spectralWindowId();
    6027             :         // loop over source table rows
    6028        1317 :         for(uInt i=0; i<numSourceRows; i++){
    6029       30261 :           for(uInt j=0; j<nSpwsToCombine; j++){
    6030             :             // if spw id affected, replace by newSpwId
    6031       28974 :             if(SOURCESPWIdCol(i) == spwsToCombine[j]){ // source row i is affected
    6032        1286 :               SOURCESPWIdCol.put(i, newSPWId);
    6033             :             }
    6034             :           } // end for j
    6035             :         }// end for i
    6036          30 :       }
    6037           0 :       else if(verbose){ // there is no source table
    6038           0 :         os << LogIO::NORMAL << "Note: MS contains no SOURCE table ..." << LogIO::POST;
    6039             :       }
    6040             : 
    6041             :       // 2) DATA_DESCRIPTION
    6042          30 :       MSDataDescription ddtable = ms_p.dataDescription();
    6043          30 :       uInt numDataDescs = ddtable.nrow();
    6044          30 :       MSDataDescColumns DDCols(ddtable);
    6045          30 :       ScalarColumn<Int> SPWIdCol = DDCols.spectralWindowId();
    6046          30 :       ScalarColumn<Int> PolIdCol = DDCols.polarizationId();
    6047          30 :       vector<uInt> affDDIds;  
    6048          30 :       vector<Bool> DDRowsToDelete(numDataDescs, false);
    6049          30 :       std::map<Int, Int> tempDDIndex; // store relation between old and new DD Ids
    6050          30 :       std::map<Int, Int> DDtoSPWIndex; // store relation between old DD Ids and old SPW Ids 
    6051             :       //  (only for affected SPW IDs)
    6052             :       // loop over DD table rows
    6053         288 :       for(uInt i=0; i<numDataDescs; i++){
    6054             :         // if spw id affected, replace by newSpwId
    6055        5526 :         for(uInt j=0; j<nSpwsToCombine; j++){
    6056             :           // if spw id affected, replace by newSpwId
    6057        5268 :           if(SPWIdCol(i) == spwsToCombine[j]){ // DD row i is affected
    6058             :             // correct the SPW Id in the DD table
    6059         258 :             SPWIdCol.put(i, newSPWId);
    6060             :             // memorize affected DD IDs in affDDIds
    6061         258 :             affDDIds.push_back(i);
    6062             :             // store relation between old DD Id and old SPW ID for later use in the modification of the MAIN table
    6063         258 :             DDtoSPWIndex.insert(std::pair<Int, Int>(i, spwsToCombine[j])); // note: this relation can be many-to-one  
    6064             :           }     
    6065             :         }
    6066             :       }
    6067             :       // Find redundant DD IDs
    6068             :       // loop over DD table rows
    6069         288 :       for(uInt i=0; i<numDataDescs; i++){
    6070         258 :         Bool affected = false;
    6071        5268 :         for(uInt j=0; j<affDDIds.size(); j++){
    6072        5040 :           if(i == affDDIds[j] && !DDRowsToDelete[i]){
    6073          30 :             affected = true;
    6074          30 :             break;
    6075             :           }
    6076             :         }
    6077         258 :         if(!affected){
    6078         228 :           continue;
    6079             :         }
    6080             :         else { // i is an affected row
    6081          30 :           Int PolIDi = PolIdCol(i);
    6082          30 :           Int SpwIDi = SPWIdCol(i);
    6083             :           // loop over following DD table rows
    6084         258 :           for(uInt j=i+1; j<numDataDescs; j++){
    6085             :             // if row i and row j redundant?
    6086         228 :             if(PolIDi == PolIdCol(j) && SpwIDi == SPWIdCol(j)){
    6087             :               // mark for deletion
    6088         228 :               DDRowsToDelete[j] = true;
    6089             :               // fill map for DDrenumbering
    6090         228 :               tempDDIndex.insert(std::pair<Int, Int>(j, i));
    6091             :             }
    6092             :           }    
    6093             :         } // end if affected 
    6094             :       }
    6095             :       // delete redundant DD rows
    6096          30 :       Int removed = 0;
    6097         288 :       for(uInt i=0; i<numDataDescs; i++){
    6098         258 :         if(DDRowsToDelete[i]){
    6099         228 :           ddtable.removeRow(i-removed);
    6100         228 :           removed++;
    6101             :         }
    6102             :         else{ // this row is not deleted but changes its number by <removed> due to removal of others
    6103          30 :         tempDDIndex.insert(std::pair<Int, Int>(i, i-removed));
    6104             :         }
    6105             :       }
    6106             : 
    6107             :       // 3) FEED  
    6108          30 :       MSFeed feedtable = ms_p.feed();
    6109          30 :       uInt numFeedRows = feedtable.nrow();
    6110          30 :       MSFeedColumns feedCols(feedtable);
    6111          30 :       ScalarColumn<Int> feedSPWIdCol = feedCols.spectralWindowId();
    6112             :  
    6113             :       // loop over FEED table rows
    6114         511 :       for(uInt i=0; i<numFeedRows; i++){
    6115             :         // if spw id affected, replace by newSpwId
    6116        2851 :         for(uint j=0; j<nSpwsToCombine; j++){
    6117             :           // if spw id affected, replace by newSpwId
    6118        2370 :           if(feedSPWIdCol(i) == spwsToCombine[j]){ // feed row i is affected
    6119          78 :             feedSPWIdCol.put(i, newSPWId);
    6120             :           }     
    6121             :         }
    6122             :       }
    6123             : 
    6124             :       // TODO: (possibly, not clear if necessary) remove redundant FEED rows and propagate
    6125             : 
    6126             :       // 4) SYSCAL
    6127             : 
    6128             :       // note: syscal is optional
    6129             : 
    6130          30 :       if(!ms_p.sysCal().isNull()){
    6131           3 :         MSSysCal sysCaltable = ms_p.sysCal();
    6132           3 :         uInt numSysCalRows = sysCaltable.nrow();
    6133           3 :         MSSysCalColumns sysCalCols(sysCaltable);
    6134           3 :         ScalarColumn<Int> sysCalSPWIdCol = sysCalCols.spectralWindowId();
    6135             :       
    6136             :         // loop over SYSCAL table rows
    6137           3 :         for(uInt i=0; i<numSysCalRows; i++){
    6138             :           // if spw id affected, replace by newSpwId
    6139           0 :           for(uInt j=0; j<nSpwsToCombine; j++){
    6140             :             // if spw id affected, replace by newSpwId
    6141           0 :             if(sysCalSPWIdCol(i) == spwsToCombine[j]){ // SysCal row i is affected
    6142           0 :               sysCalSPWIdCol.put(i, newSPWId);
    6143             :             }     
    6144             :           }
    6145             :         }
    6146           3 :       }
    6147             : 
    6148             :       // 5) FREQ_OFFSET
    6149             : 
    6150             :       // note: freq_offset is optional
    6151             : 
    6152          30 :       if(!ms_p.freqOffset().isNull()){
    6153           0 :         MSFreqOffset freqOffsettable = ms_p.freqOffset();
    6154           0 :         uInt numFreqOffsetRows = freqOffsettable.nrow();
    6155           0 :         MSFreqOffsetColumns freqOffsetCols(freqOffsettable);
    6156           0 :         ScalarColumn<Int> freqOffsetSPWIdCol = freqOffsetCols.spectralWindowId();
    6157             :       
    6158             :         // loop over FREQ_OFFSET table rows
    6159           0 :         for(uInt i=0; i<numFreqOffsetRows; i++){
    6160             :           // if spw id affected, replace by newSpwId
    6161           0 :           for(uInt j=0; j<nSpwsToCombine; j++){
    6162             :             // if spw id affected, replace by newSpwId
    6163           0 :             if(freqOffsetSPWIdCol(i) == spwsToCombine[j]){ // FreqOffset row i is affected
    6164           0 :               freqOffsetSPWIdCol.put(i, newSPWId);
    6165             :             }     
    6166             :           }
    6167             :         }
    6168           0 :       }
    6169             : 
    6170             :       // 6) MAIN
    6171             : 
    6172             :       Table newMain(TableCopy::makeEmptyTable( tempNewName,
    6173          60 :                                                Record(),
    6174          30 :                                                (Table) ms_p,
    6175             :                                                Table::New,
    6176             :                                                Table::AipsrcEndian,
    6177             :                                                true, // replaceTSM 
    6178             :                                                true // noRows
    6179             :                                                )
    6180          60 :                     );
    6181             :       
    6182          30 :       TableCopy::copySubTables(newMain, ms_p, false);
    6183             :       
    6184          30 :       MSMainColumns mainCols((MeasurementSet&)newMain);
    6185          30 :       MSMainColumns oldMainCols(ms_p);
    6186             :       
    6187          30 :       uInt nMainTabRows = ms_p.nrow();
    6188             :       
    6189             :       // columns which depend on the number of frequency channels and may need to be combined:
    6190             :       // DATA, FLOAT_DATA, CORRECTED_DATA, MODEL_DATA, LAG_DATA, SIGMA_SPECTRUM,
    6191             :       // WEIGHT_SPECTRUM, FLAG, and FLAG_CATEGORY    
    6192          30 :       ArrayColumn<Complex> CORRECTED_DATACol =  mainCols.correctedData();
    6193          30 :       ArrayColumn<Complex> oldCORRECTED_DATACol = oldMainCols.correctedData();
    6194          30 :       ArrayColumn<Complex>  DATACol =  mainCols.data();
    6195          30 :       ArrayColumn<Complex>  oldDATACol = oldMainCols.data();
    6196          30 :       ArrayColumn<Float> FLOAT_DATACol =  mainCols.floatData();
    6197          30 :       ArrayColumn<Float> oldFLOAT_DATACol = oldMainCols.floatData();
    6198          30 :       ArrayColumn<Complex> LAG_DATACol =  mainCols.lagData();
    6199          30 :       ArrayColumn<Complex> oldLAG_DATACol = oldMainCols.lagData();
    6200          30 :       ArrayColumn<Complex> MODEL_DATACol =  mainCols.modelData();
    6201          30 :       ArrayColumn<Complex> oldMODEL_DATACol = oldMainCols.modelData();
    6202          30 :       ArrayColumn<Float> SIGMA_SPECTRUMCol =  mainCols.sigmaSpectrum();
    6203          30 :       ArrayColumn<Float> oldSIGMA_SPECTRUMCol = oldMainCols.sigmaSpectrum();
    6204          30 :       ArrayColumn<Float> WEIGHT_SPECTRUMCol =  mainCols.weightSpectrum();
    6205          30 :       ArrayColumn<Float> oldWEIGHT_SPECTRUMCol = oldMainCols.weightSpectrum();
    6206          30 :       ArrayColumn<Bool> FLAGCol =  mainCols.flag();
    6207          30 :       ArrayColumn<Bool> oldFLAGCol = oldMainCols.flag();
    6208          30 :       ArrayColumn<Bool> FLAG_CATEGORYCol =  mainCols.flagCategory();
    6209          30 :       ArrayColumn<Bool> oldFLAG_CATEGORYCol = oldMainCols.flagCategory();
    6210             :       
    6211             :       // columns which may be different for otherwise matching main table rows
    6212             :       //  and need to be combined
    6213          30 :       ScalarColumn<Bool> flagRowCol = oldMainCols.flagRow();
    6214             : 
    6215             :       // administrational columns needed from the main table
    6216          30 :       ArrayColumn<Float> SIGMACol =  oldMainCols.sigma();
    6217          30 :       ScalarColumn<Int> fieldCol = oldMainCols.fieldId();
    6218          30 :       ScalarColumn<Int> DDIdCol = oldMainCols.dataDescId();
    6219          30 :       ScalarColumn<Int> antenna1Col = oldMainCols.antenna1();
    6220          30 :       ScalarColumn<Int> antenna2Col = oldMainCols.antenna2();
    6221          30 :       ScalarColumn<Double> timeCol = oldMainCols.time(); 
    6222          30 :       ScalarColumn<Double> intervalCol = oldMainCols.interval();
    6223          30 :       ScalarColumn<Double> exposureCol = oldMainCols.exposure();
    6224          30 :       ScalarMeasColumn<MEpoch> mainTimeMeasCol = oldMainCols.timeMeas();
    6225             : 
    6226             :       // arrays for composing the combined columns 
    6227             :       // model them on the first affected row of the main table
    6228             :       
    6229          30 :       Matrix<Complex> newCorrectedData; 
    6230          30 :       Matrix<Complex> newData;
    6231          30 :       Matrix<Float> newFloatData;
    6232          30 :       Matrix<Complex> newLagData;
    6233          30 :       Matrix<Complex> newModelData;
    6234          30 :       Matrix<Float> newSigmaSpectrum;
    6235          30 :       Matrix<Float> newWeightSpectrum;
    6236          30 :       Matrix<Bool> newFlag;
    6237          30 :       Array<Bool> newFlagCategory; // has three dimensions
    6238             :       Bool newFlagRow; 
    6239             : 
    6240             :       // create time-sorted index for main table access
    6241          30 :       Vector<uInt> sortedI(nMainTabRows);
    6242             :       {
    6243          30 :         Vector<Double> mainTimesV = oldMainCols.time().getColumn();
    6244          30 :         GenSortIndirect<Double>::sort(sortedI,mainTimesV);
    6245          30 :       }
    6246             : 
    6247             :       // find the first row affected by the spw combination
    6248          30 :       Int firstAffRow = 0;
    6249          30 :       for(uInt mRow=0; mRow<nMainTabRows; mRow++){
    6250          30 :         uInt sortedMRow = sortedI(mRow);
    6251          30 :         if(DDtoSPWIndex.find(DDIdCol(sortedMRow)) != DDtoSPWIndex.end( )){
    6252          30 :           firstAffRow = sortedMRow;
    6253          30 :           break;
    6254             :         }
    6255             :       }
    6256             :       
    6257             :       // get the number of correlations from the
    6258             :       // dimension of the first axis of the sigma column
    6259          30 :       uInt nCorrelations = SIGMACol(firstAffRow).shape()(0); 
    6260             :       
    6261          30 :       IPosition newShape = IPosition(2, nCorrelations, newNUM_CHAN);
    6262             :       
    6263          30 :       Bool CORRECTED_DATAColIsOK = !CORRECTED_DATACol.isNull();
    6264          30 :       Bool DATAColIsOK = !DATACol.isNull();
    6265          30 :       Bool FLOAT_DATAColIsOK = !FLOAT_DATACol.isNull();
    6266          30 :       Bool LAG_DATAColIsOK = !LAG_DATACol.isNull();
    6267          30 :       Bool MODEL_DATAColIsOK = !MODEL_DATACol.isNull();
    6268          30 :       Bool SIGMA_SPECTRUMColIsOK = !SIGMA_SPECTRUMCol.isNull();
    6269          30 :       Bool WEIGHT_SPECTRUMColIsOK = !WEIGHT_SPECTRUMCol.isNull(); // rechecked further below
    6270          30 :       Bool FLAGColIsOK = !FLAGCol.isNull();
    6271          30 :       Bool FLAG_CATEGORYColIsOK = false; // to be set to the correct value further below
    6272             :       
    6273             :       // initialize arrays to store combined column data
    6274          30 :       if(CORRECTED_DATAColIsOK){
    6275          17 :         newCorrectedData.resize(newShape);
    6276             :       }
    6277          30 :       if(DATAColIsOK){
    6278          30 :         newData.resize(newShape);
    6279             :       }
    6280          30 :       if(FLOAT_DATAColIsOK){
    6281           0 :         newFloatData.resize(newShape);
    6282             :       }
    6283          30 :       if(LAG_DATAColIsOK){
    6284           0 :         newLagData.resize(newShape); 
    6285             :       }
    6286          30 :       if(MODEL_DATAColIsOK){
    6287          17 :         newModelData.resize(newShape);
    6288             :       }
    6289          30 :       if(SIGMA_SPECTRUMColIsOK){
    6290           2 :         newSigmaSpectrum.resize(newShape);
    6291             :       }
    6292          30 :       if(WEIGHT_SPECTRUMColIsOK){
    6293          30 :         if(oldWEIGHT_SPECTRUMCol.isDefined(firstAffRow)){ // required column but may be empty
    6294          25 :           newWeightSpectrum.resize(newShape);
    6295             :         }
    6296             :         else{
    6297           5 :           WEIGHT_SPECTRUMColIsOK = false;
    6298             :         }
    6299             :       }
    6300          30 :       if(FLAGColIsOK){ // required but one never knows (there may be bugs elsewhere)
    6301          30 :         newFlag.resize(newShape);
    6302             :       }
    6303          30 :       IPosition flagCatShape;
    6304          30 :       uInt nCat  = 0;
    6305          30 :       if(!FLAG_CATEGORYCol.isNull()){ 
    6306          30 :         if(oldFLAG_CATEGORYCol.isDefined(firstAffRow)){ // required column but may be empty
    6307           0 :           FLAG_CATEGORYColIsOK = true;
    6308           0 :           flagCatShape = oldFLAG_CATEGORYCol.shape(firstAffRow);
    6309           0 :           nCat = flagCatShape(2); // the dimension of the third axis ==
    6310             :           // number of categories
    6311           0 :           newFlagCategory.resize(IPosition(3, nCorrelations, newNUM_CHAN, nCat));
    6312             :         } 
    6313             :       }
    6314             :       
    6315             :       /////////////////////////////////////////
    6316             :  
    6317             :       // Loop over main table rows
    6318          30 :       uInt mainTabRowI = 0;
    6319          30 :       uInt mainTabRow = sortedI(mainTabRowI);
    6320          30 :       uInt newMainTabRow = 0;
    6321          30 :       uInt nIncompleteCoverage = 0; // number of rows with incomplete SPW coverage
    6322             : 
    6323          30 :       Int prevNewMainTabRow = -1; // needed to reduce redundant warning output
    6324          30 :       vector<Int> prevFailedAvChans;
    6325          30 :       vector<Int> prevFailedAvCorrs;
    6326             : 
    6327             :       // prepare progress meter
    6328          30 :       Float progress = 0.2;
    6329          30 :       Float progressStep = 0.2;
    6330          30 :       if(nMainTabRows>100000){
    6331           2 :         progress = 0.1;
    6332           2 :         progressStep = 0.1;
    6333             :       }
    6334             : 
    6335     1846910 :       while(mainTabRowI<nMainTabRows &&
    6336      923440 :             (mainTabRow = sortedI(mainTabRowI)) < nMainTabRows
    6337             :             ){
    6338             :         
    6339             :         // should row be combined with others, i.e. has SPW changed?
    6340             :         // no -> just renumber DD ID (because of shrunk DD ID table)
    6341             :         
    6342             :         // yes-> find rows from the spws tobe combined with same timestamp, antennas and field
    6343             :         //       merge these rows
    6344             :         //       write merged row over first one, correcting DD ID at the same time
    6345             :         //       set TIME to 0 in other merged rows
    6346             :         //       reduce nMainTabRows accordingly
    6347             :         
    6348             :         // continue
    6349             :         //
    6350             :         // when finished, delete all rows with TIME = 0
    6351             :         
    6352      923440 :         Double theTime = timeCol(mainTabRow);
    6353             :         
    6354             :         // row was already combined with a previous row?
    6355      923440 :         if(theTime == 0){
    6356             :           //      cout << "skipping row with zero time " << mainTabRow << endl;
    6357      486918 :           mainTabRowI++;
    6358      486918 :           continue;
    6359             :         }
    6360             :         
    6361      436522 :         Int theDataDescId = DDIdCol(mainTabRow);
    6362             :         
    6363             :         // row affected by the spw combination? (uses the old DD numbering)
    6364      436522 :         if(DDtoSPWIndex.find(theDataDescId) != DDtoSPWIndex.end( )){
    6365             :           // find matching affected rows with same time stamp, antennas and field
    6366      436522 :           Int theAntenna1 = antenna1Col(mainTabRow);
    6367      436522 :           Int theAntenna2 = antenna2Col(mainTabRow);
    6368      436522 :           Int theField = fieldCol(mainTabRow);
    6369      436522 :           Double theInterval = intervalCol(mainTabRow);
    6370      436522 :           Double toleratedTimeDiff = theInterval/10.;
    6371      436522 :           Double theExposure = exposureCol(mainTabRow);
    6372      436522 :           vector<Int> matchingRows;
    6373      436522 :           matchingRows.push_back(mainTabRow);
    6374      436522 :           vector<Int> matchingRowSPWIds;
    6375      436522 :           matchingRowSPWIds.push_back(DDtoSPWIndex.at(theDataDescId));
    6376      436522 :           std::map<Int, Int> SPWtoRowIndex;
    6377      436522 :           SPWtoRowIndex.insert(std::pair<Int, Int>(matchingRowSPWIds[0], mainTabRow));
    6378             : 
    6379             :           //      cout << "theRow = " << mainTabRow << ", time = " << theTime << " DDID " << theDataDescId << endl;
    6380             :           
    6381      436522 :           uInt nextRowI = mainTabRowI+1;
    6382             :           uInt nextRow;
    6383             :           //      cout << "nextRow = " << nextRow << ", time diff  = " << timeCol(nextRow) - theTime << " DDID " << DDIdCol(nextRow) << endl;
    6384      436522 :           while(nextRowI<nMainTabRows && 
    6385    12786634 :                 (nextRow = sortedI(nextRowI))<nMainTabRows && // assignment!
    6386    38339687 :                 (timeCol(nextRow) - theTime)< toleratedTimeDiff &&
    6387    12766249 :                 matchingRows.size() < nSpwsToCombine // there should be one matching row per SPW
    6388             :                 ){
    6389             : 
    6390    12350282 :         if( DDtoSPWIndex.find(DDIdCol(nextRow)) == DDtoSPWIndex.end( ) ||
    6391    12350282 :                antenna1Col(nextRow) != theAntenna1 ||
    6392    25187482 :                antenna2Col(nextRow) != theAntenna2 ||
    6393      486918 :                fieldCol(nextRow) != theField ){ // not a matching row
    6394    11863364 :               nextRowI++;
    6395    11863364 :               continue;
    6396             :             }
    6397             :             // check that the intervals are the same
    6398      486918 :             if(fabs(intervalCol(nextRow)-theInterval) > 1E-5){
    6399           0 :               os << LogIO::WARN << "Error: for time " <<  MVTime(theTime/C::day).string(MVTime::DMY,7) << ", baseline (" << theAntenna1 << ", "
    6400             :                  << theAntenna2 << "), field "<< theField << ", DataDescID " << DDIdCol(mainTabRow)
    6401             :                  << " found matching row with DataDescID " << DDIdCol(nextRow) << endl
    6402             :                  << " but the two rows have different intervals: " << theInterval
    6403             :                  << " vs. " << intervalCol(nextRow)
    6404           0 :                  << LogIO::POST;
    6405           0 :               if(!flagRowCol(nextRow)){
    6406           0 :                 os << LogIO::SEVERE << "You need to flag row " << nextRow << " to proceed." << LogIO::POST;
    6407           0 :                 return false;
    6408             :               }
    6409             :               else{
    6410           0 :                 os << LogIO::WARN << "Fortunately, row " << nextRow << " is flagged so this problem will be ignored." << LogIO::POST;
    6411             :               }         
    6412             :             }
    6413             :             // check that the exposures are the same
    6414      486918 :             if(fabs(exposureCol(nextRow)-theExposure) > 1E-5){
    6415           0 :               os << LogIO::WARN << "Error: for time " <<  MVTime(theTime/C::day).string(MVTime::DMY,7) << ", baseline (" << theAntenna1 << ", "
    6416             :                  << theAntenna2 << "), field "<< theField << ", DataDescID " << DDIdCol(mainTabRow)
    6417             :                  << " found matching row with DataDescID " << DDIdCol(nextRow) << endl
    6418             :                  << " but the two rows have different exposures: " << theExposure
    6419             :                  << " vs. " << exposureCol(nextRow)
    6420           0 :                  << LogIO::POST;
    6421           0 :               if(!flagRowCol(nextRow)){
    6422           0 :                 os << LogIO::SEVERE << "You need to flag row " << nextRow << " to proceed." << LogIO::POST;
    6423           0 :                 return false;
    6424             :               }
    6425             :               else{
    6426           0 :                 os << LogIO::WARN << "Fortunately row " << nextRow << " is flagged so this problem will be ignored." << LogIO::POST;
    6427             :               }         
    6428             :             }
    6429             :             // found a matching row
    6430      486918 :             Int theSPWId = DDtoSPWIndex.at(DDIdCol(nextRow));
    6431      486918 :         if(SPWtoRowIndex.find(theSPWId) != SPWtoRowIndex.end( )){ // there should be a one-to-one relation: SPW <-> matching row
    6432           0 :               os << LogIO::WARN << "Error: for time " << MVTime(theTime/C::day).string(MVTime::DMY,7) << ", baseline (" << theAntenna1 << ","
    6433             :                  << theAntenna2 << "), field "<< theField << " found more than one row for SPW "
    6434           0 :                  << theSPWId << LogIO::POST;
    6435           0 :               if(!flagRowCol(nextRow)){
    6436           0 :                 os << LogIO::SEVERE << "You need to flag row " << nextRow << " to proceed." << LogIO::POST;
    6437           0 :                 return false;
    6438             :               }
    6439             :               else{
    6440           0 :                 os << LogIO::WARN << "Fortunately, row " << nextRow << " is flagged so this problem will be ignored." << LogIO::POST;
    6441             :               }         
    6442             :             }
    6443             :             else{ // this SPW not yet covered, memorize SPWId, row number, and relation
    6444      486918 :               matchingRowSPWIds.push_back(theSPWId);
    6445      486918 :               matchingRows.push_back(nextRow);
    6446      486918 :               SPWtoRowIndex.insert(std::pair<Int, Int>(theSPWId, nextRow));
    6447             :               // cout << "matching nextRow = " << nextRow << ", time = " << timeCol(nextRow) << " DDID " << DDIdCol(nextRow) << endl;
    6448             :             }
    6449      486918 :             nextRowI++;
    6450             :           } // end while nextRowI ...
    6451             :           
    6452             :           // now we have a set of matching rows
    6453      436522 :           uInt nMatchingRows = matchingRows.size();
    6454             :           
    6455      436522 :           if(nMatchingRows < nSpwsToCombine){
    6456       16924 :             if(nIncompleteCoverage==0){
    6457             :               os << LogIO::WARN << "Incomplete coverage of combined SPW starting at timestamp " 
    6458           4 :                  <<  MVTime(timeCol(mainTabRow)/C::day).string(MVTime::DMY,7)
    6459             :                  << ", baseline ( " << theAntenna1 << ", " << theAntenna2 << " )" << endl
    6460           4 :                  << "In this and further affected rows, the data arrays will be padded with zeros and corresponding channels flagged." <<  LogIO::POST;
    6461             :             }
    6462       16924 :             nIncompleteCoverage++;
    6463             :           }
    6464             : 
    6465             :           // reset arrays and prepare input data matrices
    6466             :           
    6467      436522 :           if(CORRECTED_DATAColIsOK){
    6468        7842 :             newCorrectedData.set(0);
    6469             :           }
    6470      436522 :           if(DATAColIsOK){
    6471      436522 :             newData.set(0);
    6472             :           }
    6473      436522 :           if(FLOAT_DATAColIsOK){
    6474           0 :             newFloatData.set(0);
    6475             :           }
    6476      436522 :           if(LAG_DATAColIsOK){
    6477           0 :             newLagData.set(0);
    6478             :           }
    6479      436522 :           if(MODEL_DATAColIsOK){
    6480        7842 :             newModelData.set(0);
    6481             :           }
    6482      436522 :           if(SIGMA_SPECTRUMColIsOK){
    6483       58740 :             newSigmaSpectrum.set(0);
    6484             :           }
    6485      436522 :           if(WEIGHT_SPECTRUMColIsOK){
    6486      414489 :             newWeightSpectrum.set(0);
    6487             :           }
    6488      436522 :           if(FLAGColIsOK){
    6489      436522 :             newFlag.set(0);
    6490             :           }
    6491      436522 :           if(FLAG_CATEGORYColIsOK){
    6492           0 :             newFlagCategory.set(0);
    6493             :           }
    6494             : 
    6495      436522 :           vector<Matrix<Complex> > newCorrectedDataI(nSpwsToCombine); 
    6496      436522 :           vector<Matrix<Complex> > newDataI(nSpwsToCombine);
    6497      436522 :           vector<Matrix<Float> > newFloatDataI(nSpwsToCombine);
    6498      436522 :           vector<Matrix<Complex> > newLagDataI(nSpwsToCombine);
    6499      436522 :           vector<Matrix<Complex> > newModelDataI(nSpwsToCombine);
    6500      436522 :           vector<Matrix<Float> > newSigmaSpectrumI(nSpwsToCombine);
    6501      436522 :           vector<Matrix<Float> > newWeightSpectrumI(nSpwsToCombine);
    6502      436522 :           vector<Matrix<Bool> > newFlagI(nSpwsToCombine);
    6503      436522 :           vector<Array<Bool> > newFlagCategoryI(nSpwsToCombine); // has three dimensions
    6504      436522 :           vector<Bool> newFlagRowI(nSpwsToCombine);
    6505             : 
    6506     1376886 :           for(uInt i=0; i<nSpwsToCombine; i++){
    6507      940364 :             Int theRowSPWId = spwsToCombine[i];
    6508      940364 :         if(SPWtoRowIndex.find(theRowSPWId) != SPWtoRowIndex.end( )){ // there actually is a matching row for this SPW
    6509      923440 :               Int theRow = SPWtoRowIndex[theRowSPWId];
    6510      923440 :               if(CORRECTED_DATAColIsOK){
    6511       73764 :                 newCorrectedDataI[theRowSPWId].reference(oldCORRECTED_DATACol(theRow));
    6512             :               }
    6513      923440 :               if(DATAColIsOK){
    6514      923440 :                 newDataI[theRowSPWId].reference(oldDATACol(theRow));
    6515             :               }
    6516      923440 :               if(FLOAT_DATAColIsOK){
    6517           0 :                 newFloatDataI[theRowSPWId].reference(oldFLOAT_DATACol(theRow));
    6518             :               }
    6519      923440 :               if(LAG_DATAColIsOK){
    6520           0 :                 newLagDataI[theRowSPWId].reference(oldLAG_DATACol(theRow));
    6521             :               }
    6522      923440 :               if(MODEL_DATAColIsOK){
    6523       73764 :                 newModelDataI[theRowSPWId].reference(oldMODEL_DATACol(theRow));
    6524             :               }
    6525      923440 :               if(SIGMA_SPECTRUMColIsOK){
    6526      117480 :                 newSigmaSpectrumI[theRowSPWId].reference(oldSIGMA_SPECTRUMCol(theRow));
    6527             :               }
    6528      923440 :               if(WEIGHT_SPECTRUMColIsOK){
    6529      896298 :                 newWeightSpectrumI[theRowSPWId].reference(oldWEIGHT_SPECTRUMCol(theRow));
    6530             :               }
    6531      923440 :               if(FLAGColIsOK){
    6532      923440 :                 newFlagI[theRowSPWId].reference(oldFLAGCol(theRow));
    6533             :               }
    6534      923440 :               if(FLAG_CATEGORYColIsOK){
    6535           0 :                 newFlagCategoryI[theRowSPWId].reference(oldFLAG_CATEGORYCol(theRow));
    6536             :               }
    6537      923440 :               newFlagRowI[theRowSPWId] = flagRowCol(theRow);
    6538             :             } // end if
    6539             :           } // end for i
    6540             :           
    6541             :           // merge data columns from all rows found using the averaging info from above
    6542             :           // averageN[], averageWhichSPW[], averageWhichChan[], averageChanFrac[]
    6543             : 
    6544      436522 :           Bool failedAv = false;          
    6545      436522 :           vector<Int> failedAvChans;
    6546      436522 :           vector<Int> failedAvCorrs;
    6547             : 
    6548             :           // loop over new channels
    6549    13804860 :           for(uInt i=0; i<newNUM_CHAN; i++){
    6550             :             // initialise special treatment for Bool columns
    6551    13368338 :             if(FLAGColIsOK){
    6552    33866562 :               for(uInt k=0; k<nCorrelations; k++){ 
    6553    20498224 :                 newFlag(k,i) =  true; // overwritten with false below if there is a SPW where this channel is not flagged for this correlator
    6554             :               }
    6555             :             }
    6556    13368338 :             if(FLAG_CATEGORYColIsOK){
    6557           0 :               for(uInt k=0; k<nCorrelations; k++){ 
    6558           0 :                 for(uInt m=0; m<nCat; m++){ 
    6559           0 :                   newFlagCategory(IPosition(3,k,i,m)) = false;
    6560             :                 }
    6561             :               }
    6562             :             }
    6563             : 
    6564    13368338 :             Bool haveCoverage = false;
    6565    13368338 :             Vector<Double> modNorm(nCorrelations, 0.); // normalization for the averaging of the contributions from the SPWs
    6566    26736676 :             vector<vector<Double> > modAverageChanFrac(averageN[i], vector<Double>(nCorrelations, 0.));
    6567    33866562 :             for(uInt k=0; k<nCorrelations; k++){
    6568    20498224 :               Vector<Int> spwCount(nSpwsToCombine, 0);
    6569    62076578 :               for(Int j=0; j<averageN[i]; j++){
    6570    41578354 :         if(SPWtoRowIndex.find(averageWhichSPW[i][j]) != SPWtoRowIndex.end( )){
    6571    28667844 :                   if(!newFlagI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] )){
    6572    25392748 :                     haveCoverage = true;
    6573    25392748 :                     if(FLAGColIsOK){
    6574    25392748 :                       newFlag(k,i) = false; // there is valid data for this channel and correlation => don't flag in output
    6575             :                     }
    6576    25392748 :                     modAverageChanFrac[j][k] = averageChanFrac[i][j];
    6577    25392748 :                     modNorm(k) += averageChanFrac[i][j];
    6578    25392748 :                     if(modAverageChanFrac[j][k]!=1.){
    6579    10968660 :                       ++spwCount(averageWhichSPW[i][j]); // count the contributions with non-unity overlap fraction for each spw
    6580             :                     }
    6581             :                   }
    6582             :                 }
    6583             :               }
    6584    20498224 :               if(modNorm(k)>0.){ // there are contributions
    6585    58688123 :                 for(Int j=0; j<averageN[i]; j++){
    6586             :                   // Second iteration: eliminate contributions from spws with odd numbers of contribs with non-unity overlap fraction
    6587             :                   // which could influence the averaging asymmetrically
    6588    39612642 :           if(SPWtoRowIndex.find(averageWhichSPW[i][j]) != SPWtoRowIndex.end( )
    6589    26837953 :                      && spwCount(averageWhichSPW[i][j])<averageN[i] // there are also channels with full overlap 
    6590    26837953 :                      && spwCount(averageWhichSPW[i][j])%2!=0     // the number of channels with non-unity overlap is odd
    6591    66450595 :                      && modAverageChanFrac[j][k]!=1.){           // this contributor j has non-unity overlap
    6592             :                     //cout << "spw count " << averageWhichSPW[i][j] << " " << spwCount(averageWhichSPW[i][j]) << endl;
    6593             :                     //cout << "not using i j k spw frac " << i << " " << j << " " << k << " " 
    6594             :                     //     << averageWhichSPW[i][j] << " " << modAverageChanFrac[j][k] << endl;
    6595      222193 :                     modNorm(k) -= modAverageChanFrac[j][k];
    6596      222193 :                     modAverageChanFrac[j][k] = 0.;
    6597      222193 :                     if(modNorm(k)<=0.){ // should only occur in rare cases
    6598       16935 :                       if(FLAGColIsOK && !newFlag(k,i)){
    6599       16935 :                         failedAv = true;
    6600       16935 :                         newFlag(k,i) = true;
    6601       16935 :                         if(prevNewMainTabRow<0){
    6602          14 :                           prevNewMainTabRow = newMainTabRow;
    6603             :                         }
    6604       16935 :                         failedAvChans.push_back(i);
    6605       16935 :                         failedAvCorrs.push_back(k);
    6606             :                       }
    6607       16935 :                       modNorm(k) += averageChanFrac[i][j];
    6608       16935 :                       modAverageChanFrac[j][k] = averageChanFrac[i][j];
    6609       16935 :                       break;
    6610             :                     }
    6611             :                   }             
    6612             :                 }
    6613             :               }
    6614    20498224 :             } // end loop over correlations
    6615             : 
    6616    13368338 :             if(haveCoverage){ // there is unflagged data for this channel
    6617             :               // loop over SPWs
    6618    36021074 :               for(Int j=0; j<averageN[i]; j++){
    6619             :                 // new channel value i 
    6620             :                 //   = SUM{j=0 to averageN[i]}( channelValue(SPW = averageWhichSPW[i][j], CHANNEL = averageWhichChan[i][j]) * averageChanFrac[i][j])
    6621    23973034 :         if(SPWtoRowIndex.find(averageWhichSPW[i][j]) != SPWtoRowIndex.end( )){
    6622             : 
    6623    17585645 :                   Double weight = 0.;
    6624             : 
    6625             :                   // loop over first dimension (number of correlations)
    6626    44433190 :                   for(uInt k=0; k<nCorrelations; k++){
    6627    26847545 :                     if(!newFlagI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] )
    6628    26847545 :                        && modNorm(k)>0.){ // this channel is not flagged for the given SPW and correlator and there are contributions
    6629             : 
    6630             :                       // renormalize for the case of missing SPW coverage
    6631    25392748 :                       weight = modAverageChanFrac[j][k] / modNorm(k);
    6632             : 
    6633    25392748 :                       if(CORRECTED_DATAColIsOK){
    6634     7351892 :                         newCorrectedData(k,i) += newCorrectedDataI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) * weight;                      
    6635             :                       }
    6636    25392748 :                       if(DATAColIsOK){
    6637    25392748 :                         newData(k,i) += newDataI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) * weight;
    6638             : //                      if (!wasprinted[i][j]){
    6639             : //                        cout << "row " << SPWtoRowIndex(averageWhichSPW[i][j]) << "averageWhichSPW[i][j] " 
    6640             : //                             << averageWhichSPW[i][j] << "  averageWhichChan[i][j] " << averageWhichChan[i][j]
    6641             : //                             << " i, j, k " << i << ", " << j << ", " << k << " modAverageChanFrac[j][k] " << modAverageChanFrac[j][k] 
    6642             : //                             << " modNorm(k) " << modNorm(k) << " newDataI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) "
    6643             : //                             << newDataI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) 
    6644             : //                             << " newData(k,i) " << newData(k,i) 
    6645             : //                             << " weight " << weight << endl;
    6646             : //                        wasprinted[i][j] = true;
    6647             : //                      } 
    6648             :                       }
    6649    25392748 :                       if(FLOAT_DATAColIsOK){
    6650           0 :                         newFloatData(k,i) += newFloatDataI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) * weight;
    6651             :                       }
    6652    25392748 :                       if(LAG_DATAColIsOK){
    6653           0 :                         newLagData(k,i) += newLagDataI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) * weight;
    6654             :                       }
    6655    25392748 :                       if(MODEL_DATAColIsOK){
    6656     7351892 :                         newModelData(k,i) += newModelDataI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) * weight;
    6657             :                       }
    6658    25392748 :                       if(SIGMA_SPECTRUMColIsOK){
    6659      469920 :                         newSigmaSpectrum(k,i) += newSigmaSpectrumI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) * weight;
    6660             :                       }
    6661    25392748 :                       if(WEIGHT_SPECTRUMColIsOK){
    6662    11893360 :                         newWeightSpectrum(k,i) += newWeightSpectrumI[ averageWhichSPW[i][j] ]( k, averageWhichChan[i][j] ) * weight;
    6663             :                       }
    6664             : 
    6665             :                     } // end if flagged
    6666             :                   } // end for k = 0
    6667             :                 
    6668             :                   // special treatment for flag cat
    6669    17585645 :                   if(FLAG_CATEGORYColIsOK){
    6670           0 :                     for(uInt k=0; k<nCorrelations; k++){ // logical OR of all input spws
    6671           0 :                       for(uInt m=0; m<nCat; m++){ 
    6672           0 :                         newFlagCategory(IPosition(3,k,i,m)) = 
    6673           0 :                           newFlagCategory(IPosition(3,k,i,m)) || newFlagCategoryI[ averageWhichSPW[i][j] ](IPosition(3,k,averageWhichChan[i][j],m));
    6674             :                       }
    6675             :                     }
    6676             :                   }
    6677             : 
    6678             :                 } // end if there is a row for this SPW       
    6679             :               } // end for j=0, loop over SPWs
    6680             :             } // if there is coverage for this channel 
    6681    13368338 :           } // end for i=0, loop over new channels
    6682             : 
    6683             :           // give warnings about channels with averaging problems
    6684      436522 :           if(prevNewMainTabRow>=0){ // may need to issue warnings
    6685       16974 :             if(!failedAv 
    6686        8473 :                || mainTabRowI==nMainTabRows-1
    6687       16960 :                || (prevFailedAvChans.size()>0 && !((failedAvChans==prevFailedAvChans) && (failedAvCorrs==prevFailedAvCorrs)))
    6688             :                ){
    6689          14 :               uInt lastRow = newMainTabRow-1;
    6690          14 :               if(mainTabRowI==nMainTabRows-1){
    6691           0 :                 lastRow = newMainTabRow;
    6692             :               }
    6693             :               os << LogIO::WARN << "Averaging failed for the following channel/correllation pairs from output row " 
    6694          14 :                  << prevNewMainTabRow << " up to " << lastRow << ". Corresponding visibilities will be flagged: " << endl;
    6695          31 :               for(uInt iii=0; iii<prevFailedAvChans.size(); iii++){
    6696          17 :                 os << "(" << prevFailedAvChans[iii] << ", " << prevFailedAvCorrs[iii] << ") ";
    6697             :               }
    6698          14 :               os << LogIO::POST;
    6699          14 :               prevNewMainTabRow = -1;
    6700             :             }
    6701        8487 :             prevFailedAvChans = failedAvChans;
    6702        8487 :             prevFailedAvCorrs = failedAvCorrs;
    6703             :           }     
    6704             :             
    6705             :           // calculate FLAG_ROW as logical OR of all input rows
    6706      436522 :           newFlagRow = newFlagRowI[0];
    6707      923440 :           for(uInt i=1; i<nMatchingRows; i++){
    6708      486918 :             newFlagRow = newFlagRow || newFlagRowI[i];
    6709             :           }
    6710             : 
    6711             :           // write data into the new main table
    6712      436522 :           newMain.addRow(1,false);
    6713             : 
    6714             :           //      cout << "writing new row " << newMainTabRow << endl;
    6715             :           
    6716      436522 :           if(CORRECTED_DATAColIsOK){
    6717        7842 :             CORRECTED_DATACol.put(newMainTabRow, newCorrectedData);
    6718             :           }
    6719      436522 :           if(DATAColIsOK){
    6720             : //          cout << "old " << oldDATACol(mainTabRow).shape() << endl;
    6721             : //          cout << "new " << newData.shape() << endl;
    6722      436522 :             DATACol.put(newMainTabRow, newData);
    6723             :           }
    6724      436522 :           if(FLOAT_DATAColIsOK){
    6725           0 :             FLOAT_DATACol.put(newMainTabRow, newFloatData);
    6726             :           }
    6727      436522 :           if(LAG_DATAColIsOK){
    6728           0 :             LAG_DATACol.put(newMainTabRow, newLagData);
    6729             :           }
    6730      436522 :           if(MODEL_DATAColIsOK){
    6731        7842 :             MODEL_DATACol.put(newMainTabRow, newModelData);
    6732             :           }
    6733      436522 :           if(SIGMA_SPECTRUMColIsOK){
    6734       58740 :             SIGMA_SPECTRUMCol.put(newMainTabRow, newSigmaSpectrum);
    6735             :           }
    6736      436522 :           if(WEIGHT_SPECTRUMColIsOK){
    6737      414489 :             WEIGHT_SPECTRUMCol.put(newMainTabRow, newWeightSpectrum);
    6738             :           }
    6739      436522 :           if(FLAGColIsOK){
    6740      436522 :             FLAGCol.put(newMainTabRow, newFlag);
    6741             :           }
    6742      436522 :           if(FLAG_CATEGORYColIsOK){
    6743           0 :             FLAG_CATEGORYCol.put(newMainTabRow, newFlagCategory);
    6744             :           }
    6745             : 
    6746      436522 :           mainCols.flagRow().put(newMainTabRow, newFlagRow);
    6747             :           
    6748      436522 :       if(tempDDIndex.find(theDataDescId) != tempDDIndex.end( )){
    6749             :             // do DD ID renumbering (due to shrunk DD table and spw combination )
    6750      436522 :             mainCols.dataDescId().put(newMainTabRow, tempDDIndex.at(theDataDescId)); 
    6751             :           }
    6752             :           else{
    6753           0 :             mainCols.dataDescId().put(newMainTabRow,  DDIdCol(mainTabRow)); 
    6754             :           }       
    6755             :           // copy the rest of the row contents from mainTabRow
    6756      436522 :           mainCols.sigma().put(newMainTabRow, SIGMACol(mainTabRow));
    6757      436522 :           mainCols.weight().put(newMainTabRow, oldMainCols.weight()(mainTabRow));
    6758             : 
    6759      436522 :           mainCols.fieldId().put(newMainTabRow, fieldCol(mainTabRow));
    6760      436522 :           mainCols.antenna1().put(newMainTabRow, antenna1Col(mainTabRow));
    6761      436522 :           mainCols.antenna2().put(newMainTabRow, antenna2Col(mainTabRow));
    6762      436522 :           mainCols.time().put(newMainTabRow, timeCol(mainTabRow));
    6763      436522 :           mainCols.exposure().put(newMainTabRow, exposureCol(mainTabRow));
    6764      436522 :           mainCols.interval().put(newMainTabRow, intervalCol(mainTabRow));
    6765             : 
    6766      436522 :           mainCols.uvw().put(newMainTabRow, oldMainCols.uvw()(mainTabRow));
    6767      436522 :           mainCols.arrayId().put(newMainTabRow, oldMainCols.arrayId()(mainTabRow));
    6768      436522 :           mainCols.feed1().put(newMainTabRow, oldMainCols.feed1()(mainTabRow));
    6769      436522 :           mainCols.feed2().put(newMainTabRow, oldMainCols.feed2()(mainTabRow));
    6770      436522 :           mainCols.observationId().put(newMainTabRow, oldMainCols.observationId()(mainTabRow));
    6771      436522 :           mainCols.processorId().put(newMainTabRow, oldMainCols.processorId()(mainTabRow));
    6772      436522 :           mainCols.scanNumber().put(newMainTabRow, oldMainCols.scanNumber()(mainTabRow));
    6773      436522 :           mainCols.stateId().put(newMainTabRow, oldMainCols.stateId()(mainTabRow));
    6774      436522 :           mainCols.timeCentroid().put(newMainTabRow, oldMainCols.timeCentroid()(mainTabRow));
    6775             : 
    6776             :           //      cout << "Wrote new row " << newMainTabRow << endl;
    6777      436522 :           newMainTabRow++;        
    6778             :           // mark other found rows to be ignored, i.e. set their time to zero
    6779      923440 :           for(uInt i=1; i<nMatchingRows; i++){ // don't mark the first
    6780             :             //      cout << "setting time to zero in row " << matchingRows[i] << endl;
    6781      486918 :             timeCol.put(matchingRows[i], 0);
    6782             :           }
    6783             :           
    6784      436522 :         } // end if row is affected
    6785             :         
    6786      436522 :         mainTabRowI++;
    6787      436522 :         if(mainTabRowI>nMainTabRows*progress){
    6788         130 :           cout << "combineSpws progress: " << progress*100 << "% processed ... " << endl;
    6789         130 :           progress += progressStep;
    6790             :         }
    6791             :       
    6792             :       } // end loop over main table rows
    6793          30 :       cout << "combineSpws progress: 100% processed." << endl;
    6794             :       ////////////////////////////////////////////
    6795             : 
    6796          30 :       if(verbose){
    6797             :         os << LogIO::NORMAL << "Processed " << mainTabRowI << " original rows, wrote "
    6798          30 :            << newMainTabRow << " new ones." << LogIO::POST;
    6799             : 
    6800          30 :         if(nIncompleteCoverage>0){
    6801             :           os << LogIO::WARN << "Incomplete coverage of combined SPW in " << nIncompleteCoverage
    6802           2 :              << " of " <<  newMainTabRow << " output rows." <<  LogIO::POST;
    6803             :         }
    6804             :       }
    6805             : 
    6806        3142 :     } // end scope for MS related objects
    6807             :  
    6808          30 :     String oldName(ms_p.tableName());
    6809             : 
    6810             :     // detach old MS
    6811          30 :     ms_p = MeasurementSet();
    6812          30 :     mssel_p = MeasurementSet();
    6813             : 
    6814             :     // rename the result MS overwriting the old MS
    6815             :     {
    6816          30 :       Table tab(tempNewName, Table::Update);
    6817          30 :       tab.rename(oldName, Table::New);
    6818          30 :     }
    6819             : 
    6820             :     // attach new MS
    6821          30 :     ms_p = MeasurementSet(oldName, Table::Update);
    6822          30 :     mssel_p = ms_p;
    6823             : 
    6824          30 :     if(verbose){
    6825          30 :       os << LogIO::NORMAL << "Spectral window combination complete." << LogIO::POST;
    6826             :     }
    6827             : 
    6828          30 :     return true;
    6829             : 
    6830         206 :   }
    6831             : 
    6832         250 :   const Vector<MS::PredefinedColumns>& SubMS::parseColumnNames(String col)
    6833             :   {
    6834             :     // Memoize both for efficiency and so that the info message at the bottom
    6835             :     // isn't unnecessarily repeated.
    6836         250 :     static String my_colNameStr = "";
    6837         250 :     static Vector<MS::PredefinedColumns> my_colNameVect;
    6838             : 
    6839         250 :     col.upcase();
    6840         250 :     if(col == my_colNameStr && col != ""){
    6841         249 :       return my_colNameVect;
    6842             :     }    
    6843           1 :     else if(col == "None"){
    6844           0 :       my_colNameStr = "";
    6845           0 :       my_colNameVect.resize(0);
    6846           0 :       return my_colNameVect;
    6847             :     }
    6848             :  
    6849           2 :     LogIO os(LogOrigin("SubMS", "parseColumnNames()"));
    6850             :     
    6851             :     uInt nNames;
    6852             :     
    6853           1 :     if(col.contains("ALL")){
    6854           0 :       nNames = 3;
    6855           0 :       my_colNameVect.resize(nNames);
    6856           0 :       my_colNameVect[0] = MS::DATA;
    6857           0 :       my_colNameVect[1] = MS::MODEL_DATA;
    6858           0 :       my_colNameVect[2] = MS::CORRECTED_DATA;
    6859             :     }
    6860             :     else{
    6861           1 :       nNames = dataColStrToEnums(col, my_colNameVect);
    6862             :     }
    6863             : 
    6864             :     // Whether or not the MS has the columns is checked by verifyColumns().
    6865             :     // Unfortunately it cannot be done here because this is a static method.
    6866             : 
    6867           1 :     if(col != "NONE"){  // "NONE" is used by ~SubMS().
    6868             :       os << LogIO::NORMAL
    6869           0 :          << "Using ";     // Don't say "Splitting"; this is used elsewhere.
    6870           0 :       for(uInt i = 0; i < nNames; ++i)
    6871           0 :         os << MS::columnName(my_colNameVect[i]) << " ";
    6872           0 :       os << " column" << (my_colNameVect.nelements() > 1 ? "s." : ".")
    6873           0 :          << LogIO::POST;
    6874             :     }
    6875             :     
    6876           1 :     my_colNameStr = col;
    6877           1 :     return my_colNameVect;
    6878           1 :   }
    6879             : 
    6880             : // This version uses the MeasurementSet to check what columns are present,
    6881             : // i.e. it makes col=="all" smarter, and it is not necessary to call
    6882             : // verifyColumns() after calling this.  Unlike the other version, it knows
    6883             : // about FLOAT_DATA and LAG_DATA.  It throws an exception if a
    6884             : // _specifically_ requested column is absent.
    6885          76 : const Vector<MS::PredefinedColumns>& SubMS::parseColumnNames(String col,
    6886             :                                                   const MeasurementSet& msref)
    6887             : {
    6888             :   // Memorize both for efficiency and so that the info message at the bottom
    6889             :   // isn't unnecessarily repeated.
    6890          76 :   static String my_colNameStr = "";
    6891          76 :   static Vector<MS::PredefinedColumns> my_colNameVect;
    6892             : 
    6893          76 :   Vector<MS::PredefinedColumns> wanted;       // Data columns to pick up if present.
    6894             :   
    6895          76 :   col.upcase();
    6896             : // This version of parseColumnNames does not reuse results of previous calls
    6897             : // but always checks the given columns because it cannot be certain that msref
    6898             : // refers to the same MS with every call.
    6899             : 
    6900          76 :   if(col == "None"){
    6901           0 :     my_colNameStr = "";
    6902           0 :     my_colNameVect.resize(0);
    6903           0 :     return my_colNameVect;
    6904             :   }
    6905             :  
    6906         152 :   LogIO os(LogOrigin("SubMS", "parseColumnNames()"));
    6907             :     
    6908             :   // Are we choosy?
    6909          76 :   const Bool doAny = col.contains("ALL") || col.contains("ANY");
    6910             :   
    6911             :   uInt nPoss;
    6912          76 :   if(doAny){
    6913          40 :     nPoss = 5;
    6914          40 :     wanted.resize(nPoss);
    6915          40 :     wanted[0] = MS::DATA;
    6916          40 :     wanted[1] = MS::MODEL_DATA;
    6917          40 :     wanted[2] = MS::CORRECTED_DATA;
    6918          40 :     wanted[3] = MS::FLOAT_DATA;
    6919          40 :     wanted[4] = MS::LAG_DATA;
    6920             :   }
    6921             :   else{ // split name string into individual names
    6922          36 :     nPoss = dataColStrToEnums(col, wanted);
    6923             :   } 
    6924             : 
    6925          76 :   uInt nFound = 0;
    6926          76 :   my_colNameVect.resize(0);
    6927         313 :   for(uInt i = 0; i < nPoss; ++i){
    6928         237 :     if(msref.tableDesc().isColumn(MS::columnName(wanted[i]))){
    6929         122 :       ++nFound;
    6930         122 :       my_colNameVect.resize(nFound, true);
    6931         122 :       my_colNameVect[nFound - 1] = wanted[i];
    6932             :     }
    6933         115 :     else if(!doAny){
    6934           0 :       ostringstream ostr;
    6935           0 :       ostr << "Desired column (" << MS::columnName(wanted[i])
    6936           0 :            << ") not found in the input MS (" << msref.tableName() << ").";
    6937           0 :       throw(AipsError(ostr.str()));
    6938           0 :     }
    6939             :   }
    6940          76 :   if(nFound == 0)
    6941           0 :     throw(AipsError("Did not find and select any data columns."));
    6942             :   
    6943             :   os << LogIO::NORMAL
    6944          76 :      << "Using ";     // Don't say "Splitting"; this is used elsewhere.
    6945         198 :   for(uInt i = 0; i < nFound; ++i)
    6946         122 :     os << MS::columnName(my_colNameVect[i]) << " ";
    6947          76 :   os << "column" << (nFound > 1 ? "s." : ".") << LogIO::POST;
    6948             :     
    6949          76 :   my_colNameStr = col;
    6950          76 :   return my_colNameVect;
    6951          76 : }
    6952             : 
    6953          37 : uInt SubMS::dataColStrToEnums(const String& col, Vector<MS::PredefinedColumns>& colvec)
    6954             : {
    6955          74 :   LogIO os(LogOrigin("SubMS", "dataColStrToEnums()"));
    6956          37 :   String tmpNames(col);
    6957          37 :   Vector<String> tokens;
    6958          37 :   tmpNames.upcase();
    6959             :     
    6960             :   // split name string into individual names
    6961             :   char * pch;
    6962          37 :   Int i = 0;
    6963          37 :   pch = strtok((char*)tmpNames.c_str(), " ,");
    6964          75 :   while (pch != NULL){
    6965          38 :     tokens.resize(i + 1, true);
    6966          38 :     tokens[i] = String(pch);
    6967          38 :     ++i;
    6968          38 :     pch = strtok(NULL, " ,");
    6969             :   }
    6970             : 
    6971          37 :   uInt nNames = tokens.nelements();
    6972             : 
    6973          37 :   uInt nFound = 0;
    6974          75 :   for(uInt i = 0; i < nNames; ++i){
    6975          38 :     colvec.resize(nFound + 1, true);
    6976          38 :     colvec[nFound] = MS::UNDEFINED_COLUMN;
    6977             :             
    6978          76 :     if (tokens[i] == "OBSERVED" || 
    6979          76 :         tokens[i] == "DATA" || 
    6980          13 :         tokens[i] == MS::columnName(MS::DATA)){
    6981          25 :       colvec[nFound++] = MS::DATA;
    6982             :     }
    6983          26 :     else if(tokens[i] == "FLOAT" || 
    6984          26 :             tokens[i] == "FLOAT_DATA" || 
    6985          13 :             tokens[i] == MS::columnName(MS::FLOAT_DATA)){
    6986           0 :       colvec[nFound++] = MS::FLOAT_DATA;
    6987             :     } 
    6988          26 :     else if(tokens[i] == "LAG" || 
    6989          26 :             tokens[i] == "LAG_DATA" || 
    6990          13 :             tokens[i] == MS::columnName(MS::LAG_DATA)){
    6991           0 :       colvec[nFound++] = MS::LAG_DATA;
    6992             :     } 
    6993          26 :     else if(tokens[i] == "MODEL" || 
    6994          26 :             tokens[i] == "MODEL_DATA" || 
    6995           9 :             tokens[i] == MS::columnName(MS::MODEL_DATA)){
    6996           4 :       colvec[nFound++] = MS::MODEL_DATA;
    6997             :     } 
    6998          10 :     else if(tokens[i] == "CORRECTED" || 
    6999          10 :             tokens[i] == "CORRECTED_DATA" || 
    7000           1 :             tokens[i] == MS::columnName(MS::CORRECTED_DATA)){
    7001           8 :       colvec[nFound++] = MS::CORRECTED_DATA;
    7002             :     }
    7003           1 :     else if(tmpNames != "NONE"){  // "NONE" is used by ~SubMS().
    7004           0 :       os << LogIO::SEVERE;
    7005           0 :       if(nFound == 0){
    7006           0 :         colvec[0] = MS::DATA;
    7007           0 :         os << "Unrecognized data column " << tokens[i] << "...trying DATA.";
    7008             :       }
    7009             :       else
    7010           0 :         os << "Skipping unrecognized data column " << tokens[i];
    7011           0 :       os << LogIO::POST;
    7012             :     }
    7013             :   }
    7014          37 :   return nFound;
    7015          37 : }
    7016             : 
    7017             : 
    7018          44 : Bool SubMS::fillAccessoryMainCols(){
    7019          88 :   LogIO os(LogOrigin("SubMS", "fillAccessoryMainCols()"));
    7020          44 :   uInt nrows = mssel_p.nrow();
    7021             : 
    7022          44 :   msOut_p.addRow(nrows, true);
    7023             :   
    7024             :   //#ifdef COPYTIMER
    7025          44 :   Timer timer;
    7026          44 :   timer.mark();
    7027             :   //#endif
    7028          44 :   if(!antennaSel_p){
    7029          44 :     msc_p->antenna1().putColumn(mscIn_p->antenna1().getColumn());
    7030          44 :     msc_p->antenna2().putColumn(mscIn_p->antenna2().getColumn());
    7031             :     os << LogIO::DEBUG1
    7032             :        << "Straight copying ANTENNA* took " << timer.real() << "s."
    7033          44 :        << LogIO::POST;
    7034             :   }
    7035             :   else{
    7036           0 :     Vector<Int> ant1(mscIn_p->antenna1().getColumn());
    7037           0 :     Vector<Int> ant2(mscIn_p->antenna2().getColumn());
    7038             :     
    7039           0 :     for(uInt k = 0; k < nrows; ++k){
    7040           0 :       ant1[k] = antNewIndex_p[ant1[k]];
    7041           0 :       ant2[k] = antNewIndex_p[ant2[k]];
    7042             :     }
    7043           0 :     msc_p->antenna1().putColumn(ant1);
    7044           0 :     msc_p->antenna2().putColumn(ant2);
    7045             :     os << LogIO::DEBUG1
    7046             :        << "Selectively copying ANTENNA* took " << timer.real() << "s."
    7047           0 :        << LogIO::POST;
    7048           0 :   }
    7049             :   
    7050          44 :   timer.mark();
    7051          44 :   msc_p->feed1().putColumn(mscIn_p->feed1().getColumn());
    7052          44 :   msc_p->feed2().putColumn(mscIn_p->feed2().getColumn());
    7053             :   os << LogIO::DEBUG1
    7054             :      << "Copying FEED* took " << timer.real() << "s."
    7055          44 :      << LogIO::POST;
    7056             :   
    7057          44 :   timer.mark();
    7058          44 :   msc_p->exposure().putColumn(mscIn_p->exposure().getColumn());
    7059             :   os << LogIO::DEBUG1
    7060             :      << "Copying EXPOSURE took " << timer.real() << "s."
    7061          44 :      << LogIO::POST;
    7062             : 
    7063          44 :   timer.mark();
    7064          44 :   msc_p->flagRow().putColumn(mscIn_p->flagRow().getColumn());
    7065             :   os << LogIO::DEBUG1
    7066             :      << "Copying flagRow took " << timer.real() << "s."
    7067          44 :      << LogIO::POST;
    7068             : 
    7069          44 :   timer.mark();
    7070          44 :   msc_p->interval().putColumn(mscIn_p->interval().getColumn());
    7071             :   os << LogIO::DEBUG1
    7072             :      << "Copying INTERVAL took " << timer.real() << "s."
    7073          44 :      << LogIO::POST;
    7074             : 
    7075          44 :   timer.mark();
    7076          44 :   msc_p->scanNumber().putColumn(mscIn_p->scanNumber().getColumn());
    7077             :   os << LogIO::DEBUG1
    7078             :      << "Copying scanNumber took " << timer.real() << "s."
    7079          44 :      << LogIO::POST;
    7080             : 
    7081          44 :   timer.mark();
    7082          44 :   msc_p->time().putColumn(mscIn_p->time().getColumn());
    7083             :   os << LogIO::DEBUG1
    7084             :      << "Copying TIME took " << timer.real() << "s."
    7085          44 :      << LogIO::POST;
    7086             : 
    7087          44 :   timer.mark();
    7088          44 :   msc_p->timeCentroid().putColumn(mscIn_p->timeCentroid().getColumn());
    7089             :   os << LogIO::DEBUG1
    7090             :      << "Copying timeCentroid took " << timer.real() << "s."
    7091          44 :      << LogIO::POST;
    7092             :   
    7093             :   // ScalarMeasColumn doesn't have a putColumn() for some reason.
    7094             :   //msc_p->uvwMeas().putColumn(mscIn_p->uvwMeas());
    7095          44 :   timer.mark();
    7096             :   //msc_p->uvw().putColumn(mscIn_p->uvw());      // 98s for 4.7e6 rows
    7097             : 
    7098             :   // 3.06s for 4.7e6 rows
    7099             :   //RefRows refrows(0,  nrows - 1);
    7100             :   //msc_p->uvw().putColumnCells(refrows, mscIn_p->uvw().getColumn());
    7101             : 
    7102          44 :   msc_p->uvw().putColumn(mscIn_p->uvw().getColumn());   // 2.74s for 4.7e6 rows
    7103             :   os << LogIO::DEBUG1
    7104             :      << "Copying uvw took " << timer.real() << "s."
    7105          44 :      << LogIO::POST;
    7106             :   
    7107          44 :   msc_p->arrayId().putColumn(mscIn_p->arrayId().getColumn());
    7108          44 :   msc_p->processorId().putColumn(mscIn_p->processorId().getColumn());
    7109             : 
    7110          44 :   timer.mark();
    7111          44 :   relabelIDs();
    7112             :   os << LogIO::DEBUG1
    7113             :      << "relabelIDs took " << timer.real() << "s."
    7114          44 :      << LogIO::POST;
    7115             : 
    7116          44 :   return true;
    7117          44 : }
    7118             : 
    7119          44 :   Bool SubMS::writeAllMainRows(const Vector<MS::PredefinedColumns>& colNames)
    7120             :   {  
    7121          88 :     LogIO os(LogOrigin("SubMS", "writeAllMainRows()"));
    7122          44 :     Bool success = true;
    7123          44 :     Timer timer;
    7124             : 
    7125          44 :     fillAccessoryMainCols();
    7126             : 
    7127             :     //Deal with data, flags, sigma, and weights.
    7128          44 :     timer.mark();
    7129          44 :     if(keepShape_p){
    7130          41 :       Vector<MS::PredefinedColumns> complexCols;
    7131          41 :       const Bool doFloat = sepFloat(colNames, complexCols);
    7132          41 :       const uInt nDataCols = complexCols.nelements();
    7133          41 :       const Bool writeToDataCol = mustConvertToData(nDataCols, complexCols);
    7134             : 
    7135          41 :       copyDataFlagsWtSp(complexCols, writeToDataCol);
    7136          41 :       if(doFloat)
    7137           0 :         msc_p->floatData().putColumn(mscIn_p->floatData());
    7138          41 :     }
    7139             :     else{
    7140           3 :       doChannelMods(colNames);
    7141             :     }
    7142             :     os << LogIO::DEBUG1
    7143             :        << "Total data read/write time = " << timer.real()
    7144          44 :        << LogIO::POST;
    7145             :     
    7146          44 :     return success;
    7147          44 :   }
    7148             :   
    7149          44 : Bool SubMS::existsFlagCategory() const
    7150             : {
    7151          44 :   Bool hasFC = false;
    7152          88 :   if(!mscIn_p->flagCategory().isNull() &&
    7153          44 :      mscIn_p->flagCategory().isDefined(0)){
    7154           0 :     IPosition fcshape(mscIn_p->flagCategory().shape(0));
    7155           0 :     IPosition fshape(mscIn_p->flag().shape(0));
    7156             : 
    7157             :     // I don't know or care how many flag categories there are.
    7158           0 :     hasFC = fcshape(0) == fshape(0) && fcshape(1) == fshape(1);
    7159           0 :   }
    7160          44 :   return hasFC;
    7161             : }
    7162             : 
    7163           0 :   Bool SubMS::getDataColumn(ArrayColumn<Complex>& data,
    7164             :                             const MS::PredefinedColumns colName)
    7165             :   {
    7166           0 :     if(colName == MS::DATA)
    7167           0 :       data.reference(mscIn_p->data());
    7168           0 :     else if(colName == MS::MODEL_DATA)
    7169           0 :       data.reference(mscIn_p->modelData());
    7170           0 :     else if(colName == MS::LAG_DATA)
    7171           0 :       data.reference(mscIn_p->lagData());
    7172             :     else                                // The honored-by-time-if-nothing-else
    7173           0 :       data.reference(mscIn_p->correctedData()); // default.
    7174           0 :     return true;
    7175             :   }
    7176             : 
    7177           0 :   Bool SubMS::getDataColumn(ArrayColumn<Float>& data,
    7178             :                             const MS::PredefinedColumns colName)
    7179             :   {
    7180           0 :     LogIO os(LogOrigin("SubMS", "getDataColumn()"));
    7181             : 
    7182           0 :     if(colName != MS::FLOAT_DATA)
    7183             :       os << LogIO::WARN
    7184             :          << "Using FLOAT_DATA (because it has type Float) instead of the requested "
    7185             :          << colName
    7186           0 :          << LogIO::POST;
    7187             :     
    7188           0 :     data.reference(mscIn_p->floatData());
    7189           0 :     return true;
    7190           0 :   }
    7191             : 
    7192           0 :   Bool SubMS::putDataColumn(MSColumns& msc, ArrayColumn<Complex>& data, 
    7193             :                             const MS::PredefinedColumns colName,
    7194             :                             const Bool writeToDataCol)
    7195             :   {
    7196           0 :     if(writeToDataCol || colName == MS::DATA) 
    7197           0 :       msc.data().putColumn(data);
    7198           0 :     else if (colName ==  MS::MODEL_DATA)
    7199           0 :       msc.modelData().putColumn(data);
    7200           0 :     else if (colName == MS::CORRECTED_DATA)
    7201           0 :       msc.correctedData().putColumn(data);
    7202             :     //else if(colName == MS::FLOAT_DATA)              // promotion from Float
    7203             :     //  msc.floatData().putColumn(data);              // to Complex is pvt?
    7204           0 :     else if(colName == MS::LAG_DATA)
    7205           0 :       msc.lagData().putColumn(data);
    7206             :     else
    7207           0 :       return false;
    7208           0 :     return true;
    7209             :   }
    7210             : 
    7211           0 : void SubMS::setFitOrder(Int fitorder, Bool advise)
    7212             : {
    7213           0 :   fitorder_p = fitorder;
    7214             : 
    7215           0 :   if(advise){
    7216           0 :     LogIO os(LogOrigin("SubMS", "setFitOrder()"));
    7217             : 
    7218           0 :     if(fitorder < 0)
    7219             :       os << LogIO::NORMAL
    7220           0 :          << "Keeping the continuum.";
    7221           0 :     else if(fitorder > 1)
    7222             :       os << LogIO::WARN
    7223           0 :          << "Fit orders > 1 tend to drastically add noise to line channels.";
    7224           0 :     os << LogIO::POST;
    7225           0 :   }
    7226           0 : }
    7227             : 
    7228           0 : Bool SubMS::shouldWatch(Bool& conflict, const String& col,
    7229             :                         const String& uncombinable,
    7230             :                         const Bool verbose) const
    7231             : {
    7232           0 :   Bool wantWatch = !combine_p.contains(col);
    7233             : 
    7234           0 :   if(!wantWatch && uncombinable.contains(col)){
    7235           0 :     conflict = true;
    7236           0 :     wantWatch = false;
    7237             : 
    7238           0 :     if(verbose){
    7239           0 :       LogIO os(LogOrigin("SubMS", "shouldWatch()"));
    7240             : 
    7241             :       os << LogIO::WARN
    7242             :          << "Combining by " << col
    7243             :          << " was requested, but it is not allowed by this operation and will be ignored."
    7244           0 :          << LogIO::POST;
    7245           0 :     }
    7246             :   }
    7247           0 :   return wantWatch;
    7248             : }
    7249             : 
    7250           0 : Bool SubMS::setSortOrder(Block<Int>& sort, const String& uncombinable,
    7251             :                          const Bool verbose) const
    7252             : {
    7253           0 :   Bool conflict = false;
    7254           0 :   uInt n_cols_to_watch = 7;     // 3 + #(watchables), whether or not they are watched.
    7255             : 
    7256             :   // Already separated by the chunking.
    7257             :   //const Bool watch_array(!combine_p.contains("arr")); // Pirate talk for "array".
    7258             : 
    7259           0 :   Bool watch_obs   = shouldWatch(conflict, "obs",   uncombinable, verbose);
    7260           0 :   Bool watch_scan  = shouldWatch(conflict, "scan",  uncombinable, verbose);
    7261           0 :   Bool watch_spw   = shouldWatch(conflict, "spw",   uncombinable, verbose);
    7262           0 :   Bool watch_state = shouldWatch(conflict, "state", uncombinable, verbose);
    7263             : 
    7264             :   // if(watch_obs)
    7265             :   //   ++n_cols_to_watch;
    7266             :   // if(watch_scan)
    7267             :   //   ++n_cols_to_watch;
    7268             :   // if(watch_spw)
    7269             :   //   ++n_cols_to_watch;
    7270             :   // if(watch_state)
    7271             :   //   ++n_cols_to_watch;
    7272             : 
    7273           0 :   uInt colnum = 1;
    7274             : 
    7275           0 :   sort.resize(n_cols_to_watch);
    7276           0 :   sort[0] = MS::ARRAY_ID;
    7277           0 :   if(watch_scan){
    7278           0 :     sort[colnum] = MS::SCAN_NUMBER;
    7279           0 :     ++colnum;
    7280             :   }
    7281           0 :   if(watch_state){
    7282           0 :     sort[colnum] = MS::STATE_ID;
    7283           0 :     ++colnum;
    7284             :   }
    7285           0 :   sort[colnum] = MS::FIELD_ID;
    7286           0 :   ++colnum;
    7287           0 :   if(watch_spw){
    7288           0 :     sort[colnum] = MS::DATA_DESC_ID;
    7289           0 :     ++colnum;
    7290             :   }
    7291           0 :   sort[colnum] = MS::TIME;
    7292           0 :   ++colnum;  
    7293           0 :   if(watch_obs){
    7294           0 :     sort[colnum] = MS::OBSERVATION_ID;
    7295           0 :     ++colnum;
    7296             :   }
    7297             : 
    7298             :   // Now all the axes that should be combined should be added, so that they end
    7299             :   // up in the same chunk.
    7300           0 :   if(!watch_scan){
    7301           0 :     sort[colnum] = MS::SCAN_NUMBER;
    7302           0 :     ++colnum;
    7303             :   }
    7304           0 :   if(!watch_state){
    7305           0 :     sort[colnum] = MS::STATE_ID;
    7306           0 :     ++colnum;
    7307             :   }
    7308           0 :   if(!watch_spw){
    7309           0 :     sort[colnum] = MS::DATA_DESC_ID;
    7310           0 :     ++colnum;
    7311             :   }
    7312           0 :   if(!watch_obs){
    7313           0 :     sort[colnum] = MS::OBSERVATION_ID;
    7314             :     //++colnum;
    7315             :   }
    7316             : 
    7317           0 :   return !conflict;
    7318             : }
    7319             : 
    7320           0 : Bool SubMS::subtractContinuum(const Vector<MS::PredefinedColumns>& colNames,
    7321             :                               const VBRemapper& vbmaps)
    7322             : {
    7323           0 :   LogIO os(LogOrigin("SubMS", "subtractContinuum()"));
    7324           0 :   Bool retval = true;
    7325             : 
    7326           0 :   if(colNames.nelements() != 1){
    7327             :     os << LogIO::SEVERE
    7328             :        << "The continuum cannot be subtracted from > 1 *DATA column at a time."
    7329           0 :        << LogIO::POST;
    7330           0 :     return false;
    7331             :   }
    7332             : 
    7333           0 :   Block<Int> sort;
    7334           0 :   if(!setSortOrder(sort, "obs,scan,state", false)){
    7335             :     os << LogIO::WARN
    7336             :        << "This version of continuum subtraction intentionally does not support\n"
    7337             :        << "time smearing.  The only recommended (and used) values for combine in\n"
    7338             :        << "this case are '' or 'spw'."
    7339           0 :        << LogIO::POST;
    7340             :   }
    7341             : 
    7342             :   // Aaargh...everywhere else VisIter is used a timeInterval of 0 is treated as
    7343             :   // DBL_MAX, meaning that TIME can be in sort but effectively be ignored for
    7344             :   // major chunking.  Why couldn't they just have said DBL_MAX in the first
    7345             :   // place?
    7346           0 :   ROVisibilityIterator viIn(mssel_p, sort, false, DBL_MIN);
    7347             : 
    7348             :   // Make sure it is initialized before any copies are made.
    7349           0 :   viIn.originChunks();
    7350             : 
    7351           0 :   VBGContinuumSubtractor vbgcs(msOut_p, msc_p, vbmaps, viIn, fitorder_p,
    7352           0 :                                colNames[0], fitspw_p, fitoutspw_p);
    7353           0 :   vbgcs.setTVIDebug(tvi_debug);
    7354           0 :   vbgcs.setWantCont(want_cont_p);
    7355           0 :   GroupProcessor gp(viIn, &vbgcs);
    7356           0 :   gp.setTVIDebug(tvi_debug);
    7357             : 
    7358           0 :   retval = gp.go();
    7359             : 
    7360             :   // TODO: Support uvcontsub(3)'s spw parameter by
    7361             :   //  * filtering the output by fitoutspw_p
    7362             :   //  * remapping DDID as necessary, taking (union)spw into account
    7363             :   //  * filtering and rewriting the DATA_DESC_ID and SPECTRAL_WINDOW subtables.
    7364             : 
    7365           0 :   return retval;
    7366           0 : }
    7367             : 
    7368           0 : void SubMS::fill_vbmaps(std::map<VisBufferComponents::EnumType, std::map<Int, Int> >& vbmaps)
    7369             : {
    7370             :   // In general, _IDs which are row numbers in a subtable must be
    7371             :   // remapped, and those which are not probably shouldn't be.
    7372           0 :   if(antennaSel_p){
    7373           0 :     std::map<Int, Int> antIndexer;
    7374             : 
    7375           0 :     fillAntIndexer(antIndexer, mscIn_p);
    7376           0 :     vbmaps[VisBufferComponents::Ant1] = antIndexer;
    7377           0 :     vbmaps[VisBufferComponents::Ant2] = antIndexer;
    7378           0 :   }
    7379             : 
    7380           0 :   if(!allEQ(spwRelabel_p, spw_p)){
    7381           0 :     std::map<Int, Int> ddidMapper;
    7382             : 
    7383           0 :     for(uInt i = 0; i < oldDDSpwMatch_p.nelements(); ++i)
    7384           0 :       ddidMapper[i] = spwRelabel_p[oldDDSpwMatch_p[i]];
    7385             : 
    7386           0 :     vbmaps[VisBufferComponents::DataDescriptionId] = ddidMapper;
    7387           0 :   }
    7388             : 
    7389           0 :   if(fieldid_p.nelements() < mscIn_p->field().nrow()){
    7390           0 :     std::map<Int, Int> fldMapper;
    7391             :     
    7392           0 :     make_map2(fldMapper, fieldRelabel_p);
    7393           0 :     vbmaps[VisBufferComponents::FieldId] = fldMapper;
    7394           0 :   }
    7395             : 
    7396           0 :   if(selObsId_p.nelements() > 0 && selObsId_p.nelements() < mscIn_p->observation().nrow()){
    7397           0 :     std::map<Int, Int> obsMapper;
    7398             : 
    7399           0 :     make_map(obsMapper, selObsId_p);
    7400           0 :     vbmaps[VisBufferComponents::ObservationId] = obsMapper;
    7401           0 :   }
    7402             : 
    7403             :   //std::map<Int, Int> procMapper;
    7404             :   //make_map(procMapper, mscIn_p->processorId().getColumn());
    7405             : 
    7406           0 :   if(stateRemapper_p.size() < 1)
    7407           0 :     make_map(stateRemapper_p, mscIn_p->stateId().getColumn());
    7408           0 :   if(stateRemapper_p.size() < mscIn_p->state().nrow())
    7409           0 :     vbmaps[VisBufferComponents::StateId] = stateRemapper_p;
    7410           0 : }
    7411             : 
    7412          41 : Bool SubMS::copyDataFlagsWtSp(const Vector<MS::PredefinedColumns>& colNames,
    7413             :                               const Bool writeToDataCol)
    7414             :   {
    7415          41 :     Block<Int> columns;
    7416             :     // include scan and state iteration, for more optimal iteration
    7417          41 :     columns.resize(6);
    7418          41 :     columns[0]=MS::ARRAY_ID;
    7419          41 :     columns[1]=MS::SCAN_NUMBER;
    7420          41 :     columns[2]=MS::STATE_ID;
    7421          41 :     columns[3]=MS::FIELD_ID;
    7422          41 :     columns[4]=MS::DATA_DESC_ID;
    7423          41 :     columns[5]=MS::TIME;
    7424             : 
    7425             : #ifdef COPYTIMER
    7426             :     Timer timer;
    7427             :     timer.mark();
    7428             : 
    7429             :     Vector<Int> inscan, outscan;
    7430             : #endif
    7431             : 
    7432          41 :     ROVisIter viIn(mssel_p,columns,0.0);
    7433          41 :     VisIter viOut(msOut_p,columns,0.0);
    7434          41 :     viIn.setRowBlocking(1000);
    7435          41 :     viOut.setRowBlocking(1000);
    7436          41 :     Int iChunk(0), iChunklet(0);
    7437          41 :     Cube<Complex> data;
    7438          41 :     Cube<Bool> flag;
    7439          41 :     Array<Bool> flagcat;
    7440             : 
    7441          41 :     Matrix<Float> wtmat;
    7442          41 :     viIn.originChunks();                                // Makes me feel better.
    7443          41 :     const Bool doWtSp(viIn.existsWeightSpectrum());
    7444          41 :     Cube<Float> wtsp;
    7445             : 
    7446          41 :     uInt ninrows = mssel_p.nrow();
    7447             :     ProgressMeter meter(0.0, ninrows * 1.0, "split", "rows copied", "", "",
    7448          82 :                         true, 1);
    7449          41 :     uInt inrowsdone = 0;  // only for the meter.
    7450             : 
    7451          41 :     uInt nDataCols = colNames.nelements();
    7452             : 
    7453             :     // Is CORRECTED_DATA being moved to DATA?
    7454          41 :     Bool fromCorrToData = writeToDataCol && nDataCols == 1;
    7455          41 :     if(fromCorrToData)
    7456          33 :       fromCorrToData = colNames[0] == MS::CORRECTED_DATA;
    7457             : 
    7458          41 :     Bool doFC = existsFlagCategory();
    7459             : 
    7460          41 :     for (iChunk=0,viOut.originChunks(),viIn.originChunks();
    7461        1336 :          viOut.moreChunks(),viIn.moreChunks();
    7462        1295 :          viOut.nextChunk(),viIn.nextChunk(),++iChunk) {
    7463        1295 :       inrowsdone += viIn.nRowChunk();
    7464             : 
    7465             :       // The following can help evaluable in/out index alignment
    7466             :       /*
    7467             :       cout << "****iChunk=" << iChunk 
    7468             :            << " scn: " << viIn.scan(inscan)(0) << "/" << viOut.scan(outscan)(0) << "   "
    7469             :            << "fld: " << viIn.fieldId() << "/"  << viOut.fieldId() << "   "
    7470             :            << "ddi: " << viIn.dataDescriptionId() << "/" << viOut.dataDescriptionId() << "   "
    7471             :            << "spw: " << viIn.spectralWindow() << "/"  << viOut.spectralWindow() << "   "
    7472             :            << endl;
    7473             :       */
    7474        1295 :       for (iChunklet=0,viIn.origin(),viOut.origin();
    7475        3278 :            viIn.more(),viOut.more();
    7476        1983 :            viIn++,viOut++,++iChunklet) { //  
    7477             : 
    7478             :         //      cout << "nRows = " << viIn.nRow() << "/" << viOut.nRow() << endl;
    7479             : 
    7480             : #ifdef COPYTIMER
    7481             :         timer.mark();
    7482             : #endif
    7483        1983 :         viIn.flag(flag);
    7484        1983 :         viOut.setFlag(flag);
    7485        1983 :         if(doFC){
    7486           0 :           viIn.flagCategory(flagcat);
    7487           0 :           viOut.setFlagCategory(flagcat);
    7488             :         }
    7489        1983 :         if(fromCorrToData) {
    7490          50 :           viIn.weightMat(wtmat);
    7491          50 :           viOut.setWeightMat(wtmat);
    7492          50 :           arrayTransformInPlace(wtmat, subms::wtToSigma);   // for corrected weights.
    7493          50 :           viOut.setSigmaMat(wtmat);
    7494             :         }
    7495             :         else {
    7496        1933 :           viIn.sigmaMat(wtmat);           // Yes, I'm reusing wtmat.
    7497        1933 :           viOut.setSigmaMat(wtmat);
    7498        1933 :           arrayTransformInPlace(wtmat, subms::sigToWeight);   // for corrected weights.
    7499        1933 :           viOut.setWeightMat(wtmat);
    7500             :         }         
    7501             : 
    7502        1983 :         if(doWtSp){
    7503        1916 :           viIn.weightSpectrum(wtsp);
    7504        1916 :           viOut.setWeightSpectrum(wtsp);
    7505             :         }
    7506             : 
    7507        4019 :         for(uInt colnum = 0; colnum < nDataCols; ++colnum){
    7508        2036 :           if(writeToDataCol || colNames[colnum] == MS::DATA) {
    7509             :             // write DATA, MODEL_DATA, or CORRECTED_DATA to DATA
    7510        1983 :             switch (colNames[colnum]) {
    7511        1925 :             case MS::DATA:
    7512        1925 :               viIn.visibility(data,VisibilityIterator::Observed);
    7513        1925 :               break;
    7514           8 :             case MS::MODEL_DATA:
    7515           8 :               viIn.visibility(data,VisibilityIterator::Model);
    7516           8 :               break;
    7517          50 :             case MS::CORRECTED_DATA:
    7518          50 :               viIn.visibility(data,VisibilityIterator::Corrected);
    7519          50 :               break;
    7520           0 :             default:
    7521           0 :               throw(AipsError("Unrecognized input column!"));
    7522             :               break;
    7523             :             }
    7524        1983 :             viOut.setVis(data,VisibilityIterator::Observed);
    7525             :           }
    7526          53 :           else if (colNames[colnum] ==  MS::MODEL_DATA) {
    7527             :             // write MODEL_DATA to MODEL_DATA
    7528          26 :             viIn.visibility(data,VisibilityIterator::Model);
    7529          26 :             viOut.setVis(data,VisibilityIterator::Model);
    7530             :           }
    7531          27 :           else if (colNames[colnum] == MS::CORRECTED_DATA) {
    7532             :             // write CORRECTED_DATA to CORRECTED_DATA
    7533          27 :             viIn.visibility(data,VisibilityIterator::Corrected);
    7534          27 :             viOut.setVis(data,VisibilityIterator::Corrected);
    7535             :           }
    7536             :           //else if(colNames[colnum] == MS::FLOAT_DATA)              // TBD
    7537             :           //    else if(colNames[colnum] == MS::LAG_DATA)      // TBD
    7538             :           else
    7539           0 :             return false;
    7540             :         }
    7541             : 
    7542             : #ifdef COPYTIMER        
    7543             :         Double t=timer.real();
    7544             :         cout << "Chunk: " << iChunk << " " << iChunklet 
    7545             :              << " scn: " << viIn.scan(inscan)(0) << "/" << viOut.scan(outscan)(0) 
    7546             :              << "   "
    7547             :              << " spw: " << viIn.spectralWindow() << "/"  << viOut.spectralWindow() 
    7548             :              << " : "
    7549             :              << data.nelements() << " cells = " 
    7550             :              << data.nelements()*8.e-6 << " MB in " 
    7551             :              << t << " sec, for " << data.nelements()*8.e-6/t << " MB/s" 
    7552             :              << endl;
    7553             : #endif
    7554             :         
    7555             :       }
    7556        1295 :       meter.update(inrowsdone);
    7557             :     }
    7558          41 :     return true;
    7559          41 :   }
    7560             : 
    7561           0 :   Bool SubMS::putDataColumn(MSColumns& msc, ArrayColumn<Float>& data, 
    7562             :                             const MS::PredefinedColumns colName,
    7563             :                             const Bool writeToDataCol)
    7564             :   {
    7565           0 :     LogIO os(LogOrigin("SubMS", "putDataColumn()"));
    7566             : 
    7567           0 :     if(writeToDataCol)
    7568             :       os << LogIO::NORMAL
    7569             :          << "Writing to FLOAT_DATA instead of DATA."
    7570           0 :          << LogIO::POST;
    7571             : 
    7572           0 :     if(colName == MS::FLOAT_DATA){
    7573           0 :       msc.floatData().putColumn(data);
    7574             :     }
    7575             :     else{
    7576             :       os << LogIO::SEVERE
    7577             :          << "Float data cannot be written to "
    7578             :          << MS::columnName(colName)
    7579           0 :          << LogIO::POST;
    7580           0 :       return false;
    7581             :     }
    7582           0 :     return true;
    7583           0 :   }
    7584             : 
    7585             :   // Sets outcol to row numbers in the corresponding subtable of its ms that
    7586             :   // correspond to the values of incol.
    7587             :   //
    7588             :   // Can only be used when incol and outcol have the same # of rows!
    7589             :   //
    7590          44 : void SubMS::remapColumn(ScalarColumn<Int>& outcol,
    7591             :                         const ScalarColumn<Int>& incol)
    7592             : {
    7593          44 :   uInt nrows = incol.nrow();
    7594             :     
    7595          44 :   if(nrows != outcol.nrow()){
    7596           0 :     ostringstream ostr;
    7597             : 
    7598           0 :     ostr << "SubMS::remapColumn(): the # of input rows, " << nrows
    7599           0 :          << ", != the # of output rows, " << outcol.nrow();
    7600           0 :     throw(AipsError(ostr.str()));
    7601           0 :   }
    7602             :     
    7603          44 :   std::map<Int, Int> mapper;
    7604          44 :   Vector<Int> inv(incol.getColumn());
    7605             : 
    7606          44 :   make_map(mapper, inv);
    7607          44 :   if(mapper.size() == 1){
    7608          43 :     outcol.fillColumn(0);        // Just a little optimization.
    7609             :   }
    7610             :   else{
    7611           1 :     Vector<Int> outv(nrows);
    7612             : 
    7613           1 :     if(mapper.size() > 0){
    7614       46501 :       for(uInt k = 0; k < nrows; ++k)
    7615       46500 :         outv[k] = mapper[inv[k]];
    7616             :     }
    7617             :     else
    7618           0 :       incol.getColumn(outv);
    7619           1 :     outcol.putColumn(outv);
    7620           1 :   }
    7621          44 : }
    7622             : 
    7623          44 : void SubMS::remapColumn(ScalarColumn<Int>& outcol,
    7624             :                         const ScalarColumn<Int>& incol,
    7625             :                         const Vector<Int>& selvals)
    7626             : {
    7627          44 :   uInt nrows = incol.nrow();
    7628             :     
    7629          44 :   if(nrows != outcol.nrow()){
    7630           0 :     ostringstream ostr;
    7631             : 
    7632           0 :     ostr << "SubMS::remapColumn(): the # of input rows, " << nrows
    7633           0 :          << ", != the # of output rows, " << outcol.nrow();
    7634           0 :     throw(AipsError(ostr.str()));
    7635           0 :   }
    7636             :     
    7637          44 :   std::map<Int, Int> mapper;
    7638          44 :   Vector<Int> inv(incol.getColumn());
    7639          44 :   Vector<Int> outv(nrows);
    7640             : 
    7641          44 :   make_map(mapper, selvals);
    7642          44 :   if(mapper.size() == 1){
    7643           0 :     outcol.fillColumn(0);        // Just a little optimization.
    7644             :   }
    7645             :   else{
    7646          44 :     Vector<Int> outv(nrows);
    7647             : 
    7648          44 :     if(mapper.size() > 0){
    7649           0 :       for(uInt k = 0; k < nrows; ++k)
    7650           0 :         outv[k] = mapper[inv[k]];
    7651             :     }
    7652             :     else
    7653          44 :       incol.getColumn(outv);
    7654          44 :     outcol.putColumn(outv);
    7655          44 :   }
    7656          44 : }
    7657             :   
    7658             : // Realigns some _ID vectors so that the output looks like a whole dataset
    7659             : // instead of part of one.  (i.e. we don't want references to unselected spws,
    7660             : // etc.)
    7661          44 : void SubMS::relabelIDs()
    7662             : {
    7663          44 :   const ScalarColumn<Int> inDDID(mscIn_p->dataDescId());
    7664          44 :   const ScalarColumn<Int> fieldId(mscIn_p->fieldId());
    7665             :   
    7666      815895 :   for(Int k = inDDID.nrow(); k--;){
    7667      815851 :     msc_p->dataDescId().put(k, spwRelabel_p[oldDDSpwMatch_p[inDDID(k)]]);
    7668      815851 :     msc_p->fieldId().put(k, fieldRelabel_p[fieldId(k)]);
    7669             :   }
    7670             : 
    7671             :   //remapColumn(msc_p->arrayId(), mscIn_p->arrayId());
    7672          44 :   remapColumn(msc_p->stateId(), mscIn_p->stateId());
    7673             :   //remapColumn(msc_p->processorId(), mscIn_p->processorId());
    7674          44 :   remapColumn(msc_p->observationId(), mscIn_p->observationId(), selObsId_p);
    7675          44 : }
    7676             : 
    7677           0 : Bool SubMS::writeSomeMainRows(const Vector<MS::PredefinedColumns>& colNames)
    7678             : {    
    7679           0 :   LogIO os(LogOrigin("SubMS", "writeSomeMainRows()"));
    7680           0 :   Bool retval = true;
    7681             :     
    7682             :   os << LogIO::DEBUG1 // helpdesk ticket in from Oleg Smirnov (ODU-232630)
    7683             :      << "Before fillAntIndexer(): "
    7684           0 :      << Memory::allocatedMemoryInBytes() / (1024.0 * 1024.0) << " MB"
    7685           0 :      << LogIO::POST;
    7686             : 
    7687             :   // A set of maps from input ID to output ID, keyed by VisBufferComponent.
    7688           0 :   std::map<VisBufferComponents::EnumType, std::map<Int, Int> > vbmaps;
    7689           0 :   fill_vbmaps(vbmaps);
    7690           0 :   VBRemapper remapper(vbmaps);
    7691             : 
    7692             :   //things to be taken care of in doTimeAver() or subtractContinuum...
    7693             :   // flagRow            ScanNumber      uvw             weight          
    7694             :   // sigma              ant1            ant2            time
    7695             :   // timeCentroid       feed1           feed2           exposure
    7696             :   // stateId            processorId     observationId   arrayId
    7697           0 :   if(fitorder_p >= 0)
    7698           0 :     retval = subtractContinuum(colNames, remapper); // writeToDataCol = complexCols == 1
    7699             :   else
    7700           0 :     retval = (corrString_p != "") ? doTimeAverVisIterator(colNames, remapper)
    7701           0 :                                   : doTimeAver(colNames, remapper);
    7702           0 :   return retval;
    7703           0 : }
    7704             : 
    7705         184 : uInt SubMS::addOptionalColumns(const Table& inTab, Table& outTab,
    7706             :                                const Bool beLazy)
    7707             : {
    7708         184 :   uInt nAdded = 0;    
    7709         184 :   const TableDesc& inTD = inTab.actualTableDesc();
    7710             :     
    7711             :   // Only rely on the # of columns if you are sure that inTab and outTab
    7712             :   // can't have the same # of columns without having _different_ columns,
    7713             :   // i.e. use beLazy if outTab.actualTableDesc() is in its default state.
    7714         184 :   uInt nInCol = inTD.ncolumn();
    7715         184 :   if(!beLazy || nInCol > outTab.actualTableDesc().ncolumn()){
    7716         110 :     LogIO os(LogOrigin("SubMS", "addOptionalColumns()"));
    7717             : 
    7718          55 :     Vector<String> oldColNames = inTD.columnNames();
    7719             :       
    7720         860 :     for(uInt k = 0; k < nInCol; ++k){
    7721         805 :       if(!outTab.actualTableDesc().isColumn(oldColNames[k])){
    7722             :         //TableDesc tabDesc;
    7723             :         try{
    7724             :           //M::addColumnToDesc(tabDesc, M::columnType(oldColNames[k]));
    7725             :           //if(tabDesc.ncolumn())                 // The tabDesc[0] is too 
    7726             :           //  outTab.addColumn(tabDesc[0]);       // dangerous otherwise - it 
    7727             :           //else                                  // can dump core without
    7728             :           //  throw(AipsError("Unknown column")); // throwing an exception.
    7729         285 :           outTab.addColumn(inTD.columnDesc(k), false);
    7730         285 :           ++nAdded;
    7731             :         }
    7732           0 :         catch(...){   // NOT AipsError x
    7733             :           os << LogIO::WARN 
    7734           0 :              << "Could not add column " << oldColNames[k] << " to "
    7735             :              << outTab.tableName()
    7736           0 :              << LogIO::POST;
    7737           0 :         }
    7738             :       }
    7739             :     }
    7740          55 :   }
    7741         184 :   return nAdded;
    7742         184 : }
    7743             :   
    7744           0 : Bool SubMS::copyCols(Table& out, const Table& in, const Bool flush)
    7745             : {
    7746           0 :   LogIO os(LogOrigin("SubMS", "copyCols()"));
    7747           0 :   const TableDesc& inTD = in.actualTableDesc();
    7748           0 :   Vector<String> inColNames = inTD.columnNames();
    7749           0 :   uInt nInCol = inTD.ncolumn();
    7750           0 :   Bool retval = true;
    7751             : 
    7752           0 :   if(in.nrow() > out.nrow())
    7753           0 :     out.addRow(in.nrow() - out.nrow());
    7754             : 
    7755           0 :   for(uInt k = 0; k < nInCol; ++k){
    7756             :     // Add the input column desc to out if necessary.
    7757           0 :     if(!out.actualTableDesc().isColumn(inColNames[k])){
    7758             :       try{
    7759           0 :         out.addColumn(inTD.columnDesc(k), false);
    7760             :       }
    7761           0 :       catch(...){   // NOT AipsError x
    7762             :         os << LogIO::WARN 
    7763           0 :            << "Could not add column " << inColNames[k] << " to "
    7764             :            << out.tableName()
    7765           0 :            << LogIO::POST;
    7766           0 :         retval = false;
    7767           0 :       }
    7768             :     }
    7769             : 
    7770             :     // I can't see a way to explicitly* avoid constructing these in each
    7771             :     // iteration.  (attach() would implicitly construct them.)
    7772             :     // * without relying on compiler optimization.
    7773           0 :     TableColumn incol(in, inColNames[k]);
    7774           0 :     TableColumn outcol(out, inColNames[k]);
    7775             : 
    7776           0 :     outcol.putColumn(incol);
    7777           0 :   }
    7778           0 :   if(flush)
    7779           0 :     out.flush();
    7780           0 :   return retval;
    7781           0 : }
    7782             : 
    7783          44 :   Bool SubMS::copyAntenna(){
    7784          44 :     const MSAntenna& oldAnt = mssel_p.antenna();
    7785          44 :     MSAntenna& newAnt = msOut_p.antenna();
    7786          44 :     const MSAntennaColumns incols(oldAnt);
    7787          44 :     MSAntennaColumns         outcols(newAnt);
    7788          44 :     Bool                     retval = false;
    7789             :     
    7790          44 :     outcols.setOffsetRef(MPosition::castType(incols.offsetMeas().getMeasRef().getType()));
    7791          44 :     outcols.setPositionRef(MPosition::castType(incols.positionMeas().getMeasRef().getType()));
    7792             : 
    7793          44 :     if(!antennaSel_p){
    7794          44 :       TableCopy::copyRows(newAnt, oldAnt);
    7795          44 :       retval = true;
    7796             :     }
    7797             :     else{
    7798           0 :       uInt nAnt = antNewIndex_p.nelements();
    7799           0 :       if(nAnt > oldAnt.nrow())                  // Don't use min() here,
    7800           0 :         nAnt = oldAnt.nrow();                   // it's too overloaded.
    7801             : 
    7802           0 :       for(uInt k = 0; k < nAnt; ++k){
    7803           0 :         if(antNewIndex_p[k] > -1)
    7804           0 :           TableCopy::copyRows(newAnt, oldAnt, antNewIndex_p[k], k, 1, false);
    7805             :       }
    7806           0 :       retval = true;
    7807             :     }
    7808          44 :     return retval;    
    7809          44 :   }
    7810             : 
    7811             : 
    7812          44 :   Bool SubMS::copyFeed()
    7813             :   {
    7814          44 :     const MSFeed& oldFeed = mssel_p.feed();
    7815             : 
    7816             :     // if(oldFeed.nrow() < 1)     Useless, because it ignores spw selection
    7817             :     
    7818          44 :     MSFeed& newFeed = msOut_p.feed();
    7819          44 :     const MSFeedColumns incols(oldFeed);
    7820          44 :     MSFeedColumns         outcols(newFeed);
    7821             :     
    7822          44 :     outcols.setDirectionRef(MDirection::castType(incols.beamOffsetMeas().getMeasRef().getType()));
    7823          44 :     outcols.setEpochRef(MEpoch::castType(incols.timeMeas().getMeasRef().getType()));
    7824          44 :     outcols.setPositionRef(MPosition::castType(incols.positionMeas().getMeasRef().getType()));
    7825             : 
    7826          44 :     if(!antennaSel_p && allEQ(spwRelabel_p, spw_p)){
    7827          27 :       TableCopy::copyRows(newFeed, oldFeed);
    7828             :     }
    7829             :     else{
    7830          17 :       const Vector<Int>& antIds = incols.antennaId().getColumn();
    7831          17 :       const Vector<Int>& spwIds = incols.spectralWindowId().getColumn();
    7832             : 
    7833             :       // Copy selected rows.
    7834          17 :       uInt totNFeeds = antIds.nelements();
    7835          17 :       uInt totalSelFeeds = 0;
    7836          17 :       Int maxSelAntp1 = antNewIndex_p.nelements();
    7837        1982 :       for (uInt k = 0; k < totNFeeds; ++k){
    7838             :         // antenna must be selected, and spwId must be -1 (any) or selected.
    7839        3930 :         if(antIds[k] < maxSelAntp1 && antNewIndex_p[antIds[k]] > -1 &&
    7840        1965 :            (spwIds[k] < 0 || spwRelabel_p[spwIds[k]] > -1)){
    7841             :           //                  outtab   intab    outrow       inrow nrows
    7842         249 :           TableCopy::copyRows(newFeed, oldFeed, totalSelFeeds, k, 1, false);
    7843         249 :           ++totalSelFeeds;
    7844             :         }
    7845             :       }
    7846             : 
    7847             :       // Remap antenna and spw #s.
    7848          17 :       ScalarColumn<Int>& antCol = outcols.antennaId();
    7849          17 :       ScalarColumn<Int>& spwCol = outcols.spectralWindowId();
    7850             : 
    7851         266 :       for(uInt k = 0; k < totalSelFeeds; ++k){
    7852         249 :         antCol.put(k, antNewIndex_p[antCol(k)]);
    7853         249 :         if(spwCol(k) > -1)
    7854         160 :           spwCol.put(k, spwRelabel_p[spwCol(k)]);
    7855             :       }
    7856          17 :     }
    7857             : 
    7858          44 :     if(newFeed.nrow() < 1){
    7859           0 :       LogIO os(LogOrigin("SubMS", "copyFeed()"));
    7860           0 :       os << LogIO::SEVERE << "No feeds were selected." << LogIO::POST;
    7861           0 :       return false;
    7862           0 :     }
    7863          44 :     return true;
    7864          44 :   }
    7865             :   
    7866          44 :   Bool SubMS::copyFlag_Cmd(){
    7867             :     // Like POINTING, FLAG_CMD is supposed to exist but is allowed not to.
    7868          44 :     if(Table::isReadable(mssel_p.flagCmdTableName())){
    7869             :       // An attempt to select from FLAG_CMD by timerange.  Fails because the
    7870             :       // TEN refers to the main table, not FLAG_CMD.
    7871             :       // TableExprNode condition;
    7872             : 
    7873             :       // if(timeRange_p != "" &&
    7874             :       //         msTimeGramParseCommand(&ms_p, timeRange_p, condition) == 0){
    7875             :       //        const TableExprNode *timeNode = 0x0;
    7876             :           
    7877             :       //        timeNode = msTimeGramParseNode();
    7878             :       //        if(timeNode && !timeNode->isNull())
    7879             :       //          condition = *timeNode;
    7880             :       // }
    7881             : 
    7882          44 :       const MSFlagCmd& oldFlag_Cmd = mssel_p.flagCmd();
    7883             : 
    7884          44 :       if(oldFlag_Cmd.nrow() > 0){
    7885             :         // Could be declared as Table&
    7886           2 :         MSFlagCmd& newFlag_Cmd = msOut_p.flagCmd();
    7887             : 
    7888           4 :         LogIO os(LogOrigin("SubMS", "copyFlag_Cmd()"));
    7889             : 
    7890             :         // Add optional columns if present in oldFlag_Cmd.
    7891           2 :         uInt nAddedCols = addOptionalColumns(oldFlag_Cmd, newFlag_Cmd, true);
    7892             :         os << LogIO::DEBUG1 << "FLAG_CMD has " << nAddedCols
    7893           2 :            << " optional columns." << LogIO::POST;
    7894             :         
    7895           2 :         const MSFlagCmdColumns oldFCs(oldFlag_Cmd);
    7896           2 :         MSFlagCmdColumns newFCs(newFlag_Cmd);
    7897           2 :         newFCs.setEpochRef(MEpoch::castType(oldFCs.timeMeas().getMeasRef().getType()));
    7898             :         
    7899             :         //if(!antennaSel_p && timeRange_p == ""){
    7900           2 :           TableCopy::copyRows(newFlag_Cmd, oldFlag_Cmd);
    7901             :         // }
    7902             :         // else{
    7903             :         //   const ScalarColumn<Double>& time = oldFCs.time();
    7904             : 
    7905             :         //   uInt nTRanges = selTimeRanges_p.ncolumn();
    7906             : 
    7907             :         //   uInt outRow = 0;
    7908             :         //   for (uInt inRow = 0; inRow < antIds.nrow(); ++inRow){
    7909             :         //     Int newAntInd = antIds(inRow);
    7910             :         //     if(antennaSel_p)
    7911             :         //       newAntInd = antNewIndex_p[newAntInd];
    7912             :         //     Double t = time(inRow);
    7913             :             
    7914             :         //     if(newAntInd > -1){
    7915             :         //       Bool matchT = false;
    7916             :         //       for(uInt tr = 0; tr < nTRanges; ++tr){
    7917             :         //      if(t >= selTimeRanges_p(0, tr) && t <= selTimeRanges_p(1, tr)){
    7918             :         //        matchT = true;
    7919             :         //        break;
    7920             :         //      }
    7921             :         //       }
    7922             :               
    7923             :         //       if(matchT){
    7924             :         //      TableCopy::copyRows(newFlag_Cmd, oldFlag_Cmd, outRow, inRow, 1, false);
    7925             :         //      outants.put(outRow, newAntInd);
    7926             :         //      ++outRow;
    7927             :         //       }
    7928             :         //     }
    7929             :         //   }
    7930           2 :       }
    7931             :     }
    7932          44 :     return true;
    7933             :   }
    7934             :   
    7935          44 :   Bool SubMS::copyHistory(){
    7936          44 :     const MSHistory& oldHistory = mssel_p.history();
    7937             : 
    7938             :     // Could be declared as Table&
    7939          44 :     MSHistory& newHistory = msOut_p.history();
    7940             : 
    7941          88 :     LogIO os(LogOrigin("SubMS", "copyHistory()"));
    7942             : 
    7943             :     // Add optional columns if present in oldHistory.
    7944          44 :     uInt nAddedCols = addOptionalColumns(oldHistory, newHistory, true);
    7945             :     os << LogIO::DEBUG1 << "HISTORY has " << nAddedCols
    7946          44 :        << " optional columns." << LogIO::POST;
    7947             :         
    7948          44 :     const MSHistoryColumns oldHCs(oldHistory);
    7949          44 :     MSHistoryColumns newHCs(newHistory);
    7950          44 :     newHCs.setEpochRef(MEpoch::castType(oldHCs.timeMeas().getMeasRef().getType()));
    7951             :         
    7952          44 :     TableCopy::copyRows(newHistory, oldHistory);
    7953          44 :     return true;
    7954          44 :   }
    7955             :   
    7956          44 :   Bool SubMS::copySource(){
    7957             :     //Source is an optional table, so it may not exist
    7958          44 :     if(Table::isReadable(mssel_p.sourceTableName())){
    7959          88 :       LogIO os(LogOrigin("SubMS", "copySource()"));
    7960             : 
    7961          44 :       const MSSource& oldSource = mssel_p.source();
    7962          44 :       MSSource& newSource = msOut_p.source();
    7963             :       
    7964             :       // Add optional columns if present in oldSource.
    7965          44 :       uInt nAddedCols = addOptionalColumns(oldSource, newSource, true);
    7966             :       os << LogIO::DEBUG1 << "SOURCE has " << nAddedCols
    7967          44 :          << " optional columns." << LogIO::POST;
    7968             :       
    7969          44 :       const MSSourceColumns incols(oldSource);
    7970          44 :       MSSourceColumns         outcols(newSource);
    7971             : 
    7972             :       // Copy the Measures frame info.  This has to be done before filling the
    7973             :       // rows.
    7974          44 :       outcols.setEpochRef(MEpoch::castType(incols.timeMeas().getMeasRef().getType()));
    7975          44 :       outcols.setDirectionRef(MDirection::castType(incols.directionMeas().getMeasRef().getType()));
    7976          44 :       outcols.setPositionRef(MPosition::castType(incols.positionMeas().getMeasRef().getType()));
    7977          44 :       outcols.setFrequencyRef(MFrequency::castType(incols.restFrequencyMeas().getMeasRef().getType()));
    7978          44 :       outcols.setRadialVelocityRef(MRadialVelocity::castType(incols.sysvelMeas().getMeasRef().getType()));
    7979             : 
    7980          44 :       const ScalarColumn<Int>& inSId   = incols.sourceId();
    7981          44 :       ScalarColumn<Int>&       outSId  = outcols.sourceId();
    7982          44 :       const ScalarColumn<Int>& inSPW   = incols.spectralWindowId();
    7983          44 :       ScalarColumn<Int>&       outSPW  = outcols.spectralWindowId();
    7984             : 
    7985             :       // 2009-06-09: It is hard to say whether to remap pulsarID when the
    7986             :       // PULSAR table is not described in the MS v2.0 def'n.
    7987             : //       const ScalarColumn<Int>& inPId   = incols.pulsarId();
    7988             : //       ScalarColumn<Int>&    outPId  = outcols.pulsarId();
    7989             : 
    7990          44 :       uInt outrn = 0;                                   // row number in output.
    7991          44 :       uInt nInputRows = inSId.nrow();
    7992          44 :       Int maxSId = sourceRelabel_p.nelements();  // inSidVal is Int.
    7993          44 :       Int maxSPWId = spwRelabel_p.nelements();
    7994        1849 :       for(uInt inrn = 0; inrn < nInputRows; ++inrn){
    7995        1805 :         Int inSidVal = inSId(inrn);
    7996        1805 :         Int inSPWVal = inSPW(inrn);  // -1 means the source is valid for any SPW.
    7997             :         
    7998        1805 :         if(inSidVal >= maxSId)
    7999             :           os << LogIO::WARN
    8000           0 :              << "Invalid SOURCE ID in SOURCE table row " << inrn << LogIO::POST;
    8001        1805 :         if(inSPWVal >= maxSPWId)
    8002             :           os << LogIO::WARN
    8003           0 :              << "Invalid SPW ID in SOURCE table row " << inrn << LogIO::POST;
    8004             : 
    8005        1805 :         if((inSidVal > -1) && (inSidVal < maxSId) &&
    8006        5322 :            (sourceRelabel_p[inSidVal] > -1) && 
    8007        1712 :            ((inSPWVal == -1) || (inSPWVal < maxSPWId && spwRelabel_p[inSPWVal] > -1))){
    8008             :           // Copy inrn to outrn.
    8009         266 :           TableCopy::copyRows(newSource, oldSource, outrn, inrn, 1);
    8010         266 :           outSId.put(outrn, sourceRelabel_p[inSidVal]);
    8011         266 :           outSPW.put(outrn, inSPWVal > -1 ? spwRelabel_p[inSPWVal] : -1);
    8012             :           
    8013         266 :           ++outrn;
    8014             :         }
    8015             :       }
    8016             : 
    8017          44 :       return true;
    8018          44 :     }
    8019             :   
    8020           0 :     return false;
    8021             :   }
    8022             :   
    8023          44 : Bool SubMS::copyGenericSubtables(){
    8024          88 :   LogIO os(LogOrigin("SubMS", "copyGenericSubtables()"));
    8025             : 
    8026             :   // Already handled subtables will be removed from this, so a modifiable copy
    8027             :   // is needed.
    8028          44 :   TableRecord inkws(mssel_p.keywordSet());
    8029             : 
    8030             :   // Some of the standard subtables need special handling,
    8031             :   // e.g. DATA_DESCRIPTION, SPECTRAL_WINDOW, and ANTENNA, so they are already
    8032             :   // defined in msOut_p.  Several more (e.g. FLAG_CMD) were also already
    8033             :   // created by MS::createDefaultSubtables().  Don't try to write over them - a
    8034             :   // locking error will result.
    8035          44 :   const TableRecord& outkws = msOut_p.keywordSet();
    8036         668 :   for(uInt i = 0; i < outkws.nfields(); ++i){
    8037             :     // os << LogIO::DEBUG1
    8038             :     //    << "outkws.name(" << i << "): " << outkws.name(i)
    8039             :     //    << LogIO::POST;
    8040         624 :     if(outkws.type(i) == TpTable && inkws.isDefined(outkws.name(i)))
    8041         580 :       inkws.removeField(outkws.name(i));
    8042             :   }
    8043             : 
    8044             :   // Includes a flush. 
    8045             :   //msOut_p.unlock();
    8046             : 
    8047             :   // msOut_p.rwKeywordSet() (pass a reference, not a copy) will put a lock on
    8048             :   // msOut_p.
    8049          44 :   TableCopy::copySubTables(msOut_p.rwKeywordSet(), inkws, msOut_p.tableName(),
    8050             :                            msOut_p.tableType(), mssel_p);
    8051             :   // TableCopy::copySubTables(Table, Table, Bool) includes this other code,
    8052             :   // which seems to be copying subtables at one level deeper, but not
    8053             :   // recursively? 
    8054          44 :   const TableDesc& inDesc = mssel_p.tableDesc();
    8055          44 :   const TableDesc& outDesc = msOut_p.tableDesc();
    8056        1077 :   for(uInt i = 0; i < outDesc.ncolumn(); ++i){
    8057             :     // Only writable cols can have keywords (and thus subtables) defined.
    8058        1033 :     if(msOut_p.isColumnWritable(i)){
    8059        1033 :       const String& name = outDesc[i].name();
    8060             : 
    8061        1033 :       if(inDesc.isColumn(name)){
    8062        1032 :         TableColumn outCol(msOut_p, name);
    8063        1032 :         TableColumn inCol(mssel_p, name);
    8064             :         
    8065        1032 :         TableCopy::copySubTables(outCol.rwKeywordSet(), inCol.keywordSet(),
    8066             :                                  msOut_p.tableName(), msOut_p.tableType(),
    8067             :                                  mssel_p);
    8068             : 
    8069             :         // Copy the keywords if column is FLOAT_DATA
    8070        1032 :         if (name == "FLOAT_DATA")
    8071           0 :                 copyMainTableKeywords(outCol.rwKeywordSet(), inCol.keywordSet());
    8072             : 
    8073        1032 :       }
    8074             :     }
    8075             :   }
    8076             : 
    8077          44 :   return true;
    8078          44 : }
    8079             : 
    8080          44 :   Bool SubMS::copyObservation()
    8081             :   {
    8082          44 :     const MSObservation& oldObs = mssel_p.observation();
    8083          44 :     MSObservation& newObs = msOut_p.observation();
    8084          44 :     const MSObservationColumns oldObsCols(oldObs);
    8085          44 :     MSObservationColumns newObsCols(newObs);
    8086          44 :     newObsCols.setEpochRef(MEpoch::castType(oldObsCols.releaseDateMeas().getMeasRef().getType()));
    8087             : 
    8088          44 :     uInt nObs = selObsId_p.nelements();
    8089          44 :     if(nObs > 0){
    8090           0 :       for(uInt outrn = 0; outrn < nObs; ++outrn)
    8091           0 :         TableCopy::copyRows(newObs, oldObs, outrn, selObsId_p[outrn], 1);
    8092             :     }
    8093             :     else  // '' -> '*'
    8094          44 :       TableCopy::copyRows(newObs, oldObs);
    8095             :       
    8096             :     //W TableCopy::deepCopy(newObs, oldObs, false);
    8097             :     
    8098          44 :     return true;
    8099          44 :   }
    8100             :   
    8101          44 :   Bool SubMS::copyProcessor()
    8102             :   {  
    8103          44 :     const MSProcessor& oldProc = mssel_p.processor();
    8104          44 :     MSProcessor& newProc = msOut_p.processor();
    8105             : 
    8106          44 :     TableCopy::copyRows(newProc, oldProc);
    8107             :     //W TableCopy::deepCopy(newProc, oldProc, false);
    8108             :     
    8109          44 :     return true;
    8110             :   }
    8111             : 
    8112          44 : Bool SubMS::copyState()
    8113             : {  
    8114             :   // STATE is allowed to not exist, even though it is not optional in the MS
    8115             :   // def'n.  For one thing, split dropped it for quite a while.
    8116          44 :   if(Table::isReadable(mssel_p.stateTableName())){
    8117          88 :     LogIO os(LogOrigin("SubMS", "copyState()"));
    8118          44 :     const MSState& oldState = mssel_p.state();
    8119             : 
    8120          44 :     if(oldState.nrow() > 0){
    8121           5 :       MSState& newState = msOut_p.state();
    8122           5 :       const MSStateColumns oldStateCols(oldState);
    8123           5 :       MSStateColumns newStateCols(newState);
    8124             : 
    8125             :       // Initialize stateRemapper_p if necessary.
    8126           5 :       if(stateRemapper_p.size() < 1)
    8127           5 :         make_map(stateRemapper_p, mscIn_p->stateId().getColumn());
    8128             : 
    8129           5 :       uInt nStates = stateRemapper_p.size();
    8130             :       
    8131             :       // stateRemapper_p goes from input to output, as is wanted in most
    8132             :       // places.  Here we need a map going the other way, so make one.
    8133           5 :       Vector<Int> outStateToInState(nStates);
    8134           5 :       std::map<Int, Int>::iterator mit;
    8135             :       
    8136          14 :       for(mit = stateRemapper_p.begin(); mit != stateRemapper_p.end(); ++mit)
    8137           9 :         outStateToInState[(*mit).second] = (*mit).first;
    8138             :       
    8139          14 :       for(uInt outrn = 0; outrn < nStates; ++outrn)
    8140           9 :         TableCopy::copyRows(newState, oldState, outrn,
    8141           9 :                             outStateToInState[outrn], 1);
    8142           5 :     }
    8143          44 :   }
    8144          44 :   return true;
    8145             : }
    8146             : 
    8147         122 : void SubMS::createSubtables(MeasurementSet& ms, Table::TableOption option)
    8148             : {
    8149           0 :   SetupNewTable antennaSetup(ms.antennaTableName(),
    8150         122 :                              MSAntenna::requiredTableDesc(),option);
    8151         244 :   ms.rwKeywordSet().defineTable(MS::keywordName(MS::ANTENNA),
    8152         244 :                              Table(antennaSetup));
    8153           0 :   SetupNewTable dataDescSetup(ms.dataDescriptionTableName(),
    8154         122 :                               MSDataDescription::requiredTableDesc(),option);
    8155         244 :   ms.rwKeywordSet().defineTable(MS::keywordName(MS::DATA_DESCRIPTION), 
    8156         244 :                              Table(dataDescSetup));
    8157           0 :   SetupNewTable feedSetup(ms.feedTableName(),
    8158         122 :                           MSFeed::requiredTableDesc(),option);
    8159         122 :   ms.rwKeywordSet().defineTable(MS::keywordName(MS::FEED), Table(feedSetup));
    8160           0 :   SetupNewTable flagCmdSetup(ms.flagCmdTableName(),
    8161         122 :                              MSFlagCmd::requiredTableDesc(),option);
    8162         244 :   ms.rwKeywordSet().defineTable(MS::keywordName(MS::FLAG_CMD), 
    8163         244 :                              Table(flagCmdSetup));
    8164           0 :   SetupNewTable fieldSetup(ms.fieldTableName(),
    8165         122 :                            MSField::requiredTableDesc(),option);
    8166         122 :   ms.rwKeywordSet().defineTable(MS::keywordName(MS::FIELD), Table(fieldSetup));
    8167           0 :   SetupNewTable historySetup(ms.historyTableName(),
    8168         122 :                              MSHistory::requiredTableDesc(),option);
    8169         244 :   ms.rwKeywordSet().defineTable(MS::keywordName(MS::HISTORY), 
    8170         244 :                              Table(historySetup));
    8171           0 :   SetupNewTable observationSetup(ms.observationTableName(),
    8172         122 :                                  MSObservation::requiredTableDesc(),option);
    8173         244 :   ms.rwKeywordSet().defineTable(MS::keywordName(MS::OBSERVATION), 
    8174         244 :                                 Table(observationSetup));
    8175           0 :   SetupNewTable polarizationSetup(ms.polarizationTableName(),
    8176         122 :                                   MSPolarization::requiredTableDesc(),option);
    8177         244 :   ms.rwKeywordSet().defineTable(MS::keywordName(MS::POLARIZATION),
    8178         244 :                                 Table(polarizationSetup));
    8179           0 :   SetupNewTable processorSetup(ms.processorTableName(),
    8180         122 :                                MSProcessor::requiredTableDesc(),option);
    8181         244 :   ms.rwKeywordSet().defineTable(MS::keywordName(MS::PROCESSOR),
    8182         244 :                                 Table(processorSetup));
    8183           0 :   SetupNewTable spectralWindowSetup(ms.spectralWindowTableName(),
    8184         122 :                                     MSSpectralWindow::requiredTableDesc(),option);
    8185         244 :   ms.rwKeywordSet().defineTable(MS::keywordName(MS::SPECTRAL_WINDOW),  
    8186         244 :                                 Table(spectralWindowSetup));
    8187           0 :   SetupNewTable stateSetup(ms.stateTableName(),
    8188         122 :                            MSState::requiredTableDesc(),option);
    8189         244 :   ms.rwKeywordSet().defineTable(MS::keywordName(MS::STATE),  
    8190         244 :                                 Table(stateSetup));
    8191             : 
    8192             :   // add the optional Source sub table to allow for specification of the rest
    8193             :   // frequency
    8194           0 :   SetupNewTable sourceSetup(ms.sourceTableName(), MSSource::requiredTableDesc(),
    8195         122 :                             option);
    8196         244 :   ms.rwKeywordSet().defineTable(MS::keywordName(MS::SOURCE),
    8197         244 :                                 Table(sourceSetup, 0));
    8198             : 
    8199             :   // update the references to the subtable keywords
    8200         122 :   ms.initRefs();
    8201         122 : }
    8202             :   
    8203          44 :   Bool SubMS::copyPointing(){
    8204          88 :     LogIO os(LogOrigin("SubMS", "copyPointing()"));
    8205             : 
    8206             :     //Pointing is allowed to not exist
    8207          44 :     if(Table::isReadable(mssel_p.pointingTableName())){
    8208             :       // An attempt to select from POINTING by timerange.  Fails because the
    8209             :       // TEN refers to the main table, not POINTING.
    8210             :       // TableExprNode condition;
    8211             : 
    8212             :       // if(timeRange_p != "" &&
    8213             :       //         msTimeGramParseCommand(&ms_p, timeRange_p, condition) == 0){
    8214             :       //        const TableExprNode *timeNode = 0x0;
    8215             :           
    8216             :       //        timeNode = msTimeGramParseNode();
    8217             :       //        if(timeNode && !timeNode->isNull())
    8218             :       //          condition = *timeNode;
    8219             :       // }
    8220             : 
    8221             :       //Wconst Table oldPoint(mssel_p.pointingTableName(), Table::Old);
    8222          44 :       const MSPointing& oldPoint = mssel_p.pointing();
    8223             : 
    8224          44 :       if(!antennaSel_p && timeRange_p == ""){
    8225          44 :         copySubtable(MS::keywordName(MS::POINTING), oldPoint);
    8226             :       }
    8227             :       else{
    8228           0 :         setupNewPointing();
    8229             : 
    8230           0 :         if(oldPoint.nrow() > 0){
    8231             :           // Could be declared as Table&
    8232           0 :           MSPointing& newPoint = msOut_p.pointing();
    8233             :           // Add optional columns if present in oldPoint.
    8234           0 :           uInt nAddedCols = addOptionalColumns(oldPoint, newPoint, true);
    8235             :           os << LogIO::DEBUG1 << "POINTING has " << nAddedCols
    8236           0 :              << " optional columns." << LogIO::POST;
    8237             :         
    8238             :           // W = Works, DW = Doesn't Work
    8239             :           //DW          msOut_p.pointing() = mssel_p.pointing();        
    8240             :           //DW          //TableCopy::copyInfo(newPoint, oldPoint);
    8241             :           //W   TableColumn newTC(newPoint, "DIRECTION");
    8242             :           //W   const ScalarColumn<MDirection> oldTC(oldPoint, "DIRECTION");
    8243             :           //W   const TableColumn oldTC(oldPoint, "DIRECTION");
    8244             :           //W   newTC.rwKeywordSet() = oldTC.keywordSet();
    8245             : 
    8246           0 :           const MSPointingColumns oldPCs(oldPoint);
    8247           0 :           MSPointingColumns newPCs(newPoint);
    8248           0 :           newPCs.setEpochRef(MEpoch::castType(oldPCs.timeMeas().getMeasRef().getType()));
    8249           0 :           newPCs.setDirectionRef(MDirection::castType(oldPCs.directionMeasCol().getMeasRef().getType()));
    8250           0 :           newPCs.setEncoderDirectionRef(MDirection::castType(oldPCs.encoderMeas().getMeasRef().getType()));
    8251             : 
    8252           0 :           const ScalarColumn<Int>& antIds  = oldPCs.antennaId();
    8253           0 :           const ScalarColumn<Double>& time = oldPCs.time();
    8254           0 :           ScalarColumn<Int>&       outants = newPCs.antennaId();
    8255             : 
    8256           0 :           uInt nTRanges = selTimeRanges_p.ncolumn();
    8257             : 
    8258           0 :           uInt outRow = 0;
    8259           0 :           Int maxSelAntp1 = antNewIndex_p.nelements();  // Int for comparison
    8260             :                                                         // with newAntInd.
    8261           0 :           for (uInt inRow = 0; inRow < antIds.nrow(); ++inRow){
    8262           0 :             Int newAntInd = antIds(inRow);
    8263           0 :             if(antennaSel_p)
    8264           0 :               newAntInd = newAntInd < maxSelAntp1 ? antNewIndex_p[newAntInd] : -1;
    8265           0 :             Double t = time(inRow);
    8266             :             
    8267           0 :             if(newAntInd > -1){
    8268           0 :               Bool matchT = false;
    8269           0 :               for(uInt tr = 0; tr < nTRanges; ++tr){
    8270           0 :                 if(t >= selTimeRanges_p(0, tr) && t <= selTimeRanges_p(1, tr)){
    8271           0 :                   matchT = true;
    8272           0 :                   break;
    8273             :                 }
    8274             :               }
    8275             :               
    8276           0 :               if(matchT){
    8277           0 :                 TableCopy::copyRows(newPoint, oldPoint, outRow, inRow, 1, false);
    8278           0 :                 outants.put(outRow, newAntInd);
    8279           0 :                 ++outRow;
    8280             :               }
    8281             :             }
    8282             :           }
    8283           0 :         }
    8284             :       }
    8285             :     }
    8286             :     else
    8287           0 :       setupNewPointing();       // Make an empty stub for MSColumns.
    8288             : 
    8289          44 :     return true;
    8290          44 :   }
    8291             : 
    8292           0 : void SubMS::setupNewPointing()
    8293             : {
    8294           0 :   SetupNewTable pointingSetup(msOut_p.pointingTableName(),
    8295           0 :                               MSPointing::requiredTableDesc(), Table::New);
    8296             :   // POINTING can be large, set some sensible defaults for storageMgrs
    8297           0 :   IncrementalStMan ismPointing ("ISMPointing");
    8298           0 :   StandardStMan ssmPointing("SSMPointing", 32768);
    8299           0 :   pointingSetup.bindAll(ismPointing, true);
    8300           0 :   pointingSetup.bindColumn(MSPointing::columnName(MSPointing::DIRECTION),
    8301             :                            ssmPointing);
    8302           0 :   pointingSetup.bindColumn(MSPointing::columnName(MSPointing::TARGET),
    8303             :                            ssmPointing);
    8304           0 :   pointingSetup.bindColumn(MSPointing::columnName(MSPointing::TIME),
    8305             :                            ssmPointing);
    8306           0 :   msOut_p.rwKeywordSet().defineTable(MS::keywordName(MS::POINTING),
    8307           0 :                                      Table(pointingSetup));
    8308           0 :   msOut_p.initRefs();
    8309           0 : }
    8310             :   
    8311          44 :   Bool SubMS::copyWeather(){
    8312             :     // Weather is allowed to not exist.
    8313          44 :     if(Table::isReadable(mssel_p.weatherTableName())){
    8314           5 :       const MSWeather& oldWeath = mssel_p.weather();
    8315             : 
    8316           5 :       if(oldWeath.nrow() > 0){
    8317             :         // Add a WEATHER subtable to msOut_p with 0 rows for now.
    8318           5 :         Table::TableOption option = Table::New;
    8319           5 :         TableDesc weatherTD = MSWeather::requiredTableDesc();
    8320           5 :         SetupNewTable weatherSetup(msOut_p.weatherTableName(), weatherTD,
    8321          10 :                                    option);
    8322          10 :         msOut_p.rwKeywordSet().defineTable(MS::keywordName(MS::WEATHER),
    8323          10 :                                            Table(weatherSetup,0));
    8324             :         // update the references to the subtable keywords
    8325           5 :         msOut_p.initRefs();
    8326             : 
    8327           5 :         MSWeather& newWeath = msOut_p.weather();  // Could be declared as
    8328             :                                                   // Table&
    8329             : 
    8330          10 :         LogIO os(LogOrigin("SubMS", "copyWeather()"));
    8331             : 
    8332           5 :         uInt nAddedCols = addOptionalColumns(oldWeath, newWeath, true);
    8333             :         os << LogIO::DEBUG1 << "WEATHER has " << nAddedCols
    8334           5 :            << " optional columns." << LogIO::POST;
    8335             :         
    8336           5 :         const MSWeatherColumns oldWCs(oldWeath);
    8337           5 :         MSWeatherColumns newWCs(newWeath);
    8338           5 :         newWCs.setEpochRef(MEpoch::castType(oldWCs.timeMeas().getMeasRef().getType()));
    8339             :         
    8340           5 :         if(!antennaSel_p){
    8341           5 :           TableCopy::copyRows(newWeath, oldWeath);
    8342             :         }
    8343             :         else{
    8344           0 :           const Vector<Int>& antIds(oldWCs.antennaId().getColumn());
    8345           0 :           ScalarColumn<Int>& outants = newWCs.antennaId();
    8346             : 
    8347           0 :           uInt selRow = 0;
    8348           0 :           Int maxSelAntp1 = antNewIndex_p.nelements();
    8349             : 
    8350           0 :           for(uInt k = 0; k < antIds.nelements(); ++k){          
    8351           0 :             if(antIds[k] > -1){         // Weather station is on antenna?
    8352           0 :               if(antIds[k] < maxSelAntp1){
    8353           0 :                 Int newAntInd = antNewIndex_p[antIds[k]]; // remap ant num
    8354             :               
    8355           0 :                 if(newAntInd > -1){                       // Ant selected?
    8356           0 :                   TableCopy::copyRows(newWeath, oldWeath, selRow, k, 1);
    8357           0 :                   outants.put(selRow, newAntInd);
    8358           0 :                   ++selRow;
    8359             :                 }
    8360             :               }
    8361             :             }
    8362             :             else{
    8363           0 :               TableCopy::copyRows(newWeath, oldWeath, selRow, k, 1);
    8364           0 :               outants.put(selRow, -1);  // means valid for all antennas.
    8365           0 :               ++selRow;
    8366             :             }
    8367             :           }
    8368           0 :         }
    8369           5 :       }
    8370             :     }
    8371          44 :     return true;
    8372             :   }
    8373             : 
    8374          44 : Bool SubMS::copySyscal()
    8375             : {
    8376             :   // SYSCAL is allowed to not exist.
    8377          44 :   if(Table::isReadable(mssel_p.sysCalTableName())){
    8378           5 :     const MSSysCal& oldSysc = mssel_p.sysCal();
    8379             : 
    8380           5 :     if(oldSysc.nrow() > 0){
    8381             :       // Add a SYSCAL subtable to msOut_p with 0 rows for now.
    8382           1 :       Table::TableOption option = Table::New;
    8383           1 :       TableDesc sysCalTD = MSSysCal::requiredTableDesc();
    8384           1 :       SetupNewTable sysCalSetup(msOut_p.sysCalTableName(), sysCalTD,
    8385           2 :                                 option);
    8386           2 :       msOut_p.rwKeywordSet().defineTable(MS::keywordName(MS::SYSCAL),
    8387           2 :                                          Table(sysCalSetup, 0));
    8388             :       // update the references to the subtable keywords
    8389           1 :       msOut_p.initRefs();
    8390             : 
    8391             :       // Could be declared as Table&.
    8392           1 :       MSSysCal& newSysc = msOut_p.sysCal();
    8393             : 
    8394           2 :       LogIO os(LogOrigin("SubMS", "copySysCal()"));
    8395             : 
    8396           1 :       uInt nAddedCols = addOptionalColumns(oldSysc, newSysc, true);
    8397             :       os << LogIO::DEBUG1 << "SYSCAL has " << nAddedCols
    8398           1 :          << " optional columns." << LogIO::POST;
    8399             :         
    8400           1 :       const MSSysCalColumns incols(oldSysc);
    8401           1 :       MSSysCalColumns outcols(newSysc);
    8402           1 :       outcols.setEpochRef(MEpoch::castType(incols.timeMeas().getMeasRef().getType()));
    8403             :         
    8404           1 :       if(!antennaSel_p && allEQ(spwRelabel_p, spw_p)){
    8405           0 :         TableCopy::copyRows(newSysc, oldSysc);
    8406             :       }
    8407             :       else{
    8408           1 :         const Vector<Int>& antIds = incols.antennaId().getColumn();
    8409           1 :         const Vector<Int>& spwIds = incols.spectralWindowId().getColumn();
    8410             : 
    8411             :         // Copy selected rows.
    8412           1 :         uInt totNSyscals = antIds.nelements();
    8413           1 :         uInt totalSelSyscals = 0;
    8414           1 :         Int maxSelAntp1 = antNewIndex_p.nelements(); // Int for comparison with antIds.
    8415         121 :         for(uInt k = 0; k < totNSyscals; ++k){
    8416             :           // antenna must be selected, and spwId must be -1 (any) or selected.
    8417         240 :           if(antIds[k] < maxSelAntp1 && antNewIndex_p[antIds[k]] > -1 &&
    8418         120 :              (spwIds[k] < 0 || spwRelabel_p[spwIds[k]] > -1)){
    8419             :             //                  outtab   intab    outrow       inrow nrows
    8420           0 :             TableCopy::copyRows(newSysc, oldSysc, totalSelSyscals, k, 1, false);
    8421           0 :             ++totalSelSyscals;
    8422             :           }
    8423             :         }
    8424             : 
    8425             :         // Remap antenna and spw #s.
    8426           1 :         ScalarColumn<Int>& antCol = outcols.antennaId();
    8427           1 :         ScalarColumn<Int>& spwCol = outcols.spectralWindowId();
    8428             : 
    8429           1 :         for(uInt k = 0; k < totalSelSyscals; ++k){
    8430           0 :           antCol.put(k, antNewIndex_p[antCol(k)]);
    8431           0 :           if(spwCol(k) > -1)
    8432           0 :             spwCol.put(k, spwRelabel_p[spwCol(k)]);
    8433             :         }
    8434           1 :       }
    8435           1 :     }
    8436             :   }
    8437          44 :   return true;
    8438             : }
    8439             : 
    8440          46 : void SubMS::copySubtable(const String& tabName, const Table& inTab,
    8441             :                          const Bool doFilter)
    8442             : {
    8443          46 :   String outName(msOut_p.tableName() + '/' + tabName);
    8444             : 
    8445          46 :   if(PlainTable::tableCache()(outName))
    8446           0 :     PlainTable::tableCache().remove(outName);
    8447          46 :   inTab.deepCopy(outName, Table::New, false, Table::AipsrcEndian,
    8448             :                  doFilter);
    8449          46 :   Table outTab(outName, Table::Update);
    8450          46 :   msOut_p.rwKeywordSet().defineTable(tabName, outTab);
    8451          46 :   msOut_p.initRefs();
    8452          46 : }
    8453             : 
    8454          88 : Bool SubMS::filterOptSubtable(const String& subtabname)
    8455             : {
    8456         176 :   LogIO os(LogOrigin("SubMS", "filterOptSubtable()"));
    8457             : 
    8458             :   // subtabname is allowed to not exist.  Use ms_p instead of mssel_p, because
    8459             :   // the latter has a random name which does NOT necessarily lead to
    8460             :   // subtabname.  (And if selection took care of subtables, we probably
    8461             :   // wouldn't have to do it here.)
    8462          88 :   if(Table::isReadable(ms_p.tableName() + '/' + subtabname)){
    8463           8 :     const Table intab(ms_p.tableName() + '/' + subtabname);
    8464             : 
    8465           4 :     if(intab.nrow() > 0){
    8466             :       // Add feed if selecting by it is ever added.
    8467           2 :       Bool doFilter = antennaSel_p || !allEQ(spwRelabel_p, spw_p);
    8468             : 
    8469           2 :       copySubtable(subtabname, intab, doFilter);
    8470             : 
    8471           2 :       if(doFilter){
    8472             :         // At this point msOut_p has subtab with 0 rows.
    8473           4 :         Table outtab(msOut_p.tableName() + '/' + subtabname, Table::Update);
    8474             : 
    8475           2 :         ScalarColumn<Int> inAntIdCol(intab, "ANTENNA_ID");         // + FEED_ID if it
    8476           2 :         ScalarColumn<Int> inSpwIdCol(intab, "SPECTRAL_WINDOW_ID"); // ever changed.
    8477           2 :         const Vector<Int>& antIds = inAntIdCol.getColumn();
    8478           2 :         const Vector<Int>& spwIds = inSpwIdCol.getColumn();
    8479             : 
    8480             :         // Copy selected rows.
    8481           2 :         uInt totNOuttabs = antIds.nelements();
    8482           2 :         uInt totalSelOuttabs = 0;
    8483           2 :         Int maxSelAntp1 = antNewIndex_p.nelements(); // Int for comparison with
    8484             :                                                      // antIds.
    8485           2 :         Bool haveRemappingProblem = false;
    8486         786 :         for(uInt inrow = 0; inrow < totNOuttabs; ++inrow){
    8487             :           // antenna must be selected, and spwId must be -1 (any) or selected.
    8488             :           // Extra care must be taken because for a while MSes had CALDEVICE
    8489             :           // and SYSPOWER, but the ANTENNA_ID and SPECTRAL_WINDOW_ID of those
    8490             :           // subtables were not being remapped by split.
    8491         784 :           if(antIds[inrow] < maxSelAntp1 && antNewIndex_p[antIds[inrow]] > -1){
    8492             :             
    8493        2352 :             if(spwIds[inrow] < 0 || (spwIds[inrow] <
    8494         784 :                                      static_cast<Int>(spwRelabel_p.nelements()) &&
    8495         784 :                                      spwRelabel_p[spwIds[inrow]] > -1)){
    8496         136 :               TableCopy::copyRows(outtab, intab, totalSelOuttabs, inrow, 1, false);
    8497         136 :               ++totalSelOuttabs;
    8498             :             }
    8499             :             // Ideally we'd like to catch antenna errors too.  They are
    8500             :             // avoided, but because of the way antNewIndex_p is made, 
    8501             :             // antIds[inrow] >= maxSelAntp1
    8502             :             // is not necessarily an error.  It's not even possible to catch
    8503             :             // all the spw errors, so we settle for catching the ones we can
    8504             :             // and reliably avoiding segfaults.
    8505         648 :             else if(spwIds[inrow] >= static_cast<Int>(spwRelabel_p.nelements()))
    8506           0 :               haveRemappingProblem = true;
    8507             :           }
    8508             :         }
    8509             : 
    8510           2 :         if(haveRemappingProblem)
    8511             :           os << LogIO::WARN
    8512             :              << "At least one row of " << intab.tableName()
    8513             :              << " has an antenna or spw mismatch.\n"
    8514             :              << "(Presumably from an older split, sorry.)\n"
    8515             :              << "If " << subtabname
    8516             :              << " is important, it should be fixed with tb or browsetable,\n"
    8517             :              << "or by redoing the split that made " << ms_p.tableName()
    8518             :              << " (check its history)."
    8519           0 :              << LogIO::POST;
    8520             : 
    8521             :         // Remap antenna and spw #s.
    8522           2 :         ScalarColumn<Int> outAntCol(outtab, "ANTENNA_ID");
    8523           2 :         ScalarColumn<Int> outSpwCol(outtab, "SPECTRAL_WINDOW_ID");
    8524             : 
    8525         138 :         for(uInt k = 0; k < totalSelOuttabs; ++k){
    8526         136 :           outAntCol.put(k, antNewIndex_p[outAntCol(k)]);
    8527         136 :           if(outSpwCol(k) > -1)
    8528         136 :             outSpwCol.put(k, spwRelabel_p[outSpwCol(k)]);
    8529             :         }
    8530           2 :       }
    8531             :     }
    8532           4 :   }
    8533          88 :   return true;
    8534          88 : }
    8535             : 
    8536             : // writeDiffSpwShape() was the VisIter-using channel averager, which sounds
    8537             : // great, but:
    8538             : // 0. If VisIter's sort order is different from the one in the MS, then if you
    8539             : //    write _any_ columns using VisIter-fetched data, then you must write _all_ of
    8540             : //    them.  This is crucially important for channel averaging in split: normally
    8541             : //    only *DATA, FLAG*, WEIGHT, and SIGMA would have to be updated, but if using
    8542             : //    VisIter, the ANTENNA*, FEED*, STATE_ID, etc. have to be updated too because
    8543             : //    they could be rearranged.
    8544             : //
    8545             : //    There does not appear to be an easy way of getting the MS's starting sort
    8546             : //    order, i.e. AFAIK it is not written into a header.
    8547             : //
    8548             : // 1. If FLOAT_DATA is present, VisIter will ignore DATA.  (G. Moellenbrock,
    8549             : //    =casa-staff, 1/15/2010)
    8550             : 
    8551           3 : Bool SubMS::doChannelMods(const Vector<MS::PredefinedColumns>& datacols)
    8552             : {
    8553           6 :   LogIO os(LogOrigin("SubMS", "doChannelMods()"));
    8554             : 
    8555           3 :   Vector<MS::PredefinedColumns> cmplxColLabels;
    8556           3 :   const Bool doFloat = sepFloat(datacols, cmplxColLabels);
    8557           3 :   const uInt nCmplx = cmplxColLabels.nelements();
    8558           3 :   if(doFloat && nCmplx > 0)           // 2010-12-14
    8559             :     os << LogIO::WARN
    8560             :        << "Using VisIter to average both FLOAT_DATA and another DATA column is extremely experimental."
    8561           0 :        << LogIO::POST;
    8562             : 
    8563             :   //ArrayColumn<Complex> outCmplxCols[nCmplx];
    8564             :   //outDataColMap(outCmplxCols, nCmplx, cmplxColLabels);
    8565           3 :   const Bool writeToData = mustConvertToData(nCmplx, cmplxColLabels);
    8566             : 
    8567             :   // Is CORRECTED_DATA being moved to DATA?
    8568           3 :   Bool fromCorrToData = writeToData && nCmplx == 1;
    8569           3 :   if(fromCorrToData)
    8570           0 :     fromCorrToData = cmplxColLabels[0] == MS::CORRECTED_DATA;
    8571             :   
    8572           3 :   Vector<Int> spwindex(max(spw_p) + 1);
    8573           3 :   spwindex.set(-1);
    8574           9 :   for(uInt k = 0; k < spw_p.nelements(); ++k)
    8575           6 :     spwindex[spw_p[k]] = k;
    8576             : 
    8577           3 :   Block<Int> columns;
    8578             :   // include scan and state iteration, for more optimal iteration
    8579           3 :   columns.resize(6);
    8580           3 :   columns[0]=MS::ARRAY_ID;
    8581           3 :   columns[1]=MS::SCAN_NUMBER;
    8582           3 :   columns[2]=MS::STATE_ID;
    8583           3 :   columns[3]=MS::FIELD_ID;
    8584           3 :   columns[4]=MS::DATA_DESC_ID;
    8585           3 :   columns[5]=MS::TIME;
    8586             : 
    8587             : #ifdef COPYTIMER
    8588             :   Timer timer;
    8589             :   timer.mark();
    8590             : 
    8591             :   Vector<Int> inscan, outscan;
    8592             : #endif  
    8593             : 
    8594           3 :   ROVisIterator viIn(mssel_p, columns, 0.0);
    8595             :   //ROVisibilityIterator viIn(mssel_p, columns, 0.0);
    8596           3 :   VisIter viOut(msOut_p,columns,0.0);
    8597             : 
    8598           3 :   viIn.setRowBlocking(1000);
    8599           3 :   viOut.setRowBlocking(1000);
    8600             :   //viIn.slurp();
    8601             :   //cerr << "Finished slurping." << endl;
    8602             : 
    8603             :   // Translate chanSlices_p into the form vb.channelAve() wants.
    8604           3 :   Vector<Matrix<Int> > chanAveBounds;
    8605           3 :   viIn.slicesToMatrices(chanAveBounds, chanSlices_p, widths_p);
    8606             : 
    8607             :   // // If we don't want to skip every (width - 1) out of width channels,
    8608             :   // // the increments in chanSlices_p must be set to 1.
    8609             :   // if(averageChannel_p){
    8610             :   //   for(uInt spwind = 0; spwind < chanSlices_p.nelements(); ++spwind){
    8611             :   //     Vector<Slice>& spwsls = chanSlices_p[spwind];
    8612             : 
    8613             :   //     for(uInt slnum = 0; slnum < spwsls.nelements(); ++slnum){
    8614             :   //       Slice& sl = spwsls[slnum];
    8615             : 
    8616             :   //       spwsls[slnum] = Slice(sl.start(), sl.length());
    8617             :   //     }
    8618             :   //   }
    8619             :   // }
    8620             : 
    8621             :   // Apply selection
    8622             :   // for(uInt spwind = 0; spwind < spw_p.nelements(); ++spwind)
    8623             :   //   viOut.selectChannel(1, chanStart_p[spwind], nchan_p[spwind],
    8624             :   //                       chanStep_p[spwind], spw_p[spwind]);
    8625           3 :   viIn.selectChannel(chanSlices_p);     // ROVisIterator
    8626           3 :   viIn.selectCorrelation(corrSlices_p);
    8627             :   
    8628           3 :   viIn.originChunks();                                // Makes me feel better.
    8629             : 
    8630           3 :   const Bool doSpWeight = viIn.existsWeightSpectrum();
    8631             : 
    8632           3 :   Bool doFC = existsFlagCategory();
    8633           3 :   uInt rowsdone = 0;
    8634           3 :   ProgressMeter meter(0.0, mssel_p.nrow() * 1.0, "split", "rows averaged", "", "",
    8635           9 :                       true, 1);
    8636           3 :   Cube<Complex> vis;
    8637           3 :   Cube<Float> floatvis;
    8638           3 :   VisBuffer vb(viIn);
    8639           3 :   Matrix<Float> wtmat;
    8640             : 
    8641           3 :   for(viOut.originChunks(), viIn.originChunks();
    8642          15 :       viOut.moreChunks(), viIn.moreChunks();
    8643          12 :       viOut.nextChunk(), viIn.nextChunk()){
    8644          24 :     for(viIn.origin(),viOut.origin(); viIn.more(),viOut.more();
    8645          12 :         ++viIn, ++viOut){
    8646          12 :       uInt rowsnow = vb.nRow();
    8647             : 
    8648          12 :       if(rowsnow > 0){
    8649             :         //RefRows rr(rowsdone, rowsdone + rowsnow - 1);
    8650             : 
    8651             :         // Preload the things that need to be channel averaged.
    8652          48 :         for(uInt colind = 0; colind < nCmplx; ++colind){
    8653          36 :           if(cmplxColLabels[colind] == MS::DATA)
    8654          12 :             vb.visCube();
    8655          24 :           else if(cmplxColLabels[colind] == MS::MODEL_DATA)
    8656          12 :             vb.modelVisCube();
    8657          12 :           else if(cmplxColLabels[colind] == MS::CORRECTED_DATA)
    8658          12 :             vb.correctedVisCube();
    8659             :         }
    8660          12 :         if(doFloat)
    8661           0 :           vb.floatDataCube();
    8662             : 
    8663             :         // The flags and weights are already loaded by this point, UNLESS the
    8664             :         // row flag was true for all the rows.  Make sure they're loaded, or
    8665             :         // they could end up with the wrong shape.
    8666          12 :         vb.flagCube();
    8667             :         // if(viIn.existsWeightSpectrum())
    8668             :         //   vb.weightSpectrum();
    8669             :         // vb.weightMat();
    8670          12 :         if(doFC)
    8671           0 :           vb.flagCategory();
    8672             :       
    8673          12 :         vb.channelAve(chanAveBounds[viIn.spectralWindow()],false);
    8674             : 
    8675          12 :         if(nCmplx > 0){
    8676          12 :           if(vb.flagCube().shape() !=
    8677          12 :              vb.dataCube(cmplxColLabels[0]).shape())
    8678           0 :             throw(AipsError("Shape error after channel averaging!"));
    8679             :         }
    8680           0 :         else if(doFloat){
    8681           0 :           if(vb.flagCube().shape() != vb.floatDataCube().shape())
    8682           0 :             throw(AipsError("Shape error after channel averaging!"));
    8683             :         }
    8684             :         // else  we aren't doing anything, it seems.
    8685             : 
    8686             :         // Write the output.
    8687          48 :         for(uInt colind = 0; colind < nCmplx; ++colind){
    8688          36 :           if(cmplxColLabels[colind] == MS::DATA)
    8689          12 :             viOut.setVis(vb.visCube(), VisibilityIterator::Observed);
    8690          24 :           else if(cmplxColLabels[colind] == MS::MODEL_DATA)
    8691          12 :             viOut.setVis(vb.modelVisCube(),
    8692             :                          writeToData ? VisibilityIterator::Observed :
    8693             :                                        VisibilityIterator::Model);
    8694          12 :           else if(cmplxColLabels[colind] == MS::CORRECTED_DATA)
    8695          12 :             viOut.setVis(vb.correctedVisCube(),
    8696             :                          writeToData ? VisibilityIterator::Observed :
    8697             :                                        VisibilityIterator::Corrected);
    8698             :         }
    8699             :         //if(doFloat)
    8700             :         //  viOut.setFloatData(vb.floatDataCube());    TBD!
    8701          12 :         viOut.setFlag(vb.flagCube());
    8702          12 :         if(doFC)
    8703           0 :           viOut.setFlagCategory(vb.flagCategory());
    8704             : 
    8705             : 
    8706          12 :         if(doSpWeight)
    8707           0 :           viOut.setWeightSpectrum(vb.weightSpectrum());
    8708             : 
    8709             : 
    8710          12 :         if(fromCorrToData) {
    8711           0 :           wtmat.reference(vb.weightMat());
    8712           0 :           viOut.setWeightMat(wtmat);
    8713           0 :           arrayTransformInPlace(wtmat, subms::wtToSigma);   // for corrected weights.
    8714           0 :           viOut.setSigmaMat(wtmat);
    8715             :         }
    8716             :         else {
    8717          12 :           wtmat.reference(vb.sigmaMat());           // Yes, I'm reusing wtmat.
    8718          12 :           viOut.setSigmaMat(wtmat);
    8719          12 :           arrayTransformInPlace(wtmat, subms::sigToWeight);   // for corrected weights.
    8720          12 :           viOut.setWeightMat(wtmat);
    8721             :         }
    8722             : 
    8723          12 :         rowsdone += rowsnow;
    8724             :       }
    8725             :     }
    8726          12 :     meter.update(rowsdone);
    8727             :   }   // End of for(viIn.originChunks(); viIn.moreChunks(); viIn.nextChunk())
    8728           3 :   os << LogIO::NORMAL << "Data binned." << LogIO::POST;
    8729             : 
    8730             :   //const ColumnDescSet& cds = mssel_p.tableDesc().columnDescSet();
    8731             :   //const ColumnDesc& cdesc = cds[MS::columnName(MS::DATA)];
    8732             :   //ROTiledStManAccessor tacc(mssel_p, cdesc.dataManagerGroup());
    8733             :   //tacc.showCacheStatistics(cerr);  // A 99.x% hit rate is good.  0% is bad.
    8734             : 
    8735             :   os << LogIO::DEBUG1 // helpdesk ticket in from Oleg Smirnov (ODU-232630)
    8736           6 :      << "Post binning memory: " << Memory::allocatedMemoryInBytes() / (1024.0 * 1024.0) << " MB"
    8737           3 :      << LogIO::POST;
    8738             : 
    8739           3 :   return true;
    8740           3 : }
    8741             : 
    8742             : // // Sets mapper to the distinct values of mscol, in increasing order.
    8743             : // // A static method that is used by SubMS, but doesn't necessarily have to go
    8744             : // // with it.  It may belong in something more MSColumnsish.
    8745             : // void SubMS::make_map(const Vector<Int>& mscol, Vector<Int>& mapper)
    8746             : // {
    8747             : //   std::set<Int> valSet;
    8748             :   
    8749             : //   for(Int i = mscol.nelements(); i--;)  // Strange, but slightly more
    8750             : //     valSet.insert(mscol[i]);            // efficient than going forward.
    8751             : //   mapper.resize(valSet.size());
    8752             : 
    8753             : //   uInt remaval = 0;
    8754             : //   for(std::set<Int>::const_iterator vs_iter = valSet.begin();
    8755             : //       vs_iter != valSet.end(); ++vs_iter){
    8756             : //     mapper[remaval] = *vs_iter;
    8757             : //     ++remaval;
    8758             : //   }
    8759             : // }
    8760             : 
    8761          93 : void SubMS::make_map(std::map<Int, Int>& mapper, const Vector<Int>& inv)
    8762             : {
    8763          93 :   std::set<Int> valSet;
    8764             :   
    8765      868889 :   for(Int i = inv.nelements(); i--;)  // Strange, but slightly more
    8766      868796 :     valSet.insert(inv[i]);         // efficient than going forward.
    8767             : 
    8768          93 :   uInt remaval = 0;
    8769          93 :   for(std::set<Int>::const_iterator vs_iter = valSet.begin();
    8770         150 :       vs_iter != valSet.end(); ++vs_iter){
    8771          57 :     mapper[*vs_iter] = remaval;
    8772          57 :     ++remaval;
    8773             :   }
    8774          93 : }
    8775             : 
    8776           0 : void SubMS::make_map2(std::map<Int, Int>& mapper, const Vector<Int>& inv)
    8777             : {
    8778           0 :   LogIO os(LogOrigin("SubMS", "make_map2()"));
    8779             :   // This method assumes the int vector contains mapping scheme already
    8780             :   // if inv[i] is not selected one => -1 so should be skipped
    8781             :   // ith vector element is mapped value of index i
    8782             :   // Created for remapping of field Ids with fieldRelable_p (TT 2012.07.27)
    8783           0 :   for(Vector<Int>::const_iterator vs_iter = inv.begin();
    8784           0 :      vs_iter != inv.end(); ++vs_iter){
    8785           0 :     if (*vs_iter!=-1) {
    8786           0 :       Int dist=std::distance(inv.begin(),vs_iter);
    8787           0 :       mapper.insert(std::make_pair(dist, *vs_iter));
    8788             :       os << LogIO::DEBUG1
    8789           0 :          << " *vs_iter="<< *vs_iter
    8790             :          << " index="<< dist 
    8791           0 :          << LogIO::POST;
    8792             :     }
    8793           0 :   }
    8794           0 : }
    8795             :   //
    8796             : 
    8797           0 : void SubMS::remap(Vector<Int>& col, const Vector<Int>& mapper)
    8798             : {
    8799           0 :   if(mapper.nelements() > 0)
    8800           0 :     for(Int row = col.nelements(); row--;)
    8801           0 :       col[row] = mapper[col[row]];
    8802           0 : }
    8803             : 
    8804           0 : void SubMS::remap(Vector<Int>& col, const std::map<Int, Int>& mapper)
    8805             : {
    8806           0 :   if(mapper.size() > 0)
    8807           0 :     for(Int row = col.nelements(); row--;)
    8808           0 :       col[row] = mapper.find(col[row])->second;
    8809           0 : }
    8810             : 
    8811             : // Returns rv s.t. mapper[rv] == ov, assuming that mapper[i + 1] >= mapper[i]
    8812             : // for 0 <= i < mapper.nelements() - 1.
    8813             : // i can be supplied as the first guess.
    8814           0 : uInt SubMS::remapped(const Int ov, const Vector<Int>& mapper, uInt i=0)
    8815             : {
    8816           0 :   uInt nvals = mapper.nelements();
    8817           0 :   uInt nvalsm1 = nvals - 1;
    8818             : 
    8819           0 :   if(i >= nvals)     // Second guess the guess.
    8820           0 :     i = nvals >> 1;
    8821             :   
    8822             :   // Do a widening search for the brackets, since i is probably close to the
    8823             :   // answer.
    8824           0 :   if(mapper[i] == ov)
    8825           0 :     return i;
    8826             :   
    8827           0 :   uInt inc = 1;
    8828           0 :   uInt lb = i;
    8829             :   uInt ub;
    8830           0 :   if(ov > mapper[lb]){       // Hunt up.
    8831           0 :     if(lb == nvalsm1)
    8832           0 :       return lb;
    8833           0 :     ub = lb + 1;
    8834           0 :     while(ov >= mapper[ub]){
    8835           0 :       lb = ub;
    8836           0 :       inc += inc;
    8837           0 :       ub = lb + inc;
    8838           0 :       if(ub > nvalsm1){
    8839           0 :         ub = nvals;
    8840           0 :         break;
    8841             :       }
    8842             :     }
    8843             :   }
    8844             :   else{                 // Hunt down.
    8845           0 :     ub = lb;
    8846           0 :     --lb;
    8847           0 :     while(ov < mapper[lb]){
    8848           0 :       ub = lb;
    8849           0 :       inc += inc;
    8850           0 :       if(inc >= ub){
    8851           0 :         lb = 0;
    8852           0 :         break;
    8853             :       }
    8854             :       else
    8855           0 :         lb = ub - inc;
    8856             :     }
    8857             :   }
    8858             :         
    8859           0 :   i = lb + ((ub - lb) >> 1);                      // (lb + ub) / 2 might overflow. 
    8860           0 :   while(mapper[i] != ov && ub - lb > 1){
    8861           0 :     if(mapper[i] < ov)
    8862           0 :       lb = i;
    8863             :     else
    8864           0 :       ub = i;
    8865           0 :     i = lb + ((ub - lb) >> 1);
    8866             :   }
    8867           0 :   return i;  
    8868             : }
    8869             : 
    8870           0 : uInt SubMS::fillAntIndexer(std::map<Int, Int>& antIndexer, const MSColumns *msc)
    8871             : {
    8872           0 :   const Vector<Int>& ant1 = msc->antenna1().getColumn();
    8873           0 :   const Vector<Int>& ant2 = msc->antenna2().getColumn();
    8874             : 
    8875           0 :   std::set<Int> ants;
    8876           0 :   for(Int i = ant1.nelements(); i--;){   // Strange, but slightly more
    8877           0 :     ants.insert(ant1[i]);                // efficient than going forward.
    8878           0 :     ants.insert(ant2[i]);
    8879             :   }
    8880           0 :   uInt nant = ants.size();
    8881             :   
    8882           0 :   Vector<Int> selAnt(nant);
    8883           0 :   Int remaval = 0;
    8884           0 :   for(std::set<Int>::const_iterator ant_iter = ants.begin();
    8885           0 :       ant_iter != ants.end(); ++ant_iter){
    8886           0 :     selAnt[remaval] = *ant_iter;
    8887           0 :     ++remaval;
    8888             :   }
    8889             :     
    8890           0 :   for(uInt j = 0; j < nant; ++j)
    8891           0 :     antIndexer[selAnt[j]] = static_cast<Int>(j);
    8892           0 :   return nant;
    8893           0 : }
    8894             : 
    8895           0 : const ArrayColumn<Complex>& SubMS::right_column(const MSColumns *msclala,
    8896             :                                                 const MS::PredefinedColumns col)
    8897             : {
    8898           0 :   if(col == MS::DATA)
    8899           0 :     return msclala->data();
    8900           0 :   else if(col == MS::MODEL_DATA)
    8901           0 :     return msclala->modelData();
    8902             :   //  else if(col == MS::FLOAT_DATA) // Not complex.
    8903             :   //  return msclala->floatData();
    8904           0 :   else if(col == MS::LAG_DATA)
    8905           0 :     return msclala->lagData();
    8906             :   else                                // The honored-by-time-if-nothing-else
    8907           0 :     return msclala->correctedData();  // default.
    8908             : }
    8909             : 
    8910           0 : ArrayColumn<Complex>& SubMS::right_column(MSColumns *msclala,
    8911             :                                           const MS::PredefinedColumns col,
    8912             :                                           const Bool writeToDataCol)
    8913             : {
    8914           0 :   if(writeToDataCol || col == MS::DATA)
    8915           0 :     return msclala->data();
    8916           0 :   else if(col == MS::MODEL_DATA)
    8917           0 :     return msclala->modelData();
    8918             :   //  else if(col == MS::FLOAT_DATA) // Not complex.
    8919             :   //  return msclala->floatData();
    8920           0 :   else if(col == MS::LAG_DATA)
    8921           0 :     return msclala->lagData();
    8922             :   else                                // The honored-by-time-if-nothing-else
    8923           0 :     return msclala->correctedData();  // default.
    8924             : }
    8925             : 
    8926          44 : Bool SubMS::sepFloat(const Vector<MS::PredefinedColumns>& anyDataCols,
    8927             :                      Vector<MS::PredefinedColumns>& complexDataCols)
    8928             : {
    8929             :   // Determine whether FLOAT_DATA is in anyDataCols[], and fill
    8930             :   // complexDataCols[] with the Complex members of anyDataCols[].
    8931          44 :   Bool doFloat = false;
    8932          44 :   uInt ntok = anyDataCols.nelements();
    8933             : 
    8934          44 :   complexDataCols.resize(ntok);
    8935          44 :   uInt j = 0;
    8936         109 :   for(uInt i = 0; i < ntok; ++i){
    8937          65 :     if(anyDataCols[i] != MS::FLOAT_DATA){
    8938          65 :       complexDataCols[j] = anyDataCols[i];
    8939          65 :       ++j;
    8940             :     }
    8941             :     else
    8942           0 :       doFloat = true;
    8943             :   }
    8944          44 :   if(doFloat)
    8945           0 :     complexDataCols.resize(j, true);
    8946          44 :   return doFloat;
    8947             : }
    8948             : 
    8949           0 : Bool SubMS::doTimeAver(const Vector<MS::PredefinedColumns>& dataColNames,
    8950             :                        const VBRemapper& remapper)
    8951             : {
    8952           0 :   LogIO os(LogOrigin("SubMS", "doTimeAver()"));
    8953             : 
    8954             :   //No channel averaging with time averaging ... it's better this way, but
    8955             :   //maybe that should be revisited with VisibilityIterator.
    8956           0 :   if(chanStep_p[0] > 1){
    8957           0 :     throw(AipsError("Simultaneous time and channel averaging is not handled."));
    8958             :     return false;
    8959             :   }
    8960             : 
    8961             :   os << LogIO::DEBUG1 // helpdesk ticket from Oleg Smirnov (ODU-232630)
    8962             :      << "Before msOut_p.addRow(): "
    8963           0 :      << Memory::allocatedMemoryInBytes() / (1024.0 * 1024.0) << " MB"
    8964           0 :      << LogIO::POST;
    8965             : 
    8966           0 :   Vector<MS::PredefinedColumns> cmplxColLabels;
    8967           0 :   const Bool doFloat = sepFloat(dataColNames, cmplxColLabels);
    8968           0 :   const uInt nCmplx = cmplxColLabels.nelements();
    8969           0 :   if(doFloat && cmplxColLabels.nelements() > 0)           // 2010-12-14
    8970             :     os << LogIO::WARN
    8971             :        << "Using VisibilityIterator to average both FLOAT_DATA and another DATA column is extremely experimental."
    8972           0 :        << LogIO::POST;
    8973             : 
    8974             :   // Is CORRECTED_DATA being moved to DATA?
    8975           0 :   Bool fromCorrToData = nCmplx == 1 && cmplxColLabels[0] == MS::CORRECTED_DATA;
    8976             : 
    8977           0 :   ArrayColumn<Complex> *outCmplxCols = new ArrayColumn<Complex>[nCmplx];
    8978           0 :   getDataColMap(outCmplxCols, nCmplx, cmplxColLabels);
    8979             : 
    8980             :   // We may need to watch for chunks (timebins) that should be split because of
    8981             :   // changes in scan, etc. (CAS-2401).  The old split way would have
    8982             :   // temporarily shortened timeBin, but vi.setInterval() does not work without
    8983             :   // calling vi.originChunks(), so that approach does not work with
    8984             :   // VisibilityIterator.  Instead, get VisibilityIterator's sort (which also
    8985             :   // controls how the chunks are split) to do the work.
    8986           0 :   Block<Int> sort;
    8987           0 :   if(!setSortOrder(sort, "spw", false))
    8988             :     os << LogIO::WARN
    8989             :        << "The request to combine spws while time averaging is being ignored."
    8990           0 :        << LogIO::POST;
    8991             : 
    8992             :   // MSIter tends to produce output INTERVALs that are longer than the
    8993             :   // requested interval length, by ~0.5 input integrations for a random
    8994             :   // timeBin_p.  Giving it timeBin_p - 0.5 * interval[0] removes the bias and
    8995             :   // brings it almost in line with binTimes() (which uses -0.5 *
    8996             :   // interval[bin_start]).
    8997             :   //
    8998             :   // late April 2011: MSIter removed the bias, which threw off the correction.
    8999             :   // October 2011: The bias seems to be back, possibly because of a change in
    9000             :   //               when MSInterval's "offset" is reset.
    9001             :   //               But, then, practically, timebins can be cut short but never
    9002             :   //               lengthened by changes in scan, state, or obs ID, so it seems
    9003             :   //               better to leave the bias in!
    9004             :   //
    9005             :   //Double tbin = mscIn_p->interval()(0);
    9006             :   //tbin = timeBin_p > tbin ? timeBin_p - 0.5 * tbin : timeBin_p;
    9007           0 :   ROVisibilityIterator vi(mssel_p, sort, timeBin_p);
    9008             :   //vi.slurp();
    9009             :   //cerr << "Finished slurping." << endl;
    9010             : 
    9011             :   // Apply selection
    9012           0 :   for(uInt spwind = 0; spwind < spw_p.nelements(); ++spwind)
    9013           0 :     vi.selectChannel(1, chanStart_p[spwind], nchan_p[spwind],
    9014           0 :                      chanStep_p[spwind], spw_p[spwind]);
    9015             :   //vi.selectChannel(chanSlices_p);     // ROVisIterator
    9016             :   //vi.selectCorrelation(corrSlices_p);
    9017             : 
    9018             :   // Translate chanSlices_p into the form vb.channelAve() wants.
    9019           0 :   Vector<Matrix<Int> > chanAveBounds;
    9020           0 :   vi.slicesToMatrices(chanAveBounds, chanSlices_p, widths_p);
    9021             : 
    9022           0 :   Matrix<Float> wtmat;
    9023           0 :   const Bool doSpWeight = vi.existsWeightSpectrum();
    9024             : 
    9025             :   //os << LogIO::NORMAL2 << "outNrow = " << msOut_p.nrow() << LogIO::POST;
    9026             : 
    9027             :   // All of this ddid/spw confusion really needs cleaning up.
    9028             :   // a map from input to output
    9029             :   // DATA_DESC_ID.  (ddidmap[input_ddid] = output_ddid.  Setting ddidmap to -1
    9030             :   // for unselected ddids will help make it obvious if unexpected ddids sneak
    9031             :   // through.)  Vector<Int> ddidmap(oldDDSpwMatch_p.nelements());
    9032             :   // ddidmap.set(-1);
    9033             :   // for(uInt i = 0; i < ddidmap.nelements(); ++i){
    9034             :   //   Int oldspwid = oldDDSpwMatch_p[i];
    9035             : 
    9036             :   //   if(oldspwid > -1 && oldspwid < spwRelabel_p.nelements())
    9037             :   //     ddidmap[i] = spwRelabel_p[oldspwid];
    9038             :   // }
    9039             : 
    9040           0 :   uInt rowsdone = 0;    // Output rows, used for the RefRows.
    9041             : 
    9042           0 :   uInt ninrows = mssel_p.nrow();
    9043             :   ProgressMeter meter(0.0, ninrows * 1.0, "split", "rows averaged", "", "",
    9044           0 :                       true, 1);
    9045           0 :   uInt inrowsdone = 0;  // only for the meter.
    9046             : 
    9047           0 :   VisChunkAverager vca(dataColNames, doSpWeight, chanAveBounds);
    9048             : 
    9049           0 :   Bool doFC = existsFlagCategory();
    9050             : 
    9051             :   // Iterate through the chunks.  A timebin will have multiple chunks if it has
    9052             :   // > 1 arrays, fields, or ddids.
    9053           0 :   for(vi.originChunks(); vi.moreChunks(); vi.nextChunk()){
    9054           0 :     vca.reset();        // Should be done at the start of each chunk.
    9055             : 
    9056           0 :     inrowsdone += vi.nRowChunk();
    9057             : 
    9058             :     // Fill and time average vi's current chunk.
    9059           0 :     VisBuffer& avb(vca.average(vi));
    9060           0 :     uInt rowsnow = avb.nRow();
    9061             : 
    9062           0 :     if(rowsnow > 0){
    9063           0 :       RefRows rowstoadd(rowsdone, rowsdone + rowsnow - 1);
    9064             : 
    9065             :       // msOut_p.addRow(rowsnow, true);
    9066           0 :       msOut_p.addRow(rowsnow);            // Try it without initialization.
    9067             : 
    9068             :       // avb.freqAveCubes();  // Watch out, weight must currently be handled separately.
    9069             : 
    9070           0 :       remapper.remap(avb);
    9071             : 
    9072             :       // Fill in the nonaveraging values from slotv0.
    9073           0 :       msc_p->antenna1().putColumnCells(rowstoadd, avb.antenna1());
    9074           0 :       msc_p->antenna2().putColumnCells(rowstoadd, avb.antenna2());
    9075             : 
    9076           0 :       Vector<Int> arrID(rowsnow);
    9077           0 :       arrID.set(avb.arrayId());                              // Don't remap!
    9078           0 :       msc_p->arrayId().putColumnCells(rowstoadd, arrID);
    9079             : 
    9080             :       // outCmplxCols determines whether the input column is output to DATA or not.
    9081           0 :       for(uInt datacol = 0; datacol < nCmplx; ++datacol){
    9082           0 :         if(dataColNames[datacol] == MS::DATA)
    9083           0 :           outCmplxCols[datacol].putColumnCells(rowstoadd, avb.visCube());
    9084           0 :         else if(dataColNames[datacol] == MS::MODEL_DATA)
    9085           0 :           outCmplxCols[datacol].putColumnCells(rowstoadd, avb.modelVisCube());
    9086           0 :         else if(dataColNames[datacol] == MS::CORRECTED_DATA)
    9087           0 :           outCmplxCols[datacol].putColumnCells(rowstoadd, avb.correctedVisCube());
    9088             :       }
    9089           0 :       if(doFloat)
    9090           0 :         msc_p->floatData().putColumnCells(rowstoadd, avb.floatDataCube());
    9091             : 
    9092           0 :       Vector<Int> ddID(rowsnow);
    9093           0 :       ddID.set(avb.dataDescriptionId());
    9094           0 :       msc_p->dataDescId().putColumnCells(rowstoadd, ddID);
    9095             : 
    9096           0 :       msc_p->exposure().putColumnCells(rowstoadd, avb.exposure());
    9097           0 :       msc_p->feed1().putColumnCells(rowstoadd, avb.feed1());
    9098           0 :       msc_p->feed2().putColumnCells(rowstoadd, avb.feed2());
    9099             : 
    9100           0 :       Vector<Int> fieldID(rowsnow);
    9101           0 :       fieldID.set(avb.fieldId());
    9102           0 :       msc_p->fieldId().putColumnCells(rowstoadd, fieldID);
    9103             : 
    9104           0 :       msc_p->flagRow().putColumnCells(rowstoadd, avb.flagRow()); 
    9105           0 :       msc_p->flag().putColumnCells(rowstoadd, avb.flagCube());
    9106             : 
    9107           0 :       if(doFC)
    9108           0 :         msc_p->flagCategory().putColumnCells(rowstoadd, avb.flagCategory());
    9109             : 
    9110           0 :       msc_p->interval().putColumnCells(rowstoadd, avb.timeInterval());
    9111           0 :       msc_p->observationId().putColumnCells(rowstoadd, avb.observationId());
    9112           0 :       msc_p->processorId().putColumnCells(rowstoadd, avb.processorId());
    9113           0 :       msc_p->scanNumber().putColumnCells(rowstoadd, avb.scan());   // Don't remap!
    9114             : 
    9115           0 :       if(doSpWeight)
    9116           0 :         msc_p->weightSpectrum().putColumnCells(rowstoadd, avb.weightSpectrum());
    9117             : 
    9118           0 :       if(fromCorrToData) {                          
    9119           0 :         wtmat.reference(avb.weightMat());
    9120           0 :         msc_p->weight().putColumnCells(rowstoadd, wtmat);
    9121           0 :         arrayTransformInPlace(wtmat, subms::wtToSigma);   // sig=1/sqrt(wt)
    9122           0 :         msc_p->sigma().putColumnCells(rowstoadd, wtmat);
    9123             :       }
    9124             :       else {
    9125           0 :         wtmat.reference(avb.sigmaMat());           // Yes, I'm reusing wtmat.
    9126           0 :         msc_p->sigma().putColumnCells(rowstoadd, wtmat);
    9127           0 :         arrayTransformInPlace(wtmat, subms::sigToWeight);   // wt=1/sig^2
    9128           0 :         msc_p->weight().putColumnCells(rowstoadd, wtmat);
    9129             :       }
    9130             : 
    9131             : 
    9132           0 :       msc_p->stateId().putColumnCells(rowstoadd, avb.stateId());
    9133           0 :       msc_p->time().putColumnCells(rowstoadd, avb.time());
    9134           0 :       msc_p->timeCentroid().putColumnCells(rowstoadd, avb.timeCentroid());
    9135           0 :       msc_p->uvw().putColumnCells(rowstoadd, avb.uvwMat());
    9136             :       
    9137           0 :       rowsdone += rowsnow;
    9138           0 :     }
    9139           0 :     meter.update(inrowsdone);
    9140             :   }   // End of for(vi.originChunks(); vi.moreChunks(); vi.nextChunk())
    9141           0 :   delete [] outCmplxCols;
    9142           0 :   os << LogIO::NORMAL << "Data binned." << LogIO::POST;
    9143             : 
    9144             :   //const ColumnDescSet& cds = mssel_p.tableDesc().columnDescSet();
    9145             :   //const ColumnDesc& cdesc = cds[MS::columnName(MS::DATA)];
    9146             :   //ROTiledStManAccessor tacc(mssel_p, cdesc.dataManagerGroup());
    9147             :   //tacc.showCacheStatistics(cerr);  // A 99.x% hit rate is good.  0% is bad.
    9148             : 
    9149             :   os << LogIO::DEBUG1 // helpdesk ticket in from Oleg Smirnov (ODU-232630)
    9150           0 :      << "Post binning memory: " << Memory::allocatedMemoryInBytes() / (1024.0 * 1024.0) << " MB"
    9151           0 :      << LogIO::POST;
    9152             : 
    9153           0 :   if(rowsdone < 1){
    9154             :     os << LogIO::WARN
    9155             :        << "No rows were written.  Is all the selected input flagged?"
    9156           0 :        << LogIO::POST;
    9157           0 :     return false;
    9158             :   }
    9159           0 :   return true;
    9160           0 : }
    9161             : 
    9162             : // This should become the default soon (with a name change).
    9163           0 : Bool SubMS::doTimeAverVisIterator(const Vector<MS::PredefinedColumns>& dataColNames,
    9164             :                                   const VBRemapper& remapper)
    9165             : {
    9166           0 :   LogIO os(LogOrigin("SubMS", "doTimeAverVisIterator()"));
    9167             : 
    9168             :   //No channel averaging with time averaging ... it's better this way, but
    9169             :   //maybe that should be revisited with VisibilityIterator.
    9170           0 :   if(chanStep_p[0] > 1){
    9171           0 :     throw(AipsError("Simultaneous time and channel averaging is not handled."));
    9172             :     return false;
    9173             :   }
    9174             : 
    9175             :   os << LogIO::DEBUG1 // helpdesk ticket from Oleg Smirnov (ODU-232630)
    9176             :      << "Before msOut_p.addRow(): "
    9177           0 :      << Memory::allocatedMemoryInBytes() / (1024.0 * 1024.0) << " MB"
    9178           0 :      << LogIO::POST;
    9179             : 
    9180           0 :   Vector<MS::PredefinedColumns> cmplxColLabels;
    9181           0 :   const Bool doFloat = sepFloat(dataColNames, cmplxColLabels);
    9182           0 :   const uInt nCmplx = cmplxColLabels.nelements();
    9183           0 :   if(doFloat && nCmplx > 0)                             // 2010-12-14
    9184             :     os << LogIO::WARN
    9185             :        << "Using VisIterator to average both FLOAT_DATA and another DATA column is extremely experimental."
    9186           0 :        << LogIO::POST;
    9187             : 
    9188             :   // Is CORRECTED_DATA being moved to DATA?
    9189           0 :   Bool fromCorrToData =  nCmplx == 1 && cmplxColLabels[0] == MS::CORRECTED_DATA;
    9190             : 
    9191           0 :   ArrayColumn<Complex> *outCmplxCols = new ArrayColumn<Complex>[nCmplx];
    9192           0 :   getDataColMap(outCmplxCols, nCmplx, cmplxColLabels);
    9193             : 
    9194             :   // We may need to watch for chunks (timebins) that should be split because of
    9195             :   // changes in scan, etc. (CAS-2401).  The old split way would have
    9196             :   // temporarily shortened timeBin, but vi.setInterval() does not work without
    9197             :   // calling vi.originChunks(), so that approach does not work with VisIterator.
    9198             :   // Instead, get VisIterator's sort (which also controls how the chunks are split)
    9199             :   // to do the work.
    9200           0 :   Block<Int> sort;
    9201           0 :   if(!setSortOrder(sort, "spw", false))
    9202             :     os << LogIO::WARN
    9203             :        << "The request to combine spws while time averaging is being ignored."
    9204           0 :        << LogIO::POST;
    9205             : 
    9206             :   // MSIter tends to produce output INTERVALs that are longer than the
    9207             :   // requested interval length, by ~0.5 input integrations for a random
    9208             :   // timeBin_p.  Giving it timeBin_p - 0.5 * interval[0] removes the bias and
    9209             :   // brings it almost in line with binTimes() (which uses -0.5 *
    9210             :   // interval[bin_start]).
    9211             :   //
    9212             :   // late April 2011: MSIter removed the bias, which threw off the correction.
    9213             :   // October 2011: The bias seems to be back, possibly because of a change in
    9214             :   //               when MSInterval's "offset" is reset.
    9215             :   //               But, then, practically, timebins can be cut short but never
    9216             :   //               lengthened by changes in scan, state, or obs ID, so it seems
    9217             :   //               better to leave the bias in!
    9218             :   //
    9219             :   //Double tbin = mscIn_p->interval()(0);
    9220             :   //tbin = timeBin_p > tbin ? timeBin_p - 0.5 * tbin : timeBin_p;
    9221           0 :   ROVisIterator vi(mssel_p, sort, timeBin_p);
    9222             :   
    9223             :   // Apply selection
    9224           0 :   vi.selectChannel(chanSlices_p);     // ROVisIterator
    9225           0 :   vi.selectCorrelation(corrSlices_p);
    9226             : 
    9227             :   // Translate chanSlices_p into the form vb.channelAve() wants.
    9228           0 :   Vector<Matrix<Int> > chanAveBounds;
    9229           0 :   vi.slicesToMatrices(chanAveBounds, chanSlices_p, widths_p);
    9230             : 
    9231           0 :   Matrix<Float> wtmat;
    9232           0 :   const Bool doSpWeight = vi.existsWeightSpectrum();
    9233             : 
    9234             :   //os << LogIO::NORMAL2 << "outNrow = " << msOut_p.nrow() << LogIO::POST;
    9235             : 
    9236             :   // All of this ddid/spw confusion really needs cleaning up.
    9237             :   // a map from input to output
    9238             :   // DATA_DESC_ID.  (ddidmap[input_ddid] = output_ddid.  Setting ddidmap to -1
    9239             :   // for unselected ddids will help make it obvious if unexpected ddids sneak
    9240             :   // through.)  Vector<Int> ddidmap(oldDDSpwMatch_p.nelements());
    9241             :   // ddidmap.set(-1);
    9242             :   // for(uInt i = 0; i < ddidmap.nelements(); ++i){
    9243             :   //   Int oldspwid = oldDDSpwMatch_p[i];
    9244             : 
    9245             :   //   if(oldspwid > -1 && oldspwid < spwRelabel_p.nelements())
    9246             :   //     ddidmap[i] = spwRelabel_p[oldspwid];
    9247             :   // }
    9248             : 
    9249           0 :   uInt rowsdone = 0;    // Output rows, used for the RefRows.
    9250             : 
    9251           0 :   uInt ninrows = mssel_p.nrow();
    9252             :   ProgressMeter meter(0.0, ninrows * 1.0, "split", "rows averaged", "", "",
    9253           0 :                       true, 1);
    9254           0 :   uInt inrowsdone = 0;  // only for the meter.
    9255             : 
    9256           0 :   VisChunkAverager vca(dataColNames, doSpWeight, chanAveBounds);
    9257             : 
    9258           0 :   Bool doFC = existsFlagCategory();
    9259             : 
    9260             :   // Iterate through the chunks.  A timebin will have multiple chunks if it has
    9261             :   // > 1 arrays, fields, or ddids.
    9262           0 :   for(vi.originChunks(); vi.moreChunks(); vi.nextChunk()){
    9263           0 :     vca.reset();        // Should be done at the start of each chunk.
    9264             : 
    9265           0 :     inrowsdone += vi.nRowChunk();
    9266             : 
    9267             :     // Fill and time average vi's current chunk.
    9268           0 :     VisBuffer& avb(vca.average(vi));
    9269           0 :     uInt rowsnow = avb.nRow();
    9270             : 
    9271           0 :     if(rowsnow > 0){
    9272           0 :       RefRows rowstoadd(rowsdone, rowsdone + rowsnow - 1);
    9273             : 
    9274             :       // msOut_p.addRow(rowsnow, true);
    9275           0 :       msOut_p.addRow(rowsnow);            // Try it without initialization.
    9276             :         
    9277             :       // avb.freqAveCubes();  // Watch out, weight must currently be handled
    9278             :       // separately.
    9279             : 
    9280           0 :       remapper.remap(avb);
    9281             : 
    9282             :       // Fill in the nonaveraging values from slotv0.
    9283           0 :       msc_p->antenna1().putColumnCells(rowstoadd, avb.antenna1());
    9284           0 :       msc_p->antenna2().putColumnCells(rowstoadd, avb.antenna2());
    9285             : 
    9286           0 :       Vector<Int> arrID(rowsnow);
    9287           0 :       arrID.set(avb.arrayId());                              // Don't remap!
    9288           0 :       msc_p->arrayId().putColumnCells(rowstoadd, arrID);
    9289             : 
    9290             :       // outCmplxCols determines whether the input column is output to DATA or not.
    9291           0 :       for(uInt datacol = 0; datacol < nCmplx; ++datacol){
    9292           0 :         if(dataColNames[datacol] == MS::DATA)
    9293           0 :           outCmplxCols[datacol].putColumnCells(rowstoadd, avb.visCube());
    9294           0 :         else if(dataColNames[datacol] == MS::MODEL_DATA)
    9295           0 :           outCmplxCols[datacol].putColumnCells(rowstoadd, avb.modelVisCube());
    9296           0 :         else if(dataColNames[datacol] == MS::CORRECTED_DATA)
    9297           0 :           outCmplxCols[datacol].putColumnCells(rowstoadd, avb.correctedVisCube());
    9298             :       }
    9299           0 :       if(doFloat)
    9300           0 :         msc_p->floatData().putColumnCells(rowstoadd, avb.floatDataCube());
    9301             : 
    9302           0 :       Vector<Int> ddID(rowsnow);
    9303           0 :       ddID.set(avb.dataDescriptionId());
    9304           0 :       msc_p->dataDescId().putColumnCells(rowstoadd, ddID);
    9305             : 
    9306           0 :       msc_p->exposure().putColumnCells(rowstoadd, avb.exposure());
    9307           0 :       msc_p->feed1().putColumnCells(rowstoadd, avb.feed1());
    9308           0 :       msc_p->feed2().putColumnCells(rowstoadd, avb.feed2());
    9309             : 
    9310           0 :       Vector<Int> fieldID(rowsnow);
    9311           0 :       fieldID.set(avb.fieldId());
    9312           0 :       msc_p->fieldId().putColumnCells(rowstoadd, fieldID);
    9313             : 
    9314           0 :       msc_p->flagRow().putColumnCells(rowstoadd, avb.flagRow()); 
    9315           0 :       msc_p->flag().putColumnCells(rowstoadd, avb.flagCube());
    9316             : 
    9317           0 :       if(doFC)
    9318           0 :         msc_p->flagCategory().putColumnCells(rowstoadd, avb.flagCategory());
    9319             : 
    9320           0 :       msc_p->interval().putColumnCells(rowstoadd, avb.timeInterval());
    9321           0 :       msc_p->observationId().putColumnCells(rowstoadd, avb.observationId());
    9322           0 :       msc_p->processorId().putColumnCells(rowstoadd, avb.processorId());
    9323           0 :       msc_p->scanNumber().putColumnCells(rowstoadd, avb.scan());     // Don't remap!
    9324             : 
    9325           0 :       if(doSpWeight)
    9326           0 :         msc_p->weightSpectrum().putColumnCells(rowstoadd, avb.weightSpectrum());
    9327             : 
    9328           0 :       if(fromCorrToData) {
    9329           0 :         wtmat.reference(avb.weightMat());
    9330           0 :         msc_p->weight().putColumnCells(rowstoadd, wtmat);
    9331           0 :         arrayTransformInPlace(wtmat, subms::wtToSigma);  // sig=1/sqrt(wt)
    9332           0 :         msc_p->sigma().putColumnCells(rowstoadd, wtmat);
    9333             :       }
    9334             :       else {
    9335           0 :         wtmat.reference(avb.sigmaMat());           // Yes, I'm reusing wtmat.     
    9336           0 :         msc_p->sigma().putColumnCells(rowstoadd, wtmat);
    9337           0 :         arrayTransformInPlace(wtmat, subms::sigToWeight);  // wt = 1/sig^2
    9338           0 :         msc_p->weight().putColumnCells(rowstoadd, wtmat);
    9339             :       }
    9340             : 
    9341           0 :       msc_p->stateId().putColumnCells(rowstoadd, avb.stateId());
    9342           0 :       msc_p->time().putColumnCells(rowstoadd, avb.time());
    9343           0 :       msc_p->timeCentroid().putColumnCells(rowstoadd, avb.timeCentroid());
    9344           0 :       msc_p->uvw().putColumnCells(rowstoadd, avb.uvwMat());
    9345             :       
    9346           0 :       rowsdone += rowsnow;
    9347           0 :     }
    9348           0 :     meter.update(inrowsdone);
    9349             :   }   // End of for(vi.originChunks(); vi.moreChunks(); vi.nextChunk())
    9350           0 :   delete [] outCmplxCols;
    9351           0 :   os << LogIO::NORMAL << "Data binned." << LogIO::POST;
    9352             : 
    9353             :   os << LogIO::DEBUG1 // helpdesk ticket in from Oleg Smirnov (ODU-232630)
    9354           0 :      << "Post binning memory: " << Memory::allocatedMemoryInBytes() / (1024.0 * 1024.0) << " MB"
    9355           0 :      << LogIO::POST;
    9356             : 
    9357           0 :   if(rowsdone < 1){
    9358             :     os << LogIO::WARN
    9359             :        << "No rows were written.  Is all the selected input flagged?"
    9360           0 :        << LogIO::POST;
    9361           0 :     return false;
    9362             :   }
    9363           0 :   return true;
    9364           0 : }
    9365             : 
    9366           0 : void SubMS::getDataColMap(MSColumns* msc, ArrayColumn<Complex>* mapper,
    9367             :                           uInt ntok,
    9368             :                           const Vector<MS::PredefinedColumns>& colEnums)
    9369             : {
    9370             :   // Set up a map from dataColumn indices to ArrayColumns in the output.
    9371             :   // mapper has to be a pointer (gasp!), not a Vector, because
    9372             :   // Vector<ArrayColumn<Complex> > mapper(ntok) would implicitly call
    9373             :   // .resize(), which uses =, which is banned for ArrayColumn.
    9374             : 
    9375           0 :   if(mustConvertToData(ntok, colEnums)){
    9376           0 :     mapper[0].reference(msc->data());
    9377             :   }
    9378             :   else{
    9379           0 :     for(uInt i = 0; i < ntok; ++i){
    9380           0 :       if(colEnums[i] == MS::CORRECTED_DATA)
    9381           0 :         mapper[i].reference(msc->correctedData());
    9382           0 :       else if(colEnums[i] == MS::MODEL_DATA)
    9383           0 :         mapper[i].reference(msc->modelData());
    9384           0 :       else if(colEnums[i] == MS::LAG_DATA)
    9385           0 :         mapper[i].reference(msc->lagData());
    9386             :       else                                  // The output default !=
    9387           0 :         mapper[i].reference(msc->data()); // the input default.
    9388             :     }
    9389             :   }
    9390           0 : }
    9391             : 
    9392             : inline Bool SubMS::areDataShapesConstant()
    9393             : {
    9394             :   return allSame(inNumChan_p) && allSame(nchan_p) && allSame(inNumCorr_p) && allSame(ncorr_p);
    9395             : }
    9396             : 
    9397           0 :   Bool isAllColumns(const Vector<MS::PredefinedColumns>& colNames)
    9398             :   {
    9399           0 :     Bool dCol=false, mCol=false, cCol=false;
    9400           0 :     for(uInt i=0;i<colNames.nelements();i++)
    9401             :       {
    9402           0 :         if (colNames[i] == MS::DATA)                dCol=true;
    9403           0 :         else if (colNames[i] == MS::MODEL_DATA)     mCol=true;
    9404           0 :         else if (colNames[i] == MS::CORRECTED_DATA) cCol=true;
    9405             :         // else turn off all?
    9406             :       }
    9407           0 :     return (dCol && mCol && cCol);
    9408             :   }
    9409             : 
    9410             :   // -----------------------------------------------------------------------
    9411             :   // Work-around to copy the keywords of the FLOAT_DATA column to the output MS
    9412             :   // -----------------------------------------------------------------------
    9413           0 :   void SubMS::copyMainTableKeywords (TableRecord& outKeys,
    9414             :                 const TableRecord& inKeys)
    9415             :   {
    9416           0 :         for (uInt i=0; i<inKeys.nfields(); i++) {
    9417           0 :                 if (inKeys.type(i) == TpString) {
    9418             :                         // Add keywords for MAIN table columns such as FLOAT_DATA
    9419           0 :                         String ikey = inKeys.name(i);
    9420           0 :                         if (!outKeys.isDefined (ikey)) {
    9421           0 :                                 String keyval;
    9422           0 :                                 inKeys.get(ikey, keyval);
    9423           0 :                                 outKeys.define(ikey,keyval);
    9424           0 :                         }
    9425             : 
    9426           0 :                 }
    9427             : 
    9428             :         }
    9429           0 :   }
    9430             : 
    9431             : } //#End casa namespace

Generated by: LCOV version 1.16