source: trunk/src/STMath.cpp @ 1314

Last change on this file since 1314 was 1314, checked in by mar637, 17 years ago

fixed defect, where scantable averaging output failed if first row in ouput was all flagged

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 49.0 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 "MathUtils.h"
47#include "RowAccumulator.h"
48#include "STAttr.h"
49#include "STMath.h"
50
51using namespace casa;
52
53using namespace asap;
54
55STMath::STMath(bool insitu) :
56  insitu_(insitu)
57{
58}
59
60
61STMath::~STMath()
62{
63}
64
65CountedPtr<Scantable>
66STMath::average( const std::vector<CountedPtr<Scantable> >& in,
67                 const std::vector<bool>& mask,
68                 const std::string& weight,
69                 const std::string& avmode)
70{
71  if ( avmode == "SCAN" && in.size() != 1 )
72    throw(AipsError("Can't perform 'SCAN' averaging on multiple tables.\n"
73                    "Use merge first."));
74  WeightType wtype = stringToWeight(weight);
75
76  // output
77  // clone as this is non insitu
78  bool insitu = insitu_;
79  setInsitu(false);
80  CountedPtr< Scantable > out = getScantable(in[0], true);
81  setInsitu(insitu);
82  std::vector<CountedPtr<Scantable> >::const_iterator stit = in.begin();
83  ++stit;
84  while ( stit != in.end() ) {
85    out->appendToHistoryTable((*stit)->history());
86    ++stit;
87  }
88
89  Table& tout = out->table();
90
91  /// @todo check if all scantables are conformant
92
93  ArrayColumn<Float> specColOut(tout,"SPECTRA");
94  ArrayColumn<uChar> flagColOut(tout,"FLAGTRA");
95  ArrayColumn<Float> tsysColOut(tout,"TSYS");
96  ScalarColumn<Double> mjdColOut(tout,"TIME");
97  ScalarColumn<Double> intColOut(tout,"INTERVAL");
98  ScalarColumn<uInt> cycColOut(tout,"CYCLENO");
99  ScalarColumn<uInt> scanColOut(tout,"SCANNO");
100
101  // set up the output table rows. These are based on the structure of the
102  // FIRST scantable in the vector
103  const Table& baset = in[0]->table();
104
105  Block<String> cols(3);
106  cols[0] = String("BEAMNO");
107  cols[1] = String("IFNO");
108  cols[2] = String("POLNO");
109  if ( avmode == "SOURCE" ) {
110    cols.resize(4);
111    cols[3] = String("SRCNAME");
112  }
113  if ( avmode == "SCAN"  && in.size() == 1) {
114    cols.resize(4);
115    cols[3] = String("SCANNO");
116  }
117  uInt outrowCount = 0;
118  TableIterator iter(baset, cols);
119  while (!iter.pastEnd()) {
120    Table subt = iter.table();
121    // copy the first row of this selection into the new table
122    tout.addRow();
123    TableCopy::copyRows(tout, subt, outrowCount, 0, 1);
124    // re-index to 0
125    if ( avmode != "SCAN" && avmode != "SOURCE" ) {
126      scanColOut.put(outrowCount, uInt(0));
127    }
128    ++outrowCount;
129    ++iter;
130  }
131  RowAccumulator acc(wtype);
132  Vector<Bool> cmask(mask);
133  acc.setUserMask(cmask);
134  ROTableRow row(tout);
135  ROArrayColumn<Float> specCol, tsysCol;
136  ROArrayColumn<uChar> flagCol;
137  ROScalarColumn<Double> mjdCol, intCol;
138  ROScalarColumn<Int> scanIDCol;
139
140  for (uInt i=0; i < tout.nrow(); ++i) {
141    for ( int j=0; j < int(in.size()); ++j ) {
142      const Table& tin = in[j]->table();
143      const TableRecord& rec = row.get(i);
144      ROScalarColumn<Double> tmp(tin, "TIME");
145      Double td;tmp.get(0,td);
146      Table basesubt = tin(tin.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
147                       && tin.col("IFNO") == Int(rec.asuInt("IFNO"))
148                       && tin.col("POLNO") == Int(rec.asuInt("POLNO")) );
149      Table subt;
150      if ( avmode == "SOURCE") {
151        subt = basesubt( basesubt.col("SRCNAME") == rec.asString("SRCNAME") );
152      } else if (avmode == "SCAN") {
153        subt = basesubt( basesubt.col("SCANNO") == Int(rec.asuInt("SCANNO")) );
154      } else {
155        subt = basesubt;
156      }
157      specCol.attach(subt,"SPECTRA");
158      flagCol.attach(subt,"FLAGTRA");
159      tsysCol.attach(subt,"TSYS");
160      intCol.attach(subt,"INTERVAL");
161      mjdCol.attach(subt,"TIME");
162      Vector<Float> spec,tsys;
163      Vector<uChar> flag;
164      Double inter,time;
165      for (uInt k = 0; k < subt.nrow(); ++k ) {
166        flagCol.get(k, flag);
167        Vector<Bool> bflag(flag.shape());
168        convertArray(bflag, flag);
169        /*
170        if ( allEQ(bflag, True) ) {
171        continue;//don't accumulate
172        }
173        */
174        specCol.get(k, spec);
175        tsysCol.get(k, tsys);
176        intCol.get(k, inter);
177        mjdCol.get(k, time);
178        // spectrum has to be added last to enable weighting by the other values
179        acc.add(spec, !bflag, tsys, inter, time);
180      }
181    }
182    //write out
183    specColOut.put(i, acc.getSpectrum());
184    const Vector<Bool>& msk = acc.getMask();
185    Vector<uChar> flg(msk.shape());
186    convertArray(flg, !msk);
187    flagColOut.put(i, flg);
188    tsysColOut.put(i, acc.getTsys());
189    intColOut.put(i, acc.getInterval());
190    mjdColOut.put(i, acc.getTime());
191    // we should only have one cycle now -> reset it to be 0
192    // frequency switched data has different CYCLENO for different IFNO
193    // which requires resetting this value
194    cycColOut.put(i, uInt(0));
195    acc.reset();
196  }
197  return out;
198}
199
200CountedPtr< Scantable >
201  STMath::averageChannel( const CountedPtr < Scantable > & in,
202                          const std::string & mode,
203                          const std::string& avmode )
204{
205  // clone as this is non insitu
206  bool insitu = insitu_;
207  setInsitu(false);
208  CountedPtr< Scantable > out = getScantable(in, true);
209  setInsitu(insitu);
210  Table& tout = out->table();
211  ArrayColumn<Float> specColOut(tout,"SPECTRA");
212  ArrayColumn<uChar> flagColOut(tout,"FLAGTRA");
213  ArrayColumn<Float> tsysColOut(tout,"TSYS");
214  ScalarColumn<uInt> scanColOut(tout,"SCANNO");
215  ScalarColumn<Double> intColOut(tout, "INTERVAL");
216  Table tmp = in->table().sort("BEAMNO");
217  Block<String> cols(3);
218  cols[0] = String("BEAMNO");
219  cols[1] = String("IFNO");
220  cols[2] = String("POLNO");
221  if ( avmode == "SCAN") {
222    cols.resize(4);
223    cols[3] = String("SCANNO");
224  }
225  uInt outrowCount = 0;
226  uChar userflag = 1 << 7;
227  TableIterator iter(tmp, cols);
228  while (!iter.pastEnd()) {
229    Table subt = iter.table();
230    ROArrayColumn<Float> specCol, tsysCol;
231    ROArrayColumn<uChar> flagCol;
232    ROScalarColumn<Double> intCol(subt, "INTERVAL");
233    specCol.attach(subt,"SPECTRA");
234    flagCol.attach(subt,"FLAGTRA");
235    tsysCol.attach(subt,"TSYS");
236    tout.addRow();
237    TableCopy::copyRows(tout, subt, outrowCount, 0, 1);
238    if ( avmode != "SCAN") {
239      scanColOut.put(outrowCount, uInt(0));
240    }
241    Vector<Float> tmp;
242    specCol.get(0, tmp);
243    uInt nchan = tmp.nelements();
244    // have to do channel by channel here as MaskedArrMath
245    // doesn't have partialMedians
246    Vector<uChar> flags = flagCol.getColumn(Slicer(Slice(0)));
247    Vector<Float> outspec(nchan);
248    Vector<uChar> outflag(nchan,0);
249    Vector<Float> outtsys(1);/// @fixme when tsys is channel based
250    for (uInt i=0; i<nchan; ++i) {
251      Vector<Float> specs = specCol.getColumn(Slicer(Slice(i)));
252      MaskedArray<Float> ma = maskedArray(specs,flags);
253      outspec[i] = median(ma);
254      if ( allEQ(ma.getMask(), False) )
255        outflag[i] = userflag;// flag data
256    }
257    outtsys[0] = median(tsysCol.getColumn());
258    specColOut.put(outrowCount, outspec);
259    flagColOut.put(outrowCount, outflag);
260    tsysColOut.put(outrowCount, outtsys);
261    Double intsum = sum(intCol.getColumn());
262    intColOut.put(outrowCount, intsum);
263    ++outrowCount;
264    ++iter;
265  }
266  return out;
267}
268
269CountedPtr< Scantable > STMath::getScantable(const CountedPtr< Scantable >& in,
270                                             bool droprows)
271{
272  if (insitu_) return in;
273  else {
274    // clone
275    Scantable* tabp = new Scantable(*in, Bool(droprows));
276    return CountedPtr<Scantable>(tabp);
277  }
278}
279
280CountedPtr< Scantable > STMath::unaryOperate( const CountedPtr< Scantable >& in,
281                                              float val,
282                                              const std::string& mode,
283                                              bool tsys )
284{
285  CountedPtr< Scantable > out = getScantable(in, false);
286  Table& tab = out->table();
287  ArrayColumn<Float> specCol(tab,"SPECTRA");
288  ArrayColumn<Float> tsysCol(tab,"TSYS");
289  for (uInt i=0; i<tab.nrow(); ++i) {
290    Vector<Float> spec;
291    Vector<Float> ts;
292    specCol.get(i, spec);
293    tsysCol.get(i, ts);
294    if (mode == "MUL" || mode == "DIV") {
295      if (mode == "DIV") val = 1.0/val;
296      spec *= val;
297      specCol.put(i, spec);
298      if ( tsys ) {
299        ts *= val;
300        tsysCol.put(i, ts);
301      }
302    } else if ( mode == "ADD"  || mode == "SUB") {
303      if (mode == "SUB") val *= -1.0;
304      spec += val;
305      specCol.put(i, spec);
306      if ( tsys ) {
307        ts += val;
308        tsysCol.put(i, ts);
309      }
310    }
311  }
312  return out;
313}
314
315CountedPtr<Scantable> STMath::binaryOperate(const CountedPtr<Scantable>& left,
316                                            const CountedPtr<Scantable>& right,
317                                            const std::string& mode)
318{
319  bool insitu = insitu_;
320  if ( ! left->conformant(*right) ) {
321    throw(AipsError("'left' and 'right' scantables are not conformant."));
322  }
323  setInsitu(false);
324  CountedPtr< Scantable > out = getScantable(left, false);
325  setInsitu(insitu);
326  Table& tout = out->table();
327  Block<String> coln(5);
328  coln[0] = "SCANNO";  coln[1] = "CYCLENO";  coln[2] = "BEAMNO";
329  coln[3] = "IFNO";  coln[4] = "POLNO";
330  Table tmpl = tout.sort(coln);
331  Table tmpr = right->table().sort(coln);
332  ArrayColumn<Float> lspecCol(tmpl,"SPECTRA");
333  ROArrayColumn<Float> rspecCol(tmpr,"SPECTRA");
334  ArrayColumn<uChar> lflagCol(tmpl,"FLAGTRA");
335  ROArrayColumn<uChar> rflagCol(tmpr,"FLAGTRA");
336
337  for (uInt i=0; i<tout.nrow(); ++i) {
338    Vector<Float> lspecvec, rspecvec;
339    Vector<uChar> lflagvec, rflagvec;
340    lspecvec = lspecCol(i);    rspecvec = rspecCol(i);
341    lflagvec = lflagCol(i);    rflagvec = rflagCol(i);
342    MaskedArray<Float> mleft = maskedArray(lspecvec, lflagvec);
343    MaskedArray<Float> mright = maskedArray(rspecvec, rflagvec);
344    if (mode == "ADD") {
345      mleft += mright;
346    } else if ( mode == "SUB") {
347      mleft -= mright;
348    } else if ( mode == "MUL") {
349      mleft *= mright;
350    } else if ( mode == "DIV") {
351      mleft /= mright;
352    } else {
353      throw(AipsError("Illegal binary operator"));
354    }
355    lspecCol.put(i, mleft.getArray());
356  }
357  return out;
358}
359
360
361
362MaskedArray<Float> STMath::maskedArray( const Vector<Float>& s,
363                                        const Vector<uChar>& f)
364{
365  Vector<Bool> mask;
366  mask.resize(f.shape());
367  convertArray(mask, f);
368  return MaskedArray<Float>(s,!mask);
369}
370
371Vector<uChar> STMath::flagsFromMA(const MaskedArray<Float>& ma)
372{
373  const Vector<Bool>& m = ma.getMask();
374  Vector<uChar> flags(m.shape());
375  convertArray(flags, !m);
376  return flags;
377}
378
379CountedPtr< Scantable > STMath::autoQuotient( const CountedPtr< Scantable >& in,
380                                              const std::string & mode,
381                                              bool preserve )
382{
383  /// @todo make other modes available
384  /// modes should be "nearest", "pair"
385  // make this operation non insitu
386  const Table& tin = in->table();
387  Table ons = tin(tin.col("SRCTYPE") == Int(0));
388  Table offs = tin(tin.col("SRCTYPE") == Int(1));
389  if ( offs.nrow() == 0 )
390    throw(AipsError("No 'off' scans present."));
391  // put all "on" scans into output table
392
393  bool insitu = insitu_;
394  setInsitu(false);
395  CountedPtr< Scantable > out = getScantable(in, true);
396  setInsitu(insitu);
397  Table& tout = out->table();
398
399  TableCopy::copyRows(tout, ons);
400  TableRow row(tout);
401  ROScalarColumn<Double> offtimeCol(offs, "TIME");
402  ArrayColumn<Float> outspecCol(tout, "SPECTRA");
403  ROArrayColumn<Float> outtsysCol(tout, "TSYS");
404  ArrayColumn<uChar> outflagCol(tout, "FLAGTRA");
405  for (uInt i=0; i < tout.nrow(); ++i) {
406    const TableRecord& rec = row.get(i);
407    Double ontime = rec.asDouble("TIME");
408    ROScalarColumn<Double> offtimeCol(offs, "TIME");
409    Double mindeltat = min(abs(offtimeCol.getColumn() - ontime));
410    // Timestamp may vary within a cycle ???!!!
411    // increase this by 0.5 sec in case of rounding errors...
412    // There might be a better way to do this.
413    mindeltat += 0.5;
414    Table sel = offs( abs(offs.col("TIME")-ontime) <= (mindeltat+0.5)
415                       && offs.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
416                       && offs.col("IFNO") == Int(rec.asuInt("IFNO"))
417                       && offs.col("POLNO") == Int(rec.asuInt("POLNO")) );
418
419    if ( sel.nrow() < 1 )  {
420      throw(AipsError("No closest in time found... This could be a rounding "
421                      "issue. Try quotient instead."));
422    }
423    TableRow offrow(sel);
424    const TableRecord& offrec = offrow.get(0);//should only be one row
425    RORecordFieldPtr< Array<Float> > specoff(offrec, "SPECTRA");
426    RORecordFieldPtr< Array<Float> > tsysoff(offrec, "TSYS");
427    RORecordFieldPtr< Array<uChar> > flagoff(offrec, "FLAGTRA");
428    /// @fixme this assumes tsys is a scalar not vector
429    Float tsysoffscalar = (*tsysoff)(IPosition(1,0));
430    Vector<Float> specon, tsyson;
431    outtsysCol.get(i, tsyson);
432    outspecCol.get(i, specon);
433    Vector<uChar> flagon;
434    outflagCol.get(i, flagon);
435    MaskedArray<Float> mon = maskedArray(specon, flagon);
436    MaskedArray<Float> moff = maskedArray(*specoff, *flagoff);
437    MaskedArray<Float> quot = (tsysoffscalar * mon / moff);
438    if (preserve) {
439      quot -= tsysoffscalar;
440    } else {
441      quot -= tsyson[0];
442    }
443    outspecCol.put(i, quot.getArray());
444    outflagCol.put(i, flagsFromMA(quot));
445  }
446  // renumber scanno
447  TableIterator it(tout, "SCANNO");
448  uInt i = 0;
449  while ( !it.pastEnd() ) {
450    Table t = it.table();
451    TableVector<uInt> vec(t, "SCANNO");
452    vec = i;
453    ++i;
454    ++it;
455  }
456  return out;
457}
458
459
460CountedPtr< Scantable > STMath::quotient( const CountedPtr< Scantable > & on,
461                                          const CountedPtr< Scantable > & off,
462                                          bool preserve )
463{
464  bool insitu = insitu_;
465  if ( ! on->conformant(*off) ) {
466    throw(AipsError("'on' and 'off' scantables are not conformant."));
467  }
468  setInsitu(false);
469  CountedPtr< Scantable > out = getScantable(on, false);
470  setInsitu(insitu);
471  Table& tout = out->table();
472  const Table& toff = off->table();
473  TableIterator sit(tout, "SCANNO");
474  TableIterator s2it(toff, "SCANNO");
475  while ( !sit.pastEnd() ) {
476    Table ton = sit.table();
477    TableRow row(ton);
478    Table t = s2it.table();
479    ArrayColumn<Float> outspecCol(ton, "SPECTRA");
480    ROArrayColumn<Float> outtsysCol(ton, "TSYS");
481    ArrayColumn<uChar> outflagCol(ton, "FLAGTRA");
482    for (uInt i=0; i < ton.nrow(); ++i) {
483      const TableRecord& rec = row.get(i);
484      Table offsel = t( t.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
485                          && t.col("IFNO") == Int(rec.asuInt("IFNO"))
486                          && t.col("POLNO") == Int(rec.asuInt("POLNO")) );
487      if ( offsel.nrow() == 0 )
488        throw AipsError("STMath::quotient: no matching off");
489      TableRow offrow(offsel);
490      const TableRecord& offrec = offrow.get(0);//should be ncycles - take first
491      RORecordFieldPtr< Array<Float> > specoff(offrec, "SPECTRA");
492      RORecordFieldPtr< Array<Float> > tsysoff(offrec, "TSYS");
493      RORecordFieldPtr< Array<uChar> > flagoff(offrec, "FLAGTRA");
494      Float tsysoffscalar = (*tsysoff)(IPosition(1,0));
495      Vector<Float> specon, tsyson;
496      outtsysCol.get(i, tsyson);
497      outspecCol.get(i, specon);
498      Vector<uChar> flagon;
499      outflagCol.get(i, flagon);
500      MaskedArray<Float> mon = maskedArray(specon, flagon);
501      MaskedArray<Float> moff = maskedArray(*specoff, *flagoff);
502      MaskedArray<Float> quot = (tsysoffscalar * mon / moff);
503      if (preserve) {
504        quot -= tsysoffscalar;
505      } else {
506        quot -= tsyson[0];
507      }
508      outspecCol.put(i, quot.getArray());
509      outflagCol.put(i, flagsFromMA(quot));
510    }
511    ++sit;
512    ++s2it;
513    // take the first off for each on scan which doesn't have a
514    // matching off scan
515    // non <= noff:  matching pairs, non > noff matching pairs then first off
516    if ( s2it.pastEnd() ) s2it.reset();
517  }
518  return out;
519}
520
521
522CountedPtr< Scantable > STMath::freqSwitch( const CountedPtr< Scantable >& in )
523{
524  // make copy or reference
525  CountedPtr< Scantable > out = getScantable(in, false);
526  Table& tout = out->table();
527  Block<String> cols(4);
528  cols[0] = String("SCANNO");
529  cols[1] = String("CYCLENO");
530  cols[2] = String("BEAMNO");
531  cols[3] = String("POLNO");
532  TableIterator iter(tout, cols);
533  while (!iter.pastEnd()) {
534    Table subt = iter.table();
535    // this should leave us with two rows for the two IFs....if not ignore
536    if (subt.nrow() != 2 ) {
537      continue;
538    }
539    ArrayColumn<Float> specCol(subt, "SPECTRA");
540    ArrayColumn<Float> tsysCol(subt, "TSYS");
541    ArrayColumn<uChar> flagCol(subt, "FLAGTRA");
542    Vector<Float> onspec,offspec, ontsys, offtsys;
543    Vector<uChar> onflag, offflag;
544    tsysCol.get(0, ontsys);   tsysCol.get(1, offtsys);
545    specCol.get(0, onspec);   specCol.get(1, offspec);
546    flagCol.get(0, onflag);   flagCol.get(1, offflag);
547    MaskedArray<Float> on  = maskedArray(onspec, onflag);
548    MaskedArray<Float> off = maskedArray(offspec, offflag);
549    MaskedArray<Float> oncopy = on.copy();
550
551    on /= off; on -= 1.0f;
552    on *= ontsys[0];
553    off /= oncopy; off -= 1.0f;
554    off *= offtsys[0];
555    specCol.put(0, on.getArray());
556    const Vector<Bool>& m0 = on.getMask();
557    Vector<uChar> flags0(m0.shape());
558    convertArray(flags0, !m0);
559    flagCol.put(0, flags0);
560
561    specCol.put(1, off.getArray());
562    const Vector<Bool>& m1 = off.getMask();
563    Vector<uChar> flags1(m1.shape());
564    convertArray(flags1, !m1);
565    flagCol.put(1, flags1);
566    ++iter;
567  }
568
569  return out;
570}
571
572std::vector< float > STMath::statistic( const CountedPtr< Scantable > & in,
573                                        const std::vector< bool > & mask,
574                                        const std::string& which )
575{
576
577  Vector<Bool> m(mask);
578  const Table& tab = in->table();
579  ROArrayColumn<Float> specCol(tab, "SPECTRA");
580  ROArrayColumn<uChar> flagCol(tab, "FLAGTRA");
581  std::vector<float> out;
582  for (uInt i=0; i < tab.nrow(); ++i ) {
583    Vector<Float> spec; specCol.get(i, spec);
584    Vector<uChar> flag; flagCol.get(i, flag);
585    MaskedArray<Float> ma  = maskedArray(spec, flag);
586    float outstat = 0.0;
587    if ( spec.nelements() == m.nelements() ) {
588      outstat = mathutil::statistics(which, ma(m));
589    } else {
590      outstat = mathutil::statistics(which, ma);
591    }
592    out.push_back(outstat);
593  }
594  return out;
595}
596
597CountedPtr< Scantable > STMath::bin( const CountedPtr< Scantable > & in,
598                                     int width )
599{
600  if ( !in->getSelection().empty() ) throw(AipsError("Can't bin subset of the data."));
601  CountedPtr< Scantable > out = getScantable(in, false);
602  Table& tout = out->table();
603  out->frequencies().rescale(width, "BIN");
604  ArrayColumn<Float> specCol(tout, "SPECTRA");
605  ArrayColumn<uChar> flagCol(tout, "FLAGTRA");
606  for (uInt i=0; i < tout.nrow(); ++i ) {
607    MaskedArray<Float> main  = maskedArray(specCol(i), flagCol(i));
608    MaskedArray<Float> maout;
609    LatticeUtilities::bin(maout, main, 0, Int(width));
610    /// @todo implement channel based tsys binning
611    specCol.put(i, maout.getArray());
612    flagCol.put(i, flagsFromMA(maout));
613    // take only the first binned spectrum's length for the deprecated
614    // global header item nChan
615    if (i==0) tout.rwKeywordSet().define(String("nChan"),
616                                       Int(maout.getArray().nelements()));
617  }
618  return out;
619}
620
621CountedPtr< Scantable > STMath::resample( const CountedPtr< Scantable >& in,
622                                          const std::string& method,
623                                          float width )
624//
625// Should add the possibility of width being specified in km/s. This means
626// that for each freqID (SpectralCoordinate) we will need to convert to an
627// average channel width (say at the reference pixel).  Then we would need
628// to be careful to make sure each spectrum (of different freqID)
629// is the same length.
630//
631{
632  //InterpolateArray1D<Double,Float>::InterpolationMethod interp;
633  Int interpMethod(stringToIMethod(method));
634
635  CountedPtr< Scantable > out = getScantable(in, false);
636  Table& tout = out->table();
637
638// Resample SpectralCoordinates (one per freqID)
639  out->frequencies().rescale(width, "RESAMPLE");
640  TableIterator iter(tout, "IFNO");
641  TableRow row(tout);
642  while ( !iter.pastEnd() ) {
643    Table tab = iter.table();
644    ArrayColumn<Float> specCol(tab, "SPECTRA");
645    //ArrayColumn<Float> tsysCol(tout, "TSYS");
646    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
647    Vector<Float> spec;
648    Vector<uChar> flag;
649    specCol.get(0,spec); // the number of channels should be constant per IF
650    uInt nChanIn = spec.nelements();
651    Vector<Float> xIn(nChanIn); indgen(xIn);
652    Int fac =  Int(nChanIn/width);
653    Vector<Float> xOut(fac+10); // 10 to be safe - resize later
654    uInt k = 0;
655    Float x = 0.0;
656    while (x < Float(nChanIn) ) {
657      xOut(k) = x;
658      k++;
659      x += width;
660    }
661    uInt nChanOut = k;
662    xOut.resize(nChanOut, True);
663    // process all rows for this IFNO
664    Vector<Float> specOut;
665    Vector<Bool> maskOut;
666    Vector<uChar> flagOut;
667    for (uInt i=0; i < tab.nrow(); ++i) {
668      specCol.get(i, spec);
669      flagCol.get(i, flag);
670      Vector<Bool> mask(flag.nelements());
671      convertArray(mask, flag);
672
673      IPosition shapeIn(spec.shape());
674      //sh.nchan = nChanOut;
675      InterpolateArray1D<Float,Float>::interpolate(specOut, maskOut, xOut,
676                                                   xIn, spec, mask,
677                                                   interpMethod, True, True);
678      /// @todo do the same for channel based Tsys
679      flagOut.resize(maskOut.nelements());
680      convertArray(flagOut, maskOut);
681      specCol.put(i, specOut);
682      flagCol.put(i, flagOut);
683    }
684    ++iter;
685  }
686
687  return out;
688}
689
690STMath::imethod STMath::stringToIMethod(const std::string& in)
691{
692  static STMath::imap lookup;
693
694  // initialize the lookup table if necessary
695  if ( lookup.empty() ) {
696    lookup["nearest"]   = InterpolateArray1D<Double,Float>::nearestNeighbour;
697    lookup["linear"] = InterpolateArray1D<Double,Float>::linear;
698    lookup["cubic"]  = InterpolateArray1D<Double,Float>::cubic;
699    lookup["spline"]  = InterpolateArray1D<Double,Float>::spline;
700  }
701
702  STMath::imap::const_iterator iter = lookup.find(in);
703
704  if ( lookup.end() == iter ) {
705    std::string message = in;
706    message += " is not a valid interpolation mode";
707    throw(AipsError(message));
708  }
709  return iter->second;
710}
711
712WeightType STMath::stringToWeight(const std::string& in)
713{
714  static std::map<std::string, WeightType> lookup;
715
716  // initialize the lookup table if necessary
717  if ( lookup.empty() ) {
718    lookup["NONE"]   = asap::NONE;
719    lookup["TINT"] = asap::TINT;
720    lookup["TINTSYS"]  = asap::TINTSYS;
721    lookup["TSYS"]  = asap::TSYS;
722    lookup["VAR"]  = asap::VAR;
723  }
724
725  std::map<std::string, WeightType>::const_iterator iter = lookup.find(in);
726
727  if ( lookup.end() == iter ) {
728    std::string message = in;
729    message += " is not a valid weighting mode";
730    throw(AipsError(message));
731  }
732  return iter->second;
733}
734
735CountedPtr< Scantable > STMath::gainElevation( const CountedPtr< Scantable >& in,
736                                               const vector< float > & coeff,
737                                               const std::string & filename,
738                                               const std::string& method)
739{
740  // Get elevation data from Scantable and convert to degrees
741  CountedPtr< Scantable > out = getScantable(in, false);
742  Table& tab = out->table();
743  ROScalarColumn<Float> elev(tab, "ELEVATION");
744  Vector<Float> x = elev.getColumn();
745  x *= Float(180 / C::pi);                        // Degrees
746
747  Vector<Float> coeffs(coeff);
748  const uInt nc = coeffs.nelements();
749  if ( filename.length() > 0 && nc > 0 ) {
750    throw(AipsError("You must choose either polynomial coefficients or an ascii file, not both"));
751  }
752
753  // Correct
754  if ( nc > 0 || filename.length() == 0 ) {
755    // Find instrument
756    Bool throwit = True;
757    Instrument inst =
758      STAttr::convertInstrument(tab.keywordSet().asString("AntennaName"),
759                                throwit);
760
761    // Set polynomial
762    Polynomial<Float>* ppoly = 0;
763    Vector<Float> coeff;
764    String msg;
765    if ( nc > 0 ) {
766      ppoly = new Polynomial<Float>(nc);
767      coeff = coeffs;
768      msg = String("user");
769    } else {
770      STAttr sdAttr;
771      coeff = sdAttr.gainElevationPoly(inst);
772      ppoly = new Polynomial<Float>(3);
773      msg = String("built in");
774    }
775
776    if ( coeff.nelements() > 0 ) {
777      ppoly->setCoefficients(coeff);
778    } else {
779      delete ppoly;
780      throw(AipsError("There is no known gain-elevation polynomial known for this instrument"));
781    }
782    ostringstream oss;
783    oss << "Making polynomial correction with " << msg << " coefficients:" << endl;
784    oss << "   " <<  coeff;
785    pushLog(String(oss));
786    const uInt nrow = tab.nrow();
787    Vector<Float> factor(nrow);
788    for ( uInt i=0; i < nrow; ++i ) {
789      factor[i] = 1.0 / (*ppoly)(x[i]);
790    }
791    delete ppoly;
792    scaleByVector(tab, factor, true);
793
794  } else {
795    // Read and correct
796    pushLog("Making correction from ascii Table");
797    scaleFromAsciiTable(tab, filename, method, x, true);
798  }
799  return out;
800}
801
802void STMath::scaleFromAsciiTable(Table& in, const std::string& filename,
803                                 const std::string& method,
804                                 const Vector<Float>& xout, bool dotsys)
805{
806
807// Read gain-elevation ascii file data into a Table.
808
809  String formatString;
810  Table tbl = readAsciiTable(formatString, Table::Memory, filename, "", "", False);
811  scaleFromTable(in, tbl, method, xout, dotsys);
812}
813
814void STMath::scaleFromTable(Table& in,
815                            const Table& table,
816                            const std::string& method,
817                            const Vector<Float>& xout, bool dotsys)
818{
819
820  ROScalarColumn<Float> geElCol(table, "ELEVATION");
821  ROScalarColumn<Float> geFacCol(table, "FACTOR");
822  Vector<Float> xin = geElCol.getColumn();
823  Vector<Float> yin = geFacCol.getColumn();
824  Vector<Bool> maskin(xin.nelements(),True);
825
826  // Interpolate (and extrapolate) with desired method
827
828  InterpolateArray1D<Double,Float>::InterpolationMethod interp = stringToIMethod(method);
829
830   Vector<Float> yout;
831   Vector<Bool> maskout;
832   InterpolateArray1D<Float,Float>::interpolate(yout, maskout, xout,
833                                                xin, yin, maskin, interp,
834                                                True, True);
835
836   scaleByVector(in, Float(1.0)/yout, dotsys);
837}
838
839void STMath::scaleByVector( Table& in,
840                            const Vector< Float >& factor,
841                            bool dotsys )
842{
843  uInt nrow = in.nrow();
844  if ( factor.nelements() != nrow ) {
845    throw(AipsError("factors.nelements() != table.nelements()"));
846  }
847  ArrayColumn<Float> specCol(in, "SPECTRA");
848  ArrayColumn<uChar> flagCol(in, "FLAGTRA");
849  ArrayColumn<Float> tsysCol(in, "TSYS");
850  for (uInt i=0; i < nrow; ++i) {
851    MaskedArray<Float> ma  = maskedArray(specCol(i), flagCol(i));
852    ma *= factor[i];
853    specCol.put(i, ma.getArray());
854    flagCol.put(i, flagsFromMA(ma));
855    if ( dotsys ) {
856      Vector<Float> tsys = tsysCol(i);
857      tsys *= factor[i];
858      tsysCol.put(i,tsys);
859    }
860  }
861}
862
863CountedPtr< Scantable > STMath::convertFlux( const CountedPtr< Scantable >& in,
864                                             float d, float etaap,
865                                             float jyperk )
866{
867  CountedPtr< Scantable > out = getScantable(in, false);
868  Table& tab = in->table();
869  Unit fluxUnit(tab.keywordSet().asString("FluxUnit"));
870  Unit K(String("K"));
871  Unit JY(String("Jy"));
872
873  bool tokelvin = true;
874  Double cfac = 1.0;
875
876  if ( fluxUnit == JY ) {
877    pushLog("Converting to K");
878    Quantum<Double> t(1.0,fluxUnit);
879    Quantum<Double> t2 = t.get(JY);
880    cfac = (t2 / t).getValue();               // value to Jy
881
882    tokelvin = true;
883    out->setFluxUnit("K");
884  } else if ( fluxUnit == K ) {
885    pushLog("Converting to Jy");
886    Quantum<Double> t(1.0,fluxUnit);
887    Quantum<Double> t2 = t.get(K);
888    cfac = (t2 / t).getValue();              // value to K
889
890    tokelvin = false;
891    out->setFluxUnit("Jy");
892  } else {
893    throw(AipsError("Unrecognized brightness units in Table - must be consistent with Jy or K"));
894  }
895  // Make sure input values are converted to either Jy or K first...
896  Float factor = cfac;
897
898  // Select method
899  if (jyperk > 0.0) {
900    factor *= jyperk;
901    if ( tokelvin ) factor = 1.0 / jyperk;
902    ostringstream oss;
903    oss << "Jy/K = " << jyperk;
904    pushLog(String(oss));
905    Vector<Float> factors(tab.nrow(), factor);
906    scaleByVector(tab,factors, false);
907  } else if ( etaap > 0.0) {
908    Instrument inst =
909      STAttr::convertInstrument(tab.keywordSet().asString("AntennaName"), True);
910    STAttr sda;
911    if (d < 0) d = sda.diameter(inst);
912    jyperk = STAttr::findJyPerK(etaap, d);
913    ostringstream oss;
914    oss << "Jy/K = " << jyperk;
915    pushLog(String(oss));
916    factor *= jyperk;
917    if ( tokelvin ) {
918      factor = 1.0 / factor;
919    }
920    Vector<Float> factors(tab.nrow(), factor);
921    scaleByVector(tab, factors, False);
922  } else {
923
924    // OK now we must deal with automatic look up of values.
925    // We must also deal with the fact that the factors need
926    // to be computed per IF and may be different and may
927    // change per integration.
928
929    pushLog("Looking up conversion factors");
930    convertBrightnessUnits(out, tokelvin, cfac);
931  }
932
933  return out;
934}
935
936void STMath::convertBrightnessUnits( CountedPtr<Scantable>& in,
937                                     bool tokelvin, float cfac )
938{
939  Table& table = in->table();
940  Instrument inst =
941    STAttr::convertInstrument(table.keywordSet().asString("AntennaName"), True);
942  TableIterator iter(table, "FREQ_ID");
943  STFrequencies stfreqs = in->frequencies();
944  STAttr sdAtt;
945  while (!iter.pastEnd()) {
946    Table tab = iter.table();
947    ArrayColumn<Float> specCol(tab, "SPECTRA");
948    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
949    ROScalarColumn<uInt> freqidCol(tab, "FREQ_ID");
950    MEpoch::ROScalarColumn timeCol(tab, "TIME");
951
952    uInt freqid; freqidCol.get(0, freqid);
953    Vector<Float> tmpspec; specCol.get(0, tmpspec);
954    // STAttr.JyPerK has a Vector interface... change sometime.
955    Vector<Float> freqs(1,stfreqs.getRefFreq(freqid, tmpspec.nelements()));
956    for ( uInt i=0; i<tab.nrow(); ++i) {
957      Float jyperk = (sdAtt.JyPerK(inst, timeCol(i), freqs))[0];
958      Float factor = cfac * jyperk;
959      if ( tokelvin ) factor = Float(1.0) / factor;
960      MaskedArray<Float> ma  = maskedArray(specCol(i), flagCol(i));
961      ma *= factor;
962      specCol.put(i, ma.getArray());
963      flagCol.put(i, flagsFromMA(ma));
964    }
965  ++iter;
966  }
967}
968
969CountedPtr< Scantable > STMath::opacity( const CountedPtr< Scantable > & in,
970                                         float tau )
971{
972  CountedPtr< Scantable > out = getScantable(in, false);
973
974  Table tab = out->table();
975  ROScalarColumn<Float> elev(tab, "ELEVATION");
976  ArrayColumn<Float> specCol(tab, "SPECTRA");
977  ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
978  for ( uInt i=0; i<tab.nrow(); ++i) {
979    Float zdist = Float(C::pi_2) - elev(i);
980    Float factor = exp(tau)/cos(zdist);
981    MaskedArray<Float> ma = maskedArray(specCol(i), flagCol(i));
982    ma *= factor;
983    specCol.put(i, ma.getArray());
984    flagCol.put(i, flagsFromMA(ma));
985  }
986  return out;
987}
988
989CountedPtr< Scantable > STMath::smooth( const CountedPtr< Scantable >& in,
990                                        const std::string& kernel, float width )
991{
992  CountedPtr< Scantable > out = getScantable(in, false);
993  Table& table = out->table();
994  VectorKernel::KernelTypes type = VectorKernel::toKernelType(kernel);
995  // same IFNO should have same no of channels
996  // this saves overhead
997  TableIterator iter(table, "IFNO");
998  while (!iter.pastEnd()) {
999    Table tab = iter.table();
1000    ArrayColumn<Float> specCol(tab, "SPECTRA");
1001    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1002    Vector<Float> tmpspec; specCol.get(0, tmpspec);
1003    uInt nchan = tmpspec.nelements();
1004    Vector<Float> kvec = VectorKernel::make(type, width, nchan, True, False);
1005    Convolver<Float> conv(kvec, IPosition(1,nchan));
1006    Vector<Float> spec;
1007    Vector<uChar> flag;
1008    for ( uInt i=0; i<tab.nrow(); ++i) {
1009      specCol.get(i, spec);
1010      flagCol.get(i, flag);
1011      Vector<Bool> mask(flag.nelements());
1012      convertArray(mask, flag);
1013      Vector<Float> specout;
1014      if ( type == VectorKernel::HANNING ) {
1015        Vector<Bool> maskout;
1016        mathutil::hanning(specout, maskout, spec , !mask);
1017        convertArray(flag, !maskout);
1018        flagCol.put(i, flag);
1019        specCol.put(i, specout);
1020     } else {
1021        mathutil::replaceMaskByZero(specout, mask);
1022        conv.linearConv(specout, spec);
1023        specCol.put(i, specout);
1024      }
1025    }
1026    ++iter;
1027  }
1028  return out;
1029}
1030
1031CountedPtr< Scantable >
1032  STMath::merge( const std::vector< CountedPtr < Scantable > >& in )
1033{
1034  if ( in.size() < 2 ) {
1035    throw(AipsError("Need at least two scantables to perform a merge."));
1036  }
1037  std::vector<CountedPtr < Scantable > >::const_iterator it = in.begin();
1038  bool insitu = insitu_;
1039  setInsitu(false);
1040  CountedPtr< Scantable > out = getScantable(*it, false);
1041  setInsitu(insitu);
1042  Table& tout = out->table();
1043  ScalarColumn<uInt> freqidcol(tout,"FREQ_ID"), molidcol(tout, "MOLECULE_ID");
1044  ScalarColumn<uInt> scannocol(tout,"SCANNO"), focusidcol(tout,"FOCUS_ID");
1045  // Renumber SCANNO to be 0-based
1046  Vector<uInt> scannos = scannocol.getColumn();
1047  uInt offset = min(scannos);
1048  scannos -= offset;
1049  scannocol.putColumn(scannos);
1050  uInt newscanno = max(scannos)+1;
1051  ++it;
1052  while ( it != in.end() ){
1053    if ( ! (*it)->conformant(*out) ) {
1054      // log message: "ignoring scantable i, as it isn't
1055      // conformant with the other(s)"
1056      cerr << "oh oh" << endl;
1057      ++it;
1058      continue;
1059    }
1060    out->appendToHistoryTable((*it)->history());
1061    const Table& tab = (*it)->table();
1062    TableIterator scanit(tab, "SCANNO");
1063    while (!scanit.pastEnd()) {
1064      TableIterator freqit(scanit.table(), "FREQ_ID");
1065      while ( !freqit.pastEnd() ) {
1066        Table thetab = freqit.table();
1067        uInt nrow = tout.nrow();
1068        //tout.addRow(thetab.nrow());
1069        TableCopy::copyRows(tout, thetab, nrow, 0, thetab.nrow());
1070        ROTableRow row(thetab);
1071        for ( uInt i=0; i<thetab.nrow(); ++i) {
1072          uInt k = nrow+i;
1073          scannocol.put(k, newscanno);
1074          const TableRecord& rec = row.get(i);
1075          Double rv,rp,inc;
1076          (*it)->frequencies().getEntry(rp, rv, inc, rec.asuInt("FREQ_ID"));
1077          uInt id;
1078          id = out->frequencies().addEntry(rp, rv, inc);
1079          freqidcol.put(k,id);
1080          String name,fname;Double rf;
1081          (*it)->molecules().getEntry(rf, name, fname, rec.asuInt("MOLECULE_ID"));
1082          id = out->molecules().addEntry(rf, name, fname);
1083          molidcol.put(k, id);
1084          Float frot,fax,ftan,fhand,fmount,fuser, fxy, fxyp;
1085          (*it)->focus().getEntry(fax, ftan, frot, fhand,
1086                                  fmount,fuser, fxy, fxyp,
1087                                  rec.asuInt("FOCUS_ID"));
1088          id = out->focus().addEntry(fax, ftan, frot, fhand,
1089                                     fmount,fuser, fxy, fxyp);
1090          focusidcol.put(k, id);
1091        }
1092        ++freqit;
1093      }
1094      ++newscanno;
1095      ++scanit;
1096    }
1097    ++it;
1098  }
1099  return out;
1100}
1101
1102CountedPtr< Scantable >
1103  STMath::invertPhase( const CountedPtr < Scantable >& in )
1104{
1105  return applyToPol(in, &STPol::invertPhase, Float(0.0));
1106}
1107
1108CountedPtr< Scantable >
1109  STMath::rotateXYPhase( const CountedPtr < Scantable >& in, float phase )
1110{
1111   return applyToPol(in, &STPol::rotatePhase, Float(phase));
1112}
1113
1114CountedPtr< Scantable >
1115  STMath::rotateLinPolPhase( const CountedPtr < Scantable >& in, float phase )
1116{
1117  return applyToPol(in, &STPol::rotateLinPolPhase, Float(phase));
1118}
1119
1120CountedPtr< Scantable > STMath::applyToPol( const CountedPtr<Scantable>& in,
1121                                             STPol::polOperation fptr,
1122                                             Float phase )
1123{
1124  CountedPtr< Scantable > out = getScantable(in, false);
1125  Table& tout = out->table();
1126  Block<String> cols(4);
1127  cols[0] = String("SCANNO");
1128  cols[1] = String("BEAMNO");
1129  cols[2] = String("IFNO");
1130  cols[3] = String("CYCLENO");
1131  TableIterator iter(tout, cols);
1132  STPol* stpol = STPol::getPolClass(out->factories_, out->getPolType() );
1133  while (!iter.pastEnd()) {
1134    Table t = iter.table();
1135    ArrayColumn<Float> speccol(t, "SPECTRA");
1136    ScalarColumn<uInt> focidcol(t, "FOCUS_ID");
1137    ScalarColumn<Float> parancol(t, "PARANGLE");
1138    Matrix<Float> pols = speccol.getColumn();
1139    try {
1140      stpol->setSpectra(pols);
1141      Float fang,fhand,parang;
1142      fang = in->focusTable_.getTotalFeedAngle(focidcol(0));
1143      fhand = in->focusTable_.getFeedHand(focidcol(0));
1144      parang = parancol(0);
1145      /// @todo re-enable this
1146      // disable total feed angle to support paralactifying Caswell style
1147      stpol->setPhaseCorrections(parang, -parang, fhand);
1148      (stpol->*fptr)(phase);
1149      speccol.putColumn(stpol->getSpectra());
1150      Matrix<Float> tmp = stpol->getSpectra();
1151    } catch (AipsError& e) {
1152      delete stpol;stpol=0;
1153      throw(e);
1154    }
1155    ++iter;
1156  }
1157  delete stpol;stpol=0;
1158  return out;
1159}
1160
1161CountedPtr< Scantable >
1162  STMath::swapPolarisations( const CountedPtr< Scantable > & in )
1163{
1164  CountedPtr< Scantable > out = getScantable(in, false);
1165  Table& tout = out->table();
1166  Table t0 = tout(tout.col("POLNO") == 0);
1167  Table t1 = tout(tout.col("POLNO") == 1);
1168  if ( t0.nrow() != t1.nrow() )
1169    throw(AipsError("Inconsistent number of polarisations"));
1170  ArrayColumn<Float> speccol0(t0, "SPECTRA");
1171  ArrayColumn<uChar> flagcol0(t0, "FLAGTRA");
1172  ArrayColumn<Float> speccol1(t1, "SPECTRA");
1173  ArrayColumn<uChar> flagcol1(t1, "FLAGTRA");
1174  Matrix<Float> s0 = speccol0.getColumn();
1175  Matrix<uChar> f0 = flagcol0.getColumn();
1176  speccol0.putColumn(speccol1.getColumn());
1177  flagcol0.putColumn(flagcol1.getColumn());
1178  speccol1.putColumn(s0);
1179  flagcol1.putColumn(f0);
1180  return out;
1181}
1182
1183CountedPtr< Scantable >
1184  STMath::averagePolarisations( const CountedPtr< Scantable > & in,
1185                                const std::vector<bool>& mask,
1186                                const std::string& weight )
1187{
1188  if (in->npol() < 2 )
1189    throw(AipsError("averagePolarisations can only be applied to two or more"
1190                    "polarisations"));
1191  bool insitu = insitu_;
1192  setInsitu(false);
1193  CountedPtr< Scantable > pols = getScantable(in, true);
1194  setInsitu(insitu);
1195  Table& tout = pols->table();
1196  std::string taql = "SELECT FROM $1 WHERE POLNO IN [0,1]";
1197  Table tab = tableCommand(taql, in->table());
1198  if (tab.nrow() == 0 )
1199    throw(AipsError("Could not find  any rows with POLNO==0 and POLNO==1"));
1200  TableCopy::copyRows(tout, tab);
1201  TableVector<uInt> vec(tout, "POLNO");
1202  vec = 0;
1203  pols->table_.rwKeywordSet().define("nPol", Int(1));
1204  pols->table_.rwKeywordSet().define("POLTYPE", String("stokes"));
1205  std::vector<CountedPtr<Scantable> > vpols;
1206  vpols.push_back(pols);
1207  CountedPtr< Scantable > out = average(vpols, mask, weight, "SCAN");
1208  return out;
1209}
1210
1211CountedPtr< Scantable >
1212  STMath::averageBeams( const CountedPtr< Scantable > & in,
1213                        const std::vector<bool>& mask,
1214                        const std::string& weight )
1215{
1216  bool insitu = insitu_;
1217  setInsitu(false);
1218  CountedPtr< Scantable > beams = getScantable(in, false);
1219  setInsitu(insitu);
1220  Table& tout = beams->table();
1221  // give all rows the same BEAMNO
1222  TableVector<uInt> vec(tout, "BEAMNO");
1223  vec = 0;
1224  beams->table_.rwKeywordSet().define("nBeam", Int(1));
1225  std::vector<CountedPtr<Scantable> > vbeams;
1226  vbeams.push_back(beams);
1227  CountedPtr< Scantable > out = average(vbeams, mask, weight, "SCAN");
1228  return out;
1229}
1230
1231
1232CountedPtr< Scantable >
1233  asap::STMath::frequencyAlign( const CountedPtr< Scantable > & in,
1234                                const std::string & refTime,
1235                                const std::string & method)
1236{
1237  // clone as this is not working insitu
1238  bool insitu = insitu_;
1239  setInsitu(false);
1240  CountedPtr< Scantable > out = getScantable(in, false);
1241  setInsitu(insitu);
1242  Table& tout = out->table();
1243  // Get reference Epoch to time of first row or given String
1244  Unit DAY(String("d"));
1245  MEpoch::Ref epochRef(in->getTimeReference());
1246  MEpoch refEpoch;
1247  if (refTime.length()>0) {
1248    Quantum<Double> qt;
1249    if (MVTime::read(qt,refTime)) {
1250      MVEpoch mv(qt);
1251      refEpoch = MEpoch(mv, epochRef);
1252   } else {
1253      throw(AipsError("Invalid format for Epoch string"));
1254   }
1255  } else {
1256    refEpoch = in->timeCol_(0);
1257  }
1258  MPosition refPos = in->getAntennaPosition();
1259
1260  InterpolateArray1D<Double,Float>::InterpolationMethod interp = stringToIMethod(method);
1261  // test if user frame is different to base frame
1262  if ( in->frequencies().getFrameString(true)
1263       == in->frequencies().getFrameString(false) ) {
1264    throw(AipsError("Can't convert as no output frame has been set"
1265                    " (use set_freqframe) or it is aligned already."));
1266  }
1267  MFrequency::Types system = in->frequencies().getFrame();
1268  MVTime mvt(refEpoch.getValue());
1269  String epochout = mvt.string(MVTime::YMD) + String(" (") + refEpoch.getRefString() + String(")");
1270  ostringstream oss;
1271  oss << "Aligned at reference Epoch " << epochout
1272      << " in frame " << MFrequency::showType(system);
1273  pushLog(String(oss));
1274  // set up the iterator
1275  Block<String> cols(4);
1276  // select by constant direction
1277  cols[0] = String("SRCNAME");
1278  cols[1] = String("BEAMNO");
1279  // select by IF ( no of channels varies over this )
1280  cols[2] = String("IFNO");
1281  // select by restfrequency
1282  cols[3] = String("MOLECULE_ID");
1283  TableIterator iter(tout, cols);
1284  while ( !iter.pastEnd() ) {
1285    Table t = iter.table();
1286    MDirection::ROScalarColumn dirCol(t, "DIRECTION");
1287    TableIterator fiter(t, "FREQ_ID");
1288    // determine nchan from the first row. This should work as
1289    // we are iterating over BEAMNO and IFNO    // we should have constant direction
1290
1291    ROArrayColumn<Float> sCol(t, "SPECTRA");
1292    MDirection direction = dirCol(0);
1293    uInt nchan = sCol(0).nelements();
1294    while ( !fiter.pastEnd() ) {
1295      Table ftab = fiter.table();
1296      ScalarColumn<uInt> freqidCol(ftab, "FREQ_ID");
1297      // get the SpectralCoordinate for the freqid, which we are iterating over
1298      SpectralCoordinate sC = in->frequencies().getSpectralCoordinate(freqidCol(0));
1299      FrequencyAligner<Float> fa( sC, nchan, refEpoch,
1300                                  direction, refPos, system );
1301      // realign the SpectralCoordinate and put into the output Scantable
1302      Vector<String> units(1);
1303      units = String("Hz");
1304      Bool linear=True;
1305      SpectralCoordinate sc2 = fa.alignedSpectralCoordinate(linear);
1306      sc2.setWorldAxisUnits(units);
1307      uInt id = out->frequencies().addEntry(sc2.referencePixel()[0],
1308                                            sc2.referenceValue()[0],
1309                                            sc2.increment()[0]);
1310      TableVector<uInt> tvec(ftab, "FREQ_ID");
1311      tvec = id;
1312      // create the "global" abcissa for alignment with same FREQ_ID
1313      Vector<Double> abc(nchan);
1314      Double w;
1315      for (uInt i=0; i<nchan; i++) {
1316        sC.toWorld(w,Double(i));
1317        abc[i] = w;
1318      }
1319      // cache abcissa for same time stamps, so iterate over those
1320      TableIterator timeiter(ftab, "TIME");
1321      while ( !timeiter.pastEnd() ) {
1322        Table tab = timeiter.table();
1323        ArrayColumn<Float> specCol(tab, "SPECTRA");
1324        ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1325        MEpoch::ROScalarColumn timeCol(tab, "TIME");
1326        // use align abcissa cache after the first row
1327        bool first = true;
1328        // these rows should be just be POLNO
1329        for (int i=0; i<int(tab.nrow()); ++i) {
1330          // input values
1331          Vector<uChar> flag = flagCol(i);
1332          Vector<Bool> mask(flag.shape());
1333          Vector<Float> specOut, spec;
1334          spec  = specCol(i);
1335          Vector<Bool> maskOut;Vector<uChar> flagOut;
1336          convertArray(mask, flag);
1337          // alignment
1338          Bool ok = fa.align(specOut, maskOut, abc, spec,
1339                             mask, timeCol(i), !first,
1340                             interp, False);
1341          // back into scantable
1342          flagOut.resize(maskOut.nelements());
1343          convertArray(flagOut, maskOut);
1344          flagCol.put(i, flagOut);
1345          specCol.put(i, specOut);
1346          // start abcissa caching
1347          first = false;
1348        }
1349        // next timestamp
1350        ++timeiter;
1351      }
1352      // next FREQ_ID
1353      ++fiter;
1354    }
1355    // next aligner
1356    ++iter;
1357  }
1358  // set this afterwards to ensure we are doing insitu correctly.
1359  out->frequencies().setFrame(system, true);
1360  return out;
1361}
1362
1363CountedPtr<Scantable>
1364  asap::STMath::convertPolarisation( const CountedPtr<Scantable>& in,
1365                                     const std::string & newtype )
1366{
1367  if (in->npol() != 2 && in->npol() != 4)
1368    throw(AipsError("Can only convert two or four polarisations."));
1369  if ( in->getPolType() == newtype )
1370    throw(AipsError("No need to convert."));
1371  if ( ! in->selector_.empty() )
1372    throw(AipsError("Can only convert whole scantable. Unset the selection."));
1373  bool insitu = insitu_;
1374  setInsitu(false);
1375  CountedPtr< Scantable > out = getScantable(in, true);
1376  setInsitu(insitu);
1377  Table& tout = out->table();
1378  tout.rwKeywordSet().define("POLTYPE", String(newtype));
1379
1380  Block<String> cols(4);
1381  cols[0] = "SCANNO";
1382  cols[1] = "CYCLENO";
1383  cols[2] = "BEAMNO";
1384  cols[3] = "IFNO";
1385  TableIterator it(in->originalTable_, cols);
1386  String basetype = in->getPolType();
1387  STPol* stpol = STPol::getPolClass(in->factories_, basetype);
1388  try {
1389    while ( !it.pastEnd() ) {
1390      Table tab = it.table();
1391      uInt row = tab.rowNumbers()[0];
1392      stpol->setSpectra(in->getPolMatrix(row));
1393      Float fang,fhand,parang;
1394      fang = in->focusTable_.getTotalFeedAngle(in->mfocusidCol_(row));
1395      fhand = in->focusTable_.getFeedHand(in->mfocusidCol_(row));
1396      parang = in->paraCol_(row);
1397      /// @todo re-enable this
1398      // disable total feed angle to support paralactifying Caswell style
1399      stpol->setPhaseCorrections(parang, -parang, fhand);
1400      Int npolout = 0;
1401      for (uInt i=0; i<tab.nrow(); ++i) {
1402        Vector<Float> outvec = stpol->getSpectrum(i, newtype);
1403        if ( outvec.nelements() > 0 ) {
1404          tout.addRow();
1405          TableCopy::copyRows(tout, tab, tout.nrow()-1, 0, 1);
1406          ArrayColumn<Float> sCol(tout,"SPECTRA");
1407          ScalarColumn<uInt> pCol(tout,"POLNO");
1408          sCol.put(tout.nrow()-1 ,outvec);
1409          pCol.put(tout.nrow()-1 ,uInt(npolout));
1410          npolout++;
1411       }
1412      }
1413      tout.rwKeywordSet().define("nPol", npolout);
1414      ++it;
1415    }
1416  } catch (AipsError& e) {
1417    delete stpol;
1418    throw(e);
1419  }
1420  delete stpol;
1421  return out;
1422}
1423
1424CountedPtr< Scantable >
1425  asap::STMath::mxExtract( const CountedPtr< Scantable > & in,
1426                           const std::string & scantype )
1427{
1428  bool insitu = insitu_;
1429  setInsitu(false);
1430  CountedPtr< Scantable > out = getScantable(in, true);
1431  setInsitu(insitu);
1432  Table& tout = out->table();
1433  std::string taql = "SELECT FROM $1 WHERE BEAMNO != REFBEAMNO";
1434  if (scantype == "on") {
1435    taql = "SELECT FROM $1 WHERE BEAMNO == REFBEAMNO";
1436  }
1437  Table tab = tableCommand(taql, in->table());
1438  TableCopy::copyRows(tout, tab);
1439  if (scantype == "on") {
1440    // re-index SCANNO to 0
1441    TableVector<uInt> vec(tout, "SCANNO");
1442    vec = 0;
1443  }
1444  return out;
1445}
1446
1447CountedPtr< Scantable >
1448  asap::STMath::lagFlag( const CountedPtr< Scantable > & in,
1449                          double frequency, double width )
1450{
1451  CountedPtr< Scantable > out = getScantable(in, false);
1452  Table& tout = out->table();
1453  TableIterator iter(tout, "FREQ_ID");
1454  FFTServer<Float,Complex> ffts;
1455  while ( !iter.pastEnd() ) {
1456    Table tab = iter.table();
1457    Double rp,rv,inc;
1458    ROTableRow row(tab);
1459    const TableRecord& rec = row.get(0);
1460    uInt freqid = rec.asuInt("FREQ_ID");
1461    out->frequencies().getEntry(rp, rv, inc, freqid);
1462    ArrayColumn<Float> specCol(tab, "SPECTRA");
1463    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1464    for (int i=0; i<int(tab.nrow()); ++i) {
1465      Vector<Float> spec = specCol(i);
1466      Vector<uChar> flag = flagCol(i);
1467      Int lag0 = Int(spec.nelements()*abs(inc)/(frequency+width)+0.5);
1468      Int lag1 = Int(spec.nelements()*abs(inc)/(frequency-width)+0.5);
1469      for (int k=0; k < flag.nelements(); ++k ) {
1470        if (flag[k] > 0) {
1471          spec[k] = 0.0;
1472        }
1473      }
1474      Vector<Complex> lags;
1475      ffts.fft0(lags, spec);
1476      Int start =  max(0, lag0);
1477      Int end =  min(Int(lags.nelements()-1), lag1);
1478      if (start == end) {
1479        lags[start] = Complex(0.0);
1480      } else {
1481        for (int j=start; j <=end ;++j) {
1482          lags[j] = Complex(0.0);
1483        }
1484      }
1485      ffts.fft0(spec, lags);
1486      specCol.put(i, spec);
1487    }
1488    ++iter;
1489  }
1490  return out;
1491}
Note: See TracBrowser for help on using the repository browser.