//# MS2ASDM.cc 
//#
//#  ALMA - Atacama Large Millimeter Array
//#  (c) European Southern Observatory, 2002
//#  (c) Associated Universities Inc., 2002
//#  Copyright by ESO (in the framework of the ALMA collaboration),
//#  Copyright by AUI (in the framework of the ALMA collaboration),
//#  All rights reserved.
//#  
//#  This library is free software; you can redistribute it and/or
//#  modify it under the terms of the GNU Lesser General Public
//#  License as published by the Free software Foundation; either
//#  version 2.1 of the License, or (at your option) any later version.
//#  
//#  This library is distributed in the hope that it will be useful,
//#  but WITHOUT ANY WARRANTY, without even the implied warranty of
//#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//#  Lesser General Public License for more details.
//#  
//#  You should have received a copy of the GNU Lesser General Public
//#  License along with this library; if not, write to the Free Software
//#  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
//#  MA 02111-1307  USA
//# $Id: $
#include <casacore/tables/TaQL/ExprNode.h>
#include <casacore/tables/Tables/RefRows.h>
#include <casacore/ms/MeasurementSets/MSColumns.h>
#include <casacore/casa/Quanta/MVBaseline.h>
#include <casacore/casa/Arrays/Matrix.h>
#include <casacore/casa/Arrays/Cube.h>
#include <casacore/casa/Arrays/ArrayMath.h>
#include <casacore/casa/Arrays/ArrayOpsDiffShapes.h>
#include <casacore/casa/Arrays/ArrayLogical.h>
#include <casacore/casa/Arrays/ArrayUtil.h>
#include <casacore/casa/Arrays/IPosition.h>
#include <casacore/casa/Arrays/Slice.h>
#include <casacore/casa/Logging/LogIO.h>
#include <casacore/casa/OS/File.h>
#include <casacore/casa/OS/HostInfo.h>
#include <casacore/casa/Containers/Record.h>
#include <casacore/casa/BasicMath/Math.h>
#include <casacore/casa/BasicSL/String.h>
#include <casacore/casa/Utilities/Assert.h>
#include <casacore/casa/Utilities/GenSort.h>
#include <casacore/casa/System/AppInfo.h>
#include <casacore/tables/DataMan/IncrementalStMan.h>
#include <casacore/tables/Tables/ScalarColumn.h>
#include <casacore/tables/Tables/ScaColDesc.h>
#include <casacore/tables/Tables/SetupNewTab.h>
#include <casacore/tables/DataMan/StandardStMan.h>
#include <casacore/tables/Tables/Table.h>
#include <casacore/tables/Tables/TableDesc.h>
#include <casacore/tables/Tables/TableInfo.h>
#include <casacore/tables/Tables/TableLock.h>
#include <casacore/tables/Tables/TableRecord.h>
#include <casacore/tables/Tables/TableCopy.h>
#include <casacore/tables/Tables/TableRow.h>
#include <casacore/tables/DataMan/TiledColumnStMan.h>
#include <casacore/tables/DataMan/TiledShapeStMan.h>
#include <casacore/tables/DataMan/TiledDataStMan.h>
#include <casacore/tables/DataMan/TiledStManAccessor.h>
#include <casacore/measures/Measures/MeasTable.h>
#include <sstream>
#include <iomanip>

#include <algorithm>
#include <casacore/casa/OS/Directory.h>
#include <alma/ASDM/ASDMAll.h>
#include <alma/ASDMBinaries/SDMDataObjectWriter.h>
#include <alma/ASDMBinaries/SDMDataObject.h>

#include <alma/MS2ASDM/MS2ASDM.h>

using asdm::ASDM;
using asdm::TagType;
using namespace asdm;
using namespace asdmbinaries;

using namespace casacore;
namespace casa {

  using casacore::Double;
  using casacore::Complex;
  using casacore::Float;
  
  MS2ASDM::MS2ASDM(MeasurementSet& ms) :
    MSColumns(ms),
    ms_p(ms),
    baseUid_p("uid://X0/X0/X"),
    runningId_p(0),
    currentUid_p("uid://X0/X0/X0"),
    telName_p(""),
    // the maps with defaults
    asdmFeedId_p(-1),
    asdmSourceId_p(-1),
    asdmPointingModelId_p(-1)
  {
    ASDM_p = new ASDM();
    asdmVersion_p = String((ASDM_p->getEntity()).getEntityVersion());
    setSBDuration(); // set to default values
    setSubScanDuration(); 
    setDataAPCorrected();
    setVerbosity();
  }
  
  MS2ASDM::~MS2ASDM()
  {
    delete ASDM_p;
  }
  
  const String& MS2ASDM::showversion()
  {

    static String rstr = String(asdmVersion_p);
    if(rstr==""){
      ASDM* myASDM = new ASDM();
      rstr = String((myASDM->getEntity()).getEntityVersion());
      delete myASDM;
    }
    return rstr;
  }
  
  void MS2ASDM::setBaseUid(const String& baseuid){ baseUid_p = baseuid; }

  const String& MS2ASDM::getBaseUid(){ return baseUid_p; }

  const std::string& MS2ASDM::getCurrentUid(){ 
    static std::string str;
    str = string(currentUid_p.c_str());
    return str; 
  }

  const std::string& MS2ASDM::getCurrentUidAsFileName(){ 
    static std::string str;
    str = string(currentUid_p.c_str());
    std::replace( str.begin(), str.end(), ':', '_' );
    std::replace( str.begin(), str.end(), '/', '_' );

    return str; 
  }

  Bool MS2ASDM::incrementUid()
  {
    static char cstr[20];
    runningId_p++;
    if(sprintf(cstr,"%x", runningId_p) > 0){
      currentUid_p = baseUid_p + String(cstr);
      return true;
    }
    else{
      runningId_p--;
      return false;
    }
  }

  Bool MS2ASDM::writeASDM(const String& asdmfile, const String& datacolumn, 
			  const String& archiveid, const String& rangeid, Bool verbose,
			  const casacore::Double subscanDuration, const casacore::Double schedBlockDuration,
			  const Bool msDataIsAPCorrected)
  {

    LogIO os(LogOrigin("MS2ASDM", "writeASDM()"));

    setBaseUid("uid://"+archiveid+"/"+rangeid+"/X");

    if(!incrementUid()){// need to increment before first use
      os << LogIO::SEVERE << "Error generating UID"
	 << LogIO::POST;      
      return false;
    }

    // set the container UID of all tables == the UID of the ASDM
    asdmUID_p = getCurrentUid().c_str();
    Entity myEntity;
    myEntity.setEntityId(EntityId(asdmUID_p));
    myEntity.setEntityIdEncrypted("na");
    myEntity.setEntityTypeName("ASDM");
    myEntity.setEntityVersion(asdmVersion_p);
    myEntity.setInstanceVersion("1");	
    ASDM_p->setEntity(myEntity);
      
    incrementUid();

    // initialize observatory name
    if(observation().nrow()==0){
      os << LogIO::SEVERE << "MS Observation table is empty." << LogIO::POST;
      return false;
    }

    setObservatoryName(observation().telescopeName()(0)); // get name of observatory from first row of observation table

    if(subscanDuration<1.){
      os << LogIO::SEVERE << "Input error: Unreasonably short sub scan duration limit: " << subscanDuration  
	 << " seconds." << LogIO::POST;
      return false;
    }
     
    if(schedBlockDuration<60.){
      os << LogIO::SEVERE << "Input error: Unreasonably short scheduling block duration limit: " << schedBlockDuration  
	 << " seconds. (Should be >= 60 s)" << LogIO::POST;
      return false;
    }
     
    setSubScanDuration(subscanDuration);

    setSBDuration(schedBlockDuration);

    setDataAPCorrected(msDataIsAPCorrected);

    if(verbose){
      setVerbosity(1); // set to 1 before releasing
    }
    else{
      setVerbosity(0);
    }

    if(verbosity_p>0){
      os << LogIO::NORMAL << "Converting " << ms_p.tableName() << " to ASDM " << asdmfile << endl
	 << "UID base is " << getBaseUid() << ", ASDM UID is " << asdmUID_p
	 << LogIO::POST;
    }

    // write the ASDM tables

    if(!writeStation()){
      return false;
    }

    if(!writeAntenna()){
      return false;
    }

    if(!writeSpectralWindow()){
      return false;
    }

    if(!writeSource()){
      return false;
    }

    if(!writePolarization()){
      return false;
    }

    if(!writeProcessor()){
      return false;
    }

    if(!writeField()){
      return false;
    }

    if(!writeReceiver()){
      return false;
    }

    if(!writeFeed()){
      return false;
    }

    if(!writeDataDescription()){
      return false;
    }

    if(!writeSwitchCycle()){
      return false;
    }

    if(!writeState()){
      return false;
    }

    if(!writeSysCal()){
      return false;
    }

    if(!writeConfigDescription()){
      return false;
    }

    if(!writeSBSummaryAndExecBlockStubs()){ 
      return false;
    }

    // prepare the writing of binary data
    if(!setDirectory(asdmfile)){
       return false;
    }

    if(!writeMainAndScanAndSubScan(datacolumn)){ 
      return false;
    }

    if(!writePointingModel()){
      return false;
    }

    if(!writePointing()){
      return false;
    }

    // finish writing the ASDM non-binary data
    try{
      ASDM_p->toFile(asdmfile);
    }
    catch(ConversionException x){
      os << LogIO::SEVERE << "Error writing ASDM non-binary data:" << x.getMessage()
	 << LogIO::POST;      
      return false;
    }     

    return true;

  }

  Bool MS2ASDM::setDirectory(const String& asdmfile){

    LogIO os(LogOrigin("MS2ASDM", "setDirectory()"));

    // create ASDM output directories
    Directory asdmDir(asdmfile);
    // create if it doesn't exist
    try{
      asdmDir.isEmpty(); // throws if dir doesn't exist
    }
    catch(AipsError x){
      try{
	asdmDir.create(false); // do not overwrite
      }
      catch(AipsError y){
	os << LogIO::SEVERE << "Error creating ASDM top directory: " << y.getMesg()
	   << LogIO::POST;      
	return false;
      }
    }
    // create ASDM binary output directory
    Directory asdmDir2(asdmfile+"/ASDMBinary");
    try{
      asdmDir2.create(false); // do not overwrite
    }
    catch(AipsError x){
      os << LogIO::SEVERE << "Error creating ASDMBinary directory: " << x.getMesg()
	 << LogIO::POST;      
      return false;
    }
    asdmDir_p = asdmfile;
    return true;
  }


