LCOV - code coverage report
Current view: top level - nrao/VLA - VLAFiller.cc (source / functions) Hit Total Coverage
Test: ctest_coverage.info Lines: 0 1321 0.0 %
Date: 2023-11-02 14:27:30 Functions: 0 27 0.0 %

          Line data    Source code
       1             : //# VLAFiller.cc: 
       2             : //# Copyright (C) 1999,2000,2001,2002,2003
       3             : //# Associated Universities, Inc. Washington DC, USA.
       4             : //#
       5             : //# This library is free software; you can redistribute it and/or modify it
       6             : //# under the terms of the GNU Library General Public License as published by
       7             : //# the Free Software Foundation; either version 2 of the License, or (at your
       8             : //# option) any later version.
       9             : //#
      10             : //# This library is distributed in the hope that it will be useful, but WITHOUT
      11             : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12             : //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
      13             : //# License for more details.
      14             : //#
      15             : //# You should have received a copy of the GNU Library General Public License
      16             : //# along with this library; if not, write to the Free Software Foundation,
      17             : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
      18             : //#
      19             : //# Correspondence concerning AIPS++ should be addressed as follows:
      20             : //#        Internet email: aips2-request@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: VLAFiller.cc,v 19.20.4.1 2005/12/26 21:09:43 wyoung Exp $
      27             : 
      28             : #include <nrao/VLA/VLAFiller.h>
      29             : #include <nrao/VLA/VLAADA.h>
      30             : #include <nrao/VLA/VLACDA.h>
      31             : #include <nrao/VLA/VLARCA.h>
      32             : #include <nrao/VLA/VLASDA.h>
      33             : #include <casacore/casa/Arrays/Array.h>
      34             : #include <casacore/casa/Arrays/ArrayLogical.h>
      35             : #include <casacore/casa/Arrays/ArrayMath.h>
      36             : #include <casacore/casa/Arrays/Cube.h>
      37             : #include <casacore/casa/Arrays/Matrix.h>
      38             : #include <casacore/casa/Arrays/Slice.h>
      39             : #include <casacore/casa/Arrays/Vector.h>
      40             : #include <casacore/casa/Containers/RecordFieldId.h>
      41             : #include <casacore/casa/Exceptions/Error.h>
      42             : #include <casacore/casa/Logging/LogFilter.h>
      43             : #include <casacore/casa/Logging/LogMessage.h>
      44             : #include <casacore/casa/Logging/LogOrigin.h>
      45             : #include <casacore/casa/Logging/LogSink.h>
      46             : #include <casacore/casa/BasicSL/Complex.h>
      47             : #include <casacore/ms/MeasurementSets/MSAntenna.h>
      48             : #include <casacore/ms/MeasurementSets/MSAntennaColumns.h>
      49             : #include <casacore/ms/MeasurementSets/MSDataDescColumns.h>
      50             : #include <casacore/ms/MeasurementSets/MSDataDescription.h>
      51             : #include <casacore/ms/MeasurementSets/MSFeed.h>
      52             : #include <casacore/ms/MeasurementSets/MSFeedColumns.h>
      53             : #include <casacore/ms/MeasurementSets/MSField.h>
      54             : #include <casacore/ms/MeasurementSets/MSFieldColumns.h>
      55             : #include <casacore/ms/MSSel/MSFieldIndex.h>
      56             : #include <casacore/ms/MeasurementSets/MSObsColumns.h>
      57             : #include <casacore/ms/MeasurementSets/MSObservation.h>
      58             : #include <casacore/ms/MeasurementSets/MSPolColumns.h>
      59             : #include <casacore/ms/MeasurementSets/MSPolarization.h>
      60             : #include <casacore/ms/MeasurementSets/MSSpWindowColumns.h>
      61             : #include <casacore/ms/MeasurementSets/MSSpectralWindow.h>
      62             : #include <casacore/ms/MeasurementSets/MSTileLayout.h>
      63             : #include <casacore/measures/Measures/MCBaseline.h>
      64             : #include <casacore/measures/Measures/MDirection.h>
      65             : #include <casacore/measures/Measures/MDoppler.h>
      66             : #include <casacore/measures/Measures/MEpoch.h>
      67             : #include <casacore/measures/Measures/MPosition.h>
      68             : #include <casacore/measures/Measures/MeasRef.h>
      69             : #include <casacore/measures/Measures/MeasTable.h>
      70             : #include <casacore/casa/OS/File.h>
      71             : #include <casacore/casa/OS/Path.h>
      72             : #include <casacore/casa/Quanta/MVAngle.h>
      73             : #include <casacore/casa/Quanta/MVBaseline.h>
      74             : #include <casacore/casa/Quanta/MVDirection.h>
      75             : #include <casacore/casa/Quanta/MVDoppler.h>
      76             : #include <casacore/casa/Quanta/MVEpoch.h>
      77             : #include <casacore/casa/Quanta/MVFrequency.h>
      78             : #include <casacore/casa/Quanta/MVPosition.h>
      79             : #include <casacore/casa/Quanta/MVTime.h>
      80             : #include <casacore/casa/Quanta/MVuvw.h>
      81             : #include <casacore/casa/Quanta/Quantum.h>
      82             : #include <casacore/casa/Quanta/Unit.h>
      83             : #include <casacore/measures/TableMeasures/ArrayMeasColumn.h>
      84             : #include <casacore/measures/TableMeasures/ScalarMeasColumn.h>
      85             : #include <casacore/tables/Tables/ArrayColumn.h>
      86             : #include <casacore/tables/DataMan/IncrementalStMan.h>
      87             : #include <casacore/tables/DataMan/TiledColumnStMan.h>
      88             : #include <casacore/tables/Tables/RefRows.h>
      89             : #include <casacore/tables/Tables/ScaColDesc.h>
      90             : #include <casacore/tables/Tables/ScalarColumn.h>
      91             : #include <casacore/tables/Tables/SetupNewTab.h>
      92             : #include <casacore/tables/DataMan/StandardStMan.h>
      93             : #include <casacore/tables/Tables/Table.h>
      94             : #include <casacore/tables/Tables/TableDesc.h>
      95             : #include <casacore/tables/Tables/TableInfo.h>
      96             : #include <casacore/tables/Tables/TableRecord.h>
      97             : #include <casacore/tables/Tables/TableUtil.h>
      98             : #include <casacore/tables/DataMan/TiledDataStMan.h>
      99             : #include <casacore/tables/DataMan/TiledShapeStMan.h>
     100             : #include <casacore/casa/Utilities/Assert.h>
     101             : #include <casacore/casa/Utilities/DataType.h>
     102             : #include <casacore/casa/BasicSL/String.h>
     103             : #include <sstream>
     104             : #include <iomanip>
     105             : 
     106             : #include <casacore/tables/TaQL/ExprNode.h>
     107             : 
     108             : const uInt maxCDA(VLAEnum::CDA3+1);
     109             : const uInt maxIF(VLAEnum::IFD+1);
     110             : const uInt nCat = 6; // Number of Flag categories
     111             : const uInt maxSubarrays = 5; // The maximum number of subarrays;
     112             : const String sigmaCol = "sigmaHyperColumn";
     113             : const String dataCol = "dataHyperColumn";
     114             : const String flagCol = "flagHyperColumn";
     115             : //New addition
     116             : const String modDataCol = "modDataHyperColumn";
     117             : const String corrDataCol = "corrDataHyperColumn";
     118             : const String chanFlagCol = "flagChanHyperColumn";
     119             : //====
     120             : const RecordFieldId sigmaTileId("SIGMA_HYPERCUBE_ID");
     121             : const RecordFieldId dataTileId("DATA_HYPERCUBE_ID");
     122             : const RecordFieldId flagTileId("FLAG_CATEGORY_HYPERCUBE_ID");
     123             : //=====new addition
     124             : const RecordFieldId modDataTileId("MODEL_DATA_HYPERCUBE_ID");
     125             : const RecordFieldId corrDataTileId("CORR_DATA_HYPERCUBE_ID");
     126             : const RecordFieldId chanFlagTileId("FLAG_HYPERCUBE_ID");
     127             : //=====  
     128             : const Quantum<Double> dirTol(10.0, "mas"); // Tolerance on matching fields
     129             : const Quantum<Double> posTol(1, "m");     // Tolerance on matching antennas
     130             : const Double ns2m = QC::c( ).getValue("m/ns");
     131             : 
     132             : // The following struct is just ways of bundling up a bunch of arguments to
     133             : // functions to avoid having too many in the function interface.
     134             : struct IterationStatus {
     135             :   uInt nVLARecords;
     136             :   uInt nRows;
     137             :   uInt nAnt;
     138             :   Block<Block<uInt> > lastAnt;
     139             :   uInt nSpw;
     140             :   Block<Block<Int> > lastSpw;
     141             :   uInt nPol;
     142             :   Block<Block<Int> > lastPol;
     143             :   uInt nFld;
     144             :   Block<Int> lastFld;
     145             :   String lastProject;
     146             :   String lastObsMode;
     147             : };
     148             :  
     149           0 : VLAFiller::VLAFiller(MeasurementSet& output, VLALogicalRecord& input, Double freqTolerance, Bool autocorr, const String& antnamescheme, const Bool& applyTsys):
     150             :   MSColumns(output),
     151             :   itsRecord(input),
     152             :   itsInputFilters(),
     153             :   itsMS(output),
     154             :   itsFrame(),
     155             :   //theirFrames(0, MeasFrame()),
     156           0 :   itsMSDirType(MDirection::castType(field().referenceDirMeasCol().getMeasRef().getType())),
     157             :   itsDirType(MDirection::N_Types),
     158             :   itsDirCtr(),
     159             :   itsAzElCtr(),
     160             :   itsUvwCtr(),
     161             :   itsFreqCtr(),
     162             :   itsBlCtr(),
     163             :   itsFldId(maxSubarrays, -1),
     164             :   itsAntId(),
     165             :   itsSpId(maxCDA, -1),
     166             :   itsPolId(0),
     167             :   itsDataId(maxSubarrays),
     168             :   itsNewScan(true),
     169             :   itsScan(maxSubarrays, 0),
     170             :   itsProject(),
     171             :   itsLog(),
     172             :   itsDataAcc(),
     173             :   itsTileId(),
     174             :   itsSigmaAcc(),
     175             :   itsFlagAcc(),
     176             :   itsModDataAcc(),
     177             :   itsCorrDataAcc(),
     178             :   itsChanFlagAcc(),
     179             :   itsDataShapes(0),
     180             :   itsFreqTolerance(freqTolerance),
     181           0 :   itsApplyTsys(applyTsys),
     182             :   itsEVLAisOn(false),
     183             :   itsInitEpoch(false),
     184             :   itsRevBeenWarned(false),
     185             :   itsNoPolInfoWarned(false),
     186           0 :   itsZeroEpochWarned(false)
     187             : {
     188           0 :   String antscheme=antnamescheme;
     189           0 :   antscheme.downcase();
     190           0 :   itsNewAntName=false;
     191           0 :   if(antscheme.contains("new"))
     192           0 :     itsNewAntName=true;
     193           0 :   itsKeepAutoCorr=autocorr;
     194           0 :   checkStop = false;
     195           0 :   fillStarted = false;
     196           0 :   AlwaysAssert(itsMS.tableInfo().subType() == "VLA", AipsError);
     197             : /*
     198             :   itsDataAcc = TiledDataStManAccessor(itsMS, dataCol);
     199             :   itsModDataAcc=TiledDataStManAccessor(itsMS,modDataCol);
     200             :   itsCorrDataAcc=TiledDataStManAccessor(itsMS,corrDataCol);
     201             :   itsChanFlagAcc=TiledDataStManAccessor(itsMS,chanFlagCol);
     202             :   itsSigmaAcc = TiledDataStManAccessor(itsMS, sigmaCol);
     203             :   itsFlagAcc = TiledDataStManAccessor(itsMS, flagCol);
     204             :   const uInt nShapes = itsDataAcc.nhypercubes();
     205             :   itsDataShapes.resize(nShapes);
     206             :   for (uInt s = 0; s < nShapes; s++) {
     207             :     itsDataShapes[s] = itsDataAcc.getHypercubeShape(s).getFirst(2);
     208             :   }
     209             : */
     210             :   // This ms is starting ...make sure its not J2000 when data is B1950
     211             :   // avoid unecessary conversions
     212           0 :   if(nrow()==0){
     213             : 
     214           0 :     itsInitEpoch=false;
     215             : 
     216             :   }
     217             :   else{
     218           0 :     itsInitEpoch=true;
     219             :   }
     220             : 
     221             :   // Deduce what the last scan was from the LAST_SCAN keyword in the SCAN
     222             :   // column. The alternative would be to read all the data in this column!
     223             :   // Note that the scan number is now per subarray.
     224             :   
     225           0 :   if (nrow() != 0) {
     226           0 :     const RecordFieldId key("LAST_SCAN");
     227           0 :     const TableRecord& keywords = scanNumber().keywordSet();
     228           0 :     DebugAssert(keywords.isDefined(key.fieldName()), AipsError);
     229           0 :     if (keywords.dataType(key) == TpInt) { // Old ms (v16 or earlier)
     230           0 :       itsScan[0] = keywords.asInt(key);
     231           0 :     } else if (keywords.dataType(key) == TpArrayInt) {
     232           0 :       DebugAssert(keywords.shape(key) == IPosition(1, maxSubarrays),AipsError);
     233           0 :       const Vector<Int> lastscans(keywords.asArrayInt(key));
     234           0 :       itsScan = makeBlock(lastscans);
     235             :     }
     236             :   }
     237             : 
     238             :   // Check if the frame has been initialised. If not then initialise it with a
     239             :   // position, epoch & direction measure. The direction and time values (but
     240             :   // not types) will be updated in the fillOne function. The position should
     241             :   // never be changed.
     242           0 :   itsFrame.set(MDirection(MVDirection(), itsMSDirType));
     243           0 :   itsFrame.set(MEpoch(MVEpoch(), timeMeas().getMeasRef()));
     244           0 :   MPosition vlaCentre;
     245           0 :   AlwaysAssert(MeasTable::Observatory(vlaCentre, "VLA"), AipsError);
     246           0 :   itsFrame.set(vlaCentre);
     247             : 
     248             :   // For the AzEl converter, we only need AzEl
     249           0 :   itsAzElCtr.setOut(MeasRef<MDirection>(MDirection::AZEL, itsFrame));
     250             : 
     251             :   // For the direction and uvw converter the output type is fixed.
     252           0 :   itsDirCtr.setOut(MeasRef<MDirection>(itsMSDirType, itsFrame));
     253           0 :   itsUvwCtr.setOut(MeasRef<Muvw>(Muvw::fromDirType(itsMSDirType), itsFrame));
     254             :   // For the frequency converter the input type is fixed.
     255           0 :   itsFreqCtr.setModel(MFrequency(MVFrequency(), 
     256           0 :                                  MFrequency::Ref(MFrequency::TOPO, itsFrame)));
     257             :   // For the baseline converter both the input and output frames are known.
     258           0 :   itsBlCtr.set(MBaseline(MVBaseline(), 
     259           0 :                          MBaseline::Ref(MBaseline::HADEC, itsFrame)),
     260             :                MBaseline::ITRF);
     261           0 : }
     262             : 
     263           0 : VLAFiller::~VLAFiller()
     264             : {
     265           0 : }
     266             : 
     267           0 : void VLAFiller::setFilter(const VLAFilterSet& filter){
     268           0 :   itsInputFilters = filter;
     269           0 : }
     270             : 
     271           0 : void VLAFiller::setStopParams(String &pCode, String &sTime){
     272           0 :     if(!pCode.empty() || !sTime.empty()){
     273           0 :         projectCode = upcase(pCode);
     274           0 :         if(!sTime.empty()){
     275           0 :             Quantum<Double> t;
     276           0 :             MVTime::read(t, sTime);
     277           0 :             stopTime = MVEpoch(t);
     278             :         }
     279           0 :         fillStarted = false;
     280           0 :         checkStop = true;
     281             :     }
     282           0 :     return;
     283             : }
     284             : // Well this needs some more work as right now I can only figure
     285             : // out how to have it stop filling after a time. Looks like the 
     286             : // project code can end up being something like system, especially
     287             : // if there are subarrays involved.
     288             : 
     289           0 : Bool VLAFiller::stopFilling(VLALogicalRecord &record)
     290             : {
     291           0 :    Bool rstat(false);
     292           0 :    if(checkStop){
     293             :            /*
     294             :         if(fillStarted){
     295             :            //std::cerr << projectCode << std::endl;
     296             :            //std::cerr << upcase(record.SDA().obsId()) << std::endl;
     297             :            String itsCode(upcase(record.SDA().obsId()));
     298             :            if(!projectCode.empty() && !projectCode.matches(itsCode)){
     299             :               rstat = true;
     300             :             }
     301             :         }
     302             :         */
     303           0 :         const Double recordTime = record.RCA().obsDay() +
     304           0 :               Quantum<Double>(record.SDA().obsTime(), "s").getValue("d");
     305             :            //std::cerr << stopTime.get() << std::endl;
     306             :            //std::cerr << recordTime << std::endl;
     307           0 :         if(recordTime > stopTime.get())
     308           0 :            rstat = true;
     309             :         else 
     310           0 :            rstat = false;
     311             :    }
     312           0 :    return rstat;
     313             : }
     314             : 
     315           0 : void VLAFiller::fill(Int verbose){
     316           0 :   itsLog.origin(LogOrigin("VLAFiller", "fill"));
     317           0 :   IterationStatus counts;
     318           0 :   counts.nVLARecords = 0;
     319           0 :   counts.nRows = nrow();
     320           0 :   counts.nAnt = antenna().nrow();
     321           0 :   counts.lastAnt.resize(maxSubarrays);
     322           0 :   counts.nSpw = spectralWindow().nrow();
     323           0 :   counts.lastSpw = Block<Block<Int> >(maxSubarrays, Block<Int>(2, -1));
     324           0 :   counts.nPol = polarization().nrow();
     325           0 :   counts.lastPol = Block<Block<Int> >(maxSubarrays, Block<Int>(2, -1));;
     326           0 :   counts.nFld = field().nrow();
     327           0 :   counts.lastFld.resize(maxSubarrays);
     328           0 :   counts.lastFld = -1;
     329           0 :   counts.lastProject = "";
     330           0 :   counts.lastObsMode = "";
     331           0 :   const uInt initialRow = nrow();
     332           0 :   itsRevBeenWarned = false;
     333             : #if defined(AIPS_DEBUG)
     334           0 :   const LogFilter saved(LogMessage::DEBUGGING);
     335           0 :   if (verbose > 0) LogSink::globalSink().filter(saved);
     336             : #endif
     337           0 :   AipsError error;
     338             :   try {
     339             : 
     340           0 :     String notstr("NOT ");
     341           0 :     if (itsApplyTsys) 
     342           0 :       notstr="";
     343             : 
     344           0 :     itsLog << LogIO::NORMAL
     345           0 :            << "Data and weights will "+notstr+"be scaled by Nominal Sensitivity."
     346           0 :            << LogIO::POST;
     347             : 
     348             : 
     349           0 :     while (fillOne()) {
     350           0 :       counts.nVLARecords++;
     351           0 :       if (nrow() != counts.nRows) {
     352           0 :         if (verbose > 0 && 
     353           0 :             counts.nVLARecords%verbose == 0) {
     354           0 :           logCurrentRecord(counts);
     355             :         }
     356           0 :         logChanges(counts);
     357             :       }
     358           0 :       counts.nRows = nrow();
     359             :     }
     360           0 :   } catch (AipsError x) {
     361           0 :     itsLog << LogIO::SEVERE 
     362             :            << "An error occurred. The error message is:" << endl
     363             :            << "'" << x.getMesg() << "'" << endl
     364             :            << "Perhaps you ran out of disk space or "
     365             :            << "are using a flaky tape (drive)." << endl
     366             :            << "Trying to write a valid measurement set with" << endl
     367           0 :            << "as much data as possible." << LogIO::POST;
     368           0 :     error = x;
     369           0 :   } catch (...){
     370           0 :     itsLog << LogIO::SEVERE << "Something really bad happened!" << LogIO::POST;
     371             :   }
     372             :   // Now fixup the observation subtable (only if new data has been added).
     373           0 :   if ((nrow() - initialRow) > 0) {
     374           0 :     MSObservation& msObs = itsMS.observation();
     375           0 :     const uInt newRow = msObs.nrow();
     376           0 :     msObs.addRow();
     377           0 :     MSObservationColumns& obsCols = observation();
     378           0 :     obsCols.telescopeName().put(newRow, "VLA");
     379           0 :     const String unavailable = "unavailable";
     380           0 :     const String unknown = "unknown";
     381           0 :     const Vector<String> unavailableVec(1, unavailable);
     382           0 :     obsCols.observer().put(newRow, unavailable);
     383           0 :     obsCols.log().put(newRow, unavailableVec);
     384           0 :     obsCols.scheduleType().put(newRow, unknown);
     385           0 :     obsCols.schedule().put(newRow, unavailableVec);
     386           0 :     obsCols.project().put(newRow, itsProject);
     387           0 :     obsCols.flagRow().put(newRow, false);
     388           0 :     Vector<MEpoch> obsTimeRange(2);
     389           0 :     obsTimeRange(0) = timeMeas()(initialRow);
     390           0 :     const uInt finalRow = nrow() - 1;
     391           0 :     obsTimeRange(1) = timeMeas()(finalRow);
     392           0 :     obsCols.timeRangeMeas().put(newRow, obsTimeRange);
     393           0 :     MVEpoch releaseDate = obsTimeRange(1).getValue();
     394           0 :     releaseDate += MVEpoch(Quantum<Double>(1.5, "a"));
     395           0 :     obsTimeRange(1).set(releaseDate);
     396           0 :     obsCols.releaseDateMeas().put(newRow, obsTimeRange(1));
     397           0 :     ostringstream oos;
     398             : 
     399             :     // Tidy up FIELD name duplicates
     400           0 :     fixFieldDuplicates(itsMS.field());
     401             : 
     402             :   } else {
     403           0 :     if (nrow() == 0) {
     404           0 :       itsLog << "No data in the measurement set\n";
     405             :     } else {
     406           0 :       itsLog << "No data appended to the measurement set\n";
     407             :     }
     408           0 :     if (counts.nVLARecords == 0) {
     409           0 :       itsLog << LogIO::SEVERE << "Your input may not be in VLA archive format" 
     410           0 :              << LogIO::POST;
     411             :     } else {
     412           0 :       itsLog << "There may be a problem with your data selection criteria" 
     413           0 :              << LogIO::WARN << LogIO::POST;
     414             :     }
     415             :   }
     416             : 
     417             :  
     418           0 :   if (verbose >=  0) {
     419           0 :     summarise();
     420             :   }
     421             : 
     422           0 :   scanNumber().rwKeywordSet().define(RecordFieldId("LAST_SCAN"), 
     423           0 :                                      Vector<Int>(itsScan.begin(),itsScan.end()));
     424             :  
     425             : #if defined(AIPS_DEBUG)
     426           0 :   LogSink::globalSink().filter(saved);
     427             : #endif
     428           0 :   if (error.getMesg().length() > 0) throw(error);
     429           0 : }
     430             : 
     431           0 : Bool VLAFiller::fillOne() { 
     432           0 :   if (!itsRecord.read()) return false;
     433           0 :   if (stopFilling(itsRecord)) return false;
     434           0 :   if (!itsInputFilters.passThru(itsRecord)){
     435             :           // OK here we mark a new scan if we skip anything.
     436           0 :           itsNewScan=true;
     437           0 :           return true;
     438             :   }
     439             : 
     440           0 :   fillStarted = true;
     441           0 :   const VLARCA& rca = itsRecord.RCA();
     442           0 :   const VLASDA& sda = itsRecord.SDA();
     443             :   //For new ms and first go...make sure to init this to B1950 if data is so
     444             :   // as default blank ms is in J2000 direction  
     445           0 :   if(!itsInitEpoch){
     446           0 :     itsMSDirType=validEpoch(sda.epoch());
     447           0 :     itsFrame.set(MDirection(MVDirection(), itsMSDirType));
     448           0 :     setDirectionRef(itsMSDirType);
     449           0 :     setUVWRef(Muvw::fromDirType(itsMSDirType));
     450             :     // For the direction and uvw converter the output type is fixed.
     451           0 :     itsDirCtr.setOut(MeasRef<MDirection>(itsMSDirType, itsFrame));
     452           0 :     itsUvwCtr.setOut(MeasRef<Muvw>(Muvw::fromDirType(itsMSDirType), itsFrame));
     453           0 :     itsMS.initRefs();
     454             : 
     455           0 :     itsInitEpoch=true;
     456           0 :     itsMS.flush();
     457             :   }
     458             :   // Check if the revision number is supported.
     459           0 :   if (rca.revision() < 23 && !itsRevBeenWarned) { 
     460           0 :     itsRevBeenWarned = true;
     461           0 :     itsLog << LogIO::WARN
     462             :            << "This function has not been tested on VLA archive data "
     463             :            << "with revisions less " << endl
     464             :            << "than 23 & the data in this record has a revision level of " 
     465             :            << rca.revision() << endl
     466             :            << "It is very likely that the correlation data will be scaled "
     467             :            << "incorrectly"
     468           0 :            << LogIO::POST;
     469             :   }
     470           0 :   const uInt subArray = sda.subArray() - 1;
     471             :   { // Keep track of which projects have been copied.
     472           0 :     const String thisProject = sda.obsId();
     473           0 :     if (!itsProject.contains(thisProject)) {
     474           0 :       if (itsProject.length() != 0) itsProject += String(" ");
     475           0 :       itsProject += thisProject;
     476             :     }
     477             :   }
     478             :   { // set the observing time. Do this now as it may be needed to convert the
     479             :     // field directions from the observed direction type to the direction type
     480             :     // used in the MS.
     481           0 :     const MVEpoch obsTime(rca.obsDay(),
     482           0 :                           Quantum<Double>(sda.obsTime(), "s").getValue("d"));
     483             :     // cerr << MVTime(obsTime.getTime()).string(MVTime::YMD) << endl;
     484           0 :     itsFrame.resetEpoch(obsTime);
     485             :     //NEED to use the exact date the EVLA antenna got in
     486             :     // If after 2005 EVLA can be in
     487           0 :     if(obsTime.getDay() > 53371.0)
     488           0 :       itsEVLAisOn=true;
     489             :     else
     490           0 :       itsEVLAisOn=false;
     491             :   }
     492             : 
     493             :   { // Workout the field ID.
     494           0 :     const MVDirection fieldDirVal(sda.sourceDir());
     495           0 :     const MDirection::Types fieldDirRef(validEpoch(sda.epoch()));
     496             :     // Need to convert the direction to the same type as the MS. Otherwise the
     497             :     // match will fail.
     498             : 
     499           0 :     MDirection fieldDir(fieldDirVal, fieldDirRef);
     500           0 :     if (fieldDirRef != itsMSDirType) { // need to do a conversion
     501           0 :       if (fieldDirRef == itsDirType) { // no need to setup the converter
     502           0 :         fieldDir = itsDirCtr(fieldDirVal);
     503             :       } else {
     504           0 :         itsDirCtr.setModel(fieldDir);
     505           0 :         itsDirType = fieldDirRef;
     506           0 :         fieldDir = itsDirCtr();
     507             :         // at the same time the UVW converter should be initialised
     508           0 :         itsUvwCtr.setModel(Muvw(MVuvw(), Muvw::fromDirType(fieldDirRef)));
     509             :       }
     510             :     }
     511             : 
     512             :     // Determine if field already exists in FIELD subtable
     513           0 :     Bool fldMatch=false;
     514             : 
     515             :     // First match on name (maybe multiple name matches with diff directions?):
     516             :     //   (this is a clumsy way--and inefficient for large FIELD tables--to 
     517             :     //    include name matching, should have andName option in matchDirection)
     518           0 :     MSField& msFld=itsMS.field();
     519             : 
     520             :     //Damn Damnation...as there is no MSColumns::attach ...need to use
     521             :     // a refreshed mscolumn ...especially if the epoch of the direction    
     522             :     // is resetted above..for now create a redundant msc....
     523             :     //to do a matchdirection...need to enhance mscolumns to have an attach
     524           0 :     MSColumns msc(itsMS);
     525           0 :     MSFieldIndex MSFldIdx(msFld);
     526           0 :     Vector<Int> fldNameMatches = MSFldIdx.matchFieldName(sda.sourceName());
     527             :     Int nfNM;
     528           0 :     fldNameMatches.shape(nfNM);
     529             :     // found at least one name match, verify/discern from direction matching
     530           0 :     Int ifNM=0;
     531           0 :     if (nfNM > 0) {
     532           0 :       while (ifNM < nfNM && !fldMatch) {
     533           0 :         fldMatch = (fldNameMatches(ifNM)==msc.field().matchDirection(fieldDir, fieldDir, fieldDir, dirTol,
     534           0 :                                                                  fldNameMatches(ifNM)));
     535           0 :         if (!fldMatch) ifNM++;
     536             :       }
     537             :     }
     538             :             
     539             :     Int thisfldId;
     540           0 :     if (fldMatch) {
     541             :       // found match:
     542           0 :       thisfldId=fldNameMatches(ifNM);
     543             :     } else {
     544             :       // found no match, adding a row:
     545           0 :       addSource(fieldDir);
     546           0 :       thisfldId=addField(fieldDir);
     547             :     }
     548             : 
     549           0 :     if (thisfldId != itsFldId[subArray]) {
     550           0 :       itsFrame.resetDirection(fieldDir.getValue());
     551           0 :       itsNewScan = true;
     552           0 :       itsFldId[subArray] = thisfldId;
     553             :     }
     554             :   }
     555             : 
     556           0 :   const uInt nAnt = rca.nAntennas();
     557             : // Cache the uvw coordinates of each antenna. For holography mode,
     558             : // these are the az, el offsets.
     559           0 :   Block<Double> antUvw(3*nAnt);
     560             :   {
     561           0 :     uInt elem = 0;
     562           0 :     Vector<Double> convertedUvw(3);
     563             :     Double u, v, w;
     564           0 :     const Bool doConversion = (itsMSDirType == validEpoch(sda.epoch())) ? false : true;
     565           0 :     for (uInt a = 0; a < nAnt; a++) {
     566           0 :       const VLAADA& ada = itsRecord.ADA(a);
     567           0 :       u = ada.u();
     568           0 :       v = ada.v();
     569           0 :       w = ada.w();
     570           0 :       if (doConversion) {
     571           0 :         convertedUvw = itsUvwCtr(MVuvw(u, v, w)).getValue().getValue();
     572           0 :         u = convertedUvw(0);
     573           0 :         v = convertedUvw(1);
     574           0 :         w = convertedUvw(2);
     575             :       }
     576           0 :       antUvw[elem] = u; elem++;
     577           0 :       antUvw[elem] = v; elem++;
     578           0 :       antUvw[elem] = w; elem++;
     579             :     }
     580             :   }
     581             : 
     582           0 :   Block<Bool> shadowed(nAnt, false);
     583           0 :   Bool badData = false;
     584             :   { // find out if any antennae are shadowed
     585           0 :     uInt a1Idx = 0;
     586           0 :     for (uInt a1 = 0; a1 < nAnt; a1++) {
     587           0 :       uInt a2Idx = (a1+1)*3;
     588           0 :       for (uInt a2 = a1+1; a2 < nAnt; a2++) {
     589           0 :         Double u = antUvw[a1Idx] - antUvw[a2Idx]; a2Idx++;
     590           0 :         Double v = antUvw[a1Idx+1] - antUvw[a2Idx]; a2Idx++;
     591           0 :         if (u*u + v*v < 625) {
     592           0 :           badData = true;
     593           0 :           Double w = antUvw[a1Idx+2] - antUvw[a2Idx];
     594           0 :           if (w > 0) {
     595           0 :             shadowed[a2] = true;
     596             :           } else {
     597           0 :             shadowed[a1] = true;
     598             :           }
     599             :         }
     600           0 :         a2Idx++;
     601             :       }
     602           0 :       a1Idx += 3;
     603             :     }
     604             :   }
     605             : 
     606             :   // Workout the antenna ID
     607           0 :   if (itsAntId.nelements() != nAnt) {
     608           0 :     itsAntId.resize(nAnt);
     609           0 :     itsAntId = -1;
     610             :   }
     611             :   {
     612           0 :     DebugAssert(itsFrame.position() != 0, AipsError);
     613           0 :     DebugAssert(MPosition::castType
     614             :                 (itsFrame.position()->getRefPtr()->getType()) == 
     615             :                 MPosition::ITRF, AipsError);
     616             :     const MVPosition vlaCentrePos = 
     617           0 :       dynamic_cast<const MPosition*>(itsFrame.position())->getValue();
     618             : 
     619             : 
     620           0 :     Vector<Int> antOrder(29);
     621           0 :     antOrder=-1;
     622           0 :     Vector<MPosition> thisPos(nAnt);
     623           0 :     for (uInt a = 0; a < nAnt; a++) {
     624           0 :       const VLAADA& ada = itsRecord.ADA(a);
     625             :       // Need to do the conversion from bx, by, bz (which is the HADEC frame)
     626             :       // to the ITRF frame prior to adding the reference position.
     627             :       // However, bx,by,bz differ from HADEC by handedness, thus
     628             :       // negate the y-component so ant positions come out right-side-out:
     629             :       // (perhaps HADEC is not the right thing to use)
     630           0 :       const MVBaseline thisBl(ada.bx(), -ada.by(), ada.bz());
     631           0 :       MVPosition thisAnt = itsBlCtr(thisBl).getValue();
     632           0 :       thisAnt += vlaCentrePos;
     633             :       //      const MPosition thisPos(thisAnt, MPosition::ITRF);
     634           0 :       thisPos(a) = MPosition(thisAnt, MPosition::ITRF);
     635           0 :       String leAntName;
     636             : 
     637           0 :       antOrder(ada.antId()-1)=a;
     638             : 
     639           0 :       if(!itsEVLAisOn){
     640             :         // ignore the frontend temperature naming
     641           0 :         leAntName=ada.antName(false);
     642           0 :         if(itsNewAntName){
     643           0 :           leAntName=String("VA")+leAntName;
     644             :         }       
     645             :       }
     646             :       else{
     647           0 :         leAntName=ada.antName(itsNewAntName);
     648             :       }
     649           0 :       itsAntId[a] = antenna().matchAntenna(leAntName, thisPos(a), posTol,
     650           0 :                                            itsAntId[a]);
     651             : 
     652             :       //      if (itsAntId[a]<0)
     653             :       //        cout << a << " " << ada.antId() << " " << leAntName << endl;
     654             : 
     655             :     }
     656             : 
     657             :   /*
     658             :     cout << nAnt << " " << antOrder.nelements() << " " << ntrue(antOrder>-1) << " "
     659             :          << itsAntId.nelements() << " " << max(antOrder) << " "
     660             :          << min(Vector<Int>(itsAntId,nAnt))
     661             :          << endl;
     662             :     cout << "antOrder = " << antOrder << endl;
     663             :   */
     664             :     // If there are antennas to add
     665           0 :     if (min(Vector<Int>(itsAntId.begin(),nAnt,int(0)))<0) {
     666             :       //      cout << "itsAntId 0 = " << Vector<Int>(itsAntId,nAnt) << endl;
     667             : 
     668           0 :       for (uInt ai=0; ai < antOrder.nelements(); ++ai) {
     669           0 :         if (antOrder(ai)>-1) {
     670           0 :           Int ao(antOrder(ai));
     671           0 :           if (itsAntId[ao] < 0) {
     672           0 :             itsAntId[ao] = addAntenna(thisPos(ao), ao);
     673           0 :             addFeed(itsAntId[ao]);
     674           0 :             itsNewScan = true;
     675             :           }
     676             :         }
     677             :       }
     678             :     }
     679             :     //    cout << "itsAntId 1 = " << Vector<Int>(itsAntId,nAnt) << endl;
     680             : 
     681             : 
     682             :   }
     683             : 
     684             :   
     685             :   // For holography data, add the pointing data which is to be
     686             :   // found in the u,v parts of the ADA
     687             :   // Is this Holography data? If so, the UVWs are actually the
     688             :   // pointing offsets - U = Az, V = El
     689           0 :   Bool isHolo=(itsRecord.SDA().obsMode()=="H ");
     690           0 :   if(isHolo) {
     691             : 
     692             :     // We store AzEl in the pointing table. We only need to do this
     693             :     // when the table is empty
     694           0 :     MSPointingColumns& pointingCol = pointing();
     695           0 :     if(pointingCol.nrow()==0) {
     696           0 :       pointingCol.directionMeasCol().setDescRefCode(MDirection::AZEL);
     697             :     }
     698             : 
     699           0 :     const MVDirection fieldDirVal(itsRecord.SDA().sourceDir());
     700           0 :     const MDirection::Types fieldDirRef(validEpoch(itsRecord.SDA().epoch()));
     701           0 :     MDirection fieldDir(fieldDirVal, fieldDirRef);
     702             : 
     703             :     // For the actual direction, we put (Az,El) = (0,0). For the
     704             :     // target, we put the actual Ra, Dec. The uv data (in ns!) is
     705             :     // really the pointing offset in radians.
     706           0 :     for (uInt a = 0; a < nAnt; a++) {
     707           0 :       if(itsAntId[a]>-1) {
     708           0 :         const VLAADA& ada = itsRecord.ADA(a);
     709           0 :         MDirection thisDir(MVDirection(0.0, 0.0), MDirection::AZEL);
     710           0 :         thisDir.shift(-ada.u()/ns2m, ada.v()/ns2m, true);
     711           0 :         addPointing(thisDir, fieldDir, itsAntId[a]);
     712             :       }
     713             :     }
     714             :   }
     715             : 
     716             :   // Now create a bunch of blocks that are necessary for reindexing the data
     717             :   // from different correlator blocks into the appropriate rows of the MS.
     718           0 :   Block<Block<VLAEnum::CDA> > CDAId; // Maps the local spectral ID to CDA's
     719             :                                      // ie., CDAId[0:nSpID][0:nCDA] = whichCDA
     720           0 :   Block<Block<uInt> > polId(maxCDA); // contains the polarisation index for 
     721             :                                      // each CDA
     722             :                                      // ie., polId[0:4][0:nPols] = polIdx;
     723             : 
     724           0 :   Block<Block<uInt> > polTypes(maxCDA);
     725           0 :   Block<Block<uInt> > polNewOrder;
     726           0 :   Vector<Bool> rotStokesOrder;
     727             :   
     728             : 
     729           0 :   for (uInt c = 0; c < maxCDA; c++) {
     730           0 :     const VLACDA& cda = itsRecord.CDA(c);
     731           0 :     if (!cda.isValid()) {
     732           0 :       itsSpId[c] = -1;
     733             :     } else {
     734           0 :       const VLAEnum::CDA thisCDA = VLAEnum::CDA(c);
     735             :       // can not deal with npol = 0, may be arising in poorly understood old correlator modes, needs investigating
     736           0 :       if (sda.npol(thisCDA) == 0) {
     737             :           // warn once and consider as if this is an invalid CDA
     738           0 :           if (!itsNoPolInfoWarned) {
     739           0 :               itsNoPolInfoWarned = true;
     740           0 :               itsLog << LogIO::SEVERE
     741             :                      << "Unable to determine polarization information for some or all correlator modes." << endl
     742             :                      << "That data can not be filled and the resulting visibility file may be empty."
     743           0 :                      << LogIO::POST;
     744             :           }
     745           0 :           itsSpId[c] = -1;
     746             :       } else {
     747             :           // Firstly, determine the spectral characteristics of the
     748             :           // data in the current CDA
     749           0 :           const uInt nChan = sda.nChannels(thisCDA);
     750           0 :           const Unit hz("Hz");
     751           0 :           const Double chanWidth = sda.channelWidth(thisCDA);
     752           0 :           const Quantum<Double> bandwidth(nChan*chanWidth, hz);
     753             :           // The tolerance is set at 1/4 of a channel. It is not set smaller
     754             :           // because when Doppler tracking is used the total bandwidth, when
     755             :           // converted to the rest type, will be slightly different from the
     756             :           // topocentric value. 
     757             :           // above is the original comments.
     758             :           // We reset the default tolerance for frequency to be the value of the
     759             :           // channel width and also give user the ability to pass in a tolerance
     760             :           // for frequency into vlafillerfromdisk(). For dataset G192 we need a 
     761             :           // tolerance of 6 times of the channe width. For dataset NGC7538, one
     762             :           // has to give a tolerance as larger as 60 times its channel width ( 60000000Hz ).
     763             :       
     764           0 :           if( itsFreqTolerance == 0.0 ) itsFreqTolerance = chanWidth;
     765           0 :           const Quantum<Double> tolerance( itsFreqTolerance, hz);
     766             :           // Determine the reference frequency.
     767           0 :           MFrequency refFreq;
     768             :           {
     769           0 :               if (sda.dopplerTracking(thisCDA)) {
     770           0 :                   const MDoppler dop(Quantity(sda.radialVelocity(thisCDA), "m/s"),
     771           0 :                                      sda.dopplerDefn(thisCDA));
     772             :                   refFreq =
     773           0 :                       MFrequency::fromDoppler(dop,
     774           0 :                                               MVFrequency(sda.restFrequency(thisCDA)), 
     775           0 :                                               sda.restFrame(thisCDA));
     776             :               } else {
     777           0 :                   refFreq = MFrequency(MVFrequency(sda.obsFrequency(thisCDA)),
     778           0 :                                        MFrequency::TOPO);
     779             :               }
     780             :           }
     781             :           // The local spectral Id is the value that is either zero or one and
     782             :           // depends on which IF the data in the CDA came from. Be aware that data
     783             :           // from IF B may have a local spectral Id value of either zero or one,
     784             :           // depending on whether IF A is also being used.
     785             :           uInt localSpId;
     786             :           // See if there is a matching row.
     787             :           {
     788           0 :               const uInt nSpId = CDAId.nelements();
     789           0 :               const uInt ifChain = sda.electronicPath(thisCDA);
     790             :               // set MeasFrame to MeasRef of MFrequency, which is need when converting MFrequency
     791             :               // a different frame. 
     792             :               // refFreq.getRef().set( itsFrame );
     793             :               // no, ScalarMeasColumn<M>put() will not accept this! so instead, we do
     794             :               // Find the channel frequencies and pass the first one to matchSpw().
     795           0 :               Vector<Double> chanFreqs(nChan);
     796           0 :               indgen(chanFreqs, sda.edgeFrequency( thisCDA )+0.5*chanWidth, chanWidth);
     797           0 :               const MFrequency::Types itsFreqType = MFrequency::castType(refFreq.getRef().getType());
     798           0 :               if (itsFreqType != MFrequency::TOPO) { 
     799             :                   // have to convert the channel frequencies from topocentric to the specifed
     800             :                   // frequency type.
     801           0 :                   MFrequency::Convert freqCnvtr;
     802           0 :                   freqCnvtr.setModel( MFrequency(MVFrequency(), MFrequency::Ref( MFrequency::TOPO, itsFrame )) );
     803           0 :                   freqCnvtr.setOut( itsFreqType );
     804           0 :                   Double freqInHzCnvtrd = freqCnvtr(chanFreqs(0)).getValue().getValue();
     805           0 :                   chanFreqs( 0 ) = freqInHzCnvtrd;
     806             :               }
     807             : 
     808           0 :               MFrequency chanFreq1 = MFrequency( MVFrequency( chanFreqs( 0 ) ), itsFreqType );
     809             :               // now call the matchSpw() method:
     810           0 :               itsSpId[c] = spectralWindow().matchSpw(refFreq, chanFreq1, itsFrame, doppler(), source(), nChan, bandwidth,
     811           0 :                                                      ifChain, tolerance, itsSpId[c]);
     812             : 
     813             :               // for testing frequency handling
     814             :               /*
     815             :                 cout.precision(12);
     816             :                 cout << "Field = " << sda.sourceName() 
     817             :                 << " " << Int(thisCDA)
     818             :                 << " lo=" << sda.edgeFrequency(thisCDA)
     819             :                 << " (" << sda.obsFrequency(thisCDA)<<")"
     820             :                 << " frame="<< sda.restFrame(thisCDA)
     821             :                 << " v="<< sda.radialVelocity(thisCDA)
     822             :                 << " rest="<< sda.restFrequency(thisCDA)
     823             :                 << " freq1="<<chanFreqs(0)
     824             :                 << " new="<<itsSpId[c]
     825             :                 << endl;
     826             :               */
     827             : 
     828           0 :               if (itsSpId[c] < 0) {
     829             :                   // add an entry to Dopper subtable before addSpectralWindow! Also make sure addSouce is called before this!
     830           0 :                   addDoppler( thisCDA );
     831           0 :                   itsSpId[c] = addSpectralWindow(thisCDA, refFreq, nChan,
     832             :                                                  bandwidth.getValue(hz), ifChain);
     833           0 :                   localSpId = nSpId;
     834             :               } else {
     835           0 :                   localSpId = 0;
     836           0 :                   while (localSpId < nSpId && 
     837           0 :                          CDAId[localSpId].nelements() > 0 && 
     838           0 :                          itsSpId[CDAId[localSpId][0]] != itsSpId[c]) {
     839           0 :                       localSpId++;
     840             :                   }
     841             :               }
     842           0 :               if (localSpId == nSpId) {
     843           0 :                   CDAId.resize(nSpId + 1);
     844             :               }
     845             :           }
     846             :           // Put this CDA into its spot the indexing blocks.
     847           0 :           const uInt nCDA = CDAId[localSpId].nelements();
     848           0 :           CDAId[localSpId].resize(nCDA + 1);
     849           0 :           CDAId[localSpId][nCDA] = thisCDA;
     850           0 :           uInt polIdx = 0;
     851           0 :           if (nCDA != 0) { // Here is a tricky section for you. 
     852             :               // The debugging statements should help
     853           0 :               const Block<uInt>& prevPolId =  polId[CDAId[localSpId][nCDA-1]];
     854           0 :               polIdx = prevPolId[prevPolId.nelements()-1] + 1;
     855             : 
     856             : #if defined(AIPS_DEBUG)
     857           0 :               itsLog << LogIO::DEBUGGING;
     858           0 :               itsLog << "CDA's containing this spectral ID: [";
     859           0 :               for (uInt c = 0; c < CDAId[localSpId].nelements(); c++) {
     860           0 :                   itsLog << static_cast<Int>(CDAId[localSpId][c])
     861           0 :                          << ((c+1 < CDAId[localSpId].nelements()) ? ", " : "]\n");
     862             :               }
     863           0 :               itsLog << "The previous CDA containing this spectral ID: " 
     864           0 :                      << static_cast<Int>(CDAId[localSpId][nCDA-1]) << endl;
     865           0 :               itsLog << "The polarization map of this CDA: [" ;
     866             :               {
     867           0 :                   const uInt w = CDAId[localSpId][nCDA-1];
     868           0 :                   for (uInt c = 0; c < polId[w].nelements(); c++) {
     869           0 :                       itsLog << polId[w][c]
     870           0 :                              << ((c+1 < polId[w].nelements()) ? ", " : "]\n");
     871             :                   }
     872             :               }
     873           0 :               itsLog << "The last element of the polarization map: " 
     874           0 :                      << prevPolId.nelements()-1 << endl;
     875           0 :               itsLog << "The next polarization starts at index: " 
     876           0 :                      <<  polIdx << endl;
     877           0 :               itsLog << LogIO::POST << LogIO::NORMAL;
     878             : #endif
     879             :           }
     880           0 :           const uInt nPols = sda.npol(thisCDA);
     881           0 :           polId[c].resize(nPols);
     882           0 :           for (uInt p = 0; p < nPols; p++) {
     883           0 :               polId[c][p] = p + polIdx;
     884             :           }
     885             :       }
     886             :     }
     887             :   }
     888           0 :   const uInt nSpId = CDAId.nelements();
     889           0 :   if (nSpId == 0) {
     890             :     // This can occur if there is a single antenna subarray doing VLBI. This
     891             :     // antenna may not be connected to the VLA correlator and hence the
     892             :     // auto-correlation cannot be calculated. In this case all the CDA's are
     893             :     // invalid and there is no data to add to the main table of the MS.
     894           0 :     DebugAssert(nAnt == 1, AipsError);
     895           0 :     return true; 
     896             :   }
     897             : 
     898             :   // Check if the transfer switch is only set on some antennas. If so warn
     899             :   // the user that the polarization may be misslabeled
     900             :   {
     901           0 :     const Stokes::StokesTypes ant0Pol = itsRecord.ADA(0).ifPol(VLAEnum::IFA);
     902           0 :     for (uInt a = 1; a < nAnt; a++) {
     903           0 :       if (itsRecord.ADA(a).ifPol(VLAEnum::IFA) != ant0Pol) {
     904             :           // only warn if there's been no warning on this antenna yet - only ants with warnings are ever here
     905           0 :           if (itsTransferWarned.count(itsRecord.ADA(a).antName(itsNewAntName)) == 0) {
     906           0 :               itsLog << LogIO::WARN
     907             :                      << "The IF transfer switch for antenna " 
     908           0 :                      << itsRecord.ADA(a).antName(itsNewAntName)
     909             :                      << " is different from the setting for antenna " 
     910           0 :                      << itsRecord.ADA(0).antName(itsNewAntName) << "." << endl
     911             :                      << "Correlations involving this antenna may have "
     912             :                      << "incorrect polarization labelling." 
     913           0 :                      << LogIO::POST;
     914           0 :               itsTransferWarned[itsRecord.ADA(a).antName(itsNewAntName)] = true;
     915             :           }
     916             :       }
     917             :     }
     918             :   }
     919             : 
     920             :   // Now sort out the polarisation subtable
     921           0 :   if (nSpId != itsPolId.nelements()) {
     922           0 :     itsPolId.resize(nSpId, true);
     923           0 :     itsPolId = -1;
     924             :   }
     925           0 :   polTypes.resize(nSpId);
     926           0 :   polNewOrder.resize(nSpId);
     927           0 :   rotStokesOrder.resize(nSpId);
     928           0 :   rotStokesOrder.set(false);
     929           0 :   for (uInt s = 0; s < nSpId; s++) {
     930           0 :     const Block<VLAEnum::CDA>& usedCDAs = CDAId[s];
     931           0 :     const uInt nCda = usedCDAs.nelements();
     932           0 :     uInt nPol = 0;
     933           0 :     for (uInt i = 0; i < nCda; i++) {
     934           0 :       nPol += polId[usedCDAs[i]].nelements();
     935             :     }
     936             :     
     937           0 :     Vector<Stokes::StokesTypes> allPols(nPol);
     938           0 :     uInt p = 0;
     939           0 :     for (uInt i = 0; i < nCda; i++) {
     940           0 :       Vector<Stokes::StokesTypes> pol(itsRecord.polarisations(usedCDAs[i]));
     941           0 :       for (uInt j = 0; j < pol.nelements(); j++, p++) {
     942           0 :         allPols(p) = pol(j);
     943             :       }
     944             :     }
     945           0 :     polTypes[s].resize(allPols.nelements());
     946           0 :     polNewOrder[s].resize(allPols.nelements());
     947             :     
     948           0 :     Bool standard=true;
     949           0 :     for (uInt i=0; i < allPols.nelements(); ++i){
     950           0 :       polTypes[s][i]=static_cast<uInt> (allPols[i]);
     951           0 :       polNewOrder[s][i]=i;
     952           0 :       if( (allPols[i] > Stokes::LL) || (allPols[i] < Stokes::RR)){
     953           0 :         standard=false;
     954             :       }
     955             :     }
     956             :     //Now if the 4-stokes are not in RR RL LR LL order....make sure it is
     957           0 :     if((allPols.nelements() == 4) && standard ){
     958           0 :       if(allPols[0] != Stokes::RR){
     959           0 :         rotStokesOrder[s]=true;
     960           0 :         polNewOrder[s][0]=polIndexer(allPols[0]);
     961             :       }
     962           0 :       if(allPols[1] != Stokes::RL){
     963           0 :         rotStokesOrder[s]=true;
     964           0 :         polNewOrder[s][1]=polIndexer(allPols[1]);
     965             :       } 
     966           0 :       if(allPols[2] != Stokes::LR){
     967           0 :         rotStokesOrder[s]=true;
     968           0 :         polNewOrder[s][2]=polIndexer(allPols[2]);
     969             :       }
     970           0 :       if(allPols[3] != Stokes::LL){
     971           0 :         rotStokesOrder[s]=true;
     972           0 :         polNewOrder[s][3]=polIndexer(allPols[3]);
     973             :       }
     974             : 
     975           0 :       allPols[0]=Stokes::RR; 
     976           0 :       allPols[1]=Stokes::RL;
     977           0 :       allPols[2]=Stokes::LR; 
     978           0 :       allPols[3]=Stokes::LL;
     979             :     }
     980           0 :     itsPolId[s] = polarization().match(allPols, itsPolId[s]);
     981           0 :     if (itsPolId[s] < 0) {
     982           0 :       itsPolId[s] = addPolarization(allPols);
     983             :     }
     984             :   }
     985             : 
     986             :   // Keep these values handy, as they are needed in lots of places
     987           0 :   Block<uInt> nChannels(nSpId);
     988           0 :   Block<uInt> nProducts(nSpId);
     989           0 :   for (uInt s = 0; s < nSpId; s++) {
     990           0 :     nProducts[s] = polarization().numCorr()(itsPolId[s]);
     991           0 :     nChannels[s] = spectralWindow().numChan()(itsSpId[CDAId[s][0]]);
     992             :   }
     993             : 
     994           0 :   Block<Int>& thisDataId = itsDataId[subArray];
     995             :   // Now sort out the data description subtable
     996           0 :   if (nSpId != thisDataId.nelements()) {
     997           0 :     thisDataId.resize(nSpId, true);
     998           0 :     thisDataId = -1;
     999             :   }
    1000           0 :   for (uInt s = 0; s < nSpId; s++) {
    1001           0 :     const uInt spwId = itsSpId[CDAId[s][0]];
    1002           0 :     Int newId = dataDescription().match(spwId, itsPolId[s], thisDataId[s]);
    1003           0 :     if (newId < 0) {
    1004           0 :       newId = addDataDescription(spwId, static_cast<uInt>(itsPolId[s]));
    1005             :       // this is a good place to add a hypercube as a new row in the Data
    1006             :       // Description subtable may specify a different data shape
    1007             :       //addHypercubes(nProducts[s], nChannels[s]);
    1008             :     }
    1009           0 :     if (newId != thisDataId[s]) {
    1010           0 :       thisDataId[s] = newId;
    1011           0 :       itsNewScan = true;
    1012             :     }
    1013             :   }
    1014             : 
    1015             : 
    1016             : 
    1017             : # if defined(AIPS_DEBUG)
    1018           0 :   itsLog << LogIO::DEBUGGING;
    1019           0 :   itsLog << CDAId.nelements() << " spectral ID's in this record "
    1020           0 :          << "(correlator mode '" << VLAEnum::name(sda. correlatorMode()) 
    1021           0 :          << "')" << endl;
    1022           0 :   for (uInt s = 0; s < CDAId.nelements(); s++) {
    1023           0 :     itsLog << "  Id: " << itsSpId[CDAId[s][0]] << " is in CDA's [";
    1024           0 :     for (uInt i = 0; i < CDAId[s].nelements(); i++) {
    1025           0 :       itsLog << static_cast<Int>(CDAId[s][i])+1
    1026           0 :              << ((i+1 < CDAId[s].nelements()) ? ", " : "]\n");
    1027             :     }
    1028           0 :     for (uInt cda = 0; cda < CDAId[s].nelements(); cda++) {
    1029           0 :       itsLog << "    CDA: " << static_cast<Int>(CDAId[s][cda]) + 1 
    1030           0 :              << " contains " << polId[CDAId[s][cda]].nelements() 
    1031           0 :              << " polarizations [";
    1032           0 :       for (uInt i = 0; i < polId[CDAId[s][cda]].nelements(); i++) {
    1033           0 :         itsLog << polId[CDAId[s][cda]][i]
    1034           0 :                << ((i+1 < polId[CDAId[s][cda]].nelements()) ? ", " : "] (");
    1035             :       }
    1036           0 :       Vector<Stokes::StokesTypes> pol(itsRecord.polarisations(CDAId[s][cda]));
    1037           0 :       for (uInt i = 0; i < pol.nelements(); i++) {
    1038           0 :         itsLog << Stokes::name(pol(i))
    1039           0 :                << ((i+1 < pol.nelements()) ? ", " : ")\n");
    1040             :       }
    1041             :     }
    1042             :   }
    1043           0 :   itsLog << LogIO::POST << LogIO::NORMAL;
    1044             : #endif
    1045             :   // decide if this is a new scan
    1046           0 :   if (itsNewScan) {
    1047           0 :     itsNewScan = false;
    1048           0 :     Int nextScan = itsScan[0];
    1049           0 :     for (uInt i = 1; i < maxSubarrays; i++) {
    1050           0 :       nextScan = max(nextScan, itsScan[i]);
    1051             :     }
    1052           0 :     itsScan[subArray] = nextScan + 1;
    1053             :     // flush any data to disk. This gives the user the opportunity to examine
    1054             :     // the MS while it is being filled. Doing it more frequently than once per
    1055             :     // scan starts to eat into the performance when filling from disk.
    1056           0 :     itsMS.flush(); 
    1057             :   }
    1058             :   // add empty rows
    1059           0 :   const uInt nCorr = (nAnt*(nAnt-1))/2;
    1060           0 :   uInt row = itsMS.nrow();
    1061           0 :   uInt rowsPerSpId = nCorr+nAnt;
    1062           0 :   if(!itsKeepAutoCorr)
    1063           0 :     rowsPerSpId = nCorr;
    1064           0 :   const uInt newRows = rowsPerSpId*nSpId;
    1065           0 :   itsMS.addRow(newRows);
    1066             :   //extendHypercubes(nProducts, nChannels, rowsPerSpId);
    1067             :   // Some variables needed in assorted places from now on.
    1068           0 :   Vector<Int> vecInt(newRows);
    1069           0 :   const Double intTime = sda.intTime();
    1070             :   { // fill the columns where all the rows are identical and independent of the
    1071             :     // data description id
    1072           0 :     const RefRows rows(row, row+newRows-1);
    1073           0 :     vecInt = itsScan[subArray];
    1074           0 :     scanNumber().putColumnCells(rows, vecInt);
    1075           0 :     vecInt = itsFldId[subArray];
    1076           0 :     fieldId().putColumnCells(rows, vecInt);
    1077           0 :     vecInt = subArray;
    1078           0 :     arrayId().putColumnCells(rows, vecInt);
    1079           0 :     vecInt = itsMS.observation().nrow();
    1080           0 :     observationId().putColumnCells(rows, vecInt);
    1081           0 :     vecInt = 0;
    1082           0 :     feed1().putColumnCells(rows, vecInt);
    1083           0 :     feed2().putColumnCells(rows, vecInt);
    1084           0 :     vecInt = -1;
    1085           0 :     stateId().putColumnCells(rows, vecInt);
    1086           0 :     processorId().putColumnCells(rows, vecInt);
    1087           0 :     Vector<Double> vecDbl(newRows, intTime);
    1088           0 :     exposure().putColumnCells(rows, vecDbl);
    1089           0 :     interval().putColumnCells(rows, vecDbl);
    1090           0 :     const MEpoch* mep = dynamic_cast<const MEpoch*>(itsFrame.epoch());
    1091           0 :     AlwaysAssert( mep != 0, AipsError);
    1092           0 :     vecDbl = mep->getValue().getTime("s").getValue();
    1093           0 :     time().putColumnCells(rows, vecDbl);
    1094           0 :     timeCentroid().putColumnCells(rows, vecDbl);
    1095             :   }
    1096             : 
    1097             :   // Construct a bunch of variables that will be used inside the data writing
    1098             :   // loop
    1099           0 :   Vector<Double> blUvw(3);
    1100           0 :   Matrix<Complex> cData(nProducts[0], nChannels[0]);
    1101           0 :   Matrix<Complex> modData(nProducts[0], nChannels[0]);
    1102           0 :   Matrix<Complex> onePol;
    1103           0 :   Matrix<Bool> flags(nProducts[0], nChannels[0]);
    1104           0 :   Vector<Float> weights(nProducts[0]), sigmas(nProducts[0]);
    1105           0 :   Cube<Bool> flagLevels(nProducts[0], nChannels[0], nCat);
    1106             :   VLAEnum::CDA cda;
    1107           0 :   vecInt.resize(rowsPerSpId);
    1108             : 
    1109           0 :   for (uInt s = 0; s < nSpId; s++) {
    1110           0 :     const Block<VLAEnum::CDA>& usedCDAs = CDAId[s];
    1111           0 :     const uInt nCDA = usedCDAs.nelements();
    1112           0 :     DebugAssert(nCDA > 0, AipsError);
    1113           0 :     const uInt nChan = nChannels[s];
    1114           0 :     const uInt nPol = nProducts[s];
    1115           0 :     const Double channelWidth = itsRecord.SDA().channelWidth(usedCDAs[0]);
    1116             :     
    1117             :     // fill the columns where all the rows are identical and dependent on the
    1118             :     // data description id
    1119             :     {
    1120           0 :       const RefRows rows(row, row+rowsPerSpId-1);
    1121           0 :       vecInt = thisDataId[s];
    1122           0 :       dataDescId().putColumnCells(rows, vecInt);
    1123             :     }
    1124             :     
    1125             :     // cache the online IF flags and nominal sensitivity of each antenna. It
    1126             :     // simplifies having to do it for each baseline later on.
    1127           0 :     Block<Matrix<VLAEnum::IF> > whichIF(nCDA);
    1128           0 :     Cube<Bool> antFlagLevels(maxIF, nAnt, 4, false);
    1129           0 :     Matrix<Bool> antFlag(maxIF, nAnt, false);
    1130           0 :     Matrix<Float> sens(maxIF, nAnt,0.333);
    1131           0 :     Bool isScaledByNS(false);
    1132             :     { // First work ouk out which IF's are used by this spectral id.
    1133           0 :       Block<Bool> usedIFs(maxIF, false);
    1134           0 :       for (uInt c = 0; c < nCDA; c++) {
    1135             :         const Matrix<VLAEnum::IF>& curIF = 
    1136           0 :           whichIF[c] = sda.ifUsage(usedCDAs[c]);
    1137           0 :         const uInt nCorr = curIF.ncolumn();
    1138           0 :         for (uInt p = 0; p < nCorr; p++) {
    1139           0 :           usedIFs[curIF(0, p)] = usedIFs[curIF(1, p)] = true;
    1140             :         }
    1141             :       }
    1142             : 
    1143             :       // For each antenna find the IF flags and sensitivity
    1144           0 :       Int nAntIF(0);
    1145           0 :       Int nAppAntIF(0);
    1146           0 :       for (uInt a = 0; a < nAnt; a++) { // set the flag to true if data is Bad
    1147           0 :         const VLAADA& ada = itsRecord.ADA(a);
    1148           0 :         for (uInt i = 0; i < maxIF; i++) {
    1149           0 :           if (usedIFs[i]) {
    1150           0 :             const VLAEnum::IF thisIF = static_cast<VLAEnum::IF>(i);
    1151           0 :             const Float ns = ada.nominalSensitivity(thisIF);
    1152           0 :             sens(i, a) = (ns > 1.0e-10) ? ns : 0.333; 
    1153             : 
    1154             :             // count Ant/IF combos that have nom sens applied to amplitudes
    1155           0 :             ++nAntIF;
    1156           0 :             if (ada.nomSensApplied(thisIF,rca.revision())) ++nAppAntIF;
    1157           0 :             const uInt status = ada.ifStatus(thisIF);
    1158           0 :             if (status > 0) badData = true;
    1159           0 :             if ((status&0x01) != 0) antFlagLevels(i, a, 0) = true;
    1160           0 :             if ((status&0x02) != 0) antFlagLevels(i, a, 1) = true;
    1161           0 :             if ((status&0x04) != 0) antFlag(i, a)=antFlagLevels(i, a, 2)=true;
    1162           0 :             if ((status&0x08) != 0) antFlag(i, a)=antFlagLevels(i, a, 3)=true;
    1163           0 :             if(!isHolo) {
    1164           0 :               antFlag(i, a) |= shadowed[a];
    1165             :             }
    1166             :           }
    1167             :         }
    1168             :       }
    1169             :       // determine global state of nom sens application
    1170           0 :       if (nAppAntIF==0) {
    1171           0 :         isScaledByNS=false;
    1172             :         //      cout << "****DATA has NOT been scaled by NOMINAL SENSITIVITY*****************" << endl;
    1173             :       }
    1174             :       else {
    1175             :         // one or more ant/if combos indicate that NOM SENS has been applied
    1176             :         //  in this case it is true for all even if not indicated for all.
    1177           0 :         isScaledByNS=true;
    1178             :         //      cout << "****DATA has been scaled by NOMINAL SENSITIVITY*****************" << endl;
    1179             :       }
    1180             :     }
    1181             :   
    1182           0 :     cData.resize(nPol, nChan);
    1183           0 :     modData.resize(nPol, nChan);
    1184           0 :     if(nPol==4){
    1185           0 :       modData.row(0).set(1);
    1186           0 :       modData.row(3).set(1);
    1187           0 :       modData.row(1).set(0);
    1188           0 :       modData.row(2).set(0); 
    1189             :     }
    1190             :     else{
    1191           0 :       modData.set(1);
    1192             :     }
    1193           0 :     weights.resize(nPol); 
    1194           0 :     sigmas.resize(nPol); 
    1195           0 :     flags.resize(nPol, nChan); 
    1196           0 :     flagLevels.resize(nPol, nChan, nCat); 
    1197           0 :     if (!badData) {
    1198           0 :       flags = false;
    1199           0 :       flagLevels = false;
    1200             :     }
    1201           0 :     if (nChan != 1 && nPol != 1 ) onePol.resize(1, nChan);
    1202           0 :     const Slice allChan(0, nChan);
    1203             : 
    1204             :     // Fill in the correlations
    1205           0 :     uInt b = 0;
    1206           0 :     for (uInt a1 = 0; a1 < nAnt; a1++) {
    1207           0 :       for (uInt a2 = a1; a2 < nAnt; a2++) {
    1208           0 :         const Bool crossCorr = (a1 == a2) ? false : true;
    1209           0 :         if(crossCorr || (!crossCorr && itsKeepAutoCorr)){
    1210           0 :           for (uInt c = 0; c < nCDA; c++) {
    1211           0 :             cda = usedCDAs[c];
    1212           0 :             if (nChan == 1 || nPol == 1) {
    1213           0 :               if (crossCorr) {
    1214           0 :                 itsRecord.CDA(cda).crossCorr(b).data(cData);
    1215             :               } else {
    1216           0 :                 itsRecord.CDA(cda).autoCorr(a1).data(cData);
    1217             :               }
    1218           0 :               if(nPol==4 && rotStokesOrder[s]){
    1219           0 :                 Vector<Complex> olddata(4);
    1220           0 :                 olddata=cData.column(0);
    1221           0 :                 for (uInt kk=0; kk < 4; ++kk){
    1222           0 :                   cData.column(0)(polNewOrder[s][kk])=olddata[kk];
    1223             :                 } 
    1224           0 :               }
    1225             :             } else {
    1226           0 :               DebugAssert(polId[cda].nelements() == 1, AipsError);
    1227           0 :               if (crossCorr) {
    1228           0 :                 itsRecord.CDA(cda).crossCorr(b).data(onePol);
    1229             :               } else {
    1230           0 :                 itsRecord.CDA(cda).autoCorr(a1).data(onePol);
    1231             :               } 
    1232           0 :               const Slice curPol(polNewOrder[s][polId[cda][0]], 1);
    1233           0 :               cData(curPol, allChan) = onePol;
    1234             :             }
    1235           0 :             const Matrix<VLAEnum::IF>& curIF = whichIF[c];
    1236           0 :             if (nChan == 1) { // Continuum
    1237           0 :               DebugAssert(curIF.ncolumn() == 4, AipsError);
    1238           0 :               DebugAssert(polId[cda][0] == 0, AipsError);
    1239             :               uInt p;
    1240           0 :               for (uInt ip = 0; ip < 4; ip++) {
    1241           0 :                 const VLAEnum::IF if0 = curIF(0, ip);
    1242           0 :                 const VLAEnum::IF if1 = curIF(1, ip);
    1243             : 
    1244             :                 // re-ordered output poln (ip-->p)!
    1245           0 :                 p=polNewOrder[s][ip];
    1246             : 
    1247           0 :                 const Double w = intTime * .12/10000.;
    1248             :                 // The fudge factor of .12/10000 is to make the VLA filler
    1249             :                 // consistent with AIPS. It is discussed in the .help file.
    1250           0 :                 weights(p) = w * channelWidth;
    1251           0 :                 sigmas(p) = 1.0/ sqrt(w * channelWidth);
    1252             : 
    1253             :                 // If requested, apply Tsys scaling to data & weights
    1254           0 :                 if (itsApplyTsys) {
    1255             :                   // sens already guaranteed > 0.0
    1256           0 :                   Float blsens = sens(if0, a1) * sens(if1, a2);
    1257             :                   
    1258             :                   // always apply to weights & sigma
    1259           0 :                   weights(p)/=blsens;
    1260           0 :                   sigmas(p)*=sqrt(blsens);
    1261             : 
    1262             :                   // only apply to data if necessary (post-ModComp)
    1263           0 :                   if (!isScaledByNS) 
    1264           0 :                     cData(p,0)*=sqrt(blsens);
    1265             :                   
    1266             :                 }
    1267             :                 else
    1268             :                   // Raw CCs requested
    1269           0 :                   if (isScaledByNS) {
    1270             :                     // UN-correct data which was scaled on-line (e.g. pre-EVLA)
    1271           0 :                     Float blsens = sens(if0, a1) * sens(if1, a2);
    1272             :                     // Only if correction is sane
    1273           0 :                     if (blsens>1.0e-10)
    1274           0 :                       cData(p,0)/=sqrt(blsens);
    1275             :                   }
    1276             : 
    1277             : 
    1278           0 :                 if (badData) {
    1279           0 :                   flags(p, 0) = antFlag(if0, a1) || antFlag(if1, a2);
    1280           0 :                   for (uInt l = 0; l < 4; l++) {
    1281           0 :                     flagLevels(p, 0, l) = 
    1282           0 :                       antFlagLevels(if0, a1, l) || antFlagLevels(if1, a2, l);
    1283             :                   }
    1284             :                   // Don't flag holography data for apparent shadowing
    1285             :                   // since we don't actually know if the data is
    1286             :                   // shadowed
    1287           0 :                   if(isHolo) {
    1288           0 :                     flagLevels(p, 0, 4) = false;
    1289             :                   }
    1290             :                   else {
    1291           0 :                     flagLevels(p, 0, 4) = shadowed[a1] || shadowed[a2];
    1292             :                   }
    1293           0 :                   flagLevels(p, 0, 5) = false;
    1294             :                 }
    1295             :               }
    1296             :             } else {// spectral line
    1297           0 :               DebugAssert(curIF.ncolumn() == 1, AipsError);
    1298           0 :               const VLAEnum::IF if0 = curIF(0, 0);
    1299           0 :               const VLAEnum::IF if1 = curIF(1, 0);
    1300             : 
    1301             :               // re-ordered output polarization!
    1302             :               //  const uInt startPol = polId[cda][0];
    1303           0 :               const uInt startPol =polNewOrder[s][polId[cda][0]];
    1304             : 
    1305           0 :               const Double w = intTime  * .12/10000.;
    1306             :               // The fudge factor of .12/10000 is to make the VLA filler
    1307             :               // consitant with AIPS. It is discussed in the .help file.
    1308           0 :               weights(startPol) = w * channelWidth;
    1309           0 :               sigmas(startPol) = 1.0/sqrt(w * channelWidth);
    1310             : 
    1311             :               // If requested, apply Tsys scaling to data & weights
    1312           0 :               if (itsApplyTsys) {
    1313           0 :                 const Float blsens = sens(if0, a1) * sens(if1, a2);
    1314             : 
    1315             :                 // always apply to weights & sigma
    1316           0 :                 weights(startPol)/=blsens;
    1317           0 :                 sigmas(startPol)*=sqrt(blsens);
    1318             :                 
    1319             :                 // only apply to data if necessary (post-ModComp)
    1320           0 :                 if (!isScaledByNS) {
    1321           0 :                   Array<Complex> thisdat(cData(startPol,allChan));
    1322           0 :                   thisdat*=sqrt(blsens);
    1323             :                 }
    1324             :               }
    1325             :               else
    1326             :                 // Raw CCs requested
    1327           0 :                 if (isScaledByNS) {
    1328             :                   // UN-correct data which was scaled on-line
    1329           0 :                   const Float blsens = sens(if0, a1) * sens(if1, a2);
    1330           0 :                   Array<Complex> thisdat(cData(startPol,allChan));
    1331           0 :                   thisdat/=sqrt(blsens);
    1332             :                 }
    1333             : 
    1334           0 :               if (badData) {
    1335           0 :                 const Slice curPol(startPol, 1);
    1336           0 :                 flags(curPol, allChan) = antFlag(if0, a1) || antFlag(if1, a2);
    1337           0 :                 for (uInt l = 0; l < 4; l++) {
    1338           0 :                   flagLevels(curPol, allChan, l) = 
    1339           0 :                     antFlagLevels(if0, a1, l) || antFlagLevels(if1, a2, l);
    1340             :                 }
    1341           0 :                 if(isHolo) {
    1342           0 :                   flagLevels(curPol, allChan, 4) = false;
    1343             :                 }
    1344             :                 else {
    1345           0 :                   flagLevels(curPol, allChan, 4) = shadowed[a1] || shadowed[a2];
    1346             :                 }
    1347           0 :                 flagLevels(curPol, allChan, 5) = false;
    1348             :               }
    1349             :             }
    1350             :           }
    1351             :           
    1352             :           // Some aips++ tools, in particular calibrator, require that the index
    1353             :           // in ANTENNA1 be less than or equal to the index in the ANTENNA2
    1354             :           // column. To accommodate this they are swapped here.
    1355           0 :           uInt ant1 = a1;
    1356           0 :           uInt ant2 = a2;
    1357           0 :           if (itsAntId[a1] > itsAntId[a2]) {
    1358           0 :             if(nPol < 4){
    1359           0 :               cData=conj(cData);
    1360             :             }
    1361             :             else{
    1362           0 :               cData.row(0)=conj(cData.row(0));
    1363           0 :               cData.row(3)=conj(cData.row(3));
    1364             :               //R_iL_j has to be moved to L_jR_i
    1365           0 :               Vector<Complex> tmprldata=conj(cData.row(1));
    1366           0 :               cData.row(1)=conj(cData.row(2));
    1367           0 :               cData.row(2)=tmprldata;
    1368           0 :               Float tmpwt=weights(1);
    1369           0 :               weights(1)=weights(2);
    1370           0 :               weights(2)=tmpwt;
    1371           0 :               tmpwt=sigmas(1);
    1372           0 :               sigmas(1)=sigmas(2);
    1373           0 :               sigmas(2)=tmpwt;
    1374           0 :               Vector<Bool> tmpflg=flags.row(1);
    1375           0 :               flags.row(1)=flags.row(2);
    1376           0 :               flags.row(2)=tmpflg;
    1377             :             }      
    1378           0 :             ant1 = a2;
    1379           0 :             ant2 = a1;
    1380             :           }  
    1381             : 
    1382           0 :           weight().put(row, weights);
    1383           0 :           sigma().put(row, sigmas);
    1384           0 :           flag().put(row, flags);
    1385           0 :           flagCategory().put(row, flagLevels);
    1386           0 :           if (badData) {
    1387           0 :             flagRow().put(row, allEQ(flags, true));
    1388             :           } else {
    1389           0 :             flagRow().put(row, false);
    1390             :           }
    1391             : 
    1392             : 
    1393           0 :           data().put(row, cData);
    1394           0 :           correctedData().put(row,cData);
    1395           0 :           modelData().put(row, modData);
    1396           0 :           uInt a1Index = ant1*3, a2Index = ant2*3;
    1397           0 :           if(isHolo) {
    1398           0 :             blUvw=0.0;
    1399             :           }
    1400             :           else {
    1401           0 :             blUvw(0) = antUvw[a1Index] - antUvw[a2Index]; a1Index++; a2Index++;
    1402           0 :             blUvw(1) = antUvw[a1Index] - antUvw[a2Index]; a1Index++; a2Index++;
    1403           0 :             blUvw(2) = antUvw[a1Index] - antUvw[a2Index];
    1404             :           }
    1405           0 :           uvw().put(row, blUvw);
    1406           0 :           antenna1().put(row, itsAntId[ant1]);
    1407           0 :           antenna2().put(row, itsAntId[ant2]); row++;
    1408           0 :           if (crossCorr) b++;
    1409             :         }
    1410             :       }
    1411             :     }
    1412             :   }
    1413           0 :   return true;
    1414             : }
    1415             : 
    1416           0 : MeasurementSet VLAFiller::
    1417             : getMS(const Path& tableName, const Bool overwrite) {
    1418           0 :   if (overwrite == false && File(tableName).exists()) {
    1419           0 :     return openMS(tableName);
    1420             :   } else {
    1421           0 :     return emptyMS(tableName, overwrite);
    1422             :   }
    1423             : }
    1424             : 
    1425           0 : MeasurementSet VLAFiller::
    1426             : emptyMS(const Path& tableName, const Bool overwrite) {
    1427           0 :   AlwaysAssert(tableName.isValid(), AipsError);
    1428           0 :   AlwaysAssert(File(tableName.dirName()).isWritable(), AipsError);
    1429             : 
    1430             :   // Add all the required columns
    1431           0 :   TableDesc msDesc = MeasurementSet::requiredTableDesc();
    1432             :   // Add the data column (as it is an an optional one)
    1433           0 :   MeasurementSet::addColumnToDesc(msDesc, MeasurementSet::DATA, 2);
    1434             :   //Scratch columns
    1435           0 :   MeasurementSet::addColumnToDesc(msDesc, MeasurementSet::MODEL_DATA, 2);
    1436           0 :   MeasurementSet::addColumnToDesc(msDesc, MeasurementSet::CORRECTED_DATA, 2);
    1437             : 
    1438             :   // Add the tiled id column indices
    1439             :   /*
    1440             :   msDesc.addColumn(ScalarColumnDesc<Int>(dataTileId.fieldName(),
    1441             :                                      "Index for Data tiling"));
    1442             :   msDesc.addColumn(ScalarColumnDesc<Int>(sigmaTileId.fieldName(),
    1443             :                                      "Index for Sigma tiling"));
    1444             :   msDesc.addColumn(ScalarColumnDesc<Int>(flagTileId.fieldName(),
    1445             :                                      "Index for Flag Category tiling"));
    1446             :   
    1447             :   msDesc.addColumn(ScalarColumnDesc<Int>(modDataTileId.fieldName(),
    1448             :                                      "Index for Model Data tiling"));
    1449             :   msDesc.addColumn(ScalarColumnDesc<Int>(corrDataTileId.fieldName(),
    1450             :                                      "Index for Corrected Data tiling"));
    1451             :   msDesc.addColumn(ScalarColumnDesc<Int>(chanFlagTileId.fieldName(),
    1452             :                                      "Index for Flag  tiling"));
    1453             :   */
    1454             :   // setup hypercolumns for the data/flag/flag_catagory/sigma & weight columns.
    1455             :   {
    1456           0 :     Vector<String> dataCols(1);
    1457           0 :     dataCols(0) = MeasurementSet::columnName(MeasurementSet::DATA);
    1458           0 :     const Vector<String> coordCols(0);
    1459           0 :     const Vector<String> idCols(1, dataTileId.fieldName());
    1460             :     //   msDesc.defineHypercolumn(dataCol, 3, dataCols, coordCols, idCols);
    1461           0 :     msDesc.defineHypercolumn(dataCol, 3, dataCols);
    1462             :   }
    1463             :   {
    1464           0 :     Vector<String> dataCols(1);
    1465           0 :     dataCols(0) = MeasurementSet::columnName(MeasurementSet::MODEL_DATA);
    1466           0 :     const Vector<String> coordCols(0);
    1467           0 :     const Vector<String> idCols(1, modDataTileId.fieldName());
    1468             :     // msDesc.defineHypercolumn(modDataCol, 3, dataCols, coordCols, idCols);
    1469           0 :     msDesc.defineHypercolumn(modDataCol, 3, dataCols);
    1470             :   }
    1471             :   {
    1472           0 :     Vector<String> dataCols(1);
    1473           0 :     dataCols(0) = MeasurementSet::columnName(MeasurementSet::CORRECTED_DATA);
    1474           0 :     const Vector<String> coordCols(0);
    1475           0 :     const Vector<String> idCols(1, corrDataTileId.fieldName());
    1476             :     //msDesc.defineHypercolumn(corrDataCol, 3, dataCols, coordCols, idCols);
    1477           0 :     msDesc.defineHypercolumn(corrDataCol, 3, dataCols);
    1478             :   }
    1479             :   {
    1480           0 :     Vector<String> dataCols(1);
    1481           0 :     dataCols(0) = MeasurementSet::columnName(MeasurementSet::FLAG);
    1482           0 :     const Vector<String> coordCols(0);
    1483           0 :     const Vector<String> idCols(1, chanFlagTileId.fieldName());
    1484             :     //msDesc.defineHypercolumn(chanFlagCol, 3, dataCols, coordCols, idCols);
    1485           0 :     msDesc.defineHypercolumn(chanFlagCol, 3, dataCols);
    1486             :   }
    1487             :   {
    1488           0 :     Vector<String> dataCols(1);
    1489           0 :     dataCols(0) = MeasurementSet::columnName(MeasurementSet::SIGMA);
    1490           0 :     const Vector<String> coordCols(0);
    1491           0 :     const Vector<String> idCols(1, sigmaTileId.fieldName());
    1492             :     //msDesc.defineHypercolumn(sigmaCol, 2, dataCols, coordCols, idCols);
    1493           0 :     msDesc.defineHypercolumn(sigmaCol, 2, dataCols);
    1494             :   }
    1495             :   //sigma and weight unbound as of moving to tiledshapestman
    1496             :   {
    1497           0 :     Vector<String> dataCols(1);
    1498           0 :     dataCols(0) = MeasurementSet::columnName(MeasurementSet::WEIGHT);
    1499           0 :     const Vector<String> coordCols(0);
    1500           0 :     const Vector<String> idCols(1, sigmaTileId.fieldName());
    1501           0 :     msDesc.defineHypercolumn("TiledWgtCol", 2, dataCols);
    1502             :   }
    1503             : 
    1504             :   {
    1505             :     const Vector<String> dataCols
    1506           0 :       (1, MeasurementSet::columnName(MeasurementSet::FLAG_CATEGORY));
    1507           0 :     const Vector<String> coordCols(0);
    1508           0 :     const Vector<String> idCols(1, flagTileId.fieldName());
    1509             :     //   msDesc.defineHypercolumn(flagCol, 4, dataCols, coordCols, idCols);
    1510           0 :     msDesc.defineHypercolumn(flagCol, 4, dataCols);
    1511             :   }
    1512             :   
    1513           0 :   Table::TableOption option = Table::NewNoReplace;
    1514           0 :   if (overwrite) option = Table::New;
    1515           0 :   SetupNewTable newMS(tableName.originalName(), msDesc, option);
    1516             : 
    1517             :   // setup storage managers. Use the incremental storage manager for
    1518             :   // columns where the data is likely to be the same for more than four
    1519             :   // rows at a time.
    1520             :   {
    1521           0 :     IncrementalStMan incrMan("Incremental data manager");
    1522           0 :     newMS.bindColumn(MeasurementSet::
    1523             :                      columnName(MeasurementSet::ARRAY_ID), incrMan);
    1524           0 :     newMS.bindColumn(MeasurementSet::
    1525             :                      columnName(MeasurementSet::EXPOSURE), incrMan);
    1526           0 :     newMS.bindColumn(MeasurementSet::
    1527             :                      columnName(MeasurementSet::FEED1), incrMan);
    1528           0 :     newMS.bindColumn(MeasurementSet::
    1529             :                      columnName(MeasurementSet::FEED2), incrMan);
    1530           0 :     newMS.bindColumn(MeasurementSet::
    1531             :                      columnName(MeasurementSet::FIELD_ID), incrMan);
    1532           0 :     newMS.bindColumn(MeasurementSet::
    1533             :                      columnName(MeasurementSet::FLAG_ROW), incrMan);
    1534           0 :     newMS.bindColumn(MeasurementSet::
    1535             :                      columnName(MeasurementSet::INTERVAL), incrMan);
    1536           0 :     newMS.bindColumn(MeasurementSet::
    1537             :                      columnName(MeasurementSet::OBSERVATION_ID), incrMan);
    1538           0 :     newMS.bindColumn(MeasurementSet::
    1539             :                      columnName(MeasurementSet::PROCESSOR_ID), incrMan);
    1540           0 :     newMS.bindColumn(MeasurementSet::
    1541             :                      columnName(MeasurementSet::SCAN_NUMBER), incrMan);
    1542           0 :     newMS.bindColumn(MeasurementSet::
    1543             :                      columnName(MeasurementSet::STATE_ID), incrMan);
    1544           0 :     newMS.bindColumn(MeasurementSet::
    1545             :                      columnName(MeasurementSet::TIME), incrMan);
    1546           0 :     newMS.bindColumn(MeasurementSet::
    1547             :                      columnName(MeasurementSet::TIME_CENTROID), incrMan);
    1548             :   }
    1549             :   // Use a 1 MB tile size
    1550             :   // The tile length should not be shorter than (npol, nchan)
    1551             :   // in the first 2 dimensions, otherwise performance suffers
    1552             :   // due to bookkeeping overhead [yes, that implies that using
    1553             :   // tiling is pretty pointless for such small data... But then 
    1554             :   // you will suffer from the horrors of BucketCache.]. Therefore 
    1555             :   // set the length to the maximum. Unfortunately npol, nchan is
    1556             :   // unknown here, so set the lengths to (4,128); the consequence
    1557             :   // of hardcoding this is that the real tile size will be less
    1558             :   // than 1MB, in fact 1MB/(4*128) = 2KB for npol=nchan columns.
    1559           0 :   IPosition tileShape(3, 4, 128, 256);
    1560             : 
    1561             :   {
    1562             :     //TiledDataStMan dataMan(dataCol);
    1563           0 :     TiledShapeStMan dataMan(dataCol, tileShape);
    1564           0 :     newMS.bindColumn(MeasurementSet::
    1565             :                      columnName(MeasurementSet::DATA), dataMan);
    1566             :     //   newMS.bindColumn(dataTileId.fieldName(), dataMan);
    1567             :   }
    1568             :   {
    1569             :     //TiledDataStMan dataMan(modDataCol);
    1570           0 :     TiledShapeStMan dataMan(modDataCol, tileShape);
    1571           0 :     newMS.bindColumn(MeasurementSet::
    1572             :                      columnName(MeasurementSet::MODEL_DATA), dataMan);
    1573             :     //  newMS.bindColumn(modDataTileId.fieldName(), dataMan);
    1574             :   }
    1575             :   {
    1576             :     // TiledDataStMan dataMan(corrDataCol);
    1577           0 :     TiledShapeStMan dataMan(corrDataCol, tileShape);
    1578           0 :     newMS.bindColumn(MeasurementSet::
    1579             :                      columnName(MeasurementSet::CORRECTED_DATA), dataMan);
    1580             :     //  newMS.bindColumn(corrDataTileId.fieldName(), dataMan);
    1581             :   }
    1582             :   {
    1583             :     //TiledDataStMan dataMan(chanFlagCol);
    1584             :     TiledShapeStMan dataMan(chanFlagCol, 
    1585           0 :                             IPosition(3, 
    1586           0 :                                       tileShape(0),
    1587           0 :                                       tileShape(1),
    1588           0 :                                       tileShape(2)*64)
    1589           0 :                             );
    1590           0 :     newMS.bindColumn(MeasurementSet::
    1591             :                      columnName(MeasurementSet::FLAG), dataMan);
    1592             :     //  newMS.bindColumn(chanFlagTileId.fieldName(), dataMan);
    1593             :   }
    1594             :   {
    1595             :     //TiledDataStMan dataMan(sigmaCol);
    1596           0 :     TiledShapeStMan dataMan(sigmaCol, IPosition(2,tileShape(0), tileShape(1) * tileShape(2)));
    1597           0 :     newMS.bindColumn(MeasurementSet::
    1598             :                      columnName(MeasurementSet::SIGMA), dataMan);
    1599             : 
    1600             :     //Hmmm before weight and sigma were bound by the same stman..
    1601           0 :     TiledShapeStMan dataMan2("TiledWgtCol", IPosition(2,tileShape(0), tileShape(1) * tileShape(2)));
    1602             : 
    1603           0 :     newMS.bindColumn(MeasurementSet::
    1604             :                      columnName(MeasurementSet::WEIGHT), dataMan2);
    1605             :     //  newMS.bindColumn(sigmaTileId.fieldName(), dataMan);
    1606             :   }
    1607             :   
    1608             :   {
    1609             :     //TiledDataStMan dataMan(flagCol);
    1610           0 :     TiledShapeStMan dataMan(flagCol, IPosition(4,tileShape(0),tileShape(1), 1,tileShape(2)));
    1611           0 :     newMS.bindColumn(MeasurementSet::
    1612             :                      columnName(MeasurementSet::FLAG_CATEGORY), dataMan);
    1613             :     // newMS.bindColumn(flagTileId.fieldName(), dataMan);
    1614             :   }
    1615             : 
    1616             :   {
    1617           0 :     TiledColumnStMan tiledStUVW("TiledUVW",IPosition(2, 3, tileShape(0) * tileShape(1) * tileShape(2) * 2 / 3));
    1618           0 :     newMS.bindColumn(MS::columnName(MS::UVW),tiledStUVW);
    1619             :   }
    1620             :   // The standard storage manager is the default manager but by default it only
    1621             :   // creates a bucket for every 32 rows. Thats too small for the columns in the
    1622             :   // main table of a measurement set. So I'll explicitly bind these columns
    1623             :   // here with a bucket size of (351+27)*128 bytes
    1624             :   {
    1625           0 :     StandardStMan stMan("Standard data manager", 32768);
    1626           0 :     newMS.bindColumn(MeasurementSet::
    1627             :                      columnName(MeasurementSet::ANTENNA1), stMan);
    1628           0 :     newMS.bindColumn(MeasurementSet::
    1629             :                      columnName(MeasurementSet::ANTENNA2), stMan);
    1630           0 :     newMS.bindColumn(MeasurementSet::
    1631             :                      columnName(MeasurementSet::DATA_DESC_ID), stMan);
    1632             :   }
    1633             : 
    1634             :   // Finally create the MeasurementSet.
    1635           0 :   MeasurementSet ms(newMS);
    1636             :   
    1637             :   { // Set the TableInfo
    1638           0 :     TableInfo& info(ms.tableInfo());
    1639           0 :     info.setType(TableInfo::type(TableInfo::MEASUREMENTSET));
    1640           0 :     info.setSubType(String("VLA"));
    1641             :     info.readmeAddLine
    1642           0 :       ("This is a MeasurementSet Table holding measurements from the VLA");
    1643           0 :     info.readmeAddLine("radio synthesis array (operated by NRAO)");
    1644             :   }
    1645             :   {//Create the SOURCE subtable
    1646             : 
    1647           0 :     TableDesc sourceTD=MSSource::requiredTableDesc();
    1648           0 :     MSSource::addColumnToDesc(sourceTD, MSSource::REST_FREQUENCY);
    1649           0 :     MSSource::addColumnToDesc(sourceTD, MSSource::SYSVEL);
    1650           0 :     MSSource::addColumnToDesc(sourceTD, MSSource::TRANSITION);
    1651           0 :     SetupNewTable sourceSetup(ms.sourceTableName(),sourceTD,option);
    1652           0 :     ms.rwKeywordSet().defineTable(MS::keywordName(MS::SOURCE),
    1653           0 :                                   Table(sourceSetup,0));
    1654             :   }
    1655             :   // create  the required subtables.
    1656           0 :   ms.createDefaultSubtables(option);
    1657             :   //
    1658             :   { // add optional column to SPECTRAL_WINDOW. Added by GYL
    1659           0 :       ms.spectralWindow().addColumn(
    1660           0 :             ScalarColumnDesc<Int>(
    1661             :                 MSSpectralWindow::columnName(MSSpectralWindow::DOPPLER_ID),
    1662             :                 MSSpectralWindow::columnStandardComment(
    1663             :                     MSSpectralWindow::DOPPLER_ID)));
    1664             :   
    1665             :   }
    1666             :   {  // Create the DOPPLER subtable. Added by GYL
    1667           0 :     TableDesc dopplerTD=MSDoppler::requiredTableDesc();
    1668             :     //MSDoppler::addColumnToDesc(dopplerTD, MSDoppler::VELDEF);
    1669           0 :     SetupNewTable dopplerSetup(ms.dopplerTableName(),dopplerTD,option);
    1670           0 :     ms.rwKeywordSet().defineTable(MS::keywordName(MS::DOPPLER),
    1671           0 :                                   Table(dopplerSetup,0));
    1672             :   }
    1673             : 
    1674             :   // Adjust the Measure references to ones used by the VLA.
    1675             :   {
    1676           0 :     MSColumns msc(ms);
    1677           0 :     msc.setEpochRef(MEpoch::IAT);
    1678           0 :     msc.setDirectionRef(MDirection::J2000);
    1679           0 :     msc.uvwMeas().setDescRefCode(Muvw::J2000);
    1680           0 :     msc.antenna().setPositionRef(MPosition::ITRF);
    1681           0 :     msc.antenna().setOffsetRef(MPosition::ITRF);
    1682             :     { // Put the right values into the CATEGORY keyword
    1683           0 :       Vector<String> categories(nCat);
    1684           0 :       categories(0) = "ONLINE_1";
    1685           0 :       categories(1) = "ONLINE_2";
    1686           0 :       categories(2) = "ONLINE_4";
    1687           0 :       categories(3) = "ONLINE_8";
    1688           0 :       categories(4) = "SHADOW";
    1689           0 :       categories(5) = "FLAG_CMD";
    1690           0 :       msc.setFlagCategories(categories);
    1691             :     }
    1692             :   }
    1693           0 :   return ms;
    1694             : }
    1695             : 
    1696           0 : MeasurementSet VLAFiller::
    1697             : openMS(const Path& tableName, const Bool readonly) {
    1698           0 :   const String& msName = tableName.absoluteName();
    1699           0 :   if (!Table::isReadable(msName)) {
    1700           0 :     throw(AipsError(String("VLAFiller::openMS(...) - cannot read ") + msName +
    1701           0 :                     String(" because it does not exist or is not a table.")));
    1702             :   }
    1703           0 :   if (!readonly && !Table::isWritable(msName)) {
    1704           0 :     throw(AipsError(String("VLAFiller::openMS(...) - cannot write to ") + 
    1705           0 :                     msName + "."));
    1706             :   }
    1707             :   {
    1708           0 :     const TableInfo info = TableUtil::tableInfo(msName);
    1709           0 :     if (info.type() != TableInfo::type(TableInfo::MEASUREMENTSET)) {
    1710           0 :       throw(AipsError(String("VLAFiller::openMS(...) - the table ") + 
    1711           0 :                       msName + String(" is not a measurement set.")));
    1712             :     }
    1713           0 :     if (info.subType() != "VLA") {
    1714           0 :       throw(AipsError(String("VLAFiller::openMS(...) - the table ") + 
    1715           0 :                       msName + String(" is not a VLA measurement set.")));
    1716             :     }
    1717             :     {
    1718           0 :       const Table t(msName);
    1719           0 :       const TableRecord& keys = t.keywordSet();
    1720           0 :       const String versionString("MS_VERSION");
    1721           0 :       const RecordFieldId versionKey(versionString);
    1722           0 :       if (!keys.isDefined(versionString) || 
    1723           0 :           keys.dataType(versionKey) != TpFloat || 
    1724           0 :           !near(keys.asFloat(versionKey), 2.0f)) {
    1725           0 :         throw(AipsError(String("VLAFiller::openMS(...) - the table ") + 
    1726           0 :                         msName + 
    1727           0 :                         String(" is not a version 2 measurement set.")));
    1728             :       }
    1729             :     }
    1730             :   }
    1731           0 :   const Table::TableOption openOption = readonly ? Table::Old : Table::Update;
    1732           0 :   return MeasurementSet(msName, openOption);
    1733             : }
    1734             : 
    1735           0 : void VLAFiller::logCurrentRecord(IterationStatus& counts) {
    1736           0 :   if (itsRecord.isValid()) {
    1737           0 :     const uInt curRow = nrow();
    1738           0 :     const MEpoch obsTime = timeMeas()(curRow-1);
    1739           0 :     itsLog << "Record " << counts.nVLARecords 
    1740             :            << " was observed at "
    1741           0 :            << MVTime(obsTime.getValue().getTime()).string(MVTime::YMD)
    1742           0 :            << " and has " << curRow - counts.nRows 
    1743           0 :            << " rows of data" << LogIO::POST;
    1744             :   }
    1745           0 : }
    1746             : 
    1747           0 : void VLAFiller::logChanges(IterationStatus& counts) {
    1748             :   {
    1749           0 :     const String& curProject = itsRecord.SDA().obsId();
    1750           0 :     if (counts.lastProject != curProject) {
    1751           0 :       counts.lastProject = curProject;
    1752             :       // log output clean-up (CAS-208)
    1753             :       //itsLog << "Project changed to " << curProject << LogIO::POST;
    1754           0 :       itsLog << "Project " << curProject;
    1755             : 
    1756           0 :       const uInt lastRow = nrow() - 1;
    1757           0 :       const MEpoch obsTime = timeMeas()(lastRow);
    1758           0 :       itsLog << " starting at " 
    1759           0 :            << MVTime(obsTime.getValue().getTime()).string(MVTime::YMD)
    1760           0 :            << " (" << obsTime.getRefString() << ")"
    1761           0 :            << LogIO::POST;
    1762             :     }
    1763             :   }
    1764             :   {
    1765           0 :     const String& curObsMode = itsRecord.SDA().obsMode();
    1766           0 :     if (counts.lastObsMode != curObsMode) {
    1767           0 :       counts.lastObsMode = curObsMode;
    1768             :       //itsLog << "ObsMode changed to " << itsRecord.SDA().obsModeFull()
    1769           0 :       itsLog << "ObsMode: " << itsRecord.SDA().obsModeFull()
    1770           0 :              << LogIO::POST;
    1771             :     }
    1772             :   }
    1773           0 :   const Int subArray = arrayId()(nrow() - 1);
    1774             :   {
    1775           0 :     const MSAntennaColumns& ant = antenna();
    1776           0 :     const uInt nAnt = itsRecord.RCA().nAntennas();
    1777           0 :     Bool changed = (nAnt != counts.lastAnt[subArray].nelements());
    1778             :     {
    1779           0 :       Int a = nAnt;
    1780           0 :       while (!changed && a > 0) {
    1781           0 :         a--;
    1782           0 :         changed = (itsAntId[a] != static_cast<Int>(counts.lastAnt[subArray][a]));
    1783             :       }
    1784             :     }
    1785           0 :     if (changed) {
    1786             :       // some log output clean-ups (CAS-208)
    1787             :       //itsLog << "Array configuration";
    1788             :       //itsLog << " for sub-array " << subArray + 1;
    1789           0 :       itsLog << "Sub-array " << subArray + 1
    1790           0 :               << LogIO::POST;
    1791             :       //if (counts.lastAnt[subArray].nelements() != 0) itsLog << " changed";
    1792           0 :       const uInt lastRow = nrow() - 1;
    1793           0 :       const MEpoch obsTime = timeMeas()(lastRow);
    1794             :       //itsLog << " at " 
    1795             :       //     << MVTime(obsTime.getValue().getTime()).string(MVTime::YMD)
    1796             :       //     << " (" << obsTime.getRefString() << ")"
    1797             :       //     << LogIO::POST;
    1798           0 :       counts.lastAnt[subArray].resize(nAnt, true);
    1799           0 :       for (uInt i = 0; i < nAnt; i++) {
    1800           0 :         const uInt a = static_cast<uInt>(itsAntId[i]);
    1801           0 :         itsLog << "Station: " << ant.station()(a)
    1802           0 :                << "  Antenna: " << ant.name()(a);
    1803             :       //if (counts.lastAnt[subArray][i] != a) {
    1804             :       //  itsLog << " \tNEW";
    1805             :       //}
    1806           0 :         counts.lastAnt[subArray][i] = a;
    1807           0 :         itsLog << LogIO::POST;
    1808             :       }
    1809             :     }
    1810           0 :     itsLog << LogIO::POST;
    1811             :   }
    1812             :   {
    1813           0 :     const MSDataDescColumns& dd = dataDescription();
    1814           0 :     const MSSpWindowColumns& spw = spectralWindow();
    1815           0 :     const MSPolarizationColumns& pol = polarization();
    1816           0 :     const Block<Int>& thisDataId = itsDataId[subArray];
    1817           0 :     Block<Int>& lastSpw = counts.lastSpw[subArray];
    1818           0 :     Block<Int>& lastPol = counts.lastPol[subArray];
    1819           0 :     for (uInt d = 0; d < lastSpw.nelements(); d++) {
    1820           0 :       if (d < thisDataId.nelements()) {
    1821           0 :         const Int curDD = thisDataId[d];
    1822           0 :         const Int curSpw = dd.spectralWindowId()(curDD);
    1823           0 :         bool logPostPending = false;
    1824           0 :         if (lastSpw[d] != curSpw) {
    1825           0 :           logPostPending = true;
    1826           0 :           lastSpw[d] = curSpw;
    1827             :           // also reset lastPol so the pol is logged for this spw
    1828           0 :           lastPol[d] = -1;
    1829             :           //itsLog << "Spectral window for IF#" 
    1830           0 :           itsLog << "Spectral window " 
    1831           0 :                  << spw.ifConvChain()(curSpw) + 1
    1832             :                  << ": "
    1833             :           //     << " (on sub-array " << subArray + 1 << ")"
    1834             :           //     << " changed to "
    1835           0 :                  << spw.name()(curSpw);
    1836           0 :           const MEpoch obsTime = timeMeas()(nrow()-1);
    1837             :           //itsLog << " at " 
    1838             :           //     << MVTime(obsTime.getValue().getTime()).string(MVTime::YMD)
    1839             :           //     << " (" << obsTime.getRefString() << ")";
    1840             :           //if (counts.nSpw != spw.nrow() &&
    1841             :           //    static_cast<uInt>(curSpw) >= counts.nSpw) {
    1842             :           //  counts.nSpw =  curSpw + 1;
    1843             :           //  itsLog << " NEW";
    1844             :           //}
    1845             :           // itsLog << LogIO::POST;
    1846             :         }
    1847           0 :         const Int curPol = dd.polarizationId()(curDD);
    1848           0 :         if (lastPol[d] != curPol) {
    1849           0 :           logPostPending = true;
    1850           0 :           lastPol[d] = curPol;
    1851             :           //itsLog << "Polarization setup for IF#" 
    1852             :           //     << spw.ifConvChain()(curSpw) + 1
    1853             :           //     << " (on sub-array " << subArray + 1 << ")"
    1854             :           //     << " changed to ";
    1855           0 :           const Vector<Int> corr = pol.corrType()(curPol);
    1856           0 :           const Int nCorr = corr.nelements();
    1857           0 :           itsLog << " ";
    1858           0 :           for (Int c = 0; c < nCorr - 1; c++) {
    1859           0 :             itsLog << Stokes::name(Stokes::type(corr(c))) << ", ";
    1860             :           }
    1861           0 :           itsLog << Stokes::name(Stokes::type(corr(nCorr-1)));
    1862           0 :           const MEpoch obsTime = timeMeas()(nrow()-1);
    1863             :           //itsLog << " at " 
    1864             :           //     << MVTime(obsTime.getValue().getTime()).string(MVTime::YMD)
    1865             :           //     << " (" << obsTime.getRefString() << ")";
    1866             :           //if (counts.nPol != pol.nrow() &&
    1867             :           //    static_cast<uInt>(curPol) >= counts.nPol) {
    1868             :           //  counts.nPol =  curPol + 1;
    1869             :           //  itsLog << " NEW";
    1870             :           //}
    1871             :           //itsLog << LogIO::POST;
    1872             :         }
    1873           0 :         if (logPostPending) {
    1874           0 :             itsLog << LogIO::POST;
    1875           0 :             logPostPending = false;
    1876             :         }
    1877             :       } else {
    1878           0 :         lastSpw[d] = -1;
    1879           0 :         lastPol[d] = -1;
    1880             :       }
    1881             :     }
    1882             :   }
    1883             :   {
    1884           0 :     const MSFieldColumns& fld = field();
    1885           0 :     const Int thisFld = itsFldId[subArray];
    1886           0 :     if (counts.lastFld[subArray] != thisFld) {
    1887           0 :       counts.lastFld[subArray] = thisFld;
    1888             :       //itsLog << "Field changed to ";
    1889             :       { 
    1890           0 :         const String& fldName = fld.name()(thisFld);
    1891           0 :         if (fldName.length() > 0) {
    1892           0 :           itsLog << fldName;
    1893             :         } else {
    1894           0 :           Array<MDirection> amd;
    1895           0 :           const Unit rad("rad");
    1896           0 :           fld.referenceDirMeasCol().get(thisFld, amd, true);
    1897           0 :           const MDirection& md = amd(IPosition(amd.ndim(), 0));
    1898           0 :           const MVDirection& mdv = md.getValue();
    1899           0 :           const MVTime ra(mdv.getLong(rad));
    1900           0 :           const MVAngle dec(mdv.getLat(rad));
    1901           0 :           itsLog << "(" << ra.string(MVTime::TIME, 6) << ", " 
    1902           0 :                  << dec.string(MVTime::ANGLE, 6) << ")";
    1903           0 :           itsLog << " " << md.getRefString();
    1904             :         }
    1905             :       }
    1906           0 :       const uInt lastRow = nrow() - 1;
    1907           0 :       const MEpoch obsTime = timeMeas()(lastRow);
    1908             :       //itsLog << " (on sub-array " << subArray+1 << ") at " 
    1909           0 :       itsLog << " " 
    1910             :       //     << MVTime(obsTime.getValue().getTime()).string(MVTime::YMD)
    1911           0 :              << MVTime(obsTime.getValue().getTime()).string(MVTime::YMD);
    1912             :       //     << " (" << obsTime.getRefString() << ")";
    1913             :       //if (counts.nFld != fld.nrow() && 
    1914             :       //  static_cast<uInt>(thisFld) >= counts.nFld) {
    1915             :       //  counts.nFld = fld.nrow();
    1916             :       //  itsLog << " NEW";
    1917             :       //}
    1918           0 :       itsLog << LogIO::POST;
    1919             :     }
    1920             :   }
    1921           0 : }
    1922             : 
    1923             : 
    1924           0 : void VLAFiller::summarise() {
    1925           0 :   itsLog << LogIO::NORMAL;
    1926           0 :   itsLog << "Finished filling the measurement set." << endl;
    1927           0 :   itsLog << "The measurement set contains " << nrow() << " rows." << endl;
    1928           0 :   itsLog << "The antenna sub-table contains " 
    1929           0 :       << antenna().nrow() << " entries" << endl;
    1930           0 :   itsLog << "The field sub-table contains " 
    1931           0 :       << field().nrow() << " entries" << endl;
    1932           0 :   itsLog << "The spectral window sub-table contains " 
    1933           0 :       << spectralWindow().nrow() << " entries" << endl;
    1934           0 :   itsLog << "The polarization sub-table contains " 
    1935           0 :       << polarization().nrow() << " entries" << endl;
    1936           0 :   itsLog << "The pointing sub-table contains " 
    1937           0 :       << pointing().nrow() << " entries" << endl;
    1938           0 :   itsLog << LogIO::POST;
    1939           0 : }
    1940             : 
    1941           0 : uInt VLAFiller::addAntenna(const MPosition& antPos, uInt whichAnt) {
    1942             : 
    1943           0 :   MSAntennaColumns& ant = antenna();
    1944           0 :   const uInt newRow = ant.nrow();
    1945           0 :   itsMS.antenna().addRow(1);
    1946             : 
    1947           0 :   String leAntName;
    1948           0 :   if(!itsEVLAisOn){
    1949             :     // ignore the frontend temperature naming
    1950           0 :     leAntName=itsRecord.ADA(whichAnt).antName(false);
    1951           0 :     if(itsNewAntName){
    1952           0 :       leAntName=String("VA")+leAntName;
    1953             :     }   
    1954             :   }
    1955             :   else{
    1956           0 :     leAntName=itsRecord.ADA(whichAnt).antName(itsNewAntName);
    1957             :   }
    1958             : 
    1959           0 :   ant.name().put(newRow, leAntName);
    1960             :   
    1961           0 :   ant.station().put(newRow, itsRecord.ADA(whichAnt).padName());
    1962           0 :   ant.type().put(newRow, "GROUND-BASED");
    1963           0 :   ant.mount().put(newRow, "ALT-AZ");
    1964           0 :   ant.positionMeas().put(newRow, antPos);
    1965           0 :   ant.offset().put(newRow, Vector<Double>(3, 0.0));
    1966           0 :   ant.dishDiameter().put(newRow, 25.0);
    1967           0 :   ant.flagRow().put(newRow, false);
    1968           0 :   return newRow;
    1969             : }
    1970             : 
    1971             : 
    1972           0 : uInt VLAFiller::addPointing(const MDirection& antDir,
    1973             :                             const MDirection& fieldDir,
    1974             :                             uInt whichAnt) {
    1975           0 :   MSPointingColumns& pointingCol = pointing();
    1976           0 :   const uInt newRow = pointingCol.nrow();
    1977           0 :   itsMS.pointing().addRow(1);
    1978             : 
    1979             :   // Should the antennaId just be whichAnt?  
    1980             :   //    (I.e., the MS ANT Id and not the VLA ant name integer?)
    1981           0 :   pointingCol.antennaId().put(newRow, itsRecord.ADA(whichAnt).antId());
    1982           0 :   const MEpoch* mepPtr = dynamic_cast<const MEpoch*>(itsFrame.epoch());
    1983           0 :   pointingCol.timeMeas().put(newRow, *mepPtr);
    1984           0 :   pointingCol.numPoly().put(newRow, 0);
    1985           0 :   pointingCol.timeOriginMeas().put(newRow, itsFrame.epoch());
    1986           0 :   pointingCol.interval().put(newRow, itsRecord.SDA().intTime());
    1987           0 :   Array<MDirection> bDir(IPosition(1,1));
    1988           0 :   bDir(IPosition(1,0))=antDir;
    1989           0 :   pointingCol.directionMeasCol().put(newRow, bDir);
    1990           0 :   bDir(IPosition(1,0))=fieldDir;
    1991           0 :   pointingCol.targetMeasCol().put(newRow, bDir);
    1992           0 :   pointingCol.tracking().put(newRow, true);
    1993           0 :   return newRow;
    1994             : }
    1995             : 
    1996           0 : void VLAFiller::addFeed(uInt whichAnt) {
    1997           0 :   MSFeedColumns& fd = feed();
    1998           0 :   const uInt newRow = fd.nrow();
    1999           0 :   itsMS.feed().addRow(1);
    2000             : 
    2001           0 :   fd.antennaId().put(newRow, whichAnt);
    2002           0 :   fd.feedId().put(newRow, 0);
    2003           0 :   fd.spectralWindowId().put(newRow, -1);
    2004           0 :   fd.time().put(newRow, 0.0);
    2005           0 :   fd.interval().put(newRow, 0.0);
    2006           0 :   fd.numReceptors().put(newRow, 2);
    2007           0 :   fd.beamId().put(newRow, -1);
    2008             :   
    2009           0 :   fd.beamOffset().put(newRow, Matrix<Double>(2,2, 0.0) );
    2010             :   {
    2011           0 :     Vector<String> pt(2);
    2012           0 :     pt(0) = "R"; pt(1) = "L";
    2013           0 :     fd.polarizationType().put(newRow, pt);
    2014             :   }
    2015             :   {
    2016           0 :     Matrix<Complex> resp(2, 2, Complex(0.0f, 0.0f));
    2017           0 :     resp.diagonal() = Complex(1.0f, 0.0f);
    2018           0 :     fd.polResponse().put(newRow, resp);
    2019             :   }
    2020           0 :   fd.position().put(newRow, Vector<Double>(3, 0.0));
    2021           0 :   fd.receptorAngle().put(newRow, Vector<Double>(2, 0.0));
    2022           0 : }
    2023             : 
    2024           0 : uInt VLAFiller::addField(const MDirection& dir) {
    2025           0 :   MSFieldColumns& fld = field();
    2026           0 :   const uInt newRow = fld.nrow();
    2027           0 :   itsMS.field().addRow(1);
    2028           0 :   fld.name().put(newRow, itsRecord.SDA().sourceName());
    2029           0 :   fld.code().put(newRow, itsRecord.SDA().calCode());
    2030           0 :   const MEpoch* mepPtr = dynamic_cast<const MEpoch*>(itsFrame.epoch());
    2031           0 :   fld.timeMeas().put(newRow, *mepPtr);
    2032           0 :   fld.numPoly().put(newRow, 0);
    2033             :   {
    2034           0 :     Vector<MDirection> aDir(1, dir);
    2035           0 :     fld.delayDirMeasCol().put(newRow, aDir);
    2036           0 :     fld.phaseDirMeasCol().put(newRow, aDir);
    2037           0 :     fld.referenceDirMeasCol().put(newRow, aDir);
    2038             :   }
    2039           0 :   fld.sourceId().put(newRow, newRow);
    2040           0 :   if (!fld.ephemerisId().isNull()) {
    2041           0 :     fld.ephemerisId().put(newRow, -1);
    2042             :   }
    2043           0 :   fld.flagRow().put(newRow, false);
    2044           0 :   return newRow;
    2045             : }
    2046             : 
    2047           0 : uInt VLAFiller::addDoppler( const VLAEnum::CDA cda ) {
    2048           0 :   const VLASDA& sda = itsRecord.SDA();
    2049           0 :   MSDopplerColumns& dopc = doppler();
    2050           0 :   const uInt newRow = dopc.nrow();
    2051           0 :   itsMS.doppler().addRow(1);  
    2052           0 :   dopc.dopplerId().put(newRow, newRow );
    2053             :   // find the source_id
    2054           0 :   MSSourceColumns& srcc = source();
    2055           0 :   const uInt source_id = srcc.nrow() - 1;
    2056           0 :   dopc.sourceId().put(newRow, source_id );
    2057             :   // transition column in SOURCE subtable is not filled. So here we fill TRANSITION_ID with 0.
    2058           0 :   dopc.transitionId().put(newRow, 0);
    2059           0 :   if (sda.dopplerTracking( cda )) {
    2060           0 :           const MDoppler dop(Quantity(1.0*sda.radialVelocity( cda ), "m/s"), sda.dopplerDefn( cda ));
    2061           0 :           dopc.velDefMeas().put(newRow, dop );
    2062             :   }else {
    2063           0 :      dopc.velDefMeas().put(newRow, MDoppler(Quantity(0.0,"m/s"),MDoppler::RADIO));
    2064             :   }
    2065             :   
    2066           0 :   return newRow;
    2067             : }
    2068             : 
    2069           0 : uInt VLAFiller::addSpectralWindow(const VLAEnum::CDA cda,
    2070             :                                   const MFrequency& refFreq,
    2071             :                                   const uInt nChan,
    2072             :                                   const Double /*bandwidth*/,
    2073             :                                   const uInt ifChain) {
    2074           0 :   MSSpWindowColumns& spw = spectralWindow();
    2075           0 :   const uInt newRow = spw.nrow();
    2076           0 :   itsMS.spectralWindow().addRow(1);
    2077             :   //cout.precision(8);
    2078           0 :   spw.refFrequencyMeas().put(newRow, refFreq);
    2079           0 :   spw.numChan().put(newRow, nChan);
    2080           0 :   spw.ifConvChain().put(newRow, ifChain);
    2081             :   // write doppler_id to spectral_window
    2082           0 :   MSDopplerColumns& dopc = doppler();
    2083           0 :   const uInt doppler_id = dopc.nrow() - 1;
    2084           0 :   spw.dopplerId().put( newRow, doppler_id );
    2085             :   
    2086           0 :   const VLASDA& sda = itsRecord.SDA();
    2087           0 :   const Double chanWidth = sda.channelWidth(cda);
    2088             :   const MFrequency::Types itsFreqType = 
    2089           0 :     MFrequency::castType(refFreq.getRef().getType());
    2090             : 
    2091           0 :   Vector<Double> chanFreq(nChan);
    2092           0 :   indgen(chanFreq, sda.edgeFrequency(cda)+0.5*chanWidth, chanWidth);
    2093           0 :   Vector<Double> chanWidths(nChan, chanWidth);
    2094           0 :   if (itsFreqType != MFrequency::TOPO) { 
    2095             :     // have to convert the channel frequencies from topocentric to the specifed
    2096             :     // frequency type.
    2097           0 :     itsFreqCtr.setOut(itsFreqType);
    2098           0 :     Vector<Double> chanValInHz(1);
    2099           0 :     MVFrequency  chanVal;
    2100           0 :     for (uInt c = 0; c < nChan; c++) {
    2101           0 :       chanValInHz = chanFreq(c);
    2102           0 :       chanVal.putVector(chanValInHz);
    2103           0 :       chanFreq(c) = itsFreqCtr(chanVal).getValue().getValue();
    2104             :     }
    2105             :     // To calculate the channel widths I just need to convert the topocentric
    2106             :     // channel width!
    2107           0 :     chanValInHz = chanWidth;
    2108           0 :     chanVal.putVector(chanValInHz);
    2109           0 :     chanWidths = itsFreqCtr(chanVal).getValue().getValue();
    2110             :   }
    2111           0 :   spw.chanFreq().put(newRow, chanFreq);
    2112           0 :   spw.chanWidth().put(newRow, chanWidths);
    2113           0 :   spw.effectiveBW().put(newRow, chanWidths);
    2114             : 
    2115           0 :   spw.flagRow().put(newRow, false);
    2116             :   {
    2117           0 :     Quantum<Double> qChanWidth(chanWidth, "Hz");
    2118           0 :     if (chanWidth < 1E6) {
    2119           0 :       qChanWidth.convert("kHz");
    2120             :     } else {
    2121           0 :       qChanWidth.convert("MHz");
    2122             :     }
    2123           0 :     Quantum<Double> qRefFreq(refFreq.get("GHz"));
    2124           0 :     if (qRefFreq.getValue() < 1) {
    2125           0 :       qRefFreq.convert("MHz");
    2126             :     }
    2127           0 :     ostringstream str;
    2128           0 :     str << nChan
    2129           0 :         << "*" << std::setprecision(3) << qChanWidth
    2130           0 :         << " channels @ " << qRefFreq 
    2131           0 :         << " (" << refFreq.getRefString() << ")";
    2132           0 :     spw.name().put(newRow, String(str));
    2133             :   }
    2134           0 :   if (sda.smoothed() || nChan == 1) {
    2135             :     // the effective resolution is just the channel width
    2136           0 :     spw.resolution().put(newRow, chanWidths);
    2137             :   } else {
    2138             :     // 1.21 is the FWHM of the implicitly convolved sync function
    2139             :     //  (see TMS 2nd ed p. 286)
    2140           0 :     spw.resolution().put(newRow, 
    2141           0 :                          static_cast<Array<Double> >(chanWidths) * 
    2142           0 :                          static_cast<Double>(1.21));
    2143             :     // The static cast is for a possible SGI compiler bug.  The compiler seems
    2144             :     // unable to figure out that chanWidths is an Array
    2145             : 
    2146             :   }
    2147             :   
    2148           0 :   spw.totalBandwidth().put(newRow, sum(chanWidths));
    2149           0 :   spw.netSideband().put(newRow, 1);
    2150             :   // 
    2151             :   static uInt curMSRows = 0;
    2152           0 :   Int freqGroupId = 1;
    2153           0 :   if (nrow() == curMSRows) {
    2154           0 :     if (newRow > 0) {
    2155           0 :       freqGroupId = spw.freqGroup()(newRow-1);
    2156             :     }
    2157             :   } else {
    2158           0 :     freqGroupId = max(spw.freqGroup().getColumn()) + 1;
    2159             :   }
    2160           0 :   spw.freqGroup().put(newRow, freqGroupId);
    2161           0 :   spw.freqGroupName().put(newRow, "Group " + String::toString(freqGroupId));
    2162           0 :   curMSRows = nrow();
    2163           0 :   return newRow;
    2164             : 
    2165             : }
    2166             : 
    2167           0 : uInt VLAFiller::addPolarization(const Vector<Stokes::StokesTypes>& polTypes) {
    2168           0 :   MSPolarizationColumns& pol = polarization();
    2169           0 :   const uInt newRow = pol.nrow();
    2170           0 :   itsMS.polarization().addRow(1);
    2171           0 :   const uInt nCorr = polTypes.nelements();
    2172           0 :   pol.numCorr().put(newRow, nCorr);
    2173           0 :   Vector<Int> polInt(nCorr);
    2174           0 :   Matrix<Int> polProd(2, nCorr);
    2175           0 :   for (uInt p = 0; p < nCorr; p++) {
    2176           0 :     polInt(p) = polTypes(p);
    2177           0 :     switch (polTypes(p)) {
    2178           0 :     case Stokes::RR:
    2179           0 :       polProd(0, p) = 0;
    2180           0 :       polProd(1, p) = 0;
    2181           0 :       break;
    2182           0 :     case Stokes::RL:
    2183           0 :       polProd(0, p) = 0;
    2184           0 :       polProd(1, p) = 1;
    2185           0 :       break;
    2186           0 :     case Stokes::LR:
    2187           0 :       polProd(0, p) = 1;
    2188           0 :       polProd(1, p) = 0;
    2189           0 :       break;
    2190           0 :     case Stokes::LL:
    2191           0 :       polProd(0, p) = 1;
    2192           0 :       polProd(1, p) = 1;
    2193           0 :       break;
    2194           0 :     default:
    2195           0 :       throw(AipsError("VLAFiller::addPolarization - Bad polarization value"));
    2196             :     }
    2197             :   }
    2198           0 :   pol.corrType().put(newRow, polInt);
    2199           0 :   pol.corrProduct().put(newRow, polProd);
    2200           0 :   pol.flagRow().put(newRow, false);
    2201           0 :   return newRow;
    2202             : }
    2203             : 
    2204           0 : uInt VLAFiller::addDataDescription(uInt spwId, uInt polId) {
    2205           0 :   MSDataDescColumns& dd = dataDescription();
    2206           0 :   const uInt newRow = dd.nrow();
    2207           0 :   itsMS.dataDescription().addRow(1);
    2208           0 :   dd.spectralWindowId().put(newRow, spwId);
    2209           0 :   dd.polarizationId().put(newRow, polId);
    2210           0 :   if (!dd.lagId().isNull()) {
    2211           0 :     dd.lagId().put(newRow, -1);
    2212             :   }
    2213           0 :   return newRow;
    2214             : }
    2215             : 
    2216             : 
    2217           0 : uInt VLAFiller::addSource(const MDirection& dir ){
    2218             : 
    2219             :   // TBD: this should be revised to handle multiple restfreq/cda
    2220             :   //     (requires careful coordination with addSpw, addFld, etc.)
    2221             : 
    2222           0 :   const VLASDA& sda = itsRecord.SDA();
    2223             : 
    2224           0 :   MSSourceColumns& src = source();
    2225           0 :   const uInt newRow = src.nrow();
    2226             : 
    2227           0 :   if (newRow==0) {
    2228             :     // Set frame info...
    2229           0 :     src.setFrequencyRef(MFrequency::REST);
    2230             : 
    2231             :     // This assumes the MS will have one frame
    2232           0 :     for (uInt c = 0; c < maxCDA; c++) {
    2233           0 :       const VLACDA& cda = itsRecord.CDA(c);
    2234             :       
    2235           0 :       if (cda.isValid()) {
    2236           0 :         const VLAEnum::CDA thisCDA = VLAEnum::CDA(c);
    2237             :         // We subtract 1 because RV frames are one less than Freq frames...
    2238           0 :         src.setRadialVelocityRef(MRadialVelocity::Types(sda.restFrame(thisCDA)-1));
    2239           0 :         break;
    2240             :       }
    2241             :     }
    2242             :   }
    2243             : 
    2244           0 :   itsMS.source().addRow(1);
    2245           0 :   src.name().put(newRow, sda.sourceName());
    2246           0 :   src.sourceId().put( newRow, newRow ); // added by GYL
    2247           0 :   src.spectralWindowId().put(newRow, -1);
    2248           0 :   const MEpoch* mepPtr = dynamic_cast<const MEpoch*>(itsFrame.epoch());
    2249           0 :   src.timeMeas().put(newRow, *mepPtr);
    2250           0 :   src.code().put(newRow, sda.calCode());
    2251           0 :   src.directionMeas().put(newRow, dir);
    2252           0 :   MPosition obsPos;
    2253           0 :   MeasTable::Observatory(obsPos, "VLA");
    2254           0 :   MeasFrame frame(*mepPtr, obsPos, dir);
    2255           0 :   Vector<Double> restFreq;
    2256           0 :   Vector<Double> sysvel;
    2257           0 :   uInt validRest=0;
    2258           0 :   for (uInt c = 0; c < maxCDA; c++) {
    2259           0 :     const VLACDA& cda = itsRecord.CDA(c);
    2260             :     
    2261           0 :     if (cda.isValid()) {
    2262           0 :       const VLAEnum::CDA thisCDA = VLAEnum::CDA(c);
    2263             :       // check if it has a valid frame...some old data come without one !
    2264             :       // Who said bad documentation is better than none ...aargh !
    2265           0 :       if(sda.restFrame(thisCDA) < MFrequency::N_Types){
    2266           0 :         ++validRest;
    2267           0 :         restFreq.resize(validRest, true);
    2268           0 :         restFreq(validRest-1)=sda.restFrequency(thisCDA);
    2269             : 
    2270           0 :         sysvel.resize(validRest,true);
    2271           0 :         sysvel(validRest-1) = sda.radialVelocity(thisCDA);
    2272             : 
    2273             :       }
    2274             :     }
    2275             :   }
    2276             : 
    2277           0 :   Vector<String> transition(restFreq.size(), "Unknown");
    2278           0 :   src.numLines().put(newRow, validRest);
    2279           0 :   src.restFrequency().put(newRow, restFreq);
    2280           0 :   src.sysvel().put(newRow, sysvel);
    2281           0 :   src.transition().put(newRow, transition);
    2282             : 
    2283           0 :   return newRow;
    2284             : 
    2285             : }
    2286             : 
    2287           0 : void  VLAFiller::extendHypercubes(const Block<uInt>& nPol,
    2288             :                                   const Block<uInt>& nChan, uInt rows) {
    2289           0 :   const uInt nSpId = nChan.nelements();
    2290           0 :   DebugAssert(nPol.nelements() == nSpId, AipsError);
    2291           0 :   for (uInt s = 0; s < nSpId; s++) {
    2292             :     {
    2293           0 :       itsTileId.define(sigmaTileId, static_cast<Int>(nPol[s]));
    2294           0 :       itsSigmaAcc.extendHypercube(rows, itsTileId);
    2295           0 :       itsTileId.removeField(sigmaTileId);
    2296             :     }
    2297             :     {
    2298           0 :       itsTileId.define(dataTileId, static_cast<Int>(10*nChan[s] + nPol[s]));
    2299           0 :       itsDataAcc.extendHypercube(rows, itsTileId);
    2300           0 :       itsTileId.removeField(dataTileId);
    2301             :     }
    2302             :     {
    2303           0 :       itsTileId.define(modDataTileId, static_cast<Int>(10*nChan[s] + nPol[s]));
    2304           0 :       itsModDataAcc.extendHypercube(rows, itsTileId);
    2305           0 :       itsTileId.removeField(modDataTileId);
    2306             :     }
    2307             :     {
    2308           0 :       itsTileId.define(corrDataTileId, static_cast<Int>(10*nChan[s] + nPol[s]));      itsCorrDataAcc.extendHypercube(rows, itsTileId);
    2309           0 :       itsTileId.removeField(corrDataTileId);
    2310             :     }
    2311             :     
    2312             :     {
    2313           0 :       itsTileId.define(chanFlagTileId, static_cast<Int>(10*nChan[s] + nPol[s]));      itsChanFlagAcc.extendHypercube(rows, itsTileId);
    2314           0 :       itsTileId.removeField(chanFlagTileId);
    2315             :     }
    2316             :     {
    2317           0 :       itsTileId.define(flagTileId, static_cast<Int>(10*nChan[s] + nPol[s]));
    2318           0 :       itsFlagAcc.extendHypercube(rows, itsTileId);
    2319           0 :       itsTileId.removeField(flagTileId);
    2320             :     }
    2321             :   }
    2322           0 : }
    2323             : 
    2324           0 : void  VLAFiller::addHypercubes(uInt nPol, uInt nChan) {
    2325           0 :   DebugAssert(nChan > 0 && nChan <= 4096, AipsError);
    2326           0 :   DebugAssert(nPol > 0 && nPol <= 4, AipsError);
    2327           0 :   Bool addDataCube = true;
    2328           0 :   Bool addSigmaCube = true;
    2329           0 :   uInt s = itsDataShapes.nelements();
    2330           0 :   while (addDataCube && s > 0) {
    2331           0 :     s--;
    2332           0 :     const IPosition& curShape = itsDataShapes[s];
    2333           0 :     if (curShape(0) == static_cast<Int>(nPol)) {
    2334           0 :       addSigmaCube = false;
    2335             :     }
    2336           0 :     if (curShape(0) == static_cast<Int>(nPol) && 
    2337           0 :         curShape(1) == static_cast<Int>(nChan)) {
    2338           0 :       addDataCube = false;
    2339             :     }
    2340             :     
    2341           0 :     DebugAssert(addDataCube || !addSigmaCube, AipsError);
    2342             :   }
    2343             : 
    2344           0 :   if (addDataCube) {
    2345           0 :     if (addSigmaCube) {
    2346           0 :       itsTileId.define(sigmaTileId, static_cast<Int>(nPol));
    2347             :       
    2348             :       // 1 MB tile size
    2349           0 :       uInt rowTiles = 131072 / nPol;
    2350           0 :       if (rowTiles < 1) rowTiles = 1;
    2351           0 :       itsSigmaAcc.addHypercube(IPosition(2, nPol, 0), 
    2352           0 :                                IPosition(2, nPol, rowTiles),
    2353           0 :                                itsTileId);
    2354             :     }
    2355             :         
    2356           0 :     itsTileId.define(dataTileId, static_cast<Int>(10*nChan + nPol));
    2357             :     // 1 MB tile size
    2358           0 :     uInt rowTiles = 131072 / nChan / nPol;
    2359           0 :     if (rowTiles < 1) rowTiles = 1;
    2360           0 :     itsDataAcc.addHypercube(IPosition(3, nPol, nChan, 0), 
    2361           0 :                             IPosition(3, nPol, nChan, rowTiles),
    2362           0 :                             itsTileId);
    2363             : 
    2364           0 :     itsTileId.removeField(dataTileId);
    2365             :  
    2366           0 :     itsTileId.define(modDataTileId, static_cast<Int>(10*nChan + nPol));
    2367           0 :     itsModDataAcc.addHypercube(IPosition(3, nPol, nChan, 0), 
    2368           0 :                                IPosition(3, nPol, nChan, rowTiles),
    2369           0 :                                itsTileId);
    2370           0 :     itsTileId.removeField(modDataTileId);
    2371             : 
    2372           0 :     itsTileId.define(corrDataTileId, static_cast<Int>(10*nChan + nPol));
    2373           0 :     itsCorrDataAcc.addHypercube(IPosition(3, nPol, nChan, 0), 
    2374           0 :                                IPosition(3, nPol, nChan, rowTiles),
    2375           0 :                                itsTileId);
    2376           0 :     itsTileId.removeField(corrDataTileId);
    2377           0 :     itsTileId.define(chanFlagTileId, static_cast<Int>(10*nChan + nPol));
    2378           0 :     itsChanFlagAcc.addHypercube(IPosition(3, nPol, nChan, 0), 
    2379           0 :                                IPosition(3, nPol, nChan, rowTiles),
    2380           0 :                                itsTileId);
    2381           0 :     itsTileId.removeField(chanFlagTileId);
    2382             : 
    2383           0 :     itsTileId.define(flagTileId, static_cast<Int>(10*nChan + nPol));
    2384           0 :     rowTiles = 131072 / (nPol * nChan * nCat);
    2385           0 :     if (rowTiles < 1) rowTiles = 1;
    2386           0 :     itsFlagAcc.addHypercube(IPosition(4, nPol, nChan, nCat, 0), 
    2387           0 :                             IPosition(4, nPol, nChan, nCat, rowTiles),
    2388           0 :                             itsTileId);
    2389           0 :     itsTileId.removeField(flagTileId);
    2390           0 :     const uInt nCubes = itsDataShapes.nelements();
    2391           0 :     itsDataShapes.resize(nCubes + 1);
    2392           0 :     itsDataShapes[nCubes] = IPosition(2, nPol, nChan);
    2393             :   }
    2394           0 : }
    2395             : 
    2396           0 : Int VLAFiller::polIndexer(Stokes::StokesTypes& stokes){
    2397           0 :   if (stokes == Stokes::RR)
    2398           0 :     return 0;
    2399           0 :   else if (stokes == Stokes::RL)
    2400           0 :     return 1;
    2401           0 :   else if (stokes == Stokes::LR)
    2402           0 :     return 2;
    2403           0 :   else if (stokes == Stokes::LL)
    2404           0 :     return 3;
    2405             :   else 
    2406           0 :     return -1;
    2407             : } 
    2408             : 
    2409           0 : void VLAFiller::fixFieldDuplicates(MSField& msFld) {
    2410             : 
    2411           0 :   MSFieldIndex MSFldIdx(msFld);
    2412           0 :   MSFieldColumns fldcol(msFld);
    2413           0 :   Vector<String> name(fldcol.name().getColumn());
    2414           0 :   Int nFld=fldcol.nrow();
    2415             : 
    2416           0 :   for (Int ifld=0;ifld<nFld;++ifld) {
    2417           0 :     String thisname=name(ifld);
    2418           0 :     Vector<Int> nameMatches = MSFldIdx.matchFieldName(name(ifld));
    2419           0 :     Int nMatch=nameMatches.nelements();
    2420           0 :     if (nMatch>1) {
    2421           0 :       Int suffix(0);
    2422             :       {
    2423           0 :         ostringstream newname;
    2424           0 :         newname << thisname << "_" << suffix;
    2425           0 :         name(nameMatches(0))=String(newname);
    2426           0 :         fldcol.name().put(nameMatches(0),name(nameMatches(0)));
    2427             :       }
    2428           0 :       for (Int imatch=1;imatch<nMatch;++imatch) {
    2429           0 :         suffix++;
    2430           0 :         ostringstream newname;
    2431           0 :         newname << thisname << "_" << suffix;
    2432           0 :         name(nameMatches(imatch))=String(newname);
    2433           0 :         fldcol.name().put(nameMatches(imatch),name(nameMatches(imatch)));
    2434             :       }
    2435             :     }
    2436             :   } 
    2437             : 
    2438           0 : }
    2439             : 
    2440           0 : casacore::MDirection::Types VLAFiller::validEpoch(casacore::MDirection::Types mdType)
    2441             : {
    2442           0 :     if (mdType == MDirection::N_Types) {
    2443             :         // epoch in data is 0, warn and assume B1950_VLA
    2444           0 :         mdType = MDirection::B1950_VLA;
    2445           0 :         if (!itsZeroEpochWarned) {
    2446           0 :             itsLog << LogIO::WARN
    2447             :                    << "epoch is 0, assuming B1950_VLA"
    2448           0 :                    << LogIO::POST;
    2449           0 :             itsZeroEpochWarned = true;
    2450             :         }
    2451             :     }
    2452           0 :     return mdType;
    2453             : }
    2454             : 
    2455             : 
    2456             : // Local Variables:
    2457             : // compile-command: "gmake VLAFiller; cd ../../apps/vlafiller; gmake OPTLIB=1"
    2458             : // End: 

Generated by: LCOV version 1.16