source: trunk/src/STMath.cpp @ 2986

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

New Development: No

JIRA Issue: Yes CAS-6582

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

STMath::average is changed so that empty averaged result (data to be
averaged are all flagged) is kept with all channel flags of 128 and
row flag of 1.


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