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

Last change on this file since 1607 was 1607, checked in by Takeshi Nakazato, 16 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: run sdaverage with OTF data

Put in Release Notes: No

Module(s): Module Names change impacts.

Description: Describe your changes here...

Previous averaging methods could not deal with OTF data since these methods
does not refer DIRECTION information so that dumped spectra with different
DIRECTION are unwillingly accumulated.
Currently, these methods refer DIRECTION column to support OTF data.
Therefore, spectra are accumulated only when DIRECTION is exactly same.
I have defined a tolerance for the determination of the coincidence of
DIRECTION, but it is very small value (order of significant digits for
double) right now.


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