  Int MS2ASDM::writeMainBinSubScanForOneDDIdFIdPair(const Int theDDId, const Int theFieldId, 
						    const String& datacolumn, 
						    const uInt theScan, const uInt theSubScan,
						    const uInt startRow, const uInt endRow,
						    const Tag eBlockId,
						    int& datasize, asdm::EntityRef& dataOid, 
						    vector< asdm::Tag >& stateIdV){

    LogIO os(LogOrigin("MS2ASDM", "writeMainBinForOneDDIdAndSubScan()"));

    // return values
    Int numIntegrations = 0;
    datasize = 0;
    dataOid = EntityRef();
    stateIdV.resize(0);

    asdm::ExecBlockRow* eBlockRow = (ASDM_p->getExecBlock()).getRowByKey(eBlockId);
    string eBlockUID = eBlockRow->getExecBlockUID().getEntityId ().toString();
    int eBlockNum = eBlockRow->getExecBlockNum();

    Bool warned=false; // use later to avoid repetitive warnings
    Bool warned2=false; // use later to avoid repetitive warnings

    try{

      uInt nMainTabRows = ms_p.nrow();

      unsigned int subscanNum = theSubScan;

      if(startRow>=nMainTabRows){
	os << LogIO::SEVERE << "Internal error: startRow " << startRow << " exceeds end of MS."
	   << LogIO::POST;
	return -1;
      }

      if(endRow>=nMainTabRows){
	os << LogIO::SEVERE << "Internal error: endRow " << endRow << " exceeds end of MS."
	   << LogIO::POST;
	return -1;
      }

      Int DDId = dataDescId()(startRow);
      if(DDId != theDDId){ // check Data Description Id
	os << LogIO::SEVERE << "Internal error: input parameters to this routine are inconsistent.\n"
	   << " DDId in start row should be as given in input parameters ==" << theDDId << LogIO::POST;
	return -1;
      }
      
      Int FId = fieldId()(startRow);
      if(FId != theFieldId){ // check Field Id
	os << LogIO::SEVERE << "Internal error: input parameters to this routine are inconsistent.\n"
	   << " FieldId in start row should be as given in input parameters ==" << theFieldId << LogIO::POST;
	return -1;
      }

      if(verbosity_p>1){
	os << LogIO::NORMAL << "Writing Main table entries for DataDescId " << DDId 
	   << ", Field Id " << FId << ", ExecBlock " << eBlockNum << ", Scan number " << theScan
	   << ", SubScan number " << theSubScan << LogIO::POST;
      }

      //////////////////////
      // Construct subscan == SDMDataObject
      
      // Assume MS main table is sorted in time. 
      
      // Get first timestamp.
      Double subScanStartTime = time()(startRow);
      Double subScanEndTime = time()(endRow); 
      
      // determine number of different timestamps in this subscan 
      unsigned int numTimestampsCorr = 0;
      unsigned int numTimestampsAuto = 0;
      for(uInt i=startRow; i<=endRow; i++){

	DDId = dataDescId()(i);
	if(DDId != theDDId){ // skip all other Data Description Ids
	  continue;
	}
	FId = fieldId()(i);
	if(FId != theFieldId){ // skip all other Field Ids
	  continue;
	}
	
	if(antenna1()(i)==antenna2()(i)){
	  numTimestampsAuto++;
	}
	else{
	  numTimestampsCorr++;
	}
      } // end for i

      if(verbosity_p>1){
	cout << " subscan number is " << subscanNum << endl;
	cout << " DDId " << theDDId << " FId " << theFieldId << endl;
	cout << " start row " << startRow << " end row " << endRow << endl;
	cout << "  subscan number of timestamps with crosscorrelations is " << numTimestampsCorr << endl;
	cout << "  subscan number of timestamps with autocorrelations is " << numTimestampsAuto << endl;
	cout << "  subscan end time is " << subScanEndTime << endl;
      }
      
      // open disk file for subscan
      String subscanFileName = asdmDir_p+"/ASDMBinary/"+String(getCurrentUidAsFileName());
      if(verbosity_p>1){
	cout << "  subscan filename is " << subscanFileName << endl;
      }
      try{
	dataOid = EntityRef(getCurrentUid(),"","ASDM",asdmVersion_p); 
      }
      catch(asdm::InvalidArgumentException x){
	os << LogIO::SEVERE << "Error creating ASDM:  UID \"" << getCurrentUid() 
	   << "\" (intended for a BLOB) is not a valid Entity reference: " <<  x.getMessage()
	   << LogIO::POST;      
	return -1;
      }
	
      // make sure that this file doesn't exist yet
      ofstream ofs(subscanFileName.c_str());
      
      // set up SDMDataObjectWriter
      
      SDMDataObjectWriter sdmdow(&ofs, getCurrentUid()); // use default title
      
      uint64_t startTime = (uint64_t) floor(subScanStartTime);
      unsigned int execBlockNum = eBlockNum; // constant for all scans
      unsigned int scanNum = theScan; // ASDM scan numbering starts at 1
      if(scanNum == 0 && !warned){
	os << LogIO::WARN << "Scan Number is 0. Note that by convention scan numbers in ASDMs should start at 1." << LogIO::POST;
	warned = true;
      }

      // find the first occurence of the timestamp which has the most baselines
      uInt theSampleStartRow = 0;
      {
	uInt maxNRows = 0;
	
	uInt mainTabRowX=startRow; 

	while(mainTabRowX <= endRow){
	
	  DDId = dataDescId()(mainTabRowX);
	  if(DDId != theDDId){ // skip all other Data Description Ids
	    mainTabRowX++;
	    continue;
	  }
	  FId = fieldId()(mainTabRowX);
	  if(FId != theFieldId){ // skip all other Field Ids
	    mainTabRowX++;
	    continue;
	  }
	  
	  Double theTStamp = time()(mainTabRowX);
	  uInt sRow = mainTabRowX;
	  uInt nRows = 0;
	  while(mainTabRowX < nMainTabRows 
		&& time()(mainTabRowX)==theTStamp){
	    DDId = dataDescId()(mainTabRowX);
	    if(DDId != theDDId){ // skip all other Data Description Ids
	      mainTabRowX++;
	      continue;
	    }
	    FId = fieldId()(mainTabRowX);
	    if(FId != theFieldId){ // skip all other Field Ids
	      mainTabRowX++;
	      continue;
	    }
	    nRows++;
	    mainTabRowX++;
	  }
	  if(nRows>maxNRows){
	    maxNRows = nRows;
	    theSampleStartRow = sRow;
	  }
	} // end while
      }

      // determine actual number of baselines and antennas
      // (at the same time also fill the stateId vector)
      unsigned int numAutoCorrs = 0;
      unsigned int numBaselines = 0;
      unsigned int numAntennas = 0;
      vector<Int> ant;
      {
	uInt i = theSampleStartRow;
	Double thisTStamp = time()(i); 
	while(i<nMainTabRows && time()(i)== thisTStamp){
	  
	  DDId = dataDescId()(i);
	  if(DDId != theDDId){ // skip all other Data Description Ids
	    i++;
	    continue;
	  }
	  FId = fieldId()(i);
	  if(FId != theFieldId){ // skip all other Field Ids
	    i++;
	    continue;
	  }
	  
	  if(antenna1()(i) == antenna2()(i)){
	    numAutoCorrs++;
	  }
	  else{
	    numBaselines++;
	  }
	  
	  Bool found = false;
	  for(uInt j=0;j<ant.size();j++){
	    if(antenna1()(i) == ant[j]){
	      found = true;
	      break;
	    }
	  }
	  if(!found){
	    ant.push_back(antenna1()(i));
	    stateIdV.push_back( asdmStateId_p[stateId()(i)] );
	  }
	  found = false;
	  for(uInt j=0;j<ant.size();j++){
	    if(antenna2()(i) == ant[j]){
	      found = true;
	      break;
	    }
	  }
	  if(!found){
	    ant.push_back(antenna2()(i));
	    stateIdV.push_back( asdmStateId_p[stateId()(i)] );
	  }
	  i++;
	}
      }
      numAntennas = ant.size();
      
      CorrelationModeMod::CorrelationMode correlationMode;
      if(numAutoCorrs==0){
	correlationMode = CorrelationModeMod::CROSS_ONLY;
      }
      else if(numBaselines>0){
	correlationMode = CorrelationModeMod::CROSS_AND_AUTO;
      }
      else{
	correlationMode = CorrelationModeMod::AUTO_ONLY;
      }
      // if datacolumn is FLOAT_DATA make correlation mode == AUTO as well!
      
      
      vector< AtmPhaseCorrectionMod::AtmPhaseCorrection >  apc;
      if(dataIsAPCorrected()){
	apc.push_back(AtmPhaseCorrectionMod::AP_CORRECTED); 
      }
      else{
	apc.push_back(AtmPhaseCorrectionMod::AP_UNCORRECTED); 
      }	    
      vector< SDMDataObject::Baseband > basebands; // ???
      
      // construct spectral window and basedband vectors
      
      vector<SDMDataObject::SpectralWindow> spectralWindows;
      
      // for creating a Spectral Window
      uInt PolId = dataDescription().polarizationId()(theDDId);
      uInt numStokesMS = polarization().numCorr()(PolId);

      asdm::PolarizationRow* PR = (ASDM_p->getPolarization()).getRowByKey(asdmPolarizationId_p[PolId]);
      uInt numStokes = PR->getNumCorr();
      Array<Int> corrT = polarization().corrType()(PolId);
      vector<StokesParameterMod::StokesParameter> crossPolProducts = PR->getCorrType();

      vector<StokesParameterMod::StokesParameter> sdPolProduct;
      float scaleFactor = 1.;
      uInt spwId = dataDescription().spectralWindowId()(theDDId);
      unsigned int numSpectralPoint = spectralWindow().numChan()(spwId);

      OptionalSpectralResolutionType spectralResolution = SpectralResolutionTypeMod::FULL_RESOLUTION; 
      if(numSpectralPoint<5){
	//	spectralResolution = SpectralResolutionTypeMod::CHANNEL_AVERAGE;
	if(!warned2 && verbosity_p>1){
	  //	  os << LogIO::NORMAL << "    Less than 5 channels. Assuming data is of spectral resolution type \"CHANNEL_AVERAGE\"." << LogIO::POST;      
	  //	}
	  os << LogIO::NORMAL << " DDId " << theDDId << ": Less than 5 channels. Probably should use spectral resolution type \"CHANNEL_AVERAGE\"." 
	     << endl << "    But this is not yet implemented. Assuming FULL_RESOLUTION." << LogIO::POST;      
	  warned2 = true;
	}
      } 

      unsigned int numBin = 1; // number of switch cycles
      NetSidebandMod::NetSideband sideband = CNetSideband::from_int(spectralWindow().netSideband()(spwId));
      
      SDMDataObject::SpectralWindow spw(crossPolProducts,
					sdPolProduct,
					scaleFactor,
					numSpectralPoint,
					numBin,
					sideband);
      
      spectralWindows.push_back(spw);
      
      
      SDMDataObject::Baseband bband(BasebandNameMod::NOBB, spectralWindows); // how to select name ???? -> Francois
      // note: for ALMA only four basebands exist, not easy to find baseband for a given SPW
      
      basebands.push_back(bband);
      
      // construct binary parts for dataStruct
      unsigned int bpFlagsSize = numSpectralPoint * numStokes * (numBaselines+numAutoCorrs);

      vector<AxisNameMod::AxisName> bpFlagsAxes;
      bpFlagsAxes.push_back(AxisNameMod::TIM); // order: inner part of loop should be last!!!!!!
      bpFlagsAxes.push_back(AxisNameMod::SPP); 
      bpFlagsAxes.push_back(AxisNameMod::POL);
      SDMDataObject::BinaryPart bpFlags(bpFlagsSize, bpFlagsAxes);
      if(verbosity_p>1){
	cout << "FlagsSize " << bpFlagsSize << " numStokes " << numStokes << endl;
      }
      
      unsigned int bpTimesSize = 0; // only needed for data blanking
      //unsigned int bpTimesSize = numTimestampsCorr+numTimestampsAuto; 
      vector<AxisNameMod::AxisName> bpTimesAxes;
//      bpTimesAxes.push_back(AxisNameMod::TIM);
      SDMDataObject::BinaryPart bpActualTimes(bpTimesSize, bpTimesAxes);
      //      cout << "TimesSize " << bpTimesSize << endl;
      
      unsigned int bpDurSize = 0; // only needed for data blanking
      //	unsigned int bpDurSize = numTimestampsCorr+numTimestampsAuto;
      vector<AxisNameMod::AxisName> bpDurAxes;
//      bpDurAxes.push_back(AxisNameMod::TIM);
      SDMDataObject::BinaryPart bpActualDurations(bpDurSize, bpDurAxes);
      //      cout << "DurSize " << bpDurSize << endl;
      
      unsigned int bpLagsSize = 0; // not filled for the moment (only useful if LAG_DATA column present) -> Francois 
      vector<AxisNameMod::AxisName> bpLagsAxes;
      bpLagsAxes.push_back(AxisNameMod::SPP); // ******
      SDMDataObject::ZeroLagsBinaryPart bpZeroLags(bpLagsSize, bpLagsAxes, CorrelatorTypeMod::FXF); // ALMA default
      if(telName_p != "ALMA" && telName_p != "OSF"){
	if(telName_p == "ACA" || telName_p == "VLBA" || telName_p == "EVLA"){
	  bpZeroLags = SDMDataObject::ZeroLagsBinaryPart(bpLagsSize, bpLagsAxes, CorrelatorTypeMod::FX);	  
	}
	else{
	  bpZeroLags = SDMDataObject::ZeroLagsBinaryPart(bpLagsSize, bpLagsAxes, CorrelatorTypeMod::XF);
	}
      }
      //      cout << "LagsSize " << bpLagsSize << endl;
      
      unsigned int bpCrossSize = numSpectralPoint * numStokes * numBaselines * 2; // real + imag
      vector<AxisNameMod::AxisName> bpCrossAxes;
      //      bpCrossAxes.push_back(AxisNameMod::TIM);
      bpCrossAxes.push_back(AxisNameMod::BAL);
      bpCrossAxes.push_back(AxisNameMod::SPP); 
      bpCrossAxes.push_back(AxisNameMod::POL);
      SDMDataObject::BinaryPart bpCrossData(bpCrossSize, bpCrossAxes);
      //      cout << "CrossSize " << bpCrossSize << endl;
      
      unsigned int bpAutoSize = numSpectralPoint * numStokes * numAutoCorrs;
      vector<AxisNameMod::AxisName> bpAutoAxes;
      //      bpAutoAxes.push_back(AxisNameMod::TIM);
      bpAutoAxes.push_back(AxisNameMod::ANT);
      bpAutoAxes.push_back(AxisNameMod::SPP); 
      bpAutoAxes.push_back(AxisNameMod::POL);
      SDMDataObject::AutoDataBinaryPart bpAutoData(bpAutoSize, bpAutoAxes, false); // not normalised
      //      cout << "AutoSize " << bpAutoSize << endl;
      
      SDMDataObject::DataStruct dataStruct( apc, basebands, bpFlags, bpActualTimes, bpActualDurations, 
					    bpZeroLags, bpCrossData, bpAutoData);	 
      
      // Parameters of dataStruct:
      //     	apc 	        a vector of AtmPhaseCorrection. If apc is not relevant pass an empty vector.
      //     	basebands 	a vector of Baseband.
      //     	flags 	        a BinaryPart object describing the flags. If flags is not relevant pass an 
      //                      empty BinaryPart object.
      //     	actualTimes 	a BinaryPart object describing the actual times. If actualTimes is not 
      //                      relevant pass an empty BinaryPart object.
      //     	actualDurations a BinaryPart object describing the actual durations. If actualDurations is 
      //                      not relevant pass an empty BinaryPart object.
      //     	zeroLags 	a ZeroLagsBinaryPart object describing the zero lags. If zeroLags is not 
      //                      relevant pass an empty ZeroLagsBinaryPart object.
      //     	crossData 	a BinaryPart object describing the cross data. If crossData is not relevant 
      //                      pass an empty BinaryPart object.
      //     	autoData 	an AutoDataBinaryPart object describing the auto data. If autoData is not 
      //                      relevant pass an empty AutoDataBinaryPart object. 
      
      
      // Write the global header.
      sdmdow.corrDataHeader(startTime,
			    eBlockUID,
			    execBlockNum,
			    scanNum,
			    subscanNum,
			    numAntennas,        
			    correlationMode,    // the correlation mode.
			    spectralResolution, // the spectral resolution.
			    dataStruct);        // the description of the structure of the binary data.
      
      //////////////////////////////////////////////////////
      // write the integrations until timestamp exceeds limit
      unsigned int integrationNum = 1;
      uInt mainTabRow=startRow; 

      while(mainTabRow <= endRow){
	
	DDId = dataDescId()(mainTabRow);
	if(DDId != theDDId){ // skip all other Data Description Ids
	  mainTabRow++;
	  continue;
	}
	FId = fieldId()(mainTabRow);
	if(FId != theFieldId){ // skip all other Field Ids
	  mainTabRow++;
	  continue;
	}
	
	uint64_t timev = (uint64_t) floor((time()(mainTabRow))*1E9); // what units? nanoseconds
	uint64_t intervalv = (uint64_t) floor(interval()(mainTabRow)*1E9);
	vector< unsigned int > flags;
	vector< int64_t > actualTimes;
	vector< int64_t > actualDurations;
	vector< float > zeroLags; // LAG_DATA, optional column, not used for the moment
	vector< float > crossData;
	// vector< short > crossData;
	// vector< int > crossData; // standard case for ALMA
	vector< float > autoData;	 
	
	////////////////////////////////////////////////////////
	// fill data, time, and flag vectors for this timestamp
	Double theTStamp = time()(mainTabRow);
	
	// SORT the data by baseline and antenna resp.!!!!!!!!!!!!

	// create a list of the row numbers in this timestamp sorted by baseline in BDF style,
	// i.e., e.g., for antennas (1,2,3,4): ['(1,1)', '(1,2)', '(2,2)', '(1,3)', '(2,3)', '(3,3)', '(1,4)', 
        //                             '(2,4)', '(3,4)', '(4,4)', '(1,5)', '(2,5)', '(3,5)', '(4,5)', '(5,5)']
	vector< uInt > rowsSorted;
	{
	  vector< uInt > rows;
	  while(mainTabRow < nMainTabRows 
		&& time()(mainTabRow)==theTStamp){
	    DDId = dataDescId()(mainTabRow);
	    if(DDId != theDDId){ // skip all other Data Description Ids
	      mainTabRow++;
	      continue;
	    }
	    FId = fieldId()(mainTabRow);
	    if(FId != theFieldId){ // skip all other Field Ids
	      mainTabRow++;
	      continue;
	    }
	    rows.push_back(mainTabRow);
	    mainTabRow++;
	  }

	  uInt nRows = rows.size();
	  vector<Int> bLine(nRows);
	  uInt maxAnt = 0;
	  for(uInt i=0; i<nRows; i++){
	    uInt a2 = antenna2()(rows[i]);
	    bLine[i] = antenna1()(rows[i])*1000 + a2;
	    if(maxAnt<a2){
	      maxAnt=a2;
	    }
	  }	

	  rowsSorted.resize(nRows);
	  uInt expNRows = maxAnt*(maxAnt+1)/2; // (zero-based counting)
	  uInt expNRowsWAuto = maxAnt*(maxAnt+1)/2 + maxAnt+1; // (zero-based counting)
	  Bool haveAuto = false;
	  if(nRows==expNRowsWAuto){
	    haveAuto=true;
	  }
	  else if(nRows!=expNRows){ 
	    ostringstream oss;
	    oss << "Expected " << expNRows << " rows in integration but found " << nRows << endl;
	    throw(asdmbinaries::SDMDataObjectWriterException(oss.str()));
	  }
	  uInt count=0;
	  for(uInt i= (haveAuto ? 0 : 1) ; i<maxAnt+1; i++){
	    for(uInt j=0; j< (haveAuto ? i+1 : i); j++){
	      Int myBLine = j*1000 + i;
	      for(uInt ii=0; ii<nRows; ii++){
		if(bLine[ii]==myBLine){
		  rowsSorted[count] = rows[ii];
		  break;
		}
		if(ii==nRows-1){ // not found
		  ostringstream oss;
		  oss << "Baseline " << myBLine << " not found." << endl;
		  throw(asdmbinaries::SDMDataObjectWriterException(oss.str()));
		}
	      }
	      count++;
	    }
	  }

	}
	
	for(uInt ii=0; ii<rowsSorted.size(); ii++){
	  
	  uInt iRow = rowsSorted[ii];

	  DDId = dataDescId()(iRow);
	  FId = fieldId()(iRow);
	  
	  Matrix<casacore::Complex> dat;
	  Matrix<Bool> flagsm;
	  String dataColumn(datacolumn);
	  dataColumn.upcase();
	  if(dataColumn == "MODEL"){
	    dat.reference(modelData()(iRow));
	  }
	  else if(dataColumn == "CORRECTED"){
	    dat.reference(correctedData()(iRow));
	  }
	  else{
	    dat.reference(data()(iRow));
	  }
	  flagsm.reference(flag()(iRow));
	  
	  //cout << " ii row a1 a2 " << ii << " " << iRow << " " << antenna1()(iRow) << " " << antenna2()(iRow) << endl;

	  Bool haveAuto = (antenna1()(iRow) == antenna2()(iRow));

	  if(haveAuto){
	    Complex x;  
	    float a;
	    for(uInt i=0; i<numSpectralPoint; i++){
	      for(uInt j=0; j<numStokesMS; j++){
		if(skipCorr_p[PolId][j]){
		  continue;
		}
		else{
		  x = dat(j,i);
		  a = x.real();
		  autoData.push_back( a );
		}
	      }
	    }
	  }
	  else{
	    casacore::Complex x;
	    float a,b;
	    // int a,b;
	    for(uInt i=0; i<numSpectralPoint; i++){
	      for(uInt j=0; j<numStokesMS; j++){
		x = dat(j,i);
		a = x.real();
		b = x.imag();
		crossData.push_back( a );
		crossData.push_back( b );
	      }
	    }
	  }

	  unsigned int ul;
	  for(uInt i=0; i<numSpectralPoint; i++){
	    for(uInt j=0; j<numStokesMS; j++){
	      if(haveAuto && skipCorr_p[PolId][j]){
		continue;
	      }
	      else{
		if(flagRow()(iRow)){
		  ul = 1;
		}
		else{
		  ul = flagsm(j,i);
		}
		flags.push_back( ul );
	      }
	    }
	  }
	  // the following two lines only needed for data blanking
	  //	    actualTimes.push_back((int64_t)floor(time()(iRow))*1000.);
	  //	    actualDurations.push_back((int64_t)floor(interval()(iRow))*1000.);
	}// end loop over rows in this timestamp sorted by baseline
	

	// fill with flagged entries in case there are missing baselines in the MS
	uInt nToAdd1 = 0;
	uInt nToAdd2 = 0;
	uInt nToAdd3 = 0;
	uInt nToAdd4 = 0;
	uInt nToAdd5 = 0;
	uInt nToAdd6 = 0;

	if(flags.size()<bpFlagsSize){
	  nToAdd1 = bpFlagsSize - flags.size();
	  for(uInt i=0; i<nToAdd1; i++){
	    flags.push_back(1);
	  }
	}	
	if(actualTimes.size()<bpTimesSize){
	  nToAdd2 = bpTimesSize-actualTimes.size();
	  for(uInt i=0; i<nToAdd2; i++){
	    actualTimes.push_back(0);
	  }
	}
	if(actualDurations.size()<bpDurSize){
	  nToAdd3 = bpDurSize-actualDurations.size();
	  for(uInt i=0; i<nToAdd3; i++){
	    actualDurations.push_back(0);
	  }
	}
	if(zeroLags.size()<bpLagsSize){
	  nToAdd4 = bpLagsSize-zeroLags.size();
	  for(uInt i=0; i<nToAdd4; i++){
	    zeroLags.push_back(0.);
	  }
	}
	if(crossData.size()<bpCrossSize){
	  nToAdd5 = bpCrossSize-crossData.size();
	  for(uInt i=0; i<nToAdd5; i++){
	    crossData.push_back(0.);
	  }
	}
	if(autoData.size()<bpAutoSize){
	  nToAdd6 = bpAutoSize-autoData.size();
	  for(uInt i=0; i<nToAdd6; i++){
	    autoData.push_back(0.);
	  }
	}

	if(nToAdd1+nToAdd2+nToAdd3+nToAdd4+nToAdd5+nToAdd6>0){
	  os << LogIO::WARN << "Encountered missing integrations for some baselines in MS."
	     << " Will fill with flagged entries (" << nToAdd1 << ", " << nToAdd2 << ", " << nToAdd3 
	     << ", "<< nToAdd4 << ", "<< nToAdd5 << ", "<< nToAdd6 << ")" << LogIO::POST; 
	}
	
	// finally write the integration
	  
	if(verbosity_p>1){
	  cout << "Sizes: " << endl;
	  cout << "   flags " << flags.size() << endl;
	  cout << "   actualTimes " << actualTimes.size() << endl;
	  cout << "   actualDurations " << actualDurations.size() << endl;
	  cout << "   zeroLags " << zeroLags.size() << endl;
	  cout << "   crossData " << crossData.size() << endl;
	  cout << "   autoData " << autoData.size() << endl;
	}

	try{

	  sdmdow.addIntegration(integrationNum,    // integration's index.
				timev,             // midpoint
				intervalv,         // time interval
				flags,             // flags binary data 
				actualTimes,       // actual times binary data      
				actualDurations,   // actual durations binary data          
				zeroLags,          // zero lags binary data                 
				crossData,    // cross data (can be short or int)  
				autoData);         // single dish data.  

	  integrationNum++;
	  datasize += flags.size() * sizeof(unsigned int)
	    + actualTimes.size() * sizeof( int64_t )
	    + actualDurations.size() * sizeof( int64_t )
	    + zeroLags.size() * sizeof( float )
	    + crossData.size() * sizeof( float )
	    + autoData.size() * sizeof( float );
	  numIntegrations++;

	}
	catch(asdmbinaries::SDMDataObjectWriterException x){
	  os << LogIO::WARN << "Error writing ASDM:" << x.getMessage() << endl
	     << "Will try to continue ..."
	     << LogIO::POST; 
	}
	// (Note: subintegrations are used only for channel averaging to gain time res. by sacrificing spec. res.)
	
      } // end while 
      
      sdmdow.done();
      
      ofs.close();
      
      // end write subscan
      
      incrementUid();
            
    }
    catch(asdmbinaries::SDMDataObjectWriterException x){
      os << LogIO::SEVERE << "Error creating ASDM: " << x.getMessage()
	 << LogIO::POST;      
      return -1;
    }
    catch(asdmbinaries::SDMDataObjectException x){
      os << LogIO::SEVERE << "Error creating ASDM: " << x.getMessage()
	 << LogIO::POST;      
      return -1;
    }
    catch(AipsError y){
      os << LogIO::SEVERE << "Error creating ASDM: " << y.getMesg()
	 << LogIO::POST;      
      return -1;
    }      
    catch(std::string z){
      os << LogIO::SEVERE << "Error creating ASDM: " << z
	 << LogIO::POST;      
      return -1;
    }      
    catch(std::exception zz){
      os << LogIO::SEVERE << "Error creating ASDM: " << zz.what()
	 << LogIO::POST;      
      return -1;
    }      
    
    return numIntegrations;

  } // end writeMainBinForOneDDIdAndSubScan


  /////////////////////////////////////
  //   // Pattern for wrting a non-binary table:
  //   Bool MS2ASDM::writeAntenna(){ // create asdm antenna table and fill antenna id map
  //     LogIO os(LogOrigin("MS2ASDM", "writeAntenna()"));
  
  //     Bool rstat = true;
  
  //     asdm::AntennaTable& tT = ASDM_p->getAntenna();
  
  //     asdm::AntennaRow* tR = 0;
  
  //     //    tR = tT.newRow();
  
  //     tT.add(tR);
  
  //     EntityId theUid(getCurrentUid());
  //     Entity ent = tT.getEntity();
  //     ent.setEntityId(theUid);
  //     tT.setEntity(ent);
  //     if(verbosity_p>0){
  //       os << LogIO::NORMAL << "Filled Antenna table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
  //     }
  //     incrementUid();
  
  //     return rstat;
  //   }

  Bool MS2ASDM::writeStation(){ // create asdm station table and fill station id map
    LogIO os(LogOrigin("MS2ASDM", "writeStation()"));

    Bool rstat = true;

    asdm::StationTable& tT = ASDM_p->getStation();

    asdm::StationRow* tR = 0;

    // MS has no station table; get information from the antenna table

    for(uInt irow=0; irow<antenna().nrow(); irow++){

      // parameters for the new station row
      StationTypeMod::StationType type = StationTypeMod::ANTENNA_PAD; 
      // (alternatives are MAINTENANCE_PAD and WEATHER_STATION)

      // parameters of the new row
      string name = antenna().station()(irow).c_str();

      vector<Length > position; // take the antenna position (!), (later set the ASDM antenna postion to 0,0,0)
      Vector<Double > v; // aux. vector
      v.reference(antenna().position()(irow));
      for(uInt i=0; i<v.size(); i++){
	position.push_back(Length(v[i]));
      }

      Tag stationId;
      String sId = antenna().station()(irow);
      tR = tT.newRow(name, position, type);
      
      asdm::StationRow* tR2 = 0;

      tR2 = tT.add(tR);
      if(tR2 == tR){ // adding this row caused a new tag to be defined
	// enter tag into the map
          asdmStationId_p[String(name)] = tR->getStationId();
      }
      else{
	os << LogIO::SEVERE << "Duplicate station in MS Antenna table: " << irow << LogIO::POST;
	return false;
      }

    } // end for irow

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled Station table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }

  Bool MS2ASDM::writeAntenna(){ // create asdm antenna table and fill antenna id map
    LogIO os(LogOrigin("MS2ASDM", "writeAntenna()"));

    Bool rstat = true;

    asdm::AntennaTable& tT = ASDM_p->getAntenna();

    asdm::AntennaRow* tR = 0;

    for(uInt irow=0; irow<antenna().nrow(); irow++){

      // parameters of the new row
      string name = antenna().name()(irow).c_str();
      AntennaMakeMod::AntennaMake antennaMake = AntennaMakeMod::UNDEFINED; // no info in MS (presently)
      AntennaTypeMod::AntennaType antennaType = ASDMAntennaType( antenna().type()(irow) );
      Length dishDiameter = Length( antenna().dishDiameter()(irow) );

      vector<Length > position;
      for(uInt i=0; i<3; i++){
	position.push_back(Length(0.)); // the antenna position in the ASDM is the sum of station pos and antenna pos.
      }

      vector<Length > offset;
      Vector<Double > v; // aux. vector
      v.reference(antenna().offset()(irow));
      for(uInt i=0; i<v.size(); i++){
	offset.push_back(Length(v[i]));
      }

      ArrayTime atime = ASDMArrayTime(time()(0)); // use start time of MS 

      Tag stationId;
      String sId = antenna().station()(irow); // the station name
      if(asdmStationId_p.find(sId) != asdmStationId_p.end( )){
          stationId = asdmStationId_p[sId];
      }
      else{
	os << LogIO::SEVERE << "Internal error: No station ID defined for station name " << sId << LogIO::POST;
	return false;
      }
      
      tR = tT.newRow(name, antennaMake, antennaType, dishDiameter, position, offset, atime, stationId);
      
      asdm::AntennaRow* tR2 = 0;

      tR2 = tT.add(tR);
      if(tR2 == tR){ // adding this row caused a new tag to be defined
	// enter tag into the map
          asdmAntennaId_p[irow] = tR->getAntennaId();
      }
      else{
	os << LogIO::WARN << "Duplicate row in MS Antenna table :" << irow << LogIO::POST;
      }
    }

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled Antenna table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }

  Bool MS2ASDM::writeSpectralWindow(){
    LogIO os(LogOrigin("MS2ASDM", "writeSpectralWindow()"));

    Bool rstat = true;

    asdm::SpectralWindowTable& tT = ASDM_p->getSpectralWindow();

    asdm::SpectralWindowRow* tR = 0;

    for(uInt irow=0; irow<spectralWindow().nrow(); irow++){

      // parameters of the new row
      BasebandNameMod::BasebandName basebandName = BasebandNameMod::NOBB;
      if(!spectralWindow().bbcNo().isNull()){ // BBC_NO is an optional MS column
	basebandName = ASDMBBName( spectralWindow().bbcNo()(irow) );
      }
      NetSidebandMod::NetSideband netSideband = ASDMNetSideBand( spectralWindow().netSideband()(irow) );
      int numChan = spectralWindow().numChan()(irow);

      Frequency refFreq  = Frequency( spectralWindow().refFrequencyQuant()(irow).getValue(unitASDMFreq()) );
      SidebandProcessingModeMod::SidebandProcessingMode sidebandProcessingMode = SidebandProcessingModeMod::NONE;
      Frequency totBandwidth = Frequency( spectralWindow().totalBandwidthQuant()(irow).getValue(unitASDMFreq()) );
      WindowFunctionMod::WindowFunction windowFunction = WindowFunctionMod::UNIFORM;

      tR = tT.newRow(basebandName, netSideband, numChan, refFreq, sidebandProcessingMode, totBandwidth, windowFunction);

      Vector< Quantum<Double> > v;
      vector< Frequency > chanFreqArray;
      v.reference( spectralWindow().chanFreqQuant()(irow) );
      for(uInt i=0; i<v.nelements(); i++){ 
	chanFreqArray.push_back( Frequency( v[i].getValue(unitASDMFreq()) ) );
      }
      tR->setChanFreqArray(chanFreqArray);

      vector< Frequency > chanWidthArray;
      v.reference( spectralWindow().chanWidthQuant()(irow) );
      for(uInt i=0; i<v.nelements(); i++){ 
	chanWidthArray.push_back( Frequency( v[i].getValue(unitASDMFreq()) ) );
      }
      tR->setChanWidthArray(chanWidthArray);

      vector< Frequency > effectiveBwArray;
      v.reference( spectralWindow().effectiveBWQuant()(irow) );
      for(uInt i=0; i<v.nelements(); i++){ 
	effectiveBwArray.push_back( Frequency( v[i].getValue(unitASDMFreq()) ) );
      }
      tR->setEffectiveBwArray(effectiveBwArray);

      vector< Frequency > resolutionArray;
      v.reference( spectralWindow().resolutionQuant()(irow) );
      for(uInt i=0; i<v.nelements(); i++){ 
	resolutionArray.push_back( Frequency( v[i].getValue(unitASDMFreq()) ) );
      }      
      tR->setResolutionArray( resolutionArray );

      MFrequency::Types refFrame = MFrequency::castType(spectralWindow().measFreqRef()(irow));
      FrequencyReferenceCodeMod::FrequencyReferenceCode measFreqRef = ASDMFreqRefCode( refFrame );
      tR->setMeasFreqRef( measFreqRef );

      tR->setFreqGroup( spectralWindow().freqGroup()(irow) );

      tR->setFreqGroupName( string( spectralWindow().freqGroupName()(irow).c_str() ) );	

      if(!spectralWindow().dopplerId().isNull()){ // DOPPLER_ID is an optional MS column
	tR->setDopplerId( spectralWindow().dopplerId()(irow) );
      }

      // add the row to the table
      asdm::SpectralWindowRow* tR2 = 0;
      tR2 = tT.add(tR);

      if(tR2 == tR){ // adding this row caused a new tag to be defined
	// enter tag into the map
          asdmSpectralWindowId_p[irow] = tR->getSpectralWindowId();
      }
      else{
	os << LogIO::WARN << "Duplicate row in MS Spectral Window table :" << irow << LogIO::POST;
      }
    } // end loop over MS SPW table

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled SpectralWindow table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }

