source: branches/alma/src/STMath.cpp @ 1680

Last change on this file since 1680 was 1680, checked in by Takeshi Nakazato, 14 years ago

New Development: No

JIRA Issue: Yes CAS-1823

Ready to Release: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: Yes/No?

Module(s): Module Names change impacts.

Description: Describe your changes here...

  1. Bug fix

In scantable.py, self._math = stmath() should be
self._math = stmath( rcParamsinsitu? ).

  1. Delete operation mode

I have deleted operation mode parameter which is used for a function
to do an operation of scantable with 1D list, since I have implemented
the operation of scantable with 2D list.

  1. Extend operation of scantable

Now, operation of scantable with 2D list is available.

  1. Accept integer input for operation

Operation of scantable with int as well as int list is working
in addition to operation with float or float list.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 163.9 KB
Line 
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
13#include <casa/iomanip.h>
14#include <casa/Exceptions/Error.h>
15#include <casa/Containers/Block.h>
16#include <casa/BasicSL/String.h>
17#include <casa/Arrays/MaskArrLogi.h>
18#include <casa/Arrays/MaskArrMath.h>
19#include <casa/Arrays/ArrayLogical.h>
20#include <casa/Arrays/ArrayMath.h>
21#include <casa/Arrays/Slice.h>
22#include <casa/Arrays/Slicer.h>
23#include <casa/Containers/RecordField.h>
24#include <tables/Tables/TableRow.h>
25#include <tables/Tables/TableVector.h>
26#include <tables/Tables/TabVecMath.h>
27#include <tables/Tables/ExprNode.h>
28#include <tables/Tables/TableRecord.h>
29#include <tables/Tables/TableParse.h>
30#include <tables/Tables/ReadAsciiTable.h>
31#include <tables/Tables/TableIter.h>
32#include <tables/Tables/TableCopy.h>
33#include <scimath/Mathematics/FFTServer.h>
34
35#include <lattices/Lattices/LatticeUtilities.h>
36
37#include <coordinates/Coordinates/SpectralCoordinate.h>
38#include <coordinates/Coordinates/CoordinateSystem.h>
39#include <coordinates/Coordinates/CoordinateUtil.h>
40#include <coordinates/Coordinates/FrequencyAligner.h>
41
42#include <scimath/Mathematics/VectorKernel.h>
43#include <scimath/Mathematics/Convolver.h>
44#include <scimath/Functionals/Polynomial.h>
45
46#include <casa/Logging/LogIO.h>
47#include <sstream>
48
49#include "MathUtils.h"
50#include "RowAccumulator.h"
51#include "STAttr.h"
52#include "STMath.h"
53#include "STSelector.h"
54
55using namespace casa;
56
57using namespace asap;
58
59// tolerance for direction comparison (rad)
60#define TOL_OTF    1.0e-15
61#define TOL_POINT  2.9088821e-4  // 1 arcmin
62
63STMath::STMath(bool insitu) :
64  insitu_(insitu)
65{
66}
67
68
69STMath::~STMath()
70{
71}
72
73CountedPtr<Scantable>
74STMath::average( const std::vector<CountedPtr<Scantable> >& in,
75                 const std::vector<bool>& mask,
76                 const std::string& weight,
77                 const std::string& avmode)
78{
79  LogIO os( LogOrigin( "STMath", "average()", WHERE ) ) ;
80  if ( avmode == "SCAN" && in.size() != 1 )
81    throw(AipsError("Can't perform 'SCAN' averaging on multiple tables.\n"
82                    "Use merge first."));
83  WeightType wtype = stringToWeight(weight);
84
85  // check if OTF observation
86  String obstype = in[0]->getHeader().obstype ;
87  Double tol = 0.0 ;
88  if ( obstype.find( "OTF" ) != String::npos ) {
89    tol = TOL_OTF ;
90  }
91  else {
92    tol = TOL_POINT ;
93  }
94
95  // output
96  // clone as this is non insitu
97  bool insitu = insitu_;
98  setInsitu(false);
99  CountedPtr< Scantable > out = getScantable(in[0], true);
100  setInsitu(insitu);
101  std::vector<CountedPtr<Scantable> >::const_iterator stit = in.begin();
102  ++stit;
103  while ( stit != in.end() ) {
104    out->appendToHistoryTable((*stit)->history());
105    ++stit;
106  }
107
108  Table& tout = out->table();
109
110  /// @todo check if all scantables are conformant
111
112  ArrayColumn<Float> specColOut(tout,"SPECTRA");
113  ArrayColumn<uChar> flagColOut(tout,"FLAGTRA");
114  ArrayColumn<Float> tsysColOut(tout,"TSYS");
115  ScalarColumn<Double> mjdColOut(tout,"TIME");
116  ScalarColumn<Double> intColOut(tout,"INTERVAL");
117  ScalarColumn<uInt> cycColOut(tout,"CYCLENO");
118  ScalarColumn<uInt> scanColOut(tout,"SCANNO");
119
120  // set up the output table rows. These are based on the structure of the
121  // FIRST scantable in the vector
122  const Table& baset = in[0]->table();
123
124  Block<String> cols(3);
125  cols[0] = String("BEAMNO");
126  cols[1] = String("IFNO");
127  cols[2] = String("POLNO");
128  if ( avmode == "SOURCE" ) {
129    cols.resize(4);
130    cols[3] = String("SRCNAME");
131  }
132  if ( avmode == "SCAN"  && in.size() == 1) {
133    //cols.resize(4);
134    //cols[3] = String("SCANNO");
135    cols.resize(5);
136    cols[3] = String("SRCNAME");
137    cols[4] = String("SCANNO");
138  }
139  uInt outrowCount = 0;
140  TableIterator iter(baset, cols);
141//   int count = 0 ;
142  while (!iter.pastEnd()) {
143    Table subt = iter.table();
144//     // copy the first row of this selection into the new table
145//     tout.addRow();
146//     TableCopy::copyRows(tout, subt, outrowCount, 0, 1);
147//     // re-index to 0
148//     if ( avmode != "SCAN" && avmode != "SOURCE" ) {
149//       scanColOut.put(outrowCount, uInt(0));
150//     }
151//     ++outrowCount;
152    MDirection::ScalarColumn dircol ;
153    dircol.attach( subt, "DIRECTION" ) ;
154    Int length = subt.nrow() ;
155    vector< Vector<Double> > dirs ;
156    vector<int> indexes ;
157    for ( Int i = 0 ; i < length ; i++ ) {
158      Vector<Double> t = dircol(i).getAngle(Unit(String("rad"))).getValue() ;
159      //os << << count++ << ": " ;
160      //os << "[" << t[0] << "," << t[1] << "]" << LogIO::POST ;
161      bool adddir = true ;
162      for ( uInt j = 0 ; j < dirs.size() ; j++ ) {
163        //if ( allTrue( t == dirs[j] ) ) {
164        Double dx = t[0] - dirs[j][0] ;
165        Double dy = t[1] - dirs[j][1] ;
166        Double dd = sqrt( dx * dx + dy * dy ) ;
167        //if ( allNearAbs( t, dirs[j], tol ) ) {
168        if ( dd <= tol ) {
169          adddir = false ;
170          break ;
171        }
172      }
173      if ( adddir ) {
174        dirs.push_back( t ) ;
175        indexes.push_back( i ) ;
176      }
177    }
178    uInt rowNum = dirs.size() ;
179    tout.addRow( rowNum ) ;
180    for ( uInt i = 0 ; i < rowNum ; i++ ) {
181      TableCopy::copyRows( tout, subt, outrowCount+i, indexes[i], 1 ) ;
182      // re-index to 0
183      if ( avmode != "SCAN" && avmode != "SOURCE" ) {
184        scanColOut.put(outrowCount+i, uInt(0));
185      }       
186    }
187    outrowCount += rowNum ;
188    ++iter;
189  }
190  RowAccumulator acc(wtype);
191  Vector<Bool> cmask(mask);
192  acc.setUserMask(cmask);
193  ROTableRow row(tout);
194  ROArrayColumn<Float> specCol, tsysCol;
195  ROArrayColumn<uChar> flagCol;
196  ROScalarColumn<Double> mjdCol, intCol;
197  ROScalarColumn<Int> scanIDCol;
198
199  Vector<uInt> rowstodelete;
200
201  for (uInt i=0; i < tout.nrow(); ++i) {
202    for ( int j=0; j < int(in.size()); ++j ) {
203      const Table& tin = in[j]->table();
204      const TableRecord& rec = row.get(i);
205      ROScalarColumn<Double> tmp(tin, "TIME");
206      Double td;tmp.get(0,td);
207      Table basesubt = tin(tin.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
208                       && tin.col("IFNO") == Int(rec.asuInt("IFNO"))
209                       && tin.col("POLNO") == Int(rec.asuInt("POLNO")) );
210      Table subt;
211      if ( avmode == "SOURCE") {
212        subt = basesubt( basesubt.col("SRCNAME") == rec.asString("SRCNAME") );
213      } else if (avmode == "SCAN") {
214        //subt = basesubt( basesubt.col("SCANNO") == Int(rec.asuInt("SCANNO")) );
215        subt = basesubt( basesubt.col("SCANNO") == Int(rec.asuInt("SCANNO"))
216                         && basesubt.col("SRCNAME") == rec.asString("SRCNAME") );
217      } else {
218        subt = basesubt;
219      }
220
221      vector<uInt> removeRows ;
222      uInt nrsubt = subt.nrow() ;
223      for ( uInt irow = 0 ; irow < nrsubt ; irow++ ) {
224        //if ( !allTrue((subt.col("DIRECTION").getArrayDouble(TableExprId(irow)))==rec.asArrayDouble("DIRECTION")) ) {
225        Vector<Double> x0 = (subt.col("DIRECTION").getArrayDouble(TableExprId(irow))) ;
226        Vector<Double> x1 = rec.asArrayDouble("DIRECTION") ;
227        double dx = x0[0] - x1[0] ;
228        double dy = x0[0] - x1[0] ;
229        Double dd = sqrt( dx * dx + dy * dy ) ;
230        //if ( !allNearAbs((subt.col("DIRECTION").getArrayDouble(TableExprId(irow))), rec.asArrayDouble("DIRECTION"), tol ) ) {
231        if ( dd > tol ) {
232          removeRows.push_back( irow ) ;
233        }
234      }
235      if ( removeRows.size() != 0 ) {
236        subt.removeRow( removeRows ) ;
237      }
238     
239      if ( nrsubt == removeRows.size() )
240        throw(AipsError("Averaging data is empty.")) ;
241
242      specCol.attach(subt,"SPECTRA");
243      flagCol.attach(subt,"FLAGTRA");
244      tsysCol.attach(subt,"TSYS");
245      intCol.attach(subt,"INTERVAL");
246      mjdCol.attach(subt,"TIME");
247      Vector<Float> spec,tsys;
248      Vector<uChar> flag;
249      Double inter,time;
250      for (uInt k = 0; k < subt.nrow(); ++k ) {
251        flagCol.get(k, flag);
252        Vector<Bool> bflag(flag.shape());
253        convertArray(bflag, flag);
254        /*
255        if ( allEQ(bflag, True) ) {
256        continue;//don't accumulate
257        }
258        */
259        specCol.get(k, spec);
260        tsysCol.get(k, tsys);
261        intCol.get(k, inter);
262        mjdCol.get(k, time);
263        // spectrum has to be added last to enable weighting by the other values
264        acc.add(spec, !bflag, tsys, inter, time);
265      }
266    }
267    const Vector<Bool>& msk = acc.getMask();
268    if ( allEQ(msk, False) ) {
269      uint n = rowstodelete.nelements();
270      rowstodelete.resize(n+1, True);
271      rowstodelete[n] = i;
272      continue;
273    }
274    //write out
275    if (acc.state()) {
276      Vector<uChar> flg(msk.shape());
277      convertArray(flg, !msk);
278      flagColOut.put(i, flg);
279      specColOut.put(i, acc.getSpectrum());
280      tsysColOut.put(i, acc.getTsys());
281      intColOut.put(i, acc.getInterval());
282      mjdColOut.put(i, acc.getTime());
283      // we should only have one cycle now -> reset it to be 0
284      // frequency switched data has different CYCLENO for different IFNO
285      // which requires resetting this value
286      cycColOut.put(i, uInt(0));
287    } else {
288      ostringstream oss;
289      oss << "For output row="<<i<<", all input rows of data are flagged. no averaging" << endl;
290      pushLog(String(oss));
291    }
292    acc.reset();
293  }
294  if (rowstodelete.nelements() > 0) {
295    //cout << rowstodelete << endl;
296    os << rowstodelete << LogIO::POST ;
297    tout.removeRow(rowstodelete);
298    if (tout.nrow() == 0) {
299      throw(AipsError("Can't average fully flagged data."));
300    }
301  }
302  return out;
303}
304
305CountedPtr< Scantable >
306  STMath::averageChannel( const CountedPtr < Scantable > & in,
307                          const std::string & mode,
308                          const std::string& avmode )
309{
310  // check if OTF observation
311  String obstype = in->getHeader().obstype ;
312  Double tol = 0.0 ;
313  if ( obstype.find( "OTF" ) != String::npos ) {
314    tol = TOL_OTF ;
315  }
316  else {
317    tol = TOL_POINT ;
318  }
319
320  // clone as this is non insitu
321  bool insitu = insitu_;
322  setInsitu(false);
323  CountedPtr< Scantable > out = getScantable(in, true);
324  setInsitu(insitu);
325  Table& tout = out->table();
326  ArrayColumn<Float> specColOut(tout,"SPECTRA");
327  ArrayColumn<uChar> flagColOut(tout,"FLAGTRA");
328  ArrayColumn<Float> tsysColOut(tout,"TSYS");
329  ScalarColumn<uInt> scanColOut(tout,"SCANNO");
330  ScalarColumn<Double> intColOut(tout, "INTERVAL");
331  Table tmp = in->table().sort("BEAMNO");
332  Block<String> cols(3);
333  cols[0] = String("BEAMNO");
334  cols[1] = String("IFNO");
335  cols[2] = String("POLNO");
336  if ( avmode == "SCAN") {
337    cols.resize(4);
338    cols[3] = String("SCANNO");
339  }
340  uInt outrowCount = 0;
341  uChar userflag = 1 << 7;
342  TableIterator iter(tmp, cols);
343  while (!iter.pastEnd()) {
344    Table subt = iter.table();
345    ROArrayColumn<Float> specCol, tsysCol;
346    ROArrayColumn<uChar> flagCol;
347    ROScalarColumn<Double> intCol(subt, "INTERVAL");
348    specCol.attach(subt,"SPECTRA");
349    flagCol.attach(subt,"FLAGTRA");
350    tsysCol.attach(subt,"TSYS");
351//     tout.addRow();
352//     TableCopy::copyRows(tout, subt, outrowCount, 0, 1);
353//     if ( avmode != "SCAN") {
354//       scanColOut.put(outrowCount, uInt(0));
355//     }
356//     Vector<Float> tmp;
357//     specCol.get(0, tmp);
358//     uInt nchan = tmp.nelements();
359//     // have to do channel by channel here as MaskedArrMath
360//     // doesn't have partialMedians
361//     Vector<uChar> flags = flagCol.getColumn(Slicer(Slice(0)));
362//     Vector<Float> outspec(nchan);
363//     Vector<uChar> outflag(nchan,0);
364//     Vector<Float> outtsys(1);/// @fixme when tsys is channel based
365//     for (uInt i=0; i<nchan; ++i) {
366//       Vector<Float> specs = specCol.getColumn(Slicer(Slice(i)));
367//       MaskedArray<Float> ma = maskedArray(specs,flags);
368//       outspec[i] = median(ma);
369//       if ( allEQ(ma.getMask(), False) )
370//         outflag[i] = userflag;// flag data
371//     }
372//     outtsys[0] = median(tsysCol.getColumn());
373//     specColOut.put(outrowCount, outspec);
374//     flagColOut.put(outrowCount, outflag);
375//     tsysColOut.put(outrowCount, outtsys);
376//     Double intsum = sum(intCol.getColumn());
377//     intColOut.put(outrowCount, intsum);
378//     ++outrowCount;
379//     ++iter;
380    MDirection::ScalarColumn dircol ;
381    dircol.attach( subt, "DIRECTION" ) ;
382    Int length = subt.nrow() ;
383    vector< Vector<Double> > dirs ;
384    vector<int> indexes ;
385    for ( Int i = 0 ; i < length ; i++ ) {
386      Vector<Double> t = dircol(i).getAngle(Unit(String("rad"))).getValue() ;
387      bool adddir = true ;
388      for ( uInt j = 0 ; j < dirs.size() ; j++ ) {
389        //if ( allTrue( t == dirs[j] ) ) {
390        Double dx = t[0] - dirs[j][0] ;
391        Double dy = t[1] - dirs[j][1] ;
392        Double dd = sqrt( dx * dx + dy * dy ) ;
393        //if ( allNearAbs( t, dirs[j], tol ) ) {
394        if ( dd <= tol ) {
395          adddir = false ;
396          break ;
397        }
398      }
399      if ( adddir ) {
400        dirs.push_back( t ) ;
401        indexes.push_back( i ) ;
402      }
403    }
404    uInt rowNum = dirs.size() ;
405    tout.addRow( rowNum );
406    for ( uInt i = 0 ; i < rowNum ; i++ ) {
407      TableCopy::copyRows(tout, subt, outrowCount+i, indexes[i], 1) ;
408      if ( avmode != "SCAN") {
409        //scanColOut.put(outrowCount+i, uInt(0));
410      }
411    }
412    MDirection::ScalarColumn dircolOut ;
413    dircolOut.attach( tout, "DIRECTION" ) ;
414    for ( uInt irow = 0 ; irow < rowNum ; irow++ ) {
415      Vector<Double> t = dircolOut(outrowCount+irow).getAngle(Unit(String("rad"))).getValue() ;
416      Vector<Float> tmp;
417      specCol.get(0, tmp);
418      uInt nchan = tmp.nelements();
419      // have to do channel by channel here as MaskedArrMath
420      // doesn't have partialMedians
421      Vector<uChar> flags = flagCol.getColumn(Slicer(Slice(0)));
422      // mask spectra for different DIRECTION
423      for ( uInt jrow = 0 ; jrow < subt.nrow() ; jrow++ ) {
424        Vector<Double> direction = dircol(jrow).getAngle(Unit(String("rad"))).getValue() ;
425        //if ( t[0] != direction[0] || t[1] != direction[1] ) {
426        Double dx = t[0] - direction[0] ;
427        Double dy = t[1] - direction[1] ;
428        Double dd = sqrt( dx * dx + dy * dy ) ;
429        //if ( !allNearAbs( t, direction, tol ) ) {
430        if ( dd > tol ) {
431          flags[jrow] = userflag ;
432        }
433      }
434      Vector<Float> outspec(nchan);
435      Vector<uChar> outflag(nchan,0);
436      Vector<Float> outtsys(1);/// @fixme when tsys is channel based
437      for (uInt i=0; i<nchan; ++i) {
438        Vector<Float> specs = specCol.getColumn(Slicer(Slice(i)));
439        MaskedArray<Float> ma = maskedArray(specs,flags);
440        outspec[i] = median(ma);
441        if ( allEQ(ma.getMask(), False) )
442          outflag[i] = userflag;// flag data
443      }
444      outtsys[0] = median(tsysCol.getColumn());
445      specColOut.put(outrowCount+irow, outspec);
446      flagColOut.put(outrowCount+irow, outflag);
447      tsysColOut.put(outrowCount+irow, outtsys);
448      Vector<Double> integ = intCol.getColumn() ;
449      MaskedArray<Double> mi = maskedArray( integ, flags ) ;
450      Double intsum = sum(mi);
451      intColOut.put(outrowCount+irow, intsum);
452    }
453    outrowCount += rowNum ;
454    ++iter;
455  }
456  return out;
457}
458
459CountedPtr< Scantable > STMath::getScantable(const CountedPtr< Scantable >& in,
460                                             bool droprows)
461{
462  if (insitu_) {
463    return in;
464  }
465  else {
466    // clone
467    return CountedPtr<Scantable>(new Scantable(*in, Bool(droprows)));
468  }
469}
470
471CountedPtr< Scantable > STMath::unaryOperate( const CountedPtr< Scantable >& in,
472                                              float val,
473                                              const std::string& mode,
474                                              bool tsys )
475{
476  CountedPtr< Scantable > out = getScantable(in, false);
477  Table& tab = out->table();
478  ArrayColumn<Float> specCol(tab,"SPECTRA");
479  ArrayColumn<Float> tsysCol(tab,"TSYS");
480  for (uInt i=0; i<tab.nrow(); ++i) {
481    Vector<Float> spec;
482    Vector<Float> ts;
483    specCol.get(i, spec);
484    tsysCol.get(i, ts);
485    if (mode == "MUL" || mode == "DIV") {
486      if (mode == "DIV") val = 1.0/val;
487      spec *= val;
488      specCol.put(i, spec);
489      if ( tsys ) {
490        ts *= val;
491        tsysCol.put(i, ts);
492      }
493    } else if ( mode == "ADD"  || mode == "SUB") {
494      if (mode == "SUB") val *= -1.0;
495      spec += val;
496      specCol.put(i, spec);
497      if ( tsys ) {
498        ts += val;
499        tsysCol.put(i, ts);
500      }
501    }
502  }
503  return out;
504}
505
506CountedPtr< Scantable > STMath::arrayOperate( const CountedPtr< Scantable >& in,
507                                              const std::vector<float> val,
508                                              const std::string& mode,
509                                              const std::string& opmode,
510                                              bool tsys )
511{
512  CountedPtr< Scantable > out ;
513  if ( opmode == "channel" ) {
514    out = arrayOperateChannel( in, val, mode, tsys ) ;
515  }
516  else if ( opmode == "row" ) {
517    out = arrayOperateRow( in, val, mode, tsys ) ;
518  }
519  else {
520    throw( AipsError( "Unknown array operation mode." ) ) ;
521  }
522  return out ;
523}
524
525CountedPtr< Scantable > STMath::arrayOperateChannel( const CountedPtr< Scantable >& in,
526                                                     const std::vector<float> val,
527                                                     const std::string& mode,
528                                                     bool tsys )
529{
530  // conformity of SPECTRA and TSYS
531  if ( tsys ) {
532    TableIterator titer(in->table(), "IFNO");
533    while ( !titer.pastEnd() ) {
534      ArrayColumn<Float> specCol( in->table(), "SPECTRA" ) ;
535      ArrayColumn<Float> tsysCol( in->table(), "TSYS" ) ;
536      Array<Float> spec = specCol.getColumn() ;
537      Array<Float> ts = tsysCol.getColumn() ;
538      if ( !spec.conform( ts ) ) {
539        throw( AipsError( "SPECTRA and TSYS must conform in shape if you want to apply operation on Tsys." ) ) ;
540      }
541      titer.next() ;
542    }
543  }
544
545  // check if all spectra in the scantable have the same number of channel
546  vector<uInt> nchans;
547  vector<uInt> ifnos = in->getIFNos() ;
548  for ( uInt i = 0 ; i < ifnos.size() ; i++ ) {
549    nchans.push_back( in->nchan( ifnos[i] ) ) ;
550  }
551  Vector<uInt> mchans( nchans ) ;
552  if ( anyNE( mchans, mchans[0] ) ) {
553    throw( AipsError("All spectra in the input scantable must have the same number of channel for vector operation." ) ) ;
554  }
555
556  // check if vector size is equal to nchan
557  Vector<Float> fact( val ) ;
558  if ( fact.nelements() != mchans[0] ) {
559    throw( AipsError("Vector size must be same as number of channel.") ) ;
560  }
561
562  // check divided by zero
563  if ( ( mode == "DIV" ) && anyEQ( fact, (float)0.0 ) ) {
564    throw( AipsError("Divided by zero is not recommended." ) ) ;
565  }
566
567  CountedPtr< Scantable > out = getScantable(in, false);
568  Table& tab = out->table();
569  ArrayColumn<Float> specCol(tab,"SPECTRA");
570  ArrayColumn<Float> tsysCol(tab,"TSYS");
571  for (uInt i=0; i<tab.nrow(); ++i) {
572    Vector<Float> spec;
573    Vector<Float> ts;
574    specCol.get(i, spec);
575    tsysCol.get(i, ts);
576    if (mode == "MUL" || mode == "DIV") {
577      if (mode == "DIV") fact = (float)1.0 / fact;
578      spec *= fact;
579      specCol.put(i, spec);
580      if ( tsys ) {
581        ts *= fact;
582        tsysCol.put(i, ts);
583      }
584    } else if ( mode == "ADD"  || mode == "SUB") {
585      if (mode == "SUB") fact *= (float)-1.0 ;
586      spec += fact;
587      specCol.put(i, spec);
588      if ( tsys ) {
589        ts += fact;
590        tsysCol.put(i, ts);
591      }
592    }
593  }
594  return out;
595}
596
597CountedPtr< Scantable > STMath::arrayOperateRow( const CountedPtr< Scantable >& in,
598                                                 const std::vector<float> val,
599                                                 const std::string& mode,
600                                                 bool tsys )
601{
602  // conformity of SPECTRA and TSYS
603  if ( tsys ) {
604    TableIterator titer(in->table(), "IFNO");
605    while ( !titer.pastEnd() ) {
606      ArrayColumn<Float> specCol( in->table(), "SPECTRA" ) ;
607      ArrayColumn<Float> tsysCol( in->table(), "TSYS" ) ;
608      Array<Float> spec = specCol.getColumn() ;
609      Array<Float> ts = tsysCol.getColumn() ;
610      if ( !spec.conform( ts ) ) {
611        throw( AipsError( "SPECTRA and TSYS must conform in shape if you want to apply operation on Tsys." ) ) ;
612      }
613      titer.next() ;
614    }
615  }
616
617  // check if vector size is equal to nrow
618  Vector<Float> fact( val ) ;
619  if ( fact.nelements() != in->nrow() ) {
620    throw( AipsError("Vector size must be same as number of row.") ) ;
621  }
622
623  // check divided by zero
624  if ( ( mode == "DIV" ) && anyEQ( fact, (float)0.0 ) ) {
625    throw( AipsError("Divided by zero is not recommended." ) ) ;
626  }
627
628  CountedPtr< Scantable > out = getScantable(in, false);
629  Table& tab = out->table();
630  ArrayColumn<Float> specCol(tab,"SPECTRA");
631  ArrayColumn<Float> tsysCol(tab,"TSYS");
632  if (mode == "DIV") fact = (float)1.0 / fact;
633  if (mode == "SUB") fact *= (float)-1.0 ;
634  for (uInt i=0; i<tab.nrow(); ++i) {
635    Vector<Float> spec;
636    Vector<Float> ts;
637    specCol.get(i, spec);
638    tsysCol.get(i, ts);
639    if (mode == "MUL" || mode == "DIV") {
640      spec *= fact[i];
641      specCol.put(i, spec);
642      if ( tsys ) {
643        ts *= fact[i];
644        tsysCol.put(i, ts);
645      }
646    } else if ( mode == "ADD"  || mode == "SUB") {
647      spec += fact[i];
648      specCol.put(i, spec);
649      if ( tsys ) {
650        ts += fact[i];
651        tsysCol.put(i, ts);
652      }
653    }
654  }
655  return out;
656}
657
658CountedPtr< Scantable > STMath::array2dOperate( const CountedPtr< Scantable >& in,
659                                                const std::vector< std::vector<float> > val,
660                                                const std::string& mode,
661                                                bool tsys )
662{
663  // conformity of SPECTRA and TSYS
664  if ( tsys ) {
665    TableIterator titer(in->table(), "IFNO");
666    while ( !titer.pastEnd() ) {
667      ArrayColumn<Float> specCol( in->table(), "SPECTRA" ) ;
668      ArrayColumn<Float> tsysCol( in->table(), "TSYS" ) ;
669      Array<Float> spec = specCol.getColumn() ;
670      Array<Float> ts = tsysCol.getColumn() ;
671      if ( !spec.conform( ts ) ) {
672        throw( AipsError( "SPECTRA and TSYS must conform in shape if you want to apply operation on Tsys." ) ) ;
673      }
674      titer.next() ;
675    }
676  }
677
678  // some checks
679  vector<uInt> nchans;
680  for ( uInt i = 0 ; i < in->nrow() ; i++ ) {
681    nchans.push_back( (in->getSpectrum( i )).size() ) ;
682  }
683  //Vector<uInt> mchans( nchans ) ;
684  vector< Vector<Float> > facts ;
685  for ( uInt i = 0 ; i < nchans.size() ; i++ ) {
686    Vector<Float> tmp( val[i] ) ;
687    // check divided by zero
688    if ( ( mode == "DIV" ) && anyEQ( tmp, (float)0.0 ) ) {
689      throw( AipsError("Divided by zero is not recommended." ) ) ;
690    }
691    // conformity check
692    if ( tmp.nelements() != nchans[i] ) {
693      stringstream ss ;
694      ss << "Row " << i << ": Vector size must be same as number of channel." ;
695      throw( AipsError( ss.str() ) ) ;
696    }
697    facts.push_back( tmp ) ;
698  }
699
700
701  CountedPtr< Scantable > out = getScantable(in, false);
702  Table& tab = out->table();
703  ArrayColumn<Float> specCol(tab,"SPECTRA");
704  ArrayColumn<Float> tsysCol(tab,"TSYS");
705  for (uInt i=0; i<tab.nrow(); ++i) {
706    Vector<Float> fact = facts[i] ;
707    Vector<Float> spec;
708    Vector<Float> ts;
709    specCol.get(i, spec);
710    tsysCol.get(i, ts);
711    if (mode == "MUL" || mode == "DIV") {
712      if (mode == "DIV") fact = (float)1.0 / fact;
713      spec *= fact;
714      specCol.put(i, spec);
715      if ( tsys ) {
716        ts *= fact;
717        tsysCol.put(i, ts);
718      }
719    } else if ( mode == "ADD"  || mode == "SUB") {
720      if (mode == "SUB") fact *= (float)-1.0 ;
721      spec += fact;
722      specCol.put(i, spec);
723      if ( tsys ) {
724        ts += fact;
725        tsysCol.put(i, ts);
726      }
727    }
728  }
729  return out;
730}
731
732CountedPtr<Scantable> STMath::binaryOperate(const CountedPtr<Scantable>& left,
733                                            const CountedPtr<Scantable>& right,
734                                            const std::string& mode)
735{
736  bool insitu = insitu_;
737  if ( ! left->conformant(*right) ) {
738    throw(AipsError("'left' and 'right' scantables are not conformant."));
739  }
740  setInsitu(false);
741  CountedPtr< Scantable > out = getScantable(left, false);
742  setInsitu(insitu);
743  Table& tout = out->table();
744  Block<String> coln(5);
745  coln[0] = "SCANNO";  coln[1] = "CYCLENO";  coln[2] = "BEAMNO";
746  coln[3] = "IFNO";  coln[4] = "POLNO";
747  Table tmpl = tout.sort(coln);
748  Table tmpr = right->table().sort(coln);
749  ArrayColumn<Float> lspecCol(tmpl,"SPECTRA");
750  ROArrayColumn<Float> rspecCol(tmpr,"SPECTRA");
751  ArrayColumn<uChar> lflagCol(tmpl,"FLAGTRA");
752  ROArrayColumn<uChar> rflagCol(tmpr,"FLAGTRA");
753
754  for (uInt i=0; i<tout.nrow(); ++i) {
755    Vector<Float> lspecvec, rspecvec;
756    Vector<uChar> lflagvec, rflagvec;
757    lspecvec = lspecCol(i);    rspecvec = rspecCol(i);
758    lflagvec = lflagCol(i);    rflagvec = rflagCol(i);
759    MaskedArray<Float> mleft = maskedArray(lspecvec, lflagvec);
760    MaskedArray<Float> mright = maskedArray(rspecvec, rflagvec);
761    if (mode == "ADD") {
762      mleft += mright;
763    } else if ( mode == "SUB") {
764      mleft -= mright;
765    } else if ( mode == "MUL") {
766      mleft *= mright;
767    } else if ( mode == "DIV") {
768      mleft /= mright;
769    } else {
770      throw(AipsError("Illegal binary operator"));
771    }
772    lspecCol.put(i, mleft.getArray());
773  }
774  return out;
775}
776
777
778
779MaskedArray<Float> STMath::maskedArray( const Vector<Float>& s,
780                                        const Vector<uChar>& f)
781{
782  Vector<Bool> mask;
783  mask.resize(f.shape());
784  convertArray(mask, f);
785  return MaskedArray<Float>(s,!mask);
786}
787
788MaskedArray<Double> STMath::maskedArray( const Vector<Double>& s,
789                                         const Vector<uChar>& f)
790{
791  Vector<Bool> mask;
792  mask.resize(f.shape());
793  convertArray(mask, f);
794  return MaskedArray<Double>(s,!mask);
795}
796
797Vector<uChar> STMath::flagsFromMA(const MaskedArray<Float>& ma)
798{
799  const Vector<Bool>& m = ma.getMask();
800  Vector<uChar> flags(m.shape());
801  convertArray(flags, !m);
802  return flags;
803}
804
805CountedPtr< Scantable > STMath::autoQuotient( const CountedPtr< Scantable >& in,
806                                              const std::string & mode,
807                                              bool preserve )
808{
809  /// @todo make other modes available
810  /// modes should be "nearest", "pair"
811  // make this operation non insitu
812  const Table& tin = in->table();
813  Table ons = tin(tin.col("SRCTYPE") == Int(0));
814  Table offs = tin(tin.col("SRCTYPE") == Int(1));
815  if ( offs.nrow() == 0 )
816    throw(AipsError("No 'off' scans present."));
817  // put all "on" scans into output table
818
819  bool insitu = insitu_;
820  setInsitu(false);
821  CountedPtr< Scantable > out = getScantable(in, true);
822  setInsitu(insitu);
823  Table& tout = out->table();
824
825  TableCopy::copyRows(tout, ons);
826  TableRow row(tout);
827  ROScalarColumn<Double> offtimeCol(offs, "TIME");
828  ArrayColumn<Float> outspecCol(tout, "SPECTRA");
829  ROArrayColumn<Float> outtsysCol(tout, "TSYS");
830  ArrayColumn<uChar> outflagCol(tout, "FLAGTRA");
831  for (uInt i=0; i < tout.nrow(); ++i) {
832    const TableRecord& rec = row.get(i);
833    Double ontime = rec.asDouble("TIME");
834    Table presel = offs(offs.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
835                        && offs.col("IFNO") == Int(rec.asuInt("IFNO"))
836                        && offs.col("POLNO") == Int(rec.asuInt("POLNO")) );
837    ROScalarColumn<Double> offtimeCol(presel, "TIME");
838
839    Double mindeltat = min(abs(offtimeCol.getColumn() - ontime));
840    // Timestamp may vary within a cycle ???!!!
841    // increase this by 0.01 sec in case of rounding errors...
842    // There might be a better way to do this.
843    // fix to this fix. TIME is MJD, so 1.0d not 1.0s
844    mindeltat += 0.01/24./60./60.;
845    Table sel = presel( abs(presel.col("TIME")-ontime) <= mindeltat);
846
847    if ( sel.nrow() < 1 )  {
848      throw(AipsError("No closest in time found... This could be a rounding "
849                      "issue. Try quotient instead."));
850    }
851    TableRow offrow(sel);
852    const TableRecord& offrec = offrow.get(0);//should only be one row
853    RORecordFieldPtr< Array<Float> > specoff(offrec, "SPECTRA");
854    RORecordFieldPtr< Array<Float> > tsysoff(offrec, "TSYS");
855    RORecordFieldPtr< Array<uChar> > flagoff(offrec, "FLAGTRA");
856    /// @fixme this assumes tsys is a scalar not vector
857    Float tsysoffscalar = (*tsysoff)(IPosition(1,0));
858    Vector<Float> specon, tsyson;
859    outtsysCol.get(i, tsyson);
860    outspecCol.get(i, specon);
861    Vector<uChar> flagon;
862    outflagCol.get(i, flagon);
863    MaskedArray<Float> mon = maskedArray(specon, flagon);
864    MaskedArray<Float> moff = maskedArray(*specoff, *flagoff);
865    MaskedArray<Float> quot = (tsysoffscalar * mon / moff);
866    if (preserve) {
867      quot -= tsysoffscalar;
868    } else {
869      quot -= tsyson[0];
870    }
871    outspecCol.put(i, quot.getArray());
872    outflagCol.put(i, flagsFromMA(quot));
873  }
874  // renumber scanno
875  TableIterator it(tout, "SCANNO");
876  uInt i = 0;
877  while ( !it.pastEnd() ) {
878    Table t = it.table();
879    TableVector<uInt> vec(t, "SCANNO");
880    vec = i;
881    ++i;
882    ++it;
883  }
884  return out;
885}
886
887
888CountedPtr< Scantable > STMath::quotient( const CountedPtr< Scantable > & on,
889                                          const CountedPtr< Scantable > & off,
890                                          bool preserve )
891{
892  bool insitu = insitu_;
893  if ( ! on->conformant(*off) ) {
894    throw(AipsError("'on' and 'off' scantables are not conformant."));
895  }
896  setInsitu(false);
897  CountedPtr< Scantable > out = getScantable(on, false);
898  setInsitu(insitu);
899  Table& tout = out->table();
900  const Table& toff = off->table();
901  TableIterator sit(tout, "SCANNO");
902  TableIterator s2it(toff, "SCANNO");
903  while ( !sit.pastEnd() ) {
904    Table ton = sit.table();
905    TableRow row(ton);
906    Table t = s2it.table();
907    ArrayColumn<Float> outspecCol(ton, "SPECTRA");
908    ROArrayColumn<Float> outtsysCol(ton, "TSYS");
909    ArrayColumn<uChar> outflagCol(ton, "FLAGTRA");
910    for (uInt i=0; i < ton.nrow(); ++i) {
911      const TableRecord& rec = row.get(i);
912      Table offsel = t( t.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
913                          && t.col("IFNO") == Int(rec.asuInt("IFNO"))
914                          && t.col("POLNO") == Int(rec.asuInt("POLNO")) );
915      if ( offsel.nrow() == 0 )
916        throw AipsError("STMath::quotient: no matching off");
917      TableRow offrow(offsel);
918      const TableRecord& offrec = offrow.get(0);//should be ncycles - take first
919      RORecordFieldPtr< Array<Float> > specoff(offrec, "SPECTRA");
920      RORecordFieldPtr< Array<Float> > tsysoff(offrec, "TSYS");
921      RORecordFieldPtr< Array<uChar> > flagoff(offrec, "FLAGTRA");
922      Float tsysoffscalar = (*tsysoff)(IPosition(1,0));
923      Vector<Float> specon, tsyson;
924      outtsysCol.get(i, tsyson);
925      outspecCol.get(i, specon);
926      Vector<uChar> flagon;
927      outflagCol.get(i, flagon);
928      MaskedArray<Float> mon = maskedArray(specon, flagon);
929      MaskedArray<Float> moff = maskedArray(*specoff, *flagoff);
930      MaskedArray<Float> quot = (tsysoffscalar * mon / moff);
931      if (preserve) {
932        quot -= tsysoffscalar;
933      } else {
934        quot -= tsyson[0];
935      }
936      outspecCol.put(i, quot.getArray());
937      outflagCol.put(i, flagsFromMA(quot));
938    }
939    ++sit;
940    ++s2it;
941    // take the first off for each on scan which doesn't have a
942    // matching off scan
943    // non <= noff:  matching pairs, non > noff matching pairs then first off
944    if ( s2it.pastEnd() ) s2it.reset();
945  }
946  return out;
947}
948
949// dototalpower (migration of GBTIDL procedure dototalpower.pro)
950// calibrate the CAL on-off pair. It calculate Tsys and average CAL on-off subintegrations
951// do it for each cycles in a specific scan.
952CountedPtr< Scantable > STMath::dototalpower( const CountedPtr< Scantable >& calon,
953                                              const CountedPtr< Scantable >& caloff, Float tcal )
954{
955if ( ! calon->conformant(*caloff) ) {
956    throw(AipsError("'CAL on' and 'CAL off' scantables are not conformant."));
957  }
958  setInsitu(false);
959  CountedPtr< Scantable > out = getScantable(caloff, false);
960  Table& tout = out->table();
961  const Table& tcon = calon->table();
962  Vector<Float> tcalout;
963  Vector<Float> tcalout2;  //debug
964
965  if ( tout.nrow() != tcon.nrow() ) {
966    throw(AipsError("Mismatch in number of rows to form cal on - off pair."));
967  }
968  // iteration by scanno or cycle no.
969  TableIterator sit(tout, "SCANNO");
970  TableIterator s2it(tcon, "SCANNO");
971  while ( !sit.pastEnd() ) {
972    Table toff = sit.table();
973    TableRow row(toff);
974    Table t = s2it.table();
975    ScalarColumn<Double> outintCol(toff, "INTERVAL");
976    ArrayColumn<Float> outspecCol(toff, "SPECTRA");
977    ArrayColumn<Float> outtsysCol(toff, "TSYS");
978    ArrayColumn<uChar> outflagCol(toff, "FLAGTRA");
979    ROScalarColumn<uInt> outtcalIdCol(toff, "TCAL_ID");
980    ROScalarColumn<uInt> outpolCol(toff, "POLNO");
981    ROScalarColumn<Double> onintCol(t, "INTERVAL");
982    ROArrayColumn<Float> onspecCol(t, "SPECTRA");
983    ROArrayColumn<Float> ontsysCol(t, "TSYS");
984    ROArrayColumn<uChar> onflagCol(t, "FLAGTRA");
985    //ROScalarColumn<uInt> ontcalIdCol(t, "TCAL_ID");
986
987    for (uInt i=0; i < toff.nrow(); ++i) {
988      //skip these checks -> assumes the data order are the same between the cal on off pairs
989      //
990      Vector<Float> specCalon, specCaloff;
991      // to store scalar (mean) tsys
992      Vector<Float> tsysout(1);
993      uInt tcalId, polno;
994      Double offint, onint;
995      outpolCol.get(i, polno);
996      outspecCol.get(i, specCaloff);
997      onspecCol.get(i, specCalon);
998      Vector<uChar> flagCaloff, flagCalon;
999      outflagCol.get(i, flagCaloff);
1000      onflagCol.get(i, flagCalon);
1001      outtcalIdCol.get(i, tcalId);
1002      outintCol.get(i, offint);
1003      onintCol.get(i, onint);
1004      // caluculate mean Tsys
1005      uInt nchan = specCaloff.nelements();
1006      // percentage of edge cut off
1007      uInt pc = 10;
1008      uInt bchan = nchan/pc;
1009      uInt echan = nchan-bchan;
1010
1011      Slicer chansl(IPosition(1,bchan-1), IPosition(1,echan-1), IPosition(1,1),Slicer::endIsLast);
1012      Vector<Float> testsubsp = specCaloff(chansl);
1013      MaskedArray<Float> spoff = maskedArray( specCaloff(chansl),flagCaloff(chansl) );
1014      MaskedArray<Float> spon = maskedArray( specCalon(chansl),flagCalon(chansl) );
1015      MaskedArray<Float> spdiff = spon-spoff;
1016      uInt noff = spoff.nelementsValid();
1017      //uInt non = spon.nelementsValid();
1018      uInt ndiff = spdiff.nelementsValid();
1019      Float meantsys;
1020
1021/**
1022      Double subspec, subdiff;
1023      uInt usednchan;
1024      subspec = 0;
1025      subdiff = 0;
1026      usednchan = 0;
1027      for(uInt k=(bchan-1); k<echan; k++) {
1028        subspec += specCaloff[k];
1029        subdiff += static_cast<Double>(specCalon[k]-specCaloff[k]);
1030        ++usednchan;
1031      }
1032**/
1033      // get tcal if input tcal <= 0
1034      String tcalt;
1035      Float tcalUsed;
1036      tcalUsed = tcal;
1037      if ( tcal <= 0.0 ) {
1038        caloff->tcal().getEntry(tcalt, tcalout, tcalId);
1039        if (polno<=3) {
1040          tcalUsed = tcalout[polno];
1041        }
1042        else {
1043          tcalUsed = tcalout[0];
1044        }
1045      }
1046
1047      Float meanoff;
1048      Float meandiff;
1049      if (noff && ndiff) {
1050         //Debug
1051         //if(noff!=ndiff) cerr<<"noff and ndiff is not equal"<<endl;
1052         //LogIO os( LogOrigin( "STMath", "dototalpower()", WHERE ) ) ;
1053         //if(noff!=ndiff) os<<"noff and ndiff is not equal"<<LogIO::POST;
1054         meanoff = sum(spoff)/noff;
1055         meandiff = sum(spdiff)/ndiff;
1056         meantsys= (meanoff/meandiff )*tcalUsed + tcalUsed/2;
1057      }
1058      else {
1059         meantsys=1;
1060      }
1061
1062      tsysout[0] = Float(meantsys);
1063      MaskedArray<Float> mcaloff = maskedArray(specCaloff, flagCaloff);
1064      MaskedArray<Float> mcalon = maskedArray(specCalon, flagCalon);
1065      MaskedArray<Float> sig =   Float(0.5) * (mcaloff + mcalon);
1066      //uInt ncaloff = mcaloff.nelementsValid();
1067      //uInt ncalon = mcalon.nelementsValid();
1068
1069      outintCol.put(i, offint+onint);
1070      outspecCol.put(i, sig.getArray());
1071      outflagCol.put(i, flagsFromMA(sig));
1072      outtsysCol.put(i, tsysout);
1073    }
1074    ++sit;
1075    ++s2it;
1076  }
1077  return out;
1078}
1079
1080//dosigref - migrated from GBT IDL's dosigref.pro, do calibration of position switch
1081// observatiions.
1082// input: sig and ref scantables, and an optional boxcar smoothing width(default width=0,
1083//        no smoothing).
1084// output: resultant scantable [= (sig-ref/ref)*tsys]
1085CountedPtr< Scantable > STMath::dosigref( const CountedPtr < Scantable >& sig,
1086                                          const CountedPtr < Scantable >& ref,
1087                                          int smoothref,
1088                                          casa::Float tsysv,
1089                                          casa::Float tau )
1090{
1091if ( ! ref->conformant(*sig) ) {
1092    throw(AipsError("'sig' and 'ref' scantables are not conformant."));
1093  }
1094  setInsitu(false);
1095  CountedPtr< Scantable > out = getScantable(sig, false);
1096  CountedPtr< Scantable > smref;
1097  if ( smoothref > 1 ) {
1098    float fsmoothref = static_cast<float>(smoothref);
1099    std::string inkernel = "boxcar";
1100    smref = smooth(ref, inkernel, fsmoothref );
1101    ostringstream oss;
1102    oss<<"Applied smoothing of "<<fsmoothref<<" on the reference."<<endl;
1103    pushLog(String(oss));
1104  }
1105  else {
1106    smref = ref;
1107  }
1108  Table& tout = out->table();
1109  const Table& tref = smref->table();
1110  if ( tout.nrow() != tref.nrow() ) {
1111    throw(AipsError("Mismatch in number of rows to form on-source and reference pair."));
1112  }
1113  // iteration by scanno? or cycle no.
1114  TableIterator sit(tout, "SCANNO");
1115  TableIterator s2it(tref, "SCANNO");
1116  while ( !sit.pastEnd() ) {
1117    Table ton = sit.table();
1118    Table t = s2it.table();
1119    ScalarColumn<Double> outintCol(ton, "INTERVAL");
1120    ArrayColumn<Float> outspecCol(ton, "SPECTRA");
1121    ArrayColumn<Float> outtsysCol(ton, "TSYS");
1122    ArrayColumn<uChar> outflagCol(ton, "FLAGTRA");
1123    ArrayColumn<Float> refspecCol(t, "SPECTRA");
1124    ROScalarColumn<Double> refintCol(t, "INTERVAL");
1125    ROArrayColumn<Float> reftsysCol(t, "TSYS");
1126    ArrayColumn<uChar> refflagCol(t, "FLAGTRA");
1127    ROScalarColumn<Float> refelevCol(t, "ELEVATION");
1128    for (uInt i=0; i < ton.nrow(); ++i) {
1129
1130      Double onint, refint;
1131      Vector<Float> specon, specref;
1132      // to store scalar (mean) tsys
1133      Vector<Float> tsysref;
1134      outintCol.get(i, onint);
1135      refintCol.get(i, refint);
1136      outspecCol.get(i, specon);
1137      refspecCol.get(i, specref);
1138      Vector<uChar> flagref, flagon;
1139      outflagCol.get(i, flagon);
1140      refflagCol.get(i, flagref);
1141      reftsysCol.get(i, tsysref);
1142
1143      Float tsysrefscalar;
1144      if ( tsysv > 0.0 ) {
1145        ostringstream oss;
1146        Float elev;
1147        refelevCol.get(i, elev);
1148        oss << "user specified Tsys = " << tsysv;
1149        // do recalc elevation if EL = 0
1150        if ( elev == 0 ) {
1151          throw(AipsError("EL=0, elevation data is missing."));
1152        } else {
1153          if ( tau <= 0.0 ) {
1154            throw(AipsError("Valid tau is not supplied."));
1155          } else {
1156            tsysrefscalar = tsysv * exp(tau/elev);
1157          }
1158        }
1159        oss << ", corrected (for El) tsys= "<<tsysrefscalar;
1160        pushLog(String(oss));
1161      }
1162      else {
1163        tsysrefscalar = tsysref[0];
1164      }
1165      //get quotient spectrum
1166      MaskedArray<Float> mref = maskedArray(specref, flagref);
1167      MaskedArray<Float> mon = maskedArray(specon, flagon);
1168      MaskedArray<Float> specres =   tsysrefscalar*((mon - mref)/mref);
1169      Double resint = onint*refint*smoothref/(onint+refint*smoothref);
1170
1171      //Debug
1172      //cerr<<"Tsys used="<<tsysrefscalar<<endl;
1173      //LogIO os( LogOrigin( "STMath", "dosigref", WHERE ) ) ;
1174      //os<<"Tsys used="<<tsysrefscalar<<LogIO::POST;
1175      // fill the result, replay signal tsys by reference tsys
1176      outintCol.put(i, resint);
1177      outspecCol.put(i, specres.getArray());
1178      outflagCol.put(i, flagsFromMA(specres));
1179      outtsysCol.put(i, tsysref);
1180    }
1181    ++sit;
1182    ++s2it;
1183  }
1184  return out;
1185}
1186
1187CountedPtr< Scantable > STMath::donod(const casa::CountedPtr<Scantable>& s,
1188                                     const std::vector<int>& scans,
1189                                     int smoothref,
1190                                     casa::Float tsysv,
1191                                     casa::Float tau,
1192                                     casa::Float tcal )
1193
1194{
1195  setInsitu(false);
1196  STSelector sel;
1197  std::vector<int> scan1, scan2, beams;
1198  std::vector< vector<int> > scanpair;
1199  std::vector<string> calstate;
1200  String msg;
1201
1202  CountedPtr< Scantable > s1b1on, s1b1off, s1b2on, s1b2off;
1203  CountedPtr< Scantable > s2b1on, s2b1off, s2b2on, s2b2off;
1204
1205  std::vector< CountedPtr< Scantable > > sctables;
1206  sctables.push_back(s1b1on);
1207  sctables.push_back(s1b1off);
1208  sctables.push_back(s1b2on);
1209  sctables.push_back(s1b2off);
1210  sctables.push_back(s2b1on);
1211  sctables.push_back(s2b1off);
1212  sctables.push_back(s2b2on);
1213  sctables.push_back(s2b2off);
1214
1215  //check scanlist
1216  int n=s->checkScanInfo(scans);
1217  if (n==1) {
1218     throw(AipsError("Incorrect scan pairs. "));
1219  }
1220
1221  // Assume scans contain only a pair of consecutive scan numbers.
1222  // It is assumed that first beam, b1,  is on target.
1223  // There is no check if the first beam is on or not.
1224  if ( scans.size()==1 ) {
1225    scan1.push_back(scans[0]);
1226    scan2.push_back(scans[0]+1);
1227  } else if ( scans.size()==2 ) {
1228   scan1.push_back(scans[0]);
1229   scan2.push_back(scans[1]);
1230  } else {
1231    if ( scans.size()%2 == 0 ) {
1232      for (uInt i=0; i<scans.size(); i++) {
1233        if (i%2 == 0) {
1234          scan1.push_back(scans[i]);
1235        }
1236        else {
1237          scan2.push_back(scans[i]);
1238        }
1239      }
1240    } else {
1241      throw(AipsError("Odd numbers of scans, cannot form pairs."));
1242    }
1243  }
1244  scanpair.push_back(scan1);
1245  scanpair.push_back(scan2);
1246  calstate.push_back("*calon");
1247  calstate.push_back("*[^calon]");
1248  CountedPtr< Scantable > ws = getScantable(s, false);
1249  uInt l=0;
1250  while ( l < sctables.size() ) {
1251    for (uInt i=0; i < 2; i++) {
1252      for (uInt j=0; j < 2; j++) {
1253        for (uInt k=0; k < 2; k++) {
1254          sel.reset();
1255          sel.setScans(scanpair[i]);
1256          sel.setName(calstate[k]);
1257          beams.clear();
1258          beams.push_back(j);
1259          sel.setBeams(beams);
1260          ws->setSelection(sel);
1261          sctables[l]= getScantable(ws, false);
1262          l++;
1263        }
1264      }
1265    }
1266  }
1267
1268  // replace here by splitData or getData functionality
1269  CountedPtr< Scantable > sig1;
1270  CountedPtr< Scantable > ref1;
1271  CountedPtr< Scantable > sig2;
1272  CountedPtr< Scantable > ref2;
1273  CountedPtr< Scantable > calb1;
1274  CountedPtr< Scantable > calb2;
1275
1276  msg=String("Processing dototalpower for subset of the data");
1277  ostringstream oss1;
1278  oss1 << msg  << endl;
1279  pushLog(String(oss1));
1280  // Debug for IRC CS data
1281  //float tcal1=7.0;
1282  //float tcal2=4.0;
1283  sig1 = dototalpower(sctables[0], sctables[1], tcal=tcal);
1284  ref1 = dototalpower(sctables[2], sctables[3], tcal=tcal);
1285  ref2 = dototalpower(sctables[4], sctables[5], tcal=tcal);
1286  sig2 = dototalpower(sctables[6], sctables[7], tcal=tcal);
1287
1288  // correction of user-specified tsys for elevation here
1289
1290  // dosigref calibration
1291  msg=String("Processing dosigref for subset of the data");
1292  ostringstream oss2;
1293  oss2 << msg  << endl;
1294  pushLog(String(oss2));
1295  calb1=dosigref(sig1,ref2,smoothref,tsysv,tau);
1296  calb2=dosigref(sig2,ref1,smoothref,tsysv,tau);
1297
1298  // iteration by scanno or cycle no.
1299  Table& tcalb1 = calb1->table();
1300  Table& tcalb2 = calb2->table();
1301  TableIterator sit(tcalb1, "SCANNO");
1302  TableIterator s2it(tcalb2, "SCANNO");
1303  while ( !sit.pastEnd() ) {
1304    Table t1 = sit.table();
1305    Table t2= s2it.table();
1306    ArrayColumn<Float> outspecCol(t1, "SPECTRA");
1307    ArrayColumn<Float> outtsysCol(t1, "TSYS");
1308    ArrayColumn<uChar> outflagCol(t1, "FLAGTRA");
1309    ScalarColumn<Double> outintCol(t1, "INTERVAL");
1310    ArrayColumn<Float> t2specCol(t2, "SPECTRA");
1311    ROArrayColumn<Float> t2tsysCol(t2, "TSYS");
1312    ArrayColumn<uChar> t2flagCol(t2, "FLAGTRA");
1313    ROScalarColumn<Double> t2intCol(t2, "INTERVAL");
1314    for (uInt i=0; i < t1.nrow(); ++i) {
1315      Vector<Float> spec1, spec2;
1316      // to store scalar (mean) tsys
1317      Vector<Float> tsys1, tsys2;
1318      Vector<uChar> flag1, flag2;
1319      Double tint1, tint2;
1320      outspecCol.get(i, spec1);
1321      t2specCol.get(i, spec2);
1322      outflagCol.get(i, flag1);
1323      t2flagCol.get(i, flag2);
1324      outtsysCol.get(i, tsys1);
1325      t2tsysCol.get(i, tsys2);
1326      outintCol.get(i, tint1);
1327      t2intCol.get(i, tint2);
1328      // average
1329      // assume scalar tsys for weights
1330      Float wt1, wt2, tsyssq1, tsyssq2;
1331      tsyssq1 = tsys1[0]*tsys1[0];
1332      tsyssq2 = tsys2[0]*tsys2[0];
1333      wt1 = Float(tint1)/tsyssq1;
1334      wt2 = Float(tint2)/tsyssq2;
1335      Float invsumwt=1/(wt1+wt2);
1336      MaskedArray<Float> mspec1 = maskedArray(spec1, flag1);
1337      MaskedArray<Float> mspec2 = maskedArray(spec2, flag2);
1338      MaskedArray<Float> avspec =  invsumwt * (wt1*mspec1 + wt2*mspec2);
1339      //Array<Float> avtsys =  Float(0.5) * (tsys1 + tsys2);
1340      // cerr<< "Tsys1="<<tsys1<<" Tsys2="<<tsys2<<endl;
1341      // LogIO os( LogOrigin( "STMath", "donod", WHERE ) ) ;
1342      // os<< "Tsys1="<<tsys1<<" Tsys2="<<tsys2<<LogIO::POST;
1343      tsys1[0] = sqrt(tsyssq1 + tsyssq2);
1344      Array<Float> avtsys =  tsys1;
1345
1346      outspecCol.put(i, avspec.getArray());
1347      outflagCol.put(i, flagsFromMA(avspec));
1348      outtsysCol.put(i, avtsys);
1349    }
1350    ++sit;
1351    ++s2it;
1352  }
1353  return calb1;
1354}
1355
1356//GBTIDL version of frequency switched data calibration
1357CountedPtr< Scantable > STMath::dofs( const CountedPtr< Scantable >& s,
1358                                      const std::vector<int>& scans,
1359                                      int smoothref,
1360                                      casa::Float tsysv,
1361                                      casa::Float tau,
1362                                      casa::Float tcal )
1363{
1364
1365 
1366  STSelector sel;
1367  CountedPtr< Scantable > ws = getScantable(s, false);
1368  CountedPtr< Scantable > sig, sigwcal, ref, refwcal;
1369  CountedPtr< Scantable > calsig, calref, out, out1, out2;
1370  Bool nofold=False;
1371
1372  //split the data
1373  sel.setName("*_fs");
1374  ws->setSelection(sel);
1375  sig = getScantable(ws,false);
1376  sel.reset();
1377  sel.setName("*_fs_calon");
1378  ws->setSelection(sel);
1379  sigwcal = getScantable(ws,false);
1380  sel.reset();
1381  sel.setName("*_fsr");
1382  ws->setSelection(sel);
1383  ref = getScantable(ws,false);
1384  sel.reset();
1385  sel.setName("*_fsr_calon");
1386  ws->setSelection(sel);
1387  refwcal = getScantable(ws,false);
1388
1389  calsig = dototalpower(sigwcal, sig, tcal=tcal);
1390  calref = dototalpower(refwcal, ref, tcal=tcal);
1391
1392  out1=dosigref(calsig,calref,smoothref,tsysv,tau);
1393  out2=dosigref(calref,calsig,smoothref,tsysv,tau);
1394
1395  Table& tabout1=out1->table();
1396  Table& tabout2=out2->table();
1397  ROScalarColumn<uInt> freqidCol1(tabout1, "FREQ_ID");
1398  ScalarColumn<uInt> freqidCol2(tabout2, "FREQ_ID");
1399  ROArrayColumn<Float> specCol(tabout2, "SPECTRA");
1400  Vector<Float> spec; specCol.get(0, spec);
1401  uInt nchan = spec.nelements();
1402  uInt freqid1; freqidCol1.get(0,freqid1);
1403  uInt freqid2; freqidCol2.get(0,freqid2);
1404  Double rp1, rp2, rv1, rv2, inc1, inc2;
1405  out1->frequencies().getEntry(rp1, rv1, inc1, freqid1);
1406  out2->frequencies().getEntry(rp2, rv2, inc2, freqid2);
1407  //cerr << out1->frequencies().table().nrow() << " " << out2->frequencies().table().nrow() << endl ;
1408  //LogIO os( LogOrigin( "STMath", "dofs()", WHERE ) ) ;
1409  //os << out1->frequencies().table().nrow() << " " << out2->frequencies().table().nrow() << LogIO::POST ;
1410  if (rp1==rp2) {
1411    Double foffset = rv1 - rv2;
1412    uInt choffset = static_cast<uInt>(foffset/abs(inc2));
1413    if (choffset >= nchan) {
1414      //cerr<<"out-band frequency switching, no folding"<<endl;
1415      LogIO os( LogOrigin( "STMath", "dofs()", WHERE ) ) ;
1416      os<<"out-band frequency switching, no folding"<<LogIO::POST;
1417      nofold = True;
1418    }
1419  }
1420
1421  if (nofold) {
1422    std::vector< CountedPtr< Scantable > > tabs;
1423    tabs.push_back(out1);
1424    tabs.push_back(out2);
1425    out = merge(tabs);
1426  }
1427  else {
1428    //out = out1;
1429    Double choffset = ( rv1 - rv2 ) / inc2 ;
1430    out = dofold( out1, out2, choffset ) ;
1431  }
1432   
1433  return out;
1434}
1435
1436CountedPtr<Scantable> STMath::dofold( const CountedPtr<Scantable> &sig,
1437                                      const CountedPtr<Scantable> &ref,
1438                                      Double choffset,
1439                                      Double choffset2 )
1440{
1441  LogIO os( LogOrigin( "STMath", "dofold", WHERE ) ) ;
1442  os << "choffset=" << choffset << " choffset2=" << choffset2 << LogIO::POST ;
1443
1444  // output scantable
1445  CountedPtr<Scantable> out = getScantable( sig, false ) ;
1446
1447  // separate choffset to integer part and decimal part
1448  Int ioffset = (Int)choffset ;
1449  Double doffset = choffset - ioffset ;
1450  Int ioffset2 = (Int)choffset2 ;
1451  Double doffset2 = choffset2 - ioffset2 ;
1452  os << "ioffset=" << ioffset << " doffset=" << doffset << LogIO::POST ;
1453  os << "ioffset2=" << ioffset2 << " doffset2=" << doffset2 << LogIO::POST ; 
1454
1455  // get column
1456  ROArrayColumn<Float> specCol1( sig->table(), "SPECTRA" ) ;
1457  ROArrayColumn<Float> specCol2( ref->table(), "SPECTRA" ) ;
1458  ROArrayColumn<Float> tsysCol1( sig->table(), "TSYS" ) ;
1459  ROArrayColumn<Float> tsysCol2( ref->table(), "TSYS" ) ;
1460  ROArrayColumn<uChar> flagCol1( sig->table(), "FLAGTRA" ) ;
1461  ROArrayColumn<uChar> flagCol2( ref->table(), "FLAGTRA" ) ;
1462  ROScalarColumn<Double> mjdCol1( sig->table(), "TIME" ) ;
1463  ROScalarColumn<Double> mjdCol2( ref->table(), "TIME" ) ;
1464  ROScalarColumn<Double> intervalCol1( sig->table(), "INTERVAL" ) ;
1465  ROScalarColumn<Double> intervalCol2( ref->table(), "INTERVAL" ) ;
1466
1467  // check
1468  if ( ioffset == 0 ) {
1469    LogIO os( LogOrigin( "STMath", "dofold()", WHERE ) ) ;
1470    os << "channel offset is zero, no folding" << LogIO::POST ;
1471    return out ;
1472  }
1473  int nchan = ref->nchan() ;
1474  if ( abs(ioffset) >= nchan ) {
1475    LogIO os( LogOrigin( "STMath", "dofold()", WHERE ) ) ;
1476    os << "out-band frequency switching, no folding" << LogIO::POST ;
1477    return out ;
1478  }
1479
1480  // attach column for output scantable
1481  ArrayColumn<Float> specColOut( out->table(), "SPECTRA" ) ;
1482  ArrayColumn<uChar> flagColOut( out->table(), "FLAGTRA" ) ;
1483  ArrayColumn<Float> tsysColOut( out->table(), "TSYS" ) ;
1484  ScalarColumn<Double> mjdColOut( out->table(), "TIME" ) ;
1485  ScalarColumn<Double> intervalColOut( out->table(), "INTERVAL" ) ;
1486  ScalarColumn<uInt> fidColOut( out->table(), "FREQ_ID" ) ;
1487
1488  // for each row
1489  // assume that the data order are same between sig and ref
1490  RowAccumulator acc( asap::TINTSYS ) ;
1491  for ( int i = 0 ; i < sig->nrow() ; i++ ) {
1492    // get values
1493    Vector<Float> spsig ;
1494    specCol1.get( i, spsig ) ;
1495    Vector<Float> spref ;
1496    specCol2.get( i, spref ) ;
1497    Vector<Float> tsyssig ;
1498    tsysCol1.get( i, tsyssig ) ;
1499    Vector<Float> tsysref ;
1500    tsysCol2.get( i, tsysref ) ;
1501    Vector<uChar> flagsig ;
1502    flagCol1.get( i, flagsig ) ;
1503    Vector<uChar> flagref ;
1504    flagCol2.get( i, flagref ) ;
1505    Double timesig ;
1506    mjdCol1.get( i, timesig ) ;
1507    Double timeref ;
1508    mjdCol2.get( i, timeref ) ;
1509    Double intsig ;
1510    intervalCol1.get( i, intsig ) ;
1511    Double intref ;
1512    intervalCol2.get( i, intref ) ;
1513
1514    // shift reference spectra
1515    int refchan = spref.nelements() ;
1516    Vector<Float> sspref( spref.nelements() ) ;
1517    Vector<Float> stsysref( tsysref.nelements() ) ;
1518    Vector<uChar> sflagref( flagref.nelements() ) ;
1519    if ( ioffset > 0 ) {
1520      // SPECTRA and FLAGTRA
1521      for ( int j = 0 ; j < refchan-ioffset ; j++ ) {
1522        sspref[j] = spref[j+ioffset] ;
1523        sflagref[j] = flagref[j+ioffset] ;
1524      }
1525      for ( int j = refchan-ioffset ; j < refchan ; j++ ) {
1526        sspref[j] = spref[j-refchan+ioffset] ;
1527        sflagref[j] = flagref[j-refchan+ioffset] ;
1528      }
1529      spref = sspref.copy() ;
1530      flagref = sflagref.copy() ;
1531      for ( int j = 0 ; j < refchan - 1 ; j++ ) {
1532        sspref[j] = doffset * spref[j+1] + ( 1.0 - doffset ) * spref[j] ;
1533        sflagref[j] = flagref[j+1] + flagref[j] ;
1534      }
1535      sspref[refchan-1] = doffset * spref[0] + ( 1.0 - doffset ) * spref[refchan-1] ;
1536      sflagref[refchan-1] = flagref[0] + flagref[refchan-1] ;
1537
1538      // TSYS
1539      if ( spref.nelements() == tsysref.nelements() ) {
1540        for ( int j = 0 ; j < refchan-ioffset ; j++ ) {
1541          stsysref[j] = tsysref[j+ioffset] ;
1542        }
1543        for ( int j = refchan-ioffset ; j < refchan ; j++ ) {
1544          stsysref[j] = tsysref[j-refchan+ioffset] ;
1545        }
1546        tsysref = stsysref.copy() ;
1547        for ( int j = 0 ; j < refchan - 1 ; j++ ) {
1548          stsysref[j] = doffset * tsysref[j+1] + ( 1.0 - doffset ) * tsysref[j] ;
1549        }
1550        stsysref[refchan-1] = doffset * tsysref[0] + ( 1.0 - doffset ) * tsysref[refchan-1] ;
1551      }
1552    }
1553    else {
1554      // SPECTRA and FLAGTRA
1555      for ( int j = 0 ; j < abs(ioffset) ; j++ ) {
1556        sspref[j] = spref[refchan+ioffset+j] ;
1557        sflagref[j] = flagref[refchan+ioffset+j] ;
1558      }
1559      for ( int j = abs(ioffset) ; j < refchan ; j++ ) {
1560        sspref[j] = spref[j+ioffset] ;
1561        sflagref[j] = flagref[j+ioffset] ;
1562      }
1563      spref = sspref.copy() ;
1564      flagref = sflagref.copy() ;
1565      sspref[0] = doffset * spref[refchan-1] + ( 1.0 - doffset ) * spref[0] ;
1566      sflagref[0] = flagref[0] + flagref[refchan-1] ;
1567      for ( int j = 1 ; j < refchan ; j++ ) {
1568        sspref[j] = doffset * spref[j-1] + ( 1.0 - doffset ) * spref[j] ;
1569        sflagref[j] = flagref[j-1] + flagref[j] ;
1570      }
1571      // TSYS
1572      if ( spref.nelements() == tsysref.nelements() ) {
1573        for ( int j = 0 ; j < abs(ioffset) ; j++ ) {
1574          stsysref[j] = tsysref[refchan+ioffset+j] ;
1575        }
1576        for ( int j = abs(ioffset) ; j < refchan ; j++ ) {
1577          stsysref[j] = tsysref[j+ioffset] ;
1578        }
1579        tsysref = stsysref.copy() ;
1580        stsysref[0] = doffset * tsysref[refchan-1] + ( 1.0 - doffset ) * tsysref[0] ;
1581        for ( int j = 1 ; j < refchan ; j++ ) {
1582          stsysref[j] = doffset * tsysref[j-1] + ( 1.0 - doffset ) * tsysref[j] ;
1583        }
1584      }
1585    }
1586
1587    // shift signal spectra if necessary (only for APEX?)
1588    if ( choffset2 != 0.0 ) {
1589      int sigchan = spsig.nelements() ;
1590      Vector<Float> sspsig( spsig.nelements() ) ;
1591      Vector<Float> stsyssig( tsyssig.nelements() ) ;
1592      Vector<uChar> sflagsig( flagsig.nelements() ) ;
1593      if ( ioffset2 > 0 ) {
1594        // SPECTRA and FLAGTRA
1595        for ( int j = 0 ; j < sigchan-ioffset2 ; j++ ) {
1596          sspsig[j] = spsig[j+ioffset2] ;
1597          sflagsig[j] = flagsig[j+ioffset2] ;
1598        }
1599        for ( int j = sigchan-ioffset2 ; j < sigchan ; j++ ) {
1600          sspsig[j] = spsig[j-sigchan+ioffset2] ;
1601          sflagsig[j] = flagsig[j-sigchan+ioffset2] ;
1602        }
1603        spsig = sspsig.copy() ;
1604        flagsig = sflagsig.copy() ;
1605        for ( int j = 0 ; j < sigchan - 1 ; j++ ) {
1606          sspsig[j] = doffset2 * spsig[j+1] + ( 1.0 - doffset2 ) * spsig[j] ;
1607          sflagsig[j] = flagsig[j+1] || flagsig[j] ;
1608        }
1609        sspsig[sigchan-1] = doffset2 * spsig[0] + ( 1.0 - doffset2 ) * spsig[sigchan-1] ;
1610        sflagsig[sigchan-1] = flagsig[0] || flagsig[sigchan-1] ;
1611        // TSTS
1612        if ( spsig.nelements() == tsyssig.nelements() ) {
1613          for ( int j = 0 ; j < sigchan-ioffset2 ; j++ ) {
1614            stsyssig[j] = tsyssig[j+ioffset2] ;
1615          }
1616          for ( int j = sigchan-ioffset2 ; j < sigchan ; j++ ) {
1617            stsyssig[j] = tsyssig[j-sigchan+ioffset2] ;
1618          }
1619          tsyssig = stsyssig.copy() ;
1620          for ( int j = 0 ; j < sigchan - 1 ; j++ ) {
1621            stsyssig[j] = doffset2 * tsyssig[j+1] + ( 1.0 - doffset2 ) * tsyssig[j] ;
1622          }
1623          stsyssig[sigchan-1] = doffset2 * tsyssig[0] + ( 1.0 - doffset2 ) * tsyssig[sigchan-1] ;
1624        }
1625      }
1626      else {
1627        // SPECTRA and FLAGTRA
1628        for ( int j = 0 ; j < abs(ioffset2) ; j++ ) {
1629          sspsig[j] = spsig[sigchan+ioffset2+j] ;
1630          sflagsig[j] = flagsig[sigchan+ioffset2+j] ;
1631        }
1632        for ( int j = abs(ioffset2) ; j < sigchan ; j++ ) {
1633          sspsig[j] = spsig[j+ioffset2] ;
1634          sflagsig[j] = flagsig[j+ioffset2] ;
1635        }
1636        spsig = sspsig.copy() ;
1637        flagsig = sflagsig.copy() ;
1638        sspsig[0] = doffset2 * spsig[sigchan-1] + ( 1.0 - doffset2 ) * spsig[0] ;
1639        sflagsig[0] = flagsig[0] + flagsig[sigchan-1] ;
1640        for ( int j = 1 ; j < sigchan ; j++ ) {
1641          sspsig[j] = doffset2 * spsig[j-1] + ( 1.0 - doffset2 ) * spsig[j] ;
1642          sflagsig[j] = flagsig[j-1] + flagsig[j] ;
1643        }
1644        // TSYS
1645        if ( spsig.nelements() == tsyssig.nelements() ) {
1646          for ( int j = 0 ; j < abs(ioffset2) ; j++ ) {
1647            stsyssig[j] = tsyssig[sigchan+ioffset2+j] ;
1648          }
1649          for ( int j = abs(ioffset2) ; j < sigchan ; j++ ) {
1650            stsyssig[j] = tsyssig[j+ioffset2] ;
1651          }
1652          tsyssig = stsyssig.copy() ;
1653          stsyssig[0] = doffset2 * tsyssig[sigchan-1] + ( 1.0 - doffset2 ) * tsyssig[0] ;
1654          for ( int j = 1 ; j < sigchan ; j++ ) {
1655            stsyssig[j] = doffset2 * tsyssig[j-1] + ( 1.0 - doffset2 ) * tsyssig[j] ;
1656          }
1657        }
1658      }
1659    }
1660
1661    // folding
1662    acc.add( spsig, !flagsig, tsyssig, intsig, timesig ) ;
1663    acc.add( sspref, !sflagref, stsysref, intref, timeref ) ;
1664   
1665    // put result
1666    specColOut.put( i, acc.getSpectrum() ) ;
1667    const Vector<Bool> &msk = acc.getMask() ;
1668    Vector<uChar> flg( msk.shape() ) ;
1669    convertArray( flg, !msk ) ;
1670    flagColOut.put( i, flg ) ;
1671    tsysColOut.put( i, acc.getTsys() ) ;
1672    intervalColOut.put( i, acc.getInterval() ) ;
1673    mjdColOut.put( i, acc.getTime() ) ;
1674    // change FREQ_ID to unshifted IF setting (only for APEX?)
1675    if ( choffset2 != 0.0 ) {
1676      uInt freqid = fidColOut( 0 ) ; // assume single-IF data
1677      double refpix, refval, increment ;
1678      out->frequencies().getEntry( refpix, refval, increment, freqid ) ;
1679      refval -= choffset * increment ;
1680      uInt newfreqid = out->frequencies().addEntry( refpix, refval, increment ) ;
1681      Vector<uInt> freqids = fidColOut.getColumn() ;
1682      for ( uInt j = 0 ; j < freqids.nelements() ; j++ ) {
1683        if ( freqids[j] == freqid )
1684          freqids[j] = newfreqid ;
1685      }
1686      fidColOut.putColumn( freqids ) ;
1687    }
1688
1689    acc.reset() ;
1690  }
1691
1692  return out ;
1693}
1694
1695
1696CountedPtr< Scantable > STMath::freqSwitch( const CountedPtr< Scantable >& in )
1697{
1698  // make copy or reference
1699  CountedPtr< Scantable > out = getScantable(in, false);
1700  Table& tout = out->table();
1701  Block<String> cols(4);
1702  cols[0] = String("SCANNO");
1703  cols[1] = String("CYCLENO");
1704  cols[2] = String("BEAMNO");
1705  cols[3] = String("POLNO");
1706  TableIterator iter(tout, cols);
1707  while (!iter.pastEnd()) {
1708    Table subt = iter.table();
1709    // this should leave us with two rows for the two IFs....if not ignore
1710    if (subt.nrow() != 2 ) {
1711      continue;
1712    }
1713    ArrayColumn<Float> specCol(subt, "SPECTRA");
1714    ArrayColumn<Float> tsysCol(subt, "TSYS");
1715    ArrayColumn<uChar> flagCol(subt, "FLAGTRA");
1716    Vector<Float> onspec,offspec, ontsys, offtsys;
1717    Vector<uChar> onflag, offflag;
1718    tsysCol.get(0, ontsys);   tsysCol.get(1, offtsys);
1719    specCol.get(0, onspec);   specCol.get(1, offspec);
1720    flagCol.get(0, onflag);   flagCol.get(1, offflag);
1721    MaskedArray<Float> on  = maskedArray(onspec, onflag);
1722    MaskedArray<Float> off = maskedArray(offspec, offflag);
1723    MaskedArray<Float> oncopy = on.copy();
1724
1725    on /= off; on -= 1.0f;
1726    on *= ontsys[0];
1727    off /= oncopy; off -= 1.0f;
1728    off *= offtsys[0];
1729    specCol.put(0, on.getArray());
1730    const Vector<Bool>& m0 = on.getMask();
1731    Vector<uChar> flags0(m0.shape());
1732    convertArray(flags0, !m0);
1733    flagCol.put(0, flags0);
1734
1735    specCol.put(1, off.getArray());
1736    const Vector<Bool>& m1 = off.getMask();
1737    Vector<uChar> flags1(m1.shape());
1738    convertArray(flags1, !m1);
1739    flagCol.put(1, flags1);
1740    ++iter;
1741  }
1742
1743  return out;
1744}
1745
1746std::vector< float > STMath::statistic( const CountedPtr< Scantable > & in,
1747                                        const std::vector< bool > & mask,
1748                                        const std::string& which )
1749{
1750
1751  Vector<Bool> m(mask);
1752  const Table& tab = in->table();
1753  ROArrayColumn<Float> specCol(tab, "SPECTRA");
1754  ROArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1755  std::vector<float> out;
1756  for (uInt i=0; i < tab.nrow(); ++i ) {
1757    Vector<Float> spec; specCol.get(i, spec);
1758    Vector<uChar> flag; flagCol.get(i, flag);
1759    MaskedArray<Float> ma  = maskedArray(spec, flag);
1760    float outstat = 0.0;
1761    if ( spec.nelements() == m.nelements() ) {
1762      outstat = mathutil::statistics(which, ma(m));
1763    } else {
1764      outstat = mathutil::statistics(which, ma);
1765    }
1766    out.push_back(outstat);
1767  }
1768  return out;
1769}
1770
1771std::vector< int > STMath::minMaxChan( const CountedPtr< Scantable > & in,
1772                                        const std::vector< bool > & mask,
1773                                        const std::string& which )
1774{
1775
1776  Vector<Bool> m(mask);
1777  const Table& tab = in->table();
1778  ROArrayColumn<Float> specCol(tab, "SPECTRA");
1779  ROArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1780  std::vector<int> out;
1781  for (uInt i=0; i < tab.nrow(); ++i ) {
1782    Vector<Float> spec; specCol.get(i, spec);
1783    Vector<uChar> flag; flagCol.get(i, flag);
1784    MaskedArray<Float> ma  = maskedArray(spec, flag);
1785    if (ma.ndim() != 1) {
1786      throw (ArrayError(
1787          "std::vector<int> STMath::minMaxChan("
1788          "ContedPtr<Scantable> &in, std::vector<bool> &mask, "
1789          " std::string &which)"
1790          " - MaskedArray is not 1D"));
1791    }
1792    IPosition outpos(1,0);
1793    if ( spec.nelements() == m.nelements() ) {
1794      outpos = mathutil::minMaxPos(which, ma(m));
1795    } else {
1796      outpos = mathutil::minMaxPos(which, ma);
1797    }
1798    out.push_back(outpos[0]);
1799  }
1800  return out;
1801}
1802
1803CountedPtr< Scantable > STMath::bin( const CountedPtr< Scantable > & in,
1804                                     int width )
1805{
1806  if ( !in->getSelection().empty() ) throw(AipsError("Can't bin subset of the data."));
1807  CountedPtr< Scantable > out = getScantable(in, false);
1808  Table& tout = out->table();
1809  out->frequencies().rescale(width, "BIN");
1810  ArrayColumn<Float> specCol(tout, "SPECTRA");
1811  ArrayColumn<uChar> flagCol(tout, "FLAGTRA");
1812  for (uInt i=0; i < tout.nrow(); ++i ) {
1813    MaskedArray<Float> main  = maskedArray(specCol(i), flagCol(i));
1814    MaskedArray<Float> maout;
1815    LatticeUtilities::bin(maout, main, 0, Int(width));
1816    /// @todo implement channel based tsys binning
1817    specCol.put(i, maout.getArray());
1818    flagCol.put(i, flagsFromMA(maout));
1819    // take only the first binned spectrum's length for the deprecated
1820    // global header item nChan
1821    if (i==0) tout.rwKeywordSet().define(String("nChan"),
1822                                       Int(maout.getArray().nelements()));
1823  }
1824  return out;
1825}
1826
1827CountedPtr< Scantable > STMath::resample( const CountedPtr< Scantable >& in,
1828                                          const std::string& method,
1829                                          float width )
1830//
1831// Should add the possibility of width being specified in km/s. This means
1832// that for each freqID (SpectralCoordinate) we will need to convert to an
1833// average channel width (say at the reference pixel).  Then we would need
1834// to be careful to make sure each spectrum (of different freqID)
1835// is the same length.
1836//
1837{
1838  //InterpolateArray1D<Double,Float>::InterpolationMethod interp;
1839  Int interpMethod(stringToIMethod(method));
1840
1841  CountedPtr< Scantable > out = getScantable(in, false);
1842  Table& tout = out->table();
1843
1844// Resample SpectralCoordinates (one per freqID)
1845  out->frequencies().rescale(width, "RESAMPLE");
1846  TableIterator iter(tout, "IFNO");
1847  TableRow row(tout);
1848  while ( !iter.pastEnd() ) {
1849    Table tab = iter.table();
1850    ArrayColumn<Float> specCol(tab, "SPECTRA");
1851    //ArrayColumn<Float> tsysCol(tout, "TSYS");
1852    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1853    Vector<Float> spec;
1854    Vector<uChar> flag;
1855    specCol.get(0,spec); // the number of channels should be constant per IF
1856    uInt nChanIn = spec.nelements();
1857    Vector<Float> xIn(nChanIn); indgen(xIn);
1858    Int fac =  Int(nChanIn/width);
1859    Vector<Float> xOut(fac+10); // 10 to be safe - resize later
1860    uInt k = 0;
1861    Float x = 0.0;
1862    while (x < Float(nChanIn) ) {
1863      xOut(k) = x;
1864      k++;
1865      x += width;
1866    }
1867    uInt nChanOut = k;
1868    xOut.resize(nChanOut, True);
1869    // process all rows for this IFNO
1870    Vector<Float> specOut;
1871    Vector<Bool> maskOut;
1872    Vector<uChar> flagOut;
1873    for (uInt i=0; i < tab.nrow(); ++i) {
1874      specCol.get(i, spec);
1875      flagCol.get(i, flag);
1876      Vector<Bool> mask(flag.nelements());
1877      convertArray(mask, flag);
1878
1879      IPosition shapeIn(spec.shape());
1880      //sh.nchan = nChanOut;
1881      InterpolateArray1D<Float,Float>::interpolate(specOut, maskOut, xOut,
1882                                                   xIn, spec, mask,
1883                                                   interpMethod, True, True);
1884      /// @todo do the same for channel based Tsys
1885      flagOut.resize(maskOut.nelements());
1886      convertArray(flagOut, maskOut);
1887      specCol.put(i, specOut);
1888      flagCol.put(i, flagOut);
1889    }
1890    ++iter;
1891  }
1892
1893  return out;
1894}
1895
1896STMath::imethod STMath::stringToIMethod(const std::string& in)
1897{
1898  static STMath::imap lookup;
1899
1900  // initialize the lookup table if necessary
1901  if ( lookup.empty() ) {
1902    lookup["nearest"]   = InterpolateArray1D<Double,Float>::nearestNeighbour;
1903    lookup["linear"] = InterpolateArray1D<Double,Float>::linear;
1904    lookup["cubic"]  = InterpolateArray1D<Double,Float>::cubic;
1905    lookup["spline"]  = InterpolateArray1D<Double,Float>::spline;
1906  }
1907
1908  STMath::imap::const_iterator iter = lookup.find(in);
1909
1910  if ( lookup.end() == iter ) {
1911    std::string message = in;
1912    message += " is not a valid interpolation mode";
1913    throw(AipsError(message));
1914  }
1915  return iter->second;
1916}
1917
1918WeightType STMath::stringToWeight(const std::string& in)
1919{
1920  static std::map<std::string, WeightType> lookup;
1921
1922  // initialize the lookup table if necessary
1923  if ( lookup.empty() ) {
1924    lookup["NONE"]   = asap::NONE;
1925    lookup["TINT"] = asap::TINT;
1926    lookup["TINTSYS"]  = asap::TINTSYS;
1927    lookup["TSYS"]  = asap::TSYS;
1928    lookup["VAR"]  = asap::VAR;
1929  }
1930
1931  std::map<std::string, WeightType>::const_iterator iter = lookup.find(in);
1932
1933  if ( lookup.end() == iter ) {
1934    std::string message = in;
1935    message += " is not a valid weighting mode";
1936    throw(AipsError(message));
1937  }
1938  return iter->second;
1939}
1940
1941CountedPtr< Scantable > STMath::gainElevation( const CountedPtr< Scantable >& in,
1942                                               const vector< float > & coeff,
1943                                               const std::string & filename,
1944                                               const std::string& method)
1945{
1946  // Get elevation data from Scantable and convert to degrees
1947  CountedPtr< Scantable > out = getScantable(in, false);
1948  Table& tab = out->table();
1949  ROScalarColumn<Float> elev(tab, "ELEVATION");
1950  Vector<Float> x = elev.getColumn();
1951  x *= Float(180 / C::pi);                        // Degrees
1952
1953  Vector<Float> coeffs(coeff);
1954  const uInt nc = coeffs.nelements();
1955  if ( filename.length() > 0 && nc > 0 ) {
1956    throw(AipsError("You must choose either polynomial coefficients or an ascii file, not both"));
1957  }
1958
1959  // Correct
1960  if ( nc > 0 || filename.length() == 0 ) {
1961    // Find instrument
1962    Bool throwit = True;
1963    Instrument inst =
1964      STAttr::convertInstrument(tab.keywordSet().asString("AntennaName"),
1965                                throwit);
1966
1967    // Set polynomial
1968    Polynomial<Float>* ppoly = 0;
1969    Vector<Float> coeff;
1970    String msg;
1971    if ( nc > 0 ) {
1972      ppoly = new Polynomial<Float>(nc);
1973      coeff = coeffs;
1974      msg = String("user");
1975    } else {
1976      STAttr sdAttr;
1977      coeff = sdAttr.gainElevationPoly(inst);
1978      ppoly = new Polynomial<Float>(3);
1979      msg = String("built in");
1980    }
1981
1982    if ( coeff.nelements() > 0 ) {
1983      ppoly->setCoefficients(coeff);
1984    } else {
1985      delete ppoly;
1986      throw(AipsError("There is no known gain-elevation polynomial known for this instrument"));
1987    }
1988    ostringstream oss;
1989    oss << "Making polynomial correction with " << msg << " coefficients:" << endl;
1990    oss << "   " <<  coeff;
1991    pushLog(String(oss));
1992    const uInt nrow = tab.nrow();
1993    Vector<Float> factor(nrow);
1994    for ( uInt i=0; i < nrow; ++i ) {
1995      factor[i] = 1.0 / (*ppoly)(x[i]);
1996    }
1997    delete ppoly;
1998    scaleByVector(tab, factor, true);
1999
2000  } else {
2001    // Read and correct
2002    pushLog("Making correction from ascii Table");
2003    scaleFromAsciiTable(tab, filename, method, x, true);
2004  }
2005  return out;
2006}
2007
2008void STMath::scaleFromAsciiTable(Table& in, const std::string& filename,
2009                                 const std::string& method,
2010                                 const Vector<Float>& xout, bool dotsys)
2011{
2012
2013// Read gain-elevation ascii file data into a Table.
2014
2015  String formatString;
2016  Table tbl = readAsciiTable(formatString, Table::Memory, filename, "", "", False);
2017  scaleFromTable(in, tbl, method, xout, dotsys);
2018}
2019
2020void STMath::scaleFromTable(Table& in,
2021                            const Table& table,
2022                            const std::string& method,
2023                            const Vector<Float>& xout, bool dotsys)
2024{
2025
2026  ROScalarColumn<Float> geElCol(table, "ELEVATION");
2027  ROScalarColumn<Float> geFacCol(table, "FACTOR");
2028  Vector<Float> xin = geElCol.getColumn();
2029  Vector<Float> yin = geFacCol.getColumn();
2030  Vector<Bool> maskin(xin.nelements(),True);
2031
2032  // Interpolate (and extrapolate) with desired method
2033
2034  InterpolateArray1D<Double,Float>::InterpolationMethod interp = stringToIMethod(method);
2035
2036   Vector<Float> yout;
2037   Vector<Bool> maskout;
2038   InterpolateArray1D<Float,Float>::interpolate(yout, maskout, xout,
2039                                                xin, yin, maskin, interp,
2040                                                True, True);
2041
2042   scaleByVector(in, Float(1.0)/yout, dotsys);
2043}
2044
2045void STMath::scaleByVector( Table& in,
2046                            const Vector< Float >& factor,
2047                            bool dotsys )
2048{
2049  uInt nrow = in.nrow();
2050  if ( factor.nelements() != nrow ) {
2051    throw(AipsError("factors.nelements() != table.nelements()"));
2052  }
2053  ArrayColumn<Float> specCol(in, "SPECTRA");
2054  ArrayColumn<uChar> flagCol(in, "FLAGTRA");
2055  ArrayColumn<Float> tsysCol(in, "TSYS");
2056  for (uInt i=0; i < nrow; ++i) {
2057    MaskedArray<Float> ma  = maskedArray(specCol(i), flagCol(i));
2058    ma *= factor[i];
2059    specCol.put(i, ma.getArray());
2060    flagCol.put(i, flagsFromMA(ma));
2061    if ( dotsys ) {
2062      Vector<Float> tsys = tsysCol(i);
2063      tsys *= factor[i];
2064      tsysCol.put(i,tsys);
2065    }
2066  }
2067}
2068
2069CountedPtr< Scantable > STMath::convertFlux( const CountedPtr< Scantable >& in,
2070                                             float d, float etaap,
2071                                             float jyperk )
2072{
2073  CountedPtr< Scantable > out = getScantable(in, false);
2074  Table& tab = in->table();
2075  Unit fluxUnit(tab.keywordSet().asString("FluxUnit"));
2076  Unit K(String("K"));
2077  Unit JY(String("Jy"));
2078
2079  bool tokelvin = true;
2080  Double cfac = 1.0;
2081
2082  if ( fluxUnit == JY ) {
2083    pushLog("Converting to K");
2084    Quantum<Double> t(1.0,fluxUnit);
2085    Quantum<Double> t2 = t.get(JY);
2086    cfac = (t2 / t).getValue();               // value to Jy
2087
2088    tokelvin = true;
2089    out->setFluxUnit("K");
2090  } else if ( fluxUnit == K ) {
2091    pushLog("Converting to Jy");
2092    Quantum<Double> t(1.0,fluxUnit);
2093    Quantum<Double> t2 = t.get(K);
2094    cfac = (t2 / t).getValue();              // value to K
2095
2096    tokelvin = false;
2097    out->setFluxUnit("Jy");
2098  } else {
2099    throw(AipsError("Unrecognized brightness units in Table - must be consistent with Jy or K"));
2100  }
2101  // Make sure input values are converted to either Jy or K first...
2102  Float factor = cfac;
2103
2104  // Select method
2105  if (jyperk > 0.0) {
2106    factor *= jyperk;
2107    if ( tokelvin ) factor = 1.0 / jyperk;
2108    ostringstream oss;
2109    oss << "Jy/K = " << jyperk;
2110    pushLog(String(oss));
2111    Vector<Float> factors(tab.nrow(), factor);
2112    scaleByVector(tab,factors, false);
2113  } else if ( etaap > 0.0) {
2114    if (d < 0) {
2115      Instrument inst =
2116        STAttr::convertInstrument(tab.keywordSet().asString("AntennaName"),
2117                                  True);
2118      STAttr sda;
2119      d = sda.diameter(inst);
2120    }
2121    jyperk = STAttr::findJyPerK(etaap, d);
2122    ostringstream oss;
2123    oss << "Jy/K = " << jyperk;
2124    pushLog(String(oss));
2125    factor *= jyperk;
2126    if ( tokelvin ) {
2127      factor = 1.0 / factor;
2128    }
2129    Vector<Float> factors(tab.nrow(), factor);
2130    scaleByVector(tab, factors, False);
2131  } else {
2132
2133    // OK now we must deal with automatic look up of values.
2134    // We must also deal with the fact that the factors need
2135    // to be computed per IF and may be different and may
2136    // change per integration.
2137
2138    pushLog("Looking up conversion factors");
2139    convertBrightnessUnits(out, tokelvin, cfac);
2140  }
2141
2142  return out;
2143}
2144
2145void STMath::convertBrightnessUnits( CountedPtr<Scantable>& in,
2146                                     bool tokelvin, float cfac )
2147{
2148  Table& table = in->table();
2149  Instrument inst =
2150    STAttr::convertInstrument(table.keywordSet().asString("AntennaName"), True);
2151  TableIterator iter(table, "FREQ_ID");
2152  STFrequencies stfreqs = in->frequencies();
2153  STAttr sdAtt;
2154  while (!iter.pastEnd()) {
2155    Table tab = iter.table();
2156    ArrayColumn<Float> specCol(tab, "SPECTRA");
2157    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
2158    ROScalarColumn<uInt> freqidCol(tab, "FREQ_ID");
2159    MEpoch::ROScalarColumn timeCol(tab, "TIME");
2160
2161    uInt freqid; freqidCol.get(0, freqid);
2162    Vector<Float> tmpspec; specCol.get(0, tmpspec);
2163    // STAttr.JyPerK has a Vector interface... change sometime.
2164    Vector<Float> freqs(1,stfreqs.getRefFreq(freqid, tmpspec.nelements()));
2165    for ( uInt i=0; i<tab.nrow(); ++i) {
2166      Float jyperk = (sdAtt.JyPerK(inst, timeCol(i), freqs))[0];
2167      Float factor = cfac * jyperk;
2168      if ( tokelvin ) factor = Float(1.0) / factor;
2169      MaskedArray<Float> ma  = maskedArray(specCol(i), flagCol(i));
2170      ma *= factor;
2171      specCol.put(i, ma.getArray());
2172      flagCol.put(i, flagsFromMA(ma));
2173    }
2174  ++iter;
2175  }
2176}
2177
2178CountedPtr< Scantable > STMath::opacity( const CountedPtr< Scantable > & in,
2179                                         float tau )
2180{
2181  CountedPtr< Scantable > out = getScantable(in, false);
2182
2183  Table tab = out->table();
2184  ROScalarColumn<Float> elev(tab, "ELEVATION");
2185  ArrayColumn<Float> specCol(tab, "SPECTRA");
2186  ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
2187  ArrayColumn<Float> tsysCol(tab, "TSYS");
2188  for ( uInt i=0; i<tab.nrow(); ++i) {
2189    Float zdist = Float(C::pi_2) - elev(i);
2190    Float factor = exp(tau/cos(zdist));
2191    MaskedArray<Float> ma = maskedArray(specCol(i), flagCol(i));
2192    ma *= factor;
2193    specCol.put(i, ma.getArray());
2194    flagCol.put(i, flagsFromMA(ma));
2195    Vector<Float> tsys;
2196    tsysCol.get(i, tsys);
2197    tsys *= factor;
2198    tsysCol.put(i, tsys);
2199  }
2200  return out;
2201}
2202
2203CountedPtr< Scantable > STMath::smoothOther( const CountedPtr< Scantable >& in,
2204                                             const std::string& kernel,
2205                                             float width )
2206{
2207  CountedPtr< Scantable > out = getScantable(in, false);
2208  Table& table = out->table();
2209  ArrayColumn<Float> specCol(table, "SPECTRA");
2210  ArrayColumn<uChar> flagCol(table, "FLAGTRA");
2211  Vector<Float> spec;
2212  Vector<uChar> flag;
2213  for ( uInt i=0; i<table.nrow(); ++i) {
2214    specCol.get(i, spec);
2215    flagCol.get(i, flag);
2216    Vector<Bool> mask(flag.nelements());
2217    convertArray(mask, flag);
2218    Vector<Float> specout;
2219    Vector<Bool> maskout;
2220    if ( kernel == "hanning" ) {
2221      mathutil::hanning(specout, maskout, spec , !mask);
2222      convertArray(flag, !maskout);
2223    } else if (  kernel == "rmedian" ) {
2224      mathutil::runningMedian(specout, maskout, spec , mask, width);
2225      convertArray(flag, maskout);
2226    }
2227    flagCol.put(i, flag);
2228    specCol.put(i, specout);
2229  }
2230  return out;
2231}
2232
2233CountedPtr< Scantable > STMath::smooth( const CountedPtr< Scantable >& in,
2234                                        const std::string& kernel, float width )
2235{
2236  if (kernel == "rmedian"  || kernel == "hanning") {
2237    return smoothOther(in, kernel, width);
2238  }
2239  CountedPtr< Scantable > out = getScantable(in, false);
2240  Table& table = out->table();
2241  VectorKernel::KernelTypes type = VectorKernel::toKernelType(kernel);
2242  // same IFNO should have same no of channels
2243  // this saves overhead
2244  TableIterator iter(table, "IFNO");
2245  while (!iter.pastEnd()) {
2246    Table tab = iter.table();
2247    ArrayColumn<Float> specCol(tab, "SPECTRA");
2248    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
2249    Vector<Float> tmpspec; specCol.get(0, tmpspec);
2250    uInt nchan = tmpspec.nelements();
2251    Vector<Float> kvec = VectorKernel::make(type, width, nchan, True, False);
2252    Convolver<Float> conv(kvec, IPosition(1,nchan));
2253    Vector<Float> spec;
2254    Vector<uChar> flag;
2255    for ( uInt i=0; i<tab.nrow(); ++i) {
2256      specCol.get(i, spec);
2257      flagCol.get(i, flag);
2258      Vector<Bool> mask(flag.nelements());
2259      convertArray(mask, flag);
2260      Vector<Float> specout;
2261      mathutil::replaceMaskByZero(specout, mask);
2262      conv.linearConv(specout, spec);
2263      specCol.put(i, specout);
2264    }
2265    ++iter;
2266  }
2267  return out;
2268}
2269
2270CountedPtr< Scantable >
2271  STMath::merge( const std::vector< CountedPtr < Scantable > >& in )
2272{
2273  if ( in.size() < 2 ) {
2274    throw(AipsError("Need at least two scantables to perform a merge."));
2275  }
2276  std::vector<CountedPtr < Scantable > >::const_iterator it = in.begin();
2277  bool insitu = insitu_;
2278  setInsitu(false);
2279  CountedPtr< Scantable > out = getScantable(*it, false);
2280  setInsitu(insitu);
2281  Table& tout = out->table();
2282  ScalarColumn<uInt> freqidcol(tout,"FREQ_ID"), molidcol(tout, "MOLECULE_ID");
2283  ScalarColumn<uInt> scannocol(tout,"SCANNO"), focusidcol(tout,"FOCUS_ID");
2284  // Renumber SCANNO to be 0-based
2285  Vector<uInt> scannos = scannocol.getColumn();
2286  uInt offset = min(scannos);
2287  scannos -= offset;
2288  scannocol.putColumn(scannos);
2289  uInt newscanno = max(scannos)+1;
2290  ++it;
2291  while ( it != in.end() ){
2292    if ( ! (*it)->conformant(*out) ) {
2293      // non conformant.
2294      pushLog(String("Warning: Can't merge scantables as header info differs."));
2295    }
2296    out->appendToHistoryTable((*it)->history());
2297    const Table& tab = (*it)->table();
2298    TableIterator scanit(tab, "SCANNO");
2299    while (!scanit.pastEnd()) {
2300      TableIterator freqit(scanit.table(), "FREQ_ID");
2301      while ( !freqit.pastEnd() ) {
2302        Table thetab = freqit.table();
2303        uInt nrow = tout.nrow();
2304        tout.addRow(thetab.nrow());
2305        TableCopy::copyRows(tout, thetab, nrow, 0, thetab.nrow());
2306        ROTableRow row(thetab);
2307        for ( uInt i=0; i<thetab.nrow(); ++i) {
2308          uInt k = nrow+i;
2309          scannocol.put(k, newscanno);
2310          const TableRecord& rec = row.get(i);
2311          Double rv,rp,inc;
2312          (*it)->frequencies().getEntry(rp, rv, inc, rec.asuInt("FREQ_ID"));
2313          uInt id;
2314          id = out->frequencies().addEntry(rp, rv, inc);
2315          freqidcol.put(k,id);
2316          //String name,fname;Double rf;
2317          Vector<String> name,fname;Vector<Double> rf;
2318          (*it)->molecules().getEntry(rf, name, fname, rec.asuInt("MOLECULE_ID"));
2319          id = out->molecules().addEntry(rf, name, fname);
2320          molidcol.put(k, id);
2321          Float frot,fax,ftan,fhand,fmount,fuser, fxy, fxyp;
2322          (*it)->focus().getEntry(fax, ftan, frot, fhand,
2323                                  fmount,fuser, fxy, fxyp,
2324                                  rec.asuInt("FOCUS_ID"));
2325          id = out->focus().addEntry(fax, ftan, frot, fhand,
2326                                     fmount,fuser, fxy, fxyp);
2327          focusidcol.put(k, id);
2328        }
2329        ++freqit;
2330      }
2331      ++newscanno;
2332      ++scanit;
2333    }
2334    ++it;
2335  }
2336  return out;
2337}
2338
2339CountedPtr< Scantable >
2340  STMath::invertPhase( const CountedPtr < Scantable >& in )
2341{
2342  return applyToPol(in, &STPol::invertPhase, Float(0.0));
2343}
2344
2345CountedPtr< Scantable >
2346  STMath::rotateXYPhase( const CountedPtr < Scantable >& in, float phase )
2347{
2348   return applyToPol(in, &STPol::rotatePhase, Float(phase));
2349}
2350
2351CountedPtr< Scantable >
2352  STMath::rotateLinPolPhase( const CountedPtr < Scantable >& in, float phase )
2353{
2354  return applyToPol(in, &STPol::rotateLinPolPhase, Float(phase));
2355}
2356
2357CountedPtr< Scantable > STMath::applyToPol( const CountedPtr<Scantable>& in,
2358                                             STPol::polOperation fptr,
2359                                             Float phase )
2360{
2361  CountedPtr< Scantable > out = getScantable(in, false);
2362  Table& tout = out->table();
2363  Block<String> cols(4);
2364  cols[0] = String("SCANNO");
2365  cols[1] = String("BEAMNO");
2366  cols[2] = String("IFNO");
2367  cols[3] = String("CYCLENO");
2368  TableIterator iter(tout, cols);
2369  CountedPtr<STPol> stpol = STPol::getPolClass(out->factories_,
2370                                               out->getPolType() );
2371  while (!iter.pastEnd()) {
2372    Table t = iter.table();
2373    ArrayColumn<Float> speccol(t, "SPECTRA");
2374    ScalarColumn<uInt> focidcol(t, "FOCUS_ID");
2375    ScalarColumn<Float> parancol(t, "PARANGLE");
2376    Matrix<Float> pols(speccol.getColumn());
2377    try {
2378      stpol->setSpectra(pols);
2379      Float fang,fhand,parang;
2380      fang = in->focusTable_.getTotalFeedAngle(focidcol(0));
2381      fhand = in->focusTable_.getFeedHand(focidcol(0));
2382      parang = parancol(0);
2383      /// @todo re-enable this
2384      // disable total feed angle to support paralactifying Caswell style
2385      stpol->setPhaseCorrections(parang, -parang, fhand);
2386      // use a member function pointer in STPol.  This only works on
2387      // the STPol pointer itself, not the Counted Pointer so
2388      // derefernce it.
2389      (&(*(stpol))->*fptr)(phase);
2390      speccol.putColumn(stpol->getSpectra());
2391    } catch (AipsError& e) {
2392      //delete stpol;stpol=0;
2393      throw(e);
2394    }
2395    ++iter;
2396  }
2397  //delete stpol;stpol=0;
2398  return out;
2399}
2400
2401CountedPtr< Scantable >
2402  STMath::swapPolarisations( const CountedPtr< Scantable > & in )
2403{
2404  CountedPtr< Scantable > out = getScantable(in, false);
2405  Table& tout = out->table();
2406  Table t0 = tout(tout.col("POLNO") == 0);
2407  Table t1 = tout(tout.col("POLNO") == 1);
2408  if ( t0.nrow() != t1.nrow() )
2409    throw(AipsError("Inconsistent number of polarisations"));
2410  ArrayColumn<Float> speccol0(t0, "SPECTRA");
2411  ArrayColumn<uChar> flagcol0(t0, "FLAGTRA");
2412  ArrayColumn<Float> speccol1(t1, "SPECTRA");
2413  ArrayColumn<uChar> flagcol1(t1, "FLAGTRA");
2414  Matrix<Float> s0 = speccol0.getColumn();
2415  Matrix<uChar> f0 = flagcol0.getColumn();
2416  speccol0.putColumn(speccol1.getColumn());
2417  flagcol0.putColumn(flagcol1.getColumn());
2418  speccol1.putColumn(s0);
2419  flagcol1.putColumn(f0);
2420  return out;
2421}
2422
2423CountedPtr< Scantable >
2424  STMath::averagePolarisations( const CountedPtr< Scantable > & in,
2425                                const std::vector<bool>& mask,
2426                                const std::string& weight )
2427{
2428  if (in->npol() < 2 )
2429    throw(AipsError("averagePolarisations can only be applied to two or more"
2430                    "polarisations"));
2431  bool insitu = insitu_;
2432  setInsitu(false);
2433  CountedPtr< Scantable > pols = getScantable(in, true);
2434  setInsitu(insitu);
2435  Table& tout = pols->table();
2436  std::string taql = "SELECT FROM $1 WHERE POLNO IN [0,1]";
2437  Table tab = tableCommand(taql, in->table());
2438  if (tab.nrow() == 0 )
2439    throw(AipsError("Could not find  any rows with POLNO==0 and POLNO==1"));
2440  TableCopy::copyRows(tout, tab);
2441  TableVector<uInt> vec(tout, "POLNO");
2442  vec = 0;
2443  pols->table_.rwKeywordSet().define("nPol", Int(1));
2444  //pols->table_.rwKeywordSet().define("POLTYPE", String("stokes"));
2445  pols->table_.rwKeywordSet().define("POLTYPE", in->getPolType());
2446  std::vector<CountedPtr<Scantable> > vpols;
2447  vpols.push_back(pols);
2448  CountedPtr< Scantable > out = average(vpols, mask, weight, "SCAN");
2449  return out;
2450}
2451
2452CountedPtr< Scantable >
2453  STMath::averageBeams( const CountedPtr< Scantable > & in,
2454                        const std::vector<bool>& mask,
2455                        const std::string& weight )
2456{
2457  bool insitu = insitu_;
2458  setInsitu(false);
2459  CountedPtr< Scantable > beams = getScantable(in, false);
2460  setInsitu(insitu);
2461  Table& tout = beams->table();
2462  // give all rows the same BEAMNO
2463  TableVector<uInt> vec(tout, "BEAMNO");
2464  vec = 0;
2465  beams->table_.rwKeywordSet().define("nBeam", Int(1));
2466  std::vector<CountedPtr<Scantable> > vbeams;
2467  vbeams.push_back(beams);
2468  CountedPtr< Scantable > out = average(vbeams, mask, weight, "SCAN");
2469  return out;
2470}
2471
2472
2473CountedPtr< Scantable >
2474  asap::STMath::frequencyAlign( const CountedPtr< Scantable > & in,
2475                                const std::string & refTime,
2476                                const std::string & method)
2477{
2478  // clone as this is not working insitu
2479  bool insitu = insitu_;
2480  setInsitu(false);
2481  CountedPtr< Scantable > out = getScantable(in, false);
2482  setInsitu(insitu);
2483  Table& tout = out->table();
2484  // Get reference Epoch to time of first row or given String
2485  Unit DAY(String("d"));
2486  MEpoch::Ref epochRef(in->getTimeReference());
2487  MEpoch refEpoch;
2488  if (refTime.length()>0) {
2489    Quantum<Double> qt;
2490    if (MVTime::read(qt,refTime)) {
2491      MVEpoch mv(qt);
2492      refEpoch = MEpoch(mv, epochRef);
2493   } else {
2494      throw(AipsError("Invalid format for Epoch string"));
2495   }
2496  } else {
2497    refEpoch = in->timeCol_(0);
2498  }
2499  MPosition refPos = in->getAntennaPosition();
2500
2501  InterpolateArray1D<Double,Float>::InterpolationMethod interp = stringToIMethod(method);
2502  /*
2503  // Comment from MV.
2504  // the following code has been commented out because different FREQ_IDs have to be aligned together even
2505  // if the frame doesn't change. So far, lack of this check didn't cause any problems.
2506  // test if user frame is different to base frame
2507  if ( in->frequencies().getFrameString(true)
2508       == in->frequencies().getFrameString(false) ) {
2509    throw(AipsError("Can't convert as no output frame has been set"
2510                    " (use set_freqframe) or it is aligned already."));
2511  }
2512  */
2513  MFrequency::Types system = in->frequencies().getFrame();
2514  MVTime mvt(refEpoch.getValue());
2515  String epochout = mvt.string(MVTime::YMD) + String(" (") + refEpoch.getRefString() + String(")");
2516  ostringstream oss;
2517  oss << "Aligned at reference Epoch " << epochout
2518      << " in frame " << MFrequency::showType(system);
2519  pushLog(String(oss));
2520  // set up the iterator
2521  Block<String> cols(4);
2522  // select by constant direction
2523  cols[0] = String("SRCNAME");
2524  cols[1] = String("BEAMNO");
2525  // select by IF ( no of channels varies over this )
2526  cols[2] = String("IFNO");
2527  // select by restfrequency
2528  cols[3] = String("MOLECULE_ID");
2529  TableIterator iter(tout, cols);
2530  while ( !iter.pastEnd() ) {
2531    Table t = iter.table();
2532    MDirection::ROScalarColumn dirCol(t, "DIRECTION");
2533    TableIterator fiter(t, "FREQ_ID");
2534    // determine nchan from the first row. This should work as
2535    // we are iterating over BEAMNO and IFNO    // we should have constant direction
2536
2537    ROArrayColumn<Float> sCol(t, "SPECTRA");
2538    const MDirection direction = dirCol(0);
2539    const uInt nchan = sCol(0).nelements();
2540
2541    // skip operations if there is nothing to align
2542    if (fiter.pastEnd()) {
2543        continue;
2544    }
2545
2546    Table ftab = fiter.table();
2547    // align all frequency ids with respect to the first encountered id
2548    ScalarColumn<uInt> freqidCol(ftab, "FREQ_ID");
2549    // get the SpectralCoordinate for the freqid, which we are iterating over
2550    SpectralCoordinate sC = in->frequencies().getSpectralCoordinate(freqidCol(0));
2551    FrequencyAligner<Float> fa( sC, nchan, refEpoch,
2552                                direction, refPos, system );
2553    // realign the SpectralCoordinate and put into the output Scantable
2554    Vector<String> units(1);
2555    units = String("Hz");
2556    Bool linear=True;
2557    SpectralCoordinate sc2 = fa.alignedSpectralCoordinate(linear);
2558    sc2.setWorldAxisUnits(units);
2559    const uInt id = out->frequencies().addEntry(sc2.referencePixel()[0],
2560                                                sc2.referenceValue()[0],
2561                                                sc2.increment()[0]);
2562    while ( !fiter.pastEnd() ) {
2563      ftab = fiter.table();
2564      // spectral coordinate for the current FREQ_ID
2565      ScalarColumn<uInt> freqidCol2(ftab, "FREQ_ID");
2566      sC = in->frequencies().getSpectralCoordinate(freqidCol2(0));
2567      // create the "global" abcissa for alignment with same FREQ_ID
2568      Vector<Double> abc(nchan);
2569      for (uInt i=0; i<nchan; i++) {
2570           Double w;
2571           sC.toWorld(w,Double(i));
2572           abc[i] = w;
2573      }
2574      TableVector<uInt> tvec(ftab, "FREQ_ID");
2575      // assign new frequency id to all rows
2576      tvec = id;
2577      // cache abcissa for same time stamps, so iterate over those
2578      TableIterator timeiter(ftab, "TIME");
2579      while ( !timeiter.pastEnd() ) {
2580        Table tab = timeiter.table();
2581        ArrayColumn<Float> specCol(tab, "SPECTRA");
2582        ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
2583        MEpoch::ROScalarColumn timeCol(tab, "TIME");
2584        // use align abcissa cache after the first row
2585        // these rows should be just be POLNO
2586        bool first = true;
2587        for (int i=0; i<int(tab.nrow()); ++i) {
2588          // input values
2589          Vector<uChar> flag = flagCol(i);
2590          Vector<Bool> mask(flag.shape());
2591          Vector<Float> specOut, spec;
2592          spec  = specCol(i);
2593          Vector<Bool> maskOut;Vector<uChar> flagOut;
2594          convertArray(mask, flag);
2595          // alignment
2596          Bool ok = fa.align(specOut, maskOut, abc, spec,
2597                             mask, timeCol(i), !first,
2598                             interp, False);
2599          // back into scantable
2600          flagOut.resize(maskOut.nelements());
2601          convertArray(flagOut, maskOut);
2602          flagCol.put(i, flagOut);
2603          specCol.put(i, specOut);
2604          // start abcissa caching
2605          first = false;
2606        }
2607        // next timestamp
2608        ++timeiter;
2609      }
2610      // next FREQ_ID
2611      ++fiter;
2612    }
2613    // next aligner
2614    ++iter;
2615  }
2616  // set this afterwards to ensure we are doing insitu correctly.
2617  out->frequencies().setFrame(system, true);
2618  return out;
2619}
2620
2621CountedPtr<Scantable>
2622  asap::STMath::convertPolarisation( const CountedPtr<Scantable>& in,
2623                                     const std::string & newtype )
2624{
2625  if (in->npol() != 2 && in->npol() != 4)
2626    throw(AipsError("Can only convert two or four polarisations."));
2627  if ( in->getPolType() == newtype )
2628    throw(AipsError("No need to convert."));
2629  if ( ! in->selector_.empty() )
2630    throw(AipsError("Can only convert whole scantable. Unset the selection."));
2631  bool insitu = insitu_;
2632  setInsitu(false);
2633  CountedPtr< Scantable > out = getScantable(in, true);
2634  setInsitu(insitu);
2635  Table& tout = out->table();
2636  tout.rwKeywordSet().define("POLTYPE", String(newtype));
2637
2638  Block<String> cols(4);
2639  cols[0] = "SCANNO";
2640  cols[1] = "CYCLENO";
2641  cols[2] = "BEAMNO";
2642  cols[3] = "IFNO";
2643  TableIterator it(in->originalTable_, cols);
2644  String basetype = in->getPolType();
2645  STPol* stpol = STPol::getPolClass(in->factories_, basetype);
2646  try {
2647    while ( !it.pastEnd() ) {
2648      Table tab = it.table();
2649      uInt row = tab.rowNumbers()[0];
2650      stpol->setSpectra(in->getPolMatrix(row));
2651      Float fang,fhand,parang;
2652      fang = in->focusTable_.getTotalFeedAngle(in->mfocusidCol_(row));
2653      fhand = in->focusTable_.getFeedHand(in->mfocusidCol_(row));
2654      parang = in->paraCol_(row);
2655      /// @todo re-enable this
2656      // disable total feed angle to support paralactifying Caswell style
2657      stpol->setPhaseCorrections(parang, -parang, fhand);
2658      Int npolout = 0;
2659      for (uInt i=0; i<tab.nrow(); ++i) {
2660        Vector<Float> outvec = stpol->getSpectrum(i, newtype);
2661        if ( outvec.nelements() > 0 ) {
2662          tout.addRow();
2663          TableCopy::copyRows(tout, tab, tout.nrow()-1, 0, 1);
2664          ArrayColumn<Float> sCol(tout,"SPECTRA");
2665          ScalarColumn<uInt> pCol(tout,"POLNO");
2666          sCol.put(tout.nrow()-1 ,outvec);
2667          pCol.put(tout.nrow()-1 ,uInt(npolout));
2668          npolout++;
2669       }
2670      }
2671      tout.rwKeywordSet().define("nPol", npolout);
2672      ++it;
2673    }
2674  } catch (AipsError& e) {
2675    delete stpol;
2676    throw(e);
2677  }
2678  delete stpol;
2679  return out;
2680}
2681
2682CountedPtr< Scantable >
2683  asap::STMath::mxExtract( const CountedPtr< Scantable > & in,
2684                           const std::string & scantype )
2685{
2686  bool insitu = insitu_;
2687  setInsitu(false);
2688  CountedPtr< Scantable > out = getScantable(in, true);
2689  setInsitu(insitu);
2690  Table& tout = out->table();
2691  std::string taql = "SELECT FROM $1 WHERE BEAMNO != REFBEAMNO";
2692  if (scantype == "on") {
2693    taql = "SELECT FROM $1 WHERE BEAMNO == REFBEAMNO";
2694  }
2695  Table tab = tableCommand(taql, in->table());
2696  TableCopy::copyRows(tout, tab);
2697  if (scantype == "on") {
2698    // re-index SCANNO to 0
2699    TableVector<uInt> vec(tout, "SCANNO");
2700    vec = 0;
2701  }
2702  return out;
2703}
2704
2705CountedPtr< Scantable >
2706  asap::STMath::lagFlag( const CountedPtr< Scantable > & in,
2707                          double frequency, double width )
2708{
2709  CountedPtr< Scantable > out = getScantable(in, false);
2710  Table& tout = out->table();
2711  TableIterator iter(tout, "FREQ_ID");
2712  FFTServer<Float,Complex> ffts;
2713  while ( !iter.pastEnd() ) {
2714    Table tab = iter.table();
2715    Double rp,rv,inc;
2716    ROTableRow row(tab);
2717    const TableRecord& rec = row.get(0);
2718    uInt freqid = rec.asuInt("FREQ_ID");
2719    out->frequencies().getEntry(rp, rv, inc, freqid);
2720    ArrayColumn<Float> specCol(tab, "SPECTRA");
2721    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
2722    for (int i=0; i<int(tab.nrow()); ++i) {
2723      Vector<Float> spec = specCol(i);
2724      Vector<uChar> flag = flagCol(i);
2725      Int lag0 = Int(spec.nelements()*abs(inc)/(frequency+width)+0.5);
2726      Int lag1 = Int(spec.nelements()*abs(inc)/(frequency-width)+0.5);
2727      for (unsigned int k=0; k < flag.nelements(); ++k ) {
2728        if (flag[k] > 0) {
2729          spec[k] = 0.0;
2730        }
2731      }
2732      Vector<Complex> lags;
2733      ffts.fft0(lags, spec);
2734      Int start =  max(0, lag0);
2735      Int end =  min(Int(lags.nelements()-1), lag1);
2736      if (start == end) {
2737        lags[start] = Complex(0.0);
2738      } else {
2739        for (int j=start; j <=end ;++j) {
2740          lags[j] = Complex(0.0);
2741        }
2742      }
2743      ffts.fft0(spec, lags);
2744      specCol.put(i, spec);
2745    }
2746    ++iter;
2747  }
2748  return out;
2749}
2750
2751// Averaging spectra with different channel/resolution
2752CountedPtr<Scantable>
2753STMath::new_average( const std::vector<CountedPtr<Scantable> >& in,
2754                     const bool& compel,
2755                     const std::vector<bool>& mask,
2756                     const std::string& weight,
2757                     const std::string& avmode )
2758  throw ( casa::AipsError )
2759{
2760  LogIO os( LogOrigin( "STMath", "new_average()", WHERE ) ) ;
2761  if ( avmode == "SCAN" && in.size() != 1 )
2762    throw(AipsError("Can't perform 'SCAN' averaging on multiple tables.\n"
2763                    "Use merge first."));
2764 
2765  // check if OTF observation
2766  String obstype = in[0]->getHeader().obstype ;
2767  Double tol = 0.0 ;
2768  if ( obstype.find( "OTF" ) != String::npos ) {
2769    tol = TOL_OTF ;
2770  }
2771  else {
2772    tol = TOL_POINT ;
2773  }
2774
2775  CountedPtr<Scantable> out ;     // processed result
2776  if ( compel ) {
2777    std::vector< CountedPtr<Scantable> > newin ; // input for average process
2778    uInt insize = in.size() ;    // number of input scantables
2779
2780    // TEST: do normal average in each table before IF grouping
2781    os << "Do preliminary averaging" << LogIO::POST ;
2782    vector< CountedPtr<Scantable> > tmpin( insize ) ;
2783    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2784      vector< CountedPtr<Scantable> > v( 1, in[itable] ) ;
2785      tmpin[itable] = average( v, mask, weight, avmode ) ;
2786    }
2787
2788    // warning
2789    os << "Average spectra with different spectral resolution" << LogIO::POST ;
2790
2791    // temporarily set coordinfo
2792    vector<string> oldinfo( insize ) ;
2793    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2794      vector<string> coordinfo = in[itable]->getCoordInfo() ;
2795      oldinfo[itable] = coordinfo[0] ;
2796      coordinfo[0] = "Hz" ;
2797      tmpin[itable]->setCoordInfo( coordinfo ) ;
2798    }
2799
2800    // columns
2801    ScalarColumn<uInt> freqIDCol ;
2802    ScalarColumn<uInt> ifnoCol ;
2803    ScalarColumn<uInt> scannoCol ;
2804
2805
2806    // check IF frequency coverage
2807    // freqid: list of FREQ_ID, which is used, in each table 
2808    // iffreq: list of minimum and maximum frequency for each FREQ_ID in
2809    //         each table
2810    // freqid[insize][numIF]
2811    // freqid: [[id00, id01, ...],
2812    //          [id10, id11, ...],
2813    //          ...
2814    //          [idn0, idn1, ...]]
2815    // iffreq[insize][numIF*2]
2816    // iffreq: [[min_id00, max_id00, min_id01, max_id01, ...],
2817    //          [min_id10, max_id10, min_id11, max_id11, ...],
2818    //          ...
2819    //          [min_idn0, max_idn0, min_idn1, max_idn1, ...]]
2820    //os << "Check IF settings in each table" << LogIO::POST ;
2821    vector< vector<uInt> > freqid( insize );
2822    vector< vector<double> > iffreq( insize ) ;
2823    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2824      uInt rows = tmpin[itable]->nrow() ;
2825      uInt freqnrows = tmpin[itable]->frequencies().table().nrow() ;
2826      for ( uInt irow = 0 ; irow < rows ; irow++ ) {
2827        if ( freqid[itable].size() == freqnrows ) {
2828          break ;
2829        }
2830        else {
2831          freqIDCol.attach( tmpin[itable]->table(), "FREQ_ID" ) ;
2832          ifnoCol.attach( tmpin[itable]->table(), "IFNO" ) ;
2833          uInt id = freqIDCol( irow ) ;
2834          if ( freqid[itable].size() == 0 || count( freqid[itable].begin(), freqid[itable].end(), id ) == 0 ) {
2835            //os << "itable = " << itable << ": IF " << id << " is included in the list" << LogIO::POST ;
2836            vector<double> abcissa = tmpin[itable]->getAbcissa( irow ) ;
2837            freqid[itable].push_back( id ) ;
2838            iffreq[itable].push_back( abcissa[0] - 0.5 * ( abcissa[1] - abcissa[0] ) ) ;
2839            iffreq[itable].push_back( abcissa[abcissa.size()-1] + 0.5 * ( abcissa[1] - abcissa[0] ) ) ;
2840          }
2841        }
2842      }
2843    }
2844
2845    // debug
2846    //os << "IF settings summary:" << endl ;
2847    //for ( uInt i = 0 ; i < freqid.size() ; i++ ) {
2848    //os << "   Table" << i << endl ;
2849    //for ( uInt j = 0 ; j < freqid[i].size() ; j++ ) {
2850    //os << "      id = " << freqid[i][j] << " (min,max) = (" << iffreq[i][2*j] << "," << iffreq[i][2*j+1] << ")" << endl ;
2851    //}
2852    //}
2853    //os << endl ;
2854    //os.post() ;
2855
2856    // IF grouping based on their frequency coverage
2857    // ifgrp: list of table index and FREQ_ID for all members in each IF group
2858    // ifgfreq: list of minimum and maximum frequency in each IF group
2859    // ifgrp[numgrp][nummember*2]
2860    // ifgrp: [[table00, freqrow00, table01, freqrow01, ...],
2861    //         [table10, freqrow10, table11, freqrow11, ...],
2862    //         ...
2863    //         [tablen0, freqrown0, tablen1, freqrown1, ...]]
2864    // ifgfreq[numgrp*2]
2865    // ifgfreq: [min0_grp0, max0_grp0, min1_grp1, max1_grp1, ...]
2866    //os << "IF grouping based on their frequency coverage" << LogIO::POST ;
2867    vector< vector<uInt> > ifgrp ;
2868    vector<double> ifgfreq ;
2869
2870    // parameter for IF grouping
2871    // groupmode = OR    retrieve all region
2872    //             AND   only retrieve overlaped region
2873    //string groupmode = "AND" ;
2874    string groupmode = "OR" ;
2875    uInt sizecr = 0 ;
2876    if ( groupmode == "AND" )
2877      sizecr = 2 ;
2878    else if ( groupmode == "OR" )
2879      sizecr = 0 ;
2880
2881    vector<double> sortedfreq ;
2882    for ( uInt i = 0 ; i < iffreq.size() ; i++ ) {
2883      for ( uInt j = 0 ; j < iffreq[i].size() ; j++ ) {
2884        if ( count( sortedfreq.begin(), sortedfreq.end(), iffreq[i][j] ) == 0 )
2885          sortedfreq.push_back( iffreq[i][j] ) ;
2886      }
2887    }
2888    sort( sortedfreq.begin(), sortedfreq.end() ) ;
2889    for ( vector<double>::iterator i = sortedfreq.begin() ; i != sortedfreq.end()-1 ; i++ ) {
2890      ifgfreq.push_back( *i ) ;
2891      ifgfreq.push_back( *(i+1) ) ;
2892    }
2893    ifgrp.resize( ifgfreq.size()/2 ) ;
2894    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2895      for ( uInt iif = 0 ; iif < freqid[itable].size() ; iif++ ) {
2896        double range0 = iffreq[itable][2*iif] ;
2897        double range1 = iffreq[itable][2*iif+1] ;
2898        for ( uInt j = 0 ; j < ifgrp.size() ; j++ ) {
2899          double fmin = max( range0, ifgfreq[2*j] ) ;
2900          double fmax = min( range1, ifgfreq[2*j+1] ) ;
2901          if ( fmin < fmax ) {
2902            ifgrp[j].push_back( itable ) ;
2903            ifgrp[j].push_back( freqid[itable][iif] ) ;
2904          }
2905        }
2906      }
2907    }
2908    vector< vector<uInt> >::iterator fiter = ifgrp.begin() ;
2909    vector<double>::iterator giter = ifgfreq.begin() ;
2910    while( fiter != ifgrp.end() ) {
2911      if ( fiter->size() <= sizecr ) {
2912        fiter = ifgrp.erase( fiter ) ;
2913        giter = ifgfreq.erase( giter ) ;
2914        giter = ifgfreq.erase( giter ) ;
2915      }
2916      else {
2917        fiter++ ;
2918        advance( giter, 2 ) ;
2919      }
2920    }
2921
2922    // Grouping continuous IF groups (without frequency gap)
2923    // freqgrp: list of IF group indexes in each frequency group
2924    // freqrange: list of minimum and maximum frequency in each frequency group
2925    // freqgrp[numgrp][nummember]
2926    // freqgrp: [[ifgrp00, ifgrp01, ifgrp02, ...],
2927    //           [ifgrp10, ifgrp11, ifgrp12, ...],
2928    //           ...
2929    //           [ifgrpn0, ifgrpn1, ifgrpn2, ...]]
2930    // freqrange[numgrp*2]
2931    // freqrange: [min_grp0, max_grp0, min_grp1, max_grp1, ...]
2932    vector< vector<uInt> > freqgrp ;
2933    double freqrange = 0.0 ;
2934    uInt grpnum = 0 ;
2935    for ( uInt i = 0 ; i < ifgrp.size() ; i++ ) {
2936      // Assumed that ifgfreq was sorted
2937      if ( grpnum != 0 && freqrange == ifgfreq[2*i] ) {
2938        freqgrp[grpnum-1].push_back( i ) ;
2939      }
2940      else {
2941        vector<uInt> grp0( 1, i ) ;
2942        freqgrp.push_back( grp0 ) ;
2943        grpnum++ ;
2944      }
2945      freqrange = ifgfreq[2*i+1] ;
2946    }
2947       
2948
2949    // print IF groups
2950    ostringstream oss ;
2951    oss << "IF Group summary: " << endl ;
2952    oss << "   GROUP_ID [FREQ_MIN, FREQ_MAX]: (TABLE_ID, FREQ_ID)" << endl ;
2953    for ( uInt i = 0 ; i < ifgrp.size() ; i++ ) {
2954      oss << "   GROUP " << setw( 2 ) << i << " [" << ifgfreq[2*i] << "," << ifgfreq[2*i+1] << "]: " ;
2955      for ( uInt j = 0 ; j < ifgrp[i].size()/2 ; j++ ) {
2956        oss << "(" << ifgrp[i][2*j] << "," << ifgrp[i][2*j+1] << ") " ;
2957      }
2958      oss << endl ;
2959    }
2960    oss << endl ;
2961    os << oss.str() << LogIO::POST ;
2962   
2963    // print frequency group
2964    oss.str("") ;
2965    oss << "Frequency Group summary: " << endl ;
2966    oss << "   GROUP_ID [FREQ_MIN, FREQ_MAX]: IF_GROUP_ID" << endl ;
2967    for ( uInt i = 0 ; i < freqgrp.size() ; i++ ) {
2968      oss << "   GROUP " << setw( 2 ) << i << " [" << ifgfreq[2*freqgrp[i][0]] << "," << ifgfreq[2*freqgrp[i][freqgrp[i].size()-1]+1] << "]: " ;
2969      for ( uInt j = 0 ; j < freqgrp[i].size() ; j++ ) {
2970        oss << freqgrp[i][j] << " " ;
2971      }
2972      oss << endl ;
2973    }
2974    oss << endl ;
2975    os << oss.str() << LogIO::POST ;
2976
2977    // membership check
2978    // groups: list of IF group indexes whose frequency range overlaps with
2979    //         that of each table and IF
2980    // groups[numtable][numIF][nummembership]
2981    // groups: [[[grp, grp,...], [grp, grp,...],...],
2982    //          [[grp, grp,...], [grp, grp,...],...],
2983    //          ...
2984    //          [[grp, grp,...], [grp, grp,...],...]]
2985    vector< vector< vector<uInt> > > groups( insize ) ;
2986    for ( uInt i = 0 ; i < insize ; i++ ) {
2987      groups[i].resize( freqid[i].size() ) ;
2988    }
2989    for ( uInt igrp = 0 ; igrp < ifgrp.size() ; igrp++ ) {
2990      for ( uInt imem = 0 ; imem < ifgrp[igrp].size()/2 ; imem++ ) {
2991        uInt tableid = ifgrp[igrp][2*imem] ;
2992        vector<uInt>::iterator iter = find( freqid[tableid].begin(), freqid[tableid].end(), ifgrp[igrp][2*imem+1] ) ;
2993        if ( iter != freqid[tableid].end() ) {
2994          uInt rowid = distance( freqid[tableid].begin(), iter ) ;
2995          groups[tableid][rowid].push_back( igrp ) ;
2996        }
2997      }
2998    }
2999
3000    // print membership
3001    //oss.str("") ;
3002    //for ( uInt i = 0 ; i < insize ; i++ ) {
3003    //oss << "Table " << i << endl ;
3004    //for ( uInt j = 0 ; j < groups[i].size() ; j++ ) {
3005    //oss << "   FREQ_ID " <<  setw( 2 ) << freqid[i][j] << ": " ;
3006    //for ( uInt k = 0 ; k < groups[i][j].size() ; k++ ) {
3007    //oss << setw( 2 ) << groups[i][j][k] << " " ;
3008    //}
3009    //oss << endl ;
3010    //}
3011    //}
3012    //os << oss.str() << LogIO::POST ;
3013
3014    // set back coordinfo
3015    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3016      vector<string> coordinfo = tmpin[itable]->getCoordInfo() ;
3017      coordinfo[0] = oldinfo[itable] ;
3018      tmpin[itable]->setCoordInfo( coordinfo ) ;
3019    }
3020
3021    // Create additional table if needed
3022    bool oldInsitu = insitu_ ;
3023    setInsitu( false ) ;
3024    vector< vector<uInt> > addrow( insize ) ;
3025    vector<uInt> addtable( insize, 0 ) ;
3026    vector<uInt> newtableids( insize ) ;
3027    vector<uInt> newifids( insize, 0 ) ;
3028    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3029      //os << "Table " << itable << ": " ;
3030      for ( uInt ifrow = 0 ; ifrow < groups[itable].size() ; ifrow++ ) {
3031        addrow[itable].push_back( groups[itable][ifrow].size()-1 ) ;
3032        //os << addrow[itable][ifrow] << " " ;
3033      }
3034      addtable[itable] = *max_element( addrow[itable].begin(), addrow[itable].end() ) ;
3035      //os << "(" << addtable[itable] << ")" << LogIO::POST ;
3036    }
3037    newin.resize( insize ) ;
3038    copy( tmpin.begin(), tmpin.end(), newin.begin() ) ;
3039    for ( uInt i = 0 ; i < insize ; i++ ) {
3040      newtableids[i] = i ;
3041    }
3042    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3043      for ( uInt iadd = 0 ; iadd < addtable[itable] ; iadd++ ) {
3044        CountedPtr<Scantable> add = getScantable( newin[itable], false ) ;
3045        vector<int> freqidlist ;
3046        for ( uInt i = 0 ; i < groups[itable].size() ; i++ ) {
3047          if ( groups[itable][i].size() > iadd + 1 ) {
3048            freqidlist.push_back( freqid[itable][i] ) ;
3049          }
3050        }
3051        stringstream taqlstream ;
3052        taqlstream << "SELECT FROM $1 WHERE FREQ_ID IN [" ;
3053        for ( uInt i = 0 ; i < freqidlist.size() ; i++ ) {
3054          taqlstream << i ;
3055          if ( i < freqidlist.size() - 1 )
3056            taqlstream << "," ;
3057          else
3058            taqlstream << "]" ;
3059        }
3060        string taql = taqlstream.str() ;
3061        //os << "taql = " << taql << LogIO::POST ;
3062        STSelector selector = STSelector() ;
3063        selector.setTaQL( taql ) ;
3064        add->setSelection( selector ) ;
3065        newin.push_back( add ) ;
3066        newtableids.push_back( itable ) ;
3067        newifids.push_back( iadd + 1 ) ;
3068      }
3069    }
3070
3071    // udpate ifgrp
3072    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3073      for ( uInt iadd = 0 ; iadd < addtable[itable] ; iadd++ ) {
3074        for ( uInt ifrow = 0 ; ifrow < groups[itable].size() ; ifrow++ ) {
3075          if ( groups[itable][ifrow].size() > iadd + 1 ) {
3076            uInt igrp = groups[itable][ifrow][iadd+1] ;
3077            for ( uInt imem = 0 ; imem < ifgrp[igrp].size()/2 ; imem++ ) {
3078              if ( ifgrp[igrp][2*imem] == newtableids[iadd+insize] && ifgrp[igrp][2*imem+1] == freqid[newtableids[iadd+insize]][ifrow] ) {
3079                ifgrp[igrp][2*imem] = insize + iadd ;
3080              }
3081            }
3082          }
3083        }
3084      }
3085    }
3086
3087    // print IF groups again for debug
3088    //oss.str( "" ) ;
3089    //oss << "IF Group summary: " << endl ;
3090    //oss << "   GROUP_ID [FREQ_MIN, FREQ_MAX]: (TABLE_ID, FREQ_ID)" << endl ;
3091    //for ( uInt i = 0 ; i < ifgrp.size() ; i++ ) {
3092    //oss << "   GROUP " << setw( 2 ) << i << " [" << ifgfreq[2*i] << "," << ifgfreq[2*i+1] << "]: " ;
3093    //for ( uInt j = 0 ; j < ifgrp[i].size()/2 ; j++ ) {
3094    //oss << "(" << ifgrp[i][2*j] << "," << ifgrp[i][2*j+1] << ") " ;
3095    //}
3096    //oss << endl ;
3097    //}
3098    //oss << endl ;
3099    //os << oss.str() << LogIO::POST ;
3100
3101    // reset SCANNO and IFNO/FREQ_ID: IF is reset by the result of sortation
3102    os << "All scan number is set to 0" << LogIO::POST ;
3103    //os << "All IF number is set to IF group index" << LogIO::POST ;
3104    insize = newin.size() ;
3105    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3106      uInt rows = newin[itable]->nrow() ;
3107      Table &tmpt = newin[itable]->table() ;
3108      freqIDCol.attach( tmpt, "FREQ_ID" ) ;
3109      scannoCol.attach( tmpt, "SCANNO" ) ;
3110      ifnoCol.attach( tmpt, "IFNO" ) ;
3111      for ( uInt irow=0 ; irow < rows ; irow++ ) {
3112        scannoCol.put( irow, 0 ) ;
3113        uInt freqID = freqIDCol( irow ) ;
3114        vector<uInt>::iterator iter = find( freqid[newtableids[itable]].begin(), freqid[newtableids[itable]].end(), freqID ) ;
3115        if ( iter != freqid[newtableids[itable]].end() ) {
3116          uInt index = distance( freqid[newtableids[itable]].begin(), iter ) ;
3117          ifnoCol.put( irow, groups[newtableids[itable]][index][newifids[itable]] ) ;
3118        }
3119        else {
3120          throw(AipsError("IF grouping was wrong in additional tables.")) ;
3121        }
3122      }
3123    }
3124    oldinfo.resize( insize ) ;
3125    setInsitu( oldInsitu ) ;
3126
3127    // temporarily set coordinfo
3128    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3129      vector<string> coordinfo = newin[itable]->getCoordInfo() ;
3130      oldinfo[itable] = coordinfo[0] ;
3131      coordinfo[0] = "Hz" ;
3132      newin[itable]->setCoordInfo( coordinfo ) ;
3133    }
3134
3135    // save column values in the vector
3136    vector< vector<uInt> > freqTableIdVec( insize ) ;
3137    vector< vector<uInt> > freqIdVec( insize ) ;
3138    vector< vector<uInt> > ifNoVec( insize ) ;
3139    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3140      ScalarColumn<uInt> freqIDs ;
3141      freqIDs.attach( newin[itable]->frequencies().table(), "ID" ) ;
3142      ifnoCol.attach( newin[itable]->table(), "IFNO" ) ;
3143      freqIDCol.attach( newin[itable]->table(), "FREQ_ID" ) ;
3144      for ( uInt irow = 0 ; irow < newin[itable]->frequencies().table().nrow() ; irow++ ) {
3145        freqTableIdVec[itable].push_back( freqIDs( irow ) ) ;
3146      }
3147      for ( uInt irow = 0 ; irow < newin[itable]->table().nrow() ; irow++ ) {
3148        freqIdVec[itable].push_back( freqIDCol( irow ) ) ;
3149        ifNoVec[itable].push_back( ifnoCol( irow ) ) ;
3150      }
3151    }
3152
3153    // reset spectra and flagtra: pick up common part of frequency coverage
3154    //os << "Pick common frequency range and align resolution" << LogIO::POST ;
3155    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3156      uInt rows = newin[itable]->nrow() ;
3157      int nminchan = -1 ;
3158      int nmaxchan = -1 ;
3159      vector<uInt> freqIdUpdate ;
3160      for ( uInt irow = 0 ; irow < rows ; irow++ ) {
3161        uInt ifno = ifNoVec[itable][irow] ;  // IFNO is reset by group index
3162        double minfreq = ifgfreq[2*ifno] ;
3163        double maxfreq = ifgfreq[2*ifno+1] ;
3164        //os << "frequency range: [" << minfreq << "," << maxfreq << "]" << LogIO::POST ;
3165        vector<double> abcissa = newin[itable]->getAbcissa( irow ) ;
3166        int nchan = abcissa.size() ;
3167        double resol = abcissa[1] - abcissa[0] ;
3168        //os << "abcissa range  : [" << abcissa[0] << "," << abcissa[nchan-1] << "]" << LogIO::POST ;
3169        if ( minfreq <= abcissa[0] )
3170          nminchan = 0 ;
3171        else {
3172          //double cfreq = ( minfreq - abcissa[0] ) / resol ;
3173          double cfreq = ( minfreq - abcissa[0] + 0.5 * resol ) / resol ;
3174          nminchan = int(cfreq) + ( ( cfreq - int(cfreq) <= 0.5 ) ? 0 : 1 ) ;
3175        }
3176        if ( maxfreq >= abcissa[abcissa.size()-1] )
3177          nmaxchan = abcissa.size() - 1 ;
3178        else {
3179          //double cfreq = ( abcissa[abcissa.size()-1] - maxfreq ) / resol ;
3180          double cfreq = ( abcissa[abcissa.size()-1] - maxfreq + 0.5 * resol ) / resol ;
3181          nmaxchan = abcissa.size() - 1 - int(cfreq) - ( ( cfreq - int(cfreq) >= 0.5 ) ? 1 : 0 ) ;
3182        }
3183        //os << "channel range (" << irow << "): [" << nminchan << "," << nmaxchan << "]" << LogIO::POST ;
3184        if ( nmaxchan > nminchan ) {
3185          newin[itable]->reshapeSpectrum( nminchan, nmaxchan, irow ) ;
3186          int newchan = nmaxchan - nminchan + 1 ;
3187          if ( count( freqIdUpdate.begin(), freqIdUpdate.end(), freqIdVec[itable][irow] ) == 0 && newchan < nchan )
3188            freqIdUpdate.push_back( freqIdVec[itable][irow] ) ;
3189        }
3190        else {
3191          throw(AipsError("Failed to pick up common part of frequency range.")) ;
3192        }
3193      }
3194      for ( uInt i = 0 ; i < freqIdUpdate.size() ; i++ ) {
3195        uInt freqId = freqIdUpdate[i] ;
3196        Double refpix ;
3197        Double refval ;
3198        Double increment ;
3199       
3200        // update row
3201        newin[itable]->frequencies().getEntry( refpix, refval, increment, freqId ) ;
3202        refval = refval - ( refpix - nminchan ) * increment ;
3203        refpix = 0 ;
3204        newin[itable]->frequencies().setEntry( refpix, refval, increment, freqId ) ;
3205      }   
3206    }
3207
3208   
3209    // reset spectra and flagtra: align spectral resolution
3210    //os << "Align spectral resolution" << LogIO::POST ;
3211    // gmaxdnu: the coarsest frequency resolution in the frequency group
3212    // gmemid: member index that have a resolution equal to gmaxdnu
3213    // gmaxdnu[numfreqgrp]
3214    // gmaxdnu: [dnu0, dnu1, ...]
3215    // gmemid[numfreqgrp]
3216    // gmemid: [id0, id1, ...]
3217    vector<double> gmaxdnu( freqgrp.size(), 0.0 ) ;
3218    vector<uInt> gmemid( freqgrp.size(), 0 ) ;
3219    for ( uInt igrp = 0 ; igrp < ifgrp.size() ; igrp++ ) {
3220      double maxdnu = 0.0 ;       // maximum (coarsest) frequency resolution
3221      int minchan = INT_MAX ;     // minimum channel number
3222      Double refpixref = -1 ;     // reference of 'reference pixel'
3223      Double refvalref = -1 ;     // reference of 'reference frequency'
3224      Double refinc = -1 ;        // reference frequency resolution
3225      uInt refreqid ;
3226      uInt reftable = INT_MAX;
3227      // process only if group member > 1
3228      if ( ifgrp[igrp].size() > 2 ) {
3229        // find minchan and maxdnu in each group
3230        for ( uInt imem = 0 ; imem < ifgrp[igrp].size()/2 ; imem++ ) {
3231          uInt tableid = ifgrp[igrp][2*imem] ;
3232          uInt rowid = ifgrp[igrp][2*imem+1] ;
3233          vector<uInt>::iterator iter = find( freqIdVec[tableid].begin(), freqIdVec[tableid].end(), rowid ) ;
3234          if ( iter != freqIdVec[tableid].end() ) {
3235            uInt index = distance( freqIdVec[tableid].begin(), iter ) ;
3236            vector<double> abcissa = newin[tableid]->getAbcissa( index ) ;
3237            int nchan = abcissa.size() ;
3238            double dnu = abcissa[1] - abcissa[0] ;
3239            //os << "GROUP " << igrp << " (" << tableid << "," << rowid << "): nchan = " << nchan << " (minchan = " << minchan << ")" << LogIO::POST ;
3240            if ( nchan < minchan ) {
3241              minchan = nchan ;
3242              maxdnu = dnu ;
3243              newin[tableid]->frequencies().getEntry( refpixref, refvalref, refinc, rowid ) ;
3244              refreqid = rowid ;
3245              reftable = tableid ;
3246            }
3247          }
3248        }
3249        // regrid spectra in each group
3250        os << "GROUP " << igrp << endl ;
3251        os << "   Channel number is adjusted to " << minchan << endl ;
3252        os << "   Corresponding frequency resolution is " << maxdnu << "Hz" << LogIO::POST ;
3253        for ( uInt imem = 0 ; imem < ifgrp[igrp].size()/2 ; imem++ ) {
3254          uInt tableid = ifgrp[igrp][2*imem] ;
3255          uInt rowid = ifgrp[igrp][2*imem+1] ;
3256          freqIDCol.attach( newin[tableid]->table(), "FREQ_ID" ) ;
3257          //os << "tableid = " << tableid << " rowid = " << rowid << ": " << LogIO::POST ;
3258          //os << "   regridChannel applied to " ;
3259          if ( tableid != reftable )
3260            refreqid = newin[tableid]->frequencies().addEntry( refpixref, refvalref, refinc ) ;
3261          for ( uInt irow = 0 ; irow < newin[tableid]->table().nrow() ; irow++ ) {
3262            uInt tfreqid = freqIdVec[tableid][irow] ;
3263            if ( tfreqid == rowid ) {     
3264              //os << irow << " " ;
3265              newin[tableid]->regridChannel( minchan, maxdnu, irow ) ;
3266              freqIDCol.put( irow, refreqid ) ;
3267              freqIdVec[tableid][irow] = refreqid ;
3268            }
3269          }
3270          //os << LogIO::POST ;
3271        }
3272      }
3273      else {
3274        uInt tableid = ifgrp[igrp][0] ;
3275        uInt rowid = ifgrp[igrp][1] ;
3276        vector<uInt>::iterator iter = find( freqIdVec[tableid].begin(), freqIdVec[tableid].end(), rowid ) ;
3277        if ( iter != freqIdVec[tableid].end() ) {
3278          uInt index = distance( freqIdVec[tableid].begin(), iter ) ;
3279          vector<double> abcissa = newin[tableid]->getAbcissa( index ) ;
3280          minchan = abcissa.size() ;
3281          maxdnu = abcissa[1] - abcissa[0] ;
3282        }
3283      }
3284      for ( uInt i = 0 ; i < freqgrp.size() ; i++ ) {
3285        if ( count( freqgrp[i].begin(), freqgrp[i].end(), igrp ) > 0 ) {
3286          if ( maxdnu > gmaxdnu[i] ) {
3287            gmaxdnu[i] = maxdnu ;
3288            gmemid[i] = igrp ;
3289          }
3290          break ;
3291        }
3292      }
3293    }
3294
3295    // set back coordinfo
3296    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3297      vector<string> coordinfo = newin[itable]->getCoordInfo() ;
3298      coordinfo[0] = oldinfo[itable] ;
3299      newin[itable]->setCoordInfo( coordinfo ) ;
3300    }     
3301
3302    // accumulate all rows into the first table
3303    // NOTE: assumed in.size() = 1
3304    vector< CountedPtr<Scantable> > tmp( 1 ) ;
3305    if ( newin.size() == 1 )
3306      tmp[0] = newin[0] ;
3307    else
3308      tmp[0] = merge( newin ) ;
3309
3310    //return tmp[0] ;
3311
3312    // average
3313    CountedPtr<Scantable> tmpout = average( tmp, mask, weight, avmode ) ;
3314
3315    //return tmpout ;
3316
3317    // combine frequency group
3318    os << "Combine spectra based on frequency grouping" << LogIO::POST ;
3319    os << "IFNO is renumbered as frequency group ID (see above)" << LogIO::POST ;
3320    vector<string> coordinfo = tmpout->getCoordInfo() ;
3321    oldinfo[0] = coordinfo[0] ;
3322    coordinfo[0] = "Hz" ;
3323    tmpout->setCoordInfo( coordinfo ) ;
3324    // create proformas of output table
3325    stringstream taqlstream ;
3326    taqlstream << "SELECT FROM $1 WHERE IFNO IN [" ;
3327    for ( uInt i = 0 ; i < gmemid.size() ; i++ ) {
3328      taqlstream << gmemid[i] ;
3329      if ( i < gmemid.size() - 1 )
3330        taqlstream << "," ;
3331      else
3332        taqlstream << "]" ;
3333    }
3334    string taql = taqlstream.str() ;
3335    //os << "taql = " << taql << LogIO::POST ;
3336    STSelector selector = STSelector() ;
3337    selector.setTaQL( taql ) ;
3338    oldInsitu = insitu_ ;
3339    setInsitu( false ) ;
3340    out = getScantable( tmpout, false ) ;
3341    setInsitu( oldInsitu ) ;
3342    out->setSelection( selector ) ;
3343    // regrid rows
3344    ifnoCol.attach( tmpout->table(), "IFNO" ) ;
3345    for ( uInt irow = 0 ; irow < tmpout->table().nrow() ; irow++ ) {
3346      uInt ifno = ifnoCol( irow ) ;
3347      for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3348        if ( count( freqgrp[igrp].begin(), freqgrp[igrp].end(), ifno ) > 0 ) {
3349          vector<double> abcissa = tmpout->getAbcissa( irow ) ;
3350          double bw = ( abcissa[1] - abcissa[0] ) * abcissa.size() ;
3351          int nchan = (int)( bw / gmaxdnu[igrp] ) ;
3352          tmpout->regridChannel( nchan, gmaxdnu[igrp], irow ) ;
3353          break ;
3354        }
3355      }
3356    }
3357    // combine spectra
3358    ArrayColumn<Float> specColOut ;
3359    specColOut.attach( out->table(), "SPECTRA" ) ;
3360    ArrayColumn<uChar> flagColOut ;
3361    flagColOut.attach( out->table(), "FLAGTRA" ) ;
3362    ScalarColumn<uInt> ifnoColOut ;
3363    ifnoColOut.attach( out->table(), "IFNO" ) ;
3364    ScalarColumn<uInt> polnoColOut ;
3365    polnoColOut.attach( out->table(), "POLNO" ) ;
3366    ScalarColumn<uInt> freqidColOut ;
3367    freqidColOut.attach( out->table(), "FREQ_ID" ) ;
3368    MDirection::ScalarColumn dirColOut ;
3369    dirColOut.attach( out->table(), "DIRECTION" ) ;
3370    Table &tab = tmpout->table() ;
3371    Block<String> cols(1);
3372    cols[0] = String("POLNO") ;
3373    TableIterator iter( tab, cols ) ;
3374    bool done = false ;
3375    vector< vector<uInt> > sizes( freqgrp.size() ) ;
3376    while( !iter.pastEnd() ) {
3377      vector< vector<Float> > specout( freqgrp.size() ) ;
3378      vector< vector<uChar> > flagout( freqgrp.size() ) ;
3379      ArrayColumn<Float> specCols ;
3380      specCols.attach( iter.table(), "SPECTRA" ) ;
3381      ArrayColumn<uChar> flagCols ;
3382      flagCols.attach( iter.table(), "FLAGTRA" ) ;
3383      ifnoCol.attach( iter.table(), "IFNO" ) ;
3384      ScalarColumn<uInt> polnos ;
3385      polnos.attach( iter.table(), "POLNO" ) ;
3386      MDirection::ScalarColumn dircol ;
3387      dircol.attach( iter.table(), "DIRECTION" ) ;
3388      uInt polno = polnos( 0 ) ;
3389      //os << "POLNO iteration: " << polno << LogIO::POST ;
3390//       for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3391//      sizes[igrp].resize( freqgrp[igrp].size() ) ;
3392//      for ( uInt imem = 0 ; imem < freqgrp[igrp].size() ; imem++ ) {
3393//        for ( uInt irow = 0 ; irow < iter.table().nrow() ; irow++ ) {
3394//          uInt ifno = ifnoCol( irow ) ;
3395//          if ( ifno == freqgrp[igrp][imem] ) {
3396//            Vector<Float> spec = specCols( irow ) ;
3397//            Vector<uChar> flag = flagCols( irow ) ;
3398//            vector<Float> svec ;
3399//            spec.tovector( svec ) ;
3400//            vector<uChar> fvec ;
3401//            flag.tovector( fvec ) ;
3402//            //os << "spec.size() = " << svec.size() << " fvec.size() = " << fvec.size() << LogIO::POST ;
3403//            specout[igrp].insert( specout[igrp].end(), svec.begin(), svec.end() ) ;
3404//            flagout[igrp].insert( flagout[igrp].end(), fvec.begin(), fvec.end() ) ;
3405//            //os << "specout[" << igrp << "].size() = " << specout[igrp].size() << LogIO::POST ;
3406//            sizes[igrp][imem] = spec.nelements() ;
3407//          }
3408//        }
3409//      }
3410//      for ( uInt irow = 0 ; irow < out->table().nrow() ; irow++ ) {
3411//        uInt ifout = ifnoColOut( irow ) ;
3412//        uInt polout = polnoColOut( irow ) ;
3413//        if ( ifout == gmemid[igrp] && polout == polno ) {
3414//          // set SPECTRA and FRAGTRA
3415//          Vector<Float> newspec( specout[igrp] ) ;
3416//          Vector<uChar> newflag( flagout[igrp] ) ;
3417//          specColOut.put( irow, newspec ) ;
3418//          flagColOut.put( irow, newflag ) ;
3419//          // IFNO renumbering
3420//          ifnoColOut.put( irow, igrp ) ;
3421//        }
3422//      }
3423//       }
3424      // get a list of number of channels for each frequency group member
3425      if ( !done ) {
3426        for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3427          sizes[igrp].resize( freqgrp[igrp].size() ) ;
3428          for ( uInt imem = 0 ; imem < freqgrp[igrp].size() ; imem++ ) {
3429            for ( uInt irow = 0 ; irow < iter.table().nrow() ; irow++ ) {
3430              uInt ifno = ifnoCol( irow ) ;
3431              if ( ifno == freqgrp[igrp][imem] ) {
3432                Vector<Float> spec = specCols( irow ) ;
3433                sizes[igrp][imem] = spec.nelements() ;
3434                break ;
3435              }               
3436            }
3437          }
3438        }
3439        done = true ;
3440      }
3441      // combine spectra
3442      for ( uInt irow = 0 ; irow < out->table().nrow() ; irow++ ) {
3443        uInt polout = polnoColOut( irow ) ;
3444        if ( polout == polno ) {
3445          uInt ifout = ifnoColOut( irow ) ;
3446          Vector<Double> direction = dirColOut(irow).getAngle(Unit(String("rad"))).getValue() ;
3447          uInt igrp ;
3448          for ( uInt jgrp = 0 ; jgrp < freqgrp.size() ; jgrp++ ) {
3449            if ( ifout == gmemid[jgrp] ) {
3450              igrp = jgrp ;
3451              break ;
3452            }
3453          }
3454          for ( uInt imem = 0 ; imem < freqgrp[igrp].size() ; imem++ ) {
3455            for ( uInt jrow = 0 ; jrow < iter.table().nrow() ; jrow++ ) {
3456              uInt ifno = ifnoCol( jrow ) ;
3457              Vector<Double> tdir = dircol(jrow).getAngle(Unit(String("rad"))).getValue() ;
3458              //if ( ifno == freqgrp[igrp][imem] && allTrue( tdir == direction  ) ) {
3459              Double dx = tdir[0] - direction[0] ;
3460              Double dy = tdir[1] - direction[1] ;
3461              Double dd = sqrt( dx * dx + dy * dy ) ;
3462              //if ( ifno == freqgrp[igrp][imem] && allNearAbs( tdir, direction, tol ) ) {
3463              if ( ifno == freqgrp[igrp][imem] && dd <= tol ) {
3464                Vector<Float> spec = specCols( jrow ) ;
3465                Vector<uChar> flag = flagCols( jrow ) ;
3466                vector<Float> svec ;
3467                spec.tovector( svec ) ;
3468                vector<uChar> fvec ;
3469                flag.tovector( fvec ) ;
3470                //os << "spec.size() = " << svec.size() << " fvec.size() = " << fvec.size() << LogIO::POST ;
3471                specout[igrp].insert( specout[igrp].end(), svec.begin(), svec.end() ) ;
3472                flagout[igrp].insert( flagout[igrp].end(), fvec.begin(), fvec.end() ) ;
3473                //os << "specout[" << igrp << "].size() = " << specout[igrp].size() << LogIO::POST ;
3474              }
3475            }
3476          }
3477          // set SPECTRA and FRAGTRA
3478          Vector<Float> newspec( specout[igrp] ) ;
3479          Vector<uChar> newflag( flagout[igrp] ) ;
3480          specColOut.put( irow, newspec ) ;
3481          flagColOut.put( irow, newflag ) ;
3482          // IFNO renumbering
3483          ifnoColOut.put( irow, igrp ) ;
3484        }
3485      }
3486      iter++ ;
3487    }
3488    // update FREQUENCIES subtable
3489    vector<bool> updated( freqgrp.size(), false ) ;
3490    for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3491      uInt index = 0 ;
3492      uInt pixShift = 0 ;
3493      while ( freqgrp[igrp][index] != gmemid[igrp] ) {
3494        pixShift += sizes[igrp][index++] ;
3495      }
3496      for ( uInt irow = 0 ; irow < out->table().nrow() ; irow++ ) {
3497        if ( ifnoColOut( irow ) == gmemid[igrp] && !updated[igrp] ) {
3498          uInt freqidOut = freqidColOut( irow ) ;
3499          //os << "freqgrp " << igrp << " freqidOut = " << freqidOut << LogIO::POST ;
3500          double refpix ;
3501          double refval ;
3502          double increm ;
3503          out->frequencies().getEntry( refpix, refval, increm, freqidOut ) ;
3504          refpix += pixShift ;
3505          out->frequencies().setEntry( refpix, refval, increm, freqidOut ) ;
3506          updated[igrp] = true ;
3507        }
3508      }
3509    }
3510
3511    //out = tmpout ;
3512
3513    coordinfo = tmpout->getCoordInfo() ;
3514    coordinfo[0] = oldinfo[0] ;
3515    tmpout->setCoordInfo( coordinfo ) ;
3516  }
3517  else {
3518    // simple average
3519    out =  average( in, mask, weight, avmode ) ;
3520  }
3521 
3522  return out ;
3523}
3524
3525CountedPtr<Scantable> STMath::cwcal( const CountedPtr<Scantable>& s,
3526                                     const String calmode,
3527                                     const String antname )
3528{
3529  // frequency switch
3530  if ( calmode == "fs" ) {
3531    return cwcalfs( s, antname ) ;
3532  }
3533  else {
3534    string skystr = "*_sky" ;
3535    string hotstr = "*_hot" ;
3536    string coldstr = "*_cold" ;
3537    string onstr = "*_" ;
3538    string offstr = "*_" ;
3539   
3540    if ( calmode == "ps" || calmode == "otf" ) {
3541      onstr += "pson" ;
3542      offstr += "psoff" ;
3543    }
3544    else if ( calmode == "wob" ) {
3545      onstr += "wobon" ;
3546      offstr += "woboff" ;
3547    }
3548   
3549    vector<bool> masks = s->getMask( 0 ) ;
3550   
3551    // sky scan
3552    STSelector sel = STSelector() ;
3553    sel.setName( skystr ) ;
3554    s->setSelection( sel ) ;
3555    vector< CountedPtr<Scantable> > tmp( 1, getScantable( s, false ) ) ;
3556    CountedPtr<Scantable> asky = average( tmp, masks, "TINT", "SCAN" ) ;
3557    s->unsetSelection() ;
3558    sel.reset() ;
3559
3560    // hot scan
3561    sel.setName( hotstr ) ;
3562    s->setSelection( sel ) ;
3563    tmp[0] = getScantable( s, false ) ;
3564    CountedPtr<Scantable> ahot = average( tmp, masks, "TINT", "SCAN" ) ;
3565    s->unsetSelection() ;
3566    sel.reset() ;
3567   
3568    // cold scan
3569    sel.setName( coldstr ) ;
3570    s->setSelection( sel ) ;
3571    tmp[0] = getScantable( s, false ) ;
3572    CountedPtr<Scantable> acold = average( tmp, masks, "TINT", "SCNAN" ) ;
3573    s->unsetSelection() ;
3574    sel.reset() ;
3575
3576    // off scan
3577    sel.setName( offstr ) ;
3578    s->setSelection( sel ) ;
3579    tmp[0] = getScantable( s, false ) ;
3580    CountedPtr<Scantable> aoff = average( tmp, masks, "TINT", "SCAN" ) ;
3581    s->unsetSelection() ;
3582    sel.reset() ;
3583   
3584    // on scan
3585    bool insitu = insitu_ ;
3586    insitu_ = false ;
3587    CountedPtr<Scantable> out = getScantable( s, true ) ;
3588    insitu_ = insitu ;
3589    sel.setName( onstr ) ;
3590    s->setSelection( sel ) ;
3591    TableCopy::copyRows( out->table(), s->table() ) ;
3592    s->unsetSelection() ;
3593    sel.reset() ;
3594   
3595    // process each on scan
3596    ArrayColumn<Float> tsysCol ;
3597    tsysCol.attach( out->table(), "TSYS" ) ;
3598    for ( int i = 0 ; i < out->nrow() ; i++ ) {
3599      vector<float> sp = getCalibratedSpectra( out, aoff, asky, ahot, acold, i, antname ) ;
3600      out->setSpectrum( sp, i ) ;
3601      string reftime = out->getTime( i ) ;
3602      vector<int> ii( 1, out->getIF( i ) ) ;
3603      vector<int> ib( 1, out->getBeam( i ) ) ;
3604      vector<int> ip( 1, out->getPol( i ) ) ;
3605      sel.setIFs( ii ) ;
3606      sel.setBeams( ib ) ;
3607      sel.setPolarizations( ip ) ;
3608      asky->setSelection( sel ) ;   
3609      vector<float> sptsys = getTsysFromTime( reftime, asky, "linear" ) ;
3610      const Vector<Float> Vtsys( sptsys ) ;
3611      tsysCol.put( i, Vtsys ) ;
3612      asky->unsetSelection() ;
3613      sel.reset() ;
3614    }
3615
3616    // remove additional string from SRCNAME
3617    ScalarColumn<String> srcnameCol ;
3618    srcnameCol.attach( out->table(), "SRCNAME" ) ;
3619    Vector<String> srcnames( srcnameCol.getColumn() ) ;
3620    for ( uInt i = 0 ; i < srcnames.nelements() ; i++ ) {
3621      srcnames[i] = srcnames[i].substr( 0, srcnames[i].find( onstr.substr(1,onstr.size()-1) ) ) ;
3622    }
3623    srcnameCol.putColumn( srcnames ) ;
3624
3625    // flux unit
3626    out->setFluxUnit( "K" ) ;
3627
3628    return out ;
3629  }
3630}
3631 
3632CountedPtr<Scantable> STMath::almacal( const CountedPtr<Scantable>& s,
3633                                       const String calmode )
3634{
3635  // frequency switch
3636  if ( calmode == "fs" ) {
3637    return almacalfs( s ) ;
3638  }
3639  else {
3640    vector<bool> masks = s->getMask( 0 ) ;
3641   
3642    // off scan
3643    STSelector sel = STSelector() ;
3644    string taql = "SELECT FROM $1 WHERE SRCTYPE == 1" ;
3645    sel.setTaQL( taql ) ;
3646    s->setSelection( sel ) ;
3647    // TODO 2010/01/08 TN
3648    // Grouping by time should be needed before averaging.
3649    // Each group must have own unique SCANNO (should be renumbered).
3650    // See PIPELINE/SDCalibration.py
3651    CountedPtr<Scantable> soff = getScantable( s, false ) ;
3652    Table ttab = soff->table() ;
3653    ROScalarColumn<Double> timeCol( ttab, "TIME" ) ;
3654    uInt nrow = timeCol.nrow() ;
3655    Vector<Double> timeSep( nrow - 1 ) ;
3656    for ( uInt i = 0 ; i < nrow - 1 ; i++ ) {
3657      timeSep[i] = timeCol(i+1) - timeCol(i) ;
3658    }
3659    ScalarColumn<Double> intervalCol( ttab, "INTERVAL" ) ;
3660    Vector<Double> interval = intervalCol.getColumn() ;
3661    interval /= 86400.0 ;
3662    ScalarColumn<uInt> scanCol( ttab, "SCANNO" ) ;
3663    vector<uInt> glist ;
3664    for ( uInt i = 0 ; i < nrow - 1 ; i++ ) {
3665      double gap = 2.0 * timeSep[i] / ( interval[i] + interval[i+1] ) ;
3666      //cout << "gap[" << i << "]=" << setw(5) << gap << endl ;
3667      if ( gap > 1.1 ) {
3668        glist.push_back( i ) ;
3669      }
3670    }
3671    Vector<uInt> gaplist( glist ) ;
3672    //cout << "gaplist = " << gaplist << endl ;
3673    uInt newid = 0 ;
3674    for ( uInt i = 0 ; i < nrow ; i++ ) {
3675      scanCol.put( i, newid ) ;
3676      if ( i == gaplist[newid] ) {
3677        newid++ ;
3678      }
3679    }
3680    //cout << "new scancol = " << scanCol.getColumn() << endl ;
3681    vector< CountedPtr<Scantable> > tmp( 1, soff ) ;
3682    CountedPtr<Scantable> aoff = average( tmp, masks, "TINT", "SCAN" ) ;
3683    //cout << "aoff.nrow = " << aoff->nrow() << endl ;
3684    s->unsetSelection() ;
3685    sel.reset() ;
3686   
3687    // on scan
3688    bool insitu = insitu_ ;
3689    insitu_ = false ;
3690    CountedPtr<Scantable> out = getScantable( s, true ) ;
3691    insitu_ = insitu ;
3692    taql = "SELECT FROM $1 WHERE SRCTYPE == 0" ;
3693    sel.setTaQL( taql ) ;
3694    s->setSelection( sel ) ;
3695    TableCopy::copyRows( out->table(), s->table() ) ;
3696    s->unsetSelection() ;
3697    sel.reset() ;
3698   
3699    // process each on scan
3700    ArrayColumn<Float> tsysCol ;
3701    tsysCol.attach( out->table(), "TSYS" ) ;
3702    for ( int i = 0 ; i < out->nrow() ; i++ ) {
3703      vector<float> sp = getCalibratedSpectra( out, aoff, i ) ;
3704      out->setSpectrum( sp, i ) ;
3705    }
3706
3707    // flux unit
3708    out->setFluxUnit( "K" ) ;
3709
3710    return out ;
3711  }
3712}
3713
3714CountedPtr<Scantable> STMath::cwcalfs( const CountedPtr<Scantable>& s,
3715                                       const String antname )
3716{
3717  string skystr = "*_sky" ;
3718  string skystr1 = "*_fslo_sky" ;
3719  string skystr2 = "*_fshi_sky" ;
3720  string hotstr = "*_hot" ;
3721  string hotstr1 = "*_fslo_hot" ;
3722  string hotstr2 = "*_fshi_hot" ;
3723  string coldstr = "*_cold" ;
3724  string coldstr1 = "*_fslo_cold" ;
3725  string coldstr2 = "*_fshi_cold" ;
3726  string offstr1 = "*_fslo_off" ;
3727  string offstr2 = "*_fshi_off" ;
3728  string sigstr = "*_" ;
3729  string refstr = "*_" ;
3730
3731  // APEX calibration mode
3732  int apexcalmode = 1 ;
3733 
3734  if ( antname.find( "APEX" ) != string::npos ) {
3735    sigstr += "fslo" ;
3736    refstr += "fshi" ;   
3737
3738    // check if off scan exists or not
3739    STSelector sel = STSelector() ;
3740    sel.setName( offstr1 ) ;
3741    try {
3742      s->setSelection( sel ) ;
3743    }
3744    catch ( AipsError &e ) {
3745      apexcalmode = 0 ;
3746    }
3747  }
3748  else {
3749    sigstr += "fssig" ;
3750    refstr += "fsref" ;
3751  }
3752
3753  vector<bool> masks = s->getMask( 0 ) ;
3754  CountedPtr<Scantable> ssig, sref ;
3755  CountedPtr<Scantable> out ;
3756
3757  if ( antname.find( "APEX" ) != string::npos && apexcalmode == 0 ) {
3758    // APEX fs data without off scan
3759    // sky scan
3760    STSelector sel = STSelector() ;
3761    sel.setName( skystr1 ) ;
3762    s->setSelection( sel ) ;
3763    vector< CountedPtr<Scantable> > tmp( 1, getScantable( s, false ) ) ;
3764    CountedPtr<Scantable> askylo = average( tmp, masks, "TINT", "SCAN" ) ;
3765    s->unsetSelection() ;
3766    sel.reset() ;
3767    sel.setName( skystr2 ) ;
3768    s->setSelection( sel ) ;
3769    tmp[0] = getScantable( s, false ) ;
3770    CountedPtr<Scantable> askyhi = average( tmp, masks, "TINT", "SCAN" ) ;
3771    s->unsetSelection() ;
3772    sel.reset() ;
3773   
3774    // hot scan
3775    sel.setName( hotstr1 ) ;
3776    s->setSelection( sel ) ;
3777    tmp[0] = getScantable( s, false ) ;
3778    CountedPtr<Scantable> ahotlo = average( tmp, masks, "TINT", "SCAN" ) ;
3779    s->unsetSelection() ;
3780    sel.reset() ;
3781    sel.setName( hotstr2 ) ;
3782    s->setSelection( sel ) ;
3783    tmp[0] = getScantable( s, false ) ;
3784    CountedPtr<Scantable> ahothi = average( tmp, masks, "TINT", "SCAN" ) ;
3785    s->unsetSelection() ;
3786    sel.reset() ;
3787   
3788    // cold scan
3789    sel.setName( coldstr1 ) ;
3790    s->setSelection( sel ) ;
3791    tmp[0] = getScantable( s, false ) ;
3792    CountedPtr<Scantable> acoldlo = average( tmp, masks, "TINT", "SCAN" ) ;
3793    s->unsetSelection() ;
3794    sel.reset() ;
3795    sel.setName( coldstr2 ) ;
3796    s->setSelection( sel ) ;
3797    tmp[0] = getScantable( s, false ) ;
3798    CountedPtr<Scantable> acoldhi = average( tmp, masks, "TINT", "SCAN" ) ;
3799    s->unsetSelection() ;
3800    sel.reset() ;
3801   
3802    // ref scan
3803    bool insitu = insitu_ ;
3804    insitu_ = false ;
3805    sref = getScantable( s, true ) ;
3806    insitu_ = insitu ;
3807    sel.setName( refstr ) ;
3808    s->setSelection( sel ) ;
3809    TableCopy::copyRows( sref->table(), s->table() ) ;
3810    s->unsetSelection() ;
3811    sel.reset() ;
3812   
3813    // sig scan
3814    insitu_ = false ;
3815    ssig = getScantable( s, true ) ;
3816    insitu_ = insitu ;
3817    sel.setName( sigstr ) ;
3818    s->setSelection( sel ) ;
3819    TableCopy::copyRows( ssig->table(), s->table() ) ;
3820    s->unsetSelection() ;
3821    sel.reset() ; 
3822
3823    // process each sig and ref scan
3824    ArrayColumn<Float> tsysCollo ;
3825    tsysCollo.attach( ssig->table(), "TSYS" ) ;
3826    ArrayColumn<Float> tsysColhi ;
3827    tsysColhi.attach( sref->table(), "TSYS" ) ;
3828    for ( int i = 0 ; i < ssig->nrow() ; i++ ) {
3829      vector< CountedPtr<Scantable> > sky( 2 ) ;
3830      sky[0] = askylo ;
3831      sky[1] = askyhi ;
3832      vector< CountedPtr<Scantable> > hot( 2 ) ;
3833      hot[0] = ahotlo ;
3834      hot[1] = ahothi ;
3835      vector< CountedPtr<Scantable> > cold( 2 ) ;
3836      cold[0] = acoldlo ;
3837      cold[1] = acoldhi ;
3838      vector<float> sp = getFSCalibratedSpectra( ssig, sref, sky, hot, cold, i ) ;
3839      ssig->setSpectrum( sp, i ) ;
3840      string reftime = ssig->getTime( i ) ;
3841      vector<int> ii( 1, ssig->getIF( i ) ) ;
3842      vector<int> ib( 1, ssig->getBeam( i ) ) ;
3843      vector<int> ip( 1, ssig->getPol( i ) ) ;
3844      sel.setIFs( ii ) ;
3845      sel.setBeams( ib ) ;
3846      sel.setPolarizations( ip ) ;
3847      askylo->setSelection( sel ) ;
3848      vector<float> sptsys = getTsysFromTime( reftime, askylo, "linear" ) ;
3849      const Vector<Float> Vtsyslo( sptsys ) ;
3850      tsysCollo.put( i, Vtsyslo ) ;
3851      askylo->unsetSelection() ;
3852      sel.reset() ;
3853      sky[0] = askyhi ;
3854      sky[1] = askylo ;
3855      hot[0] = ahothi ;
3856      hot[1] = ahotlo ;
3857      cold[0] = acoldhi ;
3858      cold[1] = acoldlo ;
3859      sp = getFSCalibratedSpectra( sref, ssig, sky, hot, cold, i ) ;
3860      sref->setSpectrum( sp, i ) ;
3861      reftime = sref->getTime( i ) ;
3862      ii[0] = sref->getIF( i )  ;
3863      ib[0] = sref->getBeam( i ) ;
3864      ip[0] = sref->getPol( i ) ;
3865      sel.setIFs( ii ) ;
3866      sel.setBeams( ib ) ;
3867      sel.setPolarizations( ip ) ;
3868      askyhi->setSelection( sel ) ;   
3869      sptsys = getTsysFromTime( reftime, askyhi, "linear" ) ;
3870      const Vector<Float> Vtsyshi( sptsys ) ;
3871      tsysColhi.put( i, Vtsyshi ) ;
3872      askyhi->unsetSelection() ;
3873      sel.reset() ;
3874    }
3875
3876  }
3877  else if ( antname.find( "APEX" ) != string::npos && apexcalmode == 1 ) {
3878    // APEX fs data with off scan
3879    // sky scan
3880    STSelector sel = STSelector() ;
3881    sel.setName( skystr1 ) ;
3882    s->setSelection( sel ) ;
3883    vector< CountedPtr<Scantable> > tmp( 1, getScantable( s, false ) ) ;
3884    CountedPtr<Scantable> askylo = average( tmp, masks, "TINT", "SCAN" ) ;
3885    s->unsetSelection() ;
3886    sel.reset() ;
3887    sel.setName( skystr2 ) ;
3888    s->setSelection( sel ) ;
3889    tmp[0] = getScantable( s, false ) ;
3890    CountedPtr<Scantable> askyhi = average( tmp, masks, "TINT", "SCAN" ) ;
3891    s->unsetSelection() ;
3892    sel.reset() ;
3893   
3894    // hot scan
3895    sel.setName( hotstr1 ) ;
3896    s->setSelection( sel ) ;
3897    tmp[0] = getScantable( s, false ) ;
3898    CountedPtr<Scantable> ahotlo = average( tmp, masks, "TINT", "SCAN" ) ;
3899    s->unsetSelection() ;
3900    sel.reset() ;
3901    sel.setName( hotstr2 ) ;
3902    s->setSelection( sel ) ;
3903    tmp[0] = getScantable( s, false ) ;
3904    CountedPtr<Scantable> ahothi = average( tmp, masks, "TINT", "SCAN" ) ;
3905    s->unsetSelection() ;
3906    sel.reset() ;
3907   
3908    // cold scan
3909    sel.setName( coldstr1 ) ;
3910    s->setSelection( sel ) ;
3911    tmp[0] = getScantable( s, false ) ;
3912    CountedPtr<Scantable> acoldlo = average( tmp, masks, "TINT", "SCAN" ) ;
3913    s->unsetSelection() ;
3914    sel.reset() ;
3915    sel.setName( coldstr2 ) ;
3916    s->setSelection( sel ) ;
3917    tmp[0] = getScantable( s, false ) ;
3918    CountedPtr<Scantable> acoldhi = average( tmp, masks, "TINT", "SCAN" ) ;
3919    s->unsetSelection() ;
3920    sel.reset() ;
3921
3922    // off scan
3923    sel.setName( offstr1 ) ;
3924    s->setSelection( sel ) ;
3925    tmp[0] = getScantable( s, false ) ;
3926    CountedPtr<Scantable> aofflo = average( tmp, masks, "TINT", "SCAN" ) ;
3927    s->unsetSelection() ;
3928    sel.reset() ;
3929    sel.setName( offstr2 ) ;
3930    s->setSelection( sel ) ;
3931    tmp[0] = getScantable( s, false ) ;
3932    CountedPtr<Scantable> aoffhi = average( tmp, masks, "TINT", "SCAN" ) ;
3933    s->unsetSelection() ;
3934    sel.reset() ;
3935   
3936    // ref scan
3937    bool insitu = insitu_ ;
3938    insitu_ = false ;
3939    sref = getScantable( s, true ) ;
3940    insitu_ = insitu ;
3941    sel.setName( refstr ) ;
3942    s->setSelection( sel ) ;
3943    TableCopy::copyRows( sref->table(), s->table() ) ;
3944    s->unsetSelection() ;
3945    sel.reset() ;
3946   
3947    // sig scan
3948    insitu_ = false ;
3949    ssig = getScantable( s, true ) ;
3950    insitu_ = insitu ;
3951    sel.setName( sigstr ) ;
3952    s->setSelection( sel ) ;
3953    TableCopy::copyRows( ssig->table(), s->table() ) ;
3954    s->unsetSelection() ;
3955    sel.reset() ;
3956
3957    // process each sig and ref scan
3958    ArrayColumn<Float> tsysCollo ;
3959    tsysCollo.attach( ssig->table(), "TSYS" ) ;
3960    ArrayColumn<Float> tsysColhi ;
3961    tsysColhi.attach( sref->table(), "TSYS" ) ;
3962    for ( int i = 0 ; i < ssig->nrow() ; i++ ) {
3963      vector<float> sp = getCalibratedSpectra( ssig, aofflo, askylo, ahotlo, acoldlo, i, antname ) ;
3964      ssig->setSpectrum( sp, i ) ;
3965      sp = getCalibratedSpectra( sref, aoffhi, askyhi, ahothi, acoldhi, i, antname ) ;
3966      string reftime = ssig->getTime( i ) ;
3967      vector<int> ii( 1, ssig->getIF( i ) ) ;
3968      vector<int> ib( 1, ssig->getBeam( i ) ) ;
3969      vector<int> ip( 1, ssig->getPol( i ) ) ;
3970      sel.setIFs( ii ) ;
3971      sel.setBeams( ib ) ;
3972      sel.setPolarizations( ip ) ;
3973      askylo->setSelection( sel ) ;
3974      vector<float> sptsys = getTsysFromTime( reftime, askylo, "linear" ) ;
3975      const Vector<Float> Vtsyslo( sptsys ) ;
3976      tsysCollo.put( i, Vtsyslo ) ;
3977      askylo->unsetSelection() ;
3978      sel.reset() ;
3979      sref->setSpectrum( sp, i ) ;
3980      reftime = sref->getTime( i ) ;
3981      ii[0] = sref->getIF( i )  ;
3982      ib[0] = sref->getBeam( i ) ;
3983      ip[0] = sref->getPol( i ) ;
3984      sel.setIFs( ii ) ;
3985      sel.setBeams( ib ) ;
3986      sel.setPolarizations( ip ) ;
3987      askyhi->setSelection( sel ) ;   
3988      sptsys = getTsysFromTime( reftime, askyhi, "linear" ) ;
3989      const Vector<Float> Vtsyshi( sptsys ) ;
3990      tsysColhi.put( i, Vtsyshi ) ;
3991      askyhi->unsetSelection() ;
3992      sel.reset() ;
3993    }
3994  }
3995  else if ( antname.find( "APEX" ) == string::npos ) {
3996    // non-APEX fs data
3997    // sky scan
3998    STSelector sel = STSelector() ;
3999    sel.setName( skystr ) ;
4000    s->setSelection( sel ) ;
4001    vector< CountedPtr<Scantable> > tmp( 1, getScantable( s, false ) ) ;
4002    CountedPtr<Scantable> asky = average( tmp, masks, "TINT", "SCAN" ) ;
4003    s->unsetSelection() ;
4004    sel.reset() ;
4005   
4006    // hot scan
4007    sel.setName( hotstr ) ;
4008    s->setSelection( sel ) ;
4009    tmp[0] = getScantable( s, false ) ;
4010    CountedPtr<Scantable> ahot = average( tmp, masks, "TINT", "SCAN" ) ;
4011    s->unsetSelection() ;
4012    sel.reset() ;
4013
4014     // cold scan
4015    sel.setName( coldstr ) ;
4016    s->setSelection( sel ) ;
4017    tmp[0] = getScantable( s, false ) ;
4018    CountedPtr<Scantable> acold = average( tmp, masks, "TINT", "SCAN" ) ;
4019    s->unsetSelection() ;
4020    sel.reset() ;
4021   
4022    // ref scan
4023    bool insitu = insitu_ ;
4024    insitu_ = false ;
4025    sref = getScantable( s, true ) ;
4026    insitu_ = insitu ;
4027    sel.setName( refstr ) ;
4028    s->setSelection( sel ) ;
4029    TableCopy::copyRows( sref->table(), s->table() ) ;
4030    s->unsetSelection() ;
4031    sel.reset() ;
4032   
4033    // sig scan
4034    insitu_ = false ;
4035    ssig = getScantable( s, true ) ;
4036    insitu_ = insitu ;
4037    sel.setName( sigstr ) ;
4038    s->setSelection( sel ) ;
4039    TableCopy::copyRows( ssig->table(), s->table() ) ;
4040    s->unsetSelection() ;
4041    sel.reset() ;
4042
4043    // process each sig and ref scan
4044    ArrayColumn<Float> tsysColsig ;
4045    tsysColsig.attach( ssig->table(), "TSYS" ) ;
4046    ArrayColumn<Float> tsysColref ;
4047    tsysColref.attach( ssig->table(), "TSYS" ) ;
4048    for ( int i = 0 ; i < ssig->nrow() ; i++ ) {
4049      vector<float> sp = getFSCalibratedSpectra( ssig, sref, asky, ahot, acold, i ) ;
4050      ssig->setSpectrum( sp, i ) ;
4051      string reftime = ssig->getTime( i ) ;
4052      vector<int> ii( 1, ssig->getIF( i ) ) ;
4053      vector<int> ib( 1, ssig->getBeam( i ) ) ;
4054      vector<int> ip( 1, ssig->getPol( i ) ) ;
4055      sel.setIFs( ii ) ;
4056      sel.setBeams( ib ) ;
4057      sel.setPolarizations( ip ) ;
4058      asky->setSelection( sel ) ;
4059      vector<float> sptsys = getTsysFromTime( reftime, asky, "linear" ) ;
4060      const Vector<Float> Vtsys( sptsys ) ;
4061      tsysColsig.put( i, Vtsys ) ;
4062      asky->unsetSelection() ;
4063      sel.reset() ;
4064      sp = getFSCalibratedSpectra( sref, ssig, asky, ahot, acold, i ) ;
4065      sref->setSpectrum( sp, i ) ;
4066      tsysColref.put( i, Vtsys ) ;
4067    }
4068  }
4069
4070  // do folding if necessary
4071  Table sigtab = ssig->table() ;
4072  Table reftab = sref->table() ;
4073  ScalarColumn<uInt> sigifnoCol ;
4074  ScalarColumn<uInt> refifnoCol ;
4075  ScalarColumn<uInt> sigfidCol ;
4076  ScalarColumn<uInt> reffidCol ;
4077  Int nchan = (Int)ssig->nchan() ;
4078  sigifnoCol.attach( sigtab, "IFNO" ) ;
4079  refifnoCol.attach( reftab, "IFNO" ) ;
4080  sigfidCol.attach( sigtab, "FREQ_ID" ) ;
4081  reffidCol.attach( reftab, "FREQ_ID" ) ;
4082  Vector<uInt> sfids( sigfidCol.getColumn() ) ;
4083  Vector<uInt> rfids( reffidCol.getColumn() ) ;
4084  vector<uInt> sfids_unique ;
4085  vector<uInt> rfids_unique ;
4086  vector<uInt> sifno_unique ;
4087  vector<uInt> rifno_unique ;
4088  for ( uInt i = 0 ; i < sfids.nelements() ; i++ ) {
4089    if ( count( sfids_unique.begin(), sfids_unique.end(), sfids[i] ) == 0 ) {
4090      sfids_unique.push_back( sfids[i] ) ;
4091      sifno_unique.push_back( ssig->getIF( i ) ) ;
4092    }
4093    if ( count( rfids_unique.begin(), rfids_unique.end(),  rfids[i] ) == 0 ) {
4094      rfids_unique.push_back( rfids[i] ) ;
4095      rifno_unique.push_back( sref->getIF( i ) ) ;
4096    }
4097  }
4098  double refpix_sig, refval_sig, increment_sig ;
4099  double refpix_ref, refval_ref, increment_ref ;
4100  vector< CountedPtr<Scantable> > tmp( sfids_unique.size() ) ;
4101  for ( uInt i = 0 ; i < sfids_unique.size() ; i++ ) {
4102    ssig->frequencies().getEntry( refpix_sig, refval_sig, increment_sig, sfids_unique[i] ) ;
4103    sref->frequencies().getEntry( refpix_ref, refval_ref, increment_ref, rfids_unique[i] ) ;
4104    if ( refpix_sig == refpix_ref ) {
4105      double foffset = refval_ref - refval_sig ;
4106      int choffset = static_cast<int>(foffset/increment_sig) ;
4107      double doffset = foffset / increment_sig ;
4108      if ( abs(choffset) >= nchan ) {
4109        LogIO os( LogOrigin( "STMath", "cwcalfs", WHERE ) ) ;
4110        os << "FREQ_ID=[" << sfids_unique[i] << "," << rfids_unique[i] << "]: out-band frequency switching, no folding" << LogIO::POST ;
4111        os << "Just return signal data" << LogIO::POST ;
4112        //std::vector< CountedPtr<Scantable> > tabs ;
4113        //tabs.push_back( ssig ) ;
4114        //tabs.push_back( sref ) ;
4115        //out = merge( tabs ) ;
4116        tmp[i] = ssig ;
4117      }
4118      else {
4119        STSelector sel = STSelector() ;
4120        vector<int> v( 1, sifno_unique[i] ) ;
4121        sel.setIFs( v ) ;
4122        ssig->setSelection( sel ) ;
4123        sel.reset() ;
4124        v[0] = rifno_unique[i] ;
4125        sel.setIFs( v ) ;
4126        sref->setSelection( sel ) ;
4127        sel.reset() ;
4128        if ( antname.find( "APEX" ) != string::npos ) {
4129          tmp[i] = dofold( ssig, sref, 0.5*doffset, -0.5*doffset ) ;
4130          //tmp[i] = dofold( ssig, sref, doffset ) ;
4131        }
4132        else {
4133          tmp[i] = dofold( ssig, sref, doffset ) ;
4134        }
4135        // remove additional string from SRCNAME
4136        ScalarColumn<String> srcnameCol ;
4137        srcnameCol.attach( tmp[i]->table(), "SRCNAME" ) ;
4138        Vector<String> srcnames( srcnameCol.getColumn() ) ;
4139        for ( uInt i = 0 ; i < srcnames.nelements() ; i++ ) {
4140          srcnames[i] = srcnames[i].substr( 0, srcnames[i].find( sigstr.substr(1,sigstr.size()-1) ) ) ;
4141        }
4142        srcnameCol.putColumn( srcnames ) ;
4143        ssig->unsetSelection() ;
4144        sref->unsetSelection() ;
4145      }
4146    }
4147  }
4148
4149  if ( tmp.size() > 1 ) {
4150    out = merge( tmp ) ;
4151  }
4152  else {
4153    out = tmp[0] ;
4154  }
4155
4156  // flux unit
4157  out->setFluxUnit( "K" ) ;
4158
4159  return out ;
4160}
4161
4162CountedPtr<Scantable> STMath::almacalfs( const CountedPtr<Scantable>& s )
4163{
4164  CountedPtr<Scantable> out ;
4165
4166  return out ;
4167}
4168
4169vector<float> STMath::getSpectrumFromTime( string reftime,
4170                                           CountedPtr<Scantable>& s,
4171                                           string mode )
4172{
4173  LogIO os( LogOrigin( "STMath", "getSpectrumFromTime", WHERE ) ) ;
4174  vector<float> sp ;
4175
4176  if ( s->nrow() == 0 ) {
4177    os << LogIO::SEVERE << "No spectra in the input scantable. Return empty spectrum." << LogIO::POST ;
4178    return sp ;
4179  }
4180  else if ( s->nrow() == 1 ) {
4181    //os << "use row " << 0 << " (scanno = " << s->getScan( 0 ) << ")" << LogIO::POST ;
4182    return s->getSpectrum( 0 ) ;
4183  }
4184  else {
4185    vector<int> idx = getRowIdFromTime( reftime, s ) ;
4186    if ( mode == "before" ) {
4187      int id = -1 ;
4188      if ( idx[0] != -1 ) {
4189        id = idx[0] ;
4190      }
4191      else if ( idx[1] != -1 ) {
4192        os << LogIO::WARN << "Failed to find a scan before reftime. return a spectrum just after the reftime." << LogIO::POST ;
4193        id = idx[1] ;
4194      }
4195      //os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
4196      sp = s->getSpectrum( id ) ;
4197    }
4198    else if ( mode == "after" ) {
4199      int id = -1 ;
4200      if ( idx[1] != -1 ) {
4201        id = idx[1] ;
4202      }
4203      else if ( idx[0] != -1 ) {
4204        os << LogIO::WARN << "Failed to find a scan after reftime. return a spectrum just before the reftime." << LogIO::POST ;
4205        id = idx[1] ;
4206      }
4207      //os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
4208      sp = s->getSpectrum( id ) ;
4209    }
4210    else if ( mode == "nearest" ) {
4211      int id = -1 ;
4212      if ( idx[0] == -1 ) {
4213        id = idx[1] ;
4214      }
4215      else if ( idx[1] == -1 ) {
4216        id = idx[0] ;
4217      }
4218      else if ( idx[0] == idx[1] ) {
4219        id = idx[0] ;
4220      }
4221      else {
4222        double t0 = getMJD( s->getTime( idx[0] ) ) ;
4223        double t1 = getMJD( s->getTime( idx[1] ) ) ;
4224        double tref = getMJD( reftime ) ;
4225        if ( abs( t0 - tref ) > abs( t1 - tref ) ) {
4226          id = idx[1] ;
4227        }
4228        else {
4229          id = idx[0] ;
4230        }
4231      }
4232      //os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
4233      sp = s->getSpectrum( id ) ;     
4234    }
4235    else if ( mode == "linear" ) {
4236      if ( idx[0] == -1 ) {
4237        // use after
4238        os << LogIO::WARN << "Failed to interpolate. return a spectrum just after the reftime." << LogIO::POST ;
4239        int id = idx[1] ;
4240        //os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
4241        sp = s->getSpectrum( id ) ;
4242      }
4243      else if ( idx[1] == -1 ) {
4244        // use before
4245        os << LogIO::WARN << "Failed to interpolate. return a spectrum just before the reftime." << LogIO::POST ;
4246        int id = idx[0] ;
4247        //os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
4248        sp = s->getSpectrum( id ) ;
4249      }
4250      else if ( idx[0] == idx[1] ) {
4251        // use before
4252        //os << "No need to interporate." << LogIO::POST ;
4253        int id = idx[0] ;
4254        //os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
4255        sp = s->getSpectrum( id ) ;
4256      }
4257      else {
4258        // do interpolation
4259        //os << "interpolate between " << idx[0] << " and " << idx[1] << " (scanno: " << s->getScan( idx[0] ) << ", " << s->getScan( idx[1] ) << ")" << LogIO::POST ;
4260        double t0 = getMJD( s->getTime( idx[0] ) ) ;
4261        double t1 = getMJD( s->getTime( idx[1] ) ) ;
4262        double tref = getMJD( reftime ) ;
4263        vector<float> sp0 = s->getSpectrum( idx[0] ) ;
4264        vector<float> sp1 = s->getSpectrum( idx[1] ) ;
4265        for ( unsigned int i = 0 ; i < sp0.size() ; i++ ) {
4266          float v = ( sp1[i] - sp0[i] ) / ( t1 - t0 ) * ( tref - t0 ) + sp0[i] ;
4267          sp.push_back( v ) ;
4268        }
4269      }
4270    }
4271    else {
4272      os << LogIO::SEVERE << "Unknown mode" << LogIO::POST ;
4273    }
4274    return sp ;
4275  }
4276}
4277
4278double STMath::getMJD( string strtime )
4279{
4280  if ( strtime.find("/") == string::npos ) {
4281    // MJD time string
4282    return atof( strtime.c_str() ) ;
4283  }
4284  else {
4285    // string in YYYY/MM/DD/HH:MM:SS format
4286    uInt year = atoi( strtime.substr( 0, 4 ).c_str() ) ;
4287    uInt month = atoi( strtime.substr( 5, 2 ).c_str() ) ;
4288    uInt day = atoi( strtime.substr( 8, 2 ).c_str() ) ;
4289    uInt hour = atoi( strtime.substr( 11, 2 ).c_str() ) ;
4290    uInt minute = atoi( strtime.substr( 14, 2 ).c_str() ) ;
4291    uInt sec = atoi( strtime.substr( 17, 2 ).c_str() ) ;
4292    Time t( year, month, day, hour, minute, sec ) ;
4293    return t.modifiedJulianDay() ;
4294  }
4295}
4296
4297vector<int> STMath::getRowIdFromTime( string reftime, CountedPtr<Scantable> &s )
4298{
4299  double reft = getMJD( reftime ) ;
4300  double dtmin = 1.0e100 ;
4301  double dtmax = -1.0e100 ;
4302  vector<double> dt ;
4303  int just_before = -1 ;
4304  int just_after = -1 ;
4305  for ( int i = 0 ; i < s->nrow() ; i++ ) {
4306    dt.push_back( getMJD( s->getTime( i ) ) - reft ) ;
4307  }
4308  for ( unsigned int i = 0 ; i < dt.size() ; i++ ) {
4309    if ( dt[i] > 0.0 ) {
4310      // after reftime
4311      if ( dt[i] < dtmin ) {
4312        just_after = i ;
4313        dtmin = dt[i] ;
4314      }
4315    }
4316    else if ( dt[i] < 0.0 ) {
4317      // before reftime
4318      if ( dt[i] > dtmax ) {
4319        just_before = i ;
4320        dtmax = dt[i] ;
4321      }
4322    }
4323    else {
4324      // just a reftime
4325      just_before = i ;
4326      just_after = i ;
4327      dtmax = 0 ;
4328      dtmin = 0 ;
4329      break ;
4330    }
4331  }
4332
4333  vector<int> v ;
4334  v.push_back( just_before ) ;
4335  v.push_back( just_after ) ;
4336
4337  return v ;
4338}
4339
4340vector<float> STMath::getTcalFromTime( string reftime,
4341                                       CountedPtr<Scantable>& s,
4342                                       string mode )
4343{
4344  LogIO os( LogOrigin( "STMath", "getTcalFromTime", WHERE ) ) ;
4345  vector<float> tcal ;
4346  STTcal tcalTable = s->tcal() ;
4347  String time ;
4348  Vector<Float> tcalval ;
4349  if ( s->nrow() == 0 ) {
4350    os << LogIO::SEVERE << "No row in the input scantable. Return empty tcal." << LogIO::POST ;
4351    return tcal ;
4352  }
4353  else if ( s->nrow() == 1 ) {
4354    uInt tcalid = s->getTcalId( 0 ) ;
4355    //os << "use row " << 0 << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4356    tcalTable.getEntry( time, tcalval, tcalid ) ;
4357    tcalval.tovector( tcal ) ;
4358    return tcal ;
4359  }
4360  else {
4361    vector<int> idx = getRowIdFromTime( reftime, s ) ;
4362    if ( mode == "before" ) {
4363      int id = -1 ;
4364      if ( idx[0] != -1 ) {
4365        id = idx[0] ;
4366      }
4367      else if ( idx[1] != -1 ) {
4368        os << LogIO::WARN << "Failed to find a scan before reftime. return a spectrum just after the reftime." << LogIO::POST ;
4369        id = idx[1] ;
4370      }
4371      uInt tcalid = s->getTcalId( id ) ;
4372      //os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4373      tcalTable.getEntry( time, tcalval, tcalid ) ;
4374      tcalval.tovector( tcal ) ;
4375    }
4376    else if ( mode == "after" ) {
4377      int id = -1 ;
4378      if ( idx[1] != -1 ) {
4379        id = idx[1] ;
4380      }
4381      else if ( idx[0] != -1 ) {
4382        os << LogIO::WARN << "Failed to find a scan after reftime. return a spectrum just before the reftime." << LogIO::POST ;
4383        id = idx[1] ;
4384      }
4385      uInt tcalid = s->getTcalId( id ) ;
4386      //os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4387      tcalTable.getEntry( time, tcalval, tcalid ) ;
4388      tcalval.tovector( tcal ) ;
4389    }
4390    else if ( mode == "nearest" ) {
4391      int id = -1 ;
4392      if ( idx[0] == -1 ) {
4393        id = idx[1] ;
4394      }
4395      else if ( idx[1] == -1 ) {
4396        id = idx[0] ;
4397      }
4398      else if ( idx[0] == idx[1] ) {
4399        id = idx[0] ;
4400      }
4401      else {
4402        double t0 = getMJD( s->getTime( idx[0] ) ) ;
4403        double t1 = getMJD( s->getTime( idx[1] ) ) ;
4404        double tref = getMJD( reftime ) ;
4405        if ( abs( t0 - tref ) > abs( t1 - tref ) ) {
4406          id = idx[1] ;
4407        }
4408        else {
4409          id = idx[0] ;
4410        }
4411      }
4412      uInt tcalid = s->getTcalId( id ) ;
4413      //os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4414      tcalTable.getEntry( time, tcalval, tcalid ) ;
4415      tcalval.tovector( tcal ) ;
4416    }
4417    else if ( mode == "linear" ) {
4418      if ( idx[0] == -1 ) {
4419        // use after
4420        os << LogIO::WARN << "Failed to interpolate. return a spectrum just after the reftime." << LogIO::POST ;
4421        int id = idx[1] ;
4422        uInt tcalid = s->getTcalId( id ) ;
4423        //os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4424        tcalTable.getEntry( time, tcalval, tcalid ) ;
4425        tcalval.tovector( tcal ) ;
4426      }
4427      else if ( idx[1] == -1 ) {
4428        // use before
4429        os << LogIO::WARN << "Failed to interpolate. return a spectrum just before the reftime." << LogIO::POST ;
4430        int id = idx[0] ;
4431        uInt tcalid = s->getTcalId( id ) ;
4432        //os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4433        tcalTable.getEntry( time, tcalval, tcalid ) ;
4434        tcalval.tovector( tcal ) ;
4435      }
4436      else if ( idx[0] == idx[1] ) {
4437        // use before
4438        //os << "No need to interporate." << LogIO::POST ;
4439        int id = idx[0] ;
4440        uInt tcalid = s->getTcalId( id ) ;
4441        //os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4442        tcalTable.getEntry( time, tcalval, tcalid ) ;
4443        tcalval.tovector( tcal ) ;
4444      }
4445      else {
4446        // do interpolation
4447        //os << "interpolate between " << idx[0] << " and " << idx[1] << " (scanno: " << s->getScan( idx[0] ) << ", " << s->getScan( idx[1] ) << ")" << LogIO::POST ;
4448        double t0 = getMJD( s->getTime( idx[0] ) ) ;
4449        double t1 = getMJD( s->getTime( idx[1] ) ) ;
4450        double tref = getMJD( reftime ) ;
4451        vector<float> tcal0 ;
4452        vector<float> tcal1 ;
4453        uInt tcalid0 = s->getTcalId( idx[0] ) ;
4454        uInt tcalid1 = s->getTcalId( idx[1] ) ;
4455        tcalTable.getEntry( time, tcalval, tcalid0 ) ;
4456        tcalval.tovector( tcal0 ) ;
4457        tcalTable.getEntry( time, tcalval, tcalid1 ) ;
4458        tcalval.tovector( tcal1 ) ;       
4459        for ( unsigned int i = 0 ; i < tcal0.size() ; i++ ) {
4460          float v = ( tcal1[i] - tcal0[i] ) / ( t1 - t0 ) * ( tref - t0 ) + tcal0[i] ;
4461          tcal.push_back( v ) ;
4462        }
4463      }
4464    }
4465    else {
4466      os << LogIO::SEVERE << "Unknown mode" << LogIO::POST ;
4467    }
4468    return tcal ;
4469  }
4470}
4471
4472vector<float> STMath::getTsysFromTime( string reftime,
4473                                       CountedPtr<Scantable>& s,
4474                                       string mode )
4475{
4476  LogIO os( LogOrigin( "STMath", "getTsysFromTime", WHERE ) ) ;
4477  ArrayColumn<Float> tsysCol ;
4478  tsysCol.attach( s->table(), "TSYS" ) ;
4479  vector<float> tsys ;
4480  String time ;
4481  Vector<Float> tsysval ;
4482  if ( s->nrow() == 0 ) {
4483    os << LogIO::SEVERE << "No row in the input scantable. Return empty tsys." << LogIO::POST ;
4484    return tsys ;
4485  }
4486  else if ( s->nrow() == 1 ) {
4487    //os << "use row " << 0 << LogIO::POST ;
4488    tsysval = tsysCol( 0 ) ;
4489    tsysval.tovector( tsys ) ;
4490    return tsys ;
4491  }
4492  else {
4493    vector<int> idx = getRowIdFromTime( reftime, s ) ;
4494    if ( mode == "before" ) {
4495      int id = -1 ;
4496      if ( idx[0] != -1 ) {
4497        id = idx[0] ;
4498      }
4499      else if ( idx[1] != -1 ) {
4500        os << LogIO::WARN << "Failed to find a scan before reftime. return a spectrum just after the reftime." << LogIO::POST ;
4501        id = idx[1] ;
4502      }
4503      //os << "use row " << id << LogIO::POST ;
4504      tsysval = tsysCol( id ) ;
4505      tsysval.tovector( tsys ) ;
4506    }
4507    else if ( mode == "after" ) {
4508      int id = -1 ;
4509      if ( idx[1] != -1 ) {
4510        id = idx[1] ;
4511      }
4512      else if ( idx[0] != -1 ) {
4513        os << LogIO::WARN << "Failed to find a scan after reftime. return a spectrum just before the reftime." << LogIO::POST ;
4514        id = idx[1] ;
4515      }
4516      //os << "use row " << id << LogIO::POST ;
4517      tsysval = tsysCol( id ) ;
4518      tsysval.tovector( tsys ) ;
4519    }
4520    else if ( mode == "nearest" ) {
4521      int id = -1 ;
4522      if ( idx[0] == -1 ) {
4523        id = idx[1] ;
4524      }
4525      else if ( idx[1] == -1 ) {
4526        id = idx[0] ;
4527      }
4528      else if ( idx[0] == idx[1] ) {
4529        id = idx[0] ;
4530      }
4531      else {
4532        double t0 = getMJD( s->getTime( idx[0] ) ) ;
4533        double t1 = getMJD( s->getTime( idx[1] ) ) ;
4534        double tref = getMJD( reftime ) ;
4535        if ( abs( t0 - tref ) > abs( t1 - tref ) ) {
4536          id = idx[1] ;
4537        }
4538        else {
4539          id = idx[0] ;
4540        }
4541      }
4542      //os << "use row " << id << LogIO::POST ;
4543      tsysval = tsysCol( id ) ;
4544      tsysval.tovector( tsys ) ;
4545    }
4546    else if ( mode == "linear" ) {
4547      if ( idx[0] == -1 ) {
4548        // use after
4549        os << LogIO::WARN << "Failed to interpolate. return a spectrum just after the reftime." << LogIO::POST ;
4550        int id = idx[1] ;
4551        //os << "use row " << id << LogIO::POST ;
4552        tsysval = tsysCol( id ) ;
4553        tsysval.tovector( tsys ) ;
4554      }
4555      else if ( idx[1] == -1 ) {
4556        // use before
4557        os << LogIO::WARN << "Failed to interpolate. return a spectrum just before the reftime." << LogIO::POST ;
4558        int id = idx[0] ;
4559        //os << "use row " << id << LogIO::POST ;
4560        tsysval = tsysCol( id ) ;
4561        tsysval.tovector( tsys ) ;
4562      }
4563      else if ( idx[0] == idx[1] ) {
4564        // use before
4565        //os << "No need to interporate." << LogIO::POST ;
4566        int id = idx[0] ;
4567        //os << "use row " << id << LogIO::POST ;
4568        tsysval = tsysCol( id ) ;
4569        tsysval.tovector( tsys ) ;
4570      }
4571      else {
4572        // do interpolation
4573        //os << "interpolate between " << idx[0] << " and " << idx[1] << " (scanno: " << s->getScan( idx[0] ) << ", " << s->getScan( idx[1] ) << ")" << LogIO::POST ;
4574        double t0 = getMJD( s->getTime( idx[0] ) ) ;
4575        double t1 = getMJD( s->getTime( idx[1] ) ) ;
4576        double tref = getMJD( reftime ) ;
4577        vector<float> tsys0 ;
4578        vector<float> tsys1 ;
4579        tsysval = tsysCol( idx[0] ) ;
4580        tsysval.tovector( tsys0 ) ;
4581        tsysval = tsysCol( idx[1] ) ;
4582        tsysval.tovector( tsys1 ) ;       
4583        for ( unsigned int i = 0 ; i < tsys0.size() ; i++ ) {
4584          float v = ( tsys1[i] - tsys0[i] ) / ( t1 - t0 ) * ( tref - t0 ) + tsys0[i] ;
4585          tsys.push_back( v ) ;
4586        }
4587      }
4588    }
4589    else {
4590      os << LogIO::SEVERE << "Unknown mode" << LogIO::POST ;
4591    }
4592    return tsys ;
4593  }
4594}
4595
4596vector<float> STMath::getCalibratedSpectra( CountedPtr<Scantable>& on,
4597                                            CountedPtr<Scantable>& off,
4598                                            CountedPtr<Scantable>& sky,
4599                                            CountedPtr<Scantable>& hot,
4600                                            CountedPtr<Scantable>& cold,
4601                                            int index,
4602                                            string antname )
4603{
4604  string reftime = on->getTime( index ) ;
4605  vector<int> ii( 1, on->getIF( index ) ) ;
4606  vector<int> ib( 1, on->getBeam( index ) ) ;
4607  vector<int> ip( 1, on->getPol( index ) ) ;
4608  vector<int> ic( 1, on->getScan( index ) ) ;
4609  STSelector sel = STSelector() ;
4610  sel.setIFs( ii ) ;
4611  sel.setBeams( ib ) ;
4612  sel.setPolarizations( ip ) ;
4613  sky->setSelection( sel ) ;
4614  hot->setSelection( sel ) ;
4615  cold->setSelection( sel ) ;
4616  off->setSelection( sel ) ;
4617  vector<float> spsky = getSpectrumFromTime( reftime, sky, "linear" ) ;
4618  vector<float> sphot = getSpectrumFromTime( reftime, hot, "linear" ) ;
4619  vector<float> spcold = getSpectrumFromTime( reftime, cold, "linear" ) ;
4620  vector<float> spoff = getSpectrumFromTime( reftime, off, "linear" ) ;
4621  vector<float> spec = on->getSpectrum( index ) ;
4622  vector<float> tcal = getTcalFromTime( reftime, sky, "linear" ) ;
4623  vector<float> sp( tcal.size() ) ;
4624  if ( antname.find( "APEX" ) != string::npos ) {
4625    // using gain array
4626    for ( unsigned int j = 0 ; j < tcal.size() ; j++ ) {
4627      float v = ( ( spec[j] - spoff[j] ) / spoff[j] )
4628        * ( spsky[j] / ( sphot[j] - spsky[j] ) ) * tcal[j] ;
4629      sp[j] = v ;
4630    }
4631  }
4632  else if ( antname.find( "ALMA" ) != string::npos ) {
4633    // two-load calibration
4634    // from equation 5 and 12 of ALMA memo 318 (Mangum 2000)
4635    //
4636    // 2009/09/09 Takeshi Nakazato
4637    for ( unsigned int j = 0 ; j < tcal.size() ; j++ ) {
4638      //
4639      // in case that Tcal is assumed as signal gain
4640      //
4641      //float K = ( sphot[j] - spcold[j] ) / ( thot - tcold ) ;
4642      //float v = ( spec[j] - spoff[j] ) * exp( tsig ) / ( K * tcal[j] * eta ) ;
4643      //
4644      // in case that Tcal is defined as
4645      //
4646      //    Tcal = ( K * Gs * eta_l * exp( - tau_s ) )^-1
4647      //
4648      float v = tcal[j] * ( spec[j] - spsky[j] ) ;
4649      sp[j] = v ;
4650    }
4651  }
4652  else {
4653    // Chopper-Wheel calibration (Ulich & Haas 1976)
4654    for ( unsigned int j = 0 ; j < tcal.size() ; j++ ) {
4655      float v = ( spec[j] - spoff[j] ) / ( sphot[j] - spsky[j] ) * tcal[j] ;
4656      sp[j] = v ;
4657    }
4658  }
4659  sel.reset() ;
4660  sky->unsetSelection() ;
4661  hot->unsetSelection() ;
4662  cold->unsetSelection() ;
4663  off->unsetSelection() ;
4664
4665  return sp ;
4666}
4667
4668vector<float> STMath::getCalibratedSpectra( CountedPtr<Scantable>& on,
4669                                            CountedPtr<Scantable>& off,
4670                                            int index )
4671{
4672  string reftime = on->getTime( index ) ;
4673  vector<int> ii( 1, on->getIF( index ) ) ;
4674  vector<int> ib( 1, on->getBeam( index ) ) ;
4675  vector<int> ip( 1, on->getPol( index ) ) ;
4676  vector<int> ic( 1, on->getScan( index ) ) ;
4677  STSelector sel = STSelector() ;
4678  sel.setIFs( ii ) ;
4679  sel.setBeams( ib ) ;
4680  sel.setPolarizations( ip ) ;
4681  off->setSelection( sel ) ;
4682  vector<float> spoff = getSpectrumFromTime( reftime, off, "linear" ) ;
4683  vector<float> spec = on->getSpectrum( index ) ;
4684  //vector<float> tcal = getTcalFromTime( reftime, sky, "linear" ) ;
4685  //vector<float> tsys = on->getTsysVec( index ) ;
4686  ArrayColumn<Float> tsysCol( on->table(), "TSYS" ) ;
4687  Vector<Float> tsys = tsysCol( index ) ;
4688  vector<float> sp( spec.size() ) ;
4689  // ALMA Calibration
4690  //
4691  // Ta* = Tsys * ( ON - OFF ) / OFF
4692  //
4693  // 2010/01/07 Takeshi Nakazato
4694  unsigned int tsyssize = tsys.nelements() ;
4695  unsigned int spsize = sp.size() ;
4696  for ( unsigned int j = 0 ; j < sp.size() ; j++ ) {
4697    float tscale = 0.0 ;
4698    if ( tsyssize == spsize )
4699      tscale = tsys[j] ;
4700    else
4701      tscale = tsys[0] ;
4702    float v = tscale * ( spec[j] - spoff[j] ) / spoff[j] ;
4703    sp[j] = v ;
4704  }
4705  sel.reset() ;
4706  off->unsetSelection() ;
4707
4708  return sp ;
4709}
4710
4711vector<float> STMath::getFSCalibratedSpectra( CountedPtr<Scantable>& sig,
4712                                              CountedPtr<Scantable>& ref,
4713                                              CountedPtr<Scantable>& sky,
4714                                              CountedPtr<Scantable>& hot,
4715                                              CountedPtr<Scantable>& cold,
4716                                              int index )
4717{
4718  string reftime = sig->getTime( index ) ;
4719  vector<int> ii( 1, sig->getIF( index ) ) ;
4720  vector<int> ib( 1, sig->getBeam( index ) ) ;
4721  vector<int> ip( 1, sig->getPol( index ) ) ;
4722  vector<int> ic( 1, sig->getScan( index ) ) ;
4723  STSelector sel = STSelector() ;
4724  sel.setIFs( ii ) ;
4725  sel.setBeams( ib ) ;
4726  sel.setPolarizations( ip ) ;
4727  sky->setSelection( sel ) ;
4728  hot->setSelection( sel ) ;
4729  cold->setSelection( sel ) ;
4730  vector<float> spsky = getSpectrumFromTime( reftime, sky, "linear" ) ;
4731  vector<float> sphot = getSpectrumFromTime( reftime, hot, "linear" ) ;
4732  vector<float> spcold = getSpectrumFromTime( reftime, cold, "linear" ) ;
4733  vector<float> spref = ref->getSpectrum( index ) ;
4734  vector<float> spsig = sig->getSpectrum( index ) ;
4735  vector<float> tcal = getTcalFromTime( reftime, sky, "linear" ) ;
4736  vector<float> sp( tcal.size() ) ;
4737  for ( unsigned int j = 0 ; j < tcal.size() ; j++ ) {
4738    float v = tcal[j] * spsky[j] / ( sphot[j] - spsky[j] ) * ( spsig[j] - spref[j] ) / spref[j] ;
4739    sp[j] = v ;
4740  }
4741  sel.reset() ;
4742  sky->unsetSelection() ;
4743  hot->unsetSelection() ;
4744  cold->unsetSelection() ;
4745
4746  return sp ;
4747}
4748
4749vector<float> STMath::getFSCalibratedSpectra( CountedPtr<Scantable>& sig,
4750                                              CountedPtr<Scantable>& ref,
4751                                              vector< CountedPtr<Scantable> >& sky,
4752                                              vector< CountedPtr<Scantable> >& hot,
4753                                              vector< CountedPtr<Scantable> >& cold,
4754                                              int index )
4755{
4756  string reftime = sig->getTime( index ) ;
4757  vector<int> ii( 1, sig->getIF( index ) ) ;
4758  vector<int> ib( 1, sig->getBeam( index ) ) ;
4759  vector<int> ip( 1, sig->getPol( index ) ) ;
4760  vector<int> ic( 1, sig->getScan( index ) ) ;
4761  STSelector sel = STSelector() ;
4762  sel.setIFs( ii ) ;
4763  sel.setBeams( ib ) ;
4764  sel.setPolarizations( ip ) ;
4765  sky[0]->setSelection( sel ) ;
4766  hot[0]->setSelection( sel ) ;
4767  cold[0]->setSelection( sel ) ;
4768  vector<float> spskys = getSpectrumFromTime( reftime, sky[0], "linear" ) ;
4769  vector<float> sphots = getSpectrumFromTime( reftime, hot[0], "linear" ) ;
4770  vector<float> spcolds = getSpectrumFromTime( reftime, cold[0], "linear" ) ;
4771  vector<float> tcals = getTcalFromTime( reftime, sky[0], "linear" ) ;
4772  sel.reset() ;
4773  ii[0] = ref->getIF( index ) ;
4774  sel.setIFs( ii ) ;
4775  sel.setBeams( ib ) ;
4776  sel.setPolarizations( ip ) ;
4777  sky[1]->setSelection( sel ) ;
4778  hot[1]->setSelection( sel ) ;
4779  cold[1]->setSelection( sel ) ;
4780  vector<float> spskyr = getSpectrumFromTime( reftime, sky[1], "linear" ) ;
4781  vector<float> sphotr = getSpectrumFromTime( reftime, hot[1], "linear" ) ;
4782  vector<float> spcoldr = getSpectrumFromTime( reftime, cold[1], "linear" ) ;
4783  vector<float> tcalr = getTcalFromTime( reftime, sky[1], "linear" ) ; 
4784  vector<float> spref = ref->getSpectrum( index ) ;
4785  vector<float> spsig = sig->getSpectrum( index ) ;
4786  vector<float> sp( tcals.size() ) ;
4787  for ( unsigned int j = 0 ; j < tcals.size() ; j++ ) {
4788    float v = tcals[j] * spsig[j] / ( sphots[j] - spskys[j] ) - tcalr[j] * spref[j] / ( sphotr[j] - spskyr[j] ) ;
4789    sp[j] = v ;
4790  }
4791  sel.reset() ;
4792  sky[0]->unsetSelection() ;
4793  hot[0]->unsetSelection() ;
4794  cold[0]->unsetSelection() ;
4795  sky[1]->unsetSelection() ;
4796  hot[1]->unsetSelection() ;
4797  cold[1]->unsetSelection() ;
4798
4799  return sp ;
4800}
Note: See TracBrowser for help on using the repository browser.