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

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

New Development: No

JIRA Issue: Yes CAS-1823

Ready to Release: Yes

Interface Changes: Yes

What Interface Changed: The mode parameter is added to scantable.scale() method.

Test Programs: s = sd.scantable('yourfile',False)

factor = []
for i in range(s.nrow()):

factor.append(i)

s2 = s + factor

Put in Release Notes: Yes

Module(s): -

Description: Describe your changes here...

Basic operations (addition, subtraction, multiplication, division)
of scantable with one dimensional list are implemented.
Size of list operand should be equal to either number of spectral channel
or number of row. In the former case, the list is operated as
channel-by-channel manner, while it is operated as row-by-row manner
in the latter case.
If number of spectral channel is equal to number of row, row-by-row
operation will be done.

The user is able to select operation mode (channel-by-channel or row-by-row)
manually by using lower level function, stmath.arrayop().

The scantable.scale() method is updated to allow list scaling factor.
Scaling is done in channel-by-channel manner if mode is set to 'channel',
while in row-by-row manner if mode is set to 'row'.


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