source: trunk/src/STMath.cpp @ 2670

Last change on this file since 2670 was 2670, checked in by Malte Marquarding, 12 years ago

Fix for #270: rmedian flags were incorrectly handled. Also remove excessive conversion step

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