source: trunk/src/STMath.cpp @ 2919

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

New Development: No

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: Yes/No?

Module(s): Module Names change impacts.

Description: Describe your changes here...

Refactoring.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 146.3 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#include "IterationHelper.h"
61
62using namespace casa;
63using namespace asap;
64
65// 2012/02/17 TN
66// Since STGrid is implemented, average doesn't consider direction
67// when accumulating
68// tolerance for direction comparison (rad)
69// #define TOL_OTF    1.0e-15
70// #define TOL_POINT  2.9088821e-4  // 1 arcmin
71
72STMath::STMath(bool insitu) :
73  insitu_(insitu)
74{
75}
76
77
78STMath::~STMath()
79{
80}
81
82CountedPtr<Scantable>
83STMath::average( const std::vector<CountedPtr<Scantable> >& in,
84                 const std::vector<bool>& mask,
85                 const std::string& weight,
86                 const std::string& avmode)
87{
88//    double t0, t1 ;
89//    t0 = mathutil::gettimeofday_sec() ;
90
91  LogIO os( LogOrigin( "STMath", "average()", WHERE ) ) ;
92  if ( avmode == "SCAN" && in.size() != 1 )
93    throw(AipsError("Can't perform 'SCAN' averaging on multiple tables.\n"
94                    "Use merge first."));
95  WeightType wtype = stringToWeight(weight);
96
97  // 2012/02/17 TN
98  // Since STGrid is implemented, average doesn't consider direction
99  // when accumulating
100  // check if OTF observation
101//   String obstype = in[0]->getHeader().obstype ;
102//   Double tol = 0.0 ;
103//   if ( (obstype.find( "OTF" ) != String::npos) || (obstype.find( "OBSERVE_TARGET" ) != String::npos) ) {
104//     tol = TOL_OTF ;
105//   }
106//   else {
107//     tol = TOL_POINT ;
108//   }
109
110  // output
111  // clone as this is non insitu
112  bool insitu = insitu_;
113  setInsitu(false);
114  CountedPtr< Scantable > out = getScantable(in[0], true);
115  setInsitu(insitu);
116  std::vector<CountedPtr<Scantable> >::const_iterator stit = in.begin();
117  ++stit;
118  while ( stit != in.end() ) {
119    out->appendToHistoryTable((*stit)->history());
120    ++stit;
121  }
122
123  Table& tout = out->table();
124
125  /// @todo check if all scantables are conformant
126
127  ArrayColumn<Float> specColOut(tout,"SPECTRA");
128  ArrayColumn<uChar> flagColOut(tout,"FLAGTRA");
129  ArrayColumn<Float> tsysColOut(tout,"TSYS");
130  ScalarColumn<Double> mjdColOut(tout,"TIME");
131  ScalarColumn<Double> intColOut(tout,"INTERVAL");
132  ScalarColumn<uInt> cycColOut(tout,"CYCLENO");
133  ScalarColumn<uInt> scanColOut(tout,"SCANNO");
134  ScalarColumn<uInt> flagRowColOut(tout,"FLAGROW");
135
136  // set up the output table rows. These are based on the structure of the
137  // FIRST scantable in the vector
138  const Table& baset = in[0]->table();
139
140  RowAccumulator acc(wtype);
141  Vector<Bool> cmask(mask);
142  acc.setUserMask(cmask);
143//   ROTableRow row(tout);
144  ROArrayColumn<Float> specCol, tsysCol;
145  ROArrayColumn<uChar> flagCol;
146  ROScalarColumn<Double> mjdCol, intCol;
147  ROScalarColumn<Int> scanIDCol;
148  ROScalarColumn<uInt> flagRowCol;
149
150  //Vector<uInt> rowstodelete;
151  Block<uInt> rowstodelB( in[0]->nrow() ) ;
152  uInt nrowdel = 0 ;
153
154//   Block<String> cols(3);
155  vector<string> cols(3) ;
156  cols[0] = String("BEAMNO");
157  cols[1] = String("IFNO");
158  cols[2] = String("POLNO");
159  if ( avmode == "SOURCE" ) {
160    cols.resize(4);
161    cols[3] = String("SRCNAME");
162  }
163  if ( avmode == "SCAN"  && in.size() == 1) {
164    //cols.resize(4);
165    //cols[3] = String("SCANNO");
166    cols.resize(5);
167    cols[3] = String("SRCNAME");
168    cols[4] = String("SCANNO");
169  }
170  uInt outrowCount = 0;
171  // use STIdxIter2 instead of TableIterator
172  STIdxIter2 iter( in[0], cols ) ;
173//   double t2 = 0 ;
174//   double t3 = 0 ;
175//   double t4 = 0 ;
176//   double t5 = 0 ;
177//   TableIterator iter(baset, cols);
178//   int count = 0 ;
179  while (!iter.pastEnd()) {
180    Vector<uInt> rows = iter.getRows( SHARE ) ;
181    if ( rows.nelements() == 0 ) {
182      iter.next() ;
183      continue ;
184    }
185    Record current = iter.currentValue() ;
186    //Table subt = iter.table();
187    // copy the first row of this selection into the new table
188    tout.addRow();
189//     t4 = mathutil::gettimeofday_sec() ;
190    // skip to copy SPECTRA, FLAGTRA, and TSYS since those heavy columns are
191    // overwritten in the following process
192    copyRows( tout, baset, outrowCount, rows[0], 1, False, False, False ) ;
193//     t5 += mathutil::gettimeofday_sec() - t4 ;
194    // re-index to 0
195    if ( avmode != "SCAN" && avmode != "SOURCE" ) {
196      scanColOut.put(outrowCount, uInt(0));
197    }
198
199    // 2012/02/17 TN
200    // Since STGrid is implemented, average doesn't consider direction
201    // when accumulating
202//     MDirection::ScalarColumn dircol ;
203//     dircol.attach( subt, "DIRECTION" ) ;
204//     Int length = subt.nrow() ;
205//     vector< Vector<Double> > dirs ;
206//     vector<int> indexes ;
207//     for ( Int i = 0 ; i < length ; i++ ) {
208//       Vector<Double> t = dircol(i).getAngle(Unit(String("rad"))).getValue() ;
209//       //os << << count++ << ": " ;
210//       //os << "[" << t[0] << "," << t[1] << "]" << LogIO::POST ;
211//       bool adddir = true ;
212//       for ( uInt j = 0 ; j < dirs.size() ; j++ ) {
213//         //if ( allTrue( t == dirs[j] ) ) {
214//         Double dx = t[0] - dirs[j][0] ;
215//         Double dy = t[1] - dirs[j][1] ;
216//         Double dd = sqrt( dx * dx + dy * dy ) ;
217//         //if ( allNearAbs( t, dirs[j], tol ) ) {
218//         if ( dd <= tol ) {
219//           adddir = false ;
220//           break ;
221//         }
222//       }
223//       if ( adddir ) {
224//         dirs.push_back( t ) ;
225//         indexes.push_back( i ) ;
226//       }
227//     }
228//     uInt rowNum = dirs.size() ;
229//     tout.addRow( rowNum ) ;
230//     for ( uInt i = 0 ; i < rowNum ; i++ ) {
231//       TableCopy::copyRows( tout, subt, outrowCount+i, indexes[i], 1 ) ;
232//       // re-index to 0
233//       if ( avmode != "SCAN" && avmode != "SOURCE" ) {
234//         scanColOut.put(outrowCount+i, uInt(0));
235//       }       
236//     }
237//     outrowCount += rowNum ;
238
239    // merge loop
240    uInt i = outrowCount ;
241    // in[0] is already selected by iterator
242    specCol.attach(baset,"SPECTRA");
243    flagCol.attach(baset,"FLAGTRA");
244    tsysCol.attach(baset,"TSYS");
245    intCol.attach(baset,"INTERVAL");
246    mjdCol.attach(baset,"TIME");
247    flagRowCol.attach(baset,"FLAGROW");
248    Vector<Float> spec,tsys;
249    Vector<uChar> flag;
250    Double inter,time;
251    uInt flagRow;
252
253    for (uInt l = 0; l < rows.nelements(); ++l ) {
254      uInt k = rows[l] ;
255      flagCol.get(k, flag);
256      Vector<Bool> bflag(flag.shape());
257      flagRowCol.get(k, flagRow);
258      if (flagRow > 0)
259        bflag = true;
260      else
261        convertArray(bflag, flag);
262      /*                                                                                                   
263        if ( allEQ(bflag, True) ) {                                                                         
264        continue;//don't accumulate                                                                         
265        }                                                                                                   
266      */
267      specCol.get(k, spec);
268      tsysCol.get(k, tsys);
269      intCol.get(k, inter);
270      mjdCol.get(k, time);
271      // spectrum has to be added last to enable weighting by the other values                             
272//       t2 = mathutil::gettimeofday_sec() ;
273      acc.add(spec, !bflag, tsys, inter, time);
274//       t3 += mathutil::gettimeofday_sec() - t2 ;
275     
276    }
277
278
279    // in[0] is already selected by TableIterator so that index is
280    // started from 1
281    for ( int j=1; j < int(in.size()); ++j ) {
282      const Table& tin = in[j]->table();
283      //const TableRecord& rec = row.get(i);
284      ROScalarColumn<Double> tmp(tin, "TIME");
285      Double td;tmp.get(0,td);
286
287#if 1
288      static char const*const colNames1[] = { "IFNO", "BEAMNO", "POLNO" };
289      //uInt const values1[] = { rec.asuInt("IFNO"), rec.asuInt("BEAMNO"), rec.asuInt("POLNO") };
290      uInt const values1[] = { current.asuInt("IFNO"), current.asuInt("BEAMNO"), current.asuInt("POLNO") };
291      SingleTypeEqPredicate<uInt, 3> myPred(tin, colNames1, values1);
292      CustomTableExprNodeRep myNodeRep(tin, myPred);
293      myNodeRep.link(); // to avoid automatic delete when myExpr is destructed.
294      CustomTableExprNode myExpr(myNodeRep);
295      Table basesubt = tin(myExpr);
296#else
297//       Table basesubt = tin( tin.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
298//                          && tin.col("IFNO") == Int(rec.asuInt("IFNO"))
299//                          && tin.col("POLNO") == Int(rec.asuInt("POLNO")) );
300      Table basesubt = tin( tin.col("BEAMNO") == current.asuInt("BEAMNO")
301                            && tin.col("IFNO") == current.asuInt("IFNO")
302                            && tin.col("POLNO") == current.asuInt("POLNO") );
303#endif
304      Table subt;
305      if ( avmode == "SOURCE") {
306//         subt = basesubt( basesubt.col("SRCNAME") == rec.asString("SRCNAME"));
307        subt = basesubt( basesubt.col("SRCNAME") == current.asString("SRCNAME") );
308
309      } else if (avmode == "SCAN") {
310//         subt = basesubt( basesubt.col("SRCNAME") == rec.asString("SRCNAME")
311//                    && basesubt.col("SCANNO") == Int(rec.asuInt("SCANNO")) );
312        subt = basesubt( basesubt.col("SRCNAME") == current.asString("SRCNAME")
313                         && basesubt.col("SCANNO") == current.asuInt("SCANNO") );
314      } else {
315        subt = basesubt;
316      }
317
318      // 2012/02/17 TN
319      // Since STGrid is implemented, average doesn't consider direction
320      // when accumulating
321//       vector<uInt> removeRows ;
322//       uInt nrsubt = subt.nrow() ;
323//       for ( uInt irow = 0 ; irow < nrsubt ; irow++ ) {
324//         //if ( !allTrue((subt.col("DIRECTION").getArrayDouble(TableExprId(irow)))==rec.asArrayDouble("DIRECTION")) ) {
325//         Vector<Double> x0 = (subt.col("DIRECTION").getArrayDouble(TableExprId(irow))) ;
326//         Vector<Double> x1 = rec.asArrayDouble("DIRECTION") ;
327//         double dx = x0[0] - x1[0];
328//         double dy = x0[1] - x1[1];
329//         Double dd = sqrt( dx * dx + dy * dy ) ;
330//         //if ( !allNearAbs((subt.col("DIRECTION").getArrayDouble(TableExprId(irow))), rec.asArrayDouble("DIRECTION"), tol ) ) {
331//         if ( dd > tol ) {
332//           removeRows.push_back( irow ) ;
333//         }
334//       }
335//       if ( removeRows.size() != 0 ) {
336//         subt.removeRow( removeRows ) ;
337//       }
338     
339//       if ( nrsubt == removeRows.size() )
340//         throw(AipsError("Averaging data is empty.")) ;
341
342      specCol.attach(subt,"SPECTRA");
343      flagCol.attach(subt,"FLAGTRA");
344      tsysCol.attach(subt,"TSYS");
345      intCol.attach(subt,"INTERVAL");
346      mjdCol.attach(subt,"TIME");
347      flagRowCol.attach(subt,"FLAGROW");
348      for (uInt k = 0; k < subt.nrow(); ++k ) {
349        flagCol.get(k, flag);
350        Vector<Bool> bflag(flag.shape());
351        flagRowCol.get(k, flagRow);
352        if (flagRow > 0)
353          bflag = true;
354        else
355          convertArray(bflag, flag);
356        /*
357        if ( allEQ(bflag, True) ) {
358        continue;//don't accumulate
359        }
360        */
361        specCol.get(k, spec);
362        //tsysCol.get(k, tsys);
363        tsys.assign( tsysCol(k) );
364        intCol.get(k, inter);
365        mjdCol.get(k, time);
366        // spectrum has to be added last to enable weighting by the other values
367//         t2 = mathutil::gettimeofday_sec() ;
368        acc.add(spec, !bflag, tsys, inter, time);
369//         t3 += mathutil::gettimeofday_sec() - t2 ;
370      }
371
372    }
373    const Vector<Bool>& msk = acc.getMask();
374    if ( allEQ(msk, False) ) {
375      rowstodelB[nrowdel] = i ;
376      nrowdel++ ;
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    Vector<Float> spec;
2473    Vector<uChar> flag;
2474    for (uInt i = 0; i < tab.nrow(); ++i) {
2475      specCol.get(i, spec);
2476      flagCol.get(i, flag);
2477      Vector<Bool> mask(flag.nelements());
2478      convertArray(mask, flag);
2479      Vector<Float> specout;
2480      Vector<Bool> maskout;
2481      if (kernel == "hanning") {
2482        mathutil::hanning(specout, maskout, spec, !mask);
2483      } else if (kernel == "rmedian") {
2484        mathutil::runningMedian(specout, maskout, spec , mask, width);
2485      } else if (kernel == "poly") {
2486        mathutil::polyfit(specout, maskout, spec, !mask, width, order);
2487      }
2488
2489      for (uInt j = 0; j < flag.nelements(); ++j) {
2490        uChar userFlag = 1 << 7;
2491        if (maskout[j]==True) userFlag = 0 << 7;
2492        flag(j) = userFlag;
2493      }
2494
2495      flagCol.put(i, flag);
2496      specCol.put(i, specout);
2497    }
2498  ++iter;
2499  }
2500  return out;
2501}
2502
2503CountedPtr< Scantable > STMath::smooth( const CountedPtr< Scantable >& in,
2504                                        const std::string& kernel, float width,
2505                                        int order)
2506{
2507  if (kernel == "rmedian"  || kernel == "hanning" || kernel == "poly") {
2508    return smoothOther(in, kernel, width, order);
2509  }
2510  CountedPtr< Scantable > out = getScantable(in, false);
2511  Table& table = out->table();
2512  VectorKernel::KernelTypes type = VectorKernel::toKernelType(kernel);
2513  // same IFNO should have same no of channels
2514  // this saves overhead
2515  TableIterator iter(table, "IFNO");
2516  while (!iter.pastEnd()) {
2517    Table tab = iter.table();
2518    ArrayColumn<Float> specCol(tab, "SPECTRA");
2519    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
2520    Vector<Float> spec = specCol( 0 );
2521    uInt nchan = spec.nelements();
2522    Vector<Float> kvec = VectorKernel::make(type, width, nchan, True, False);
2523    Convolver<Float> conv(kvec, IPosition(1,nchan));
2524    Vector<uChar> flag;
2525    Vector<Bool> mask(nchan);
2526    for ( uInt i=0; i<tab.nrow(); ++i) {
2527      specCol.get(i, spec);
2528      flagCol.get(i, flag);
2529      convertArray(mask, flag);
2530      Vector<Float> specout;
2531      //mathutil::replaceMaskByZero(specout, mask);
2532      mathutil::replaceMaskByZero(spec, !mask);
2533      //std::vector<bool> vmask;
2534      //(!mask).tovector(vmask);
2535      //mathutil::doZeroOrderInterpolation(spec, vmask);
2536      conv.linearConv(specout, spec);
2537      specCol.put(i, specout);
2538    }
2539    ++iter;
2540  }
2541  return out;
2542}
2543
2544CountedPtr< Scantable >
2545STMath::merge( const std::vector< CountedPtr < Scantable > >& in,
2546               const std::string &freqTol )
2547{
2548  Double freqTolInHz = 0.0; // default is 0.0Hz (merge only when exact match)
2549  if (freqTol.size() > 0) {
2550    Quantum<Double> freqTolInQuantity;
2551    if (!Quantum<Double>::read(freqTolInQuantity, freqTol)) {
2552      throw(AipsError("Failed to convert freqTol string to quantity"));
2553    }
2554    if (!freqTolInQuantity.isConform("Hz")) {
2555      throw(AipsError("Invalid freqTol string"));
2556    }
2557    freqTolInHz = freqTolInQuantity.getValue("Hz");
2558    LogIO os(LogOrigin("STMath", "merge", WHERE));
2559    os << "frequency tolerance = " << freqTolInHz << "Hz" << LogIO::POST;
2560  }
2561 
2562  if ( in.size() < 2 ) {
2563    throw(AipsError("Need at least two scantables to perform a merge."));
2564  }
2565  std::vector<CountedPtr < Scantable > >::const_iterator it = in.begin();
2566  bool insitu = insitu_;
2567  setInsitu(false);
2568  CountedPtr< Scantable > out = getScantable(*it, false);
2569  setInsitu(insitu);
2570  Table& tout = out->table();
2571  ScalarColumn<uInt> freqidcol(tout,"FREQ_ID"), molidcol(tout, "MOLECULE_ID");
2572  ScalarColumn<uInt> scannocol(tout,"SCANNO"), focusidcol(tout,"FOCUS_ID");
2573  ScalarColumn<uInt> ifnocol(tout, "IFNO");
2574  // Renumber SCANNO to be 0-based
2575  Vector<uInt> scannos = scannocol.getColumn();
2576  uInt offset = min(scannos);
2577  scannos -= offset;
2578  scannocol.putColumn(scannos);
2579  uInt newscanno = max(scannos)+1;
2580  ++it;
2581
2582  // new IFNO
2583  uInt ifnoCounter = max(ifnocol.getColumn()) + 1;
2584 
2585  // Here we assume that each IFNO has unique MOLECULE_ID
2586  // molIdMap:
2587  //    KEY: IFNO
2588  //    VALUE: MOLECULE_ID
2589  map<uInt, uInt> molIdMap;
2590  {
2591    TableIterator ifit(tout, "IFNO");
2592    while (!ifit.pastEnd()) {
2593      ROTableRow row(ifit.table());
2594      const TableRecord& rec = row.get(0);
2595      molIdMap[rec.asuInt("IFNO")] = rec.asuInt("MOLECULE_ID");
2596      ifit.next();
2597    }
2598  }
2599 
2600  while ( it != in.end() ){
2601    // Check FREQUENCIES/BASEFRAME
2602    if ( out->frequencies().getFrame(true) != (*it)->frequencies().getFrame(true) ) {
2603      throw(AipsError("BASEFRAME is not identical"));
2604    }
2605   
2606    if ( ! (*it)->conformant(*out) ) {
2607      // non conformant.
2608      LogIO os( LogOrigin( "STMath", "merge()", WHERE ) ) ;
2609      os << LogIO::SEVERE << "Can't merge scantables as header informations (any one of AntennaName, Equinox, and FluxUnit) differ." << LogIO::EXCEPTION ;
2610    }
2611    out->appendToHistoryTable((*it)->history());
2612    const Table& tab = (*it)->table();
2613
2614    Block<String> cols(3);
2615    cols[0] = String("FREQ_ID");
2616    cols[1] = String("MOLECULE_ID");
2617    cols[2] = String("FOCUS_ID");
2618   
2619    TableIterator scanit(tab, "SCANNO");
2620    while (!scanit.pastEnd()) {
2621      TableIterator subit(scanit.table(), cols);
2622      while ( !subit.pastEnd() ) {
2623        uInt nrow = tout.nrow();
2624        Table thetab = subit.table();
2625        ROTableRow row(thetab);
2626        Vector<uInt> thecolvals(thetab.nrow());
2627        // The selected subset of table should have
2628        // the equal FREQ_ID, MOLECULE_ID, and FOCUS_ID values.
2629        const TableRecord& rec = row.get(0);
2630        tout.addRow(thetab.nrow());
2631        TableCopy::copyRows(tout, thetab, nrow, 0, thetab.nrow());
2632
2633        Slicer slice(IPosition(1, nrow), IPosition(1, thetab.nrow()),
2634                     Slicer::endIsLength);
2635
2636        // Set the proper FREQ_ID
2637        Double rv,rp,inc;
2638        (*it)->frequencies().getEntry(rp, rv, inc, rec.asuInt("FREQ_ID"));
2639        uInt id;
2640       
2641        // default value is new unique IFNO
2642        uInt newifno = ifnoCounter;
2643        Bool isIfMerged = False;
2644        uInt nchan = rec.asArrayFloat("SPECTRA").shape()[0];
2645        //id = out->frequencies().addEntry(rp, rv, inc);
2646        if ( !out->frequencies().match(rp, rv, inc, freqTolInHz, id) ) {
2647          // add new entry to FREQUENCIES table
2648          id = out->frequencies().addEntry(rp, rv, inc);
2649
2650          // increment counter for IFNO
2651          ifnoCounter++;
2652        }
2653        else {
2654          // should renumber IFNO to be same as existing rows that have same FREQ_ID
2655          LogIO os(LogOrigin("STMath", "merge", WHERE));
2656          Table outFreqIdSelected = tout(tout.col("FREQ_ID") == id);
2657          TableIterator _iter(outFreqIdSelected, "IFNO");
2658          map<uInt, uInt> nchanMap;
2659          while (!_iter.pastEnd()) {
2660            const Table _table = _iter.table();
2661            ROTableRow _row(_table);
2662            const TableRecord &_rec = _row.get(0);
2663            uInt nchan = _rec.asArrayFloat("SPECTRA").shape()[0];
2664            if (nchanMap.find(nchan) != nchanMap.end()) {
2665              throw(AipsError("There are non-unique IFNOs assigned to spectra that have same FREQ_ID and same nchan. Something wrong."));
2666            }
2667            nchanMap[nchan] = _rec.asuInt("IFNO");
2668            _iter.next();
2669          }
2670
2671          os << LogIO::DEBUGGING << "nchanMap for " << id << ":" << LogIO::POST;
2672          for (map<uInt, uInt>::iterator i = nchanMap.begin(); i != nchanMap.end(); ++i) {
2673            os << LogIO::DEBUGGING << "nchanMap[" << i->first << "] = " << i->second << LogIO::POST;
2674          }
2675
2676          if (nchanMap.find(nchan) == nchanMap.end()) {
2677            // increment counter for IFNO
2678            ifnoCounter++;
2679          }
2680          else {
2681            // renumber IFNO to be same as existing value that corresponds to nchan
2682            newifno = nchanMap[nchan];
2683            isIfMerged = True;
2684          }
2685          os << LogIO::DEBUGGING << "newifno = " << newifno << LogIO::POST;
2686        }
2687        thecolvals = id;
2688        freqidcol.putColumnRange(slice, thecolvals);
2689
2690        thecolvals = newifno;
2691        ifnocol.putColumnRange(slice, thecolvals);
2692       
2693        // Set the proper MOLECULE_ID
2694        Vector<String> name,fname;Vector<Double> rf;
2695        (*it)->molecules().getEntry(rf, name, fname, rec.asuInt("MOLECULE_ID"));
2696        id = out->molecules().addEntry(rf, name, fname);
2697        if (molIdMap.find(newifno) == molIdMap.end()) {
2698          // add new entry to molIdMap
2699          molIdMap[newifno] = id;
2700        }
2701        if (isIfMerged) {
2702          id = molIdMap[newifno];
2703        }
2704        thecolvals = id;
2705        molidcol.putColumnRange(slice, thecolvals);
2706       
2707        // Set the proper FOCUS_ID
2708        Float fpa,frot,fax,ftan,fhand,fmount,fuser, fxy, fxyp;
2709        (*it)->focus().getEntry(fpa, fax, ftan, frot, fhand, fmount,fuser,
2710                                fxy, fxyp, rec.asuInt("FOCUS_ID"));
2711        id = out->focus().addEntry(fpa, fax, ftan, frot, fhand, fmount,fuser,
2712                                   fxy, fxyp);
2713        thecolvals = id;
2714        focusidcol.putColumnRange(slice, thecolvals);
2715
2716        // Set the proper SCANNO
2717        thecolvals = newscanno;
2718        scannocol.putColumnRange(slice, thecolvals);
2719
2720        ++subit;
2721      }
2722      ++newscanno;
2723      ++scanit;
2724    }
2725    ++it;
2726  }
2727  return out;
2728}
2729
2730CountedPtr< Scantable >
2731  STMath::invertPhase( const CountedPtr < Scantable >& in )
2732{
2733  return applyToPol(in, &STPol::invertPhase, Float(0.0));
2734}
2735
2736CountedPtr< Scantable >
2737  STMath::rotateXYPhase( const CountedPtr < Scantable >& in, float phase )
2738{
2739   return applyToPol(in, &STPol::rotatePhase, Float(phase));
2740}
2741
2742CountedPtr< Scantable >
2743  STMath::rotateLinPolPhase( const CountedPtr < Scantable >& in, float phase )
2744{
2745  return applyToPol(in, &STPol::rotateLinPolPhase, Float(phase));
2746}
2747
2748CountedPtr< Scantable > STMath::applyToPol( const CountedPtr<Scantable>& in,
2749                                             STPol::polOperation fptr,
2750                                             Float phase )
2751{
2752  CountedPtr< Scantable > out = getScantable(in, false);
2753  Table& tout = out->table();
2754  Block<String> cols(4);
2755  cols[0] = String("SCANNO");
2756  cols[1] = String("BEAMNO");
2757  cols[2] = String("IFNO");
2758  cols[3] = String("CYCLENO");
2759  TableIterator iter(tout, cols);
2760  CountedPtr<STPol> stpol = STPol::getPolClass(out->factories_,
2761                                               out->getPolType() );
2762  while (!iter.pastEnd()) {
2763    Table t = iter.table();
2764    ArrayColumn<Float> speccol(t, "SPECTRA");
2765    ScalarColumn<uInt> focidcol(t, "FOCUS_ID");
2766    Matrix<Float> pols(speccol.getColumn());
2767    try {
2768      stpol->setSpectra(pols);
2769      Float fang,fhand;
2770      fang = in->focusTable_.getTotalAngle(focidcol(0));
2771      fhand = in->focusTable_.getFeedHand(focidcol(0));
2772      stpol->setPhaseCorrections(fang, fhand);
2773      // use a member function pointer in STPol.  This only works on
2774      // the STPol pointer itself, not the Counted Pointer so
2775      // derefernce it.
2776      (&(*(stpol))->*fptr)(phase);
2777      speccol.putColumn(stpol->getSpectra());
2778    } catch (AipsError& e) {
2779      //delete stpol;stpol=0;
2780      throw(e);
2781    }
2782    ++iter;
2783  }
2784  //delete stpol;stpol=0;
2785  return out;
2786}
2787
2788CountedPtr< Scantable >
2789  STMath::swapPolarisations( const CountedPtr< Scantable > & in )
2790{
2791  CountedPtr< Scantable > out = getScantable(in, false);
2792  Table& tout = out->table();
2793  Table t0 = tout(tout.col("POLNO") == 0);
2794  Table t1 = tout(tout.col("POLNO") == 1);
2795  if ( t0.nrow() != t1.nrow() )
2796    throw(AipsError("Inconsistent number of polarisations"));
2797  ArrayColumn<Float> speccol0(t0, "SPECTRA");
2798  ArrayColumn<uChar> flagcol0(t0, "FLAGTRA");
2799  ArrayColumn<Float> speccol1(t1, "SPECTRA");
2800  ArrayColumn<uChar> flagcol1(t1, "FLAGTRA");
2801  Matrix<Float> s0 = speccol0.getColumn();
2802  Matrix<uChar> f0 = flagcol0.getColumn();
2803  speccol0.putColumn(speccol1.getColumn());
2804  flagcol0.putColumn(flagcol1.getColumn());
2805  speccol1.putColumn(s0);
2806  flagcol1.putColumn(f0);
2807  return out;
2808}
2809
2810CountedPtr< Scantable >
2811  STMath::averagePolarisations( const CountedPtr< Scantable > & in,
2812                                const std::vector<bool>& mask,
2813                                const std::string& weight )
2814{
2815  if (in->npol() < 2 )
2816    throw(AipsError("averagePolarisations can only be applied to two or more"
2817                    "polarisations"));
2818  bool insitu = insitu_;
2819  setInsitu(false);
2820  CountedPtr< Scantable > pols = getScantable(in, true);
2821  setInsitu(insitu);
2822  Table& tout = pols->table();
2823  std::string taql = "SELECT FROM $1 WHERE POLNO IN [0,1]";
2824  Table tab = tableCommand(taql, in->table());
2825  if (tab.nrow() == 0 )
2826    throw(AipsError("Could not find  any rows with POLNO==0 and POLNO==1"));
2827  TableCopy::copyRows(tout, tab);
2828  TableVector<uInt> vec(tout, "POLNO");
2829  vec = 0;
2830  pols->table_.rwKeywordSet().define("nPol", Int(1));
2831  pols->table_.rwKeywordSet().define("POLTYPE", String("stokes"));
2832  //pols->table_.rwKeywordSet().define("POLTYPE", in->getPolType());
2833  std::vector<CountedPtr<Scantable> > vpols;
2834  vpols.push_back(pols);
2835  CountedPtr< Scantable > out = average(vpols, mask, weight, "SCAN");
2836  return out;
2837}
2838
2839CountedPtr< Scantable >
2840  STMath::averageBeams( const CountedPtr< Scantable > & in,
2841                        const std::vector<bool>& mask,
2842                        const std::string& weight )
2843{
2844  bool insitu = insitu_;
2845  setInsitu(false);
2846  CountedPtr< Scantable > beams = getScantable(in, false);
2847  setInsitu(insitu);
2848  Table& tout = beams->table();
2849  // give all rows the same BEAMNO
2850  TableVector<uInt> vec(tout, "BEAMNO");
2851  vec = 0;
2852  beams->table_.rwKeywordSet().define("nBeam", Int(1));
2853  std::vector<CountedPtr<Scantable> > vbeams;
2854  vbeams.push_back(beams);
2855  CountedPtr< Scantable > out = average(vbeams, mask, weight, "SCAN");
2856  return out;
2857}
2858
2859
2860CountedPtr< Scantable >
2861  asap::STMath::frequencyAlign( const CountedPtr< Scantable > & in,
2862                                const std::string & refTime,
2863                                const std::string & method)
2864{
2865  LogIO os( casa::LogOrigin("STMath", "frequencyAlign()", WHERE));
2866  // clone as this is not working insitu
2867  bool insitu = insitu_;
2868  setInsitu(false);
2869  CountedPtr< Scantable > out = getScantable(in, false);
2870  setInsitu(insitu);
2871  Table& tout = out->table();
2872  // Get reference Epoch to time of first row or given String
2873  Unit DAY(String("d"));
2874  MEpoch::Ref epochRef(in->getTimeReference());
2875  MEpoch refEpoch;
2876  if (refTime.length()>0) {
2877    Quantum<Double> qt;
2878    if (MVTime::read(qt,refTime)) {
2879      MVEpoch mv(qt);
2880      refEpoch = MEpoch(mv, epochRef);
2881   } else {
2882      throw(AipsError("Invalid format for Epoch string"));
2883   }
2884  } else {
2885    refEpoch = in->timeCol_(0);
2886  }
2887  MPosition refPos = in->getAntennaPosition();
2888
2889  InterpolateArray1D<Double,Float>::InterpolationMethod interp = stringToIMethod(method);
2890  /*
2891  // Comment from MV.
2892  // the following code has been commented out because different FREQ_IDs have to be aligned together even
2893  // if the frame doesn't change. So far, lack of this check didn't cause any problems.
2894  // test if user frame is different to base frame
2895  if ( in->frequencies().getFrameString(true)
2896       == in->frequencies().getFrameString(false) ) {
2897    throw(AipsError("Can't convert as no output frame has been set"
2898                    " (use set_freqframe) or it is aligned already."));
2899  }
2900  */
2901  MFrequency::Types system = in->frequencies().getFrame();
2902  MVTime mvt(refEpoch.getValue());
2903  String epochout = mvt.string(MVTime::YMD) + String(" (") + refEpoch.getRefString() + String(")");
2904  os << "Aligning at reference Epoch " << epochout
2905     << " in frame " << MFrequency::showType(system) << LogIO::POST;
2906  // set up the iterator
2907  Block<String> cols(4);
2908  // select by constant direction
2909  cols[0] = String("SRCNAME");
2910  cols[1] = String("BEAMNO");
2911  // select by IF ( no of channels varies over this )
2912  cols[2] = String("IFNO");
2913  // select by restfrequency
2914  cols[3] = String("MOLECULE_ID");
2915  TableIterator iter(tout, cols);
2916  while ( !iter.pastEnd() ) {
2917    Table t = iter.table();
2918    ROScalarColumn<String> snCol(t, "SRCNAME");
2919    os << "Aligning to position of source '" << snCol(0) << "'" << LogIO::POST;
2920    MDirection::ROScalarColumn dirCol(t, "DIRECTION");
2921    TableIterator fiter(t, "FREQ_ID");
2922    // determine nchan from the first row. This should work as
2923    // we are iterating over BEAMNO and IFNO   
2924    // we should have constant direction
2925
2926    ROArrayColumn<Float> sCol(t, "SPECTRA");
2927    const MDirection direction = dirCol(0);
2928    const uInt nchan = sCol(0).nelements();
2929
2930    // skip operations if there is nothing to align
2931    if (fiter.pastEnd()) {
2932        continue;
2933    }
2934
2935    Table ftab = fiter.table();
2936    // align all frequency ids with respect to the first encountered id
2937    ScalarColumn<uInt> freqidCol(ftab, "FREQ_ID");
2938    // get the SpectralCoordinate for the freqid, which we are iterating over
2939    SpectralCoordinate sC = \
2940      in->frequencies().getSpectralCoordinate(freqidCol(0));
2941    FrequencyAligner<Float> fa( sC, nchan, refEpoch,
2942                                direction, refPos, system );
2943    // realign the SpectralCoordinate and put into the output Scantable
2944    Vector<String> units(1);
2945    units = String("Hz");
2946    Bool linear=True;
2947    SpectralCoordinate sc2 = fa.alignedSpectralCoordinate(linear);
2948    sc2.setWorldAxisUnits(units);
2949    const uInt id = out->frequencies().addEntry(sc2.referencePixel()[0],
2950                                                sc2.referenceValue()[0],
2951                                                sc2.increment()[0]);
2952    while ( !fiter.pastEnd() ) {
2953     
2954      ftab = fiter.table();
2955      // spectral coordinate for the current FREQ_ID
2956      ScalarColumn<uInt> freqidCol2(ftab, "FREQ_ID");
2957      sC = in->frequencies().getSpectralCoordinate(freqidCol2(0));
2958      // create the "global" abcissa for alignment with same FREQ_ID
2959      Vector<Double> abc(nchan);
2960      for (uInt i=0; i<nchan; i++) {
2961           Double w;
2962           sC.toWorld(w,Double(i));
2963           abc[i] = w;
2964      }
2965      TableVector<uInt> tvec(ftab, "FREQ_ID");
2966      // assign new frequency id to all rows
2967      tvec = id;
2968      // cache abcissa for same time stamps, so iterate over those
2969      TableIterator timeiter(ftab, "TIME");
2970      while ( !timeiter.pastEnd() ) {
2971        Table tab = timeiter.table();
2972        ArrayColumn<Float> specCol(tab, "SPECTRA");
2973        ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
2974        MEpoch::ROScalarColumn timeCol(tab, "TIME");
2975        // use align abcissa cache after the first row
2976        // these rows should be just be POLNO
2977        bool first = true;
2978        for (int i=0; i<int(tab.nrow()); ++i) {
2979          // input values
2980          Vector<uChar> flag = flagCol(i);
2981          Vector<Bool> mask(flag.shape());
2982          Vector<Float> specOut, spec;
2983          spec  = specCol(i);
2984          Vector<Bool> maskOut;Vector<uChar> flagOut;
2985          convertArray(mask, flag);
2986          // alignment
2987          Bool ok = fa.align(specOut, maskOut, abc, spec,
2988                             mask, timeCol(i), !first,
2989                             interp, False);
2990          (void) ok; // unused stop compiler nagging
2991          // back into scantable
2992          flagOut.resize(maskOut.nelements());
2993          convertArray(flagOut, maskOut);
2994          flagCol.put(i, flagOut);
2995          specCol.put(i, specOut);
2996          // start abcissa caching
2997          first = false;
2998        }
2999        // next timestamp
3000        ++timeiter;
3001      }
3002      // next FREQ_ID
3003      ++fiter;
3004    }
3005    // next aligner
3006    ++iter;
3007  }
3008  // set this afterwards to ensure we are doing insitu correctly.
3009  out->frequencies().setFrame(system, true);
3010  return out;
3011}
3012
3013CountedPtr<Scantable>
3014  asap::STMath::convertPolarisation( const CountedPtr<Scantable>& in,
3015                                     const std::string & newtype )
3016{
3017  if (in->npol() != 2 && in->npol() != 4)
3018    throw(AipsError("Can only convert two or four polarisations."));
3019  if ( in->getPolType() == newtype )
3020    throw(AipsError("No need to convert."));
3021  if ( ! in->selector_.empty() )
3022    throw(AipsError("Can only convert whole scantable. Unset the selection."));
3023  bool insitu = insitu_;
3024  setInsitu(false);
3025  CountedPtr< Scantable > out = getScantable(in, true);
3026  setInsitu(insitu);
3027  Table& tout = out->table();
3028  tout.rwKeywordSet().define("POLTYPE", String(newtype));
3029
3030  Block<String> cols(4);
3031  cols[0] = "SCANNO";
3032  cols[1] = "CYCLENO";
3033  cols[2] = "BEAMNO";
3034  cols[3] = "IFNO";
3035  TableIterator it(in->originalTable_, cols);
3036  String basetype = in->getPolType();
3037  STPol* stpol = STPol::getPolClass(in->factories_, basetype);
3038  try {
3039    while ( !it.pastEnd() ) {
3040      Table tab = it.table();
3041      uInt row = tab.rowNumbers()[0];
3042      stpol->setSpectra(in->getPolMatrix(row));
3043      Float fang,fhand;
3044      fang = in->focusTable_.getTotalAngle(in->mfocusidCol_(row));
3045      fhand = in->focusTable_.getFeedHand(in->mfocusidCol_(row));
3046      stpol->setPhaseCorrections(fang, fhand);
3047      Int npolout = 0;
3048      for (uInt i=0; i<tab.nrow(); ++i) {
3049        Vector<Float> outvec = stpol->getSpectrum(i, newtype);
3050        if ( outvec.nelements() > 0 ) {
3051          tout.addRow();
3052          TableCopy::copyRows(tout, tab, tout.nrow()-1, 0, 1);
3053          ArrayColumn<Float> sCol(tout,"SPECTRA");
3054          ScalarColumn<uInt> pCol(tout,"POLNO");
3055          sCol.put(tout.nrow()-1 ,outvec);
3056          pCol.put(tout.nrow()-1 ,uInt(npolout));
3057          npolout++;
3058       }
3059      }
3060      tout.rwKeywordSet().define("nPol", npolout);
3061      ++it;
3062    }
3063  } catch (AipsError& e) {
3064    delete stpol;
3065    throw(e);
3066  }
3067  delete stpol;
3068  return out;
3069}
3070
3071CountedPtr< Scantable >
3072  asap::STMath::mxExtract( const CountedPtr< Scantable > & in,
3073                           const std::string & scantype )
3074{
3075  bool insitu = insitu_;
3076  setInsitu(false);
3077  CountedPtr< Scantable > out = getScantable(in, true);
3078  setInsitu(insitu);
3079  Table& tout = out->table();
3080  std::string taql = "SELECT FROM $1 WHERE BEAMNO != REFBEAMNO";
3081  if (scantype == "on") {
3082    taql = "SELECT FROM $1 WHERE BEAMNO == REFBEAMNO";
3083  }
3084  Table tab = tableCommand(taql, in->table());
3085  TableCopy::copyRows(tout, tab);
3086  if (scantype == "on") {
3087    // re-index SCANNO to 0
3088    TableVector<uInt> vec(tout, "SCANNO");
3089    vec = 0;
3090  }
3091  return out;
3092}
3093
3094std::vector<float>
3095  asap::STMath::fft( const casa::CountedPtr< Scantable > & in,
3096                     const std::vector<int>& whichrow,
3097                     bool getRealImag )
3098{
3099  std::vector<float> res;
3100  Table tab = in->table();
3101  std::vector<bool> mask;
3102
3103  if (whichrow.size() < 1) {          // for all rows (by default)
3104    int nrow = int(tab.nrow());
3105    for (int i = 0; i < nrow; ++i) {
3106      res = in->execFFT(i, mask, getRealImag);
3107    }
3108  } else {                           // for specified rows
3109    for (uInt i = 0; i < whichrow.size(); ++i) {
3110      res = in->execFFT(i, mask, getRealImag);
3111    }
3112  }
3113
3114  return res;
3115}
3116
3117
3118CountedPtr<Scantable>
3119  asap::STMath::lagFlag( const CountedPtr<Scantable>& in,
3120                         double start, double end,
3121                         const std::string& mode )
3122{
3123  CountedPtr<Scantable> out = getScantable(in, false);
3124  Table& tout = out->table();
3125  TableIterator iter(tout, "FREQ_ID");
3126  FFTServer<Float,Complex> ffts;
3127
3128  while ( !iter.pastEnd() ) {
3129    Table tab = iter.table();
3130    Double rp,rv,inc;
3131    ROTableRow row(tab);
3132    const TableRecord& rec = row.get(0);
3133    uInt freqid = rec.asuInt("FREQ_ID");
3134    out->frequencies().getEntry(rp, rv, inc, freqid);
3135    ArrayColumn<Float> specCol(tab, "SPECTRA");
3136    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
3137
3138    for (int i=0; i<int(tab.nrow()); ++i) {
3139      Vector<Float> spec = specCol(i);
3140      Vector<uChar> flag = flagCol(i);
3141      std::vector<bool> mask;
3142      for (uInt j = 0; j < flag.nelements(); ++j) {
3143        mask.push_back(!(flag[j]>0));
3144      }
3145      mathutil::doZeroOrderInterpolation(spec, mask);
3146
3147      Vector<Complex> lags;
3148      ffts.fft0(lags, spec);
3149
3150      Int lag0(start+0.5);
3151      Int lag1(end+0.5);
3152      if (mode == "frequency") {
3153        lag0 = Int(spec.nelements()*abs(inc)/(start)+0.5);
3154        lag1 = Int(spec.nelements()*abs(inc)/(end)+0.5);
3155      }
3156      Int lstart =  max(0, lag0);
3157      Int lend   =  min(Int(lags.nelements()-1), lag1);
3158      if (lstart == lend) {
3159        lags[lstart] = Complex(0.0);
3160      } else {
3161        if (lstart > lend) {
3162          Int tmp = lend;
3163          lend = lstart;
3164          lstart = tmp;
3165        }
3166        for (int j=lstart; j <=lend ;++j) {
3167          lags[j] = Complex(0.0);
3168        }
3169      }
3170
3171      ffts.fft0(spec, lags);
3172
3173      specCol.put(i, spec);
3174    }
3175    ++iter;
3176  }
3177  return out;
3178}
3179
3180// Averaging spectra with different channel/resolution
3181CountedPtr<Scantable>
3182STMath::new_average( const std::vector<CountedPtr<Scantable> >& in,
3183                     const bool& compel,
3184                     const std::vector<bool>& mask,
3185                     const std::string& weight,
3186                     const std::string& avmode )
3187  throw ( casa::AipsError )
3188{
3189  LogIO os( LogOrigin( "STMath", "new_average()", WHERE ) ) ;
3190  if ( avmode == "SCAN" && in.size() != 1 )
3191    throw(AipsError("Can't perform 'SCAN' averaging on multiple tables.\n"
3192                    "Use merge first."));
3193 
3194  CountedPtr<Scantable> out ;     // processed result
3195  if ( compel ) {
3196    std::vector< CountedPtr<Scantable> > newin ; // input for average process
3197    uInt insize = in.size() ;    // number of input scantables
3198
3199    // setup newin
3200    bool oldInsitu = insitu_ ;
3201    setInsitu( false ) ;
3202    newin.resize( insize ) ;
3203    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3204      newin[itable] = getScantable( in[itable], false ) ;
3205    }
3206    setInsitu( oldInsitu ) ;
3207
3208    // warning
3209    os << "Average spectra with different spectral resolution" << LogIO::POST ;
3210
3211    // temporarily set coordinfo
3212    vector<string> oldinfo( insize ) ;
3213    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3214      vector<string> coordinfo = in[itable]->getCoordInfo() ;
3215      oldinfo[itable] = coordinfo[0] ;
3216      coordinfo[0] = "Hz" ;
3217      newin[itable]->setCoordInfo( coordinfo ) ;
3218    }
3219
3220    ostringstream oss ;
3221
3222    // check IF frequency coverage
3223    // freqid: list of FREQ_ID, which is used, in each table 
3224    // iffreq: list of minimum and maximum frequency for each FREQ_ID in
3225    //         each table
3226    // freqid[insize][numIF]
3227    // freqid: [[id00, id01, ...],
3228    //          [id10, id11, ...],
3229    //          ...
3230    //          [idn0, idn1, ...]]
3231    // iffreq[insize][numIF*2]
3232    // iffreq: [[min_id00, max_id00, min_id01, max_id01, ...],
3233    //          [min_id10, max_id10, min_id11, max_id11, ...],
3234    //          ...
3235    //          [min_idn0, max_idn0, min_idn1, max_idn1, ...]]
3236    //os << "Check IF settings in each table" << LogIO::POST ;
3237    vector< vector<uInt> > freqid( insize );
3238    vector< vector<double> > iffreq( insize ) ;
3239    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3240      Vector<uInt> freqIds = newin[itable]->mfreqidCol_.getColumn() ;
3241      vector<uInt> uniqueFreqId = newin[itable]->getNumbers(newin[itable]->mfreqidCol_) ;
3242      for ( vector<uInt>::iterator i = uniqueFreqId.begin() ;
3243            i != uniqueFreqId.end() ; i++ ) {
3244        //os << "itable = " << itable << ": IF " << id << " is included in the list" << LogIO::POST ;
3245        uInt target = 0 ;
3246        while ( freqIds[target] != *i )
3247          target++ ;
3248        vector<double> abcissa = newin[itable]->getAbcissa( target ) ;
3249        freqid[itable].push_back( *i ) ;
3250        double incr = abs( abcissa[1] - abcissa[0] ) ;
3251        iffreq[itable].push_back( (*min_element(abcissa.begin(),abcissa.end()))-0.5*incr ) ;
3252        iffreq[itable].push_back( (*max_element(abcissa.begin(),abcissa.end()))+0.5*incr ) ;
3253      }
3254    }
3255
3256    // debug
3257//     os << "IF settings summary:" << endl ;
3258//     for ( uInt i = 0 ; i < freqid.size() ; i++ ) {
3259//       os << "   Table" << i << endl ;
3260//       for ( uInt j = 0 ; j < freqid[i].size() ; j++ ) {
3261//         os << "      id = " << freqid[i][j] << " (min,max) = (" << iffreq[i][2*j] << "," << iffreq[i][2*j+1] << ")" << endl ;
3262//       }
3263//     }
3264//     os << endl ;
3265//     os.post() ;
3266
3267    // IF grouping based on their frequency coverage
3268    // ifgrp: number of member in each IF group
3269    // ifgrp[numgrp]
3270    // ifgrp: [n0, n1, ...]
3271    //os << "IF grouping based on their frequency coverage" << LogIO::POST ;
3272
3273    // parameter for IF grouping
3274    // groupmode = OR    retrieve all region
3275    //             AND   only retrieve overlaped region
3276    //string groupmode = "AND" ;
3277    string groupmode = "OR" ;
3278    uInt sizecr = 0 ;
3279    if ( groupmode == "AND" )
3280      sizecr = 1 ;
3281    else if ( groupmode == "OR" )
3282      sizecr = 0 ;
3283
3284    vector<double> sortedfreq ;
3285    for ( uInt i = 0 ; i < iffreq.size() ; i++ ) {
3286      for ( uInt j = 0 ; j < iffreq[i].size() ; j++ ) {
3287        if ( count( sortedfreq.begin(), sortedfreq.end(), iffreq[i][j] ) == 0 )
3288          sortedfreq.push_back( iffreq[i][j] ) ;
3289      }
3290    }
3291    sort( sortedfreq.begin(), sortedfreq.end() ) ;
3292    vector<uInt> ifgrp( sortedfreq.size()-1, 0 ) ;
3293    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3294      for ( uInt iif = 0 ; iif < freqid[itable].size() ; iif++ ) {
3295        double range0 = iffreq[itable][2*iif] ;
3296        double range1 = iffreq[itable][2*iif+1] ;
3297        for ( uInt j = 0 ; j < sortedfreq.size()-1 ; j++ ) {
3298          double fmin = max( range0, sortedfreq[j] ) ;
3299          double fmax = min( range1, sortedfreq[j+1] ) ;
3300          if ( fmin < fmax ) {
3301            ifgrp[j]++ ;
3302          }
3303        }
3304      }
3305    }
3306
3307    // Grouping continuous IF groups (without frequency gap)
3308    // freqgrp: list of IF group indexes in each frequency group
3309    // freqgrp[numgrp][nummember]
3310    // freqgrp: [[ifgrp00, ifgrp01, ifgrp02, ...],
3311    //           [ifgrp10, ifgrp11, ifgrp12, ...],
3312    //           ...
3313    //           [ifgrpn0, ifgrpn1, ifgrpn2, ...]]
3314    // grprange[2*numgrp]
3315    // grprange: [fmin0,fmax0,fmin1,fmax1,...]
3316    vector< vector<uInt> > freqgrp ;
3317    vector<double> grprange ;
3318    vector<uInt> grpedge ;
3319    for ( uInt igrp = 0 ; igrp < ifgrp.size() ; igrp++ ) {
3320      if ( ifgrp[igrp] <= sizecr ) {
3321        grpedge.push_back( igrp ) ;
3322      }
3323    }
3324    grpedge.push_back( ifgrp.size() ) ;
3325    uInt itmp = 0 ;
3326    for ( uInt i = 0 ; i < grpedge.size() ; i++ ) {
3327      int n = grpedge[i] - itmp ;
3328      if ( n > 0 ) {
3329        vector<uInt> members( n ) ;
3330        for ( int j = 0 ; j < n ; j++ ) {
3331          members[j] = itmp+j ;
3332        }
3333        freqgrp.push_back( members ) ;
3334        grprange.push_back( sortedfreq[itmp] ) ;
3335        grprange.push_back( sortedfreq[grpedge[i]] ) ;
3336      }
3337      itmp += n + 1 ;
3338    }
3339
3340    // print frequency group
3341    oss.str("") ;
3342    oss << "Frequency Group summary: " << endl ;
3343    oss << "   GROUP_ID: [FREQ_MIN, FREQ_MAX]" << endl ;
3344    for ( uInt i = 0 ; i < freqgrp.size() ; i++ ) {
3345      oss << "   GROUP " << setw( 2 ) << i << ": [" << grprange[2*i] << "," << grprange[2*i+1] << "]" ;
3346      oss << endl ;
3347    }
3348    oss << endl ;
3349    os << oss.str() << LogIO::POST ;
3350
3351    // groups: list of frequency group index whose frequency range overlaps
3352    //         with that of each table and IF
3353    // groups[numtable][numIF]
3354    // groups: [[grpx, grpy,...],
3355    //          [grpa, grpb,...],
3356    //          ...
3357    //          [grpk, grpm,...]]
3358    vector< vector<uInt> > groups( insize ) ;
3359    for ( uInt i = 0 ; i < insize ; i++ ) {
3360      groups[i].resize( freqid[i].size() ) ;
3361    }
3362    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3363      for ( uInt ifreq = 0 ; ifreq < freqid[itable].size() ; ifreq++ ) {
3364        double minf = iffreq[itable][2*ifreq] ;
3365        uInt groupid ;
3366        for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3367          vector<uInt> memberlist = freqgrp[igrp] ;
3368          if ( (minf >= grprange[2*igrp]) && (minf <= grprange[2*igrp+1]) ) {
3369            groupid = igrp ;
3370            break ;
3371          }
3372        }
3373        groups[itable][ifreq] = groupid ;
3374      }
3375    }
3376                                                         
3377
3378    // print membership
3379    oss.str("") ;
3380    for ( uInt i = 0 ; i < insize ; i++ ) {
3381      oss << "Table " << i << endl ;
3382      for ( uInt j = 0 ; j < groups[i].size() ; j++ ) {
3383        oss << "   FREQ_ID " <<  setw( 2 ) << freqid[i][j] << ": " ;
3384        oss << setw( 2 ) << groups[i][j] ;
3385        oss << endl ;
3386      }
3387    }
3388    os << oss.str() << LogIO::POST ;
3389
3390    // reset SCANNO and IFNO/FREQ_ID: IF is reset by the result of sortation
3391    //os << "All IF number is set to IF group index" << LogIO::POST ;
3392    // reset SCANNO only when avmode != "SCAN"
3393    if ( avmode != "SCAN" ) {
3394      os << "All scan number is set to 0" << LogIO::POST ;
3395      for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3396        uInt nrow = newin[itable]->nrow() ;
3397        Vector<uInt> resetScan( nrow, 0 ) ;
3398        newin[itable]->scanCol_.putColumn( resetScan ) ;
3399      }
3400    }
3401
3402    // reset spectra and flagtra: align spectral resolution
3403    //os << "Align spectral resolution" << LogIO::POST ;
3404    // gmaxdnu: the coarsest frequency resolution in the frequency group
3405    // gminfreq: lower frequency edge of the frequency group
3406    // gnchan: number of channels for the frequency group
3407    vector<double> gmaxdnu( freqgrp.size(), 0.0 ) ;
3408    vector<double> gminfreq( freqgrp.size() ) ;
3409    vector<double> gnchan( freqgrp.size() ) ;
3410    for ( uInt i = 0 ; i < insize ; i++ ) {
3411      vector<uInt> members = groups[i] ;
3412      for ( uInt j = 0 ; j < members.size() ; j++ ) {
3413        uInt groupid = members[j] ;
3414        Double rp,rv,ic ;
3415        newin[i]->frequencies().getEntry( rp, rv, ic, j ) ;
3416        if ( abs(ic) > abs(gmaxdnu[groupid]) )
3417          gmaxdnu[groupid] = ic ;
3418      }
3419    }
3420    for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3421      gminfreq[igrp] = grprange[2*igrp] ;
3422      double maxfreq = grprange[2*igrp+1] ;
3423      gnchan[igrp] = (int)(abs((maxfreq-gminfreq[igrp])/gmaxdnu[igrp])+0.9) ;
3424    }
3425     
3426    // regrid spectral data and update frequency info
3427    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3428      Vector<uInt> oldFreqId = newin[itable]->mfreqidCol_.getColumn() ;
3429      Vector<uInt> newFreqId( oldFreqId.nelements() ) ;
3430
3431      // update MAIN
3432      for ( uInt irow = 0 ; irow < newin[itable]->nrow() ; irow++ ) {
3433        uInt groupid = groups[itable][oldFreqId[irow]] ;
3434        newFreqId[irow] = groupid ;
3435        newin[itable]->regridChannel( gnchan[groupid],
3436                                      gmaxdnu[groupid],
3437                                      gminfreq[groupid],
3438                                      irow ) ;
3439      }
3440      newin[itable]->mfreqidCol_.putColumn( newFreqId ) ;
3441      newin[itable]->ifCol_.putColumn( newFreqId ) ;
3442
3443      // update FREQUENCIES
3444      Table tab = newin[itable]->frequencies().table() ;
3445      ScalarColumn<uInt> fIdCol( tab, "ID" ) ;
3446      ScalarColumn<Double> fRefPixCol( tab, "REFPIX" ) ;
3447      ScalarColumn<Double> fRefValCol( tab, "REFVAL" ) ;
3448      ScalarColumn<Double> fIncrCol( tab, "INCREMENT" ) ;
3449      if ( freqgrp.size() > tab.nrow() ) {
3450        tab.addRow( freqgrp.size()-tab.nrow() ) ;
3451      }
3452      for ( uInt irow = 0 ; irow < freqgrp.size() ; irow++ ) {
3453        Double refval = gminfreq[irow] + 0.5 * abs(gmaxdnu[irow]) ;
3454        Double refpix = (gmaxdnu[irow] > 0.0) ? 0 : gnchan[irow]-1 ;
3455        Double increment = gmaxdnu[irow] ;
3456        fIdCol.put( irow, irow ) ;
3457        fRefPixCol.put( irow, refpix ) ;
3458        fRefValCol.put( irow, refval ) ;
3459        fIncrCol.put( irow, increment ) ;
3460      }
3461    }
3462
3463    // set back coordinfo
3464    for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3465      vector<string> coordinfo = newin[itable]->getCoordInfo() ;
3466      coordinfo[0] = oldinfo[itable] ;
3467      newin[itable]->setCoordInfo( coordinfo ) ;
3468    }
3469
3470    // average
3471    out = average( newin, mask, weight, avmode ) ;
3472  }
3473  else {
3474    // simple average
3475    out =  average( in, mask, weight, avmode ) ;
3476  }
3477 
3478  return out;
3479}
3480
3481CountedPtr<Scantable> STMath::cwcal( const CountedPtr<Scantable>& s,
3482                                     const String calmode,
3483                                     const String antname )
3484{
3485  // frequency switch
3486  if ( calmode == "fs" ) {
3487    return cwcalfs( s, antname ) ;
3488  }
3489  else {
3490    vector<bool> masks = s->getMask( 0 ) ;
3491    vector<int> types ;
3492
3493    // save original table selection
3494    Table torg  = s->table_ ;
3495
3496    // sky scan
3497    bool insitu = insitu_ ;
3498    insitu_ = false ;
3499    // share calibration scans before average with out
3500    CountedPtr<Scantable> out = getScantable( s, true ) ;
3501    insitu_ = insitu ;
3502    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::SKY ) ;
3503    out->attach() ;
3504    CountedPtr<Scantable> asky = averageWithinSession( out,
3505                                                       masks,
3506                                                       "TINT" ) ;
3507    // hot scan
3508    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::HOT ) ;
3509    out->attach() ;
3510    CountedPtr<Scantable> ahot = averageWithinSession( out,
3511                                                       masks,
3512                                                       "TINT" ) ;
3513    // cold scan
3514    CountedPtr<Scantable> acold ;
3515//     out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::COLD ) ;
3516//     out->attach() ;
3517//     CountedPtr<Scantable> acold = averageWithinSession( out,
3518//                                                         masks,
3519//                                                         "TINT" ) ;
3520
3521    // off scan
3522    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::PSOFF ) ;
3523    out->attach() ;
3524    CountedPtr<Scantable> aoff = averageWithinSession( out,
3525                                                       masks,
3526                                                       "TINT" ) ;
3527   
3528    // on scan
3529    s->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::PSON ) ;
3530    s->attach() ;
3531    out->table_ = out->originalTable_ ;
3532    out->attach() ;
3533    out->table().addRow( s->nrow() ) ;
3534    copyRows( out->table(), s->table(), 0, 0, s->nrow(), False, True, False ) ;
3535   
3536    // iterate throgh IterationHelper
3537    ChopperWheelCalibrator cal(out, s, aoff, asky, ahot, acold);
3538    IterationHelper<ChopperWheelCalibrator>::Iterate(cal, "BEAMNO,POLNO,IFNO");
3539
3540    s->table_ = torg ;
3541    s->attach() ;
3542
3543    // flux unit
3544    out->setFluxUnit( "K" ) ;
3545
3546    return out ;
3547  }
3548}
3549 
3550CountedPtr<Scantable> STMath::almacal( const CountedPtr<Scantable>& s,
3551                                       const String calmode )
3552{
3553  // frequency switch
3554  if ( calmode == "fs" ) {
3555    return almacalfs( s ) ;
3556  }
3557  else {
3558//     double t0, t1 ;
3559//     t0 = mathutil::gettimeofday_sec() ;
3560    vector<bool> masks = s->getMask( 0 ) ;
3561
3562    // save original table selection
3563    Table torg = s->table_ ;
3564
3565    // off scan
3566    // TODO 2010/01/08 TN
3567    // Grouping by time should be needed before averaging.
3568    // Each group must have own unique SCANNO (should be renumbered).
3569    // See PIPELINE/SDCalibration.py
3570    bool insitu = insitu_ ;
3571    insitu_ = false ;
3572    // share off scan before average with out
3573    CountedPtr<Scantable> out = getScantable( s, true ) ;
3574    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::PSOFF ) ;
3575    out->attach() ;
3576    insitu_ = insitu ;
3577    CountedPtr<Scantable> aoff = averageWithinSession( out,
3578                                                       masks,
3579                                                       "TINT" ) ;
3580
3581    // on scan
3582//     t0 = mathutil::gettimeofday_sec() ;
3583    s->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::PSON ) ;
3584    s->attach() ;
3585    out->table_ = out->originalTable_ ;
3586    out->attach() ;
3587    out->table().addRow( s->nrow() ) ;
3588    copyRows( out->table(), s->table(), 0, 0, s->nrow(), False ) ;
3589//     t1 = mathutil::gettimeofday_sec() ;
3590//     cout << "elapsed time for preparing output table: " << t1-t0 << " sec" << endl ;
3591
3592    // process each on scan
3593//     t0 = mathutil::gettimeofday_sec() ;
3594
3595    // iterate throgh IterationHelper
3596    AlmaCalibrator cal(out, s, aoff);
3597    IterationHelper<AlmaCalibrator>::Iterate(cal, "BEAMNO,POLNO,IFNO");
3598
3599    // finalize
3600    s->table_ = torg ;
3601    s->attach() ;
3602
3603//     t1 = mathutil::gettimeofday_sec() ;
3604//     cout << "elapsed time for calibration: " << t1-t0 << " sec" << endl ;
3605
3606    // flux unit
3607    out->setFluxUnit( "K" ) ;
3608
3609    return out ;
3610  }
3611}
3612
3613CountedPtr<Scantable> STMath::cwcalfs( const CountedPtr<Scantable>& s,
3614                                       const String antname )
3615{
3616  vector<int> types ;
3617
3618  // APEX calibration mode
3619  int apexcalmode = 1 ;
3620 
3621  if ( antname.find( "APEX" ) != string::npos ) {
3622    // check if off scan exists or not
3623    STSelector sel = STSelector() ;
3624    //sel.setName( offstr1 ) ;
3625    types.push_back( SrcType::FLOOFF ) ;
3626    sel.setTypes( types ) ;
3627    try {
3628      s->setSelection( sel ) ;
3629    }
3630    catch ( AipsError &e ) {
3631      apexcalmode = 0 ;
3632    }
3633    sel.reset() ;
3634  }
3635  s->unsetSelection() ;
3636  types.clear() ;
3637
3638  vector<bool> masks = s->getMask( 0 ) ;
3639  CountedPtr<Scantable> ssig, sref ;
3640  //CountedPtr<Scantable> out ;
3641  bool insitu = insitu_ ;
3642  insitu_ = False ;
3643  CountedPtr<Scantable> out = getScantable( s, true ) ;
3644  insitu_ = insitu ;
3645
3646  if ( antname.find( "APEX" ) != string::npos ) {
3647    // APEX calibration
3648    // sky scan
3649    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FLOSKY ) ;
3650    out->attach() ;
3651    CountedPtr<Scantable> askylo = averageWithinSession( out,
3652                                                         masks,
3653                                                         "TINT" ) ;
3654    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FHISKY ) ;
3655    out->attach() ;
3656    CountedPtr<Scantable> askyhi = averageWithinSession( out,
3657                                                         masks,
3658                                                         "TINT" ) ;
3659   
3660    // hot scan
3661    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FLOHOT ) ;
3662    out->attach() ;
3663    CountedPtr<Scantable> ahotlo = averageWithinSession( out,
3664                                                         masks,
3665                                                         "TINT" ) ;
3666    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FHIHOT ) ;
3667    out->attach() ;
3668    CountedPtr<Scantable> ahothi = averageWithinSession( out,
3669                                                         masks,
3670                                                         "TINT" ) ;
3671   
3672    // cold scan
3673    CountedPtr<Scantable> acoldlo, acoldhi ;
3674//     out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FLOCOLD ) ;
3675//     out->attach() ;
3676//     CountedPtr<Scantable> acoldlo = averageWithinSession( out,
3677//                                                           masks,
3678//                                                           "TINT" ) ;
3679//     out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FHICOLD ) ;
3680//     out->attach() ;
3681//     CountedPtr<Scantable> acoldhi = averageWithinSession( out,
3682//                                                           masks,
3683//                                                           "TINT" ) ;
3684
3685    // ref scan
3686    insitu_ = false ;
3687    sref = getScantable( s, true ) ;
3688    CountedPtr<Scantable> rref = getScantable( s, true ) ;
3689    insitu_ = insitu ;
3690    rref->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FSLO ) ;
3691    rref->attach() ;
3692    copyRows( sref->table_, rref->table_, 0, 0, rref->nrow(), False, True, False ) ;
3693   
3694    // sig scan
3695    insitu_ = false ;
3696    ssig = getScantable( s, true ) ;
3697    CountedPtr<Scantable> rsig = getScantable( s, true ) ;
3698    insitu_ = insitu ;
3699    rsig->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FSHI ) ;
3700    rsig->attach() ;
3701    copyRows( ssig->table_, rsig->table_, 0, 0, rsig->nrow(), False, True, False ) ;
3702         
3703    if ( apexcalmode == 0 ) {
3704      // using STIdxIter2
3705      vector<string> cols( 3 ) ;
3706      cols[0] = "BEAMNO" ;
3707      cols[1] = "POLNO" ;
3708      cols[2] = "IFNO" ;
3709      STIdxIter2 iter(ssig, cols) ;
3710      STSelector sel ;
3711      vector< CountedPtr<Scantable> > on( 2 ) ;
3712      on[0] = rsig ;
3713      on[1] = rref ;
3714      vector< CountedPtr<Scantable> > sky( 2 ) ;
3715      sky[0] = askylo ;
3716      sky[1] = askyhi ;
3717      vector< CountedPtr<Scantable> > hot( 2 ) ;
3718      hot[0] = ahotlo ;
3719      hot[1] = ahothi ;
3720      vector< CountedPtr<Scantable> > cold( 2 ) ;
3721      while ( !iter.pastEnd() ) {
3722        Record ids = iter.currentValue() ;
3723        stringstream ss ;
3724        ss << "SELECT FROM $1 WHERE "
3725           << "BEAMNO==" << ids.asuInt("BEAMNO") << "&&"
3726           << "POLNO==" << ids.asuInt("POLNO") << "&&"
3727           << "IFNO==" << ids.asuInt("IFNO") ;
3728        //cout << "TaQL string: " << ss.str() << endl ;
3729        sel.setTaQL( ss.str() ) ;
3730        sky[0]->setSelection( sel ) ;
3731        sky[1]->setSelection( sel ) ;
3732        hot[0]->setSelection( sel ) ;
3733        hot[1]->setSelection( sel ) ;
3734        Vector<uInt> rows = iter.getRows( SHARE ) ;
3735        calibrateAPEXFS( ssig, sref, on, sky, hot, cold, rows ) ;
3736        sky[0]->unsetSelection() ;
3737        sky[1]->unsetSelection() ;
3738        hot[0]->unsetSelection() ;
3739        hot[1]->unsetSelection() ;
3740        sel.reset() ;
3741        iter.next() ;
3742      }
3743
3744    }
3745    else if ( apexcalmode == 1 ) {
3746      // APEX fs data with off scan
3747      // off scan
3748      out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FLOOFF ) ;
3749      out->attach() ;
3750      CountedPtr<Scantable> aofflo = averageWithinSession( out,
3751                                                           masks,
3752                                                           "TINT" ) ;
3753      out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::FHIOFF ) ;
3754      out->attach() ;
3755      CountedPtr<Scantable> aoffhi = averageWithinSession( out,
3756                                                           masks,
3757                                                           "TINT" ) ;
3758     
3759      // process each sig and ref scan
3760      // iterate throgh IterationHelper
3761      ChopperWheelCalibrator cal_sig(ssig, rsig, aofflo, askylo, ahotlo, acoldlo);
3762      IterationHelper<ChopperWheelCalibrator>::Iterate(cal_sig, "BEAMNO,POLNO,IFNO");
3763      ChopperWheelCalibrator cal_ref(sref, rref, aoffhi, askyhi, ahothi, acoldhi);
3764      IterationHelper<ChopperWheelCalibrator>::Iterate(cal_ref, "BEAMNO,POLNO,IFNO");
3765    }
3766  }
3767  else {
3768    // non-APEX fs data
3769    // sky scan
3770    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::SKY ) ;
3771    out->attach() ;
3772    CountedPtr<Scantable> asky = averageWithinSession( out,
3773                                                       masks,
3774                                                       "TINT" ) ;
3775    STSelector sel = STSelector() ;
3776
3777    // hot scan
3778    out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::HOT ) ;
3779    out->attach() ;
3780    CountedPtr<Scantable> ahot = averageWithinSession( out,
3781                                                       masks,
3782                                                       "TINT" ) ;
3783
3784    // cold scan
3785    CountedPtr<Scantable> acold ;
3786//     out->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::COLD ) ;
3787//     out->attach() ;
3788//     CountedPtr<Scantable> acold = averageWithinSession( out,
3789//                                                         masks,
3790//                                                         "TINT" ) ;
3791   
3792    // ref scan
3793    bool insitu = insitu_ ;
3794    insitu_ = false ;
3795    sref = getScantable( s, true ) ;
3796    CountedPtr<Scantable> rref = getScantable( s, true ) ;
3797    insitu_ = insitu ;
3798    rref->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::PSOFF ) ;
3799    rref->attach() ;
3800    copyRows( sref->table_, rref->table_, 0, 0, rref->nrow(), False, True, False ) ;
3801   
3802    // sig scan
3803    insitu_ = false ;
3804    ssig = getScantable( s, true ) ;
3805    CountedPtr<Scantable> rsig = getScantable( s, true ) ;
3806    insitu_ = insitu ;
3807    rsig->table_ = s->table_( s->table_.col("SRCTYPE") == (Int)SrcType::PSON ) ;
3808    rsig->attach() ;
3809    copyRows( ssig->table_, rsig->table_, 0, 0, rsig->nrow(), False, True, False ) ;
3810
3811    // process each sig and ref scan
3812    vector<string> cols( 3 ) ;
3813    cols[0] = "BEAMNO" ;
3814    cols[1] = "POLNO" ;
3815    cols[2] = "IFNO" ;
3816    STIdxIter2 iter(ssig, cols);
3817    while ( !iter.pastEnd() ) {
3818      Record ids = iter.currentValue() ;
3819      stringstream ss ;
3820      ss << "SELECT FROM $1 WHERE "
3821         << "BEAMNO==" << ids.asuInt("BEAMNO") << "&&"
3822         << "POLNO==" << ids.asuInt("POLNO") << "&&"
3823         << "IFNO==" << ids.asuInt("IFNO") ;
3824      //cout << "TaQL string: " << ss.str() << endl ;
3825      sel.setTaQL( ss.str() ) ;
3826      ahot->setSelection( sel ) ;
3827      asky->setSelection( sel ) ;
3828      Vector<uInt> rows = iter.getRows( SHARE ) ;
3829      // out should be an exact copy of s except that SPECTRA column is empty
3830      calibrateFS( ssig, sref, rsig, rref, asky, ahot, acold, rows ) ;
3831      ahot->unsetSelection() ;
3832      asky->unsetSelection() ;
3833      sel.reset() ;
3834      iter.next() ;
3835    }
3836  }
3837
3838  // do folding if necessary
3839  Table sigtab = ssig->table() ;
3840  Table reftab = sref->table() ;
3841  ScalarColumn<uInt> reffidCol ;
3842  Int nchan = (Int)ssig->nchan() ;
3843  reffidCol.attach( reftab, "FREQ_ID" ) ;
3844  Vector<uInt> sfids = ssig->mfreqidCol_.getColumn() ;
3845  Vector<uInt> rfids = sref->mfreqidCol_.getColumn() ;
3846  vector<uInt> sfids_unique ;
3847  vector<uInt> rfids_unique ;
3848  vector<uInt> sifno_unique ;
3849  vector<uInt> rifno_unique ;
3850  for ( uInt i = 0 ; i < sfids.nelements() ; i++ ) {
3851    if ( count( sfids_unique.begin(), sfids_unique.end(), sfids[i] ) == 0 ) {
3852      sfids_unique.push_back( sfids[i] ) ;
3853      sifno_unique.push_back( ssig->getIF( i ) ) ;
3854    }
3855    if ( count( rfids_unique.begin(), rfids_unique.end(),  rfids[i] ) == 0 ) {
3856      rfids_unique.push_back( rfids[i] ) ;
3857      rifno_unique.push_back( sref->getIF( i ) ) ;
3858    }
3859  }
3860  double refpix_sig, refval_sig, increment_sig ;
3861  double refpix_ref, refval_ref, increment_ref ;
3862  vector< CountedPtr<Scantable> > tmp( sfids_unique.size() ) ;
3863  for ( uInt i = 0 ; i < sfids_unique.size() ; i++ ) {
3864    ssig->frequencies().getEntry( refpix_sig, refval_sig, increment_sig, sfids_unique[i] ) ;
3865    sref->frequencies().getEntry( refpix_ref, refval_ref, increment_ref, rfids_unique[i] ) ;
3866    if ( refpix_sig == refpix_ref ) {
3867      double foffset = refval_ref - refval_sig ;
3868      int choffset = static_cast<int>(foffset/increment_sig) ;
3869      double doffset = foffset / increment_sig ;
3870      if ( abs(choffset) >= nchan ) {
3871        LogIO os( LogOrigin( "STMath", "cwcalfs", WHERE ) ) ;
3872        os << "FREQ_ID=[" << sfids_unique[i] << "," << rfids_unique[i] << "]: out-band frequency switching, no folding" << LogIO::POST ;
3873        os << "Just return signal data" << LogIO::POST ;
3874        //std::vector< CountedPtr<Scantable> > tabs ;
3875        //tabs.push_back( ssig ) ;
3876        //tabs.push_back( sref ) ;
3877        //out = merge( tabs ) ;
3878        tmp[i] = ssig ;
3879      }
3880      else {
3881        STSelector sel = STSelector() ;
3882        vector<int> v( 1, sifno_unique[i] ) ;
3883        sel.setIFs( v ) ;
3884        ssig->setSelection( sel ) ;
3885        sel.reset() ;
3886        v[0] = rifno_unique[i] ;
3887        sel.setIFs( v ) ;
3888        sref->setSelection( sel ) ;
3889        sel.reset() ;
3890        if ( antname.find( "APEX" ) != string::npos ) {
3891          tmp[i] = dofold( ssig, sref, 0.5*doffset, -0.5*doffset ) ;
3892          //tmp[i] = dofold( ssig, sref, doffset ) ;
3893        }
3894        else {
3895          tmp[i] = dofold( ssig, sref, doffset ) ;
3896        }
3897        ssig->unsetSelection() ;
3898        sref->unsetSelection() ;
3899      }
3900    }
3901  }
3902
3903  if ( tmp.size() > 1 ) {
3904    out = merge( tmp ) ;
3905  }
3906  else {
3907    out = tmp[0] ;
3908  }
3909
3910  // flux unit
3911  out->setFluxUnit( "K" ) ;
3912
3913  return out ;
3914}
3915
3916CountedPtr<Scantable> STMath::almacalfs( const CountedPtr<Scantable>& s )
3917{
3918  (void) s; //currently unused
3919  CountedPtr<Scantable> out ;
3920
3921  return out ;
3922}
3923
3924void STMath::calibrateAPEXFS( CountedPtr<Scantable> &sig,
3925                              CountedPtr<Scantable> &ref,
3926                              const vector< CountedPtr<Scantable> >& on,
3927                              const vector< CountedPtr<Scantable> >& sky,
3928                              const vector< CountedPtr<Scantable> >& hot,
3929                              const vector< CountedPtr<Scantable> >& cold,
3930                              const Vector<uInt> &rows )
3931{
3932  // if rows is empty, just return
3933  if ( rows.nelements() == 0 )
3934    return ;
3935  ROScalarColumn<Double> timeCol( sky[0]->table(), "TIME" ) ;
3936  Vector<Double> timeSkyS = timeCol.getColumn() ;
3937  timeCol.attach( sky[1]->table(), "TIME" ) ;
3938  Vector<Double> timeSkyR = timeCol.getColumn() ;
3939  timeCol.attach( hot[0]->table(), "TIME" ) ;
3940  Vector<Double> timeHotS = timeCol.getColumn() ;
3941  timeCol.attach( hot[1]->table(), "TIME" ) ;
3942  Vector<Double> timeHotR = timeCol.getColumn() ;
3943  timeCol.attach( sig->table(), "TIME" ) ;
3944  ROScalarColumn<Double> timeCol2( ref->table(), "TIME" ) ;
3945  ROArrayColumn<Float> arrayFloatCol( sky[0]->table(), "SPECTRA" ) ;
3946  SpectralData skyspectraS(arrayFloatCol.getColumn());
3947  arrayFloatCol.attach( sky[1]->table(), "SPECTRA" ) ;
3948  SpectralData skyspectraR(arrayFloatCol.getColumn());
3949  arrayFloatCol.attach( hot[0]->table(), "SPECTRA" ) ;
3950  SpectralData hotspectraS(arrayFloatCol.getColumn());
3951  arrayFloatCol.attach( hot[1]->table(), "SPECTRA" ) ;
3952  SpectralData hotspectraR(arrayFloatCol.getColumn());
3953  TcalData tcaldataS(sky[0]);
3954  TsysData tsysdataS(sky[0]);
3955  TcalData tcaldataR(sky[1]);
3956  TsysData tsysdataR(sky[1]);
3957  unsigned int spsize = sig->nchan( sig->getIF(rows[0]) ) ;
3958  Vector<Float> spec( spsize ) ;
3959  // I know that the data is contiguous
3960  const uInt *p = rows.data() ;
3961  vector<int> ids( 2 ) ;
3962  Block<uInt> flagchan( spsize ) ;
3963  uInt nflag = 0 ;
3964  for ( int irow = 0 ; irow < rows.nelements() ; irow++ ) {
3965    double reftime = timeCol.asdouble(*p) ;
3966    ids = getRowIdFromTime( reftime, timeSkyS ) ;
3967    Vector<Float> spskyS = SimpleInterpolationHelper<SpectralData>::GetFromTime(reftime, timeSkyS, ids, skyspectraS, "linear");
3968    Vector<Float> tcalS = SimpleInterpolationHelper<TcalData>::GetFromTime(reftime, timeSkyS, ids, tcaldataS, "linear");
3969    Vector<Float> tsysS = SimpleInterpolationHelper<TsysData>::GetFromTime(reftime, timeSkyS, ids, tsysdataS, "linear");
3970    ids = getRowIdFromTime( reftime, timeHotS ) ;
3971    Vector<Float> sphotS = SimpleInterpolationHelper<SpectralData>::GetFromTime(reftime, timeHotS, ids, hotspectraS, "linear");
3972    reftime = timeCol2.asdouble(*p) ;
3973    ids = getRowIdFromTime( reftime, timeSkyR ) ;
3974    Vector<Float> spskyR = SimpleInterpolationHelper<SpectralData>::GetFromTime(reftime, timeSkyR, ids, skyspectraR, "linear");
3975    Vector<Float> tcalR = SimpleInterpolationHelper<TcalData>::GetFromTime(reftime, timeSkyR, ids, tcaldataR, "linear");
3976    Vector<Float> tsysR = SimpleInterpolationHelper<TsysData>::GetFromTime(reftime, timeSkyR, ids, tsysdataR, "linear");
3977    ids = getRowIdFromTime( reftime, timeHotR ) ;
3978    Vector<Float> sphotR = SimpleInterpolationHelper<SpectralData>::GetFromTime(reftime, timeHotR, ids, hotspectraR, "linear");
3979    Vector<Float> spsig = on[0]->specCol_( *p ) ;
3980    Vector<Float> spref = on[1]->specCol_( *p ) ;
3981    for ( unsigned int j = 0 ; j < spsize ; j++ ) {
3982      if ( (sphotS[j]-spskyS[j]) == 0.0 || (sphotR[j]-spskyR[j]) == 0.0 ) {
3983        spec[j] = 0.0 ;
3984        flagchan[nflag++] = j ;
3985      }
3986      else {
3987        spec[j] = tcalS[j] * spsig[j] / ( sphotS[j] - spskyS[j] )
3988          - tcalR[j] * spref[j] / ( sphotR[j] - spskyR[j] ) ;
3989      }
3990    }
3991    sig->specCol_.put( *p, spec ) ;
3992    sig->tsysCol_.put( *p, tsysS ) ;
3993    spec *= (Float)-1.0 ;
3994    ref->specCol_.put( *p, spec ) ;
3995    ref->tsysCol_.put( *p, tsysR ) ;   
3996    if ( nflag > 0 ) {
3997      Vector<uChar> flsig = sig->flagsCol_( *p ) ;
3998      Vector<uChar> flref = ref->flagsCol_( *p ) ;
3999      for ( unsigned int j = 0 ; j < nflag ; j++ ) {
4000        flsig[flagchan[j]] = (uChar)True ;
4001        flref[flagchan[j]] = (uChar)True ;
4002      }
4003      sig->flagsCol_.put( *p, flsig ) ;
4004      ref->flagsCol_.put( *p, flref ) ;
4005    }
4006    nflag = 0 ;
4007    p++ ;
4008  }
4009}
4010
4011void STMath::calibrateFS( CountedPtr<Scantable> &sig,
4012                          CountedPtr<Scantable> &ref,
4013                          const CountedPtr<Scantable>& rsig,
4014                          const CountedPtr<Scantable>& rref,
4015                          const CountedPtr<Scantable>& sky,
4016                          const CountedPtr<Scantable>& hot,
4017                          const CountedPtr<Scantable>& cold,
4018                          const Vector<uInt> &rows )
4019{
4020  // if rows is empty, just return
4021  if ( rows.nelements() == 0 )
4022    return ;
4023  ROScalarColumn<Double> timeCol( sky->table(), "TIME" ) ;
4024  Vector<Double> timeSky = timeCol.getColumn() ;
4025  timeCol.attach( hot->table(), "TIME" ) ;
4026  Vector<Double> timeHot = timeCol.getColumn() ;
4027  timeCol.attach( sig->table(), "TIME" ) ;
4028  ROScalarColumn<Double> timeCol2( ref->table(), "TIME" ) ;
4029  ROArrayColumn<Float> arrayFloatCol( sky->table(), "SPECTRA" ) ;
4030  SpectralData skyspectra(arrayFloatCol.getColumn());
4031  arrayFloatCol.attach( hot->table(), "SPECTRA" ) ;
4032  SpectralData hotspectra(arrayFloatCol.getColumn());
4033  TcalData tcaldata(sky);
4034  TsysData tsysdata(sky);
4035  unsigned int spsize = sig->nchan( sig->getIF(rows[0]) ) ;
4036  Vector<Float> spec( spsize ) ;
4037  // I know that the data is contiguous
4038  const uInt *p = rows.data() ;
4039  vector<int> ids( 2 ) ;
4040  Block<uInt> flagchan( spsize ) ;
4041  uInt nflag = 0 ;
4042  for ( int irow = 0 ; irow < rows.nelements() ; irow++ ) {
4043    double reftime = timeCol.asdouble(*p) ;
4044    ids = getRowIdFromTime( reftime, timeSky ) ;
4045    Vector<Float> spsky = SimpleInterpolationHelper<SpectralData>::GetFromTime(reftime, timeSky, ids, skyspectra, "linear");
4046    Vector<Float> tcal = SimpleInterpolationHelper<TcalData>::GetFromTime(reftime, timeSky, ids, tcaldata, "linear");
4047    Vector<Float> tsys = SimpleInterpolationHelper<TsysData>::GetFromTime(reftime, timeSky, ids, tsysdata, "linear");
4048    ids = getRowIdFromTime( reftime, timeHot ) ;
4049    Vector<Float> sphot = SimpleInterpolationHelper<SpectralData>::GetFromTime(reftime, timeHot, ids, hotspectra, "linear");
4050    Vector<Float> spsig = rsig->specCol_( *p ) ;
4051    Vector<Float> spref = rref->specCol_( *p ) ;
4052    // using gain array
4053    for ( unsigned int j = 0 ; j < spsize ; j++ ) {
4054      if ( spref[j] == 0.0 || (sphot[j]-spsky[j]) == 0.0 ) {
4055        spec[j] = 0.0 ;
4056        flagchan[nflag++] = j ;
4057      }
4058      else {
4059        spec[j] = ( ( spsig[j] - spref[j] ) / spref[j] )
4060          * ( spsky[j] / ( sphot[j] - spsky[j] ) ) * tcal[j] ;
4061      }
4062    }
4063    sig->specCol_.put( *p, spec ) ;
4064    sig->tsysCol_.put( *p, tsys ) ;
4065    if ( nflag > 0 ) {
4066      Vector<uChar> fl = sig->flagsCol_( *p ) ;
4067      for ( unsigned int j = 0 ; j < nflag ; j++ ) {
4068        fl[flagchan[j]] = (uChar)True ;
4069      }
4070      sig->flagsCol_.put( *p, fl ) ;
4071    }
4072    nflag = 0 ;
4073
4074    reftime = timeCol2.asdouble(*p) ;
4075    ids = getRowIdFromTime( reftime, timeSky ) ;
4076    spsky = SimpleInterpolationHelper<SpectralData>::GetFromTime(reftime, timeSky, ids, skyspectra, "linear");
4077    tcal = SimpleInterpolationHelper<TcalData>::GetFromTime(reftime, timeSky, ids, tcaldata, "linear");
4078    tsys = SimpleInterpolationHelper<TsysData>::GetFromTime(reftime, timeSky, ids, tsysdata, "linear");
4079    ids = getRowIdFromTime( reftime, timeHot ) ;
4080    sphot = SimpleInterpolationHelper<SpectralData>::GetFromTime(reftime, timeHot, ids, hotspectra, "linear");
4081    // using gain array
4082    for ( unsigned int j = 0 ; j < spsize ; j++ ) {
4083      if ( spsig[j] == 0.0 || (sphot[j]-spsky[j]) == 0.0 ) {
4084        spec[j] = 0.0 ;
4085        flagchan[nflag++] = j ;
4086      }
4087      else {
4088        spec[j] = ( ( spref[j] - spsig[j] ) / spsig[j] )
4089          * ( spsky[j] / ( sphot[j] - spsky[j] ) ) * tcal[j] ;
4090      }
4091    }
4092    ref->specCol_.put( *p, spec ) ;
4093    ref->tsysCol_.put( *p, tsys ) ;   
4094    if ( nflag > 0 ) {
4095      Vector<uChar> fl = ref->flagsCol_( *p ) ;
4096      for ( unsigned int j = 0 ; j < nflag ; j++ ) {
4097        fl[flagchan[j]] = (uChar)True ;
4098      }
4099      ref->flagsCol_.put( *p, fl ) ;
4100    }
4101    nflag = 0 ;
4102    p++ ;
4103  }
4104}
4105
4106void STMath::copyRows( Table &out,
4107                       const Table &in,
4108                       uInt startout,
4109                       uInt startin,
4110                       uInt nrow,
4111                       Bool copySpectra,
4112                       Bool copyFlagtra,
4113                       Bool copyTsys )
4114{
4115  uInt nexclude = 0 ;
4116  Block<String> excludeColsBlock( 3 ) ;
4117  if ( !copySpectra ) {
4118    excludeColsBlock[nexclude] = "SPECTRA" ;
4119    nexclude++ ;
4120  }
4121  if ( !copyFlagtra ) {
4122    excludeColsBlock[nexclude] = "FLAGTRA" ;
4123    nexclude++ ;
4124  }
4125  if ( !copyTsys ) {
4126    excludeColsBlock[nexclude] = "TSYS" ;
4127    nexclude++ ;
4128  }
4129  //  if ( nexclude < 3 ) {
4130  //    excludeCols.resize( nexclude, True ) ;
4131  //  }
4132  Vector<String> excludeCols( IPosition(1,nexclude),
4133                              excludeColsBlock.storage(),
4134                              SHARE ) ;
4135//   cout << "excludeCols=" << excludeCols << endl ;
4136  TableRow rowout( out, excludeCols, True ) ;
4137  ROTableRow rowin( in, excludeCols, True ) ;
4138  uInt rin = startin ;
4139  uInt rout = startout ;
4140  for ( uInt i = 0 ; i < nrow ; i++ ) {
4141    rowin.get( rin ) ;
4142    rowout.putMatchingFields( rout, rowin.record() ) ;
4143    rin++ ;
4144    rout++ ;
4145  }
4146}
4147
4148CountedPtr<Scantable> STMath::averageWithinSession( CountedPtr<Scantable> &s,
4149                                                    vector<bool> &mask,
4150                                                    string weight )
4151{
4152  // prepare output table
4153  bool insitu = insitu_ ;
4154  insitu_ = false ;
4155  CountedPtr<Scantable> a = getScantable( s, true ) ;
4156  insitu_ = insitu ;
4157  Table &atab = a->table() ;
4158  ScalarColumn<Double> timeColOut( atab, "TIME" ) ;
4159
4160  if ( s->nrow() == 0 )
4161    return a ;
4162
4163  // setup RowAccumulator
4164  WeightType wtype = stringToWeight( weight ) ;
4165  RowAccumulator acc( wtype ) ;
4166  Vector<Bool> cmask( mask ) ;
4167  acc.setUserMask( cmask ) ;
4168
4169  vector<string> cols( 3 ) ;
4170  cols[0] = "IFNO" ;
4171  cols[1] = "POLNO" ;
4172  cols[2] = "BEAMNO" ;
4173  STIdxIter2 iter( s, cols ) ;
4174
4175  Table ttab = s->table() ;
4176  ROScalarColumn<Double> *timeCol = new ROScalarColumn<Double>( ttab, "TIME" ) ;
4177  Vector<Double> timeVec = timeCol->getColumn() ;
4178  delete timeCol ;
4179  Vector<Double> interval = s->integrCol_.getColumn() ;
4180  uInt nrow = timeVec.nelements() ;
4181  uInt outrow = 0 ;
4182
4183  while( !iter.pastEnd() ) {
4184
4185    Vector<uInt> rows = iter.getRows( SHARE ) ;
4186    uInt len = rows.nelements() ;
4187
4188    if ( len == 0 ) {
4189      iter.next() ;
4190      continue ;
4191    }
4192
4193    uInt nchan = s->nchan(s->getIF(rows[0])) ;
4194    Vector<uChar> flag( nchan ) ;
4195    Vector<Bool> bflag( nchan ) ;
4196    Vector<Float> spec( nchan ) ;
4197    Vector<Float> tsys( nchan ) ;
4198
4199    Vector<Double> timeSep( len-1 ) ;
4200    for ( uInt i = 0 ; i < len-1 ; i++ ) {
4201      timeSep[i] = timeVec[rows[i+1]] - timeVec[rows[i]] ;
4202    }
4203
4204    uInt irow ;
4205    uInt jrow ;
4206    for ( uInt i = 0 ; i < len-1 ; i++ ) {
4207      irow = rows[i] ;
4208      jrow = rows[i+1] ;
4209      // accumulate data
4210      s->flagsCol_.get( irow, flag ) ;
4211      convertArray( bflag, flag ) ;
4212      s->specCol_.get( irow, spec ) ;
4213      tsys.assign( s->tsysCol_( irow ) ) ;
4214      if ( !allEQ(bflag,True) )
4215        acc.add( spec, !bflag, tsys, interval[irow], timeVec[irow] ) ;
4216      double gap = 2.0 * 86400.0 * timeSep[i] / ( interval[jrow] + interval[irow] ) ;
4217      //cout << "gap[" << i << "]=" << setw(5) << gap << endl ;
4218      if ( gap > 1.1 ) {
4219        //cout << "detected gap between " << i << " and " << i+1 << endl ;
4220        // put data to output table
4221        // reset RowAccumulator
4222        if ( acc.state() ) {
4223          atab.addRow() ;
4224          copyRows( atab, ttab, outrow, irow, 1, False, False, False ) ;
4225          acc.replaceNaN() ;
4226          const Vector<Bool> &msk = acc.getMask() ;
4227          convertArray( flag, !msk ) ;
4228          for (uInt k = 0; k < nchan; ++k) {
4229            uChar userFlag = 1 << 7;
4230            if (msk[k]==True) userFlag = 0 << 7;
4231            flag(k) = userFlag;
4232          }
4233          a->flagsCol_.put( outrow, flag ) ;
4234          a->specCol_.put( outrow, acc.getSpectrum() ) ;
4235          a->tsysCol_.put( outrow, acc.getTsys() ) ;
4236          a->integrCol_.put( outrow, acc.getInterval() ) ;
4237          timeColOut.put( outrow, acc.getTime() ) ;
4238          a->cycleCol_.put( outrow, 0 ) ;
4239        }
4240        acc.reset() ;
4241        outrow++ ;
4242      }
4243    }
4244
4245    // accumulate and add last data
4246    irow = rows[len-1] ;
4247    s->flagsCol_.get( irow, flag ) ;
4248    convertArray( bflag, flag ) ;
4249    s->specCol_.get( irow, spec ) ;
4250    tsys.assign( s->tsysCol_( irow ) ) ;
4251    if (!allEQ(bflag,True) )
4252      acc.add( spec, !bflag, tsys, interval[irow], timeVec[irow] ) ;
4253    if ( acc.state() ) {
4254      atab.addRow() ;
4255      copyRows( atab, ttab, outrow, irow, 1, False, False, False ) ;
4256      acc.replaceNaN() ;
4257      const Vector<Bool> &msk = acc.getMask() ;
4258      convertArray( flag, !msk ) ;
4259      for (uInt k = 0; k < nchan; ++k) {
4260        uChar userFlag = 1 << 7;
4261        if (msk[k]==True) userFlag = 0 << 7;
4262        flag(k) = userFlag;
4263      }
4264      a->flagsCol_.put( outrow, flag ) ;
4265      a->specCol_.put( outrow, acc.getSpectrum() ) ;
4266      a->tsysCol_.put( outrow, acc.getTsys() ) ;
4267      a->integrCol_.put( outrow, acc.getInterval() ) ;
4268      timeColOut.put( outrow, acc.getTime() ) ;
4269      a->cycleCol_.put( outrow, 0 ) ;
4270    }
4271    acc.reset() ;
4272    outrow++ ;
4273
4274    iter.next() ;
4275  }
4276
4277  return a ;
4278}
Note: See TracBrowser for help on using the repository browser.