  Bool MS2ASDM::writeSource(){ // create asdm source table and fill source id map
    LogIO os(LogOrigin("MS2ASDM", "writeSource()"));
    
    Bool rstat = true;
    
    asdm::SourceTable& tT = ASDM_p->getSource();
    
    asdm::SourceRow* tR = 0;
    
    if(source().isNull()){// the source table doesn't exist (it is optional)
      os << LogIO::WARN << "MS Source table doesn't exist (it is optional). Cannot create ASDM Source table."
	 << LogIO::POST;
      rstat = true; // not an error
    }
    else {
      for(uInt irow=0; irow<source().nrow(); irow++){

	Int sId = source().sourceId()(irow);

	// parameters of the new row

	ArrayTimeInterval timeInterval( ASDMTimeInterval(source().timeQuant()(irow), source().intervalQuant()(irow)) );
	//cout << "in writeSource: timeInterval " << source().time()(irow) << ", " << source().interval()(irow) << endl;
	//cout << "                timeInterval " << timeInterval.getStartInNanoSeconds() << ", " << timeInterval.getDurationInNanoSeconds() << endl;

	Int spwId = source().spectralWindowId()(irow);
	Tag spectralWindowId;
	if( asdmSpectralWindowId_p.find(spwId) == asdmSpectralWindowId_p.end( ) ){
	  os << LogIO::SEVERE << "Undefined SPW id " << spwId << " in MS Source table row "<< irow << LogIO::POST;
	  return false;
	} else {
	  spectralWindowId = asdmSpectralWindowId_p[spwId];
	}
	string code = source().code()(irow).c_str();
	if(code=="" || code==" "){
	  code="-";
	}
	vector< Angle > direction;
	MDirection theSourceDir = source().directionMeas()(irow);
	direction.push_back( Angle( theSourceDir.getAngle( unitASDMAngle() ).getValue()(0) ) ); // RA
	direction.push_back( Angle( theSourceDir.getAngle( unitASDMAngle() ).getValue()(1) ) ); // DEC
	
	MDirection::Types dirRef;
	MDirection::getType(dirRef, theSourceDir.getRefString());
	DirectionReferenceCodeMod::DirectionReferenceCode directionCode
	  = ASDMDirRefCode(dirRef);

	vector< AngularRate > properMotion;
	if(!source().properMotionQuant().isNull()){
	  Vector< Quantity > pMV;
	  pMV.reference(source().properMotionQuant()(irow));
	  try{
	    properMotion.push_back( AngularRate( pMV[0].getValue(unitASDMAngularRate()) ) );
	    properMotion.push_back( AngularRate( pMV[1].getValue(unitASDMAngularRate()) ) );
	  }
	  catch(AipsError x){
	    os << LogIO::SEVERE << "Error accessing proper motion parameters in MS Source table row " << irow 
	       << ":\n   " << x.getMesg() << LogIO::POST;
	  }
	}
	else{ 
	  properMotion.push_back( AngularRate( 0. ) );
	  properMotion.push_back( AngularRate( 0. ) );
	}	  
	
	string sourceName = (source().name()(irow)).c_str();

	tR = tT.newRow(timeInterval, spectralWindowId, code, direction, properMotion, sourceName);
    
	tR->setDirectionCode(directionCode);

	asdm::SourceRow* tR2 = 0;
	try{
	  tR2 = tT.add(tR);
	}
	catch(asdm::UniquenessViolationException x){
	  os << LogIO::WARN << "While creating ASDM:  UID \"" << getCurrentUid() 
	     << "\" Source table: " <<  x.getMessage() << endl
	     << "Will try to continue."
	     << LogIO::POST;   
	}

	if(tR2 != tR){ // did not lead to the creation of a new tag
	  os << LogIO::WARN << "Duplicate MS Source table row " << irow << ", source id " << sId << LogIO::POST;
	}
	if( asdmSourceId_p.find(sId) == asdmSourceId_p.end( ) ){
	  int souId = tR2->getSourceId();
	  asdmSourceId_p[sId] = souId;
	}
      } // end loop over source table
    } // id if source table exists

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled Source table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();
    
    return rstat;
  }



  Bool MS2ASDM::writePolarization(){
    LogIO os(LogOrigin("MS2ASDM", "writePolarization()"));

    Bool rstat = true;
    asdm::PolarizationTable& tT = ASDM_p->getPolarization();

    asdm::PolarizationRow* tR = 0;

    skipCorr_p.resize(0); 

    for(uInt irow=0; irow<polarization().nrow(); irow++){

      if(polarization().flagRow()(irow)){
	continue;
      }

      vector< Bool > skipCorr;

      // parameters of the new row

      vector< StokesParameterMod::StokesParameter > corrTypeV;
      vector< vector< PolarizationTypeMod::PolarizationType > > corrProduct;
      
      Vector< Int > v; // aux. vector
      v.reference( polarization().corrType()(irow) );
      for(uInt i=0; i<v.nelements(); i++){
	Bool skip = true;
	Stokes::StokesTypes st = static_cast<Stokes::StokesTypes>(v[i]);
	if(st == Stokes::LR){ // only add if RL is not also present
	  if(!stokesTypePresent(v, Stokes::RL)){
	    skip = false;
	  }
	}
	else if(st == Stokes::YX){ // only add if XY is not also present
	  if(!stokesTypePresent(v, Stokes::XY)){
	    skip = false;
	  }
	}
	else{
	  skip = false;
	}
	corrTypeV.push_back( ASDMStokesParameter( st ) );
	skipCorr.push_back(skip);
      }
      int numCorr = corrTypeV.size(); 
      skipCorr_p.push_back(skipCorr);

      // now read the just created corrTypeV and write the correlation products accordingly
      for(uInt i=0; i<corrTypeV.size(); i++){
	vector< PolarizationTypeMod::PolarizationType > w;
	switch(corrTypeV[i]){
	case StokesParameterMod::RR:
	  w.push_back(PolarizationTypeMod::R);
	  w.push_back(PolarizationTypeMod::R);
	  break;
	case StokesParameterMod::RL:
	  w.push_back(PolarizationTypeMod::R);
	  w.push_back(PolarizationTypeMod::L);
	  break;
	case StokesParameterMod::LR:
	  w.push_back(PolarizationTypeMod::L);
	  w.push_back(PolarizationTypeMod::R);
	  break;
	case StokesParameterMod::LL:
	  w.push_back(PolarizationTypeMod::L);
	  w.push_back(PolarizationTypeMod::L);
	  break;
	case StokesParameterMod::XX:
	  w.push_back(PolarizationTypeMod::X);
	  w.push_back(PolarizationTypeMod::X);
	  break;
	case StokesParameterMod::XY:
	  w.push_back(PolarizationTypeMod::X);
	  w.push_back(PolarizationTypeMod::Y);
	  break;
	case StokesParameterMod::YX:
	  w.push_back(PolarizationTypeMod::Y);
	  w.push_back(PolarizationTypeMod::X);
	  break;
	case StokesParameterMod::YY:
	  w.push_back(PolarizationTypeMod::Y);
	  w.push_back(PolarizationTypeMod::Y);
	  break;
	case StokesParameterMod::RX:
	  w.push_back(PolarizationTypeMod::R);
	  w.push_back(PolarizationTypeMod::X);
	  break;
	case StokesParameterMod::RY:
	  w.push_back(PolarizationTypeMod::R);
	  w.push_back(PolarizationTypeMod::Y);
	  break;
	case StokesParameterMod::LX:
	  w.push_back(PolarizationTypeMod::L);
	  w.push_back(PolarizationTypeMod::X);
	  break;
	case StokesParameterMod::LY:
	  w.push_back(PolarizationTypeMod::L);
	  w.push_back(PolarizationTypeMod::Y);
	  break;
	case StokesParameterMod::XR:
	  w.push_back(PolarizationTypeMod::X);
	  w.push_back(PolarizationTypeMod::R);
	  break;
	case StokesParameterMod::XL:
	  w.push_back(PolarizationTypeMod::X);
	  w.push_back(PolarizationTypeMod::L);
	  break;
	case StokesParameterMod::YR:
	  w.push_back(PolarizationTypeMod::Y);
	  w.push_back(PolarizationTypeMod::R);
	  break;
	case StokesParameterMod::YL:
	  w.push_back(PolarizationTypeMod::Y);
	  w.push_back(PolarizationTypeMod::L);
	  break;
	case StokesParameterMod::I:
	  os << LogIO::NORMAL << "Note: Stokes I (probably WVR data) stored with corr. types XX." << LogIO::POST;
	  w.push_back(PolarizationTypeMod::X);
	  w.push_back(PolarizationTypeMod::X);
	  break;
	default:
	  os << LogIO::SEVERE << "Cannot store correlation product for stokes parameter " << CStokesParameter::name(corrTypeV[i]) << LogIO::POST;
	  rstat = false;
	  break;
	}	  
	corrProduct.push_back(w);
      } // end loop over corrTypeV

      tR = tT.newRow(numCorr, corrTypeV, corrProduct);

      //cout << "ASDM numCorr is " << numCorr << endl;

      ////bool flagRow = polarization().flagRow()(irow);
      ////tR->setFlagRow(flagRow);

      // add the row to the table
      asdm::PolarizationRow* tR2 = 0;
      tR2 = tT.add(tR);

      if(tR2 == tR){ // adding this row caused a new tag to be defined
	// enter tag into the map
          asdmPolarizationId_p[irow] = tR->getPolarizationId();
      }
      else{
	os << LogIO::WARN << "Duplicate row in MS Polarization table :" << irow << LogIO::POST;
      }
    } // end loop over MS Pol table

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled Polarization table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }

  Bool MS2ASDM::writeCorrelatorMode(){
    LogIO os(LogOrigin("MS2ASDM", "writeCorrelatorMode()"));

    Bool rstat = true;
    asdm::CorrelatorModeTable& tT = ASDM_p->getCorrelatorMode();

    asdm::CorrelatorModeRow* tR = 0;

    // create only one row

    int numBaseband = 1;
    vector<BasebandNameMod::BasebandName > basebandNames;
    basebandNames.push_back(BasebandNameMod::NOBB);
    vector<int > basebandConfig;
    basebandConfig.push_back(0);
    AccumModeMod::AccumMode accumMode = AccumModeMod::NORMAL;
    int binMode = 1; // standard setting for interferometry
    int numAxes = 4; // time, antenna, stokes, pol 
    vector<AxisNameMod::AxisName > axesOrderArray;
    axesOrderArray.push_back(AxisNameMod::TIM);
    axesOrderArray.push_back(AxisNameMod::ANT);
    axesOrderArray.push_back(AxisNameMod::SPP); 
    axesOrderArray.push_back(AxisNameMod::POL);
    vector<FilterModeMod::FilterMode > filterMode;
    filterMode.push_back(FilterModeMod::UNDEFINED);

    CorrelatorNameMod::CorrelatorName correlatorName = CorrelatorNameMod::ALMA_BASELINE; // the default
    if(telName_p == "ALMA" || telName_p == "OSF"){
      correlatorName = CorrelatorNameMod::ALMA_BASELINE; //???
    }
    else if(telName_p == "ACA"){
      correlatorName = CorrelatorNameMod::ALMA_ACA; //???
    }
    else if(telName_p == "VLA"){
      correlatorName = CorrelatorNameMod::NRAO_VLA; //???
    }
    else if(telName_p == "EVLA"){
      correlatorName = CorrelatorNameMod::NRAO_WIDAR; //???
    }
    else if(telName_p == "PDB"){
      correlatorName = CorrelatorNameMod::IRAM_PDB; //???
    }
    else{
      os << LogIO::WARN << "Unknown telescope name: " << telName_p << ". Assuming ALMA_BASELINE." << LogIO::POST;
    }      

    tR = tT.newRow(numBaseband, basebandNames, basebandConfig, accumMode, binMode, numAxes, axesOrderArray, filterMode, correlatorName);

    tT.add(tR);

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled CorrelatorMode table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }

  Bool MS2ASDM::writeAlmaRadiometer(){
    LogIO os(LogOrigin("MS2ASDM", "writeAlmaRadiometer()"));

    Bool rstat = true;
    asdm::AlmaRadiometerTable& tT = ASDM_p->getAlmaRadiometer();

    asdm::AlmaRadiometerRow* tR = 0;

    tR = tT.newRow();

    tT.add(tR);

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled AlmaRadiometer table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }

  Bool MS2ASDM::writeHolography(){
    LogIO os(LogOrigin("MS2ASDM", "writeHolography()"));

    Bool rstat = true;
    asdm::HolographyTable& tT = ASDM_p->getHolography();

    asdm::HolographyRow* tR = 0;

    //    tR = tT.newRow();

    tT.add(tR);

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled Holography table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }

  Bool MS2ASDM::writeProcessor(){
    LogIO os(LogOrigin("MS2ASDM", "writeProcessor()"));

    Bool rstat = true;
    asdm::ProcessorTable& tT = ASDM_p->getProcessor();

    asdm::ProcessorRow* tR = 0;

    uInt nPRows = processor().nrow();

    if(nPRows > 0){ // need to test because MS processor table is obligatory but may be empty
      for(uInt irow=0; irow<nPRows; irow++){
	// parameters of the new row
	Tag modeId;
	ProcessorTypeMod::ProcessorType processorType;
	ProcessorSubTypeMod::ProcessorSubType processorSubType;
	if(processor().type()(irow) == "CORRELATOR"){
	  processorType = ProcessorTypeMod::CORRELATOR; 
	  if(processor().subType()(irow) == "ALMA_CORRELATOR_MODE"){
	    processorSubType = ProcessorSubTypeMod::ALMA_CORRELATOR_MODE; 
	  }
	  else{
	    os << LogIO::WARN << "Unsupported processor subType for type CORRELATOR " << processor().subType()(irow)
	       << " assuming ALMA_CORRELATOR" << LogIO::POST;
	    processorSubType = ProcessorSubTypeMod::ALMA_CORRELATOR_MODE; 
	  }	    
	}
	else if(processor().type()(irow) == "SPECTROMETER"){
	  processorType = ProcessorTypeMod::SPECTROMETER; 
	  if(processor().subType()(irow) == "HOLOGRAPHY"){
	    processorSubType = ProcessorSubTypeMod::HOLOGRAPHY; 
	  }
	  else{
	    os << LogIO::WARN << "Unsupported processor subType for type SPECTROMETER " << processor().subType()(irow)
	       << " assuming HOLOGRAPHY" << LogIO::POST;
	    processorSubType = ProcessorSubTypeMod::HOLOGRAPHY; 
	  }	    
	}
	else if(processor().type()(irow) == "RADIOMETER"){
	  processorType = ProcessorTypeMod::RADIOMETER; 
	  if(processor().subType()(irow) == "ALMA_RADIOMETER"){
	    processorSubType = ProcessorSubTypeMod::ALMA_RADIOMETER;
	  }
	  else{
	    os << LogIO::WARN << "Unsupported processor type " << processor().subType()(irow)
	       << " assuming ALMA_RADIOMETER" << LogIO::POST;
	    processorSubType = ProcessorSubTypeMod::ALMA_RADIOMETER;
	  }	    
	}
	else{
	  os << LogIO::WARN << "Unsupported processor type " << processor().type()(irow)
	     << " assuming CORRELATOR" << LogIO::POST;
	  processorType = ProcessorTypeMod::CORRELATOR; 
	  processorSubType = ProcessorSubTypeMod::ALMA_CORRELATOR_MODE; 
	}

	// the following three vectors need to be declared outside the switch statement below;
	// otherwise the compiler complains
	vector< asdm::CorrelatorModeRow* > corrModeRows;
	vector< asdm::HolographyRow* > holographyRows;
	vector< asdm::AlmaRadiometerRow* > almaRadiometerRows;
	  
	switch(processorSubType){
	case ProcessorSubTypeMod::ALMA_CORRELATOR_MODE:
	  if(!writeCorrelatorMode()){ // create the optional CorrelatorMode table
	    return false;
	  }
	  corrModeRows = (ASDM_p->getCorrelatorMode()).get();
	  if(corrModeRows.size()==0){
	    os << LogIO::SEVERE << "Internal error: ASDM CorrelatorMode table is empty." << LogIO::POST;
	    return false;
	  }
	  modeId = corrModeRows[0]->getCorrelatorModeId(); // get tag from first row of CorrelatorMode table (there is only one) ??? 
	  break;
	case ProcessorSubTypeMod::HOLOGRAPHY:
	  if(!writeHolography()){ // create the optional Holography table
	    return false;
	  }
	  holographyRows = (ASDM_p->getHolography()).get();
	  if(holographyRows.size()==0){
	    os << LogIO::SEVERE << "Internal error: ASDM Holography table is empty." << LogIO::POST;
	    return false;
	  }
	  modeId = holographyRows[0]->getHolographyId(); // get tag from first row of Holography table (there is only one) ??? 
	  break;
	case ProcessorSubTypeMod::ALMA_RADIOMETER:
	  if(!writeAlmaRadiometer()){ // create the optional AlmaRadiometer table
	    return false;
	  }
	  almaRadiometerRows = (ASDM_p->getAlmaRadiometer()).get();
	  if(almaRadiometerRows.size()==0){
	    os << LogIO::SEVERE << "Internal error: ASDM AlmaRadiometer table is empty." << LogIO::POST;
	    return false;
	  }
	  modeId = almaRadiometerRows[0]->getAlmaRadiometerId(); // get tag from first row of AlmaRadiometer table (there is only one) ??? 
	  break;
	default:
	  os << LogIO::SEVERE << "Internal error: unsupported processor sub type." 
	     << CProcessorSubType::name(processorSubType) << LogIO::POST;
	  return false;
	}
	  
	tR = tT.newRow(modeId, processorType, processorSubType);
	// add the row to the table
	asdm::ProcessorRow* tR2 = 0;
	tR2 = tT.add(tR);

	if(tR2 == tR){ // adding this row caused a new tag to be defined
            // enter tag into the map
            asdmProcessorId_p[irow] = tR->getProcessorId();
	}
	else{
	  os << LogIO::WARN << "Duplicate row in MS Processor table :" << irow << LogIO::POST;
	}
      } // end loop over MS processor table
    }
    else{ // MS processor table is empty
      os << LogIO::WARN << "MS Processor table is empty. Will try to proceed assuming a standard ALMA Correlator." << LogIO::POST;
      ProcessorTypeMod::ProcessorType processorType = ProcessorTypeMod::CORRELATOR;
      ProcessorSubTypeMod::ProcessorSubType processorSubType = ProcessorSubTypeMod::ALMA_CORRELATOR_MODE;
      if(!writeCorrelatorMode()){ // create the optional CorrelatorMode table
	return false;
      }
      vector< asdm::CorrelatorModeRow* > corrModeRows = ASDM_p->getCorrelatorMode().get();
      if(corrModeRows.size()==0){
	os << LogIO::SEVERE << "Internal error: ASDM CorrelatorMode table is empty." << LogIO::POST;
	return false;
      }
      Tag modeId = corrModeRows[0]->getCorrelatorModeId(); // get tag from first row of CorrelatorMode table (there is only one) ??? 
      tR = tT.newRow(modeId, processorType, processorSubType);
      tT.add(tR);
      // enter tag into the map connecting it to "-1"
      asdmProcessorId_p[-1] = tR->getProcessorId();
    } // end if

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled Processor table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }


  Bool MS2ASDM::writeField(){
    LogIO os(LogOrigin("MS2ASDM", "writeField()"));

    Bool rstat = true;
    asdm::FieldTable& tT = ASDM_p->getField();

    asdm::FieldRow* tR = 0;

    for(uInt irow=0; irow<field().nrow(); irow++){

      // parameters of the new row
      string fieldName = field().name()(irow).c_str();
      string code = field().code()(irow).c_str();
      if(code=="" || code==" "){
       code="-";
      }
      int numPoly = field().numPoly()(irow) + 1; // MS give poly order, ASDM needs number of coefficients
      if(numPoly>1){
	os << LogIO::SEVERE << "Internal error: MS Field table with NUM_POLY > 0 not yet supported." << LogIO::POST;
	return false;
      }
      Int numpol = 0;

      String msAngUnit = "rad"; // MS uses radians here
      Matrix< Double > mdir; // aux. matrix


      MDirection::Types phaseDirRef;
      MDirection::getType(phaseDirRef, field().phaseDirMeasCol()(irow)(IPosition(1,0)).getRefString());
      MDirection::Types delayDirRef;
      MDirection::getType(delayDirRef, field().delayDirMeasCol()(irow)(IPosition(1,0)).getRefString());
      MDirection::Types refDirRef;
      MDirection::getType(refDirRef, field().referenceDirMeasCol()(irow)(IPosition(1,0)).getRefString());
      if((phaseDirRef!=delayDirRef) || phaseDirRef!=refDirRef){
	os << LogIO::SEVERE << "Internal error: the reference frames for phase, delay, and reference direction are not identical" 
	   << "in the MS Field table row " << irow << "." << endl
	   << "Not yet supported case." << LogIO::POST;
	return false;
      }
	
      DirectionReferenceCodeMod::DirectionReferenceCode directionCode
	= ASDMDirRefCode(phaseDirRef);

      vector< vector< Angle > > delayDirV;
      mdir.reference(field().delayDir()(irow));
      {
	vector< Angle > dirV;
	Quantity angle0(mdir(0,numpol), msAngUnit);
	dirV.push_back(Angle(angle0.getValue(unitASDMAngle())));
	Quantity angle1(mdir(1,numpol), msAngUnit);
	dirV.push_back(Angle(angle1.getValue(unitASDMAngle())));
	delayDirV.push_back(dirV);
      }

      vector< vector< Angle > > phaseDirV;
      mdir.reference(field().phaseDir()(irow));
      {
	vector< Angle > dirV;
	Quantity angle0(mdir(0,numpol), msAngUnit);
	dirV.push_back(Angle(angle0.getValue(unitASDMAngle())));
	Quantity angle1(mdir(1,numpol), msAngUnit);
	dirV.push_back(Angle(angle1.getValue(unitASDMAngle())));
	phaseDirV.push_back(dirV);
      }

      vector< vector< Angle > > referenceDirV;
      mdir.reference(field().referenceDir()(irow));
      {
	vector< Angle > dirV;
	Quantity angle0(mdir(0,numpol), msAngUnit);
	dirV.push_back(Angle(angle0.getValue(unitASDMAngle())));
	Quantity angle1(mdir(1,numpol), msAngUnit);
	dirV.push_back(Angle(angle1.getValue(unitASDMAngle())));
	referenceDirV.push_back(dirV);
      }

      ////tR = tT.newRow(fieldName, code, numPoly, delayDirV, phaseDirV, referenceDirV);
      tR = tT.newRow(fieldName, numPoly, delayDirV, phaseDirV, referenceDirV);
      
      tR->setCode(code);
      tR->setDirectionCode(directionCode);
      tR->setTime(ASDMArrayTime(field().timeQuant()(irow).getValue("s")));

      Int sId = field().sourceId()(irow);
      if ( asdmSourceId_p.find(sId) != asdmSourceId_p.end( ) ) {
          tR->setSourceId(asdmSourceId_p[sId]);	
      }
      else if(sId!=-1){ // -1 means "no source"
	os << LogIO::WARN << "Undefined source id " << sId << " in MS field table row " << irow << LogIO::POST;
      }

      /*
      if(!field().ephemerisId().isNull()){
	Int eid = field().ephemerisId()(irow);
	if(asdmEphemerisId_p.isDefined(eid)){
	  tR->setEphemerisId(asdmEphemerisId_p(eid));
	}
	else{
	  os << LogIO::WARN << "Undefined ephemeris id " << eid << " in MS field table row " << irow << LogIO::POST;
	}
      }
      */
      // add the row to the table
      asdm::FieldRow* tR2 = 0;
      tR2 = tT.add(tR);
      if(tR2 == tR){ // adding this row caused a new tag to be defined
	// enter tag into the map
          asdmFieldId_p[irow] = tR->getFieldId();
      }
      else{
	if(sId == tR2->getSourceId()){ // if also the Source ID agrees, we really have a duplication
	  os << LogIO::SEVERE << "Duplicate row in MS Field table :" << irow << LogIO::POST;
	  return false;
	}
	fieldName = fieldName+"_B";
	tR->setFieldName(fieldName);
	tR2 = tT.add(tR);
	if(tR2 == tR){ // adding this row caused a new tag to be defined
	  os << LogIO::WARN << "Duplicate row in MS Field table :" << irow << endl
	     << "   appended \"_B\" to field name for second occurrence. New field name: " << fieldName << LogIO::POST;
	  asdmFieldId_p[irow] = tR->getFieldId();
	}
	else{
	  os << LogIO::SEVERE << "Duplicate row in MS Field table :" << irow << LogIO::POST;
	  return false;
	} 
      }
    } // end loop over MS field table

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled Field table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }


