source: trunk/src/STMath.cpp@ 2977

Last change on this file since 2977 was 2974, checked in by WataruKawasaki, 10 years ago

New Development: No

JIRA Issue: Yes CAS-6594

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs: test_sdmath

Put in Release Notes: No

Module(s): sd

Description: modified STMath::binaryOperate() so that:

(1) If one of or both spectra are row-flagged,

operation will be skipped so the 'left'
spectrum values are not modified, while
the FLAGROW of the output spectrum will
be set flagged.

(2) Otherwise, operation is executed for all

channels even if there are masked ones.
If a channel is flagged in one of or both
spectra, operation is done for that channel
but the channel is flagged.


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