source: branches/mergetest/src/STMath.cpp @ 1777

Last change on this file since 1777 was 1777, checked in by Malte Marquarding, 14 years ago

Created branch to test alma merge back into trunk

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 67.1 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 <casa/iomanip.h>
14#include <casa/Exceptions/Error.h>
15#include <casa/Containers/Block.h>
16#include <casa/BasicSL/String.h>
17#include <casa/Arrays/MaskArrLogi.h>
18#include <casa/Arrays/MaskArrMath.h>
19#include <casa/Arrays/ArrayLogical.h>
20#include <casa/Arrays/ArrayMath.h>
21#include <casa/Arrays/Slice.h>
22#include <casa/Arrays/Slicer.h>
23#include <casa/Containers/RecordField.h>
24#include <tables/Tables/TableRow.h>
25#include <tables/Tables/TableVector.h>
26#include <tables/Tables/TabVecMath.h>
27#include <tables/Tables/ExprNode.h>
28#include <tables/Tables/TableRecord.h>
29#include <tables/Tables/TableParse.h>
30#include <tables/Tables/ReadAsciiTable.h>
31#include <tables/Tables/TableIter.h>
32#include <tables/Tables/TableCopy.h>
33#include <scimath/Mathematics/FFTServer.h>
34
35#include <lattices/Lattices/LatticeUtilities.h>
36
37#include <coordinates/Coordinates/SpectralCoordinate.h>
38#include <coordinates/Coordinates/CoordinateSystem.h>
39#include <coordinates/Coordinates/CoordinateUtil.h>
40#include <coordinates/Coordinates/FrequencyAligner.h>
41
42#include <scimath/Mathematics/VectorKernel.h>
43#include <scimath/Mathematics/Convolver.h>
44#include <scimath/Functionals/Polynomial.h>
45
46#include <casa/Logging/LogIO.h>
47
48#include "MathUtils.h"
49#include "RowAccumulator.h"
50#include "STAttr.h"
51#include "STSelector.h"
52
53#include "STMath.h"
54using namespace casa;
55
56using namespace asap;
57
58STMath::STMath(bool insitu) :
59  insitu_(insitu)
60{
61}
62
63
64STMath::~STMath()
65{
66}
67
68CountedPtr<Scantable>
69STMath::average( const std::vector<CountedPtr<Scantable> >& in,
70                 const std::vector<bool>& mask,
71                 const std::string& weight,
72                 const std::string& avmode)
73{
74  if ( avmode == "SCAN" && in.size() != 1 )
75    throw(AipsError("Can't perform 'SCAN' averaging on multiple tables.\n"
76                    "Use merge first."));
77  WeightType wtype = stringToWeight(weight);
78  LogIO os( LogOrigin( "STMath", "average()", WHERE ) ) ;
79  os << "test" << LogIO::POST ;
80
81  // output
82  // clone as this is non insitu
83  bool insitu = insitu_;
84  setInsitu(false);
85  CountedPtr< Scantable > out = getScantable(in[0], true);
86  setInsitu(insitu);
87  std::vector<CountedPtr<Scantable> >::const_iterator stit = in.begin();
88  ++stit;
89  while ( stit != in.end() ) {
90    out->appendToHistoryTable((*stit)->history());
91    ++stit;
92  }
93
94  Table& tout = out->table();
95
96  /// @todo check if all scantables are conformant
97
98  ArrayColumn<Float> specColOut(tout,"SPECTRA");
99  ArrayColumn<uChar> flagColOut(tout,"FLAGTRA");
100  ArrayColumn<Float> tsysColOut(tout,"TSYS");
101  ScalarColumn<Double> mjdColOut(tout,"TIME");
102  ScalarColumn<Double> intColOut(tout,"INTERVAL");
103  ScalarColumn<uInt> cycColOut(tout,"CYCLENO");
104  ScalarColumn<uInt> scanColOut(tout,"SCANNO");
105
106  // set up the output table rows. These are based on the structure of the
107  // FIRST scantable in the vector
108  const Table& baset = in[0]->table();
109
110  Block<String> cols(3);
111  cols[0] = String("BEAMNO");
112  cols[1] = String("IFNO");
113  cols[2] = String("POLNO");
114  if ( avmode == "SOURCE" ) {
115    cols.resize(4);
116    cols[3] = String("SRCNAME");
117  }
118  if ( avmode == "SCAN"  && in.size() == 1) {
119    cols.resize(4);
120    cols[3] = String("SCANNO");
121  }
122  uInt outrowCount = 0;
123  TableIterator iter(baset, cols);
124  while (!iter.pastEnd()) {
125    Table subt = iter.table();
126    // copy the first row of this selection into the new table
127    tout.addRow();
128    TableCopy::copyRows(tout, subt, outrowCount, 0, 1);
129    // re-index to 0
130    if ( avmode != "SCAN" && avmode != "SOURCE" ) {
131      scanColOut.put(outrowCount, uInt(0));
132    }
133    ++outrowCount;
134    ++iter;
135  }
136
137  RowAccumulator acc(wtype);
138  Vector<Bool> cmask(mask);
139  acc.setUserMask(cmask);
140  ROTableRow row(tout);
141  ROArrayColumn<Float> specCol, tsysCol;
142  ROArrayColumn<uChar> flagCol;
143  ROScalarColumn<Double> mjdCol, intCol;
144  ROScalarColumn<Int> scanIDCol;
145
146  Vector<uInt> rowstodelete;
147
148  for (uInt i=0; i < tout.nrow(); ++i) {
149    for ( int j=0; j < int(in.size()); ++j ) {
150      const Table& tin = in[j]->table();
151      const TableRecord& rec = row.get(i);
152      ROScalarColumn<Double> tmp(tin, "TIME");
153      Double td;tmp.get(0,td);
154      Table basesubt = tin(tin.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
155                       && tin.col("IFNO") == Int(rec.asuInt("IFNO"))
156                       && tin.col("POLNO") == Int(rec.asuInt("POLNO")) );
157      Table subt;
158      if ( avmode == "SOURCE") {
159        subt = basesubt( basesubt.col("SRCNAME") == rec.asString("SRCNAME") );
160      } else if (avmode == "SCAN") {
161        subt = basesubt( basesubt.col("SCANNO") == Int(rec.asuInt("SCANNO")) );
162      } else {
163        subt = basesubt;
164      }
165      specCol.attach(subt,"SPECTRA");
166      flagCol.attach(subt,"FLAGTRA");
167      tsysCol.attach(subt,"TSYS");
168      intCol.attach(subt,"INTERVAL");
169      mjdCol.attach(subt,"TIME");
170      Vector<Float> spec,tsys;
171      Vector<uChar> flag;
172      Double inter,time;
173      for (uInt k = 0; k < subt.nrow(); ++k ) {
174        flagCol.get(k, flag);
175        Vector<Bool> bflag(flag.shape());
176        convertArray(bflag, flag);
177        /*
178        if ( allEQ(bflag, True) ) {
179        continue;//don't accumulate
180        }
181        */
182        specCol.get(k, spec);
183        tsysCol.get(k, tsys);
184        intCol.get(k, inter);
185        mjdCol.get(k, time);
186        // spectrum has to be added last to enable weighting by the other values
187        acc.add(spec, !bflag, tsys, inter, time);
188      }
189    }
190    const Vector<Bool>& msk = acc.getMask();
191    if ( allEQ(msk, False) ) {
192      uint n = rowstodelete.nelements();
193      rowstodelete.resize(n+1, True);
194      rowstodelete[n] = i;
195      continue;
196    }
197    //write out
198    Vector<uChar> flg(msk.shape());
199    convertArray(flg, !msk);
200    flagColOut.put(i, flg);
201    specColOut.put(i, acc.getSpectrum());
202    tsysColOut.put(i, acc.getTsys());
203    intColOut.put(i, acc.getInterval());
204    mjdColOut.put(i, acc.getTime());
205    // we should only have one cycle now -> reset it to be 0
206    // frequency switched data has different CYCLENO for different IFNO
207    // which requires resetting this value
208    cycColOut.put(i, uInt(0));
209    acc.reset();
210  }
211  if (rowstodelete.nelements() > 0) {
212    tout.removeRow(rowstodelete);
213    if (tout.nrow() == 0) {
214      throw(AipsError("Can't average fully flagged data."));
215    }
216  }
217  return out;
218}
219
220CountedPtr< Scantable >
221  STMath::averageChannel( const CountedPtr < Scantable > & in,
222                          const std::string & mode,
223                          const std::string& avmode )
224{
225  // clone as this is non insitu
226  bool insitu = insitu_;
227  setInsitu(false);
228  CountedPtr< Scantable > out = getScantable(in, true);
229  setInsitu(insitu);
230  Table& tout = out->table();
231  ArrayColumn<Float> specColOut(tout,"SPECTRA");
232  ArrayColumn<uChar> flagColOut(tout,"FLAGTRA");
233  ArrayColumn<Float> tsysColOut(tout,"TSYS");
234  ScalarColumn<uInt> scanColOut(tout,"SCANNO");
235  ScalarColumn<Double> intColOut(tout, "INTERVAL");
236  Table tmp = in->table().sort("BEAMNO");
237  Block<String> cols(3);
238  cols[0] = String("BEAMNO");
239  cols[1] = String("IFNO");
240  cols[2] = String("POLNO");
241  if ( avmode == "SCAN") {
242    cols.resize(4);
243    cols[3] = String("SCANNO");
244  }
245  uInt outrowCount = 0;
246  uChar userflag = 1 << 7;
247  TableIterator iter(tmp, cols);
248  while (!iter.pastEnd()) {
249    Table subt = iter.table();
250    ROArrayColumn<Float> specCol, tsysCol;
251    ROArrayColumn<uChar> flagCol;
252    ROScalarColumn<Double> intCol(subt, "INTERVAL");
253    specCol.attach(subt,"SPECTRA");
254    flagCol.attach(subt,"FLAGTRA");
255    tsysCol.attach(subt,"TSYS");
256    tout.addRow();
257    TableCopy::copyRows(tout, subt, outrowCount, 0, 1);
258    if ( avmode != "SCAN") {
259      scanColOut.put(outrowCount, uInt(0));
260    }
261    Vector<Float> tmp;
262    specCol.get(0, tmp);
263    uInt nchan = tmp.nelements();
264    // have to do channel by channel here as MaskedArrMath
265    // doesn't have partialMedians
266    Vector<uChar> flags = flagCol.getColumn(Slicer(Slice(0)));
267    Vector<Float> outspec(nchan);
268    Vector<uChar> outflag(nchan,0);
269    Vector<Float> outtsys(1);/// @fixme when tsys is channel based
270    for (uInt i=0; i<nchan; ++i) {
271      Vector<Float> specs = specCol.getColumn(Slicer(Slice(i)));
272      MaskedArray<Float> ma = maskedArray(specs,flags);
273      outspec[i] = median(ma);
274      if ( allEQ(ma.getMask(), False) )
275        outflag[i] = userflag;// flag data
276    }
277    outtsys[0] = median(tsysCol.getColumn());
278    specColOut.put(outrowCount, outspec);
279    flagColOut.put(outrowCount, outflag);
280    tsysColOut.put(outrowCount, outtsys);
281    Double intsum = sum(intCol.getColumn());
282    intColOut.put(outrowCount, intsum);
283    ++outrowCount;
284    ++iter;
285  }
286  return out;
287}
288
289CountedPtr< Scantable > STMath::getScantable(const CountedPtr< Scantable >& in,
290                                             bool droprows)
291{
292  if (insitu_) {
293    return in;
294  }
295  else {
296    // clone
297    return CountedPtr<Scantable>(new Scantable(*in, Bool(droprows)));
298  }
299}
300
301CountedPtr< Scantable > STMath::unaryOperate( const CountedPtr< Scantable >& in,
302                                              float val,
303                                              const std::string& mode,
304                                              bool tsys )
305{
306  CountedPtr< Scantable > out = getScantable(in, false);
307  Table& tab = out->table();
308  ArrayColumn<Float> specCol(tab,"SPECTRA");
309  ArrayColumn<Float> tsysCol(tab,"TSYS");
310  for (uInt i=0; i<tab.nrow(); ++i) {
311    Vector<Float> spec;
312    Vector<Float> ts;
313    specCol.get(i, spec);
314    tsysCol.get(i, ts);
315    if (mode == "MUL" || mode == "DIV") {
316      if (mode == "DIV") val = 1.0/val;
317      spec *= val;
318      specCol.put(i, spec);
319      if ( tsys ) {
320        ts *= val;
321        tsysCol.put(i, ts);
322      }
323    } else if ( mode == "ADD"  || mode == "SUB") {
324      if (mode == "SUB") val *= -1.0;
325      spec += val;
326      specCol.put(i, spec);
327      if ( tsys ) {
328        ts += val;
329        tsysCol.put(i, ts);
330      }
331    }
332  }
333  return out;
334}
335
336CountedPtr<Scantable> STMath::binaryOperate(const CountedPtr<Scantable>& left,
337                                            const CountedPtr<Scantable>& right,
338                                            const std::string& mode)
339{
340  bool insitu = insitu_;
341  if ( ! left->conformant(*right) ) {
342    throw(AipsError("'left' and 'right' scantables are not conformant."));
343  }
344  setInsitu(false);
345  CountedPtr< Scantable > out = getScantable(left, false);
346  setInsitu(insitu);
347  Table& tout = out->table();
348  Block<String> coln(5);
349  coln[0] = "SCANNO";  coln[1] = "CYCLENO";  coln[2] = "BEAMNO";
350  coln[3] = "IFNO";  coln[4] = "POLNO";
351  Table tmpl = tout.sort(coln);
352  Table tmpr = right->table().sort(coln);
353  ArrayColumn<Float> lspecCol(tmpl,"SPECTRA");
354  ROArrayColumn<Float> rspecCol(tmpr,"SPECTRA");
355  ArrayColumn<uChar> lflagCol(tmpl,"FLAGTRA");
356  ROArrayColumn<uChar> rflagCol(tmpr,"FLAGTRA");
357
358  for (uInt i=0; i<tout.nrow(); ++i) {
359    Vector<Float> lspecvec, rspecvec;
360    Vector<uChar> lflagvec, rflagvec;
361    lspecvec = lspecCol(i);    rspecvec = rspecCol(i);
362    lflagvec = lflagCol(i);    rflagvec = rflagCol(i);
363    MaskedArray<Float> mleft = maskedArray(lspecvec, lflagvec);
364    MaskedArray<Float> mright = maskedArray(rspecvec, rflagvec);
365    if (mode == "ADD") {
366      mleft += mright;
367    } else if ( mode == "SUB") {
368      mleft -= mright;
369    } else if ( mode == "MUL") {
370      mleft *= mright;
371    } else if ( mode == "DIV") {
372      mleft /= mright;
373    } else {
374      throw(AipsError("Illegal binary operator"));
375    }
376    lspecCol.put(i, mleft.getArray());
377  }
378  return out;
379}
380
381
382
383MaskedArray<Float> STMath::maskedArray( const Vector<Float>& s,
384                                        const Vector<uChar>& f)
385{
386  Vector<Bool> mask;
387  mask.resize(f.shape());
388  convertArray(mask, f);
389  return MaskedArray<Float>(s,!mask);
390}
391
392Vector<uChar> STMath::flagsFromMA(const MaskedArray<Float>& ma)
393{
394  const Vector<Bool>& m = ma.getMask();
395  Vector<uChar> flags(m.shape());
396  convertArray(flags, !m);
397  return flags;
398}
399
400CountedPtr< Scantable > STMath::autoQuotient( const CountedPtr< Scantable >& in,
401                                              const std::string & mode,
402                                              bool preserve )
403{
404  /// @todo make other modes available
405  /// modes should be "nearest", "pair"
406  // make this operation non insitu
407  const Table& tin = in->table();
408  Table ons = tin(tin.col("SRCTYPE") == Int(0));
409  Table offs = tin(tin.col("SRCTYPE") == Int(1));
410  if ( offs.nrow() == 0 )
411    throw(AipsError("No 'off' scans present."));
412  // put all "on" scans into output table
413
414  bool insitu = insitu_;
415  setInsitu(false);
416  CountedPtr< Scantable > out = getScantable(in, true);
417  setInsitu(insitu);
418  Table& tout = out->table();
419
420  TableCopy::copyRows(tout, ons);
421  TableRow row(tout);
422  ROScalarColumn<Double> offtimeCol(offs, "TIME");
423  ArrayColumn<Float> outspecCol(tout, "SPECTRA");
424  ROArrayColumn<Float> outtsysCol(tout, "TSYS");
425  ArrayColumn<uChar> outflagCol(tout, "FLAGTRA");
426  for (uInt i=0; i < tout.nrow(); ++i) {
427    const TableRecord& rec = row.get(i);
428    Double ontime = rec.asDouble("TIME");
429    Table presel = offs(offs.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
430                        && offs.col("IFNO") == Int(rec.asuInt("IFNO"))
431                        && offs.col("POLNO") == Int(rec.asuInt("POLNO")) );
432    ROScalarColumn<Double> offtimeCol(presel, "TIME");
433
434    Double mindeltat = min(abs(offtimeCol.getColumn() - ontime));
435    // Timestamp may vary within a cycle ???!!!
436    // increase this by 0.01 sec in case of rounding errors...
437    // There might be a better way to do this.
438    // fix to this fix. TIME is MJD, so 1.0d not 1.0s
439    mindeltat += 0.01/24./60./60.;
440    Table sel = presel( abs(presel.col("TIME")-ontime) <= mindeltat);
441
442    if ( sel.nrow() < 1 )  {
443      throw(AipsError("No closest in time found... This could be a rounding "
444                      "issue. Try quotient instead."));
445    }
446    TableRow offrow(sel);
447    const TableRecord& offrec = offrow.get(0);//should only be one row
448    RORecordFieldPtr< Array<Float> > specoff(offrec, "SPECTRA");
449    RORecordFieldPtr< Array<Float> > tsysoff(offrec, "TSYS");
450    RORecordFieldPtr< Array<uChar> > flagoff(offrec, "FLAGTRA");
451    /// @fixme this assumes tsys is a scalar not vector
452    Float tsysoffscalar = (*tsysoff)(IPosition(1,0));
453    Vector<Float> specon, tsyson;
454    outtsysCol.get(i, tsyson);
455    outspecCol.get(i, specon);
456    Vector<uChar> flagon;
457    outflagCol.get(i, flagon);
458    MaskedArray<Float> mon = maskedArray(specon, flagon);
459    MaskedArray<Float> moff = maskedArray(*specoff, *flagoff);
460    MaskedArray<Float> quot = (tsysoffscalar * mon / moff);
461    if (preserve) {
462      quot -= tsysoffscalar;
463    } else {
464      quot -= tsyson[0];
465    }
466    outspecCol.put(i, quot.getArray());
467    outflagCol.put(i, flagsFromMA(quot));
468  }
469  // renumber scanno
470  TableIterator it(tout, "SCANNO");
471  uInt i = 0;
472  while ( !it.pastEnd() ) {
473    Table t = it.table();
474    TableVector<uInt> vec(t, "SCANNO");
475    vec = i;
476    ++i;
477    ++it;
478  }
479  return out;
480}
481
482
483CountedPtr< Scantable > STMath::quotient( const CountedPtr< Scantable > & on,
484                                          const CountedPtr< Scantable > & off,
485                                          bool preserve )
486{
487  bool insitu = insitu_;
488  if ( ! on->conformant(*off) ) {
489    throw(AipsError("'on' and 'off' scantables are not conformant."));
490  }
491  setInsitu(false);
492  CountedPtr< Scantable > out = getScantable(on, false);
493  setInsitu(insitu);
494  Table& tout = out->table();
495  const Table& toff = off->table();
496  TableIterator sit(tout, "SCANNO");
497  TableIterator s2it(toff, "SCANNO");
498  while ( !sit.pastEnd() ) {
499    Table ton = sit.table();
500    TableRow row(ton);
501    Table t = s2it.table();
502    ArrayColumn<Float> outspecCol(ton, "SPECTRA");
503    ROArrayColumn<Float> outtsysCol(ton, "TSYS");
504    ArrayColumn<uChar> outflagCol(ton, "FLAGTRA");
505    for (uInt i=0; i < ton.nrow(); ++i) {
506      const TableRecord& rec = row.get(i);
507      Table offsel = t( t.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
508                          && t.col("IFNO") == Int(rec.asuInt("IFNO"))
509                          && t.col("POLNO") == Int(rec.asuInt("POLNO")) );
510      if ( offsel.nrow() == 0 )
511        throw AipsError("STMath::quotient: no matching off");
512      TableRow offrow(offsel);
513      const TableRecord& offrec = offrow.get(0);//should be ncycles - take first
514      RORecordFieldPtr< Array<Float> > specoff(offrec, "SPECTRA");
515      RORecordFieldPtr< Array<Float> > tsysoff(offrec, "TSYS");
516      RORecordFieldPtr< Array<uChar> > flagoff(offrec, "FLAGTRA");
517      Float tsysoffscalar = (*tsysoff)(IPosition(1,0));
518      Vector<Float> specon, tsyson;
519      outtsysCol.get(i, tsyson);
520      outspecCol.get(i, specon);
521      Vector<uChar> flagon;
522      outflagCol.get(i, flagon);
523      MaskedArray<Float> mon = maskedArray(specon, flagon);
524      MaskedArray<Float> moff = maskedArray(*specoff, *flagoff);
525      MaskedArray<Float> quot = (tsysoffscalar * mon / moff);
526      if (preserve) {
527        quot -= tsysoffscalar;
528      } else {
529        quot -= tsyson[0];
530      }
531      outspecCol.put(i, quot.getArray());
532      outflagCol.put(i, flagsFromMA(quot));
533    }
534    ++sit;
535    ++s2it;
536    // take the first off for each on scan which doesn't have a
537    // matching off scan
538    // non <= noff:  matching pairs, non > noff matching pairs then first off
539    if ( s2it.pastEnd() ) s2it.reset();
540  }
541  return out;
542}
543
544// dototalpower (migration of GBTIDL procedure dototalpower.pro)
545// calibrate the CAL on-off pair. It calculate Tsys and average CAL on-off subintegrations
546// do it for each cycles in a specific scan.
547CountedPtr< Scantable > STMath::dototalpower( const CountedPtr< Scantable >& calon,
548                                              const CountedPtr< Scantable >& caloff, Float tcal )
549{
550if ( ! calon->conformant(*caloff) ) {
551    throw(AipsError("'CAL on' and 'CAL off' scantables are not conformant."));
552  }
553  setInsitu(false);
554  CountedPtr< Scantable > out = getScantable(caloff, false);
555  Table& tout = out->table();
556  const Table& tcon = calon->table();
557  Vector<Float> tcalout;
558  Vector<Float> tcalout2;  //debug
559
560  if ( tout.nrow() != tcon.nrow() ) {
561    throw(AipsError("Mismatch in number of rows to form cal on - off pair."));
562  }
563  // iteration by scanno or cycle no.
564  TableIterator sit(tout, "SCANNO");
565  TableIterator s2it(tcon, "SCANNO");
566  while ( !sit.pastEnd() ) {
567    Table toff = sit.table();
568    TableRow row(toff);
569    Table t = s2it.table();
570    ScalarColumn<Double> outintCol(toff, "INTERVAL");
571    ArrayColumn<Float> outspecCol(toff, "SPECTRA");
572    ArrayColumn<Float> outtsysCol(toff, "TSYS");
573    ArrayColumn<uChar> outflagCol(toff, "FLAGTRA");
574    ROScalarColumn<uInt> outtcalIdCol(toff, "TCAL_ID");
575    ROScalarColumn<uInt> outpolCol(toff, "POLNO");
576    ROScalarColumn<Double> onintCol(t, "INTERVAL");
577    ROArrayColumn<Float> onspecCol(t, "SPECTRA");
578    ROArrayColumn<Float> ontsysCol(t, "TSYS");
579    ROArrayColumn<uChar> onflagCol(t, "FLAGTRA");
580    //ROScalarColumn<uInt> ontcalIdCol(t, "TCAL_ID");
581
582    for (uInt i=0; i < toff.nrow(); ++i) {
583      //skip these checks -> assumes the data order are the same between the cal on off pairs
584      //
585      Vector<Float> specCalon, specCaloff;
586      // to store scalar (mean) tsys
587      Vector<Float> tsysout(1);
588      uInt tcalId, polno;
589      Double offint, onint;
590      outpolCol.get(i, polno);
591      outspecCol.get(i, specCaloff);
592      onspecCol.get(i, specCalon);
593      Vector<uChar> flagCaloff, flagCalon;
594      outflagCol.get(i, flagCaloff);
595      onflagCol.get(i, flagCalon);
596      outtcalIdCol.get(i, tcalId);
597      outintCol.get(i, offint);
598      onintCol.get(i, onint);
599      // caluculate mean Tsys
600      uInt nchan = specCaloff.nelements();
601      // percentage of edge cut off
602      uInt pc = 10;
603      uInt bchan = nchan/pc;
604      uInt echan = nchan-bchan;
605
606      Slicer chansl(IPosition(1,bchan-1), IPosition(1,echan-1), IPosition(1,1),Slicer::endIsLast);
607      Vector<Float> testsubsp = specCaloff(chansl);
608      MaskedArray<Float> spoff = maskedArray( specCaloff(chansl),flagCaloff(chansl) );
609      MaskedArray<Float> spon = maskedArray( specCalon(chansl),flagCalon(chansl) );
610      MaskedArray<Float> spdiff = spon-spoff;
611      uInt noff = spoff.nelementsValid();
612      //uInt non = spon.nelementsValid();
613      uInt ndiff = spdiff.nelementsValid();
614      Float meantsys;
615
616/**
617      Double subspec, subdiff;
618      uInt usednchan;
619      subspec = 0;
620      subdiff = 0;
621      usednchan = 0;
622      for(uInt k=(bchan-1); k<echan; k++) {
623        subspec += specCaloff[k];
624        subdiff += static_cast<Double>(specCalon[k]-specCaloff[k]);
625        ++usednchan;
626      }
627**/
628      // get tcal if input tcal <= 0
629      String tcalt;
630      Float tcalUsed;
631      tcalUsed = tcal;
632      if ( tcal <= 0.0 ) {
633        caloff->tcal().getEntry(tcalt, tcalout, tcalId);
634        if (polno<=3) {
635          tcalUsed = tcalout[polno];
636        }
637        else {
638          tcalUsed = tcalout[0];
639        }
640      }
641
642      Float meanoff;
643      Float meandiff;
644      if (noff && ndiff) {
645         //Debug
646         //if(noff!=ndiff) cerr<<"noff and ndiff is not equal"<<endl;
647         meanoff = sum(spoff)/noff;
648         meandiff = sum(spdiff)/ndiff;
649         meantsys= (meanoff/meandiff )*tcalUsed + tcalUsed/2;
650      }
651      else {
652         meantsys=1;
653      }
654
655      tsysout[0] = Float(meantsys);
656      MaskedArray<Float> mcaloff = maskedArray(specCaloff, flagCaloff);
657      MaskedArray<Float> mcalon = maskedArray(specCalon, flagCalon);
658      MaskedArray<Float> sig =   Float(0.5) * (mcaloff + mcalon);
659      //uInt ncaloff = mcaloff.nelementsValid();
660      //uInt ncalon = mcalon.nelementsValid();
661
662      outintCol.put(i, offint+onint);
663      outspecCol.put(i, sig.getArray());
664      outflagCol.put(i, flagsFromMA(sig));
665      outtsysCol.put(i, tsysout);
666    }
667    ++sit;
668    ++s2it;
669  }
670  return out;
671}
672
673//dosigref - migrated from GBT IDL's dosigref.pro, do calibration of position switch
674// observatiions.
675// input: sig and ref scantables, and an optional boxcar smoothing width(default width=0,
676//        no smoothing).
677// output: resultant scantable [= (sig-ref/ref)*tsys]
678CountedPtr< Scantable > STMath::dosigref( const CountedPtr < Scantable >& sig,
679                                          const CountedPtr < Scantable >& ref,
680                                          int smoothref,
681                                          casa::Float tsysv,
682                                          casa::Float tau )
683{
684if ( ! ref->conformant(*sig) ) {
685    throw(AipsError("'sig' and 'ref' scantables are not conformant."));
686  }
687  setInsitu(false);
688  CountedPtr< Scantable > out = getScantable(sig, false);
689  CountedPtr< Scantable > smref;
690  if ( smoothref > 1 ) {
691    float fsmoothref = static_cast<float>(smoothref);
692    std::string inkernel = "boxcar";
693    smref = smooth(ref, inkernel, fsmoothref );
694    ostringstream oss;
695    oss<<"Applied smoothing of "<<fsmoothref<<" on the reference."<<endl;
696    pushLog(String(oss));
697  }
698  else {
699    smref = ref;
700  }
701  Table& tout = out->table();
702  const Table& tref = smref->table();
703  if ( tout.nrow() != tref.nrow() ) {
704    throw(AipsError("Mismatch in number of rows to form on-source and reference pair."));
705  }
706  // iteration by scanno? or cycle no.
707  TableIterator sit(tout, "SCANNO");
708  TableIterator s2it(tref, "SCANNO");
709  while ( !sit.pastEnd() ) {
710    Table ton = sit.table();
711    Table t = s2it.table();
712    ScalarColumn<Double> outintCol(ton, "INTERVAL");
713    ArrayColumn<Float> outspecCol(ton, "SPECTRA");
714    ArrayColumn<Float> outtsysCol(ton, "TSYS");
715    ArrayColumn<uChar> outflagCol(ton, "FLAGTRA");
716    ArrayColumn<Float> refspecCol(t, "SPECTRA");
717    ROScalarColumn<Double> refintCol(t, "INTERVAL");
718    ROArrayColumn<Float> reftsysCol(t, "TSYS");
719    ArrayColumn<uChar> refflagCol(t, "FLAGTRA");
720    ROScalarColumn<Float> refelevCol(t, "ELEVATION");
721    for (uInt i=0; i < ton.nrow(); ++i) {
722
723      Double onint, refint;
724      Vector<Float> specon, specref;
725      // to store scalar (mean) tsys
726      Vector<Float> tsysref;
727      outintCol.get(i, onint);
728      refintCol.get(i, refint);
729      outspecCol.get(i, specon);
730      refspecCol.get(i, specref);
731      Vector<uChar> flagref, flagon;
732      outflagCol.get(i, flagon);
733      refflagCol.get(i, flagref);
734      reftsysCol.get(i, tsysref);
735
736      Float tsysrefscalar;
737      if ( tsysv > 0.0 ) {
738        ostringstream oss;
739        Float elev;
740        refelevCol.get(i, elev);
741        oss << "user specified Tsys = " << tsysv;
742        // do recalc elevation if EL = 0
743        if ( elev == 0 ) {
744          throw(AipsError("EL=0, elevation data is missing."));
745        } else {
746          if ( tau <= 0.0 ) {
747            throw(AipsError("Valid tau is not supplied."));
748          } else {
749            tsysrefscalar = tsysv * exp(tau/elev);
750          }
751        }
752        oss << ", corrected (for El) tsys= "<<tsysrefscalar;
753        pushLog(String(oss));
754      }
755      else {
756        tsysrefscalar = tsysref[0];
757      }
758      //get quotient spectrum
759      MaskedArray<Float> mref = maskedArray(specref, flagref);
760      MaskedArray<Float> mon = maskedArray(specon, flagon);
761      MaskedArray<Float> specres =   tsysrefscalar*((mon - mref)/mref);
762      Double resint = onint*refint*smoothref/(onint+refint*smoothref);
763
764      //Debug
765      //cerr<<"Tsys used="<<tsysrefscalar<<endl;
766      // fill the result, replay signal tsys by reference tsys
767      outintCol.put(i, resint);
768      outspecCol.put(i, specres.getArray());
769      outflagCol.put(i, flagsFromMA(specres));
770      outtsysCol.put(i, tsysref);
771    }
772    ++sit;
773    ++s2it;
774  }
775  return out;
776}
777
778CountedPtr< Scantable > STMath::donod(const casa::CountedPtr<Scantable>& s,
779                                     const std::vector<int>& scans,
780                                     int smoothref,
781                                     casa::Float tsysv,
782                                     casa::Float tau,
783                                     casa::Float tcal )
784
785{
786  setInsitu(false);
787  STSelector sel;
788  std::vector<int> scan1, scan2, beams;
789  std::vector< vector<int> > scanpair;
790  std::vector<string> calstate;
791  String msg;
792
793  CountedPtr< Scantable > s1b1on, s1b1off, s1b2on, s1b2off;
794  CountedPtr< Scantable > s2b1on, s2b1off, s2b2on, s2b2off;
795
796  std::vector< CountedPtr< Scantable > > sctables;
797  sctables.push_back(s1b1on);
798  sctables.push_back(s1b1off);
799  sctables.push_back(s1b2on);
800  sctables.push_back(s1b2off);
801  sctables.push_back(s2b1on);
802  sctables.push_back(s2b1off);
803  sctables.push_back(s2b2on);
804  sctables.push_back(s2b2off);
805
806  //check scanlist
807  int n=s->checkScanInfo(scans);
808  if (n==1) {
809     throw(AipsError("Incorrect scan pairs. "));
810  }
811
812  // Assume scans contain only a pair of consecutive scan numbers.
813  // It is assumed that first beam, b1,  is on target.
814  // There is no check if the first beam is on or not.
815  if ( scans.size()==1 ) {
816    scan1.push_back(scans[0]);
817    scan2.push_back(scans[0]+1);
818  } else if ( scans.size()==2 ) {
819   scan1.push_back(scans[0]);
820   scan2.push_back(scans[1]);
821  } else {
822    if ( scans.size()%2 == 0 ) {
823      for (uInt i=0; i<scans.size(); i++) {
824        if (i%2 == 0) {
825          scan1.push_back(scans[i]);
826        }
827        else {
828          scan2.push_back(scans[i]);
829        }
830      }
831    } else {
832      throw(AipsError("Odd numbers of scans, cannot form pairs."));
833    }
834  }
835  scanpair.push_back(scan1);
836  scanpair.push_back(scan2);
837  calstate.push_back("*calon");
838  calstate.push_back("*[^calon]");
839  CountedPtr< Scantable > ws = getScantable(s, false);
840  uInt l=0;
841  while ( l < sctables.size() ) {
842    for (uInt i=0; i < 2; i++) {
843      for (uInt j=0; j < 2; j++) {
844        for (uInt k=0; k < 2; k++) {
845          sel.reset();
846          sel.setScans(scanpair[i]);
847          sel.setName(calstate[k]);
848          beams.clear();
849          beams.push_back(j);
850          sel.setBeams(beams);
851          ws->setSelection(sel);
852          sctables[l]= getScantable(ws, false);
853          l++;
854        }
855      }
856    }
857  }
858
859  // replace here by splitData or getData functionality
860  CountedPtr< Scantable > sig1;
861  CountedPtr< Scantable > ref1;
862  CountedPtr< Scantable > sig2;
863  CountedPtr< Scantable > ref2;
864  CountedPtr< Scantable > calb1;
865  CountedPtr< Scantable > calb2;
866
867  msg=String("Processing dototalpower for subset of the data");
868  ostringstream oss1;
869  oss1 << msg  << endl;
870  pushLog(String(oss1));
871  // Debug for IRC CS data
872  //float tcal1=7.0;
873  //float tcal2=4.0;
874  sig1 = dototalpower(sctables[0], sctables[1], tcal=tcal);
875  ref1 = dototalpower(sctables[2], sctables[3], tcal=tcal);
876  ref2 = dototalpower(sctables[4], sctables[5], tcal=tcal);
877  sig2 = dototalpower(sctables[6], sctables[7], tcal=tcal);
878
879  // correction of user-specified tsys for elevation here
880
881  // dosigref calibration
882  msg=String("Processing dosigref for subset of the data");
883  ostringstream oss2;
884  oss2 << msg  << endl;
885  pushLog(String(oss2));
886  calb1=dosigref(sig1,ref2,smoothref,tsysv,tau);
887  calb2=dosigref(sig2,ref1,smoothref,tsysv,tau);
888
889  // iteration by scanno or cycle no.
890  Table& tcalb1 = calb1->table();
891  Table& tcalb2 = calb2->table();
892  TableIterator sit(tcalb1, "SCANNO");
893  TableIterator s2it(tcalb2, "SCANNO");
894  while ( !sit.pastEnd() ) {
895    Table t1 = sit.table();
896    Table t2= s2it.table();
897    ArrayColumn<Float> outspecCol(t1, "SPECTRA");
898    ArrayColumn<Float> outtsysCol(t1, "TSYS");
899    ArrayColumn<uChar> outflagCol(t1, "FLAGTRA");
900    ScalarColumn<Double> outintCol(t1, "INTERVAL");
901    ArrayColumn<Float> t2specCol(t2, "SPECTRA");
902    ROArrayColumn<Float> t2tsysCol(t2, "TSYS");
903    ArrayColumn<uChar> t2flagCol(t2, "FLAGTRA");
904    ROScalarColumn<Double> t2intCol(t2, "INTERVAL");
905    for (uInt i=0; i < t1.nrow(); ++i) {
906      Vector<Float> spec1, spec2;
907      // to store scalar (mean) tsys
908      Vector<Float> tsys1, tsys2;
909      Vector<uChar> flag1, flag2;
910      Double tint1, tint2;
911      outspecCol.get(i, spec1);
912      t2specCol.get(i, spec2);
913      outflagCol.get(i, flag1);
914      t2flagCol.get(i, flag2);
915      outtsysCol.get(i, tsys1);
916      t2tsysCol.get(i, tsys2);
917      outintCol.get(i, tint1);
918      t2intCol.get(i, tint2);
919      // average
920      // assume scalar tsys for weights
921      Float wt1, wt2, tsyssq1, tsyssq2;
922      tsyssq1 = tsys1[0]*tsys1[0];
923      tsyssq2 = tsys2[0]*tsys2[0];
924      wt1 = Float(tint1)/tsyssq1;
925      wt2 = Float(tint2)/tsyssq2;
926      Float invsumwt=1/(wt1+wt2);
927      MaskedArray<Float> mspec1 = maskedArray(spec1, flag1);
928      MaskedArray<Float> mspec2 = maskedArray(spec2, flag2);
929      MaskedArray<Float> avspec =  invsumwt * (wt1*mspec1 + wt2*mspec2);
930      //Array<Float> avtsys =  Float(0.5) * (tsys1 + tsys2);
931      // cerr<< "Tsys1="<<tsys1<<" Tsys2="<<tsys2<<endl;
932      tsys1[0] = sqrt(tsyssq1 + tsyssq2);
933      Array<Float> avtsys =  tsys1;
934
935      outspecCol.put(i, avspec.getArray());
936      outflagCol.put(i, flagsFromMA(avspec));
937      outtsysCol.put(i, avtsys);
938    }
939    ++sit;
940    ++s2it;
941  }
942  return calb1;
943}
944
945//GBTIDL version of frequency switched data calibration
946CountedPtr< Scantable > STMath::dofs( const CountedPtr< Scantable >& s,
947                                      const std::vector<int>& scans,
948                                      int smoothref,
949                                      casa::Float tsysv,
950                                      casa::Float tau,
951                                      casa::Float tcal )
952{
953
954
955  STSelector sel;
956  CountedPtr< Scantable > ws = getScantable(s, false);
957  CountedPtr< Scantable > sig, sigwcal, ref, refwcal;
958  CountedPtr< Scantable > calsig, calref, out;
959
960  //split the data
961  sel.setName("*_fs");
962  ws->setSelection(sel);
963  sig = getScantable(ws,false);
964  sel.reset();
965  sel.setName("*_fs_calon");
966  ws->setSelection(sel);
967  sigwcal = getScantable(ws,false);
968  sel.reset();
969  sel.setName("*_fsr");
970  ws->setSelection(sel);
971  ref = getScantable(ws,false);
972  sel.reset();
973  sel.setName("*_fsr_calon");
974  ws->setSelection(sel);
975  refwcal = getScantable(ws,false);
976
977  calsig = dototalpower(sigwcal, sig, tcal=tcal);
978  calref = dototalpower(refwcal, ref, tcal=tcal);
979
980  out=dosigref(calsig,calref,smoothref,tsysv,tau);
981
982  return out;
983}
984
985
986CountedPtr< Scantable > STMath::freqSwitch( const CountedPtr< Scantable >& in )
987{
988  // make copy or reference
989  CountedPtr< Scantable > out = getScantable(in, false);
990  Table& tout = out->table();
991  Block<String> cols(4);
992  cols[0] = String("SCANNO");
993  cols[1] = String("CYCLENO");
994  cols[2] = String("BEAMNO");
995  cols[3] = String("POLNO");
996  TableIterator iter(tout, cols);
997  while (!iter.pastEnd()) {
998    Table subt = iter.table();
999    // this should leave us with two rows for the two IFs....if not ignore
1000    if (subt.nrow() != 2 ) {
1001      continue;
1002    }
1003    ArrayColumn<Float> specCol(subt, "SPECTRA");
1004    ArrayColumn<Float> tsysCol(subt, "TSYS");
1005    ArrayColumn<uChar> flagCol(subt, "FLAGTRA");
1006    Vector<Float> onspec,offspec, ontsys, offtsys;
1007    Vector<uChar> onflag, offflag;
1008    tsysCol.get(0, ontsys);   tsysCol.get(1, offtsys);
1009    specCol.get(0, onspec);   specCol.get(1, offspec);
1010    flagCol.get(0, onflag);   flagCol.get(1, offflag);
1011    MaskedArray<Float> on  = maskedArray(onspec, onflag);
1012    MaskedArray<Float> off = maskedArray(offspec, offflag);
1013    MaskedArray<Float> oncopy = on.copy();
1014
1015    on /= off; on -= 1.0f;
1016    on *= ontsys[0];
1017    off /= oncopy; off -= 1.0f;
1018    off *= offtsys[0];
1019    specCol.put(0, on.getArray());
1020    const Vector<Bool>& m0 = on.getMask();
1021    Vector<uChar> flags0(m0.shape());
1022    convertArray(flags0, !m0);
1023    flagCol.put(0, flags0);
1024
1025    specCol.put(1, off.getArray());
1026    const Vector<Bool>& m1 = off.getMask();
1027    Vector<uChar> flags1(m1.shape());
1028    convertArray(flags1, !m1);
1029    flagCol.put(1, flags1);
1030    ++iter;
1031  }
1032
1033  return out;
1034}
1035
1036std::vector< float > STMath::statistic( const CountedPtr< Scantable > & in,
1037                                        const std::vector< bool > & mask,
1038                                        const std::string& which )
1039{
1040
1041  Vector<Bool> m(mask);
1042  const Table& tab = in->table();
1043  ROArrayColumn<Float> specCol(tab, "SPECTRA");
1044  ROArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1045  std::vector<float> out;
1046  for (uInt i=0; i < tab.nrow(); ++i ) {
1047    Vector<Float> spec; specCol.get(i, spec);
1048    Vector<uChar> flag; flagCol.get(i, flag);
1049    MaskedArray<Float> ma  = maskedArray(spec, flag);
1050    float outstat = 0.0;
1051    if ( spec.nelements() == m.nelements() ) {
1052      outstat = mathutil::statistics(which, ma(m));
1053    } else {
1054      outstat = mathutil::statistics(which, ma);
1055    }
1056    out.push_back(outstat);
1057  }
1058  return out;
1059}
1060
1061CountedPtr< Scantable > STMath::bin( const CountedPtr< Scantable > & in,
1062                                     int width )
1063{
1064  if ( !in->getSelection().empty() ) throw(AipsError("Can't bin subset of the data."));
1065  CountedPtr< Scantable > out = getScantable(in, false);
1066  Table& tout = out->table();
1067  out->frequencies().rescale(width, "BIN");
1068  ArrayColumn<Float> specCol(tout, "SPECTRA");
1069  ArrayColumn<uChar> flagCol(tout, "FLAGTRA");
1070  for (uInt i=0; i < tout.nrow(); ++i ) {
1071    MaskedArray<Float> main  = maskedArray(specCol(i), flagCol(i));
1072    MaskedArray<Float> maout;
1073    LatticeUtilities::bin(maout, main, 0, Int(width));
1074    /// @todo implement channel based tsys binning
1075    specCol.put(i, maout.getArray());
1076    flagCol.put(i, flagsFromMA(maout));
1077    // take only the first binned spectrum's length for the deprecated
1078    // global header item nChan
1079    if (i==0) tout.rwKeywordSet().define(String("nChan"),
1080                                       Int(maout.getArray().nelements()));
1081  }
1082  return out;
1083}
1084
1085CountedPtr< Scantable > STMath::resample( const CountedPtr< Scantable >& in,
1086                                          const std::string& method,
1087                                          float width )
1088//
1089// Should add the possibility of width being specified in km/s. This means
1090// that for each freqID (SpectralCoordinate) we will need to convert to an
1091// average channel width (say at the reference pixel).  Then we would need
1092// to be careful to make sure each spectrum (of different freqID)
1093// is the same length.
1094//
1095{
1096  //InterpolateArray1D<Double,Float>::InterpolationMethod interp;
1097  Int interpMethod(stringToIMethod(method));
1098
1099  CountedPtr< Scantable > out = getScantable(in, false);
1100  Table& tout = out->table();
1101
1102// Resample SpectralCoordinates (one per freqID)
1103  out->frequencies().rescale(width, "RESAMPLE");
1104  TableIterator iter(tout, "IFNO");
1105  TableRow row(tout);
1106  while ( !iter.pastEnd() ) {
1107    Table tab = iter.table();
1108    ArrayColumn<Float> specCol(tab, "SPECTRA");
1109    //ArrayColumn<Float> tsysCol(tout, "TSYS");
1110    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1111    Vector<Float> spec;
1112    Vector<uChar> flag;
1113    specCol.get(0,spec); // the number of channels should be constant per IF
1114    uInt nChanIn = spec.nelements();
1115    Vector<Float> xIn(nChanIn); indgen(xIn);
1116    Int fac =  Int(nChanIn/width);
1117    Vector<Float> xOut(fac+10); // 10 to be safe - resize later
1118    uInt k = 0;
1119    Float x = 0.0;
1120    while (x < Float(nChanIn) ) {
1121      xOut(k) = x;
1122      k++;
1123      x += width;
1124    }
1125    uInt nChanOut = k;
1126    xOut.resize(nChanOut, True);
1127    // process all rows for this IFNO
1128    Vector<Float> specOut;
1129    Vector<Bool> maskOut;
1130    Vector<uChar> flagOut;
1131    for (uInt i=0; i < tab.nrow(); ++i) {
1132      specCol.get(i, spec);
1133      flagCol.get(i, flag);
1134      Vector<Bool> mask(flag.nelements());
1135      convertArray(mask, flag);
1136
1137      IPosition shapeIn(spec.shape());
1138      //sh.nchan = nChanOut;
1139      InterpolateArray1D<Float,Float>::interpolate(specOut, maskOut, xOut,
1140                                                   xIn, spec, mask,
1141                                                   interpMethod, True, True);
1142      /// @todo do the same for channel based Tsys
1143      flagOut.resize(maskOut.nelements());
1144      convertArray(flagOut, maskOut);
1145      specCol.put(i, specOut);
1146      flagCol.put(i, flagOut);
1147    }
1148    ++iter;
1149  }
1150
1151  return out;
1152}
1153
1154STMath::imethod STMath::stringToIMethod(const std::string& in)
1155{
1156  static STMath::imap lookup;
1157
1158  // initialize the lookup table if necessary
1159  if ( lookup.empty() ) {
1160    lookup["nearest"]   = InterpolateArray1D<Double,Float>::nearestNeighbour;
1161    lookup["linear"] = InterpolateArray1D<Double,Float>::linear;
1162    lookup["cubic"]  = InterpolateArray1D<Double,Float>::cubic;
1163    lookup["spline"]  = InterpolateArray1D<Double,Float>::spline;
1164  }
1165
1166  STMath::imap::const_iterator iter = lookup.find(in);
1167
1168  if ( lookup.end() == iter ) {
1169    std::string message = in;
1170    message += " is not a valid interpolation mode";
1171    throw(AipsError(message));
1172  }
1173  return iter->second;
1174}
1175
1176WeightType STMath::stringToWeight(const std::string& in)
1177{
1178  static std::map<std::string, WeightType> lookup;
1179
1180  // initialize the lookup table if necessary
1181  if ( lookup.empty() ) {
1182    lookup["NONE"]   = asap::W_NONE;
1183    lookup["TINT"] = asap::W_TINT;
1184    lookup["TINTSYS"]  = asap::W_TINTSYS;
1185    lookup["TSYS"]  = asap::W_TSYS;
1186    lookup["VAR"]  = asap::W_VAR;
1187  }
1188
1189  std::map<std::string, WeightType>::const_iterator iter = lookup.find(in);
1190
1191  if ( lookup.end() == iter ) {
1192    std::string message = in;
1193    message += " is not a valid weighting mode";
1194    throw(AipsError(message));
1195  }
1196  return iter->second;
1197}
1198
1199CountedPtr< Scantable > STMath::gainElevation( const CountedPtr< Scantable >& in,
1200                                               const vector< float > & coeff,
1201                                               const std::string & filename,
1202                                               const std::string& method)
1203{
1204  // Get elevation data from Scantable and convert to degrees
1205  CountedPtr< Scantable > out = getScantable(in, false);
1206  Table& tab = out->table();
1207  ROScalarColumn<Float> elev(tab, "ELEVATION");
1208  Vector<Float> x = elev.getColumn();
1209  x *= Float(180 / C::pi);                        // Degrees
1210
1211  Vector<Float> coeffs(coeff);
1212  const uInt nc = coeffs.nelements();
1213  if ( filename.length() > 0 && nc > 0 ) {
1214    throw(AipsError("You must choose either polynomial coefficients or an ascii file, not both"));
1215  }
1216
1217  // Correct
1218  if ( nc > 0 || filename.length() == 0 ) {
1219    // Find instrument
1220    Bool throwit = True;
1221    Instrument inst =
1222      STAttr::convertInstrument(tab.keywordSet().asString("AntennaName"),
1223                                throwit);
1224
1225    // Set polynomial
1226    Polynomial<Float>* ppoly = 0;
1227    Vector<Float> coeff;
1228    String msg;
1229    if ( nc > 0 ) {
1230      ppoly = new Polynomial<Float>(nc-1);
1231      coeff = coeffs;
1232      msg = String("user");
1233    } else {
1234      STAttr sdAttr;
1235      coeff = sdAttr.gainElevationPoly(inst);
1236      ppoly = new Polynomial<Float>(coeff.nelements()-1);
1237      msg = String("built in");
1238    }
1239
1240    if ( coeff.nelements() > 0 ) {
1241      ppoly->setCoefficients(coeff);
1242    } else {
1243      delete ppoly;
1244      throw(AipsError("There is no known gain-elevation polynomial known for this instrument"));
1245    }
1246    ostringstream oss;
1247    oss << "Making polynomial correction with " << msg << " coefficients:" << endl;
1248    oss << "   " <<  coeff;
1249    pushLog(String(oss));
1250    const uInt nrow = tab.nrow();
1251    Vector<Float> factor(nrow);
1252    for ( uInt i=0; i < nrow; ++i ) {
1253      factor[i] = 1.0 / (*ppoly)(x[i]);
1254    }
1255    delete ppoly;
1256    scaleByVector(tab, factor, true);
1257
1258  } else {
1259    // Read and correct
1260    pushLog("Making correction from ascii Table");
1261    scaleFromAsciiTable(tab, filename, method, x, true);
1262  }
1263  return out;
1264}
1265
1266void STMath::scaleFromAsciiTable(Table& in, const std::string& filename,
1267                                 const std::string& method,
1268                                 const Vector<Float>& xout, bool dotsys)
1269{
1270
1271// Read gain-elevation ascii file data into a Table.
1272
1273  String formatString;
1274  Table tbl = readAsciiTable(formatString, Table::Memory, filename, "", "", False);
1275  scaleFromTable(in, tbl, method, xout, dotsys);
1276}
1277
1278void STMath::scaleFromTable(Table& in,
1279                            const Table& table,
1280                            const std::string& method,
1281                            const Vector<Float>& xout, bool dotsys)
1282{
1283
1284  ROScalarColumn<Float> geElCol(table, "ELEVATION");
1285  ROScalarColumn<Float> geFacCol(table, "FACTOR");
1286  Vector<Float> xin = geElCol.getColumn();
1287  Vector<Float> yin = geFacCol.getColumn();
1288  Vector<Bool> maskin(xin.nelements(),True);
1289
1290  // Interpolate (and extrapolate) with desired method
1291
1292  InterpolateArray1D<Double,Float>::InterpolationMethod interp = stringToIMethod(method);
1293
1294   Vector<Float> yout;
1295   Vector<Bool> maskout;
1296   InterpolateArray1D<Float,Float>::interpolate(yout, maskout, xout,
1297                                                xin, yin, maskin, interp,
1298                                                True, True);
1299
1300   scaleByVector(in, Float(1.0)/yout, dotsys);
1301}
1302
1303void STMath::scaleByVector( Table& in,
1304                            const Vector< Float >& factor,
1305                            bool dotsys )
1306{
1307  uInt nrow = in.nrow();
1308  if ( factor.nelements() != nrow ) {
1309    throw(AipsError("factors.nelements() != table.nelements()"));
1310  }
1311  ArrayColumn<Float> specCol(in, "SPECTRA");
1312  ArrayColumn<uChar> flagCol(in, "FLAGTRA");
1313  ArrayColumn<Float> tsysCol(in, "TSYS");
1314  for (uInt i=0; i < nrow; ++i) {
1315    MaskedArray<Float> ma  = maskedArray(specCol(i), flagCol(i));
1316    ma *= factor[i];
1317    specCol.put(i, ma.getArray());
1318    flagCol.put(i, flagsFromMA(ma));
1319    if ( dotsys ) {
1320      Vector<Float> tsys = tsysCol(i);
1321      tsys *= factor[i];
1322      tsysCol.put(i,tsys);
1323    }
1324  }
1325}
1326
1327CountedPtr< Scantable > STMath::convertFlux( const CountedPtr< Scantable >& in,
1328                                             float d, float etaap,
1329                                             float jyperk )
1330{
1331  CountedPtr< Scantable > out = getScantable(in, false);
1332  Table& tab = in->table();
1333  Unit fluxUnit(tab.keywordSet().asString("FluxUnit"));
1334  Unit K(String("K"));
1335  Unit JY(String("Jy"));
1336
1337  bool tokelvin = true;
1338  Double cfac = 1.0;
1339
1340  if ( fluxUnit == JY ) {
1341    pushLog("Converting to K");
1342    Quantum<Double> t(1.0,fluxUnit);
1343    Quantum<Double> t2 = t.get(JY);
1344    cfac = (t2 / t).getValue();               // value to Jy
1345
1346    tokelvin = true;
1347    out->setFluxUnit("K");
1348  } else if ( fluxUnit == K ) {
1349    pushLog("Converting to Jy");
1350    Quantum<Double> t(1.0,fluxUnit);
1351    Quantum<Double> t2 = t.get(K);
1352    cfac = (t2 / t).getValue();              // value to K
1353
1354    tokelvin = false;
1355    out->setFluxUnit("Jy");
1356  } else {
1357    throw(AipsError("Unrecognized brightness units in Table - must be consistent with Jy or K"));
1358  }
1359  // Make sure input values are converted to either Jy or K first...
1360  Float factor = cfac;
1361
1362  // Select method
1363  if (jyperk > 0.0) {
1364    factor *= jyperk;
1365    if ( tokelvin ) factor = 1.0 / jyperk;
1366    ostringstream oss;
1367    oss << "Jy/K = " << jyperk;
1368    pushLog(String(oss));
1369    Vector<Float> factors(tab.nrow(), factor);
1370    scaleByVector(tab,factors, false);
1371  } else if ( etaap > 0.0) {
1372    if (d < 0) {
1373      Instrument inst =
1374        STAttr::convertInstrument(tab.keywordSet().asString("AntennaName"),
1375                                  True);
1376      STAttr sda;
1377      d = sda.diameter(inst);
1378    }
1379    jyperk = STAttr::findJyPerK(etaap, d);
1380    ostringstream oss;
1381    oss << "Jy/K = " << jyperk;
1382    pushLog(String(oss));
1383    factor *= jyperk;
1384    if ( tokelvin ) {
1385      factor = 1.0 / factor;
1386    }
1387    Vector<Float> factors(tab.nrow(), factor);
1388    scaleByVector(tab, factors, False);
1389  } else {
1390
1391    // OK now we must deal with automatic look up of values.
1392    // We must also deal with the fact that the factors need
1393    // to be computed per IF and may be different and may
1394    // change per integration.
1395
1396    pushLog("Looking up conversion factors");
1397    convertBrightnessUnits(out, tokelvin, cfac);
1398  }
1399
1400  return out;
1401}
1402
1403void STMath::convertBrightnessUnits( CountedPtr<Scantable>& in,
1404                                     bool tokelvin, float cfac )
1405{
1406  Table& table = in->table();
1407  Instrument inst =
1408    STAttr::convertInstrument(table.keywordSet().asString("AntennaName"), True);
1409  TableIterator iter(table, "FREQ_ID");
1410  STFrequencies stfreqs = in->frequencies();
1411  STAttr sdAtt;
1412  while (!iter.pastEnd()) {
1413    Table tab = iter.table();
1414    ArrayColumn<Float> specCol(tab, "SPECTRA");
1415    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1416    ROScalarColumn<uInt> freqidCol(tab, "FREQ_ID");
1417    MEpoch::ROScalarColumn timeCol(tab, "TIME");
1418
1419    uInt freqid; freqidCol.get(0, freqid);
1420    Vector<Float> tmpspec; specCol.get(0, tmpspec);
1421    // STAttr.JyPerK has a Vector interface... change sometime.
1422    Vector<Float> freqs(1,stfreqs.getRefFreq(freqid, tmpspec.nelements()));
1423    for ( uInt i=0; i<tab.nrow(); ++i) {
1424      Float jyperk = (sdAtt.JyPerK(inst, timeCol(i), freqs))[0];
1425      Float factor = cfac * jyperk;
1426      if ( tokelvin ) factor = Float(1.0) / factor;
1427      MaskedArray<Float> ma  = maskedArray(specCol(i), flagCol(i));
1428      ma *= factor;
1429      specCol.put(i, ma.getArray());
1430      flagCol.put(i, flagsFromMA(ma));
1431    }
1432  ++iter;
1433  }
1434}
1435
1436CountedPtr< Scantable > STMath::opacity( const CountedPtr< Scantable > & in,
1437                                         const std::vector<float>& tau )
1438{
1439  CountedPtr< Scantable > out = getScantable(in, false);
1440
1441  Table outtab = out->table();
1442
1443  const uInt ntau = uInt(tau.size());
1444  std::vector<float>::const_iterator tauit = tau.begin();
1445  AlwaysAssert((ntau == 1 || ntau == in->nif() || ntau == in->nif() * in->npol()),
1446               AipsError);
1447  TableIterator iiter(outtab, "IFNO");
1448  while ( !iiter.pastEnd() ) {
1449    Table itab = iiter.table();
1450    TableIterator piter(outtab, "POLNO");
1451    while ( !piter.pastEnd() ) {
1452      Table tab = piter.table();
1453      ROScalarColumn<Float> elev(tab, "ELEVATION");
1454      ArrayColumn<Float> specCol(tab, "SPECTRA");
1455      ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1456      ArrayColumn<Float> tsysCol(tab, "TSYS");
1457      for ( uInt i=0; i<tab.nrow(); ++i) {
1458        Float zdist = Float(C::pi_2) - elev(i);
1459        Float factor = exp(*tauit/cos(zdist));
1460        MaskedArray<Float> ma = maskedArray(specCol(i), flagCol(i));
1461        ma *= factor;
1462        specCol.put(i, ma.getArray());
1463        flagCol.put(i, flagsFromMA(ma));
1464        Vector<Float> tsys;
1465        tsysCol.get(i, tsys);
1466        tsys *= factor;
1467        tsysCol.put(i, tsys);
1468      }
1469      if (ntau == in->nif()*in->npol() ) {
1470        tauit++;
1471      }
1472      piter++;
1473    }
1474    if (ntau >= in->nif() ) {
1475      tauit++;
1476    }
1477    iiter++;
1478  }
1479  return out;
1480}
1481
1482CountedPtr< Scantable > STMath::smoothOther( const CountedPtr< Scantable >& in,
1483                                             const std::string& kernel,
1484                                             float width, int order)
1485{
1486  CountedPtr< Scantable > out = getScantable(in, false);
1487  Table& table = out->table();
1488  ArrayColumn<Float> specCol(table, "SPECTRA");
1489  ArrayColumn<uChar> flagCol(table, "FLAGTRA");
1490  Vector<Float> spec;
1491  Vector<uChar> flag;
1492  for ( uInt i=0; i<table.nrow(); ++i) {
1493    specCol.get(i, spec);
1494    flagCol.get(i, flag);
1495    Vector<Bool> mask(flag.nelements());
1496    convertArray(mask, flag);
1497    Vector<Float> specout;
1498    Vector<Bool> maskout;
1499    if ( kernel == "hanning" ) {
1500      mathutil::hanning(specout, maskout, spec , !mask);
1501      convertArray(flag, !maskout);
1502    } else if (  kernel == "rmedian" ) {
1503      mathutil::runningMedian(specout, maskout, spec , mask, width);
1504      convertArray(flag, maskout);
1505    } else if ( kernel == "poly" ) {
1506      mathutil::polyfit(specout, maskout, spec, !mask, width, order);
1507      convertArray(flag, !maskout);
1508    }
1509    flagCol.put(i, flag);
1510    specCol.put(i, specout);
1511  }
1512  return out;
1513}
1514
1515CountedPtr< Scantable > STMath::smooth( const CountedPtr< Scantable >& in,
1516                                        const std::string& kernel, float width,
1517                                        int order)
1518{
1519  if (kernel == "rmedian"  || kernel == "hanning" || kernel == "poly") {
1520    return smoothOther(in, kernel, width, order);
1521  }
1522  CountedPtr< Scantable > out = getScantable(in, false);
1523  Table& table = out->table();
1524  VectorKernel::KernelTypes type = VectorKernel::toKernelType(kernel);
1525  // same IFNO should have same no of channels
1526  // this saves overhead
1527  TableIterator iter(table, "IFNO");
1528  while (!iter.pastEnd()) {
1529    Table tab = iter.table();
1530    ArrayColumn<Float> specCol(tab, "SPECTRA");
1531    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1532    Vector<Float> tmpspec; specCol.get(0, tmpspec);
1533    uInt nchan = tmpspec.nelements();
1534    Vector<Float> kvec = VectorKernel::make(type, width, nchan, True, False);
1535    Convolver<Float> conv(kvec, IPosition(1,nchan));
1536    Vector<Float> spec;
1537    Vector<uChar> flag;
1538    for ( uInt i=0; i<tab.nrow(); ++i) {
1539      specCol.get(i, spec);
1540      flagCol.get(i, flag);
1541      Vector<Bool> mask(flag.nelements());
1542      convertArray(mask, flag);
1543      Vector<Float> specout;
1544      mathutil::replaceMaskByZero(specout, mask);
1545      conv.linearConv(specout, spec);
1546      specCol.put(i, specout);
1547    }
1548    ++iter;
1549  }
1550  return out;
1551}
1552
1553CountedPtr< Scantable >
1554  STMath::merge( const std::vector< CountedPtr < Scantable > >& in )
1555{
1556  if ( in.size() < 2 ) {
1557    throw(AipsError("Need at least two scantables to perform a merge."));
1558  }
1559  std::vector<CountedPtr < Scantable > >::const_iterator it = in.begin();
1560  bool insitu = insitu_;
1561  setInsitu(false);
1562  CountedPtr< Scantable > out = getScantable(*it, false);
1563  setInsitu(insitu);
1564  Table& tout = out->table();
1565  ScalarColumn<uInt> freqidcol(tout,"FREQ_ID"), molidcol(tout, "MOLECULE_ID");
1566  ScalarColumn<uInt> scannocol(tout,"SCANNO"), focusidcol(tout,"FOCUS_ID");
1567  // Renumber SCANNO to be 0-based
1568  Vector<uInt> scannos = scannocol.getColumn();
1569  uInt offset = min(scannos);
1570  scannos -= offset;
1571  scannocol.putColumn(scannos);
1572  uInt newscanno = max(scannos)+1;
1573  ++it;
1574  while ( it != in.end() ){
1575    if ( ! (*it)->conformant(*out) ) {
1576      // non conformant.
1577      pushLog(String("Warning: Can't merge scantables as header info differs."));
1578    }
1579    out->appendToHistoryTable((*it)->history());
1580    const Table& tab = (*it)->table();
1581    TableIterator scanit(tab, "SCANNO");
1582    while (!scanit.pastEnd()) {
1583      TableIterator freqit(scanit.table(), "FREQ_ID");
1584      while ( !freqit.pastEnd() ) {
1585        Table thetab = freqit.table();
1586        uInt nrow = tout.nrow();
1587        tout.addRow(thetab.nrow());
1588        TableCopy::copyRows(tout, thetab, nrow, 0, thetab.nrow());
1589        ROTableRow row(thetab);
1590        for ( uInt i=0; i<thetab.nrow(); ++i) {
1591          uInt k = nrow+i;
1592          scannocol.put(k, newscanno);
1593          const TableRecord& rec = row.get(i);
1594          Double rv,rp,inc;
1595          (*it)->frequencies().getEntry(rp, rv, inc, rec.asuInt("FREQ_ID"));
1596          uInt id;
1597          id = out->frequencies().addEntry(rp, rv, inc);
1598          freqidcol.put(k,id);
1599          String name,fname;Double rf;
1600          (*it)->molecules().getEntry(rf, name, fname, rec.asuInt("MOLECULE_ID"));
1601          id = out->molecules().addEntry(rf, name, fname);
1602          molidcol.put(k, id);
1603          Float fpa,frot,fax,ftan,fhand,fmount,fuser, fxy, fxyp;
1604          (*it)->focus().getEntry(fpa, fax, ftan, frot, fhand,
1605                                  fmount,fuser, fxy, fxyp,
1606                                  rec.asuInt("FOCUS_ID"));
1607          id = out->focus().addEntry(fpa, fax, ftan, frot, fhand,
1608                                     fmount,fuser, fxy, fxyp);
1609          focusidcol.put(k, id);
1610        }
1611        ++freqit;
1612      }
1613      ++newscanno;
1614      ++scanit;
1615    }
1616    ++it;
1617  }
1618  return out;
1619}
1620
1621CountedPtr< Scantable >
1622  STMath::invertPhase( const CountedPtr < Scantable >& in )
1623{
1624  return applyToPol(in, &STPol::invertPhase, Float(0.0));
1625}
1626
1627CountedPtr< Scantable >
1628  STMath::rotateXYPhase( const CountedPtr < Scantable >& in, float phase )
1629{
1630   return applyToPol(in, &STPol::rotatePhase, Float(phase));
1631}
1632
1633CountedPtr< Scantable >
1634  STMath::rotateLinPolPhase( const CountedPtr < Scantable >& in, float phase )
1635{
1636  return applyToPol(in, &STPol::rotateLinPolPhase, Float(phase));
1637}
1638
1639CountedPtr< Scantable > STMath::applyToPol( const CountedPtr<Scantable>& in,
1640                                             STPol::polOperation fptr,
1641                                             Float phase )
1642{
1643  CountedPtr< Scantable > out = getScantable(in, false);
1644  Table& tout = out->table();
1645  Block<String> cols(4);
1646  cols[0] = String("SCANNO");
1647  cols[1] = String("BEAMNO");
1648  cols[2] = String("IFNO");
1649  cols[3] = String("CYCLENO");
1650  TableIterator iter(tout, cols);
1651  CountedPtr<STPol> stpol = STPol::getPolClass(out->factories_,
1652                                               out->getPolType() );
1653  while (!iter.pastEnd()) {
1654    Table t = iter.table();
1655    ArrayColumn<Float> speccol(t, "SPECTRA");
1656    ScalarColumn<uInt> focidcol(t, "FOCUS_ID");
1657    Matrix<Float> pols(speccol.getColumn());
1658    try {
1659      stpol->setSpectra(pols);
1660      Float fang,fhand;
1661      fang = in->focusTable_.getTotalAngle(focidcol(0));
1662      fhand = in->focusTable_.getFeedHand(focidcol(0));
1663      stpol->setPhaseCorrections(fang, fhand);
1664      // use a member function pointer in STPol.  This only works on
1665      // the STPol pointer itself, not the Counted Pointer so
1666      // derefernce it.
1667      (&(*(stpol))->*fptr)(phase);
1668      speccol.putColumn(stpol->getSpectra());
1669    } catch (AipsError& e) {
1670      //delete stpol;stpol=0;
1671      throw(e);
1672    }
1673    ++iter;
1674  }
1675  //delete stpol;stpol=0;
1676  return out;
1677}
1678
1679CountedPtr< Scantable >
1680  STMath::swapPolarisations( const CountedPtr< Scantable > & in )
1681{
1682  CountedPtr< Scantable > out = getScantable(in, false);
1683  Table& tout = out->table();
1684  Table t0 = tout(tout.col("POLNO") == 0);
1685  Table t1 = tout(tout.col("POLNO") == 1);
1686  if ( t0.nrow() != t1.nrow() )
1687    throw(AipsError("Inconsistent number of polarisations"));
1688  ArrayColumn<Float> speccol0(t0, "SPECTRA");
1689  ArrayColumn<uChar> flagcol0(t0, "FLAGTRA");
1690  ArrayColumn<Float> speccol1(t1, "SPECTRA");
1691  ArrayColumn<uChar> flagcol1(t1, "FLAGTRA");
1692  Matrix<Float> s0 = speccol0.getColumn();
1693  Matrix<uChar> f0 = flagcol0.getColumn();
1694  speccol0.putColumn(speccol1.getColumn());
1695  flagcol0.putColumn(flagcol1.getColumn());
1696  speccol1.putColumn(s0);
1697  flagcol1.putColumn(f0);
1698  return out;
1699}
1700
1701CountedPtr< Scantable >
1702  STMath::averagePolarisations( const CountedPtr< Scantable > & in,
1703                                const std::vector<bool>& mask,
1704                                const std::string& weight )
1705{
1706  if (in->npol() < 2 )
1707    throw(AipsError("averagePolarisations can only be applied to two or more"
1708                    "polarisations"));
1709  bool insitu = insitu_;
1710  setInsitu(false);
1711  CountedPtr< Scantable > pols = getScantable(in, true);
1712  setInsitu(insitu);
1713  Table& tout = pols->table();
1714  std::string taql = "SELECT FROM $1 WHERE POLNO IN [0,1]";
1715  Table tab = tableCommand(taql, in->table());
1716  if (tab.nrow() == 0 )
1717    throw(AipsError("Could not find  any rows with POLNO==0 and POLNO==1"));
1718  TableCopy::copyRows(tout, tab);
1719  TableVector<uInt> vec(tout, "POLNO");
1720  vec = 0;
1721  pols->table_.rwKeywordSet().define("nPol", Int(1));
1722  //pols->table_.rwKeywordSet().define("POLTYPE", String("stokes"));
1723  pols->table_.rwKeywordSet().define("POLTYPE", in->getPolType());
1724  std::vector<CountedPtr<Scantable> > vpols;
1725  vpols.push_back(pols);
1726  CountedPtr< Scantable > out = average(vpols, mask, weight, "SCAN");
1727  return out;
1728}
1729
1730CountedPtr< Scantable >
1731  STMath::averageBeams( const CountedPtr< Scantable > & in,
1732                        const std::vector<bool>& mask,
1733                        const std::string& weight )
1734{
1735  bool insitu = insitu_;
1736  setInsitu(false);
1737  CountedPtr< Scantable > beams = getScantable(in, false);
1738  setInsitu(insitu);
1739  Table& tout = beams->table();
1740  // give all rows the same BEAMNO
1741  TableVector<uInt> vec(tout, "BEAMNO");
1742  vec = 0;
1743  beams->table_.rwKeywordSet().define("nBeam", Int(1));
1744  std::vector<CountedPtr<Scantable> > vbeams;
1745  vbeams.push_back(beams);
1746  CountedPtr< Scantable > out = average(vbeams, mask, weight, "SCAN");
1747  return out;
1748}
1749
1750
1751CountedPtr< Scantable >
1752  asap::STMath::frequencyAlign( const CountedPtr< Scantable > & in,
1753                                const std::string & refTime,
1754                                const std::string & method)
1755{
1756  // clone as this is not working insitu
1757  bool insitu = insitu_;
1758  setInsitu(false);
1759  CountedPtr< Scantable > out = getScantable(in, false);
1760  setInsitu(insitu);
1761  Table& tout = out->table();
1762  // Get reference Epoch to time of first row or given String
1763  Unit DAY(String("d"));
1764  MEpoch::Ref epochRef(in->getTimeReference());
1765  MEpoch refEpoch;
1766  if (refTime.length()>0) {
1767    Quantum<Double> qt;
1768    if (MVTime::read(qt,refTime)) {
1769      MVEpoch mv(qt);
1770      refEpoch = MEpoch(mv, epochRef);
1771   } else {
1772      throw(AipsError("Invalid format for Epoch string"));
1773   }
1774  } else {
1775    refEpoch = in->timeCol_(0);
1776  }
1777  MPosition refPos = in->getAntennaPosition();
1778
1779  InterpolateArray1D<Double,Float>::InterpolationMethod interp = stringToIMethod(method);
1780  /*
1781  // Comment from MV.
1782  // the following code has been commented out because different FREQ_IDs have to be aligned together even
1783  // if the frame doesn't change. So far, lack of this check didn't cause any problems.
1784  // test if user frame is different to base frame
1785  if ( in->frequencies().getFrameString(true)
1786       == in->frequencies().getFrameString(false) ) {
1787    throw(AipsError("Can't convert as no output frame has been set"
1788                    " (use set_freqframe) or it is aligned already."));
1789  }
1790  */
1791  MFrequency::Types system = in->frequencies().getFrame();
1792  MVTime mvt(refEpoch.getValue());
1793  String epochout = mvt.string(MVTime::YMD) + String(" (") + refEpoch.getRefString() + String(")");
1794  ostringstream oss;
1795  oss << "Aligned at reference Epoch " << epochout
1796      << " in frame " << MFrequency::showType(system);
1797  pushLog(String(oss));
1798  // set up the iterator
1799  Block<String> cols(4);
1800  // select by constant direction
1801  cols[0] = String("SRCNAME");
1802  cols[1] = String("BEAMNO");
1803  // select by IF ( no of channels varies over this )
1804  cols[2] = String("IFNO");
1805  // select by restfrequency
1806  cols[3] = String("MOLECULE_ID");
1807  TableIterator iter(tout, cols);
1808  while ( !iter.pastEnd() ) {
1809    Table t = iter.table();
1810    MDirection::ROScalarColumn dirCol(t, "DIRECTION");
1811    TableIterator fiter(t, "FREQ_ID");
1812    // determine nchan from the first row. This should work as
1813    // we are iterating over BEAMNO and IFNO    // we should have constant direction
1814
1815    ROArrayColumn<Float> sCol(t, "SPECTRA");
1816    const MDirection direction = dirCol(0);
1817    const uInt nchan = sCol(0).nelements();
1818
1819    // skip operations if there is nothing to align
1820    if (fiter.pastEnd()) {
1821        continue;
1822    }
1823
1824    Table ftab = fiter.table();
1825    // align all frequency ids with respect to the first encountered id
1826    ScalarColumn<uInt> freqidCol(ftab, "FREQ_ID");
1827    // get the SpectralCoordinate for the freqid, which we are iterating over
1828    SpectralCoordinate sC = in->frequencies().getSpectralCoordinate(freqidCol(0));
1829    FrequencyAligner<Float> fa( sC, nchan, refEpoch,
1830                                direction, refPos, system );
1831    // realign the SpectralCoordinate and put into the output Scantable
1832    Vector<String> units(1);
1833    units = String("Hz");
1834    Bool linear=True;
1835    SpectralCoordinate sc2 = fa.alignedSpectralCoordinate(linear);
1836    sc2.setWorldAxisUnits(units);
1837    const uInt id = out->frequencies().addEntry(sc2.referencePixel()[0],
1838                                                sc2.referenceValue()[0],
1839                                                sc2.increment()[0]);
1840    while ( !fiter.pastEnd() ) {
1841      ftab = fiter.table();
1842      // spectral coordinate for the current FREQ_ID
1843      ScalarColumn<uInt> freqidCol2(ftab, "FREQ_ID");
1844      sC = in->frequencies().getSpectralCoordinate(freqidCol2(0));
1845      // create the "global" abcissa for alignment with same FREQ_ID
1846      Vector<Double> abc(nchan);
1847      for (uInt i=0; i<nchan; i++) {
1848           Double w;
1849           sC.toWorld(w,Double(i));
1850           abc[i] = w;
1851      }
1852      TableVector<uInt> tvec(ftab, "FREQ_ID");
1853      // assign new frequency id to all rows
1854      tvec = id;
1855      // cache abcissa for same time stamps, so iterate over those
1856      TableIterator timeiter(ftab, "TIME");
1857      while ( !timeiter.pastEnd() ) {
1858        Table tab = timeiter.table();
1859        ArrayColumn<Float> specCol(tab, "SPECTRA");
1860        ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1861        MEpoch::ROScalarColumn timeCol(tab, "TIME");
1862        // use align abcissa cache after the first row
1863        // these rows should be just be POLNO
1864        bool first = true;
1865        for (int i=0; i<int(tab.nrow()); ++i) {
1866          // input values
1867          Vector<uChar> flag = flagCol(i);
1868          Vector<Bool> mask(flag.shape());
1869          Vector<Float> specOut, spec;
1870          spec  = specCol(i);
1871          Vector<Bool> maskOut;Vector<uChar> flagOut;
1872          convertArray(mask, flag);
1873          // alignment
1874          Bool ok = fa.align(specOut, maskOut, abc, spec,
1875                             mask, timeCol(i), !first,
1876                             interp, False);
1877          // back into scantable
1878          flagOut.resize(maskOut.nelements());
1879          convertArray(flagOut, maskOut);
1880          flagCol.put(i, flagOut);
1881          specCol.put(i, specOut);
1882          // start abcissa caching
1883          first = false;
1884        }
1885        // next timestamp
1886        ++timeiter;
1887      }
1888      // next FREQ_ID
1889      ++fiter;
1890    }
1891    // next aligner
1892    ++iter;
1893  }
1894  // set this afterwards to ensure we are doing insitu correctly.
1895  out->frequencies().setFrame(system, true);
1896  return out;
1897}
1898
1899CountedPtr<Scantable>
1900  asap::STMath::convertPolarisation( const CountedPtr<Scantable>& in,
1901                                     const std::string & newtype )
1902{
1903  if (in->npol() != 2 && in->npol() != 4)
1904    throw(AipsError("Can only convert two or four polarisations."));
1905  if ( in->getPolType() == newtype )
1906    throw(AipsError("No need to convert."));
1907  if ( ! in->selector_.empty() )
1908    throw(AipsError("Can only convert whole scantable. Unset the selection."));
1909  bool insitu = insitu_;
1910  setInsitu(false);
1911  CountedPtr< Scantable > out = getScantable(in, true);
1912  setInsitu(insitu);
1913  Table& tout = out->table();
1914  tout.rwKeywordSet().define("POLTYPE", String(newtype));
1915
1916  Block<String> cols(4);
1917  cols[0] = "SCANNO";
1918  cols[1] = "CYCLENO";
1919  cols[2] = "BEAMNO";
1920  cols[3] = "IFNO";
1921  TableIterator it(in->originalTable_, cols);
1922  String basetype = in->getPolType();
1923  STPol* stpol = STPol::getPolClass(in->factories_, basetype);
1924  try {
1925    while ( !it.pastEnd() ) {
1926      Table tab = it.table();
1927      uInt row = tab.rowNumbers()[0];
1928      stpol->setSpectra(in->getPolMatrix(row));
1929      Float fang,fhand;
1930      fang = in->focusTable_.getTotalAngle(in->mfocusidCol_(row));
1931      fhand = in->focusTable_.getFeedHand(in->mfocusidCol_(row));
1932      stpol->setPhaseCorrections(fang, fhand);
1933      Int npolout = 0;
1934      for (uInt i=0; i<tab.nrow(); ++i) {
1935        Vector<Float> outvec = stpol->getSpectrum(i, newtype);
1936        if ( outvec.nelements() > 0 ) {
1937          tout.addRow();
1938          TableCopy::copyRows(tout, tab, tout.nrow()-1, 0, 1);
1939          ArrayColumn<Float> sCol(tout,"SPECTRA");
1940          ScalarColumn<uInt> pCol(tout,"POLNO");
1941          sCol.put(tout.nrow()-1 ,outvec);
1942          pCol.put(tout.nrow()-1 ,uInt(npolout));
1943          npolout++;
1944       }
1945      }
1946      tout.rwKeywordSet().define("nPol", npolout);
1947      ++it;
1948    }
1949  } catch (AipsError& e) {
1950    delete stpol;
1951    throw(e);
1952  }
1953  delete stpol;
1954  return out;
1955}
1956
1957CountedPtr< Scantable >
1958  asap::STMath::mxExtract( const CountedPtr< Scantable > & in,
1959                           const std::string & scantype )
1960{
1961  bool insitu = insitu_;
1962  setInsitu(false);
1963  CountedPtr< Scantable > out = getScantable(in, true);
1964  setInsitu(insitu);
1965  Table& tout = out->table();
1966  std::string taql = "SELECT FROM $1 WHERE BEAMNO != REFBEAMNO";
1967  if (scantype == "on") {
1968    taql = "SELECT FROM $1 WHERE BEAMNO == REFBEAMNO";
1969  }
1970  Table tab = tableCommand(taql, in->table());
1971  TableCopy::copyRows(tout, tab);
1972  if (scantype == "on") {
1973    // re-index SCANNO to 0
1974    TableVector<uInt> vec(tout, "SCANNO");
1975    vec = 0;
1976  }
1977  return out;
1978}
1979
1980CountedPtr< Scantable >
1981  asap::STMath::lagFlag( const CountedPtr< Scantable > & in,
1982                         double start, double end,
1983                         const std::string& mode)
1984{
1985  CountedPtr< Scantable > out = getScantable(in, false);
1986  Table& tout = out->table();
1987  TableIterator iter(tout, "FREQ_ID");
1988  FFTServer<Float,Complex> ffts;
1989  while ( !iter.pastEnd() ) {
1990    Table tab = iter.table();
1991    Double rp,rv,inc;
1992    ROTableRow row(tab);
1993    const TableRecord& rec = row.get(0);
1994    uInt freqid = rec.asuInt("FREQ_ID");
1995    out->frequencies().getEntry(rp, rv, inc, freqid);
1996    ArrayColumn<Float> specCol(tab, "SPECTRA");
1997    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1998    for (int i=0; i<int(tab.nrow()); ++i) {
1999      Vector<Float> spec = specCol(i);
2000      Vector<uChar> flag = flagCol(i);
2001      int fstart = -1;
2002      int fend = -1;
2003      for (int k=0; k < flag.nelements(); ++k ) {
2004        if (flag[k] > 0) {
2005          fstart = k;
2006          while (flag[k] > 0 && k < flag.nelements()) {
2007            fend = k;
2008            k++;
2009          }
2010        }
2011        Float interp = 0.0;
2012        if (fstart-1 > 0 ) {
2013          interp = spec[fstart-1];
2014          if (fend+1 < spec.nelements()) {
2015            interp = (interp+spec[fend+1])/2.0;
2016          }
2017        } else {
2018          interp = spec[fend+1];
2019        }
2020        if (fstart > -1 && fend > -1) {
2021          for (int j=fstart;j<=fend;++j) {
2022            spec[j] = interp;
2023          }
2024        }
2025        fstart =-1;
2026        fend = -1;
2027      }
2028      Vector<Complex> lags;
2029      ffts.fft0(lags, spec);
2030      Int lag0(start+0.5);
2031      Int lag1(end+0.5);
2032      if (mode == "frequency") {
2033        lag0 = Int(spec.nelements()*abs(inc)/(start)+0.5);
2034        lag1 = Int(spec.nelements()*abs(inc)/(end)+0.5);
2035      }
2036      Int lstart =  max(0, lag0);
2037      Int lend =  min(Int(lags.nelements()-1), lag1);
2038      if (lstart == lend) {
2039        lags[lstart] = Complex(0.0);
2040      } else {
2041        if (lstart > lend) {
2042          Int tmp = lend;
2043          lend = lstart;
2044          lstart = tmp;
2045        }
2046        for (int j=lstart; j <=lend ;++j) {
2047          lags[j] = Complex(0.0);
2048        }
2049      }
2050      ffts.fft0(spec, lags);
2051      specCol.put(i, spec);
2052    }
2053    ++iter;
2054  }
2055  return out;
2056}
Note: See TracBrowser for help on using the repository browser.