  Bool MS2ASDM::writeReceiver(){
    LogIO os(LogOrigin("MS2ASDM", "writeReceiver()"));

    Bool rstat = true;
    asdm::ReceiverTable& tT = ASDM_p->getReceiver();

    asdm::ReceiverRow* tR = 0;

    // create one row for each spectral window Id and time interval (i.e. receiverId is always == 0) 

    // loop over ASDM SPW table
    vector< asdm::SpectralWindowRow* > SPWRows = (ASDM_p->getSpectralWindow()).get();

    Bool informed = false;

    for(uInt irow=0; irow<SPWRows.size(); irow++){
   
      // parameters for the new Recevier table row
      Tag spectralWindowId = SPWRows[irow]->getSpectralWindowId();
      if(!informed){
	if(verbosity_p>0){
	  os << LogIO::NORMAL << "Taking validity time interval for all ASDM Receiver table entries from row 0 of MS Feed table." 
	     << LogIO::POST;
	}
	informed = true;
      }
      asdm::ArrayTimeInterval timeInterval( ASDMTimeInterval(feed().timeQuant()(0), feed().intervalQuant()(0)) ); 
      string name = "unspec. frontend";
      ReceiverBandMod::ReceiverBand frequencyBand;
      ReceiverSidebandMod::ReceiverSideband receiverSideband;
      double dummyF;
      setRecBands(SPWRows[irow]->getRefFreq(), dummyF, frequencyBand, receiverSideband); 
      int numLO = 0; // no information in the MS ???
      vector<Frequency > freqLO;
      //freqLO.push_back(Frequency(1.)); // ???
      vector<NetSidebandMod::NetSideband > sidebandLO;
      //sidebandLO.push_back(SPWRows[irow]->getNetSideband()); // ???

      tR = tT.newRow(spectralWindowId, timeInterval, name, numLO, frequencyBand, freqLO, receiverSideband, sidebandLO);

      // add the row to the table
      tT.add(tR);
    } // end loop over SPW rows

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled Receiver table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }

  Bool MS2ASDM::writeFeed(){
    LogIO os(LogOrigin("MS2ASDM", "writeFeed()"));

    Bool rstat = true;
    asdm::FeedTable& tT = ASDM_p->getFeed();

    asdm::FeedRow* tR = 0;

    Bool warned = false;
    Bool warned2 = false;
    Bool warned3 = false;

    for(uInt irow=0; irow<feed().nrow(); irow++){

      // parameters of the new feed row
      Tag antennaId;
      Int aid = feed().antennaId()(irow);
      if( asdmAntennaId_p.find(aid) != asdmAntennaId_p.end( ) ){
          antennaId = asdmAntennaId_p[aid];
      }
      else{
	os << LogIO::SEVERE << "Undefined antenna id " << aid << " in MS feed table row "<< irow << LogIO::POST;
	return false;
      }
      ArrayTimeInterval timeInterval( ASDMTimeInterval(feed().timeQuant()(irow), feed().intervalQuant()(irow)) );
      
      int numReceptor = feed().numReceptors()(irow);

      vector< vector< double > > beamOffsetV;
      vector< vector< Length > > focusReferenceV;
      vector< PolarizationTypeMod::PolarizationType > polarizationTypesV;
      vector< vector< asdm::Complex > > polResponseV;
      vector< Angle > receptorAngleV;
      vector< int > receiverIdV;

      Matrix< Double > mboffset; // aux. matrix
      mboffset.reference(feed().beamOffset()(irow));

      Vector< String > polT; // aux. vector
      polT.reference(feed().polarizationType()(irow));

      Matrix< Complex > polR;
      polR.reference(feed().polResponse()(irow));

      Vector< Quantity > receptA;
      receptA.reference(feed().receptorAngleQuant()(irow));

      for(uInt rnum=0; rnum<(uInt)numReceptor; rnum++){ // loop over all receptors
	vector< double > abo;
	abo.push_back(mboffset(0,rnum));
	abo.push_back(mboffset(1,rnum));
	beamOffsetV.push_back(abo);

	vector< Length > afr;
	afr.push_back(0); // x
	afr.push_back(0); // y
	if(!feed().focusLength().isNull()){ // the FOCUS_LENGTH column is optional
	  afr.push_back(Length(feed().focusLength()(irow))); // z  ???
	}
	else{
	  afr.push_back(0); // z
	} 
	focusReferenceV.push_back(afr);

	try{
	  polarizationTypesV.push_back(CPolarizationType::literal(polT[rnum].c_str()));
	}
	catch(std::string z){
	  os << LogIO::SEVERE << "Polarization type " << polT[rnum].c_str() << " for receptor " 
	     << rnum << " in MS Feed table row  " << irow << " not defined in ASDM: " 
	     << z << LogIO::POST;      
	  return false;
	}      	
	
	vector< asdm::Complex > apr;
	for(uInt rnum2=0; rnum2<(uInt)numReceptor; rnum2++){
	  apr.push_back( ASDMComplex( polR(rnum,rnum2) ) );
	}
	polResponseV.push_back(apr);

	receptorAngleV.push_back( Angle( receptA[rnum].getValue( unitASDMAngle() ) ) );

	if(telName_p=="ALMA" || telName_p=="ACA" || telName_p == "OSF"){
	  receiverIdV.push_back(0); // always zero for ALMA
	}
	else{
	  receiverIdV.push_back(0);
	  if(!warned){
	    os << LogIO::WARN << "Setting receiver ID to zero (ALMA convention)." << LogIO::POST;
	    warned = true;
	  }
	}
      } // end loop over receptors

      // look at SPW Id parameter last!
      Tag spectralWindowId;
      vector< Tag > spwIdV; // the spw ids fow which to insert rows for this feed
      Int spwid = feed().spectralWindowId()(irow);
      if(spwid == -1){ // this means the MS Feed row is valid for all SPWs => need to insert same row for each SPW!
	// loop over all SPWs
	for(Int ispw=0; ispw<(Int)spectralWindow().nrow(); ispw++){
	  if( asdmSpectralWindowId_p.find(ispw) != asdmSpectralWindowId_p.end( ) ){
	    spectralWindowId = asdmSpectralWindowId_p[ispw];
	    spwIdV.push_back(spectralWindowId); 
	  }
	}  
      }
      else if( asdmSpectralWindowId_p.find(spwid) != asdmSpectralWindowId_p.end( ) ){
          spectralWindowId = asdmSpectralWindowId_p[spwid];
          spwIdV.push_back(spectralWindowId); // just one entry
      }
      else{
	os << LogIO::SEVERE << "Undefined SPW id " << spwid << " in MS feed table row "<< irow << LogIO::POST;
	return false;
      }

      // create the row for the first of the SPW Ids
      tR = tT.newRow(antennaId, spwIdV[0], timeInterval, numReceptor, beamOffsetV, focusReferenceV, 
		     polarizationTypesV, polResponseV, receptorAngleV, receiverIdV);

      if(telName_p=="ALMA" || telName_p=="ACA" || telName_p == "OSF"){
	tR->setFeedNum(1); // always 1 for ALMA
      }
      else{
	tR->setFeedNum(1); 
	if(!warned2){
	  os << LogIO::WARN << "Assuming single-feed receivers. Setting FeedNum to 1 (as for ALMA)." << LogIO::POST;
	  warned2 = true;
	}
      }

      vector< Length > positionV;
      Vector< Quantity > pos;
      pos.reference(feed().positionQuant()(irow));
      for(uInt i=0; i<3; i++){
	positionV.push_back( Length( pos[0].getValue( unitASDMLength() ) ) );
      }
      tR->setPosition(positionV);

      if(feed().beamId()(irow)!=-1 && !warned3){ // there should be a beam table in the MS, but presently it is not implemented!!!
	os << LogIO::WARN << "MS Feed table contains reference to a Beam table row " << feed().beamId()(irow)
	   << " but a Beam table is not implemented in CASA. Ignoring." << LogIO::POST;
      }

      // add the row to the table
      tT.add(tR);	

      int asdmFId = tR->getFeedId(); // the determination of the feed id is done internally by the add() method
      Int fId = feed().feedId()(irow);
      if( asdmFeedId_p.find(fId) != asdmFeedId_p.end( ) ){ // there is already a mapping
	if(asdmFId!=asdmFeedId_p[fId]){ // but it doesn't agree with the newly defined id
	  os << LogIO::WARN << "Internal problem: field id map inconsistent for MS feed table row:" << irow 
	     << ". MS FId " << fId << " is already mapped to ASDM FId" << asdmFeedId_p[fId]
	     << " but should also be mapped to ASDM FId " << asdmFId << LogIO::POST;
	}
      }
      else{
	// enter id into the map
	asdmFeedId_p[fId] = asdmFId;
      }

      // add the same row for the remaining SPW Ids in the vector accumulated above
      for(uint i=1; i<spwIdV.size(); i++){
	tR = tT.newRow(antennaId, spwIdV[i], timeInterval, numReceptor, beamOffsetV, focusReferenceV, 
		     polarizationTypesV, polResponseV, receptorAngleV, receiverIdV);
	tT.add(tR);	
      }	

    } // end loop over MS feed table

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled Feed table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }


  Bool MS2ASDM::writeDataDescription(){
    LogIO os(LogOrigin("MS2ASDM", "writeDataDescription()"));

    Bool rstat = true;
    asdm::DataDescriptionTable& tT = ASDM_p->getDataDescription();

    asdm::DataDescriptionRow* tR = 0;

    // loop over MS data description table
    for(uInt irow=0; irow<dataDescription().nrow(); irow++){
      // parameters for the new row
      Tag polOrHoloId;
      Tag spectralWindowId;
      Int polId = dataDescription().polarizationId()(irow);
      Int spwId = dataDescription().spectralWindowId()(irow);
      if( asdmPolarizationId_p.find(polId) != asdmPolarizationId_p.end( ) ){
	polOrHoloId = asdmPolarizationId_p[polId];
      }
      else{
	os << LogIO::SEVERE << "Inconsistent MS: undefined polarization id " << polId 
	   << " in row " << irow << " of the DataDesc table." << LogIO::POST;
	return false;
      }
      if( asdmSpectralWindowId_p.find(spwId) != asdmSpectralWindowId_p.end( ) ){
	spectralWindowId = asdmSpectralWindowId_p[spwId];
      }
      else{
	os << LogIO::SEVERE << "Inconsistent MS: undefined SPW id " << spwId 
	   << " in row " << irow << " of the DataDesc table." << LogIO::POST;
	return false;
      }

      tR = tT.newRow(polOrHoloId, spectralWindowId);

      asdm::DataDescriptionRow* tR2 = 0;

      tR2 = tT.add(tR);
      if(tR2 == tR){ // adding this row caused a new tag to be defined
	// enter tag into the map
	asdmDataDescriptionId_p[irow] = tR->getDataDescriptionId();
      }
      else{
	os << LogIO::WARN << "Duplicate row in MS DataDesc table :" << irow << LogIO::POST;
      }
    } // end loop over MS DD table

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled DataDescription table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }

  Bool MS2ASDM::writeSwitchCycle(){ 
    LogIO os(LogOrigin("MS2ASDM", "writeSwitchCycle()"));
    
    Bool rstat = true;
    
    asdm::SwitchCycleTable& tT = ASDM_p->getSwitchCycle();
    
    asdm::SwitchCycleRow* tR = 0;
    
    // switch cycle table will only be dummy ? -> Francois
    // dummy if PHASE_ID column doesn't exist in MS main
    // PHASE_ID identifies bin in switch cycle
    //   otherwise, e.g. PHASE_ID = 0 and 1 => numStep == 2

    if(phaseId().isNull()){ // phaseId column doesn't exist

      // parameters of the new row
      int numStep = 1;
      vector< float > weightArray;
      weightArray.push_back(1.);
      vector< vector< Angle > > dirOffsetArray;
      vector< Angle > aV;
      aV.push_back(Angle(0.));
      aV.push_back(Angle(0.));
      dirOffsetArray.push_back(aV);
      vector< Frequency > freqOffsetArray;
      freqOffsetArray.push_back(Frequency(0.));
      vector< Interval > stepDurationArray;
      stepDurationArray.push_back(Interval(0)); // set to zero ???
      
      tR = tT.newRow(numStep, weightArray, dirOffsetArray, freqOffsetArray, stepDurationArray);
      
      tT.add(tR);
      
      EntityId theUid(getCurrentUid());
      Entity ent = tT.getEntity();
      ent.setEntityId(theUid);
      tT.setEntity(ent);
      if(verbosity_p>0){
	os << LogIO::NORMAL << "PHASE_ID column doesn't exist in MS Main table.\n Filled ASDM SwitchCycle table " 
	   << getCurrentUid() << " with one dummy entry." << LogIO::POST;
      }
      incrementUid();
    }
    else{ // phaseId column exists
      os << LogIO::SEVERE 
	 << "PHASE_ID column exists in MS Main table but proper creation of ASDM SwitchCycle table not yet implemented." 
	 << LogIO::POST;
      rstat = false;
    }      

    return rstat;
  }

  Bool MS2ASDM::writeState(){ 
    LogIO os(LogOrigin("MS2ASDM", "writeState()"));

    Bool rstat = true;

    asdm::StateTable& tT = ASDM_p->getState();

    asdm::StateRow* tR = 0;

    if(state().nrow()<1){ // State table not filled

      os << LogIO::WARN << "MS State table is empty. Creating ASDM State table with one on-source entry." 
	 << LogIO::POST;
     
      // parameters of the new row
      bool bSig = true;
      bool bRef = false;
      bool bOnSky = true; 
      CalibrationDeviceMod::CalibrationDevice calDeviceName = CalibrationDeviceMod::NONE;

      tR = tT.newRow(calDeviceName, bSig, bRef, bOnSky);
      
      tR->setWeight(1.); // optional column

      // add the new row to the table
      tT.add(tR);
      // enter tag into the map
      asdmStateId_p[-1] = tR->getStateId();
    }
    else{ // MS State table exists
      for(uInt irow=0; irow<state().nrow(); irow++){
	// parameters of the new row
	bool bSig = state().sig()(irow);
	bool bRef = state().ref()(irow);
	Double loadT = state().load()(irow);
	Double noiseT = state().cal()(irow);
	bool bOnSky = bSig || bRef; 
	CalibrationDeviceMod::CalibrationDevice calDeviceName;
	if(0.<loadT && loadT<270.){
	  calDeviceName = CalibrationDeviceMod::COLD_LOAD;
	}
	else if(270<=loadT && loadT<303.){
	  calDeviceName = CalibrationDeviceMod::AMBIENT_LOAD;
	}
	else if(303.<=loadT){
	  calDeviceName = CalibrationDeviceMod::HOT_LOAD;
	}
	else if(0.<noiseT){
	  calDeviceName = CalibrationDeviceMod::NOISE_TUBE_LOAD;
	}
	else{
	  calDeviceName = CalibrationDeviceMod::NONE;
	  if(!bSig){
	    os << LogIO::WARN << "Trouble determining Cal Device for row " << irow << " in MS State table."
	       << "Assuming NONE." << LogIO::POST;
	  }
	}
	
	tR = tT.newRow(calDeviceName, bSig, bRef, bOnSky);
	
	tR->setWeight(1.); // optional column
	
	// add the new row to the table
	asdm::StateRow* tR2 = 0;
	
	tR2 = tT.add(tR);
	// enter tag into the map
	asdmStateId_p[irow] = tR2->getStateId();
	if(tR2 != tR){ // adding this row did not cause a new tag to be defined
	  os << LogIO::WARN << "Duplicate row in MS State table :" << irow << LogIO::POST;
	}
      } // end loop over MS state table
    } // end else

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled State table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }

