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

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

New Development: No

JIRA Issue: No

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...

Use direct access to Scantable.specCol_ instead to call Scantable::getSpectrum.


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