source: trunk/src/STMath.cpp@ 866

Last change on this file since 866 was 862, checked in by mar637, 19 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.