  Bool MS2ASDM::writeSysCal(){ 
    LogIO os(LogOrigin("MS2ASDM", "writeSysCal()"));

    Bool rstat = true;

    asdm::SysCalTable& tT = ASDM_p->getSysCal();

    asdm::SysCalRow* tR = 0;

    uInt nSysCalRows = sysCal().nrow();

    if(nSysCalRows<1){ // SysCal table not filled
      os << LogIO::WARN << "MS SysCal table doesn't exist or is empty. Creating ASDM SysCal table with default entries." 
	 << LogIO::POST;
    
      // loop over the main table
      uInt nMainTabRows = ms_p.nrow();
      for(uInt mainTabRow=0; mainTabRow<nMainTabRows; mainTabRow++){

	// get DDId and feed id
	Int f1Id = feed1()(mainTabRow);
	Int f2Id = feed2()(mainTabRow);
	Int DDId = dataDescId()(mainTabRow);	
	// get start time stamp
	Double startTime = timestampStartSecs(mainTabRow);
	// create vectors of info for each antenna
	vector< Int > aIdV;
	vector< Int > SPWIdV;
	vector< Int > feedIdV;
	vector< int > nRecV;
	vector< int > nChanV;
        MapWithDefault<Int, Int> antennaDone(-1);

	uInt irow = mainTabRow;
	// while ddid and feed id remain the same
	while(irow<nMainTabRows &&
	      dataDescId()(irow) == DDId &&
	      feed1()(irow) == f1Id &&
	      feed2()(irow) == f2Id
	      ){
	  Int aId = antenna1()(irow);
	  //   if info for given antenna not yet filled
	  if( antennaDone.find(aId) == antennaDone.end( ) ){
	    //       get info for antenna and fill vectors
	    aIdV.push_back(aId);
	    Int spwId = dataDescription().spectralWindowId()(DDId);
	    SPWIdV.push_back(spwId);
	    feedIdV.push_back(f1Id);
	    nRecV.push_back(feed().numReceptors()(f1Id)); 
	    nChanV.push_back(spectralWindow().numChan()(spwId));
	    antennaDone[aId] = f1Id;
	  }
	  aId = antenna2()(irow);
	  //   if info for given antenna not yet filled
	  if( antennaDone.find(aId) == antennaDone.end( ) ){
	    //       get info for antenna and fill vectors
	    aIdV.push_back(aId);
	    Int spwId = dataDescription().spectralWindowId()(DDId);
	    SPWIdV.push_back(spwId);
	    feedIdV.push_back(f2Id);
	    nRecV.push_back(feed().numReceptors()(f2Id)); 
	    nChanV.push_back(spectralWindow().numChan()(spwId));
	    antennaDone[aId] = f2Id;
	  }
	  irow++;
	} // end while
	// get end timestamp
	Double endTime = timestampEndSecs(irow-1);
	// create ArrayTimeInterval
	asdm::ArrayTimeInterval timeInterval( ASDMArrayTime(startTime),
					      ASDMInterval(endTime-startTime) );
	// create new rows in syscal table based on the vectors
	for(uInt i=0; i<aIdV.size(); i++){
	  // parameters of the new SysCal row
	  Tag antennaId = asdmAntennaId_p[aIdV[i]];
	  Tag spectralWindowId = asdmSpectralWindowId_p[SPWIdV[i]];
	  int feedId = asdmFeedId_p[feedIdV[i]];
	  int numReceptor = nRecV[i];
	  int numChan = nChanV[i];

	  tR = tT.newRow(antennaId, spectralWindowId, timeInterval, feedId, numReceptor, numChan);
      
	  // add the new row to the table
	  tT.add(tR);
	}
	mainTabRow = irow;
      } // end loop over main table
    }
    else{ // MS SysCal table exists
      for(uInt irow=0; irow<nSysCalRows; irow++){
	// parameters of the new row
	Tag antennaId = asdmAntennaId_p[ sysCal().antennaId()(irow) ];
	Int spwId = sysCal().spectralWindowId()(irow);
	Tag spectralWindowId = asdmSpectralWindowId_p[ spwId ];
	int feedId = sysCal().feedId()(irow);
	ArrayTimeInterval timeInterval( ASDMTimeInterval(sysCal().timeQuant()(irow), sysCal().intervalQuant()(irow)) );

	uInt numReceptor = feed().numReceptors()(feedId); 
	uInt nChan = spectralWindow().numChan()(spwId); 

	tR = tT.newRow(antennaId, spectralWindowId, timeInterval, feedId, (int)numReceptor, (int)nChan);


	// now set the optional columns if they exist in the MS
	
	// Tant 
	if(!sysCal().tantFlag().isNull()){
	  tR->setTantFlag(sysCal().tantFlag()(irow));
	}
	if(!sysCal().tantSpectrumQuant().isNull()){
	  Matrix< Quantum< Float > > sM;
	  sM.reference(sysCal().tantSpectrumQuant()(irow));
	  if(sM.shape()(0) != (Int)numReceptor){
	    os << LogIO::SEVERE << "Inconsistent MS: TANT spectrum in syscal table row " << irow
	       << " should have number of receptors as in Feed table: " << numReceptor << LogIO::POST;
	    return false;
	  } 
	  if(sM.shape()(1) != (Int)nChan){
	    os << LogIO::SEVERE << "Inconsistent MS: TANT spectrum in syscal table row " << irow
	       << " should have second dimension as referenced SPW." << LogIO::POST;
	    return false;
	  } 
	  vector< vector< float > > fVV; // presently a float but should be a Temperature ???
	  for(uInt i=0; i<numReceptor; i++){
	    vector< float > fV;
	    for(uInt j=0; j<nChan; j++){
	      fV.push_back( sM(i,j).getValue(unitASDMTemp()) ); 
	    }
	    fVV.push_back(fV);
	  }
	  tR->setTantSpectrum(fVV);
	}
	else if(!sysCal().tantQuant().isNull()){
	  Vector< Quantum< Float > > sV;
	  sV.reference(sysCal().tantQuant()(irow));
	  vector< vector< float > > fVV; // presently a float but should be a Temperature ???
	  if(sV.size() != numReceptor){
	    os << LogIO::SEVERE << "Inconsistent MS: TANT in syscal table row " << irow
	       << " should have number of receptors as in Feed table: " << numReceptor << LogIO::POST;
	    return false;
	  } 
	  for(uInt i=0; i<numReceptor; i++){
	    vector< float > fV;
	    for(uInt j=0; j<nChan; j++){
	      fV.push_back( sV[i].getValue(unitASDMTemp()) );
	    }
	    fVV.push_back(fV);
	  }
	  tR->setTantSpectrum(fVV);
	}

	// Tant/Tsys
	if(!sysCal().tantTsysFlag().isNull()){
	  tR->setTantTsysFlag(sysCal().tantTsysFlag()(irow));
	}
	if(!sysCal().tantTsysSpectrum().isNull()){
	  Matrix< Float > sM;
	  sM.reference(sysCal().tantTsysSpectrum()(irow));
	  if(sM.shape()(0) != (Int)numReceptor){
	    os << LogIO::SEVERE << "Inconsistent MS: TANT_TSYS spectrum in syscal table row " << irow
	       << " should have number of receptors as in Feed table: " << numReceptor << LogIO::POST;
	    return false;
	  } 
	  if(sM.shape()(1) != (Int)nChan){
	    os << LogIO::SEVERE << "Inconsistent MS: TANT_TSYS spectrum in syscal table row " << irow
	       << " should have second dimension as referenced SPW." << LogIO::POST;
	    return false;
	  } 
	  vector< vector< float > > fVV; 
	  for(uInt i=0; i<numReceptor; i++){
	    vector< float > fV;
	    for(uInt j=0; j<nChan; j++){
	      fV.push_back( sM(i,j) ); 
	    }
	    fVV.push_back(fV);
	  }
	  tR->setTantTsysSpectrum(fVV);
	}
	else if(!sysCal().tantTsys().isNull()){
	  Vector< Float > sV;
	  sV.reference(sysCal().tantTsys()(irow));
	  vector< vector< float > > fVV; 
	  if(sV.size() != numReceptor){
	    os << LogIO::SEVERE << "Inconsistent MS: TANT_TSYS in syscal table row " << irow
	       << " should have number of receptors as in Feed table: " << numReceptor << LogIO::POST;
	    return false;
	  } 
	  for(uInt i=0; i<numReceptor; i++){
	    vector< float > fV;
	    for(uInt j=0; j<nChan; j++){
	      fV.push_back( sV[i] );
	    }
	    fVV.push_back(fV);
	  }
	  tR->setTantTsysSpectrum(fVV);
	}

	// Tcal
	if(!sysCal().tcalFlag().isNull()){
	  tR->setTcalFlag(sysCal().tcalFlag()(irow));
	}
	if(!sysCal().tcalSpectrumQuant().isNull()){
	  Matrix< Quantum< Float > > sM;
	  sM.reference(sysCal().tcalSpectrumQuant()(irow));
	  if(sM.shape()(0) != (Int)numReceptor){
	    os << LogIO::SEVERE << "Inconsistent MS: TCAL spectrum in syscal table row " << irow
	       << " should have number of receptors as in Feed table: " << numReceptor << LogIO::POST;
	    return false;
	  } 
	  if(sM.shape()(1) != (Int)nChan){
	    os << LogIO::SEVERE << "Inconsistent MS: TCAL spectrum in syscal table row " << irow
	       << " should have second dimension as referenced SPW." << LogIO::POST;
	    return false;
	  } 
	  vector< vector< Temperature > > fVV; 
	  for(uInt i=0; i<numReceptor; i++){
	    vector< Temperature > fV;
	    for(uInt j=0; j<nChan; j++){
	      fV.push_back( Temperature(sM(i,j).getValue(unitASDMTemp())) ); 
	    }
	    fVV.push_back(fV);
	  }
	  tR->setTcalSpectrum(fVV);
	}
	else if(!sysCal().tcalQuant().isNull()){
	  Vector< Quantum< Float > > sV;
	  sV.reference(sysCal().tcalQuant()(irow));
	  vector< vector< Temperature > > fVV; 
	  if(sV.size() != numReceptor){
	    os << LogIO::SEVERE << "Inconsistent MS: TCAL in syscal table row " << irow
	       << " should have number of receptors as in Feed table: " << numReceptor << LogIO::POST;
	    return false;
	  } 
	  for(uInt i=0; i<numReceptor; i++){
	    vector< Temperature > fV;
	    for(uInt j=0; j<nChan; j++){
	      fV.push_back( Temperature(sV[i].getValue(unitASDMTemp())) );
	    }
	    fVV.push_back(fV);
	  }
	  tR->setTcalSpectrum(fVV);
	}

	// Trx
	if(!sysCal().trxFlag().isNull()){
	  tR->setTrxFlag(sysCal().trxFlag()(irow));
	}
	if(!sysCal().trxSpectrumQuant().isNull()){
	  Matrix< Quantum< Float > > sM;
	  sM.reference(sysCal().trxSpectrumQuant()(irow));
	  if(sM.shape()(0) != (Int)numReceptor){
	    os << LogIO::SEVERE << "Inconsistent MS: TRX spectrum in syscal table row " << irow
	       << " should have number of receptors as in Feed table: " << numReceptor << LogIO::POST;
	    return false;
	  } 
	  if(sM.shape()(1) != (Int)nChan){
	    os << LogIO::SEVERE << "Inconsistent MS: TRX spectrum in syscal table row " << irow
	       << " should have second dimension as referenced SPW." << LogIO::POST;
	    return false;
	  } 
	  vector< vector< Temperature > > fVV; 
	  for(uInt i=0; i<numReceptor; i++){
	    vector< Temperature > fV;
	    for(uInt j=0; j<nChan; j++){
	      fV.push_back( Temperature(sM(i,j).getValue(unitASDMTemp())) ); 
	    }
	    fVV.push_back(fV);
	  }
	  tR->setTrxSpectrum(fVV);
	}
	else if(!sysCal().trxQuant().isNull()){
	  Vector< Quantum< Float > > sV;
	  sV.reference(sysCal().trxQuant()(irow));
	  vector< vector< Temperature > > fVV; 
	  if(sV.size() != numReceptor){
	    os << LogIO::SEVERE << "Inconsistent MS: TRX in syscal table row " << irow
	       << " should have number of receptors as in Feed table: " << numReceptor << LogIO::POST;
	    return false;
	  } 
	  for(uInt i=0; i<numReceptor; i++){
	    vector< Temperature > fV;
	    for(uInt j=0; j<nChan; j++){
	      fV.push_back( Temperature(sV[i].getValue(unitASDMTemp())) );
	    }
	    fVV.push_back(fV);
	  }
	  tR->setTrxSpectrum(fVV);
	}

	// Tsky
	if(!sysCal().tskyFlag().isNull()){
	  tR->setTskyFlag(sysCal().tskyFlag()(irow));
	}
	if(!sysCal().tskySpectrumQuant().isNull()){
	  Matrix< Quantum< Float > > sM;
	  sM.reference(sysCal().tskySpectrumQuant()(irow));
	  if(sM.shape()(0) != (Int)numReceptor){
	    os << LogIO::SEVERE << "Inconsistent MS: TSKY spectrum in syscal table row " << irow
	       << " should have number of receptors as in Feed table: " << numReceptor << LogIO::POST;
	    return false;
	  } 
	  if(sM.shape()(1) != (Int)nChan){
	    os << LogIO::SEVERE << "Inconsistent MS: TSKY spectrum in syscal table row " << irow
	       << " should have second dimension as referenced SPW." << LogIO::POST;
	    return false;
	  } 
	  vector< vector< Temperature > > fVV; 
	  for(uInt i=0; i<numReceptor; i++){
	    vector< Temperature > fV;
	    for(uInt j=0; j<nChan; j++){
	      fV.push_back( Temperature(sM(i,j).getValue(unitASDMTemp())) ); 
	    }
	    fVV.push_back(fV);
	  }
	  tR->setTskySpectrum(fVV);
	}
	else if(!sysCal().tskyQuant().isNull()){
	  Vector< Quantum< Float > > sV;
	  sV.reference(sysCal().tskyQuant()(irow));
	  vector< vector< Temperature > > fVV; 
	  if(sV.size() != numReceptor){
	    os << LogIO::SEVERE << "Inconsistent MS: TSKY in syscal table row " << irow
	       << " should have number of receptors as in Feed table: " << numReceptor << LogIO::POST;
	    return false;
	  } 
	  for(uInt i=0; i<numReceptor; i++){
	    vector< Temperature > fV;
	    for(uInt j=0; j<nChan; j++){
	      fV.push_back( Temperature(sV[i].getValue(unitASDMTemp())) );
	    }
	    fVV.push_back(fV);
	  }
	  tR->setTskySpectrum(fVV);
	}

	// Tsys
	if(!sysCal().tsysFlag().isNull()){
	  tR->setTsysFlag(sysCal().tsysFlag()(irow));
	}
	if(!sysCal().tsysSpectrumQuant().isNull()){
	  Matrix< Quantum< Float > > sM;
	  sM.reference(sysCal().tsysSpectrumQuant()(irow));
	  if(sM.shape()(0) != (Int)numReceptor){
	    os << LogIO::SEVERE << "Inconsistent MS: TSYS spectrum in syscal table row " << irow
	       << " should have number of receptors as in Feed table: " << numReceptor << LogIO::POST;
	    return false;
	  } 
	  if(sM.shape()(1) != (Int)nChan){
	    os << LogIO::SEVERE << "Inconsistent MS: TSYS spectrum in syscal table row " << irow
	       << " should have second dimension as referenced SPW." << LogIO::POST;
	    return false;
	  } 
	  vector< vector< Temperature > > fVV; 
	  for(uInt i=0; i<numReceptor; i++){
	    vector< Temperature > fV;
	    for(uInt j=0; j<nChan; j++){
	      fV.push_back( Temperature(sM(i,j).getValue(unitASDMTemp())) ); 
	    }
	    fVV.push_back(fV);
	  }
	  tR->setTsysSpectrum(fVV);
	}
	else if(!sysCal().tsysQuant().isNull()){
	  Vector< Quantum< Float > > sV;
	  sV.reference(sysCal().tsysQuant()(irow));
	  vector< vector< Temperature > > fVV; 
	  if(sV.size() != numReceptor){
	    os << LogIO::SEVERE << "Inconsistent MS: TSYS in syscal table row " << irow
	       << " should have number of receptors as in Feed table: " << numReceptor << LogIO::POST;
	    return false;
	  } 
	  for(uInt i=0; i<numReceptor; i++){
	    vector< Temperature > fV;
	    for(uInt j=0; j<nChan; j++){
	      fV.push_back( Temperature(sV[i].getValue(unitASDMTemp())) );
	    }
	    fVV.push_back(fV);
	  }
	  tR->setTsysSpectrum(fVV);
	}

	// phase diff
	if(!sysCal().phaseDiffFlag().isNull()){
	  tR->setPhaseDiffFlag(sysCal().phaseDiffFlag()(irow));
	}
	if(!sysCal().phaseDiffQuant().isNull()){
	  float pD = sysCal().phaseDiffQuant()(irow).getValue(unitASDMAngle());
	  vector< vector< float > > fVV;
	  for(uInt i=0; i<numReceptor; i++){
	    vector< float > fV;
	    for(uInt j=0; j<nChan; j++){
	      fV.push_back(pD); 
	    }
	    fVV.push_back(fV);
	  }
	  tR->setPhaseDiffSpectrum(fVV);
	}
	
	// finally add the completed new row to the table
	asdm::SysCalRow* tR2 = 0;
	tR2 = tT.add(tR);
	if(tR2 != tR){ 
	  os << LogIO::WARN << "Duplicate row in MS SysCal table :" << irow << LogIO::POST;
	}	

      } // end loop over MS syscal table
    } // end else

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled SysCal table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }


  Bool MS2ASDM::writeConfigDescription(){

   LogIO os(LogOrigin("MS2ASDM", "writeConfigDesc()"));

    Bool rstat = true;

    asdm::ConfigDescriptionTable& tT = ASDM_p->getConfigDescription();

    asdm::ProcessorTable& procT = ASDM_p->getProcessor();

    asdm::SwitchCycleTable& swcT = ASDM_p->getSwitchCycle();
    vector< asdm::SwitchCycleRow * > swcRV = swcT.get();
    Tag swcTag = swcRV[0]->getSwitchCycleId(); // preliminary implementation: get tag from first (and only) row
    
    uInt nMainTabRows = ms_p.nrow();	
    uInt nProcTabRows =  processor().nrow();
    Int dummyProcId = -1;
    if(nProcTabRows<1){ // processor table not filled, all data should have proc id == -1
      os <<  LogIO::WARN << "MS Processor table is empty. Will assume processor type is CORRELATOR." << LogIO::POST;
      nProcTabRows = 1;
      if(ms_p.nrow()>0 && processorId()(0)!=dummyProcId){
	os <<  LogIO::WARN << "   Still, the MS Main table seems to refer to an existing processor id "
	   << processorId()(0) << ". Will try to proceed ..." << LogIO::POST;
	dummyProcId = processorId()(0); // accept other proc id (e.g. 0)
      }
    }

    // temprorarily needed until all processor types are supported
    vector<Int> goodSpwV;
    vector<Int> badSpwV;

    // loop over MS processor table (typically, this loop will only be executed once)
    for(uInt uprocId=0; uprocId<nProcTabRows; uprocId++){
      
      Int procId = uprocId;
      
      if(processor().nrow()<1){
	procId = dummyProcId;
      }
      
      if(verbosity_p>0){
	os << LogIO::NORMAL << "Processor Id: " << procId << LogIO::POST;
      }
      
      asdm::ConfigDescriptionRow* tR = 0;
      
      Tag procIdTag;
      if(asdmProcessorId_p.find(procId) != asdmProcessorId_p.end()){
	procIdTag = asdmProcessorId_p[procId];
      }
      else{
	if(procId == dummyProcId && asdmProcessorId_p.find(-1) != asdmProcessorId_p.end( )){ // there is no MS Proc table and the main table is
	  procIdTag = asdmProcessorId_p[-1];                          //   using wrong proc ids
	}
	else{
	  os << LogIO::SEVERE << "Internal error: undefined mapping for processor id " << procId << LogIO::POST;
	  return false;
	}
      }
      
      // get processor type from already existing ASDM processor table
      ProcessorTypeMod::ProcessorType processorType = procT.getRowByKey(procIdTag)->getProcessorType();
      
      // loop over data description table
      for(Int iDDId=0; iDDId<(Int)dataDescription().nrow(); iDDId++){

	// find first row in main table with this proc ID and extract spectral type
	SpectralResolutionTypeMod::SpectralResolutionType spectralType = SpectralResolutionTypeMod::FULL_RESOLUTION;
	
	uInt jrow=0;
	while(jrow<nMainTabRows){
	  if(processorId()(jrow)==procId && dataDescId()(jrow)==iDDId){
	    break;
	  }
	  jrow++;
	}
	if(jrow>=nMainTabRows){ // DDId-processor pair not found
	  continue;
	}
	
	// temprorary solution until other processro types are supported
	if(processorType!=ProcessorTypeMod::CORRELATOR){
	  badSpwV.push_back(dataDescription().spectralWindowId()(iDDId));
	}
	else{
	  goodSpwV.push_back(dataDescription().spectralWindowId()(iDDId));
	}	  
        ///////////

	if(asdmDataDescriptionId_p.find(iDDId) == asdmDataDescriptionId_p.end( )){
	  os << LogIO::SEVERE << "Internal error: undefined mapping for data desc. id " << iDDId
	     << " in main table row " << jrow << LogIO::POST;
	  return false;
	}
	
	uInt spwId = dataDescription().spectralWindowId()(iDDId);
	if(spectralWindow().numChan()(spwId)<5){
// 	  spectralType = SpectralResolutionTypeMod::CHANNEL_AVERAGE;
 	  if(verbosity_p>1){
// 	    os << LogIO::NORMAL << "    Less than 5 channels. Assuming data is of spectral resolution type \"CHANNEL_AVERAGE\"." 
// 	       << LogIO::POST;      
	    os << LogIO::WARN << "    SPW " << spwId << ": less than 5 channels. Probably should use spectral resolution type \"CHANNEL_AVERAGE\"." 
	       << endl << "    But this is not yet implemented. Assuming FULL_RESOLUTION." << LogIO::POST;      
	  }
	}
      
	// loop over MS Main table
	Tag previousTag = Tag();
	for(uInt mainTabRow=jrow; mainTabRow<nMainTabRows; mainTabRow++){

	  if(dataDescId()(mainTabRow)!=iDDId || processorId()(mainTabRow)!=procId){
	    continue;
	  }
	  
	  if(verbosity_p>2){
	    cout << "proc id " << procId << " used at main table row " << mainTabRow << endl;
	  } 
	  
	  vector<Int> msAntennaIdV;
	  vector<Int> msDDIdV;
	  msDDIdV.push_back(iDDId); // always just this one entry
	  vector<Int> msFeedIdV;
	  vector<Int> msFeedKeyV;
	  
	  vector<Tag> antennaId;
	  vector<Tag> dataDId;
	  vector<int> feedId; 
	  vector<Tag> switchCycleId;
	  vector<AtmPhaseCorrectionMod::AtmPhaseCorrection> atmPhaseCorrection;
	  int numAntenna = 0;
	  int numDD = 0;
	  int numFeed = 0;
	  CorrelationModeMod::CorrelationMode correlationMode;
	  
	  // loop over MS main table and find for this proc id, DDId, and timestamp
	  //  a) all used antennas
	  //  b) all used feed IDs
	  uInt numAutoCorrs = 0;
	  uInt numBaselines = 0;
	  
	  uInt irow = mainTabRow;
	  Double thisTStamp = time()(irow); 
	  
	  while(irow<nMainTabRows && time()(irow)==thisTStamp){
	    
	    if(dataDescId()(irow)!=iDDId || processorId()(irow)!=procId){
	      irow++;
	      continue;
	    }
	    
	    // for the later determination of the correlation mode
	    if(antenna1()(irow) == antenna2()(irow)){
	      numAutoCorrs++;
	    }
	    else{
	      numBaselines++;
	    }
	    
	    // antenna ids
	    
	    Int aId = antenna1()(irow); 
	    Bool found = false;
	    for(uInt j=0; j<msAntennaIdV.size(); j++){
	      if(aId == msAntennaIdV[j]){
		found = true;
		break;
	      }
	    }
	    if(!found){
	      msAntennaIdV.push_back(aId);
	      if(asdmAntennaId_p.find(aId) == asdmAntennaId_p.end( )){
		os << LogIO::SEVERE << "Internal error: undefined mapping for antenna1 id " << aId 
		   << " in main table row " << irow << LogIO::POST;
		return false;
	      }
	    }
	    aId = antenna2()(irow); 
	    found = false;
	    for(uInt j=0; j<msAntennaIdV.size(); j++){
	      if(aId == msAntennaIdV[j]){
		found = true;
		break;
	      }
	    }
	    if(!found){
	      msAntennaIdV.push_back(aId);
	      if(asdmAntennaId_p.find(aId) == asdmAntennaId_p.end( )){
		os << LogIO::SEVERE << "Internal error: undefined mapping for antenna2 id " << aId 
		   << " in main table row " << irow << LogIO::POST;
		return false;
	      }
	    }
	    
	    
	    // feed ids
	    Int fIdi = feed1()(irow);
	    Int fKeyi = fIdi + 10000*antenna1()(irow);
	    found = false;	      
	    for(uInt j=0;j<msFeedKeyV.size();j++){
	      if(fKeyi == msFeedKeyV[j]){
		found = true;
		break;
	      }
	    }
	    if(!found){
	      msFeedKeyV.push_back(fKeyi);
	      msFeedIdV.push_back(fIdi);
	      if(asdmFeedId_p.find(fIdi) == asdmFeedId_p.end( )){
		os << LogIO::SEVERE << "Internal error: undefined mapping for feed1 id " << fIdi
		   << " in main table row " << irow << LogIO::POST;
		return false;
	      }
	    }
	    fIdi = feed2()(irow);
	    fKeyi = fIdi + 10000*antenna2()(irow);
	    found = false;	      
	    for(uInt j=0;j<msFeedKeyV.size();j++){
	      if(fKeyi == msFeedKeyV[j]){
		found = true;
		break;
	      }
	    }
	    if(!found){
	      msFeedKeyV.push_back(fKeyi);
	      msFeedIdV.push_back(fIdi);
	      if(asdmFeedId_p.find(fIdi) == asdmFeedId_p.end( )){
		os << LogIO::SEVERE << "Internal error: undefined mapping for feed2 id " << fIdi
		   << " in main table row " << irow << LogIO::POST;
		return false;
	      }
	    }
	    
	    irow++;
	  } // end while
	  
	    // sort the  antenna ids before entering them into the ConfigDescription table
	  std::sort(msAntennaIdV.begin(), msAntennaIdV.end());
	  for(uInt i=0; i<msAntennaIdV.size(); i++){
              antennaId.push_back(asdmAntennaId_p[msAntennaIdV[i]]);
	  }
	  numAntenna = antennaId.size();
	  
	  // (there is just one DDId per config description in this scheme)
	  dataDId.push_back(asdmDataDescriptionId_p[msDDIdV[0]]);
	  numDD = 1;
	  
	  // sort the feed ids before entering them into the ConfigDescription table
	  std::sort(msFeedIdV.begin(), msFeedIdV.end());
	  for(uInt i=0; i<msFeedIdV.size(); i++){
	    feedId.push_back(asdmFeedId_p[msFeedIdV[i]]);
	  }
	  numFeed = feedId.size();
	  if(numAntenna>1){
	    numFeed = numFeed/numAntenna;
	  }
	  
	  if(numAutoCorrs==0){
	    correlationMode = CorrelationModeMod::CROSS_ONLY;
	  }
	  else if(numBaselines>0){
	    correlationMode = CorrelationModeMod::CROSS_AND_AUTO;
	  }
	  else{
	    correlationMode = CorrelationModeMod::AUTO_ONLY;
	  }
	  
	  switchCycleId.push_back(swcTag); // switch cycle table will only be dummy ? -> Francois
	  // dummy if PHASE_ID column doesn't exist in MS main
	  // PHASE_ID identifies bin in switch cycle
	  //   otherwise, e.g. PHASE_ID = 0 and 1 => numStep == 2
	  
	  if(dataIsAPCorrected()){
	    atmPhaseCorrection.push_back(AtmPhaseCorrectionMod::AP_CORRECTED); 
	  }
	  else{
	    atmPhaseCorrection.push_back(AtmPhaseCorrectionMod::AP_UNCORRECTED); 
	  }	    
	  
	  // create a new row with its mandatory attributes.
	  tR = tT.newRow (numAntenna,
			  numDD,
			  numFeed,
			  correlationMode, 
			  atmPhaseCorrection.size(),
			  atmPhaseCorrection, 
			  processorType, 
			  spectralType, 
			  antennaId, 
			  feedId, 
			  switchCycleId, 
			  dataDId, 
			  procIdTag);
	  
	  // optional attributes.
	  //vector<Tag> assocConfigDescriptionId(1);
	  //assocConfigDescriptionId[0] = Tag(1, TagType::ConfigDescription);
	  //vector<int> phasedArrayList(2);
	  //phasedArrayList[0] = 0;
	  //phasedArrayList[1] = 1;
	  //vector<bool> flagAnt(2, false);
	  //	  vector<SpectralResolutionTypeMod::SpectralResolutionType> assocNature(1);
	  //assocNature[0] = SpectralResolutionTypeMod::FULL_RESOLUTION;
	  //tR->setAssocConfigDescriptionId(assocConfigDescriptionId);
	  //tR->setPhasedArrayList(phasedArrayList);
	  //tR->setFlagAnt(flagAnt);
	  //tR->setAssocNature(assocNature);	  
	  
	  // add this row to to the config description table.
	  //  note that this will check for uniqueness
	  asdm::ConfigDescriptionRow* tR2 = 0;
	  
	  tR2 = tT.add(tR);
	  Tag newTag = tR2->getConfigDescriptionId();
	  asdmConfigDescriptionId_p[mainTabRow] = newTag;
	  if(verbosity_p>1){
	    cout << "Defined conf desc id for main table row " << mainTabRow << endl;
	  }

	  mainTabRow = irow-1;
	  
	} // end loop over remainder of timestamp in MS main table 

      } // end loop over MS DD table

    } // end loop over MS processor table

    // temporarily needed until all processor types are supported
    if(badSpwV.size() > 0){
      os << LogIO::SEVERE << "Input MS contains data which is not of processor type CORRELATOR.\n" 
	 << "Writing this data to an ASDM is not yet properly supported by exportasdm.\n"
	 << "As a temporary solution please create an input MS containing only the following SPWs" << LogIO::POST;
      for(uInt ii=0; ii<goodSpwV.size(); ii++){
	os <<  LogIO::SEVERE <<  "    " << goodSpwV[ii] << "  " << LogIO::POST;
      }
      os <<  LogIO::SEVERE << "using task \"split\"." << LogIO::POST;
      return false;
    }

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled ConfigDescription table " << getCurrentUid() << " with " << tT.size() << " rows ... " << LogIO::POST;
    }
    incrementUid();

