source: branches/hpc33/src/STMath.cpp @ 2551

Last change on this file since 2551 was 2551, checked in by Takeshi Nakazato, 12 years ago

New Development: No

JIRA Issue: Yes CAS-4195

Ready for Test: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: Yes/No?

Module(s): Module Names change impacts.

Description: Describe your changes here...

Load whole (averaged) off spectra on memory instead to get one spectrum
when it is needed since those are not so heavy. It might reduce number of
call of ArrayColumn::get().

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