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

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

New Development: No

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: Yes/No?

Module(s): Module Names change impacts.

Description: Describe your changes here...

More speedup of STMath::average().

  • Reduced number of call of RowAccumulator::replaceNaN().
  • Performance of RowAccumulator::add() is improved.


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