source: trunk/src/STMath.cpp @ 862

Last change on this file since 862 was 862, checked in by mar637, 18 years ago

added history append to average and merge

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.6 KB
RevLine 
[805]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//
[38]12
[330]13#include <casa/iomanip.h>
[805]14#include <casa/Exceptions/Error.h>
15#include <casa/Containers/Block.h>
[81]16#include <casa/BasicSL/String.h>
[805]17#include <tables/Tables/TableIter.h>
18#include <tables/Tables/TableCopy.h>
19#include <casa/Arrays/MaskArrLogi.h>
20#include <casa/Arrays/MaskArrMath.h>
21#include <casa/Arrays/ArrayLogical.h>
[81]22#include <casa/Arrays/ArrayMath.h>
[805]23#include <casa/Containers/RecordField.h>
24#include <tables/Tables/TableRow.h>
25#include <tables/Tables/TableVector.h>
26#include <tables/Tables/ExprNode.h>
27#include <tables/Tables/TableRecord.h>
28#include <tables/Tables/ReadAsciiTable.h>
[2]29
[262]30#include <lattices/Lattices/LatticeUtilities.h>
31
[177]32#include <scimath/Mathematics/VectorKernel.h>
33#include <scimath/Mathematics/Convolver.h>
[234]34#include <scimath/Functionals/Polynomial.h>
[177]35
[38]36#include "MathUtils.h"
[805]37#include "RowAccumulator.h"
[354]38#include "SDAttr.h"
[805]39#include "STMath.h"
[2]40
[805]41using namespace casa;
[2]42
[83]43using namespace asap;
[2]44
[805]45STMath::STMath(bool insitu) :
46  insitu_(insitu)
[716]47{
48}
[170]49
50
[805]51STMath::~STMath()
[170]52{
53}
54
[805]55CountedPtr<Scantable>
56STMath::average( const std::vector<CountedPtr<Scantable> >& in,
[858]57                 const std::vector<bool>& mask,
[805]58                 const std::string& weight,
59                 const std::string& avmode,
60                 bool alignfreq)
[262]61{
[805]62  if ( avmode == "SCAN" && in.size() != 1 )
63    throw(AipsError("Can't perform 'SCAN' averaging on multiple tables"));
64  WeightType wtype = stringToWeight(weight);
65  // output
66  // clone as this is non insitu
67  bool insitu = insitu_;
68  setInsitu(false);
69  CountedPtr< Scantable > out = getScantable(in[0], true);
70  setInsitu(insitu);
[862]71  std::vector<CountedPtr<Scantable> >::const_iterator stit = in.begin();
72  ++stit;
73  while ( stit != in.end() ) {
74    out->appendToHistoryTable((*stit)->history());
75    ++stit;
76  }
[294]77
[805]78  Table& tout = out->table();
[701]79
[805]80  /// @todo check if all scantables are conformant
[294]81
[805]82  ArrayColumn<Float> specColOut(tout,"SPECTRA");
83  ArrayColumn<uChar> flagColOut(tout,"FLAGTRA");
84  ArrayColumn<Float> tsysColOut(tout,"TSYS");
85  ScalarColumn<Double> mjdColOut(tout,"TIME");
86  ScalarColumn<Double> intColOut(tout,"INTERVAL");
[262]87
[805]88  // set up the output table rows. These are based on the structure of the
[862]89  // FIRST scantable in the vector
[805]90  const Table& baset = in[0]->table();
[262]91
[805]92  Block<String> cols(3);
93  cols[0] = String("BEAMNO");
94  cols[1] = String("IFNO");
95  cols[2] = String("POLNO");
96  if ( avmode == "SOURCE" ) {
97    cols.resize(4);
98    cols[3] = String("SRCNAME");
[488]99  }
[805]100  if ( avmode == "SCAN"  && in.size() == 1) {
101    cols.resize(4);
102    cols[3] = String("SCANNO");
[2]103  }
[805]104  uInt outrowCount = 0;
105  TableIterator iter(baset, cols);
106  while (!iter.pastEnd()) {
107    Table subt = iter.table();
108    // copy the first row of this selection into the new table
109    tout.addRow();
110    TableCopy::copyRows(tout, subt, outrowCount, 0, 1);
111    ++outrowCount;
112    ++iter;
[144]113  }
[805]114  RowAccumulator acc(wtype);
[858]115  Vector<Bool> cmask(mask);
116  acc.setUserMask(cmask);
[805]117  ROTableRow row(tout);
118  ROArrayColumn<Float> specCol, tsysCol;
119  ROArrayColumn<uChar> flagCol;
120  ROScalarColumn<Double> mjdCol, intCol;
121  ROScalarColumn<Int> scanIDCol;
[144]122
[805]123  for (uInt i=0; i < tout.nrow(); ++i) {
124    for ( int j=0; j < in.size(); ++j ) {
125      const Table& tin = in[j]->table();
126      const TableRecord& rec = row.get(i);
127      ROScalarColumn<Double> tmp(tin, "TIME");
128      Double td;tmp.get(0,td);
129      Table basesubt = tin(tin.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
130                       && tin.col("IFNO") == Int(rec.asuInt("IFNO"))
131                       && tin.col("POLNO") == Int(rec.asuInt("POLNO")) );
132      Table subt;
133      if ( avmode == "SOURCE") {
134        subt = basesubt( basesubt.col("SRCNAME") == rec.asString("SRCNAME") );
135      } else if (avmode == "SCAN") {
136        subt = basesubt( basesubt.col("SCANNO") == Int(rec.asuInt("SCANNO")) );
137      } else {
138        subt = basesubt;
139      }
140      specCol.attach(subt,"SPECTRA");
141      flagCol.attach(subt,"FLAGTRA");
142      tsysCol.attach(subt,"TSYS");
143      intCol.attach(subt,"INTERVAL");
144      mjdCol.attach(subt,"TIME");
145      Vector<Float> spec,tsys;
146      Vector<uChar> flag;
147      Double inter,time;
148      for (uInt k = 0; k < subt.nrow(); ++k ) {
149        flagCol.get(k, flag);
150        Vector<Bool> bflag(flag.shape());
151        convertArray(bflag, flag);
152        if ( allEQ(bflag, True) ) {
153          continue;//don't accumulate
[144]154        }
[805]155        specCol.get(k, spec);
156        tsysCol.get(k, tsys);
157        intCol.get(k, inter);
158        mjdCol.get(k, time);
159        // spectrum has to be added last to enable weighting by the other values
160        acc.add(spec, !bflag, tsys, inter, time);
161      }
162    }
163    //write out
164    specColOut.put(i, acc.getSpectrum());
165    const Vector<Bool>& msk = acc.getMask();
166    Vector<uChar> flg(msk.shape());
167    convertArray(flg, !msk);
168    flagColOut.put(i, flg);
169    tsysColOut.put(i, acc.getTsys());
170    intColOut.put(i, acc.getInterval());
171    mjdColOut.put(i, acc.getTime());
172    acc.reset();
[144]173  }
[805]174  return out;
[2]175}
[9]176
[805]177CountedPtr< Scantable > STMath::getScantable(const CountedPtr< Scantable >& in,
178                                             bool droprows)
[185]179{
[805]180  if (insitu_) return in;
181  else {
182    // clone
183    Scantable* tabp = new Scantable(*in, Bool(droprows));
184    return CountedPtr<Scantable>(tabp);
[234]185  }
[805]186}
[234]187
[805]188CountedPtr< Scantable > STMath::unaryOperate( const CountedPtr< Scantable >& in,
189                                              float val,
190                                              const std::string& mode,
191                                              bool tsys )
192{
193  // modes are "ADD" and "MUL"
194  CountedPtr< Scantable > out = getScantable(in, false);
195  Table& tab = out->table();
196  ArrayColumn<Float> specCol(tab,"SPECTRA");
197  ArrayColumn<Float> tsysCol(tab,"TSYS");
198  for (uInt i=0; i<tab.nrow(); ++i) {
199    Vector<Float> spec;
200    Vector<Float> ts;
201    specCol.get(i, spec);
202    tsysCol.get(i, ts);
203    if (mode == "MUL") {
204      spec *= val;
205      specCol.put(i, spec);
206      if ( tsys ) {
207        ts *= val;
208        tsysCol.put(i, ts);
209      }
210    } else if ( mode == "ADD" ) {
211      spec += val;
212      specCol.put(i, spec);
213      if ( tsys ) {
214        ts += val;
215        tsysCol.put(i, ts);
216      }
217    }
[234]218  }
[805]219  return out;
220}
[234]221
[805]222MaskedArray<Float> STMath::maskedArray( const Vector<Float>& s,
223                                        const Vector<uChar>& f)
224{
225  Vector<Bool> mask;
226  mask.resize(f.shape());
227  convertArray(mask, f);
228  return MaskedArray<Float>(s,!mask);
229}
[248]230
[805]231Vector<uChar> STMath::flagsFromMA(const MaskedArray<Float>& ma)
232{
233  const Vector<Bool>& m = ma.getMask();
234  Vector<uChar> flags(m.shape());
235  convertArray(flags, !m);
236  return flags;
237}
[234]238
[805]239CountedPtr< Scantable > STMath::quotient( const CountedPtr< Scantable >& in,
240                                          const std::string & mode,
241                                          bool preserve )
242{
243  /// @todo make other modes available
244  /// modes should be "nearest", "pair"
245  // make this operation non insitu
246  const Table& tin = in->table();
247  Table ons = tin(tin.col("SRCTYPE") == Int(0));
248  Table offs = tin(tin.col("SRCTYPE") == Int(1));
249  if ( offs.nrow() == 0 )
250    throw(AipsError("No 'off' scans present."));
251  // put all "on" scans into output table
[701]252
[805]253  bool insitu = insitu_;
254  setInsitu(false);
255  CountedPtr< Scantable > out = getScantable(in, true);
256  setInsitu(insitu);
257  Table& tout = out->table();
[248]258
[805]259  TableCopy::copyRows(tout, ons);
260  TableRow row(tout);
261  ROScalarColumn<Double> offtimeCol(offs, "TIME");
[234]262
[805]263  ArrayColumn<Float> outspecCol(tout, "SPECTRA");
264  ROArrayColumn<Float> outtsysCol(tout, "TSYS");
265  ArrayColumn<uChar> outflagCol(tout, "FLAGTRA");
[780]266
[805]267  for (uInt i=0; i < tout.nrow(); ++i) {
268    const TableRecord& rec = row.get(i);
269    Double ontime = rec.asDouble("TIME");
270    ROScalarColumn<Double> offtimeCol(offs, "TIME");
271    Double mindeltat = min(abs(offtimeCol.getColumn() - ontime));
272    Table sel = offs( abs(offs.col("TIME")-ontime) <= mindeltat
273                       && offs.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
274                       && offs.col("IFNO") == Int(rec.asuInt("IFNO"))
275                       && offs.col("POLNO") == Int(rec.asuInt("POLNO")) );
[780]276
[805]277    TableRow offrow(sel);
278    const TableRecord& offrec = offrow.get(0);//should only be one row
279    RORecordFieldPtr< Array<Float> > specoff(offrec, "SPECTRA");
280    RORecordFieldPtr< Array<Float> > tsysoff(offrec, "TSYS");
281    RORecordFieldPtr< Array<uChar> > flagoff(offrec, "FLAGTRA");
282    /// @fixme this assumes tsys is a scalar not vector
283    Float tsysoffscalar = (*tsysoff)(IPosition(1,0));
284    Vector<Float> specon, tsyson;
285    outtsysCol.get(i, tsyson);
286    outspecCol.get(i, specon);
287    Vector<uChar> flagon;
288    outflagCol.get(i, flagon);
289    MaskedArray<Float> mon = maskedArray(specon, flagon);
290    MaskedArray<Float> moff = maskedArray(*specoff, *flagoff);
291    MaskedArray<Float> quot = (tsysoffscalar * mon / moff);
292    if (preserve) {
293      quot -= tsysoffscalar;
294    } else {
295      quot -= tsyson[0];
[701]296    }
[805]297    outspecCol.put(i, quot.getArray());
298    outflagCol.put(i, flagsFromMA(quot));
299  }
300  return out;
301}
[234]302
[805]303CountedPtr< Scantable > STMath::freqSwitch( const CountedPtr< Scantable >& in )
304{
305  // make copy or reference
306  CountedPtr< Scantable > out = getScantable(in, false);
307  Table& tout = out->table();
308  Block<String> cols(3);
309  cols[0] = String("SCANNO");
310  cols[1] = String("BEAMNO");
311  cols[2] = String("POLNO");
312  TableIterator iter(tout, cols);
313  while (!iter.pastEnd()) {
314    Table subt = iter.table();
315    // this should leave us with two rows for the two IFs....if not ignore
316    if (subt.nrow() != 2 ) {
317      continue;
[701]318    }
[805]319    ArrayColumn<Float> specCol(tout, "SPECTRA");
320    ArrayColumn<Float> tsysCol(tout, "TSYS");
321    ArrayColumn<uChar> flagCol(tout, "FLAGTRA");
322    Vector<Float> onspec,offspec, ontsys, offtsys;
323    Vector<uChar> onflag, offflag;
324    tsysCol.get(0, ontsys);   tsysCol.get(1, offtsys);
325    specCol.get(0, onspec);   specCol.get(1, offspec);
326    flagCol.get(0, onflag);   flagCol.get(1, offflag);
327    MaskedArray<Float> on  = maskedArray(onspec, onflag);
328    MaskedArray<Float> off = maskedArray(offspec, offflag);
329    MaskedArray<Float> oncopy = on.copy();
[248]330
[805]331    on /= off; on -= 1.0f;
332    on *= ontsys[0];
333    off /= oncopy; off -= 1.0f;
334    off *= offtsys[0];
335    specCol.put(0, on.getArray());
336    const Vector<Bool>& m0 = on.getMask();
337    Vector<uChar> flags0(m0.shape());
338    convertArray(flags0, !m0);
339    flagCol.put(0, flags0);
[234]340
[805]341    specCol.put(1, off.getArray());
342    const Vector<Bool>& m1 = off.getMask();
343    Vector<uChar> flags1(m1.shape());
344    convertArray(flags1, !m1);
345    flagCol.put(1, flags1);
[234]346
[130]347  }
[780]348
[805]349  return out;
[9]350}
[48]351
[805]352std::vector< float > STMath::statistic( const CountedPtr< Scantable > & in,
353                                        const std::vector< bool > & mask,
354                                        const std::string& which )
[130]355{
356
[805]357  Vector<Bool> m(mask);
358  const Table& tab = in->table();
359  ROArrayColumn<Float> specCol(tab, "SPECTRA");
360  ROArrayColumn<uChar> flagCol(tab, "FLAGTRA");
361  std::vector<float> out;
362  for (uInt i=0; i < tab.nrow(); ++i ) {
363    Vector<Float> spec; specCol.get(i, spec);
364    MaskedArray<Float> ma  = maskedArray(spec, flagCol(i));
365    float outstat;
366    if ( spec.nelements() == m.nelements() ) {
367      outstat = mathutil::statistics(which, ma(m));
368    } else {
369      outstat = mathutil::statistics(which, ma);
370    }
371    out.push_back(outstat);
[234]372  }
[805]373  return out;
[130]374}
375
[805]376CountedPtr< Scantable > STMath::bin( const CountedPtr< Scantable > & in,
377                                     int width )
[144]378{
[841]379  if ( !in->getSelection().empty() ) throw(AipsError("Can't bin subset of the data."));
[805]380  CountedPtr< Scantable > out = getScantable(in, false);
381  Table& tout = out->table();
382  out->frequencies().rescale(width, "BIN");
383  ArrayColumn<Float> specCol(tout, "SPECTRA");
384  ArrayColumn<uChar> flagCol(tout, "FLAGTRA");
385  for (uInt i=0; i < tout.nrow(); ++i ) {
386    MaskedArray<Float> main  = maskedArray(specCol(i), flagCol(i));
387    MaskedArray<Float> maout;
388    LatticeUtilities::bin(maout, main, 0, Int(width));
389    /// @todo implement channel based tsys binning
390    specCol.put(i, maout.getArray());
391    flagCol.put(i, flagsFromMA(maout));
392    // take only the first binned spectrum's length for the deprecated
393    // global header item nChan
394    if (i==0) tout.rwKeywordSet().define(String("nChan"),
395                                       Int(maout.getArray().nelements()));
[169]396  }
[805]397  return out;
[146]398}
399
[805]400CountedPtr< Scantable > STMath::resample( const CountedPtr< Scantable >& in,
401                                          const std::string& method,
402                                          float width )
[299]403//
404// Should add the possibility of width being specified in km/s. This means
[780]405// that for each freqID (SpectralCoordinate) we will need to convert to an
406// average channel width (say at the reference pixel).  Then we would need
407// to be careful to make sure each spectrum (of different freqID)
[299]408// is the same length.
409//
410{
[317]411  InterpolateArray1D<Double,Float>::InterpolationMethod interp;
[805]412  Int interpMethod(stringToIMethod(method));
[299]413
[805]414  CountedPtr< Scantable > out = getScantable(in, false);
415  Table& tout = out->table();
[299]416
417// Resample SpectralCoordinates (one per freqID)
[805]418  out->frequencies().rescale(width, "RESAMPLE");
419  TableIterator iter(tout, "IFNO");
420  TableRow row(tout);
421  while ( !iter.pastEnd() ) {
422    Table tab = iter.table();
423    ArrayColumn<Float> specCol(tab, "SPECTRA");
424    //ArrayColumn<Float> tsysCol(tout, "TSYS");
425    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
426    Vector<Float> spec;
427    Vector<uChar> flag;
428    specCol.get(0,spec); // the number of channels should be constant per IF
429    uInt nChanIn = spec.nelements();
430    Vector<Float> xIn(nChanIn); indgen(xIn);
431    Int fac =  Int(nChanIn/width);
432    Vector<Float> xOut(fac+10); // 10 to be safe - resize later
433    uInt k = 0;
434    Float x = 0.0;
435    while (x < Float(nChanIn) ) {
436      xOut(k) = x;
437      k++;
438      x += width;
439    }
440    uInt nChanOut = k;
441    xOut.resize(nChanOut, True);
442    // process all rows for this IFNO
443    Vector<Float> specOut;
444    Vector<Bool> maskOut;
445    Vector<uChar> flagOut;
446    for (uInt i=0; i < tab.nrow(); ++i) {
447      specCol.get(i, spec);
448      flagCol.get(i, flag);
449      Vector<Bool> mask(flag.nelements());
450      convertArray(mask, flag);
[299]451
[805]452      IPosition shapeIn(spec.shape());
453      //sh.nchan = nChanOut;
454      InterpolateArray1D<Float,Float>::interpolate(specOut, maskOut, xOut,
455                                                   xIn, spec, mask,
456                                                   interpMethod, True, True);
457      /// @todo do the same for channel based Tsys
458      flagOut.resize(maskOut.nelements());
459      convertArray(flagOut, maskOut);
460      specCol.put(i, specOut);
461      flagCol.put(i, flagOut);
462    }
463    ++iter;
[299]464  }
465
[805]466  return out;
467}
[299]468
[805]469STMath::imethod STMath::stringToIMethod(const std::string& in)
470{
471  static STMath::imap lookup;
[299]472
[805]473  // initialize the lookup table if necessary
474  if ( lookup.empty() ) {
475    lookup["NEAR"]   = InterpolateArray1D<Double,Float>::nearestNeighbour;
476    lookup["LIN"] = InterpolateArray1D<Double,Float>::linear;
477    lookup["CUB"]  = InterpolateArray1D<Double,Float>::cubic;
478    lookup["SPL"]  = InterpolateArray1D<Double,Float>::spline;
[299]479  }
480
[805]481  STMath::imap::const_iterator iter = lookup.find(in);
[299]482
[805]483  if ( lookup.end() == iter ) {
484    std::string message = in;
485    message += " is not a valid interpolation mode";
486    throw(AipsError(message));
[299]487  }
[805]488  return iter->second;
[299]489}
490
[805]491WeightType STMath::stringToWeight(const std::string& in)
[146]492{
[805]493  static std::map<std::string, WeightType> lookup;
[434]494
[805]495  // initialize the lookup table if necessary
496  if ( lookup.empty() ) {
497    lookup["NONE"]   = asap::NONE;
498    lookup["TINT"] = asap::TINT;
499    lookup["TINTSYS"]  = asap::TINTSYS;
500    lookup["TSYS"]  = asap::TSYS;
501    lookup["VAR"]  = asap::VAR;
502  }
[434]503
[805]504  std::map<std::string, WeightType>::const_iterator iter = lookup.find(in);
[294]505
[805]506  if ( lookup.end() == iter ) {
507    std::string message = in;
508    message += " is not a valid weighting mode";
509    throw(AipsError(message));
510  }
511  return iter->second;
[146]512}
513
[805]514CountedPtr< Scantable > STMath::gainElevation( const CountedPtr< Scantable >& in,
515                                               const Vector< Float > & coeffs,
516                                               const std::string & filename,
517                                               const std::string& method)
[165]518{
[805]519  // Get elevation data from Scantable and convert to degrees
520  CountedPtr< Scantable > out = getScantable(in, false);
521  Table& tab = in->table();
522  ROScalarColumn<Float> elev(tab, "ELEVATION");
523  Vector<Float> x = elev.getColumn();
524  x *= Float(180 / C::pi);                        // Degrees
[165]525
[805]526  const uInt nc = coeffs.nelements();
527  if ( filename.length() > 0 && nc > 0 ) {
528    throw(AipsError("You must choose either polynomial coefficients or an ascii file, not both"));
[315]529  }
[165]530
[805]531  // Correct
532  if ( nc > 0 || filename.length() == 0 ) {
533    // Find instrument
534    Bool throwit = True;
535    Instrument inst =
536      SDAttr::convertInstrument(tab.keywordSet().asString("AntennaName"),
537                                throwit);
[165]538
[805]539    // Set polynomial
540    Polynomial<Float>* ppoly = 0;
541    Vector<Float> coeff;
542    String msg;
543    if ( nc > 0 ) {
544      ppoly = new Polynomial<Float>(nc);
545      coeff = coeffs;
546      msg = String("user");
547    } else {
548      SDAttr sdAttr;
549      coeff = sdAttr.gainElevationPoly(inst);
550      ppoly = new Polynomial<Float>(3);
551      msg = String("built in");
552    }
[532]553
[805]554    if ( coeff.nelements() > 0 ) {
555      ppoly->setCoefficients(coeff);
556    } else {
557      delete ppoly;
558      throw(AipsError("There is no known gain-elevation polynomial known for this instrument"));
559    }
560    ostringstream oss;
561    oss << "Making polynomial correction with " << msg << " coefficients:" << endl;
562    oss << "   " <<  coeff;
563    pushLog(String(oss));
564    const uInt nrow = tab.nrow();
565    Vector<Float> factor(nrow);
566    for ( uInt i=0; i < nrow; ++i ) {
567      factor[i] = 1.0 / (*ppoly)(x[i]);
568    }
569    delete ppoly;
570    scaleByVector(tab, factor, true);
[532]571
[805]572  } else {
573    // Read and correct
574    pushLog("Making correction from ascii Table");
575    scaleFromAsciiTable(tab, filename, method, x, true);
[532]576  }
[805]577  return out;
578}
[165]579
[805]580void STMath::scaleFromAsciiTable(Table& in, const std::string& filename,
581                                 const std::string& method,
582                                 const Vector<Float>& xout, bool dotsys)
583{
[165]584
[805]585// Read gain-elevation ascii file data into a Table.
[165]586
[805]587  String formatString;
588  Table tbl = readAsciiTable(formatString, Table::Memory, filename, "", "", False);
589  scaleFromTable(in, tbl, method, xout, dotsys);
590}
[165]591
[805]592void STMath::scaleFromTable(Table& in,
593                            const Table& table,
594                            const std::string& method,
595                            const Vector<Float>& xout, bool dotsys)
596{
[780]597
[805]598  ROScalarColumn<Float> geElCol(table, "ELEVATION");
599  ROScalarColumn<Float> geFacCol(table, "FACTOR");
600  Vector<Float> xin = geElCol.getColumn();
601  Vector<Float> yin = geFacCol.getColumn();
602  Vector<Bool> maskin(xin.nelements(),True);
[165]603
[805]604  // Interpolate (and extrapolate) with desired method
[532]605
[805]606   //InterpolateArray1D<Double,Float>::InterpolationMethod method;
607   Int intmethod(stringToIMethod(method));
[165]608
[805]609   Vector<Float> yout;
610   Vector<Bool> maskout;
611   InterpolateArray1D<Float,Float>::interpolate(yout, maskout, xout,
612                                                xin, yin, maskin, intmethod,
613                                                True, True);
[165]614
[805]615   scaleByVector(in, Float(1.0)/yout, dotsys);
[165]616}
[167]617
[805]618void STMath::scaleByVector( Table& in,
619                            const Vector< Float >& factor,
620                            bool dotsys )
[177]621{
[805]622  uInt nrow = in.nrow();
623  if ( factor.nelements() != nrow ) {
624    throw(AipsError("factors.nelements() != table.nelements()"));
625  }
626  ArrayColumn<Float> specCol(in, "SPECTRA");
627  ArrayColumn<uChar> flagCol(in, "FLAGTRA");
628  ArrayColumn<Float> tsysCol(in, "TSYS");
629  for (uInt i=0; i < nrow; ++i) {
630    MaskedArray<Float> ma  = maskedArray(specCol(i), flagCol(i));
631    ma *= factor[i];
632    specCol.put(i, ma.getArray());
633    flagCol.put(i, flagsFromMA(ma));
634    if ( dotsys ) {
635      Vector<Float> tsys;
636      tsysCol.get(i, tsys);
637      tsys *= factor[i];
638      specCol.put(i,tsys);
639    }
640  }
[177]641}
642
[805]643CountedPtr< Scantable > STMath::convertFlux( const CountedPtr< Scantable >& in,
644                                             float d, float etaap,
645                                             float jyperk )
[221]646{
[805]647  CountedPtr< Scantable > out = getScantable(in, false);
648  Table& tab = in->table();
649  Unit fluxUnit(tab.keywordSet().asString("FluxUnit"));
[221]650  Unit K(String("K"));
651  Unit JY(String("Jy"));
[701]652
[805]653  bool tokelvin = true;
654  Double cfac = 1.0;
[716]655
[805]656  if ( fluxUnit == JY ) {
[716]657    pushLog("Converting to K");
[701]658    Quantum<Double> t(1.0,fluxUnit);
659    Quantum<Double> t2 = t.get(JY);
[805]660    cfac = (t2 / t).getValue();               // value to Jy
[780]661
[805]662    tokelvin = true;
663    out->setFluxUnit("K");
664  } else if ( fluxUnit == K ) {
[716]665    pushLog("Converting to Jy");
[701]666    Quantum<Double> t(1.0,fluxUnit);
667    Quantum<Double> t2 = t.get(K);
[805]668    cfac = (t2 / t).getValue();              // value to K
[780]669
[805]670    tokelvin = false;
671    out->setFluxUnit("Jy");
[221]672  } else {
[701]673    throw(AipsError("Unrecognized brightness units in Table - must be consistent with Jy or K"));
[221]674  }
[701]675  // Make sure input values are converted to either Jy or K first...
[805]676  Float factor = cfac;
[221]677
[701]678  // Select method
[805]679  if (jyperk > 0.0) {
680    factor *= jyperk;
681    if ( tokelvin ) factor = 1.0 / jyperk;
[716]682    ostringstream oss;
[805]683    oss << "Jy/K = " << jyperk;
[716]684    pushLog(String(oss));
[805]685    Vector<Float> factors(tab.nrow(), factor);
686    scaleByVector(tab,factors, false);
687  } else if ( etaap > 0.0) {
688    Instrument inst =
689      SDAttr::convertInstrument(tab.keywordSet().asString("AntennaName"), True);
[701]690    SDAttr sda;
[805]691    if (d < 0) d = sda.diameter(inst);
692    Float jyPerk = SDAttr::findJyPerK(etaap, d);
[716]693    ostringstream oss;
[805]694    oss << "Jy/K = " << jyperk;
[716]695    pushLog(String(oss));
[805]696    factor *= jyperk;
697    if ( tokelvin ) {
[701]698      factor = 1.0 / factor;
699    }
[805]700    Vector<Float> factors(tab.nrow(), factor);
701    scaleByVector(tab, factors, False);
[354]702  } else {
[780]703
[701]704    // OK now we must deal with automatic look up of values.
705    // We must also deal with the fact that the factors need
706    // to be computed per IF and may be different and may
707    // change per integration.
[780]708
[716]709    pushLog("Looking up conversion factors");
[805]710    convertBrightnessUnits(out, tokelvin, cfac);
[701]711  }
[805]712
713  return out;
[221]714}
715
[805]716void STMath::convertBrightnessUnits( CountedPtr<Scantable>& in,
717                                     bool tokelvin, float cfac )
[227]718{
[805]719  Table& table = in->table();
720  Instrument inst =
721    SDAttr::convertInstrument(table.keywordSet().asString("AntennaName"), True);
722  TableIterator iter(table, "FREQ_ID");
723  STFrequencies stfreqs = in->frequencies();
724  SDAttr sdAtt;
725  while (!iter.pastEnd()) {
726    Table tab = iter.table();
727    ArrayColumn<Float> specCol(tab, "SPECTRA");
728    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
729    ROScalarColumn<uInt> freqidCol(tab, "FREQ_ID");
730    MEpoch::ROScalarColumn timeCol(tab, "TIME");
[234]731
[805]732    uInt freqid; freqidCol.get(0, freqid);
733    Vector<Float> tmpspec; specCol.get(0, tmpspec);
734    // SDAttr.JyPerK has a Vector interface... change sometime.
735    Vector<Float> freqs(1,stfreqs.getRefFreq(freqid, tmpspec.nelements()));
736    for ( uInt i=0; i<tab.nrow(); ++i) {
737      Float jyperk = (sdAtt.JyPerK(inst, timeCol(i), freqs))[0];
738      Float factor = cfac * jyperk;
739      if ( tokelvin ) factor = Float(1.0) / factor;
740      MaskedArray<Float> ma  = maskedArray(specCol(i), flagCol(i));
741      ma *= factor;
742      specCol.put(i, ma.getArray());
743      flagCol.put(i, flagsFromMA(ma));
744    }
[234]745  }
[230]746}
[227]747
[805]748CountedPtr< Scantable > STMath::opacity( const CountedPtr< Scantable > & in,
749                                         float tau )
[234]750{
[805]751  CountedPtr< Scantable > out = getScantable(in, false);
752  Table& tab = in->table();
[234]753  ROScalarColumn<Float> elev(tab, "ELEVATION");
[805]754  ArrayColumn<Float> specCol(tab, "SPECTRA");
755  ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
756  for ( uInt i=0; i<tab.nrow(); ++i) {
757    Float zdist = Float(C::pi_2) - elev(i);
758    Float factor = exp(tau)/cos(zdist);
759    MaskedArray<Float> ma  = maskedArray(specCol(i), flagCol(i));
760    ma *= factor;
761    specCol.put(i, ma.getArray());
762    flagCol.put(i, flagsFromMA(ma));
[234]763  }
[805]764  return out;
[234]765}
766
[805]767CountedPtr< Scantable > STMath::smooth( const CountedPtr< Scantable >& in,
768                                        const std::string& kernel, float width )
[457]769{
[805]770  CountedPtr< Scantable > out = getScantable(in, false);
771  Table& table = in->table();
772  VectorKernel::KernelTypes type = VectorKernel::toKernelType(kernel);
773  // same IFNO should have same no of channels
774  // this saves overhead
775  TableIterator iter(table, "IFNO");
776  while (!iter.pastEnd()) {
777    Table tab = iter.table();
778    ArrayColumn<Float> specCol(tab, "SPECTRA");
779    ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
780    Vector<Float> tmpspec; specCol.get(0, tmpspec);
781    uInt nchan = tmpspec.nelements();
782    Vector<Float> kvec = VectorKernel::make(type, width, nchan, True, False);
783    Convolver<Float> conv(kvec, IPosition(1,nchan));
784    Vector<Float> spec;
785    Vector<uChar> flag;
786    for ( uInt i=0; i<tab.nrow(); ++i) {
787      specCol.get(i, spec);
788      flagCol.get(i, flag);
789      Vector<Bool> mask(flag.nelements());
790      convertArray(mask, flag);
791      Vector<Float> specout;
792      if ( type == VectorKernel::HANNING ) {
793        Vector<Bool> maskout;
794        mathutil::hanning(specout, maskout, spec , mask);
795        convertArray(flag, maskout);
796        flagCol.put(i, flag);
797      } else {
798        mathutil::replaceMaskByZero(specout, mask);
799        conv.linearConv(specout, spec);
[354]800      }
[805]801      specCol.put(i, specout);
802    }
[701]803  }
[805]804  return out;
[701]805}
[841]806
807CountedPtr< Scantable >
808  STMath::merge( const std::vector< CountedPtr < Scantable > >& in )
809{
810  if ( in.size() < 2 ) {
[862]811    throw(AipsError("Need at least two scantables to perform a merge."));
[841]812  }
813  std::vector<CountedPtr < Scantable > >::const_iterator it = in.begin();
814  bool insitu = insitu_;
815  setInsitu(false);
[862]816  CountedPtr< Scantable > out = getScantable(*it, false);
[841]817  setInsitu(insitu);
818  Table& tout = out->table();
819  ScalarColumn<uInt> freqidcol(tout,"FREQ_ID"), molidcol(tout, "MOLECULE_ID");
820  ScalarColumn<uInt> scannocol(tout,"SCANNO"),focusidcol(tout,"FOCUS_ID");
821  uInt newscanno = max(scannocol.getColumn())+1;
[862]822  ++it;
[841]823  while ( it != in.end() ){
824    if ( ! (*it)->conformant(*out) ) {
825      // log message: "ignoring scantable i, as it isn't
826      // conformant with the other(s)"
827      cerr << "oh oh" << endl;
828      ++it;
829      continue;
830    }
[862]831    out->appendToHistoryTable((*it)->history());
[841]832    const Table& tab = (*it)->table();
833    TableIterator scanit(tab, "SCANNO");
834    while (!scanit.pastEnd()) {
835      TableIterator freqit(scanit.table(), "FREQ_ID");
836      while ( !freqit.pastEnd() ) {
837        Table thetab = freqit.table();
838        uInt nrow = tout.nrow();
839        //tout.addRow(thetab.nrow());
840        TableCopy::copyRows(tout, thetab, nrow, 0, thetab.nrow());
841        ROTableRow row(thetab);
842        for ( uInt i=0; i<thetab.nrow(); ++i) {
843          uInt k = nrow+i;
844          scannocol.put(k, newscanno);
845          const TableRecord& rec = row.get(i);
846          Double rv,rp,inc;
847          (*it)->frequencies().getEntry(rp, rv, inc, rec.asuInt("FREQ_ID"));
848          uInt id;
849          id = out->frequencies().addEntry(rp, rv, inc);
850          freqidcol.put(k,id);
851          String name,fname;Double rf;
852          (*it)->molecules().getEntry(rf, name, fname, rec.asuInt("MOLECULE_ID"));
853          id = out->molecules().addEntry(rf, name, fname);
854          molidcol.put(k, id);
855          Float frot,fang,ftan;
856          (*it)->focus().getEntry(frot, fang, ftan, rec.asuInt("FOCUS_ID"));
857          id = out->focus().addEntry(frot, fang, ftan);
858          focusidcol.put(k, id);
859        }
860        ++freqit;
861      }
862      ++newscanno;
863      ++scanit;
864    }
865    ++it;
866  }
867  return out;
868}
Note: See TracBrowser for help on using the repository browser.