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

Last change on this file since 1613 was 1611, checked in by Takeshi Nakazato, 15 years ago

New Development: No

JIRA Issue: Yes CAS-1423

Ready to Release: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: No

Module(s): Module Names change impacts.

Description: Describe your changes here...

Averaging methods are changed to refer DIRECTION all the time.
This change affects the behavior of sdaverage when timeaverage is
set to True.
Tolerance for direction is set to 1.0e-15 rad for OTF data and
is set to 1.0e-5 rad (around 2 arcsec) for non-OTF data.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 107.7 KB
Line 
1//
2// C++ Implementation: STMath
3//
4// Description:
5//
6//
7// Author: Malte Marquarding <asap@atnf.csiro.au>, (C) 2006
8//
9// Copyright: See COPYING file that comes with this distribution
10//
11//
12
13#include <casa/iomanip.h>
14#include <casa/Exceptions/Error.h>
15#include <casa/Containers/Block.h>
16#include <casa/BasicSL/String.h>
17#include <casa/Arrays/MaskArrLogi.h>
18#include <casa/Arrays/MaskArrMath.h>
19#include <casa/Arrays/ArrayLogical.h>
20#include <casa/Arrays/ArrayMath.h>
21#include <casa/Arrays/Slice.h>
22#include <casa/Arrays/Slicer.h>
23#include <casa/Containers/RecordField.h>
24#include <tables/Tables/TableRow.h>
25#include <tables/Tables/TableVector.h>
26#include <tables/Tables/TabVecMath.h>
27#include <tables/Tables/ExprNode.h>
28#include <tables/Tables/TableRecord.h>
29#include <tables/Tables/TableParse.h>
30#include <tables/Tables/ReadAsciiTable.h>
31#include <tables/Tables/TableIter.h>
32#include <tables/Tables/TableCopy.h>
33#include <scimath/Mathematics/FFTServer.h>
34
35#include <lattices/Lattices/LatticeUtilities.h>
36
37#include <coordinates/Coordinates/SpectralCoordinate.h>
38#include <coordinates/Coordinates/CoordinateSystem.h>
39#include <coordinates/Coordinates/CoordinateUtil.h>
40#include <coordinates/Coordinates/FrequencyAligner.h>
41
42#include <scimath/Mathematics/VectorKernel.h>
43#include <scimath/Mathematics/Convolver.h>
44#include <scimath/Functionals/Polynomial.h>
45
46#include "MathUtils.h"
47#include "RowAccumulator.h"
48#include "STAttr.h"
49#include "STMath.h"
50#include "STSelector.h"
51
52using namespace casa;
53
54using namespace asap;
55
56// tolerance for direction comparison (rad)
57#define TOL_OTF 1.0e-15
58#define TOL_POINT 1.0e-5 // 2 arcsec
59
60STMath::STMath(bool insitu) :
61 insitu_(insitu)
62{
63}
64
65
66STMath::~STMath()
67{
68}
69
70CountedPtr<Scantable>
71STMath::average( const std::vector<CountedPtr<Scantable> >& in,
72 const std::vector<bool>& mask,
73 const std::string& weight,
74 const std::string& avmode)
75{
76 if ( avmode == "SCAN" && in.size() != 1 )
77 throw(AipsError("Can't perform 'SCAN' averaging on multiple tables.\n"
78 "Use merge first."));
79 WeightType wtype = stringToWeight(weight);
80
81 // check if OTF observation
82 String obstype = in[0]->getHeader().obstype ;
83 //bool otfscan = false ;
84 Double tol = 0.0 ;
85 if ( obstype.find( "OTF" ) != String::npos ) {
86 //cout << "OTF scan" << endl ;
87 //otfscan = true ;
88 tol = TOL_OTF ;
89 }
90 else {
91 tol = TOL_POINT ;
92 }
93
94 // output
95 // clone as this is non insitu
96 bool insitu = insitu_;
97 setInsitu(false);
98 CountedPtr< Scantable > out = getScantable(in[0], true);
99 setInsitu(insitu);
100 std::vector<CountedPtr<Scantable> >::const_iterator stit = in.begin();
101 ++stit;
102 while ( stit != in.end() ) {
103 out->appendToHistoryTable((*stit)->history());
104 ++stit;
105 }
106
107 Table& tout = out->table();
108
109 /// @todo check if all scantables are conformant
110
111 ArrayColumn<Float> specColOut(tout,"SPECTRA");
112 ArrayColumn<uChar> flagColOut(tout,"FLAGTRA");
113 ArrayColumn<Float> tsysColOut(tout,"TSYS");
114 ScalarColumn<Double> mjdColOut(tout,"TIME");
115 ScalarColumn<Double> intColOut(tout,"INTERVAL");
116 ScalarColumn<uInt> cycColOut(tout,"CYCLENO");
117 ScalarColumn<uInt> scanColOut(tout,"SCANNO");
118
119 // set up the output table rows. These are based on the structure of the
120 // FIRST scantable in the vector
121 const Table& baset = in[0]->table();
122
123 Block<String> cols(3);
124 cols[0] = String("BEAMNO");
125 cols[1] = String("IFNO");
126 cols[2] = String("POLNO");
127 if ( avmode == "SOURCE" ) {
128 cols.resize(4);
129 cols[3] = String("SRCNAME");
130 }
131 if ( avmode == "SCAN" && in.size() == 1) {
132 //cols.resize(4);
133 //cols[3] = String("SCANNO");
134 cols.resize(5);
135 cols[3] = String("SRCNAME");
136 cols[4] = String("SCANNO");
137 }
138 uInt outrowCount = 0;
139 TableIterator iter(baset, cols);
140// int count = 0 ;
141 while (!iter.pastEnd()) {
142 Table subt = iter.table();
143// // copy the first row of this selection into the new table
144// tout.addRow();
145// TableCopy::copyRows(tout, subt, outrowCount, 0, 1);
146// // re-index to 0
147// if ( avmode != "SCAN" && avmode != "SOURCE" ) {
148// scanColOut.put(outrowCount, uInt(0));
149// }
150// ++outrowCount;
151 MDirection::ScalarColumn dircol ;
152 dircol.attach( subt, "DIRECTION" ) ;
153 Int length = subt.nrow() ;
154 vector< Vector<Double> > dirs ;
155 vector<int> indexes ;
156 for ( Int i = 0 ; i < length ; i++ ) {
157 Vector<Double> t = dircol(i).getAngle(Unit(String("rad"))).getValue() ;
158 //cout << setw( 3 ) << count++ << ": " ;
159 //cout << "[" << t[0] << "," << t[1] << "]" << endl ;
160 bool adddir = true ;
161 for ( uInt j = 0 ; j < dirs.size() ; j++ ) {
162 //if ( allTrue( t == dirs[j] ) ) {
163 Double dx = t[0] - dirs[j][0] ;
164 Double dy = t[1] - dirs[j][1] ;
165 Double dd = sqrt( dx * dx + dy * dy ) ;
166 //if ( allNearAbs( t, dirs[j], tol ) ) {
167 if ( dd <= tol ) {
168 adddir = false ;
169 break ;
170 }
171 }
172 if ( adddir ) {
173 dirs.push_back( t ) ;
174 indexes.push_back( i ) ;
175 }
176 }
177 uInt rowNum = dirs.size() ;
178 //cout << "dirs.size()=" << dirs.size() << endl ;
179 tout.addRow( rowNum ) ;
180 for ( uInt i = 0 ; i < rowNum ; i++ ) {
181 TableCopy::copyRows( tout, subt, outrowCount+i, indexes[i], 1 ) ;
182 // re-index to 0
183 if ( avmode != "SCAN" && avmode != "SOURCE" ) {
184 scanColOut.put(outrowCount+i, uInt(0));
185 }
186 }
187 outrowCount += rowNum ;
188 ++iter;
189 }
190 RowAccumulator acc(wtype);
191 Vector<Bool> cmask(mask);
192 acc.setUserMask(cmask);
193 ROTableRow row(tout);
194 ROArrayColumn<Float> specCol, tsysCol;
195 ROArrayColumn<uChar> flagCol;
196 ROScalarColumn<Double> mjdCol, intCol;
197 ROScalarColumn<Int> scanIDCol;
198
199 Vector<uInt> rowstodelete;
200
201 for (uInt i=0; i < tout.nrow(); ++i) {
202 for ( int j=0; j < int(in.size()); ++j ) {
203 const Table& tin = in[j]->table();
204 const TableRecord& rec = row.get(i);
205 ROScalarColumn<Double> tmp(tin, "TIME");
206 Double td;tmp.get(0,td);
207 Table basesubt = tin(tin.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
208 && tin.col("IFNO") == Int(rec.asuInt("IFNO"))
209 && tin.col("POLNO") == Int(rec.asuInt("POLNO")) );
210 Table subt;
211 if ( avmode == "SOURCE") {
212 subt = basesubt( basesubt.col("SRCNAME") == rec.asString("SRCNAME") );
213 } else if (avmode == "SCAN") {
214 //subt = basesubt( basesubt.col("SCANNO") == Int(rec.asuInt("SCANNO")) );
215 subt = basesubt( basesubt.col("SCANNO") == Int(rec.asuInt("SCANNO"))
216 && basesubt.col("SRCNAME") == rec.asString("SRCNAME") );
217 } else {
218 subt = basesubt;
219 }
220
221 vector<uInt> removeRows ;
222 uInt nrsubt = subt.nrow() ;
223 for ( uInt irow = 0 ; irow < nrsubt ; irow++ ) {
224 //if ( !allTrue((subt.col("DIRECTION").getArrayDouble(TableExprId(irow)))==rec.asArrayDouble("DIRECTION")) ) {
225 Vector<Double> x0 = (subt.col("DIRECTION").getArrayDouble(TableExprId(irow))) ;
226 Vector<Double> x1 = rec.asArrayDouble("DIRECTION") ;
227 double dx = x0[0] - x1[0] ;
228 double dy = x0[0] - x1[0] ;
229 Double dd = sqrt( dx * dx + dy * dy ) ;
230 //if ( !allNearAbs((subt.col("DIRECTION").getArrayDouble(TableExprId(irow))), rec.asArrayDouble("DIRECTION"), tol ) ) {
231 if ( dd > tol ) {
232 removeRows.push_back( irow ) ;
233 }
234 }
235 //cout << "removeRows.size()=" << removeRows.size() << endl ;
236 if ( removeRows.size() != 0 ) {
237 //cout << "[" ;
238 //for ( uInt irow=0 ; irow<removeRows.size()-1 ; irow++ )
239 //cout << removeRows[irow] << "," ;
240 //cout << removeRows[removeRows.size()-1] << "]" << endl ;
241 subt.removeRow( removeRows ) ;
242 }
243
244 if ( nrsubt == removeRows.size() )
245 throw(AipsError("Averaging data is empty.")) ;
246
247 specCol.attach(subt,"SPECTRA");
248 flagCol.attach(subt,"FLAGTRA");
249 tsysCol.attach(subt,"TSYS");
250 intCol.attach(subt,"INTERVAL");
251 mjdCol.attach(subt,"TIME");
252 Vector<Float> spec,tsys;
253 Vector<uChar> flag;
254 Double inter,time;
255 for (uInt k = 0; k < subt.nrow(); ++k ) {
256 flagCol.get(k, flag);
257 Vector<Bool> bflag(flag.shape());
258 convertArray(bflag, flag);
259 /*
260 if ( allEQ(bflag, True) ) {
261 continue;//don't accumulate
262 }
263 */
264 specCol.get(k, spec);
265 tsysCol.get(k, tsys);
266 intCol.get(k, inter);
267 mjdCol.get(k, time);
268 // spectrum has to be added last to enable weighting by the other values
269 acc.add(spec, !bflag, tsys, inter, time);
270 }
271 }
272 const Vector<Bool>& msk = acc.getMask();
273 if ( allEQ(msk, False) ) {
274 uint n = rowstodelete.nelements();
275 rowstodelete.resize(n+1, True);
276 rowstodelete[n] = i;
277 continue;
278 }
279 //write out
280 if (acc.state()) {
281 Vector<uChar> flg(msk.shape());
282 convertArray(flg, !msk);
283 flagColOut.put(i, flg);
284 specColOut.put(i, acc.getSpectrum());
285 tsysColOut.put(i, acc.getTsys());
286 intColOut.put(i, acc.getInterval());
287 mjdColOut.put(i, acc.getTime());
288 // we should only have one cycle now -> reset it to be 0
289 // frequency switched data has different CYCLENO for different IFNO
290 // which requires resetting this value
291 cycColOut.put(i, uInt(0));
292 } else {
293 ostringstream oss;
294 oss << "For output row="<<i<<", all input rows of data are flagged. no averaging" << endl;
295 pushLog(String(oss));
296 }
297 acc.reset();
298 }
299 if (rowstodelete.nelements() > 0) {
300 cout << rowstodelete << endl;
301 tout.removeRow(rowstodelete);
302 if (tout.nrow() == 0) {
303 throw(AipsError("Can't average fully flagged data."));
304 }
305 }
306 return out;
307}
308
309CountedPtr< Scantable >
310 STMath::averageChannel( const CountedPtr < Scantable > & in,
311 const std::string & mode,
312 const std::string& avmode )
313{
314 // check if OTF observation
315 String obstype = in->getHeader().obstype ;
316 //bool otfscan = false ;
317 Double tol = 0.0 ;
318 if ( obstype.find( "OTF" ) != String::npos ) {
319 //cout << "OTF scan" << endl ;
320 //otfscan = true ;
321 tol = TOL_OTF ;
322 }
323 else {
324 tol = TOL_POINT ;
325 }
326
327 // clone as this is non insitu
328 bool insitu = insitu_;
329 setInsitu(false);
330 CountedPtr< Scantable > out = getScantable(in, true);
331 setInsitu(insitu);
332 Table& tout = out->table();
333 ArrayColumn<Float> specColOut(tout,"SPECTRA");
334 ArrayColumn<uChar> flagColOut(tout,"FLAGTRA");
335 ArrayColumn<Float> tsysColOut(tout,"TSYS");
336 ScalarColumn<uInt> scanColOut(tout,"SCANNO");
337 ScalarColumn<Double> intColOut(tout, "INTERVAL");
338 Table tmp = in->table().sort("BEAMNO");
339 Block<String> cols(3);
340 cols[0] = String("BEAMNO");
341 cols[1] = String("IFNO");
342 cols[2] = String("POLNO");
343 if ( avmode == "SCAN") {
344 cols.resize(4);
345 cols[3] = String("SCANNO");
346 }
347 uInt outrowCount = 0;
348 uChar userflag = 1 << 7;
349 TableIterator iter(tmp, cols);
350 while (!iter.pastEnd()) {
351 Table subt = iter.table();
352 ROArrayColumn<Float> specCol, tsysCol;
353 ROArrayColumn<uChar> flagCol;
354 ROScalarColumn<Double> intCol(subt, "INTERVAL");
355 specCol.attach(subt,"SPECTRA");
356 flagCol.attach(subt,"FLAGTRA");
357 tsysCol.attach(subt,"TSYS");
358// tout.addRow();
359// TableCopy::copyRows(tout, subt, outrowCount, 0, 1);
360// if ( avmode != "SCAN") {
361// scanColOut.put(outrowCount, uInt(0));
362// }
363// Vector<Float> tmp;
364// specCol.get(0, tmp);
365// uInt nchan = tmp.nelements();
366// // have to do channel by channel here as MaskedArrMath
367// // doesn't have partialMedians
368// Vector<uChar> flags = flagCol.getColumn(Slicer(Slice(0)));
369// Vector<Float> outspec(nchan);
370// Vector<uChar> outflag(nchan,0);
371// Vector<Float> outtsys(1);/// @fixme when tsys is channel based
372// for (uInt i=0; i<nchan; ++i) {
373// Vector<Float> specs = specCol.getColumn(Slicer(Slice(i)));
374// MaskedArray<Float> ma = maskedArray(specs,flags);
375// outspec[i] = median(ma);
376// if ( allEQ(ma.getMask(), False) )
377// outflag[i] = userflag;// flag data
378// }
379// outtsys[0] = median(tsysCol.getColumn());
380// specColOut.put(outrowCount, outspec);
381// flagColOut.put(outrowCount, outflag);
382// tsysColOut.put(outrowCount, outtsys);
383// Double intsum = sum(intCol.getColumn());
384// intColOut.put(outrowCount, intsum);
385// ++outrowCount;
386// ++iter;
387 MDirection::ScalarColumn dircol ;
388 dircol.attach( subt, "DIRECTION" ) ;
389 Int length = subt.nrow() ;
390 vector< Vector<Double> > dirs ;
391 vector<int> indexes ;
392 for ( Int i = 0 ; i < length ; i++ ) {
393 Vector<Double> t = dircol(i).getAngle(Unit(String("rad"))).getValue() ;
394 bool adddir = true ;
395 for ( uInt j = 0 ; j < dirs.size() ; j++ ) {
396 //if ( allTrue( t == dirs[j] ) ) {
397 Double dx = t[0] - dirs[j][0] ;
398 Double dy = t[1] - dirs[j][1] ;
399 Double dd = sqrt( dx * dx + dy * dy ) ;
400 //if ( allNearAbs( t, dirs[j], tol ) ) {
401 if ( dd <= tol ) {
402 adddir = false ;
403 break ;
404 }
405 }
406 if ( adddir ) {
407 dirs.push_back( t ) ;
408 indexes.push_back( i ) ;
409 }
410 }
411 uInt rowNum = dirs.size() ;
412 tout.addRow( rowNum );
413 for ( uInt i = 0 ; i < rowNum ; i++ ) {
414 TableCopy::copyRows(tout, subt, outrowCount+i, indexes[i], 1) ;
415 if ( avmode != "SCAN") {
416 //scanColOut.put(outrowCount+i, uInt(0));
417 }
418 }
419 MDirection::ScalarColumn dircolOut ;
420 dircolOut.attach( tout, "DIRECTION" ) ;
421 for ( uInt irow = 0 ; irow < rowNum ; irow++ ) {
422 Vector<Double> t = dircolOut(outrowCount+irow).getAngle(Unit(String("rad"))).getValue() ;
423 Vector<Float> tmp;
424 specCol.get(0, tmp);
425 uInt nchan = tmp.nelements();
426 // have to do channel by channel here as MaskedArrMath
427 // doesn't have partialMedians
428 Vector<uChar> flags = flagCol.getColumn(Slicer(Slice(0)));
429 // mask spectra for different DIRECTION
430 //cout << "irow=" << outrowCount+irow << ": flagged [" ;
431 for ( uInt jrow = 0 ; jrow < subt.nrow() ; jrow++ ) {
432 Vector<Double> direction = dircol(jrow).getAngle(Unit(String("rad"))).getValue() ;
433 //if ( t[0] != direction[0] || t[1] != direction[1] ) {
434 Double dx = t[0] - direction[0] ;
435 Double dy = t[1] - direction[1] ;
436 Double dd = sqrt( dx * dx + dy * dy ) ;
437 //if ( !allNearAbs( t, direction, tol ) ) {
438 if ( dd > tol ) {
439 //cout << jrow << " " ;
440 flags[jrow] = userflag ;
441 }
442 }
443 //cout << "]" << endl ;
444 //cout << "flags=" << flags << endl ;
445 Vector<Float> outspec(nchan);
446 Vector<uChar> outflag(nchan,0);
447 Vector<Float> outtsys(1);/// @fixme when tsys is channel based
448 for (uInt i=0; i<nchan; ++i) {
449 Vector<Float> specs = specCol.getColumn(Slicer(Slice(i)));
450 MaskedArray<Float> ma = maskedArray(specs,flags);
451 outspec[i] = median(ma);
452 if ( allEQ(ma.getMask(), False) )
453 outflag[i] = userflag;// flag data
454 }
455 outtsys[0] = median(tsysCol.getColumn());
456 specColOut.put(outrowCount+irow, outspec);
457 flagColOut.put(outrowCount+irow, outflag);
458 tsysColOut.put(outrowCount+irow, outtsys);
459 Vector<Double> integ = intCol.getColumn() ;
460 MaskedArray<Double> mi = maskedArray( integ, flags ) ;
461 Double intsum = sum(mi);
462 intColOut.put(outrowCount+irow, intsum);
463 }
464 outrowCount += rowNum ;
465 ++iter;
466 }
467 return out;
468}
469
470CountedPtr< Scantable > STMath::getScantable(const CountedPtr< Scantable >& in,
471 bool droprows)
472{
473 if (insitu_) {
474 return in;
475 }
476 else {
477 // clone
478 return CountedPtr<Scantable>(new Scantable(*in, Bool(droprows)));
479 }
480}
481
482CountedPtr< Scantable > STMath::unaryOperate( const CountedPtr< Scantable >& in,
483 float val,
484 const std::string& mode,
485 bool tsys )
486{
487 CountedPtr< Scantable > out = getScantable(in, false);
488 Table& tab = out->table();
489 ArrayColumn<Float> specCol(tab,"SPECTRA");
490 ArrayColumn<Float> tsysCol(tab,"TSYS");
491 for (uInt i=0; i<tab.nrow(); ++i) {
492 Vector<Float> spec;
493 Vector<Float> ts;
494 specCol.get(i, spec);
495 tsysCol.get(i, ts);
496 if (mode == "MUL" || mode == "DIV") {
497 if (mode == "DIV") val = 1.0/val;
498 spec *= val;
499 specCol.put(i, spec);
500 if ( tsys ) {
501 ts *= val;
502 tsysCol.put(i, ts);
503 }
504 } else if ( mode == "ADD" || mode == "SUB") {
505 if (mode == "SUB") val *= -1.0;
506 spec += val;
507 specCol.put(i, spec);
508 if ( tsys ) {
509 ts += val;
510 tsysCol.put(i, ts);
511 }
512 }
513 }
514 return out;
515}
516
517CountedPtr<Scantable> STMath::binaryOperate(const CountedPtr<Scantable>& left,
518 const CountedPtr<Scantable>& right,
519 const std::string& mode)
520{
521 bool insitu = insitu_;
522 if ( ! left->conformant(*right) ) {
523 throw(AipsError("'left' and 'right' scantables are not conformant."));
524 }
525 setInsitu(false);
526 CountedPtr< Scantable > out = getScantable(left, false);
527 setInsitu(insitu);
528 Table& tout = out->table();
529 Block<String> coln(5);
530 coln[0] = "SCANNO"; coln[1] = "CYCLENO"; coln[2] = "BEAMNO";
531 coln[3] = "IFNO"; coln[4] = "POLNO";
532 Table tmpl = tout.sort(coln);
533 Table tmpr = right->table().sort(coln);
534 ArrayColumn<Float> lspecCol(tmpl,"SPECTRA");
535 ROArrayColumn<Float> rspecCol(tmpr,"SPECTRA");
536 ArrayColumn<uChar> lflagCol(tmpl,"FLAGTRA");
537 ROArrayColumn<uChar> rflagCol(tmpr,"FLAGTRA");
538
539 for (uInt i=0; i<tout.nrow(); ++i) {
540 Vector<Float> lspecvec, rspecvec;
541 Vector<uChar> lflagvec, rflagvec;
542 lspecvec = lspecCol(i); rspecvec = rspecCol(i);
543 lflagvec = lflagCol(i); rflagvec = rflagCol(i);
544 MaskedArray<Float> mleft = maskedArray(lspecvec, lflagvec);
545 MaskedArray<Float> mright = maskedArray(rspecvec, rflagvec);
546 if (mode == "ADD") {
547 mleft += mright;
548 } else if ( mode == "SUB") {
549 mleft -= mright;
550 } else if ( mode == "MUL") {
551 mleft *= mright;
552 } else if ( mode == "DIV") {
553 mleft /= mright;
554 } else {
555 throw(AipsError("Illegal binary operator"));
556 }
557 lspecCol.put(i, mleft.getArray());
558 }
559 return out;
560}
561
562
563
564MaskedArray<Float> STMath::maskedArray( const Vector<Float>& s,
565 const Vector<uChar>& f)
566{
567 Vector<Bool> mask;
568 mask.resize(f.shape());
569 convertArray(mask, f);
570 return MaskedArray<Float>(s,!mask);
571}
572
573MaskedArray<Double> STMath::maskedArray( const Vector<Double>& s,
574 const Vector<uChar>& f)
575{
576 Vector<Bool> mask;
577 mask.resize(f.shape());
578 convertArray(mask, f);
579 return MaskedArray<Double>(s,!mask);
580}
581
582Vector<uChar> STMath::flagsFromMA(const MaskedArray<Float>& ma)
583{
584 const Vector<Bool>& m = ma.getMask();
585 Vector<uChar> flags(m.shape());
586 convertArray(flags, !m);
587 return flags;
588}
589
590CountedPtr< Scantable > STMath::autoQuotient( const CountedPtr< Scantable >& in,
591 const std::string & mode,
592 bool preserve )
593{
594 /// @todo make other modes available
595 /// modes should be "nearest", "pair"
596 // make this operation non insitu
597 const Table& tin = in->table();
598 Table ons = tin(tin.col("SRCTYPE") == Int(0));
599 Table offs = tin(tin.col("SRCTYPE") == Int(1));
600 if ( offs.nrow() == 0 )
601 throw(AipsError("No 'off' scans present."));
602 // put all "on" scans into output table
603
604 bool insitu = insitu_;
605 setInsitu(false);
606 CountedPtr< Scantable > out = getScantable(in, true);
607 setInsitu(insitu);
608 Table& tout = out->table();
609
610 TableCopy::copyRows(tout, ons);
611 TableRow row(tout);
612 ROScalarColumn<Double> offtimeCol(offs, "TIME");
613 ArrayColumn<Float> outspecCol(tout, "SPECTRA");
614 ROArrayColumn<Float> outtsysCol(tout, "TSYS");
615 ArrayColumn<uChar> outflagCol(tout, "FLAGTRA");
616 for (uInt i=0; i < tout.nrow(); ++i) {
617 const TableRecord& rec = row.get(i);
618 Double ontime = rec.asDouble("TIME");
619 Table presel = offs(offs.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
620 && offs.col("IFNO") == Int(rec.asuInt("IFNO"))
621 && offs.col("POLNO") == Int(rec.asuInt("POLNO")) );
622 ROScalarColumn<Double> offtimeCol(presel, "TIME");
623
624 Double mindeltat = min(abs(offtimeCol.getColumn() - ontime));
625 // Timestamp may vary within a cycle ???!!!
626 // increase this by 0.01 sec in case of rounding errors...
627 // There might be a better way to do this.
628 // fix to this fix. TIME is MJD, so 1.0d not 1.0s
629 mindeltat += 0.01/24./60./60.;
630 Table sel = presel( abs(presel.col("TIME")-ontime) <= mindeltat);
631
632 if ( sel.nrow() < 1 ) {
633 throw(AipsError("No closest in time found... This could be a rounding "
634 "issue. Try quotient instead."));
635 }
636 TableRow offrow(sel);
637 const TableRecord& offrec = offrow.get(0);//should only be one row
638 RORecordFieldPtr< Array<Float> > specoff(offrec, "SPECTRA");
639 RORecordFieldPtr< Array<Float> > tsysoff(offrec, "TSYS");
640 RORecordFieldPtr< Array<uChar> > flagoff(offrec, "FLAGTRA");
641 /// @fixme this assumes tsys is a scalar not vector
642 Float tsysoffscalar = (*tsysoff)(IPosition(1,0));
643 Vector<Float> specon, tsyson;
644 outtsysCol.get(i, tsyson);
645 outspecCol.get(i, specon);
646 Vector<uChar> flagon;
647 outflagCol.get(i, flagon);
648 MaskedArray<Float> mon = maskedArray(specon, flagon);
649 MaskedArray<Float> moff = maskedArray(*specoff, *flagoff);
650 MaskedArray<Float> quot = (tsysoffscalar * mon / moff);
651 if (preserve) {
652 quot -= tsysoffscalar;
653 } else {
654 quot -= tsyson[0];
655 }
656 outspecCol.put(i, quot.getArray());
657 outflagCol.put(i, flagsFromMA(quot));
658 }
659 // renumber scanno
660 TableIterator it(tout, "SCANNO");
661 uInt i = 0;
662 while ( !it.pastEnd() ) {
663 Table t = it.table();
664 TableVector<uInt> vec(t, "SCANNO");
665 vec = i;
666 ++i;
667 ++it;
668 }
669 return out;
670}
671
672
673CountedPtr< Scantable > STMath::quotient( const CountedPtr< Scantable > & on,
674 const CountedPtr< Scantable > & off,
675 bool preserve )
676{
677 bool insitu = insitu_;
678 if ( ! on->conformant(*off) ) {
679 throw(AipsError("'on' and 'off' scantables are not conformant."));
680 }
681 setInsitu(false);
682 CountedPtr< Scantable > out = getScantable(on, false);
683 setInsitu(insitu);
684 Table& tout = out->table();
685 const Table& toff = off->table();
686 TableIterator sit(tout, "SCANNO");
687 TableIterator s2it(toff, "SCANNO");
688 while ( !sit.pastEnd() ) {
689 Table ton = sit.table();
690 TableRow row(ton);
691 Table t = s2it.table();
692 ArrayColumn<Float> outspecCol(ton, "SPECTRA");
693 ROArrayColumn<Float> outtsysCol(ton, "TSYS");
694 ArrayColumn<uChar> outflagCol(ton, "FLAGTRA");
695 for (uInt i=0; i < ton.nrow(); ++i) {
696 const TableRecord& rec = row.get(i);
697 Table offsel = t( t.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
698 && t.col("IFNO") == Int(rec.asuInt("IFNO"))
699 && t.col("POLNO") == Int(rec.asuInt("POLNO")) );
700 if ( offsel.nrow() == 0 )
701 throw AipsError("STMath::quotient: no matching off");
702 TableRow offrow(offsel);
703 const TableRecord& offrec = offrow.get(0);//should be ncycles - take first
704 RORecordFieldPtr< Array<Float> > specoff(offrec, "SPECTRA");
705 RORecordFieldPtr< Array<Float> > tsysoff(offrec, "TSYS");
706 RORecordFieldPtr< Array<uChar> > flagoff(offrec, "FLAGTRA");
707 Float tsysoffscalar = (*tsysoff)(IPosition(1,0));
708 Vector<Float> specon, tsyson;
709 outtsysCol.get(i, tsyson);
710 outspecCol.get(i, specon);
711 Vector<uChar> flagon;
712 outflagCol.get(i, flagon);
713 MaskedArray<Float> mon = maskedArray(specon, flagon);
714 MaskedArray<Float> moff = maskedArray(*specoff, *flagoff);
715 MaskedArray<Float> quot = (tsysoffscalar * mon / moff);
716 if (preserve) {
717 quot -= tsysoffscalar;
718 } else {
719 quot -= tsyson[0];
720 }
721 outspecCol.put(i, quot.getArray());
722 outflagCol.put(i, flagsFromMA(quot));
723 }
724 ++sit;
725 ++s2it;
726 // take the first off for each on scan which doesn't have a
727 // matching off scan
728 // non <= noff: matching pairs, non > noff matching pairs then first off
729 if ( s2it.pastEnd() ) s2it.reset();
730 }
731 return out;
732}
733
734// dototalpower (migration of GBTIDL procedure dototalpower.pro)
735// calibrate the CAL on-off pair. It calculate Tsys and average CAL on-off subintegrations
736// do it for each cycles in a specific scan.
737CountedPtr< Scantable > STMath::dototalpower( const CountedPtr< Scantable >& calon,
738 const CountedPtr< Scantable >& caloff, Float tcal )
739{
740if ( ! calon->conformant(*caloff) ) {
741 throw(AipsError("'CAL on' and 'CAL off' scantables are not conformant."));
742 }
743 setInsitu(false);
744 CountedPtr< Scantable > out = getScantable(caloff, false);
745 Table& tout = out->table();
746 const Table& tcon = calon->table();
747 Vector<Float> tcalout;
748 Vector<Float> tcalout2; //debug
749
750 if ( tout.nrow() != tcon.nrow() ) {
751 throw(AipsError("Mismatch in number of rows to form cal on - off pair."));
752 }
753 // iteration by scanno or cycle no.
754 TableIterator sit(tout, "SCANNO");
755 TableIterator s2it(tcon, "SCANNO");
756 while ( !sit.pastEnd() ) {
757 Table toff = sit.table();
758 TableRow row(toff);
759 Table t = s2it.table();
760 ScalarColumn<Double> outintCol(toff, "INTERVAL");
761 ArrayColumn<Float> outspecCol(toff, "SPECTRA");
762 ArrayColumn<Float> outtsysCol(toff, "TSYS");
763 ArrayColumn<uChar> outflagCol(toff, "FLAGTRA");
764 ROScalarColumn<uInt> outtcalIdCol(toff, "TCAL_ID");
765 ROScalarColumn<uInt> outpolCol(toff, "POLNO");
766 ROScalarColumn<Double> onintCol(t, "INTERVAL");
767 ROArrayColumn<Float> onspecCol(t, "SPECTRA");
768 ROArrayColumn<Float> ontsysCol(t, "TSYS");
769 ROArrayColumn<uChar> onflagCol(t, "FLAGTRA");
770 //ROScalarColumn<uInt> ontcalIdCol(t, "TCAL_ID");
771
772 for (uInt i=0; i < toff.nrow(); ++i) {
773 //skip these checks -> assumes the data order are the same between the cal on off pairs
774 //
775 Vector<Float> specCalon, specCaloff;
776 // to store scalar (mean) tsys
777 Vector<Float> tsysout(1);
778 uInt tcalId, polno;
779 Double offint, onint;
780 outpolCol.get(i, polno);
781 outspecCol.get(i, specCaloff);
782 onspecCol.get(i, specCalon);
783 Vector<uChar> flagCaloff, flagCalon;
784 outflagCol.get(i, flagCaloff);
785 onflagCol.get(i, flagCalon);
786 outtcalIdCol.get(i, tcalId);
787 outintCol.get(i, offint);
788 onintCol.get(i, onint);
789 // caluculate mean Tsys
790 uInt nchan = specCaloff.nelements();
791 // percentage of edge cut off
792 uInt pc = 10;
793 uInt bchan = nchan/pc;
794 uInt echan = nchan-bchan;
795
796 Slicer chansl(IPosition(1,bchan-1), IPosition(1,echan-1), IPosition(1,1),Slicer::endIsLast);
797 Vector<Float> testsubsp = specCaloff(chansl);
798 MaskedArray<Float> spoff = maskedArray( specCaloff(chansl),flagCaloff(chansl) );
799 MaskedArray<Float> spon = maskedArray( specCalon(chansl),flagCalon(chansl) );
800 MaskedArray<Float> spdiff = spon-spoff;
801 uInt noff = spoff.nelementsValid();
802 //uInt non = spon.nelementsValid();
803 uInt ndiff = spdiff.nelementsValid();
804 Float meantsys;
805
806/**
807 Double subspec, subdiff;
808 uInt usednchan;
809 subspec = 0;
810 subdiff = 0;
811 usednchan = 0;
812 for(uInt k=(bchan-1); k<echan; k++) {
813 subspec += specCaloff[k];
814 subdiff += static_cast<Double>(specCalon[k]-specCaloff[k]);
815 ++usednchan;
816 }
817**/
818 // get tcal if input tcal <= 0
819 String tcalt;
820 Float tcalUsed;
821 tcalUsed = tcal;
822 if ( tcal <= 0.0 ) {
823 caloff->tcal().getEntry(tcalt, tcalout, tcalId);
824 if (polno<=3) {
825 tcalUsed = tcalout[polno];
826 }
827 else {
828 tcalUsed = tcalout[0];
829 }
830 }
831
832 Float meanoff;
833 Float meandiff;
834 if (noff && ndiff) {
835 //Debug
836 //if(noff!=ndiff) cerr<<"noff and ndiff is not equal"<<endl;
837 meanoff = sum(spoff)/noff;
838 meandiff = sum(spdiff)/ndiff;
839 meantsys= (meanoff/meandiff )*tcalUsed + tcalUsed/2;
840 }
841 else {
842 meantsys=1;
843 }
844
845 tsysout[0] = Float(meantsys);
846 MaskedArray<Float> mcaloff = maskedArray(specCaloff, flagCaloff);
847 MaskedArray<Float> mcalon = maskedArray(specCalon, flagCalon);
848 MaskedArray<Float> sig = Float(0.5) * (mcaloff + mcalon);
849 //uInt ncaloff = mcaloff.nelementsValid();
850 //uInt ncalon = mcalon.nelementsValid();
851
852 outintCol.put(i, offint+onint);
853 outspecCol.put(i, sig.getArray());
854 outflagCol.put(i, flagsFromMA(sig));
855 outtsysCol.put(i, tsysout);
856 }
857 ++sit;
858 ++s2it;
859 }
860 return out;
861}
862
863//dosigref - migrated from GBT IDL's dosigref.pro, do calibration of position switch
864// observatiions.
865// input: sig and ref scantables, and an optional boxcar smoothing width(default width=0,
866// no smoothing).
867// output: resultant scantable [= (sig-ref/ref)*tsys]
868CountedPtr< Scantable > STMath::dosigref( const CountedPtr < Scantable >& sig,
869 const CountedPtr < Scantable >& ref,
870 int smoothref,
871 casa::Float tsysv,
872 casa::Float tau )
873{
874if ( ! ref->conformant(*sig) ) {
875 throw(AipsError("'sig' and 'ref' scantables are not conformant."));
876 }
877 setInsitu(false);
878 CountedPtr< Scantable > out = getScantable(sig, false);
879 CountedPtr< Scantable > smref;
880 if ( smoothref > 1 ) {
881 float fsmoothref = static_cast<float>(smoothref);
882 std::string inkernel = "boxcar";
883 smref = smooth(ref, inkernel, fsmoothref );
884 ostringstream oss;
885 oss<<"Applied smoothing of "<<fsmoothref<<" on the reference."<<endl;
886 pushLog(String(oss));
887 }
888 else {
889 smref = ref;
890 }
891 Table& tout = out->table();
892 const Table& tref = smref->table();
893 if ( tout.nrow() != tref.nrow() ) {
894 throw(AipsError("Mismatch in number of rows to form on-source and reference pair."));
895 }
896 // iteration by scanno? or cycle no.
897 TableIterator sit(tout, "SCANNO");
898 TableIterator s2it(tref, "SCANNO");
899 while ( !sit.pastEnd() ) {
900 Table ton = sit.table();
901 Table t = s2it.table();
902 ScalarColumn<Double> outintCol(ton, "INTERVAL");
903 ArrayColumn<Float> outspecCol(ton, "SPECTRA");
904 ArrayColumn<Float> outtsysCol(ton, "TSYS");
905 ArrayColumn<uChar> outflagCol(ton, "FLAGTRA");
906 ArrayColumn<Float> refspecCol(t, "SPECTRA");
907 ROScalarColumn<Double> refintCol(t, "INTERVAL");
908 ROArrayColumn<Float> reftsysCol(t, "TSYS");
909 ArrayColumn<uChar> refflagCol(t, "FLAGTRA");
910 ROScalarColumn<Float> refelevCol(t, "ELEVATION");
911 for (uInt i=0; i < ton.nrow(); ++i) {
912
913 Double onint, refint;
914 Vector<Float> specon, specref;
915 // to store scalar (mean) tsys
916 Vector<Float> tsysref;
917 outintCol.get(i, onint);
918 refintCol.get(i, refint);
919 outspecCol.get(i, specon);
920 refspecCol.get(i, specref);
921 Vector<uChar> flagref, flagon;
922 outflagCol.get(i, flagon);
923 refflagCol.get(i, flagref);
924 reftsysCol.get(i, tsysref);
925
926 Float tsysrefscalar;
927 if ( tsysv > 0.0 ) {
928 ostringstream oss;
929 Float elev;
930 refelevCol.get(i, elev);
931 oss << "user specified Tsys = " << tsysv;
932 // do recalc elevation if EL = 0
933 if ( elev == 0 ) {
934 throw(AipsError("EL=0, elevation data is missing."));
935 } else {
936 if ( tau <= 0.0 ) {
937 throw(AipsError("Valid tau is not supplied."));
938 } else {
939 tsysrefscalar = tsysv * exp(tau/elev);
940 }
941 }
942 oss << ", corrected (for El) tsys= "<<tsysrefscalar;
943 pushLog(String(oss));
944 }
945 else {
946 tsysrefscalar = tsysref[0];
947 }
948 //get quotient spectrum
949 MaskedArray<Float> mref = maskedArray(specref, flagref);
950 MaskedArray<Float> mon = maskedArray(specon, flagon);
951 MaskedArray<Float> specres = tsysrefscalar*((mon - mref)/mref);
952 Double resint = onint*refint*smoothref/(onint+refint*smoothref);
953
954 //Debug
955 //cerr<<"Tsys used="<<tsysrefscalar<<endl;
956 // fill the result, replay signal tsys by reference tsys
957 outintCol.put(i, resint);
958 outspecCol.put(i, specres.getArray());
959 outflagCol.put(i, flagsFromMA(specres));
960 outtsysCol.put(i, tsysref);
961 }
962 ++sit;
963 ++s2it;
964 }
965 return out;
966}
967
968CountedPtr< Scantable > STMath::donod(const casa::CountedPtr<Scantable>& s,
969 const std::vector<int>& scans,
970 int smoothref,
971 casa::Float tsysv,
972 casa::Float tau,
973 casa::Float tcal )
974
975{
976 setInsitu(false);
977 STSelector sel;
978 std::vector<int> scan1, scan2, beams;
979 std::vector< vector<int> > scanpair;
980 std::vector<string> calstate;
981 String msg;
982
983 CountedPtr< Scantable > s1b1on, s1b1off, s1b2on, s1b2off;
984 CountedPtr< Scantable > s2b1on, s2b1off, s2b2on, s2b2off;
985
986 std::vector< CountedPtr< Scantable > > sctables;
987 sctables.push_back(s1b1on);
988 sctables.push_back(s1b1off);
989 sctables.push_back(s1b2on);
990 sctables.push_back(s1b2off);
991 sctables.push_back(s2b1on);
992 sctables.push_back(s2b1off);
993 sctables.push_back(s2b2on);
994 sctables.push_back(s2b2off);
995
996 //check scanlist
997 int n=s->checkScanInfo(scans);
998 if (n==1) {
999 throw(AipsError("Incorrect scan pairs. "));
1000 }
1001
1002 // Assume scans contain only a pair of consecutive scan numbers.
1003 // It is assumed that first beam, b1, is on target.
1004 // There is no check if the first beam is on or not.
1005 if ( scans.size()==1 ) {
1006 scan1.push_back(scans[0]);
1007 scan2.push_back(scans[0]+1);
1008 } else if ( scans.size()==2 ) {
1009 scan1.push_back(scans[0]);
1010 scan2.push_back(scans[1]);
1011 } else {
1012 if ( scans.size()%2 == 0 ) {
1013 for (uInt i=0; i<scans.size(); i++) {
1014 if (i%2 == 0) {
1015 scan1.push_back(scans[i]);
1016 }
1017 else {
1018 scan2.push_back(scans[i]);
1019 }
1020 }
1021 } else {
1022 throw(AipsError("Odd numbers of scans, cannot form pairs."));
1023 }
1024 }
1025 scanpair.push_back(scan1);
1026 scanpair.push_back(scan2);
1027 calstate.push_back("*calon");
1028 calstate.push_back("*[^calon]");
1029 CountedPtr< Scantable > ws = getScantable(s, false);
1030 uInt l=0;
1031 while ( l < sctables.size() ) {
1032 for (uInt i=0; i < 2; i++) {
1033 for (uInt j=0; j < 2; j++) {
1034 for (uInt k=0; k < 2; k++) {
1035 sel.reset();
1036 sel.setScans(scanpair[i]);
1037 sel.setName(calstate[k]);
1038 beams.clear();
1039 beams.push_back(j);
1040 sel.setBeams(beams);
1041 ws->setSelection(sel);
1042 sctables[l]= getScantable(ws, false);
1043 l++;
1044 }
1045 }
1046 }
1047 }
1048
1049 // replace here by splitData or getData functionality
1050 CountedPtr< Scantable > sig1;
1051 CountedPtr< Scantable > ref1;
1052 CountedPtr< Scantable > sig2;
1053 CountedPtr< Scantable > ref2;
1054 CountedPtr< Scantable > calb1;
1055 CountedPtr< Scantable > calb2;
1056
1057 msg=String("Processing dototalpower for subset of the data");
1058 ostringstream oss1;
1059 oss1 << msg << endl;
1060 pushLog(String(oss1));
1061 // Debug for IRC CS data
1062 //float tcal1=7.0;
1063 //float tcal2=4.0;
1064 sig1 = dototalpower(sctables[0], sctables[1], tcal=tcal);
1065 ref1 = dototalpower(sctables[2], sctables[3], tcal=tcal);
1066 ref2 = dototalpower(sctables[4], sctables[5], tcal=tcal);
1067 sig2 = dototalpower(sctables[6], sctables[7], tcal=tcal);
1068
1069 // correction of user-specified tsys for elevation here
1070
1071 // dosigref calibration
1072 msg=String("Processing dosigref for subset of the data");
1073 ostringstream oss2;
1074 oss2 << msg << endl;
1075 pushLog(String(oss2));
1076 calb1=dosigref(sig1,ref2,smoothref,tsysv,tau);
1077 calb2=dosigref(sig2,ref1,smoothref,tsysv,tau);
1078
1079 // iteration by scanno or cycle no.
1080 Table& tcalb1 = calb1->table();
1081 Table& tcalb2 = calb2->table();
1082 TableIterator sit(tcalb1, "SCANNO");
1083 TableIterator s2it(tcalb2, "SCANNO");
1084 while ( !sit.pastEnd() ) {
1085 Table t1 = sit.table();
1086 Table t2= s2it.table();
1087 ArrayColumn<Float> outspecCol(t1, "SPECTRA");
1088 ArrayColumn<Float> outtsysCol(t1, "TSYS");
1089 ArrayColumn<uChar> outflagCol(t1, "FLAGTRA");
1090 ScalarColumn<Double> outintCol(t1, "INTERVAL");
1091 ArrayColumn<Float> t2specCol(t2, "SPECTRA");
1092 ROArrayColumn<Float> t2tsysCol(t2, "TSYS");
1093 ArrayColumn<uChar> t2flagCol(t2, "FLAGTRA");
1094 ROScalarColumn<Double> t2intCol(t2, "INTERVAL");
1095 for (uInt i=0; i < t1.nrow(); ++i) {
1096 Vector<Float> spec1, spec2;
1097 // to store scalar (mean) tsys
1098 Vector<Float> tsys1, tsys2;
1099 Vector<uChar> flag1, flag2;
1100 Double tint1, tint2;
1101 outspecCol.get(i, spec1);
1102 t2specCol.get(i, spec2);
1103 outflagCol.get(i, flag1);
1104 t2flagCol.get(i, flag2);
1105 outtsysCol.get(i, tsys1);
1106 t2tsysCol.get(i, tsys2);
1107 outintCol.get(i, tint1);
1108 t2intCol.get(i, tint2);
1109 // average
1110 // assume scalar tsys for weights
1111 Float wt1, wt2, tsyssq1, tsyssq2;
1112 tsyssq1 = tsys1[0]*tsys1[0];
1113 tsyssq2 = tsys2[0]*tsys2[0];
1114 wt1 = Float(tint1)/tsyssq1;
1115 wt2 = Float(tint2)/tsyssq2;
1116 Float invsumwt=1/(wt1+wt2);
1117 MaskedArray<Float> mspec1 = maskedArray(spec1, flag1);
1118 MaskedArray<Float> mspec2 = maskedArray(spec2, flag2);
1119 MaskedArray<Float> avspec = invsumwt * (wt1*mspec1 + wt2*mspec2);
1120 //Array<Float> avtsys = Float(0.5) * (tsys1 + tsys2);
1121 // cerr<< "Tsys1="<<tsys1<<" Tsys2="<<tsys2<<endl;
1122 tsys1[0] = sqrt(tsyssq1 + tsyssq2);
1123 Array<Float> avtsys = tsys1;
1124
1125 outspecCol.put(i, avspec.getArray());
1126 outflagCol.put(i, flagsFromMA(avspec));
1127 outtsysCol.put(i, avtsys);
1128 }
1129 ++sit;
1130 ++s2it;
1131 }
1132 return calb1;
1133}
1134
1135//GBTIDL version of frequency switched data calibration
1136CountedPtr< Scantable > STMath::dofs( const CountedPtr< Scantable >& s,
1137 const std::vector<int>& scans,
1138 int smoothref,
1139 casa::Float tsysv,
1140 casa::Float tau,
1141 casa::Float tcal )
1142{
1143
1144
1145 STSelector sel;
1146 CountedPtr< Scantable > ws = getScantable(s, false);
1147 CountedPtr< Scantable > sig, sigwcal, ref, refwcal;
1148 CountedPtr< Scantable > calsig, calref, out, out1, out2;
1149 Bool nofold=False;
1150
1151 //split the data
1152 sel.setName("*_fs");
1153 ws->setSelection(sel);
1154 sig = getScantable(ws,false);
1155 sel.reset();
1156 sel.setName("*_fs_calon");
1157 ws->setSelection(sel);
1158 sigwcal = getScantable(ws,false);
1159 sel.reset();
1160 sel.setName("*_fsr");
1161 ws->setSelection(sel);
1162 ref = getScantable(ws,false);
1163 sel.reset();
1164 sel.setName("*_fsr_calon");
1165 ws->setSelection(sel);
1166 refwcal = getScantable(ws,false);
1167
1168 calsig = dototalpower(sigwcal, sig, tcal=tcal);
1169 calref = dototalpower(refwcal, ref, tcal=tcal);
1170
1171 out1=dosigref(calsig,calref,smoothref,tsysv,tau);
1172 out2=dosigref(calref,calsig,smoothref,tsysv,tau);
1173
1174 Table& tabout1=out1->table();
1175 Table& tabout2=out2->table();
1176 ROScalarColumn<uInt> freqidCol1(tabout1, "FREQ_ID");
1177 ScalarColumn<uInt> freqidCol2(tabout2, "FREQ_ID");
1178 ROArrayColumn<Float> specCol(tabout2, "SPECTRA");
1179 Vector<Float> spec; specCol.get(0, spec);
1180 uInt nchan = spec.nelements();
1181 uInt freqid1; freqidCol1.get(0,freqid1);
1182 uInt freqid2; freqidCol2.get(0,freqid2);
1183 Double rp1, rp2, rv1, rv2, inc1, inc2;
1184 out1->frequencies().getEntry(rp1, rv1, inc1, freqid1);
1185 out2->frequencies().getEntry(rp2, rv2, inc2, freqid2);
1186 //cerr << out1->frequencies().table().nrow() << " " << out2->frequencies().table().nrow() << endl ;
1187 if (rp1==rp2) {
1188 Double foffset = rv1 - rv2;
1189 uInt choffset = static_cast<uInt>(foffset/abs(inc2));
1190 if (choffset >= nchan) {
1191 cerr<<"out-band frequency switching, no folding"<<endl;
1192 nofold = True;
1193 }
1194 }
1195
1196 if (nofold) {
1197 std::vector< CountedPtr< Scantable > > tabs;
1198 tabs.push_back(out1);
1199 tabs.push_back(out2);
1200 out = merge(tabs);
1201 }
1202 else { //folding is not implemented yet
1203 //out = out1;
1204 Int choffset = static_cast<Int>((rv1-rv2)/inc2) ;
1205 out = dofold( out1, out2, choffset ) ;
1206 }
1207
1208 return out;
1209}
1210
1211CountedPtr<Scantable> STMath::dofold( const CountedPtr<Scantable> &sig,
1212 const CountedPtr<Scantable> &ref,
1213 Int choffset )
1214{
1215 // output scantable
1216 CountedPtr<Scantable> out = getScantable( sig, false ) ;
1217
1218 // get column
1219 ROArrayColumn<Float> specCol1( sig->table(), "SPECTRA" ) ;
1220 ROArrayColumn<Float> specCol2( ref->table(), "SPECTRA" ) ;
1221 ROArrayColumn<Float> tsysCol1( sig->table(), "TSYS" ) ;
1222 ROArrayColumn<Float> tsysCol2( ref->table(), "TSYS" ) ;
1223 ROArrayColumn<uChar> flagCol1( sig->table(), "FLAGTRA" ) ;
1224 ROArrayColumn<uChar> flagCol2( ref->table(), "FLAGTRA" ) ;
1225 ROScalarColumn<Double> mjdCol1( sig->table(), "TIME" ) ;
1226 ROScalarColumn<Double> mjdCol2( ref->table(), "TIME" ) ;
1227 ROScalarColumn<Double> intervalCol1( sig->table(), "INTERVAL" ) ;
1228 ROScalarColumn<Double> intervalCol2( ref->table(), "INTERVAL" ) ;
1229
1230 // check
1231 if ( choffset == 0 ) {
1232 cerr << "channel offset is zero, no folding" << endl ;
1233 return out ;
1234 }
1235 int nchan = ref->nchan() ;
1236 if ( abs(choffset) >= nchan ) {
1237 cerr << "out-band frequency switching, no folding" << endl ;
1238 return out ;
1239 }
1240
1241 // attach column for output scantable
1242 ArrayColumn<Float> specColOut( out->table(), "SPECTRA" ) ;
1243 ArrayColumn<uChar> flagColOut( out->table(), "FLAGTRA" ) ;
1244 ArrayColumn<Float> tsysColOut( out->table(), "TSYS" ) ;
1245 ScalarColumn<Double> mjdColOut( out->table(), "TIME" ) ;
1246 ScalarColumn<Double> intervalColOut( out->table(), "INTERVAL" ) ;
1247
1248 // for each row
1249 // assume that the data order are same between sig and ref
1250 RowAccumulator acc( asap::TINTSYS ) ;
1251 for ( int i = 0 ; i < sig->nrow() ; i++ ) {
1252 // get values
1253 Vector<Float> spsig ;
1254 specCol1.get( i, spsig ) ;
1255 Vector<Float> spref ;
1256 specCol2.get( i, spref ) ;
1257 Vector<Float> tsyssig ;
1258 tsysCol1.get( i, tsyssig ) ;
1259 Vector<Float> tsysref ;
1260 tsysCol2.get( i, tsysref ) ;
1261 Vector<uChar> flagsig ;
1262 flagCol1.get( i, flagsig ) ;
1263 Vector<uChar> flagref ;
1264 flagCol2.get( i, flagref ) ;
1265 Double timesig ;
1266 mjdCol1.get( i, timesig ) ;
1267 Double timeref ;
1268 mjdCol2.get( i, timeref ) ;
1269 Double intsig ;
1270 intervalCol1.get( i, intsig ) ;
1271 Double intref ;
1272 intervalCol2.get( i, intref ) ;
1273
1274 // shift reference spectra
1275 int refchan = spref.nelements() ;
1276 if ( choffset > 0 ) {
1277 for ( int j = 0 ; j < refchan-choffset ; j++ ) {
1278 spref[j] = spref[j+choffset] ;
1279 tsysref[j] = tsysref[j+choffset] ;
1280 flagref[j] = flagref[j+choffset] ;
1281 }
1282 for ( int j = refchan-choffset ; j < refchan ; j++ ) {
1283 spref[j] = spref[j-refchan+choffset] ;
1284 tsysref[j] = tsysref[j-refchan+choffset] ;
1285 flagref[j] = flagref[j-refchan+choffset] ;
1286 }
1287 }
1288 else {
1289 for ( int j = 0 ; j < abs(choffset) ; j++ ) {
1290 spref[j] = spref[refchan+choffset+j] ;
1291 tsysref[j] = tsysref[refchan+choffset+j] ;
1292 flagref[j] = flagref[refchan+choffset+j] ;
1293 }
1294 for ( int j = abs(choffset) ; j < refchan ; j++ ) {
1295 spref[j] = spref[j+choffset] ;
1296 tsysref[j] = tsysref[j+choffset] ;
1297 flagref[j] = flagref[j+choffset] ;
1298 }
1299 }
1300
1301 // folding
1302 acc.add( spsig, !flagsig, tsyssig, intsig, timesig ) ;
1303 acc.add( spref, !flagref, tsysref, intref, timeref ) ;
1304
1305 // put result
1306 specColOut.put( i, acc.getSpectrum() ) ;
1307 const Vector<Bool> &msk = acc.getMask() ;
1308 Vector<uChar> flg( msk.shape() ) ;
1309 convertArray( flg, !msk ) ;
1310 flagColOut.put( i, flg ) ;
1311 tsysColOut.put( i, acc.getTsys() ) ;
1312 intervalColOut.put( i, acc.getInterval() ) ;
1313 mjdColOut.put( i, acc.getTime() ) ;
1314
1315 acc.reset() ;
1316 }
1317
1318 return out ;
1319}
1320
1321
1322CountedPtr< Scantable > STMath::freqSwitch( const CountedPtr< Scantable >& in )
1323{
1324 // make copy or reference
1325 CountedPtr< Scantable > out = getScantable(in, false);
1326 Table& tout = out->table();
1327 Block<String> cols(4);
1328 cols[0] = String("SCANNO");
1329 cols[1] = String("CYCLENO");
1330 cols[2] = String("BEAMNO");
1331 cols[3] = String("POLNO");
1332 TableIterator iter(tout, cols);
1333 while (!iter.pastEnd()) {
1334 Table subt = iter.table();
1335 // this should leave us with two rows for the two IFs....if not ignore
1336 if (subt.nrow() != 2 ) {
1337 continue;
1338 }
1339 ArrayColumn<Float> specCol(subt, "SPECTRA");
1340 ArrayColumn<Float> tsysCol(subt, "TSYS");
1341 ArrayColumn<uChar> flagCol(subt, "FLAGTRA");
1342 Vector<Float> onspec,offspec, ontsys, offtsys;
1343 Vector<uChar> onflag, offflag;
1344 tsysCol.get(0, ontsys); tsysCol.get(1, offtsys);
1345 specCol.get(0, onspec); specCol.get(1, offspec);
1346 flagCol.get(0, onflag); flagCol.get(1, offflag);
1347 MaskedArray<Float> on = maskedArray(onspec, onflag);
1348 MaskedArray<Float> off = maskedArray(offspec, offflag);
1349 MaskedArray<Float> oncopy = on.copy();
1350
1351 on /= off; on -= 1.0f;
1352 on *= ontsys[0];
1353 off /= oncopy; off -= 1.0f;
1354 off *= offtsys[0];
1355 specCol.put(0, on.getArray());
1356 const Vector<Bool>& m0 = on.getMask();
1357 Vector<uChar> flags0(m0.shape());
1358 convertArray(flags0, !m0);
1359 flagCol.put(0, flags0);
1360
1361 specCol.put(1, off.getArray());
1362 const Vector<Bool>& m1 = off.getMask();
1363 Vector<uChar> flags1(m1.shape());
1364 convertArray(flags1, !m1);
1365 flagCol.put(1, flags1);
1366 ++iter;
1367 }
1368
1369 return out;
1370}
1371
1372std::vector< float > STMath::statistic( const CountedPtr< Scantable > & in,
1373 const std::vector< bool > & mask,
1374 const std::string& which )
1375{
1376
1377 Vector<Bool> m(mask);
1378 const Table& tab = in->table();
1379 ROArrayColumn<Float> specCol(tab, "SPECTRA");
1380 ROArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1381 std::vector<float> out;
1382 for (uInt i=0; i < tab.nrow(); ++i ) {
1383 Vector<Float> spec; specCol.get(i, spec);
1384 Vector<uChar> flag; flagCol.get(i, flag);
1385 MaskedArray<Float> ma = maskedArray(spec, flag);
1386 float outstat = 0.0;
1387 if ( spec.nelements() == m.nelements() ) {
1388 outstat = mathutil::statistics(which, ma(m));
1389 } else {
1390 outstat = mathutil::statistics(which, ma);
1391 }
1392 out.push_back(outstat);
1393 }
1394 return out;
1395}
1396
1397std::vector< int > STMath::minMaxChan( const CountedPtr< Scantable > & in,
1398 const std::vector< bool > & mask,
1399 const std::string& which )
1400{
1401
1402 Vector<Bool> m(mask);
1403 const Table& tab = in->table();
1404 ROArrayColumn<Float> specCol(tab, "SPECTRA");
1405 ROArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1406 std::vector<int> out;
1407 for (uInt i=0; i < tab.nrow(); ++i ) {
1408 Vector<Float> spec; specCol.get(i, spec);
1409 Vector<uChar> flag; flagCol.get(i, flag);
1410 MaskedArray<Float> ma = maskedArray(spec, flag);
1411 if (ma.ndim() != 1) {
1412 throw (ArrayError(
1413 "std::vector<int> STMath::minMaxChan("
1414 "ContedPtr<Scantable> &in, std::vector<bool> &mask, "
1415 " std::string &which)"
1416 " - MaskedArray is not 1D"));
1417 }
1418 IPosition outpos(1,0);
1419 if ( spec.nelements() == m.nelements() ) {
1420 outpos = mathutil::minMaxPos(which, ma(m));
1421 } else {
1422 outpos = mathutil::minMaxPos(which, ma);
1423 }
1424 out.push_back(outpos[0]);
1425 }
1426 return out;
1427}
1428
1429CountedPtr< Scantable > STMath::bin( const CountedPtr< Scantable > & in,
1430 int width )
1431{
1432 if ( !in->getSelection().empty() ) throw(AipsError("Can't bin subset of the data."));
1433 CountedPtr< Scantable > out = getScantable(in, false);
1434 Table& tout = out->table();
1435 out->frequencies().rescale(width, "BIN");
1436 ArrayColumn<Float> specCol(tout, "SPECTRA");
1437 ArrayColumn<uChar> flagCol(tout, "FLAGTRA");
1438 for (uInt i=0; i < tout.nrow(); ++i ) {
1439 MaskedArray<Float> main = maskedArray(specCol(i), flagCol(i));
1440 MaskedArray<Float> maout;
1441 LatticeUtilities::bin(maout, main, 0, Int(width));
1442 /// @todo implement channel based tsys binning
1443 specCol.put(i, maout.getArray());
1444 flagCol.put(i, flagsFromMA(maout));
1445 // take only the first binned spectrum's length for the deprecated
1446 // global header item nChan
1447 if (i==0) tout.rwKeywordSet().define(String("nChan"),
1448 Int(maout.getArray().nelements()));
1449 }
1450 return out;
1451}
1452
1453CountedPtr< Scantable > STMath::resample( const CountedPtr< Scantable >& in,
1454 const std::string& method,
1455 float width )
1456//
1457// Should add the possibility of width being specified in km/s. This means
1458// that for each freqID (SpectralCoordinate) we will need to convert to an
1459// average channel width (say at the reference pixel). Then we would need
1460// to be careful to make sure each spectrum (of different freqID)
1461// is the same length.
1462//
1463{
1464 //InterpolateArray1D<Double,Float>::InterpolationMethod interp;
1465 Int interpMethod(stringToIMethod(method));
1466
1467 CountedPtr< Scantable > out = getScantable(in, false);
1468 Table& tout = out->table();
1469
1470// Resample SpectralCoordinates (one per freqID)
1471 out->frequencies().rescale(width, "RESAMPLE");
1472 TableIterator iter(tout, "IFNO");
1473 TableRow row(tout);
1474 while ( !iter.pastEnd() ) {
1475 Table tab = iter.table();
1476 ArrayColumn<Float> specCol(tab, "SPECTRA");
1477 //ArrayColumn<Float> tsysCol(tout, "TSYS");
1478 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1479 Vector<Float> spec;
1480 Vector<uChar> flag;
1481 specCol.get(0,spec); // the number of channels should be constant per IF
1482 uInt nChanIn = spec.nelements();
1483 Vector<Float> xIn(nChanIn); indgen(xIn);
1484 Int fac = Int(nChanIn/width);
1485 Vector<Float> xOut(fac+10); // 10 to be safe - resize later
1486 uInt k = 0;
1487 Float x = 0.0;
1488 while (x < Float(nChanIn) ) {
1489 xOut(k) = x;
1490 k++;
1491 x += width;
1492 }
1493 uInt nChanOut = k;
1494 xOut.resize(nChanOut, True);
1495 // process all rows for this IFNO
1496 Vector<Float> specOut;
1497 Vector<Bool> maskOut;
1498 Vector<uChar> flagOut;
1499 for (uInt i=0; i < tab.nrow(); ++i) {
1500 specCol.get(i, spec);
1501 flagCol.get(i, flag);
1502 Vector<Bool> mask(flag.nelements());
1503 convertArray(mask, flag);
1504
1505 IPosition shapeIn(spec.shape());
1506 //sh.nchan = nChanOut;
1507 InterpolateArray1D<Float,Float>::interpolate(specOut, maskOut, xOut,
1508 xIn, spec, mask,
1509 interpMethod, True, True);
1510 /// @todo do the same for channel based Tsys
1511 flagOut.resize(maskOut.nelements());
1512 convertArray(flagOut, maskOut);
1513 specCol.put(i, specOut);
1514 flagCol.put(i, flagOut);
1515 }
1516 ++iter;
1517 }
1518
1519 return out;
1520}
1521
1522STMath::imethod STMath::stringToIMethod(const std::string& in)
1523{
1524 static STMath::imap lookup;
1525
1526 // initialize the lookup table if necessary
1527 if ( lookup.empty() ) {
1528 lookup["nearest"] = InterpolateArray1D<Double,Float>::nearestNeighbour;
1529 lookup["linear"] = InterpolateArray1D<Double,Float>::linear;
1530 lookup["cubic"] = InterpolateArray1D<Double,Float>::cubic;
1531 lookup["spline"] = InterpolateArray1D<Double,Float>::spline;
1532 }
1533
1534 STMath::imap::const_iterator iter = lookup.find(in);
1535
1536 if ( lookup.end() == iter ) {
1537 std::string message = in;
1538 message += " is not a valid interpolation mode";
1539 throw(AipsError(message));
1540 }
1541 return iter->second;
1542}
1543
1544WeightType STMath::stringToWeight(const std::string& in)
1545{
1546 static std::map<std::string, WeightType> lookup;
1547
1548 // initialize the lookup table if necessary
1549 if ( lookup.empty() ) {
1550 lookup["NONE"] = asap::NONE;
1551 lookup["TINT"] = asap::TINT;
1552 lookup["TINTSYS"] = asap::TINTSYS;
1553 lookup["TSYS"] = asap::TSYS;
1554 lookup["VAR"] = asap::VAR;
1555 }
1556
1557 std::map<std::string, WeightType>::const_iterator iter = lookup.find(in);
1558
1559 if ( lookup.end() == iter ) {
1560 std::string message = in;
1561 message += " is not a valid weighting mode";
1562 throw(AipsError(message));
1563 }
1564 return iter->second;
1565}
1566
1567CountedPtr< Scantable > STMath::gainElevation( const CountedPtr< Scantable >& in,
1568 const vector< float > & coeff,
1569 const std::string & filename,
1570 const std::string& method)
1571{
1572 // Get elevation data from Scantable and convert to degrees
1573 CountedPtr< Scantable > out = getScantable(in, false);
1574 Table& tab = out->table();
1575 ROScalarColumn<Float> elev(tab, "ELEVATION");
1576 Vector<Float> x = elev.getColumn();
1577 x *= Float(180 / C::pi); // Degrees
1578
1579 Vector<Float> coeffs(coeff);
1580 const uInt nc = coeffs.nelements();
1581 if ( filename.length() > 0 && nc > 0 ) {
1582 throw(AipsError("You must choose either polynomial coefficients or an ascii file, not both"));
1583 }
1584
1585 // Correct
1586 if ( nc > 0 || filename.length() == 0 ) {
1587 // Find instrument
1588 Bool throwit = True;
1589 Instrument inst =
1590 STAttr::convertInstrument(tab.keywordSet().asString("AntennaName"),
1591 throwit);
1592
1593 // Set polynomial
1594 Polynomial<Float>* ppoly = 0;
1595 Vector<Float> coeff;
1596 String msg;
1597 if ( nc > 0 ) {
1598 ppoly = new Polynomial<Float>(nc);
1599 coeff = coeffs;
1600 msg = String("user");
1601 } else {
1602 STAttr sdAttr;
1603 coeff = sdAttr.gainElevationPoly(inst);
1604 ppoly = new Polynomial<Float>(3);
1605 msg = String("built in");
1606 }
1607
1608 if ( coeff.nelements() > 0 ) {
1609 ppoly->setCoefficients(coeff);
1610 } else {
1611 delete ppoly;
1612 throw(AipsError("There is no known gain-elevation polynomial known for this instrument"));
1613 }
1614 ostringstream oss;
1615 oss << "Making polynomial correction with " << msg << " coefficients:" << endl;
1616 oss << " " << coeff;
1617 pushLog(String(oss));
1618 const uInt nrow = tab.nrow();
1619 Vector<Float> factor(nrow);
1620 for ( uInt i=0; i < nrow; ++i ) {
1621 factor[i] = 1.0 / (*ppoly)(x[i]);
1622 }
1623 delete ppoly;
1624 scaleByVector(tab, factor, true);
1625
1626 } else {
1627 // Read and correct
1628 pushLog("Making correction from ascii Table");
1629 scaleFromAsciiTable(tab, filename, method, x, true);
1630 }
1631 return out;
1632}
1633
1634void STMath::scaleFromAsciiTable(Table& in, const std::string& filename,
1635 const std::string& method,
1636 const Vector<Float>& xout, bool dotsys)
1637{
1638
1639// Read gain-elevation ascii file data into a Table.
1640
1641 String formatString;
1642 Table tbl = readAsciiTable(formatString, Table::Memory, filename, "", "", False);
1643 scaleFromTable(in, tbl, method, xout, dotsys);
1644}
1645
1646void STMath::scaleFromTable(Table& in,
1647 const Table& table,
1648 const std::string& method,
1649 const Vector<Float>& xout, bool dotsys)
1650{
1651
1652 ROScalarColumn<Float> geElCol(table, "ELEVATION");
1653 ROScalarColumn<Float> geFacCol(table, "FACTOR");
1654 Vector<Float> xin = geElCol.getColumn();
1655 Vector<Float> yin = geFacCol.getColumn();
1656 Vector<Bool> maskin(xin.nelements(),True);
1657
1658 // Interpolate (and extrapolate) with desired method
1659
1660 InterpolateArray1D<Double,Float>::InterpolationMethod interp = stringToIMethod(method);
1661
1662 Vector<Float> yout;
1663 Vector<Bool> maskout;
1664 InterpolateArray1D<Float,Float>::interpolate(yout, maskout, xout,
1665 xin, yin, maskin, interp,
1666 True, True);
1667
1668 scaleByVector(in, Float(1.0)/yout, dotsys);
1669}
1670
1671void STMath::scaleByVector( Table& in,
1672 const Vector< Float >& factor,
1673 bool dotsys )
1674{
1675 uInt nrow = in.nrow();
1676 if ( factor.nelements() != nrow ) {
1677 throw(AipsError("factors.nelements() != table.nelements()"));
1678 }
1679 ArrayColumn<Float> specCol(in, "SPECTRA");
1680 ArrayColumn<uChar> flagCol(in, "FLAGTRA");
1681 ArrayColumn<Float> tsysCol(in, "TSYS");
1682 for (uInt i=0; i < nrow; ++i) {
1683 MaskedArray<Float> ma = maskedArray(specCol(i), flagCol(i));
1684 ma *= factor[i];
1685 specCol.put(i, ma.getArray());
1686 flagCol.put(i, flagsFromMA(ma));
1687 if ( dotsys ) {
1688 Vector<Float> tsys = tsysCol(i);
1689 tsys *= factor[i];
1690 tsysCol.put(i,tsys);
1691 }
1692 }
1693}
1694
1695CountedPtr< Scantable > STMath::convertFlux( const CountedPtr< Scantable >& in,
1696 float d, float etaap,
1697 float jyperk )
1698{
1699 CountedPtr< Scantable > out = getScantable(in, false);
1700 Table& tab = in->table();
1701 Unit fluxUnit(tab.keywordSet().asString("FluxUnit"));
1702 Unit K(String("K"));
1703 Unit JY(String("Jy"));
1704
1705 bool tokelvin = true;
1706 Double cfac = 1.0;
1707
1708 if ( fluxUnit == JY ) {
1709 pushLog("Converting to K");
1710 Quantum<Double> t(1.0,fluxUnit);
1711 Quantum<Double> t2 = t.get(JY);
1712 cfac = (t2 / t).getValue(); // value to Jy
1713
1714 tokelvin = true;
1715 out->setFluxUnit("K");
1716 } else if ( fluxUnit == K ) {
1717 pushLog("Converting to Jy");
1718 Quantum<Double> t(1.0,fluxUnit);
1719 Quantum<Double> t2 = t.get(K);
1720 cfac = (t2 / t).getValue(); // value to K
1721
1722 tokelvin = false;
1723 out->setFluxUnit("Jy");
1724 } else {
1725 throw(AipsError("Unrecognized brightness units in Table - must be consistent with Jy or K"));
1726 }
1727 // Make sure input values are converted to either Jy or K first...
1728 Float factor = cfac;
1729
1730 // Select method
1731 if (jyperk > 0.0) {
1732 factor *= jyperk;
1733 if ( tokelvin ) factor = 1.0 / jyperk;
1734 ostringstream oss;
1735 oss << "Jy/K = " << jyperk;
1736 pushLog(String(oss));
1737 Vector<Float> factors(tab.nrow(), factor);
1738 scaleByVector(tab,factors, false);
1739 } else if ( etaap > 0.0) {
1740 if (d < 0) {
1741 Instrument inst =
1742 STAttr::convertInstrument(tab.keywordSet().asString("AntennaName"),
1743 True);
1744 STAttr sda;
1745 d = sda.diameter(inst);
1746 }
1747 jyperk = STAttr::findJyPerK(etaap, d);
1748 ostringstream oss;
1749 oss << "Jy/K = " << jyperk;
1750 pushLog(String(oss));
1751 factor *= jyperk;
1752 if ( tokelvin ) {
1753 factor = 1.0 / factor;
1754 }
1755 Vector<Float> factors(tab.nrow(), factor);
1756 scaleByVector(tab, factors, False);
1757 } else {
1758
1759 // OK now we must deal with automatic look up of values.
1760 // We must also deal with the fact that the factors need
1761 // to be computed per IF and may be different and may
1762 // change per integration.
1763
1764 pushLog("Looking up conversion factors");
1765 convertBrightnessUnits(out, tokelvin, cfac);
1766 }
1767
1768 return out;
1769}
1770
1771void STMath::convertBrightnessUnits( CountedPtr<Scantable>& in,
1772 bool tokelvin, float cfac )
1773{
1774 Table& table = in->table();
1775 Instrument inst =
1776 STAttr::convertInstrument(table.keywordSet().asString("AntennaName"), True);
1777 TableIterator iter(table, "FREQ_ID");
1778 STFrequencies stfreqs = in->frequencies();
1779 STAttr sdAtt;
1780 while (!iter.pastEnd()) {
1781 Table tab = iter.table();
1782 ArrayColumn<Float> specCol(tab, "SPECTRA");
1783 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1784 ROScalarColumn<uInt> freqidCol(tab, "FREQ_ID");
1785 MEpoch::ROScalarColumn timeCol(tab, "TIME");
1786
1787 uInt freqid; freqidCol.get(0, freqid);
1788 Vector<Float> tmpspec; specCol.get(0, tmpspec);
1789 // STAttr.JyPerK has a Vector interface... change sometime.
1790 Vector<Float> freqs(1,stfreqs.getRefFreq(freqid, tmpspec.nelements()));
1791 for ( uInt i=0; i<tab.nrow(); ++i) {
1792 Float jyperk = (sdAtt.JyPerK(inst, timeCol(i), freqs))[0];
1793 Float factor = cfac * jyperk;
1794 if ( tokelvin ) factor = Float(1.0) / factor;
1795 MaskedArray<Float> ma = maskedArray(specCol(i), flagCol(i));
1796 ma *= factor;
1797 specCol.put(i, ma.getArray());
1798 flagCol.put(i, flagsFromMA(ma));
1799 }
1800 ++iter;
1801 }
1802}
1803
1804CountedPtr< Scantable > STMath::opacity( const CountedPtr< Scantable > & in,
1805 float tau )
1806{
1807 CountedPtr< Scantable > out = getScantable(in, false);
1808
1809 Table tab = out->table();
1810 ROScalarColumn<Float> elev(tab, "ELEVATION");
1811 ArrayColumn<Float> specCol(tab, "SPECTRA");
1812 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1813 ArrayColumn<Float> tsysCol(tab, "TSYS");
1814 for ( uInt i=0; i<tab.nrow(); ++i) {
1815 Float zdist = Float(C::pi_2) - elev(i);
1816 Float factor = exp(tau/cos(zdist));
1817 MaskedArray<Float> ma = maskedArray(specCol(i), flagCol(i));
1818 ma *= factor;
1819 specCol.put(i, ma.getArray());
1820 flagCol.put(i, flagsFromMA(ma));
1821 Vector<Float> tsys;
1822 tsysCol.get(i, tsys);
1823 tsys *= factor;
1824 tsysCol.put(i, tsys);
1825 }
1826 return out;
1827}
1828
1829CountedPtr< Scantable > STMath::smoothOther( const CountedPtr< Scantable >& in,
1830 const std::string& kernel,
1831 float width )
1832{
1833 CountedPtr< Scantable > out = getScantable(in, false);
1834 Table& table = out->table();
1835 ArrayColumn<Float> specCol(table, "SPECTRA");
1836 ArrayColumn<uChar> flagCol(table, "FLAGTRA");
1837 Vector<Float> spec;
1838 Vector<uChar> flag;
1839 for ( uInt i=0; i<table.nrow(); ++i) {
1840 specCol.get(i, spec);
1841 flagCol.get(i, flag);
1842 Vector<Bool> mask(flag.nelements());
1843 convertArray(mask, flag);
1844 Vector<Float> specout;
1845 Vector<Bool> maskout;
1846 if ( kernel == "hanning" ) {
1847 mathutil::hanning(specout, maskout, spec , !mask);
1848 convertArray(flag, !maskout);
1849 } else if ( kernel == "rmedian" ) {
1850 mathutil::runningMedian(specout, maskout, spec , mask, width);
1851 convertArray(flag, maskout);
1852 }
1853 flagCol.put(i, flag);
1854 specCol.put(i, specout);
1855 }
1856 return out;
1857}
1858
1859CountedPtr< Scantable > STMath::smooth( const CountedPtr< Scantable >& in,
1860 const std::string& kernel, float width )
1861{
1862 if (kernel == "rmedian" || kernel == "hanning") {
1863 return smoothOther(in, kernel, width);
1864 }
1865 CountedPtr< Scantable > out = getScantable(in, false);
1866 Table& table = out->table();
1867 VectorKernel::KernelTypes type = VectorKernel::toKernelType(kernel);
1868 // same IFNO should have same no of channels
1869 // this saves overhead
1870 TableIterator iter(table, "IFNO");
1871 while (!iter.pastEnd()) {
1872 Table tab = iter.table();
1873 ArrayColumn<Float> specCol(tab, "SPECTRA");
1874 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
1875 Vector<Float> tmpspec; specCol.get(0, tmpspec);
1876 uInt nchan = tmpspec.nelements();
1877 Vector<Float> kvec = VectorKernel::make(type, width, nchan, True, False);
1878 Convolver<Float> conv(kvec, IPosition(1,nchan));
1879 Vector<Float> spec;
1880 Vector<uChar> flag;
1881 for ( uInt i=0; i<tab.nrow(); ++i) {
1882 specCol.get(i, spec);
1883 flagCol.get(i, flag);
1884 Vector<Bool> mask(flag.nelements());
1885 convertArray(mask, flag);
1886 Vector<Float> specout;
1887 mathutil::replaceMaskByZero(specout, mask);
1888 conv.linearConv(specout, spec);
1889 specCol.put(i, specout);
1890 }
1891 ++iter;
1892 }
1893 return out;
1894}
1895
1896CountedPtr< Scantable >
1897 STMath::merge( const std::vector< CountedPtr < Scantable > >& in )
1898{
1899 if ( in.size() < 2 ) {
1900 throw(AipsError("Need at least two scantables to perform a merge."));
1901 }
1902 std::vector<CountedPtr < Scantable > >::const_iterator it = in.begin();
1903 bool insitu = insitu_;
1904 setInsitu(false);
1905 CountedPtr< Scantable > out = getScantable(*it, false);
1906 setInsitu(insitu);
1907 Table& tout = out->table();
1908 ScalarColumn<uInt> freqidcol(tout,"FREQ_ID"), molidcol(tout, "MOLECULE_ID");
1909 ScalarColumn<uInt> scannocol(tout,"SCANNO"), focusidcol(tout,"FOCUS_ID");
1910 // Renumber SCANNO to be 0-based
1911 Vector<uInt> scannos = scannocol.getColumn();
1912 uInt offset = min(scannos);
1913 scannos -= offset;
1914 scannocol.putColumn(scannos);
1915 uInt newscanno = max(scannos)+1;
1916 ++it;
1917 while ( it != in.end() ){
1918 if ( ! (*it)->conformant(*out) ) {
1919 // non conformant.
1920 pushLog(String("Warning: Can't merge scantables as header info differs."));
1921 }
1922 out->appendToHistoryTable((*it)->history());
1923 const Table& tab = (*it)->table();
1924 TableIterator scanit(tab, "SCANNO");
1925 while (!scanit.pastEnd()) {
1926 TableIterator freqit(scanit.table(), "FREQ_ID");
1927 while ( !freqit.pastEnd() ) {
1928 Table thetab = freqit.table();
1929 uInt nrow = tout.nrow();
1930 tout.addRow(thetab.nrow());
1931 TableCopy::copyRows(tout, thetab, nrow, 0, thetab.nrow());
1932 ROTableRow row(thetab);
1933 for ( uInt i=0; i<thetab.nrow(); ++i) {
1934 uInt k = nrow+i;
1935 scannocol.put(k, newscanno);
1936 const TableRecord& rec = row.get(i);
1937 Double rv,rp,inc;
1938 (*it)->frequencies().getEntry(rp, rv, inc, rec.asuInt("FREQ_ID"));
1939 uInt id;
1940 id = out->frequencies().addEntry(rp, rv, inc);
1941 freqidcol.put(k,id);
1942 //String name,fname;Double rf;
1943 Vector<String> name,fname;Vector<Double> rf;
1944 (*it)->molecules().getEntry(rf, name, fname, rec.asuInt("MOLECULE_ID"));
1945 id = out->molecules().addEntry(rf, name, fname);
1946 molidcol.put(k, id);
1947 Float frot,fax,ftan,fhand,fmount,fuser, fxy, fxyp;
1948 (*it)->focus().getEntry(fax, ftan, frot, fhand,
1949 fmount,fuser, fxy, fxyp,
1950 rec.asuInt("FOCUS_ID"));
1951 id = out->focus().addEntry(fax, ftan, frot, fhand,
1952 fmount,fuser, fxy, fxyp);
1953 focusidcol.put(k, id);
1954 }
1955 ++freqit;
1956 }
1957 ++newscanno;
1958 ++scanit;
1959 }
1960 ++it;
1961 }
1962 return out;
1963}
1964
1965CountedPtr< Scantable >
1966 STMath::invertPhase( const CountedPtr < Scantable >& in )
1967{
1968 return applyToPol(in, &STPol::invertPhase, Float(0.0));
1969}
1970
1971CountedPtr< Scantable >
1972 STMath::rotateXYPhase( const CountedPtr < Scantable >& in, float phase )
1973{
1974 return applyToPol(in, &STPol::rotatePhase, Float(phase));
1975}
1976
1977CountedPtr< Scantable >
1978 STMath::rotateLinPolPhase( const CountedPtr < Scantable >& in, float phase )
1979{
1980 return applyToPol(in, &STPol::rotateLinPolPhase, Float(phase));
1981}
1982
1983CountedPtr< Scantable > STMath::applyToPol( const CountedPtr<Scantable>& in,
1984 STPol::polOperation fptr,
1985 Float phase )
1986{
1987 CountedPtr< Scantable > out = getScantable(in, false);
1988 Table& tout = out->table();
1989 Block<String> cols(4);
1990 cols[0] = String("SCANNO");
1991 cols[1] = String("BEAMNO");
1992 cols[2] = String("IFNO");
1993 cols[3] = String("CYCLENO");
1994 TableIterator iter(tout, cols);
1995 CountedPtr<STPol> stpol = STPol::getPolClass(out->factories_,
1996 out->getPolType() );
1997 while (!iter.pastEnd()) {
1998 Table t = iter.table();
1999 ArrayColumn<Float> speccol(t, "SPECTRA");
2000 ScalarColumn<uInt> focidcol(t, "FOCUS_ID");
2001 ScalarColumn<Float> parancol(t, "PARANGLE");
2002 Matrix<Float> pols(speccol.getColumn());
2003 try {
2004 stpol->setSpectra(pols);
2005 Float fang,fhand,parang;
2006 fang = in->focusTable_.getTotalFeedAngle(focidcol(0));
2007 fhand = in->focusTable_.getFeedHand(focidcol(0));
2008 parang = parancol(0);
2009 /// @todo re-enable this
2010 // disable total feed angle to support paralactifying Caswell style
2011 stpol->setPhaseCorrections(parang, -parang, fhand);
2012 // use a member function pointer in STPol. This only works on
2013 // the STPol pointer itself, not the Counted Pointer so
2014 // derefernce it.
2015 (&(*(stpol))->*fptr)(phase);
2016 speccol.putColumn(stpol->getSpectra());
2017 } catch (AipsError& e) {
2018 //delete stpol;stpol=0;
2019 throw(e);
2020 }
2021 ++iter;
2022 }
2023 //delete stpol;stpol=0;
2024 return out;
2025}
2026
2027CountedPtr< Scantable >
2028 STMath::swapPolarisations( const CountedPtr< Scantable > & in )
2029{
2030 CountedPtr< Scantable > out = getScantable(in, false);
2031 Table& tout = out->table();
2032 Table t0 = tout(tout.col("POLNO") == 0);
2033 Table t1 = tout(tout.col("POLNO") == 1);
2034 if ( t0.nrow() != t1.nrow() )
2035 throw(AipsError("Inconsistent number of polarisations"));
2036 ArrayColumn<Float> speccol0(t0, "SPECTRA");
2037 ArrayColumn<uChar> flagcol0(t0, "FLAGTRA");
2038 ArrayColumn<Float> speccol1(t1, "SPECTRA");
2039 ArrayColumn<uChar> flagcol1(t1, "FLAGTRA");
2040 Matrix<Float> s0 = speccol0.getColumn();
2041 Matrix<uChar> f0 = flagcol0.getColumn();
2042 speccol0.putColumn(speccol1.getColumn());
2043 flagcol0.putColumn(flagcol1.getColumn());
2044 speccol1.putColumn(s0);
2045 flagcol1.putColumn(f0);
2046 return out;
2047}
2048
2049CountedPtr< Scantable >
2050 STMath::averagePolarisations( const CountedPtr< Scantable > & in,
2051 const std::vector<bool>& mask,
2052 const std::string& weight )
2053{
2054 if (in->npol() < 2 )
2055 throw(AipsError("averagePolarisations can only be applied to two or more"
2056 "polarisations"));
2057 bool insitu = insitu_;
2058 setInsitu(false);
2059 CountedPtr< Scantable > pols = getScantable(in, true);
2060 setInsitu(insitu);
2061 Table& tout = pols->table();
2062 std::string taql = "SELECT FROM $1 WHERE POLNO IN [0,1]";
2063 Table tab = tableCommand(taql, in->table());
2064 if (tab.nrow() == 0 )
2065 throw(AipsError("Could not find any rows with POLNO==0 and POLNO==1"));
2066 TableCopy::copyRows(tout, tab);
2067 TableVector<uInt> vec(tout, "POLNO");
2068 vec = 0;
2069 pols->table_.rwKeywordSet().define("nPol", Int(1));
2070 //pols->table_.rwKeywordSet().define("POLTYPE", String("stokes"));
2071 pols->table_.rwKeywordSet().define("POLTYPE", in->getPolType());
2072 std::vector<CountedPtr<Scantable> > vpols;
2073 vpols.push_back(pols);
2074 CountedPtr< Scantable > out = average(vpols, mask, weight, "SCAN");
2075 return out;
2076}
2077
2078CountedPtr< Scantable >
2079 STMath::averageBeams( const CountedPtr< Scantable > & in,
2080 const std::vector<bool>& mask,
2081 const std::string& weight )
2082{
2083 bool insitu = insitu_;
2084 setInsitu(false);
2085 CountedPtr< Scantable > beams = getScantable(in, false);
2086 setInsitu(insitu);
2087 Table& tout = beams->table();
2088 // give all rows the same BEAMNO
2089 TableVector<uInt> vec(tout, "BEAMNO");
2090 vec = 0;
2091 beams->table_.rwKeywordSet().define("nBeam", Int(1));
2092 std::vector<CountedPtr<Scantable> > vbeams;
2093 vbeams.push_back(beams);
2094 CountedPtr< Scantable > out = average(vbeams, mask, weight, "SCAN");
2095 return out;
2096}
2097
2098
2099CountedPtr< Scantable >
2100 asap::STMath::frequencyAlign( const CountedPtr< Scantable > & in,
2101 const std::string & refTime,
2102 const std::string & method)
2103{
2104 // clone as this is not working insitu
2105 bool insitu = insitu_;
2106 setInsitu(false);
2107 CountedPtr< Scantable > out = getScantable(in, false);
2108 setInsitu(insitu);
2109 Table& tout = out->table();
2110 // Get reference Epoch to time of first row or given String
2111 Unit DAY(String("d"));
2112 MEpoch::Ref epochRef(in->getTimeReference());
2113 MEpoch refEpoch;
2114 if (refTime.length()>0) {
2115 Quantum<Double> qt;
2116 if (MVTime::read(qt,refTime)) {
2117 MVEpoch mv(qt);
2118 refEpoch = MEpoch(mv, epochRef);
2119 } else {
2120 throw(AipsError("Invalid format for Epoch string"));
2121 }
2122 } else {
2123 refEpoch = in->timeCol_(0);
2124 }
2125 MPosition refPos = in->getAntennaPosition();
2126
2127 InterpolateArray1D<Double,Float>::InterpolationMethod interp = stringToIMethod(method);
2128 /*
2129 // Comment from MV.
2130 // the following code has been commented out because different FREQ_IDs have to be aligned together even
2131 // if the frame doesn't change. So far, lack of this check didn't cause any problems.
2132 // test if user frame is different to base frame
2133 if ( in->frequencies().getFrameString(true)
2134 == in->frequencies().getFrameString(false) ) {
2135 throw(AipsError("Can't convert as no output frame has been set"
2136 " (use set_freqframe) or it is aligned already."));
2137 }
2138 */
2139 MFrequency::Types system = in->frequencies().getFrame();
2140 MVTime mvt(refEpoch.getValue());
2141 String epochout = mvt.string(MVTime::YMD) + String(" (") + refEpoch.getRefString() + String(")");
2142 ostringstream oss;
2143 oss << "Aligned at reference Epoch " << epochout
2144 << " in frame " << MFrequency::showType(system);
2145 pushLog(String(oss));
2146 // set up the iterator
2147 Block<String> cols(4);
2148 // select by constant direction
2149 cols[0] = String("SRCNAME");
2150 cols[1] = String("BEAMNO");
2151 // select by IF ( no of channels varies over this )
2152 cols[2] = String("IFNO");
2153 // select by restfrequency
2154 cols[3] = String("MOLECULE_ID");
2155 TableIterator iter(tout, cols);
2156 while ( !iter.pastEnd() ) {
2157 Table t = iter.table();
2158 MDirection::ROScalarColumn dirCol(t, "DIRECTION");
2159 TableIterator fiter(t, "FREQ_ID");
2160 // determine nchan from the first row. This should work as
2161 // we are iterating over BEAMNO and IFNO // we should have constant direction
2162
2163 ROArrayColumn<Float> sCol(t, "SPECTRA");
2164 const MDirection direction = dirCol(0);
2165 const uInt nchan = sCol(0).nelements();
2166
2167 // skip operations if there is nothing to align
2168 if (fiter.pastEnd()) {
2169 continue;
2170 }
2171
2172 Table ftab = fiter.table();
2173 // align all frequency ids with respect to the first encountered id
2174 ScalarColumn<uInt> freqidCol(ftab, "FREQ_ID");
2175 // get the SpectralCoordinate for the freqid, which we are iterating over
2176 SpectralCoordinate sC = in->frequencies().getSpectralCoordinate(freqidCol(0));
2177 FrequencyAligner<Float> fa( sC, nchan, refEpoch,
2178 direction, refPos, system );
2179 // realign the SpectralCoordinate and put into the output Scantable
2180 Vector<String> units(1);
2181 units = String("Hz");
2182 Bool linear=True;
2183 SpectralCoordinate sc2 = fa.alignedSpectralCoordinate(linear);
2184 sc2.setWorldAxisUnits(units);
2185 const uInt id = out->frequencies().addEntry(sc2.referencePixel()[0],
2186 sc2.referenceValue()[0],
2187 sc2.increment()[0]);
2188 while ( !fiter.pastEnd() ) {
2189 ftab = fiter.table();
2190 // spectral coordinate for the current FREQ_ID
2191 ScalarColumn<uInt> freqidCol2(ftab, "FREQ_ID");
2192 sC = in->frequencies().getSpectralCoordinate(freqidCol2(0));
2193 // create the "global" abcissa for alignment with same FREQ_ID
2194 Vector<Double> abc(nchan);
2195 for (uInt i=0; i<nchan; i++) {
2196 Double w;
2197 sC.toWorld(w,Double(i));
2198 abc[i] = w;
2199 }
2200 TableVector<uInt> tvec(ftab, "FREQ_ID");
2201 // assign new frequency id to all rows
2202 tvec = id;
2203 // cache abcissa for same time stamps, so iterate over those
2204 TableIterator timeiter(ftab, "TIME");
2205 while ( !timeiter.pastEnd() ) {
2206 Table tab = timeiter.table();
2207 ArrayColumn<Float> specCol(tab, "SPECTRA");
2208 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
2209 MEpoch::ROScalarColumn timeCol(tab, "TIME");
2210 // use align abcissa cache after the first row
2211 // these rows should be just be POLNO
2212 bool first = true;
2213 for (int i=0; i<int(tab.nrow()); ++i) {
2214 // input values
2215 Vector<uChar> flag = flagCol(i);
2216 Vector<Bool> mask(flag.shape());
2217 Vector<Float> specOut, spec;
2218 spec = specCol(i);
2219 Vector<Bool> maskOut;Vector<uChar> flagOut;
2220 convertArray(mask, flag);
2221 // alignment
2222 Bool ok = fa.align(specOut, maskOut, abc, spec,
2223 mask, timeCol(i), !first,
2224 interp, False);
2225 // back into scantable
2226 flagOut.resize(maskOut.nelements());
2227 convertArray(flagOut, maskOut);
2228 flagCol.put(i, flagOut);
2229 specCol.put(i, specOut);
2230 // start abcissa caching
2231 first = false;
2232 }
2233 // next timestamp
2234 ++timeiter;
2235 }
2236 // next FREQ_ID
2237 ++fiter;
2238 }
2239 // next aligner
2240 ++iter;
2241 }
2242 // set this afterwards to ensure we are doing insitu correctly.
2243 out->frequencies().setFrame(system, true);
2244 return out;
2245}
2246
2247CountedPtr<Scantable>
2248 asap::STMath::convertPolarisation( const CountedPtr<Scantable>& in,
2249 const std::string & newtype )
2250{
2251 if (in->npol() != 2 && in->npol() != 4)
2252 throw(AipsError("Can only convert two or four polarisations."));
2253 if ( in->getPolType() == newtype )
2254 throw(AipsError("No need to convert."));
2255 if ( ! in->selector_.empty() )
2256 throw(AipsError("Can only convert whole scantable. Unset the selection."));
2257 bool insitu = insitu_;
2258 setInsitu(false);
2259 CountedPtr< Scantable > out = getScantable(in, true);
2260 setInsitu(insitu);
2261 Table& tout = out->table();
2262 tout.rwKeywordSet().define("POLTYPE", String(newtype));
2263
2264 Block<String> cols(4);
2265 cols[0] = "SCANNO";
2266 cols[1] = "CYCLENO";
2267 cols[2] = "BEAMNO";
2268 cols[3] = "IFNO";
2269 TableIterator it(in->originalTable_, cols);
2270 String basetype = in->getPolType();
2271 STPol* stpol = STPol::getPolClass(in->factories_, basetype);
2272 try {
2273 while ( !it.pastEnd() ) {
2274 Table tab = it.table();
2275 uInt row = tab.rowNumbers()[0];
2276 stpol->setSpectra(in->getPolMatrix(row));
2277 Float fang,fhand,parang;
2278 fang = in->focusTable_.getTotalFeedAngle(in->mfocusidCol_(row));
2279 fhand = in->focusTable_.getFeedHand(in->mfocusidCol_(row));
2280 parang = in->paraCol_(row);
2281 /// @todo re-enable this
2282 // disable total feed angle to support paralactifying Caswell style
2283 stpol->setPhaseCorrections(parang, -parang, fhand);
2284 Int npolout = 0;
2285 for (uInt i=0; i<tab.nrow(); ++i) {
2286 Vector<Float> outvec = stpol->getSpectrum(i, newtype);
2287 if ( outvec.nelements() > 0 ) {
2288 tout.addRow();
2289 TableCopy::copyRows(tout, tab, tout.nrow()-1, 0, 1);
2290 ArrayColumn<Float> sCol(tout,"SPECTRA");
2291 ScalarColumn<uInt> pCol(tout,"POLNO");
2292 sCol.put(tout.nrow()-1 ,outvec);
2293 pCol.put(tout.nrow()-1 ,uInt(npolout));
2294 npolout++;
2295 }
2296 }
2297 tout.rwKeywordSet().define("nPol", npolout);
2298 ++it;
2299 }
2300 } catch (AipsError& e) {
2301 delete stpol;
2302 throw(e);
2303 }
2304 delete stpol;
2305 return out;
2306}
2307
2308CountedPtr< Scantable >
2309 asap::STMath::mxExtract( const CountedPtr< Scantable > & in,
2310 const std::string & scantype )
2311{
2312 bool insitu = insitu_;
2313 setInsitu(false);
2314 CountedPtr< Scantable > out = getScantable(in, true);
2315 setInsitu(insitu);
2316 Table& tout = out->table();
2317 std::string taql = "SELECT FROM $1 WHERE BEAMNO != REFBEAMNO";
2318 if (scantype == "on") {
2319 taql = "SELECT FROM $1 WHERE BEAMNO == REFBEAMNO";
2320 }
2321 Table tab = tableCommand(taql, in->table());
2322 TableCopy::copyRows(tout, tab);
2323 if (scantype == "on") {
2324 // re-index SCANNO to 0
2325 TableVector<uInt> vec(tout, "SCANNO");
2326 vec = 0;
2327 }
2328 return out;
2329}
2330
2331CountedPtr< Scantable >
2332 asap::STMath::lagFlag( const CountedPtr< Scantable > & in,
2333 double frequency, double width )
2334{
2335 CountedPtr< Scantable > out = getScantable(in, false);
2336 Table& tout = out->table();
2337 TableIterator iter(tout, "FREQ_ID");
2338 FFTServer<Float,Complex> ffts;
2339 while ( !iter.pastEnd() ) {
2340 Table tab = iter.table();
2341 Double rp,rv,inc;
2342 ROTableRow row(tab);
2343 const TableRecord& rec = row.get(0);
2344 uInt freqid = rec.asuInt("FREQ_ID");
2345 out->frequencies().getEntry(rp, rv, inc, freqid);
2346 ArrayColumn<Float> specCol(tab, "SPECTRA");
2347 ArrayColumn<uChar> flagCol(tab, "FLAGTRA");
2348 for (int i=0; i<int(tab.nrow()); ++i) {
2349 Vector<Float> spec = specCol(i);
2350 Vector<uChar> flag = flagCol(i);
2351 Int lag0 = Int(spec.nelements()*abs(inc)/(frequency+width)+0.5);
2352 Int lag1 = Int(spec.nelements()*abs(inc)/(frequency-width)+0.5);
2353 for (int k=0; k < flag.nelements(); ++k ) {
2354 if (flag[k] > 0) {
2355 spec[k] = 0.0;
2356 }
2357 }
2358 Vector<Complex> lags;
2359 ffts.fft0(lags, spec);
2360 Int start = max(0, lag0);
2361 Int end = min(Int(lags.nelements()-1), lag1);
2362 if (start == end) {
2363 lags[start] = Complex(0.0);
2364 } else {
2365 for (int j=start; j <=end ;++j) {
2366 lags[j] = Complex(0.0);
2367 }
2368 }
2369 ffts.fft0(spec, lags);
2370 specCol.put(i, spec);
2371 }
2372 ++iter;
2373 }
2374 return out;
2375}
2376
2377// Averaging spectra with different channel/resolution
2378CountedPtr<Scantable>
2379STMath::new_average( const std::vector<CountedPtr<Scantable> >& in,
2380 const bool& compel,
2381 const std::vector<bool>& mask,
2382 const std::string& weight,
2383 const std::string& avmode )
2384 throw ( casa::AipsError )
2385{
2386 if ( avmode == "SCAN" && in.size() != 1 )
2387 throw(AipsError("Can't perform 'SCAN' averaging on multiple tables.\n"
2388 "Use merge first."));
2389
2390 // check if OTF observation
2391 String obstype = in[0]->getHeader().obstype ;
2392 //bool otfscan = false ;
2393 Double tol = 0.0 ;
2394 if ( obstype.find( "OTF" ) != String::npos ) {
2395 //cout << "OTF scan" << endl ;
2396 //otfscan = true ;
2397 tol = TOL_OTF ;
2398 }
2399 else {
2400 tol = TOL_POINT ;
2401 }
2402
2403 CountedPtr<Scantable> out ; // processed result
2404 if ( compel ) {
2405 std::vector< CountedPtr<Scantable> > newin ; // input for average process
2406 uInt insize = in.size() ; // number of input scantables
2407
2408 // TEST: do normal average in each table before IF grouping
2409 cout << "Do preliminary averaging" << endl ;
2410 vector< CountedPtr<Scantable> > tmpin( insize ) ;
2411 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2412 vector< CountedPtr<Scantable> > v( 1, in[itable] ) ;
2413 tmpin[itable] = average( v, mask, weight, avmode ) ;
2414 }
2415
2416 // warning
2417 cout << "Average spectra with different spectral resolution" << endl ;
2418 cout << endl ;
2419
2420 // temporarily set coordinfo
2421 vector<string> oldinfo( insize ) ;
2422 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2423 vector<string> coordinfo = in[itable]->getCoordInfo() ;
2424 oldinfo[itable] = coordinfo[0] ;
2425 coordinfo[0] = "Hz" ;
2426 tmpin[itable]->setCoordInfo( coordinfo ) ;
2427 }
2428
2429 // columns
2430 ScalarColumn<uInt> freqIDCol ;
2431 ScalarColumn<uInt> ifnoCol ;
2432 ScalarColumn<uInt> scannoCol ;
2433
2434
2435 // check IF frequency coverage
2436 // freqid: list of FREQ_ID, which is used, in each table
2437 // iffreq: list of minimum and maximum frequency for each FREQ_ID in
2438 // each table
2439 // freqid[insize][numIF]
2440 // freqid: [[id00, id01, ...],
2441 // [id10, id11, ...],
2442 // ...
2443 // [idn0, idn1, ...]]
2444 // iffreq[insize][numIF*2]
2445 // iffreq: [[min_id00, max_id00, min_id01, max_id01, ...],
2446 // [min_id10, max_id10, min_id11, max_id11, ...],
2447 // ...
2448 // [min_idn0, max_idn0, min_idn1, max_idn1, ...]]
2449 //cout << "Check IF settings in each table" << endl ;
2450 vector< vector<uInt> > freqid( insize );
2451 vector< vector<double> > iffreq( insize ) ;
2452 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2453 uInt rows = tmpin[itable]->nrow() ;
2454 uInt freqnrows = tmpin[itable]->frequencies().table().nrow() ;
2455 for ( uInt irow = 0 ; irow < rows ; irow++ ) {
2456 if ( freqid[itable].size() == freqnrows ) {
2457 break ;
2458 }
2459 else {
2460 freqIDCol.attach( tmpin[itable]->table(), "FREQ_ID" ) ;
2461 ifnoCol.attach( tmpin[itable]->table(), "IFNO" ) ;
2462 uInt id = freqIDCol( irow ) ;
2463 if ( freqid[itable].size() == 0 || count( freqid[itable].begin(), freqid[itable].end(), id ) == 0 ) {
2464 //cout << "itable = " << itable << ": IF " << id << " is included in the list" << endl ;
2465 vector<double> abcissa = tmpin[itable]->getAbcissa( irow ) ;
2466 freqid[itable].push_back( id ) ;
2467 iffreq[itable].push_back( abcissa[0] - 0.5 * ( abcissa[1] - abcissa[0] ) ) ;
2468 iffreq[itable].push_back( abcissa[abcissa.size()-1] + 0.5 * ( abcissa[1] - abcissa[0] ) ) ;
2469 }
2470 }
2471 }
2472 }
2473
2474 // debug
2475 //cout << "IF settings summary:" << endl ;
2476 //for ( uInt i = 0 ; i < freqid.size() ; i++ ) {
2477 //cout << " Table" << i << endl ;
2478 //for ( uInt j = 0 ; j < freqid[i].size() ; j++ ) {
2479 //cout << " id = " << freqid[i][j] << " (min,max) = (" << iffreq[i][2*j] << "," << iffreq[i][2*j+1] << ")" << endl ;
2480 //}
2481 //}
2482 //cout << endl ;
2483
2484 // IF grouping based on their frequency coverage
2485 // ifgrp: list of table index and FREQ_ID for all members in each IF group
2486 // ifgfreq: list of minimum and maximum frequency in each IF group
2487 // ifgrp[numgrp][nummember*2]
2488 // ifgrp: [[table00, freqrow00, table01, freqrow01, ...],
2489 // [table10, freqrow10, table11, freqrow11, ...],
2490 // ...
2491 // [tablen0, freqrown0, tablen1, freqrown1, ...]]
2492 // ifgfreq[numgrp*2]
2493 // ifgfreq: [min0_grp0, max0_grp0, min1_grp1, max1_grp1, ...]
2494 //cout << "IF grouping based on their frequency coverage" << endl ;
2495 vector< vector<uInt> > ifgrp ;
2496 vector<double> ifgfreq ;
2497
2498 // parameter for IF grouping
2499 // groupmode = OR retrieve all region
2500 // AND only retrieve overlaped region
2501 //string groupmode = "AND" ;
2502 string groupmode = "OR" ;
2503 uInt sizecr = 0 ;
2504 if ( groupmode == "AND" )
2505 sizecr = 2 ;
2506 else if ( groupmode == "OR" )
2507 sizecr = 0 ;
2508
2509 vector<double> sortedfreq ;
2510 for ( uInt i = 0 ; i < iffreq.size() ; i++ ) {
2511 for ( uInt j = 0 ; j < iffreq[i].size() ; j++ ) {
2512 if ( count( sortedfreq.begin(), sortedfreq.end(), iffreq[i][j] ) == 0 )
2513 sortedfreq.push_back( iffreq[i][j] ) ;
2514 }
2515 }
2516 sort( sortedfreq.begin(), sortedfreq.end() ) ;
2517 for ( vector<double>::iterator i = sortedfreq.begin() ; i != sortedfreq.end()-1 ; i++ ) {
2518 ifgfreq.push_back( *i ) ;
2519 ifgfreq.push_back( *(i+1) ) ;
2520 }
2521 ifgrp.resize( ifgfreq.size()/2 ) ;
2522 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2523 for ( uInt iif = 0 ; iif < freqid[itable].size() ; iif++ ) {
2524 double range0 = iffreq[itable][2*iif] ;
2525 double range1 = iffreq[itable][2*iif+1] ;
2526 for ( uInt j = 0 ; j < ifgrp.size() ; j++ ) {
2527 double fmin = max( range0, ifgfreq[2*j] ) ;
2528 double fmax = min( range1, ifgfreq[2*j+1] ) ;
2529 if ( fmin < fmax ) {
2530 ifgrp[j].push_back( itable ) ;
2531 ifgrp[j].push_back( freqid[itable][iif] ) ;
2532 }
2533 }
2534 }
2535 }
2536 vector< vector<uInt> >::iterator fiter = ifgrp.begin() ;
2537 vector<double>::iterator giter = ifgfreq.begin() ;
2538 while( fiter != ifgrp.end() ) {
2539 if ( fiter->size() <= sizecr ) {
2540 fiter = ifgrp.erase( fiter ) ;
2541 giter = ifgfreq.erase( giter ) ;
2542 giter = ifgfreq.erase( giter ) ;
2543 }
2544 else {
2545 fiter++ ;
2546 advance( giter, 2 ) ;
2547 }
2548 }
2549
2550 // Grouping continuous IF groups (without frequency gap)
2551 // freqgrp: list of IF group indexes in each frequency group
2552 // freqrange: list of minimum and maximum frequency in each frequency group
2553 // freqgrp[numgrp][nummember]
2554 // freqgrp: [[ifgrp00, ifgrp01, ifgrp02, ...],
2555 // [ifgrp10, ifgrp11, ifgrp12, ...],
2556 // ...
2557 // [ifgrpn0, ifgrpn1, ifgrpn2, ...]]
2558 // freqrange[numgrp*2]
2559 // freqrange: [min_grp0, max_grp0, min_grp1, max_grp1, ...]
2560 vector< vector<uInt> > freqgrp ;
2561 double freqrange = 0.0 ;
2562 uInt grpnum = 0 ;
2563 for ( uInt i = 0 ; i < ifgrp.size() ; i++ ) {
2564 // Assumed that ifgfreq was sorted
2565 if ( grpnum != 0 && freqrange == ifgfreq[2*i] ) {
2566 freqgrp[grpnum-1].push_back( i ) ;
2567 }
2568 else {
2569 vector<uInt> grp0( 1, i ) ;
2570 freqgrp.push_back( grp0 ) ;
2571 grpnum++ ;
2572 }
2573 freqrange = ifgfreq[2*i+1] ;
2574 }
2575
2576
2577 // print IF groups
2578 cout << "IF Group summary: " << endl ;
2579 cout << " GROUP_ID [FREQ_MIN, FREQ_MAX]: (TABLE_ID, FREQ_ID)" << endl ;
2580 for ( uInt i = 0 ; i < ifgrp.size() ; i++ ) {
2581 cout << " GROUP " << setw( 2 ) << i << " [" << ifgfreq[2*i] << "," << ifgfreq[2*i+1] << "]: " ;
2582 for ( uInt j = 0 ; j < ifgrp[i].size()/2 ; j++ ) {
2583 cout << "(" << ifgrp[i][2*j] << "," << ifgrp[i][2*j+1] << ") " ;
2584 }
2585 cout << endl ;
2586 }
2587 cout << endl ;
2588
2589 // print frequency group
2590 cout << "Frequency Group summary: " << endl ;
2591 cout << " GROUP_ID [FREQ_MIN, FREQ_MAX]: IF_GROUP_ID" << endl ;
2592 for ( uInt i = 0 ; i < freqgrp.size() ; i++ ) {
2593 cout << " GROUP " << setw( 2 ) << i << " [" << ifgfreq[2*freqgrp[i][0]] << "," << ifgfreq[2*freqgrp[i][freqgrp[i].size()-1]+1] << "]: " ;
2594 for ( uInt j = 0 ; j < freqgrp[i].size() ; j++ ) {
2595 cout << freqgrp[i][j] << " " ;
2596 }
2597 cout << endl ;
2598 }
2599 cout << endl ;
2600
2601 // membership check
2602 // groups: list of IF group indexes whose frequency range overlaps with
2603 // that of each table and IF
2604 // groups[numtable][numIF][nummembership]
2605 // groups: [[[grp, grp,...], [grp, grp,...],...],
2606 // [[grp, grp,...], [grp, grp,...],...],
2607 // ...
2608 // [[grp, grp,...], [grp, grp,...],...]]
2609 vector< vector< vector<uInt> > > groups( insize ) ;
2610 for ( uInt i = 0 ; i < insize ; i++ ) {
2611 groups[i].resize( freqid[i].size() ) ;
2612 }
2613 for ( uInt igrp = 0 ; igrp < ifgrp.size() ; igrp++ ) {
2614 for ( uInt imem = 0 ; imem < ifgrp[igrp].size()/2 ; imem++ ) {
2615 uInt tableid = ifgrp[igrp][2*imem] ;
2616 vector<uInt>::iterator iter = find( freqid[tableid].begin(), freqid[tableid].end(), ifgrp[igrp][2*imem+1] ) ;
2617 if ( iter != freqid[tableid].end() ) {
2618 uInt rowid = distance( freqid[tableid].begin(), iter ) ;
2619 groups[tableid][rowid].push_back( igrp ) ;
2620 }
2621 }
2622 }
2623
2624 // print membership
2625 //for ( uInt i = 0 ; i < insize ; i++ ) {
2626 //cout << "Table " << i << endl ;
2627 //for ( uInt j = 0 ; j < groups[i].size() ; j++ ) {
2628 //cout << " FREQ_ID " << setw( 2 ) << freqid[i][j] << ": " ;
2629 //for ( uInt k = 0 ; k < groups[i][j].size() ; k++ ) {
2630 //cout << setw( 2 ) << groups[i][j][k] << " " ;
2631 //}
2632 //cout << endl ;
2633 //}
2634 //}
2635
2636 // set back coordinfo
2637 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2638 vector<string> coordinfo = tmpin[itable]->getCoordInfo() ;
2639 coordinfo[0] = oldinfo[itable] ;
2640 tmpin[itable]->setCoordInfo( coordinfo ) ;
2641 }
2642
2643 // Create additional table if needed
2644 bool oldInsitu = insitu_ ;
2645 setInsitu( false ) ;
2646 vector< vector<uInt> > addrow( insize ) ;
2647 vector<uInt> addtable( insize, 0 ) ;
2648 vector<uInt> newtableids( insize ) ;
2649 vector<uInt> newifids( insize, 0 ) ;
2650 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2651 //cout << "Table " << setw(2) << itable << ": " ;
2652 for ( uInt ifrow = 0 ; ifrow < groups[itable].size() ; ifrow++ ) {
2653 addrow[itable].push_back( groups[itable][ifrow].size()-1 ) ;
2654 //cout << addrow[itable][ifrow] << " " ;
2655 }
2656 addtable[itable] = *max_element( addrow[itable].begin(), addrow[itable].end() ) ;
2657 //cout << "(" << addtable[itable] << ")" << endl ;
2658 }
2659 newin.resize( insize ) ;
2660 copy( tmpin.begin(), tmpin.end(), newin.begin() ) ;
2661 for ( uInt i = 0 ; i < insize ; i++ ) {
2662 newtableids[i] = i ;
2663 }
2664 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2665 for ( uInt iadd = 0 ; iadd < addtable[itable] ; iadd++ ) {
2666 CountedPtr<Scantable> add = getScantable( newin[itable], false ) ;
2667 vector<int> freqidlist ;
2668 for ( uInt i = 0 ; i < groups[itable].size() ; i++ ) {
2669 if ( groups[itable][i].size() > iadd + 1 ) {
2670 freqidlist.push_back( freqid[itable][i] ) ;
2671 }
2672 }
2673 stringstream taqlstream ;
2674 taqlstream << "SELECT FROM $1 WHERE FREQ_ID IN [" ;
2675 for ( uInt i = 0 ; i < freqidlist.size() ; i++ ) {
2676 taqlstream << i ;
2677 if ( i < freqidlist.size() - 1 )
2678 taqlstream << "," ;
2679 else
2680 taqlstream << "]" ;
2681 }
2682 string taql = taqlstream.str() ;
2683 //cout << "taql = " << taql << endl ;
2684 STSelector selector = STSelector() ;
2685 selector.setTaQL( taql ) ;
2686 add->setSelection( selector ) ;
2687 newin.push_back( add ) ;
2688 newtableids.push_back( itable ) ;
2689 newifids.push_back( iadd + 1 ) ;
2690 }
2691 }
2692
2693 // udpate ifgrp
2694 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2695 for ( uInt iadd = 0 ; iadd < addtable[itable] ; iadd++ ) {
2696 for ( uInt ifrow = 0 ; ifrow < groups[itable].size() ; ifrow++ ) {
2697 if ( groups[itable][ifrow].size() > iadd + 1 ) {
2698 uInt igrp = groups[itable][ifrow][iadd+1] ;
2699 for ( uInt imem = 0 ; imem < ifgrp[igrp].size()/2 ; imem++ ) {
2700 if ( ifgrp[igrp][2*imem] == newtableids[iadd+insize] && ifgrp[igrp][2*imem+1] == freqid[newtableids[iadd+insize]][ifrow] ) {
2701 ifgrp[igrp][2*imem] = insize + iadd ;
2702 }
2703 }
2704 }
2705 }
2706 }
2707 }
2708
2709 // print IF groups again for debug
2710 //cout << "IF Group summary: " << endl ;
2711 //cout << " GROUP_ID [FREQ_MIN, FREQ_MAX]: (TABLE_ID, FREQ_ID)" << endl ;
2712 //for ( uInt i = 0 ; i < ifgrp.size() ; i++ ) {
2713 //cout << " GROUP " << setw( 2 ) << i << " [" << ifgfreq[2*i] << "," << ifgfreq[2*i+1] << "]: " ;
2714 //for ( uInt j = 0 ; j < ifgrp[i].size()/2 ; j++ ) {
2715 //cout << "(" << ifgrp[i][2*j] << "," << ifgrp[i][2*j+1] << ") " ;
2716 //}
2717 //cout << endl ;
2718 //}
2719 //cout << endl ;
2720
2721 // reset SCANNO and IFNO/FREQ_ID: IF is reset by the result of sortation
2722 cout << "All scan number is set to 0" << endl ;
2723 //cout << "All IF number is set to IF group index" << endl ;
2724 cout << endl ;
2725 insize = newin.size() ;
2726 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2727 uInt rows = newin[itable]->nrow() ;
2728 Table &tmpt = newin[itable]->table() ;
2729 freqIDCol.attach( tmpt, "FREQ_ID" ) ;
2730 scannoCol.attach( tmpt, "SCANNO" ) ;
2731 ifnoCol.attach( tmpt, "IFNO" ) ;
2732 for ( uInt irow=0 ; irow < rows ; irow++ ) {
2733 scannoCol.put( irow, 0 ) ;
2734 uInt freqID = freqIDCol( irow ) ;
2735 vector<uInt>::iterator iter = find( freqid[newtableids[itable]].begin(), freqid[newtableids[itable]].end(), freqID ) ;
2736 if ( iter != freqid[newtableids[itable]].end() ) {
2737 uInt index = distance( freqid[newtableids[itable]].begin(), iter ) ;
2738 ifnoCol.put( irow, groups[newtableids[itable]][index][newifids[itable]] ) ;
2739 }
2740 else {
2741 throw(AipsError("IF grouping was wrong in additional tables.")) ;
2742 }
2743 }
2744 }
2745 oldinfo.resize( insize ) ;
2746 setInsitu( oldInsitu ) ;
2747
2748 // temporarily set coordinfo
2749 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2750 vector<string> coordinfo = newin[itable]->getCoordInfo() ;
2751 oldinfo[itable] = coordinfo[0] ;
2752 coordinfo[0] = "Hz" ;
2753 newin[itable]->setCoordInfo( coordinfo ) ;
2754 }
2755
2756 // save column values in the vector
2757 vector< vector<uInt> > freqTableIdVec( insize ) ;
2758 vector< vector<uInt> > freqIdVec( insize ) ;
2759 vector< vector<uInt> > ifNoVec( insize ) ;
2760 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2761 ScalarColumn<uInt> freqIDs ;
2762 freqIDs.attach( newin[itable]->frequencies().table(), "ID" ) ;
2763 ifnoCol.attach( newin[itable]->table(), "IFNO" ) ;
2764 freqIDCol.attach( newin[itable]->table(), "FREQ_ID" ) ;
2765 for ( uInt irow = 0 ; irow < newin[itable]->frequencies().table().nrow() ; irow++ ) {
2766 freqTableIdVec[itable].push_back( freqIDs( irow ) ) ;
2767 }
2768 for ( uInt irow = 0 ; irow < newin[itable]->table().nrow() ; irow++ ) {
2769 freqIdVec[itable].push_back( freqIDCol( irow ) ) ;
2770 ifNoVec[itable].push_back( ifnoCol( irow ) ) ;
2771 }
2772 }
2773
2774 // reset spectra and flagtra: pick up common part of frequency coverage
2775 //cout << "Pick common frequency range and align resolution" << endl ;
2776 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2777 uInt rows = newin[itable]->nrow() ;
2778 int nminchan = -1 ;
2779 int nmaxchan = -1 ;
2780 vector<uInt> freqIdUpdate ;
2781 for ( uInt irow = 0 ; irow < rows ; irow++ ) {
2782 uInt ifno = ifNoVec[itable][irow] ; // IFNO is reset by group index
2783 double minfreq = ifgfreq[2*ifno] ;
2784 double maxfreq = ifgfreq[2*ifno+1] ;
2785 //cout << "frequency range: [" << minfreq << "," << maxfreq << "]" << endl ;
2786 vector<double> abcissa = newin[itable]->getAbcissa( irow ) ;
2787 int nchan = abcissa.size() ;
2788 double resol = abcissa[1] - abcissa[0] ;
2789 //cout << "abcissa range : [" << abcissa[0] << "," << abcissa[nchan-1] << "]" << endl ;
2790 if ( minfreq <= abcissa[0] )
2791 nminchan = 0 ;
2792 else {
2793 //double cfreq = ( minfreq - abcissa[0] ) / resol ;
2794 double cfreq = ( minfreq - abcissa[0] + 0.5 * resol ) / resol ;
2795 nminchan = int(cfreq) + ( ( cfreq - int(cfreq) <= 0.5 ) ? 0 : 1 ) ;
2796 }
2797 if ( maxfreq >= abcissa[abcissa.size()-1] )
2798 nmaxchan = abcissa.size() - 1 ;
2799 else {
2800 //double cfreq = ( abcissa[abcissa.size()-1] - maxfreq ) / resol ;
2801 double cfreq = ( abcissa[abcissa.size()-1] - maxfreq + 0.5 * resol ) / resol ;
2802 nmaxchan = abcissa.size() - 1 - int(cfreq) - ( ( cfreq - int(cfreq) >= 0.5 ) ? 1 : 0 ) ;
2803 }
2804 //cout << "channel range (" << irow << "): [" << nminchan << "," << nmaxchan << "]" << endl ;
2805 if ( nmaxchan > nminchan ) {
2806 newin[itable]->reshapeSpectrum( nminchan, nmaxchan, irow ) ;
2807 int newchan = nmaxchan - nminchan + 1 ;
2808 if ( count( freqIdUpdate.begin(), freqIdUpdate.end(), freqIdVec[itable][irow] ) == 0 && newchan < nchan )
2809 freqIdUpdate.push_back( freqIdVec[itable][irow] ) ;
2810 }
2811 else {
2812 throw(AipsError("Failed to pick up common part of frequency range.")) ;
2813 }
2814 }
2815 for ( uInt i = 0 ; i < freqIdUpdate.size() ; i++ ) {
2816 uInt freqId = freqIdUpdate[i] ;
2817 Double refpix ;
2818 Double refval ;
2819 Double increment ;
2820
2821 // update row
2822 newin[itable]->frequencies().getEntry( refpix, refval, increment, freqId ) ;
2823 refval = refval - ( refpix - nminchan ) * increment ;
2824 refpix = 0 ;
2825 newin[itable]->frequencies().setEntry( refpix, refval, increment, freqId ) ;
2826 }
2827 }
2828
2829
2830 // reset spectra and flagtra: align spectral resolution
2831 //cout << "Align spectral resolution" << endl ;
2832 // gmaxdnu: the coarsest frequency resolution in the frequency group
2833 // gmemid: member index that have a resolution equal to gmaxdnu
2834 // gmaxdnu[numfreqgrp]
2835 // gmaxdnu: [dnu0, dnu1, ...]
2836 // gmemid[numfreqgrp]
2837 // gmemid: [id0, id1, ...]
2838 vector<double> gmaxdnu( freqgrp.size(), 0.0 ) ;
2839 vector<uInt> gmemid( freqgrp.size(), 0 ) ;
2840 for ( uInt igrp = 0 ; igrp < ifgrp.size() ; igrp++ ) {
2841 double maxdnu = 0.0 ; // maximum (coarsest) frequency resolution
2842 int minchan = INT_MAX ; // minimum channel number
2843 Double refpixref = -1 ; // reference of 'reference pixel'
2844 Double refvalref = -1 ; // reference of 'reference frequency'
2845 Double refinc = -1 ; // reference frequency resolution
2846 uInt refreqid ;
2847 uInt reftable = INT_MAX;
2848 // process only if group member > 1
2849 if ( ifgrp[igrp].size() > 2 ) {
2850 // find minchan and maxdnu in each group
2851 for ( uInt imem = 0 ; imem < ifgrp[igrp].size()/2 ; imem++ ) {
2852 uInt tableid = ifgrp[igrp][2*imem] ;
2853 uInt rowid = ifgrp[igrp][2*imem+1] ;
2854 vector<uInt>::iterator iter = find( freqIdVec[tableid].begin(), freqIdVec[tableid].end(), rowid ) ;
2855 if ( iter != freqIdVec[tableid].end() ) {
2856 uInt index = distance( freqIdVec[tableid].begin(), iter ) ;
2857 vector<double> abcissa = newin[tableid]->getAbcissa( index ) ;
2858 int nchan = abcissa.size() ;
2859 double dnu = abcissa[1] - abcissa[0] ;
2860 //cout << "GROUP " << igrp << " (" << tableid << "," << rowid << "): nchan = " << nchan << " (minchan = " << minchan << ")" << endl ;
2861 if ( nchan < minchan ) {
2862 minchan = nchan ;
2863 maxdnu = dnu ;
2864 newin[tableid]->frequencies().getEntry( refpixref, refvalref, refinc, rowid ) ;
2865 refreqid = rowid ;
2866 reftable = tableid ;
2867 }
2868 }
2869 }
2870 // regrid spectra in each group
2871 cout << "GROUP " << igrp << endl ;
2872 cout << " Channel number is adjusted to " << minchan << endl ;
2873 cout << " Corresponding frequency resolution is " << maxdnu << "Hz" << endl ;
2874 for ( uInt imem = 0 ; imem < ifgrp[igrp].size()/2 ; imem++ ) {
2875 uInt tableid = ifgrp[igrp][2*imem] ;
2876 uInt rowid = ifgrp[igrp][2*imem+1] ;
2877 freqIDCol.attach( newin[tableid]->table(), "FREQ_ID" ) ;
2878 //cout << "tableid = " << tableid << " rowid = " << rowid << ": " << endl ;
2879 //cout << " regridChannel applied to " ;
2880 if ( tableid != reftable )
2881 refreqid = newin[tableid]->frequencies().addEntry( refpixref, refvalref, refinc ) ;
2882 for ( uInt irow = 0 ; irow < newin[tableid]->table().nrow() ; irow++ ) {
2883 uInt tfreqid = freqIdVec[tableid][irow] ;
2884 if ( tfreqid == rowid ) {
2885 //cout << irow << " " ;
2886 newin[tableid]->regridChannel( minchan, maxdnu, irow ) ;
2887 freqIDCol.put( irow, refreqid ) ;
2888 freqIdVec[tableid][irow] = refreqid ;
2889 }
2890 }
2891 //cout << endl ;
2892 }
2893 }
2894 else {
2895 uInt tableid = ifgrp[igrp][0] ;
2896 uInt rowid = ifgrp[igrp][1] ;
2897 vector<uInt>::iterator iter = find( freqIdVec[tableid].begin(), freqIdVec[tableid].end(), rowid ) ;
2898 if ( iter != freqIdVec[tableid].end() ) {
2899 uInt index = distance( freqIdVec[tableid].begin(), iter ) ;
2900 vector<double> abcissa = newin[tableid]->getAbcissa( index ) ;
2901 minchan = abcissa.size() ;
2902 maxdnu = abcissa[1] - abcissa[0] ;
2903 }
2904 }
2905 for ( uInt i = 0 ; i < freqgrp.size() ; i++ ) {
2906 if ( count( freqgrp[i].begin(), freqgrp[i].end(), igrp ) > 0 ) {
2907 if ( maxdnu > gmaxdnu[i] ) {
2908 gmaxdnu[i] = maxdnu ;
2909 gmemid[i] = igrp ;
2910 }
2911 break ;
2912 }
2913 }
2914 }
2915 cout << endl ;
2916
2917 // set back coordinfo
2918 for ( uInt itable = 0 ; itable < insize ; itable++ ) {
2919 vector<string> coordinfo = newin[itable]->getCoordInfo() ;
2920 coordinfo[0] = oldinfo[itable] ;
2921 newin[itable]->setCoordInfo( coordinfo ) ;
2922 }
2923
2924 // accumulate all rows into the first table
2925 // NOTE: assumed in.size() = 1
2926 vector< CountedPtr<Scantable> > tmp( 1 ) ;
2927 if ( newin.size() == 1 )
2928 tmp[0] = newin[0] ;
2929 else
2930 tmp[0] = merge( newin ) ;
2931
2932 //return tmp[0] ;
2933
2934 // average
2935 CountedPtr<Scantable> tmpout = average( tmp, mask, weight, avmode ) ;
2936
2937 //return tmpout ;
2938
2939 // combine frequency group
2940 cout << "Combine spectra based on frequency grouping" << endl ;
2941 cout << "IFNO is renumbered as frequency group ID (see above)" << endl ;
2942 vector<string> coordinfo = tmpout->getCoordInfo() ;
2943 oldinfo[0] = coordinfo[0] ;
2944 coordinfo[0] = "Hz" ;
2945 tmpout->setCoordInfo( coordinfo ) ;
2946 // create proformas of output table
2947 stringstream taqlstream ;
2948 taqlstream << "SELECT FROM $1 WHERE IFNO IN [" ;
2949 for ( uInt i = 0 ; i < gmemid.size() ; i++ ) {
2950 taqlstream << gmemid[i] ;
2951 if ( i < gmemid.size() - 1 )
2952 taqlstream << "," ;
2953 else
2954 taqlstream << "]" ;
2955 }
2956 string taql = taqlstream.str() ;
2957 //cout << "taql = " << taql << endl ;
2958 STSelector selector = STSelector() ;
2959 selector.setTaQL( taql ) ;
2960 oldInsitu = insitu_ ;
2961 setInsitu( false ) ;
2962 out = getScantable( tmpout, false ) ;
2963 setInsitu( oldInsitu ) ;
2964 out->setSelection( selector ) ;
2965 // regrid rows
2966 ifnoCol.attach( tmpout->table(), "IFNO" ) ;
2967 for ( uInt irow = 0 ; irow < tmpout->table().nrow() ; irow++ ) {
2968 uInt ifno = ifnoCol( irow ) ;
2969 for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
2970 if ( count( freqgrp[igrp].begin(), freqgrp[igrp].end(), ifno ) > 0 ) {
2971 vector<double> abcissa = tmpout->getAbcissa( irow ) ;
2972 double bw = ( abcissa[1] - abcissa[0] ) * abcissa.size() ;
2973 int nchan = (int)( bw / gmaxdnu[igrp] ) ;
2974 tmpout->regridChannel( nchan, gmaxdnu[igrp], irow ) ;
2975 break ;
2976 }
2977 }
2978 }
2979 // combine spectra
2980 ArrayColumn<Float> specColOut ;
2981 specColOut.attach( out->table(), "SPECTRA" ) ;
2982 ArrayColumn<uChar> flagColOut ;
2983 flagColOut.attach( out->table(), "FLAGTRA" ) ;
2984 ScalarColumn<uInt> ifnoColOut ;
2985 ifnoColOut.attach( out->table(), "IFNO" ) ;
2986 ScalarColumn<uInt> polnoColOut ;
2987 polnoColOut.attach( out->table(), "POLNO" ) ;
2988 ScalarColumn<uInt> freqidColOut ;
2989 freqidColOut.attach( out->table(), "FREQ_ID" ) ;
2990 MDirection::ScalarColumn dirColOut ;
2991 dirColOut.attach( out->table(), "DIRECTION" ) ;
2992 Table &tab = tmpout->table() ;
2993 Block<String> cols(1);
2994 cols[0] = String("POLNO") ;
2995 TableIterator iter( tab, cols ) ;
2996 bool done = false ;
2997 vector< vector<uInt> > sizes( freqgrp.size() ) ;
2998 while( !iter.pastEnd() ) {
2999 vector< vector<Float> > specout( freqgrp.size() ) ;
3000 vector< vector<uChar> > flagout( freqgrp.size() ) ;
3001 ArrayColumn<Float> specCols ;
3002 specCols.attach( iter.table(), "SPECTRA" ) ;
3003 ArrayColumn<uChar> flagCols ;
3004 flagCols.attach( iter.table(), "FLAGTRA" ) ;
3005 ifnoCol.attach( iter.table(), "IFNO" ) ;
3006 ScalarColumn<uInt> polnos ;
3007 polnos.attach( iter.table(), "POLNO" ) ;
3008 MDirection::ScalarColumn dircol ;
3009 dircol.attach( iter.table(), "DIRECTION" ) ;
3010 uInt polno = polnos( 0 ) ;
3011 //cout << "POLNO iteration: " << polno << endl ;
3012// for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3013// sizes[igrp].resize( freqgrp[igrp].size() ) ;
3014// for ( uInt imem = 0 ; imem < freqgrp[igrp].size() ; imem++ ) {
3015// for ( uInt irow = 0 ; irow < iter.table().nrow() ; irow++ ) {
3016// uInt ifno = ifnoCol( irow ) ;
3017// if ( ifno == freqgrp[igrp][imem] ) {
3018// Vector<Float> spec = specCols( irow ) ;
3019// Vector<uChar> flag = flagCols( irow ) ;
3020// vector<Float> svec ;
3021// spec.tovector( svec ) ;
3022// vector<uChar> fvec ;
3023// flag.tovector( fvec ) ;
3024// //cout << "spec.size() = " << svec.size() << " fvec.size() = " << fvec.size() << endl ;
3025// specout[igrp].insert( specout[igrp].end(), svec.begin(), svec.end() ) ;
3026// flagout[igrp].insert( flagout[igrp].end(), fvec.begin(), fvec.end() ) ;
3027// //cout << "specout[" << igrp << "].size() = " << specout[igrp].size() << endl ;
3028// sizes[igrp][imem] = spec.nelements() ;
3029// }
3030// }
3031// }
3032// for ( uInt irow = 0 ; irow < out->table().nrow() ; irow++ ) {
3033// uInt ifout = ifnoColOut( irow ) ;
3034// uInt polout = polnoColOut( irow ) ;
3035// if ( ifout == gmemid[igrp] && polout == polno ) {
3036// // set SPECTRA and FRAGTRA
3037// Vector<Float> newspec( specout[igrp] ) ;
3038// Vector<uChar> newflag( flagout[igrp] ) ;
3039// specColOut.put( irow, newspec ) ;
3040// flagColOut.put( irow, newflag ) ;
3041// // IFNO renumbering
3042// ifnoColOut.put( irow, igrp ) ;
3043// }
3044// }
3045// }
3046 // get a list of number of channels for each frequency group member
3047 if ( !done ) {
3048 for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3049 sizes[igrp].resize( freqgrp[igrp].size() ) ;
3050 for ( uInt imem = 0 ; imem < freqgrp[igrp].size() ; imem++ ) {
3051 for ( uInt irow = 0 ; irow < iter.table().nrow() ; irow++ ) {
3052 uInt ifno = ifnoCol( irow ) ;
3053 if ( ifno == freqgrp[igrp][imem] ) {
3054 Vector<Float> spec = specCols( irow ) ;
3055 sizes[igrp][imem] = spec.nelements() ;
3056 break ;
3057 }
3058 }
3059 }
3060 }
3061 done = true ;
3062 }
3063 // combine spectra
3064 for ( uInt irow = 0 ; irow < out->table().nrow() ; irow++ ) {
3065 uInt polout = polnoColOut( irow ) ;
3066 if ( polout == polno ) {
3067 uInt ifout = ifnoColOut( irow ) ;
3068 Vector<Double> direction = dirColOut(irow).getAngle(Unit(String("rad"))).getValue() ;
3069 uInt igrp ;
3070 for ( uInt jgrp = 0 ; jgrp < freqgrp.size() ; jgrp++ ) {
3071 if ( ifout == gmemid[jgrp] ) {
3072 igrp = jgrp ;
3073 break ;
3074 }
3075 }
3076 for ( uInt imem = 0 ; imem < freqgrp[igrp].size() ; imem++ ) {
3077 for ( uInt jrow = 0 ; jrow < iter.table().nrow() ; jrow++ ) {
3078 uInt ifno = ifnoCol( jrow ) ;
3079 Vector<Double> tdir = dircol(jrow).getAngle(Unit(String("rad"))).getValue() ;
3080 //if ( ifno == freqgrp[igrp][imem] && allTrue( tdir == direction ) ) {
3081 Double dx = tdir[0] - direction[0] ;
3082 Double dy = tdir[1] - direction[1] ;
3083 Double dd = sqrt( dx * dx + dy * dy ) ;
3084 //if ( ifno == freqgrp[igrp][imem] && allNearAbs( tdir, direction, tol ) ) {
3085 if ( ifno == freqgrp[igrp][imem] && dd <= tol ) {
3086 Vector<Float> spec = specCols( jrow ) ;
3087 Vector<uChar> flag = flagCols( jrow ) ;
3088 vector<Float> svec ;
3089 spec.tovector( svec ) ;
3090 vector<uChar> fvec ;
3091 flag.tovector( fvec ) ;
3092 //cout << "spec.size() = " << svec.size() << " fvec.size() = " << fvec.size() << endl ;
3093 specout[igrp].insert( specout[igrp].end(), svec.begin(), svec.end() ) ;
3094 flagout[igrp].insert( flagout[igrp].end(), fvec.begin(), fvec.end() ) ;
3095 //cout << "specout[" << igrp << "].size() = " << specout[igrp].size() << endl ;
3096 }
3097 }
3098 }
3099 // set SPECTRA and FRAGTRA
3100 Vector<Float> newspec( specout[igrp] ) ;
3101 Vector<uChar> newflag( flagout[igrp] ) ;
3102 specColOut.put( irow, newspec ) ;
3103 flagColOut.put( irow, newflag ) ;
3104 // IFNO renumbering
3105 ifnoColOut.put( irow, igrp ) ;
3106 }
3107 }
3108 iter++ ;
3109 }
3110 // update FREQUENCIES subtable
3111 vector<bool> updated( freqgrp.size(), false ) ;
3112 for ( uInt igrp = 0 ; igrp < freqgrp.size() ; igrp++ ) {
3113 uInt index = 0 ;
3114 uInt pixShift = 0 ;
3115 while ( freqgrp[igrp][index] != gmemid[igrp] ) {
3116 pixShift += sizes[igrp][index++] ;
3117 }
3118 for ( uInt irow = 0 ; irow < out->table().nrow() ; irow++ ) {
3119 if ( ifnoColOut( irow ) == gmemid[igrp] && !updated[igrp] ) {
3120 uInt freqidOut = freqidColOut( irow ) ;
3121 //cout << "freqgrp " << igrp << " freqidOut = " << freqidOut << endl ;
3122 double refpix ;
3123 double refval ;
3124 double increm ;
3125 out->frequencies().getEntry( refpix, refval, increm, freqidOut ) ;
3126 refpix += pixShift ;
3127 out->frequencies().setEntry( refpix, refval, increm, freqidOut ) ;
3128 updated[igrp] = true ;
3129 }
3130 }
3131 }
3132
3133 //out = tmpout ;
3134
3135 coordinfo = tmpout->getCoordInfo() ;
3136 coordinfo[0] = oldinfo[0] ;
3137 tmpout->setCoordInfo( coordinfo ) ;
3138 }
3139 else {
3140 // simple average
3141 out = average( in, mask, weight, avmode ) ;
3142 }
3143
3144 return out ;
3145}
Note: See TracBrowser for help on using the repository browser.