source: trunk/src/STMath.cpp@ 977

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

Removed align option from average as it is buggy. The user has to provide a vector of aligned scantables.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.7 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 <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>
22#include <casa/Arrays/ArrayMath.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/ReadAsciiTable.h>
30
31#include <lattices/Lattices/LatticeUtilities.h>
32
33#include <coordinates/Coordinates/SpectralCoordinate.h>
34#include <coordinates/Coordinates/CoordinateSystem.h>
35#include <coordinates/Coordinates/CoordinateUtil.h>
36#include <coordinates/Coordinates/FrequencyAligner.h>
37
38#include <scimath/Mathematics/VectorKernel.h>
39#include <scimath/Mathematics/Convolver.h>
40#include <scimath/Functionals/Polynomial.h>
41
42#include "MathUtils.h"
43#include "RowAccumulator.h"
44#include "STAttr.h"
45#include "STMath.h"
46
47using namespace casa;
48
49using namespace asap;
50
51STMath::STMath(bool insitu) :
52 insitu_(insitu)
53{
54}
55
56
57STMath::~STMath()
58{
59}
60
61CountedPtr<Scantable>
62STMath::average( const std::vector<CountedPtr<Scantable> >& in,
63 const std::vector<bool>& mask,
64 const std::string& weight,
65 const std::string& avmode)
66{
67 if ( avmode == "SCAN" && in.size() != 1 )
68 throw(AipsError("Can't perform 'SCAN' averaging on multiple tables"));
69 WeightType wtype = stringToWeight(weight);
70
71 // output
72 // clone as this is non insitu
73 bool insitu = insitu_;
74 setInsitu(false);
75 CountedPtr< Scantable > out = getScantable(in[0], true);
76 setInsitu(insitu);
77 std::vector<CountedPtr<Scantable> >::const_iterator stit = in.begin();
78 ++stit;
79 while ( stit != in.end() ) {
80 out->appendToHistoryTable((*stit)->history());
81 ++stit;
82 }
83
84 Table& tout = out->table();
85
86 /// @todo check if all scantables are conformant
87
88 ArrayColumn<Float> specColOut(tout,"SPECTRA");
89 ArrayColumn<uChar> flagColOut(tout,"FLAGTRA");
90 ArrayColumn<Float> tsysColOut(tout,"TSYS");
91 ScalarColumn<Double> mjdColOut(tout,"TIME");
92 ScalarColumn<Double> intColOut(tout,"INTERVAL");
93
94 // set up the output table rows. These are based on the structure of the
95 // FIRST scantable in the vector
96 const Table& baset = in[0]->table();
97
98 Block<String> cols(3);
99 cols[0] = String("BEAMNO");
100 cols[1] = String("IFNO");
101 cols[2] = String("POLNO");
102 if ( avmode == "SOURCE" ) {
103 cols.resize(4);
104 cols[3] = String("SRCNAME");
105 }
106 if ( avmode == "SCAN" && in.size() == 1) {
107 cols.resize(4);
108 cols[3] = String("SCANNO");
109 }
110 uInt outrowCount = 0;
111 TableIterator iter(baset, cols);
112 while (!iter.pastEnd()) {
113 Table subt = iter.table();
114 // copy the first row of this selection into the new table
115 tout.addRow();
116 TableCopy::copyRows(tout, subt, outrowCount, 0, 1);
117 ++outrowCount;
118 ++iter;
119 }
120 RowAccumulator acc(wtype);
121 Vector<Bool> cmask(mask);
122 acc.setUserMask(cmask);
123 ROTableRow row(tout);
124 ROArrayColumn<Float> specCol, tsysCol;
125 ROArrayColumn<uChar> flagCol;
126 ROScalarColumn<Double> mjdCol, intCol;
127 ROScalarColumn<Int> scanIDCol;
128
129 for (uInt i=0; i < tout.nrow(); ++i) {
130 for ( int j=0; j < in.size(); ++j ) {
131 const Table& tin = in[j]->table();
132 const TableRecord& rec = row.get(i);
133 ROScalarColumn<Double> tmp(tin, "TIME");
134 Double td;tmp.get(0,td);
135 Table basesubt = tin(tin.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
136 && tin.col("IFNO") == Int(rec.asuInt("IFNO"))
137 && tin.col("POLNO") == Int(rec.asuInt("POLNO")) );
138 Table subt;
139 if ( avmode == "SOURCE") {
140 subt = basesubt( basesubt.col("SRCNAME") == rec.asString("SRCNAME") );
141 } else if (avmode == "SCAN") {
142 subt = basesubt( basesubt.col("SCANNO") == Int(rec.asuInt("SCANNO")) );
143 } else {
144 subt = basesubt;
145 }
146 specCol.attach(subt,"SPECTRA");
147 flagCol.attach(subt,"FLAGTRA");
148 tsysCol.attach(subt,"TSYS");
149 intCol.attach(subt,"INTERVAL");
150 mjdCol.attach(subt,"TIME");
151 Vector<Float> spec,tsys;
152 Vector<uChar> flag;
153 Double inter,time;
154 for (uInt k = 0; k < subt.nrow(); ++k ) {
155 flagCol.get(k, flag);
156 Vector<Bool> bflag(flag.shape());
157 convertArray(bflag, flag);
158 if ( allEQ(bflag, True) ) {
159 continue;//don't accumulate
160 }
161 specCol.get(k, spec);
162 tsysCol.get(k, tsys);
163 intCol.get(k, inter);
164 mjdCol.get(k, time);
165 // spectrum has to be added last to enable weighting by the other values
166 acc.add(spec, !bflag, tsys, inter, time);
167 }
168 }
169 //write out
170 specColOut.put(i, acc.getSpectrum());
171 const Vector<Bool>& msk = acc.getMask();
172 Vector<uChar> flg(msk.shape());
173 convertArray(flg, !msk);
174 flagColOut.put(i, flg);
175 tsysColOut.put(i, acc.getTsys());
176 intColOut.put(i, acc.getInterval());
177 mjdColOut.put(i, acc.getTime());
178 acc.reset();
179 }
180 return out;
181}
182
183CountedPtr< Scantable > STMath::getScantable(const CountedPtr< Scantable >& in,
184 bool droprows)
185{
186 if (insitu_) return in;
187 else {
188 // clone
189 Scantable* tabp = new Scantable(*in, Bool(droprows));
190 return CountedPtr<Scantable>(tabp);
191 }
192}
193
194CountedPtr< Scantable > STMath::unaryOperate( const CountedPtr< Scantable >& in,
195 float val,
196 const std::string& mode,
197 bool tsys )
198{
199 // modes are "ADD" and "MUL"
200 CountedPtr< Scantable > out = getScantable(in, false);
201 Table& tab = out->table();
202 ArrayColumn<Float> specCol(tab,"SPECTRA");
203 ArrayColumn<Float> tsysCol(tab,"TSYS");
204 for (uInt i=0; i<tab.nrow(); ++i) {
205 Vector<Float> spec;
206 Vector<Float> ts;
207 specCol.get(i, spec);
208 tsysCol.get(i, ts);
209 if (mode == "MUL") {
210 spec *= val;
211 specCol.put(i, spec);
212 if ( tsys ) {
213 ts *= val;
214 tsysCol.put(i, ts);
215 }
216 } else if ( mode == "ADD" ) {
217 spec += val;
218 specCol.put(i, spec);
219 if ( tsys ) {
220 ts += val;
221 tsysCol.put(i, ts);
222 }
223 }
224 }
225 return out;
226}
227
228MaskedArray<Float> STMath::maskedArray( const Vector<Float>& s,
229 const Vector<uChar>& f)
230{
231 Vector<Bool> mask;
232 mask.resize(f.shape());
233 convertArray(mask, f);
234 return MaskedArray<Float>(s,!mask);
235}
236
237Vector<uChar> STMath::flagsFromMA(const MaskedArray<Float>& ma)
238{
239 const Vector<Bool>& m = ma.getMask();
240 Vector<uChar> flags(m.shape());
241 convertArray(flags, !m);
242 return flags;
243}
244
245CountedPtr< Scantable > STMath::quotient( const CountedPtr< Scantable >& in,
246 const std::string & mode,
247 bool preserve )
248{
249 /// @todo make other modes available
250 /// modes should be "nearest", "pair"
251 // make this operation non insitu
252 const Table& tin = in->table();
253 Table ons = tin(tin.col("SRCTYPE") == Int(0));
254 Table offs = tin(tin.col("SRCTYPE") == Int(1));
255 if ( offs.nrow() == 0 )
256 throw(AipsError("No 'off' scans present."));
257 // put all "on" scans into output table
258
259 bool insitu = insitu_;
260 setInsitu(false);
261 CountedPtr< Scantable > out = getScantable(in, true);
262 setInsitu(insitu);
263 Table& tout = out->table();
264
265 TableCopy::copyRows(tout, ons);
266 TableRow row(tout);
267 ROScalarColumn<Double> offtimeCol(offs, "TIME");
268
269 ArrayColumn<Float> outspecCol(tout, "SPECTRA");
270 ROArrayColumn<Float> outtsysCol(tout, "TSYS");
271 ArrayColumn<uChar> outflagCol(tout, "FLAGTRA");
272 for (uInt i=0; i < tout.nrow(); ++i) {
273 const TableRecord& rec = row.get(i);
274 Double ontime = rec.asDouble("TIME");
275 ROScalarColumn<Double> offtimeCol(offs, "TIME");
276 Double mindeltat = min(abs(offtimeCol.getColumn() - ontime));
277 Table sel = offs( abs(offs.col("TIME")-ontime) <= mindeltat
278 && offs.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
279 && offs.col("IFNO") == Int(rec.asuInt("IFNO"))
280 && offs.col("POLNO") == Int(rec.asuInt("POLNO")) );
281
282 TableRow offrow(sel);
283 const TableRecord& offrec = offrow.get(0);//should only be one row
284 RORecordFieldPtr< Array<Float> > specoff(offrec, "SPECTRA");
285 RORecordFieldPtr< Array<Float> > tsysoff(offrec, "TSYS");
286 RORecordFieldPtr< Array<uChar> > flagoff(offrec, "FLAGTRA");
287 /// @fixme this assumes tsys is a scalar not vector
288 Float tsysoffscalar = (*tsysoff)(IPosition(1,0));
289 Vector<Float> specon, tsyson;
290 outtsysCol.get(i, tsyson);
291 outspecCol.get(i, specon);
292 Vector<uChar> flagon;
293 outflagCol.get(i, flagon);
294 MaskedArray<Float> mon = maskedArray(specon, flagon);
295 MaskedArray<Float> moff = maskedArray(*specoff, *flagoff);
296 MaskedArray<Float> quot = (tsysoffscalar * mon / moff);
297 if (preserve) {
298 quot -= tsysoffscalar;
299 } else {
300 quot -= tsyson[0];
301 }
302 outspecCol.put(i, quot.getArray());
303 outflagCol.put(i, flagsFromMA(quot));
304 }
305 // renumber scanno
306 TableIterator it(tout, "SCANNO");
307 uInt i = 0;
308 while ( !it.pastEnd() ) {
309 Table t = it.table();
310 TableVector<uInt> vec(t, "SCANNO");
311 vec = i;
312 ++i;
313 ++it;
314 }
315 return out;
316}
317
318CountedPtr< Scantable > STMath::freqSwitch( const CountedPtr< Scantable >& in )
319{
320 // make copy or reference
321 CountedPtr< Scantable > out = getScantable(in, false);
322 Table& tout = out->table();
323 Block<String> cols(3);
324 cols[0] = String("SCANNO");
325 cols[1] = String("BEAMNO");
326 cols[2] = String("POLNO");
327 TableIterator iter(tout, cols);
328 while (!iter.pastEnd()) {
329 Table subt = iter.table();
330 // this should leave us with two rows for the two IFs....if not ignore
331 if (subt.nrow() != 2 ) {
332 continue;
333 }
334 ArrayColumn<Float> specCol(tout, "SPECTRA");
335 ArrayColumn<Float> tsysCol(tout, "TSYS");
336 ArrayColumn<uChar> flagCol(tout, "FLAGTRA");
337 Vector<Float> onspec,offspec, ontsys, offtsys;
338 Vector<uChar> onflag, offflag;
339 tsysCol.get(0, ontsys); tsysCol.get(1, offtsys);
340 specCol.get(0, onspec); specCol.get(1, offspec);
341 flagCol.get(0, onflag); flagCol.get(1, offflag);
342 MaskedArray<Float> on = maskedArray(onspec, onflag);
343 MaskedArray<Float> off = maskedArray(offspec, offflag);
344 MaskedArray<Float> oncopy = on.copy();
345
346 on /= off; on -= 1.0f;
347 on *= ontsys[0];
348 off /= oncopy; off -= 1.0f;
349 off *= offtsys[0];
350 specCol.put(0, on.getArray());
351 const Vector<Bool>& m0 = on.getMask();
352 Vector<uChar> flags0(m0.shape());
353 convertArray(flags0, !m0);
354 flagCol.put(0, flags0);
355
356 specCol.put(1, off.getArray());
357 const Vector<Bool>& m1 = off.getMask();
358 Vector<uChar> flags1(m1.shape());
359 convertArray(flags1, !m1);
360 flagCol.put(1, flags1);
361 ++iter;
362 }
363
364 return out;
365}
366
367std::vector< float > STMath::statistic( const CountedPtr< Scantable > & in,
368 const std::vector< bool > & mask,
369 const std::string& which )
370{
371
372 Vector<Bool> m(mask);
373 const Table& tab = in->table();
374 ROArrayColumn<Float> specCol(tab, "SPECTRA");
375 ROArrayColumn<uChar> flagCol(tab, "FLAGTRA");
376 std::vector<float> out;
377 for (uInt i=0; i < tab.nrow(); ++i ) {
378 Vector<Float> spec; specCol.get(i, spec);
379 Vector<uChar> flag; flagCol.get(i, flag);
380 MaskedArray<Float> ma = maskedArray(spec, flag);
381 float outstat = 0.0;
382 if ( spec.nelements() == m.nelements() ) {
383 outstat = mathutil::statistics(which, ma(m));
384 } else {
385 outstat = mathutil::statistics(which, ma);
386 }
387 out.push_back(outstat);
388 }
389 return out;
390}
391
392CountedPtr< Scantable > STMath::bin( const CountedPtr< Scantable > & in,
393 int width )
394{
395 if ( !in->getSelection().empty() ) throw(AipsError("Can't bin subset of the data."));
396 CountedPtr< Scantable > out = getScantable(in, false);
397 Table& tout = out->table();
398 out->frequencies().rescale(width, "BIN");
399 ArrayColumn<Float> specCol(tout, "SPECTRA");
400 ArrayColumn<uChar> flagCol(tout, "FLAGTRA");
401 for (uInt i=0; i < tout.nrow(); ++i ) {
402 MaskedArray<Float> main = maskedArray(specCol(i), flagCol(i));
403 MaskedArray<Float> maout;
404 LatticeUtilities::bin(maout, main, 0, Int(width));
405 /// @todo implement channel based tsys binning
406 specCol.put(i, maout.getArray());
407 flagCol.put(i, flagsFromMA(maout));
408 // take only the first binned spectrum's length for the deprecated
409 // global header item nChan
410 if (i==0) tout.rwKeywordSet().define(String("nChan"),
411 Int(maout.getArray().nelements()));
412 }
413 return out;
414}
415
416CountedPtr< Scantable > STMath::resample( const CountedPtr< Scantable >& in,
417 const std::string& method,
418 float width )
419//
420// Should add the possibility of width being specified in km/s. This means
421// that for each freqID (SpectralCoordinate) we will need to convert to an
422// average channel width (say at the reference pixel). Then we would need
423// to be careful to make sure each spectrum (of different freqID)
424// is the same length.
425//
426{
427 InterpolateArray1D<Double,Float>::InterpolationMethod interp;
428 Int interpMethod(stringToIMethod(method));
429
430 CountedPtr< Scantable > out = getScantable(in, false);
431 Table& tout = out->table();
432
433// Resample SpectralCoordinates (one per freqID)
434 out->frequencies().rescale(width, "RESAMPLE");
435 TableIterator iter(tout, "IFNO");
436 TableRow row(tout);
437 while ( !iter.pastEnd() ) {
438 Table tab = iter.table();
439 ArrayColumn<Float> specCol(tab, "SPECTRA");
440 //ArrayColumn<Float> tsysCol(tout, "TSYS");
441 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
442 Vector<Float> spec;
443 Vector<uChar> flag;
444 specCol.get(0,spec); // the number of channels should be constant per IF
445 uInt nChanIn = spec.nelements();
446 Vector<Float> xIn(nChanIn); indgen(xIn);
447 Int fac = Int(nChanIn/width);
448 Vector<Float> xOut(fac+10); // 10 to be safe - resize later
449 uInt k = 0;
450 Float x = 0.0;
451 while (x < Float(nChanIn) ) {
452 xOut(k) = x;
453 k++;
454 x += width;
455 }
456 uInt nChanOut = k;
457 xOut.resize(nChanOut, True);
458 // process all rows for this IFNO
459 Vector<Float> specOut;
460 Vector<Bool> maskOut;
461 Vector<uChar> flagOut;
462 for (uInt i=0; i < tab.nrow(); ++i) {
463 specCol.get(i, spec);
464 flagCol.get(i, flag);
465 Vector<Bool> mask(flag.nelements());
466 convertArray(mask, flag);
467
468 IPosition shapeIn(spec.shape());
469 //sh.nchan = nChanOut;
470 InterpolateArray1D<Float,Float>::interpolate(specOut, maskOut, xOut,
471 xIn, spec, mask,
472 interpMethod, True, True);
473 /// @todo do the same for channel based Tsys
474 flagOut.resize(maskOut.nelements());
475 convertArray(flagOut, maskOut);
476 specCol.put(i, specOut);
477 flagCol.put(i, flagOut);
478 }
479 ++iter;
480 }
481
482 return out;
483}
484
485STMath::imethod STMath::stringToIMethod(const std::string& in)
486{
487 static STMath::imap lookup;
488
489 // initialize the lookup table if necessary
490 if ( lookup.empty() ) {
491 lookup["nearest"] = InterpolateArray1D<Double,Float>::nearestNeighbour;
492 lookup["linear"] = InterpolateArray1D<Double,Float>::linear;
493 lookup["cubic"] = InterpolateArray1D<Double,Float>::cubic;
494 lookup["spline"] = InterpolateArray1D<Double,Float>::spline;
495 }
496
497 STMath::imap::const_iterator iter = lookup.find(in);
498
499 if ( lookup.end() == iter ) {
500 std::string message = in;
501 message += " is not a valid interpolation mode";
502 throw(AipsError(message));
503 }
504 return iter->second;
505}
506
507WeightType STMath::stringToWeight(const std::string& in)
508{
509 static std::map<std::string, WeightType> lookup;
510
511 // initialize the lookup table if necessary
512 if ( lookup.empty() ) {
513 lookup["NONE"] = asap::NONE;
514 lookup["TINT"] = asap::TINT;
515 lookup["TINTSYS"] = asap::TINTSYS;
516 lookup["TSYS"] = asap::TSYS;
517 lookup["VAR"] = asap::VAR;
518 }
519
520 std::map<std::string, WeightType>::const_iterator iter = lookup.find(in);
521
522 if ( lookup.end() == iter ) {
523 std::string message = in;
524 message += " is not a valid weighting mode";
525 throw(AipsError(message));
526 }
527 return iter->second;
528}
529
530CountedPtr< Scantable > STMath::gainElevation( const CountedPtr< Scantable >& in,
531 const vector< float > & coeff,
532 const std::string & filename,
533 const std::string& method)
534{
535 // Get elevation data from Scantable and convert to degrees
536 CountedPtr< Scantable > out = getScantable(in, false);
537 Table& tab = out->table();
538 ROScalarColumn<Float> elev(tab, "ELEVATION");
539 Vector<Float> x = elev.getColumn();
540 x *= Float(180 / C::pi); // Degrees
541
542 Vector<Float> coeffs(coeff);
543 const uInt nc = coeffs.nelements();
544 if ( filename.length() > 0 && nc > 0 ) {
545 throw(AipsError("You must choose either polynomial coefficients or an ascii file, not both"));
546 }
547
548 // Correct
549 if ( nc > 0 || filename.length() == 0 ) {
550 // Find instrument
551 Bool throwit = True;
552 Instrument inst =
553 STAttr::convertInstrument(tab.keywordSet().asString("AntennaName"),
554 throwit);
555
556 // Set polynomial
557 Polynomial<Float>* ppoly = 0;
558 Vector<Float> coeff;
559 String msg;
560 if ( nc > 0 ) {
561 ppoly = new Polynomial<Float>(nc);
562 coeff = coeffs;
563 msg = String("user");
564 } else {
565 STAttr sdAttr;
566 coeff = sdAttr.gainElevationPoly(inst);
567 ppoly = new Polynomial<Float>(3);
568 msg = String("built in");
569 }
570
571 if ( coeff.nelements() > 0 ) {
572 ppoly->setCoefficients(coeff);
573 } else {
574 delete ppoly;
575 throw(AipsError("There is no known gain-elevation polynomial known for this instrument"));
576 }
577 ostringstream oss;
578 oss << "Making polynomial correction with " << msg << " coefficients:" << endl;
579 oss << " " << coeff;
580 pushLog(String(oss));
581 const uInt nrow = tab.nrow();
582 Vector<Float> factor(nrow);
583 for ( uInt i=0; i < nrow; ++i ) {
584 factor[i] = 1.0 / (*ppoly)(x[i]);
585 }
586 delete ppoly;
587 scaleByVector(tab, factor, true);
588
589 } else {
590 // Read and correct
591 pushLog("Making correction from ascii Table");
592 scaleFromAsciiTable(tab, filename, method, x, true);
593 }
594 return out;
595}
596
597void STMath::scaleFromAsciiTable(Table& in, const std::string& filename,
598 const std::string& method,
599 const Vector<Float>& xout, bool dotsys)
600{
601
602// Read gain-elevation ascii file data into a Table.
603
604 String formatString;
605 Table tbl = readAsciiTable(formatString, Table::Memory, filename, "", "", False);
606 scaleFromTable(in, tbl, method, xout, dotsys);
607}
608
609void STMath::scaleFromTable(Table& in,
610 const Table& table,
611 const std::string& method,
612 const Vector<Float>& xout, bool dotsys)
613{
614
615 ROScalarColumn<Float> geElCol(table, "ELEVATION");
616 ROScalarColumn<Float> geFacCol(table, "FACTOR");
617 Vector<Float> xin = geElCol.getColumn();
618 Vector<Float> yin = geFacCol.getColumn();
619 Vector<Bool> maskin(xin.nelements(),True);
620
621 // Interpolate (and extrapolate) with desired method
622
623 //InterpolateArray1D<Double,Float>::InterpolationMethod method;
624 Int intmethod(stringToIMethod(method));
625
626 Vector<Float> yout;
627 Vector<Bool> maskout;
628 InterpolateArray1D<Float,Float>::interpolate(yout, maskout, xout,
629 xin, yin, maskin, intmethod,
630 True, True);
631
632 scaleByVector(in, Float(1.0)/yout, dotsys);
633}
634
635void STMath::scaleByVector( Table& in,
636 const Vector< Float >& factor,
637 bool dotsys )
638{
639 uInt nrow = in.nrow();
640 if ( factor.nelements() != nrow ) {
641 throw(AipsError("factors.nelements() != table.nelements()"));
642 }
643 ArrayColumn<Float> specCol(in, "SPECTRA");
644 ArrayColumn<uChar> flagCol(in, "FLAGTRA");
645 ArrayColumn<Float> tsysCol(in, "TSYS");
646 for (uInt i=0; i < nrow; ++i) {
647 MaskedArray<Float> ma = maskedArray(specCol(i), flagCol(i));
648 ma *= factor[i];
649 specCol.put(i, ma.getArray());
650 flagCol.put(i, flagsFromMA(ma));
651 if ( dotsys ) {
652 Vector<Float> tsys = tsysCol(i);
653 tsys *= factor[i];
654 tsysCol.put(i,tsys);
655 }
656 }
657}
658
659CountedPtr< Scantable > STMath::convertFlux( const CountedPtr< Scantable >& in,
660 float d, float etaap,
661 float jyperk )
662{
663 CountedPtr< Scantable > out = getScantable(in, false);
664 Table& tab = in->table();
665 Unit fluxUnit(tab.keywordSet().asString("FluxUnit"));
666 Unit K(String("K"));
667 Unit JY(String("Jy"));
668
669 bool tokelvin = true;
670 Double cfac = 1.0;
671
672 if ( fluxUnit == JY ) {
673 pushLog("Converting to K");
674 Quantum<Double> t(1.0,fluxUnit);
675 Quantum<Double> t2 = t.get(JY);
676 cfac = (t2 / t).getValue(); // value to Jy
677
678 tokelvin = true;
679 out->setFluxUnit("K");
680 } else if ( fluxUnit == K ) {
681 pushLog("Converting to Jy");
682 Quantum<Double> t(1.0,fluxUnit);
683 Quantum<Double> t2 = t.get(K);
684 cfac = (t2 / t).getValue(); // value to K
685
686 tokelvin = false;
687 out->setFluxUnit("Jy");
688 } else {
689 throw(AipsError("Unrecognized brightness units in Table - must be consistent with Jy or K"));
690 }
691 // Make sure input values are converted to either Jy or K first...
692 Float factor = cfac;
693
694 // Select method
695 if (jyperk > 0.0) {
696 factor *= jyperk;
697 if ( tokelvin ) factor = 1.0 / jyperk;
698 ostringstream oss;
699 oss << "Jy/K = " << jyperk;
700 pushLog(String(oss));
701 Vector<Float> factors(tab.nrow(), factor);
702 scaleByVector(tab,factors, false);
703 } else if ( etaap > 0.0) {
704 Instrument inst =
705 STAttr::convertInstrument(tab.keywordSet().asString("AntennaName"), True);
706 STAttr sda;
707 if (d < 0) d = sda.diameter(inst);
708 Float jyPerk = STAttr::findJyPerK(etaap, d);
709 ostringstream oss;
710 oss << "Jy/K = " << jyperk;
711 pushLog(String(oss));
712 factor *= jyperk;
713 if ( tokelvin ) {
714 factor = 1.0 / factor;
715 }
716 Vector<Float> factors(tab.nrow(), factor);
717 scaleByVector(tab, factors, False);
718 } else {
719
720 // OK now we must deal with automatic look up of values.
721 // We must also deal with the fact that the factors need
722 // to be computed per IF and may be different and may
723 // change per integration.
724
725 pushLog("Looking up conversion factors");
726 convertBrightnessUnits(out, tokelvin, cfac);
727 }
728
729 return out;
730}
731
732void STMath::convertBrightnessUnits( CountedPtr<Scantable>& in,
733 bool tokelvin, float cfac )
734{
735 Table& table = in->table();
736 Instrument inst =
737 STAttr::convertInstrument(table.keywordSet().asString("AntennaName"), True);
738 TableIterator iter(table, "FREQ_ID");
739 STFrequencies stfreqs = in->frequencies();
740 STAttr sdAtt;
741 while (!iter.pastEnd()) {
742 Table tab = iter.table();
743 ArrayColumn<Float> specCol(tab, "SPECTRA");
744 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
745 ROScalarColumn<uInt> freqidCol(tab, "FREQ_ID");
746 MEpoch::ROScalarColumn timeCol(tab, "TIME");
747
748 uInt freqid; freqidCol.get(0, freqid);
749 Vector<Float> tmpspec; specCol.get(0, tmpspec);
750 // STAttr.JyPerK has a Vector interface... change sometime.
751 Vector<Float> freqs(1,stfreqs.getRefFreq(freqid, tmpspec.nelements()));
752 for ( uInt i=0; i<tab.nrow(); ++i) {
753 Float jyperk = (sdAtt.JyPerK(inst, timeCol(i), freqs))[0];
754 Float factor = cfac * jyperk;
755 if ( tokelvin ) factor = Float(1.0) / factor;
756 MaskedArray<Float> ma = maskedArray(specCol(i), flagCol(i));
757 ma *= factor;
758 specCol.put(i, ma.getArray());
759 flagCol.put(i, flagsFromMA(ma));
760 }
761 ++iter;
762 }
763}
764
765CountedPtr< Scantable > STMath::opacity( const CountedPtr< Scantable > & in,
766 float tau )
767{
768 CountedPtr< Scantable > out = getScantable(in, false);
769
770 Table tab = out->table();
771 ROScalarColumn<Float> elev(tab, "ELEVATION");
772 ArrayColumn<Float> specCol(tab, "SPECTRA");
773 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
774 for ( uInt i=0; i<tab.nrow(); ++i) {
775 Float zdist = Float(C::pi_2) - elev(i);
776 Float factor = exp(tau)/cos(zdist);
777 MaskedArray<Float> ma = maskedArray(specCol(i), flagCol(i));
778 ma *= factor;
779 specCol.put(i, ma.getArray());
780 flagCol.put(i, flagsFromMA(ma));
781 }
782 return out;
783}
784
785CountedPtr< Scantable > STMath::smooth( const CountedPtr< Scantable >& in,
786 const std::string& kernel, float width )
787{
788 CountedPtr< Scantable > out = getScantable(in, false);
789 Table& table = in->table();
790 VectorKernel::KernelTypes type = VectorKernel::toKernelType(kernel);
791 // same IFNO should have same no of channels
792 // this saves overhead
793 TableIterator iter(table, "IFNO");
794 while (!iter.pastEnd()) {
795 Table tab = iter.table();
796 ArrayColumn<Float> specCol(tab, "SPECTRA");
797 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
798 Vector<Float> tmpspec; specCol.get(0, tmpspec);
799 uInt nchan = tmpspec.nelements();
800 Vector<Float> kvec = VectorKernel::make(type, width, nchan, True, False);
801 Convolver<Float> conv(kvec, IPosition(1,nchan));
802 Vector<Float> spec;
803 Vector<uChar> flag;
804 for ( uInt i=0; i<tab.nrow(); ++i) {
805 specCol.get(i, spec);
806 flagCol.get(i, flag);
807 Vector<Bool> mask(flag.nelements());
808 convertArray(mask, flag);
809 Vector<Float> specout;
810 if ( type == VectorKernel::HANNING ) {
811 Vector<Bool> maskout;
812 mathutil::hanning(specout, maskout, spec , mask);
813 convertArray(flag, maskout);
814 flagCol.put(i, flag);
815 } else {
816 mathutil::replaceMaskByZero(specout, mask);
817 conv.linearConv(specout, spec);
818 }
819 specCol.put(i, specout);
820 }
821 ++iter;
822 }
823 return out;
824}
825
826CountedPtr< Scantable >
827 STMath::merge( const std::vector< CountedPtr < Scantable > >& in )
828{
829 if ( in.size() < 2 ) {
830 throw(AipsError("Need at least two scantables to perform a merge."));
831 }
832 std::vector<CountedPtr < Scantable > >::const_iterator it = in.begin();
833 bool insitu = insitu_;
834 setInsitu(false);
835 CountedPtr< Scantable > out = getScantable(*it, false);
836 setInsitu(insitu);
837 Table& tout = out->table();
838 ScalarColumn<uInt> freqidcol(tout,"FREQ_ID"), molidcol(tout, "MOLECULE_ID");
839 ScalarColumn<uInt> scannocol(tout,"SCANNO"), focusidcol(tout,"FOCUS_ID");
840 // Renumber SCANNO to be 0-based
841 Vector<uInt> scannos = scannocol.getColumn();
842 uInt offset = min(scannos);
843 scannos -= offset;
844 scannocol.putColumn(scannos);
845 uInt newscanno = max(scannos)+1;
846 ++it;
847 while ( it != in.end() ){
848 if ( ! (*it)->conformant(*out) ) {
849 // log message: "ignoring scantable i, as it isn't
850 // conformant with the other(s)"
851 cerr << "oh oh" << endl;
852 ++it;
853 continue;
854 }
855 out->appendToHistoryTable((*it)->history());
856 const Table& tab = (*it)->table();
857 TableIterator scanit(tab, "SCANNO");
858 while (!scanit.pastEnd()) {
859 TableIterator freqit(scanit.table(), "FREQ_ID");
860 while ( !freqit.pastEnd() ) {
861 Table thetab = freqit.table();
862 uInt nrow = tout.nrow();
863 //tout.addRow(thetab.nrow());
864 TableCopy::copyRows(tout, thetab, nrow, 0, thetab.nrow());
865 ROTableRow row(thetab);
866 for ( uInt i=0; i<thetab.nrow(); ++i) {
867 uInt k = nrow+i;
868 scannocol.put(k, newscanno);
869 const TableRecord& rec = row.get(i);
870 Double rv,rp,inc;
871 (*it)->frequencies().getEntry(rp, rv, inc, rec.asuInt("FREQ_ID"));
872 uInt id;
873 id = out->frequencies().addEntry(rp, rv, inc);
874 freqidcol.put(k,id);
875 String name,fname;Double rf;
876 (*it)->molecules().getEntry(rf, name, fname, rec.asuInt("MOLECULE_ID"));
877 id = out->molecules().addEntry(rf, name, fname);
878 molidcol.put(k, id);
879 Float frot,fax,ftan,fhand,fmount,fuser, fxy, fxyp;
880 (*it)->focus().getEntry(fax, ftan, frot, fhand,
881 fmount,fuser, fxy, fxyp,
882 rec.asuInt("FOCUS_ID"));
883 id = out->focus().addEntry(fax, ftan, frot, fhand,
884 fmount,fuser, fxy, fxyp);
885 focusidcol.put(k, id);
886 }
887 ++freqit;
888 }
889 ++newscanno;
890 ++scanit;
891 }
892 ++it;
893 }
894 return out;
895}
896
897CountedPtr< Scantable >
898 STMath::invertPhase( const CountedPtr < Scantable >& in )
899{
900 applyToPol(in, &STPol::invertPhase, Float(0.0));
901}
902
903CountedPtr< Scantable >
904 STMath::rotateXYPhase( const CountedPtr < Scantable >& in, float phase )
905{
906 return applyToPol(in, &STPol::rotatePhase, Float(phase));
907}
908
909CountedPtr< Scantable >
910 STMath::rotateLinPolPhase( const CountedPtr < Scantable >& in, float phase )
911{
912 return applyToPol(in, &STPol::rotateLinPolPhase, Float(phase));
913}
914
915CountedPtr< Scantable > STMath::applyToPol( const CountedPtr<Scantable>& in,
916 STPol::polOperation fptr,
917 Float phase )
918{
919 CountedPtr< Scantable > out = getScantable(in, false);
920 Table& tout = out->table();
921 Block<String> cols(4);
922 cols[0] = String("SCANNO");
923 cols[1] = String("BEAMNO");
924 cols[2] = String("IFNO");
925 cols[3] = String("CYCLENO");
926 TableIterator iter(tout, cols);
927 STPol* stpol = NULL;
928 stpol =STPol::getPolClass(out->factories_, out->getPolType() );
929 while (!iter.pastEnd()) {
930 Table t = iter.table();
931 ArrayColumn<Float> speccol(t, "SPECTRA");
932 Matrix<Float> pols = speccol.getColumn();
933 try {
934 stpol->setSpectra(pols);
935 (stpol->*fptr)(phase);
936 speccol.putColumn(stpol->getSpectra());
937 } catch (AipsError& e) {
938 delete stpol;stpol=0;
939 throw(e);
940 }
941 ++iter;
942 }
943 delete stpol;stpol=0;
944 return out;
945}
946
947CountedPtr< Scantable >
948 STMath::swapPolarisations( const CountedPtr< Scantable > & in )
949{
950 CountedPtr< Scantable > out = getScantable(in, false);
951 Table& tout = out->table();
952 Table t0 = tout(tout.col("POLNO") == 0);
953 Table t1 = tout(tout.col("POLNO") == 1);
954 if ( t0.nrow() != t1.nrow() )
955 throw(AipsError("Inconsistent number of polarisations"));
956 ArrayColumn<Float> speccol0(t0, "SPECTRA");
957 ArrayColumn<uChar> flagcol0(t0, "FLAGTRA");
958 ArrayColumn<Float> speccol1(t1, "SPECTRA");
959 ArrayColumn<uChar> flagcol1(t1, "FLAGTRA");
960 Matrix<Float> s0 = speccol0.getColumn();
961 Matrix<uChar> f0 = flagcol0.getColumn();
962 speccol0.putColumn(speccol1.getColumn());
963 flagcol0.putColumn(flagcol1.getColumn());
964 speccol1.putColumn(s0);
965 flagcol1.putColumn(f0);
966 return out;
967}
968
969CountedPtr< Scantable >
970 STMath::averagePolarisations( const CountedPtr< Scantable > & in,
971 const std::vector<bool>& mask,
972 const std::string& weight )
973{
974 if (in->getPolType() != "linear" || in->npol() != 2 )
975 throw(AipsError("averagePolarisations can only be applied to two linear polarisations."));
976 CountedPtr<Scantable> pol0( new Scantable(*in), false);
977 CountedPtr<Scantable> pol1( new Scantable(*in), false);
978 Table& tpol0 = pol0->table();
979 Table& tpol1 = pol1->table();
980 Vector<uInt> pol0rows = tpol0(tpol0.col("POLNO") == 0).rowNumbers();
981 Vector<uInt> pol1rows = tpol1(tpol1.col("POLNO") == 1).rowNumbers();
982 tpol0.removeRow(pol1rows);
983 tpol1.removeRow(pol0rows);
984 // give both tables the same POLNO
985 TableVector<uInt> vec(tpol1,"POLNO");
986 vec = 0;
987 std::vector<CountedPtr<Scantable> > pols;
988 pols.push_back(pol0);
989 pols.push_back(pol1);
990 CountedPtr< Scantable > out = average(pols, mask, weight, "NONE");
991 out->table_.rwKeywordSet().define("nPol",Int(1));
992 return out;
993}
994
995
996CountedPtr< Scantable >
997 asap::STMath::frequencyAlign( const CountedPtr< Scantable > & in,
998 const std::string & refTime,
999 const std::string & method)
1000{
1001 // clone as this is not working insitu
1002 bool insitu = insitu_;
1003 setInsitu(false);
1004 CountedPtr< Scantable > out = getScantable(in, false);
1005 setInsitu(insitu);
1006 Table& tout = out->table();
1007 // clear ouput frequency table
1008 //Table ftable = out->frequencies().table();
1009 //ftable.removeRow(ftable.rowNumbers());
1010 // Get reference Epoch to time of first row or given String
1011 Unit DAY(String("d"));
1012 MEpoch::Ref epochRef(in->getTimeReference());
1013 MEpoch refEpoch;
1014 if (refTime.length()>0) {
1015 Quantum<Double> qt;
1016 if (MVTime::read(qt,refTime)) {
1017 MVEpoch mv(qt);
1018 refEpoch = MEpoch(mv, epochRef);
1019 } else {
1020 throw(AipsError("Invalid format for Epoch string"));
1021 }
1022 } else {
1023 refEpoch = in->timeCol_(0);
1024 }
1025 MPosition refPos = in->getAntennaPosition();
1026
1027 InterpolateArray1D<Double,Float>::InterpolationMethod interp;
1028 Int interpMethod(stringToIMethod(method));
1029 // test if user frame is different to base frame
1030 if ( in->frequencies().getFrameString(true)
1031 == in->frequencies().getFrameString(false) ) {
1032 throw(AipsError("You have not set a frequency frame different from the initial - use function set_freqframe"));
1033 }
1034 MFrequency::Types system = in->frequencies().getFrame();
1035 MVTime mvt(refEpoch.getValue());
1036 String epochout = mvt.string(MVTime::YMD) + String(" (") + refEpoch.getRefString() + String(")");
1037 ostringstream oss;
1038 oss << "Aligned at reference Epoch " << epochout
1039 << " in frame " << MFrequency::showType(system);
1040 pushLog(String(oss));
1041 // set up the iterator
1042 Block<String> cols(4);
1043 // select by constant direction
1044 cols[0] = String("SRCNAME");
1045 cols[1] = String("BEAMNO");
1046 // select by IF ( no of channels varies over this )
1047 cols[2] = String("IFNO");
1048 // select by restfrequency
1049 cols[3] = String("MOLECULE_ID");
1050 TableIterator iter(tout, cols);
1051 while ( !iter.pastEnd() ) {
1052 Table t = iter.table();
1053 MDirection::ROScalarColumn dirCol(t, "DIRECTION");
1054 TableIterator fiter(t, "FREQ_ID");
1055 // determine nchan from the first row. This should work as
1056 // we are iterating over BEAMNO and IFNO // we should have constant direction
1057
1058 ROArrayColumn<Float> sCol(t, "SPECTRA");
1059 MDirection direction = dirCol(0);
1060 uInt nchan = sCol(0).nelements();
1061 while ( !fiter.pastEnd() ) {
1062 Table ftab = fiter.table();
1063 ScalarColumn<uInt> freqidCol(ftab, "FREQ_ID");
1064 // get the SpectralCoordinate for the freqid, which we are iterating over
1065 SpectralCoordinate sC = in->frequencies().getSpectralCoordinate(freqidCol(0));
1066 FrequencyAligner<Float> fa( sC, nchan, refEpoch,
1067 direction, refPos, system );
1068 // realign the SpectralCoordinate and put into the output Scantable
1069 Vector<String> units(1);
1070 units = String("Hz");
1071 Bool linear=True;
1072 SpectralCoordinate sc2 = fa.alignedSpectralCoordinate(linear);
1073 sc2.setWorldAxisUnits(units);
1074 uInt id = out->frequencies().addEntry(sc2.referencePixel()[0],
1075 sc2.referenceValue()[0],
1076 sc2.increment()[0]);
1077 TableVector<uInt> tvec(ftab, "FREQ_ID");
1078 tvec = id;
1079 // create the "global" abcissa for alignment with same FREQ_ID
1080 Vector<Double> abc(nchan);
1081 Double w;
1082 for (uInt i=0; i<nchan; i++) {
1083 sC.toWorld(w,Double(i));
1084 abc[i] = w;
1085 }
1086 // cache abcissa for same time stamps, so iterate over those
1087 TableIterator timeiter(ftab, "TIME");
1088 while ( !timeiter.pastEnd() ) {
1089 Table tab = timeiter.table();
1090 ArrayColumn<Float> specCol(tab, "SPECTRA");
1091 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1092 MEpoch::ROScalarColumn timeCol(tab, "TIME");
1093 // use align abcissa cache after the first row
1094 bool first = true;
1095 // these rows should be just be POLNO
1096 for (int i=0; i<tab.nrow(); ++i) {
1097 // input values
1098 Vector<uChar> flag = flagCol(i);
1099 Vector<Bool> mask(flag.shape());
1100 Vector<Float> specOut, spec;
1101 spec = specCol(i);
1102 Vector<Bool> maskOut;Vector<uChar> flagOut;
1103 convertArray(mask, flag);
1104 // alignment
1105 Bool ok = fa.align(specOut, maskOut, abc, spec,
1106 mask, timeCol(i), !first,
1107 interp, False);
1108 // back into scantable
1109 flagOut.resize(maskOut.nelements());
1110 convertArray(flagOut, maskOut);
1111 flagCol.put(i, flagOut);
1112 specCol.put(i, specOut);
1113 // start abcissa caching
1114 first = false;
1115 }
1116 // next timestamp
1117 ++timeiter;
1118 }
1119 // next FREQ_ID
1120 ++fiter;
1121 }
1122 // next aligner
1123 ++iter;
1124 }
1125 // set this afterwards to ensure we are doing insitu correctly.
1126 out->frequencies().setFrame(system, true);
1127 return out;
1128}
Note: See TracBrowser for help on using the repository browser.