source: trunk/src/STMath.cpp@ 2107

Last change on this file since 2107 was 2102, checked in by Takeshi Nakazato, 14 years ago

New Development: No

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed: Please list interface changes

Test Programs: List test programs

Put in Release Notes: Yes/No

Module(s): Module Names change impacts.

Description: Describe your changes here...

Bug fix on calibration script and polarization type resolution.


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