source: branches/alma/src/STMath.cpp@ 1633

Last change on this file since 1633 was 1633, checked in by Takeshi Nakazato, 16 years ago

New Development: No

JIRA Issue: Yes CAS-1422

Ready to Release: Yes

Interface Changes: Yes

What Interface Changed: Defined calibrate() and almacal() in python/asapmath.py

Defined cwcal() in STMath class

Test Programs: List test programs

Put in Release Notes: Yes

Module(s): task_sdaverage

Description: Describe your changes here...

asapmath.py is changed to be able to calibrate data for APEX.
This modification is tentatively considered a calibration of ALMA
single-dish data. However, it must be updated in the future since
I don't know how raw ALMA data are provided and I have to change
code along with read ALMA data.

The calibrate() function takes calibration mode from its argument and
looks antenna name of the input scantable, and calls appropriate calibration
function depending on the calibration mode and antenna name.
If antenna name include 'APEX' or 'ALMA', newly defined calibration function
apexcal() is called. For other antenna name, one of the existing calibration
functions (calps, calnod, calfs, auto_quotient) is called.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 144.9 KB
Line 
1//
2// C++ Implementation: STMath
3//
4// Description:
5//
6//
7// Author: Malte Marquarding <asap@atnf.csiro.au>, (C) 2006
8//
9// Copyright: See COPYING file that comes with this distribution
10//
11//
12
13#include <casa/iomanip.h>
14#include <casa/Exceptions/Error.h>
15#include <casa/Containers/Block.h>
16#include <casa/BasicSL/String.h>
17#include <casa/Arrays/MaskArrLogi.h>
18#include <casa/Arrays/MaskArrMath.h>
19#include <casa/Arrays/ArrayLogical.h>
20#include <casa/Arrays/ArrayMath.h>
21#include <casa/Arrays/Slice.h>
22#include <casa/Arrays/Slicer.h>
23#include <casa/Containers/RecordField.h>
24#include <tables/Tables/TableRow.h>
25#include <tables/Tables/TableVector.h>
26#include <tables/Tables/TabVecMath.h>
27#include <tables/Tables/ExprNode.h>
28#include <tables/Tables/TableRecord.h>
29#include <tables/Tables/TableParse.h>
30#include <tables/Tables/ReadAsciiTable.h>
31#include <tables/Tables/TableIter.h>
32#include <tables/Tables/TableCopy.h>
33#include <scimath/Mathematics/FFTServer.h>
34
35#include <lattices/Lattices/LatticeUtilities.h>
36
37#include <coordinates/Coordinates/SpectralCoordinate.h>
38#include <coordinates/Coordinates/CoordinateSystem.h>
39#include <coordinates/Coordinates/CoordinateUtil.h>
40#include <coordinates/Coordinates/FrequencyAligner.h>
41
42#include <scimath/Mathematics/VectorKernel.h>
43#include <scimath/Mathematics/Convolver.h>
44#include <scimath/Functionals/Polynomial.h>
45
46#include <casa/Logging/LogIO.h>
47#include <sstream>
48
49#include "MathUtils.h"
50#include "RowAccumulator.h"
51#include "STAttr.h"
52#include "STMath.h"
53#include "STSelector.h"
54
55using namespace casa;
56
57using namespace asap;
58
59// tolerance for direction comparison (rad)
60#define TOL_OTF 1.0e-15
61#define TOL_POINT 1.0e-5 // 2 arcsec
62
63STMath::STMath(bool insitu) :
64 insitu_(insitu)
65{
66}
67
68
69STMath::~STMath()
70{
71}
72
73CountedPtr<Scantable>
74STMath::average( const std::vector<CountedPtr<Scantable> >& in,
75 const std::vector<bool>& mask,
76 const std::string& weight,
77 const std::string& avmode)
78{
79 LogIO os( LogOrigin( "STMath", "average()", WHERE ) ) ;
80 if ( avmode == "SCAN" && in.size() != 1 )
81 throw(AipsError("Can't perform 'SCAN' averaging on multiple tables.\n"
82 "Use merge first."));
83 WeightType wtype = stringToWeight(weight);
84
85 // check if OTF observation
86 String obstype = in[0]->getHeader().obstype ;
87 Double tol = 0.0 ;
88 if ( obstype.find( "OTF" ) != String::npos ) {
89 tol = TOL_OTF ;
90 }
91 else {
92 tol = TOL_POINT ;
93 }
94
95 // output
96 // clone as this is non insitu
97 bool insitu = insitu_;
98 setInsitu(false);
99 CountedPtr< Scantable > out = getScantable(in[0], true);
100 setInsitu(insitu);
101 std::vector<CountedPtr<Scantable> >::const_iterator stit = in.begin();
102 ++stit;
103 while ( stit != in.end() ) {
104 out->appendToHistoryTable((*stit)->history());
105 ++stit;
106 }
107
108 Table& tout = out->table();
109
110 /// @todo check if all scantables are conformant
111
112 ArrayColumn<Float> specColOut(tout,"SPECTRA");
113 ArrayColumn<uChar> flagColOut(tout,"FLAGTRA");
114 ArrayColumn<Float> tsysColOut(tout,"TSYS");
115 ScalarColumn<Double> mjdColOut(tout,"TIME");
116 ScalarColumn<Double> intColOut(tout,"INTERVAL");
117 ScalarColumn<uInt> cycColOut(tout,"CYCLENO");
118 ScalarColumn<uInt> scanColOut(tout,"SCANNO");
119
120 // set up the output table rows. These are based on the structure of the
121 // FIRST scantable in the vector
122 const Table& baset = in[0]->table();
123
124 Block<String> cols(3);
125 cols[0] = String("BEAMNO");
126 cols[1] = String("IFNO");
127 cols[2] = String("POLNO");
128 if ( avmode == "SOURCE" ) {
129 cols.resize(4);
130 cols[3] = String("SRCNAME");
131 }
132 if ( avmode == "SCAN" && in.size() == 1) {
133 //cols.resize(4);
134 //cols[3] = String("SCANNO");
135 cols.resize(5);
136 cols[3] = String("SRCNAME");
137 cols[4] = String("SCANNO");
138 }
139 uInt outrowCount = 0;
140 TableIterator iter(baset, cols);
141// int count = 0 ;
142 while (!iter.pastEnd()) {
143 Table subt = iter.table();
144// // copy the first row of this selection into the new table
145// tout.addRow();
146// TableCopy::copyRows(tout, subt, outrowCount, 0, 1);
147// // re-index to 0
148// if ( avmode != "SCAN" && avmode != "SOURCE" ) {
149// scanColOut.put(outrowCount, uInt(0));
150// }
151// ++outrowCount;
152 MDirection::ScalarColumn dircol ;
153 dircol.attach( subt, "DIRECTION" ) ;
154 Int length = subt.nrow() ;
155 vector< Vector<Double> > dirs ;
156 vector<int> indexes ;
157 for ( Int i = 0 ; i < length ; i++ ) {
158 Vector<Double> t = dircol(i).getAngle(Unit(String("rad"))).getValue() ;
159 //os << << count++ << ": " ;
160 //os << "[" << t[0] << "," << t[1] << "]" << LogIO::POST ;
161 bool adddir = true ;
162 for ( uInt j = 0 ; j < dirs.size() ; j++ ) {
163 //if ( allTrue( t == dirs[j] ) ) {
164 Double dx = t[0] - dirs[j][0] ;
165 Double dy = t[1] - dirs[j][1] ;
166 Double dd = sqrt( dx * dx + dy * dy ) ;
167 //if ( allNearAbs( t, dirs[j], tol ) ) {
168 if ( dd <= tol ) {
169 adddir = false ;
170 break ;
171 }
172 }
173 if ( adddir ) {
174 dirs.push_back( t ) ;
175 indexes.push_back( i ) ;
176 }
177 }
178 uInt rowNum = dirs.size() ;
179 tout.addRow( rowNum ) ;
180 for ( uInt i = 0 ; i < rowNum ; i++ ) {
181 TableCopy::copyRows( tout, subt, outrowCount+i, indexes[i], 1 ) ;
182 // re-index to 0
183 if ( avmode != "SCAN" && avmode != "SOURCE" ) {
184 scanColOut.put(outrowCount+i, uInt(0));
185 }
186 }
187 outrowCount += rowNum ;
188 ++iter;
189 }
190 RowAccumulator acc(wtype);
191 Vector<Bool> cmask(mask);
192 acc.setUserMask(cmask);
193 ROTableRow row(tout);
194 ROArrayColumn<Float> specCol, tsysCol;
195 ROArrayColumn<uChar> flagCol;
196 ROScalarColumn<Double> mjdCol, intCol;
197 ROScalarColumn<Int> scanIDCol;
198
199 Vector<uInt> rowstodelete;
200
201 for (uInt i=0; i < tout.nrow(); ++i) {
202 for ( int j=0; j < int(in.size()); ++j ) {
203 const Table& tin = in[j]->table();
204 const TableRecord& rec = row.get(i);
205 ROScalarColumn<Double> tmp(tin, "TIME");
206 Double td;tmp.get(0,td);
207 Table basesubt = tin(tin.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
208 && tin.col("IFNO") == Int(rec.asuInt("IFNO"))
209 && tin.col("POLNO") == Int(rec.asuInt("POLNO")) );
210 Table subt;
211 if ( avmode == "SOURCE") {
212 subt = basesubt( basesubt.col("SRCNAME") == rec.asString("SRCNAME") );
213 } else if (avmode == "SCAN") {
214 //subt = basesubt( basesubt.col("SCANNO") == Int(rec.asuInt("SCANNO")) );
215 subt = basesubt( basesubt.col("SCANNO") == Int(rec.asuInt("SCANNO"))
216 && basesubt.col("SRCNAME") == rec.asString("SRCNAME") );
217 } else {
218 subt = basesubt;
219 }
220
221 vector<uInt> removeRows ;
222 uInt nrsubt = subt.nrow() ;
223 for ( uInt irow = 0 ; irow < nrsubt ; irow++ ) {
224 //if ( !allTrue((subt.col("DIRECTION").getArrayDouble(TableExprId(irow)))==rec.asArrayDouble("DIRECTION")) ) {
225 Vector<Double> x0 = (subt.col("DIRECTION").getArrayDouble(TableExprId(irow))) ;
226 Vector<Double> x1 = rec.asArrayDouble("DIRECTION") ;
227 double dx = x0[0] - x1[0] ;
228 double dy = x0[0] - x1[0] ;
229 Double dd = sqrt( dx * dx + dy * dy ) ;
230 //if ( !allNearAbs((subt.col("DIRECTION").getArrayDouble(TableExprId(irow))), rec.asArrayDouble("DIRECTION"), tol ) ) {
231 if ( dd > tol ) {
232 removeRows.push_back( irow ) ;
233 }
234 }
235 if ( removeRows.size() != 0 ) {
236 subt.removeRow( removeRows ) ;
237 }
238
239 if ( nrsubt == removeRows.size() )
240 throw(AipsError("Averaging data is empty.")) ;
241
242 specCol.attach(subt,"SPECTRA");
243 flagCol.attach(subt,"FLAGTRA");
244 tsysCol.attach(subt,"TSYS");
245 intCol.attach(subt,"INTERVAL");
246 mjdCol.attach(subt,"TIME");
247 Vector<Float> spec,tsys;
248 Vector<uChar> flag;
249 Double inter,time;
250 for (uInt k = 0; k < subt.nrow(); ++k ) {
251 flagCol.get(k, flag);
252 Vector<Bool> bflag(flag.shape());
253 convertArray(bflag, flag);
254 /*
255 if ( allEQ(bflag, True) ) {
256 continue;//don't accumulate
257 }
258 */
259 specCol.get(k, spec);
260 tsysCol.get(k, tsys);
261 intCol.get(k, inter);
262 mjdCol.get(k, time);
263 // spectrum has to be added last to enable weighting by the other values
264 acc.add(spec, !bflag, tsys, inter, time);
265 }
266 }
267 const Vector<Bool>& msk = acc.getMask();
268 if ( allEQ(msk, False) ) {
269 uint n = rowstodelete.nelements();
270 rowstodelete.resize(n+1, True);
271 rowstodelete[n] = i;
272 continue;
273 }
274 //write out
275 if (acc.state()) {
276 Vector<uChar> flg(msk.shape());
277 convertArray(flg, !msk);
278 flagColOut.put(i, flg);
279 specColOut.put(i, acc.getSpectrum());
280 tsysColOut.put(i, acc.getTsys());
281 intColOut.put(i, acc.getInterval());
282 mjdColOut.put(i, acc.getTime());
283 // we should only have one cycle now -> reset it to be 0
284 // frequency switched data has different CYCLENO for different IFNO
285 // which requires resetting this value
286 cycColOut.put(i, uInt(0));
287 } else {
288 ostringstream oss;
289 oss << "For output row="<<i<<", all input rows of data are flagged. no averaging" << endl;
290 pushLog(String(oss));
291 }
292 acc.reset();
293 }
294 if (rowstodelete.nelements() > 0) {
295 //cout << rowstodelete << endl;
296 os << rowstodelete << LogIO::POST ;
297 tout.removeRow(rowstodelete);
298 if (tout.nrow() == 0) {
299 throw(AipsError("Can't average fully flagged data."));
300 }
301 }
302 return out;
303}
304
305CountedPtr< Scantable >
306 STMath::averageChannel( const CountedPtr < Scantable > & in,
307 const std::string & mode,
308 const std::string& avmode )
309{
310 // check if OTF observation
311 String obstype = in->getHeader().obstype ;
312 Double tol = 0.0 ;
313 if ( obstype.find( "OTF" ) != String::npos ) {
314 tol = TOL_OTF ;
315 }
316 else {
317 tol = TOL_POINT ;
318 }
319
320 // clone as this is non insitu
321 bool insitu = insitu_;
322 setInsitu(false);
323 CountedPtr< Scantable > out = getScantable(in, true);
324 setInsitu(insitu);
325 Table& tout = out->table();
326 ArrayColumn<Float> specColOut(tout,"SPECTRA");
327 ArrayColumn<uChar> flagColOut(tout,"FLAGTRA");
328 ArrayColumn<Float> tsysColOut(tout,"TSYS");
329 ScalarColumn<uInt> scanColOut(tout,"SCANNO");
330 ScalarColumn<Double> intColOut(tout, "INTERVAL");
331 Table tmp = in->table().sort("BEAMNO");
332 Block<String> cols(3);
333 cols[0] = String("BEAMNO");
334 cols[1] = String("IFNO");
335 cols[2] = String("POLNO");
336 if ( avmode == "SCAN") {
337 cols.resize(4);
338 cols[3] = String("SCANNO");
339 }
340 uInt outrowCount = 0;
341 uChar userflag = 1 << 7;
342 TableIterator iter(tmp, cols);
343 while (!iter.pastEnd()) {
344 Table subt = iter.table();
345 ROArrayColumn<Float> specCol, tsysCol;
346 ROArrayColumn<uChar> flagCol;
347 ROScalarColumn<Double> intCol(subt, "INTERVAL");
348 specCol.attach(subt,"SPECTRA");
349 flagCol.attach(subt,"FLAGTRA");
350 tsysCol.attach(subt,"TSYS");
351// tout.addRow();
352// TableCopy::copyRows(tout, subt, outrowCount, 0, 1);
353// if ( avmode != "SCAN") {
354// scanColOut.put(outrowCount, uInt(0));
355// }
356// Vector<Float> tmp;
357// specCol.get(0, tmp);
358// uInt nchan = tmp.nelements();
359// // have to do channel by channel here as MaskedArrMath
360// // doesn't have partialMedians
361// Vector<uChar> flags = flagCol.getColumn(Slicer(Slice(0)));
362// Vector<Float> outspec(nchan);
363// Vector<uChar> outflag(nchan,0);
364// Vector<Float> outtsys(1);/// @fixme when tsys is channel based
365// for (uInt i=0; i<nchan; ++i) {
366// Vector<Float> specs = specCol.getColumn(Slicer(Slice(i)));
367// MaskedArray<Float> ma = maskedArray(specs,flags);
368// outspec[i] = median(ma);
369// if ( allEQ(ma.getMask(), False) )
370// outflag[i] = userflag;// flag data
371// }
372// outtsys[0] = median(tsysCol.getColumn());
373// specColOut.put(outrowCount, outspec);
374// flagColOut.put(outrowCount, outflag);
375// tsysColOut.put(outrowCount, outtsys);
376// Double intsum = sum(intCol.getColumn());
377// intColOut.put(outrowCount, intsum);
378// ++outrowCount;
379// ++iter;
380 MDirection::ScalarColumn dircol ;
381 dircol.attach( subt, "DIRECTION" ) ;
382 Int length = subt.nrow() ;
383 vector< Vector<Double> > dirs ;
384 vector<int> indexes ;
385 for ( Int i = 0 ; i < length ; i++ ) {
386 Vector<Double> t = dircol(i).getAngle(Unit(String("rad"))).getValue() ;
387 bool adddir = true ;
388 for ( uInt j = 0 ; j < dirs.size() ; j++ ) {
389 //if ( allTrue( t == dirs[j] ) ) {
390 Double dx = t[0] - dirs[j][0] ;
391 Double dy = t[1] - dirs[j][1] ;
392 Double dd = sqrt( dx * dx + dy * dy ) ;
393 //if ( allNearAbs( t, dirs[j], tol ) ) {
394 if ( dd <= tol ) {
395 adddir = false ;
396 break ;
397 }
398 }
399 if ( adddir ) {
400 dirs.push_back( t ) ;
401 indexes.push_back( i ) ;
402 }
403 }
404 uInt rowNum = dirs.size() ;
405 tout.addRow( rowNum );
406 for ( uInt i = 0 ; i < rowNum ; i++ ) {
407 TableCopy::copyRows(tout, subt, outrowCount+i, indexes[i], 1) ;
408 if ( avmode != "SCAN") {
409 //scanColOut.put(outrowCount+i, uInt(0));
410 }
411 }
412 MDirection::ScalarColumn dircolOut ;
413 dircolOut.attach( tout, "DIRECTION" ) ;
414 for ( uInt irow = 0 ; irow < rowNum ; irow++ ) {
415 Vector<Double> t = dircolOut(outrowCount+irow).getAngle(Unit(String("rad"))).getValue() ;
416 Vector<Float> tmp;
417 specCol.get(0, tmp);
418 uInt nchan = tmp.nelements();
419 // have to do channel by channel here as MaskedArrMath
420 // doesn't have partialMedians
421 Vector<uChar> flags = flagCol.getColumn(Slicer(Slice(0)));
422 // mask spectra for different DIRECTION
423 for ( uInt jrow = 0 ; jrow < subt.nrow() ; jrow++ ) {
424 Vector<Double> direction = dircol(jrow).getAngle(Unit(String("rad"))).getValue() ;
425 //if ( t[0] != direction[0] || t[1] != direction[1] ) {
426 Double dx = t[0] - direction[0] ;
427 Double dy = t[1] - direction[1] ;
428 Double dd = sqrt( dx * dx + dy * dy ) ;
429 //if ( !allNearAbs( t, direction, tol ) ) {
430 if ( dd > tol ) {
431 flags[jrow] = userflag ;
432 }
433 }
434 Vector<Float> outspec(nchan);
435 Vector<uChar> outflag(nchan,0);
436 Vector<Float> outtsys(1);/// @fixme when tsys is channel based
437 for (uInt i=0; i<nchan; ++i) {
438 Vector<Float> specs = specCol.getColumn(Slicer(Slice(i)));
439 MaskedArray<Float> ma = maskedArray(specs,flags);
440 outspec[i] = median(ma);
441 if ( allEQ(ma.getMask(), False) )
442 outflag[i] = userflag;// flag data
443 }
444 outtsys[0] = median(tsysCol.getColumn());
445 specColOut.put(outrowCount+irow, outspec);
446 flagColOut.put(outrowCount+irow, outflag);
447 tsysColOut.put(outrowCount+irow, outtsys);
448 Vector<Double> integ = intCol.getColumn() ;
449 MaskedArray<Double> mi = maskedArray( integ, flags ) ;
450 Double intsum = sum(mi);
451 intColOut.put(outrowCount+irow, intsum);
452 }
453 outrowCount += rowNum ;
454 ++iter;
455 }
456 return out;
457}
458
459CountedPtr< Scantable > STMath::getScantable(const CountedPtr< Scantable >& in,
460 bool droprows)
461{
462 if (insitu_) {
463 return in;
464 }
465 else {
466 // clone
467 return CountedPtr<Scantable>(new Scantable(*in, Bool(droprows)));
468 }
469}
470
471CountedPtr< Scantable > STMath::unaryOperate( const CountedPtr< Scantable >& in,
472 float val,
473 const std::string& mode,
474 bool tsys )
475{
476 CountedPtr< Scantable > out = getScantable(in, false);
477 Table& tab = out->table();
478 ArrayColumn<Float> specCol(tab,"SPECTRA");
479 ArrayColumn<Float> tsysCol(tab,"TSYS");
480 for (uInt i=0; i<tab.nrow(); ++i) {
481 Vector<Float> spec;
482 Vector<Float> ts;
483 specCol.get(i, spec);
484 tsysCol.get(i, ts);
485 if (mode == "MUL" || mode == "DIV") {
486 if (mode == "DIV") val = 1.0/val;
487 spec *= val;
488 specCol.put(i, spec);
489 if ( tsys ) {
490 ts *= val;
491 tsysCol.put(i, ts);
492 }
493 } else if ( mode == "ADD" || mode == "SUB") {
494 if (mode == "SUB") val *= -1.0;
495 spec += val;
496 specCol.put(i, spec);
497 if ( tsys ) {
498 ts += val;
499 tsysCol.put(i, ts);
500 }
501 }
502 }
503 return out;
504}
505
506CountedPtr<Scantable> STMath::binaryOperate(const CountedPtr<Scantable>& left,
507 const CountedPtr<Scantable>& right,
508 const std::string& mode)
509{
510 bool insitu = insitu_;
511 if ( ! left->conformant(*right) ) {
512 throw(AipsError("'left' and 'right' scantables are not conformant."));
513 }
514 setInsitu(false);
515 CountedPtr< Scantable > out = getScantable(left, false);
516 setInsitu(insitu);
517 Table& tout = out->table();
518 Block<String> coln(5);
519 coln[0] = "SCANNO"; coln[1] = "CYCLENO"; coln[2] = "BEAMNO";
520 coln[3] = "IFNO"; coln[4] = "POLNO";
521 Table tmpl = tout.sort(coln);
522 Table tmpr = right->table().sort(coln);
523 ArrayColumn<Float> lspecCol(tmpl,"SPECTRA");
524 ROArrayColumn<Float> rspecCol(tmpr,"SPECTRA");
525 ArrayColumn<uChar> lflagCol(tmpl,"FLAGTRA");
526 ROArrayColumn<uChar> rflagCol(tmpr,"FLAGTRA");
527
528 for (uInt i=0; i<tout.nrow(); ++i) {
529 Vector<Float> lspecvec, rspecvec;
530 Vector<uChar> lflagvec, rflagvec;
531 lspecvec = lspecCol(i); rspecvec = rspecCol(i);
532 lflagvec = lflagCol(i); rflagvec = rflagCol(i);
533 MaskedArray<Float> mleft = maskedArray(lspecvec, lflagvec);
534 MaskedArray<Float> mright = maskedArray(rspecvec, rflagvec);
535 if (mode == "ADD") {
536 mleft += mright;
537 } else if ( mode == "SUB") {
538 mleft -= mright;
539 } else if ( mode == "MUL") {
540 mleft *= mright;
541 } else if ( mode == "DIV") {
542 mleft /= mright;
543 } else {
544 throw(AipsError("Illegal binary operator"));
545 }
546 lspecCol.put(i, mleft.getArray());
547 }
548 return out;
549}
550
551
552
553MaskedArray<Float> STMath::maskedArray( const Vector<Float>& s,
554 const Vector<uChar>& f)
555{
556 Vector<Bool> mask;
557 mask.resize(f.shape());
558 convertArray(mask, f);
559 return MaskedArray<Float>(s,!mask);
560}
561
562MaskedArray<Double> STMath::maskedArray( const Vector<Double>& s,
563 const Vector<uChar>& f)
564{
565 Vector<Bool> mask;
566 mask.resize(f.shape());
567 convertArray(mask, f);
568 return MaskedArray<Double>(s,!mask);
569}
570
571Vector<uChar> STMath::flagsFromMA(const MaskedArray<Float>& ma)
572{
573 const Vector<Bool>& m = ma.getMask();
574 Vector<uChar> flags(m.shape());
575 convertArray(flags, !m);
576 return flags;
577}
578
579CountedPtr< Scantable > STMath::autoQuotient( const CountedPtr< Scantable >& in,
580 const std::string & mode,
581 bool preserve )
582{
583 /// @todo make other modes available
584 /// modes should be "nearest", "pair"
585 // make this operation non insitu
586 const Table& tin = in->table();
587 Table ons = tin(tin.col("SRCTYPE") == Int(0));
588 Table offs = tin(tin.col("SRCTYPE") == Int(1));
589 if ( offs.nrow() == 0 )
590 throw(AipsError("No 'off' scans present."));
591 // put all "on" scans into output table
592
593 bool insitu = insitu_;
594 setInsitu(false);
595 CountedPtr< Scantable > out = getScantable(in, true);
596 setInsitu(insitu);
597 Table& tout = out->table();
598
599 TableCopy::copyRows(tout, ons);
600 TableRow row(tout);
601 ROScalarColumn<Double> offtimeCol(offs, "TIME");
602 ArrayColumn<Float> outspecCol(tout, "SPECTRA");
603 ROArrayColumn<Float> outtsysCol(tout, "TSYS");
604 ArrayColumn<uChar> outflagCol(tout, "FLAGTRA");
605 for (uInt i=0; i < tout.nrow(); ++i) {
606 const TableRecord& rec = row.get(i);
607 Double ontime = rec.asDouble("TIME");
608 Table presel = offs(offs.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
609 && offs.col("IFNO") == Int(rec.asuInt("IFNO"))
610 && offs.col("POLNO") == Int(rec.asuInt("POLNO")) );
611 ROScalarColumn<Double> offtimeCol(presel, "TIME");
612
613 Double mindeltat = min(abs(offtimeCol.getColumn() - ontime));
614 // Timestamp may vary within a cycle ???!!!
615 // increase this by 0.01 sec in case of rounding errors...
616 // There might be a better way to do this.
617 // fix to this fix. TIME is MJD, so 1.0d not 1.0s
618 mindeltat += 0.01/24./60./60.;
619 Table sel = presel( abs(presel.col("TIME")-ontime) <= mindeltat);
620
621 if ( sel.nrow() < 1 ) {
622 throw(AipsError("No closest in time found... This could be a rounding "
623 "issue. Try quotient instead."));
624 }
625 TableRow offrow(sel);
626 const TableRecord& offrec = offrow.get(0);//should only be one row
627 RORecordFieldPtr< Array<Float> > specoff(offrec, "SPECTRA");
628 RORecordFieldPtr< Array<Float> > tsysoff(offrec, "TSYS");
629 RORecordFieldPtr< Array<uChar> > flagoff(offrec, "FLAGTRA");
630 /// @fixme this assumes tsys is a scalar not vector
631 Float tsysoffscalar = (*tsysoff)(IPosition(1,0));
632 Vector<Float> specon, tsyson;
633 outtsysCol.get(i, tsyson);
634 outspecCol.get(i, specon);
635 Vector<uChar> flagon;
636 outflagCol.get(i, flagon);
637 MaskedArray<Float> mon = maskedArray(specon, flagon);
638 MaskedArray<Float> moff = maskedArray(*specoff, *flagoff);
639 MaskedArray<Float> quot = (tsysoffscalar * mon / moff);
640 if (preserve) {
641 quot -= tsysoffscalar;
642 } else {
643 quot -= tsyson[0];
644 }
645 outspecCol.put(i, quot.getArray());
646 outflagCol.put(i, flagsFromMA(quot));
647 }
648 // renumber scanno
649 TableIterator it(tout, "SCANNO");
650 uInt i = 0;
651 while ( !it.pastEnd() ) {
652 Table t = it.table();
653 TableVector<uInt> vec(t, "SCANNO");
654 vec = i;
655 ++i;
656 ++it;
657 }
658 return out;
659}
660
661
662CountedPtr< Scantable > STMath::quotient( const CountedPtr< Scantable > & on,
663 const CountedPtr< Scantable > & off,
664 bool preserve )
665{
666 bool insitu = insitu_;
667 if ( ! on->conformant(*off) ) {
668 throw(AipsError("'on' and 'off' scantables are not conformant."));
669 }
670 setInsitu(false);
671 CountedPtr< Scantable > out = getScantable(on, false);
672 setInsitu(insitu);
673 Table& tout = out->table();
674 const Table& toff = off->table();
675 TableIterator sit(tout, "SCANNO");
676 TableIterator s2it(toff, "SCANNO");
677 while ( !sit.pastEnd() ) {
678 Table ton = sit.table();
679 TableRow row(ton);
680 Table t = s2it.table();
681 ArrayColumn<Float> outspecCol(ton, "SPECTRA");
682 ROArrayColumn<Float> outtsysCol(ton, "TSYS");
683 ArrayColumn<uChar> outflagCol(ton, "FLAGTRA");
684 for (uInt i=0; i < ton.nrow(); ++i) {
685 const TableRecord& rec = row.get(i);
686 Table offsel = t( t.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
687 && t.col("IFNO") == Int(rec.asuInt("IFNO"))
688 && t.col("POLNO") == Int(rec.asuInt("POLNO")) );
689 if ( offsel.nrow() == 0 )
690 throw AipsError("STMath::quotient: no matching off");
691 TableRow offrow(offsel);
692 const TableRecord& offrec = offrow.get(0);//should be ncycles - take first
693 RORecordFieldPtr< Array<Float> > specoff(offrec, "SPECTRA");
694 RORecordFieldPtr< Array<Float> > tsysoff(offrec, "TSYS");
695 RORecordFieldPtr< Array<uChar> > flagoff(offrec, "FLAGTRA");
696 Float tsysoffscalar = (*tsysoff)(IPosition(1,0));
697 Vector<Float> specon, tsyson;
698 outtsysCol.get(i, tsyson);
699 outspecCol.get(i, specon);
700 Vector<uChar> flagon;
701 outflagCol.get(i, flagon);
702 MaskedArray<Float> mon = maskedArray(specon, flagon);
703 MaskedArray<Float> moff = maskedArray(*specoff, *flagoff);
704 MaskedArray<Float> quot = (tsysoffscalar * mon / moff);
705 if (preserve) {
706 quot -= tsysoffscalar;
707 } else {
708 quot -= tsyson[0];
709 }
710 outspecCol.put(i, quot.getArray());
711 outflagCol.put(i, flagsFromMA(quot));
712 }
713 ++sit;
714 ++s2it;
715 // take the first off for each on scan which doesn't have a
716 // matching off scan
717 // non <= noff: matching pairs, non > noff matching pairs then first off
718 if ( s2it.pastEnd() ) s2it.reset();
719 }
720 return out;
721}
722
723// dototalpower (migration of GBTIDL procedure dototalpower.pro)
724// calibrate the CAL on-off pair. It calculate Tsys and average CAL on-off subintegrations
725// do it for each cycles in a specific scan.
726CountedPtr< Scantable > STMath::dototalpower( const CountedPtr< Scantable >& calon,
727 const CountedPtr< Scantable >& caloff, Float tcal )
728{
729if ( ! calon->conformant(*caloff) ) {
730 throw(AipsError("'CAL on' and 'CAL off' scantables are not conformant."));
731 }
732 setInsitu(false);
733 CountedPtr< Scantable > out = getScantable(caloff, false);
734 Table& tout = out->table();
735 const Table& tcon = calon->table();
736 Vector<Float> tcalout;
737 Vector<Float> tcalout2; //debug
738
739 if ( tout.nrow() != tcon.nrow() ) {
740 throw(AipsError("Mismatch in number of rows to form cal on - off pair."));
741 }
742 // iteration by scanno or cycle no.
743 TableIterator sit(tout, "SCANNO");
744 TableIterator s2it(tcon, "SCANNO");
745 while ( !sit.pastEnd() ) {
746 Table toff = sit.table();
747 TableRow row(toff);
748 Table t = s2it.table();
749 ScalarColumn<Double> outintCol(toff, "INTERVAL");
750 ArrayColumn<Float> outspecCol(toff, "SPECTRA");
751 ArrayColumn<Float> outtsysCol(toff, "TSYS");
752 ArrayColumn<uChar> outflagCol(toff, "FLAGTRA");
753 ROScalarColumn<uInt> outtcalIdCol(toff, "TCAL_ID");
754 ROScalarColumn<uInt> outpolCol(toff, "POLNO");
755 ROScalarColumn<Double> onintCol(t, "INTERVAL");
756 ROArrayColumn<Float> onspecCol(t, "SPECTRA");
757 ROArrayColumn<Float> ontsysCol(t, "TSYS");
758 ROArrayColumn<uChar> onflagCol(t, "FLAGTRA");
759 //ROScalarColumn<uInt> ontcalIdCol(t, "TCAL_ID");
760
761 for (uInt i=0; i < toff.nrow(); ++i) {
762 //skip these checks -> assumes the data order are the same between the cal on off pairs
763 //
764 Vector<Float> specCalon, specCaloff;
765 // to store scalar (mean) tsys
766 Vector<Float> tsysout(1);
767 uInt tcalId, polno;
768 Double offint, onint;
769 outpolCol.get(i, polno);
770 outspecCol.get(i, specCaloff);
771 onspecCol.get(i, specCalon);
772 Vector<uChar> flagCaloff, flagCalon;
773 outflagCol.get(i, flagCaloff);
774 onflagCol.get(i, flagCalon);
775 outtcalIdCol.get(i, tcalId);
776 outintCol.get(i, offint);
777 onintCol.get(i, onint);
778 // caluculate mean Tsys
779 uInt nchan = specCaloff.nelements();
780 // percentage of edge cut off
781 uInt pc = 10;
782 uInt bchan = nchan/pc;
783 uInt echan = nchan-bchan;
784
785 Slicer chansl(IPosition(1,bchan-1), IPosition(1,echan-1), IPosition(1,1),Slicer::endIsLast);
786 Vector<Float> testsubsp = specCaloff(chansl);
787 MaskedArray<Float> spoff = maskedArray( specCaloff(chansl),flagCaloff(chansl) );
788 MaskedArray<Float> spon = maskedArray( specCalon(chansl),flagCalon(chansl) );
789 MaskedArray<Float> spdiff = spon-spoff;
790 uInt noff = spoff.nelementsValid();
791 //uInt non = spon.nelementsValid();
792 uInt ndiff = spdiff.nelementsValid();
793 Float meantsys;
794
795/**
796 Double subspec, subdiff;
797 uInt usednchan;
798 subspec = 0;
799 subdiff = 0;
800 usednchan = 0;
801 for(uInt k=(bchan-1); k<echan; k++) {
802 subspec += specCaloff[k];
803 subdiff += static_cast<Double>(specCalon[k]-specCaloff[k]);
804 ++usednchan;
805 }
806**/
807 // get tcal if input tcal <= 0
808 String tcalt;
809 Float tcalUsed;
810 tcalUsed = tcal;
811 if ( tcal <= 0.0 ) {
812 caloff->tcal().getEntry(tcalt, tcalout, tcalId);
813 if (polno<=3) {
814 tcalUsed = tcalout[polno];
815 }
816 else {
817 tcalUsed = tcalout[0];
818 }
819 }
820
821 Float meanoff;
822 Float meandiff;
823 if (noff && ndiff) {
824 //Debug
825 //if(noff!=ndiff) cerr<<"noff and ndiff is not equal"<<endl;
826 //LogIO os( LogOrigin( "STMath", "dototalpower()", WHERE ) ) ;
827 //if(noff!=ndiff) os<<"noff and ndiff is not equal"<<LogIO::POST;
828 meanoff = sum(spoff)/noff;
829 meandiff = sum(spdiff)/ndiff;
830 meantsys= (meanoff/meandiff )*tcalUsed + tcalUsed/2;
831 }
832 else {
833 meantsys=1;
834 }
835
836 tsysout[0] = Float(meantsys);
837 MaskedArray<Float> mcaloff = maskedArray(specCaloff, flagCaloff);
838 MaskedArray<Float> mcalon = maskedArray(specCalon, flagCalon);
839 MaskedArray<Float> sig = Float(0.5) * (mcaloff + mcalon);
840 //uInt ncaloff = mcaloff.nelementsValid();
841 //uInt ncalon = mcalon.nelementsValid();
842
843 outintCol.put(i, offint+onint);
844 outspecCol.put(i, sig.getArray());
845 outflagCol.put(i, flagsFromMA(sig));
846 outtsysCol.put(i, tsysout);
847 }
848 ++sit;
849 ++s2it;
850 }
851 return out;
852}
853
854//dosigref - migrated from GBT IDL's dosigref.pro, do calibration of position switch
855// observatiions.
856// input: sig and ref scantables, and an optional boxcar smoothing width(default width=0,
857// no smoothing).
858// output: resultant scantable [= (sig-ref/ref)*tsys]
859CountedPtr< Scantable > STMath::dosigref( const CountedPtr < Scantable >& sig,
860 const CountedPtr < Scantable >& ref,
861 int smoothref,
862 casa::Float tsysv,
863 casa::Float tau )
864{
865if ( ! ref->conformant(*sig) ) {
866 throw(AipsError("'sig' and 'ref' scantables are not conformant."));
867 }
868 setInsitu(false);
869 CountedPtr< Scantable > out = getScantable(sig, false);
870 CountedPtr< Scantable > smref;
871 if ( smoothref > 1 ) {
872 float fsmoothref = static_cast<float>(smoothref);
873 std::string inkernel = "boxcar";
874 smref = smooth(ref, inkernel, fsmoothref );
875 ostringstream oss;
876 oss<<"Applied smoothing of "<<fsmoothref<<" on the reference."<<endl;
877 pushLog(String(oss));
878 }
879 else {
880 smref = ref;
881 }
882 Table& tout = out->table();
883 const Table& tref = smref->table();
884 if ( tout.nrow() != tref.nrow() ) {
885 throw(AipsError("Mismatch in number of rows to form on-source and reference pair."));
886 }
887 // iteration by scanno? or cycle no.
888 TableIterator sit(tout, "SCANNO");
889 TableIterator s2it(tref, "SCANNO");
890 while ( !sit.pastEnd() ) {
891 Table ton = sit.table();
892 Table t = s2it.table();
893 ScalarColumn<Double> outintCol(ton, "INTERVAL");
894 ArrayColumn<Float> outspecCol(ton, "SPECTRA");
895 ArrayColumn<Float> outtsysCol(ton, "TSYS");
896 ArrayColumn<uChar> outflagCol(ton, "FLAGTRA");
897 ArrayColumn<Float> refspecCol(t, "SPECTRA");
898 ROScalarColumn<Double> refintCol(t, "INTERVAL");
899 ROArrayColumn<Float> reftsysCol(t, "TSYS");
900 ArrayColumn<uChar> refflagCol(t, "FLAGTRA");
901 ROScalarColumn<Float> refelevCol(t, "ELEVATION");
902 for (uInt i=0; i < ton.nrow(); ++i) {
903
904 Double onint, refint;
905 Vector<Float> specon, specref;
906 // to store scalar (mean) tsys
907 Vector<Float> tsysref;
908 outintCol.get(i, onint);
909 refintCol.get(i, refint);
910 outspecCol.get(i, specon);
911 refspecCol.get(i, specref);
912 Vector<uChar> flagref, flagon;
913 outflagCol.get(i, flagon);
914 refflagCol.get(i, flagref);
915 reftsysCol.get(i, tsysref);
916
917 Float tsysrefscalar;
918 if ( tsysv > 0.0 ) {
919 ostringstream oss;
920 Float elev;
921 refelevCol.get(i, elev);
922 oss << "user specified Tsys = " << tsysv;
923 // do recalc elevation if EL = 0
924 if ( elev == 0 ) {
925 throw(AipsError("EL=0, elevation data is missing."));
926 } else {
927 if ( tau <= 0.0 ) {
928 throw(AipsError("Valid tau is not supplied."));
929 } else {
930 tsysrefscalar = tsysv * exp(tau/elev);
931 }
932 }
933 oss << ", corrected (for El) tsys= "<<tsysrefscalar;
934 pushLog(String(oss));
935 }
936 else {
937 tsysrefscalar = tsysref[0];
938 }
939 //get quotient spectrum
940 MaskedArray<Float> mref = maskedArray(specref, flagref);
941 MaskedArray<Float> mon = maskedArray(specon, flagon);
942 MaskedArray<Float> specres = tsysrefscalar*((mon - mref)/mref);
943 Double resint = onint*refint*smoothref/(onint+refint*smoothref);
944
945 //Debug
946 //cerr<<"Tsys used="<<tsysrefscalar<<endl;
947 //LogIO os( LogOrigin( "STMath", "dosigref", WHERE ) ) ;
948 //os<<"Tsys used="<<tsysrefscalar<<LogIO::POST;
949 // fill the result, replay signal tsys by reference tsys
950 outintCol.put(i, resint);
951 outspecCol.put(i, specres.getArray());
952 outflagCol.put(i, flagsFromMA(specres));
953 outtsysCol.put(i, tsysref);
954 }
955 ++sit;
956 ++s2it;
957 }
958 return out;
959}
960
961CountedPtr< Scantable > STMath::donod(const casa::CountedPtr<Scantable>& s,
962 const std::vector<int>& scans,
963 int smoothref,
964 casa::Float tsysv,
965 casa::Float tau,
966 casa::Float tcal )
967
968{
969 setInsitu(false);
970 STSelector sel;
971 std::vector<int> scan1, scan2, beams;
972 std::vector< vector<int> > scanpair;
973 std::vector<string> calstate;
974 String msg;
975
976 CountedPtr< Scantable > s1b1on, s1b1off, s1b2on, s1b2off;
977 CountedPtr< Scantable > s2b1on, s2b1off, s2b2on, s2b2off;
978
979 std::vector< CountedPtr< Scantable > > sctables;
980 sctables.push_back(s1b1on);
981 sctables.push_back(s1b1off);
982 sctables.push_back(s1b2on);
983 sctables.push_back(s1b2off);
984 sctables.push_back(s2b1on);
985 sctables.push_back(s2b1off);
986 sctables.push_back(s2b2on);
987 sctables.push_back(s2b2off);
988
989 //check scanlist
990 int n=s->checkScanInfo(scans);
991 if (n==1) {
992 throw(AipsError("Incorrect scan pairs. "));
993 }
994
995 // Assume scans contain only a pair of consecutive scan numbers.
996 // It is assumed that first beam, b1, is on target.
997 // There is no check if the first beam is on or not.
998 if ( scans.size()==1 ) {
999 scan1.push_back(scans[0]);
1000 scan2.push_back(scans[0]+1);
1001 } else if ( scans.size()==2 ) {
1002 scan1.push_back(scans[0]);
1003 scan2.push_back(scans[1]);
1004 } else {
1005 if ( scans.size()%2 == 0 ) {
1006 for (uInt i=0; i<scans.size(); i++) {
1007 if (i%2 == 0) {
1008 scan1.push_back(scans[i]);
1009 }
1010 else {
1011 scan2.push_back(scans[i]);
1012 }
1013 }
1014 } else {
1015 throw(AipsError("Odd numbers of scans, cannot form pairs."));
1016 }
1017 }
1018 scanpair.push_back(scan1);
1019 scanpair.push_back(scan2);
1020 calstate.push_back("*calon");
1021 calstate.push_back("*[^calon]");
1022 CountedPtr< Scantable > ws = getScantable(s, false);
1023 uInt l=0;
1024 while ( l < sctables.size() ) {
1025 for (uInt i=0; i < 2; i++) {
1026 for (uInt j=0; j < 2; j++) {
1027 for (uInt k=0; k < 2; k++) {
1028 sel.reset();
1029 sel.setScans(scanpair[i]);
1030 sel.setName(calstate[k]);
1031 beams.clear();
1032 beams.push_back(j);
1033 sel.setBeams(beams);
1034 ws->setSelection(sel);
1035 sctables[l]= getScantable(ws, false);
1036 l++;
1037 }
1038 }
1039 }
1040 }
1041
1042 // replace here by splitData or getData functionality
1043 CountedPtr< Scantable > sig1;
1044 CountedPtr< Scantable > ref1;
1045 CountedPtr< Scantable > sig2;
1046 CountedPtr< Scantable > ref2;
1047 CountedPtr< Scantable > calb1;
1048 CountedPtr< Scantable > calb2;
1049
1050 msg=String("Processing dototalpower for subset of the data");
1051 ostringstream oss1;
1052 oss1 << msg << endl;
1053 pushLog(String(oss1));
1054 // Debug for IRC CS data
1055 //float tcal1=7.0;
1056 //float tcal2=4.0;
1057 sig1 = dototalpower(sctables[0], sctables[1], tcal=tcal);
1058 ref1 = dototalpower(sctables[2], sctables[3], tcal=tcal);
1059 ref2 = dototalpower(sctables[4], sctables[5], tcal=tcal);
1060 sig2 = dototalpower(sctables[6], sctables[7], tcal=tcal);
1061
1062 // correction of user-specified tsys for elevation here
1063
1064 // dosigref calibration
1065 msg=String("Processing dosigref for subset of the data");
1066 ostringstream oss2;
1067 oss2 << msg << endl;
1068 pushLog(String(oss2));
1069 calb1=dosigref(sig1,ref2,smoothref,tsysv,tau);
1070 calb2=dosigref(sig2,ref1,smoothref,tsysv,tau);
1071
1072 // iteration by scanno or cycle no.
1073 Table& tcalb1 = calb1->table();
1074 Table& tcalb2 = calb2->table();
1075 TableIterator sit(tcalb1, "SCANNO");
1076 TableIterator s2it(tcalb2, "SCANNO");
1077 while ( !sit.pastEnd() ) {
1078 Table t1 = sit.table();
1079 Table t2= s2it.table();
1080 ArrayColumn<Float> outspecCol(t1, "SPECTRA");
1081 ArrayColumn<Float> outtsysCol(t1, "TSYS");
1082 ArrayColumn<uChar> outflagCol(t1, "FLAGTRA");
1083 ScalarColumn<Double> outintCol(t1, "INTERVAL");
1084 ArrayColumn<Float> t2specCol(t2, "SPECTRA");
1085 ROArrayColumn<Float> t2tsysCol(t2, "TSYS");
1086 ArrayColumn<uChar> t2flagCol(t2, "FLAGTRA");
1087 ROScalarColumn<Double> t2intCol(t2, "INTERVAL");
1088 for (uInt i=0; i < t1.nrow(); ++i) {
1089 Vector<Float> spec1, spec2;
1090 // to store scalar (mean) tsys
1091 Vector<Float> tsys1, tsys2;
1092 Vector<uChar> flag1, flag2;
1093 Double tint1, tint2;
1094 outspecCol.get(i, spec1);
1095 t2specCol.get(i, spec2);
1096 outflagCol.get(i, flag1);
1097 t2flagCol.get(i, flag2);
1098 outtsysCol.get(i, tsys1);
1099 t2tsysCol.get(i, tsys2);
1100 outintCol.get(i, tint1);
1101 t2intCol.get(i, tint2);
1102 // average
1103 // assume scalar tsys for weights
1104 Float wt1, wt2, tsyssq1, tsyssq2;
1105 tsyssq1 = tsys1[0]*tsys1[0];
1106 tsyssq2 = tsys2[0]*tsys2[0];
1107 wt1 = Float(tint1)/tsyssq1;
1108 wt2 = Float(tint2)/tsyssq2;
1109 Float invsumwt=1/(wt1+wt2);
1110 MaskedArray<Float> mspec1 = maskedArray(spec1, flag1);
1111 MaskedArray<Float> mspec2 = maskedArray(spec2, flag2);
1112 MaskedArray<Float> avspec = invsumwt * (wt1*mspec1 + wt2*mspec2);
1113 //Array<Float> avtsys = Float(0.5) * (tsys1 + tsys2);
1114 // cerr<< "Tsys1="<<tsys1<<" Tsys2="<<tsys2<<endl;
1115 // LogIO os( LogOrigin( "STMath", "donod", WHERE ) ) ;
1116 // os<< "Tsys1="<<tsys1<<" Tsys2="<<tsys2<<LogIO::POST;
1117 tsys1[0] = sqrt(tsyssq1 + tsyssq2);
1118 Array<Float> avtsys = tsys1;
1119
1120 outspecCol.put(i, avspec.getArray());
1121 outflagCol.put(i, flagsFromMA(avspec));
1122 outtsysCol.put(i, avtsys);
1123 }
1124 ++sit;
1125 ++s2it;
1126 }
1127 return calb1;
1128}
1129
1130//GBTIDL version of frequency switched data calibration
1131CountedPtr< Scantable > STMath::dofs( const CountedPtr< Scantable >& s,
1132 const std::vector<int>& scans,
1133 int smoothref,
1134 casa::Float tsysv,
1135 casa::Float tau,
1136 casa::Float tcal )
1137{
1138
1139
1140 STSelector sel;
1141 CountedPtr< Scantable > ws = getScantable(s, false);
1142 CountedPtr< Scantable > sig, sigwcal, ref, refwcal;
1143 CountedPtr< Scantable > calsig, calref, out, out1, out2;
1144 Bool nofold=False;
1145
1146 //split the data
1147 sel.setName("*_fs");
1148 ws->setSelection(sel);
1149 sig = getScantable(ws,false);
1150 sel.reset();
1151 sel.setName("*_fs_calon");
1152 ws->setSelection(sel);
1153 sigwcal = getScantable(ws,false);
1154 sel.reset();
1155 sel.setName("*_fsr");
1156 ws->setSelection(sel);
1157 ref = getScantable(ws,false);
1158 sel.reset();
1159 sel.setName("*_fsr_calon");
1160 ws->setSelection(sel);
1161 refwcal = getScantable(ws,false);
1162
1163 calsig = dototalpower(sigwcal, sig, tcal=tcal);
1164 calref = dototalpower(refwcal, ref, tcal=tcal);
1165
1166 out1=dosigref(calsig,calref,smoothref,tsysv,tau);
1167 out2=dosigref(calref,calsig,smoothref,tsysv,tau);
1168
1169 Table& tabout1=out1->table();
1170 Table& tabout2=out2->table();
1171 ROScalarColumn<uInt> freqidCol1(tabout1, "FREQ_ID");
1172 ScalarColumn<uInt> freqidCol2(tabout2, "FREQ_ID");
1173 ROArrayColumn<Float> specCol(tabout2, "SPECTRA");
1174 Vector<Float> spec; specCol.get(0, spec);
1175 uInt nchan = spec.nelements();
1176 uInt freqid1; freqidCol1.get(0,freqid1);
1177 uInt freqid2; freqidCol2.get(0,freqid2);
1178 Double rp1, rp2, rv1, rv2, inc1, inc2;
1179 out1->frequencies().getEntry(rp1, rv1, inc1, freqid1);
1180 out2->frequencies().getEntry(rp2, rv2, inc2, freqid2);
1181 //cerr << out1->frequencies().table().nrow() << " " << out2->frequencies().table().nrow() << endl ;
1182 //LogIO os( LogOrigin( "STMath", "dofs()", WHERE ) ) ;
1183 //os << out1->frequencies().table().nrow() << " " << out2->frequencies().table().nrow() << LogIO::POST ;
1184 if (rp1==rp2) {
1185 Double foffset = rv1 - rv2;
1186 uInt choffset = static_cast<uInt>(foffset/abs(inc2));
1187 if (choffset >= nchan) {
1188 //cerr<<"out-band frequency switching, no folding"<<endl;
1189 LogIO os( LogOrigin( "STMath", "dofs()", WHERE ) ) ;
1190 os<<"out-band frequency switching, no folding"<<LogIO::POST;
1191 nofold = True;
1192 }
1193 }
1194
1195 if (nofold) {
1196 std::vector< CountedPtr< Scantable > > tabs;
1197 tabs.push_back(out1);
1198 tabs.push_back(out2);
1199 out = merge(tabs);
1200 }
1201 else {
1202 //out = out1;
1203 Double choffset = ( rv1 - rv2 ) / inc2 ;
1204 out = dofold( out1, out2, choffset ) ;
1205 }
1206
1207 return out;
1208}
1209
1210CountedPtr<Scantable> STMath::dofold( const CountedPtr<Scantable> &sig,
1211 const CountedPtr<Scantable> &ref,
1212 Double choffset,
1213 Double choffset2 )
1214{
1215 LogIO os( LogOrigin( "STMath", "dofold", WHERE ) ) ;
1216 os << "choffset=" << choffset << " choffset2=" << choffset2 << LogIO::POST ;
1217
1218 // output scantable
1219 CountedPtr<Scantable> out = getScantable( sig, false ) ;
1220
1221 // separate choffset to integer part and decimal part
1222 Int ioffset = (Int)choffset ;
1223 Double doffset = choffset - ioffset ;
1224 Int ioffset2 = (Int)choffset2 ;
1225 Double doffset2 = choffset2 - ioffset2 ;
1226 os << "ioffset=" << ioffset << " doffset=" << doffset << LogIO::POST ;
1227 os << "ioffset2=" << ioffset2 << " doffset2=" << doffset2 << LogIO::POST ;
1228
1229 // get column
1230 ROArrayColumn<Float> specCol1( sig->table(), "SPECTRA" ) ;
1231 ROArrayColumn<Float> specCol2( ref->table(), "SPECTRA" ) ;
1232 ROArrayColumn<Float> tsysCol1( sig->table(), "TSYS" ) ;
1233 ROArrayColumn<Float> tsysCol2( ref->table(), "TSYS" ) ;
1234 ROArrayColumn<uChar> flagCol1( sig->table(), "FLAGTRA" ) ;
1235 ROArrayColumn<uChar> flagCol2( ref->table(), "FLAGTRA" ) ;
1236 ROScalarColumn<Double> mjdCol1( sig->table(), "TIME" ) ;
1237 ROScalarColumn<Double> mjdCol2( ref->table(), "TIME" ) ;
1238 ROScalarColumn<Double> intervalCol1( sig->table(), "INTERVAL" ) ;
1239 ROScalarColumn<Double> intervalCol2( ref->table(), "INTERVAL" ) ;
1240
1241 // check
1242 if ( ioffset == 0 ) {
1243 LogIO os( LogOrigin( "STMath", "dofold()", WHERE ) ) ;
1244 os << "channel offset is zero, no folding" << LogIO::POST ;
1245 return out ;
1246 }
1247 int nchan = ref->nchan() ;
1248 if ( abs(ioffset) >= nchan ) {
1249 LogIO os( LogOrigin( "STMath", "dofold()", WHERE ) ) ;
1250 os << "out-band frequency switching, no folding" << LogIO::POST ;
1251 return out ;
1252 }
1253
1254 // attach column for output scantable
1255 ArrayColumn<Float> specColOut( out->table(), "SPECTRA" ) ;
1256 ArrayColumn<uChar> flagColOut( out->table(), "FLAGTRA" ) ;
1257 ArrayColumn<Float> tsysColOut( out->table(), "TSYS" ) ;
1258 ScalarColumn<Double> mjdColOut( out->table(), "TIME" ) ;
1259 ScalarColumn<Double> intervalColOut( out->table(), "INTERVAL" ) ;
1260 ScalarColumn<uInt> fidColOut( out->table(), "FREQ_ID" ) ;
1261
1262 // for each row
1263 // assume that the data order are same between sig and ref
1264 RowAccumulator acc( asap::TINTSYS ) ;
1265 for ( int i = 0 ; i < sig->nrow() ; i++ ) {
1266 // get values
1267 Vector<Float> spsig ;
1268 specCol1.get( i, spsig ) ;
1269 Vector<Float> spref ;
1270 specCol2.get( i, spref ) ;
1271 Vector<Float> tsyssig ;
1272 tsysCol1.get( i, tsyssig ) ;
1273 Vector<Float> tsysref ;
1274 tsysCol2.get( i, tsysref ) ;
1275 Vector<uChar> flagsig ;
1276 flagCol1.get( i, flagsig ) ;
1277 Vector<uChar> flagref ;
1278 flagCol2.get( i, flagref ) ;
1279 Double timesig ;
1280 mjdCol1.get( i, timesig ) ;
1281 Double timeref ;
1282 mjdCol2.get( i, timeref ) ;
1283 Double intsig ;
1284 intervalCol1.get( i, intsig ) ;
1285 Double intref ;
1286 intervalCol2.get( i, intref ) ;
1287
1288 // shift reference spectra
1289 int refchan = spref.nelements() ;
1290 Vector<Float> sspref( spref.nelements() ) ;
1291 Vector<Float> stsysref( tsysref.nelements() ) ;
1292 Vector<uChar> sflagref( flagref.nelements() ) ;
1293 if ( ioffset > 0 ) {
1294 // SPECTRA and FLAGTRA
1295 for ( int j = 0 ; j < refchan-ioffset ; j++ ) {
1296 sspref[j] = spref[j+ioffset] ;
1297 sflagref[j] = flagref[j+ioffset] ;
1298 }
1299 for ( int j = refchan-ioffset ; j < refchan ; j++ ) {
1300 sspref[j] = spref[j-refchan+ioffset] ;
1301 sflagref[j] = flagref[j-refchan+ioffset] ;
1302 }
1303 spref = sspref.copy() ;
1304 flagref = sflagref.copy() ;
1305 for ( int j = 0 ; j < refchan - 1 ; j++ ) {
1306 sspref[j] = doffset * spref[j+1] + ( 1.0 - doffset ) * spref[j] ;
1307 sflagref[j] = flagref[j+1] + flagref[j] ;
1308 }
1309 sspref[refchan-1] = doffset * spref[0] + ( 1.0 - doffset ) * spref[refchan-1] ;
1310 sflagref[refchan-1] = flagref[0] + flagref[refchan-1] ;
1311
1312 // TSYS
1313 if ( spref.nelements() == tsysref.nelements() ) {
1314 for ( int j = 0 ; j < refchan-ioffset ; j++ ) {
1315 stsysref[j] = tsysref[j+ioffset] ;
1316 }
1317 for ( int j = refchan-ioffset ; j < refchan ; j++ ) {
1318 stsysref[j] = tsysref[j-refchan+ioffset] ;
1319 }
1320 tsysref = stsysref.copy() ;
1321 for ( int j = 0 ; j < refchan - 1 ; j++ ) {
1322 stsysref[j] = doffset * tsysref[j+1] + ( 1.0 - doffset ) * tsysref[j] ;
1323 }
1324 stsysref[refchan-1] = doffset * tsysref[0] + ( 1.0 - doffset ) * tsysref[refchan-1] ;
1325 }
1326 }
1327 else {
1328 // SPECTRA and FLAGTRA
1329 for ( int j = 0 ; j < abs(ioffset) ; j++ ) {
1330 sspref[j] = spref[refchan+ioffset+j] ;
1331 sflagref[j] = flagref[refchan+ioffset+j] ;
1332 }
1333 for ( int j = abs(ioffset) ; j < refchan ; j++ ) {
1334 sspref[j] = spref[j+ioffset] ;
1335 sflagref[j] = flagref[j+ioffset] ;
1336 }
1337 spref = sspref.copy() ;
1338 flagref = sflagref.copy() ;
1339 sspref[0] = doffset * spref[refchan-1] + ( 1.0 - doffset ) * spref[0] ;
1340 sflagref[0] = flagref[0] + flagref[refchan-1] ;
1341 for ( int j = 1 ; j < refchan ; j++ ) {
1342 sspref[j] = doffset * spref[j-1] + ( 1.0 - doffset ) * spref[j] ;
1343 sflagref[j] = flagref[j-1] + flagref[j] ;
1344 }
1345 // TSYS
1346 if ( spref.nelements() == tsysref.nelements() ) {
1347 for ( int j = 0 ; j < abs(ioffset) ; j++ ) {
1348 stsysref[j] = tsysref[refchan+ioffset+j] ;
1349 }
1350 for ( int j = abs(ioffset) ; j < refchan ; j++ ) {
1351 stsysref[j] = tsysref[j+ioffset] ;
1352 }
1353 tsysref = stsysref.copy() ;
1354 stsysref[0] = doffset * tsysref[refchan-1] + ( 1.0 - doffset ) * tsysref[0] ;
1355 for ( int j = 1 ; j < refchan ; j++ ) {
1356 stsysref[j] = doffset * tsysref[j-1] + ( 1.0 - doffset ) * tsysref[j] ;
1357 }
1358 }
1359 }
1360
1361 // shift signal spectra if necessary (only for APEX?)
1362 if ( choffset2 != 0.0 ) {
1363 int sigchan = spsig.nelements() ;
1364 Vector<Float> sspsig( spsig.nelements() ) ;
1365 Vector<Float> stsyssig( tsyssig.nelements() ) ;
1366 Vector<uChar> sflagsig( flagsig.nelements() ) ;
1367 if ( ioffset2 > 0 ) {
1368 // SPECTRA and FLAGTRA
1369 for ( int j = 0 ; j < sigchan-ioffset2 ; j++ ) {
1370 sspsig[j] = spsig[j+ioffset2] ;
1371 sflagsig[j] = flagsig[j+ioffset2] ;
1372 }
1373 for ( int j = sigchan-ioffset2 ; j < sigchan ; j++ ) {
1374 sspsig[j] = spsig[j-sigchan+ioffset2] ;
1375 sflagsig[j] = flagsig[j-sigchan+ioffset2] ;
1376 }
1377 spsig = sspsig.copy() ;
1378 flagsig = sflagsig.copy() ;
1379 for ( int j = 0 ; j < sigchan - 1 ; j++ ) {
1380 sspsig[j] = doffset2 * spsig[j+1] + ( 1.0 - doffset2 ) * spsig[j] ;
1381 sflagsig[j] = flagsig[j+1] || flagsig[j] ;
1382 }
1383 sspsig[sigchan-1] = doffset2 * spsig[0] + ( 1.0 - doffset2 ) * spsig[sigchan-1] ;
1384 sflagsig[sigchan-1] = flagsig[0] || flagsig[sigchan-1] ;
1385 // TSTS
1386 if ( spsig.nelements() == tsyssig.nelements() ) {
1387 for ( int j = 0 ; j < sigchan-ioffset2 ; j++ ) {
1388 stsyssig[j] = tsyssig[j+ioffset2] ;
1389 }
1390 for ( int j = sigchan-ioffset2 ; j < sigchan ; j++ ) {
1391 stsyssig[j] = tsyssig[j-sigchan+ioffset2] ;
1392 }
1393 tsyssig = stsyssig.copy() ;
1394 for ( int j = 0 ; j < sigchan - 1 ; j++ ) {
1395 stsyssig[j] = doffset2 * tsyssig[j+1] + ( 1.0 - doffset2 ) * tsyssig[j] ;
1396 }
1397 stsyssig[sigchan-1] = doffset2 * tsyssig[0] + ( 1.0 - doffset2 ) * tsyssig[sigchan-1] ;
1398 }
1399 }
1400 else {
1401 // SPECTRA and FLAGTRA
1402 for ( int j = 0 ; j < abs(ioffset2) ; j++ ) {
1403 sspsig[j] = spsig[sigchan+ioffset2+j] ;
1404 sflagsig[j] = flagsig[sigchan+ioffset2+j] ;
1405 }
1406 for ( int j = abs(ioffset2) ; j < sigchan ; j++ ) {
1407 sspsig[j] = spsig[j+ioffset2] ;
1408 sflagsig[j] = flagsig[j+ioffset2] ;
1409 }
1410 spsig = sspsig.copy() ;
1411 flagsig = sflagsig.copy() ;
1412 sspsig[0] = doffset2 * spsig[sigchan-1] + ( 1.0 - doffset2 ) * spsig[0] ;
1413 sflagsig[0] = flagsig[0] + flagsig[sigchan-1] ;
1414 for ( int j = 1 ; j < sigchan ; j++ ) {
1415 sspsig[j] = doffset2 * spsig[j-1] + ( 1.0 - doffset2 ) * spsig[j] ;
1416 sflagsig[j] = flagsig[j-1] + flagsig[j] ;
1417 }
1418 // TSYS
1419 if ( spsig.nelements() == tsyssig.nelements() ) {
1420 for ( int j = 0 ; j < abs(ioffset2) ; j++ ) {
1421 stsyssig[j] = tsyssig[sigchan+ioffset2+j] ;
1422 }
1423 for ( int j = abs(ioffset2) ; j < sigchan ; j++ ) {
1424 stsyssig[j] = tsyssig[j+ioffset2] ;
1425 }
1426 tsyssig = stsyssig.copy() ;
1427 stsyssig[0] = doffset2 * tsyssig[sigchan-1] + ( 1.0 - doffset2 ) * tsyssig[0] ;
1428 for ( int j = 1 ; j < sigchan ; j++ ) {
1429 stsyssig[j] = doffset2 * tsyssig[j-1] + ( 1.0 - doffset2 ) * tsyssig[j] ;
1430 }
1431 }
1432 }
1433 }
1434
1435 // folding
1436 acc.add( spsig, !flagsig, tsyssig, intsig, timesig ) ;
1437 acc.add( sspref, !sflagref, stsysref, intref, timeref ) ;
1438
1439 // put result
1440 specColOut.put( i, acc.getSpectrum() ) ;
1441 const Vector<Bool> &msk = acc.getMask() ;
1442 Vector<uChar> flg( msk.shape() ) ;
1443 convertArray( flg, !msk ) ;
1444 flagColOut.put( i, flg ) ;
1445 tsysColOut.put( i, acc.getTsys() ) ;
1446 intervalColOut.put( i, acc.getInterval() ) ;
1447 mjdColOut.put( i, acc.getTime() ) ;
1448 // change FREQ_ID to unshifted IF setting (only for APEX?)
1449 if ( choffset2 != 0.0 ) {
1450 int freqid = fidColOut( 0 ) ; // assume single-IF data
1451 double refpix, refval, increment ;
1452 out->frequencies().getEntry( refpix, refval, increment, freqid ) ;
1453 refval -= choffset * increment ;
1454 uInt newfreqid = out->frequencies().addEntry( refpix, refval, increment ) ;
1455 Vector<uInt> freqids = fidColOut.getColumn() ;
1456 for ( uInt j = 0 ; j < freqids.nelements() ; j++ ) {
1457 if ( freqids[j] == freqid )
1458 freqids[j] = newfreqid ;
1459 }
1460 fidColOut.putColumn( freqids ) ;
1461 }
1462
1463 acc.reset() ;
1464 }
1465
1466 return out ;
1467}
1468
1469
1470CountedPtr< Scantable > STMath::freqSwitch( const CountedPtr< Scantable >& in )
1471{
1472 // make copy or reference
1473 CountedPtr< Scantable > out = getScantable(in, false);
1474 Table& tout = out->table();
1475 Block<String> cols(4);
1476 cols[0] = String("SCANNO");
1477 cols[1] = String("CYCLENO");
1478 cols[2] = String("BEAMNO");
1479 cols[3] = String("POLNO");
1480 TableIterator iter(tout, cols);
1481 while (!iter.pastEnd()) {
1482 Table subt = iter.table();
1483 // this should leave us with two rows for the two IFs....if not ignore
1484 if (subt.nrow() != 2 ) {
1485 continue;
1486 }
1487 ArrayColumn<Float> specCol(subt, "SPECTRA");
1488 ArrayColumn<Float> tsysCol(subt, "TSYS");
1489 ArrayColumn<uChar> flagCol(subt, "FLAGTRA");
1490 Vector<Float> onspec,offspec, ontsys, offtsys;
1491 Vector<uChar> onflag, offflag;
1492 tsysCol.get(0, ontsys); tsysCol.get(1, offtsys);
1493 specCol.get(0, onspec); specCol.get(1, offspec);
1494 flagCol.get(0, onflag); flagCol.get(1, offflag);
1495 MaskedArray<Float> on = maskedArray(onspec, onflag);
1496 MaskedArray<Float> off = maskedArray(offspec, offflag);
1497 MaskedArray<Float> oncopy = on.copy();
1498
1499 on /= off; on -= 1.0f;
1500 on *= ontsys[0];
1501 off /= oncopy; off -= 1.0f;
1502 off *= offtsys[0];
1503 specCol.put(0, on.getArray());
1504 const Vector<Bool>& m0 = on.getMask();
1505 Vector<uChar> flags0(m0.shape());
1506 convertArray(flags0, !m0);
1507 flagCol.put(0, flags0);
1508
1509 specCol.put(1, off.getArray());
1510 const Vector<Bool>& m1 = off.getMask();
1511 Vector<uChar> flags1(m1.shape());
1512 convertArray(flags1, !m1);
1513 flagCol.put(1, flags1);
1514 ++iter;
1515 }
1516
1517 return out;
1518}
1519
1520std::vector< float > STMath::statistic( const CountedPtr< Scantable > & in,
1521 const std::vector< bool > & mask,
1522 const std::string& which )
1523{
1524
1525 Vector<Bool> m(mask);
1526 const Table& tab = in->table();
1527 ROArrayColumn<Float> specCol(tab, "SPECTRA");
1528 ROArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1529 std::vector<float> out;
1530 for (uInt i=0; i < tab.nrow(); ++i ) {
1531 Vector<Float> spec; specCol.get(i, spec);
1532 Vector<uChar> flag; flagCol.get(i, flag);
1533 MaskedArray<Float> ma = maskedArray(spec, flag);
1534 float outstat = 0.0;
1535 if ( spec.nelements() == m.nelements() ) {
1536 outstat = mathutil::statistics(which, ma(m));
1537 } else {
1538 outstat = mathutil::statistics(which, ma);
1539 }
1540 out.push_back(outstat);
1541 }
1542 return out;
1543}
1544
1545std::vector< int > STMath::minMaxChan( const CountedPtr< Scantable > & in,
1546 const std::vector< bool > & mask,
1547 const std::string& which )
1548{
1549
1550 Vector<Bool> m(mask);
1551 const Table& tab = in->table();
1552 ROArrayColumn<Float> specCol(tab, "SPECTRA");
1553 ROArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1554 std::vector<int> out;
1555 for (uInt i=0; i < tab.nrow(); ++i ) {
1556 Vector<Float> spec; specCol.get(i, spec);
1557 Vector<uChar> flag; flagCol.get(i, flag);
1558 MaskedArray<Float> ma = maskedArray(spec, flag);
1559 if (ma.ndim() != 1) {
1560 throw (ArrayError(
1561 "std::vector<int> STMath::minMaxChan("
1562 "ContedPtr<Scantable> &in, std::vector<bool> &mask, "
1563 " std::string &which)"
1564 " - MaskedArray is not 1D"));
1565 }
1566 IPosition outpos(1,0);
1567 if ( spec.nelements() == m.nelements() ) {
1568 outpos = mathutil::minMaxPos(which, ma(m));
1569 } else {
1570 outpos = mathutil::minMaxPos(which, ma);
1571 }
1572 out.push_back(outpos[0]);
1573 }
1574 return out;
1575}
1576
1577CountedPtr< Scantable > STMath::bin( const CountedPtr< Scantable > & in,
1578 int width )
1579{
1580 if ( !in->getSelection().empty() ) throw(AipsError("Can't bin subset of the data."));
1581 CountedPtr< Scantable > out = getScantable(in, false);
1582 Table& tout = out->table();
1583 out->frequencies().rescale(width, "BIN");
1584 ArrayColumn<Float> specCol(tout, "SPECTRA");
1585 ArrayColumn<uChar> flagCol(tout, "FLAGTRA");
1586 for (uInt i=0; i < tout.nrow(); ++i ) {
1587 MaskedArray<Float> main = maskedArray(specCol(i), flagCol(i));
1588 MaskedArray<Float> maout;
1589 LatticeUtilities::bin(maout, main, 0, Int(width));
1590 /// @todo implement channel based tsys binning
1591 specCol.put(i, maout.getArray());
1592 flagCol.put(i, flagsFromMA(maout));
1593 // take only the first binned spectrum's length for the deprecated
1594 // global header item nChan
1595 if (i==0) tout.rwKeywordSet().define(String("nChan"),
1596 Int(maout.getArray().nelements()));
1597 }
1598 return out;
1599}
1600
1601CountedPtr< Scantable > STMath::resample( const CountedPtr< Scantable >& in,
1602 const std::string& method,
1603 float width )
1604//
1605// Should add the possibility of width being specified in km/s. This means
1606// that for each freqID (SpectralCoordinate) we will need to convert to an
1607// average channel width (say at the reference pixel). Then we would need
1608// to be careful to make sure each spectrum (of different freqID)
1609// is the same length.
1610//
1611{
1612 //InterpolateArray1D<Double,Float>::InterpolationMethod interp;
1613 Int interpMethod(stringToIMethod(method));
1614
1615 CountedPtr< Scantable > out = getScantable(in, false);
1616 Table& tout = out->table();
1617
1618// Resample SpectralCoordinates (one per freqID)
1619 out->frequencies().rescale(width, "RESAMPLE");
1620 TableIterator iter(tout, "IFNO");
1621 TableRow row(tout);
1622 while ( !iter.pastEnd() ) {
1623 Table tab = iter.table();
1624 ArrayColumn<Float> specCol(tab, "SPECTRA");
1625 //ArrayColumn<Float> tsysCol(tout, "TSYS");
1626 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1627 Vector<Float> spec;
1628 Vector<uChar> flag;
1629 specCol.get(0,spec); // the number of channels should be constant per IF
1630 uInt nChanIn = spec.nelements();
1631 Vector<Float> xIn(nChanIn); indgen(xIn);
1632 Int fac = Int(nChanIn/width);
1633 Vector<Float> xOut(fac+10); // 10 to be safe - resize later
1634 uInt k = 0;
1635 Float x = 0.0;
1636 while (x < Float(nChanIn) ) {
1637 xOut(k) = x;
1638 k++;
1639 x += width;
1640 }
1641 uInt nChanOut = k;
1642 xOut.resize(nChanOut, True);
1643 // process all rows for this IFNO
1644 Vector<Float> specOut;
1645 Vector<Bool> maskOut;
1646 Vector<uChar> flagOut;
1647 for (uInt i=0; i < tab.nrow(); ++i) {
1648 specCol.get(i, spec);
1649 flagCol.get(i, flag);
1650 Vector<Bool> mask(flag.nelements());
1651 convertArray(mask, flag);
1652
1653 IPosition shapeIn(spec.shape());
1654 //sh.nchan = nChanOut;
1655 InterpolateArray1D<Float,Float>::interpolate(specOut, maskOut, xOut,
1656 xIn, spec, mask,
1657 interpMethod, True, True);
1658 /// @todo do the same for channel based Tsys
1659 flagOut.resize(maskOut.nelements());
1660 convertArray(flagOut, maskOut);
1661 specCol.put(i, specOut);
1662 flagCol.put(i, flagOut);
1663 }
1664 ++iter;
1665 }
1666
1667 return out;
1668}
1669
1670STMath::imethod STMath::stringToIMethod(const std::string& in)
1671{
1672 static STMath::imap lookup;
1673
1674 // initialize the lookup table if necessary
1675 if ( lookup.empty() ) {
1676 lookup["nearest"] = InterpolateArray1D<Double,Float>::nearestNeighbour;
1677 lookup["linear"] = InterpolateArray1D<Double,Float>::linear;
1678 lookup["cubic"] = InterpolateArray1D<Double,Float>::cubic;
1679 lookup["spline"] = InterpolateArray1D<Double,Float>::spline;
1680 }
1681
1682 STMath::imap::const_iterator iter = lookup.find(in);
1683
1684 if ( lookup.end() == iter ) {
1685 std::string message = in;
1686 message += " is not a valid interpolation mode";
1687 throw(AipsError(message));
1688 }
1689 return iter->second;
1690}
1691
1692WeightType STMath::stringToWeight(const std::string& in)
1693{
1694 static std::map<std::string, WeightType> lookup;
1695
1696 // initialize the lookup table if necessary
1697 if ( lookup.empty() ) {
1698 lookup["NONE"] = asap::NONE;
1699 lookup["TINT"] = asap::TINT;
1700 lookup["TINTSYS"] = asap::TINTSYS;
1701 lookup["TSYS"] = asap::TSYS;
1702 lookup["VAR"] = asap::VAR;
1703 }
1704
1705 std::map<std::string, WeightType>::const_iterator iter = lookup.find(in);
1706
1707 if ( lookup.end() == iter ) {
1708 std::string message = in;
1709 message += " is not a valid weighting mode";
1710 throw(AipsError(message));
1711 }
1712 return iter->second;
1713}
1714
1715CountedPtr< Scantable > STMath::gainElevation( const CountedPtr< Scantable >& in,
1716 const vector< float > & coeff,
1717 const std::string & filename,
1718 const std::string& method)
1719{
1720 // Get elevation data from Scantable and convert to degrees
1721 CountedPtr< Scantable > out = getScantable(in, false);
1722 Table& tab = out->table();
1723 ROScalarColumn<Float> elev(tab, "ELEVATION");
1724 Vector<Float> x = elev.getColumn();
1725 x *= Float(180 / C::pi); // Degrees
1726
1727 Vector<Float> coeffs(coeff);
1728 const uInt nc = coeffs.nelements();
1729 if ( filename.length() > 0 && nc > 0 ) {
1730 throw(AipsError("You must choose either polynomial coefficients or an ascii file, not both"));
1731 }
1732
1733 // Correct
1734 if ( nc > 0 || filename.length() == 0 ) {
1735 // Find instrument
1736 Bool throwit = True;
1737 Instrument inst =
1738 STAttr::convertInstrument(tab.keywordSet().asString("AntennaName"),
1739 throwit);
1740
1741 // Set polynomial
1742 Polynomial<Float>* ppoly = 0;
1743 Vector<Float> coeff;
1744 String msg;
1745 if ( nc > 0 ) {
1746 ppoly = new Polynomial<Float>(nc);
1747 coeff = coeffs;
1748 msg = String("user");
1749 } else {
1750 STAttr sdAttr;
1751 coeff = sdAttr.gainElevationPoly(inst);
1752 ppoly = new Polynomial<Float>(3);
1753 msg = String("built in");
1754 }
1755
1756 if ( coeff.nelements() > 0 ) {
1757 ppoly->setCoefficients(coeff);
1758 } else {
1759 delete ppoly;
1760 throw(AipsError("There is no known gain-elevation polynomial known for this instrument"));
1761 }
1762 ostringstream oss;
1763 oss << "Making polynomial correction with " << msg << " coefficients:" << endl;
1764 oss << " " << coeff;
1765 pushLog(String(oss));
1766 const uInt nrow = tab.nrow();
1767 Vector<Float> factor(nrow);
1768 for ( uInt i=0; i < nrow; ++i ) {
1769 factor[i] = 1.0 / (*ppoly)(x[i]);
1770 }
1771 delete ppoly;
1772 scaleByVector(tab, factor, true);
1773
1774 } else {
1775 // Read and correct
1776 pushLog("Making correction from ascii Table");
1777 scaleFromAsciiTable(tab, filename, method, x, true);
1778 }
1779 return out;
1780}
1781
1782void STMath::scaleFromAsciiTable(Table& in, const std::string& filename,
1783 const std::string& method,
1784 const Vector<Float>& xout, bool dotsys)
1785{
1786
1787// Read gain-elevation ascii file data into a Table.
1788
1789 String formatString;
1790 Table tbl = readAsciiTable(formatString, Table::Memory, filename, "", "", False);
1791 scaleFromTable(in, tbl, method, xout, dotsys);
1792}
1793
1794void STMath::scaleFromTable(Table& in,
1795 const Table& table,
1796 const std::string& method,
1797 const Vector<Float>& xout, bool dotsys)
1798{
1799
1800 ROScalarColumn<Float> geElCol(table, "ELEVATION");
1801 ROScalarColumn<Float> geFacCol(table, "FACTOR");
1802 Vector<Float> xin = geElCol.getColumn();
1803 Vector<Float> yin = geFacCol.getColumn();
1804 Vector<Bool> maskin(xin.nelements(),True);
1805
1806 // Interpolate (and extrapolate) with desired method
1807
1808 InterpolateArray1D<Double,Float>::InterpolationMethod interp = stringToIMethod(method);
1809
1810 Vector<Float> yout;
1811 Vector<Bool> maskout;
1812 InterpolateArray1D<Float,Float>::interpolate(yout, maskout, xout,
1813 xin, yin, maskin, interp,
1814 True, True);
1815
1816 scaleByVector(in, Float(1.0)/yout, dotsys);
1817}
1818
1819void STMath::scaleByVector( Table& in,
1820 const Vector< Float >& factor,
1821 bool dotsys )
1822{
1823 uInt nrow = in.nrow();
1824 if ( factor.nelements() != nrow ) {
1825 throw(AipsError("factors.nelements() != table.nelements()"));
1826 }
1827 ArrayColumn<Float> specCol(in, "SPECTRA");
1828 ArrayColumn<uChar> flagCol(in, "FLAGTRA");
1829 ArrayColumn<Float> tsysCol(in, "TSYS");
1830 for (uInt i=0; i < nrow; ++i) {
1831 MaskedArray<Float> ma = maskedArray(specCol(i), flagCol(i));
1832 ma *= factor[i];
1833 specCol.put(i, ma.getArray());
1834 flagCol.put(i, flagsFromMA(ma));
1835 if ( dotsys ) {
1836 Vector<Float> tsys = tsysCol(i);
1837 tsys *= factor[i];
1838 tsysCol.put(i,tsys);
1839 }
1840 }
1841}
1842
1843CountedPtr< Scantable > STMath::convertFlux( const CountedPtr< Scantable >& in,
1844 float d, float etaap,
1845 float jyperk )
1846{
1847 CountedPtr< Scantable > out = getScantable(in, false);
1848 Table& tab = in->table();
1849 Unit fluxUnit(tab.keywordSet().asString("FluxUnit"));
1850 Unit K(String("K"));
1851 Unit JY(String("Jy"));
1852
1853 bool tokelvin = true;
1854 Double cfac = 1.0;
1855
1856 if ( fluxUnit == JY ) {
1857 pushLog("Converting to K");
1858 Quantum<Double> t(1.0,fluxUnit);
1859 Quantum<Double> t2 = t.get(JY);
1860 cfac = (t2 / t).getValue(); // value to Jy
1861
1862 tokelvin = true;
1863 out->setFluxUnit("K");
1864 } else if ( fluxUnit == K ) {
1865 pushLog("Converting to Jy");
1866 Quantum<Double> t(1.0,fluxUnit);
1867 Quantum<Double> t2 = t.get(K);
1868 cfac = (t2 / t).getValue(); // value to K
1869
1870 tokelvin = false;
1871 out->setFluxUnit("Jy");
1872 } else {
1873 throw(AipsError("Unrecognized brightness units in Table - must be consistent with Jy or K"));
1874 }
1875 // Make sure input values are converted to either Jy or K first...
1876 Float factor = cfac;
1877
1878 // Select method
1879 if (jyperk > 0.0) {
1880 factor *= jyperk;
1881 if ( tokelvin ) factor = 1.0 / jyperk;
1882 ostringstream oss;
1883 oss << "Jy/K = " << jyperk;
1884 pushLog(String(oss));
1885 Vector<Float> factors(tab.nrow(), factor);
1886 scaleByVector(tab,factors, false);
1887 } else if ( etaap > 0.0) {
1888 if (d < 0) {
1889 Instrument inst =
1890 STAttr::convertInstrument(tab.keywordSet().asString("AntennaName"),
1891 True);
1892 STAttr sda;
1893 d = sda.diameter(inst);
1894 }
1895 jyperk = STAttr::findJyPerK(etaap, d);
1896 ostringstream oss;
1897 oss << "Jy/K = " << jyperk;
1898 pushLog(String(oss));
1899 factor *= jyperk;
1900 if ( tokelvin ) {
1901 factor = 1.0 / factor;
1902 }
1903 Vector<Float> factors(tab.nrow(), factor);
1904 scaleByVector(tab, factors, False);
1905 } else {
1906
1907 // OK now we must deal with automatic look up of values.
1908 // We must also deal with the fact that the factors need
1909 // to be computed per IF and may be different and may
1910 // change per integration.
1911
1912 pushLog("Looking up conversion factors");
1913 convertBrightnessUnits(out, tokelvin, cfac);
1914 }
1915
1916 return out;
1917}
1918
1919void STMath::convertBrightnessUnits( CountedPtr<Scantable>& in,
1920 bool tokelvin, float cfac )
1921{
1922 Table& table = in->table();
1923 Instrument inst =
1924 STAttr::convertInstrument(table.keywordSet().asString("AntennaName"), True);
1925 TableIterator iter(table, "FREQ_ID");
1926 STFrequencies stfreqs = in->frequencies();
1927 STAttr sdAtt;
1928 while (!iter.pastEnd()) {
1929 Table tab = iter.table();
1930 ArrayColumn<Float> specCol(tab, "SPECTRA");
1931 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1932 ROScalarColumn<uInt> freqidCol(tab, "FREQ_ID");
1933 MEpoch::ROScalarColumn timeCol(tab, "TIME");
1934
1935 uInt freqid; freqidCol.get(0, freqid);
1936 Vector<Float> tmpspec; specCol.get(0, tmpspec);
1937 // STAttr.JyPerK has a Vector interface... change sometime.
1938 Vector<Float> freqs(1,stfreqs.getRefFreq(freqid, tmpspec.nelements()));
1939 for ( uInt i=0; i<tab.nrow(); ++i) {
1940 Float jyperk = (sdAtt.JyPerK(inst, timeCol(i), freqs))[0];
1941 Float factor = cfac * jyperk;
1942 if ( tokelvin ) factor = Float(1.0) / factor;
1943 MaskedArray<Float> ma = maskedArray(specCol(i), flagCol(i));
1944 ma *= factor;
1945 specCol.put(i, ma.getArray());
1946 flagCol.put(i, flagsFromMA(ma));
1947 }
1948 ++iter;
1949 }
1950}
1951
1952CountedPtr< Scantable > STMath::opacity( const CountedPtr< Scantable > & in,
1953 float tau )
1954{
1955 CountedPtr< Scantable > out = getScantable(in, false);
1956
1957 Table tab = out->table();
1958 ROScalarColumn<Float> elev(tab, "ELEVATION");
1959 ArrayColumn<Float> specCol(tab, "SPECTRA");
1960 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1961 ArrayColumn<Float> tsysCol(tab, "TSYS");
1962 for ( uInt i=0; i<tab.nrow(); ++i) {
1963 Float zdist = Float(C::pi_2) - elev(i);
1964 Float factor = exp(tau/cos(zdist));
1965 MaskedArray<Float> ma = maskedArray(specCol(i), flagCol(i));
1966 ma *= factor;
1967 specCol.put(i, ma.getArray());
1968 flagCol.put(i, flagsFromMA(ma));
1969 Vector<Float> tsys;
1970 tsysCol.get(i, tsys);
1971 tsys *= factor;
1972 tsysCol.put(i, tsys);
1973 }
1974 return out;
1975}
1976
1977CountedPtr< Scantable > STMath::smoothOther( const CountedPtr< Scantable >& in,
1978 const std::string& kernel,
1979 float width )
1980{
1981 CountedPtr< Scantable > out = getScantable(in, false);
1982 Table& table = out->table();
1983 ArrayColumn<Float> specCol(table, "SPECTRA");
1984 ArrayColumn<uChar> flagCol(table, "FLAGTRA");
1985 Vector<Float> spec;
1986 Vector<uChar> flag;
1987 for ( uInt i=0; i<table.nrow(); ++i) {
1988 specCol.get(i, spec);
1989 flagCol.get(i, flag);
1990 Vector<Bool> mask(flag.nelements());
1991 convertArray(mask, flag);
1992 Vector<Float> specout;
1993 Vector<Bool> maskout;
1994 if ( kernel == "hanning" ) {
1995 mathutil::hanning(specout, maskout, spec , !mask);
1996 convertArray(flag, !maskout);
1997 } else if ( kernel == "rmedian" ) {
1998 mathutil::runningMedian(specout, maskout, spec , mask, width);
1999 convertArray(flag, maskout);
2000 }
2001 flagCol.put(i, flag);
2002 specCol.put(i, specout);
2003 }
2004 return out;
2005}
2006
2007CountedPtr< Scantable > STMath::smooth( const CountedPtr< Scantable >& in,
2008 const std::string& kernel, float width )
2009{
2010 if (kernel == "rmedian" || kernel == "hanning") {
2011 return smoothOther(in, kernel, width);
2012 }
2013 CountedPtr< Scantable > out = getScantable(in, false);
2014 Table& table = out->table();
2015 VectorKernel::KernelTypes type = VectorKernel::toKernelType(kernel);
2016 // same IFNO should have same no of channels
2017 // this saves overhead
2018 TableIterator iter(table, "IFNO");
2019 while (!iter.pastEnd()) {
2020 Table tab = iter.table();
2021 ArrayColumn<Float> specCol(tab, "SPECTRA");
2022 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
2023 Vector<Float> tmpspec; specCol.get(0, tmpspec);
2024 uInt nchan = tmpspec.nelements();
2025 Vector<Float> kvec = VectorKernel::make(type, width, nchan, True, False);
2026 Convolver<Float> conv(kvec, IPosition(1,nchan));
2027 Vector<Float> spec;
2028 Vector<uChar> flag;
2029 for ( uInt i=0; i<tab.nrow(); ++i) {
2030 specCol.get(i, spec);
2031 flagCol.get(i, flag);
2032 Vector<Bool> mask(flag.nelements());
2033 convertArray(mask, flag);
2034 Vector<Float> specout;
2035 mathutil::replaceMaskByZero(specout, mask);
2036 conv.linearConv(specout, spec);
2037 specCol.put(i, specout);
2038 }
2039 ++iter;
2040 }
2041 return out;
2042}
2043
2044CountedPtr< Scantable >
2045 STMath::merge( const std::vector< CountedPtr < Scantable > >& in )
2046{
2047 if ( in.size() < 2 ) {
2048 throw(AipsError("Need at least two scantables to perform a merge."));
2049 }
2050 std::vector<CountedPtr < Scantable > >::const_iterator it = in.begin();
2051 bool insitu = insitu_;
2052 setInsitu(false);
2053 CountedPtr< Scantable > out = getScantable(*it, false);
2054 setInsitu(insitu);
2055 Table& tout = out->table();
2056 ScalarColumn<uInt> freqidcol(tout,"FREQ_ID"), molidcol(tout, "MOLECULE_ID");
2057 ScalarColumn<uInt> scannocol(tout,"SCANNO"), focusidcol(tout,"FOCUS_ID");
2058 // Renumber SCANNO to be 0-based
2059 Vector<uInt> scannos = scannocol.getColumn();
2060 uInt offset = min(scannos);
2061 scannos -= offset;
2062 scannocol.putColumn(scannos);
2063 uInt newscanno = max(scannos)+1;
2064 ++it;
2065 while ( it != in.end() ){
2066 if ( ! (*it)->conformant(*out) ) {
2067 // non conformant.
2068 pushLog(String("Warning: Can't merge scantables as header info differs."));
2069 }
2070 out->appendToHistoryTable((*it)->history());
2071 const Table& tab = (*it)->table();
2072 TableIterator scanit(tab, "SCANNO");
2073 while (!scanit.pastEnd()) {
2074 TableIterator freqit(scanit.table(), "FREQ_ID");
2075 while ( !freqit.pastEnd() ) {
2076 Table thetab = freqit.table();
2077 uInt nrow = tout.nrow();
2078 tout.addRow(thetab.nrow());
2079 TableCopy::copyRows(tout, thetab, nrow, 0, thetab.nrow());
2080 ROTableRow row(thetab);
2081 for ( uInt i=0; i<thetab.nrow(); ++i) {
2082 uInt k = nrow+i;
2083 scannocol.put(k, newscanno);
2084 const TableRecord& rec = row.get(i);
2085 Double rv,rp,inc;
2086 (*it)->frequencies().getEntry(rp, rv, inc, rec.asuInt("FREQ_ID"));
2087 uInt id;
2088 id = out->frequencies().addEntry(rp, rv, inc);
2089 freqidcol.put(k,id);
2090 //String name,fname;Double rf;
2091 Vector<String> name,fname;Vector<Double> rf;
2092 (*it)->molecules().getEntry(rf, name, fname, rec.asuInt("MOLECULE_ID"));
2093 id = out->molecules().addEntry(rf, name, fname);
2094 molidcol.put(k, id);
2095 Float frot,fax,ftan,fhand,fmount,fuser, fxy, fxyp;
2096 (*it)->focus().getEntry(fax, ftan, frot, fhand,
2097 fmount,fuser, fxy, fxyp,
2098 rec.asuInt("FOCUS_ID"));
2099 id = out->focus().addEntry(fax, ftan, frot, fhand,
2100 fmount,fuser, fxy, fxyp);
2101 focusidcol.put(k, id);
2102 }
2103 ++freqit;
2104 }
2105 ++newscanno;
2106 ++scanit;
2107 }
2108 ++it;
2109 }
2110 return out;
2111}
2112
2113CountedPtr< Scantable >
2114 STMath::invertPhase( const CountedPtr < Scantable >& in )
2115{
2116 return applyToPol(in, &STPol::invertPhase, Float(0.0));
2117}
2118
2119CountedPtr< Scantable >
2120 STMath::rotateXYPhase( const CountedPtr < Scantable >& in, float phase )
2121{
2122 return applyToPol(in, &STPol::rotatePhase, Float(phase));
2123}
2124
2125CountedPtr< Scantable >
2126 STMath::rotateLinPolPhase( const CountedPtr < Scantable >& in, float phase )
2127{
2128 return applyToPol(in, &STPol::rotateLinPolPhase, Float(phase));
2129}
2130
2131CountedPtr< Scantable > STMath::applyToPol( const CountedPtr<Scantable>& in,
2132 STPol::polOperation fptr,
2133 Float phase )
2134{
2135 CountedPtr< Scantable > out = getScantable(in, false);
2136 Table& tout = out->table();
2137 Block<String> cols(4);
2138 cols[0] = String("SCANNO");
2139 cols[1] = String("BEAMNO");
2140 cols[2] = String("IFNO");
2141 cols[3] = String("CYCLENO");
2142 TableIterator iter(tout, cols);
2143 CountedPtr<STPol> stpol = STPol::getPolClass(out->factories_,
2144 out->getPolType() );
2145 while (!iter.pastEnd()) {
2146 Table t = iter.table();
2147 ArrayColumn<Float> speccol(t, "SPECTRA");
2148 ScalarColumn<uInt> focidcol(t, "FOCUS_ID");
2149 ScalarColumn<Float> parancol(t, "PARANGLE");
2150 Matrix<Float> pols(speccol.getColumn());
2151 try {
2152 stpol->setSpectra(pols);
2153 Float fang,fhand,parang;
2154 fang = in->focusTable_.getTotalFeedAngle(focidcol(0));
2155 fhand = in->focusTable_.getFeedHand(focidcol(0));
2156 parang = parancol(0);
2157 /// @todo re-enable this
2158 // disable total feed angle to support paralactifying Caswell style
2159 stpol->setPhaseCorrections(parang, -parang, fhand);
2160 // use a member function pointer in STPol. This only works on
2161 // the STPol pointer itself, not the Counted Pointer so
2162 // derefernce it.
2163 (&(*(stpol))->*fptr)(phase);
2164 speccol.putColumn(stpol->getSpectra());
2165 } catch (AipsError& e) {
2166 //delete stpol;stpol=0;
2167 throw(e);
2168 }
2169 ++iter;
2170 }
2171 //delete stpol;stpol=0;
2172 return out;
2173}
2174
2175CountedPtr< Scantable >
2176 STMath::swapPolarisations( const CountedPtr< Scantable > & in )
2177{
2178 CountedPtr< Scantable > out = getScantable(in, false);
2179 Table& tout = out->table();
2180 Table t0 = tout(tout.col("POLNO") == 0);
2181 Table t1 = tout(tout.col("POLNO") == 1);
2182 if ( t0.nrow() != t1.nrow() )
2183 throw(AipsError("Inconsistent number of polarisations"));
2184 ArrayColumn<Float> speccol0(t0, "SPECTRA");
2185 ArrayColumn<uChar> flagcol0(t0, "FLAGTRA");
2186 ArrayColumn<Float> speccol1(t1, "SPECTRA");
2187 ArrayColumn<uChar> flagcol1(t1, "FLAGTRA");
2188 Matrix<Float> s0 = speccol0.getColumn();
2189 Matrix<uChar> f0 = flagcol0.getColumn();
2190 speccol0.putColumn(speccol1.getColumn());
2191 flagcol0.putColumn(flagcol1.getColumn());
2192 speccol1.putColumn(s0);
2193 flagcol1.putColumn(f0);
2194 return out;
2195}
2196
2197CountedPtr< Scantable >
2198 STMath::averagePolarisations( const CountedPtr< Scantable > & in,
2199 const std::vector<bool>& mask,
2200 const std::string& weight )
2201{
2202 if (in->npol() < 2 )
2203 throw(AipsError("averagePolarisations can only be applied to two or more"
2204 "polarisations"));
2205 bool insitu = insitu_;
2206 setInsitu(false);
2207 CountedPtr< Scantable > pols = getScantable(in, true);
2208 setInsitu(insitu);
2209 Table& tout = pols->table();
2210 std::string taql = "SELECT FROM $1 WHERE POLNO IN [0,1]";
2211 Table tab = tableCommand(taql, in->table());
2212 if (tab.nrow() == 0 )
2213 throw(AipsError("Could not find any rows with POLNO==0 and POLNO==1"));
2214 TableCopy::copyRows(tout, tab);
2215 TableVector<uInt> vec(tout, "POLNO");
2216 vec = 0;
2217 pols->table_.rwKeywordSet().define("nPol", Int(1));
2218 //pols->table_.rwKeywordSet().define("POLTYPE", String("stokes"));
2219 pols->table_.rwKeywordSet().define("POLTYPE", in->getPolType());
2220 std::vector<CountedPtr<Scantable> > vpols;
2221 vpols.push_back(pols);
2222 CountedPtr< Scantable > out = average(vpols, mask, weight, "SCAN");
2223 return out;
2224}
2225
2226CountedPtr< Scantable >
2227 STMath::averageBeams( const CountedPtr< Scantable > & in,
2228 const std::vector<bool>& mask,
2229 const std::string& weight )
2230{
2231 bool insitu = insitu_;
2232 setInsitu(false);
2233 CountedPtr< Scantable > beams = getScantable(in, false);
2234 setInsitu(insitu);
2235 Table& tout = beams->table();
2236 // give all rows the same BEAMNO
2237 TableVector<uInt> vec(tout, "BEAMNO");
2238 vec = 0;
2239 beams->table_.rwKeywordSet().define("nBeam", Int(1));
2240 std::vector<CountedPtr<Scantable> > vbeams;
2241 vbeams.push_back(beams);
2242 CountedPtr< Scantable > out = average(vbeams, mask, weight, "SCAN");
2243 return out;
2244}
2245
2246
2247CountedPtr< Scantable >
2248 asap::STMath::frequencyAlign( const CountedPtr< Scantable > & in,
2249 const std::string & refTime,
2250 const std::string & method)
2251{
2252 // clone as this is not working insitu
2253 bool insitu = insitu_;
2254 setInsitu(false);
2255 CountedPtr< Scantable > out = getScantable(in, false);
2256 setInsitu(insitu);
2257 Table& tout = out->table();
2258 // Get reference Epoch to time of first row or given String
2259 Unit DAY(String("d"));
2260 MEpoch::Ref epochRef(in->getTimeReference());
2261 MEpoch refEpoch;
2262 if (refTime.length()>0) {
2263 Quantum<Double> qt;
2264 if (MVTime::read(qt,refTime)) {
2265 MVEpoch mv(qt);
2266 refEpoch = MEpoch(mv, epochRef);
2267 } else {
2268 throw(AipsError("Invalid format for Epoch string"));
2269 }
2270 } else {
2271 refEpoch = in->timeCol_(0);
2272 }
2273 MPosition refPos = in->getAntennaPosition();
2274
2275 InterpolateArray1D<Double,Float>::InterpolationMethod interp = stringToIMethod(method);
2276 /*
2277 // Comment from MV.
2278 // the following code has been commented out because different FREQ_IDs have to be aligned together even
2279 // if the frame doesn't change. So far, lack of this check didn't cause any problems.
2280 // test if user frame is different to base frame
2281 if ( in->frequencies().getFrameString(true)
2282 == in->frequencies().getFrameString(false) ) {
2283 throw(AipsError("Can't convert as no output frame has been set"
2284 " (use set_freqframe) or it is aligned already."));
2285 }
2286 */
2287 MFrequency::Types system = in->frequencies().getFrame();
2288 MVTime mvt(refEpoch.getValue());
2289 String epochout = mvt.string(MVTime::YMD) + String(" (") + refEpoch.getRefString() + String(")");
2290 ostringstream oss;
2291 oss << "Aligned at reference Epoch " << epochout
2292 << " in frame " << MFrequency::showType(system);
2293 pushLog(String(oss));
2294 // set up the iterator
2295 Block<String> cols(4);
2296 // select by constant direction
2297 cols[0] = String("SRCNAME");
2298 cols[1] = String("BEAMNO");
2299 // select by IF ( no of channels varies over this )
2300 cols[2] = String("IFNO");
2301 // select by restfrequency
2302 cols[3] = String("MOLECULE_ID");
2303 TableIterator iter(tout, cols);
2304 while ( !iter.pastEnd() ) {
2305 Table t = iter.table();
2306 MDirection::ROScalarColumn dirCol(t, "DIRECTION");
2307 TableIterator fiter(t, "FREQ_ID");
2308 // determine nchan from the first row. This should work as
2309 // we are iterating over BEAMNO and IFNO // we should have constant direction
2310
2311 ROArrayColumn<Float> sCol(t, "SPECTRA");
2312 const MDirection direction = dirCol(0);
2313 const uInt nchan = sCol(0).nelements();
2314
2315 // skip operations if there is nothing to align
2316 if (fiter.pastEnd()) {
2317 continue;
2318 }
2319
2320 Table ftab = fiter.table();
2321 // align all frequency ids with respect to the first encountered id
2322 ScalarColumn<uInt> freqidCol(ftab, "FREQ_ID");
2323 // get the SpectralCoordinate for the freqid, which we are iterating over
2324 SpectralCoordinate sC = in->frequencies().getSpectralCoordinate(freqidCol(0));
2325 FrequencyAligner<Float> fa( sC, nchan, refEpoch,
2326 direction, refPos, system );
2327 // realign the SpectralCoordinate and put into the output Scantable
2328 Vector<String> units(1);
2329 units = String("Hz");
2330 Bool linear=True;
2331 SpectralCoordinate sc2 = fa.alignedSpectralCoordinate(linear);
2332 sc2.setWorldAxisUnits(units);
2333 const uInt id = out->frequencies().addEntry(sc2.referencePixel()[0],
2334 sc2.referenceValue()[0],
2335 sc2.increment()[0]);
2336 while ( !fiter.pastEnd() ) {
2337 ftab = fiter.table();
2338 // spectral coordinate for the current FREQ_ID
2339 ScalarColumn<uInt> freqidCol2(ftab, "FREQ_ID");
2340 sC = in->frequencies().getSpectralCoordinate(freqidCol2(0));
2341 // create the "global" abcissa for alignment with same FREQ_ID
2342 Vector<Double> abc(nchan);
2343 for (uInt i=0; i<nchan; i++) {
2344 Double w;
2345 sC.toWorld(w,Double(i));
2346 abc[i] = w;
2347 }
2348 TableVector<uInt> tvec(ftab, "FREQ_ID");
2349 // assign new frequency id to all rows
2350 tvec = id;
2351 // cache abcissa for same time stamps, so iterate over those
2352 TableIterator timeiter(ftab, "TIME");
2353 while ( !timeiter.pastEnd() ) {
2354 Table tab = timeiter.table();
2355 ArrayColumn<Float> specCol(tab, "SPECTRA");
2356 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
2357 MEpoch::ROScalarColumn timeCol(tab, "TIME");
2358 // use align abcissa cache after the first row
2359 // these rows should be just be POLNO
2360 bool first = true;
2361 for (int i=0; i<int(tab.nrow()); ++i) {
2362 // input values
2363 Vector<uChar> flag = flagCol(i);
2364 Vector<Bool> mask(flag.shape());
2365 Vector<Float> specOut, spec;
2366 spec = specCol(i);
2367 Vector<Bool> maskOut;Vector<uChar> flagOut;
2368 convertArray(mask, flag);
2369 // alignment
2370 Bool ok = fa.align(specOut, maskOut, abc, spec,
2371 mask, timeCol(i), !first,
2372 interp, False);
2373 // back into scantable
2374 flagOut.resize(maskOut.nelements());
2375 convertArray(flagOut, maskOut);
2376 flagCol.put(i, flagOut);
2377 specCol.put(i, specOut);
2378 // start abcissa caching
2379 first = false;
2380 }
2381 // next timestamp
2382 ++timeiter;
2383 }
2384 // next FREQ_ID
2385 ++fiter;
2386 }
2387 // next aligner
2388 ++iter;
2389 }
2390 // set this afterwards to ensure we are doing insitu correctly.
2391 out->frequencies().setFrame(system, true);
2392 return out;
2393}
2394
2395CountedPtr<Scantable>
2396 asap::STMath::convertPolarisation( const CountedPtr<Scantable>& in,
2397 const std::string & newtype )
2398{
2399 if (in->npol() != 2 && in->npol() != 4)
2400 throw(AipsError("Can only convert two or four polarisations."));
2401 if ( in->getPolType() == newtype )
2402 throw(AipsError("No need to convert."));
2403 if ( ! in->selector_.empty() )
2404 throw(AipsError("Can only convert whole scantable. Unset the selection."));
2405 bool insitu = insitu_;
2406 setInsitu(false);
2407 CountedPtr< Scantable > out = getScantable(in, true);
2408 setInsitu(insitu);
2409 Table& tout = out->table();
2410 tout.rwKeywordSet().define("POLTYPE", String(newtype));
2411
2412 Block<String> cols(4);
2413 cols[0] = "SCANNO";
2414 cols[1] = "CYCLENO";
2415 cols[2] = "BEAMNO";
2416 cols[3] = "IFNO";
2417 TableIterator it(in->originalTable_, cols);
2418 String basetype = in->getPolType();
2419 STPol* stpol = STPol::getPolClass(in->factories_, basetype);
2420 try {
2421 while ( !it.pastEnd() ) {
2422 Table tab = it.table();
2423 uInt row = tab.rowNumbers()[0];
2424 stpol->setSpectra(in->getPolMatrix(row));
2425 Float fang,fhand,parang;
2426 fang = in->focusTable_.getTotalFeedAngle(in->mfocusidCol_(row));
2427 fhand = in->focusTable_.getFeedHand(in->mfocusidCol_(row));
2428 parang = in->paraCol_(row);
2429 /// @todo re-enable this
2430 // disable total feed angle to support paralactifying Caswell style
2431 stpol->setPhaseCorrections(parang, -parang, fhand);
2432 Int npolout = 0;
2433 for (uInt i=0; i<tab.nrow(); ++i) {
2434 Vector<Float> outvec = stpol->getSpectrum(i, newtype);
2435 if ( outvec.nelements() > 0 ) {
2436 tout.addRow();
2437 TableCopy::copyRows(tout, tab, tout.nrow()-1, 0, 1);
2438 ArrayColumn<Float> sCol(tout,"SPECTRA");
2439 ScalarColumn<uInt> pCol(tout,"POLNO");
2440 sCol.put(tout.nrow()-1 ,outvec);
2441 pCol.put(tout.nrow()-1 ,uInt(npolout));
2442 npolout++;
2443 }
2444 }
2445 tout.rwKeywordSet().define("nPol", npolout);
2446 ++it;
2447 }
2448 } catch (AipsError& e) {
2449 delete stpol;
2450 throw(e);
2451 }
2452 delete stpol;
2453 return out;
2454}
2455
2456CountedPtr< Scantable >
2457 asap::STMath::mxExtract( const CountedPtr< Scantable > & in,
2458 const std::string & scantype )
2459{
2460 bool insitu = insitu_;
2461 setInsitu(false);
2462 CountedPtr< Scantable > out = getScantable(in, true);
2463 setInsitu(insitu);
2464 Table& tout = out->table();
2465 std::string taql = "SELECT FROM $1 WHERE BEAMNO != REFBEAMNO";
2466 if (scantype == "on") {
2467 taql = "SELECT FROM $1 WHERE BEAMNO == REFBEAMNO";
2468 }
2469 Table tab = tableCommand(taql, in->table());
2470 TableCopy::copyRows(tout, tab);
2471 if (scantype == "on") {
2472 // re-index SCANNO to 0
2473 TableVector<uInt> vec(tout, "SCANNO");
2474 vec = 0;
2475 }
2476 return out;
2477}
2478
2479CountedPtr< Scantable >
2480 asap::STMath::lagFlag( const CountedPtr< Scantable > & in,
2481 double frequency, double width )
2482{
2483 CountedPtr< Scantable > out = getScantable(in, false);
2484 Table& tout = out->table();
2485 TableIterator iter(tout, "FREQ_ID");
2486 FFTServer<Float,Complex> ffts;
2487 while ( !iter.pastEnd() ) {
2488 Table tab = iter.table();
2489 Double rp,rv,inc;
2490 ROTableRow row(tab);
2491 const TableRecord& rec = row.get(0);
2492 uInt freqid = rec.asuInt("FREQ_ID");
2493 out->frequencies().getEntry(rp, rv, inc, freqid);
2494 ArrayColumn<Float> specCol(tab, "SPECTRA");
2495 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
2496 for (int i=0; i<int(tab.nrow()); ++i) {
2497 Vector<Float> spec = specCol(i);
2498 Vector<uChar> flag = flagCol(i);
2499 Int lag0 = Int(spec.nelements()*abs(inc)/(frequency+width)+0.5);
2500 Int lag1 = Int(spec.nelements()*abs(inc)/(frequency-width)+0.5);
2501 for (int k=0; k < flag.nelements(); ++k ) {
2502 if (flag[k] > 0) {
2503 spec[k] = 0.0;
2504 }
2505 }
2506 Vector<Complex> lags;
2507 ffts.fft0(lags, spec);
2508 Int start = max(0, lag0);
2509 Int end = min(Int(lags.nelements()-1), lag1);
2510 if (start == end) {
2511 lags[start] = Complex(0.0);
2512 } else {
2513 for (int j=start; j <=end ;++j) {
2514 lags[j] = Complex(0.0);
2515 }
2516 }
2517 ffts.fft0(spec, lags);
2518 specCol.put(i, spec);
2519 }
2520 ++iter;
2521 }
2522 return out;
2523}
2524
2525// Averaging spectra with different channel/resolution
2526CountedPtr<Scantable>
2527STMath::new_average( const std::vector<CountedPtr<Scantable> >& in,
2528 const bool& compel,
2529 const std::vector<bool>& mask,
2530 const std::string& weight,
2531 const std::string& avmode )
2532 throw ( casa::AipsError )
2533{
2534 LogIO os( LogOrigin( "STMath", "new_average()", WHERE ) ) ;
2535 if ( avmode == "SCAN" && in.size() != 1 )
2536 throw(AipsError("Can't perform 'SCAN' averaging on multiple tables.\n"
2537 "Use merge first."));
2538
2539 // check if OTF observation
2540 String obstype = in[0]->getHeader().obstype ;
2541 Double tol = 0.0 ;
2542 if ( obstype.find( "OTF" ) != String::npos ) {
2543 tol = TOL_OTF ;
2544 }
2545 else {
2546 tol = TOL_POINT ;
2547 }
2548
2549 CountedPtr<Scantable> out ; // processed result
2550 if ( compel ) {
2551 std::vector< CountedPtr<Scantable> > newin ; // input for average process
2552 uInt insize = in.size() ; // number of input scantables
2553
2554 // TEST: do normal average in each table before IF grouping
2555 os << "Do preliminary averaging" << LogIO::POST ;
2556 vector< CountedPtr<Scantable> > tmpin( insize ) ;
2557 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2558 vector< CountedPtr<Scantable> > v( 1, in[itable] ) ;
2559 tmpin[itable] = average( v, mask, weight, avmode ) ;
2560 }
2561
2562 // warning
2563 os << "Average spectra with different spectral resolution" << LogIO::POST ;
2564
2565 // temporarily set coordinfo
2566 vector<string> oldinfo( insize ) ;
2567 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2568 vector<string> coordinfo = in[itable]->getCoordInfo() ;
2569 oldinfo[itable] = coordinfo[0] ;
2570 coordinfo[0] = "Hz" ;
2571 tmpin[itable]->setCoordInfo( coordinfo ) ;
2572 }
2573
2574 // columns
2575 ScalarColumn<uInt> freqIDCol ;
2576 ScalarColumn<uInt> ifnoCol ;
2577 ScalarColumn<uInt> scannoCol ;
2578
2579
2580 // check IF frequency coverage
2581 // freqid: list of FREQ_ID, which is used, in each table
2582 // iffreq: list of minimum and maximum frequency for each FREQ_ID in
2583 // each table
2584 // freqid[insize][numIF]
2585 // freqid: [[id00, id01, ...],
2586 // [id10, id11, ...],
2587 // ...
2588 // [idn0, idn1, ...]]
2589 // iffreq[insize][numIF*2]
2590 // iffreq: [[min_id00, max_id00, min_id01, max_id01, ...],
2591 // [min_id10, max_id10, min_id11, max_id11, ...],
2592 // ...
2593 // [min_idn0, max_idn0, min_idn1, max_idn1, ...]]
2594 //os << "Check IF settings in each table" << LogIO::POST ;
2595 vector< vector<uInt> > freqid( insize );
2596 vector< vector<double> > iffreq( insize ) ;
2597 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2598 uInt rows = tmpin[itable]->nrow() ;
2599 uInt freqnrows = tmpin[itable]->frequencies().table().nrow() ;
2600 for ( uInt irow = 0 ; irow < rows ; irow++ ) {
2601 if ( freqid[itable].size() == freqnrows ) {
2602 break ;
2603 }
2604 else {
2605 freqIDCol.attach( tmpin[itable]->table(), "FREQ_ID" ) ;
2606 ifnoCol.attach( tmpin[itable]->table(), "IFNO" ) ;
2607 uInt id = freqIDCol( irow ) ;
2608 if ( freqid[itable].size() == 0 || count( freqid[itable].begin(), freqid[itable].end(), id ) == 0 ) {
2609 //os << "itable = " << itable << ": IF " << id << " is included in the list" << LogIO::POST ;
2610 vector<double> abcissa = tmpin[itable]->getAbcissa( irow ) ;
2611 freqid[itable].push_back( id ) ;
2612 iffreq[itable].push_back( abcissa[0] - 0.5 * ( abcissa[1] - abcissa[0] ) ) ;
2613 iffreq[itable].push_back( abcissa[abcissa.size()-1] + 0.5 * ( abcissa[1] - abcissa[0] ) ) ;
2614 }
2615 }
2616 }
2617 }
2618
2619 // debug
2620 //os << "IF settings summary:" << endl ;
2621 //for ( uInt i = 0 ; i < freqid.size() ; i++ ) {
2622 //os << " Table" << i << endl ;
2623 //for ( uInt j = 0 ; j < freqid[i].size() ; j++ ) {
2624 //os << " id = " << freqid[i][j] << " (min,max) = (" << iffreq[i][2*j] << "," << iffreq[i][2*j+1] << ")" << endl ;
2625 //}
2626 //}
2627 //os << endl ;
2628 //os.post() ;
2629
2630 // IF grouping based on their frequency coverage
2631 // ifgrp: list of table index and FREQ_ID for all members in each IF group
2632 // ifgfreq: list of minimum and maximum frequency in each IF group
2633 // ifgrp[numgrp][nummember*2]
2634 // ifgrp: [[table00, freqrow00, table01, freqrow01, ...],
2635 // [table10, freqrow10, table11, freqrow11, ...],
2636 // ...
2637 // [tablen0, freqrown0, tablen1, freqrown1, ...]]
2638 // ifgfreq[numgrp*2]
2639 // ifgfreq: [min0_grp0, max0_grp0, min1_grp1, max1_grp1, ...]
2640 //os << "IF grouping based on their frequency coverage" << LogIO::POST ;
2641 vector< vector<uInt> > ifgrp ;
2642 vector<double> ifgfreq ;
2643
2644 // parameter for IF grouping
2645 // groupmode = OR retrieve all region
2646 // AND only retrieve overlaped region
2647 //string groupmode = "AND" ;
2648 string groupmode = "OR" ;
2649 uInt sizecr = 0 ;
2650 if ( groupmode == "AND" )
2651 sizecr = 2 ;
2652 else if ( groupmode == "OR" )
2653 sizecr = 0 ;
2654
2655 vector<double> sortedfreq ;
2656 for ( uInt i = 0 ; i < iffreq.size() ; i++ ) {
2657 for ( uInt j = 0 ; j < iffreq[i].size() ; j++ ) {
2658 if ( count( sortedfreq.begin(), sortedfreq.end(), iffreq[i][j] ) == 0 )
2659 sortedfreq.push_back( iffreq[i][j] ) ;
2660 }
2661 }
2662 sort( sortedfreq.begin(), sortedfreq.end() ) ;
2663 for ( vector<double>::iterator i = sortedfreq.begin() ; i != sortedfreq.end()-1 ; i++ ) {
2664 ifgfreq.push_back( *i ) ;
2665 ifgfreq.push_back( *(i+1) ) ;
2666 }
2667 ifgrp.resize( ifgfreq.size()/2 ) ;
2668 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2669 for ( uInt iif = 0 ; iif < freqid[itable].size() ; iif++ ) {
2670 double range0 = iffreq[itable][2*iif] ;
2671 double range1 = iffreq[itable][2*iif+1] ;
2672 for ( uInt j = 0 ; j < ifgrp.size() ; j++ ) {
2673 double fmin = max( range0, ifgfreq[2*j] ) ;
2674 double fmax = min( range1, ifgfreq[2*j+1] ) ;
2675 if ( fmin < fmax ) {
2676 ifgrp[j].push_back( itable ) ;
2677 ifgrp[j].push_back( freqid[itable][iif] ) ;
2678 }
2679 }
2680 }
2681 }
2682 vector< vector<uInt> >::iterator fiter = ifgrp.begin() ;
2683 vector<double>::iterator giter = ifgfreq.begin() ;
2684 while( fiter != ifgrp.end() ) {
2685 if ( fiter->size() <= sizecr ) {
2686 fiter = ifgrp.erase( fiter ) ;
2687 giter = ifgfreq.erase( giter ) ;
2688 giter = ifgfreq.erase( giter ) ;
2689 }
2690 else {
2691 fiter++ ;
2692 advance( giter, 2 ) ;
2693 }
2694 }
2695
2696 // Grouping continuous IF groups (without frequency gap)
2697 // freqgrp: list of IF group indexes in each frequency group
2698 // freqrange: list of minimum and maximum frequency in each frequency group
2699 // freqgrp[numgrp][nummember]
2700 // freqgrp: [[ifgrp00, ifgrp01, ifgrp02, ...],
2701 // [ifgrp10, ifgrp11, ifgrp12, ...],
2702 // ...
2703 // [ifgrpn0, ifgrpn1, ifgrpn2, ...]]
2704 // freqrange[numgrp*2]
2705 // freqrange: [min_grp0, max_grp0, min_grp1, max_grp1, ...]
2706 vector< vector<uInt> > freqgrp ;
2707 double freqrange = 0.0 ;
2708 uInt grpnum = 0 ;
2709 for ( uInt i = 0 ; i < ifgrp.size() ; i++ ) {
2710 // Assumed that ifgfreq was sorted
2711 if ( grpnum != 0 && freqrange == ifgfreq[2*i] ) {
2712 freqgrp[grpnum-1].push_back( i ) ;
2713 }
2714 else {
2715 vector<uInt> grp0( 1, i ) ;
2716 freqgrp.push_back( grp0 ) ;
2717 grpnum++ ;
2718 }
2719 freqrange = ifgfreq[2*i+1] ;
2720 }
2721
2722
2723 // print IF groups
2724 ostringstream oss ;
2725 oss << "IF Group summary: " << endl ;
2726 oss << " GROUP_ID [FREQ_MIN, FREQ_MAX]: (TABLE_ID, FREQ_ID)" << endl ;
2727 for ( uInt i = 0 ; i < ifgrp.size() ; i++ ) {
2728 oss << " GROUP " << setw( 2 ) << i << " [" << ifgfreq[2*i] << "," << ifgfreq[2*i+1] << "]: " ;
2729 for ( uInt j = 0 ; j < ifgrp[i].size()/2 ; j++ ) {
2730 oss << "(" << ifgrp[i][2*j] << "," << ifgrp[i][2*j+1] << ") " ;
2731 }
2732 oss << endl ;
2733 }
2734 oss << endl ;
2735 os << oss.str() << LogIO::POST ;
2736
2737 // print frequency group
2738 oss.str("") ;
2739 oss << "Frequency Group summary: " << endl ;
2740 oss << " GROUP_ID [FREQ_MIN, FREQ_MAX]: IF_GROUP_ID" << endl ;
2741 for ( uInt i = 0 ; i < freqgrp.size() ; i++ ) {
2742 oss << " GROUP " << setw( 2 ) << i << " [" << ifgfreq[2*freqgrp[i][0]] << "," << ifgfreq[2*freqgrp[i][freqgrp[i].size()-1]+1] << "]: " ;
2743 for ( uInt j = 0 ; j < freqgrp[i].size() ; j++ ) {
2744 oss << freqgrp[i][j] << " " ;
2745 }
2746 oss << endl ;
2747 }
2748 oss << endl ;
2749 os << oss.str() << LogIO::POST ;
2750
2751 // membership check
2752 // groups: list of IF group indexes whose frequency range overlaps with
2753 // that of each table and IF
2754 // groups[numtable][numIF][nummembership]
2755 // groups: [[[grp, grp,...], [grp, grp,...],...],
2756 // [[grp, grp,...], [grp, grp,...],...],
2757 // ...
2758 // [[grp, grp,...], [grp, grp,...],...]]
2759 vector< vector< vector<uInt> > > groups( insize ) ;
2760 for ( uInt i = 0 ; i < insize ; i++ ) {
2761 groups[i].resize( freqid[i].size() ) ;
2762 }
2763 for ( uInt igrp = 0 ; igrp < ifgrp.size() ; igrp++ ) {
2764 for ( uInt imem = 0 ; imem < ifgrp[igrp].size()/2 ; imem++ ) {
2765 uInt tableid = ifgrp[igrp][2*imem] ;
2766 vector<uInt>::iterator iter = find( freqid[tableid].begin(), freqid[tableid].end(), ifgrp[igrp][2*imem+1] ) ;
2767 if ( iter != freqid[tableid].end() ) {
2768 uInt rowid = distance( freqid[tableid].begin(), iter ) ;
2769 groups[tableid][rowid].push_back( igrp ) ;
2770 }
2771 }
2772 }
2773
2774 // print membership
2775 //oss.str("") ;
2776 //for ( uInt i = 0 ; i < insize ; i++ ) {
2777 //oss << "Table " << i << endl ;
2778 //for ( uInt j = 0 ; j < groups[i].size() ; j++ ) {
2779 //oss << " FREQ_ID " << setw( 2 ) << freqid[i][j] << ": " ;
2780 //for ( uInt k = 0 ; k < groups[i][j].size() ; k++ ) {
2781 //oss << setw( 2 ) << groups[i][j][k] << " " ;
2782 //}
2783 //oss << endl ;
2784 //}
2785 //}
2786 //os << oss.str() << LogIO::POST ;
2787
2788 // set back coordinfo
2789 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2790 vector<string> coordinfo = tmpin[itable]->getCoordInfo() ;
2791 coordinfo[0] = oldinfo[itable] ;
2792 tmpin[itable]->setCoordInfo( coordinfo ) ;
2793 }
2794
2795 // Create additional table if needed
2796 bool oldInsitu = insitu_ ;
2797 setInsitu( false ) ;
2798 vector< vector<uInt> > addrow( insize ) ;
2799 vector<uInt> addtable( insize, 0 ) ;
2800 vector<uInt> newtableids( insize ) ;
2801 vector<uInt> newifids( insize, 0 ) ;
2802 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2803 //os << "Table " << itable << ": " ;
2804 for ( uInt ifrow = 0 ; ifrow < groups[itable].size() ; ifrow++ ) {
2805 addrow[itable].push_back( groups[itable][ifrow].size()-1 ) ;
2806 //os << addrow[itable][ifrow] << " " ;
2807 }
2808 addtable[itable] = *max_element( addrow[itable].begin(), addrow[itable].end() ) ;
2809 //os << "(" << addtable[itable] << ")" << LogIO::POST ;
2810 }
2811 newin.resize( insize ) ;
2812 copy( tmpin.begin(), tmpin.end(), newin.begin() ) ;
2813 for ( uInt i = 0 ; i < insize ; i++ ) {
2814 newtableids[i] = i ;
2815 }
2816 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2817 for ( uInt iadd = 0 ; iadd < addtable[itable] ; iadd++ ) {
2818 CountedPtr<Scantable> add = getScantable( newin[itable], false ) ;
2819 vector<int> freqidlist ;
2820 for ( uInt i = 0 ; i < groups[itable].size() ; i++ ) {
2821 if ( groups[itable][i].size() > iadd + 1 ) {
2822 freqidlist.push_back( freqid[itable][i] ) ;
2823 }
2824 }
2825 stringstream taqlstream ;
2826 taqlstream << "SELECT FROM $1 WHERE FREQ_ID IN [" ;
2827 for ( uInt i = 0 ; i < freqidlist.size() ; i++ ) {
2828 taqlstream << i ;
2829 if ( i < freqidlist.size() - 1 )
2830 taqlstream << "," ;
2831 else
2832 taqlstream << "]" ;
2833 }
2834 string taql = taqlstream.str() ;
2835 //os << "taql = " << taql << LogIO::POST ;
2836 STSelector selector = STSelector() ;
2837 selector.setTaQL( taql ) ;
2838 add->setSelection( selector ) ;
2839 newin.push_back( add ) ;
2840 newtableids.push_back( itable ) ;
2841 newifids.push_back( iadd + 1 ) ;
2842 }
2843 }
2844
2845 // udpate ifgrp
2846 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2847 for ( uInt iadd = 0 ; iadd < addtable[itable] ; iadd++ ) {
2848 for ( uInt ifrow = 0 ; ifrow < groups[itable].size() ; ifrow++ ) {
2849 if ( groups[itable][ifrow].size() > iadd + 1 ) {
2850 uInt igrp = groups[itable][ifrow][iadd+1] ;
2851 for ( uInt imem = 0 ; imem < ifgrp[igrp].size()/2 ; imem++ ) {
2852 if ( ifgrp[igrp][2*imem] == newtableids[iadd+insize] && ifgrp[igrp][2*imem+1] == freqid[newtableids[iadd+insize]][ifrow] ) {
2853 ifgrp[igrp][2*imem] = insize + iadd ;
2854 }
2855 }
2856 }
2857 }
2858 }
2859 }
2860
2861 // print IF groups again for debug
2862 //oss.str( "" ) ;
2863 //oss << "IF Group summary: " << endl ;
2864 //oss << " GROUP_ID [FREQ_MIN, FREQ_MAX]: (TABLE_ID, FREQ_ID)" << endl ;
2865 //for ( uInt i = 0 ; i < ifgrp.size() ; i++ ) {
2866 //oss << " GROUP " << setw( 2 ) << i << " [" << ifgfreq[2*i] << "," << ifgfreq[2*i+1] << "]: " ;
2867 //for ( uInt j = 0 ; j < ifgrp[i].size()/2 ; j++ ) {
2868 //oss << "(" << ifgrp[i][2*j] << "," << ifgrp[i][2*j+1] << ") " ;
2869 //}
2870 //oss << endl ;
2871 //}
2872 //oss << endl ;
2873 //os << oss.str() << LogIO::POST ;
2874
2875 // reset SCANNO and IFNO/FREQ_ID: IF is reset by the result of sortation
2876 os << "All scan number is set to 0" << LogIO::POST ;
2877 //os << "All IF number is set to IF group index" << LogIO::POST ;
2878 insize = newin.size() ;
2879 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2880 uInt rows = newin[itable]->nrow() ;
2881 Table &tmpt = newin[itable]->table() ;
2882 freqIDCol.attach( tmpt, "FREQ_ID" ) ;
2883 scannoCol.attach( tmpt, "SCANNO" ) ;
2884 ifnoCol.attach( tmpt, "IFNO" ) ;
2885 for ( uInt irow=0 ; irow < rows ; irow++ ) {
2886 scannoCol.put( irow, 0 ) ;
2887 uInt freqID = freqIDCol( irow ) ;
2888 vector<uInt>::iterator iter = find( freqid[newtableids[itable]].begin(), freqid[newtableids[itable]].end(), freqID ) ;
2889 if ( iter != freqid[newtableids[itable]].end() ) {
2890 uInt index = distance( freqid[newtableids[itable]].begin(), iter ) ;
2891 ifnoCol.put( irow, groups[newtableids[itable]][index][newifids[itable]] ) ;
2892 }
2893 else {
2894 throw(AipsError("IF grouping was wrong in additional tables.")) ;
2895 }
2896 }
2897 }
2898 oldinfo.resize( insize ) ;
2899 setInsitu( oldInsitu ) ;
2900
2901 // temporarily set coordinfo
2902 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2903 vector<string> coordinfo = newin[itable]->getCoordInfo() ;
2904 oldinfo[itable] = coordinfo[0] ;
2905 coordinfo[0] = "Hz" ;
2906 newin[itable]->setCoordInfo( coordinfo ) ;
2907 }
2908
2909 // save column values in the vector
2910 vector< vector<uInt> > freqTableIdVec( insize ) ;
2911 vector< vector<uInt> > freqIdVec( insize ) ;
2912 vector< vector<uInt> > ifNoVec( insize ) ;
2913 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2914 ScalarColumn<uInt> freqIDs ;
2915 freqIDs.attach( newin[itable]->frequencies().table(), "ID" ) ;
2916 ifnoCol.attach( newin[itable]->table(), "IFNO" ) ;
2917 freqIDCol.attach( newin[itable]->table(), "FREQ_ID" ) ;
2918 for ( uInt irow = 0 ; irow < newin[itable]->frequencies().table().nrow() ; irow++ ) {
2919 freqTableIdVec[itable].push_back( freqIDs( irow ) ) ;
2920 }
2921 for ( uInt irow = 0 ; irow < newin[itable]->table().nrow() ; irow++ ) {
2922 freqIdVec[itable].push_back( freqIDCol( irow ) ) ;
2923 ifNoVec[itable].push_back( ifnoCol( irow ) ) ;
2924 }
2925 }
2926
2927 // reset spectra and flagtra: pick up common part of frequency coverage
2928 //os << "Pick common frequency range and align resolution" << LogIO::POST ;
2929 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2930 uInt rows = newin[itable]->nrow() ;
2931 int nminchan = -1 ;
2932 int nmaxchan = -1 ;
2933 vector<uInt> freqIdUpdate ;
2934 for ( uInt irow = 0 ; irow < rows ; irow++ ) {
2935 uInt ifno = ifNoVec[itable][irow] ; // IFNO is reset by group index
2936 double minfreq = ifgfreq[2*ifno] ;
2937 double maxfreq = ifgfreq[2*ifno+1] ;
2938 //os << "frequency range: [" << minfreq << "," << maxfreq << "]" << LogIO::POST ;
2939 vector<double> abcissa = newin[itable]->getAbcissa( irow ) ;
2940 int nchan = abcissa.size() ;
2941 double resol = abcissa[1] - abcissa[0] ;
2942 //os << "abcissa range : [" << abcissa[0] << "," << abcissa[nchan-1] << "]" << LogIO::POST ;
2943 if ( minfreq <= abcissa[0] )
2944 nminchan = 0 ;
2945 else {
2946 //double cfreq = ( minfreq - abcissa[0] ) / resol ;
2947 double cfreq = ( minfreq - abcissa[0] + 0.5 * resol ) / resol ;
2948 nminchan = int(cfreq) + ( ( cfreq - int(cfreq) <= 0.5 ) ? 0 : 1 ) ;
2949 }
2950 if ( maxfreq >= abcissa[abcissa.size()-1] )
2951 nmaxchan = abcissa.size() - 1 ;
2952 else {
2953 //double cfreq = ( abcissa[abcissa.size()-1] - maxfreq ) / resol ;
2954 double cfreq = ( abcissa[abcissa.size()-1] - maxfreq + 0.5 * resol ) / resol ;
2955 nmaxchan = abcissa.size() - 1 - int(cfreq) - ( ( cfreq - int(cfreq) >= 0.5 ) ? 1 : 0 ) ;
2956 }
2957 //os << "channel range (" << irow << "): [" << nminchan << "," << nmaxchan << "]" << LogIO::POST ;
2958 if ( nmaxchan > nminchan ) {
2959 newin[itable]->reshapeSpectrum( nminchan, nmaxchan, irow ) ;
2960 int newchan = nmaxchan - nminchan + 1 ;
2961 if ( count( freqIdUpdate.begin(), freqIdUpdate.end(), freqIdVec[itable][irow] ) == 0 && newchan < nchan )
2962 freqIdUpdate.push_back( freqIdVec[itable][irow] ) ;
2963 }
2964 else {
2965 throw(AipsError("Failed to pick up common part of frequency range.")) ;
2966 }
2967 }
2968 for ( uInt i = 0 ; i < freqIdUpdate.size() ; i++ ) {
2969 uInt freqId = freqIdUpdate[i] ;
2970 Double refpix ;
2971 Double refval ;
2972 Double increment ;
2973
2974 // update row
2975 newin[itable]->frequencies().getEntry( refpix, refval, increment, freqId ) ;
2976 refval = refval - ( refpix - nminchan ) * increment ;
2977 refpix = 0 ;
2978 newin[itable]->frequencies().setEntry( refpix, refval, increment, freqId ) ;
2979 }
2980 }
2981
2982
2983 // reset spectra and flagtra: align spectral resolution
2984 //os << "Align spectral resolution" << LogIO::POST ;
2985 // gmaxdnu: the coarsest frequency resolution in the frequency group
2986 // gmemid: member index that have a resolution equal to gmaxdnu
2987 // gmaxdnu[numfreqgrp]
2988 // gmaxdnu: [dnu0, dnu1, ...]
2989 // gmemid[numfreqgrp]
2990 // gmemid: [id0, id1, ...]
2991 vector<double> gmaxdnu( freqgrp.size(), 0.0 ) ;
2992 vector<uInt> gmemid( freqgrp.size(), 0 ) ;
2993 for ( uInt igrp = 0 ; igrp < ifgrp.size() ; igrp++ ) {
2994 double maxdnu = 0.0 ; // maximum (coarsest) frequency resolution
2995 int minchan = INT_MAX ; // minimum channel number
2996 Double refpixref = -1 ; // reference of 'reference pixel'
2997 Double refvalref = -1 ; // reference of 'reference frequency'
2998 Double refinc = -1 ; // reference frequency resolution
2999 uInt refreqid ;
3000 uInt reftable = INT_MAX;
3001 // process only if group member > 1
3002 if ( ifgrp[igrp].size() > 2 ) {
3003 // find minchan and maxdnu in each group
3004 for ( uInt imem = 0 ; imem < ifgrp[igrp].size()/2 ; imem++ ) {
3005 uInt tableid = ifgrp[igrp][2*imem] ;
3006 uInt rowid = ifgrp[igrp][2*imem+1] ;
3007 vector<uInt>::iterator iter = find( freqIdVec[tableid].begin(), freqIdVec[tableid].end(), rowid ) ;
3008 if ( iter != freqIdVec[tableid].end() ) {
3009 uInt index = distance( freqIdVec[tableid].begin(), iter ) ;
3010 vector<double> abcissa = newin[tableid]->getAbcissa( index ) ;
3011 int nchan = abcissa.size() ;
3012 double dnu = abcissa[1] - abcissa[0] ;
3013 //os << "GROUP " << igrp << " (" << tableid << "," << rowid << "): nchan = " << nchan << " (minchan = " << minchan << ")" << LogIO::POST ;
3014 if ( nchan < minchan ) {
3015 minchan = nchan ;
3016 maxdnu = dnu ;
3017 newin[tableid]->frequencies().getEntry( refpixref, refvalref, refinc, rowid ) ;
3018 refreqid = rowid ;
3019 reftable = tableid ;
3020 }
3021 }
3022 }
3023 // regrid spectra in each group
3024 os << "GROUP " << igrp << endl ;
3025 os << " Channel number is adjusted to " << minchan << endl ;
3026 os << " Corresponding frequency resolution is " << maxdnu << "Hz" << LogIO::POST ;
3027 for ( uInt imem = 0 ; imem < ifgrp[igrp].size()/2 ; imem++ ) {
3028 uInt tableid = ifgrp[igrp][2*imem] ;
3029 uInt rowid = ifgrp[igrp][2*imem+1] ;
3030 freqIDCol.attach( newin[tableid]->table(), "FREQ_ID" ) ;
3031 //os << "tableid = " << tableid << " rowid = " << rowid << ": " << LogIO::POST ;
3032 //os << " regridChannel applied to " ;
3033 if ( tableid != reftable )
3034 refreqid = newin[tableid]->frequencies().addEntry( refpixref, refvalref, refinc ) ;
3035 for ( uInt irow = 0 ; irow < newin[tableid]->table().nrow() ; irow++ ) {
3036 uInt tfreqid = freqIdVec[tableid][irow] ;
3037 if ( tfreqid == rowid ) {
3038 //os << irow << " " ;
3039 newin[tableid]->regridChannel( minchan, maxdnu, irow ) ;
3040 freqIDCol.put( irow, refreqid ) ;
3041 freqIdVec[tableid][irow] = refreqid ;
3042 }
3043 }
3044 //os << LogIO::POST ;
3045 }
3046 }
3047 else {
3048 uInt tableid = ifgrp[igrp][0] ;
3049 uInt rowid = ifgrp[igrp][1] ;
3050 vector<uInt>::iterator iter = find( freqIdVec[tableid].begin(), freqIdVec[tableid].end(), rowid ) ;
3051 if ( iter != freqIdVec[tableid].end() ) {
3052 uInt index = distance( freqIdVec[tableid].begin(), iter ) ;
3053 vector<double> abcissa = newin[tableid]->getAbcissa( index ) ;
3054 minchan = abcissa.size() ;
3055 maxdnu = abcissa[1] - abcissa[0] ;
3056 }
3057 }
3058 for ( uInt i = 0 ; i < freqgrp.size() ; i++ ) {
3059 if ( count( freqgrp[i].begin(), freqgrp[i].end(), igrp ) > 0 ) {
3060 if ( maxdnu > gmaxdnu[i] ) {
3061 gmaxdnu[i] = maxdnu ;
3062 gmemid[i] = igrp ;
3063 }
3064 break ;
3065 }
3066 }
3067 }
3068
3069 // set back coordinfo
3070 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
3071 vector<string> coordinfo = newin[itable]->getCoordInfo() ;
3072 coordinfo[0] = oldinfo[itable] ;
3073 newin[itable]->setCoordInfo( coordinfo ) ;
3074 }
3075
3076 // accumulate all rows into the first table
3077 // NOTE: assumed in.size() = 1
3078 vector< CountedPtr<Scantable> > tmp( 1 ) ;
3079 if ( newin.size() == 1 )
3080 tmp[0] = newin[0] ;
3081 else
3082 tmp[0] = merge( newin ) ;
3083
3084 //return tmp[0] ;
3085
3086 // average
3087 CountedPtr<Scantable> tmpout = average( tmp, mask, weight, avmode ) ;
3088
3089 //return tmpout ;
3090
3091 // combine frequency group
3092 os << "Combine spectra based on frequency grouping" << LogIO::POST ;
3093 os << "IFNO is renumbered as frequency group ID (see above)" << LogIO::POST ;
3094 vector<string> coordinfo = tmpout->getCoordInfo() ;
3095 oldinfo[0] = coordinfo[0] ;
3096 coordinfo[0] = "Hz" ;
3097 tmpout->setCoordInfo( coordinfo ) ;
3098 // create proformas of output table
3099 stringstream taqlstream ;
3100 taqlstream << "SELECT FROM $1 WHERE IFNO IN [" ;
3101 for ( uInt i = 0 ; i < gmemid.size() ; i++ ) {
3102 taqlstream << gmemid[i] ;
3103 if ( i < gmemid.size() - 1 )
3104 taqlstream << "," ;
3105 else
3106 taqlstream << "]" ;
3107 }
3108 string taql = taqlstream.str() ;
3109 //os << "taql = " << taql << LogIO::POST ;
3110 STSelector selector = STSelector() ;
3111 selector.setTaQL( taql ) ;
3112 oldInsitu = insitu_ ;
3113 setInsitu( false ) ;
3114 out = getScantable( tmpout, false ) ;
3115 setInsitu( oldInsitu ) ;
3116 out->setSelection( selector ) ;
3117 // regrid rows
3118 ifnoCol.attach( tmpout->table(), "IFNO" ) ;
3119 for ( uInt irow = 0 ; irow < tmpout->table().nrow() ; irow++ ) {
3120 uInt ifno = ifnoCol( irow ) ;
3121 for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3122 if ( count( freqgrp[igrp].begin(), freqgrp[igrp].end(), ifno ) > 0 ) {
3123 vector<double> abcissa = tmpout->getAbcissa( irow ) ;
3124 double bw = ( abcissa[1] - abcissa[0] ) * abcissa.size() ;
3125 int nchan = (int)( bw / gmaxdnu[igrp] ) ;
3126 tmpout->regridChannel( nchan, gmaxdnu[igrp], irow ) ;
3127 break ;
3128 }
3129 }
3130 }
3131 // combine spectra
3132 ArrayColumn<Float> specColOut ;
3133 specColOut.attach( out->table(), "SPECTRA" ) ;
3134 ArrayColumn<uChar> flagColOut ;
3135 flagColOut.attach( out->table(), "FLAGTRA" ) ;
3136 ScalarColumn<uInt> ifnoColOut ;
3137 ifnoColOut.attach( out->table(), "IFNO" ) ;
3138 ScalarColumn<uInt> polnoColOut ;
3139 polnoColOut.attach( out->table(), "POLNO" ) ;
3140 ScalarColumn<uInt> freqidColOut ;
3141 freqidColOut.attach( out->table(), "FREQ_ID" ) ;
3142 MDirection::ScalarColumn dirColOut ;
3143 dirColOut.attach( out->table(), "DIRECTION" ) ;
3144 Table &tab = tmpout->table() ;
3145 Block<String> cols(1);
3146 cols[0] = String("POLNO") ;
3147 TableIterator iter( tab, cols ) ;
3148 bool done = false ;
3149 vector< vector<uInt> > sizes( freqgrp.size() ) ;
3150 while( !iter.pastEnd() ) {
3151 vector< vector<Float> > specout( freqgrp.size() ) ;
3152 vector< vector<uChar> > flagout( freqgrp.size() ) ;
3153 ArrayColumn<Float> specCols ;
3154 specCols.attach( iter.table(), "SPECTRA" ) ;
3155 ArrayColumn<uChar> flagCols ;
3156 flagCols.attach( iter.table(), "FLAGTRA" ) ;
3157 ifnoCol.attach( iter.table(), "IFNO" ) ;
3158 ScalarColumn<uInt> polnos ;
3159 polnos.attach( iter.table(), "POLNO" ) ;
3160 MDirection::ScalarColumn dircol ;
3161 dircol.attach( iter.table(), "DIRECTION" ) ;
3162 uInt polno = polnos( 0 ) ;
3163 //os << "POLNO iteration: " << polno << LogIO::POST ;
3164// for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3165// sizes[igrp].resize( freqgrp[igrp].size() ) ;
3166// for ( uInt imem = 0 ; imem < freqgrp[igrp].size() ; imem++ ) {
3167// for ( uInt irow = 0 ; irow < iter.table().nrow() ; irow++ ) {
3168// uInt ifno = ifnoCol( irow ) ;
3169// if ( ifno == freqgrp[igrp][imem] ) {
3170// Vector<Float> spec = specCols( irow ) ;
3171// Vector<uChar> flag = flagCols( irow ) ;
3172// vector<Float> svec ;
3173// spec.tovector( svec ) ;
3174// vector<uChar> fvec ;
3175// flag.tovector( fvec ) ;
3176// //os << "spec.size() = " << svec.size() << " fvec.size() = " << fvec.size() << LogIO::POST ;
3177// specout[igrp].insert( specout[igrp].end(), svec.begin(), svec.end() ) ;
3178// flagout[igrp].insert( flagout[igrp].end(), fvec.begin(), fvec.end() ) ;
3179// //os << "specout[" << igrp << "].size() = " << specout[igrp].size() << LogIO::POST ;
3180// sizes[igrp][imem] = spec.nelements() ;
3181// }
3182// }
3183// }
3184// for ( uInt irow = 0 ; irow < out->table().nrow() ; irow++ ) {
3185// uInt ifout = ifnoColOut( irow ) ;
3186// uInt polout = polnoColOut( irow ) ;
3187// if ( ifout == gmemid[igrp] && polout == polno ) {
3188// // set SPECTRA and FRAGTRA
3189// Vector<Float> newspec( specout[igrp] ) ;
3190// Vector<uChar> newflag( flagout[igrp] ) ;
3191// specColOut.put( irow, newspec ) ;
3192// flagColOut.put( irow, newflag ) ;
3193// // IFNO renumbering
3194// ifnoColOut.put( irow, igrp ) ;
3195// }
3196// }
3197// }
3198 // get a list of number of channels for each frequency group member
3199 if ( !done ) {
3200 for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3201 sizes[igrp].resize( freqgrp[igrp].size() ) ;
3202 for ( uInt imem = 0 ; imem < freqgrp[igrp].size() ; imem++ ) {
3203 for ( uInt irow = 0 ; irow < iter.table().nrow() ; irow++ ) {
3204 uInt ifno = ifnoCol( irow ) ;
3205 if ( ifno == freqgrp[igrp][imem] ) {
3206 Vector<Float> spec = specCols( irow ) ;
3207 sizes[igrp][imem] = spec.nelements() ;
3208 break ;
3209 }
3210 }
3211 }
3212 }
3213 done = true ;
3214 }
3215 // combine spectra
3216 for ( uInt irow = 0 ; irow < out->table().nrow() ; irow++ ) {
3217 uInt polout = polnoColOut( irow ) ;
3218 if ( polout == polno ) {
3219 uInt ifout = ifnoColOut( irow ) ;
3220 Vector<Double> direction = dirColOut(irow).getAngle(Unit(String("rad"))).getValue() ;
3221 uInt igrp ;
3222 for ( uInt jgrp = 0 ; jgrp < freqgrp.size() ; jgrp++ ) {
3223 if ( ifout == gmemid[jgrp] ) {
3224 igrp = jgrp ;
3225 break ;
3226 }
3227 }
3228 for ( uInt imem = 0 ; imem < freqgrp[igrp].size() ; imem++ ) {
3229 for ( uInt jrow = 0 ; jrow < iter.table().nrow() ; jrow++ ) {
3230 uInt ifno = ifnoCol( jrow ) ;
3231 Vector<Double> tdir = dircol(jrow).getAngle(Unit(String("rad"))).getValue() ;
3232 //if ( ifno == freqgrp[igrp][imem] && allTrue( tdir == direction ) ) {
3233 Double dx = tdir[0] - direction[0] ;
3234 Double dy = tdir[1] - direction[1] ;
3235 Double dd = sqrt( dx * dx + dy * dy ) ;
3236 //if ( ifno == freqgrp[igrp][imem] && allNearAbs( tdir, direction, tol ) ) {
3237 if ( ifno == freqgrp[igrp][imem] && dd <= tol ) {
3238 Vector<Float> spec = specCols( jrow ) ;
3239 Vector<uChar> flag = flagCols( jrow ) ;
3240 vector<Float> svec ;
3241 spec.tovector( svec ) ;
3242 vector<uChar> fvec ;
3243 flag.tovector( fvec ) ;
3244 //os << "spec.size() = " << svec.size() << " fvec.size() = " << fvec.size() << LogIO::POST ;
3245 specout[igrp].insert( specout[igrp].end(), svec.begin(), svec.end() ) ;
3246 flagout[igrp].insert( flagout[igrp].end(), fvec.begin(), fvec.end() ) ;
3247 //os << "specout[" << igrp << "].size() = " << specout[igrp].size() << LogIO::POST ;
3248 }
3249 }
3250 }
3251 // set SPECTRA and FRAGTRA
3252 Vector<Float> newspec( specout[igrp] ) ;
3253 Vector<uChar> newflag( flagout[igrp] ) ;
3254 specColOut.put( irow, newspec ) ;
3255 flagColOut.put( irow, newflag ) ;
3256 // IFNO renumbering
3257 ifnoColOut.put( irow, igrp ) ;
3258 }
3259 }
3260 iter++ ;
3261 }
3262 // update FREQUENCIES subtable
3263 vector<bool> updated( freqgrp.size(), false ) ;
3264 for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3265 uInt index = 0 ;
3266 uInt pixShift = 0 ;
3267 while ( freqgrp[igrp][index] != gmemid[igrp] ) {
3268 pixShift += sizes[igrp][index++] ;
3269 }
3270 for ( uInt irow = 0 ; irow < out->table().nrow() ; irow++ ) {
3271 if ( ifnoColOut( irow ) == gmemid[igrp] && !updated[igrp] ) {
3272 uInt freqidOut = freqidColOut( irow ) ;
3273 //os << "freqgrp " << igrp << " freqidOut = " << freqidOut << LogIO::POST ;
3274 double refpix ;
3275 double refval ;
3276 double increm ;
3277 out->frequencies().getEntry( refpix, refval, increm, freqidOut ) ;
3278 refpix += pixShift ;
3279 out->frequencies().setEntry( refpix, refval, increm, freqidOut ) ;
3280 updated[igrp] = true ;
3281 }
3282 }
3283 }
3284
3285 //out = tmpout ;
3286
3287 coordinfo = tmpout->getCoordInfo() ;
3288 coordinfo[0] = oldinfo[0] ;
3289 tmpout->setCoordInfo( coordinfo ) ;
3290 }
3291 else {
3292 // simple average
3293 out = average( in, mask, weight, avmode ) ;
3294 }
3295
3296 return out ;
3297}
3298
3299CountedPtr<Scantable> STMath::cwcal( const CountedPtr<Scantable>& s,
3300 const String calmode,
3301 const String antname )
3302{
3303 // frequency switch
3304 if ( calmode == "fs" ) {
3305 return cwcalfs( s, antname ) ;
3306 }
3307 else {
3308 string skystr = "*_sky" ;
3309 string hotstr = "*_hot" ;
3310 string coldstr = "*_cold" ;
3311 string onstr = "*_" ;
3312 string offstr = "*_" ;
3313
3314 if ( calmode == "ps" || calmode == "otf" ) {
3315 onstr += "pson" ;
3316 offstr += "psoff" ;
3317 }
3318 else if ( calmode == "wob" ) {
3319 onstr += "wobon" ;
3320 offstr += "woboff" ;
3321 }
3322
3323 vector<bool> masks = s->getMask( 0 ) ;
3324
3325 // sky scan
3326 STSelector sel = STSelector() ;
3327 sel.setName( skystr ) ;
3328 s->setSelection( sel ) ;
3329 vector< CountedPtr<Scantable> > tmp( 1, getScantable( s, false ) ) ;
3330 CountedPtr<Scantable> asky = average( tmp, masks, "TINT", "SCAN" ) ;
3331 s->unsetSelection() ;
3332 sel.reset() ;
3333
3334 // hot scan
3335 sel.setName( hotstr ) ;
3336 s->setSelection( sel ) ;
3337 tmp[0] = getScantable( s, false ) ;
3338 CountedPtr<Scantable> ahot = average( tmp, masks, "TINT", "SCAN" ) ;
3339 s->unsetSelection() ;
3340 sel.reset() ;
3341
3342 // cold scan
3343 sel.setName( coldstr ) ;
3344 s->setSelection( sel ) ;
3345 tmp[0] = getScantable( s, false ) ;
3346 CountedPtr<Scantable> acold = average( tmp, masks, "TINT", "SCNAN" ) ;
3347 s->unsetSelection() ;
3348 sel.reset() ;
3349
3350 // off scan
3351 sel.setName( offstr ) ;
3352 s->setSelection( sel ) ;
3353 tmp[0] = getScantable( s, false ) ;
3354 CountedPtr<Scantable> aoff = average( tmp, masks, "TINT", "SCAN" ) ;
3355 s->unsetSelection() ;
3356 sel.reset() ;
3357
3358 // on scan
3359 bool insitu = insitu_ ;
3360 insitu_ = false ;
3361 CountedPtr<Scantable> out = getScantable( s, true ) ;
3362 insitu_ = insitu ;
3363 sel.setName( onstr ) ;
3364 s->setSelection( sel ) ;
3365 TableCopy::copyRows( out->table(), s->table() ) ;
3366 s->unsetSelection() ;
3367 sel.reset() ;
3368
3369 // process each on scan
3370 for ( int i = 0 ; i < out->nrow() ; i++ ) {
3371 vector<float> sp = getCalibratedSpectra( out, aoff, asky, ahot, acold, i, antname ) ;
3372 out->setSpectrum( sp, i ) ;
3373 }
3374
3375 // remove additional string from SRCNAME
3376 ScalarColumn<String> srcnameCol ;
3377 srcnameCol.attach( out->table(), "SRCNAME" ) ;
3378 Vector<String> srcnames( srcnameCol.getColumn() ) ;
3379 for ( uInt i = 0 ; i < srcnames.nelements() ; i++ ) {
3380 srcnames[i] = srcnames[i].substr( 0, srcnames[i].find( onstr.substr(1,onstr.size()-1) ) ) ;
3381 }
3382 srcnameCol.putColumn( srcnames ) ;
3383
3384 return out ;
3385 }
3386}
3387
3388CountedPtr<Scantable> STMath::cwcalfs( const CountedPtr<Scantable>& s,
3389 const String antname )
3390{
3391 string skystr = "*_sky" ;
3392 string skystr1 = "*_fslo_sky" ;
3393 string skystr2 = "*_fshi_sky" ;
3394 string hotstr = "*_hot" ;
3395 string hotstr1 = "*_fslo_hot" ;
3396 string hotstr2 = "*_fshi_hot" ;
3397 string coldstr = "*_cold" ;
3398 string coldstr1 = "*_fslo_cold" ;
3399 string coldstr2 = "*_fshi_cold" ;
3400 string offstr1 = "*_fslo_off" ;
3401 string offstr2 = "*_fshi_off" ;
3402 string sigstr = "*_" ;
3403 string refstr = "*_" ;
3404
3405 // APEX calibration mode
3406 int apexcalmode = 1 ;
3407
3408 if ( antname.find( "APEX" ) != string::npos ) {
3409 sigstr += "fslo" ;
3410 refstr += "fshi" ;
3411
3412 // check if off scan exists or not
3413 STSelector sel = STSelector() ;
3414 sel.setName( offstr1 ) ;
3415 try {
3416 s->setSelection( sel ) ;
3417 }
3418 catch ( AipsError &e ) {
3419 apexcalmode = 0 ;
3420 }
3421 }
3422 else {
3423 sigstr += "fssig" ;
3424 refstr += "fsref" ;
3425 }
3426
3427 vector<bool> masks = s->getMask( 0 ) ;
3428 CountedPtr<Scantable> ssig, sref ;
3429 CountedPtr<Scantable> out ;
3430
3431 if ( antname.find( "APEX" ) != string::npos && apexcalmode == 0 ) {
3432 // APEX fs data without off scan
3433 // sky scan
3434 STSelector sel = STSelector() ;
3435 sel.setName( skystr1 ) ;
3436 s->setSelection( sel ) ;
3437 vector< CountedPtr<Scantable> > tmp( 1, getScantable( s, false ) ) ;
3438 CountedPtr<Scantable> askylo = average( tmp, masks, "TINT", "SCAN" ) ;
3439 s->unsetSelection() ;
3440 sel.reset() ;
3441 sel.setName( skystr2 ) ;
3442 s->setSelection( sel ) ;
3443 tmp[0] = getScantable( s, false ) ;
3444 CountedPtr<Scantable> askyhi = average( tmp, masks, "TINT", "SCAN" ) ;
3445 s->unsetSelection() ;
3446 sel.reset() ;
3447
3448 // hot scan
3449 sel.setName( hotstr1 ) ;
3450 s->setSelection( sel ) ;
3451 tmp[0] = getScantable( s, false ) ;
3452 CountedPtr<Scantable> ahotlo = average( tmp, masks, "TINT", "SCAN" ) ;
3453 s->unsetSelection() ;
3454 sel.reset() ;
3455 sel.setName( hotstr2 ) ;
3456 s->setSelection( sel ) ;
3457 tmp[0] = getScantable( s, false ) ;
3458 CountedPtr<Scantable> ahothi = average( tmp, masks, "TINT", "SCAN" ) ;
3459 s->unsetSelection() ;
3460 sel.reset() ;
3461
3462 // cold scan
3463 sel.setName( coldstr1 ) ;
3464 s->setSelection( sel ) ;
3465 tmp[0] = getScantable( s, false ) ;
3466 CountedPtr<Scantable> acoldlo = average( tmp, masks, "TINT", "SCAN" ) ;
3467 s->unsetSelection() ;
3468 sel.reset() ;
3469 sel.setName( coldstr2 ) ;
3470 s->setSelection( sel ) ;
3471 tmp[0] = getScantable( s, false ) ;
3472 CountedPtr<Scantable> acoldhi = average( tmp, masks, "TINT", "SCAN" ) ;
3473 s->unsetSelection() ;
3474 sel.reset() ;
3475
3476 // ref scan
3477 bool insitu = insitu_ ;
3478 insitu_ = false ;
3479 sref = getScantable( s, true ) ;
3480 insitu_ = insitu ;
3481 sel.setName( refstr ) ;
3482 s->setSelection( sel ) ;
3483 TableCopy::copyRows( sref->table(), s->table() ) ;
3484 s->unsetSelection() ;
3485 sel.reset() ;
3486
3487 // sig scan
3488 insitu_ = false ;
3489 ssig = getScantable( s, true ) ;
3490 insitu_ = insitu ;
3491 sel.setName( sigstr ) ;
3492 s->setSelection( sel ) ;
3493 TableCopy::copyRows( ssig->table(), s->table() ) ;
3494 s->unsetSelection() ;
3495 sel.reset() ;
3496
3497 // process each sig and ref scan
3498 for ( int i = 0 ; i < ssig->nrow() ; i++ ) {
3499 vector< CountedPtr<Scantable> > sky( 2 ) ;
3500 sky[0] = askylo ;
3501 sky[1] = askyhi ;
3502 vector< CountedPtr<Scantable> > hot( 2 ) ;
3503 hot[0] = ahotlo ;
3504 hot[1] = ahothi ;
3505 vector< CountedPtr<Scantable> > cold( 2 ) ;
3506 cold[0] = acoldlo ;
3507 cold[1] = acoldhi ;
3508 vector<float> sp = getFSCalibratedSpectra( ssig, sref, sky, hot, cold, i ) ;
3509 ssig->setSpectrum( sp, i ) ;
3510 sky[0] = askyhi ;
3511 sky[1] = askylo ;
3512 hot[0] = ahothi ;
3513 hot[1] = ahotlo ;
3514 cold[0] = acoldhi ;
3515 cold[1] = acoldlo ;
3516 sp = getFSCalibratedSpectra( sref, ssig, sky, hot, cold, i ) ;
3517 sref->setSpectrum( sp, i ) ;
3518 }
3519
3520 }
3521 else if ( antname.find( "APEX" ) != string::npos && apexcalmode == 1 ) {
3522 // APEX fs data with off scan
3523 // sky scan
3524 STSelector sel = STSelector() ;
3525 sel.setName( skystr1 ) ;
3526 s->setSelection( sel ) ;
3527 vector< CountedPtr<Scantable> > tmp( 1, getScantable( s, false ) ) ;
3528 CountedPtr<Scantable> askylo = average( tmp, masks, "TINT", "SCAN" ) ;
3529 s->unsetSelection() ;
3530 sel.reset() ;
3531 sel.setName( skystr2 ) ;
3532 s->setSelection( sel ) ;
3533 tmp[0] = getScantable( s, false ) ;
3534 CountedPtr<Scantable> askyhi = average( tmp, masks, "TINT", "SCAN" ) ;
3535 s->unsetSelection() ;
3536 sel.reset() ;
3537
3538 // hot scan
3539 sel.setName( hotstr1 ) ;
3540 s->setSelection( sel ) ;
3541 tmp[0] = getScantable( s, false ) ;
3542 CountedPtr<Scantable> ahotlo = average( tmp, masks, "TINT", "SCAN" ) ;
3543 s->unsetSelection() ;
3544 sel.reset() ;
3545 sel.setName( hotstr2 ) ;
3546 s->setSelection( sel ) ;
3547 tmp[0] = getScantable( s, false ) ;
3548 CountedPtr<Scantable> ahothi = average( tmp, masks, "TINT", "SCAN" ) ;
3549 s->unsetSelection() ;
3550 sel.reset() ;
3551
3552 // cold scan
3553 sel.setName( coldstr1 ) ;
3554 s->setSelection( sel ) ;
3555 tmp[0] = getScantable( s, false ) ;
3556 CountedPtr<Scantable> acoldlo = average( tmp, masks, "TINT", "SCAN" ) ;
3557 s->unsetSelection() ;
3558 sel.reset() ;
3559 sel.setName( coldstr2 ) ;
3560 s->setSelection( sel ) ;
3561 tmp[0] = getScantable( s, false ) ;
3562 CountedPtr<Scantable> acoldhi = average( tmp, masks, "TINT", "SCAN" ) ;
3563 s->unsetSelection() ;
3564 sel.reset() ;
3565
3566 // off scan
3567 sel.setName( offstr1 ) ;
3568 s->setSelection( sel ) ;
3569 tmp[0] = getScantable( s, false ) ;
3570 CountedPtr<Scantable> aofflo = average( tmp, masks, "TINT", "SCAN" ) ;
3571 s->unsetSelection() ;
3572 sel.reset() ;
3573 sel.setName( offstr2 ) ;
3574 s->setSelection( sel ) ;
3575 tmp[0] = getScantable( s, false ) ;
3576 CountedPtr<Scantable> aoffhi = average( tmp, masks, "TINT", "SCAN" ) ;
3577 s->unsetSelection() ;
3578 sel.reset() ;
3579
3580 // ref scan
3581 bool insitu = insitu_ ;
3582 insitu_ = false ;
3583 sref = getScantable( s, true ) ;
3584 insitu_ = insitu ;
3585 sel.setName( refstr ) ;
3586 s->setSelection( sel ) ;
3587 TableCopy::copyRows( sref->table(), s->table() ) ;
3588 s->unsetSelection() ;
3589 sel.reset() ;
3590
3591 // sig scan
3592 insitu_ = false ;
3593 ssig = getScantable( s, true ) ;
3594 insitu_ = insitu ;
3595 sel.setName( sigstr ) ;
3596 s->setSelection( sel ) ;
3597 TableCopy::copyRows( ssig->table(), s->table() ) ;
3598 s->unsetSelection() ;
3599 sel.reset() ;
3600
3601 // process each sig and ref scan
3602 for ( int i = 0 ; i < ssig->nrow() ; i++ ) {
3603 vector<float> sp = getCalibratedSpectra( ssig, aofflo, askylo, ahotlo, acoldlo, i, antname ) ;
3604 ssig->setSpectrum( sp, i ) ;
3605 sp = getCalibratedSpectra( sref, aoffhi, askyhi, ahothi, acoldhi, i, antname ) ;
3606 sref->setSpectrum( sp, i ) ;
3607 }
3608 }
3609 else if ( antname.find( "APEX" ) == string::npos ) {
3610 // non-APEX fs data
3611 // sky scan
3612 STSelector sel = STSelector() ;
3613 sel.setName( skystr ) ;
3614 s->setSelection( sel ) ;
3615 vector< CountedPtr<Scantable> > tmp( 1, getScantable( s, false ) ) ;
3616 CountedPtr<Scantable> asky = average( tmp, masks, "TINT", "SCAN" ) ;
3617 s->unsetSelection() ;
3618 sel.reset() ;
3619
3620 // hot scan
3621 sel.setName( hotstr ) ;
3622 s->setSelection( sel ) ;
3623 tmp[0] = getScantable( s, false ) ;
3624 CountedPtr<Scantable> ahot = average( tmp, masks, "TINT", "SCAN" ) ;
3625 s->unsetSelection() ;
3626 sel.reset() ;
3627
3628 // cold scan
3629 sel.setName( coldstr ) ;
3630 s->setSelection( sel ) ;
3631 tmp[0] = getScantable( s, false ) ;
3632 CountedPtr<Scantable> acold = average( tmp, masks, "TINT", "SCAN" ) ;
3633 s->unsetSelection() ;
3634 sel.reset() ;
3635
3636 // ref scan
3637 bool insitu = insitu_ ;
3638 insitu_ = false ;
3639 sref = getScantable( s, true ) ;
3640 insitu_ = insitu ;
3641 sel.setName( refstr ) ;
3642 s->setSelection( sel ) ;
3643 TableCopy::copyRows( sref->table(), s->table() ) ;
3644 s->unsetSelection() ;
3645 sel.reset() ;
3646
3647 // sig scan
3648 insitu_ = false ;
3649 ssig = getScantable( s, true ) ;
3650 insitu_ = insitu ;
3651 sel.setName( sigstr ) ;
3652 s->setSelection( sel ) ;
3653 TableCopy::copyRows( ssig->table(), s->table() ) ;
3654 s->unsetSelection() ;
3655 sel.reset() ;
3656
3657 // process each sig and ref scan
3658 for ( int i = 0 ; i < ssig->nrow() ; i++ ) {
3659 vector<float> sp = getFSCalibratedSpectra( ssig, sref, asky, ahot, acold, i ) ;
3660 ssig->setSpectrum( sp, i ) ;
3661 sp = getFSCalibratedSpectra( sref, ssig, asky, ahot, acold, i ) ;
3662 sref->setSpectrum( sp, i ) ;
3663 }
3664 }
3665
3666 // do folding if necessary
3667 Table sigtab = ssig->table() ;
3668 Table reftab = sref->table() ;
3669 ScalarColumn<uInt> sigifnoCol ;
3670 ScalarColumn<uInt> refifnoCol ;
3671 ScalarColumn<uInt> sigfidCol ;
3672 ScalarColumn<uInt> reffidCol ;
3673 uInt nchan = (uInt)ssig->nchan() ;
3674 sigifnoCol.attach( sigtab, "IFNO" ) ;
3675 refifnoCol.attach( reftab, "IFNO" ) ;
3676 sigfidCol.attach( sigtab, "FREQ_ID" ) ;
3677 reffidCol.attach( reftab, "FREQ_ID" ) ;
3678 Vector<uInt> sfids( sigfidCol.getColumn() ) ;
3679 Vector<uInt> rfids( reffidCol.getColumn() ) ;
3680 vector<uInt> sfids_unique ;
3681 vector<uInt> rfids_unique ;
3682 vector<uInt> sifno_unique ;
3683 vector<uInt> rifno_unique ;
3684 for ( uInt i = 0 ; i < sfids.nelements() ; i++ ) {
3685 if ( count( sfids_unique.begin(), sfids_unique.end(), sfids[i] ) == 0 ) {
3686 sfids_unique.push_back( sfids[i] ) ;
3687 sifno_unique.push_back( ssig->getIF( i ) ) ;
3688 }
3689 if ( count( rfids_unique.begin(), rfids_unique.end(), rfids[i] ) == 0 ) {
3690 rfids_unique.push_back( rfids[i] ) ;
3691 rifno_unique.push_back( sref->getIF( i ) ) ;
3692 }
3693 }
3694 double refpix_sig, refval_sig, increment_sig ;
3695 double refpix_ref, refval_ref, increment_ref ;
3696 vector< CountedPtr<Scantable> > tmp( sfids_unique.size() ) ;
3697 for ( uInt i = 0 ; i < sfids_unique.size() ; i++ ) {
3698 ssig->frequencies().getEntry( refpix_sig, refval_sig, increment_sig, sfids_unique[i] ) ;
3699 sref->frequencies().getEntry( refpix_ref, refval_ref, increment_ref, rfids_unique[i] ) ;
3700 if ( refpix_sig == refpix_ref ) {
3701 double foffset = refval_ref - refval_sig ;
3702 int choffset = static_cast<int>(foffset/increment_sig) ;
3703 double doffset = foffset / increment_sig ;
3704 if ( abs(choffset) >= nchan ) {
3705 LogIO os( LogOrigin( "STMath", "cwcalfs", WHERE ) ) ;
3706 os << "FREQ_ID=[" << sfids_unique[i] << "," << rfids_unique[i] << "]: out-band frequency switching, no folding" << LogIO::POST ;
3707 os << "Just return signal data" << LogIO::POST ;
3708 //std::vector< CountedPtr<Scantable> > tabs ;
3709 //tabs.push_back( ssig ) ;
3710 //tabs.push_back( sref ) ;
3711 //out = merge( tabs ) ;
3712 tmp[i] = ssig ;
3713 }
3714 else {
3715 STSelector sel = STSelector() ;
3716 vector<int> v( 1, sifno_unique[i] ) ;
3717 sel.setIFs( v ) ;
3718 ssig->setSelection( sel ) ;
3719 sel.reset() ;
3720 v[0] = rifno_unique[i] ;
3721 sel.setIFs( v ) ;
3722 sref->setSelection( sel ) ;
3723 sel.reset() ;
3724 if ( antname.find( "APEX" ) != string::npos ) {
3725 tmp[i] = dofold( ssig, sref, 0.5*doffset, -0.5*doffset ) ;
3726 //tmp[i] = dofold( ssig, sref, doffset ) ;
3727 }
3728 else {
3729 tmp[i] = dofold( ssig, sref, doffset ) ;
3730 }
3731 // remove additional string from SRCNAME
3732 ScalarColumn<String> srcnameCol ;
3733 srcnameCol.attach( tmp[i]->table(), "SRCNAME" ) ;
3734 Vector<String> srcnames( srcnameCol.getColumn() ) ;
3735 for ( uInt i = 0 ; i < srcnames.nelements() ; i++ ) {
3736 srcnames[i] = srcnames[i].substr( 0, srcnames[i].find( sigstr.substr(1,sigstr.size()-1) ) ) ;
3737 }
3738 srcnameCol.putColumn( srcnames ) ;
3739 ssig->unsetSelection() ;
3740 sref->unsetSelection() ;
3741 }
3742 }
3743 }
3744
3745 out = merge( tmp ) ;
3746
3747 return out ;
3748}
3749
3750vector<float> STMath::getSpectrumFromTime( string reftime,
3751 CountedPtr<Scantable>& s,
3752 string mode )
3753{
3754 LogIO os( LogOrigin( "STMath", "getSpectrumFromTime", WHERE ) ) ;
3755 vector<float> sp ;
3756
3757 if ( s->nrow() == 0 ) {
3758 os << LogIO::SEVERE << "No spectra in the input scantable. Return empty spectrum." << LogIO::POST ;
3759 return sp ;
3760 }
3761 else if ( s->nrow() == 1 ) {
3762 os << "use row " << 0 << " (scanno = " << s->getScan( 0 ) << ")" << LogIO::POST ;
3763 return s->getSpectrum( 0 ) ;
3764 }
3765 else {
3766 vector<int> idx = getRowIdFromTime( reftime, s ) ;
3767 if ( mode == "before" ) {
3768 int id = -1 ;
3769 if ( idx[0] != -1 ) {
3770 id = idx[0] ;
3771 }
3772 else if ( idx[1] != -1 ) {
3773 os << LogIO::WARN << "Failed to find a scan before reftime. return a spectrum just after the reftime." << LogIO::POST ;
3774 id = idx[1] ;
3775 }
3776 os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
3777 sp = s->getSpectrum( id ) ;
3778 }
3779 else if ( mode == "after" ) {
3780 int id = -1 ;
3781 if ( idx[1] != -1 ) {
3782 id = idx[1] ;
3783 }
3784 else if ( idx[0] != -1 ) {
3785 os << LogIO::WARN << "Failed to find a scan after reftime. return a spectrum just before the reftime." << LogIO::POST ;
3786 id = idx[1] ;
3787 }
3788 os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
3789 sp = s->getSpectrum( id ) ;
3790 }
3791 else if ( mode == "nearest" ) {
3792 int id = -1 ;
3793 if ( idx[0] == -1 ) {
3794 id = idx[1] ;
3795 }
3796 else if ( idx[1] == -1 ) {
3797 id = idx[0] ;
3798 }
3799 else if ( idx[0] == idx[1] ) {
3800 id = idx[0] ;
3801 }
3802 else {
3803 double t0 = getMJD( s->getTime( idx[0] ) ) ;
3804 double t1 = getMJD( s->getTime( idx[1] ) ) ;
3805 double tref = getMJD( reftime ) ;
3806 if ( abs( t0 - tref ) > abs( t1 - tref ) ) {
3807 id = idx[1] ;
3808 }
3809 else {
3810 id = idx[0] ;
3811 }
3812 }
3813 os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
3814 sp = s->getSpectrum( id ) ;
3815 }
3816 else if ( mode == "linear" ) {
3817 if ( idx[0] == -1 ) {
3818 // use after
3819 os << LogIO::WARN << "Failed to interpolate. return a spectrum just after the reftime." << LogIO::POST ;
3820 int id = idx[1] ;
3821 os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
3822 sp = s->getSpectrum( id ) ;
3823 }
3824 else if ( idx[1] == -1 ) {
3825 // use before
3826 os << LogIO::WARN << "Failed to interpolate. return a spectrum just before the reftime." << LogIO::POST ;
3827 int id = idx[0] ;
3828 os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
3829 sp = s->getSpectrum( id ) ;
3830 }
3831 else if ( idx[0] == idx[1] ) {
3832 // use before
3833 os << "No need to interporate." << LogIO::POST ;
3834 int id = idx[0] ;
3835 os << "use row " << id << " (scanno = " << s->getScan( id ) << ")" << LogIO::POST ;
3836 sp = s->getSpectrum( id ) ;
3837 }
3838 else {
3839 // do interpolation
3840 os << "interpolate between " << idx[0] << " and " << idx[1] << " (scanno: " << s->getScan( idx[0] ) << ", " << s->getScan( idx[1] ) << ")" << LogIO::POST ;
3841 double t0 = getMJD( s->getTime( idx[0] ) ) ;
3842 double t1 = getMJD( s->getTime( idx[1] ) ) ;
3843 double tref = getMJD( reftime ) ;
3844 vector<float> sp0 = s->getSpectrum( idx[0] ) ;
3845 vector<float> sp1 = s->getSpectrum( idx[1] ) ;
3846 for ( unsigned int i = 0 ; i < sp0.size() ; i++ ) {
3847 float v = ( sp1[i] - sp0[i] ) / ( t1 - t0 ) * ( tref - t0 ) + sp0[i] ;
3848 sp.push_back( v ) ;
3849 }
3850 }
3851 }
3852 else {
3853 os << LogIO::SEVERE << "Unknown mode" << LogIO::POST ;
3854 }
3855 return sp ;
3856 }
3857}
3858
3859double STMath::getMJD( string strtime )
3860{
3861 if ( strtime.find("/") == string::npos ) {
3862 // MJD time string
3863 return atof( strtime.c_str() ) ;
3864 }
3865 else {
3866 // string in YYYY/MM/DD/HH:MM:SS format
3867 uInt year = atoi( strtime.substr( 0, 4 ).c_str() ) ;
3868 uInt month = atoi( strtime.substr( 5, 2 ).c_str() ) ;
3869 uInt day = atoi( strtime.substr( 8, 2 ).c_str() ) ;
3870 uInt hour = atoi( strtime.substr( 11, 2 ).c_str() ) ;
3871 uInt minute = atoi( strtime.substr( 14, 2 ).c_str() ) ;
3872 uInt sec = atoi( strtime.substr( 17, 2 ).c_str() ) ;
3873 Time t( year, month, day, hour, minute, sec ) ;
3874 return t.modifiedJulianDay() ;
3875 }
3876}
3877
3878vector<int> STMath::getRowIdFromTime( string reftime, CountedPtr<Scantable> &s )
3879{
3880 double reft = getMJD( reftime ) ;
3881 double dtmin = 1.0e100 ;
3882 double dtmax = -1.0e100 ;
3883 vector<double> dt ;
3884 int just_before = -1 ;
3885 int just_after = -1 ;
3886 for ( int i = 0 ; i < s->nrow() ; i++ ) {
3887 dt.push_back( getMJD( s->getTime( i ) ) - reft ) ;
3888 }
3889 for ( unsigned int i = 0 ; i < dt.size() ; i++ ) {
3890 if ( dt[i] > 0.0 ) {
3891 // after reftime
3892 if ( dt[i] < dtmin ) {
3893 just_after = i ;
3894 dtmin = dt[i] ;
3895 }
3896 }
3897 else if ( dt[i] < 0.0 ) {
3898 // before reftime
3899 if ( dt[i] > dtmax ) {
3900 just_before = i ;
3901 dtmax = dt[i] ;
3902 }
3903 }
3904 else {
3905 // just a reftime
3906 just_before = i ;
3907 just_after = i ;
3908 dtmax = 0 ;
3909 dtmin = 0 ;
3910 break ;
3911 }
3912 }
3913
3914 vector<int> v ;
3915 v.push_back( just_before ) ;
3916 v.push_back( just_after ) ;
3917
3918 return v ;
3919}
3920
3921vector<float> STMath::getTcalFromTime( string reftime,
3922 CountedPtr<Scantable>& s,
3923 string mode )
3924{
3925 LogIO os( LogOrigin( "STMath", "getTcalFromTime", WHERE ) ) ;
3926 vector<float> tcal ;
3927 STTcal tcalTable = s->tcal() ;
3928 String time ;
3929 Vector<Float> tcalval ;
3930 if ( s->nrow() == 0 ) {
3931 os << LogIO::SEVERE << "No row in the input scantable. Return empty tcal." << LogIO::POST ;
3932 return tcal ;
3933 }
3934 else if ( s->nrow() == 1 ) {
3935 uInt tcalid = s->getTcalId( 0 ) ;
3936 os << "use row " << 0 << " (tcalid = " << tcalid << ")" << LogIO::POST ;
3937 tcalTable.getEntry( time, tcalval, tcalid ) ;
3938 tcalval.tovector( tcal ) ;
3939 return tcal ;
3940 }
3941 else {
3942 vector<int> idx = getRowIdFromTime( reftime, s ) ;
3943 if ( mode == "before" ) {
3944 int id = -1 ;
3945 if ( idx[0] != -1 ) {
3946 id = idx[0] ;
3947 }
3948 else if ( idx[1] != -1 ) {
3949 os << LogIO::WARN << "Failed to find a scan before reftime. return a spectrum just after the reftime." << LogIO::POST ;
3950 id = idx[1] ;
3951 }
3952 uInt tcalid = s->getTcalId( id ) ;
3953 os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
3954 tcalTable.getEntry( time, tcalval, tcalid ) ;
3955 tcalval.tovector( tcal ) ;
3956 }
3957 else if ( mode == "after" ) {
3958 int id = -1 ;
3959 if ( idx[1] != -1 ) {
3960 id = idx[1] ;
3961 }
3962 else if ( idx[0] != -1 ) {
3963 os << LogIO::WARN << "Failed to find a scan after reftime. return a spectrum just before the reftime." << LogIO::POST ;
3964 id = idx[1] ;
3965 }
3966 uInt tcalid = s->getTcalId( id ) ;
3967 os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
3968 tcalTable.getEntry( time, tcalval, tcalid ) ;
3969 tcalval.tovector( tcal ) ;
3970 }
3971 else if ( mode == "nearest" ) {
3972 int id = -1 ;
3973 if ( idx[0] == -1 ) {
3974 id = idx[1] ;
3975 }
3976 else if ( idx[1] == -1 ) {
3977 id = idx[0] ;
3978 }
3979 else if ( idx[0] == idx[1] ) {
3980 id = idx[0] ;
3981 }
3982 else {
3983 double t0 = getMJD( s->getTime( idx[0] ) ) ;
3984 double t1 = getMJD( s->getTime( idx[1] ) ) ;
3985 double tref = getMJD( reftime ) ;
3986 if ( abs( t0 - tref ) > abs( t1 - tref ) ) {
3987 id = idx[1] ;
3988 }
3989 else {
3990 id = idx[0] ;
3991 }
3992 }
3993 uInt tcalid = s->getTcalId( id ) ;
3994 os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
3995 tcalTable.getEntry( time, tcalval, tcalid ) ;
3996 tcalval.tovector( tcal ) ;
3997 }
3998 else if ( mode == "linear" ) {
3999 if ( idx[0] == -1 ) {
4000 // use after
4001 os << LogIO::WARN << "Failed to interpolate. return a spectrum just after the reftime." << LogIO::POST ;
4002 int id = idx[1] ;
4003 uInt tcalid = s->getTcalId( id ) ;
4004 os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4005 tcalTable.getEntry( time, tcalval, tcalid ) ;
4006 tcalval.tovector( tcal ) ;
4007 }
4008 else if ( idx[1] == -1 ) {
4009 // use before
4010 os << LogIO::WARN << "Failed to interpolate. return a spectrum just before the reftime." << LogIO::POST ;
4011 int id = idx[0] ;
4012 uInt tcalid = s->getTcalId( id ) ;
4013 os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4014 tcalTable.getEntry( time, tcalval, tcalid ) ;
4015 tcalval.tovector( tcal ) ;
4016 }
4017 else if ( idx[0] == idx[1] ) {
4018 // use before
4019 os << "No need to interporate." << LogIO::POST ;
4020 int id = idx[0] ;
4021 uInt tcalid = s->getTcalId( id ) ;
4022 os << "use row " << id << " (tcalid = " << tcalid << ")" << LogIO::POST ;
4023 tcalTable.getEntry( time, tcalval, tcalid ) ;
4024 tcalval.tovector( tcal ) ;
4025 }
4026 else {
4027 // do interpolation
4028 os << "interpolate between " << idx[0] << " and " << idx[1] << " (scanno: " << s->getScan( idx[0] ) << ", " << s->getScan( idx[1] ) << ")" << LogIO::POST ;
4029 double t0 = getMJD( s->getTime( idx[0] ) ) ;
4030 double t1 = getMJD( s->getTime( idx[1] ) ) ;
4031 double tref = getMJD( reftime ) ;
4032 vector<float> tcal0 ;
4033 vector<float> tcal1 ;
4034 uInt tcalid0 = s->getTcalId( idx[0] ) ;
4035 uInt tcalid1 = s->getTcalId( idx[1] ) ;
4036 tcalTable.getEntry( time, tcalval, tcalid0 ) ;
4037 tcalval.tovector( tcal0 ) ;
4038 tcalTable.getEntry( time, tcalval, tcalid1 ) ;
4039 tcalval.tovector( tcal1 ) ;
4040 for ( unsigned int i = 0 ; i < tcal0.size() ; i++ ) {
4041 float v = ( tcal1[i] - tcal0[i] ) / ( t1 - t0 ) * ( tref - t0 ) + tcal0[i] ;
4042 tcal.push_back( v ) ;
4043 }
4044 }
4045 }
4046 else {
4047 os << LogIO::SEVERE << "Unknown mode" << LogIO::POST ;
4048 }
4049 return tcal ;
4050 }
4051}
4052
4053vector<float> STMath::getCalibratedSpectra( CountedPtr<Scantable>& on,
4054 CountedPtr<Scantable>& off,
4055 CountedPtr<Scantable>& sky,
4056 CountedPtr<Scantable>& hot,
4057 CountedPtr<Scantable>& cold,
4058 int index,
4059 string antname )
4060{
4061 string reftime = on->getTime( index ) ;
4062 vector<int> ii( 1, on->getIF( index ) ) ;
4063 vector<int> ib( 1, on->getBeam( index ) ) ;
4064 vector<int> ip( 1, on->getPol( index ) ) ;
4065 vector<int> ic( 1, on->getScan( index ) ) ;
4066 STSelector sel = STSelector() ;
4067 sel.setIFs( ii ) ;
4068 sel.setBeams( ib ) ;
4069 sel.setPolarizations( ip ) ;
4070 sky->setSelection( sel ) ;
4071 hot->setSelection( sel ) ;
4072 cold->setSelection( sel ) ;
4073 off->setSelection( sel ) ;
4074 vector<float> spsky = getSpectrumFromTime( reftime, sky, "linear" ) ;
4075 vector<float> sphot = getSpectrumFromTime( reftime, hot, "linear" ) ;
4076 vector<float> spcold = getSpectrumFromTime( reftime, cold, "linear" ) ;
4077 vector<float> spoff = getSpectrumFromTime( reftime, off, "linear" ) ;
4078 vector<float> spec = on->getSpectrum( index ) ;
4079 vector<float> tcal = getTcalFromTime( reftime, sky, "linear" ) ;
4080 vector<float> sp( tcal.size() ) ;
4081 if ( antname.find( "APEX" ) != string::npos ) {
4082 // using gain array
4083 for ( unsigned int j = 0 ; j < tcal.size() ; j++ ) {
4084 float v = ( ( spec[j] - spoff[j] ) / spoff[j] )
4085 * ( spsky[j] / ( sphot[j] - spsky[j] ) ) * tcal[j] ;
4086 sp[j] = v ;
4087 }
4088 }
4089 else if ( antname.find( "ALMA" ) != string::npos ) {
4090 // two-load calibration
4091 // from equation 5 and 12 of ALMA memo 318 (Mangum 2000)
4092 //
4093 // 2009/09/09 Takeshi Nakazato
4094 for ( unsigned int j = 0 ; j < tcal.size() ; j++ ) {
4095 //
4096 // in case that Tcal is assumed as signal gain
4097 //
4098 //float K = ( sphot[j] - spcold[j] ) / ( thot - tcold ) ;
4099 //float v = ( spec[j] - spoff[j] ) * exp( tsig ) / ( K * tcal[j] * eta ) ;
4100 //
4101 // in case that Tcal is defined as
4102 //
4103 // Tcal = ( K * Gs * eta_l * exp( - tau_s ) )^-1
4104 //
4105 float v = tcal[j] * ( spec[j] - spsky[j] ) ;
4106 sp[j] = v ;
4107 }
4108 }
4109 else {
4110 // Chopper-Wheel calibration (Ulich & Haas 1976)
4111 for ( unsigned int j = 0 ; j < tcal.size() ; j++ ) {
4112 float v = ( spec[j] - spoff[j] ) / ( sphot[j] - spsky[j] ) * tcal[j] ;
4113 sp[j] = v ;
4114 }
4115 }
4116 sel.reset() ;
4117 sky->unsetSelection() ;
4118 hot->unsetSelection() ;
4119 cold->unsetSelection() ;
4120 off->unsetSelection() ;
4121
4122 return sp ;
4123}
4124
4125vector<float> STMath::getFSCalibratedSpectra( CountedPtr<Scantable>& sig,
4126 CountedPtr<Scantable>& ref,
4127 CountedPtr<Scantable>& sky,
4128 CountedPtr<Scantable>& hot,
4129 CountedPtr<Scantable>& cold,
4130 int index )
4131{
4132 string reftime = sig->getTime( index ) ;
4133 vector<int> ii( 1, sig->getIF( index ) ) ;
4134 vector<int> ib( 1, sig->getBeam( index ) ) ;
4135 vector<int> ip( 1, sig->getPol( index ) ) ;
4136 vector<int> ic( 1, sig->getScan( index ) ) ;
4137 STSelector sel = STSelector() ;
4138 sel.setIFs( ii ) ;
4139 sel.setBeams( ib ) ;
4140 sel.setPolarizations( ip ) ;
4141 sky->setSelection( sel ) ;
4142 hot->setSelection( sel ) ;
4143 cold->setSelection( sel ) ;
4144 vector<float> spsky = getSpectrumFromTime( reftime, sky, "linear" ) ;
4145 vector<float> sphot = getSpectrumFromTime( reftime, hot, "linear" ) ;
4146 vector<float> spcold = getSpectrumFromTime( reftime, cold, "linear" ) ;
4147 vector<float> spref = ref->getSpectrum( index ) ;
4148 vector<float> spsig = sig->getSpectrum( index ) ;
4149 vector<float> tcal = getTcalFromTime( reftime, sky, "linear" ) ;
4150 vector<float> sp( tcal.size() ) ;
4151 for ( unsigned int j = 0 ; j < tcal.size() ; j++ ) {
4152 float v = tcal[j] * spsky[j] / ( sphot[j] - spsky[j] ) * ( spsig[j] - spref[j] ) / spref[j] ;
4153 sp[j] = v ;
4154 }
4155 sel.reset() ;
4156 sky->unsetSelection() ;
4157 hot->unsetSelection() ;
4158 cold->unsetSelection() ;
4159
4160 return sp ;
4161}
4162
4163vector<float> STMath::getFSCalibratedSpectra( CountedPtr<Scantable>& sig,
4164 CountedPtr<Scantable>& ref,
4165 vector< CountedPtr<Scantable> >& sky,
4166 vector< CountedPtr<Scantable> >& hot,
4167 vector< CountedPtr<Scantable> >& cold,
4168 int index )
4169{
4170 string reftime = sig->getTime( index ) ;
4171 vector<int> ii( 1, sig->getIF( index ) ) ;
4172 vector<int> ib( 1, sig->getBeam( index ) ) ;
4173 vector<int> ip( 1, sig->getPol( index ) ) ;
4174 vector<int> ic( 1, sig->getScan( index ) ) ;
4175 STSelector sel = STSelector() ;
4176 sel.setIFs( ii ) ;
4177 sel.setBeams( ib ) ;
4178 sel.setPolarizations( ip ) ;
4179 sky[0]->setSelection( sel ) ;
4180 hot[0]->setSelection( sel ) ;
4181 cold[0]->setSelection( sel ) ;
4182 vector<float> spskys = getSpectrumFromTime( reftime, sky[0], "linear" ) ;
4183 vector<float> sphots = getSpectrumFromTime( reftime, hot[0], "linear" ) ;
4184 vector<float> spcolds = getSpectrumFromTime( reftime, cold[0], "linear" ) ;
4185 vector<float> tcals = getTcalFromTime( reftime, sky[0], "linear" ) ;
4186 sel.reset() ;
4187 ii[0] = ref->getIF( index ) ;
4188 sel.setIFs( ii ) ;
4189 sel.setBeams( ib ) ;
4190 sel.setPolarizations( ip ) ;
4191 sky[1]->setSelection( sel ) ;
4192 hot[1]->setSelection( sel ) ;
4193 cold[1]->setSelection( sel ) ;
4194 vector<float> spskyr = getSpectrumFromTime( reftime, sky[1], "linear" ) ;
4195 vector<float> sphotr = getSpectrumFromTime( reftime, hot[1], "linear" ) ;
4196 vector<float> spcoldr = getSpectrumFromTime( reftime, cold[1], "linear" ) ;
4197 vector<float> tcalr = getTcalFromTime( reftime, sky[1], "linear" ) ;
4198 vector<float> spref = ref->getSpectrum( index ) ;
4199 vector<float> spsig = sig->getSpectrum( index ) ;
4200 vector<float> sp( tcals.size() ) ;
4201 for ( unsigned int j = 0 ; j < tcals.size() ; j++ ) {
4202 float v = tcals[j] * spsig[j] / ( sphots[j] - spskys[j] ) - tcalr[j] * spref[j] / ( sphotr[j] - spskyr[j] ) ;
4203 sp[j] = v ;
4204 }
4205 sel.reset() ;
4206 sky[0]->unsetSelection() ;
4207 hot[0]->unsetSelection() ;
4208 cold[0]->unsetSelection() ;
4209 sky[1]->unsetSelection() ;
4210 hot[1]->unsetSelection() ;
4211 cold[1]->unsetSelection() ;
4212
4213 return sp ;
4214}
Note: See TracBrowser for help on using the repository browser.