source: tags/asap-4.1.0/src/STMath.cpp @ 2662

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

merge from trunk into release candidate

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 162.5 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        convertArray(flag, !maskout);
2458      } else if (kernel == "rmedian") {
2459        mathutil::runningMedian(specout, maskout, spec , mask, width);
2460        convertArray(flag, maskout);
2461      } else if (kernel == "poly") {
2462        mathutil::polyfit(specout, maskout, spec, !mask, width, order);
2463        convertArray(flag, !maskout);
2464      }
2465
2466      for (uInt j = 0; j < flag.nelements(); ++j) {
2467        uChar userFlag = 1 << 7;
2468        if (maskout[j]==True) userFlag = 0 << 7;
2469        flag(j) = userFlag;
2470      }
2471
2472      flagCol.put(i, flag);
2473      specCol.put(i, specout);
2474    }
2475  ++iter;
2476  }
2477  return out;
2478}
2479
2480CountedPtr< Scantable > STMath::smooth( const CountedPtr< Scantable >& in,
2481                                        const std::string& kernel, float width,
2482                                        int order)
2483{
2484  if (kernel == "rmedian"  || kernel == "hanning" || kernel == "poly") {
2485    return smoothOther(in, kernel, width, order);
2486  }
2487  CountedPtr< Scantable > out = getScantable(in, false);
2488  Table& table = out->table();
2489  VectorKernel::KernelTypes type = VectorKernel::toKernelType(kernel);
2490  // same IFNO should have same no of channels
2491  // this saves overhead
2492  TableIterator iter(table, "IFNO");
2493  while (!iter.pastEnd()) {
2494    Table tab = iter.table();
2495    ArrayColumn<Float> specCol(tab, "SPECTRA");
2496    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
2497    Vector<Float> spec = specCol( 0 );
2498    uInt nchan = spec.nelements();
2499    Vector<Float> kvec = VectorKernel::make(type, width, nchan, True, False);
2500    Convolver<Float> conv(kvec, IPosition(1,nchan));
2501    Vector<uChar> flag;
2502    Vector<Bool> mask(nchan);
2503    for ( uInt i=0; i<tab.nrow(); ++i) {
2504      specCol.get(i, spec);
2505      flagCol.get(i, flag);
2506      convertArray(mask, flag);
2507      Vector<Float> specout;
2508      mathutil::replaceMaskByZero(specout, mask);
2509      conv.linearConv(specout, spec);
2510      specCol.put(i, specout);
2511    }
2512    ++iter;
2513  }
2514  return out;
2515}
2516
2517CountedPtr< Scantable >
2518  STMath::merge( const std::vector< CountedPtr < Scantable > >& in )
2519{
2520  if ( in.size() < 2 ) {
2521    throw(AipsError("Need at least two scantables to perform a merge."));
2522  }
2523  std::vector<CountedPtr < Scantable > >::const_iterator it = in.begin();
2524  bool insitu = insitu_;
2525  setInsitu(false);
2526  CountedPtr< Scantable > out = getScantable(*it, false);
2527  setInsitu(insitu);
2528  Table& tout = out->table();
2529  ScalarColumn<uInt> freqidcol(tout,"FREQ_ID"), molidcol(tout, "MOLECULE_ID");
2530  ScalarColumn<uInt> scannocol(tout,"SCANNO"), focusidcol(tout,"FOCUS_ID");
2531  // Renumber SCANNO to be 0-based
2532  Vector<uInt> scannos = scannocol.getColumn();
2533  uInt offset = min(scannos);
2534  scannos -= offset;
2535  scannocol.putColumn(scannos);
2536  uInt newscanno = max(scannos)+1;
2537  ++it;
2538  while ( it != in.end() ){
2539    if ( ! (*it)->conformant(*out) ) {
2540      // non conformant.
2541      LogIO os( LogOrigin( "STMath", "merge()", WHERE ) ) ;
2542      os << LogIO::SEVERE << "Can't merge scantables as header informations (any one of AntennaName, Equinox, and FluxUnit) differ." << LogIO::EXCEPTION ;
2543    }
2544    out->appendToHistoryTable((*it)->history());
2545    const Table& tab = (*it)->table();
2546
2547    Block<String> cols(3);
2548    cols[0] = String("FREQ_ID");
2549    cols[1] = String("MOLECULE_ID");
2550    cols[2] = String("FOCUS_ID");
2551
2552    TableIterator scanit(tab, "SCANNO");
2553    while (!scanit.pastEnd()) {
2554      ScalarColumn<uInt> thescannocol(scanit.table(),"SCANNO");
2555      Vector<uInt> thescannos(thescannocol.nrow(),newscanno);
2556      thescannocol.putColumn(thescannos);
2557      TableIterator subit(scanit.table(), cols);
2558      while ( !subit.pastEnd() ) {
2559        uInt nrow = tout.nrow();
2560        Table thetab = subit.table();
2561        ROTableRow row(thetab);
2562        Vector<uInt> thecolvals(thetab.nrow());
2563        ScalarColumn<uInt> thefreqidcol(thetab,"FREQ_ID");
2564        ScalarColumn<uInt> themolidcol(thetab, "MOLECULE_ID");
2565        ScalarColumn<uInt> thefocusidcol(thetab,"FOCUS_ID");
2566        // The selected subset of table should have
2567        // the equal FREQ_ID, MOLECULE_ID, and FOCUS_ID values.
2568        const TableRecord& rec = row.get(0);
2569        // Set the proper FREQ_ID
2570        Double rv,rp,inc;
2571        (*it)->frequencies().getEntry(rp, rv, inc, rec.asuInt("FREQ_ID"));
2572        uInt id;
2573        id = out->frequencies().addEntry(rp, rv, inc);
2574        thecolvals = id;
2575        thefreqidcol.putColumn(thecolvals);
2576        // Set the proper MOLECULE_ID
2577        Vector<String> name,fname;Vector<Double> rf;
2578        (*it)->molecules().getEntry(rf, name, fname, rec.asuInt("MOLECULE_ID"));
2579        id = out->molecules().addEntry(rf, name, fname);
2580        thecolvals = id;
2581        themolidcol.putColumn(thecolvals);
2582        // Set the proper FOCUS_ID
2583        Float fpa,frot,fax,ftan,fhand,fmount,fuser, fxy, fxyp;
2584        (*it)->focus().getEntry(fpa, fax, ftan, frot, fhand, fmount,fuser,
2585                                fxy, fxyp, rec.asuInt("FOCUS_ID"));
2586        id = out->focus().addEntry(fpa, fax, ftan, frot, fhand, fmount,fuser,
2587                                   fxy, fxyp);
2588        thecolvals = id;
2589        thefocusidcol.putColumn(thecolvals);
2590
2591        tout.addRow(thetab.nrow());
2592        TableCopy::copyRows(tout, thetab, nrow, 0, thetab.nrow());
2593
2594        ++subit;
2595      }
2596      ++newscanno;
2597      ++scanit;
2598    }
2599    ++it;
2600  }
2601  return out;
2602}
2603
2604CountedPtr< Scantable >
2605  STMath::invertPhase( const CountedPtr < Scantable >& in )
2606{
2607  return applyToPol(in, &STPol::invertPhase, Float(0.0));
2608}
2609
2610CountedPtr< Scantable >
2611  STMath::rotateXYPhase( const CountedPtr < Scantable >& in, float phase )
2612{
2613   return applyToPol(in, &STPol::rotatePhase, Float(phase));
2614}
2615
2616CountedPtr< Scantable >
2617  STMath::rotateLinPolPhase( const CountedPtr < Scantable >& in, float phase )
2618{
2619  return applyToPol(in, &STPol::rotateLinPolPhase, Float(phase));
2620}
2621
2622CountedPtr< Scantable > STMath::applyToPol( const CountedPtr<Scantable>& in,
2623                                             STPol::polOperation fptr,
2624                                             Float phase )
2625{
2626  CountedPtr< Scantable > out = getScantable(in, false);
2627  Table& tout = out->table();
2628  Block<String> cols(4);
2629  cols[0] = String("SCANNO");
2630  cols[1] = String("BEAMNO");
2631  cols[2] = String("IFNO");
2632  cols[3] = String("CYCLENO");
2633  TableIterator iter(tout, cols);
2634  CountedPtr<STPol> stpol = STPol::getPolClass(out->factories_,
2635                                               out->getPolType() );
2636  while (!iter.pastEnd()) {
2637    Table t = iter.table();
2638    ArrayColumn<Float> speccol(t, "SPECTRA");
2639    ScalarColumn<uInt> focidcol(t, "FOCUS_ID");
2640    Matrix<Float> pols(speccol.getColumn());
2641    try {
2642      stpol->setSpectra(pols);
2643      Float fang,fhand;
2644      fang = in->focusTable_.getTotalAngle(focidcol(0));
2645      fhand = in->focusTable_.getFeedHand(focidcol(0));
2646      stpol->setPhaseCorrections(fang, fhand);
2647      // use a member function pointer in STPol.  This only works on
2648      // the STPol pointer itself, not the Counted Pointer so
2649      // derefernce it.
2650      (&(*(stpol))->*fptr)(phase);
2651      speccol.putColumn(stpol->getSpectra());
2652    } catch (AipsError& e) {
2653      //delete stpol;stpol=0;
2654      throw(e);
2655    }
2656    ++iter;
2657  }
2658  //delete stpol;stpol=0;
2659  return out;
2660}
2661
2662CountedPtr< Scantable >
2663  STMath::swapPolarisations( const CountedPtr< Scantable > & in )
2664{
2665  CountedPtr< Scantable > out = getScantable(in, false);
2666  Table& tout = out->table();
2667  Table t0 = tout(tout.col("POLNO") == 0);
2668  Table t1 = tout(tout.col("POLNO") == 1);
2669  if ( t0.nrow() != t1.nrow() )
2670    throw(AipsError("Inconsistent number of polarisations"));
2671  ArrayColumn<Float> speccol0(t0, "SPECTRA");
2672  ArrayColumn<uChar> flagcol0(t0, "FLAGTRA");
2673  ArrayColumn<Float> speccol1(t1, "SPECTRA");
2674  ArrayColumn<uChar> flagcol1(t1, "FLAGTRA");
2675  Matrix<Float> s0 = speccol0.getColumn();
2676  Matrix<uChar> f0 = flagcol0.getColumn();
2677  speccol0.putColumn(speccol1.getColumn());
2678  flagcol0.putColumn(flagcol1.getColumn());
2679  speccol1.putColumn(s0);
2680  flagcol1.putColumn(f0);
2681  return out;
2682}
2683
2684CountedPtr< Scantable >
2685  STMath::averagePolarisations( const CountedPtr< Scantable > & in,
2686                                const std::vector<bool>& mask,
2687                                const std::string& weight )
2688{
2689  if (in->npol() < 2 )
2690    throw(AipsError("averagePolarisations can only be applied to two or more"
2691                    "polarisations"));
2692  bool insitu = insitu_;
2693  setInsitu(false);
2694  CountedPtr< Scantable > pols = getScantable(in, true);
2695  setInsitu(insitu);
2696  Table& tout = pols->table();
2697  std::string taql = "SELECT FROM $1 WHERE POLNO IN [0,1]";
2698  Table tab = tableCommand(taql, in->table());
2699  if (tab.nrow() == 0 )
2700    throw(AipsError("Could not find  any rows with POLNO==0 and POLNO==1"));
2701  TableCopy::copyRows(tout, tab);
2702  TableVector<uInt> vec(tout, "POLNO");
2703  vec = 0;
2704  pols->table_.rwKeywordSet().define("nPol", Int(1));
2705  pols->table_.rwKeywordSet().define("POLTYPE", String("stokes"));
2706  //pols->table_.rwKeywordSet().define("POLTYPE", in->getPolType());
2707  std::vector<CountedPtr<Scantable> > vpols;
2708  vpols.push_back(pols);
2709  CountedPtr< Scantable > out = average(vpols, mask, weight, "SCAN");
2710  return out;
2711}
2712
2713CountedPtr< Scantable >
2714  STMath::averageBeams( const CountedPtr< Scantable > & in,
2715                        const std::vector<bool>& mask,
2716                        const std::string& weight )
2717{
2718  bool insitu = insitu_;
2719  setInsitu(false);
2720  CountedPtr< Scantable > beams = getScantable(in, false);
2721  setInsitu(insitu);
2722  Table& tout = beams->table();
2723  // give all rows the same BEAMNO
2724  TableVector<uInt> vec(tout, "BEAMNO");
2725  vec = 0;
2726  beams->table_.rwKeywordSet().define("nBeam", Int(1));
2727  std::vector<CountedPtr<Scantable> > vbeams;
2728  vbeams.push_back(beams);
2729  CountedPtr< Scantable > out = average(vbeams, mask, weight, "SCAN");
2730  return out;
2731}
2732
2733
2734CountedPtr< Scantable >
2735  asap::STMath::frequencyAlign( const CountedPtr< Scantable > & in,
2736                                const std::string & refTime,
2737                                const std::string & method)
2738{
2739  LogIO os( casa::LogOrigin("STMath", "frequencyAlign()", WHERE));
2740  // clone as this is not working insitu
2741  bool insitu = insitu_;
2742  setInsitu(false);
2743  CountedPtr< Scantable > out = getScantable(in, false);
2744  setInsitu(insitu);
2745  Table& tout = out->table();
2746  // Get reference Epoch to time of first row or given String
2747  Unit DAY(String("d"));
2748  MEpoch::Ref epochRef(in->getTimeReference());
2749  MEpoch refEpoch;
2750  if (refTime.length()>0) {
2751    Quantum<Double> qt;
2752    if (MVTime::read(qt,refTime)) {
2753      MVEpoch mv(qt);
2754      refEpoch = MEpoch(mv, epochRef);
2755   } else {
2756      throw(AipsError("Invalid format for Epoch string"));
2757   }
2758  } else {
2759    refEpoch = in->timeCol_(0);
2760  }
2761  MPosition refPos = in->getAntennaPosition();
2762
2763  InterpolateArray1D<Double,Float>::InterpolationMethod interp = stringToIMethod(method);
2764  /*
2765  // Comment from MV.
2766  // the following code has been commented out because different FREQ_IDs have to be aligned together even
2767  // if the frame doesn't change. So far, lack of this check didn't cause any problems.
2768  // test if user frame is different to base frame
2769  if ( in->frequencies().getFrameString(true)
2770       == in->frequencies().getFrameString(false) ) {
2771    throw(AipsError("Can't convert as no output frame has been set"
2772                    " (use set_freqframe) or it is aligned already."));
2773  }
2774  */
2775  MFrequency::Types system = in->frequencies().getFrame();
2776  MVTime mvt(refEpoch.getValue());
2777  String epochout = mvt.string(MVTime::YMD) + String(" (") + refEpoch.getRefString() + String(")");
2778  os << "Aligned at reference Epoch " << epochout
2779     << " in frame " << MFrequency::showType(system) << LogIO::POST;
2780  // set up the iterator
2781  Block<String> cols(4);
2782  // select by constant direction
2783  cols[0] = String("SRCNAME");
2784  cols[1] = String("BEAMNO");
2785  // select by IF ( no of channels varies over this )
2786  cols[2] = String("IFNO");
2787  // select by restfrequency
2788  cols[3] = String("MOLECULE_ID");
2789  TableIterator iter(tout, cols);
2790  while ( !iter.pastEnd() ) {
2791    Table t = iter.table();
2792    MDirection::ROScalarColumn dirCol(t, "DIRECTION");
2793    TableIterator fiter(t, "FREQ_ID");
2794    // determine nchan from the first row. This should work as
2795    // we are iterating over BEAMNO and IFNO    // we should have constant direction
2796
2797    ROArrayColumn<Float> sCol(t, "SPECTRA");
2798    const MDirection direction = dirCol(0);
2799    const uInt nchan = sCol(0).nelements();
2800
2801    // skip operations if there is nothing to align
2802    if (fiter.pastEnd()) {
2803        continue;
2804    }
2805
2806    Table ftab = fiter.table();
2807    // align all frequency ids with respect to the first encountered id
2808    ScalarColumn<uInt> freqidCol(ftab, "FREQ_ID");
2809    // get the SpectralCoordinate for the freqid, which we are iterating over
2810    SpectralCoordinate sC = in->frequencies().getSpectralCoordinate(freqidCol(0));
2811    FrequencyAligner<Float> fa( sC, nchan, refEpoch,
2812                                direction, refPos, system );
2813    // realign the SpectralCoordinate and put into the output Scantable
2814    Vector<String> units(1);
2815    units = String("Hz");
2816    Bool linear=True;
2817    SpectralCoordinate sc2 = fa.alignedSpectralCoordinate(linear);
2818    sc2.setWorldAxisUnits(units);
2819    const uInt id = out->frequencies().addEntry(sc2.referencePixel()[0],
2820                                                sc2.referenceValue()[0],
2821                                                sc2.increment()[0]);
2822    while ( !fiter.pastEnd() ) {
2823      ftab = fiter.table();
2824      // spectral coordinate for the current FREQ_ID
2825      ScalarColumn<uInt> freqidCol2(ftab, "FREQ_ID");
2826      sC = in->frequencies().getSpectralCoordinate(freqidCol2(0));
2827      // create the "global" abcissa for alignment with same FREQ_ID
2828      Vector<Double> abc(nchan);
2829      for (uInt i=0; i<nchan; i++) {
2830           Double w;
2831           sC.toWorld(w,Double(i));
2832           abc[i] = w;
2833      }
2834      TableVector<uInt> tvec(ftab, "FREQ_ID");
2835      // assign new frequency id to all rows
2836      tvec = id;
2837      // cache abcissa for same time stamps, so iterate over those
2838      TableIterator timeiter(ftab, "TIME");
2839      while ( !timeiter.pastEnd() ) {
2840        Table tab = timeiter.table();
2841        ArrayColumn<Float> specCol(tab, "SPECTRA");
2842        ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
2843        MEpoch::ROScalarColumn timeCol(tab, "TIME");
2844        // use align abcissa cache after the first row
2845        // these rows should be just be POLNO
2846        bool first = true;
2847        for (int i=0; i<int(tab.nrow()); ++i) {
2848          // input values
2849          Vector<uChar> flag = flagCol(i);
2850          Vector<Bool> mask(flag.shape());
2851          Vector<Float> specOut, spec;
2852          spec  = specCol(i);
2853          Vector<Bool> maskOut;Vector<uChar> flagOut;
2854          convertArray(mask, flag);
2855          // alignment
2856          Bool ok = fa.align(specOut, maskOut, abc, spec,
2857                             mask, timeCol(i), !first,
2858                             interp, False);
2859          (void) ok; // unused stop compiler nagging
2860          // back into scantable
2861          flagOut.resize(maskOut.nelements());
2862          convertArray(flagOut, maskOut);
2863          flagCol.put(i, flagOut);
2864          specCol.put(i, specOut);
2865          // start abcissa caching
2866          first = false;
2867        }
2868        // next timestamp
2869        ++timeiter;
2870      }
2871      // next FREQ_ID
2872      ++fiter;
2873    }
2874    // next aligner
2875    ++iter;
2876  }
2877  // set this afterwards to ensure we are doing insitu correctly.
2878  out->frequencies().setFrame(system, true);
2879  return out;
2880}
2881
2882CountedPtr<Scantable>
2883  asap::STMath::convertPolarisation( const CountedPtr<Scantable>& in,
2884                                     const std::string & newtype )
2885{
2886  if (in->npol() != 2 && in->npol() != 4)
2887    throw(AipsError("Can only convert two or four polarisations."));
2888  if ( in->getPolType() == newtype )
2889    throw(AipsError("No need to convert."));
2890  if ( ! in->selector_.empty() )
2891    throw(AipsError("Can only convert whole scantable. Unset the selection."));
2892  bool insitu = insitu_;
2893  setInsitu(false);
2894  CountedPtr< Scantable > out = getScantable(in, true);
2895  setInsitu(insitu);
2896  Table& tout = out->table();
2897  tout.rwKeywordSet().define("POLTYPE", String(newtype));
2898
2899  Block<String> cols(4);
2900  cols[0] = "SCANNO";
2901  cols[1] = "CYCLENO";
2902  cols[2] = "BEAMNO";
2903  cols[3] = "IFNO";
2904  TableIterator it(in->originalTable_, cols);
2905  String basetype = in->getPolType();
2906  STPol* stpol = STPol::getPolClass(in->factories_, basetype);
2907  try {
2908    while ( !it.pastEnd() ) {
2909      Table tab = it.table();
2910      uInt row = tab.rowNumbers()[0];
2911      stpol->setSpectra(in->getPolMatrix(row));
2912      Float fang,fhand;
2913      fang = in->focusTable_.getTotalAngle(in->mfocusidCol_(row));
2914      fhand = in->focusTable_.getFeedHand(in->mfocusidCol_(row));
2915      stpol->setPhaseCorrections(fang, fhand);
2916      Int npolout = 0;
2917      for (uInt i=0; i<tab.nrow(); ++i) {
2918        Vector<Float> outvec = stpol->getSpectrum(i, newtype);
2919        if ( outvec.nelements() > 0 ) {
2920          tout.addRow();
2921          TableCopy::copyRows(tout, tab, tout.nrow()-1, 0, 1);
2922          ArrayColumn<Float> sCol(tout,"SPECTRA");
2923          ScalarColumn<uInt> pCol(tout,"POLNO");
2924          sCol.put(tout.nrow()-1 ,outvec);
2925          pCol.put(tout.nrow()-1 ,uInt(npolout));
2926          npolout++;
2927       }
2928      }
2929      tout.rwKeywordSet().define("nPol", npolout);
2930      ++it;
2931    }
2932  } catch (AipsError& e) {
2933    delete stpol;
2934    throw(e);
2935  }
2936  delete stpol;
2937  return out;
2938}
2939
2940CountedPtr< Scantable >
2941  asap::STMath::mxExtract( const CountedPtr< Scantable > & in,
2942                           const std::string & scantype )
2943{
2944  bool insitu = insitu_;
2945  setInsitu(false);
2946  CountedPtr< Scantable > out = getScantable(in, true);
2947  setInsitu(insitu);
2948  Table& tout = out->table();
2949  std::string taql = "SELECT FROM $1 WHERE BEAMNO != REFBEAMNO";
2950  if (scantype == "on") {
2951    taql = "SELECT FROM $1 WHERE BEAMNO == REFBEAMNO";
2952  }
2953  Table tab = tableCommand(taql, in->table());
2954  TableCopy::copyRows(tout, tab);
2955  if (scantype == "on") {
2956    // re-index SCANNO to 0
2957    TableVector<uInt> vec(tout, "SCANNO");
2958    vec = 0;
2959  }
2960  return out;
2961}
2962
2963std::vector<float>
2964  asap::STMath::fft( const casa::CountedPtr< Scantable > & in,
2965                     const std::vector<int>& whichrow,
2966                     bool getRealImag )
2967{
2968  std::vector<float> res;
2969  Table tab = in->table();
2970  std::vector<bool> mask;
2971
2972  if (whichrow.size() < 1) {          // for all rows (by default)
2973    int nrow = int(tab.nrow());
2974    for (int i = 0; i < nrow; ++i) {
2975      res = in->execFFT(i, mask, getRealImag);
2976    }
2977  } else {                           // for specified rows
2978    for (uInt i = 0; i < whichrow.size(); ++i) {
2979      res = in->execFFT(i, mask, getRealImag);
2980    }
2981  }
2982
2983  return res;
2984}
2985
2986
2987CountedPtr<Scantable>
2988  asap::STMath::lagFlag( const CountedPtr<Scantable>& in,
2989                         double start, double end,
2990                         const std::string& mode )
2991{
2992  CountedPtr<Scantable> out = getScantable(in, false);
2993  Table& tout = out->table();
2994  TableIterator iter(tout, "FREQ_ID");
2995  FFTServer<Float,Complex> ffts;
2996
2997  while ( !iter.pastEnd() ) {
2998    Table tab = iter.table();
2999    Double rp,rv,inc;
3000    ROTableRow row(tab);
3001    const TableRecord& rec = row.get(0);
3002    uInt freqid = rec.asuInt("FREQ_ID");
3003    out->frequencies().getEntry(rp, rv, inc, freqid);
3004    ArrayColumn<Float> specCol(tab, "SPECTRA");
3005    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
3006
3007    for (int i=0; i<int(tab.nrow()); ++i) {
3008      Vector<Float> spec = specCol(i);
3009      Vector<uChar> flag = flagCol(i);
3010      std::vector<bool> mask;
3011      for (uInt j = 0; j < flag.nelements(); ++j) {
3012        mask.push_back(!(flag[j]>0));
3013      }
3014      mathutil::doZeroOrderInterpolation(spec, mask);
3015
3016      Vector<Complex> lags;
3017      ffts.fft0(lags, spec);
3018
3019      Int lag0(start+0.5);
3020      Int lag1(end+0.5);
3021      if (mode == "frequency") {
3022        lag0 = Int(spec.nelements()*abs(inc)/(start)+0.5);
3023        lag1 = Int(spec.nelements()*abs(inc)/(end)+0.5);
3024      }
3025      Int lstart =  max(0, lag0);
3026      Int lend   =  min(Int(lags.nelements()-1), lag1);
3027      if (lstart == lend) {
3028        lags[lstart] = Complex(0.0);
3029      } else {
3030        if (lstart > lend) {
3031          Int tmp = lend;
3032          lend = lstart;
3033          lstart = tmp;
3034        }
3035        for (int j=lstart; j <=lend ;++j) {
3036          lags[j] = Complex(0.0);
3037        }
3038      }
3039
3040      ffts.fft0(spec, lags);
3041
3042      specCol.put(i, spec);
3043    }
3044    ++iter;
3045  }
3046  return out;
3047}
3048
3049// Averaging spectra with different channel/resolution
3050CountedPtr<Scantable>
3051STMath::new_average( const std::vector<CountedPtr<Scantable> >& in,
3052                     const bool& compel,
3053                     const std::vector<bool>& mask,
3054                     const std::string& weight,
3055                     const std::string& avmode )
3056  throw ( casa::AipsError )
3057{
3058  LogIO os( LogOrigin( "STMath", "new_average()", WHERE ) ) ;
3059  if ( avmode == "SCAN" && in.size() != 1 )
3060    throw(AipsError("Can't perform 'SCAN' averaging on multiple tables.\n"
3061                    "Use merge first."));
3062 
3063  CountedPtr<Scantable> out ;     // processed result
3064  if ( compel ) {
3065    std::vector< CountedPtr<Scantable> > newin ; // input for average process
3066    uInt insize = in.size() ;    // number of input scantables
3067
3068    // setup newin
3069    bool oldInsitu = insitu_ ;
3070    setInsitu( false ) ;
3071    newin.resize( insize ) ;
3072    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3073      newin[itable] = getScantable( in[itable], false ) ;
3074    }
3075    setInsitu( oldInsitu ) ;
3076
3077    // warning
3078    os << "Average spectra with different spectral resolution" << LogIO::POST ;
3079
3080    // temporarily set coordinfo
3081    vector<string> oldinfo( insize ) ;
3082    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3083      vector<string> coordinfo = in[itable]->getCoordInfo() ;
3084      oldinfo[itable] = coordinfo[0] ;
3085      coordinfo[0] = "Hz" ;
3086      newin[itable]->setCoordInfo( coordinfo ) ;
3087    }
3088
3089    ostringstream oss ;
3090
3091    // check IF frequency coverage
3092    // freqid: list of FREQ_ID, which is used, in each table 
3093    // iffreq: list of minimum and maximum frequency for each FREQ_ID in
3094    //         each table
3095    // freqid[insize][numIF]
3096    // freqid: [[id00, id01, ...],
3097    //          [id10, id11, ...],
3098    //          ...
3099    //          [idn0, idn1, ...]]
3100    // iffreq[insize][numIF*2]
3101    // iffreq: [[min_id00, max_id00, min_id01, max_id01, ...],
3102    //          [min_id10, max_id10, min_id11, max_id11, ...],
3103    //          ...
3104    //          [min_idn0, max_idn0, min_idn1, max_idn1, ...]]
3105    //os << "Check IF settings in each table" << LogIO::POST ;
3106    vector< vector<uInt> > freqid( insize );
3107    vector< vector<double> > iffreq( insize ) ;
3108    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3109      Vector<uInt> freqIds = newin[itable]->mfreqidCol_.getColumn() ;
3110      vector<uInt> uniqueFreqId = newin[itable]->getNumbers(newin[itable]->mfreqidCol_) ;
3111      for ( vector<uInt>::iterator i = uniqueFreqId.begin() ;
3112            i != uniqueFreqId.end() ; i++ ) {
3113        //os << "itable = " << itable << ": IF " << id << " is included in the list" << LogIO::POST ;
3114        uInt target = 0 ;
3115        while ( freqIds[target] != *i )
3116          target++ ;
3117        vector<double> abcissa = newin[itable]->getAbcissa( target ) ;
3118        freqid[itable].push_back( *i ) ;
3119        double incr = abs( abcissa[1] - abcissa[0] ) ;
3120        iffreq[itable].push_back( (*min_element(abcissa.begin(),abcissa.end()))-0.5*incr ) ;
3121        iffreq[itable].push_back( (*max_element(abcissa.begin(),abcissa.end()))+0.5*incr ) ;
3122      }
3123    }
3124
3125    // debug
3126//     os << "IF settings summary:" << endl ;
3127//     for ( uInt i = 0 ; i < freqid.size() ; i++ ) {
3128//       os << "   Table" << i << endl ;
3129//       for ( uInt j = 0 ; j < freqid[i].size() ; j++ ) {
3130//         os << "      id = " << freqid[i][j] << " (min,max) = (" << iffreq[i][2*j] << "," << iffreq[i][2*j+1] << ")" << endl ;
3131//       }
3132//     }
3133//     os << endl ;
3134//     os.post() ;
3135
3136    // IF grouping based on their frequency coverage
3137    // ifgrp: number of member in each IF group
3138    // ifgrp[numgrp]
3139    // ifgrp: [n0, n1, ...]
3140    //os << "IF grouping based on their frequency coverage" << LogIO::POST ;
3141
3142    // parameter for IF grouping
3143    // groupmode = OR    retrieve all region
3144    //             AND   only retrieve overlaped region
3145    //string groupmode = "AND" ;
3146    string groupmode = "OR" ;
3147    uInt sizecr = 0 ;
3148    if ( groupmode == "AND" )
3149      sizecr = 1 ;
3150    else if ( groupmode == "OR" )
3151      sizecr = 0 ;
3152
3153    vector<double> sortedfreq ;
3154    for ( uInt i = 0 ; i < iffreq.size() ; i++ ) {
3155      for ( uInt j = 0 ; j < iffreq[i].size() ; j++ ) {
3156        if ( count( sortedfreq.begin(), sortedfreq.end(), iffreq[i][j] ) == 0 )
3157          sortedfreq.push_back( iffreq[i][j] ) ;
3158      }
3159    }
3160    sort( sortedfreq.begin(), sortedfreq.end() ) ;
3161    vector<uInt> ifgrp( sortedfreq.size()-1, 0 ) ;
3162    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3163      for ( uInt iif = 0 ; iif < freqid[itable].size() ; iif++ ) {
3164        double range0 = iffreq[itable][2*iif] ;
3165        double range1 = iffreq[itable][2*iif+1] ;
3166        for ( uInt j = 0 ; j < sortedfreq.size()-1 ; j++ ) {
3167          double fmin = max( range0, sortedfreq[j] ) ;
3168          double fmax = min( range1, sortedfreq[j+1] ) ;
3169          if ( fmin < fmax ) {
3170            ifgrp[j]++ ;
3171          }
3172        }
3173      }
3174    }
3175
3176    // Grouping continuous IF groups (without frequency gap)
3177    // freqgrp: list of IF group indexes in each frequency group
3178    // freqgrp[numgrp][nummember]
3179    // freqgrp: [[ifgrp00, ifgrp01, ifgrp02, ...],
3180    //           [ifgrp10, ifgrp11, ifgrp12, ...],
3181    //           ...
3182    //           [ifgrpn0, ifgrpn1, ifgrpn2, ...]]
3183    // grprange[2*numgrp]
3184    // grprange: [fmin0,fmax0,fmin1,fmax1,...]
3185    vector< vector<uInt> > freqgrp ;
3186    vector<double> grprange ;
3187    vector<uInt> grpedge ;
3188    for ( uInt igrp = 0 ; igrp < ifgrp.size() ; igrp++ ) {
3189      if ( ifgrp[igrp] <= sizecr ) {
3190        grpedge.push_back( igrp ) ;
3191      }
3192    }
3193    grpedge.push_back( ifgrp.size() ) ;
3194    uInt itmp = 0 ;
3195    for ( uInt i = 0 ; i < grpedge.size() ; i++ ) {
3196      int n = grpedge[i] - itmp ;
3197      if ( n > 0 ) {
3198        vector<uInt> members( n ) ;
3199        for ( int j = 0 ; j < n ; j++ ) {
3200          members[j] = itmp+j ;
3201        }
3202        freqgrp.push_back( members ) ;
3203        grprange.push_back( sortedfreq[itmp] ) ;
3204        grprange.push_back( sortedfreq[grpedge[i]] ) ;
3205      }
3206      itmp += n + 1 ;
3207    }
3208
3209    // print frequency group
3210    oss.str("") ;
3211    oss << "Frequency Group summary: " << endl ;
3212    oss << "   GROUP_ID: [FREQ_MIN, FREQ_MAX]" << endl ;
3213    for ( uInt i = 0 ; i < freqgrp.size() ; i++ ) {
3214      oss << "   GROUP " << setw( 2 ) << i << ": [" << grprange[2*i] << "," << grprange[2*i+1] << "]" ;
3215      oss << endl ;
3216    }
3217    oss << endl ;
3218    os << oss.str() << LogIO::POST ;
3219
3220    // groups: list of frequency group index whose frequency range overlaps
3221    //         with that of each table and IF
3222    // groups[numtable][numIF]
3223    // groups: [[grpx, grpy,...],
3224    //          [grpa, grpb,...],
3225    //          ...
3226    //          [grpk, grpm,...]]
3227    vector< vector<uInt> > groups( insize ) ;
3228    for ( uInt i = 0 ; i < insize ; i++ ) {
3229      groups[i].resize( freqid[i].size() ) ;
3230    }
3231    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3232      for ( uInt ifreq = 0 ; ifreq < freqid[itable].size() ; ifreq++ ) {
3233        double minf = iffreq[itable][2*ifreq] ;
3234        uInt groupid ;
3235        for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3236          vector<uInt> memberlist = freqgrp[igrp] ;
3237          if ( (minf >= grprange[2*igrp]) && (minf <= grprange[2*igrp+1]) ) {
3238            groupid = igrp ;
3239            break ;
3240          }
3241        }
3242        groups[itable][ifreq] = groupid ;
3243      }
3244    }
3245                                                         
3246
3247    // print membership
3248    oss.str("") ;
3249    for ( uInt i = 0 ; i < insize ; i++ ) {
3250      oss << "Table " << i << endl ;
3251      for ( uInt j = 0 ; j < groups[i].size() ; j++ ) {
3252        oss << "   FREQ_ID " <<  setw( 2 ) << freqid[i][j] << ": " ;
3253        oss << setw( 2 ) << groups[i][j] ;
3254        oss << endl ;
3255      }
3256    }
3257    os << oss.str() << LogIO::POST ;
3258
3259    // reset SCANNO and IFNO/FREQ_ID: IF is reset by the result of sortation
3260    //os << "All IF number is set to IF group index" << LogIO::POST ;
3261    // reset SCANNO only when avmode != "SCAN"
3262    if ( avmode != "SCAN" ) {
3263      os << "All scan number is set to 0" << LogIO::POST ;
3264      for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3265        uInt nrow = newin[itable]->nrow() ;
3266        Vector<uInt> resetScan( nrow, 0 ) ;
3267        newin[itable]->scanCol_.putColumn( resetScan ) ;
3268      }
3269    }
3270
3271    // reset spectra and flagtra: align spectral resolution
3272    //os << "Align spectral resolution" << LogIO::POST ;
3273    // gmaxdnu: the coarsest frequency resolution in the frequency group
3274    // gminfreq: lower frequency edge of the frequency group
3275    // gnchan: number of channels for the frequency group
3276    vector<double> gmaxdnu( freqgrp.size(), 0.0 ) ;
3277    vector<double> gminfreq( freqgrp.size() ) ;
3278    vector<double> gnchan( freqgrp.size() ) ;
3279    for ( uInt i = 0 ; i < insize ; i++ ) {
3280      vector<uInt> members = groups[i] ;
3281      for ( uInt j = 0 ; j < members.size() ; j++ ) {
3282        uInt groupid = members[j] ;
3283        Double rp,rv,ic ;
3284        newin[i]->frequencies().getEntry( rp, rv, ic, j ) ;
3285        if ( abs(ic) > abs(gmaxdnu[groupid]) )
3286          gmaxdnu[groupid] = ic ;
3287      }
3288    }
3289    for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3290      gminfreq[igrp] = grprange[2*igrp] ;
3291      double maxfreq = grprange[2*igrp+1] ;
3292      gnchan[igrp] = (int)(abs((maxfreq-gminfreq[igrp])/gmaxdnu[igrp])+0.9) ;
3293    }
3294     
3295    // regrid spectral data and update frequency info
3296    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3297      Vector<uInt> oldFreqId = newin[itable]->mfreqidCol_.getColumn() ;
3298      Vector<uInt> newFreqId( oldFreqId.nelements() ) ;
3299
3300      // update MAIN
3301      for ( uInt irow = 0 ; irow < newin[itable]->nrow() ; irow++ ) {
3302        uInt groupid = groups[itable][oldFreqId[irow]] ;
3303        newFreqId[irow] = groupid ;
3304        newin[itable]->regridChannel( gnchan[groupid],
3305                                      gmaxdnu[groupid],
3306                                      gminfreq[groupid],
3307                                      irow ) ;
3308      }
3309      newin[itable]->mfreqidCol_.putColumn( newFreqId ) ;
3310      newin[itable]->ifCol_.putColumn( newFreqId ) ;
3311
3312      // update FREQUENCIES
3313      Table tab = newin[itable]->frequencies().table() ;
3314      ScalarColumn<uInt> fIdCol( tab, "ID" ) ;
3315      ScalarColumn<Double> fRefPixCol( tab, "REFPIX" ) ;
3316      ScalarColumn<Double> fRefValCol( tab, "REFVAL" ) ;
3317      ScalarColumn<Double> fIncrCol( tab, "INCREMENT" ) ;
3318      if ( freqgrp.size() > tab.nrow() ) {
3319        tab.addRow( freqgrp.size()-tab.nrow() ) ;
3320      }
3321      for ( uInt irow = 0 ; irow < freqgrp.size() ; irow++ ) {
3322        Double refval = gminfreq[irow] + 0.5 * abs(gmaxdnu[irow]) ;
3323        Double refpix = (gmaxdnu[irow] > 0.0) ? 0 : gnchan[irow]-1 ;
3324        Double increment = gmaxdnu[irow] ;
3325        fIdCol.put( irow, irow ) ;
3326        fRefPixCol.put( irow, refpix ) ;
3327        fRefValCol.put( irow, refval ) ;
3328        fIncrCol.put( irow, increment ) ;
3329      }
3330    }
3331
3332    // set back coordinfo
3333    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3334      vector<string> coordinfo = newin[itable]->getCoordInfo() ;
3335      coordinfo[0] = oldinfo[itable] ;
3336      newin[itable]->setCoordInfo( coordinfo ) ;
3337    }
3338
3339    // average
3340    out = average( newin, mask, weight, avmode ) ;
3341  }
3342  else {
3343    // simple average
3344    out =  average( in, mask, weight, avmode ) ;
3345  }
3346 
3347  return out;
3348}
3349
3350CountedPtr<Scantable> STMath::cwcal( const CountedPtr<Scantable>& s,
3351                                     const String calmode,
3352                                     const String antname )
3353{
3354  // frequency switch
3355  if ( calmode == "fs" ) {
3356    return cwcalfs( s, antname ) ;
3357  }
3358  else {
3359    vector<bool> masks = s->getMask( 0 ) ;
3360    vector<int> types ;
3361
3362    // save original table selection
3363    Table torg  = s->table_ ;
3364
3365    // sky scan
3366    bool insitu = insitu_ ;
3367    insitu_ = false ;
3368    // share calibration scans before average with out
3369    CountedPtr<Scantable> out = getScantable( s, true ) ;
3370    insitu_ = insitu ;
3371    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::SKY ) ;
3372    out->attach() ;
3373    CountedPtr<Scantable> asky = averageWithinSession( out,
3374                                                       masks,
3375                                                       "TINT" ) ;
3376    // hot scan
3377    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::HOT ) ;
3378    out->attach() ;
3379    CountedPtr<Scantable> ahot = averageWithinSession( out,
3380                                                       masks,
3381                                                       "TINT" ) ;
3382    // cold scan
3383    CountedPtr<Scantable> acold ;
3384//     out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::COLD ) ;
3385//     out->attach() ;
3386//     CountedPtr<Scantable> acold = averageWithinSession( out,
3387//                                                         masks,
3388//                                                         "TINT" ) ;
3389
3390    // off scan
3391    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::PSOFF ) ;
3392    out->attach() ;
3393    CountedPtr<Scantable> aoff = averageWithinSession( out,
3394                                                       masks,
3395                                                       "TINT" ) ;
3396   
3397    // on scan
3398    s->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::PSON ) ;
3399    s->attach() ;
3400    out->table_ = out->originalTable_ ;
3401    out->attach() ;
3402    out->table().addRow( s->nrow() ) ;
3403    copyRows( out->table(), s->table(), 0, 0, s->nrow(), False, True, False ) ;
3404   
3405    // process each on scan
3406    STSelector sel ;
3407    vector<string> cols( 3 ) ;
3408    cols[0] = "BEAMNO" ;
3409    cols[1] = "POLNO" ;
3410    cols[2] = "IFNO" ;
3411    STIdxIter *iter = new STIdxIterAcc( out, cols ) ;
3412    while ( !iter->pastEnd() ) {
3413      Vector<uInt> ids = iter->current() ;
3414      stringstream ss ;
3415      ss << "SELECT FROM $1 WHERE "
3416         << "BEAMNO==" << ids[0] << "&&"
3417         << "POLNO==" << ids[1] << "&&"
3418         << "IFNO==" << ids[2] ;
3419      //cout << "TaQL string: " << ss.str() << endl ;
3420      sel.setTaQL( ss.str() ) ;
3421      aoff->setSelection( sel ) ;
3422      ahot->setSelection( sel ) ;
3423      asky->setSelection( sel ) ;
3424      Vector<uInt> rows = iter->getRows( SHARE ) ;
3425      // out should be an exact copy of s except that SPECTRA column is empty
3426      calibrateCW( out, s, aoff, asky, ahot, acold, rows, antname ) ;
3427      aoff->unsetSelection() ;
3428      ahot->unsetSelection() ;
3429      asky->unsetSelection() ;
3430      sel.reset() ;
3431      iter->next() ;
3432    }
3433    delete iter ;
3434    s->table_ = torg ;
3435    s->attach() ;
3436
3437    // flux unit
3438    out->setFluxUnit( "K" ) ;
3439
3440    return out ;
3441  }
3442}
3443 
3444CountedPtr<Scantable> STMath::almacal( const CountedPtr<Scantable>& s,
3445                                       const String calmode )
3446{
3447  // frequency switch
3448  if ( calmode == "fs" ) {
3449    return almacalfs( s ) ;
3450  }
3451  else {
3452//     double t0, t1 ;
3453//     t0 = mathutil::gettimeofday_sec() ;
3454    vector<bool> masks = s->getMask( 0 ) ;
3455
3456    // save original table selection
3457    Table torg = s->table_ ;
3458
3459    // off scan
3460    // TODO 2010/01/08 TN
3461    // Grouping by time should be needed before averaging.
3462    // Each group must have own unique SCANNO (should be renumbered).
3463    // See PIPELINE/SDCalibration.py
3464    bool insitu = insitu_ ;
3465    insitu_ = false ;
3466    // share off scan before average with out
3467    CountedPtr<Scantable> out = getScantable( s, true ) ;
3468    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::PSOFF ) ;
3469    out->attach() ;
3470    insitu_ = insitu ;
3471    CountedPtr<Scantable> aoff = averageWithinSession( out,
3472                                                       masks,
3473                                                       "TINT" ) ;
3474
3475    // on scan
3476//     t0 = mathutil::gettimeofday_sec() ;
3477    s->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::PSON ) ;
3478    s->attach() ;
3479    out->table_ = out->originalTable_ ;
3480    out->attach() ;
3481    out->table().addRow( s->nrow() ) ;
3482    copyRows( out->table(), s->table(), 0, 0, s->nrow(), False ) ;
3483//     t1 = mathutil::gettimeofday_sec() ;
3484//     cout << "elapsed time for preparing output table: " << t1-t0 << " sec" << endl ;
3485
3486    // process each on scan
3487//     t0 = mathutil::gettimeofday_sec() ;
3488
3489    // using STIdxIterAcc
3490    vector<string> cols( 3 ) ;
3491    cols[0] = "BEAMNO" ;
3492    cols[1] = "POLNO" ;
3493    cols[2] = "IFNO" ;
3494    STIdxIter *iter = new STIdxIterAcc( out, cols ) ;
3495    STSelector sel ;
3496    while ( !iter->pastEnd() ) {
3497      Vector<uInt> ids = iter->current() ;
3498      stringstream ss ;
3499      ss << "SELECT FROM $1 WHERE "
3500         << "BEAMNO==" << ids[0] << "&&"
3501         << "POLNO==" << ids[1] << "&&"
3502         << "IFNO==" << ids[2] ;
3503      //cout << "TaQL string: " << ss.str() << endl ;
3504      sel.setTaQL( ss.str() ) ;
3505      aoff->setSelection( sel ) ;
3506      Vector<uInt> rows = iter->getRows( SHARE ) ;
3507      // out should be an exact copy of s except that SPECTRA column is empty
3508      calibrateALMA( out, s, aoff, rows ) ;
3509      aoff->unsetSelection() ;
3510      sel.reset() ;
3511      iter->next() ;
3512    }
3513    delete iter ;
3514    s->table_ = torg ;
3515    s->attach() ;
3516
3517//     t1 = mathutil::gettimeofday_sec() ;
3518//     cout << "elapsed time for calibration: " << t1-t0 << " sec" << endl ;
3519
3520    // flux unit
3521    out->setFluxUnit( "K" ) ;
3522
3523    return out ;
3524  }
3525}
3526
3527CountedPtr<Scantable> STMath::cwcalfs( const CountedPtr<Scantable>& s,
3528                                       const String antname )
3529{
3530  vector<int> types ;
3531
3532  // APEX calibration mode
3533  int apexcalmode = 1 ;
3534 
3535  if ( antname.find( "APEX" ) != string::npos ) {
3536    // check if off scan exists or not
3537    STSelector sel = STSelector() ;
3538    //sel.setName( offstr1 ) ;
3539    types.push_back( SrcType::FLOOFF ) ;
3540    sel.setTypes( types ) ;
3541    try {
3542      s->setSelection( sel ) ;
3543    }
3544    catch ( AipsError &e ) {
3545      apexcalmode = 0 ;
3546    }
3547    sel.reset() ;
3548  }
3549  s->unsetSelection() ;
3550  types.clear() ;
3551
3552  vector<bool> masks = s->getMask( 0 ) ;
3553  CountedPtr<Scantable> ssig, sref ;
3554  //CountedPtr<Scantable> out ;
3555  bool insitu = insitu_ ;
3556  insitu_ = False ;
3557  CountedPtr<Scantable> out = getScantable( s, true ) ;
3558  insitu_ = insitu ;
3559
3560  if ( antname.find( "APEX" ) != string::npos ) {
3561    // APEX calibration
3562    // sky scan
3563    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FLOSKY ) ;
3564    out->attach() ;
3565    CountedPtr<Scantable> askylo = averageWithinSession( out,
3566                                                         masks,
3567                                                         "TINT" ) ;
3568    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FHISKY ) ;
3569    out->attach() ;
3570    CountedPtr<Scantable> askyhi = averageWithinSession( out,
3571                                                         masks,
3572                                                         "TINT" ) ;
3573   
3574    // hot scan
3575    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FLOHOT ) ;
3576    out->attach() ;
3577    CountedPtr<Scantable> ahotlo = averageWithinSession( out,
3578                                                         masks,
3579                                                         "TINT" ) ;
3580    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FHIHOT ) ;
3581    out->attach() ;
3582    CountedPtr<Scantable> ahothi = averageWithinSession( out,
3583                                                         masks,
3584                                                         "TINT" ) ;
3585   
3586    // cold scan
3587    CountedPtr<Scantable> acoldlo, acoldhi ;
3588//     out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FLOCOLD ) ;
3589//     out->attach() ;
3590//     CountedPtr<Scantable> acoldlo = averageWithinSession( out,
3591//                                                           masks,
3592//                                                           "TINT" ) ;
3593//     out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FHICOLD ) ;
3594//     out->attach() ;
3595//     CountedPtr<Scantable> acoldhi = averageWithinSession( out,
3596//                                                           masks,
3597//                                                           "TINT" ) ;
3598
3599    // ref scan
3600    insitu_ = false ;
3601    sref = getScantable( s, true ) ;
3602    CountedPtr<Scantable> rref = getScantable( s, true ) ;
3603    insitu_ = insitu ;
3604    rref->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FSLO ) ;
3605    rref->attach() ;
3606    copyRows( sref->table_, rref->table_, 0, 0, rref->nrow(), False, True, False ) ;
3607   
3608    // sig scan
3609    insitu_ = false ;
3610    ssig = getScantable( s, true ) ;
3611    CountedPtr<Scantable> rsig = getScantable( s, true ) ;
3612    insitu_ = insitu ;
3613    rsig->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FSHI ) ;
3614    rsig->attach() ;
3615    copyRows( ssig->table_, rsig->table_, 0, 0, rsig->nrow(), False, True, False ) ;
3616         
3617    if ( apexcalmode == 0 ) {
3618      // using STIdxIterAcc
3619      vector<string> cols( 3 ) ;
3620      cols[0] = "BEAMNO" ;
3621      cols[1] = "POLNO" ;
3622      cols[2] = "IFNO" ;
3623      STIdxIter *iter = new STIdxIterAcc( ssig, cols ) ;
3624      STSelector sel ;
3625      vector< CountedPtr<Scantable> > on( 2 ) ;
3626      on[0] = rsig ;
3627      on[1] = rref ;
3628      vector< CountedPtr<Scantable> > sky( 2 ) ;
3629      sky[0] = askylo ;
3630      sky[1] = askyhi ;
3631      vector< CountedPtr<Scantable> > hot( 2 ) ;
3632      hot[0] = ahotlo ;
3633      hot[1] = ahothi ;
3634      vector< CountedPtr<Scantable> > cold( 2 ) ;
3635      while ( !iter->pastEnd() ) {
3636        Vector<uInt> ids = iter->current() ;
3637        stringstream ss ;
3638        ss << "SELECT FROM $1 WHERE "
3639           << "BEAMNO==" << ids[0] << "&&"
3640           << "POLNO==" << ids[1] << "&&"
3641           << "IFNO==" << ids[2] ;
3642        //cout << "TaQL string: " << ss.str() << endl ;
3643        sel.setTaQL( ss.str() ) ;
3644        sky[0]->setSelection( sel ) ;
3645        sky[1]->setSelection( sel ) ;
3646        hot[0]->setSelection( sel ) ;
3647        hot[1]->setSelection( sel ) ;
3648        Vector<uInt> rows = iter->getRows( SHARE ) ;
3649        calibrateAPEXFS( ssig, sref, on, sky, hot, cold, rows ) ;
3650        sky[0]->unsetSelection() ;
3651        sky[1]->unsetSelection() ;
3652        hot[0]->unsetSelection() ;
3653        hot[1]->unsetSelection() ;
3654        sel.reset() ;
3655        iter->next() ;
3656      }
3657      delete iter ;
3658
3659    }
3660    else if ( apexcalmode == 1 ) {
3661      // APEX fs data with off scan
3662      // off scan
3663      out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FLOOFF ) ;
3664      out->attach() ;
3665      CountedPtr<Scantable> aofflo = averageWithinSession( out,
3666                                                           masks,
3667                                                           "TINT" ) ;
3668      out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FHIOFF ) ;
3669      out->attach() ;
3670      CountedPtr<Scantable> aoffhi = averageWithinSession( out,
3671                                                           masks,
3672                                                           "TINT" ) ;
3673     
3674      // process each sig and ref scan
3675//       STSelector sel ;
3676      vector<string> cols( 3 ) ;
3677      cols[0] = "BEAMNO" ;
3678      cols[1] = "POLNO" ;
3679      cols[2] = "IFNO" ;
3680      STIdxIter *iter = new STIdxIterAcc( ssig, cols ) ;
3681      STSelector sel ;
3682      while ( !iter->pastEnd() ) {
3683        Vector<uInt> ids = iter->current() ;
3684        stringstream ss ;
3685        ss << "SELECT FROM $1 WHERE "
3686           << "BEAMNO==" << ids[0] << "&&"
3687           << "POLNO==" << ids[1] << "&&"
3688           << "IFNO==" << ids[2] ;
3689        //cout << "TaQL string: " << ss.str() << endl ;
3690        sel.setTaQL( ss.str() ) ;
3691        aofflo->setSelection( sel ) ;
3692        ahotlo->setSelection( sel ) ;
3693        askylo->setSelection( sel ) ;
3694        Vector<uInt> rows = iter->getRows( SHARE ) ;
3695        calibrateCW( ssig, rsig, aofflo, askylo, ahotlo, acoldlo, rows, antname ) ;
3696        aofflo->unsetSelection() ;
3697        ahotlo->unsetSelection() ;
3698        askylo->unsetSelection() ;
3699        sel.reset() ;
3700        iter->next() ;
3701      }
3702      delete iter ;
3703      iter = new STIdxIterAcc( sref, cols ) ;
3704      while ( !iter->pastEnd() ) {
3705        Vector<uInt> ids = iter->current() ;
3706        stringstream ss ;
3707        ss << "SELECT FROM $1 WHERE "
3708           << "BEAMNO==" << ids[0] << "&&"
3709           << "POLNO==" << ids[1] << "&&"
3710           << "IFNO==" << ids[2] ;
3711        //cout << "TaQL string: " << ss.str() << endl ;
3712        sel.setTaQL( ss.str() ) ;
3713        aoffhi->setSelection( sel ) ;
3714        ahothi->setSelection( sel ) ;
3715        askyhi->setSelection( sel ) ;
3716        Vector<uInt> rows = iter->getRows( SHARE ) ;
3717        calibrateCW( sref, rref, aoffhi, askyhi, ahothi, acoldhi, rows, antname ) ;
3718        aoffhi->unsetSelection() ;
3719        ahothi->unsetSelection() ;
3720        askyhi->unsetSelection() ;
3721        sel.reset() ;
3722        iter->next() ;
3723      }
3724      delete iter ;
3725    }
3726  }
3727  else {
3728    // non-APEX fs data
3729    // sky scan
3730    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::SKY ) ;
3731    out->attach() ;
3732    CountedPtr<Scantable> asky = averageWithinSession( out,
3733                                                       masks,
3734                                                       "TINT" ) ;
3735    STSelector sel = STSelector() ;
3736
3737    // hot scan
3738    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::HOT ) ;
3739    out->attach() ;
3740    CountedPtr<Scantable> ahot = averageWithinSession( out,
3741                                                       masks,
3742                                                       "TINT" ) ;
3743
3744    // cold scan
3745    CountedPtr<Scantable> acold ;
3746//     out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::COLD ) ;
3747//     out->attach() ;
3748//     CountedPtr<Scantable> acold = averageWithinSession( out,
3749//                                                         masks,
3750//                                                         "TINT" ) ;
3751   
3752    // ref scan
3753    bool insitu = insitu_ ;
3754    insitu_ = false ;
3755    sref = getScantable( s, true ) ;
3756    CountedPtr<Scantable> rref = getScantable( s, true ) ;
3757    insitu_ = insitu ;
3758    rref->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::PSOFF ) ;
3759    rref->attach() ;
3760    copyRows( sref->table_, rref->table_, 0, 0, rref->nrow(), False, True, False ) ;
3761   
3762    // sig scan
3763    insitu_ = false ;
3764    ssig = getScantable( s, true ) ;
3765    CountedPtr<Scantable> rsig = getScantable( s, true ) ;
3766    insitu_ = insitu ;
3767    rsig->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::PSON ) ;
3768    rsig->attach() ;
3769    copyRows( ssig->table_, rsig->table_, 0, 0, rsig->nrow(), False, True, False ) ;
3770
3771    // process each sig and ref scan
3772    vector<string> cols( 3 ) ;
3773    cols[0] = "BEAMNO" ;
3774    cols[1] = "POLNO" ;
3775    cols[2] = "IFNO" ;
3776    STIdxIter *iter = new STIdxIterAcc( ssig, cols ) ;
3777    while ( !iter->pastEnd() ) {
3778      Vector<uInt> ids = iter->current() ;
3779      stringstream ss ;
3780      ss << "SELECT FROM $1 WHERE "
3781         << "BEAMNO==" << ids[0] << "&&"
3782         << "POLNO==" << ids[1] << "&&"
3783         << "IFNO==" << ids[2] ;
3784      //cout << "TaQL string: " << ss.str() << endl ;
3785      sel.setTaQL( ss.str() ) ;
3786      ahot->setSelection( sel ) ;
3787      asky->setSelection( sel ) ;
3788      Vector<uInt> rows = iter->getRows( SHARE ) ;
3789      // out should be an exact copy of s except that SPECTRA column is empty
3790      calibrateFS( ssig, sref, rsig, rref, asky, ahot, acold, rows ) ;
3791      ahot->unsetSelection() ;
3792      asky->unsetSelection() ;
3793      sel.reset() ;
3794      iter->next() ;
3795    }
3796    delete iter ;
3797  }
3798
3799  // do folding if necessary
3800  Table sigtab = ssig->table() ;
3801  Table reftab = sref->table() ;
3802  ScalarColumn<uInt> reffidCol ;
3803  Int nchan = (Int)ssig->nchan() ;
3804  reffidCol.attach( reftab, "FREQ_ID" ) ;
3805  Vector<uInt> sfids = ssig->mfreqidCol_.getColumn() ;
3806  Vector<uInt> rfids = sref->mfreqidCol_.getColumn() ;
3807  vector<uInt> sfids_unique ;
3808  vector<uInt> rfids_unique ;
3809  vector<uInt> sifno_unique ;
3810  vector<uInt> rifno_unique ;
3811  for ( uInt i = 0 ; i < sfids.nelements() ; i++ ) {
3812    if ( count( sfids_unique.begin(), sfids_unique.end(), sfids[i] ) == 0 ) {
3813      sfids_unique.push_back( sfids[i] ) ;
3814      sifno_unique.push_back( ssig->getIF( i ) ) ;
3815    }
3816    if ( count( rfids_unique.begin(), rfids_unique.end(),  rfids[i] ) == 0 ) {
3817      rfids_unique.push_back( rfids[i] ) ;
3818      rifno_unique.push_back( sref->getIF( i ) ) ;
3819    }
3820  }
3821  double refpix_sig, refval_sig, increment_sig ;
3822  double refpix_ref, refval_ref, increment_ref ;
3823  vector< CountedPtr<Scantable> > tmp( sfids_unique.size() ) ;
3824  for ( uInt i = 0 ; i < sfids_unique.size() ; i++ ) {
3825    ssig->frequencies().getEntry( refpix_sig, refval_sig, increment_sig, sfids_unique[i] ) ;
3826    sref->frequencies().getEntry( refpix_ref, refval_ref, increment_ref, rfids_unique[i] ) ;
3827    if ( refpix_sig == refpix_ref ) {
3828      double foffset = refval_ref - refval_sig ;
3829      int choffset = static_cast<int>(foffset/increment_sig) ;
3830      double doffset = foffset / increment_sig ;
3831      if ( abs(choffset) >= nchan ) {
3832        LogIO os( LogOrigin( "STMath", "cwcalfs", WHERE ) ) ;
3833        os << "FREQ_ID=[" << sfids_unique[i] << "," << rfids_unique[i] << "]: out-band frequency switching, no folding" << LogIO::POST ;
3834        os << "Just return signal data" << LogIO::POST ;
3835        //std::vector< CountedPtr<Scantable> > tabs ;
3836        //tabs.push_back( ssig ) ;
3837        //tabs.push_back( sref ) ;
3838        //out = merge( tabs ) ;
3839        tmp[i] = ssig ;
3840      }
3841      else {
3842        STSelector sel = STSelector() ;
3843        vector<int> v( 1, sifno_unique[i] ) ;
3844        sel.setIFs( v ) ;
3845        ssig->setSelection( sel ) ;
3846        sel.reset() ;
3847        v[0] = rifno_unique[i] ;
3848        sel.setIFs( v ) ;
3849        sref->setSelection( sel ) ;
3850        sel.reset() ;
3851        if ( antname.find( "APEX" ) != string::npos ) {
3852          tmp[i] = dofold( ssig, sref, 0.5*doffset, -0.5*doffset ) ;
3853          //tmp[i] = dofold( ssig, sref, doffset ) ;
3854        }
3855        else {
3856          tmp[i] = dofold( ssig, sref, doffset ) ;
3857        }
3858        ssig->unsetSelection() ;
3859        sref->unsetSelection() ;
3860      }
3861    }
3862  }
3863
3864  if ( tmp.size() > 1 ) {
3865    out = merge( tmp ) ;
3866  }
3867  else {
3868    out = tmp[0] ;
3869  }
3870
3871  // flux unit
3872  out->setFluxUnit( "K" ) ;
3873
3874  return out ;
3875}
3876
3877CountedPtr<Scantable> STMath::almacalfs( const CountedPtr<Scantable>& s )
3878{
3879  (void) s; //currently unused
3880  CountedPtr<Scantable> out ;
3881
3882  return out ;
3883}
3884
3885Vector<Float> STMath::getSpectrumFromTime( double reftime,
3886                                           const Vector<Double> &timeVec,
3887                                           const vector<int> &idx,
3888                                           const Matrix<Float>& spectra,
3889                                           string mode )
3890{
3891  LogIO os( LogOrigin( "STMath", "getSpectrumFromTime", WHERE ) ) ;
3892  Vector<Float> sp ;
3893  uInt ncol = spectra.ncolumn() ;
3894
3895  if ( ncol == 0 ) {
3896    os << LogIO::SEVERE << "No spectra in the input scantable. Return empty spectrum." << LogIO::POST ;
3897    return sp ;
3898  }
3899  else if ( ncol == 1 ) {
3900    //os << "use row " << 0 << " (scanno = " << s->getScan( 0 ) << ")" << LogIO::POST ;
3901    sp.reference( spectra.column( 0 ) ) ;
3902    return sp ;
3903  }
3904  else {
3905    if ( mode == "before" ) {
3906      int id = -1 ;
3907      if ( idx[0] != -1 ) {
3908        id = idx[0] ;
3909      }
3910      else if ( idx[1] != -1 ) {
3911        os << LogIO::WARN << "Failed to find a scan before reftime. return a spectrum just after the reftime." << LogIO::POST ;
3912        id = idx[1] ;
3913      }
3914      //os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
3915      sp.reference( spectra.column( id ) ) ;
3916    }
3917    else if ( mode == "after" ) {
3918      int id = -1 ;
3919      if ( idx[1] != -1 ) {
3920        id = idx[1] ;
3921      }
3922      else if ( idx[0] != -1 ) {
3923        os << LogIO::WARN << "Failed to find a scan after reftime. return a spectrum just before the reftime." << LogIO::POST ;
3924        id = idx[1] ;
3925      }
3926      //os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
3927      sp.reference( spectra.column( id ) ) ;
3928    }
3929    else if ( mode == "nearest" ) {
3930      int id = -1 ;
3931      if ( idx[0] == -1 ) {
3932        id = idx[1] ;
3933      }
3934      else if ( idx[1] == -1 ) {
3935        id = idx[0] ;
3936      }
3937      else if ( idx[0] == idx[1] ) {
3938        id = idx[0] ;
3939      }
3940      else {
3941        double t0 = timeVec[idx[0]] ;
3942        double t1 = timeVec[idx[1]] ;
3943        double tref = reftime ;
3944        if ( abs( t0 - tref ) > abs( t1 - tref ) ) {
3945          id = idx[1] ;
3946        }
3947        else {
3948          id = idx[0] ;
3949        }
3950      }
3951      //os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
3952      sp.reference( spectra.column( id ) ) ;
3953    }
3954    else if ( mode == "linear" ) {
3955      if ( idx[0] == -1 ) {
3956        // use after
3957        os << LogIO::WARN << "Failed to interpolate. return a spectrum just after the reftime." << LogIO::POST ;
3958        int id = idx[1] ;
3959        //os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
3960        sp.reference( spectra.column( id ) ) ;
3961      }
3962      else if ( idx[1] == -1 ) {
3963        // use before
3964        os << LogIO::WARN << "Failed to interpolate. return a spectrum just before the reftime." << LogIO::POST ;
3965        int id = idx[0] ;
3966        //os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
3967        sp.reference( spectra.column( id ) ) ;
3968      }
3969      else if ( idx[0] == idx[1] ) {
3970        // use before
3971        //os << "No need to interporate." << LogIO::POST ;
3972        int id = idx[0] ;
3973        //os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
3974        sp.reference( spectra.column( id ) ) ;
3975      }
3976      else {
3977        // do interpolation
3978        //os << "interpolate between " << idx[0] << " and " << idx[1] << " (scanno: " << s->getScan( idx[0] ) << ", " << s->getScan( idx[1] ) << ")" << LogIO::POST ;
3979        double t0 = timeVec[idx[0]] ;
3980        double t1 = timeVec[idx[1]] ;
3981        double tref = reftime ;
3982        sp = spectra.column( idx[0] ).copy() ;
3983        Vector<Float> sp1( spectra.column( idx[1] ) ) ;
3984        double tfactor = ( tref - t0 ) / ( t1 - t0 ) ;
3985        for ( unsigned int i = 0 ; i < sp.size() ; i++ ) {
3986          sp[i] = ( sp1[i] - sp[i] ) * tfactor + sp[i] ;
3987        }
3988      }
3989    }
3990    else {
3991      os << LogIO::SEVERE << "Unknown mode" << LogIO::POST ;
3992    }
3993    return sp ;
3994  }
3995}
3996
3997vector<int> STMath::getRowIdFromTime( double reftime, const Vector<Double> &t )
3998{
3999//   double reft = reftime ;
4000  double dtmin = 1.0e100 ;
4001  double dtmax = -1.0e100 ;
4002//   vector<double> dt ;
4003  int just_before = -1 ;
4004  int just_after = -1 ;
4005  Vector<Double> dt = t - reftime ;
4006  for ( unsigned int i = 0 ; i < dt.size() ; i++ ) {
4007    if ( dt[i] > 0.0 ) {
4008      // after reftime
4009      if ( dt[i] < dtmin ) {
4010        just_after = i ;
4011        dtmin = dt[i] ;
4012      }
4013    }
4014    else if ( dt[i] < 0.0 ) {
4015      // before reftime
4016      if ( dt[i] > dtmax ) {
4017        just_before = i ;
4018        dtmax = dt[i] ;
4019      }
4020    }
4021    else {
4022      // just a reftime
4023      just_before = i ;
4024      just_after = i ;
4025      dtmax = 0 ;
4026      dtmin = 0 ;
4027      break ;
4028    }
4029  }
4030
4031  vector<int> v(2) ;
4032  v[0] = just_before ;
4033  v[1] = just_after ;
4034
4035  return v ;
4036}
4037
4038Vector<Float> STMath::getTcalFromTime( double reftime,
4039                                       const Vector<Double> &timeVec,
4040                                       const vector<int> &idx,
4041                                       const CountedPtr<Scantable>& s,
4042                                       string mode )
4043{
4044  LogIO os( LogOrigin( "STMath", "getTcalFromTime", WHERE ) ) ;
4045  STTcal tcalTable = s->tcal() ;
4046  String time ;
4047  Vector<Float> tcalval ;
4048  if ( s->nrow() == 0 ) {
4049    os << LogIO::SEVERE << "No row in the input scantable. Return empty tcal." << LogIO::POST ;
4050    return tcalval ;
4051  }
4052  else if ( s->nrow() == 1 ) {
4053    uInt tcalid = s->getTcalId( 0 ) ;
4054    //os << "use row " << 0 << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4055    tcalTable.getEntry( time, tcalval, tcalid ) ;
4056    return tcalval ;
4057  }
4058  else {
4059    if ( mode == "before" ) {
4060      int id = -1 ;
4061      if ( idx[0] != -1 ) {
4062        id = idx[0] ;
4063      }
4064      else if ( idx[1] != -1 ) {
4065        os << LogIO::WARN << "Failed to find a scan before reftime. return a spectrum just after the reftime." << LogIO::POST ;
4066        id = idx[1] ;
4067      }
4068      uInt tcalid = s->getTcalId( id ) ;
4069      //os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4070      tcalTable.getEntry( time, tcalval, tcalid ) ;
4071    }
4072    else if ( mode == "after" ) {
4073      int id = -1 ;
4074      if ( idx[1] != -1 ) {
4075        id = idx[1] ;
4076      }
4077      else if ( idx[0] != -1 ) {
4078        os << LogIO::WARN << "Failed to find a scan after reftime. return a spectrum just before the reftime." << LogIO::POST ;
4079        id = idx[1] ;
4080      }
4081      uInt tcalid = s->getTcalId( id ) ;
4082      //os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4083      tcalTable.getEntry( time, tcalval, tcalid ) ;
4084    }
4085    else if ( mode == "nearest" ) {
4086      int id = -1 ;
4087      if ( idx[0] == -1 ) {
4088        id = idx[1] ;
4089      }
4090      else if ( idx[1] == -1 ) {
4091        id = idx[0] ;
4092      }
4093      else if ( idx[0] == idx[1] ) {
4094        id = idx[0] ;
4095      }
4096      else {
4097        double t0 = timeVec[idx[0]] ;
4098        double t1 = timeVec[idx[1]] ;
4099        if ( abs( t0 - reftime ) > abs( t1 - reftime ) ) {
4100          id = idx[1] ;
4101        }
4102        else {
4103          id = idx[0] ;
4104        }
4105      }
4106      uInt tcalid = s->getTcalId( id ) ;
4107      //os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4108      tcalTable.getEntry( time, tcalval, tcalid ) ;
4109    }
4110    else if ( mode == "linear" ) {
4111      if ( idx[0] == -1 ) {
4112        // use after
4113        os << LogIO::WARN << "Failed to interpolate. return a spectrum just after the reftime." << LogIO::POST ;
4114        int id = idx[1] ;
4115        uInt tcalid = s->getTcalId( id ) ;
4116        //os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4117        tcalTable.getEntry( time, tcalval, tcalid ) ;
4118      }
4119      else if ( idx[1] == -1 ) {
4120        // use before
4121        os << LogIO::WARN << "Failed to interpolate. return a spectrum just before the reftime." << LogIO::POST ;
4122        int id = idx[0] ;
4123        uInt tcalid = s->getTcalId( id ) ;
4124        //os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4125        tcalTable.getEntry( time, tcalval, tcalid ) ;
4126      }
4127      else if ( idx[0] == idx[1] ) {
4128        // use before
4129        //os << "No need to interporate." << LogIO::POST ;
4130        int id = idx[0] ;
4131        uInt tcalid = s->getTcalId( id ) ;
4132        //os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4133        tcalTable.getEntry( time, tcalval, tcalid ) ;
4134      }
4135      else {
4136        // do interpolation
4137        //os << "interpolate between " << idx[0] << " and " << idx[1] << " (scanno: " << s->getScan( idx[0] ) << ", " << s->getScan( idx[1] ) << ")" << LogIO::POST ;
4138        double t0 = timeVec[idx[0]] ;
4139        double t1 = timeVec[idx[1]] ;
4140        Vector<Float> tcal0 ;
4141        uInt tcalid0 = s->getTcalId( idx[0] ) ;
4142        uInt tcalid1 = s->getTcalId( idx[1] ) ;
4143        tcalTable.getEntry( time, tcal0, tcalid0 ) ;
4144        tcalTable.getEntry( time, tcalval, tcalid1 ) ;
4145        double tfactor = (reftime - t0) / (t1 - t0) ;
4146        for ( unsigned int i = 0 ; i < tcal0.size() ; i++ ) {
4147          tcalval[i] = ( tcalval[i] - tcal0[i] ) * tfactor + tcal0[i] ;
4148        }
4149      }
4150    }
4151    else {
4152      os << LogIO::SEVERE << "Unknown mode" << LogIO::POST ;
4153    }
4154    return tcalval ;
4155  }
4156}
4157
4158Vector<Float> STMath::getTsysFromTime( double reftime,
4159                                       const Vector<Double> &timeVec,
4160                                       const vector<int> &idx,
4161                                       const CountedPtr<Scantable> &s,
4162                                       string mode )
4163{
4164  LogIO os( LogOrigin( "STMath", "getTsysFromTime", WHERE ) ) ;
4165  ArrayColumn<Float> tsysCol ;
4166  tsysCol.attach( s->table(), "TSYS" ) ;
4167  Vector<Float> tsysval ;
4168  if ( s->nrow() == 0 ) {
4169    os << LogIO::SEVERE << "No row in the input scantable. Return empty tsys." << LogIO::POST ;
4170    return tsysval ;
4171  }
4172  else if ( s->nrow() == 1 ) {
4173    //os << "use row " << 0 << LogIO::POST ;
4174    tsysval = tsysCol( 0 ) ;
4175    return tsysval ;
4176  }
4177  else {
4178    if ( mode == "before" ) {
4179      int id = -1 ;
4180      if ( idx[0] != -1 ) {
4181        id = idx[0] ;
4182      }
4183      else if ( idx[1] != -1 ) {
4184        os << LogIO::WARN << "Failed to find a scan before reftime. return a spectrum just after the reftime." << LogIO::POST ;
4185        id = idx[1] ;
4186      }
4187      //os << "use row " << id << LogIO::POST ;
4188      tsysval = tsysCol( id ) ;
4189    }
4190    else if ( mode == "after" ) {
4191      int id = -1 ;
4192      if ( idx[1] != -1 ) {
4193        id = idx[1] ;
4194      }
4195      else if ( idx[0] != -1 ) {
4196        os << LogIO::WARN << "Failed to find a scan after reftime. return a spectrum just before the reftime." << LogIO::POST ;
4197        id = idx[1] ;
4198      }
4199      //os << "use row " << id << LogIO::POST ;
4200      tsysval = tsysCol( id ) ;
4201    }
4202    else if ( mode == "nearest" ) {
4203      int id = -1 ;
4204      if ( idx[0] == -1 ) {
4205        id = idx[1] ;
4206      }
4207      else if ( idx[1] == -1 ) {
4208        id = idx[0] ;
4209      }
4210      else if ( idx[0] == idx[1] ) {
4211        id = idx[0] ;
4212      }
4213      else {
4214        double t0 = timeVec[idx[0]] ;
4215        double t1 = timeVec[idx[1]] ;
4216        if ( abs( t0 - reftime ) > abs( t1 - reftime ) ) {
4217          id = idx[1] ;
4218        }
4219        else {
4220          id = idx[0] ;
4221        }
4222      }
4223      //os << "use row " << id << LogIO::POST ;
4224      tsysval = tsysCol( id ) ;
4225    }
4226    else if ( mode == "linear" ) {
4227      if ( idx[0] == -1 ) {
4228        // use after
4229        os << LogIO::WARN << "Failed to interpolate. return a spectrum just after the reftime." << LogIO::POST ;
4230        int id = idx[1] ;
4231        //os << "use row " << id << LogIO::POST ;
4232        tsysval = tsysCol( id ) ;
4233      }
4234      else if ( idx[1] == -1 ) {
4235        // use before
4236        os << LogIO::WARN << "Failed to interpolate. return a spectrum just before the reftime." << LogIO::POST ;
4237        int id = idx[0] ;
4238        //os << "use row " << id << LogIO::POST ;
4239        tsysval = tsysCol( id ) ;
4240      }
4241      else if ( idx[0] == idx[1] ) {
4242        // use before
4243        //os << "No need to interporate." << LogIO::POST ;
4244        int id = idx[0] ;
4245        //os << "use row " << id << LogIO::POST ;
4246        tsysval = tsysCol( id ) ;
4247      }
4248      else {
4249        // do interpolation
4250        //os << "interpolate between " << idx[0] << " and " << idx[1] << " (scanno: " << s->getScan( idx[0] ) << ", " << s->getScan( idx[1] ) << ")" << LogIO::POST ;
4251        double t0 = timeVec[idx[0]] ;
4252        double t1 = timeVec[idx[1]] ;
4253        Vector<Float> tsys0 ;
4254        tsys0 = tsysCol( idx[0] ) ;
4255        tsysval = tsysCol( idx[1] ) ;
4256        double tfactor = (reftime - t0) / (t1 - t0) ;
4257        for ( unsigned int i = 0 ; i < tsys0.size() ; i++ ) {
4258          tsysval[i] = ( tsysval[i] - tsys0[i] ) * tfactor + tsys0[i] ;
4259        }
4260      }
4261    }
4262    else {
4263      os << LogIO::SEVERE << "Unknown mode" << LogIO::POST ;
4264    }
4265    return tsysval ;
4266  }
4267}
4268
4269void STMath::calibrateCW( CountedPtr<Scantable> &out,
4270                          const CountedPtr<Scantable>& on,
4271                          const CountedPtr<Scantable>& off,
4272                          const CountedPtr<Scantable>& sky,
4273                          const CountedPtr<Scantable>& hot,
4274                          const CountedPtr<Scantable>& cold,
4275                          const Vector<uInt> &rows,
4276                          const String &antname )
4277{
4278  // 2012/05/22 TN
4279  // Assume that out has empty SPECTRA column
4280
4281  // if rows is empty, just return
4282  if ( rows.nelements() == 0 )
4283    return ;
4284  ROScalarColumn<Double> timeCol( off->table(), "TIME" ) ;
4285  Vector<Double> timeOff = timeCol.getColumn() ;
4286  timeCol.attach( sky->table(), "TIME" ) ;
4287  Vector<Double> timeSky = timeCol.getColumn() ;
4288  timeCol.attach( hot->table(), "TIME" ) ;
4289  Vector<Double> timeHot = timeCol.getColumn() ;
4290  timeCol.attach( on->table(), "TIME" ) ;
4291  ROArrayColumn<Float> arrayFloatCol( off->table(), "SPECTRA" ) ;
4292  Matrix<Float> offspectra = arrayFloatCol.getColumn() ;
4293  arrayFloatCol.attach( sky->table(), "SPECTRA" ) ;
4294  Matrix<Float> skyspectra = arrayFloatCol.getColumn() ;
4295  arrayFloatCol.attach( hot->table(), "SPECTRA" ) ;
4296  Matrix<Float> hotspectra = arrayFloatCol.getColumn() ;
4297  unsigned int spsize = on->nchan( on->getIF(rows[0]) ) ;
4298  // I know that the data is contiguous
4299  const uInt *p = rows.data() ;
4300  vector<int> ids( 2 ) ;
4301  Block<uInt> flagchan( spsize ) ;
4302  uInt nflag = 0 ;
4303  for ( int irow = 0 ; irow < rows.nelements() ; irow++ ) {
4304    double reftime = timeCol.asdouble(*p) ;
4305    ids = getRowIdFromTime( reftime, timeOff ) ;
4306    Vector<Float> spoff = getSpectrumFromTime( reftime, timeOff, ids, offspectra, "linear" ) ;
4307    ids = getRowIdFromTime( reftime, timeSky ) ;
4308    Vector<Float> spsky = getSpectrumFromTime( reftime, timeSky, ids, skyspectra, "linear" ) ;
4309    Vector<Float> tcal = getTcalFromTime( reftime, timeSky, ids, sky, "linear" ) ;
4310    Vector<Float> tsys = getTsysFromTime( reftime, timeSky, ids, sky, "linear" ) ;
4311    ids = getRowIdFromTime( reftime, timeHot ) ;
4312    Vector<Float> sphot = getSpectrumFromTime( reftime, timeHot, ids, hotspectra, "linear" ) ;
4313    Vector<Float> spec = on->specCol_( *p ) ;
4314    if ( antname.find( "APEX" ) != String::npos ) {
4315      // using gain array
4316      for ( unsigned int j = 0 ; j < tcal.size() ; j++ ) {
4317        if ( spoff[j] == 0.0 || (sphot[j]-spsky[j]) == 0.0 ) {
4318          spec[j] = 0.0 ;
4319          flagchan[nflag++] = j ;
4320        }
4321        else {
4322          spec[j] = ( ( spec[j] - spoff[j] ) / spoff[j] )
4323            * ( spsky[j] / ( sphot[j] - spsky[j] ) ) * tcal[j] ;
4324        }
4325      }
4326    }
4327    else {
4328      // Chopper-Wheel calibration (Ulich & Haas 1976)
4329      for ( unsigned int j = 0 ; j < tcal.size() ; j++ ) {
4330        if ( (sphot[j]-spsky[j]) == 0.0 ) {
4331          spec[j] = 0.0 ;
4332          flagchan[nflag++] = j ;
4333        }
4334        else {
4335          spec[j] = ( spec[j] - spoff[j] ) / ( sphot[j] - spsky[j] ) * tcal[j] ;
4336        }
4337      }
4338    }
4339    out->specCol_.put( *p, spec ) ;
4340    out->tsysCol_.put( *p, tsys ) ;
4341    if ( nflag > 0 ) {
4342      Vector<uChar> fl = out->flagsCol_( *p ) ;
4343      for ( unsigned int j = 0 ; j < nflag ; j++ ) {
4344        fl[flagchan[j]] = (uChar)True ;
4345      }
4346      out->flagsCol_.put( *p, fl ) ;
4347    }
4348    nflag = 0 ;
4349    p++ ;
4350  }
4351}
4352
4353void STMath::calibrateALMA( CountedPtr<Scantable>& out,
4354                            const CountedPtr<Scantable>& on,
4355                            const CountedPtr<Scantable>& off,
4356                            const Vector<uInt>& rows )
4357{
4358  // 2012/05/22 TN
4359  // Assume that out has empty SPECTRA column
4360
4361  // if rows is empty, just return
4362  if ( rows.nelements() == 0 )
4363    return ;
4364  ROScalarColumn<Double> timeCol( off->table(), "TIME" ) ;
4365  Vector<Double> timeVec = timeCol.getColumn() ;
4366  timeCol.attach( on->table(), "TIME" ) ;
4367  ROArrayColumn<Float> arrayFloatCol( off->table(), "SPECTRA" ) ;
4368  Matrix<Float> offspectra = arrayFloatCol.getColumn() ;
4369  unsigned int spsize = on->nchan( on->getIF(rows[0]) ) ;
4370  // I know that the data is contiguous
4371  const uInt *p = rows.data() ;
4372  vector<int> ids( 2 ) ;
4373  Block<uInt> flagchan( spsize ) ;
4374  uInt nflag = 0 ;
4375  for ( int irow = 0 ; irow < rows.nelements() ; irow++ ) {
4376    double reftime = timeCol.asdouble(*p) ;
4377    ids = getRowIdFromTime( reftime, timeVec ) ;
4378    Vector<Float> spoff = getSpectrumFromTime( reftime, timeVec, ids, offspectra, "linear" ) ;
4379    //Vector<Float> spoff = getSpectrumFromTime( reftime, timeVec, off, "linear" ) ;
4380    Vector<Float> spec = on->specCol_( *p ) ;
4381    Vector<Float> tsys = on->tsysCol_( *p ) ;
4382    // ALMA Calibration
4383    //
4384    // Ta* = Tsys * ( ON - OFF ) / OFF
4385    //
4386    // 2010/01/07 Takeshi Nakazato
4387    unsigned int tsyssize = tsys.nelements() ;
4388    for ( unsigned int j = 0 ; j < spsize ; j++ ) {
4389      if ( spoff[j] == 0.0 ) {
4390        spec[j] = 0.0 ;
4391        flagchan[nflag++] = j ;
4392      }
4393      else {
4394        spec[j] = ( spec[j] - spoff[j] ) / spoff[j] ;
4395      }
4396      if ( tsyssize == spsize )
4397        spec[j] *= tsys[j] ;
4398      else
4399        spec[j] *= tsys[0] ;
4400    }
4401    out->specCol_.put( *p, spec ) ;
4402    if ( nflag > 0 ) {
4403      Vector<uChar> fl = out->flagsCol_( *p ) ;
4404      for ( unsigned int j = 0 ; j < nflag ; j++ ) {
4405        fl[flagchan[j]] = (uChar)True ;
4406      }
4407      out->flagsCol_.put( *p, fl ) ;
4408    }
4409    nflag = 0 ;
4410    p++ ;
4411  }
4412}
4413
4414void STMath::calibrateAPEXFS( CountedPtr<Scantable> &sig,
4415                              CountedPtr<Scantable> &ref,
4416                              const vector< CountedPtr<Scantable> >& on,
4417                              const vector< CountedPtr<Scantable> >& sky,
4418                              const vector< CountedPtr<Scantable> >& hot,
4419                              const vector< CountedPtr<Scantable> >& cold,
4420                              const Vector<uInt> &rows )
4421{
4422  // if rows is empty, just return
4423  if ( rows.nelements() == 0 )
4424    return ;
4425  ROScalarColumn<Double> timeCol( sky[0]->table(), "TIME" ) ;
4426  Vector<Double> timeSkyS = timeCol.getColumn() ;
4427  timeCol.attach( sky[1]->table(), "TIME" ) ;
4428  Vector<Double> timeSkyR = timeCol.getColumn() ;
4429  timeCol.attach( hot[0]->table(), "TIME" ) ;
4430  Vector<Double> timeHotS = timeCol.getColumn() ;
4431  timeCol.attach( hot[1]->table(), "TIME" ) ;
4432  Vector<Double> timeHotR = timeCol.getColumn() ;
4433  timeCol.attach( sig->table(), "TIME" ) ;
4434  ROScalarColumn<Double> timeCol2( ref->table(), "TIME" ) ;
4435  ROArrayColumn<Float> arrayFloatCol( sky[0]->table(), "SPECTRA" ) ;
4436  Matrix<Float> skyspectraS = arrayFloatCol.getColumn() ;
4437  arrayFloatCol.attach( sky[1]->table(), "SPECTRA" ) ;
4438  Matrix<Float> skyspectraR = arrayFloatCol.getColumn() ;
4439  arrayFloatCol.attach( hot[0]->table(), "SPECTRA" ) ;
4440  Matrix<Float> hotspectraS = arrayFloatCol.getColumn() ;
4441  arrayFloatCol.attach( hot[1]->table(), "SPECTRA" ) ;
4442  Matrix<Float> hotspectraR = arrayFloatCol.getColumn() ;
4443  unsigned int spsize = sig->nchan( sig->getIF(rows[0]) ) ;
4444  Vector<Float> spec( spsize ) ;
4445  // I know that the data is contiguous
4446  const uInt *p = rows.data() ;
4447  vector<int> ids( 2 ) ;
4448  Block<uInt> flagchan( spsize ) ;
4449  uInt nflag = 0 ;
4450  for ( int irow = 0 ; irow < rows.nelements() ; irow++ ) {
4451    double reftime = timeCol.asdouble(*p) ;
4452    ids = getRowIdFromTime( reftime, timeSkyS ) ;
4453    Vector<Float> spskyS = getSpectrumFromTime( reftime, timeSkyS, ids, skyspectraS, "linear" ) ;
4454    Vector<Float> tcalS = getTcalFromTime( reftime, timeSkyS, ids, sky[0], "linear" ) ;
4455    Vector<Float> tsysS = getTsysFromTime( reftime, timeSkyS, ids, sky[0], "linear" ) ;
4456    ids = getRowIdFromTime( reftime, timeHotS ) ;
4457    Vector<Float> sphotS = getSpectrumFromTime( reftime, timeHotS, ids, hotspectraS ) ;
4458    reftime = timeCol2.asdouble(*p) ;
4459    ids = getRowIdFromTime( reftime, timeSkyR ) ;
4460    Vector<Float> spskyR = getSpectrumFromTime( reftime, timeSkyR, ids, skyspectraR, "linear" ) ;
4461    Vector<Float> tcalR = getTcalFromTime( reftime, timeSkyR, ids, sky[1], "linear" ) ;
4462    Vector<Float> tsysR = getTsysFromTime( reftime, timeSkyR, ids, sky[1], "linear" ) ;
4463    ids = getRowIdFromTime( reftime, timeHotR ) ;
4464    Vector<Float> sphotR = getSpectrumFromTime( reftime, timeHotR, ids, hotspectraR ) ;
4465    Vector<Float> spsig = on[0]->specCol_( *p ) ;
4466    Vector<Float> spref = on[1]->specCol_( *p ) ;
4467    for ( unsigned int j = 0 ; j < spsize ; j++ ) {
4468      if ( (sphotS[j]-spskyS[j]) == 0.0 || (sphotR[j]-spskyR[j]) == 0.0 ) {
4469        spec[j] = 0.0 ;
4470        flagchan[nflag++] = j ;
4471      }
4472      else {
4473        spec[j] = tcalS[j] * spsig[j] / ( sphotS[j] - spskyS[j] )
4474          - tcalR[j] * spref[j] / ( sphotR[j] - spskyR[j] ) ;
4475      }
4476    }
4477    sig->specCol_.put( *p, spec ) ;
4478    sig->tsysCol_.put( *p, tsysS ) ;
4479    spec *= (Float)-1.0 ;
4480    ref->specCol_.put( *p, spec ) ;
4481    ref->tsysCol_.put( *p, tsysR ) ;   
4482    if ( nflag > 0 ) {
4483      Vector<uChar> flsig = sig->flagsCol_( *p ) ;
4484      Vector<uChar> flref = ref->flagsCol_( *p ) ;
4485      for ( unsigned int j = 0 ; j < nflag ; j++ ) {
4486        flsig[flagchan[j]] = (uChar)True ;
4487        flref[flagchan[j]] = (uChar)True ;
4488      }
4489      sig->flagsCol_.put( *p, flsig ) ;
4490      ref->flagsCol_.put( *p, flref ) ;
4491    }
4492    nflag = 0 ;
4493    p++ ;
4494  }
4495}
4496
4497void STMath::calibrateFS( CountedPtr<Scantable> &sig,
4498                          CountedPtr<Scantable> &ref,
4499                          const CountedPtr<Scantable>& rsig,
4500                          const CountedPtr<Scantable>& rref,
4501                          const CountedPtr<Scantable>& sky,
4502                          const CountedPtr<Scantable>& hot,
4503                          const CountedPtr<Scantable>& cold,
4504                          const Vector<uInt> &rows )
4505{
4506  // if rows is empty, just return
4507  if ( rows.nelements() == 0 )
4508    return ;
4509  ROScalarColumn<Double> timeCol( sky->table(), "TIME" ) ;
4510  Vector<Double> timeSky = timeCol.getColumn() ;
4511  timeCol.attach( hot->table(), "TIME" ) ;
4512  Vector<Double> timeHot = timeCol.getColumn() ;
4513  timeCol.attach( sig->table(), "TIME" ) ;
4514  ROScalarColumn<Double> timeCol2( ref->table(), "TIME" ) ;
4515  ROArrayColumn<Float> arrayFloatCol( sky->table(), "SPECTRA" ) ;
4516  Matrix<Float> skyspectra = arrayFloatCol.getColumn() ;
4517  arrayFloatCol.attach( hot->table(), "SPECTRA" ) ;
4518  Matrix<Float> hotspectra = arrayFloatCol.getColumn() ;
4519  unsigned int spsize = sig->nchan( sig->getIF(rows[0]) ) ;
4520  Vector<Float> spec( spsize ) ;
4521  // I know that the data is contiguous
4522  const uInt *p = rows.data() ;
4523  vector<int> ids( 2 ) ;
4524  Block<uInt> flagchan( spsize ) ;
4525  uInt nflag = 0 ;
4526  for ( int irow = 0 ; irow < rows.nelements() ; irow++ ) {
4527    double reftime = timeCol.asdouble(*p) ;
4528    ids = getRowIdFromTime( reftime, timeSky ) ;
4529    Vector<Float> spsky = getSpectrumFromTime( reftime, timeSky, ids, skyspectra, "linear" ) ;
4530    Vector<Float> tcal = getTcalFromTime( reftime, timeSky, ids, sky, "linear" ) ;
4531    Vector<Float> tsys = getTsysFromTime( reftime, timeSky, ids, sky, "linear" ) ;
4532    ids = getRowIdFromTime( reftime, timeHot ) ;
4533    Vector<Float> sphot = getSpectrumFromTime( reftime, timeHot, ids, hotspectra ) ;
4534    Vector<Float> spsig = rsig->specCol_( *p ) ;
4535    Vector<Float> spref = rref->specCol_( *p ) ;
4536    // using gain array
4537    for ( unsigned int j = 0 ; j < spsize ; j++ ) {
4538      if ( spref[j] == 0.0 || (sphot[j]-spsky[j]) == 0.0 ) {
4539        spec[j] = 0.0 ;
4540        flagchan[nflag++] = j ;
4541      }
4542      else {
4543        spec[j] = ( ( spsig[j] - spref[j] ) / spref[j] )
4544          * ( spsky[j] / ( sphot[j] - spsky[j] ) ) * tcal[j] ;
4545      }
4546    }
4547    sig->specCol_.put( *p, spec ) ;
4548    sig->tsysCol_.put( *p, tsys ) ;
4549    if ( nflag > 0 ) {
4550      Vector<uChar> fl = sig->flagsCol_( *p ) ;
4551      for ( unsigned int j = 0 ; j < nflag ; j++ ) {
4552        fl[flagchan[j]] = (uChar)True ;
4553      }
4554      sig->flagsCol_.put( *p, fl ) ;
4555    }
4556    nflag = 0 ;
4557
4558    reftime = timeCol2.asdouble(*p) ;
4559    spsky = getSpectrumFromTime( reftime, timeSky, ids, skyspectra, "linear" ) ;
4560    tcal = getTcalFromTime( reftime, timeSky, ids, sky, "linear" ) ;
4561    tsys = getTsysFromTime( reftime, timeSky, ids, sky, "linear" ) ;
4562    ids = getRowIdFromTime( reftime, timeHot ) ;
4563    sphot = getSpectrumFromTime( reftime, timeHot, ids, hotspectra ) ;
4564    // using gain array
4565    for ( unsigned int j = 0 ; j < spsize ; j++ ) {
4566      if ( spsig[j] == 0.0 || (sphot[j]-spsky[j]) == 0.0 ) {
4567        spec[j] = 0.0 ;
4568        flagchan[nflag++] = j ;
4569      }
4570      else {
4571        spec[j] = ( ( spref[j] - spsig[j] ) / spsig[j] )
4572          * ( spsky[j] / ( sphot[j] - spsky[j] ) ) * tcal[j] ;
4573      }
4574    }
4575    ref->specCol_.put( *p, spec ) ;
4576    ref->tsysCol_.put( *p, tsys ) ;   
4577    if ( nflag > 0 ) {
4578      Vector<uChar> fl = ref->flagsCol_( *p ) ;
4579      for ( unsigned int j = 0 ; j < nflag ; j++ ) {
4580        fl[flagchan[j]] = (uChar)True ;
4581      }
4582      ref->flagsCol_.put( *p, fl ) ;
4583    }
4584    nflag = 0 ;
4585    p++ ;
4586  }
4587}
4588
4589void STMath::copyRows( Table &out,
4590                       const Table &in,
4591                       uInt startout,
4592                       uInt startin,
4593                       uInt nrow,
4594                       Bool copySpectra,
4595                       Bool copyFlagtra,
4596                       Bool copyTsys )
4597{
4598  uInt nexclude = 0 ;
4599  Block<String> excludeColsBlock( 3 ) ;
4600  if ( !copySpectra ) {
4601    excludeColsBlock[nexclude] = "SPECTRA" ;
4602    nexclude++ ;
4603  }
4604  if ( !copyFlagtra ) {
4605    excludeColsBlock[nexclude] = "FLAGTRA" ;
4606    nexclude++ ;
4607  }
4608  if ( !copyTsys ) {
4609    excludeColsBlock[nexclude] = "TSYS" ;
4610    nexclude++ ;
4611  }
4612  //  if ( nexclude < 3 ) {
4613  //    excludeCols.resize( nexclude, True ) ;
4614  //  }
4615  Vector<String> excludeCols( IPosition(1,nexclude),
4616                              excludeColsBlock.storage(),
4617                              SHARE ) ;
4618//   cout << "excludeCols=" << excludeCols << endl ;
4619  TableRow rowout( out, excludeCols, True ) ;
4620  ROTableRow rowin( in, excludeCols, True ) ;
4621  uInt rin = startin ;
4622  uInt rout = startout ;
4623  for ( uInt i = 0 ; i < nrow ; i++ ) {
4624    rowin.get( rin ) ;
4625    rowout.putMatchingFields( rout, rowin.record() ) ;
4626    rin++ ;
4627    rout++ ;
4628  }
4629}
4630
4631CountedPtr<Scantable> STMath::averageWithinSession( CountedPtr<Scantable> &s,
4632                                                    vector<bool> &mask,
4633                                                    string weight )
4634{
4635  // prepare output table
4636  bool insitu = insitu_ ;
4637  insitu_ = false ;
4638  CountedPtr<Scantable> a = getScantable( s, true ) ;
4639  insitu_ = insitu ;
4640  Table &atab = a->table() ;
4641  ScalarColumn<Double> timeColOut( atab, "TIME" ) ;
4642
4643  if ( s->nrow() == 0 )
4644    return a ;
4645
4646  // setup RowAccumulator
4647  WeightType wtype = stringToWeight( weight ) ;
4648  RowAccumulator acc( wtype ) ;
4649  Vector<Bool> cmask( mask ) ;
4650  acc.setUserMask( cmask ) ;
4651
4652  vector<string> cols( 3 ) ;
4653  cols[0] = "IFNO" ;
4654  cols[1] = "POLNO" ;
4655  cols[2] = "BEAMNO" ;
4656  STIdxIterAcc iter( s, cols ) ;
4657
4658  Table ttab = s->table() ;
4659  ROScalarColumn<Double> *timeCol = new ROScalarColumn<Double>( ttab, "TIME" ) ;
4660  Vector<Double> timeVec = timeCol->getColumn() ;
4661  delete timeCol ;
4662  Vector<Double> interval = s->integrCol_.getColumn() ;
4663  uInt nrow = timeVec.nelements() ;
4664  uInt outrow = 0 ;
4665
4666  while( !iter.pastEnd() ) {
4667
4668    Vector<uInt> rows = iter.getRows( SHARE ) ;
4669    uInt len = rows.nelements() ;
4670
4671    if ( len == 0 ) {
4672      iter.next() ;
4673      continue ;
4674    }
4675
4676    uInt nchan = s->nchan(s->getIF(rows[0])) ;
4677    Vector<uChar> flag( nchan ) ;
4678    Vector<Bool> bflag( nchan ) ;
4679    Vector<Float> spec( nchan ) ;
4680    Vector<Float> tsys( nchan ) ;
4681
4682    Vector<Double> timeSep( len-1 ) ;
4683    for ( uInt i = 0 ; i < len-1 ; i++ ) {
4684      timeSep[i] = timeVec[rows[i+1]] - timeVec[rows[i]] ;
4685    }
4686
4687    uInt irow ;
4688    uInt jrow ;
4689    for ( uInt i = 0 ; i < len-1 ; i++ ) {
4690      irow = rows[i] ;
4691      jrow = rows[i+1] ;
4692      // accumulate data
4693      s->flagsCol_.get( irow, flag ) ;
4694      convertArray( bflag, flag ) ;
4695      s->specCol_.get( irow, spec ) ;
4696      tsys.assign( s->tsysCol_( irow ) ) ;
4697      if ( !allEQ(bflag,True) )
4698        acc.add( spec, !bflag, tsys, interval[irow], timeVec[irow] ) ;
4699      double gap = 2.0 * 86400.0 * timeSep[i] / ( interval[jrow] + interval[irow] ) ;
4700      //cout << "gap[" << i << "]=" << setw(5) << gap << endl ;
4701      if ( gap > 1.1 ) {
4702        //cout << "detected gap between " << i << " and " << i+1 << endl ;
4703        // put data to output table
4704        // reset RowAccumulator
4705        if ( acc.state() ) {
4706          atab.addRow() ;
4707          copyRows( atab, ttab, outrow, irow, 1, False, False, False ) ;
4708          acc.replaceNaN() ;
4709          const Vector<Bool> &msk = acc.getMask() ;
4710          convertArray( flag, !msk ) ;
4711          for (uInt k = 0; k < nchan; ++k) {
4712            uChar userFlag = 1 << 7;
4713            if (msk[k]==True) userFlag = 0 << 7;
4714            flag(k) = userFlag;
4715          }
4716          a->flagsCol_.put( outrow, flag ) ;
4717          a->specCol_.put( outrow, acc.getSpectrum() ) ;
4718          a->tsysCol_.put( outrow, acc.getTsys() ) ;
4719          a->integrCol_.put( outrow, acc.getInterval() ) ;
4720          timeColOut.put( outrow, acc.getTime() ) ;
4721          a->cycleCol_.put( outrow, 0 ) ;
4722        }
4723        acc.reset() ;
4724        outrow++ ;
4725      }
4726    }
4727
4728    // accumulate and add last data
4729    irow = rows[len-1] ;
4730    s->flagsCol_.get( irow, flag ) ;
4731    convertArray( bflag, flag ) ;
4732    s->specCol_.get( irow, spec ) ;
4733    tsys.assign( s->tsysCol_( irow ) ) ;
4734    if (!allEQ(bflag,True) )
4735      acc.add( spec, !bflag, tsys, interval[irow], timeVec[irow] ) ;
4736    if ( acc.state() ) {
4737      atab.addRow() ;
4738      copyRows( atab, ttab, outrow, irow, 1, False, False, False ) ;
4739      acc.replaceNaN() ;
4740      const Vector<Bool> &msk = acc.getMask() ;
4741      convertArray( flag, !msk ) ;
4742      for (uInt k = 0; k < nchan; ++k) {
4743        uChar userFlag = 1 << 7;
4744        if (msk[k]==True) userFlag = 0 << 7;
4745        flag(k) = userFlag;
4746      }
4747      a->flagsCol_.put( outrow, flag ) ;
4748      a->specCol_.put( outrow, acc.getSpectrum() ) ;
4749      a->tsysCol_.put( outrow, acc.getTsys() ) ;
4750      a->integrCol_.put( outrow, acc.getInterval() ) ;
4751      timeColOut.put( outrow, acc.getTime() ) ;
4752      a->cycleCol_.put( outrow, 0 ) ;
4753    }
4754    acc.reset() ;
4755    outrow++ ;
4756
4757    iter.next() ;
4758  }
4759
4760  return a ;
4761}
Note: See TracBrowser for help on using the repository browser.