    return rstat;

  }

  Bool MS2ASDM::writeSBSummaryAndExecBlockStubs(){
    LogIO os(LogOrigin("MS2ASDM", "writeSBSummaryAndExecBlockStubs()"));
    
    Bool rstat = true;
    
    asdm::SBSummaryTable& tT = ASDM_p->getSBSummary();
    
    asdm::SBSummaryRow* tR = 0;

    asdm::ExecBlockTable& tET = ASDM_p->getExecBlock();
    
    asdm::ExecBlockRow* tER = 0;

    MapWithDefault <asdm::Tag, Double> execBlockStartTime(-1.); // map from SBSummaryID to current execblock start time
    MapWithDefault <asdm::Tag, Double> execBlockEndTime(-1.); // map from SBSummaryID to current execblock end time
    MapWithDefault <asdm::Tag, asdm::ConfigDescriptionRow*> correspConfigDescRow(0); // map from SBSummaryID to the 
                                                                             // ConfigDescription row of current exec block
    MapWithDefault <asdm::Tag, Int> execBlockNumber(0); // map from SBSummaryID to current execblock number
    MapWithDefault <asdm::Tag, Int> obsIdFromSBSum(-1); // map from SBSummaryID to current obs ID
    MapWithDefault <asdm::Tag, Double> minBaseline(0.); // map from SBSummaryID to minimum baseline of current exec block
    MapWithDefault <asdm::Tag, Double> maxBaseline(0.); // map from SBSummaryID to maximum baseline of current exec block

    MapWithDefault <Int, Int> firstFieldIdFromObsId(-1); // map from obsId to first field id (for the representative direction)

    // unfortunately, we have to loop over the main table to get the information

    // but beforehand we calculate the position of the array center for later reference

    MPosition pos;
    {
      MPosition Xpos;
      String Xobservatory;
      if (observation().nrow() > 0) {
	Xobservatory = observation().telescopeName()(observationId()(0));
      }
      if (Xobservatory.length() == 0 || 
	  !MeasTable::Observatory(Xpos,Xobservatory)) {
	// unknown observatory
	os << LogIO::WARN << "Unknown observatory: \"" << Xobservatory 
	   << "\". Determining observatory position from antenna 0." << LogIO::POST;
	Xpos=MPosition::Convert(antenna().positionMeas()(0), MPosition::WGS84)();
      }
      else{
	os << LogIO::NORMAL << "Using tabulated observatory position for " << Xobservatory << ":"
	   << LogIO::POST;
	Xpos=MPosition::Convert(Xpos, MPosition::WGS84)();
      }
      pos = Xpos;
      ostringstream oss;
      oss <<  "   " << pos << " (WGS84)";
      os << LogIO::NORMAL << oss.str() << LogIO::POST;
    }

    ////MVPosition mObsPos = pos.getValue();
    ////Vector<Double> hlonlat = mObsPos.get(); // get three-vector of height, lon, lat  in m, rad, rad
    ////Length siteAltitude = Length(hlonlat(0));
    ////Angle siteLongitude = Angle(hlonlat(1));
    ////Angle siteLatitude = Angle(hlonlat(2));

    // loop over main table
    Bool warned = false; // aux. var. to avoid warning repetition  
    uInt nMainTabRows = ms_p.nrow();

    Int prevSBKey = -1;
    double prevReprFreq = (163.+211.)/2.*1E9;
    ReceiverBandMod::ReceiverBand prevFrequencyBand = ReceiverBandMod::ALMA_RB_05; 
    ReceiverSidebandMod::ReceiverSideband prevRSB = ReceiverSidebandMod::TSB;
    Int nProcTabRows =  processor().nrow();

    for(uInt mainTabRow=0; mainTabRow<nMainTabRows; mainTabRow++){

      // Step 1: determine SBSummary ID and fill SBSummary table row
      // (duplicate rows will automatically be taken care of by the row adding method)

      Int obsId = observationId()(mainTabRow);

      // parameters of the new SBSummary row
      Int ddId = dataDescId()(mainTabRow);
      Int spwId = dataDescription().spectralWindowId()(ddId);
      Int procId = processorId()(mainTabRow);

      Bool isWVR = false;
      if(procId>=0 && nProcTabRows>0 && procId < nProcTabRows){
	if(processor().type()(procId) == "RADIOMETER"){
	  //cout << "Found WVR data" << endl;
	  isWVR = true;
	}
      }

      double frequency = (spectralWindow().refFrequencyQuant()(spwId)).getValue(unitASDMFreq()); 
      //cout << "Freq " << frequency << endl;

      ReceiverBandMod::ReceiverBand frequencyBand; // get from frequency
      ReceiverSidebandMod::ReceiverSideband rSB;
      double reprFreq = 0.;
      Int bandNum = setRecBands(Frequency(frequency), reprFreq, frequencyBand, rSB); 
      //cout << "Band " << bandNum << endl;

      Int sbKey = obsId;
      
      if(bandNum >= 0){
	if(isWVR){// special case: WVR data is observed in a (potentially) different band but no separate SB is created for it
	  if(prevSBKey>=0){ // other data was encountered beforehand, there is already a proper SBKey from it
	    sbKey = prevSBKey;
	    reprFreq = prevReprFreq;
	    frequencyBand = prevFrequencyBand;
	    rSB = prevRSB;
	  }
	  else{ // we need to peek forward until non-WVR data is found
	    Bool foundNonWVR = false;
	    uInt mainTabRowB = 0;
	    for(mainTabRowB=mainTabRow+1; mainTabRowB<nMainTabRows; mainTabRowB++){
	      Int procIdB = processorId()(mainTabRowB);
	      if(procIdB>=0 && nProcTabRows>0 && procIdB < nProcTabRows){
		if(processor().type()(procIdB) == "RADIOMETER"){
		  //cout << "Found WVR data again" << endl;
		  continue;
		}
		foundNonWVR=true;
		break;
		
	      }
	      foundNonWVR=true;
	      break;
	    }// end for
	    if(foundNonWVR){
	      obsId = observationId()(mainTabRowB);
	      ddId = dataDescId()(mainTabRowB);
	      spwId = dataDescription().spectralWindowId()(ddId);
	      frequency = (spectralWindow().refFrequencyQuant()(spwId)).getValue(unitASDMFreq());
	      bandNum = setRecBands(Frequency(frequency), reprFreq, frequencyBand, rSB);
	      sbKey = obsId+10000*bandNum;
	    }
	    else{ // there is only WVR data
	      sbKey = obsId+10000*bandNum;
	    }
	  }
	}
	else{ // this is normal non-WVR data
	  sbKey = obsId+10000*bandNum; // an SB can only observe one band
	}
      }
      else{
	os << LogIO::WARN << "Could not determine ALMA frequency band for frequency " 
	   << frequency << " Hz in MS Spectral Window " << spwId << ". Will try to continue." << LogIO::POST;
	  sbKey = obsId+10000*bandNum; // an SB can only observe one band
      }
      // memorize freq band info
      prevSBKey = sbKey;
      prevReprFreq = reprFreq;
      prevFrequencyBand = frequencyBand;
      prevRSB = rSB;

      //cout << "   SBKey " << sbKey << endl;
      //cout << "   reprFreq " << reprFreq << endl;

      String sbsUid("uid://SAFFEC0C0/X1/X1");
      ostringstream oss;
      oss << sbKey;
      sbsUid = sbsUid + String(oss);
      EntityRef sbSummaryUID(sbsUid.c_str(), "", "ASDM", asdmVersion_p); // will be reset later when linking the ASDM to an APDM 
      EntityRef projectUID("uid://SAFFEC0C0/X1/X2", "", "ASDM", asdmVersion_p); // dto.
      EntityRef obsUnitSetId("uid://SAFFEC0C0/X1/X3", "", "ASDM", asdmVersion_p); // dto. 

      SBTypeMod::SBType sbType = SBTypeMod::OBSERVATORY; //???
      Vector< Quantum< Double > > tRange;
      tRange.reference(observation().timeRangeQuant()(obsId)); 
      Double durationSecs = tRange[1].getValue("s") - tRange[0].getValue("s"); 
      if(durationSecs == 0){ // try to derive the sched block duration in a different way
	if(!warned){
	  os << LogIO::WARN << "Observation time range is zero length for obs ID "
	     << obsId << " in MS Observation table.\n Will try to proceed ..."
	     <<LogIO::POST;
	  warned = true;
	}
	durationSecs = timestampEndSecs(nMainTabRows-1) - timestampStartSecs(0);
      } 
      Interval sbDuration = ASDMInterval(durationSecs);
      int numberRepeats = 1;
      // limit the scheduling block duration (not the same as the observation duration)
      if(durationSecs > schedBlockDuration_p){
	sbDuration = ASDMInterval(schedBlockDuration_p);
	numberRepeats = (int) ceil(durationSecs/schedBlockDuration_p);
	durationSecs = schedBlockDuration_p;
      }
      vector< Angle > centerDirection;
      Int fId = fieldId()(mainTabRow);
      // an observation (and an SB) can have many fields. use the first one as representative direction
      if(firstFieldIdFromObsId.find(obsId) != firstFieldIdFromObsId.end( )){
	fId = firstFieldIdFromObsId[obsId];
      }
      else{
	firstFieldIdFromObsId[obsId] = fId;
      } 
      ////MDirection theFieldDir = field().phaseDirMeas(fId,0);
      ////centerDirection.push_back( theFieldDir.getAngle( unitASDMAngle() ).getValue()(0) ); // RA
      ////centerDirection.push_back( theFieldDir.getAngle( unitASDMAngle() ).getValue()(1) ); // DEC
      
      int numObservingMode = 1;
      vector< string > observingMode;
      observingMode.push_back("observing mode t.b.d.");
      int numScienceGoal = 1;
      vector< string > scienceGoal;
      scienceGoal.push_back("science goal t.b.d.");
      int numWeatherConstraint = 1;
      vector< string > weatherConstraint;
      weatherConstraint.push_back("weather constraint t.b.d.");
      
      tR = tT.newRow(sbSummaryUID, projectUID, obsUnitSetId, reprFreq, frequencyBand, sbType, sbDuration, 
		     ////centerDirection, 
		     numObservingMode, observingMode, numberRepeats, numScienceGoal, 
		     scienceGoal, numWeatherConstraint, weatherConstraint);
      
      asdm::SBSummaryRow* tR2 = 0;
      tR2 = tT.add(tR);
      Tag sBSummaryTag = tR2->getSBSummaryId();
      if(tR2 == tR){ // adding the row led to the creation of a new tag
	if(verbosity_p>2){
	  cout << "New SBSummary tag created: " << tR2 << endl;
	}
	if( asdmSBSummaryId_p.find(sbKey) != asdmSBSummaryId_p.end( ) ){
	  os << LogIO::WARN << "There is more than one scheduling block necessary for the obsid - freqBand pair (" 
	     << obsId << ", " << bandNum << ").\n This can presently not yet be handled properly.\n" 
	     << "(MS Main table row " << mainTabRow << ")" << LogIO::POST;
	}
	else{
        asdmSBSummaryId_p[sbKey] = sBSummaryTag;
	}
      }

      // now have a valid SBSummaryID for the execblock

      // Step 2: write exec block table

      // has the exec block been started already?
      if(execBlockStartTime.find(sBSummaryTag) != execBlockStartTime.end( )){ // yes

	// continue accumulation of min and max baseline
	Double baseLine = MVBaseline( (antenna().positionMeas()(antenna1()(mainTabRow))).getValue(),
				      (antenna().positionMeas()(antenna2()(mainTabRow))).getValue()
				      ).getLength().getValue(unitASDMLength());
	if(baseLine>maxBaseline[sBSummaryTag]){
        maxBaseline[sBSummaryTag] = baseLine;
	}
	else if(baseLine<minBaseline[sBSummaryTag]){
        minBaseline[sBSummaryTag] = baseLine;
	}

	// is the exec block complete?
	Double endT = timestampEndSecs(mainTabRow);
	if(endT > execBlockEndTime[sBSummaryTag]){ // integration intervals may be different for different DD Ids, take max endT
        execBlockEndTime[sBSummaryTag] = endT;
	}
	if(verbosity_p>2){
	  cout << "interval = " << endT - execBlockStartTime[sBSummaryTag] << ", duration == " <<  durationSecs << endl;
	}

	if(endT - execBlockStartTime[sBSummaryTag] >= durationSecs){ // yes, it is complete
	  // parameters for a new row
  
	  ArrayTime startTime = ASDMArrayTime(execBlockStartTime[sBSummaryTag]);
	  ArrayTime endTime = ASDMArrayTime(endT);
	  int execBlockNum = execBlockNumber[sBSummaryTag];
	  EntityRef execBlockUID; // to be filled with the EntityRef of the containing ASDM 
	  try{
	    execBlockUID = EntityRef(asdmUID_p, "", "ASDM", asdmVersion_p);
	  }
	  catch(asdm::InvalidArgumentException x){
	    os << LogIO::SEVERE << "Error creating ASDM:  UID \"" << getCurrentUid() 
	       << "\" (intended for the ASDM) is not a valid Entity reference: " <<  x.getMessage()
	       << LogIO::POST;      
	    return false;
	  }
	  incrementUid();
	  EntityRef projectId = projectUID;
	  string configName = "configName t.b.d."; // ???
	  string telescopeName = telName_p;
	  string observerName = observation().observer()(obsId).c_str();
	  if(observerName==""){
	    observerName = "unknown";
	  }
	  ////string observingLog = "log not filled";
	  vector<string > observingLog(1);
	  int numObservingLog = 1;
	  observingLog[0] = "log not filled"; 
	  Vector< String > sV;
	  if(observation().log().isDefined(obsId)){// log string array not empty
	    sV.reference(observation().log()(obsId)); // the observation log is an array of strings
	    observingLog.resize(sV.size());
	    numObservingLog = observingLog.size();
	    for(uInt i=0; i<sV.size(); i++){
	      observingLog[i] = string(sV[i].c_str());
	    }
	  }
	  ////string sessionReference = "sessionReference t.b.d."; // ???
	  ////EntityRef sbSummary = sbSummaryUID;
	  EntityRef sessionReference = sbSummaryUID;
	  ////string schedulerMode = "CASA exportasdm"; //???
	  Length baseRangeMin = Length( minBaseline[sBSummaryTag] );
	  Length baseRangeMax = Length( maxBaseline[sBSummaryTag] );
	  Length baseRmsMinor = Length(0); // ???
	  Length baseRmsMajor = Length(0); // ???
	  Angle basePa = Angle(0); // ???
	  bool aborted = false;
	  asdm::ConfigDescriptionRow* cDR = correspConfigDescRow[sBSummaryTag];
	  int numAntenna = cDR->getNumAntenna();
	  vector< Tag > antennaId = cDR->getAntennaId();

	  tER = tET.newRow(startTime, endTime, execBlockNum, execBlockUID, projectId, configName, telescopeName, observerName, 
			   numObservingLog, observingLog, //// now vector< string>
			   sessionReference, //// now of type EntityRef
			   ////sbSummary, schedulerMode, 
			   baseRangeMin, baseRangeMax, baseRmsMinor, baseRmsMajor, basePa, 
			   ////siteAltitude, siteLongitude, siteLatitude, 
			   aborted, numAntenna, antennaId, sBSummaryTag);
	  
	  asdm::ExecBlockRow* tER2;

	  tER2 = tET.add(tER);
	  if(tER2 != tER){
	    os << LogIO::SEVERE << "Internal error: attempt to store duplicate exec block row." << LogIO::POST;
	    return false;
	  }
	  asdmExecBlockId_p[execBlockStartTime[sBSummaryTag]] = tER->getExecBlockId();

	  if(verbosity_p>2){
	    std::cout << "eblock id defined in loop 1 for start time " << std::setprecision(13) << execBlockStartTime[sBSummaryTag] << endl;
	    std::cout << "                                  end time " << std::setprecision(13) << execBlockEndTime[sBSummaryTag] << endl;
	  }

	  // undefine the mapping for this Tag since the ExecBlock was completed
      auto startptr = execBlockStartTime.find(sBSummaryTag);
	  if ( startptr != execBlockStartTime.end( ) ) execBlockStartTime.erase(startptr);
      auto endptr = execBlockEndTime.find(sBSummaryTag);
	  if ( endptr != execBlockEndTime.end( ) ) execBlockEndTime.erase(endptr);
      auto corptr = correspConfigDescRow.find(sBSummaryTag);
	  if ( corptr != correspConfigDescRow.end( ) ) correspConfigDescRow.erase(corptr);
	  auto sumptr = obsIdFromSBSum.find(sBSummaryTag);
	  if ( sumptr != obsIdFromSBSum.end( ) ) obsIdFromSBSum.erase(sumptr);
	  auto minptr = minBaseline.find(sBSummaryTag);
	  if ( minptr != minBaseline.end( ) ) minBaseline.erase(minptr);
	  auto maxptr = maxBaseline.find(sBSummaryTag);
	  if ( maxptr != maxBaseline.end( ) ) maxBaseline.erase(maxptr);
	  
	}
// 	else{ // no, it is not complete	 
// 	}
      } 
      else{// no, it has not been started, yet

	// check if there is another exec block which started at the same time
          for ( auto iter = execBlockStartTime.begin( ); iter != execBlockStartTime.end( ); ++iter ) {
              if ( iter->second == timestampStartSecs(mainTabRow) ){
                  os << LogIO::SEVERE << "Observation of different frequency bands at the same time and under the same observation ID is not supported by the ASDM."
                     << "\n  Please split out the different spectral bands into individual MSs and process separately." << LogIO::POST;
                  return false;
              }
          }

          execBlockStartTime[sBSummaryTag] = timestampStartSecs(mainTabRow);
          execBlockEndTime[sBSummaryTag] = timestampEndSecs(mainTabRow); // will be updated

	Int oldNum = 0;
    auto numptr = execBlockNumber.find(sBSummaryTag);
	if( numptr != execBlockNumber.end( ) ){ 
	  // increment exec block number
        oldNum = numptr->second;
        execBlockNumber.erase(numptr);
	}
	execBlockNumber[sBSummaryTag] = oldNum + 1; // sequential numbering starting at 1

	if(verbosity_p>2){
	  std::cout << "eblock number " << oldNum + 1 << " defined for start time " << std::setprecision (9) << timestampStartSecs(mainTabRow) << endl;
	}

	obsIdFromSBSum[sBSummaryTag] = obsId; // remember the obsId for this exec block
	
	if( asdmConfigDescriptionId_p.find(mainTabRow) == asdmConfigDescriptionId_p.end( ) ){
	  os << LogIO::SEVERE << "Internal error: undefined config description id for MS main table row "
	     << mainTabRow << LogIO::POST;
	  return false;
	}  
	asdm::ConfigDescriptionRow* cDR = (ASDM_p->getConfigDescription()).getRowByKey(asdmConfigDescriptionId_p[mainTabRow]);
	if(cDR ==0){
	  os << LogIO::SEVERE << "Internal error: no row in ASDM ConfigDesc Table for ConfigDescriptionId stored for main table row "
	     << mainTabRow << LogIO::POST;
	  return false;
	}
	correspConfigDescRow[sBSummaryTag] = cDR; // remember the config description row for this exec block

	// start accumulation of min and max baseline
	Double bLine = MVBaseline( (antenna().positionMeas()(antenna1()(mainTabRow))).getValue(),
				   (antenna().positionMeas()(antenna2()(mainTabRow))).getValue()
				   ).getLength().getValue(unitASDMLength());
	minBaseline[sBSummaryTag] = bLine;
	maxBaseline[sBSummaryTag] = bLine;
      }
      // skip rest of this timestamp
      Double tStamp = time()(mainTabRow);
      while(mainTabRow<nMainTabRows 
	    && time()(mainTabRow)==tStamp
	    && dataDescId()(mainTabRow)==ddId){
	mainTabRow++;
      }
      mainTabRow--;// we are inside a for loop which will perform the last mainTabRow++ 
    } // end loop over main table

    // are there pending exec blocks?
    while(execBlockStartTime.size()>0){ // yes
      Tag sBSummaryTag = execBlockStartTime.begin( )->first;
      tR = tT.getRowByKey(sBSummaryTag);
      Int obsId = obsIdFromSBSum[sBSummaryTag];
      // parameters for a new row      
      ArrayTime startTime = ASDMArrayTime(execBlockStartTime[sBSummaryTag]);
      ArrayTime endTime = ASDMArrayTime(execBlockEndTime[sBSummaryTag]);
      int execBlockNum = execBlockNumber[sBSummaryTag];
      EntityRef execBlockUID; // to be filled with the EntityRef of the containing ASDM 
      try{
	execBlockUID = EntityRef(asdmUID_p, "", "ASDM", asdmVersion_p);
      }
      catch(asdm::InvalidArgumentException x){
	os << LogIO::SEVERE << "Error creating ASDM:  UID \"" << getCurrentUid() 
	   << "\" (intended for an exec block) not a valid Entity reference: " <<  x.getMessage()
	   << LogIO::POST;      
	return false;
      }
      incrementUid();
      EntityRef projectId = tR->getProjectUID();
      string configName = "configName t.b.d."; // ???
      string telescopeName = telName_p;
      string observerName = observation().observer()(obsId).c_str();
      if(observerName==""){
	observerName = "unknown";
      }

      ////string observingLog = "log not filled";
      vector<string > observingLog(1);
      int numObservingLog = 1;
      observingLog[0] = "log not filled"; 
      Vector< String > sV;
      if(observation().log().isDefined(obsId)){// log string array not empty
	sV.reference(observation().log()(obsId)); // the observation log is an array of strings
	observingLog.resize(sV.size());
	numObservingLog = observingLog.size();
	for(uInt i=0; i<sV.size(); i++){
	  observingLog[i] = string(sV[i].c_str());
	}
      }
    
      //// string sessionReference = "sessionReference t.b.d."; // ???
      ////EntityRef sbSummary = tR->getSbSummaryUID();
      EntityRef sessionReference = tR->getSbSummaryUID();
      ////string schedulerMode = "CASA exportasdm"; //???
      Length baseRangeMin = Length( minBaseline[sBSummaryTag] );
      Length baseRangeMax = Length( maxBaseline[sBSummaryTag] );
      Length baseRmsMinor = Length(0); // ???
      Length baseRmsMajor = Length(0); // ???
      Angle basePa = Angle(0); // ???
      bool aborted = false;
      asdm::ConfigDescriptionRow* cDR = correspConfigDescRow[sBSummaryTag];
      int numAntenna = cDR->getNumAntenna();
      vector< Tag > antennaId = cDR->getAntennaId();
      
      tER = tET.newRow(startTime, endTime, execBlockNum, execBlockUID, projectId, configName, telescopeName, observerName, 
		       numObservingLog, observingLog, 
		       sessionReference, 
		       ////sbSummary, schedulerMode, 
		       baseRangeMin, baseRangeMax, baseRmsMinor, baseRmsMajor, basePa, 
		       ////siteAltitude, siteLongitude, siteLatitude, 
		       aborted, numAntenna, antennaId, sBSummaryTag);
      
      asdm::ExecBlockRow* tER2;
      
      tER2 = tET.add(tER);
      if(tER2 != tER){
	os << LogIO::SEVERE << "Internal error: attempt to store duplicate exec block row." << LogIO::POST;
	return false;
      }
      asdmExecBlockId_p[execBlockStartTime[sBSummaryTag]] = tER->getExecBlockId();

      if(verbosity_p>2){
	std::cout << "eblock id defined in loop 2 for start time " << std::setprecision(13) << execBlockStartTime[sBSummaryTag] << endl;
	std::cout << "                                  end time " << std::setprecision(13) << execBlockEndTime[sBSummaryTag] << endl;
      }

      // undefine the mapping for this Tag since the ExecBlock was completed
      auto startptr = execBlockStartTime.find(sBSummaryTag); // need only remove from the map what is tested
      if ( startptr != execBlockStartTime.end( ) ) execBlockStartTime.erase(startptr);
      auto endptr = execBlockEndTime.find(sBSummaryTag);
      if ( endptr != execBlockEndTime.end( ) ) execBlockEndTime.erase(endptr);

    }

    // finish the SBSummary table
    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled SBSummary table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    // finish the ExecBlock table
    theUid = getCurrentUid();
    ent = tET.getEntity();
    ent.setEntityId(theUid);
    tET.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled ExecBlock table " << getCurrentUid() << " with " << tET.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();
    
    return rstat;
    
  }

  Bool MS2ASDM::writeMainAndScanAndSubScan(const String& datacolumn){
    LogIO os(LogOrigin("MS2ASDM", "writeMainAndScanAndSubScan()"));
    
    Bool rstat = true;
    
    // check if datacolumn exists
    
    String dataColumn(datacolumn);
    dataColumn.upcase();

    if( (dataColumn == "CORRECTED" && !ms_p.tableDesc().isColumn("CORRECTED_DATA"))
	|| (dataColumn == "MODEL" && !ms_p.tableDesc().isColumn("MODEL_DATA"))
	|| (dataColumn == "DATA" && !ms_p.tableDesc().isColumn("DATA"))
	){
      os << LogIO::SEVERE << "Error: column " << dataColumn << " does not exist in "
	 << ms_p.tableName() << LogIO::POST;      
      return false;
    }
    else{
      if(verbosity_p>0){
	os << LogIO::NORMAL << "Using column " << dataColumn << "." << LogIO::POST;      
      }
    }      
    
    asdm::MainTable& tT = ASDM_p->getMain();
    asdm::MainRow* tR = 0;
    
    asdm::ScanTable& tST = ASDM_p->getScan();
    asdm::ScanRow* tSR = 0;
    
    asdm::SubscanTable& tSST = ASDM_p->getSubscan();
    asdm::SubscanRow* tSSR = 0;
    
    
    // Scheme
    // loop over main table
    //   asdmExecBlockId_p(time()(mainTabRow) defined?
    //   if so, a new exec block has started
    //      is there a previous exec block?
    //        if so, finish it
    //      set up new exec block
    //      set scanNumber to 1
    //      set subscanNumber to 1
    //   end if
    //   while(scan not finished)
    //      find all DDIds in the time between now and now+subscanduration or until Scan ends
    //        and memorize their start rows
    //      for each DDId found
    //        find all FieldIds in the time between now and now+subscanduration or until Scan ends
    //        for each FieldId
    //           Construct subscan == SDMDataObject
    //              using the ConfigDescription table row asdmConfigDescriptionId_p(startRow)
    //           and write it
    //           write corresponding Main table row and subscan table row
    //           subscanNumber++
    //        end for
    //      end for
    //      next mainTabRow
    //      error if asdmExecBlockId_p(time()(mainTabRow) defined: 
    //   end while
    //   write scan table row
    //   scanNumber++
    // end loop (i.e. next main table row)  
    
    
    ////////////////////////////////////////////////
    // Prepare loop over main table
    Double scanStart;
    
    Tag execBlockId = Tag();
    int subscanNumber = 0;
    // parameters for the new Scan table row
    int scanNumber = 0;
    ArrayTime scanStartTime;
    ArrayTime scanEndTime;
    int scanNumIntent = 0;
    int numSubScan = 0;
    vector< ScanIntentMod::ScanIntent > scanIntent;
    vector< CalDataOriginMod::CalDataOrigin > scanCalDataType;
    vector< bool > scanCalibrationOnLine;
    ////bool scanFlagRow = false; // always false ???
    
    uInt nMainTabRows = ms_p.nrow();
    for(uInt mainTabRow=0; mainTabRow<nMainTabRows; mainTabRow++){
      
      Double rowTime = timestampStartSecs(mainTabRow);
      
      //   asdmExecBlockId_p defined for this timestamp?
      if(asdmExecBlockId_p.find(rowTime) != asdmExecBlockId_p.end( )){ // a new exec block has started
	// is there a previous exec block?
	if(execBlockId != Tag()){
	  //  finish the old exec block
	}
	// set up new exec block
	// parameters for the first scan
	execBlockId = asdmExecBlockId_p[rowTime];
	asdm::ExecBlockRow* EBR = (ASDM_p->getExecBlock()).getRowByKey(execBlockId);
	scanNumber = 1; // ASDM scan numbering starts at 1
        subscanNumber = 1; // dito for subscans
	scanStart = rowTime;
	scanStartTime = ASDMArrayTime( scanStart );
	scanEndTime = EBR->getEndTime(); // preset to the end of the execblock
	scanNumIntent = 0;
	numSubScan = 0;
	scanIntent.resize(0);
	scanCalDataType.resize(0);
	scanCalibrationOnLine.resize(0);
	////scanFlagRow = false;
      } // end if a new exec block has started
      else if(execBlockId == Tag()){
	os << LogIO::WARN << "Encountered main tab row " << mainTabRow << " which is not part of an execblock." << LogIO::POST;
	continue;
      }
      else if(MSTimeSecs(scanEndTime) - timestampEndSecs(mainTabRow) <= 0.9){
	os << LogIO::NORMAL << "Potential problem at main tab row " << mainTabRow << ": misaligned scan and execblock end." 
	   << endl << "Will try to continue ..." << LogIO::POST;
	// search back to see if the execblock start can be found

	Double searchIntervalSecs = 60.;

	uInt mainTabRowB = mainTabRow;
	Bool foundEBStart = false;
	Double rowTimeB = rowTime;
	while(rowTime - rowTimeB < searchIntervalSecs && mainTabRowB>0){
	  rowTimeB = timestampStartSecs(--mainTabRowB);
	  if(asdmExecBlockId_p.find(rowTimeB) != asdmExecBlockId_p.end( )){
	    foundEBStart = true;
	    execBlockId = asdmExecBlockId_p[rowTimeB];
	    asdm::ExecBlockRow* EBR = (ASDM_p->getExecBlock()).getRowByKey(execBlockId);
	    scanNumber = 1; // ASDM scan numbering starts at 1
	    subscanNumber = 1; // dito for subscans
	    scanStart = rowTimeB;
	    scanStartTime = ASDMArrayTime( scanStart );
	    scanEndTime = EBR->getEndTime(); // preset to the end of the execblock
	    scanNumIntent = 0;
	    numSubScan = 0;
	    scanIntent.resize(0);
	    scanCalDataType.resize(0);
	    scanCalibrationOnLine.resize(0);
	    ////scanFlagRow = false;
	    break;
	  }
	}
	if(foundEBStart){
	  os << LogIO::NORMAL << "Problem resolved. Found execblock start " << rowTime - rowTimeB << " s earlier." << LogIO::POST;
	}
	else{
	  os << LogIO::SEVERE << "Searched back for " << searchIntervalSecs 
	     << " s. Could not resolve misalignment." << LogIO::POST;
	  return false;
	}
      }
      
      // while(scan not finished)
      while( mainTabRow<nMainTabRows && 
	     MSTimeSecs(scanEndTime) - (rowTime = timestampStartSecs(mainTabRow)) > 1E-3 ){ // presently one scan per exec block ???

	// parameters for the new SubScan table row
	Double subScanEnd = rowTime + subscanDuration_p; 
	if(subScanEnd > MSTimeSecs(scanEndTime)){
	  subScanEnd = MSTimeSecs(scanEndTime);
	}
	
	// find all DDIds in the time between now and end of subscan
	uInt irow = mainTabRow;
	std::map< Int, uInt > subScanDDIdStartRows;
	while(irow<nMainTabRows &&
	      timestampStartSecs(irow) < subScanEnd){
	  Int ddId = dataDescId()(irow);
	  if(subScanDDIdStartRows.find(ddId) == subScanDDIdStartRows.end( )){
          subScanDDIdStartRows[ddId] = irow;    // memorize their start rows
	  }
	  irow++;
	}
	
	// for each DDId found
	for( auto iter = subScanDDIdStartRows.begin( ); iter != subScanDDIdStartRows.end( ); ++iter ){
	  Int theDDId = iter->first;

	  // find all FieldIds in the time between now and now+subscanduration or until Scan ends	  
	  uInt irow2 = mainTabRow;
	  std::map< Int, uInt > subScanStartRows;
	  std::map< Int, uInt > subScanEndRows;
	  while(irow2<nMainTabRows &&
		timestampStartSecs(irow2) < subScanEnd){
	    Int ddId = dataDescId()(irow2);
	    Int fId = fieldId()(irow2);
	    if(ddId == theDDId){
            if( subScanEndRows.find(fId) != subScanEndRows.end( ) ){
                subScanEndRows[fId] = irow2;    // update end row
            }
            if( subScanStartRows.find(fId) == subScanStartRows.end( ) ){
                subScanStartRows[fId] = irow2;    // memorize their start rows
                subScanEndRows[fId] = irow2;    // and end rows
            }
	    }
	    irow2++;
	  }
	  // for each FieldId
	  for( auto iter = subScanStartRows.begin( ); iter != subScanStartRows.end( ); ++iter ) {
	    Int theFId = iter->first;
	    uInt startRow = subScanStartRows[theFId];
	    uInt endRow = subScanEndRows[theFId];
	    // write subscan
	    // parameters for the new SubScan table row
	    ArrayTime subScanStartArrayTime = ASDMArrayTime(timestampStartSecs(startRow)); 
	    ArrayTime subScanEndArrayTime = ASDMArrayTime(timestampEndSecs(endRow)); 
	    string fieldName = field().name()(fieldId()(startRow)).c_str(); 
	    SubscanIntentMod::SubscanIntent subscanIntent = SubscanIntentMod::ON_SOURCE;
	    vector< int > numberSubintegration;
	    ////bool flagRow = false;

	    // parameters for the corresponding new Main table row
	    ArrayTime mainTime = ASDMArrayTime((timestampStartSecs(startRow) + timestampEndSecs(endRow))/2.); // midpoint!

	    if(asdmConfigDescriptionId_p.find(startRow) == asdmConfigDescriptionId_p.end( )){
	      os << LogIO::SEVERE << "Internal error: undefined config description id for MS main table row "
		 << startRow << LogIO::POST;
	      return false;
	    }  
	    Tag configDescriptionId = asdmConfigDescriptionId_p[startRow];
	    asdm::ConfigDescriptionRow* CDR = (ASDM_p->getConfigDescription()).getRowByKey(configDescriptionId);
	    if(CDR ==0){
	      os << LogIO::SEVERE << "Internal error: no row in ASDM ConfigDesc Table for ConfigDescriptionId stored for main table row "
		 << startRow << LogIO::POST;
	      return false;
	    }

	    Tag fieldIdTag = asdmFieldId_p[theFId];
	    int numAntenna = CDR->getNumAntenna();
	    TimeSamplingMod::TimeSampling timeSampling = TimeSamplingMod::INTEGRATION;
	    Interval interval = ASDMInterval(intervalQuant()(startRow).getValue("s")); // data sampling interval
	    int numIntegration; // to be set by the following method call
	    int dataSize; // to be set by the following method call
	    EntityRef dataOid; // to be set by the following method call
	    vector< Tag > stateIdV; // "
	  
	    // Note: for WVR data, a special case would have to be made here or inside
            //       writeMainBinSubScanForOneDDIdFIdPair() which does not call corrDataHeader
            //       and addIntegration but instead only SDMDataObjectWriter::wvrData()

	    numIntegration = writeMainBinSubScanForOneDDIdFIdPair(theDDId, theFId, 
								  datacolumn, 
								  scanNumber, subscanNumber,
								  startRow, endRow,
								  execBlockId,
								  dataSize, dataOid, stateIdV);
	    if(numIntegration<0){ // error!
	      os << LogIO::SEVERE << "Error writing Subscan starting at main table row " 
		 << startRow << LogIO::POST;
	      return false;
	    }

	    for(uInt i=0; i<(uInt)numIntegration; i++){
	      numberSubintegration.push_back(0); // no subintegrations for the moment, no channel averaging (???)
	    }
	  
	    // end write subscan
	  
	    // write corresponding Main table row
	    tR = tT.newRow(mainTime, configDescriptionId, fieldIdTag, numAntenna, timeSampling, interval, numIntegration, 
			   scanNumber, subscanNumber, dataSize, dataOid, stateIdV, execBlockId);
	    tT.add(tR);
	  
	    // write corresponding Subscan table row
	    
	    tSSR = tSST.newRow(execBlockId, scanNumber, subscanNumber, subScanStartArrayTime, subScanEndArrayTime, 
			       fieldName, subscanIntent, numIntegration, numberSubintegration //// , flagRow
			       );
	    
	    tSST.add(tSSR);
	    
	    subscanNumber++;
	    numSubScan++;

	  } // end loop over Field indices         

	} // end loop over DD indices
	// update mainTabRow
	mainTabRow = irow;
      } // end while scan continues
      // scan finished
      // complete and write scan table row
      mainTabRow--; // return to the last row of the scan
      scanEndTime = ASDMArrayTime( timestampEndSecs(mainTabRow) );	  
      scanNumIntent = 1; // hardwired (???)
      for(uInt i=0; i<(uInt)scanNumIntent; i++){
	scanIntent.push_back(ScanIntentMod::OBSERVE_TARGET); // hardwired for the moment (???)
	scanCalDataType.push_back(CalDataOriginMod::FULL_RESOLUTION_CROSS); // hardwired for the moment (???)
	scanCalibrationOnLine.push_back(false); // hardwired for the moment (???)
      }

      tSR = tST.newRow(execBlockId, scanNumber, scanStartTime, scanEndTime, scanNumIntent, numSubScan, scanIntent, 
		       scanCalDataType, scanCalibrationOnLine ////, scanFlagRow
		       );
      
      tST.add(tSR);
      
      scanNumber++;
      
    }//  end for

    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled Main table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();
    
    theUid = getCurrentUid();
    ent = tST.getEntity();
    ent.setEntityId(theUid);
    tST.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled Scan table " << getCurrentUid() << " with " << tST.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();
    
    theUid = getCurrentUid();
    ent = tSST.getEntity();
    ent.setEntityId(theUid);
    tSST.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled SubScan table " << getCurrentUid() << " with " << tSST.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();
    
    return rstat;
  }

  Bool MS2ASDM::writePointingModel(){ // create asdm PointingModel table 
    LogIO os(LogOrigin("MS2ASDM", "writePointingModel()"));
    
    Bool rstat = true;
    
    asdm::PointingModelTable& tT = ASDM_p->getPointingModel();
    
    asdm::PointingModelRow* tR = 0;
    
    asdm::FeedTable& tFT = ASDM_p->getFeed();
    
    vector< asdm::FeedRow * > feedRowV = tFT.get();

    // loop over ASDM Feed table and create Pointing model rows for each
    // receptor of each Feed table row 

    for(uInt feedRow=0; feedRow<feedRowV.size(); feedRow++){
      

      uInt numRec = feedRowV[feedRow]->getNumReceptor();
      vector< PolarizationTypeMod::PolarizationType > polTypeV = feedRowV[feedRow]->getPolarizationTypes();
      vector< int > receivIdV = feedRowV[feedRow]->getReceiverId(); 

      for(uInt iRec=0; iRec<numRec; iRec++){ // loop over all receptors

	const vector< asdm::ReceiverRow * > recRowV = feedRowV[feedRow]->getReceivers(receivIdV[iRec]);
	
	// parameters for new PointingModel row

	Tag antennaId = feedRowV[feedRow]->getAntennaId();
	int numCoeff = 2; // seems to be the dummy value ???, to be confirmed
	vector< string > coeffName;
	coeffName.push_back("IA");
	coeffName.push_back("IE");
	vector< float > coeffVal;
	coeffVal.push_back(0.);
	coeffVal.push_back(0.);
	PolarizationTypeMod::PolarizationType polarizationType;
	try{
	  polarizationType = polTypeV[iRec];
	}
	catch(std::string z){
	  os << LogIO::SEVERE << "Internal error: invalid polarization type in Feed table row  " << z
	     << LogIO::POST;      
	  return false;
	}      
	  
	ReceiverBandMod::ReceiverBand receiverBand = recRowV[0]->getFrequencyBand(); // take from the first receiver 
	string assocNature = "NOT_SET";
	int assocPointingModelId = -1;

        tR = tT.newRow(antennaId, numCoeff, coeffName, coeffVal, polarizationType, 
		       receiverBand, assocNature, assocPointingModelId);
    
	asdm::PointingModelRow* tR2 = 0;

	tR2 = tT.add(tR);
	if(asdmPointingModelId_p.find(antennaId) == asdmPointingModelId_p.end( )){
        asdmPointingModelId_p[antennaId] = tR2->getPointingModelId();
	}

      } // end loop over receptors

    } // end loop over ASDM Feed table
    
    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled PointingModel table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();

    return rstat;
  }

  Bool MS2ASDM::writePointing(){ // create asdm pointing table
    LogIO os(LogOrigin("MS2ASDM", "writePointing()"));

    Bool rstat = true;
    
    asdm::PointingTable& tT = ASDM_p->getPointing();
    
    asdm::PointingRow* tR = 0;

    uInt nPointingRows = pointing().nrow();

    if(nPointingRows==0){
      os << LogIO::WARN << "MS Pointing table doesn't exist or is empty." << LogIO::POST;	
      return true; // not an error
    }

    Bool warned = false; // aux. var. to avoid repetition of warnings

    // loop over MS antenna table
    for(Int aId=0; aId<(Int)antenna().nrow(); aId++){

      if(asdmAntennaId_p.find(aId) == asdmAntennaId_p.end( )){
	os << LogIO::SEVERE << "Internal error: no tag defined for antenna id " 
	   << aId << LogIO::POST;
	return false;
      }

      uInt irow=0;
      uInt totNumRows=0; // total of MS Pointing table rows for this antenna

      while(irow<nPointingRows){

	// find next pointing entry for this antenna in MS pointing table (== beginning of a new ASDM pointing table entry)
	Int firstRow=-1;
	while(irow<nPointingRows){
	  if(pointing().antennaId()(irow) == aId){
	    firstRow = irow;
	    break;
	  }
	  irow++;
	}

	if(firstRow==-1){ // no further data for this antenna
	  break;
	}

	uInt numRows=1; // number of rows with contiguous timestamps for this antenna 
	
	// parameters for the next pointing table row
	Tag antennaId = asdmAntennaId_p[aId];
	ArrayTimeInterval timeInterval( ASDMTimeInterval( pointing().timeQuant()(firstRow), pointing().intervalQuant()(firstRow)) );

	bool pointingTracking = pointing().tracking()(firstRow);

	bool usePolynomials = false;
	int numTerm = 0; // to be updated later

	if(pointing().numPoly()(firstRow)>0){
	  usePolynomials = true;
	  numTerm = pointing().numPoly()(irow)+1;
	}

	ArrayTime timeOrigin = ASDMArrayTime( pointing().timeOriginQuant()(firstRow).getValue("s") );
	
	vector< vector< Angle > > pointingDirection;
	Vector< MDirection > dirV; // aux. vector to access array column
	dirV.reference(pointing().directionMeasCol()(firstRow));
	if(numTerm == 0){
	  pointingDirection.push_back(ASDMAngleV(dirV[0]));
	}
	else{
	  if(numTerm != (Int)dirV.size()){
	    os << LogIO::SEVERE << "Inconsistent MS: in pointing table row " << firstRow
	       << ": numpoly + 1 should be == dimension of array DIRECTION." << LogIO::POST;	
	    return false;
	  }	    
	  for(uInt i=0; i<(uInt)numTerm; i++){
	    pointingDirection.push_back(ASDMAngleV(dirV[i]));
	  }
	}	     
	
	vector< vector< Angle > > encoder;
	if(pointing().encoderMeas().isNull()){ // encoder column is optional in MS but not in ASDM
	  if(numTerm == 0){
	    // use pointing Direction instead
	    if(!warned){
	      os << LogIO::WARN << "No ENCODER column in MS Pointing table. Will use DIRECTION instead." 
		 << LogIO::POST;	
	      warned = true;
	    }
	    dirV.reference(pointing().directionMeasCol()(firstRow));
	    encoder.push_back(ASDMAngleV(dirV[0]));
	  }
	  else{ // cannot use pointing direction because it contains only polynomial terms
	    vector< Angle > angV;
	    angV.push_back(Angle(0.));
	    angV.push_back(Angle(0.));
	    if(!warned){
	      os << LogIO::WARN << "No ENCODER column in MS Pointing table. Will fill with zeros." 
		 << LogIO::POST;	
	      warned = true;
	    }
	    encoder.push_back(angV);
	  }
	}
	else{
	  encoder.push_back(ASDMAngleV(pointing().encoderMeas()(firstRow)));
	}
	
	vector< vector< Angle > > target;
	dirV.reference(pointing().targetMeasCol()(firstRow));
	if(numTerm == 0){
	  target.push_back(ASDMAngleV(dirV[0]));
	}
	else{
	  if(numTerm != (Int)dirV.size()){
	    os << LogIO::SEVERE << "Inconsistent MS: in pointing table row " << firstRow
	       << ": numpoly + 1 should be == dimension of array TARGET." << LogIO::POST;	
	    return false;
	  }	    
	  for(uInt i=0; i<(uInt)numTerm; i++){
	    target.push_back(ASDMAngleV(dirV[i]));
	  }
	}	     
	
	vector< vector< asdm::Angle > > offset;
	// source offset column is optional in the MS but not in the ASDM
	if(pointing().pointingOffsetMeasCol().isNull()){ // no MS source offset column 
	  vector< Angle > angV;
	  angV.push_back(Angle(0.));
	  angV.push_back(Angle(0.));
	  offset.push_back(angV);
	  if(numTerm>0){
	    for(uInt i=1; i<(uInt)numTerm; i++){
	      offset.push_back(angV);
	    }
	  }
	}
	else{
	  dirV.reference(pointing().pointingOffsetMeasCol()(firstRow));
	  if(numTerm==0){
	    offset.push_back(ASDMAngleV(dirV[0]));
	  }
	  else{
	    if(numTerm != (Int)dirV.size()){
	      os << LogIO::SEVERE << "Inconsistent MS: in pointing table row " << firstRow
		 << ": numpoly + 1 should be == dimension of array POINTING_OFFSET." << LogIO::POST;	
	      return false;
	    }	    
	    for(uInt i=0; i<(uInt)numTerm; i++){
	      offset.push_back(ASDMAngleV(dirV[i]));
	    }
	  }
	}	
	
	vector< vector< Angle > > sourceOffset; // optional in the ASDM and in the MS
	if(!pointing().sourceOffsetMeasCol().isNull()){ // sourceOffset column is present
	  dirV.reference(pointing().sourceOffsetMeasCol()(firstRow));
	  if(numTerm==0){
	    sourceOffset.push_back(ASDMAngleV(dirV[0]));
	  }
	  else{
	    if(numTerm != (Int)dirV.size()){
	      os << LogIO::SEVERE << "Inconsistent MS: in pointing table row " << firstRow
		 << ": numpoly + 1 should be == dimension of array SOURCE_OFFSET." << LogIO::POST;	
	      return false;
	    }	    
	    for(uInt i=0; i<(uInt)numTerm; i++){
	      sourceOffset.push_back(ASDMAngleV(dirV[i]));
	    }
	  }
	} 

	int pointingModelId = asdmPointingModelId_p[antennaId];
        double endTimeMJD = timeInterval.getStartInMJD() + timeInterval.getDurationInDays();

	// check if there are more rows for this antenna with adjacent time intervals
	irow++;
	
	while(irow<nPointingRows && numTerm==0){ // while we find more adjacent rows and don't use polynomials

	  if(pointing().antennaId()(irow) != aId){
	    irow++;
	    continue;
	  }

          // need to do the comparison this way because this is close to how the PointingTable class
          // decides how to add a new row

          ArrayTimeInterval thisTimeInterval = ASDMTimeInterval(pointing().timeQuant()(irow), pointing().intervalQuant()(irow));
	  if( !casacore::near(endTimeMJD,thisTimeInterval.getStartInMJD()) // row irow is adjacent in time to previous row
	      || pointingTracking != pointing().tracking()(irow) 
	      || (usePolynomials == false && pointing().numPoly()(irow)>0)
	      ){
	    break; // there will be no further samples for this ASDM pointing table row
	  }

	  // found a second pointing row for the antenna ID, now accumulate directions
	  // until time ranges not contiguous or end of table

          numRows++;
          endTimeMJD = thisTimeInterval.getStartInMJD() + thisTimeInterval.getDurationInDays();

	  // update timeInterval - this may not be exactly the same as adding the durations
	  timeInterval.setDuration(endTimeMJD - timeInterval.getStartInMJD());

	  dirV.reference(pointing().directionMeasCol()(irow));
	  pointingDirection.push_back(ASDMAngleV(dirV[0]));
	
	  if(pointing().encoderMeas().isNull()){ // encoder column is optional
	    // use pointing Direction instead
	    encoder.push_back(ASDMAngleV(dirV[0]));
	  }
	  else{
	    encoder.push_back(ASDMAngleV(pointing().encoderMeas()(irow)));
	  }
	
	  dirV.reference(pointing().targetMeasCol()(irow));
	  target.push_back(ASDMAngleV(dirV[0]));
	
	  if(pointing().pointingOffsetMeasCol().isNull()){ // source offset column is optional
	    vector< Angle > angV;
	    angV.push_back(Angle(0.));
	    angV.push_back(Angle(0.));
	    offset.push_back(angV);
	  }
	  else{
	    dirV.reference(pointing().pointingOffsetMeasCol()(irow));
	    offset.push_back(ASDMAngleV(dirV[0]));
	  }	
	
	  if(!pointing().sourceOffsetMeasCol().isNull()){ // source offset column is optional
	    dirV.reference(pointing().sourceOffsetMeasCol()(irow));
	    sourceOffset.push_back(ASDMAngleV(dirV[0]));
	  }	
          irow++;
	
	} // end while accumulating for started  entry

	// finish the ASDM table row and add it to the table
	int numSample = encoder.size(); 
	if(!usePolynomials){
	  numTerm = numSample;
	}

	tR = tT.newRow(antennaId, timeInterval, numSample, encoder, pointingTracking, usePolynomials, timeOrigin, 
		       numTerm, pointingDirection, target, offset, pointingModelId);
	
	if(sourceOffset.size()>0){
	  tR->setSourceOffset(sourceOffset);
	} 

	asdm::PointingRow* tR2 = 0;
	
	try{
	  tR2 = tT.add(tR);
	}
	catch(asdm::DuplicateKey){
	  os << LogIO::WARN << "Caught asdm::DuplicateKey error for antenna id " 
	     << aId << LogIO::POST;
	}	  
	if(tR2 != tR){// no new row was inserted
	  os << LogIO::WARN << "Internal error: duplicate row in Pointing table for antenna id " 
	     << aId << LogIO::POST;	
	}
	else{
	  if(verbosity_p>1){
	    os << LogIO::NORMAL << "Combined " << numRows 
	       << " MS Pointing table rows into one ASDM Pointing table row for antenna id " 
	       << aId << LogIO::POST;	
	  }
	}
	totNumRows += numRows;
	
      } // end while rows left in pointing table
      
      if(totNumRows==0){
	os << LogIO::WARN << "No MS Pointing table rows found for antenna id " 
	    << aId << LogIO::POST;	
      }	

    } // end loop over antenna ids
    
    EntityId theUid(getCurrentUid());
    Entity ent = tT.getEntity();
    ent.setEntityId(theUid);
    tT.setEntity(ent);
    if(verbosity_p>0){
      os << LogIO::NORMAL << "Filled Pointing table " << getCurrentUid() << " with " << tT.size() << " rows ..." << LogIO::POST;
    }
    incrementUid();
    
    return rstat;
  }

  StokesParameterMod::StokesParameter MS2ASDM::ASDMStokesParameter( Stokes::StokesTypes s) {
    switch (s) {
    case Stokes::I:     return StokesParameterMod::I;         
    case Stokes::Q: 	return StokesParameterMod::Q;        
    case Stokes::U: 	return StokesParameterMod::U;        
    case Stokes::V: 	return StokesParameterMod::V;        
    case Stokes::RR: 	return StokesParameterMod::RR;       
    case Stokes::RL: 	return StokesParameterMod::RL;       
    case Stokes::LR: 	return StokesParameterMod::LR;       
    case Stokes::LL: 	return StokesParameterMod::LL;       
    case Stokes::XX: 	return StokesParameterMod::XX;       
    case Stokes::XY: 	return StokesParameterMod::XY;       
    case Stokes::YX: 	return StokesParameterMod::YX;       
    case Stokes::YY: 	return StokesParameterMod::YY;       
    case Stokes::RX: 	return StokesParameterMod::RX;       
    case Stokes::RY: 	return StokesParameterMod::RY;       
    case Stokes::LX: 	return StokesParameterMod::LX;       
    case Stokes::LY: 	return StokesParameterMod::LY;       
    case Stokes::XR: 	return StokesParameterMod::XR;       
    case Stokes::XL: 	return StokesParameterMod::XL;       
    case Stokes::YR: 	return StokesParameterMod::YR;       
    case Stokes::YL: 	return StokesParameterMod::YL;       
    case Stokes::PP: 	return StokesParameterMod::PP;       
    case Stokes::PQ: 	return StokesParameterMod::PQ;       
    case Stokes::QP: 	return StokesParameterMod::QP;       
    case Stokes::QQ: 	return StokesParameterMod::QQ;       
    case Stokes::RCircular: return StokesParameterMod::RCIRCULAR;
    case Stokes::LCircular: return StokesParameterMod::LCIRCULAR;
    case Stokes::Linear: 	return StokesParameterMod::LINEAR;   
    case Stokes::Ptotal: 	return StokesParameterMod::PTOTAL;   
    case Stokes::Plinear: 	return StokesParameterMod::PLINEAR;  
    case Stokes::PFtotal: 	return StokesParameterMod::PFTOTAL;  
    case Stokes::PFlinear: 	return StokesParameterMod::PFLINEAR; 
    case Stokes::Pangle:  	return StokesParameterMod::PANGLE; 
    case Stokes::Undefined:
    default:    
      throw(AipsError("Undefined stokes parameter."+String((Int)s)) );
    }
  }

  AntennaTypeMod::AntennaType MS2ASDM::ASDMAntennaType( const String& type ){
    LogIO os(LogOrigin("MS2ASDM", "(ASDMAntennaType)"));
    if(type == "GROUND-BASED"){
      return AntennaTypeMod::GROUND_BASED;
    }
    else if(type == "SPACE-BASED"){
      return AntennaTypeMod::SPACE_BASED;
    }      
    else{
      os << LogIO::WARN << "Unknown antenna type " << type << " assuming GROUND-BASED." << LogIO::POST;
      return AntennaTypeMod::GROUND_BASED;
    }      
  } 

    ArrayTimeInterval MS2ASDM::ASDMTimeInterval( const Quantity midpoint, const Quantity interval){
        Double sTime = midpoint.getValue("s");  
        Double sInterval = interval.getValue("s");

        // watch for sInterval==0 which means these correspond to a constant value over the whole MS
        if (sInterval == 0.) {
            sTime = timestampStartSecs(0);
            sInterval = timestampEndSecs(ms_p.nrow()-1) - sTime;
        } else {
            // very large values of sInterval also signify a constant value, probably in the original SDM
            // this is somewhat arbitrary but is intended to be safe, there's probably no harm
            // in writing out large values to the SDM as they will be recovered when read back in
            // let "large" here be > about 1 year - could probably be smaller and still be safe
            // 24*60*60*365
            if (sInterval > 31536000.0) {
                sTime = timestampStartSecs(0);
                sInterval = timestampEndSecs(ms_p.nrow()-1) - sTime;
            } else {
                // the usual case, turn sTime into the start time
                sTime -= sInterval/2.;
            }
        } 
    
    ArrayTimeInterval timeInterval( ASDMArrayTime(sTime),
				    ASDMInterval(sInterval) );
    return timeInterval;
  }

  vector< Angle > MS2ASDM::ASDMAngleV(const MDirection mDir){
    vector< Angle > angV;
    angV.push_back( mDir.getAngle( unitASDMAngle() ).getValue()(0) ); 
    angV.push_back( mDir.getAngle( unitASDMAngle() ).getValue()(1) ); 
    return angV;
  }
    
  DirectionReferenceCodeMod::DirectionReferenceCode MS2ASDM::ASDMDirRefCode(const MDirection::Types type){

    switch(type){
    case MDirection::J2000:     return DirectionReferenceCodeMod::J2000; 	  
    case MDirection::JMEAN:     return DirectionReferenceCodeMod::JMEAN; 	  
    case MDirection::JTRUE:     return DirectionReferenceCodeMod::JTRUE; 	  
    case MDirection::APP:       return DirectionReferenceCodeMod::APP; 	  
    case MDirection::B1950:     return DirectionReferenceCodeMod::B1950; 	  
    case MDirection::B1950_VLA: return DirectionReferenceCodeMod::B1950_VLA; 	
    case MDirection::BMEAN:     return DirectionReferenceCodeMod::BMEAN; 	  
    case MDirection::BTRUE:     return DirectionReferenceCodeMod::BTRUE; 	  
    case MDirection::GALACTIC:  return DirectionReferenceCodeMod::GALACTIC;  	
    case MDirection::HADEC:     return DirectionReferenceCodeMod::HADEC; 	  
    case MDirection::AZELSW:    return DirectionReferenceCodeMod::AZELSW; 	  
    case MDirection::AZELSWGEO: return DirectionReferenceCodeMod::AZELSWGEO; 
      //case MDirection::AZELGEO:   return DirectionReferenceCodeMod::AZELNEGEO; //(same case as MDirection::AZELNEGEO!)   	
    case MDirection::AZELNEGEO: return DirectionReferenceCodeMod::AZELNEGEO; 	  
    case MDirection::JNAT:      return DirectionReferenceCodeMod::JNAT; 	  
    case MDirection::ECLIPTIC:  return DirectionReferenceCodeMod::ECLIPTIC;  	
    case MDirection::MECLIPTIC: return DirectionReferenceCodeMod::MECLIPTIC; 	
    case MDirection::TECLIPTIC: return DirectionReferenceCodeMod::TECLIPTIC; 	
    case MDirection::SUPERGAL:  return DirectionReferenceCodeMod::SUPERGAL;  	
    case MDirection::ITRF:      return DirectionReferenceCodeMod::ITRF; 	  
    case MDirection::TOPO:      return DirectionReferenceCodeMod::TOPO; 	  
    case MDirection::ICRS:      return DirectionReferenceCodeMod::ICRS;      
    
    case MDirection::MERCURY: return DirectionReferenceCodeMod::MERCURY; 
    case MDirection::VENUS:   return DirectionReferenceCodeMod::VENUS;
    case MDirection::MARS:    return DirectionReferenceCodeMod::MARS;
    case MDirection::JUPITER: return DirectionReferenceCodeMod::JUPITER;
    case MDirection::SATURN:  return DirectionReferenceCodeMod::SATURN;
    case MDirection::URANUS:  return DirectionReferenceCodeMod::URANUS;
    case MDirection::NEPTUNE: return DirectionReferenceCodeMod::NEPTUNE;
    case MDirection::PLUTO:   return DirectionReferenceCodeMod::PLUTO;
    case MDirection::SUN:     return DirectionReferenceCodeMod::SUN;
    case MDirection::MOON:    return DirectionReferenceCodeMod::MOON;
    default:
      return DirectionReferenceCodeMod::J2000;
    }

  }


  BasebandNameMod::BasebandName MS2ASDM::ASDMBBName( Int BBCNo ){
    switch(BBCNo){
    case 1: return BasebandNameMod::BB_1;
    case 2: return BasebandNameMod::BB_2;
    case 3: return BasebandNameMod::BB_3;
    case 4: return BasebandNameMod::BB_4;
    case 5: return BasebandNameMod::BB_5;
    case 6: return BasebandNameMod::BB_6;
    case 7: return BasebandNameMod::BB_7;
    case 8: return BasebandNameMod::BB_8;
    case 0: 
    default:
      return BasebandNameMod::NOBB;
    }
  }

  NetSidebandMod::NetSideband MS2ASDM::ASDMNetSideBand( Int netSideB ){
    switch(netSideB){
    case 1: return NetSidebandMod::LSB;
    case 2: return NetSidebandMod::USB;
    case 3: return NetSidebandMod::DSB;
    case 0:
    default:
      return NetSidebandMod::NOSB;
    }
  }

  FrequencyReferenceCodeMod::FrequencyReferenceCode MS2ASDM::ASDMFreqRefCode( const MFrequency::Types refFrame ){
    LogIO os(LogOrigin("MS2ASDM", "(ASDMFreqRefCode)"));
    switch( refFrame ){
    case MFrequency::LSRD: return FrequencyReferenceCodeMod::LSRD;
    case MFrequency::LSRK: return FrequencyReferenceCodeMod::LSRK;
    case MFrequency::BARY: return FrequencyReferenceCodeMod::BARY;
    case MFrequency::REST: return FrequencyReferenceCodeMod::REST;
    case MFrequency::GEO: return FrequencyReferenceCodeMod::GEO;
    case MFrequency::GALACTO: return FrequencyReferenceCodeMod::GALACTO;
    case MFrequency::TOPO: return FrequencyReferenceCodeMod::TOPO;
    default:
      os << LogIO::SEVERE << "Unsupported CASA reference frame " << MFrequency::showType(refFrame) 
	 << ", assuming TOPO." << LogIO::POST;
      return FrequencyReferenceCodeMod::TOPO; 
    }
  }

  Bool MS2ASDM::stokesTypePresent( const Vector< Int > corrT, 
				   const Stokes::StokesTypes st ){
    Bool rval = false;
    for(uInt j=0; j<corrT.size(); j++){
      if(corrT[j]==static_cast<Int>(st)){
	 rval = true;
	 break;
      }
    }
    return rval;
  }

  Int MS2ASDM::setRecBands( const asdm::Frequency refFreq, 
			    double& repFreq,
			    ReceiverBandMod::ReceiverBand& frequencyBand,
			    ReceiverSidebandMod::ReceiverSideband& receiverSideband){

    // return the band number as an Int, -1 means failure, 0 means unknown observatory
    Int rval = -1;

    Quantity theFreq( refFreq.get(), String(Frequency::unit()) );
    Double theFreqGHz = theFreq.getValue("GHz");
    
    //cout << "tel " << telName_p << endl;
    //cout << "Freq (GHz) " << theFreqGHz << endl; 

    // default values
    Quantity tempQ( ((Int)theFreqGHz)*1E9, "Hz");
    repFreq =  tempQ.getValue(unitASDMFreq());
    frequencyBand = ReceiverBandMod::UNSPECIFIED;
    receiverSideband = ReceiverSidebandMod::NOSB;

    // implementation of the ALMA freq bands !!!
    if(telName_p == "ALMA" || telName_p == "OSF" || telName_p == "ACA"){
      if(31.<=theFreqGHz &&  theFreqGHz<45.){
	repFreq = (31.+45.)/2.*1E9;
	frequencyBand = ReceiverBandMod::ALMA_RB_01;
	receiverSideband = ReceiverSidebandMod::SSB; 
	rval = 1;
      }
      else if(67.<=theFreqGHz &&  theFreqGHz<90.){
	repFreq = (67.+90.)/2.*1E9;
	frequencyBand = ReceiverBandMod::ALMA_RB_02;
	receiverSideband = ReceiverSidebandMod::SSB; 
	rval = 2;
      }
      else if(84.<=theFreqGHz &&  theFreqGHz<116.){
	repFreq = (84.+116.)/2.*1E9;
	frequencyBand = ReceiverBandMod::ALMA_RB_03;
	receiverSideband = ReceiverSidebandMod::TSB; 
	rval = 3;
      }
      else if(125.<=theFreqGHz &&  theFreqGHz<163.){
	repFreq = (125.+163.)/2.*1E9;
	frequencyBand = ReceiverBandMod::ALMA_RB_04;
	receiverSideband = ReceiverSidebandMod::TSB; 
	rval = 4;
      }	  
      else if(163.<=theFreqGHz &&  theFreqGHz<211.){
	repFreq = (163.+211.)/2.*1E9;
	frequencyBand = ReceiverBandMod::ALMA_RB_05;
	receiverSideband = ReceiverSidebandMod::TSB; 
	rval = 5;
      }	  
      else if(211.<=theFreqGHz &&  theFreqGHz<275.){
	repFreq = (211.+275.)/2.*1E9;
	frequencyBand = ReceiverBandMod::ALMA_RB_06;
	receiverSideband = ReceiverSidebandMod::TSB; 
	rval = 6;
      }	  
      else if(275.<=theFreqGHz &&  theFreqGHz<373.){
	repFreq = (275.+373.)/2.*1E9;
	frequencyBand = ReceiverBandMod::ALMA_RB_07;
	receiverSideband = ReceiverSidebandMod::TSB; 
	rval = 7;
      }	  
      else if(385.<=theFreqGHz &&  theFreqGHz<500.){
	repFreq = (385.+500.)/2.*1E9;
	frequencyBand = ReceiverBandMod::ALMA_RB_08;
	receiverSideband = ReceiverSidebandMod::TSB; 
	rval = 8;
      }	  
      else if(602.<=theFreqGHz &&  theFreqGHz<720.){
	repFreq = (602.+720.)/2.*1E9;
	frequencyBand = ReceiverBandMod::ALMA_RB_09;
	receiverSideband = ReceiverSidebandMod::DSB; 
	rval = 9;
      }	  
      else if(787.<=theFreqGHz &&  theFreqGHz<950.){
	repFreq = (787.+950.)/2.*1E9;
	frequencyBand = ReceiverBandMod::ALMA_RB_10;
	receiverSideband = ReceiverSidebandMod::DSB; 
	rval = 10;
      }
      else{
	repFreq = theFreqGHz*1E9;
	frequencyBand = ReceiverBandMod::UNSPECIFIED;
	receiverSideband = ReceiverSidebandMod::TSB; 
	rval = 0;
      }
	
      Quantity tempQ2(repFreq, "Hz");
      repFreq =  tempQ2.getValue(unitASDMFreq());
      return rval;
    }
    else if(telName_p == "VLA" || telName_p == "EVLA" || telName_p == "JVLA"){
      // EVLA freq band implementation!!
      if( 0.033 <=theFreqGHz &&  theFreqGHz<0.081 ){
	repFreq = (0.033/0.081)/2.*1E9;
	frequencyBand = ReceiverBandMod::EVLA_4;
	receiverSideband = ReceiverSidebandMod::NOSB; 
	rval = 1;
      }
      else if(0.298<=theFreqGHz &&  theFreqGHz< 0.345){
	repFreq = (0.298+0.345)/2.*1E9;
	frequencyBand = ReceiverBandMod::EVLA_P;
	receiverSideband = ReceiverSidebandMod::NOSB; 
	rval = 2;
      }
      else if(1.0 <=theFreqGHz &&  theFreqGHz< 2.0){
	repFreq = (1.+2.)/2.*1E9;
	frequencyBand = ReceiverBandMod::EVLA_L;
	receiverSideband = ReceiverSidebandMod::NOSB; 
	rval = 3;
      }
      else if(2.0 <=theFreqGHz &&  theFreqGHz< 4.0){
	repFreq = (2.+4.)/2.*1E9;
	frequencyBand = ReceiverBandMod::EVLA_S;
	receiverSideband = ReceiverSidebandMod::NOSB; 
	rval = 4;
      }	  
      else if(4.0 <=theFreqGHz &&  theFreqGHz< 8.0){
	repFreq = (4.+8.)/2.*1E9;
	frequencyBand = ReceiverBandMod::EVLA_C;
	receiverSideband = ReceiverSidebandMod::NOSB; 
	rval = 5;
      }	  
      else if(8.0 <=theFreqGHz &&  theFreqGHz< 12.0){
	repFreq = (8.+12.)/2.*1E9;
	frequencyBand = ReceiverBandMod::EVLA_X;
	receiverSideband = ReceiverSidebandMod::NOSB; 
	rval = 6;
      }	  
      else if(12. <=theFreqGHz &&  theFreqGHz< 18.){ 
	repFreq = (12.+18.)/2.*1E9;
	frequencyBand = ReceiverBandMod::EVLA_Ku; // a.k.a. U
	receiverSideband = ReceiverSidebandMod::NOSB; 
	rval = 7;
      }	  
      else if(18.0 <=theFreqGHz &&  theFreqGHz< 26.5){
	repFreq = (18.+26.5)/2.*1E9;
	frequencyBand = ReceiverBandMod::EVLA_K;
	receiverSideband = ReceiverSidebandMod::NOSB; 
	rval = 8;
      }	  
      else if(26.5 <=theFreqGHz &&  theFreqGHz< 40.){
	repFreq = (26.5+40.)/2.*1E9;
	frequencyBand = ReceiverBandMod::EVLA_Ka;
	receiverSideband = ReceiverSidebandMod::NOSB; 
	rval = 9;
      }	  
      else if(40. <=theFreqGHz &&  theFreqGHz< 50.){
	repFreq = (40.+50.)/2.*1E9;
	frequencyBand = ReceiverBandMod::EVLA_Q;
	receiverSideband = ReceiverSidebandMod::NOSB; 
	rval = 10;
      }
      else{
	repFreq = theFreqGHz*1E9;
	frequencyBand = ReceiverBandMod::UNSPECIFIED;
	receiverSideband = ReceiverSidebandMod::NOSB; 
	rval = 0;
      }
      Quantity tempQ2(repFreq, "Hz");
      repFreq =  tempQ2.getValue(unitASDMFreq());
      return rval;
    }

    return 0; // unknown observatory
  }  


} //#End casa namespace