Changeset 805


Ignore:
Timestamp:
02/16/06 12:02:18 (19 years ago)
Author:
mar637
Message:

Code replacemnts after the rename

Location:
trunk/src
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/STFiller.cpp

    r804 r805  
    1 //#---------------------------------------------------------------------------
    2 //# SDReader.cc: A class to read single dish spectra from SDFITS, RPFITS
    3 //#---------------------------------------------------------------------------
    4 //# Copyright (C) 2004
    5 //# ATNF
    6 //#
    7 //# This program is free software; you can redistribute it and/or modify it
    8 //# under the terms of the GNU General Public License as published by the Free
    9 //# Software Foundation; either version 2 of the License, or (at your option)
    10 //# any later version.
    11 //#
    12 //# This program is distributed in the hope that it will be useful, but
    13 //# WITHOUT ANY WARRANTY; without even the implied warranty of
    14 //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
    15 //# Public License for more details.
    16 //#
    17 //# You should have received a copy of the GNU General Public License along
    18 //# with this program; if not, write to the Free Software Foundation, Inc.,
    19 //# 675 Massachusetts Ave, Cambridge, MA 02139, USA.
    20 //#
    21 //# Correspondence concerning this software should be addressed as follows:
    22 //#        Internet email: Malte.Marquarding@csiro.au
    23 //#        Postal address: Malte Marquarding,
    24 //#                        Australia Telescope National Facility,
    25 //#                        P.O. Box 76,
    26 //#                        Epping, NSW, 2121,
    27 //#                        AUSTRALIA
    28 //#
    29 //# $Id:
    30 //#---------------------------------------------------------------------------
     1//
     2// C++ Implementation: STFiller
     3//
     4// Description:
     5//
     6//
     7// Author: Malte Marquarding <asap@atnf.csiro.au>, (C) 2006
     8//
     9// Copyright: See COPYING file that comes with this distribution
     10//
     11//
    3112#include <casa/iostream.h>
    3213#include <casa/iomanip.h>
     
    3617#include <casa/OS/File.h>
    3718#include <casa/Quanta/Unit.h>
     19#include <casa/Arrays/ArrayMath.h>
     20#include <casa/Utilities/Regex.h>
     21
     22#include <casa/Containers/RecordField.h>
     23
     24#include <tables/Tables/TableRow.h>
     25
    3826#include <atnf/PKSIO/PKSreader.h>
    3927
    40 #include "SDReader.h"
    4128#include "SDDefs.h"
    4229#include "SDAttr.h"
    4330
     31#include "STFiller.h"
     32
    4433using namespace casa;
    45 using namespace asap;
    46 
    47 SDReader::SDReader() :
     34
     35namespace asap {
     36
     37STFiller::STFiller() :
    4838  reader_(0),
    4939  header_(0),
    50   frequencies_(0),
    51   table_(new SDMemTable()),
    52   haveXPol_(False)
    53 {
    54   cursor_ = 0;
    55 }
    56 SDReader::SDReader(const std::string& filename,
    57                    int whichIF, int whichBeam) :
     40  table_(0)
     41{
     42}
     43
     44STFiller::STFiller( CountedPtr< Scantable > stbl ) :
    5845  reader_(0),
    5946  header_(0),
    60   frequencies_(0),
    61   table_(new SDMemTable()),
    62   haveXPol_(False)
    63 {
    64   cursor_ = 0;
    65   open(filename, whichIF, whichBeam);
    66 }
    67 
    68 SDReader::SDReader(CountedPtr<SDMemTable> tbl) :
     47  table_(stbl)
     48{
     49}
     50
     51STFiller::STFiller(const std::string & filename,
     52                                 int whichIF, int whichBeam ) :
    6953  reader_(0),
    7054  header_(0),
    71   table_(tbl),
    72   haveXPol_(False)
    73 {
    74   cursor_ = 0;
    75 }
    76 
    77 SDReader::~SDReader() {
    78   if (reader_) delete reader_;
    79   if (header_) delete header_;
    80   if (frequencies_) delete frequencies_;
    81 }
    82 
    83 void SDReader::reset() {
    84   cursor_ = 0;
    85   table_ = new SDMemTable();
    86   open(filename_,ifOffset_, beamOffset_);
    87 }
    88 
    89 
    90 void SDReader::close() {
    91   //cerr << "disabled" << endl;
    92 }
    93 
    94 void SDReader::open(const std::string& filename,
    95                     int whichIF, int whichBeam) {
    96   if (reader_) delete reader_; reader_ = 0;
    97   Bool   haveBase, haveSpectra;
     55  table_(0)
     56{
     57  open(filename, whichIF, whichBeam);
     58}
     59
     60STFiller::~STFiller()
     61{
     62  close();
     63}
     64
     65void STFiller::open( const std::string & filename,
     66                            int whichIF, int whichBeam )
     67{
     68  if (table_.null()) table_ = new Scantable();
     69  if (reader_)  { delete reader_; reader_ = 0; }
     70  Bool haveBase, haveSpectra;
    9871
    9972  String inName(filename);
     
    10275
    10376  File file(inName);
    104   if (!file.exists()) {
     77  if ( !file.exists() ) {
    10578     throw(AipsError("File does not exist"));
    10679  }
     
    11083  String format;
    11184  Vector<Bool> beams;
    112   if ((reader_ = getPKSreader(inName, 0, False, format, beams, nIF_,
     85  if ( (reader_ = getPKSreader(inName, 0, 0, format, beams, nIF_,
    11386                              nChan_, nPol_, haveBase, haveSpectra,
    114                               haveXPol_)) == 0)  {
     87                              haveXPol_)) == 0 )  {
    11588    throw(AipsError("Creation of PKSreader failed"));
    11689  }
     
    12497  nBeam_ = beams.nelements();
    12598  // Get basic parameters.
    126   if (haveXPol_) {
     99  if ( haveXPol_ ) {
    127100    pushLog("Cross polarization present");
    128101    nPol_ += 2;                          // Convert Complex -> 2 Floats
     
    145118    delete reader_;
    146119    reader_ = 0;
     120    delete header_;
     121    header_ = 0;
    147122    throw(AipsError("Failed to get header."));
    148     return;
    149123  }
    150124  if ((header_->obstype).matches("*SW*")) {
     
    153127               "setting # of IFs = 1 ");
    154128    nIF_ = 1;
     129    header_->obstype = String("fswitch");
    155130  }
    156131
     
    166141  header_->nif = nIF_;
    167142  header_->epoch = "UTC";
    168 
     143  // *** header_->frequnit = "Hz"
    169144  // Apply selection criteria.
    170145
     
    176151  if (whichIF>=0) {
    177152    if (whichIF>=0 && whichIF<nIF_) {
    178        IFsel = False;
    179        IFsel(whichIF) = True;
    180        header_->nif = 1;
    181        nIF_ = 1;
    182        ifOffset_ = whichIF;
     153      IFsel = False;
     154      IFsel(whichIF) = True;
     155      header_->nif = 1;
     156      nIF_ = 1;
     157      ifOffset_ = whichIF;
    183158    } else {
    184        throw(AipsError("Illegal IF selection"));
     159      delete reader_;
     160      reader_ = 0;
     161      delete header_;
     162      header_ = 0;
     163      throw(AipsError("Illegal IF selection"));
    185164    }
    186165  }
     
    188167  beamOffset_ = 0;
    189168  if (whichBeam>=0) {
    190      if (whichBeam>=0 && whichBeam<nBeam_) {
    191         beamSel = False;
    192         beamSel(whichBeam) = True;
    193         header_->nbeam = 1;
    194         nBeam_ = 1;
    195         beamOffset_ = whichBeam;
    196      } else {
    197        throw(AipsError("Illegal Beam selection"));
    198      }
     169    if (whichBeam>=0 && whichBeam<nBeam_) {
     170      beamSel = False;
     171      beamSel(whichBeam) = True;
     172      header_->nbeam = 1;
     173      nBeam_ = 1;
     174      beamOffset_ = whichBeam;
     175    } else {
     176      delete reader_;
     177      reader_ = 0;
     178      delete header_;
     179      header_ = 0;
     180      throw(AipsError("Illegal Beam selection"));
     181    }
    199182  }
    200183  Vector<Int> start(nIF_, 1);
     
    202185  reader_->select(beamSel, IFsel, start, end, ref, True, haveXPol_);
    203186  table_->putSDHeader(*header_);
    204 
    205   if (frequencies_) delete frequencies_;
    206   frequencies_ = new SDFrequencyTable();
    207   frequencies_->setRefFrame(header_->freqref);
    208   frequencies_->setBaseRefFrame(header_->freqref);
    209   frequencies_->setRestFrequencyUnit("Hz");
    210   frequencies_->setEquinox(header_->equinox);
    211 }
    212 
    213 int SDReader::read(const std::vector<int>& seq) {
     187}
     188
     189void STFiller::close( )
     190{
     191  delete reader_;reader_=0;
     192  delete header_;header_=0;
     193  table_ = 0;
     194}
     195
     196int asap::STFiller::read( )
     197{
    214198  int status = 0;
    215199
     
    226210  Complex         xCalFctr;
    227211  Vector<Complex> xPol;
    228   uInt n = seq.size();
    229 
    230 
    231   uInt stepsize = header_->nif*header_->nbeam;
    232   uInt seqi = 0;
    233   Bool getAll = False;
    234 
    235   if (seq[n-1] == -1) getAll = True;
    236   while ( (cursor_ <= seq[n-1]) || getAll) {
    237     // only needs to be create if in seq
    238     SDContainer sc(header_->nbeam,header_->nif,header_->npol,header_->nchan);
    239     // iterate over one correlator integration cycle = nBeam*nIF
    240     for (uInt row=0; row < stepsize; row++) {
    241       // stepsize as well
    242       // spectra(nChan,nPol)!!!
    243       status = reader_->read(scanNo, cycleNo, mjd, interval, fieldName,
    244                              srcName, srcDir, srcPM, srcVel, IFno, refFreq,
    245                              bandwidth, freqInc, restFreq, tcal, tcalTime,
    246                              azimuth, elevation, parAngle, focusAxi,
    247                              focusTan, focusRot, temperature, pressure,
    248                              humidity, windSpeed, windAz, refBeam,
    249                              beamNo, direction, scanRate,
    250                              tsys, sigma, calFctr, baseLin, baseSub,
    251                              spectra, flagtra, xCalFctr, xPol);
    252 
    253       // Make sure beam/IF numbers are 0-relative - dealing with
    254       // possible IF or Beam selection
    255       beamNo = beamNo - beamOffset_ - 1;
    256       IFno = IFno - ifOffset_ - 1;
    257 
    258       if (status) {
    259         if (status == -1) {
    260           // EOF.
    261           if (row > 0 && row < stepsize-1)
    262             pushLog("incomplete scan data.\n Probably means not all Beams/IFs/Pols within a scan are present.");
    263 
    264           // flush frequency table
    265           table_->putSDFreqTable(*frequencies_);
    266           return status;
    267         }
    268       }
    269       // if in the given list
    270       if (cursor_ == seq[seqi] || getAll) {
    271         // add integration cycle
    272         if (row==0) {
    273           //add invariant info: scanNo, mjd, interval, fieldName,
    274           //srcName, azimuth, elevation, parAngle, focusAxi, focusTan,
    275           //focusRot, temperature, pressure, humidity, windSpeed,
    276           //windAz  srcDir, srcPM, srcVel
    277           sc.timestamp = mjd;
    278           sc.interval = interval;
    279           sc.sourcename = srcName;
    280           sc.fieldname = fieldName;
    281           sc.azimuth = azimuth;
    282           sc.elevation = elevation;
    283         }
    284         // add specific info
    285         // refPix = nChan/2+1 in  1-rel Integer arith.!
    286         Int refPix = header_->nchan/2;       // 0-rel
    287         uInt freqID = frequencies_->addFrequency(refPix, refFreq, freqInc);
    288         uInt restFreqID = frequencies_->addRestFrequency(restFreq);
    289 
    290         sc.setFrequencyMap(freqID, IFno);
    291         sc.setRestFrequencyMap(restFreqID, IFno);
    292 
    293         sc.tcal[0] = tcal[0];sc.tcal[1] = tcal[1];
    294         sc.tcaltime = tcalTime;
    295         sc.parangle = parAngle;
    296         sc.refbeam = -1; //nbeams == 1
    297         if (nBeam_ > 1) // circumvent a bug "asap0000" in read which
    298                         // returns a random refbema number on multiple
    299                         // reads
    300           sc.refbeam = refBeam-1;//make it 0-based;
    301         sc.scanid = scanNo-1;//make it 0-based
    302         if (haveXPol_) {
    303            sc.setSpectrum(spectra, xPol, beamNo, IFno);
    304            sc.setFlags(flagtra,  beamNo, IFno, True);
    305         } else {
    306            sc.setSpectrum(spectra, beamNo, IFno);
    307            sc.setFlags(flagtra,  beamNo, IFno, False);
    308         }
    309         sc.setTsys(tsys, beamNo, IFno, haveXPol_);
    310         sc.setDirection(direction, beamNo);
    311       }
    312     }
    313 
    314     if (cursor_ == seq[seqi] || getAll) {
    315       // insert container into table/list
    316       table_->putSDContainer(sc);
    317       seqi++;// next in list
    318     }
    319     cursor_++;// increment position in file
    320 
    321   }
    322   table_->putSDFreqTable(*frequencies_);
     212  while ( status == 0 ) {
     213    status = reader_->read(scanNo, cycleNo, mjd, interval, fieldName,
     214                          srcName, srcDir, srcPM, srcVel, IFno, refFreq,
     215                          bandwidth, freqInc, restFreq, tcal, tcalTime,
     216                          azimuth, elevation, parAngle, focusAxi,
     217                          focusTan, focusRot, temperature, pressure,
     218                          humidity, windSpeed, windAz, refBeam,
     219                          beamNo, direction, scanRate,
     220                          tsys, sigma, calFctr, baseLin, baseSub,
     221                          spectra, flagtra, xCalFctr, xPol);
     222    if ( status != 0 ) break;
     223    TableRow row(table_->table());
     224    TableRecord& rec = row.record();
     225    RecordFieldPtr<uInt> scanoCol(rec, "SCANNO");
     226    *scanoCol = scanNo-1;
     227    RecordFieldPtr<uInt> cyclenoCol(rec, "CYCLENO");
     228    *cyclenoCol = cycleNo-1;
     229    RecordFieldPtr<Double> mjdCol(rec, "TIME");
     230    *mjdCol = mjd;
     231    RecordFieldPtr<Double> intCol(rec, "INTERVAL");
     232    *intCol = interval;
     233    RecordFieldPtr<String> srcnCol(rec, "SRCNAME");
     234    RecordFieldPtr<Int> srctCol(rec, "SRCTYPE");
     235    // try to auto-identify if it is on or off.
     236    Regex rx(".*_[e|w|R]$");
     237    Regex rx2("_[e|w|R|S]$");
     238    Int match = srcName.matches(rx);
     239    if (match) {
     240      *srcnCol = srcName;
     241    } else {
     242      *srcnCol = srcName.before(rx2);
     243    }
     244    //*srcnCol = srcName;//.before(rx2);
     245    *srctCol = match;
     246    RecordFieldPtr<uInt> beamCol(rec, "BEAMNO");
     247    *beamCol = beamNo-beamOffset_-1;
     248    RecordFieldPtr<Int> rbCol(rec, "REFBEAMNO");
     249    Int rb = -1;
     250    if (nBeam_ > 1 ) rb = refBeam-1;
     251    *rbCol = rb;
     252    RecordFieldPtr<uInt> ifCol(rec, "IFNO");
     253    *ifCol = IFno-ifOffset_- 1;
     254    uInt id;
     255    /// @todo this has to change when nchan isn't global anymore
     256    id = table_->frequencies().addEntry(Double(header_->nchan/2),
     257                                            refFreq, freqInc);
     258    RecordFieldPtr<uInt> mfreqidCol(rec, "FREQ_ID");
     259    *mfreqidCol = id;
     260
     261    id = table_->molecules().addEntry(restFreq);
     262    RecordFieldPtr<uInt> molidCol(rec, "MOLECULE_ID");
     263    *molidCol = id;
     264
     265    id = table_->tcal().addEntry(tcalTime, tcal);
     266    RecordFieldPtr<uInt> mcalidCol(rec, "TCAL_ID");
     267    *mcalidCol = id;
     268    id = table_->weather().addEntry(temperature, pressure, humidity,
     269                                    windSpeed, windAz);
     270    RecordFieldPtr<uInt> mweatheridCol(rec, "WEATHER_ID");
     271    *mweatheridCol = id;
     272    RecordFieldPtr<uInt> mfocusidCol(rec, "FOCUS_ID");
     273    id = table_->focus().addEntry(focusAxi, focusTan, focusRot);
     274    *mfocusidCol = id;
     275    RecordFieldPtr<Array<Double> > dirCol(rec, "DIRECTION");
     276    *dirCol = direction;
     277    RecordFieldPtr<Double> azCol(rec, "AZIMUTH");
     278    *azCol = azimuth;
     279    RecordFieldPtr<Double> elCol(rec, "ELEVATION");
     280    *elCol = elevation;
     281
     282    RecordFieldPtr<Float> parCol(rec, "PARANGLE");
     283    *parCol = parAngle;
     284
     285    RecordFieldPtr< Array<Float> > specCol(rec, "SPECTRA");
     286    RecordFieldPtr< Array<uChar> > flagCol(rec, "FLAGTRA");
     287    RecordFieldPtr< uInt > polnoCol(rec, "POLNO");
     288
     289    RecordFieldPtr< Array<Float> > tsysCol(rec, "TSYS");
     290    // Turn the (nchan,npol) matrix and possible complex xPol vector
     291    // into 2-4 rows in the scantable
     292    Vector<Float> tsysvec(1);
     293    // Why is spectra.ncolumn() == 3 for haveXPol_ == True
     294    uInt npol = (spectra.ncolumn()==1 ? 1: 2);
     295    for ( uInt i=0; i< npol; ++i ) {
     296      tsysvec = tsys(i);
     297      *tsysCol = tsysvec;
     298      *polnoCol = i;
     299
     300      *specCol = spectra.column(i);
     301      *flagCol = flagtra.column(i);
     302      table_->table().addRow();
     303      row.put(table_->table().nrow()-1, rec);
     304    }
     305    if ( haveXPol_ ) {
     306      // no tsys given for xpol, so emulate it
     307      tsysvec = sqrt(tsys[0]*tsys[1]);
     308      *tsysCol = tsysvec;
     309      // add real part of cross pol
     310      *polnoCol = 2;
     311      Vector<Float> r(real(xPol));
     312      *specCol = r;
     313      // make up flags from linears
     314      /// @fixme this has to be a bitwise or of both pols
     315      *flagCol = flagtra.column(0);// | flagtra.column(1);
     316      table_->table().addRow();
     317      row.put(table_->table().nrow()-1, rec);
     318      // ad imaginary part of cross pol
     319      *polnoCol = 3;
     320      Vector<Float> im(imag(xPol));
     321      *specCol = im;
     322      table_->table().addRow();
     323      row.put(table_->table().nrow()-1, rec);
     324    }
     325  }
     326  if (status > 0) {
     327    close();
     328    throw(AipsError("Reading error occured, data possibly corrupted."));
     329  }
     330
    323331  return status;
    324332}
     333
     334}//namespace asap
  • trunk/src/STFiller.h

    r804 r805  
    1 //#---------------------------------------------------------------------------
    2 //# SDReader.h: A class to read single dish spectra from SDFITS, RPFITS
    3 //#---------------------------------------------------------------------------
    4 //# Copyright (C) 2004
    5 //# ATNF
    6 //#
    7 //# This program is free software; you can redistribute it and/or modify it
    8 //# under the terms of the GNU General Public License as published by the Free
    9 //# Software Foundation; either version 2 of the License, or (at your option)
    10 //# any later version.
    11 //#
    12 //# This program is distributed in the hope that it will be useful, but
    13 //# WITHOUT ANY WARRANTY; without even the implied warranty of
    14 //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
    15 //# Public License for more details.
    16 //#
    17 //# You should have received a copy of the GNU General Public License along
    18 //# with this program; if not, write to the Free Software Foundation, Inc.,
    19 //# 675 Massachusetts Ave, Cambridge, MA 02139, USA.
    20 //#
    21 //# Correspondence concerning this software should be addressed as follows:
    22 //#        Internet email: Malte.Marquarding@csiro.au
    23 //#        Postal address: Malte Marquarding,
    24 //#                        Australia Telescope National Facility,
    25 //#                        P.O. Box 76,
    26 //#                        Epping, NSW, 2121,
    27 //#                        AUSTRALIA
    28 //#
    29 //# $Id:
    30 //#---------------------------------------------------------------------------
    31 #ifndef SDREADER_H
    32 #define SDREADER_H
     1//
     2// C++ Interface: STFiller
     3//
     4// Description:
     5//
     6//
     7// Author: Malte Marquarding <asap@atnf.csiro.au>, (C) 2006
     8//
     9// Copyright: See COPYING file that comes with this distribution
     10//
     11//
     12#ifndef STFILLER_H
     13#define STFILLER_H
    3314
    3415#include <vector>
     
    4122#include <casa/Arrays/Vector.h>
    4223
    43 #include "SDMemTable.h"
     24#include "Scantable.h"
    4425#include "SDContainer.h"
    4526#include "SDLog.h"
     
    4930namespace asap {
    5031
    51 class SDReader : public SDLog {
     32/**
     33This class fills a Scantable from external data formats using the PKSReader class.
     34
     35@author   Malte Marquarding
     36@date     2006/01/16
     37@version  2.0a
     38*/
     39class STFiller : public SDLog {
    5240public:
    53   SDReader();
    54   SDReader(const std::string& filename,
    55            int whichIF=-1, int whichBeam=-1);
    56   SDReader(casa::CountedPtr<SDMemTable> tbl);
    57   virtual ~SDReader();
    5841
    59   void open(const std::string& filename,
    60             int whichIF=-1,
    61             int whichBeam=-1);
    62   void close();
    63   int read(const std::vector<int>& seq);
     42  STFiller();
    6443
    65   casa::CountedPtr<SDMemTable> getTable() const { return table_;}
    66 
    67   void reset();
    68 
    69   std::vector<int> pseudoHeader() const {
    70     std::vector<int> v;
    71     v.push_back(nBeam_);v.push_back(nIF_);
    72     v.push_back(nPol_);v.push_back(nChan_);
    73     return v;
    74   }
     44  STFiller(casa::CountedPtr< Scantable > stbl);
    7545
    7646
    77 protected:
    78  
     47  /**
     48    * A constructor for a filler with associated input file
     49    * @param filename the input file (rpf,sdfite or ms)
     50    * @param whichIF read a specific IF only (default -1 means all IFs)
     51    * @param whichBeam read a specific beam only (default -1 means all beams)
     52    */
     53  STFiller( const std::string& filename, int whichIF=-1,
     54                  int whichBeam=-1 );
     55
     56  ~STFiller();
     57
     58  /**
     59   * associate the Filler with a file on disk
     60   * @param filename the input file (rpf,sdfite or ms)
     61   * @param whichIF read a specific IF only (default -1 means all IFs)
     62   * @param whichBeam read a specific beam only (default -1 means all beams)
     63   * @exception AipsError Creation of PKSreader failed
     64   */
     65  void open( const std::string& filename, int whichIF=-1, int whichBeam=-1 );
     66
     67  /**
     68   * detatch from file
     69   */
     70  void close( );
     71
     72  /**
     73   * Read in "rows" from the source file attached with open()
     74   * @return a status flag passed on by PKSreader
     75   */
     76  int read( );
     77
     78  casa::CountedPtr<Scantable> getTable() const { return table_;}
     79
    7980private:
    80   casa::Int nBeam_,nIF_,nPol_,nChan_;
    81   PKSreader* reader_; 
     81
     82  PKSreader* reader_;
    8283  SDHeader* header_;
    83   SDFrequencyTable* frequencies_;
    84   casa::CountedPtr<SDMemTable> table_;
    8584  casa::String filename_;
    86   casa::uInt cursor_;
    87   casa::Double timestamp_;
    88   casa::uInt beamOffset_, ifOffset_;
     85  casa::CountedPtr< Scantable > table_;
     86  casa::Int nIF_, nBeam_, nPol_, nChan_;
     87  casa::uInt ifOffset_, beamOffset_;
    8988  casa::Bool haveXPol_;
    9089};
    9190
    92 }// namespace
     91} // namespace
     92
    9393#endif
  • trunk/src/STMath.cpp

    r804 r805  
    1 //#---------------------------------------------------------------------------
    2 //# SDMath.cc: A collection of single dish mathematical operations
    3 //#---------------------------------------------------------------------------
    4 //# Copyright (C) 2004
    5 //# ATNF
    6 //#
    7 //# This program is free software; you can redistribute it and/or modify it
    8 //# under the terms of the GNU General Public License as published by the Free
    9 //# Software Foundation; either version 2 of the License, or (at your option)
    10 //# any later version.
    11 //#
    12 //# This program is distributed in the hope that it will be useful, but
    13 //# WITHOUT ANY WARRANTY; without even the implied warranty of
    14 //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
    15 //# Public License for more details.
    16 //#
    17 //# You should have received a copy of the GNU General Public License along
    18 //# with this program; if not, write to the Free Software Foundation, Inc.,
    19 //# 675 Massachusetts Ave, Cambridge, MA 02139, USA.
    20 //#
    21 //# Correspondence concerning this software should be addressed as follows:
    22 //#        Internet email: Malte.Marquarding@csiro.au
    23 //#        Postal address: Malte Marquarding,
    24 //#                        Australia Telescope National Facility,
    25 //#                        P.O. Box 76,
    26 //#                        Epping, NSW, 2121,
    27 //#                        AUSTRALIA
    28 //#
    29 //# $Id:
    30 //#---------------------------------------------------------------------------
    31 #include <vector>
    32 
    33 
    34 #include <casa/aips.h>
    35 #include <casa/iostream.h>
    36 #include <casa/sstream.h>
     1//
     2// C++ Implementation: STMath
     3//
     4// Description:
     5//
     6//
     7// Author: Malte Marquarding <asap@atnf.csiro.au>, (C) 2006
     8//
     9// Copyright: See COPYING file that comes with this distribution
     10//
     11//
     12
    3713#include <casa/iomanip.h>
     14#include <casa/Exceptions/Error.h>
     15#include <casa/Containers/Block.h>
    3816#include <casa/BasicSL/String.h>
    39 #include <casa/Arrays/IPosition.h>
    40 #include <casa/Arrays/Array.h>
    41 #include <casa/Arrays/ArrayIter.h>
    42 #include <casa/Arrays/VectorIter.h>
     17#include <tables/Tables/TableIter.h>
     18#include <tables/Tables/TableCopy.h>
     19#include <casa/Arrays/MaskArrLogi.h>
     20#include <casa/Arrays/MaskArrMath.h>
     21#include <casa/Arrays/ArrayLogical.h>
    4322#include <casa/Arrays/ArrayMath.h>
    44 #include <casa/Arrays/ArrayLogical.h>
    45 #include <casa/Arrays/MaskedArray.h>
    46 #include <casa/Arrays/MaskArrMath.h>
    47 #include <casa/Arrays/MaskArrLogi.h>
    48 #include <casa/Arrays/Matrix.h>
    49 #include <casa/BasicMath/Math.h>
    50 #include <casa/Exceptions.h>
    51 #include <casa/Quanta/Quantum.h>
    52 #include <casa/Quanta/Unit.h>
    53 #include <casa/Quanta/MVEpoch.h>
    54 #include <casa/Quanta/MVTime.h>
    55 #include <casa/Utilities/Assert.h>
    56 
    57 #include <coordinates/Coordinates/SpectralCoordinate.h>
    58 #include <coordinates/Coordinates/CoordinateSystem.h>
    59 #include <coordinates/Coordinates/CoordinateUtil.h>
    60 #include <coordinates/Coordinates/FrequencyAligner.h>
     23#include <casa/Containers/RecordField.h>
     24#include <tables/Tables/TableRow.h>
     25#include <tables/Tables/TableVector.h>
     26#include <tables/Tables/ExprNode.h>
     27#include <tables/Tables/TableRecord.h>
     28#include <tables/Tables/ReadAsciiTable.h>
    6129
    6230#include <lattices/Lattices/LatticeUtilities.h>
    63 #include <lattices/Lattices/RebinLattice.h>
    64 
    65 #include <measures/Measures/MEpoch.h>
    66 #include <measures/Measures/MDirection.h>
    67 #include <measures/Measures/MPosition.h>
    6831
    6932#include <scimath/Mathematics/VectorKernel.h>
    7033#include <scimath/Mathematics/Convolver.h>
    71 #include <scimath/Mathematics/InterpolateArray1D.h>
    7234#include <scimath/Functionals/Polynomial.h>
    7335
    74 #include <tables/Tables/Table.h>
    75 #include <tables/Tables/ScalarColumn.h>
    76 #include <tables/Tables/ArrayColumn.h>
    77 #include <tables/Tables/ReadAsciiTable.h>
    78 
    7936#include "MathUtils.h"
    80 #include "SDDefs.h"
     37#include "RowAccumulator.h"
    8138#include "SDAttr.h"
    82 #include "SDContainer.h"
    83 #include "SDMemTable.h"
    84 
    85 #include "SDMath.h"
    86 #include "SDPol.h"
     39#include "STMath.h"
    8740
    8841using namespace casa;
     42
    8943using namespace asap;
    9044
    91 
    92 SDMath::SDMath()
    93 {
    94 }
    95 
    96 SDMath::SDMath(const SDMath& other)
    97 {
    98 
    99 // No state
    100 
    101 }
    102 
    103 SDMath& SDMath::operator=(const SDMath& other)
    104 {
    105   if (this != &other) {
    106 // No state
    107   }
    108   return *this;
    109 }
    110 
    111 SDMath::~SDMath()
    112 {;}
    113 
    114 
    115 SDMemTable* SDMath::frequencyAlignment(const SDMemTable& in,
    116                                        const String& refTime,
    117                                        const String& method,
    118                                        Bool perFreqID)
    119 {
    120   // Get frame info from Table
    121    std::vector<std::string> info = in.getCoordInfo();
    122 
    123    // Parse frequency system
    124    String systemStr(info[1]);
    125    String baseSystemStr(info[3]);
    126    if (baseSystemStr==systemStr) {
    127      throw(AipsError("You have not set a frequency frame different from the initial - use function set_freqframe"));
    128    }
    129 
    130    MFrequency::Types freqSystem;
    131    MFrequency::getType(freqSystem, systemStr);
    132 
    133    return frequencyAlign(in, freqSystem, refTime, method, perFreqID);
    134 }
    135 
    136 
    137 
    138 CountedPtr<SDMemTable>
    139 SDMath::average(const std::vector<CountedPtr<SDMemTable> >& in,
    140                 const Vector<Bool>& mask, Bool scanAv,
    141                 const String& weightStr, Bool alignFreq)
    142 // Weighted averaging of spectra from one or more Tables.
    143 {
    144   // Convert weight type
    145   WeightType wtType = NONE;
    146   convertWeightString(wtType, weightStr, True);
    147 
    148   // Create output Table by cloning from the first table
    149   SDMemTable* pTabOut = new SDMemTable(*in[0],True);
    150   if (in.size() > 1) {
    151     for (uInt i=1; i < in.size(); ++i) {
    152       pTabOut->appendToHistoryTable(in[i]->getHistoryTable());
    153     }
    154   }
    155   // Setup
    156   IPosition shp = in[0]->rowAsMaskedArray(0).shape();      // Must not change
    157   Array<Float> arr(shp);
    158   Array<Bool> barr(shp);
    159   const Bool useMask = (mask.nelements() == shp(asap::ChanAxis));
    160 
    161   // Columns from Tables
    162   ROArrayColumn<Float> tSysCol;
    163   ROScalarColumn<Double> mjdCol;
    164   ROScalarColumn<String> srcNameCol;
    165   ROScalarColumn<Double> intCol;
    166   ROArrayColumn<uInt> fqIDCol;
     45STMath::STMath(bool insitu) :
     46  insitu_(insitu)
     47{
     48}
     49
     50
     51STMath::~STMath()
     52{
     53}
     54
     55CountedPtr<Scantable>
     56STMath::average( const std::vector<CountedPtr<Scantable> >& in,
     57                 const Vector<Bool>& mask,
     58                 const std::string& weight,
     59                 const std::string& avmode,
     60                 bool alignfreq)
     61{
     62  if ( avmode == "SCAN" && in.size() != 1 )
     63    throw(AipsError("Can't perform 'SCAN' averaging on multiple tables"));
     64  WeightType wtype = stringToWeight(weight);
     65  // output
     66  // clone as this is non insitu
     67  bool insitu = insitu_;
     68  setInsitu(false);
     69  CountedPtr< Scantable > out = getScantable(in[0], true);
     70  setInsitu(insitu);
     71
     72  Table& tout = out->table();
     73
     74  /// @todo check if all scantables are conformant
     75
     76  ArrayColumn<Float> specColOut(tout,"SPECTRA");
     77  ArrayColumn<uChar> flagColOut(tout,"FLAGTRA");
     78  ArrayColumn<Float> tsysColOut(tout,"TSYS");
     79  ScalarColumn<Double> mjdColOut(tout,"TIME");
     80  ScalarColumn<Double> intColOut(tout,"INTERVAL");
     81
     82  // set up the output table rows. These are based on the structure of the
     83  // FIRST scantabel in the vector
     84  const Table& baset = in[0]->table();
     85
     86  Block<String> cols(3);
     87  cols[0] = String("BEAMNO");
     88  cols[1] = String("IFNO");
     89  cols[2] = String("POLNO");
     90  if ( avmode == "SOURCE" ) {
     91    cols.resize(4);
     92    cols[3] = String("SRCNAME");
     93  }
     94  if ( avmode == "SCAN"  && in.size() == 1) {
     95    cols.resize(4);
     96    cols[3] = String("SCANNO");
     97  }
     98  uInt outrowCount = 0;
     99  TableIterator iter(baset, cols);
     100  while (!iter.pastEnd()) {
     101    Table subt = iter.table();
     102    // copy the first row of this selection into the new table
     103    tout.addRow();
     104    TableCopy::copyRows(tout, subt, outrowCount, 0, 1);
     105    ++outrowCount;
     106    ++iter;
     107  }
     108  RowAccumulator acc(wtype);
     109  acc.setUserMask(mask);
     110  ROTableRow row(tout);
     111  ROArrayColumn<Float> specCol, tsysCol;
     112  ROArrayColumn<uChar> flagCol;
     113  ROScalarColumn<Double> mjdCol, intCol;
    167114  ROScalarColumn<Int> scanIDCol;
    168115
    169   // Create accumulation MaskedArray. We accumulate for each
    170   // channel,if,pol,beam Note that the mask of the accumulation array
    171   // will ALWAYS remain ALL True.  The MA is only used so that when
    172   // data which is masked Bad is added to it, that data does not
    173   // contribute.
    174 
    175   Array<Float> zero(shp);
    176   zero=0.0;
    177   Array<Bool> good(shp);
    178   good = True;
    179   MaskedArray<Float> sum(zero,good);
    180 
    181   // Counter arrays
    182   Array<Float> nPts(shp);             // Number of points
    183   nPts = 0.0;
    184   Array<Float> nInc(shp);             // Increment
    185   nInc = 1.0;
    186 
    187   // Create accumulation Array for variance. We accumulate for each
    188   // if,pol,beam, but average over channel.  So we need a shape with
    189   // one less axis dropping channels.
    190   const uInt nAxesSub = shp.nelements() - 1;
    191   IPosition shp2(nAxesSub);
    192   for (uInt i=0,j=0; i<(nAxesSub+1); i++) {
    193      if (i!=asap::ChanAxis) {
    194        shp2(j) = shp(i);
    195        j++;
    196      }
    197   }
    198   Array<Float> sumSq(shp2);
    199   sumSq = 0.0;
    200   IPosition pos2(nAxesSub,0);                        // For indexing
    201 
    202   // Time-related accumulators
    203   Double time;
    204   Double timeSum = 0.0;
    205   Double intSum = 0.0;
    206   Double interval = 0.0;
    207 
    208   // To get the right shape for the Tsys accumulator we need to access
    209   // a column from the first table.  The shape of this array must not
    210   // change.  Note however that since the TSysSqSum array is used in a
    211   // normalization process, and that I ignore the channel axis
    212   // replication of values for now, it loses a dimension
    213 
    214   Array<Float> tSysSum, tSysSqSum;
    215   {
    216     const Table& tabIn = in[0]->table();
    217     tSysCol.attach(tabIn,"TSYS");
    218     tSysSum.resize(tSysCol.shape(0));
    219     tSysSqSum.resize(shp2);
    220   }
    221   tSysSum = 0.0;
    222   tSysSqSum = 0.0;
    223   Array<Float> tSys;
    224 
    225   // Scan and row tracking
    226   Int oldScanID = 0;
    227   Int outScanID = 0;
    228   Int scanID = 0;
    229   Int rowStart = 0;
    230   Int nAccum = 0;
    231   Int tableStart = 0;
    232 
    233   // Source and FreqID
    234   String sourceName, oldSourceName, sourceNameStart;
    235   Vector<uInt> freqID, freqIDStart, oldFreqID;
    236 
    237   // Loop over tables
    238   Float fac = 1.0;
    239   const uInt nTables = in.size();
    240   for (uInt iTab=0; iTab<nTables; iTab++) {
    241 
    242     // Should check that the frequency tables don't change if doing
    243     // FreqAlignment
    244 
    245     // Attach columns to Table
    246      const Table& tabIn = in[iTab]->table();
    247      tSysCol.attach(tabIn, "TSYS");
    248      mjdCol.attach(tabIn, "TIME");
    249      srcNameCol.attach(tabIn, "SRCNAME");
    250      intCol.attach(tabIn, "INTERVAL");
    251      fqIDCol.attach(tabIn, "FREQID");
    252      scanIDCol.attach(tabIn, "SCANID");
    253 
    254      // Loop over rows in Table
    255      const uInt nRows = in[iTab]->nRow();
    256      for (uInt iRow=0; iRow<nRows; iRow++) {
    257        // Check conformance
    258         IPosition shp2 = in[iTab]->rowAsMaskedArray(iRow).shape();
    259         if (!shp.isEqual(shp2)) {
    260           delete pTabOut;
    261            throw (AipsError("Shapes for all rows must be the same"));
     116  for (uInt i=0; i < tout.nrow(); ++i) {
     117    for ( int j=0; j < in.size(); ++j ) {
     118      const Table& tin = in[j]->table();
     119      const TableRecord& rec = row.get(i);
     120      ROScalarColumn<Double> tmp(tin, "TIME");
     121      Double td;tmp.get(0,td);
     122      Table basesubt = tin(tin.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
     123                       && tin.col("IFNO") == Int(rec.asuInt("IFNO"))
     124                       && tin.col("POLNO") == Int(rec.asuInt("POLNO")) );
     125      Table subt;
     126      if ( avmode == "SOURCE") {
     127        subt = basesubt( basesubt.col("SRCNAME") == rec.asString("SRCNAME") );
     128      } else if (avmode == "SCAN") {
     129        subt = basesubt( basesubt.col("SCANNO") == Int(rec.asuInt("SCANNO")) );
     130      } else {
     131        subt = basesubt;
     132      }
     133      specCol.attach(subt,"SPECTRA");
     134      flagCol.attach(subt,"FLAGTRA");
     135      tsysCol.attach(subt,"TSYS");
     136      intCol.attach(subt,"INTERVAL");
     137      mjdCol.attach(subt,"TIME");
     138      Vector<Float> spec,tsys;
     139      Vector<uChar> flag;
     140      Double inter,time;
     141      for (uInt k = 0; k < subt.nrow(); ++k ) {
     142        flagCol.get(k, flag);
     143        Vector<Bool> bflag(flag.shape());
     144        convertArray(bflag, flag);
     145        if ( allEQ(bflag, True) ) {
     146          continue;//don't accumulate
    262147        }
    263 
    264         // If we are not doing scan averages, make checks for source
    265         // and frequency setup and warn if averaging across them
    266         scanIDCol.getScalar(iRow, scanID);
    267 
    268         // Get quantities from columns
    269         srcNameCol.getScalar(iRow, sourceName);
    270         mjdCol.get(iRow, time);
    271         tSysCol.get(iRow, tSys);
    272         intCol.get(iRow, interval);
    273         fqIDCol.get(iRow, freqID);
    274 
    275         // Initialize first source and freqID
    276         if (iRow==0 && iTab==0) {
    277           sourceNameStart = sourceName;
    278           freqIDStart = freqID;
    279         }
    280 
    281         // If we are doing scan averages, see if we are at the end of
    282         // an accumulation period (scan).  We must check soutce names
    283         // too, since we might have two tables with one scan each but
    284         // different source names; we shouldn't average different
    285         // sources together
    286         if (scanAv && ( (scanID != oldScanID)  ||
    287                         (iRow==0 && iTab>0 && sourceName!=oldSourceName))) {
    288 
    289           // Normalize data in 'sum' accumulation array according to
    290           // weighting scheme
    291            normalize(sum, sumSq, tSysSqSum, nPts, intSum, wtType,
    292                      asap::ChanAxis, nAxesSub);
    293 
    294            // Get ScanContainer for the first row of this averaged Scan
    295            SDContainer scOut = in[iTab]->getSDContainer(rowStart);
    296 
    297            // Fill scan container. The source and freqID come from the
    298            // first row of the first table that went into this average
    299            // ( should be the same for all rows in the scan average)
    300 
    301            Float nR(nAccum);
    302            fillSDC(scOut, sum.getMask(), sum.getArray(), tSysSum/nR, outScanID,
    303                    timeSum/nR, intSum, sourceNameStart, freqIDStart);
    304 
    305            // Write container out to Table
    306            pTabOut->putSDContainer(scOut);
    307 
    308            // Reset accumulators
    309            sum = 0.0;
    310            sumSq = 0.0;
    311            nAccum = 0;
    312 
    313            tSysSum =0.0;
    314            tSysSqSum =0.0;
    315            timeSum = 0.0;
    316            intSum = 0.0;
    317            nPts = 0.0;
    318 
    319            // Increment
    320            rowStart = iRow;              // First row for next accumulation
    321            tableStart = iTab;            // First table for next accumulation
    322            sourceNameStart = sourceName; // First source name for next
    323                                          // accumulation
    324            freqIDStart = freqID;         // First FreqID for next accumulation
    325 
    326            oldScanID = scanID;
    327            outScanID += 1;               // Scan ID for next
    328                                          // accumulation period
    329         }
    330 
    331         // Accumulate
    332         accumulate(timeSum, intSum, nAccum, sum, sumSq, nPts,
    333                    tSysSum, tSysSqSum, tSys,
    334                    nInc, mask, time, interval, in, iTab, iRow, asap::ChanAxis,
    335                    nAxesSub, useMask, wtType);
    336         oldSourceName = sourceName;
    337         oldFreqID = freqID;
    338      }
    339   }
    340 
    341   // OK at this point we have accumulation data which is either
    342   //   - accumulated from all tables into one row
    343   // or
    344   //   - accumulated from the last scan average
    345   //
    346   // Normalize data in 'sum' accumulation array according to weighting
    347   // scheme
    348 
    349   normalize(sum, sumSq, tSysSqSum, nPts, intSum, wtType,
    350             asap::ChanAxis, nAxesSub);
    351 
    352   // Create and fill container.  The container we clone will be from
    353   // the last Table and the first row that went into the current
    354   // accumulation.  It probably doesn't matter that much really...
    355   Float nR(nAccum);
    356   SDContainer scOut = in[tableStart]->getSDContainer(rowStart);
    357   fillSDC(scOut, sum.getMask(), sum.getArray(), tSysSum/nR, outScanID,
    358           timeSum/nR, intSum, sourceNameStart, freqIDStart);
    359   pTabOut->putSDContainer(scOut);
    360   pTabOut->resetCursor();
    361 
    362   return CountedPtr<SDMemTable>(pTabOut);
    363 }
    364 
    365 
    366 
    367 CountedPtr<SDMemTable>
    368 SDMath::binaryOperate(const CountedPtr<SDMemTable>& left,
    369                       const CountedPtr<SDMemTable>& right,
    370                       const String& op, Bool preserve, Bool doTSys)
    371 {
    372 
    373   // Check operator
    374   String op2(op);
    375   op2.upcase();
    376   uInt what = 0;
    377   if (op2=="ADD") {
    378      what = 0;
    379   } else if (op2=="SUB") {
    380      what = 1;
    381   } else if (op2=="MUL") {
    382      what = 2;
    383   } else if (op2=="DIV") {
    384      what = 3;
    385   } else if (op2=="QUOTIENT") {
    386      what = 4;
    387      doTSys = True;
    388   } else {
    389     throw( AipsError("Unrecognized operation"));
    390   }
    391 
    392   // Check rows
    393   const uInt nRowLeft = left->nRow();
    394   const uInt nRowRight = right->nRow();
    395   Bool ok = (nRowRight==1 && nRowLeft>0) ||
    396             (nRowRight>=1 && nRowLeft==nRowRight);
    397   if (!ok) {
    398      throw (AipsError("The right Scan Table can have one row or the same number of rows as the left Scan Table"));
    399   }
    400 
    401   // Input Tables
    402   const Table& tLeft = left->table();
    403   const Table& tRight = right->table();
    404 
    405   // TSys columns
    406   ROArrayColumn<Float> tSysLeftCol, tSysRightCol;
    407   if (doTSys) {
    408     tSysLeftCol.attach(tLeft, "TSYS");
    409     tSysRightCol.attach(tRight, "TSYS");
    410   }
    411 
    412   // First row for right
    413   Array<Float> tSysLeftArr, tSysRightArr;
    414   if (doTSys) tSysRightCol.get(0, tSysRightArr);
    415   MaskedArray<Float>* pMRight =
    416     new MaskedArray<Float>(right->rowAsMaskedArray(0));
    417 
    418   IPosition shpRight = pMRight->shape();
    419 
    420   // Output Table cloned from left
    421   SDMemTable* pTabOut = new SDMemTable(*left, True);
    422   pTabOut->appendToHistoryTable(right->getHistoryTable());
    423 
    424   // Loop over rows
    425   for (uInt i=0; i<nRowLeft; i++) {
    426 
    427     // Get data
    428     MaskedArray<Float> mLeft(left->rowAsMaskedArray(i));
    429     IPosition shpLeft = mLeft.shape();
    430     if (doTSys) tSysLeftCol.get(i, tSysLeftArr);
    431 
    432     if (nRowRight>1) {
    433       delete pMRight;
    434       pMRight = new MaskedArray<Float>(right->rowAsMaskedArray(i));
    435       shpRight = pMRight->shape();
    436       if (doTSys) tSysRightCol.get(i, tSysRightArr);
    437     }
    438 
    439     if (!shpRight.isEqual(shpLeft)) {
    440       delete pTabOut;
    441       delete pMRight;
    442       throw(AipsError("left and right scan tables are not conformant"));
    443     }
    444     if (doTSys) {
    445       if (!tSysRightArr.shape().isEqual(tSysRightArr.shape())) {
    446         delete pTabOut;
    447         delete pMRight;
    448         throw(AipsError("left and right Tsys data are not conformant"));
     148        specCol.get(k, spec);
     149        tsysCol.get(k, tsys);
     150        intCol.get(k, inter);
     151        mjdCol.get(k, time);
     152        // spectrum has to be added last to enable weighting by the other values
     153        acc.add(spec, !bflag, tsys, inter, time);
    449154      }
    450       if (!shpRight.isEqual(tSysRightArr.shape())) {
    451         delete pTabOut;
    452         delete pMRight;
    453         throw(AipsError("left and right scan tables are not conformant"));
     155    }
     156    //write out
     157    specColOut.put(i, acc.getSpectrum());
     158    const Vector<Bool>& msk = acc.getMask();
     159    Vector<uChar> flg(msk.shape());
     160    convertArray(flg, !msk);
     161    flagColOut.put(i, flg);
     162    tsysColOut.put(i, acc.getTsys());
     163    intColOut.put(i, acc.getInterval());
     164    mjdColOut.put(i, acc.getTime());
     165    acc.reset();
     166  }
     167  return out;
     168}
     169
     170CountedPtr< Scantable > STMath::getScantable(const CountedPtr< Scantable >& in,
     171                                             bool droprows)
     172{
     173  if (insitu_) return in;
     174  else {
     175    // clone
     176    Scantable* tabp = new Scantable(*in, Bool(droprows));
     177    return CountedPtr<Scantable>(tabp);
     178  }
     179}
     180
     181CountedPtr< Scantable > STMath::unaryOperate( const CountedPtr< Scantable >& in,
     182                                              float val,
     183                                              const std::string& mode,
     184                                              bool tsys )
     185{
     186  // modes are "ADD" and "MUL"
     187  CountedPtr< Scantable > out = getScantable(in, false);
     188  Table& tab = out->table();
     189  ArrayColumn<Float> specCol(tab,"SPECTRA");
     190  ArrayColumn<Float> tsysCol(tab,"TSYS");
     191  for (uInt i=0; i<tab.nrow(); ++i) {
     192    Vector<Float> spec;
     193    Vector<Float> ts;
     194    specCol.get(i, spec);
     195    tsysCol.get(i, ts);
     196    if (mode == "MUL") {
     197      spec *= val;
     198      specCol.put(i, spec);
     199      if ( tsys ) {
     200        ts *= val;
     201        tsysCol.put(i, ts);
    454202      }
    455     }
    456 
    457     // Make container
    458      SDContainer sc = left->getSDContainer(i);
    459 
    460      // Operate on data and TSys
    461      if (what==0) {
    462         MaskedArray<Float> tmp = mLeft + *pMRight;
    463         putDataInSDC(sc, tmp.getArray(), tmp.getMask());
    464         if (doTSys) sc.putTsys(tSysLeftArr+tSysRightArr);
    465      } else if (what==1) {
    466         MaskedArray<Float> tmp = mLeft - *pMRight;
    467         putDataInSDC(sc, tmp.getArray(), tmp.getMask());
    468         if (doTSys) sc.putTsys(tSysLeftArr-tSysRightArr);
    469      } else if (what==2) {
    470         MaskedArray<Float> tmp = mLeft * *pMRight;
    471         putDataInSDC(sc, tmp.getArray(), tmp.getMask());
    472         if (doTSys) sc.putTsys(tSysLeftArr*tSysRightArr);
    473      } else if (what==3) {
    474         MaskedArray<Float> tmp = mLeft / *pMRight;
    475         putDataInSDC(sc, tmp.getArray(), tmp.getMask());
    476         if (doTSys) sc.putTsys(tSysLeftArr/tSysRightArr);
    477      } else if (what==4) {
    478        if (preserve) {
    479          MaskedArray<Float> tmp = (tSysRightArr * mLeft / *pMRight) -
    480            tSysRightArr;
    481          putDataInSDC(sc, tmp.getArray(), tmp.getMask());
    482        } else {
    483          MaskedArray<Float> tmp = (tSysRightArr * mLeft / *pMRight) -
    484            tSysLeftArr;
    485          putDataInSDC(sc, tmp.getArray(), tmp.getMask());
    486        }
    487        sc.putTsys(tSysRightArr);
    488      }
    489 
    490      // Put new row in output Table
    491      pTabOut->putSDContainer(sc);
    492   }
    493   if (pMRight) delete pMRight;
    494   pTabOut->resetCursor();
    495 
    496   return CountedPtr<SDMemTable>(pTabOut);
    497 }
    498 
    499 
    500 std::vector<float> SDMath::statistic(const CountedPtr<SDMemTable>& in,
    501                                      const Vector<Bool>& mask,
    502                                      const String& which, Int row) const
    503 //
    504 // Perhaps iteration over pol/beam/if should be in here
    505 // and inside the nrow iteration ?
    506 //
    507 {
    508   const uInt nRow = in->nRow();
    509 
    510 // Specify cursor location
    511 
    512   IPosition start, end;
    513   Bool doAll = False;
    514   setCursorSlice(start, end, doAll, *in);
    515 
    516 // Loop over rows
    517 
    518   const uInt nEl = mask.nelements();
    519   uInt iStart = 0;
    520   uInt iEnd = in->nRow()-1;
    521 //
    522   if (row>=0) {
    523      iStart = row;
    524      iEnd = row;
    525   }
    526 //
    527   std::vector<float> result(iEnd-iStart+1);
    528   for (uInt ii=iStart; ii <= iEnd; ++ii) {
    529 
    530 // Get row and deconstruct
    531 
    532      MaskedArray<Float> dataIn = (in->rowAsMaskedArray(ii))(start,end);
    533      Array<Float> v = dataIn.getArray().nonDegenerate();
    534      Array<Bool>  m = dataIn.getMask().nonDegenerate();
    535 
    536 // Access desired piece of data
    537 
    538 //     Array<Float> v((arr(start,end)).nonDegenerate());
    539 //     Array<Bool> m((barr(start,end)).nonDegenerate());
    540 
    541 // Apply OTF mask
    542 
    543      MaskedArray<Float> tmp;
    544      if (m.nelements()==nEl) {
    545        tmp.setData(v,m&&mask);
    546      } else {
    547        tmp.setData(v,m);
    548      }
    549 
    550 // Get statistic
    551 
    552      result[ii-iStart] = mathutil::statistics(which, tmp);
    553   }
    554 //
    555   return result;
    556 }
    557 
    558 
    559 SDMemTable* SDMath::bin(const SDMemTable& in, Int width)
    560 {
    561   SDHeader sh = in.getSDHeader();
    562   SDMemTable* pTabOut = new SDMemTable(in, True);
    563 
    564 // Bin up SpectralCoordinates
    565 
    566   IPosition factors(1);
    567   factors(0) = width;
    568   for (uInt j=0; j<in.nCoordinates(); ++j) {
    569     CoordinateSystem cSys;
    570     cSys.addCoordinate(in.getSpectralCoordinate(j));
    571     CoordinateSystem cSysBin =
    572       CoordinateUtil::makeBinnedCoordinateSystem(factors, cSys, False);
    573 //
    574     SpectralCoordinate sCBin = cSysBin.spectralCoordinate(0);
    575     pTabOut->setCoordinate(sCBin, j);
    576   }
    577 
    578 // Use RebinLattice to find shape
    579 
    580   IPosition shapeIn(1,sh.nchan);
    581   IPosition shapeOut = RebinLattice<Float>::rebinShape(shapeIn, factors);
    582   sh.nchan = shapeOut(0);
    583   pTabOut->putSDHeader(sh);
    584 
    585 // Loop over rows and bin along channel axis
    586 
    587   for (uInt i=0; i < in.nRow(); ++i) {
    588     SDContainer sc = in.getSDContainer(i);
    589 //
    590     Array<Float> tSys(sc.getTsys());                           // Get it out before sc changes shape
    591 
    592 // Bin up spectrum
    593 
    594     MaskedArray<Float> marr(in.rowAsMaskedArray(i));
    595     MaskedArray<Float> marrout;
    596     LatticeUtilities::bin(marrout, marr, asap::ChanAxis, width);
    597 
    598 // Put back the binned data and flags
    599 
    600     IPosition ip2 = marrout.shape();
    601     sc.resize(ip2);
    602 //
    603     putDataInSDC(sc, marrout.getArray(), marrout.getMask());
    604 
    605 // Bin up Tsys.
    606 
    607     Array<Bool> allGood(tSys.shape(),True);
    608     MaskedArray<Float> tSysIn(tSys, allGood, True);
    609 //
    610     MaskedArray<Float> tSysOut;
    611     LatticeUtilities::bin(tSysOut, tSysIn, asap::ChanAxis, width);
    612     sc.putTsys(tSysOut.getArray());
    613 //
    614     pTabOut->putSDContainer(sc);
    615   }
    616   return pTabOut;
    617 }
    618 
    619 SDMemTable* SDMath::resample(const SDMemTable& in, const String& methodStr,
    620                              Float width)
     203    } else if ( mode == "ADD" ) {
     204      spec += val;
     205      specCol.put(i, spec);
     206      if ( tsys ) {
     207        ts += val;
     208        tsysCol.put(i, ts);
     209      }
     210    }
     211  }
     212  return out;
     213}
     214
     215MaskedArray<Float> STMath::maskedArray( const Vector<Float>& s,
     216                                        const Vector<uChar>& f)
     217{
     218  Vector<Bool> mask;
     219  mask.resize(f.shape());
     220  convertArray(mask, f);
     221  return MaskedArray<Float>(s,!mask);
     222}
     223
     224Vector<uChar> STMath::flagsFromMA(const MaskedArray<Float>& ma)
     225{
     226  const Vector<Bool>& m = ma.getMask();
     227  Vector<uChar> flags(m.shape());
     228  convertArray(flags, !m);
     229  return flags;
     230}
     231
     232CountedPtr< Scantable > STMath::quotient( const CountedPtr< Scantable >& in,
     233                                          const std::string & mode,
     234                                          bool preserve )
     235{
     236  /// @todo make other modes available
     237  /// modes should be "nearest", "pair"
     238  // make this operation non insitu
     239  const Table& tin = in->table();
     240  Table ons = tin(tin.col("SRCTYPE") == Int(0));
     241  Table offs = tin(tin.col("SRCTYPE") == Int(1));
     242  if ( offs.nrow() == 0 )
     243    throw(AipsError("No 'off' scans present."));
     244  // put all "on" scans into output table
     245
     246  bool insitu = insitu_;
     247  setInsitu(false);
     248  CountedPtr< Scantable > out = getScantable(in, true);
     249  setInsitu(insitu);
     250  Table& tout = out->table();
     251
     252  TableCopy::copyRows(tout, ons);
     253  TableRow row(tout);
     254  ROScalarColumn<Double> offtimeCol(offs, "TIME");
     255
     256  ArrayColumn<Float> outspecCol(tout, "SPECTRA");
     257  ROArrayColumn<Float> outtsysCol(tout, "TSYS");
     258  ArrayColumn<uChar> outflagCol(tout, "FLAGTRA");
     259
     260  for (uInt i=0; i < tout.nrow(); ++i) {
     261    const TableRecord& rec = row.get(i);
     262    Double ontime = rec.asDouble("TIME");
     263    ROScalarColumn<Double> offtimeCol(offs, "TIME");
     264    Double mindeltat = min(abs(offtimeCol.getColumn() - ontime));
     265    Table sel = offs( abs(offs.col("TIME")-ontime) <= mindeltat
     266                       && offs.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
     267                       && offs.col("IFNO") == Int(rec.asuInt("IFNO"))
     268                       && offs.col("POLNO") == Int(rec.asuInt("POLNO")) );
     269
     270    TableRow offrow(sel);
     271    const TableRecord& offrec = offrow.get(0);//should only be one row
     272    RORecordFieldPtr< Array<Float> > specoff(offrec, "SPECTRA");
     273    RORecordFieldPtr< Array<Float> > tsysoff(offrec, "TSYS");
     274    RORecordFieldPtr< Array<uChar> > flagoff(offrec, "FLAGTRA");
     275    /// @fixme this assumes tsys is a scalar not vector
     276    Float tsysoffscalar = (*tsysoff)(IPosition(1,0));
     277    Vector<Float> specon, tsyson;
     278    outtsysCol.get(i, tsyson);
     279    outspecCol.get(i, specon);
     280    Vector<uChar> flagon;
     281    outflagCol.get(i, flagon);
     282    MaskedArray<Float> mon = maskedArray(specon, flagon);
     283    MaskedArray<Float> moff = maskedArray(*specoff, *flagoff);
     284    MaskedArray<Float> quot = (tsysoffscalar * mon / moff);
     285    if (preserve) {
     286      quot -= tsysoffscalar;
     287    } else {
     288      quot -= tsyson[0];
     289    }
     290    outspecCol.put(i, quot.getArray());
     291    outflagCol.put(i, flagsFromMA(quot));
     292  }
     293  return out;
     294}
     295
     296CountedPtr< Scantable > STMath::freqSwitch( const CountedPtr< Scantable >& in )
     297{
     298  // make copy or reference
     299  CountedPtr< Scantable > out = getScantable(in, false);
     300  Table& tout = out->table();
     301  Block<String> cols(3);
     302  cols[0] = String("SCANNO");
     303  cols[1] = String("BEAMNO");
     304  cols[2] = String("POLNO");
     305  TableIterator iter(tout, cols);
     306  while (!iter.pastEnd()) {
     307    Table subt = iter.table();
     308    // this should leave us with two rows for the two IFs....if not ignore
     309    if (subt.nrow() != 2 ) {
     310      continue;
     311    }
     312    ArrayColumn<Float> specCol(tout, "SPECTRA");
     313    ArrayColumn<Float> tsysCol(tout, "TSYS");
     314    ArrayColumn<uChar> flagCol(tout, "FLAGTRA");
     315    Vector<Float> onspec,offspec, ontsys, offtsys;
     316    Vector<uChar> onflag, offflag;
     317    tsysCol.get(0, ontsys);   tsysCol.get(1, offtsys);
     318    specCol.get(0, onspec);   specCol.get(1, offspec);
     319    flagCol.get(0, onflag);   flagCol.get(1, offflag);
     320    MaskedArray<Float> on  = maskedArray(onspec, onflag);
     321    MaskedArray<Float> off = maskedArray(offspec, offflag);
     322    MaskedArray<Float> oncopy = on.copy();
     323
     324    on /= off; on -= 1.0f;
     325    on *= ontsys[0];
     326    off /= oncopy; off -= 1.0f;
     327    off *= offtsys[0];
     328    specCol.put(0, on.getArray());
     329    const Vector<Bool>& m0 = on.getMask();
     330    Vector<uChar> flags0(m0.shape());
     331    convertArray(flags0, !m0);
     332    flagCol.put(0, flags0);
     333
     334    specCol.put(1, off.getArray());
     335    const Vector<Bool>& m1 = off.getMask();
     336    Vector<uChar> flags1(m1.shape());
     337    convertArray(flags1, !m1);
     338    flagCol.put(1, flags1);
     339
     340  }
     341
     342  return out;
     343}
     344
     345std::vector< float > STMath::statistic( const CountedPtr< Scantable > & in,
     346                                        const std::vector< bool > & mask,
     347                                        const std::string& which )
     348{
     349
     350  Vector<Bool> m(mask);
     351  const Table& tab = in->table();
     352  ROArrayColumn<Float> specCol(tab, "SPECTRA");
     353  ROArrayColumn<uChar> flagCol(tab, "FLAGTRA");
     354  std::vector<float> out;
     355  for (uInt i=0; i < tab.nrow(); ++i ) {
     356    Vector<Float> spec; specCol.get(i, spec);
     357    MaskedArray<Float> ma  = maskedArray(spec, flagCol(i));
     358    float outstat;
     359    if ( spec.nelements() == m.nelements() ) {
     360      outstat = mathutil::statistics(which, ma(m));
     361    } else {
     362      outstat = mathutil::statistics(which, ma);
     363    }
     364    out.push_back(outstat);
     365  }
     366  return out;
     367}
     368
     369CountedPtr< Scantable > STMath::bin( const CountedPtr< Scantable > & in,
     370                                     int width )
     371{
     372  if ( !in->selection().empty() ) throw(AipsError("Can't bin subset of the data."));
     373  CountedPtr< Scantable > out = getScantable(in, false);
     374  Table& tout = out->table();
     375  out->frequencies().rescale(width, "BIN");
     376  ArrayColumn<Float> specCol(tout, "SPECTRA");
     377  ArrayColumn<uChar> flagCol(tout, "FLAGTRA");
     378  for (uInt i=0; i < tout.nrow(); ++i ) {
     379    MaskedArray<Float> main  = maskedArray(specCol(i), flagCol(i));
     380    MaskedArray<Float> maout;
     381    LatticeUtilities::bin(maout, main, 0, Int(width));
     382    /// @todo implement channel based tsys binning
     383    specCol.put(i, maout.getArray());
     384    flagCol.put(i, flagsFromMA(maout));
     385    // take only the first binned spectrum's length for the deprecated
     386    // global header item nChan
     387    if (i==0) tout.rwKeywordSet().define(String("nChan"),
     388                                       Int(maout.getArray().nelements()));
     389  }
     390  return out;
     391}
     392
     393CountedPtr< Scantable > STMath::resample( const CountedPtr< Scantable >& in,
     394                                          const std::string& method,
     395                                          float width )
    621396//
    622397// Should add the possibility of width being specified in km/s. This means
     
    627402//
    628403{
    629    Bool doVel = False;
    630    if (doVel) {
    631       for (uInt j=0; j<in.nCoordinates(); ++j) {
    632          SpectralCoordinate sC = in.getSpectralCoordinate(j);
    633       }
    634    }
    635 
    636 // Interpolation method
    637 
    638404  InterpolateArray1D<Double,Float>::InterpolationMethod interp;
    639   convertInterpString(interp, methodStr);
    640   Int interpMethod(interp);
    641 
    642 // Make output table
    643 
    644   SDMemTable* pTabOut = new SDMemTable(in, True);
     405  Int interpMethod(stringToIMethod(method));
     406
     407  CountedPtr< Scantable > out = getScantable(in, false);
     408  Table& tout = out->table();
    645409
    646410// Resample SpectralCoordinates (one per freqID)
    647 
    648   const uInt nCoord = in.nCoordinates();
    649   Vector<Float> offset(1,0.0);
    650   Vector<Float> factors(1,1.0/width);
    651   Vector<Int> newShape;
    652   for (uInt j=0; j<in.nCoordinates(); ++j) {
    653     CoordinateSystem cSys;
    654     cSys.addCoordinate(in.getSpectralCoordinate(j));
    655     CoordinateSystem cSys2 = cSys.subImage(offset, factors, newShape);
    656     SpectralCoordinate sC = cSys2.spectralCoordinate(0);
    657 //
    658     pTabOut->setCoordinate(sC, j);
    659   }
    660 
    661 // Get header
    662 
    663   SDHeader sh = in.getSDHeader();
    664 
    665 // Generate resampling vectors
    666 
    667   const uInt nChanIn = sh.nchan;
    668   Vector<Float> xIn(nChanIn);
    669   indgen(xIn);
    670 //
    671   Int fac =  Int(nChanIn/width);
    672   Vector<Float> xOut(fac+10);          // 10 to be safe - resize later
    673   uInt i = 0;
    674   Float x = 0.0;
    675   Bool more = True;
    676   while (more) {
    677     xOut(i) = x;
    678 //
    679     i++;
    680     x += width;
    681     if (x>nChanIn-1) more = False;
    682   }
    683   const uInt nChanOut = i;
    684   xOut.resize(nChanOut,True);
    685 //
    686   IPosition shapeIn(in.rowAsMaskedArray(0).shape());
    687   sh.nchan = nChanOut;
    688   pTabOut->putSDHeader(sh);
    689 
    690 // Loop over rows and resample along channel axis
    691 
    692   Array<Float> valuesOut;
    693   Array<Bool> maskOut;
    694   Array<Float> tSysOut;
    695   Array<Bool> tSysMaskIn(shapeIn,True);
    696   Array<Bool> tSysMaskOut;
    697   for (uInt i=0; i < in.nRow(); ++i) {
    698 
    699 // Get container
    700 
    701      SDContainer sc = in.getSDContainer(i);
    702 
    703 // Get data and Tsys
    704 
    705      const Array<Float>& tSysIn = sc.getTsys();
    706      const MaskedArray<Float>& dataIn(in.rowAsMaskedArray(i));
    707      Array<Float> valuesIn = dataIn.getArray();
    708      Array<Bool> maskIn = dataIn.getMask();
    709 
    710 // Interpolate data
    711 
    712      InterpolateArray1D<Float,Float>::interpolate(valuesOut, maskOut, xOut,
    713                                                   xIn, valuesIn, maskIn,
    714                                                   interpMethod, True, True);
    715      sc.resize(valuesOut.shape());
    716      putDataInSDC(sc, valuesOut, maskOut);
    717 
    718 // Interpolate TSys
    719 
    720      InterpolateArray1D<Float,Float>::interpolate(tSysOut, tSysMaskOut, xOut,
    721                                                   xIn, tSysIn, tSysMaskIn,
    722                                                   interpMethod, True, True);
    723     sc.putTsys(tSysOut);
    724 
    725 // Put container in output
    726 
    727     pTabOut->putSDContainer(sc);
    728   }
    729 //
    730   return pTabOut;
    731 }
    732 
    733 SDMemTable* SDMath::unaryOperate(const SDMemTable& in, Float val, Bool doAll,
    734                                  uInt what, Bool doTSys)
    735 //
    736 // what = 0   Multiply
    737 //        1   Add
    738 {
    739    SDMemTable* pOut = new SDMemTable(in,False);
    740    const Table& tOut = pOut->table();
    741    ArrayColumn<Float> specCol(tOut,"SPECTRA");
    742    ArrayColumn<Float> tSysCol(tOut,"TSYS");
    743    Array<Float> tSysArr;
    744 
    745 // Get data slice bounds
    746 
    747    IPosition start, end;
    748    setCursorSlice (start, end, doAll, in);
    749 //
    750    for (uInt i=0; i<tOut.nrow(); i++) {
    751 
    752 // Modify data
    753 
    754       MaskedArray<Float> dataIn(pOut->rowAsMaskedArray(i));
    755       MaskedArray<Float> dataIn2 = dataIn(start,end);    // Reference
    756       if (what==0) {
    757          dataIn2 *= val;
    758       } else if (what==1) {
    759          dataIn2 += val;
    760       }
    761       specCol.put(i, dataIn.getArray());
    762 
    763 // Modify Tsys
    764 
    765       if (doTSys) {
    766          tSysCol.get(i, tSysArr);
    767          Array<Float> tSysArr2 = tSysArr(start,end);     // Reference
    768          if (what==0) {
    769             tSysArr2 *= val;
    770          } else if (what==1) {
    771             tSysArr2 += val;
    772          }
    773          tSysCol.put(i, tSysArr);
    774       }
    775    }
    776 //
    777    return pOut;
    778 }
    779 
    780 SDMemTable* SDMath::averagePol(const SDMemTable& in, const Vector<Bool>& mask,
    781                                const String& weightStr)
    782 //
    783 // Average all polarizations together, weighted by variance
    784 //
    785 {
    786    WeightType wtType = NONE;
    787    convertWeightString(wtType, weightStr, True);
    788 
    789 // Create output Table and reshape number of polarizations
    790 
    791   Bool clear=True;
    792   SDMemTable* pTabOut = new SDMemTable(in, clear);
    793   SDHeader header = pTabOut->getSDHeader();
    794   header.npol = 1;
    795   pTabOut->putSDHeader(header);
    796 //
    797   const Table& tabIn = in.table();
    798 
    799 // Shape of input and output data
    800 
    801   const IPosition& shapeIn = in.rowAsMaskedArray(0).shape();
    802   IPosition shapeOut(shapeIn);
    803   shapeOut(asap::PolAxis) = 1;                          // Average all polarizations
    804   if (shapeIn(asap::PolAxis)==1) {
    805     delete  pTabOut;
    806     throw(AipsError("The input has only one polarisation"));
    807   }
    808 //
    809   const uInt nRows = in.nRow();
    810   const uInt nChan = shapeIn(asap::ChanAxis);
    811   AlwaysAssert(asap::nAxes==4,AipsError);
    812   const IPosition vecShapeOut(4,1,1,1,nChan);     // A multi-dim form of a Vector shape
    813   IPosition start(4), end(4);
    814 
    815 // Output arrays
    816 
    817   Array<Float> outData(shapeOut, 0.0);
    818   Array<Bool> outMask(shapeOut, True);
    819   const IPosition axes(2, asap::PolAxis, asap::ChanAxis);              // pol-channel plane
    820 
    821 // Attach Tsys column if needed
    822 
    823   ROArrayColumn<Float> tSysCol;
    824   Array<Float> tSys;
    825   if (wtType==TSYS) {
    826      tSysCol.attach(tabIn,"TSYS");
    827   }
    828 //
    829   const Bool useMask = (mask.nelements() == shapeIn(asap::ChanAxis));
    830 
    831 // Loop over rows
    832 
    833    for (uInt iRow=0; iRow<nRows; iRow++) {
    834 
    835 // Get data for this row
    836 
    837       MaskedArray<Float> marr(in.rowAsMaskedArray(iRow));
    838       Array<Float>& arr = marr.getRWArray();
    839       const Array<Bool>& barr = marr.getMask();
    840 
    841 // Get Tsys
    842 
    843       if (wtType==TSYS) {
    844          tSysCol.get(iRow,tSys);
    845       }
    846 
    847 // Make iterators to iterate by pol-channel planes
    848 // The tSys array is empty unless wtType=TSYS so only
    849 // access the iterator is that is the case
    850 
    851       ReadOnlyArrayIterator<Float> itDataPlane(arr, axes);
    852       ReadOnlyArrayIterator<Bool> itMaskPlane(barr, axes);
    853       ReadOnlyArrayIterator<Float>* pItTsysPlane = 0;
    854       if (wtType==TSYS)
    855         pItTsysPlane = new ReadOnlyArrayIterator<Float>(tSys, axes);
    856 
    857 // Accumulations
    858 
    859       Float fac = 1.0;
    860       Vector<Float> vecSum(nChan,0.0);
    861 
    862 // Iterate through data by pol-channel planes
    863 
    864       while (!itDataPlane.pastEnd()) {
    865 
    866 // Iterate through plane by polarization  and accumulate Vectors
    867 
    868         Vector<Float> t1(nChan); t1 = 0.0;
    869         Vector<Bool> t2(nChan); t2 = True;
    870         Float tSys = 0.0;
    871         MaskedArray<Float> vecSum(t1,t2);
    872         Float norm = 0.0;
    873         {
    874            ReadOnlyVectorIterator<Float> itDataVec(itDataPlane.array(), 1);
    875            ReadOnlyVectorIterator<Bool> itMaskVec(itMaskPlane.array(), 1);
    876 //
    877            ReadOnlyVectorIterator<Float>* pItTsysVec = 0;
    878            if (wtType==TSYS) {
    879               pItTsysVec =
    880                 new ReadOnlyVectorIterator<Float>(pItTsysPlane->array(), 1);
    881            }
    882 //
    883            while (!itDataVec.pastEnd()) {
    884 
    885 // Create MA of data & mask (optionally including OTF mask) and  get variance for this spectrum
    886 
    887               if (useMask) {
    888                  const MaskedArray<Float> spec(itDataVec.vector(),
    889                                                mask&&itMaskVec.vector());
    890                  if (wtType==VAR) {
    891                     fac = 1.0 / variance(spec);
    892                  } else if (wtType==TSYS) {
    893                     tSys = pItTsysVec->vector()[0];      // Drop pseudo channel dependency
    894                     fac = 1.0 / tSys / tSys;
    895                  }
    896               } else {
    897                  const MaskedArray<Float> spec(itDataVec.vector(),
    898                                                itMaskVec.vector());
    899                  if (wtType==VAR) {
    900                     fac = 1.0 / variance(spec);
    901                  } else if (wtType==TSYS) {
    902                     tSys = pItTsysVec->vector()[0];      // Drop pseudo channel dependency
    903                     fac = 1.0 / tSys / tSys;
    904                  }
    905               }
    906 
    907 // Normalize spectrum (without OTF mask) and accumulate
    908 
    909               const MaskedArray<Float> spec(fac*itDataVec.vector(),
    910                                             itMaskVec.vector());
    911               vecSum += spec;
    912               norm += fac;
    913 
    914 // Next
    915 
    916               itDataVec.next();
    917               itMaskVec.next();
    918               if (wtType==TSYS) pItTsysVec->next();
    919            }
    920 
    921 // Clean up
    922 
    923            if (pItTsysVec) {
    924               delete pItTsysVec;
    925               pItTsysVec = 0;
    926            }
    927         }
    928 
    929 // Normalize summed spectrum
    930 
    931         vecSum /= norm;
    932 
    933 // FInd position in input data array.  We are iterating by pol-channel
    934 // plane so all that will change is beam and IF and that's what we want.
    935 
    936         IPosition pos = itDataPlane.pos();
    937 
    938 // Write out data. This is a bit messy. We have to reform the Vector
    939 // accumulator into an Array of shape (1,1,1,nChan)
    940 
    941         start = pos;
    942         end = pos;
    943         end(asap::ChanAxis) = nChan-1;
    944         outData(start,end) = vecSum.getArray().reform(vecShapeOut);
    945         outMask(start,end) = vecSum.getMask().reform(vecShapeOut);
    946 
    947 // Step to next beam/IF combination
    948 
    949         itDataPlane.next();
    950         itMaskPlane.next();
    951         if (wtType==TSYS) pItTsysPlane->next();
    952       }
    953 
    954 // Generate output container and write it to output table
    955 
    956       SDContainer sc = in.getSDContainer();
    957       sc.resize(shapeOut);
    958 //
    959       putDataInSDC(sc, outData, outMask);
    960       pTabOut->putSDContainer(sc);
    961 //
    962       if (wtType==TSYS) {
    963          delete pItTsysPlane;
    964          pItTsysPlane = 0;
    965       }
    966    }
    967 
    968 // Set polarization cursor to 0
    969 
    970   pTabOut->setPol(0);
    971 //
    972   return pTabOut;
    973 }
    974 
    975 
    976 SDMemTable* SDMath::smooth(const SDMemTable& in,
    977                            const casa::String& kernelType,
    978                            casa::Float width, Bool doAll)
    979 //
    980 // Should smooth TSys as well
    981 //
    982 {
    983 
    984   // Number of channels
    985    const uInt nChan = in.nChan();
    986 
    987    // Generate Kernel
    988    VectorKernel::KernelTypes type = VectorKernel::toKernelType(kernelType);
    989    Vector<Float> kernel = VectorKernel::make(type, width, nChan, True, False);
    990 
    991    // Generate Convolver
    992    IPosition shape(1,nChan);
    993    Convolver<Float> conv(kernel, shape);
    994 
    995    // New Table
    996    SDMemTable* pTabOut = new SDMemTable(in,True);
    997 
    998    // Output Vectors
    999    Vector<Float> valuesOut(nChan);
    1000    Vector<Bool> maskOut(nChan);
    1001 
    1002    // Get data slice bounds
    1003    IPosition start, end;
    1004    setCursorSlice (start, end, doAll, in);
    1005 
    1006    // Loop over rows in Table
    1007    for (uInt ri=0; ri < in.nRow(); ++ri) {
    1008 
    1009      // Get slice of data
    1010       MaskedArray<Float> dataIn = in.rowAsMaskedArray(ri);
    1011 
    1012       // Deconstruct and get slices which reference these arrays
    1013       Array<Float> valuesIn = dataIn.getArray();
    1014       Array<Bool> maskIn = dataIn.getMask();
    1015 
    1016       Array<Float> valuesIn2 = valuesIn(start,end);       // ref to valuesIn
    1017       Array<Bool> maskIn2 = maskIn(start,end);
    1018 
    1019       // Iterate through by spectra
    1020       VectorIterator<Float> itValues(valuesIn2, asap::ChanAxis);
    1021       VectorIterator<Bool> itMask(maskIn2, asap::ChanAxis);
    1022       while (!itValues.pastEnd()) {
    1023 
    1024         // Smooth
    1025         if (kernelType==VectorKernel::HANNING) {
    1026           mathutil::hanning(valuesOut, maskOut, itValues.vector(),
    1027                             itMask.vector());
    1028           itMask.vector() = maskOut;
    1029         } else {
    1030           mathutil::replaceMaskByZero(itValues.vector(), itMask.vector());
    1031           conv.linearConv(valuesOut, itValues.vector());
    1032         }
    1033 
    1034         itValues.vector() = valuesOut;
    1035         itValues.next();
    1036         itMask.next();
    1037       }
    1038 
    1039       // Create and put back
    1040       SDContainer sc = in.getSDContainer(ri);
    1041       putDataInSDC(sc, valuesIn, maskIn);
    1042 
    1043       pTabOut->putSDContainer(sc);
    1044    }
    1045 
    1046   return pTabOut;
    1047 }
    1048 
    1049 
    1050 
    1051 SDMemTable* SDMath::convertFlux(const SDMemTable& in, Float D, Float etaAp,
    1052                                 Float JyPerK, Bool doAll)
    1053 //
    1054 // etaAp = aperture efficiency (-1 means find)
    1055 // D     = geometric diameter (m)  (-1 means find)
    1056 // JyPerK
    1057 //
    1058 {
    1059   SDHeader sh = in.getSDHeader();
    1060   SDMemTable* pTabOut = new SDMemTable(in, True);
    1061 
    1062   // Find out how to convert values into Jy and K (e.g. units might be
    1063   // mJy or mK) Also automatically find out what we are converting to
    1064   // according to the flux unit
    1065   Unit fluxUnit(sh.fluxunit);
     411  out->frequencies().rescale(width, "RESAMPLE");
     412  TableIterator iter(tout, "IFNO");
     413  TableRow row(tout);
     414  while ( !iter.pastEnd() ) {
     415    Table tab = iter.table();
     416    ArrayColumn<Float> specCol(tab, "SPECTRA");
     417    //ArrayColumn<Float> tsysCol(tout, "TSYS");
     418    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
     419    Vector<Float> spec;
     420    Vector<uChar> flag;
     421    specCol.get(0,spec); // the number of channels should be constant per IF
     422    uInt nChanIn = spec.nelements();
     423    Vector<Float> xIn(nChanIn); indgen(xIn);
     424    Int fac =  Int(nChanIn/width);
     425    Vector<Float> xOut(fac+10); // 10 to be safe - resize later
     426    uInt k = 0;
     427    Float x = 0.0;
     428    while (x < Float(nChanIn) ) {
     429      xOut(k) = x;
     430      k++;
     431      x += width;
     432    }
     433    uInt nChanOut = k;
     434    xOut.resize(nChanOut, True);
     435    // process all rows for this IFNO
     436    Vector<Float> specOut;
     437    Vector<Bool> maskOut;
     438    Vector<uChar> flagOut;
     439    for (uInt i=0; i < tab.nrow(); ++i) {
     440      specCol.get(i, spec);
     441      flagCol.get(i, flag);
     442      Vector<Bool> mask(flag.nelements());
     443      convertArray(mask, flag);
     444
     445      IPosition shapeIn(spec.shape());
     446      //sh.nchan = nChanOut;
     447      InterpolateArray1D<Float,Float>::interpolate(specOut, maskOut, xOut,
     448                                                   xIn, spec, mask,
     449                                                   interpMethod, True, True);
     450      /// @todo do the same for channel based Tsys
     451      flagOut.resize(maskOut.nelements());
     452      convertArray(flagOut, maskOut);
     453      specCol.put(i, specOut);
     454      flagCol.put(i, flagOut);
     455    }
     456    ++iter;
     457  }
     458
     459  return out;
     460}
     461
     462STMath::imethod STMath::stringToIMethod(const std::string& in)
     463{
     464  static STMath::imap lookup;
     465
     466  // initialize the lookup table if necessary
     467  if ( lookup.empty() ) {
     468    lookup["NEAR"]   = InterpolateArray1D<Double,Float>::nearestNeighbour;
     469    lookup["LIN"] = InterpolateArray1D<Double,Float>::linear;
     470    lookup["CUB"]  = InterpolateArray1D<Double,Float>::cubic;
     471    lookup["SPL"]  = InterpolateArray1D<Double,Float>::spline;
     472  }
     473
     474  STMath::imap::const_iterator iter = lookup.find(in);
     475
     476  if ( lookup.end() == iter ) {
     477    std::string message = in;
     478    message += " is not a valid interpolation mode";
     479    throw(AipsError(message));
     480  }
     481  return iter->second;
     482}
     483
     484WeightType STMath::stringToWeight(const std::string& in)
     485{
     486  static std::map<std::string, WeightType> lookup;
     487
     488  // initialize the lookup table if necessary
     489  if ( lookup.empty() ) {
     490    lookup["NONE"]   = asap::NONE;
     491    lookup["TINT"] = asap::TINT;
     492    lookup["TINTSYS"]  = asap::TINTSYS;
     493    lookup["TSYS"]  = asap::TSYS;
     494    lookup["VAR"]  = asap::VAR;
     495  }
     496
     497  std::map<std::string, WeightType>::const_iterator iter = lookup.find(in);
     498
     499  if ( lookup.end() == iter ) {
     500    std::string message = in;
     501    message += " is not a valid weighting mode";
     502    throw(AipsError(message));
     503  }
     504  return iter->second;
     505}
     506
     507CountedPtr< Scantable > STMath::gainElevation( const CountedPtr< Scantable >& in,
     508                                               const Vector< Float > & coeffs,
     509                                               const std::string & filename,
     510                                               const std::string& method)
     511{
     512  // Get elevation data from Scantable and convert to degrees
     513  CountedPtr< Scantable > out = getScantable(in, false);
     514  Table& tab = in->table();
     515  ROScalarColumn<Float> elev(tab, "ELEVATION");
     516  Vector<Float> x = elev.getColumn();
     517  x *= Float(180 / C::pi);                        // Degrees
     518
     519  const uInt nc = coeffs.nelements();
     520  if ( filename.length() > 0 && nc > 0 ) {
     521    throw(AipsError("You must choose either polynomial coefficients or an ascii file, not both"));
     522  }
     523
     524  // Correct
     525  if ( nc > 0 || filename.length() == 0 ) {
     526    // Find instrument
     527    Bool throwit = True;
     528    Instrument inst =
     529      SDAttr::convertInstrument(tab.keywordSet().asString("AntennaName"),
     530                                throwit);
     531
     532    // Set polynomial
     533    Polynomial<Float>* ppoly = 0;
     534    Vector<Float> coeff;
     535    String msg;
     536    if ( nc > 0 ) {
     537      ppoly = new Polynomial<Float>(nc);
     538      coeff = coeffs;
     539      msg = String("user");
     540    } else {
     541      SDAttr sdAttr;
     542      coeff = sdAttr.gainElevationPoly(inst);
     543      ppoly = new Polynomial<Float>(3);
     544      msg = String("built in");
     545    }
     546
     547    if ( coeff.nelements() > 0 ) {
     548      ppoly->setCoefficients(coeff);
     549    } else {
     550      delete ppoly;
     551      throw(AipsError("There is no known gain-elevation polynomial known for this instrument"));
     552    }
     553    ostringstream oss;
     554    oss << "Making polynomial correction with " << msg << " coefficients:" << endl;
     555    oss << "   " <<  coeff;
     556    pushLog(String(oss));
     557    const uInt nrow = tab.nrow();
     558    Vector<Float> factor(nrow);
     559    for ( uInt i=0; i < nrow; ++i ) {
     560      factor[i] = 1.0 / (*ppoly)(x[i]);
     561    }
     562    delete ppoly;
     563    scaleByVector(tab, factor, true);
     564
     565  } else {
     566    // Read and correct
     567    pushLog("Making correction from ascii Table");
     568    scaleFromAsciiTable(tab, filename, method, x, true);
     569  }
     570  return out;
     571}
     572
     573void STMath::scaleFromAsciiTable(Table& in, const std::string& filename,
     574                                 const std::string& method,
     575                                 const Vector<Float>& xout, bool dotsys)
     576{
     577
     578// Read gain-elevation ascii file data into a Table.
     579
     580  String formatString;
     581  Table tbl = readAsciiTable(formatString, Table::Memory, filename, "", "", False);
     582  scaleFromTable(in, tbl, method, xout, dotsys);
     583}
     584
     585void STMath::scaleFromTable(Table& in,
     586                            const Table& table,
     587                            const std::string& method,
     588                            const Vector<Float>& xout, bool dotsys)
     589{
     590
     591  ROScalarColumn<Float> geElCol(table, "ELEVATION");
     592  ROScalarColumn<Float> geFacCol(table, "FACTOR");
     593  Vector<Float> xin = geElCol.getColumn();
     594  Vector<Float> yin = geFacCol.getColumn();
     595  Vector<Bool> maskin(xin.nelements(),True);
     596
     597  // Interpolate (and extrapolate) with desired method
     598
     599   //InterpolateArray1D<Double,Float>::InterpolationMethod method;
     600   Int intmethod(stringToIMethod(method));
     601
     602   Vector<Float> yout;
     603   Vector<Bool> maskout;
     604   InterpolateArray1D<Float,Float>::interpolate(yout, maskout, xout,
     605                                                xin, yin, maskin, intmethod,
     606                                                True, True);
     607
     608   scaleByVector(in, Float(1.0)/yout, dotsys);
     609}
     610
     611void STMath::scaleByVector( Table& in,
     612                            const Vector< Float >& factor,
     613                            bool dotsys )
     614{
     615  uInt nrow = in.nrow();
     616  if ( factor.nelements() != nrow ) {
     617    throw(AipsError("factors.nelements() != table.nelements()"));
     618  }
     619  ArrayColumn<Float> specCol(in, "SPECTRA");
     620  ArrayColumn<uChar> flagCol(in, "FLAGTRA");
     621  ArrayColumn<Float> tsysCol(in, "TSYS");
     622  for (uInt i=0; i < nrow; ++i) {
     623    MaskedArray<Float> ma  = maskedArray(specCol(i), flagCol(i));
     624    ma *= factor[i];
     625    specCol.put(i, ma.getArray());
     626    flagCol.put(i, flagsFromMA(ma));
     627    if ( dotsys ) {
     628      Vector<Float> tsys;
     629      tsysCol.get(i, tsys);
     630      tsys *= factor[i];
     631      specCol.put(i,tsys);
     632    }
     633  }
     634}
     635
     636CountedPtr< Scantable > STMath::convertFlux( const CountedPtr< Scantable >& in,
     637                                             float d, float etaap,
     638                                             float jyperk )
     639{
     640  CountedPtr< Scantable > out = getScantable(in, false);
     641  Table& tab = in->table();
     642  Unit fluxUnit(tab.keywordSet().asString("FluxUnit"));
    1066643  Unit K(String("K"));
    1067644  Unit JY(String("Jy"));
    1068645
    1069   Bool toKelvin = True;
    1070   Double cFac = 1.0;
    1071 
    1072   if (fluxUnit==JY) {
     646  bool tokelvin = true;
     647  Double cfac = 1.0;
     648
     649  if ( fluxUnit == JY ) {
    1073650    pushLog("Converting to K");
    1074651    Quantum<Double> t(1.0,fluxUnit);
    1075652    Quantum<Double> t2 = t.get(JY);
    1076     cFac = (t2 / t).getValue();               // value to Jy
    1077 
    1078     toKelvin = True;
    1079     sh.fluxunit = "K";
    1080   } else if (fluxUnit==K) {
     653    cfac = (t2 / t).getValue();               // value to Jy
     654
     655    tokelvin = true;
     656    out->setFluxUnit("K");
     657  } else if ( fluxUnit == K ) {
    1081658    pushLog("Converting to Jy");
    1082659    Quantum<Double> t(1.0,fluxUnit);
    1083660    Quantum<Double> t2 = t.get(K);
    1084     cFac = (t2 / t).getValue();              // value to K
    1085 
    1086     toKelvin = False;
    1087     sh.fluxunit = "Jy";
     661    cfac = (t2 / t).getValue();              // value to K
     662
     663    tokelvin = false;
     664    out->setFluxUnit("Jy");
    1088665  } else {
    1089666    throw(AipsError("Unrecognized brightness units in Table - must be consistent with Jy or K"));
    1090667  }
    1091 
    1092   pTabOut->putSDHeader(sh);
    1093 
    1094668  // Make sure input values are converted to either Jy or K first...
    1095   Float factor = cFac;
     669  Float factor = cfac;
    1096670
    1097671  // Select method
    1098   if (JyPerK>0.0) {
    1099     factor *= JyPerK;
    1100     if (toKelvin) factor = 1.0 / JyPerK;
     672  if (jyperk > 0.0) {
     673    factor *= jyperk;
     674    if ( tokelvin ) factor = 1.0 / jyperk;
    1101675    ostringstream oss;
    1102     oss << "Jy/K = " << JyPerK;
     676    oss << "Jy/K = " << jyperk;
    1103677    pushLog(String(oss));
    1104     Vector<Float> factors(in.nRow(), factor);
    1105     scaleByVector(pTabOut, in, doAll, factors, False);
    1106   } else if (etaAp>0.0) {
    1107     Bool throwIt = True;
    1108     Instrument inst = SDAttr::convertInstrument(sh.antennaname, throwIt);
     678    Vector<Float> factors(tab.nrow(), factor);
     679    scaleByVector(tab,factors, false);
     680  } else if ( etaap > 0.0) {
     681    Instrument inst =
     682      SDAttr::convertInstrument(tab.keywordSet().asString("AntennaName"), True);
    1109683    SDAttr sda;
    1110     if (D < 0) D = sda.diameter(inst);
    1111     Float JyPerK = SDAttr::findJyPerK(etaAp,D);
     684    if (d < 0) d = sda.diameter(inst);
     685    Float jyPerk = SDAttr::findJyPerK(etaap, d);
    1112686    ostringstream oss;
    1113     oss << "Jy/K = " << JyPerK;
     687    oss << "Jy/K = " << jyperk;
    1114688    pushLog(String(oss));
    1115     factor *= JyPerK;
    1116     if (toKelvin) {
     689    factor *= jyperk;
     690    if ( tokelvin ) {
    1117691      factor = 1.0 / factor;
    1118692    }
    1119 
    1120     Vector<Float> factors(in.nRow(), factor);
    1121     scaleByVector(pTabOut, in, doAll, factors, False);
     693    Vector<Float> factors(tab.nrow(), factor);
     694    scaleByVector(tab, factors, False);
    1122695  } else {
    1123696
     
    1128701
    1129702    pushLog("Looking up conversion factors");
    1130     convertBrightnessUnits (pTabOut, in, toKelvin, cFac, doAll);
    1131   }
    1132   return pTabOut;
    1133 }
    1134 
    1135 
    1136 SDMemTable* SDMath::gainElevation(const SDMemTable& in,
    1137                                   const Vector<Float>& coeffs,
    1138                                   const String& fileName,
    1139                                   const String& methodStr, Bool doAll)
    1140 {
    1141 
    1142   // Get header and clone output table
    1143   SDHeader sh = in.getSDHeader();
    1144   SDMemTable* pTabOut = new SDMemTable(in, True);
    1145 
    1146   // Get elevation data from SDMemTable and convert to degrees
    1147   const Table& tab = in.table();
     703    convertBrightnessUnits(out, tokelvin, cfac);
     704  }
     705
     706  return out;
     707}
     708
     709void STMath::convertBrightnessUnits( CountedPtr<Scantable>& in,
     710                                     bool tokelvin, float cfac )
     711{
     712  Table& table = in->table();
     713  Instrument inst =
     714    SDAttr::convertInstrument(table.keywordSet().asString("AntennaName"), True);
     715  TableIterator iter(table, "FREQ_ID");
     716  STFrequencies stfreqs = in->frequencies();
     717  SDAttr sdAtt;
     718  while (!iter.pastEnd()) {
     719    Table tab = iter.table();
     720    ArrayColumn<Float> specCol(tab, "SPECTRA");
     721    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
     722    ROScalarColumn<uInt> freqidCol(tab, "FREQ_ID");
     723    MEpoch::ROScalarColumn timeCol(tab, "TIME");
     724
     725    uInt freqid; freqidCol.get(0, freqid);
     726    Vector<Float> tmpspec; specCol.get(0, tmpspec);
     727    // SDAttr.JyPerK has a Vector interface... change sometime.
     728    Vector<Float> freqs(1,stfreqs.getRefFreq(freqid, tmpspec.nelements()));
     729    for ( uInt i=0; i<tab.nrow(); ++i) {
     730      Float jyperk = (sdAtt.JyPerK(inst, timeCol(i), freqs))[0];
     731      Float factor = cfac * jyperk;
     732      if ( tokelvin ) factor = Float(1.0) / factor;
     733      MaskedArray<Float> ma  = maskedArray(specCol(i), flagCol(i));
     734      ma *= factor;
     735      specCol.put(i, ma.getArray());
     736      flagCol.put(i, flagsFromMA(ma));
     737    }
     738  }
     739}
     740
     741CountedPtr< Scantable > STMath::opacity( const CountedPtr< Scantable > & in,
     742                                         float tau )
     743{
     744  CountedPtr< Scantable > out = getScantable(in, false);
     745  Table& tab = in->table();
    1148746  ROScalarColumn<Float> elev(tab, "ELEVATION");
    1149   Vector<Float> x = elev.getColumn();
    1150   x *= Float(180 / C::pi);                        // Degrees
    1151 
    1152   const uInt nC = coeffs.nelements();
    1153   if (fileName.length()>0 && nC>0) {
    1154     throw(AipsError("You must choose either polynomial coefficients or an ascii file, not both"));
    1155   }
    1156 
    1157   // Correct
    1158   if (nC>0 || fileName.length()==0) {
    1159     // Find instrument
    1160      Bool throwIt = True;
    1161      Instrument inst = SDAttr::convertInstrument (sh.antennaname, throwIt);
    1162 
    1163      // Set polynomial
    1164      Polynomial<Float>* pPoly = 0;
    1165      Vector<Float> coeff;
    1166      String msg;
    1167      if (nC>0) {
    1168        pPoly = new Polynomial<Float>(nC);
    1169        coeff = coeffs;
    1170        msg = String("user");
    1171      } else {
    1172        SDAttr sdAttr;
    1173        coeff = sdAttr.gainElevationPoly(inst);
    1174        pPoly = new Polynomial<Float>(3);
    1175        msg = String("built in");
    1176      }
    1177 
    1178      if (coeff.nelements()>0) {
    1179        pPoly->setCoefficients(coeff);
    1180      } else {
    1181        delete pPoly;
    1182        throw(AipsError("There is no known gain-elevation polynomial known for this instrument"));
    1183      }
    1184      ostringstream oss;
    1185      oss << "Making polynomial correction with " << msg << " coefficients:" << endl;
    1186      oss << "   " <<  coeff;
    1187      pushLog(String(oss));
    1188      const uInt nRow = in.nRow();
    1189      Vector<Float> factor(nRow);
    1190      for (uInt i=0; i<nRow; i++) {
    1191        factor[i] = 1.0 / (*pPoly)(x[i]);
    1192      }
    1193      delete pPoly;
    1194      scaleByVector (pTabOut, in, doAll, factor, True);
    1195 
    1196   } else {
    1197 
    1198     // Indicate which columns to read from ascii file
    1199     String col0("ELEVATION");
    1200     String col1("FACTOR");
    1201 
    1202     // Read and correct
    1203 
    1204     pushLog("Making correction from ascii Table");
    1205     scaleFromAsciiTable (pTabOut, in, fileName, col0, col1,
    1206                          methodStr, doAll, x, True);
    1207   }
    1208 
    1209   return pTabOut;
    1210 }
    1211 
    1212 
    1213 SDMemTable* SDMath::opacity(const SDMemTable& in, Float tau, Bool doAll)
    1214 {
    1215 
    1216   // Get header and clone output table
    1217 
    1218   SDHeader sh = in.getSDHeader();
    1219   SDMemTable* pTabOut = new SDMemTable(in, True);
    1220 
    1221 // Get elevation data from SDMemTable and convert to degrees
    1222 
    1223   const Table& tab = in.table();
    1224   ROScalarColumn<Float> elev(tab, "ELEVATION");
    1225   Vector<Float> zDist = elev.getColumn();
    1226   zDist = Float(C::pi_2) - zDist;
    1227 
    1228 // Generate correction factor
    1229 
    1230   const uInt nRow = in.nRow();
    1231   Vector<Float> factor(nRow);
    1232   Vector<Float> factor2(nRow);
    1233   for (uInt i=0; i<nRow; i++) {
    1234      factor[i] = exp(tau)/cos(zDist[i]);
    1235   }
    1236 
    1237 // Correct
    1238 
    1239   scaleByVector (pTabOut, in, doAll, factor, True);
    1240 
    1241   return pTabOut;
    1242 }
    1243 
    1244 
    1245 void SDMath::rotateXYPhase(SDMemTable& in, Float value, Bool doAll)
    1246 //
    1247 // phase in degrees
    1248 // assumes linear correlations
    1249 //
    1250 {
    1251   if (in.nPol() != 4) {
    1252     throw(AipsError("You must have 4 polarizations to run this function"));
    1253   }
    1254 
    1255    SDHeader sh = in.getSDHeader();
    1256    Instrument inst = SDAttr::convertInstrument(sh.antennaname, False);
    1257    SDAttr sdAtt;
    1258    if (sdAtt.feedPolType(inst) != LINEAR) {
    1259       throw(AipsError("Only linear polarizations are supported"));
    1260    }
    1261 //
    1262    const Table& tabIn = in.table();
    1263    ArrayColumn<Float> specCol(tabIn,"SPECTRA");
    1264    IPosition start(asap::nAxes,0);
    1265    IPosition end(asap::nAxes);
    1266 
    1267 // Set cursor slice. Assumes shape the same for all rows
    1268 
    1269    setCursorSlice (start, end, doAll, in);
    1270    IPosition start3(start);
    1271    start3(asap::PolAxis) = 2;                 // Real(XY)
    1272    IPosition end3(end);
    1273    end3(asap::PolAxis) = 2;
    1274 //
    1275    IPosition start4(start);
    1276    start4(asap::PolAxis) = 3;                 // Imag (XY)
    1277    IPosition end4(end);
    1278    end4(asap::PolAxis) = 3;
    1279 //
    1280    uInt nRow = in.nRow();
    1281    Array<Float> data;
    1282    for (uInt i=0; i<nRow;++i) {
    1283       specCol.get(i,data);
    1284       IPosition shape = data.shape();
    1285 
    1286       // Get polarization slice references
    1287       Array<Float> C3 = data(start3,end3);
    1288       Array<Float> C4 = data(start4,end4);
    1289 
    1290       // Rotate
    1291       SDPolUtil::rotatePhase(C3, C4, value);
    1292 
    1293       // Put
    1294       specCol.put(i,data);
    1295    }
    1296 }
    1297 
    1298 
    1299 void SDMath::rotateLinPolPhase(SDMemTable& in, Float value, Bool doAll)
    1300 //
    1301 // phase in degrees
    1302 // assumes linear correlations
    1303 //
    1304 {
    1305    if (in.nPol() != 4) {
    1306       throw(AipsError("You must have 4 polarizations to run this function"));
    1307    }
    1308 //
    1309    SDHeader sh = in.getSDHeader();
    1310    Instrument inst = SDAttr::convertInstrument(sh.antennaname, False);
    1311    SDAttr sdAtt;
    1312    if (sdAtt.feedPolType(inst) != LINEAR) {
    1313       throw(AipsError("Only linear polarizations are supported"));
    1314    }
    1315 //
    1316    const Table& tabIn = in.table();
    1317    ArrayColumn<Float> specCol(tabIn,"SPECTRA");
    1318    ROArrayColumn<Float> stokesCol(tabIn,"STOKES");
    1319    IPosition start(asap::nAxes,0);
    1320    IPosition end(asap::nAxes);
    1321 
    1322 // Set cursor slice. Assumes shape the same for all rows
    1323 
    1324    setCursorSlice (start, end, doAll, in);
    1325 //
    1326    IPosition start1(start);
    1327    start1(asap::PolAxis) = 0;                // C1 (XX)
    1328    IPosition end1(end);
    1329    end1(asap::PolAxis) = 0;
    1330 //
    1331    IPosition start2(start);
    1332    start2(asap::PolAxis) = 1;                 // C2 (YY)
    1333    IPosition end2(end);
    1334    end2(asap::PolAxis) = 1;
    1335 //
    1336    IPosition start3(start);
    1337    start3(asap::PolAxis) = 2;                 // C3 ( Real(XY) )
    1338    IPosition end3(end);
    1339    end3(asap::PolAxis) = 2;
    1340 //
    1341    IPosition startI(start);
    1342    startI(asap::PolAxis) = 0;                 // I
    1343    IPosition endI(end);
    1344    endI(asap::PolAxis) = 0;
    1345 //
    1346    IPosition startQ(start);
    1347    startQ(asap::PolAxis) = 1;                 // Q
    1348    IPosition endQ(end);
    1349    endQ(asap::PolAxis) = 1;
    1350 //
    1351    IPosition startU(start);
    1352    startU(asap::PolAxis) = 2;                 // U
    1353    IPosition endU(end);
    1354    endU(asap::PolAxis) = 2;
    1355 
    1356 //
    1357    uInt nRow = in.nRow();
    1358    Array<Float> data, stokes;
    1359    for (uInt i=0; i<nRow;++i) {
    1360       specCol.get(i,data);
    1361       stokesCol.get(i,stokes);
    1362       IPosition shape = data.shape();
    1363 
    1364 // Get linear polarization slice references
    1365 
    1366       Array<Float> C1 = data(start1,end1);
    1367       Array<Float> C2 = data(start2,end2);
    1368       Array<Float> C3 = data(start3,end3);
    1369 
    1370 // Get STokes slice references
    1371 
    1372       Array<Float> I = stokes(startI,endI);
    1373       Array<Float> Q = stokes(startQ,endQ);
    1374       Array<Float> U = stokes(startU,endU);
    1375 
    1376 // Rotate
    1377 
    1378       SDPolUtil::rotateLinPolPhase(C1, C2, C3, I, Q, U, value);
    1379 
    1380 // Put
    1381 
    1382       specCol.put(i,data);
    1383    }
    1384 }
    1385 
    1386 // 'private' functions
    1387 
    1388 void SDMath::convertBrightnessUnits (SDMemTable* pTabOut, const SDMemTable& in,
    1389                                      Bool toKelvin, Float cFac, Bool doAll)
    1390 {
    1391 
    1392 // Get header
    1393 
    1394    SDHeader sh = in.getSDHeader();
    1395    const uInt nChan = sh.nchan;
    1396 
    1397 // Get instrument
    1398 
    1399    Bool throwIt = True;
    1400    Instrument inst = SDAttr::convertInstrument(sh.antennaname, throwIt);
    1401 
    1402 // Get Diameter (m)
    1403 
    1404    SDAttr sdAtt;
    1405 // Get epoch of first row
    1406 
    1407    MEpoch dateObs = in.getEpoch(0);
    1408 
    1409 // Generate a Vector of correction factors. One per FreqID
    1410 
    1411    SDFrequencyTable sdft = in.getSDFreqTable();
    1412    Vector<uInt> freqIDs;
    1413 //
    1414    Vector<Float> freqs(sdft.length());
    1415    for (uInt i=0; i<sdft.length(); i++) {
    1416       freqs(i) = (nChan/2 - sdft.referencePixel(i))*sdft.increment(i) + sdft.referenceValue(i);
    1417    }
    1418 //
    1419    Vector<Float> JyPerK = sdAtt.JyPerK(inst, dateObs, freqs);
    1420    ostringstream oss;
    1421    oss << "Jy/K = " << JyPerK;
    1422    pushLog(String(oss));
    1423    Vector<Float> factors = cFac * JyPerK;
    1424    if (toKelvin) factors = Float(1.0) / factors;
    1425 
    1426 // Get data slice bounds
    1427 
    1428    IPosition start, end;
    1429    setCursorSlice (start, end, doAll, in);
    1430    const uInt ifAxis = in.getIF();
    1431 
    1432 // Iteration axes
    1433 
    1434    IPosition axes(asap::nAxes-1,0);
    1435    for (uInt i=0,j=0; i<asap::nAxes; i++) {
    1436       if (i!=asap::IFAxis) {
    1437          axes(j++) = i;
     747  ArrayColumn<Float> specCol(tab, "SPECTRA");
     748  ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
     749  for ( uInt i=0; i<tab.nrow(); ++i) {
     750    Float zdist = Float(C::pi_2) - elev(i);
     751    Float factor = exp(tau)/cos(zdist);
     752    MaskedArray<Float> ma  = maskedArray(specCol(i), flagCol(i));
     753    ma *= factor;
     754    specCol.put(i, ma.getArray());
     755    flagCol.put(i, flagsFromMA(ma));
     756  }
     757  return out;
     758}
     759
     760CountedPtr< Scantable > STMath::smooth( const CountedPtr< Scantable >& in,
     761                                        const std::string& kernel, float width )
     762{
     763  CountedPtr< Scantable > out = getScantable(in, false);
     764  Table& table = in->table();
     765  VectorKernel::KernelTypes type = VectorKernel::toKernelType(kernel);
     766  // same IFNO should have same no of channels
     767  // this saves overhead
     768  TableIterator iter(table, "IFNO");
     769  while (!iter.pastEnd()) {
     770    Table tab = iter.table();
     771    ArrayColumn<Float> specCol(tab, "SPECTRA");
     772    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
     773    Vector<Float> tmpspec; specCol.get(0, tmpspec);
     774    uInt nchan = tmpspec.nelements();
     775    Vector<Float> kvec = VectorKernel::make(type, width, nchan, True, False);
     776    Convolver<Float> conv(kvec, IPosition(1,nchan));
     777    Vector<Float> spec;
     778    Vector<uChar> flag;
     779    for ( uInt i=0; i<tab.nrow(); ++i) {
     780      specCol.get(i, spec);
     781      flagCol.get(i, flag);
     782      Vector<Bool> mask(flag.nelements());
     783      convertArray(mask, flag);
     784      Vector<Float> specout;
     785      if ( type == VectorKernel::HANNING ) {
     786        Vector<Bool> maskout;
     787        mathutil::hanning(specout, maskout, spec , mask);
     788        convertArray(flag, maskout);
     789        flagCol.put(i, flag);
     790      } else {
     791        mathutil::replaceMaskByZero(specout, mask);
     792        conv.linearConv(specout, spec);
    1438793      }
    1439    }
    1440 
    1441 // Loop over rows and apply correction factor
    1442 
    1443    Float factor = 1.0;
    1444    const uInt axis = asap::ChanAxis;
    1445    for (uInt i=0; i < in.nRow(); ++i) {
    1446 
    1447 // Get data
    1448 
    1449       MaskedArray<Float> dataIn = in.rowAsMaskedArray(i);
    1450       Array<Float>& values = dataIn.getRWArray();           // Ref to dataIn
    1451       Array<Float> values2 = values(start,end);             // Ref to values to dataIn
    1452 
    1453 // Get SDCOntainer
    1454 
    1455       SDContainer sc = in.getSDContainer(i);
    1456 
    1457 // Get FreqIDs
    1458 
    1459       freqIDs = sc.getFreqMap();
    1460 
    1461 // Now the conversion factor depends only upon frequency
    1462 // So we need to iterate through by IF only giving
    1463 // us BEAM/POL/CHAN cubes
    1464 
    1465       ArrayIterator<Float> itIn(values2, axes);
    1466       uInt ax = 0;
    1467       while (!itIn.pastEnd()) {
    1468         itIn.array() *= factors(freqIDs(ax));         // Writes back to dataIn
    1469         itIn.next();
    1470       }
    1471 
    1472 // Write out
    1473 
    1474       putDataInSDC(sc, dataIn.getArray(), dataIn.getMask());
    1475 //
    1476       pTabOut->putSDContainer(sc);
    1477    }
    1478 }
    1479 
    1480 
    1481 
    1482 SDMemTable* SDMath::frequencyAlign(const SDMemTable& in,
    1483                                    MFrequency::Types freqSystem,
    1484                                    const String& refTime,
    1485                                    const String& methodStr,
    1486                                    Bool perFreqID)
    1487 {
    1488 // Get Header
    1489 
    1490    SDHeader sh = in.getSDHeader();
    1491    const uInt nChan = sh.nchan;
    1492    const uInt nRows = in.nRow();
    1493    const uInt nIF = sh.nif;
    1494 
    1495 // Get Table reference
    1496 
    1497    const Table& tabIn = in.table();
    1498 
    1499 // Get Columns from Table
    1500 
    1501    ROScalarColumn<Double> mjdCol(tabIn, "TIME");
    1502    ROScalarColumn<String> srcCol(tabIn, "SRCNAME");
    1503    ROArrayColumn<uInt> fqIDCol(tabIn, "FREQID");
    1504    Vector<Double> times = mjdCol.getColumn();
    1505 
    1506 // Generate DataDesc table
    1507 
    1508    Matrix<uInt> ddIdx;
    1509    SDDataDesc dDesc;
    1510    generateDataDescTable(ddIdx, dDesc, nIF, in, tabIn, srcCol,
    1511                           fqIDCol, perFreqID);
    1512 
    1513 // Get reference Epoch to time of first row or given String
    1514 
    1515    Unit DAY(String("d"));
    1516    MEpoch::Ref epochRef(in.getTimeReference());
    1517    MEpoch refEpoch;
    1518    if (refTime.length()>0) {
    1519      refEpoch = epochFromString(refTime, in.getTimeReference());
    1520    } else {
    1521      refEpoch = in.getEpoch(0);
    1522    }
    1523    ostringstream oss;
    1524    oss << "Aligned at reference Epoch " << formatEpoch(refEpoch) << " in frame " << MFrequency::showType(freqSystem);
    1525    pushLog(String(oss));
    1526 
    1527    // Get Reference Position
    1528 
    1529    MPosition refPos = in.getAntennaPosition();
    1530 
    1531    // Create FrequencyAligner Block. One FA for each possible
    1532    // source/freqID (perFreqID=True) or source/IF (perFreqID=False)
    1533    // combination
    1534 
    1535    PtrBlock<FrequencyAligner<Float>* > a(dDesc.length());
    1536    generateFrequencyAligners(a, dDesc, in, nChan, freqSystem, refPos,
    1537                               refEpoch, perFreqID);
    1538 
    1539    // Generate and fill output Frequency Table.  WHen perFreqID=True,
    1540    // there is one output FreqID for each entry in the SDDataDesc
    1541    // table.  However, in perFreqID=False mode, there may be some
    1542    // degeneracy, so we need a little translation map
    1543 
    1544    SDFrequencyTable freqTabOut = in.getSDFreqTable();
    1545    freqTabOut.setLength(0);
    1546    Vector<String> units(1);
    1547    units = String("Hz");
    1548    Bool linear=True;
    1549    //
    1550    Vector<uInt> ddFQTrans(dDesc.length(),0);
    1551    for (uInt i=0; i<dDesc.length(); i++) {
    1552 
    1553      // Get Aligned SC in Hz
    1554 
    1555      SpectralCoordinate sC = a[i]->alignedSpectralCoordinate(linear);
    1556      sC.setWorldAxisUnits(units);
    1557 
    1558      // Add FreqID
    1559 
    1560      uInt idx = freqTabOut.addFrequency(sC.referencePixel()[0],
    1561                                         sC.referenceValue()[0],
    1562                                         sC.increment()[0]);
    1563      // output FreqID = ddFQTrans(ddIdx)
    1564      ddFQTrans(i) = idx;
    1565    }
    1566 
    1567    // Interpolation method
    1568 
    1569    InterpolateArray1D<Double,Float>::InterpolationMethod interp;
    1570    convertInterpString(interp, methodStr);
    1571 
    1572    // New output Table
    1573 
    1574    //pushLog("Create output table");
    1575    SDMemTable* pTabOut = new SDMemTable(in,True);
    1576    pTabOut->putSDFreqTable(freqTabOut);
    1577 
    1578    // Loop over rows in Table
    1579 
    1580    Bool extrapolate=False;
    1581    const IPosition polChanAxes(2, asap::PolAxis, asap::ChanAxis);
    1582    Bool useCachedAbcissa = False;
    1583    Bool first = True;
    1584    Bool ok;
    1585    Vector<Float> yOut;
    1586    Vector<Bool> maskOut;
    1587    Vector<uInt> freqID(nIF);
    1588    uInt ifIdx, faIdx;
    1589    Vector<Double> xIn;
    1590    //
    1591    for (uInt iRow=0; iRow<nRows; ++iRow) {
    1592 //      if (iRow%10==0) {
    1593 //        ostringstream oss;
    1594 //        oss << "Processing row " << iRow;
    1595 //        pushLog(String(oss));
    1596 //      }
    1597 
    1598      // Get EPoch
    1599 
    1600      Quantum<Double> tQ2(times[iRow],DAY);
    1601      MVEpoch mv2(tQ2);
    1602      MEpoch epoch(mv2, epochRef);
    1603 
    1604      // Get copy of data
    1605 
    1606      const MaskedArray<Float>& mArrIn(in.rowAsMaskedArray(iRow));
    1607      Array<Float> values = mArrIn.getArray();
    1608      Array<Bool> mask = mArrIn.getMask();
    1609 
    1610      // For each row, the Frequency abcissa will be the same
    1611      // regardless of polarization.  For all other axes (IF and BEAM)
    1612      // the abcissa will change.  So we iterate through the data by
    1613      // pol-chan planes to mimimize the work.  Probably won't work for
    1614      // multiple beams at this point.
    1615 
    1616      ArrayIterator<Float> itValuesPlane(values, polChanAxes);
    1617      ArrayIterator<Bool> itMaskPlane(mask, polChanAxes);
    1618      while (!itValuesPlane.pastEnd()) {
    1619 
    1620        // Find the IF index and then the FA PtrBlock index
    1621 
    1622        const IPosition& pos = itValuesPlane.pos();
    1623        ifIdx = pos(asap::IFAxis);
    1624        faIdx = ddIdx(iRow,ifIdx);
    1625 
    1626        // Generate abcissa for perIF.  Could cache this in a Matrix on
    1627        // a per scan basis.  Pretty expensive doing it for every row.
    1628 
    1629        if (!perFreqID) {
    1630          xIn.resize(nChan);
    1631          uInt fqID = dDesc.secID(ddIdx(iRow,ifIdx));
    1632          SpectralCoordinate sC = in.getSpectralCoordinate(fqID);
    1633            Double w;
    1634            for (uInt i=0; i<nChan; i++) {
    1635              sC.toWorld(w,Double(i));
    1636               xIn[i] = w;
    1637            }
    1638        }
    1639 
    1640        VectorIterator<Float> itValuesVec(itValuesPlane.array(), 1);
    1641        VectorIterator<Bool> itMaskVec(itMaskPlane.array(), 1);
    1642 
    1643        // Iterate through the plane by vector and align
    1644 
    1645         first = True;
    1646         useCachedAbcissa=False;
    1647         while (!itValuesVec.pastEnd()) {
    1648           if (perFreqID) {
    1649             ok = a[faIdx]->align (yOut, maskOut, itValuesVec.vector(),
    1650                                   itMaskVec.vector(), epoch, useCachedAbcissa,
    1651                                   interp, extrapolate);
    1652           } else {
    1653             ok = a[faIdx]->align (yOut, maskOut, xIn, itValuesVec.vector(),
    1654                                   itMaskVec.vector(), epoch, useCachedAbcissa,
    1655                                   interp, extrapolate);
    1656           }
    1657           //
    1658           itValuesVec.vector() = yOut;
    1659           itMaskVec.vector() = maskOut;
    1660           //
    1661           itValuesVec.next();
    1662           itMaskVec.next();
    1663           //
    1664           if (first) {
    1665             useCachedAbcissa = True;
    1666             first = False;
    1667           }
    1668         }
    1669         //
    1670         itValuesPlane.next();
    1671         itMaskPlane.next();
    1672      }
    1673 
    1674      // Create SDContainer and put back
    1675 
    1676      SDContainer sc = in.getSDContainer(iRow);
    1677      putDataInSDC(sc, values, mask);
    1678 
    1679      // Set output FreqIDs
    1680 
    1681      for (uInt i=0; i<nIF; i++) {
    1682        uInt idx = ddIdx(iRow,i);               // Index into SDDataDesc table
    1683        freqID(i) = ddFQTrans(idx);             // FreqID in output FQ table
    1684      }
    1685      sc.putFreqMap(freqID);
    1686      //
    1687      pTabOut->putSDContainer(sc);
    1688    }
    1689 
    1690    // Now we must set the base and extra frames to the input frame
    1691    std::vector<string> info = pTabOut->getCoordInfo();
    1692    info[1] = MFrequency::showType(freqSystem);   // Conversion frame
    1693    info[3] = info[1];                            // Base frame
    1694    pTabOut->setCoordInfo(info);
    1695 
    1696    // Clean up PointerBlock
    1697    for (uInt i=0; i<a.nelements(); i++) delete a[i];
    1698 
    1699    return pTabOut;
    1700 }
    1701 
    1702 
    1703 SDMemTable* SDMath::frequencySwitch(const SDMemTable& in)
    1704 {
    1705   if (in.nIF() != 2) {
    1706     throw(AipsError("nIF != 2 "));
    1707   }
    1708   Bool clear = True;
    1709   SDMemTable* pTabOut = new SDMemTable(in, clear);
    1710   const Table& tabIn = in.table();
    1711 
    1712   // Shape of input and output data
    1713   const IPosition& shapeIn = in.rowAsMaskedArray(0).shape();
    1714 
    1715   const uInt nRows = in.nRow();
    1716   AlwaysAssert(asap::nAxes==4,AipsError);
    1717 
    1718   ROArrayColumn<Float> tSysCol;
    1719   Array<Float> tsys;
    1720   tSysCol.attach(tabIn,"TSYS");
    1721 
    1722   for (uInt iRow=0; iRow<nRows; iRow++) {
    1723     // Get data for this row
    1724     MaskedArray<Float> marr(in.rowAsMaskedArray(iRow));
    1725     tSysCol.get(iRow, tsys);
    1726 
    1727     // whole Array for IF 0
    1728     IPosition start(asap::nAxes,0);
    1729     IPosition end = shapeIn-1;
    1730     end(asap::IFAxis) = 0;
    1731 
    1732     MaskedArray<Float> on = marr(start,end);
    1733     Array<Float> ton = tsys(start,end);
    1734     // Make a copy as "src" is a refrence which is manipulated.
    1735     // oncopy is needed for the inverse quotient
    1736     MaskedArray<Float> oncopy = on.copy();
    1737 
    1738     // whole Array for IF 1
    1739     start(asap::IFAxis) = 1;
    1740     end(asap::IFAxis) = 1;
    1741 
    1742     MaskedArray<Float> off = marr(start,end);
    1743     Array<Float> toff = tsys(start,end);
    1744 
    1745     on /= off; on -= 1.0f;
    1746     on *= ton;
    1747     off /= oncopy; off -= 1.0f;
    1748     off *= toff;
    1749 
    1750     SDContainer sc = in.getSDContainer(iRow);
    1751     putDataInSDC(sc, marr.getArray(), marr.getMask());
    1752     pTabOut->putSDContainer(sc);
    1753   }
    1754   return pTabOut;
    1755 }
    1756 
    1757 void SDMath::fillSDC(SDContainer& sc,
    1758                      const Array<Bool>& mask,
    1759                      const Array<Float>& data,
    1760                      const Array<Float>& tSys,
    1761                      Int scanID, Double timeStamp,
    1762                      Double interval, const String& sourceName,
    1763                      const Vector<uInt>& freqID)
    1764 {
    1765 // Data and mask
    1766 
    1767   putDataInSDC(sc, data, mask);
    1768 
    1769 // TSys
    1770 
    1771   sc.putTsys(tSys);
    1772 
    1773 // Time things
    1774 
    1775   sc.timestamp = timeStamp;
    1776   sc.interval = interval;
    1777   sc.scanid = scanID;
    1778 //
    1779   sc.sourcename = sourceName;
    1780   sc.putFreqMap(freqID);
    1781 }
    1782 
    1783 void SDMath::accumulate(Double& timeSum, Double& intSum, Int& nAccum,
    1784                         MaskedArray<Float>& sum, Array<Float>& sumSq,
    1785                         Array<Float>& nPts, Array<Float>& tSysSum,
    1786                         Array<Float>& tSysSqSum,
    1787                         const Array<Float>& tSys, const Array<Float>& nInc,
    1788                         const Vector<Bool>& mask, Double time, Double interval,
    1789                         const std::vector<CountedPtr<SDMemTable> >& in,
    1790                         uInt iTab, uInt iRow, uInt axis,
    1791                         uInt nAxesSub, Bool useMask,
    1792                         WeightType wtType)
    1793 {
    1794 
    1795 // Get data
    1796 
    1797    MaskedArray<Float> dataIn(in[iTab]->rowAsMaskedArray(iRow));
    1798    Array<Float>& valuesIn = dataIn.getRWArray();           // writable reference
    1799    const Array<Bool>& maskIn = dataIn.getMask();          // RO reference
    1800 //
    1801    if (wtType==NONE) {
    1802       const MaskedArray<Float> n(nInc,dataIn.getMask());
    1803       nPts += n;                               // Only accumulates where mask==T
    1804    } else if (wtType==TINT) {
    1805 
    1806 // We are weighting the data by integration time.
    1807 
    1808      valuesIn *= Float(interval);
    1809 
    1810    } else if (wtType==VAR) {
    1811 
    1812 // We are going to average the data, weighted by the noise for each pol, beam and IF.
    1813 // So therefore we need to iterate through by spectrum (axis 3)
    1814 
    1815       VectorIterator<Float> itData(valuesIn, axis);
    1816       ReadOnlyVectorIterator<Bool> itMask(maskIn, axis);
    1817       Float fac = 1.0;
    1818       IPosition pos(nAxesSub,0);
    1819 //
    1820       while (!itData.pastEnd()) {
    1821 
    1822 // Make MaskedArray of Vector, optionally apply OTF mask, and find scaling factor
    1823 
    1824          if (useMask) {
    1825             MaskedArray<Float> tmp(itData.vector(),mask&&itMask.vector());
    1826             fac = 1.0/variance(tmp);
    1827          } else {
    1828             MaskedArray<Float> tmp(itData.vector(),itMask.vector());
    1829             fac = 1.0/variance(tmp);
    1830          }
    1831 
    1832 // Scale data
    1833 
    1834          itData.vector() *= fac;     // Writes back into 'dataIn'
    1835 //
    1836 // Accumulate variance per if/pol/beam averaged over spectrum
    1837 // This method to get pos2 from itData.pos() is only valid
    1838 // because the spectral axis is the last one (so we can just
    1839 // copy the first nAXesSub positions out)
    1840 
    1841          pos = itData.pos().getFirst(nAxesSub);
    1842          sumSq(pos) += fac;
    1843 //
    1844          itData.next();
    1845          itMask.next();
    1846       }
    1847    } else if (wtType==TSYS || wtType==TINTSYS) {
    1848 
    1849 // We are going to average the data, weighted by 1/Tsys**2 for each pol, beam and IF.
    1850 // So therefore we need to iterate through by spectrum (axis 3).  Although
    1851 // Tsys is stored as a vector of length nChan, the values are replicated.
    1852 // We will take a short cut and just use the value from the first channel
    1853 // for now.
    1854 //
    1855       VectorIterator<Float> itData(valuesIn, axis);
    1856       ReadOnlyVectorIterator<Float> itTSys(tSys, axis);
    1857       IPosition pos(nAxesSub,0);
    1858 //
    1859       Float fac = 1.0;
    1860       if (wtType==TINTSYS) fac *= interval;
    1861       while (!itData.pastEnd()) {
    1862          Float t = itTSys.vector()[0];
    1863          fac *= 1.0/t/t;
    1864 
    1865 // Scale data
    1866 
    1867          itData.vector() *= fac;     // Writes back into 'dataIn'
    1868 //
    1869 // Accumulate Tsys  per if/pol/beam averaged over spectrum
    1870 // This method to get pos2 from itData.pos() is only valid
    1871 // because the spectral axis is the last one (so we can just
    1872 // copy the first nAXesSub positions out)
    1873 
    1874          pos = itData.pos().getFirst(nAxesSub);
    1875          tSysSqSum(pos) += fac;
    1876 //
    1877          itData.next();
    1878          itTSys.next();
    1879       }
    1880    }
    1881 
    1882 // Accumulate sum of (possibly scaled) data
    1883 
    1884    sum += dataIn;
    1885 
    1886 // Accumulate Tsys, time, and interval
    1887 
    1888    tSysSum += tSys;
    1889    timeSum += time;
    1890    intSum += interval;
    1891    nAccum += 1;
    1892 }
    1893 
    1894 
    1895 void SDMath::normalize(MaskedArray<Float>& sum,
    1896                        const Array<Float>& sumSq,
    1897                        const Array<Float>& tSysSqSum,
    1898                        const Array<Float>& nPts,
    1899                        Double intSum,
    1900                        WeightType wtType, Int axis,
    1901                        Int nAxesSub)
    1902 {
    1903    IPosition pos2(nAxesSub,0);
    1904 //
    1905    if (wtType==NONE) {
    1906 
    1907 // We just average by the number of points accumulated.
    1908 // We need to make a MA out of nPts so that no divide by
    1909 // zeros occur
    1910 
    1911       MaskedArray<Float> t(nPts, (nPts>Float(0.0)));
    1912       sum /= t;
    1913    } else if (wtType==TINT) {
    1914 
    1915 // Average by sum of Tint
    1916 
    1917       sum /= Float(intSum);
    1918    } else if (wtType==VAR) {
    1919 
    1920 // Normalize each spectrum by sum(1/var) where the variance
    1921 // is worked out for each spectrum
    1922 
    1923       Array<Float>& data = sum.getRWArray();
    1924       VectorIterator<Float> itData(data, axis);
    1925       while (!itData.pastEnd()) {
    1926          pos2 = itData.pos().getFirst(nAxesSub);
    1927          itData.vector() /= sumSq(pos2);
    1928          itData.next();
    1929       }
    1930    } else if (wtType==TSYS || wtType==TINTSYS) {
    1931 
    1932 // Normalize each spectrum by sum(1/Tsys**2) (TSYS) or
    1933 // sum(Tint/Tsys**2) (TINTSYS) where the pseudo
    1934 // replication over channel for Tsys has been dropped.
    1935 
    1936       Array<Float>& data = sum.getRWArray();
    1937       VectorIterator<Float> itData(data, axis);
    1938       while (!itData.pastEnd()) {
    1939          pos2 = itData.pos().getFirst(nAxesSub);
    1940          itData.vector() /= tSysSqSum(pos2);
    1941          itData.next();
    1942       }
    1943    }
    1944 }
    1945 
    1946 
    1947 
    1948 
    1949 void SDMath::setCursorSlice (IPosition& start, IPosition& end, Bool doAll, const SDMemTable& in) const
    1950 {
    1951   const uInt nDim = asap::nAxes;
    1952   DebugAssert(nDim==4,AipsError);
    1953 //
    1954   start.resize(nDim);
    1955   end.resize(nDim);
    1956   if (doAll) {
    1957      start = 0;
    1958      end(0) = in.nBeam()-1;
    1959      end(1) = in.nIF()-1;
    1960      end(2) = in.nPol()-1;
    1961      end(3) = in.nChan()-1;
    1962   } else {
    1963      start(0) = in.getBeam();
    1964      end(0) = start(0);
    1965 //
    1966      start(1) = in.getIF();
    1967      end(1) = start(1);
    1968 //
    1969      start(2) = in.getPol();
    1970      end(2) = start(2);
    1971 //
    1972      start(3) = 0;
    1973      end(3) = in.nChan()-1;
    1974    }
    1975 }
    1976 
    1977 
    1978 void SDMath::convertWeightString(WeightType& wtType, const String& weightStr,
    1979                                  Bool listType)
    1980 {
    1981   String tStr(weightStr);
    1982   tStr.upcase();
    1983   String msg;
    1984   if (tStr.contains(String("NONE"))) {
    1985      wtType = NONE;
    1986      msg = String("Weighting type selected : None");
    1987   } else if (tStr.contains(String("VAR"))) {
    1988      wtType = VAR;
    1989      msg = String("Weighting type selected : Variance");
    1990   } else if (tStr.contains(String("TINTSYS"))) {
    1991        wtType = TINTSYS;
    1992        msg = String("Weighting type selected : Tint&Tsys");
    1993   } else if (tStr.contains(String("TINT"))) {
    1994      wtType = TINT;
    1995      msg = String("Weighting type selected : Tint");
    1996   } else if (tStr.contains(String("TSYS"))) {
    1997      wtType = TSYS;
    1998      msg = String("Weighting type selected : Tsys");
    1999   } else {
    2000      msg = String("Weighting type selected : None");
    2001      throw(AipsError("Unrecognized weighting type"));
    2002   }
    2003 //
    2004   if (listType) pushLog(msg);
    2005 }
    2006 
    2007 
    2008 void SDMath::convertInterpString(casa::InterpolateArray1D<Double,Float>::InterpolationMethod& type,
    2009                                  const casa::String& interp)
    2010 {
    2011   String tStr(interp);
    2012   tStr.upcase();
    2013   if (tStr.contains(String("NEAR"))) {
    2014      type = InterpolateArray1D<Double,Float>::nearestNeighbour;
    2015   } else if (tStr.contains(String("LIN"))) {
    2016      type = InterpolateArray1D<Double,Float>::linear;
    2017   } else if (tStr.contains(String("CUB"))) {
    2018      type = InterpolateArray1D<Double,Float>::cubic;
    2019   } else if (tStr.contains(String("SPL"))) {
    2020      type = InterpolateArray1D<Double,Float>::spline;
    2021   } else {
    2022     throw(AipsError("Unrecognized interpolation type"));
    2023   }
    2024 }
    2025 
    2026 void SDMath::putDataInSDC(SDContainer& sc, const Array<Float>& data,
    2027                           const Array<Bool>& mask)
    2028 {
    2029     sc.putSpectrum(data);
    2030 //
    2031     Array<uChar> outflags(data.shape());
    2032     convertArray(outflags,!mask);
    2033     sc.putFlags(outflags);
    2034 }
    2035 
    2036 Table SDMath::readAsciiFile(const String& fileName) const
    2037 {
    2038    String formatString;
    2039    Table tbl = readAsciiTable (formatString, Table::Memory, fileName, "", "", False);
    2040    return tbl;
    2041 }
    2042 
    2043 
    2044 
    2045 void SDMath::scaleFromAsciiTable(SDMemTable* pTabOut,
    2046                                  const SDMemTable& in, const String& fileName,
    2047                                  const String& col0, const String& col1,
    2048                                  const String& methodStr, Bool doAll,
    2049                                  const Vector<Float>& xOut, Bool doTSys)
    2050 {
    2051 
    2052 // Read gain-elevation ascii file data into a Table.
    2053 
    2054   Table geTable = readAsciiFile (fileName);
    2055 //
    2056   scaleFromTable (pTabOut, in, geTable, col0, col1, methodStr, doAll, xOut, doTSys);
    2057 }
    2058 
    2059 void SDMath::scaleFromTable(SDMemTable* pTabOut, const SDMemTable& in,
    2060                             const Table& tTable, const String& col0,
    2061                             const String& col1,
    2062                             const String& methodStr, Bool doAll,
    2063                             const Vector<Float>& xOut, Bool doTsys)
    2064 {
    2065 
    2066 // Get data from Table
    2067 
    2068   ROScalarColumn<Float> geElCol(tTable, col0);
    2069   ROScalarColumn<Float> geFacCol(tTable, col1);
    2070   Vector<Float> xIn = geElCol.getColumn();
    2071   Vector<Float> yIn = geFacCol.getColumn();
    2072   Vector<Bool> maskIn(xIn.nelements(),True);
    2073 
    2074 // Interpolate (and extrapolate) with desired method
    2075 
    2076    InterpolateArray1D<Double,Float>::InterpolationMethod method;
    2077    convertInterpString(method, methodStr);
    2078    Int intMethod(method);
    2079 //
    2080    Vector<Float> yOut;
    2081    Vector<Bool> maskOut;
    2082    InterpolateArray1D<Float,Float>::interpolate(yOut, maskOut, xOut,
    2083                                                 xIn, yIn, maskIn, intMethod,
    2084                                                 True, True);
    2085 // Apply
    2086 
    2087    scaleByVector(pTabOut, in, doAll, Float(1.0)/yOut, doTsys);
    2088 }
    2089 
    2090 
    2091 void SDMath::scaleByVector(SDMemTable* pTabOut, const SDMemTable& in,
    2092                            Bool doAll, const Vector<Float>& factor,
    2093                            Bool doTSys)
    2094 {
    2095 
    2096 // Set up data slice
    2097 
    2098   IPosition start, end;
    2099   setCursorSlice (start, end, doAll, in);
    2100 
    2101 // Get Tsys column
    2102 
    2103   const Table& tIn = in.table();
    2104   ArrayColumn<Float> tSysCol(tIn, "TSYS");
    2105   Array<Float> tSys;
    2106 
    2107 // Loop over rows and apply correction factor
    2108 
    2109   const uInt axis = asap::ChanAxis;
    2110   for (uInt i=0; i < in.nRow(); ++i) {
    2111 
    2112 // Get data
    2113 
    2114      MaskedArray<Float> dataIn(in.rowAsMaskedArray(i));
    2115      MaskedArray<Float> dataIn2 = dataIn(start,end);  // reference to dataIn
    2116 //
    2117      if (doTSys) {
    2118         tSysCol.get(i, tSys);
    2119         Array<Float> tSys2 = tSys(start,end) * factor[i];
    2120         tSysCol.put(i, tSys);
    2121      }
    2122 
    2123 // Apply factor
    2124 
    2125      dataIn2 *= factor[i];
    2126 
    2127 // Write out
    2128 
    2129      SDContainer sc = in.getSDContainer(i);
    2130      putDataInSDC(sc, dataIn.getArray(), dataIn.getMask());
    2131 //
    2132      pTabOut->putSDContainer(sc);
    2133   }
    2134 }
    2135 
    2136 
    2137 
    2138 
    2139 void SDMath::generateDataDescTable (Matrix<uInt>& ddIdx,
    2140                                     SDDataDesc& dDesc,
    2141                                     uInt nIF,
    2142                                     const SDMemTable& in,
    2143                                     const Table& tabIn,
    2144                                     const ROScalarColumn<String>& srcCol,
    2145                                     const ROArrayColumn<uInt>& fqIDCol,
    2146                                     Bool perFreqID)
    2147 {
    2148    const uInt nRows = tabIn.nrow();
    2149    ddIdx.resize(nRows,nIF);
    2150 //
    2151    String srcName;
    2152    Vector<uInt> freqIDs;
    2153    for (uInt iRow=0; iRow<nRows; iRow++) {
    2154       srcCol.get(iRow, srcName);
    2155       fqIDCol.get(iRow, freqIDs);
    2156       const MDirection& dir = in.getDirection(iRow);
    2157 //
    2158       if (perFreqID) {
    2159 
    2160 // One entry per source/freqID pair
    2161 
    2162          for (uInt iIF=0; iIF<nIF; iIF++) {
    2163             ddIdx(iRow,iIF) = dDesc.addEntry(srcName, freqIDs[iIF], dir, 0);
    2164          }
    2165       } else {
    2166 
    2167 // One entry per source/IF pair.  Hang onto the FreqID as well
    2168 
    2169          for (uInt iIF=0; iIF<nIF; iIF++) {
    2170             ddIdx(iRow,iIF) = dDesc.addEntry(srcName, iIF, dir, freqIDs[iIF]);
    2171          }
    2172       }
    2173    }
    2174 }
    2175 
    2176 
    2177 
    2178 
    2179 
    2180 MEpoch SDMath::epochFromString(const String& str, MEpoch::Types timeRef)
    2181 {
    2182    Quantum<Double> qt;
    2183    if (MVTime::read(qt,str)) {
    2184       MVEpoch mv(qt);
    2185       MEpoch me(mv, timeRef);
    2186       return me;
    2187    } else {
    2188       throw(AipsError("Invalid format for Epoch string"));
    2189    }
    2190 }
    2191 
    2192 
    2193 String SDMath::formatEpoch(const MEpoch& epoch)  const
    2194 {
    2195    MVTime mvt(epoch.getValue());
    2196    return mvt.string(MVTime::YMD) + String(" (") + epoch.getRefString() + String(")");
    2197 }
    2198 
    2199 
    2200 
    2201 void SDMath::generateFrequencyAligners(PtrBlock<FrequencyAligner<Float>* >& a,
    2202                                        const SDDataDesc& dDesc,
    2203                                        const SDMemTable& in, uInt nChan,
    2204                                        MFrequency::Types system,
    2205                                        const MPosition& refPos,
    2206                                        const MEpoch& refEpoch,
    2207                                        Bool perFreqID)
    2208 {
    2209    for (uInt i=0; i<dDesc.length(); i++) {
    2210       uInt ID = dDesc.ID(i);
    2211       uInt secID = dDesc.secID(i);
    2212       const MDirection& refDir = dDesc.secDir(i);
    2213 //
    2214       if (perFreqID) {
    2215 
    2216 // One aligner per source/FreqID pair.
    2217 
    2218          SpectralCoordinate sC = in.getSpectralCoordinate(ID);
    2219          a[i] = new FrequencyAligner<Float>(sC, nChan, refEpoch, refDir, refPos, system);
    2220       } else {
    2221 
    2222 // One aligner per source/IF pair.  But we still need the FreqID to
    2223 // get the right SC.  Hence the messing about with the secondary ID
    2224 
    2225          SpectralCoordinate sC = in.getSpectralCoordinate(secID);
    2226          a[i] = new FrequencyAligner<Float>(sC, nChan, refEpoch, refDir, refPos, system);
    2227       }
    2228    }
    2229 }
    2230 
    2231 Vector<uInt> SDMath::getRowRange(const SDMemTable& in) const
    2232 {
    2233    Vector<uInt> range(2);
    2234    range[0] = 0;
    2235    range[1] = in.nRow()-1;
    2236    return range;
    2237 }
    2238 
    2239 
    2240 Bool SDMath::rowInRange(uInt i, const Vector<uInt>& range) const
    2241 {
    2242    return (i>=range[0] && i<=range[1]);
    2243 }
    2244 
     794      specCol.put(i, specout);
     795    }
     796  }
     797  return out;
     798}
  • trunk/src/STMath.h

    r804 r805  
    1 //#---------------------------------------------------------------------------
    2 //# SDMath.h: A collection of single dish mathematical operations
    3 //#---------------------------------------------------------------------------
    4 //# Copyright (C) 2004
    5 //# ATNF
    6 //#
    7 //# This program is free software; you can redistribute it and/or modify it
    8 //# under the terms of the GNU General Public License as published by the Free
    9 //# Software Foundation; either version 2 of the License, or (at your option)
    10 //# any later version.
    11 //#
    12 //# This program is distributed in the hope that it will be useful, but
    13 //# WITHOUT ANY WARRANTY; without even the implied warranty of
    14 //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
    15 //# Public License for more details.
    16 //#
    17 //# You should have received a copy of the GNU General Public License along
    18 //# with this program; if not, write to the Free Software Foundation, Inc.,
    19 //# 675 Massachusetts Ave, Cambridge, MA 02139, USA.
    20 //#
    21 //# Correspondence concerning this software should be addressed as follows:
    22 //#        Internet email: Malte.Marquarding@csiro.au
    23 //#        Postal address: Malte Marquarding,
    24 //#                        Australia Telescope National Facility,
    25 //#                        P.O. Box 76,
    26 //#                        Epping, NSW, 2121,
    27 //#                        AUSTRALIA
    28 //#
    29 //# $Id:
    30 //#---------------------------------------------------------------------------
    31 #ifndef SDMATH_H
    32 #define SDMATH_H
     1//
     2// C++ Interface: STMath
     3//
     4// Description:
     5//
     6//
     7// Author: Malte Marquarding <asap@atnf.csiro.au>, (C) 2006
     8//
     9// Copyright: See COPYING file that comes with this distribution
     10//
     11//
     12#ifndef ASAPSTMATH_H
     13#define ASAPSTMATH_H
    3314
    3415#include <string>
    35 #include <vector>
     16#include <map>
     17
    3618#include <casa/aips.h>
    3719#include <casa/Utilities/CountedPtr.h>
    38 #include <coordinates/Coordinates/FrequencyAligner.h>
     20#include <casa/BasicSL/String.h>
     21#include <casa/Arrays/Vector.h>
     22#include <scimath/Mathematics/InterpolateArray1D.h>
    3923
     24#include "Scantable.h"
    4025#include "SDDefs.h"
    4126#include "SDLog.h"
    4227
    43 class casa::Table;
    44 class casa::MEpoch;
    45 class casa::MPosition;
    46 template<class T> class casa::PtrBlock;
    47 template<class T> class casa::Matrix;
    48 template<class T> class casa::ROScalarColumn;
    49 template<class T> class casa::ROArrayColumn;
    50 
    5128namespace asap {
    5229
    53 class SDMemTable;
    54 class SDDataDesc;
    55  
    56 class SDMath : private SDLog {
     30/**
     31Mathmatical operations on Scantable objects
    5732
     33@author Malte Marquarding
     34*/
     35class STMath : private SDLog {
    5836public:
    59  
    60   // Default constructor
    61   SDMath();
    62  
    63   // Copy Constructor (copy semantics)
    64   SDMath(const SDMath& other);
    65  
    66   // Assignment  (copy semantics)
    67   SDMath &operator=(const SDMath& other);
    68  
    69   // Destructor
    70   ~SDMath();
    71  
    72   // Binary Table operators. op=ADD, SUB, MUL, DIV, QUOTIENT
    73   casa::CountedPtr<SDMemTable> binaryOperate(const casa::CountedPtr<SDMemTable>& left,
    74                                              const casa::CountedPtr<SDMemTable>& right,
    75                                              const casa::String& op, casa::Bool preserve,
    76                                              casa::Bool tSys);
    77    
    78     // Average in time
    79     casa::CountedPtr<SDMemTable> average(const std::vector<casa::CountedPtr<SDMemTable> >& in,
    80                                          const casa::Vector<casa::Bool>& mask,
    81                                          casa::Bool scanAverage,
    82                                          const casa::String& weightStr,
    83                                          casa::Bool align=casa::False);
    84    
    85   // Statistics. If row<0, all rows are done otherwise, just the
    86   // specified row.
    87   std::vector<float> statistic(const casa::CountedPtr<SDMemTable>& in,
    88                                const casa::Vector<casa::Bool>& mask,
    89                                const casa::String& which, casa::Int row) const;
    90                                
    91 // Bin up spectra
    92    SDMemTable* bin(const SDMemTable& in, casa::Int width);
    9337
    94   // Resample spectra
    95    SDMemTable* resample(const SDMemTable& in, const casa::String& method,
    96                         casa::Float factor);
     38  typedef casa::InterpolateArray1D<casa::Double,
     39                                   casa::Float>::InterpolationMethod imethod;
    9740
    98 // Smooth
    99   SDMemTable* smooth(const SDMemTable& in, const casa::String& kernel,
    100                       casa::Float width, casa::Bool doAll);
     41  typedef std::map<std::string, imethod> imap;
    10142
    102 // Flux conversion between Jansky and Kelvin
    103    SDMemTable* convertFlux(const SDMemTable& in, casa::Float D,
    104                            casa::Float etaAp,
    105                            casa::Float JyPerK, casa::Bool doAll);
     43  STMath(bool insitu=true);
    10644
    107 // Gain-elevation correction
    108    SDMemTable* gainElevation(const SDMemTable& in,
    109                              const casa::Vector<casa::Float>& coeffs,
    110                              const casa::String& fileName,
    111                              const casa::String& method,
    112                              casa::Bool doAll);
     45  ~STMath();
    11346
    114 // Frequency Alignment
    115    SDMemTable* frequencyAlignment(const SDMemTable& in, const casa::String& refTime,
    116                                    const casa::String& method, casa::Bool perFreqID);
     47  /**
     48   * set the @attr insitu attribute
     49   * @param b
     50   */
     51  bool insitu() const { return insitu_;};
     52  void setInsitu(bool b) { insitu_ = b; };
    11753
    118 // Opacity correction
    119    SDMemTable* opacity(const SDMemTable& in, casa::Float tau, casa::Bool doAll);
     54  casa::CountedPtr<Scantable>
     55    average( const std::vector<casa::CountedPtr<Scantable> >& in,
     56             const casa::Vector<casa::Bool>& mask,
     57             const std::string& weight,
     58             const std::string& avmode = "",
     59             bool alignfreq = false );
    12060
    121 // Simple unary mathematical operations.  what=0 (mul) or 1 (add)
    122    SDMemTable* unaryOperate(const SDMemTable& in, casa::Float offset,
    123                             casa::Bool doAll, casa::uInt what, casa::Bool tSys);
     61  casa::CountedPtr<Scantable>
     62    unaryOperate( const casa::CountedPtr<Scantable>& in, float val,
     63                  const std::string& mode, bool tsys=false );
    12464
    125   // Average polarizations.
    126   SDMemTable* averagePol(const SDMemTable& in,
    127                          const casa::Vector<casa::Bool>& mask,
    128                          const casa::String& wtStr);
     65  casa::CountedPtr<Scantable> quotient( const casa::CountedPtr<Scantable>& in,
     66                                        const std::string& mode = "NEAREST",
     67                                        bool preserve = true );
    12968
    130   SDMemTable* frequencySwitch(const SDMemTable& in);
    131  
     69  casa::CountedPtr<Scantable>
     70    freqSwitch( const casa::CountedPtr<Scantable>& in );
    13271
    133 // Rotate XY phase. Value in degrees.
    134    void rotateXYPhase(SDMemTable& in, casa::Float value, casa::Bool doAll);
     72  std::vector<float> statistic(const casa::CountedPtr<Scantable>& in,
     73                               const std::vector<bool>& mask,
     74                               const std::string& which);
    13575
    136 // Rotate Q & U by operating on the raw correlations.Value in degrees.
    137    void rotateLinPolPhase(SDMemTable& in, casa::Float value, casa::Bool doAll);
     76  casa::CountedPtr<Scantable> bin( const casa::CountedPtr<Scantable>& in,
     77                                   int width=5);
     78  casa::CountedPtr<Scantable>
     79    resample(const casa::CountedPtr<Scantable>& in,
     80             const std::string& method, float width);
    13881
    139  
    140  private:
     82  casa::CountedPtr<Scantable>
     83    smooth(const casa::CountedPtr<Scantable>& in, const std::string& kernel,
     84                      float width);
    14185
    142 // Weighting type for time averaging
     86  casa::CountedPtr<Scantable>
     87    gainElevation(const casa::CountedPtr<Scantable>& in,
     88                  const casa::Vector<casa::Float>& coeffs,
     89                  const std::string& fileName,
     90                  const std::string& method);
     91  casa::CountedPtr<Scantable>
     92    convertFlux(const casa::CountedPtr<Scantable>& in, float d,
     93                float etaap, float jyperk);
    14394
    144   enum WeightType {NONE=0,VAR,TSYS,TINT,TINTSYS,nWeightTypes};
     95  casa::CountedPtr<Scantable> opacity(const casa::CountedPtr<Scantable>& in,
     96                                      float tau);
    14597
    146 // Function to use accumulate data during time averaging
     98  /// @todo frequency alignment
    14799
    148   void accumulate(casa::Double& timeSum, casa::Double& intSum,
    149                   casa::Int& nAccum,
    150                   casa::MaskedArray<casa::Float>& sum,
    151                   casa::Array<casa::Float>& sumSq,
    152                   casa::Array<casa::Float>& nPts,
    153                   casa::Array<casa::Float>& tSysSum,
    154                   casa::Array<casa::Float>& tSysSqSum,
    155                   const casa::Array<casa::Float>& tSys, 
    156                   const casa::Array<casa::Float>& nInc,
    157                   const casa::Vector<casa::Bool>& mask,
    158                   casa::Double time, casa::Double interval,
    159                   const std::vector<casa::CountedPtr<SDMemTable> >& in,
    160                   casa::uInt iTab, casa::uInt iRow,
    161                   casa::uInt axis, casa::uInt nAxesSub,
    162                   casa::Bool useMask, WeightType wtType);
     100private:
     101  static imethod stringToIMethod(const std::string& in);
     102  static WeightType stringToWeight(const std::string& in);
    163103
    164 // Work out conversion factor for converting Jy<->K per IF per row and apply
    165     void convertBrightnessUnits(SDMemTable* pTabOut, const SDMemTable& in,
    166                                 casa::Bool toKelvin, casa::Float sFac, casa::Bool doAll);
     104  void scaleByVector(casa::Table& in,
     105                     const casa::Vector<casa::Float>& factor,
     106                     bool dotsys);
    167107
    168 // Convert weight string to enum value
     108  void scaleFromAsciiTable(casa::Table& in, const std::string& filename,
     109                           const std::string& method,
     110                           const casa::Vector<casa::Float>& xout,
     111                           bool dotsys);
    169112
    170    void convertWeightString(WeightType& wt, const casa::String& weightStr,
    171                              casa::Bool listType);;
     113  void scaleFromTable(casa::Table& in, const casa::Table& table,
     114                      const std::string& method,
     115                      const casa::Vector<casa::Float>& xout, bool dotsys);
    172116
    173 // Convert interpolation type string
    174 //   void convertInterpString(casa::Int& type, const casa::String& interp);
    175    void convertInterpString(casa::InterpolateArray1D<casa::Double,casa::Float>::InterpolationMethod& method, 
    176                              const casa::String& interp);
     117  void convertBrightnessUnits(casa::CountedPtr<Scantable>& in,
     118                              bool tokelvin, float cfac);
    177119
    178 // Scale data with values from an ascii Table
    179    void scaleFromAsciiTable(SDMemTable* pTabOut, const SDMemTable& in,
    180                               const casa::String& fileName,
    181                               const casa::String& col0, const casa::String& col1,
    182                               const casa::String& methodStr, casa::Bool doAll,
    183                               const casa::Vector<casa::Float>& xOut, casa::Bool doTSys);
     120  casa::CountedPtr< Scantable >
     121    getScantable(const casa::CountedPtr< Scantable >& in, bool droprows);
    184122
    185 // Scale data with values from a Table
    186    void scaleFromTable(SDMemTable* pTabOut, const SDMemTable& in, const casa::Table& tTable,
    187                          const casa::String& col0, const casa::String& col1,
    188                          const casa::String& methodStr, casa::Bool doAll,
    189                          const casa::Vector<casa::Float>& xOut, casa::Bool doTSys);
     123  casa::MaskedArray<casa::Float>
     124    maskedArray( const casa::Vector<casa::Float>& s,
     125                 const casa::Vector<casa::uChar>& f );
     126  casa::Vector<casa::uChar>
     127    flagsFromMA(const casa::MaskedArray<casa::Float>& ma);
    190128
    191 // Scale data and optionally TSys by values in a Vector
    192    void scaleByVector(SDMemTable* pTabOut, const SDMemTable& in,
    193                        casa::Bool doAll, const casa::Vector<casa::Float>& factor,
    194                        casa::Bool doTSys);
     129  bool insitu_;
     130};
    195131
    196 // Convert time String to Epoch
    197    casa::MEpoch epochFromString(const casa::String& str, casa::MEpoch::Types timeRef);
    198 
    199 // Function to fill Scan Container when averaging in time
    200 
    201   void fillSDC(SDContainer& sc, const casa::Array<casa::Bool>& mask,
    202                 const casa::Array<casa::Float>& data,
    203                 const casa::Array<casa::Float>& tSys,
    204                 casa::Int scanID, casa::Double timeStamp,
    205                 casa::Double interval, const casa::String& sourceName,
    206                 const casa::Vector<casa::uInt>& freqID);
    207 
    208 // Format EPoch
    209    casa::String formatEpoch(const casa::MEpoch& epoch) const;
    210 
    211 // Align in Frequency
    212    SDMemTable* frequencyAlign(const SDMemTable& in,
    213                               casa::MFrequency::Types system,
    214                               const casa::String& timeRef,
    215                               const casa::String& method,
    216                                casa::Bool perIF);
    217 
    218 // Generate frequency aligners
    219    void generateFrequencyAligners(casa::PtrBlock<casa::FrequencyAligner<casa::Float>* >& a,
    220                                    const SDDataDesc& dDesc,
    221                                    const SDMemTable& in, casa::uInt nChan,
    222                                    casa::MFrequency::Types system,
    223                                    const casa::MPosition& refPos,
    224                                    const casa::MEpoch& refEpoch,
    225                                    casa::Bool perFreqID);
    226 
    227 // Generate data description table(combines source and freqID);
    228    void generateDataDescTable(casa::Matrix<casa::uInt>& ddIdx,
    229                                SDDataDesc& dDesc,
    230                                casa::uInt nIF,
    231                                const SDMemTable& in,
    232                                const casa::Table& tabIn,
    233                                const casa::ROScalarColumn<casa::String>& srcCol,
    234                                const casa::ROArrayColumn<casa::uInt>& fqIDCol,
    235                                casa::Bool perFreqID);
    236 
    237 // Get row range from SDMemTable state
    238   casa::Vector<casa::uInt> getRowRange(const SDMemTable& in) const;
    239 
    240 // Is row in the row range ?
    241   casa::Bool rowInRange(casa::uInt i, const casa::Vector<casa::uInt>& range) const;
    242 
    243 // Set slice to cursor or all axes
    244     void setCursorSlice(casa::IPosition& start, casa::IPosition& end,
    245                         casa::Bool doAll, const SDMemTable& in) const;
    246 
    247 // Function to normalize data when averaging in time
    248 
    249   void normalize(casa::MaskedArray<casa::Float>& data,
    250                   const casa::Array<casa::Float>& sumSq,
    251                   const casa::Array<casa::Float>& tSysSumSq,
    252                   const casa::Array<casa::Float>& nPts,
    253                   casa::Double intSum,
    254                  WeightType wtType, casa::Int axis, casa::Int nAxes);
    255 
    256 // Put the data and mask into the SDContainer
    257    void putDataInSDC(SDContainer& sc, const casa::Array<casa::Float>& data,
    258                      const casa::Array<casa::Bool>& mask);
    259 
    260 // Read ascii file into a Table
    261 
    262   casa::Table readAsciiFile(const casa::String& fileName) const;
    263 
    264 }; // class
    265 
    266 } // namespace
    267 
     132}
    268133#endif
  • trunk/src/Scantable.cpp

    r804 r805  
    1 //#---------------------------------------------------------------------------
    2 //# SDMemTable.cc: A MemoryTable container for single dish integrations
    3 //#---------------------------------------------------------------------------
    4 //# Copyright (C) 2004
    5 //# ATNF
    6 //#
    7 //# This program is free software; you can redistribute it and/or modify it
    8 //# under the terms of the GNU General Public License as published by the Free
    9 //# Software Foundation; either version 2 of the License, or (at your option)
    10 //# any later version.
    11 //#
    12 //# This program is distributed in the hope that it will be useful, but
    13 //# WITHOUT ANY WARRANTY; without even the implied warranty of
    14 //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
    15 //# Public License for more details.
    16 //#
    17 //# You should have received a copy of the GNU General Public License along
    18 //# with this program; if not, write to the Free Software Foundation, Inc.,
    19 //# 675 Massachusetts Ave, Cambridge, MA 02139, USA.
    20 //#
    21 //# Correspondence concerning this software should be addressed as follows:
    22 //#        Internet email: Malte.Marquarding@csiro.au
    23 //#        Postal address: Malte Marquarding,
    24 //#                        Australia Telescope National Facility,
    25 //#                        P.O. Box 76,
    26 //#                        Epping, NSW, 2121,
    27 //#                        AUSTRALIA
    28 //#
    29 //# $Id:
    30 //#---------------------------------------------------------------------------
    31 
     1//
     2// C++ Implementation: Scantable
     3//
     4// Description:
     5//
     6//
     7// Author: Malte Marquarding <asap@atnf.csiro.au>, (C) 2005
     8//
     9// Copyright: See COPYING file that comes with this distribution
     10//
     11//
    3212#include <map>
    3313
     
    3515#include <casa/iostream.h>
    3616#include <casa/iomanip.h>
     17#include <casa/OS/Path.h>
     18#include <casa/OS/File.h>
    3719#include <casa/Arrays/Array.h>
    3820#include <casa/Arrays/ArrayMath.h>
     
    4527#include <casa/BasicSL/Constants.h>
    4628#include <casa/Quanta/MVAngle.h>
     29#include <casa/Containers/RecordField.h>
    4730
    4831#include <tables/Tables/TableParse.h>
     
    5235#include <tables/Tables/ScaColDesc.h>
    5336#include <tables/Tables/ArrColDesc.h>
     37#include <tables/Tables/TableRow.h>
     38#include <tables/Tables/TableVector.h>
     39#include <tables/Tables/TableIter.h>
    5440
    5541#include <tables/Tables/ExprNode.h>
    5642#include <tables/Tables/TableRecord.h>
    5743#include <measures/Measures/MFrequency.h>
     44#include <measures/Measures/MEpoch.h>
    5845#include <measures/Measures/MeasTable.h>
     46#include <measures/Measures/MeasRef.h>
     47#include <measures/TableMeasures/TableMeasRefDesc.h>
     48#include <measures/TableMeasures/TableMeasValueDesc.h>
     49#include <measures/TableMeasures/TableMeasDesc.h>
     50#include <measures/TableMeasures/ScalarMeasColumn.h>
    5951#include <coordinates/Coordinates/CoordinateUtil.h>
    6052#include <casa/Quanta/MVTime.h>
    6153#include <casa/Quanta/MVAngle.h>
    6254
    63 #include "SDDefs.h"
    64 #include "SDContainer.h"
    65 #include "MathUtils.h"
    66 #include "SDPol.h"
     55#include "Scantable.h"
    6756#include "SDAttr.h"
    6857
    69 #include "SDMemTable.h"
    70 
    7158using namespace casa;
    72 using namespace asap;
    73 
    74 SDMemTable::SDMemTable() :
    75   IFSel_(0),
    76   beamSel_(0),
    77   polSel_(0)
    78 {
    79   setup();
     59
     60namespace asap {
     61
     62Scantable::Scantable(Table::TableType ttype) :
     63  type_(ttype),
     64  freqTable_(ttype),
     65  focusTable_(ttype),
     66  weatherTable_(ttype),
     67  tcalTable_(ttype),
     68  moleculeTable_(ttype)
     69{
     70  setupMainTable();
     71  table_.rwKeywordSet().defineTable("FREQUENCIES", freqTable_.table());
     72  table_.rwKeywordSet().defineTable("WEATHER", weatherTable_.table());
     73  table_.rwKeywordSet().defineTable("FOCUS", focusTable_.table());
     74  table_.rwKeywordSet().defineTable("TCAL", tcalTable_.table());
     75  table_.rwKeywordSet().defineTable("MOLECULES", moleculeTable_.table());
     76  setupHistoryTable();
     77  setupFitTable();
     78
     79  originalTable_ = table_;
    8080  attach();
    8181}
    8282
    83 SDMemTable::SDMemTable(const std::string& name) :
    84   IFSel_(0),
    85   beamSel_(0),
    86   polSel_(0)
     83Scantable::Scantable(const std::string& name, Table::TableType ttype) :
     84  type_(ttype),
     85  freqTable_(ttype)
    8786{
    8887  Table tab(name);
     
    9291    throw(AipsError("Unsupported version of ASAP file."));
    9392  }
    94   table_ = tab.copyToMemoryTable("dummy");
     93  if ( type_ == Table::Memory )
     94    table_ = tab.copyToMemoryTable("dummy");
     95  else
     96    table_ = tab;
     97
     98  originalTable_ = table_;
    9599  attach();
    96100}
    97101
    98 SDMemTable::SDMemTable(const SDMemTable& other, Bool clear)
    99 {
    100   table_ = other.table_.copyToMemoryTable(String("dummy"));
    101   // clear all rows()
     102
     103Scantable::Scantable( const Scantable& other, bool clear )
     104{
     105  // with or without data
    102106  if (clear) {
    103     table_.removeRow(this->table_.rowNumbers());
    104     IFSel_= 0;
    105     beamSel_= 0;
    106     polSel_= 0;
    107   } else {
    108     IFSel_= other.IFSel_;
    109     beamSel_= other.beamSel_;
    110     polSel_= other.polSel_;
    111   }
    112 
     107    table_ = TableCopy::makeEmptyMemoryTable(String("dummy"), other.table_,
     108                                             True);
     109  } else {
     110    table_ = other.table_.copyToMemoryTable(String("dummy"));
     111  }
     112
     113  originalTable_ = table_;
    113114  attach();
    114115}
    115116
    116 SDMemTable::SDMemTable(const Table& tab, const std::string& exprs) :
    117   IFSel_(0),
    118   beamSel_(0),
    119   polSel_(0)
    120 {
    121   Table t = tableCommand(exprs,tab);
    122   if (t.nrow() == 0)
    123       throw(AipsError("Query unsuccessful."));
    124   table_ = t.copyToMemoryTable("dummy");
    125   attach();
    126   renumber();
    127 }
    128 
    129 SDMemTable::~SDMemTable()
    130 {
    131   //cerr << "goodbye from SDMemTable @ " << this << endl;
    132 }
    133 
    134 SDMemTable SDMemTable::getScan(Int scanID) const
    135 {
    136   String cond("SELECT * from $1 WHERE SCANID == ");
    137   cond += String::toString(scanID);
    138   return SDMemTable(table_, cond);
    139 }
    140 
    141 SDMemTable &SDMemTable::operator=(const SDMemTable& other)
    142 {
    143   if (this != &other) {
    144      IFSel_= other.IFSel_;
    145      beamSel_= other.beamSel_;
    146      polSel_= other.polSel_;
    147      table_ = other.table_.copyToMemoryTable(String("dummy"));
    148      attach();
    149   }
    150   return *this;
    151 }
    152 
    153 SDMemTable SDMemTable::getSource(const std::string& source) const
    154 {
    155   String cond("SELECT * from $1 WHERE SRCNAME == ");
    156   cond += source;
    157   return SDMemTable(table_, cond);
    158 }
    159 
    160 void SDMemTable::setup()
     117Scantable::~Scantable()
     118{
     119  cout << "~Scantable() " << this << endl;
     120}
     121
     122void Scantable::setupMainTable()
    161123{
    162124  TableDesc td("", "1", TableDesc::Scratch);
    163   td.comment() = "A SDMemTable";
     125  td.comment() = "An ASAP Scantable";
    164126  td.rwKeywordSet().define("VERSION", Int(version_));
    165127
     128  // n Cycles
     129  td.addColumn(ScalarColumnDesc<uInt>("SCANNO"));
     130  // new index every nBeam x nIF x nPol
     131  td.addColumn(ScalarColumnDesc<uInt>("CYCLENO"));
     132
     133  td.addColumn(ScalarColumnDesc<uInt>("BEAMNO"));
     134  td.addColumn(ScalarColumnDesc<uInt>("IFNO"));
     135  td.rwKeywordSet().define("POLTYPE", String("linear"));
     136  td.addColumn(ScalarColumnDesc<uInt>("POLNO"));
     137
     138  td.addColumn(ScalarColumnDesc<uInt>("FREQ_ID"));
     139  td.addColumn(ScalarColumnDesc<uInt>("MOLECULE_ID"));
     140  // linear, circular, stokes [I Q U V], stokes1 [I Plinear Pangle V]
     141  td.addColumn(ScalarColumnDesc<Int>("REFBEAMNO"));
     142
    166143  td.addColumn(ScalarColumnDesc<Double>("TIME"));
     144  TableMeasRefDesc measRef(MEpoch::UTC); // UTC as default
     145  TableMeasValueDesc measVal(td, "TIME");
     146  TableMeasDesc<MEpoch> mepochCol(measVal, measRef);
     147  mepochCol.write(td);
     148
     149  td.addColumn(ScalarColumnDesc<Double>("INTERVAL"));
     150
    167151  td.addColumn(ScalarColumnDesc<String>("SRCNAME"));
     152  // Type of source (on=0, off=1, other=-1)
     153  td.addColumn(ScalarColumnDesc<Int>("SRCTYPE", Int(-1)));
     154  td.addColumn(ScalarColumnDesc<String>("FIELDNAME"));
     155
     156  //The actual Data Vectors
    168157  td.addColumn(ArrayColumnDesc<Float>("SPECTRA"));
    169158  td.addColumn(ArrayColumnDesc<uChar>("FLAGTRA"));
    170159  td.addColumn(ArrayColumnDesc<Float>("TSYS"));
    171   td.addColumn(ArrayColumnDesc<Float>("STOKES"));
    172   td.addColumn(ScalarColumnDesc<Int>("SCANID"));
    173   td.addColumn(ScalarColumnDesc<Double>("INTERVAL"));
    174   td.addColumn(ArrayColumnDesc<uInt>("FREQID"));
    175   td.addColumn(ArrayColumnDesc<uInt>("RESTFREQID"));
    176   td.addColumn(ArrayColumnDesc<Double>("DIRECTION"));
    177   td.addColumn(ScalarColumnDesc<String>("FIELDNAME"));
    178   td.addColumn(ScalarColumnDesc<String>("TCALTIME"));
    179   td.addColumn(ArrayColumnDesc<Float>("TCAL"));
    180   td.addColumn(ScalarColumnDesc<Float>("AZIMUTH"));
    181   td.addColumn(ScalarColumnDesc<Float>("ELEVATION"));
     160
     161  td.addColumn(ArrayColumnDesc<Double>("DIRECTION",
     162                                       IPosition(1,2),
     163                                       ColumnDesc::Direct));
     164  TableMeasRefDesc mdirRef(MDirection::J2000); // default
     165  TableMeasValueDesc tmvdMDir(td, "DIRECTION");
     166  // the TableMeasDesc gives the column a type
     167  TableMeasDesc<MDirection> mdirCol(tmvdMDir, mdirRef);
     168  // writing create the measure column
     169  mdirCol.write(td);
     170  td.addColumn(ScalarColumnDesc<Double>("AZIMUTH"));
     171  td.addColumn(ScalarColumnDesc<Double>("ELEVATION"));
    182172  td.addColumn(ScalarColumnDesc<Float>("PARANGLE"));
    183   td.addColumn(ScalarColumnDesc<Int>("REFBEAM"));
    184   td.addColumn(ArrayColumnDesc<Int>("FITID"));
     173
     174  td.addColumn(ScalarColumnDesc<uInt>("TCAL_ID"));
     175  td.addColumn(ScalarColumnDesc<uInt>("FIT_ID"));
     176
     177  td.addColumn(ScalarColumnDesc<uInt>("FOCUS_ID"));
     178  td.addColumn(ScalarColumnDesc<uInt>("WEATHER_ID"));
     179
     180  td.rwKeywordSet().define("OBSMODE", String(""));
    185181
    186182  // Now create Table SetUp from the description.
    187183  SetupNewTable aNewTab("dummy", td, Table::New);
    188 
    189   // Bind the Stokes Virtual machine to the STOKES column Because we
    190   // don't know how many polarizations will be in the data at this
    191   // point, we must bind the Virtual Engine regardless.  The STOKES
    192   // column won't be accessed if not appropriate (nPol=4)
    193   SDStokesEngine::registerClass();
    194   SDStokesEngine stokesEngine(String("STOKES"), String("SPECTRA"));
    195   aNewTab.bindColumn("STOKES", stokesEngine);
    196 
    197   // Create Table
    198184  table_ = Table(aNewTab, Table::Memory, 0);
    199   // add subtable
    200   TableDesc tdf("", "1", TableDesc::Scratch);
    201   tdf.addColumn(ArrayColumnDesc<String>("FUNCTIONS"));
    202   tdf.addColumn(ArrayColumnDesc<Int>("COMPONENTS"));
    203   tdf.addColumn(ArrayColumnDesc<Double>("PARAMETERS"));
    204   tdf.addColumn(ArrayColumnDesc<Bool>("PARMASK"));
    205   tdf.addColumn(ArrayColumnDesc<String>("FRAMEINFO"));
    206   SetupNewTable fittab("fits", tdf, Table::New);
    207   Table fitTable(fittab, Table::Memory);
    208   table_.rwKeywordSet().defineTable("FITS", fitTable);
    209 
     185
     186  originalTable_ = table_;
     187
     188}
     189
     190void asap::Scantable::setupHistoryTable( )
     191{
    210192  TableDesc tdh("", "1", TableDesc::Scratch);
    211193  tdh.addColumn(ScalarColumnDesc<String>("ITEM"));
    212   SetupNewTable histtab("hist", tdh, Table::New);
     194  SetupNewTable histtab("history", tdh, Table::New);
    213195  Table histTable(histtab, Table::Memory);
    214196  table_.rwKeywordSet().defineTable("HISTORY", histTable);
    215197}
    216198
    217 void SDMemTable::attach()
    218 {
    219   timeCol_.attach(table_, "TIME");
    220   srcnCol_.attach(table_, "SRCNAME");
    221   specCol_.attach(table_, "SPECTRA");
    222   flagsCol_.attach(table_, "FLAGTRA");
    223   tsCol_.attach(table_, "TSYS");
    224   stokesCol_.attach(table_, "STOKES");
    225   scanCol_.attach(table_, "SCANID");
    226   integrCol_.attach(table_, "INTERVAL");
    227   freqidCol_.attach(table_, "FREQID");
    228   restfreqidCol_.attach(table_, "RESTFREQID");
    229   dirCol_.attach(table_, "DIRECTION");
    230   fldnCol_.attach(table_, "FIELDNAME");
    231   tcaltCol_.attach(table_, "TCALTIME");
    232   tcalCol_.attach(table_, "TCAL");
    233   azCol_.attach(table_, "AZIMUTH");
    234   elCol_.attach(table_, "ELEVATION");
    235   paraCol_.attach(table_, "PARANGLE");
    236   rbeamCol_.attach(table_, "REFBEAM");
    237   fitCol_.attach(table_,"FITID");
    238 }
    239 
    240 
    241 std::string SDMemTable::getSourceName(Int whichRow) const
    242 {
    243   String name;
    244   srcnCol_.get(whichRow, name);
    245   return name;
    246 }
    247 
    248 float SDMemTable::getElevation(Int whichRow) const
    249 {
    250   float elevation;
    251   elCol_.get(whichRow, elevation);
    252   return elevation;
    253 }
    254 
    255 float SDMemTable::getAzimuth(Int whichRow) const
    256 {
    257   float azimuth;
    258   azCol_.get(whichRow, azimuth);
    259   return azimuth;
    260 }
    261 
    262 float SDMemTable::getParAngle(Int whichRow) const
    263 {
    264   float parangle;
    265   paraCol_.get(whichRow, parangle);
    266   return parangle;
    267 }
    268 
    269 std::string SDMemTable::getTime(Int whichRow, Bool showDate) const
    270 {
    271   Double tm;
    272   if (whichRow > -1) {
    273     timeCol_.get(whichRow, tm);
    274   } else {
    275     table_.keywordSet().get("UTC",tm);
    276   }
    277   MVTime mvt(tm);
    278   if (showDate)
    279     mvt.setFormat(MVTime::YMD);
    280   else
    281     mvt.setFormat(MVTime::TIME);
    282   ostringstream oss;
    283   oss << mvt;
    284   return String(oss);
    285 }
    286 
    287 double SDMemTable::getInterval(Int whichRow) const
    288 {
    289   Double intval;
    290   integrCol_.get(whichRow, intval);
    291   return intval;
    292 }
    293 
    294 bool SDMemTable::setIF(Int whichIF)
    295 {
    296   if ( whichIF >= 0 && whichIF < nIF()) {
    297     IFSel_ = whichIF;
    298     return true;
    299   }
    300   return false;
    301 }
    302 
    303 bool SDMemTable::setBeam(Int whichBeam)
    304 {
    305   if ( whichBeam >= 0 && whichBeam < nBeam()) {
    306     beamSel_ = whichBeam;
    307     return true;
    308   }
    309   return false;
    310 }
    311 
    312 bool SDMemTable::setPol(Int whichPol)
    313 {
    314   if ( whichPol >= 0 && whichPol < nPol()) {
    315     polSel_ = whichPol;
    316     return true;
    317   }
    318   return false;
    319 }
    320 
    321 void SDMemTable::resetCursor()
    322 {
    323    polSel_ = 0;
    324    IFSel_ = 0;
    325    beamSel_ = 0;
    326 }
    327 
    328 std::vector<bool> SDMemTable::getMask(Int whichRow) const
    329 {
    330 
    331   std::vector<bool> mask;
    332 
    333   Array<uChar> arr;
    334   flagsCol_.get(whichRow, arr);
    335 
    336   ArrayAccessor<uChar, Axis<asap::BeamAxis> > aa0(arr);
    337   aa0.reset(aa0.begin(uInt(beamSel_)));//go to beam
    338   ArrayAccessor<uChar, Axis<asap::IFAxis> > aa1(aa0);
    339   aa1.reset(aa1.begin(uInt(IFSel_)));// go to IF
    340   ArrayAccessor<uChar, Axis<asap::PolAxis> > aa2(aa1);
    341   aa2.reset(aa2.begin(uInt(polSel_)));// go to pol
    342 
    343   for (ArrayAccessor<uChar, Axis<asap::ChanAxis> > i(aa2); i != i.end(); ++i) {
    344     bool out =!static_cast<bool>(*i);
    345     mask.push_back(out);
    346   }
    347   return mask;
    348 }
    349 
    350 
    351 
    352 std::vector<float> SDMemTable::getSpectrum(Int whichRow) const
    353 {
    354   Array<Float> arr;
    355   specCol_.get(whichRow, arr);
    356   return getFloatSpectrum(arr);
    357 }
    358 
    359 
    360 int SDMemTable::nStokes() const
    361 {
    362    return stokesCol_.shape(0).nelements();        // All rows same shape
    363 }
    364 
    365 
    366 std::vector<float> SDMemTable::getStokesSpectrum(Int whichRow,
    367                                                  Bool doPol) const
    368   //
    369   // Gets one STokes parameter depending on cursor polSel location
    370   //  doPol=False  : I,Q,U,V
    371   //  doPol=True   : I,P,PA,V   ; P = sqrt(Q**2+U**2), PA = 0.5*atan2(Q,U)
    372   //
    373 {
    374   AlwaysAssert(asap::nAxes==4,AipsError);
    375   if (nPol()!=1 && nPol()!=2 && nPol()!=4) {
    376     throw (AipsError("You must have 1,2 or 4 polarizations to get the Stokes parameters"));
    377   }
    378 
    379   // For full conversion we are only supporting linears at the moment
    380 
    381   if (nPol() > 2) {
    382     String antName;
    383     table_.keywordSet().get("AntennaName", antName);
    384     Instrument inst = SDAttr::convertInstrument (antName, True);
    385     SDAttr sdAtt;
    386     if (sdAtt.feedPolType(inst) != LINEAR) {
    387       throw(AipsError("Only linear polarizations are supported"));
    388     }
    389   }
    390 
    391   Array<Float> arr;
    392   stokesCol_.get(whichRow, arr);
    393 
    394   if (doPol && (polSel_==1 || polSel_==2)) {       //   Q,U --> P, P.A.
    395 
    396     // Set current cursor location
    397 
    398     const IPosition& shape = arr.shape();
    399     IPosition start, end;
    400     getCursorSlice(start, end, shape);
    401 
    402     // Get Q and U slices
    403 
    404     Array<Float> Q = SDPolUtil::getStokesSlice(arr,start,end,"Q");
    405     Array<Float> U = SDPolUtil::getStokesSlice(arr,start,end,"U");
    406 
    407     // Compute output
    408 
    409     Array<Float> out;
    410     if (polSel_==1) {                                        // P
    411       out = SDPolUtil::polarizedIntensity(Q,U);
    412     } else if (polSel_==2) {                                 // P.A.
    413       out = SDPolUtil::positionAngle(Q,U);
    414     }
    415 
    416     // Copy to output
    417 
    418     IPosition vecShape(1,shape(asap::ChanAxis));
    419     Vector<Float> outV = out.reform(vecShape);
    420     std::vector<float> stlout;
    421     outV.tovector(stlout);
    422     return stlout;
    423 
    424   } else {
    425     // Selects at the cursor location
    426     return getFloatSpectrum(arr);
    427   }
    428 }
    429 
    430 std::string SDMemTable::getPolarizationLabel(Bool linear, Bool stokes,
    431                                               Bool linPol, Int polIdx) const
    432 {
    433    uInt idx = polSel_;
    434    if (polIdx >=0) idx = polIdx;
    435    return SDPolUtil::polarizationLabel(idx, linear, stokes, linPol);
    436 }
    437 
    438 
    439 
    440 std::vector<float> SDMemTable::stokesToPolSpectrum(Int whichRow,
    441                                                    Bool toLinear,
    442                                                    Int polIdx) const
    443 //
    444 // polIdx
    445 //   0:3 -> RR,LL,Real(RL),Imag(RL)
    446 //          XX,YY,Real(XY),Image(XY)
    447 //
    448 // Gets only
    449 //  RR = I + V
    450 //  LL = I - V
    451 // at the moment
    452 //
    453 {
    454   AlwaysAssert(asap::nAxes==4,AipsError);
    455   if (nStokes()!=4) {
    456      throw (AipsError("You must have 4 Stokes to convert to linear or circular"));
    457   }
    458 //
    459   Array<Float> arr, out;
    460   stokesCol_.get(whichRow, arr);
    461 
    462 // Set current cursor location
    463 
    464   const IPosition& shape = arr.shape();
    465   IPosition start, end;
    466   getCursorSlice(start, end, shape);
    467 
    468 // Get the slice
    469 
    470   if (toLinear) {
    471      throw(AipsError("Conversion to linears not yet supported"));
    472   } else {
    473     uInt selection = polSel_;
    474     if (polIdx > -1) selection = polIdx;
    475     Bool doRR = (selection==0);
    476     if (selection>1) {
    477       throw(AipsError("Only conversion to RR & LL is currently supported"));
    478     }
    479 
    480     // Get I and V slices
    481     Array<Float> I = SDPolUtil::getStokesSlice(arr,start,end,"I");
    482     Array<Float> V = SDPolUtil::getStokesSlice(arr,start,end,"V");
    483 
    484     // Compute output
    485     out = SDPolUtil::circularPolarizationFromStokes(I, V, doRR);
    486   }
    487 
    488   // Copy to output
    489    IPosition vecShape(1,shape(asap::ChanAxis));
    490    Vector<Float> outV = out.reform(vecShape);
    491    std::vector<float> stlout;
    492    outV.tovector(stlout);
    493 //
    494    return stlout;
    495 }
    496 
    497 
    498 
    499 
    500 Array<Float> SDMemTable::getStokesSpectrum(Int whichRow, Int iBeam, Int iIF) const
    501 {
    502 
    503 // Get data
    504 
    505   Array<Float> arr;
    506   stokesCol_.get(whichRow, arr);
    507 
    508 // Set current cursor location and overwrite polarization axis
    509 
    510   const IPosition& shape = arr.shape();
    511   IPosition start(shape.nelements(),0);
    512   IPosition end(shape-1);
    513   if (iBeam!=-1) {
    514      start(asap::BeamAxis) = iBeam;
    515      end(asap::BeamAxis) = iBeam;
    516   }
    517   if (iIF!=-1) {
    518      start(asap::IFAxis) = iIF;
    519      end(asap::IFAxis) = iIF;
    520   }
    521 
    522 // Get slice
    523 
    524   return arr(start,end);
    525 }
    526 
    527 
    528 std::vector<string> SDMemTable::getCoordInfo() const
    529 {
    530   String un;
    531   Table t = table_.keywordSet().asTable("FREQUENCIES");
    532   String sunit;
    533   t.keywordSet().get("UNIT",sunit);
    534   String dpl;
    535   t.keywordSet().get("DOPPLER",dpl);
    536   if (dpl == "") dpl = "RADIO";
    537   String rfrm;
    538   t.keywordSet().get("REFFRAME",rfrm);
    539   std::vector<string> inf;
    540   inf.push_back(sunit);
    541   inf.push_back(rfrm);
    542   inf.push_back(dpl);
    543   t.keywordSet().get("BASEREFFRAME",rfrm);
    544   inf.push_back(rfrm);
    545   return inf;
    546 }
    547 
    548 void SDMemTable::setCoordInfo(std::vector<string> theinfo)
    549 {
    550   std::vector<string>::iterator it;
    551   String un,rfrm, brfrm,dpl;
    552   un = theinfo[0];              // Abcissa unit
    553   rfrm = theinfo[1];            // Active (or conversion) frame
    554   dpl = theinfo[2];             // Doppler
    555   brfrm = theinfo[3];           // Base frame
    556   Table t = table_.rwKeywordSet().asTable("FREQUENCIES");
    557 
    558   Vector<Double> rstf;
    559   t.keywordSet().get("RESTFREQS",rstf);
    560 
    561   Bool canDo = True;
    562   Unit u1("km/s");Unit u2("Hz");
    563   if (Unit(un) == u1) {
    564     Vector<Double> rstf;
    565     t.keywordSet().get("RESTFREQS",rstf);
    566     if (rstf.nelements() == 0) {
    567         throw(AipsError("Can't set unit to km/s if no restfrequencies are specified"));
    568     }
    569   } else if (Unit(un) != u2 && un != "") {
    570         throw(AipsError("Unit not conformant with Spectral Coordinates"));
    571   }
    572   t.rwKeywordSet().define("UNIT", un);
    573 
    574   MFrequency::Types mdr;
    575   if (!MFrequency::getType(mdr, rfrm)) {
    576 
    577     Int a,b;const uInt* c;
    578     const String* valid = MFrequency::allMyTypes(a, b, c);
    579     String pfix = "Please specify a legal frame type. Types are\n";
    580     throw(AipsError(pfix+(*valid)));
    581   } else {
    582     t.rwKeywordSet().define("REFFRAME",rfrm);
    583   }
    584 
    585   MDoppler::Types dtype;
    586   dpl.upcase();
    587   if (!MDoppler::getType(dtype, dpl)) {
    588     throw(AipsError("Doppler type unknown"));
    589   } else {
    590     t.rwKeywordSet().define("DOPPLER",dpl);
    591   }
    592 
    593   if (!MFrequency::getType(mdr, brfrm)) {
    594      Int a,b;const uInt* c;
    595      const String* valid = MFrequency::allMyTypes(a, b, c);
    596      String pfix = "Please specify a legal frame type. Types are\n";
    597      throw(AipsError(pfix+(*valid)));
    598    } else {
    599     t.rwKeywordSet().define("BASEREFFRAME",brfrm);
    600    }
    601 }
    602 
    603 
    604 std::vector<double> SDMemTable::getAbcissa(Int whichRow) const
    605 {
    606   std::vector<double> abc(nChan());
    607 
    608   // Get header units keyword
    609   Table t = table_.keywordSet().asTable("FREQUENCIES");
    610   String sunit;
    611   t.keywordSet().get("UNIT",sunit);
    612   if (sunit == "") sunit = "pixel";
    613   Unit u(sunit);
    614 
    615   // Easy if just wanting pixels
    616   if (sunit==String("pixel")) {
    617     // assume channels/pixels
    618     std::vector<double>::iterator it;
    619     uInt i=0;
    620     for (it = abc.begin(); it != abc.end(); ++it) {
    621       (*it) = Double(i++);
    622     }
    623     return abc;
    624   }
    625 
    626   // Continue with km/s or Hz.  Get FreqIDs
    627   Vector<uInt> freqIDs;
    628   freqidCol_.get(whichRow, freqIDs);
    629   uInt freqID = freqIDs(IFSel_);
    630   restfreqidCol_.get(whichRow, freqIDs);
    631   uInt restFreqID = freqIDs(IFSel_);
    632 
    633   // Get SpectralCoordinate, set reference frame conversion,
    634   // velocity conversion, and rest freq state
    635 
    636   SpectralCoordinate spc = getSpectralCoordinate(freqID, restFreqID, whichRow);
    637   Vector<Double> pixel(nChan());
    638   indgen(pixel);
    639 
    640   if (u == Unit("km/s")) {
    641      Vector<Double> world;
    642      spc.pixelToVelocity(world,pixel);
    643      std::vector<double>::iterator it;
    644      uInt i = 0;
    645      for (it = abc.begin(); it != abc.end(); ++it) {
    646        (*it) = world[i];
    647        i++;
    648      }
    649   } else if (u == Unit("Hz")) {
    650 
    651     // Set world axis units
    652     Vector<String> wau(1); wau = u.getName();
    653     spc.setWorldAxisUnits(wau);
    654 
    655     std::vector<double>::iterator it;
    656     Double tmp;
    657     uInt i = 0;
    658     for (it = abc.begin(); it != abc.end(); ++it) {
    659       spc.toWorld(tmp,pixel[i]);
    660       (*it) = tmp;
    661       i++;
    662     }
    663   }
    664   return abc;
    665 }
    666 
    667 std::string SDMemTable::getAbcissaString(Int whichRow) const
    668 {
    669   Table t = table_.keywordSet().asTable("FREQUENCIES");
    670 
    671   String sunit;
    672   t.keywordSet().get("UNIT",sunit);
    673   if (sunit == "") sunit = "pixel";
    674   Unit u(sunit);
    675 
    676   Vector<uInt> freqIDs;
    677   freqidCol_.get(whichRow, freqIDs);
    678   uInt freqID = freqIDs(IFSel_);
    679   restfreqidCol_.get(whichRow, freqIDs);
    680   uInt restFreqID = freqIDs(IFSel_);
    681 
    682   // Get SpectralCoordinate, with frame, velocity, rest freq state set
    683   SpectralCoordinate spc = getSpectralCoordinate(freqID, restFreqID, whichRow);
    684 
    685   String s = "Channel";
    686   if (u == Unit("km/s")) {
    687     s = CoordinateUtil::axisLabel(spc,0,True,True,True);
    688   } else if (u == Unit("Hz")) {
    689     Vector<String> wau(1);wau = u.getName();
    690     spc.setWorldAxisUnits(wau);
    691 
    692     s = CoordinateUtil::axisLabel(spc,0,True,True,False);
    693   }
    694   return s;
    695 }
    696 
    697 void SDMemTable::setSpectrum(std::vector<float> spectrum, int whichRow)
    698 {
    699   Array<Float> arr;
    700   specCol_.get(whichRow, arr);
    701   if (spectrum.size() != arr.shape()(asap::ChanAxis)) {
    702     throw(AipsError("Attempting to set spectrum with incorrect length."));
    703   }
    704 
    705   // Setup accessors
    706   ArrayAccessor<Float, Axis<asap::BeamAxis> > aa0(arr);
    707   aa0.reset(aa0.begin(uInt(beamSel_)));                   // Beam selection
    708   ArrayAccessor<Float, Axis<asap::IFAxis> > aa1(aa0);
    709   aa1.reset(aa1.begin(uInt(IFSel_)));                     // IF selection
    710   ArrayAccessor<Float, Axis<asap::PolAxis> > aa2(aa1);
    711   aa2.reset(aa2.begin(uInt(polSel_)));                    // Pol selection
    712 
    713   // Iterate
    714   std::vector<float>::iterator it = spectrum.begin();
    715   for (ArrayAccessor<Float, Axis<asap::ChanAxis> > i(aa2); i != i.end(); ++i) {
    716     (*i) = Float(*it);
    717     it++;
    718   }
    719   specCol_.put(whichRow, arr);
    720 }
    721 
    722 void SDMemTable::getSpectrum(Vector<Float>& spectrum, Int whichRow) const
    723 {
    724   Array<Float> arr;
    725   specCol_.get(whichRow, arr);
    726 
    727   // Iterate and extract
    728   spectrum.resize(arr.shape()(3));
    729   ArrayAccessor<Float, Axis<asap::BeamAxis> > aa0(arr);
    730   aa0.reset(aa0.begin(uInt(beamSel_)));//go to beam
    731   ArrayAccessor<Float, Axis<asap::IFAxis> > aa1(aa0);
    732   aa1.reset(aa1.begin(uInt(IFSel_)));// go to IF
    733   ArrayAccessor<Float, Axis<asap::PolAxis> > aa2(aa1);
    734   aa2.reset(aa2.begin(uInt(polSel_)));// go to pol
    735 
    736   ArrayAccessor<Float, Axis<asap::BeamAxis> > va(spectrum);
    737   for (ArrayAccessor<Float, Axis<asap::ChanAxis> > i(aa2); i != i.end(); ++i) {
    738     (*va) = (*i);
    739     va++;
    740   }
    741 }
    742 
    743 
    744 /*
    745 void SDMemTable::getMask(Vector<Bool>& mask, Int whichRow) const {
    746   Array<uChar> arr;
    747   flagsCol_.get(whichRow, arr);
    748   mask.resize(arr.shape()(3));
    749 
    750   ArrayAccessor<uChar, Axis<asap::BeamAxis> > aa0(arr);
    751   aa0.reset(aa0.begin(uInt(beamSel_)));//go to beam
    752   ArrayAccessor<uChar, Axis<asap::IFAxis> > aa1(aa0);
    753   aa1.reset(aa1.begin(uInt(IFSel_)));// go to IF
    754   ArrayAccessor<uChar, Axis<asap::PolAxis> > aa2(aa1);
    755   aa2.reset(aa2.begin(uInt(polSel_)));// go to pol
    756 
    757   Bool useUserMask = ( chanMask_.size() == arr.shape()(3) );
    758 
    759   ArrayAccessor<Bool, Axis<asap::BeamAxis> > va(mask);
    760   std::vector<bool> tmp;
    761   tmp = chanMask_; // WHY the fxxx do I have to make a copy here. The
    762                    // iterator should work on chanMask_??
    763   std::vector<bool>::iterator miter;
    764   miter = tmp.begin();
    765 
    766   for (ArrayAccessor<uChar, Axis<asap::ChanAxis> > i(aa2); i != i.end(); ++i) {
    767     bool out =!static_cast<bool>(*i);
    768     if (useUserMask) {
    769       out = out && (*miter);
    770       miter++;
    771     }
    772     (*va) = out;
    773     va++;
    774   }
    775 }
    776 */
    777 
    778 MaskedArray<Float> SDMemTable::rowAsMaskedArray(uInt whichRow,
    779                                                 Bool toStokes) const
    780 {
    781   // Get flags
    782   Array<uChar> farr;
    783   flagsCol_.get(whichRow, farr);
    784 
    785   // Get data and convert mask to Bool
    786   Array<Float> arr;
    787   Array<Bool> mask;
    788   if (toStokes) {
    789      stokesCol_.get(whichRow, arr);
    790 
    791      Array<Bool> tMask(farr.shape());
    792      convertArray(tMask, farr);
    793      mask = SDPolUtil::stokesData (tMask, True);
    794   } else {
    795      specCol_.get(whichRow, arr);
    796      mask.resize(farr.shape());
    797      convertArray(mask, farr);
    798   }
    799 
    800   return MaskedArray<Float>(arr,!mask);
    801 }
    802 
    803 Float SDMemTable::getTsys(Int whichRow) const
    804 {
    805   Array<Float> arr;
    806   tsCol_.get(whichRow, arr);
    807   Float out;
    808 
    809   IPosition ip(arr.shape());
    810   ip(asap::BeamAxis) = beamSel_;
    811   ip(asap::IFAxis) = IFSel_;
    812   ip(asap::PolAxis) = polSel_;
    813   ip(asap::ChanAxis)=0;               // First channel only
    814 
    815   out = arr(ip);
    816   return out;
    817 }
    818 
    819 MDirection SDMemTable::getDirection(Int whichRow, Bool refBeam) const
    820 {
    821   MDirection::Types mdr = getDirectionReference();
    822   Array<Double> posit;
    823   dirCol_.get(whichRow,posit);
    824   Vector<Double> wpos(2);
    825   Int rb;
    826   rbeamCol_.get(whichRow,rb);
    827   wpos[0] = posit(IPosition(2,beamSel_,0));
    828   wpos[1] = posit(IPosition(2,beamSel_,1));
    829   if (refBeam && rb > -1) {  // use refBeam instead if it exists
    830     wpos[0] = posit(IPosition(2,rb,0));
    831     wpos[1] = posit(IPosition(2,rb,1));
    832   }
    833 
    834   Quantum<Double> lon(wpos[0],Unit(String("rad")));
    835   Quantum<Double> lat(wpos[1],Unit(String("rad")));
    836   return MDirection(lon, lat, mdr);
    837 }
    838 
    839 MEpoch SDMemTable::getEpoch(Int whichRow) const
    840 {
    841   MEpoch::Types met = getTimeReference();
    842 
    843   Double obstime;
    844   timeCol_.get(whichRow,obstime);
    845   MVEpoch tm2(Quantum<Double>(obstime, Unit(String("d"))));
    846   return MEpoch(tm2, met);
    847 }
    848 
    849 MPosition SDMemTable::getAntennaPosition () const
    850 {
    851   Vector<Double> antpos;
    852   table_.keywordSet().get("AntennaPosition", antpos);
    853   MVPosition mvpos(antpos(0),antpos(1),antpos(2));
    854   return MPosition(mvpos);
    855 }
    856 
    857 
    858 SpectralCoordinate SDMemTable::getSpectralCoordinate(uInt freqID) const
    859 {
    860 
    861   Table t = table_.keywordSet().asTable("FREQUENCIES");
    862   if (freqID> t.nrow() ) {
    863     throw(AipsError("SDMemTable::getSpectralCoordinate - freqID out of range"));
    864   }
    865 
    866   Double rp,rv,inc;
    867   String rf;
    868   ROScalarColumn<Double> rpc(t, "REFPIX");
    869   ROScalarColumn<Double> rvc(t, "REFVAL");
    870   ROScalarColumn<Double> incc(t, "INCREMENT");
    871   t.keywordSet().get("BASEREFFRAME",rf);
    872 
    873   // Create SpectralCoordinate (units Hz)
    874   MFrequency::Types mft;
    875   if (!MFrequency::getType(mft, rf)) {
    876     ostringstream oss;
    877     pushLog("WARNING: Frequency type unknown assuming TOPO");
    878     mft = MFrequency::TOPO;
    879   }
    880   rpc.get(freqID, rp);
    881   rvc.get(freqID, rv);
    882   incc.get(freqID, inc);
    883 
    884   SpectralCoordinate spec(mft,rv,inc,rp);
    885   return spec;
    886 }
    887 
    888 
    889 SpectralCoordinate SDMemTable::getSpectralCoordinate(uInt freqID,
    890                                                      uInt restFreqID,
    891                                                      uInt whichRow) const
    892 {
    893 
    894   // Create basic SC
    895   SpectralCoordinate spec = getSpectralCoordinate (freqID);
    896 
    897   Table t = table_.keywordSet().asTable("FREQUENCIES");
    898 
    899   // Set rest frequency
    900   Vector<Double> restFreqIDs;
    901   t.keywordSet().get("RESTFREQS",restFreqIDs);
    902   if (restFreqID < restFreqIDs.nelements()) {    // Should always be true
    903     spec.setRestFrequency(restFreqIDs(restFreqID),True);
    904   }
    905 
    906   // Set up frame conversion layer
    907   String frm;
    908   t.keywordSet().get("REFFRAME",frm);
    909   if (frm == "") frm = "TOPO";
    910   MFrequency::Types mtype;
    911   if (!MFrequency::getType(mtype, frm)) {
    912     // Should never happen
    913     pushLog("WARNING: Frequency type unknown assuming TOPO");
    914     mtype = MFrequency::TOPO;
    915   }
    916 
    917   // Set reference frame conversion  (requires row)
    918   MDirection dir = getDirection(whichRow);
    919   MEpoch epoch = getEpoch(whichRow);
    920   MPosition pos = getAntennaPosition();
    921 
    922   if (!spec.setReferenceConversion(mtype,epoch,pos,dir)) {
    923     throw(AipsError("Couldn't convert frequency frame."));
    924   }
    925 
    926   // Now velocity conversion if appropriate
    927   String unitStr;
    928   t.keywordSet().get("UNIT",unitStr);
    929 
    930   String dpl;
    931   t.keywordSet().get("DOPPLER",dpl);
    932   MDoppler::Types dtype;
    933   MDoppler::getType(dtype, dpl);
    934 
    935   // Only set velocity unit if non-blank and non-Hz
    936   if (!unitStr.empty()) {
    937      Unit unitU(unitStr);
    938      if (unitU==Unit("Hz")) {
    939      } else {
    940         spec.setVelocity(unitStr, dtype);
    941      }
    942   }
    943 
    944   return spec;
    945 }
    946 
    947 
    948 Bool SDMemTable::setCoordinate(const SpectralCoordinate& speccord,
    949                                uInt freqID) {
    950   Table t = table_.rwKeywordSet().asTable("FREQUENCIES");
    951   if (freqID > t.nrow() ) {
    952     throw(AipsError("SDMemTable::setCoordinate - coord no out of range"));
    953   }
    954   ScalarColumn<Double> rpc(t, "REFPIX");
    955   ScalarColumn<Double> rvc(t, "REFVAL");
    956   ScalarColumn<Double> incc(t, "INCREMENT");
    957 
    958   rpc.put(freqID, speccord.referencePixel()[0]);
    959   rvc.put(freqID, speccord.referenceValue()[0]);
    960   incc.put(freqID, speccord.increment()[0]);
    961 
    962   return True;
    963 }
    964 
    965 Int SDMemTable::nCoordinates() const
    966 {
    967   return table_.keywordSet().asTable("FREQUENCIES").nrow();
    968 }
    969 
    970 
    971 std::vector<double> SDMemTable::getRestFreqs() const
    972 {
    973   Table t = table_.keywordSet().asTable("FREQUENCIES");
    974   Vector<Double> tvec;
    975   t.keywordSet().get("RESTFREQS",tvec);
    976   std::vector<double> stlout;
    977   tvec.tovector(stlout);
    978   return stlout;
    979 }
    980 
    981 bool SDMemTable::putSDFreqTable(const SDFrequencyTable& sdft)
     199void Scantable::setupFitTable()
    982200{
    983201  TableDesc td("", "1", TableDesc::Scratch);
    984   td.addColumn(ScalarColumnDesc<Double>("REFPIX"));
    985   td.addColumn(ScalarColumnDesc<Double>("REFVAL"));
    986   td.addColumn(ScalarColumnDesc<Double>("INCREMENT"));
    987   SetupNewTable aNewTab("freqs", td, Table::New);
    988   Table aTable (aNewTab, Table::Memory, sdft.length());
    989   ScalarColumn<Double> sc0(aTable, "REFPIX");
    990   ScalarColumn<Double> sc1(aTable, "REFVAL");
    991   ScalarColumn<Double> sc2(aTable, "INCREMENT");
    992   for (uInt i=0; i < sdft.length(); ++i) {
    993     sc0.put(i,sdft.referencePixel(i));
    994     sc1.put(i,sdft.referenceValue(i));
    995     sc2.put(i,sdft.increment(i));
    996   }
    997   String rf = sdft.refFrame();
    998   if (rf.contains("TOPO")) rf = "TOPO";
    999   String brf = sdft.baseRefFrame();
    1000   if (brf.contains("TOPO")) brf = "TOPO";
    1001 
    1002   aTable.rwKeywordSet().define("BASEREFFRAME", brf);
    1003   aTable.rwKeywordSet().define("REFFRAME", rf);
    1004   aTable.rwKeywordSet().define("EQUINOX", sdft.equinox());
    1005   aTable.rwKeywordSet().define("UNIT", sdft.unit());
    1006   aTable.rwKeywordSet().define("DOPPLER", String("RADIO"));
    1007   Vector<Double> rfvec;
    1008   String rfunit;
    1009   sdft.restFrequencies(rfvec,rfunit);
    1010   Quantum<Vector<Double> > q(rfvec, rfunit);
    1011   rfvec.resize();
    1012   rfvec = q.getValue("Hz");
    1013   aTable.rwKeywordSet().define("RESTFREQS", rfvec);
    1014   table_.rwKeywordSet().defineTable("FREQUENCIES", aTable);
    1015   return true;
    1016 }
    1017 
    1018 bool SDMemTable::putSDFitTable(const SDFitTable& sdft)
    1019 {
    1020   TableDesc td("", "1", TableDesc::Scratch);
     202  td.addColumn(ScalarColumnDesc<uInt>("FIT_ID"));
    1021203  td.addColumn(ArrayColumnDesc<String>("FUNCTIONS"));
    1022204  td.addColumn(ArrayColumnDesc<Int>("COMPONENTS"));
     
    1026208  SetupNewTable aNewTab("fits", td, Table::New);
    1027209  Table aTable(aNewTab, Table::Memory);
    1028   ArrayColumn<String> sc0(aTable, "FUNCTIONS");
    1029   ArrayColumn<Int> sc1(aTable, "COMPONENTS");
    1030   ArrayColumn<Double> sc2(aTable, "PARAMETERS");
    1031   ArrayColumn<Bool> sc3(aTable, "PARMASK");
    1032   ArrayColumn<String> sc4(aTable, "FRAMEINFO");
    1033   for (uInt i; i<sdft.length(); ++i) {
    1034     const Vector<Double>& parms = sdft.getParameters(i);
    1035     const Vector<Bool>& parmask = sdft.getParameterMask(i);
    1036     const Vector<String>& funcs = sdft.getFunctions(i);
    1037     const Vector<Int>& comps = sdft.getComponents(i);
    1038     const Vector<String>& finfo = sdft.getFrameInfo(i);
    1039     sc0.put(i,funcs);
    1040     sc1.put(i,comps);
    1041     sc3.put(i,parmask);
    1042     sc2.put(i,parms);
    1043     sc4.put(i,finfo);
    1044   }
    1045210  table_.rwKeywordSet().defineTable("FITS", aTable);
    1046   return true;
    1047 }
    1048 
    1049 SDFitTable SDMemTable::getSDFitTable() const
    1050 {
    1051   const Table& t = table_.keywordSet().asTable("FITS");
    1052   Vector<Double> parms;
    1053   Vector<Bool> parmask;
    1054   Vector<String> funcs;
    1055   Vector<String> finfo;
    1056   Vector<Int> comps;
    1057   ROArrayColumn<Double> parmsCol(t, "PARAMETERS");
    1058   ROArrayColumn<Bool> parmaskCol(t, "PARMASK");
    1059   ROArrayColumn<Int> compsCol(t, "COMPONENTS");
    1060   ROArrayColumn<String> funcsCol(t, "FUNCTIONS");
    1061   ROArrayColumn<String> finfoCol(t, "FRAMEINFO");
    1062   uInt n = t.nrow();
    1063   SDFitTable sdft;
    1064   for (uInt i=0; i<n; ++i) {
    1065     parmaskCol.get(i, parmask);
    1066     parmsCol.get(i, parms);
    1067     funcsCol.get(i, funcs);
    1068     compsCol.get(i, comps);
    1069     finfoCol.get(i, finfo);
    1070     sdft.addFit(parms, parmask, funcs, comps, finfo);
    1071   }
    1072   return sdft;
    1073 }
    1074 
    1075 SDFitTable SDMemTable::getSDFitTable(uInt whichRow) const {
    1076   const Table& t = table_.keywordSet().asTable("FITS");
    1077   if (t.nrow() == 0 || whichRow >= t.nrow()) return SDFitTable();
    1078   Array<Int> fitid;
    1079   fitCol_.get(whichRow, fitid);
    1080   if (fitid.nelements() == 0) return SDFitTable();
    1081 
    1082   IPosition shp = fitid.shape();
    1083   IPosition start(4, beamSel_, IFSel_, polSel_,0);
    1084   IPosition end(4, beamSel_, IFSel_, polSel_, shp[3]-1);
    1085 
    1086   // reform the output array slice to be of dim=1
    1087   Vector<Int> tmp = (fitid(start, end)).reform(IPosition(1,shp[3]));
    1088 
    1089   Vector<Double> parms;
    1090   Vector<Bool> parmask;
    1091   Vector<String> funcs;
    1092   Vector<String> finfo;
    1093   Vector<Int> comps;
    1094   ROArrayColumn<Double> parmsCol(t, "PARAMETERS");
    1095   ROArrayColumn<Bool> parmaskCol(t, "PARMASK");
    1096   ROArrayColumn<Int> compsCol(t, "COMPONENTS");
    1097   ROArrayColumn<String> funcsCol(t, "FUNCTIONS");
    1098   ROArrayColumn<String> finfoCol(t, "FRAMEINFO");
    1099   SDFitTable sdft;
    1100   Int k=-1;
    1101   for (uInt i=0; i< tmp.nelements(); ++i) {
    1102     k = tmp[i];
    1103     if ( k > -1 && k < t.nrow() ) {
    1104       parms.resize();
    1105       parmsCol.get(k, parms);
    1106       parmask.resize();
    1107       parmaskCol.get(k, parmask);
    1108       funcs.resize();
    1109       funcsCol.get(k, funcs);
    1110       comps.resize();
    1111       compsCol.get(k, comps);
    1112       finfo.resize();
    1113       finfoCol.get(k, finfo);
    1114       sdft.addFit(parms, parmask, funcs, comps, finfo);
    1115     }
    1116   }
    1117   return sdft;
    1118 }
    1119 
    1120 void SDMemTable::addFit(uInt whichRow,
    1121                         const Vector<Double>& p, const Vector<Bool>& m,
    1122                         const Vector<String>& f, const Vector<Int>& c)
    1123 {
    1124   if (whichRow >= nRow()) {
    1125     throw(AipsError("Specified row out of range"));
    1126   }
    1127   Table t = table_.keywordSet().asTable("FITS");
    1128   uInt nrow = t.nrow();
    1129   t.addRow();
    1130   ArrayColumn<Double> parmsCol(t, "PARAMETERS");
    1131   ArrayColumn<Bool> parmaskCol(t, "PARMASK");
    1132   ArrayColumn<Int> compsCol(t, "COMPONENTS");
    1133   ArrayColumn<String> funcsCol(t, "FUNCTIONS");
    1134   ArrayColumn<String> finfoCol(t, "FRAMEINFO");
    1135   parmsCol.put(nrow, p);
    1136   parmaskCol.put(nrow, m);
    1137   compsCol.put(nrow, c);
    1138   funcsCol.put(nrow, f);
    1139   Vector<String> fi = mathutil::toVectorString(getCoordInfo());
    1140   finfoCol.put(nrow, fi);
    1141 
    1142   Array<Int> fitarr;
    1143   fitCol_.get(whichRow, fitarr);
    1144 
    1145   Array<Int> newarr;               // The new Array containing the fitid
    1146   Int pos =-1;                     // The fitid position in the array
    1147   if ( fitarr.nelements() == 0 ) { // no fits at all in this row
    1148     Array<Int> arr(IPosition(4,nBeam(),nIF(),nPol(),1));
    1149     arr = -1;
    1150     newarr.reference(arr);
    1151     pos = 0;
    1152   } else {
    1153     IPosition shp = fitarr.shape();
    1154     IPosition start(4, beamSel_, IFSel_, polSel_,0);
    1155     IPosition end(4, beamSel_, IFSel_, polSel_, shp[3]-1);
    1156     // reform the output array slice to be of dim=1
    1157     Array<Int> tmp = (fitarr(start, end)).reform(IPosition(1,shp[3]));
    1158     const Vector<Int>& fits = tmp;
    1159     VectorSTLIterator<Int> it(fits);
    1160     Int i = 0;
    1161     while (it != fits.end()) {
    1162       if (*it == -1) {
    1163         pos = i;
    1164         break;
    1165       }
    1166       ++i;
    1167       ++it;
    1168     };
    1169   }
    1170   if (pos == -1) {
    1171       mathutil::extendLastArrayAxis(newarr,fitarr, -1);
    1172       pos = fitarr.shape()[3];     // the new element position
    1173   } else {
    1174     if (fitarr.nelements() > 0)
    1175       newarr = fitarr;
    1176   }
    1177   newarr(IPosition(4, beamSel_, IFSel_, polSel_, pos)) = Int(nrow);
    1178   fitCol_.put(whichRow, newarr);
    1179 
    1180 }
    1181 
    1182 SDFrequencyTable SDMemTable::getSDFreqTable() const
    1183 {
    1184   const Table& t = table_.keywordSet().asTable("FREQUENCIES");
    1185   SDFrequencyTable sdft;
    1186 
    1187   // Add refpix/refval/incr.  What are the units ? Hz I suppose
    1188   // but it's nowhere described...
    1189   Vector<Double> refPix, refVal, incr;
    1190   ScalarColumn<Double> refPixCol(t, "REFPIX");
    1191   ScalarColumn<Double> refValCol(t, "REFVAL");
    1192   ScalarColumn<Double> incrCol(t, "INCREMENT");
    1193   refPix = refPixCol.getColumn();
    1194   refVal = refValCol.getColumn();
    1195   incr = incrCol.getColumn();
    1196 
    1197   uInt n = refPix.nelements();
    1198   for (uInt i=0; i<n; i++) {
    1199      sdft.addFrequency(refPix[i], refVal[i], incr[i]);
    1200   }
    1201 
    1202   // Frequency reference frame.  I don't know if this
    1203   // is the correct frame.  It might be 'REFFRAME'
    1204   // rather than 'BASEREFFRAME' ?
    1205   String frame;
    1206   t.keywordSet().get("REFFRAME",frame);
    1207   sdft.setRefFrame(frame);
    1208   t.keywordSet().get("BASEREFFRAME",frame);
    1209   sdft.setBaseRefFrame(frame);
    1210 
    1211   // Equinox
    1212   Float equinox;
    1213   t.keywordSet().get("EQUINOX", equinox);
    1214   sdft.setEquinox(equinox);
    1215 
    1216   String unit;
    1217   t.keywordSet().get("UNIT", unit);
    1218   sdft.setUnit(unit);
    1219 
    1220   // Rest Frequency
    1221   Vector<Double> restFreqs;
    1222   t.keywordSet().get("RESTFREQS", restFreqs);
    1223   for (uInt i=0; i<restFreqs.nelements(); i++) {
    1224      sdft.addRestFrequency(restFreqs[i]);
    1225   }
    1226   sdft.setRestFrequencyUnit(String("Hz"));
    1227 
    1228   return sdft;
    1229 }
    1230 
    1231 bool SDMemTable::putSDContainer(const SDContainer& sdc)
    1232 {
    1233   uInt rno = table_.nrow();
    1234   table_.addRow();
    1235 
    1236   timeCol_.put(rno, sdc.timestamp);
    1237   srcnCol_.put(rno, sdc.sourcename);
    1238   fldnCol_.put(rno, sdc.fieldname);
    1239   specCol_.put(rno, sdc.getSpectrum());
    1240   flagsCol_.put(rno, sdc.getFlags());
    1241   tsCol_.put(rno, sdc.getTsys());
    1242   scanCol_.put(rno, sdc.scanid);
    1243   integrCol_.put(rno, sdc.interval);
    1244   freqidCol_.put(rno, sdc.getFreqMap());
    1245   restfreqidCol_.put(rno, sdc.getRestFreqMap());
    1246   dirCol_.put(rno, sdc.getDirection());
    1247   rbeamCol_.put(rno, sdc.refbeam);
    1248   tcalCol_.put(rno, sdc.tcal);
    1249   tcaltCol_.put(rno, sdc.tcaltime);
    1250   azCol_.put(rno, sdc.azimuth);
    1251   elCol_.put(rno, sdc.elevation);
    1252   paraCol_.put(rno, sdc.parangle);
    1253   fitCol_.put(rno, sdc.getFitMap());
    1254   return true;
    1255 }
    1256 
    1257 SDContainer SDMemTable::getSDContainer(uInt whichRow) const
    1258 {
    1259   SDContainer sdc(nBeam(),nIF(),nPol(),nChan());
    1260   timeCol_.get(whichRow, sdc.timestamp);
    1261   srcnCol_.get(whichRow, sdc.sourcename);
    1262   integrCol_.get(whichRow, sdc.interval);
    1263   scanCol_.get(whichRow, sdc.scanid);
    1264   fldnCol_.get(whichRow, sdc.fieldname);
    1265   rbeamCol_.get(whichRow, sdc.refbeam);
    1266   azCol_.get(whichRow, sdc.azimuth);
    1267   elCol_.get(whichRow, sdc.elevation);
    1268   paraCol_.get(whichRow, sdc.parangle);
    1269   Vector<Float> tc;
    1270   tcalCol_.get(whichRow, tc);
    1271   sdc.tcal[0] = tc[0];sdc.tcal[1] = tc[1];
    1272   tcaltCol_.get(whichRow, sdc.tcaltime);
    1273 
    1274   Array<Float> spectrum;
    1275   Array<Float> tsys;
    1276   Array<uChar> flagtrum;
    1277   Vector<uInt> fmap;
    1278   Array<Double> direction;
    1279   Array<Int> fits;
    1280 
    1281   specCol_.get(whichRow, spectrum);
    1282   sdc.putSpectrum(spectrum);
    1283   flagsCol_.get(whichRow, flagtrum);
    1284   sdc.putFlags(flagtrum);
    1285   tsCol_.get(whichRow, tsys);
    1286   sdc.putTsys(tsys);
    1287   freqidCol_.get(whichRow, fmap);
    1288   sdc.putFreqMap(fmap);
    1289   restfreqidCol_.get(whichRow, fmap);
    1290   sdc.putRestFreqMap(fmap);
    1291   dirCol_.get(whichRow, direction);
    1292   sdc.putDirection(direction);
    1293   fitCol_.get(whichRow, fits);
    1294   sdc.putFitMap(fits);
    1295   return sdc;
    1296 }
    1297 
    1298 bool SDMemTable::putSDHeader(const SDHeader& sdh)
     211}
     212
     213void Scantable::attach()
     214{
     215  historyTable_ = table_.keywordSet().asTable("HISTORY");
     216  fitTable_ = table_.keywordSet().asTable("FITS");
     217
     218  timeCol_.attach(table_, "TIME");
     219  srcnCol_.attach(table_, "SRCNAME");
     220  specCol_.attach(table_, "SPECTRA");
     221  flagsCol_.attach(table_, "FLAGTRA");
     222  tsCol_.attach(table_, "TSYS");
     223  cycleCol_.attach(table_,"CYCLENO");
     224  scanCol_.attach(table_, "SCANNO");
     225  beamCol_.attach(table_, "BEAMNO");
     226  integrCol_.attach(table_, "INTERVAL");
     227  azCol_.attach(table_, "AZIMUTH");
     228  elCol_.attach(table_, "ELEVATION");
     229  dirCol_.attach(table_, "DIRECTION");
     230  paraCol_.attach(table_, "PARANGLE");
     231  fldnCol_.attach(table_, "FIELDNAME");
     232  rbeamCol_.attach(table_, "REFBEAMNO");
     233
     234  mfitidCol_.attach(table_,"FIT_ID");
     235  fitidCol_.attach(fitTable_,"FIT_ID");
     236
     237  mfreqidCol_.attach(table_, "FREQ_ID");
     238
     239  mtcalidCol_.attach(table_, "TCAL_ID");
     240
     241  mfocusidCol_.attach(table_, "FOCUS_ID");
     242
     243  mmolidCol_.attach(table_, "MOLECULE_ID");
     244}
     245
     246void Scantable::putSDHeader(const SDHeader& sdh)
    1299247{
    1300248  table_.rwKeywordSet().define("nIF", sdh.nif);
     
    1314262  table_.rwKeywordSet().define("FluxUnit", sdh.fluxunit);
    1315263  table_.rwKeywordSet().define("Epoch", sdh.epoch);
    1316   return true;
    1317 }
    1318 
    1319 SDHeader SDMemTable::getSDHeader() const
     264}
     265
     266SDHeader Scantable::getSDHeader() const
    1320267{
    1321268  SDHeader sdh;
     
    1338285  return sdh;
    1339286}
    1340 void SDMemTable::makePersistent(const std::string& filename)
    1341 {
    1342   table_.deepCopy(filename,Table::New);
    1343 
    1344 }
    1345 
    1346 Int SDMemTable::nScan() const {
    1347   Int n = 0;
    1348   Int previous = -1;Int current=0;
     287
     288int Scantable::rowToScanIndex( int therow )
     289{
     290  int therealrow = -1;
     291
     292  return therealrow;
     293}
     294
     295int Scantable::nScan() const {
     296  int n = 0;
     297  int previous = -1; int current = 0;
    1349298  for (uInt i=0; i< scanCol_.nrow();i++) {
    1350299    scanCol_.getScalar(i,current);
     
    1357306}
    1358307
    1359 String SDMemTable::formatSec(Double x) const
     308std::string Scantable::formatSec(Double x) const
    1360309{
    1361310  Double xcop = x;
     
    1374323};
    1375324
    1376 String SDMemTable::formatDirection(const MDirection& md) const
     325std::string Scantable::formatDirection(const MDirection& md) const
    1377326{
    1378327  Vector<Double> t = md.getAngle(Unit(String("rad"))).getValue();
     
    1387336
    1388337
    1389 std::string SDMemTable::getFluxUnit() const
     338std::string Scantable::getFluxUnit() const
    1390339{
    1391340  String tmp;
     
    1394343}
    1395344
    1396 void SDMemTable::setFluxUnit(const std::string& unit)
     345void Scantable::setFluxUnit(const std::string& unit)
    1397346{
    1398347  String tmp(unit);
     
    1405354}
    1406355
    1407 
    1408 void SDMemTable::setInstrument(const std::string& name)
    1409 {
    1410   Bool throwIt = True;
     356void Scantable::setInstrument(const std::string& name)
     357{
     358  bool throwIt = true;
    1411359  Instrument ins = SDAttr::convertInstrument(name, throwIt);
    1412360  String nameU(name);
     
    1415363}
    1416364
    1417 std::string SDMemTable::summary(bool verbose) const  {
    1418 
    1419   // Format header info
    1420   ostringstream oss;
    1421   oss << endl;
    1422   oss << "--------------------------------------------------------------------------------" << endl;
    1423   oss << " Scan Table Summary" << endl;
    1424   oss << "--------------------------------------------------------------------------------" << endl;
    1425   oss.flags(std::ios_base::left);
    1426   oss << setw(15) << "Beams:" << setw(4) << nBeam() << endl
    1427       << setw(15) << "IFs:" << setw(4) << nIF() << endl
    1428       << setw(15) << "Polarisations:" << setw(4) << nPol() << endl
    1429       << setw(15) << "Channels:"  << setw(4) << nChan() << endl;
    1430   oss << endl;
    1431   String tmp;
    1432   table_.keywordSet().get("Observer", tmp);
    1433   oss << setw(15) << "Observer:" << tmp << endl;
    1434   oss << setw(15) << "Obs Date:" << getTime(-1,True) << endl;
    1435   table_.keywordSet().get("Project", tmp);
    1436   oss << setw(15) << "Project:" << tmp << endl;
    1437   table_.keywordSet().get("Obstype", tmp);
    1438   oss << setw(15) << "Obs. Type:" << tmp << endl;
    1439   table_.keywordSet().get("AntennaName", tmp);
    1440   oss << setw(15) << "Antenna Name:" << tmp << endl;
    1441   table_.keywordSet().get("FluxUnit", tmp);
    1442   oss << setw(15) << "Flux Unit:" << tmp << endl;
    1443   Table t = table_.keywordSet().asTable("FREQUENCIES");
    1444   Vector<Double> vec;
    1445   t.keywordSet().get("RESTFREQS",vec);
    1446   oss << setw(15) << "Rest Freqs:";
    1447   if (vec.nelements() > 0) {
    1448       oss << setprecision(10) << vec << " [Hz]" << endl;
    1449   } else {
    1450       oss << "None set" << endl;
    1451   }
    1452   oss << setw(15) << "Abcissa:" << getAbcissaString() << endl;
    1453   oss << setw(15) << "Cursor:" << "Beam[" << getBeam() << "] "
    1454       << "IF[" << getIF() << "] " << "Pol[" << getPol() << "]" << endl;
    1455   oss << endl;
    1456 
    1457   String dirtype ="Position ("+ MDirection::showType(getDirectionReference()) + ")";
    1458   oss << setw(5) << "Scan"
    1459       << setw(15) << "Source"
    1460       << setw(24) << dirtype
    1461       << setw(10) << "Time"
    1462       << setw(18) << "Integration"
    1463       << setw(7) << "FreqIDs" << endl;
    1464   oss << "--------------------------------------------------------------------------------" << endl;
    1465 
    1466   // Generate list of scan start and end integrations
    1467   Vector<Int> scanIDs = scanCol_.getColumn();
    1468   Vector<uInt> startInt, endInt;
    1469   mathutil::scanBoundaries(startInt, endInt, scanIDs);
    1470 
    1471   const uInt nScans = startInt.nelements();
    1472   String name;
    1473   Vector<uInt> freqIDs, listFQ;
    1474   Vector<uInt> restFreqIDs, listRestFQ;
    1475   uInt nInt;
    1476 
    1477   for (uInt i=0; i<nScans; i++) {
    1478     // Get things from first integration of scan
    1479     String time = getTime(startInt(i),False);
    1480     String tInt = formatSec(Double(getInterval(startInt(i))));
    1481     String posit = formatDirection(getDirection(startInt(i),True));
    1482     srcnCol_.getScalar(startInt(i),name);
    1483 
    1484     // Find all the FreqIDs in this scan
    1485     listFQ.resize(0);
    1486     listRestFQ.resize(0);
    1487     for (uInt j=startInt(i); j<endInt(i)+1; j++) {
    1488       freqidCol_.get(j, freqIDs);
    1489       for (uInt k=0; k<freqIDs.nelements(); k++) {
    1490         mathutil::addEntry(listFQ, freqIDs(k));
    1491       }
    1492 //
    1493       restfreqidCol_.get(j, restFreqIDs);
    1494       for (uInt k=0; k<restFreqIDs.nelements(); k++) {
    1495         mathutil::addEntry(listRestFQ, restFreqIDs(k));
    1496       }
    1497     }
    1498 
    1499     nInt = endInt(i) - startInt(i) + 1;
    1500     oss << setw(3) << std::right << i << std::left << setw(2) << "  "
    1501         << setw(15) << name
    1502         << setw(24) << posit
    1503         << setw(10) << time
    1504         << setw(3) << std::right << nInt  << setw(3) << " x " << std::left
    1505         << setw(6) <<  tInt
    1506         << " " << listFQ << " " << listRestFQ << endl;
    1507   }
    1508   oss << endl;
    1509   oss << "Table contains " << table_.nrow() << " integration(s) in "
    1510       << nScans << " scan(s)." << endl;
    1511 
    1512   // Frequency Table
    1513   if (verbose) {
    1514     std::vector<string> info = getCoordInfo();
    1515     SDFrequencyTable sdft = getSDFreqTable();
    1516     oss << endl << endl;
    1517     oss << "FreqID  Frame   RefFreq(Hz)     RefPix   Increment(Hz)" << endl;
    1518     oss << "--------------------------------------------------------------------------------" << endl;
    1519     for (uInt i=0; i<sdft.length(); i++) {
    1520       oss << setw(8) << i << setw(8)
    1521           << info[3] << setw(16) << setprecision(8)
    1522           << sdft.referenceValue(i) << setw(10)
    1523           << sdft.referencePixel(i) << setw(12)
    1524           << sdft.increment(i) << endl;
    1525     }
    1526     oss << "--------------------------------------------------------------------------------" << endl;
    1527   }
    1528   return String(oss);
    1529 }
    1530 /*
    1531 std::string SDMemTable::scanSummary(const std::vector<int>& whichScans) {
    1532   ostringstream oss;
    1533   Vector<Int> scanIDs = scanCol_.getColumn();
    1534   Vector<uInt> startInt, endInt;
    1535   mathutil::scanBoundaries(startInt, endInt, scanIDs);
    1536   const uInt nScans = startInt.nelements();
    1537   std::vector<int>::const_iterator it(whichScans);
    1538   return String(oss);
    1539 }
    1540 */
    1541 Int SDMemTable::nBeam() const
    1542 {
    1543   Int n;
    1544   table_.keywordSet().get("nBeam",n);
    1545   return n;
    1546 }
    1547 
    1548 Int SDMemTable::nIF() const {
    1549   Int n;
    1550   table_.keywordSet().get("nIF",n);
    1551   return n;
    1552 }
    1553 
    1554 Int SDMemTable::nPol() const {
    1555   Int n;
    1556   table_.keywordSet().get("nPol",n);
    1557   return n;
    1558 }
    1559 
    1560 Int SDMemTable::nChan() const {
    1561   Int n;
    1562   table_.keywordSet().get("nChan",n);
    1563   return n;
    1564 }
    1565 
    1566 Table SDMemTable::getHistoryTable() const
     365MPosition Scantable::getAntennaPosition () const
     366{
     367  Vector<Double> antpos;
     368  table_.keywordSet().get("AntennaPosition", antpos);
     369  MVPosition mvpos(antpos(0),antpos(1),antpos(2));
     370  return MPosition(mvpos);
     371}
     372
     373void Scantable::makePersistent(const std::string& filename)
     374{
     375  String inname(filename);
     376  Path path(inname);
     377  inname = path.expandedName();
     378  table_.deepCopy(inname, Table::New);
     379}
     380
     381int asap::Scantable::nbeam( int scanno ) const
     382{
     383  if ( scanno < 0 ) {
     384    Int n;
     385    table_.keywordSet().get("nBeam",n);
     386    return int(n);
     387  } else {
     388    // take the first POLNO,IFNO,CYCLENO as nbeam shouldn't vary with these
     389    Table tab = table_(table_.col("SCANNO") == scanno
     390                       && table_.col("POLNO") == 0
     391                       && table_.col("IFNO") == 0
     392                       && table_.col("CYCLENO") == 0 );
     393    ROTableVector<uInt> v(tab, "BEAMNO");
     394    return int(v.nelements());
     395  }
     396  return 0;
     397}
     398
     399int asap::Scantable::nif( int scanno ) const
     400{
     401  if ( scanno < 0 ) {
     402    Int n;
     403    table_.keywordSet().get("nIF",n);
     404    return int(n);
     405  } else {
     406    // take the first POLNO,BEAMNO,CYCLENO as nbeam shouldn't vary with these
     407    Table tab = table_(table_.col("SCANNO") == scanno
     408                       && table_.col("POLNO") == 0
     409                       && table_.col("BEAMNO") == 0
     410                       && table_.col("CYCLENO") == 0 );
     411    ROTableVector<uInt> v(tab, "IFNO");
     412    return int(v.nelements());
     413  }
     414  return 0;
     415}
     416
     417int asap::Scantable::npol( int scanno ) const
     418{
     419  if ( scanno < 0 ) {
     420    Int n;
     421    table_.keywordSet().get("nPol",n);
     422    return n;
     423  } else {
     424    // take the first POLNO,IFNO,CYCLENO as nbeam shouldn't vary with these
     425    Table tab = table_(table_.col("SCANNO") == scanno
     426                       && table_.col("IFNO") == 0
     427                       && table_.col("BEAMNO") == 0
     428                       && table_.col("CYCLENO") == 0 );
     429    ROTableVector<uInt> v(tab, "POLNO");
     430    return int(v.nelements());
     431  }
     432  return 0;
     433}
     434
     435int asap::Scantable::nrow( int scanno ) const
     436{
     437  if ( scanno < 0 ) {
     438    return int(table_.nrow());
     439  } else {
     440    // take the first POLNO,IFNO,CYCLENO as nbeam shouldn't vary with these
     441    Table tab = table_(table_.col("SCANNO") == scanno
     442                       && table_.col("BEAMNO") == 0
     443                       && table_.col("IFNO") == 0
     444                       && table_.col("POLNO") == 0 );
     445    return int(tab.nrow());
     446  }
     447  return 0;
     448}
     449
     450
     451int asap::Scantable::nchan( int scanno, int ifno ) const
     452{
     453  if ( scanno < 0 && ifno < 0 ) {
     454    Int n;
     455    table_.keywordSet().get("nChan",n);
     456    return int(n);
     457  } else {
     458    // take the first POLNO,IFNO,CYCLENO as nbeam shouldn't vary with these
     459    Table tab = table_(table_.col("SCANNO") == scanno
     460                       && table_.col("IFNO") == ifno
     461                       && table_.col("BEAMNO") == 0
     462                       && table_.col("POLNO") == 0
     463                       && table_.col("CYCLENO") == 0 );
     464    ROArrayColumn<Float> v(tab, "SPECTRA");
     465    cout << v.shape(0) << endl;
     466    return 0;
     467  }
     468  return 0;
     469}
     470
     471Table Scantable::getHistoryTable() const
    1567472{
    1568473  return table_.keywordSet().asTable("HISTORY");
    1569474}
    1570475
    1571 void SDMemTable::appendToHistoryTable(const Table& otherHist)
     476void Scantable::appendToHistoryTable(const Table& otherHist)
    1572477{
    1573478  Table t = table_.rwKeywordSet().asTable("HISTORY");
    1574   const String sep = "--------------------------------------------------------------------------------";
    1575   addHistory(sep);
     479
     480  addHistory(asap::SEPERATOR);
    1576481  TableCopy::copyRows(t, otherHist, t.nrow(), 0, otherHist.nrow());
    1577   addHistory(sep);
    1578 }
    1579 
    1580 void SDMemTable::addHistory(const std::string& hist)
     482  addHistory(asap::SEPERATOR);
     483}
     484
     485void Scantable::addHistory(const std::string& hist)
    1581486{
    1582487  Table t = table_.rwKeywordSet().asTable("HISTORY");
     
    1587492}
    1588493
    1589 std::vector<std::string> SDMemTable::getHistory() const
     494std::vector<std::string> Scantable::getHistory() const
    1590495{
    1591496  Vector<String> history;
     
    1602507}
    1603508
    1604 
    1605 /*
    1606   void SDMemTable::maskChannels(const std::vector<Int>& whichChans ) {
    1607 
    1608   std::vector<int>::iterator it;
    1609   ArrayAccessor<uChar, Axis<asap::PolAxis> > j(flags_);
    1610   for (it = whichChans.begin(); it != whichChans.end(); it++) {
    1611     j.reset(j.begin(uInt(*it)));
    1612     for (ArrayAccessor<uChar, Axis<asap::BeamAxis> > i(j); i != i.end(); ++i) {
    1613       for (ArrayAccessor<uChar, Axis<asap::IFAxis> > ii(i); ii != ii.end(); ++ii) {
    1614         for (ArrayAccessor<uChar, Axis<asap::ChanAxis> > iii(ii);
    1615              iii != iii.end(); ++iii) {
    1616           (*iii) =
    1617         }
    1618       }
    1619     }
    1620   }
    1621 
    1622 }
    1623 */
    1624 void SDMemTable::flag(int whichRow)
    1625   {
    1626   Array<uChar> arr;
    1627   flagsCol_.get(whichRow, arr);
    1628 
    1629   ArrayAccessor<uChar, Axis<asap::BeamAxis> > aa0(arr);
    1630   aa0.reset(aa0.begin(uInt(beamSel_)));//go to beam
    1631   ArrayAccessor<uChar, Axis<asap::IFAxis> > aa1(aa0);
    1632   aa1.reset(aa1.begin(uInt(IFSel_)));// go to IF
    1633   ArrayAccessor<uChar, Axis<asap::PolAxis> > aa2(aa1);
    1634   aa2.reset(aa2.begin(uInt(polSel_)));// go to pol
    1635 
    1636   for (ArrayAccessor<uChar, Axis<asap::ChanAxis> > i(aa2); i != i.end(); ++i) {
    1637     (*i) = uChar(True);
    1638   }
    1639 
    1640   flagsCol_.put(whichRow, arr);
    1641 }
    1642 
    1643 MDirection::Types SDMemTable::getDirectionReference() const
    1644 {
    1645   Float eq;
    1646   table_.keywordSet().get("Equinox",eq);
    1647   std::map<float,string> mp;
    1648   mp[2000.0] = "J2000";
    1649   mp[1950.0] = "B1950";
    1650   MDirection::Types mdr;
    1651   if (!MDirection::getType(mdr, mp[eq])) {
    1652     mdr = MDirection::J2000;
    1653     pushLog("WARNING: Unknown equinox using J2000");
    1654   }
    1655 
    1656   return mdr;
    1657 }
    1658 
    1659 MEpoch::Types SDMemTable::getTimeReference() const
    1660 {
    1661   MEpoch::Types met;
    1662   String ep;
    1663   table_.keywordSet().get("Epoch",ep);
    1664   if (!MEpoch::getType(met, ep)) {
    1665      pushLog("WARNING: Epoch type unknown - using UTC");
    1666     met = MEpoch::UTC;
    1667   }
    1668 
    1669   return met;
    1670 }
    1671 
    1672 
    1673 Bool SDMemTable::setRestFreqs(const Vector<Double>& restFreqsIn,
    1674                               const String& sUnit,
    1675                               const vector<string>& lines,
    1676                               const String& source,
    1677                               Int whichIF)
    1678 {
    1679    const Int nIFs = nIF();
    1680    if (whichIF>=nIFs) {
    1681       throw(AipsError("Illegal IF index"));
    1682    }
    1683 
    1684    // Find vector of restfrequencies
    1685    // Double takes precedence over String
    1686    Unit unit;
    1687    Vector<Double> restFreqs;
    1688    if (restFreqsIn.nelements()>0) {
    1689       restFreqs.resize(restFreqsIn.nelements());
    1690       restFreqs = restFreqsIn;
    1691       unit = Unit(sUnit);
    1692    } else if (lines.size()>0) {
    1693       const uInt nLines = lines.size();
    1694       unit = Unit("Hz");
    1695       restFreqs.resize(nLines);
    1696       MFrequency lineFreq;
    1697       for (uInt i=0; i<nLines; i++) {
    1698          String tS(lines[i]);
    1699          tS.upcase();
    1700          if (MeasTable::Line(lineFreq, tS)) {
    1701             restFreqs[i] = lineFreq.getValue().getValue();          // Hz
    1702          } else {
    1703             String s = String(lines[i]) +
    1704               String(" is an unrecognized spectral line");
    1705             throw(AipsError(s));
    1706          }
    1707       }
    1708    } else {
    1709       throw(AipsError("You have not specified any rest frequencies or lines"));
    1710    }
    1711 
    1712    // If multiple restfreqs, must be length nIF. In this
    1713    // case we will just replace the rest frequencies
    1714    // We can't disinguish scalar and vector of length 1
    1715    const uInt nRestFreqs = restFreqs.nelements();
    1716    Int idx = -1;
    1717    SDFrequencyTable sdft = getSDFreqTable();
    1718 
    1719    ostringstream oss;
    1720    if (nRestFreqs>1) {
    1721      // Replace restFreqs, one per IF
    1722      if (nRestFreqs != nIFs) {
    1723        throw (AipsError("Number of rest frequencies must be equal to the number of IFs"));
    1724      }
    1725      ostringstream oss;
    1726      oss << "Replaced rest frequencies, one per IF, with given list : " << restFreqs;
    1727      sdft.deleteRestFrequencies();
    1728      for (uInt i=0; i<nRestFreqs; i++) {
    1729        Quantum<Double> rf(restFreqs[i], unit);
    1730        sdft.addRestFrequency(rf.getValue("Hz"));
    1731      }
    1732    } else {
    1733 
    1734      // Add new rest freq
    1735       Quantum<Double> rf(restFreqs[0], unit);
    1736       idx = sdft.addRestFrequency(rf.getValue("Hz"));
    1737       if (whichIF>=0) {
    1738          oss << "Selected given rest frequency (" << restFreqs[0] << ") for IF " << whichIF << endl;
    1739       } else {
    1740          oss << "Selected given rest frequency (" << restFreqs[0] << ") for all IFs" << endl;
    1741       }
    1742    }
    1743    pushLog(String(oss));
    1744    // Replace
    1745    Bool empty = source.empty();
    1746    Bool ok = False;
    1747    if (putSDFreqTable(sdft)) {
    1748       const uInt nRow = table_.nrow();
    1749       String srcName;
    1750       Vector<uInt> restFreqIDs;
    1751       for (uInt i=0; i<nRow; i++) {
    1752          srcnCol_.get(i, srcName);
    1753          restfreqidCol_.get(i,restFreqIDs);
    1754          if (idx==-1) {
    1755            // Replace vector of restFreqs; one per IF.
    1756            // No selection possible
    1757             for (uInt i=0; i<nIFs; i++) restFreqIDs[i] = i;
    1758          } else {
    1759            // Set RestFreqID for selected data
    1760             if (empty || source==srcName) {
    1761                if (whichIF<0) {
    1762                   restFreqIDs = idx;
    1763                } else {
    1764                   restFreqIDs[whichIF] = idx;
    1765                }
    1766             }
    1767          }
    1768          restfreqidCol_.put(i,restFreqIDs);
    1769       }
    1770       ok = True;
    1771    } else {
    1772      ok = False;
    1773    }
    1774 
    1775    return ok;
    1776 }
    1777 
    1778 std::string SDMemTable::spectralLines() const
    1779 {
    1780    Vector<String> lines = MeasTable::Lines();
    1781    MFrequency lineFreq;
    1782    Double freq;
    1783    ostringstream oss;
    1784 
    1785    oss.flags(std::ios_base::left);
    1786    oss << "Line      Frequency (Hz)" << endl;
    1787    oss << "-----------------------" << endl;
    1788    for (uInt i=0; i<lines.nelements(); i++) {
    1789      MeasTable::Line(lineFreq, lines[i]);
    1790      freq = lineFreq.getValue().getValue();          // Hz
    1791      oss << setw(11) << lines[i] << setprecision(10) << freq << endl;
    1792    }
    1793    return String(oss);
    1794 }
    1795 
    1796 void SDMemTable::renumber()
    1797 {
    1798   uInt nRow = scanCol_.nrow();
    1799   Int newscanid = 0;
    1800   Int cIdx;// the current scanid
    1801   // get the first scanid
    1802   scanCol_.getScalar(0,cIdx);
    1803   Int pIdx = cIdx;// the scanid of the previous row
    1804   for (uInt i=0; i<nRow;++i) {
    1805     scanCol_.getScalar(i,cIdx);
    1806     if (pIdx == cIdx) {
    1807       // renumber
    1808       scanCol_.put(i,newscanid);
    1809     } else {
    1810       ++newscanid;
    1811       pIdx = cIdx;   // store scanid
    1812       --i;           // don't increment next loop
    1813     }
    1814   }
    1815 }
    1816 
    1817 
    1818 void SDMemTable::getCursorSlice(IPosition& start, IPosition& end,
    1819                                 const IPosition& shape) const
    1820 {
    1821   const uInt nDim = shape.nelements();
    1822   start.resize(nDim);
    1823   end.resize(nDim);
    1824 
    1825   start(asap::BeamAxis) = beamSel_;
    1826   end(asap::BeamAxis) = beamSel_;
    1827   start(asap::IFAxis) = IFSel_;
    1828   end(asap::IFAxis) = IFSel_;
    1829 
    1830   start(asap::PolAxis) = polSel_;
    1831   end(asap::PolAxis) = polSel_;
    1832 
    1833   start(asap::ChanAxis) = 0;
    1834   end(asap::ChanAxis) = shape(asap::ChanAxis) - 1;
    1835 }
    1836 
    1837 
    1838 std::vector<float> SDMemTable::getFloatSpectrum(const Array<Float>& arr) const
    1839   // Get spectrum at cursor location
    1840 {
    1841 
    1842   // Setup accessors
    1843   ArrayAccessor<Float, Axis<asap::BeamAxis> > aa0(arr);
    1844   aa0.reset(aa0.begin(uInt(beamSel_)));                    // Beam selection
    1845 
    1846   ArrayAccessor<Float, Axis<asap::IFAxis> > aa1(aa0);
    1847   aa1.reset(aa1.begin(uInt(IFSel_)));                      // IF selection
    1848 
    1849   ArrayAccessor<Float, Axis<asap::PolAxis> > aa2(aa1);
    1850   aa2.reset(aa2.begin(uInt(polSel_)));                     // Pol selection
    1851 
    1852   std::vector<float> spectrum;
    1853   for (ArrayAccessor<Float, Axis<asap::ChanAxis> > i(aa2); i != i.end(); ++i) {
    1854     spectrum.push_back(*i);
    1855   }
    1856   return spectrum;
    1857 }
    1858 
    1859 void SDMemTable::calculateAZEL()
     509std::string Scantable::formatTime(const MEpoch& me, bool showdate) const
     510{
     511  MVTime mvt(me.getValue());
     512  if (showdate)
     513    mvt.setFormat(MVTime::YMD);
     514  else
     515    mvt.setFormat(MVTime::TIME);
     516  ostringstream oss;
     517  oss << mvt;
     518  return String(oss);
     519}
     520
     521void Scantable::calculateAZEL()
    1860522{
    1861523  MPosition mp = getAntennaPosition();
     524  MEpoch::ROScalarColumn timeCol(table_, "TIME");
    1862525  ostringstream oss;
    1863526  oss << "Computed azimuth/elevation using " << endl
    1864527      << mp << endl;
    1865   for (uInt i=0; i<nRow();++i) {
    1866     MEpoch me = getEpoch(i);
    1867     MDirection md = getDirection(i,False);
    1868     oss  << " Time: " << getTime(i,False) << " Direction: " << formatDirection(md)
     528  for (uInt i=0; i<nrow(); ++i) {
     529    MEpoch me = timeCol(i);
     530    MDirection md = dirCol_(i);
     531    dirCol_.get(i,md);
     532    oss  << " Time: " << formatTime(me,False) << " Direction: " << formatDirection(md)
    1869533         << endl << "     => ";
    1870534    MeasFrame frame(mp, me);
     
    1880544  pushLog(String(oss));
    1881545}
     546
     547double Scantable::getInterval(int whichrow) const
     548{
     549  if (whichrow < 0) return 0.0;
     550  Double intval;
     551  integrCol_.get(Int(whichrow), intval);
     552  return intval;
     553}
     554
     555std::vector<bool> Scantable::getMask(int whichrow) const
     556{
     557  Vector<uChar> flags;
     558  flagsCol_.get(uInt(whichrow), flags);
     559  Vector<Bool> bflag(flags.shape());
     560  convertArray(bflag, flags);
     561  bflag = !bflag;
     562  std::vector<bool> mask;
     563  bflag.tovector(mask);
     564  return mask;
     565}
     566
     567std::vector<float> Scantable::getSpectrum(int whichrow) const
     568{
     569  Vector<Float> arr;
     570  specCol_.get(whichrow, arr);
     571  std::vector<float> out;
     572  arr.tovector(out);
     573  return out;
     574}
     575
     576String Scantable::generateName()
     577{
     578  return (File::newUniqueName("./","temp")).baseName();
     579}
     580
     581const casa::Table& Scantable::table( ) const
     582{
     583  return table_;
     584}
     585
     586casa::Table& Scantable::table( )
     587{
     588  return table_;
     589}
     590
     591std::string Scantable::getPolarizationLabel(bool linear, bool stokes,
     592                                            bool linpol, int polidx) const
     593{
     594  uInt idx = 0;
     595  if (polidx >=0) idx = polidx;
     596  return "";
     597  //return SDPolUtil::polarizationLabel(idx, linear, stokes, linpol);
     598}
     599
     600void Scantable::unsetSelection()
     601{
     602  table_ = originalTable_;
     603  selector_.reset();
     604}
     605
     606void Scantable::setSelection( const STSelector& selection )
     607{
     608  Table tab = const_cast<STSelector&>(selection).apply(originalTable_);
     609  if ( tab.nrow() == 0 ) {
     610    throw(AipsError("Selection contains no data. Not applying it."));
     611  }
     612  table_ = tab;
     613  selector_ = selection;
     614}
     615
     616std::string asap::Scantable::summary( bool verbose )
     617{
     618  // Format header info
     619  ostringstream oss;
     620  oss << endl;
     621  oss << asap::SEPERATOR << endl;
     622  oss << " Scan Table Summary" << endl;
     623  oss << asap::SEPERATOR << endl;
     624  oss.flags(std::ios_base::left);
     625  oss << setw(15) << "Beams:" << setw(4) << nbeam() << endl
     626      << setw(15) << "IFs:" << setw(4) << nif() << endl
     627      << setw(15) << "Polarisations:" << setw(4) << npol() << endl
     628      << setw(15) << "Channels:"  << setw(4) << nchan() << endl;
     629  oss << endl;
     630  String tmp;
     631  //table_.keywordSet().get("Observer", tmp);
     632  oss << setw(15) << "Observer:" << table_.keywordSet().asString("Observer") << endl;
     633  oss << setw(15) << "Obs Date:" << getTime(-1,true) << endl;
     634  table_.keywordSet().get("Project", tmp);
     635  oss << setw(15) << "Project:" << tmp << endl;
     636  table_.keywordSet().get("Obstype", tmp);
     637  oss << setw(15) << "Obs. Type:" << tmp << endl;
     638  table_.keywordSet().get("AntennaName", tmp);
     639  oss << setw(15) << "Antenna Name:" << tmp << endl;
     640  table_.keywordSet().get("FluxUnit", tmp);
     641  oss << setw(15) << "Flux Unit:" << tmp << endl;
     642  Vector<Float> vec;
     643  oss << setw(15) << "Rest Freqs:";
     644  if (vec.nelements() > 0) {
     645      oss << setprecision(10) << vec << " [Hz]" << endl;
     646  } else {
     647      oss << "none" << endl;
     648  }
     649  oss << setw(15) << "Abcissa:" << "channel" << endl;
     650  oss << selector_.print() << endl;
     651  oss << endl;
     652  // main table
     653  String dirtype = "Position ("
     654                  + MDirection::showType(dirCol_.getMeasRef().getType())
     655                  + ")";
     656  oss << setw(5) << "Scan"
     657      << setw(15) << "Source"
     658//      << setw(24) << dirtype
     659      << setw(10) << "Time"
     660      << setw(18) << "Integration" << endl
     661      << setw(5) << "" << setw(10) << "Beam" << dirtype << endl
     662      << setw(15) << "" << setw(5) << "IF"
     663      << setw(8) << "Frame" << setw(16)
     664      << "RefVal" << setw(10) << "RefPix" << setw(12) << "Increment" <<endl;
     665  oss << asap::SEPERATOR << endl;
     666  TableIterator iter(table_, "SCANNO");
     667  while (!iter.pastEnd()) {
     668    Table subt = iter.table();
     669    ROTableRow row(subt);
     670    MEpoch::ROScalarColumn timeCol(subt,"TIME");
     671    const TableRecord& rec = row.get(0);
     672    oss << setw(4) << std::right << rec.asuInt("SCANNO")
     673        << std::left << setw(1) << ""
     674        << setw(15) << rec.asString("SRCNAME")
     675        << setw(10) << formatTime(timeCol(0), false);
     676    // count the cycles in the scan
     677    TableIterator cyciter(subt, "CYCLENO");
     678    int nint = 0;
     679    while (!cyciter.pastEnd()) {
     680      ++nint;
     681      ++cyciter;
     682    }
     683    oss << setw(3) << std::right << nint  << setw(3) << " x " << std::left
     684        << setw(6) <<  formatSec(rec.asFloat("INTERVAL")) << endl;
     685
     686    TableIterator biter(subt, "BEAMNO");
     687    while (!biter.pastEnd()) {
     688      Table bsubt = biter.table();
     689      ROTableRow brow(bsubt);
     690      MDirection::ROScalarColumn bdirCol(bsubt,"DIRECTION");
     691      const TableRecord& brec = brow.get(0);
     692      oss << setw(6) << "" <<  setw(10) << brec.asuInt("BEAMNO");
     693      oss  << setw(24) << formatDirection(bdirCol(0)) << endl;
     694      TableIterator iiter(bsubt, "IFNO");
     695      while (!iiter.pastEnd()) {
     696        Table isubt = iiter.table();
     697        ROTableRow irow(isubt);
     698        const TableRecord& irec = irow.get(0);
     699        oss << std::right <<setw(8) << "" << std::left << irec.asuInt("IFNO");
     700        oss << frequencies().print(irec.asuInt("FREQ_ID"));
     701
     702        ++iiter;
     703      }
     704      ++biter;
     705    }
     706    ++iter;
     707  }
     708  /// @todo implement verbose mode
     709  return String(oss);
     710}
     711
     712std::string Scantable::getTime(int whichrow, bool showdate) const
     713{
     714  MEpoch::ROScalarColumn timeCol(table_, "TIME");
     715  MEpoch me;
     716  if (whichrow > -1) {
     717    me = timeCol(uInt(whichrow));
     718  } else {
     719    Double tm;
     720    table_.keywordSet().get("UTC",tm);
     721    me = MEpoch(MVEpoch(tm));
     722  }
     723  return formatTime(me, showdate);
     724}
     725
     726}//namespace asap
Note: See TracChangeset for help on using the changeset viewer.