source: trunk/src/STMath.cpp @ 2879

Last change on this file since 2879 was 2879, checked in by Kana Sugimoto, 10 years ago

New Development: No (IMPORTANT bug fix)

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): scantable.smooth

Description: Fixed a bug that flag is ignored in smoothing.


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