source: trunk/src/STMath.cpp @ 2950

Last change on this file since 2950 was 2950, checked in by Takeshi Nakazato, 10 years ago

New Development: No

JIRA Issue: Yes CAS-6582

Ready for Test: Yes

Interface Changes: Yes/No?

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: Yes/No?

Module(s): Module Names change impacts.

Description: Describe your changes here...


Smoothing functions are updated so that flagged rows are not processed.
Flag value for regridding function is changed from 1 to 128.

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