source: trunk/src/Scantable.cpp@ 3078

Last change on this file since 3078 was 3076, checked in by Takeshi Nakazato, 9 years ago

New Development: No

JIRA Issue: No

Ready for Test: Yes

Interface Changes: Yes/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...


Make Scantable warning free.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 172.0 KB
Line 
1//
2// C++ Implementation: Scantable
3//
4// Description:
5//
6//
7// Author: Malte Marquarding <asap@atnf.csiro.au>, (C) 2005-2013
8//
9// Copyright: See COPYING file that comes with this distribution
10//
11//
12#include <map>
13#include <sys/time.h>
14#include <iostream>
15
16#include <atnf/PKSIO/SrcType.h>
17
18#include <casa/aips.h>
19#include <casa/iomanip.h>
20#include <casa/iostream.h>
21#include <casa/OS/File.h>
22#include <casa/OS/Path.h>
23#include <casa/Logging/LogIO.h>
24#include <casa/Arrays/Array.h>
25#include <casa/Arrays/ArrayAccessor.h>
26#include <casa/Arrays/ArrayLogical.h>
27#include <casa/Arrays/ArrayMath.h>
28#include <casa/Arrays/MaskArrMath.h>
29#include <casa/Arrays/Slice.h>
30#include <casa/Arrays/Vector.h>
31#include <casa/Arrays/VectorSTLIterator.h>
32#include <casa/BasicMath/Math.h>
33#include <casa/BasicSL/Constants.h>
34#include <casa/Containers/RecordField.h>
35#include <casa/Logging/LogIO.h>
36#include <casa/Quanta/MVAngle.h>
37#include <casa/Quanta/MVTime.h>
38#include <casa/Utilities/GenSort.h>
39#include <casa/Utilities/Assert.h>
40
41#include <coordinates/Coordinates/CoordinateUtil.h>
42
43// needed to avoid error in .tcc
44#include <measures/Measures/MCDirection.h>
45//
46#include <measures/Measures/MDirection.h>
47#include <measures/Measures/MEpoch.h>
48#include <measures/Measures/MFrequency.h>
49#include <measures/Measures/MeasRef.h>
50#include <measures/Measures/MeasTable.h>
51#include <measures/TableMeasures/ScalarMeasColumn.h>
52#include <measures/TableMeasures/TableMeasDesc.h>
53#include <measures/TableMeasures/TableMeasRefDesc.h>
54#include <measures/TableMeasures/TableMeasValueDesc.h>
55
56#include <tables/Tables/ArrColDesc.h>
57#include <tables/Tables/ExprNode.h>
58#include <tables/Tables/ScaColDesc.h>
59#include <tables/Tables/SetupNewTab.h>
60#include <tables/Tables/TableCopy.h>
61#include <tables/Tables/TableDesc.h>
62#include <tables/Tables/TableIter.h>
63#include <tables/Tables/TableParse.h>
64#include <tables/Tables/TableRecord.h>
65#include <tables/Tables/TableRow.h>
66#include <tables/Tables/TableVector.h>
67
68#include "MathUtils.h"
69#include "STAttr.h"
70#include "STBaselineTable.h"
71#include "STLineFinder.h"
72#include "STPolCircular.h"
73#include "STPolLinear.h"
74#include "STPolStokes.h"
75#include "STUpgrade.h"
76#include "STFitter.h"
77#include "Scantable.h"
78
79#define debug 1
80
81using namespace casa;
82
83namespace asap {
84
85std::map<std::string, STPol::STPolFactory *> Scantable::factories_;
86
87void Scantable::initFactories() {
88 if ( factories_.empty() ) {
89 Scantable::factories_["linear"] = &STPolLinear::myFactory;
90 Scantable::factories_["circular"] = &STPolCircular::myFactory;
91 Scantable::factories_["stokes"] = &STPolStokes::myFactory;
92 }
93}
94
95Scantable::Scantable(Table::TableType ttype) :
96 type_(ttype),
97 cubicSplineModelPool_()
98{
99 initFactories();
100 setupMainTable();
101 freqTable_ = STFrequencies(*this);
102 table_.rwKeywordSet().defineTable("FREQUENCIES", freqTable_.table());
103 weatherTable_ = STWeather(*this);
104 table_.rwKeywordSet().defineTable("WEATHER", weatherTable_.table());
105 focusTable_ = STFocus(*this);
106 table_.rwKeywordSet().defineTable("FOCUS", focusTable_.table());
107 tcalTable_ = STTcal(*this);
108 table_.rwKeywordSet().defineTable("TCAL", tcalTable_.table());
109 moleculeTable_ = STMolecules(*this);
110 table_.rwKeywordSet().defineTable("MOLECULES", moleculeTable_.table());
111 historyTable_ = STHistory(*this);
112 table_.rwKeywordSet().defineTable("HISTORY", historyTable_.table());
113 fitTable_ = STFit(*this);
114 table_.rwKeywordSet().defineTable("FIT", fitTable_.table());
115 table_.tableInfo().setType( "Scantable" ) ;
116 originalTable_ = table_;
117 attach();
118}
119
120Scantable::Scantable(const std::string& name, Table::TableType ttype) :
121 type_(ttype),
122 cubicSplineModelPool_()
123{
124 initFactories();
125
126 Table tab(name, Table::Update);
127 uInt version = tab.keywordSet().asuInt("VERSION");
128 if (version != version_) {
129 STUpgrade upgrader(version_);
130 LogIO os( LogOrigin( "Scantable" ) ) ;
131 os << LogIO::WARN
132 << name << " data format version " << version
133 << " is deprecated" << endl
134 << "Running upgrade."<< endl
135 << LogIO::POST ;
136 std::string outname = upgrader.upgrade(name);
137 if ( outname != name ) {
138 os << LogIO::WARN
139 << "Data will be loaded from " << outname << " instead of "
140 << name << LogIO::POST ;
141 tab = Table(outname, Table::Update ) ;
142 }
143 }
144 if ( type_ == Table::Memory ) {
145 table_ = tab.copyToMemoryTable(generateName());
146 } else {
147 table_ = tab;
148 }
149 table_.tableInfo().setType( "Scantable" ) ;
150
151 attachSubtables();
152 originalTable_ = table_;
153 attach();
154}
155/*
156Scantable::Scantable(const std::string& name, Table::TableType ttype) :
157 type_(ttype)
158{
159 initFactories();
160 Table tab(name, Table::Update);
161 uInt version = tab.keywordSet().asuInt("VERSION");
162 if (version != version_) {
163 throw(AipsError("Unsupported version of ASAP file."));
164 }
165 if ( type_ == Table::Memory ) {
166 table_ = tab.copyToMemoryTable(generateName());
167 } else {
168 table_ = tab;
169 }
170
171 attachSubtables();
172 originalTable_ = table_;
173 attach();
174}
175*/
176
177Scantable::Scantable( const Scantable& other, bool clear )
178{
179 // with or without data
180 String newname = String(generateName());
181 type_ = other.table_.tableType();
182 if ( other.table_.tableType() == Table::Memory ) {
183 if ( clear ) {
184 table_ = TableCopy::makeEmptyMemoryTable(newname,
185 other.table_, True);
186 } else {
187 table_ = other.table_.copyToMemoryTable(newname);
188 }
189 } else {
190 other.table_.deepCopy(newname, Table::New, False,
191 other.table_.endianFormat(),
192 Bool(clear));
193 table_ = Table(newname, Table::Update);
194 table_.markForDelete();
195 }
196 table_.tableInfo().setType( "Scantable" ) ;
197 /// @todo reindex SCANNO, recompute nbeam, nif, npol
198 if ( clear ) copySubtables(other);
199 attachSubtables();
200 originalTable_ = table_;
201 attach();
202}
203
204void Scantable::copySubtables(const Scantable& other) {
205 Table t = table_.rwKeywordSet().asTable("FREQUENCIES");
206 TableCopy::copyRows(t, other.freqTable_.table());
207 t = table_.rwKeywordSet().asTable("FOCUS");
208 TableCopy::copyRows(t, other.focusTable_.table());
209 t = table_.rwKeywordSet().asTable("WEATHER");
210 TableCopy::copyRows(t, other.weatherTable_.table());
211 t = table_.rwKeywordSet().asTable("TCAL");
212 TableCopy::copyRows(t, other.tcalTable_.table());
213 t = table_.rwKeywordSet().asTable("MOLECULES");
214 TableCopy::copyRows(t, other.moleculeTable_.table());
215 t = table_.rwKeywordSet().asTable("HISTORY");
216 TableCopy::copyRows(t, other.historyTable_.table());
217 t = table_.rwKeywordSet().asTable("FIT");
218 TableCopy::copyRows(t, other.fitTable_.table());
219}
220
221void Scantable::attachSubtables()
222{
223 freqTable_ = STFrequencies(table_);
224 focusTable_ = STFocus(table_);
225 weatherTable_ = STWeather(table_);
226 tcalTable_ = STTcal(table_);
227 moleculeTable_ = STMolecules(table_);
228 historyTable_ = STHistory(table_);
229 fitTable_ = STFit(table_);
230}
231
232Scantable::~Scantable()
233{
234}
235
236void Scantable::setupMainTable()
237{
238 TableDesc td("", "1", TableDesc::Scratch);
239 td.comment() = "An ASAP Scantable";
240 td.rwKeywordSet().define("VERSION", uInt(version_));
241
242 // n Cycles
243 td.addColumn(ScalarColumnDesc<uInt>("SCANNO"));
244 // new index every nBeam x nIF x nPol
245 td.addColumn(ScalarColumnDesc<uInt>("CYCLENO"));
246
247 td.addColumn(ScalarColumnDesc<uInt>("BEAMNO"));
248 td.addColumn(ScalarColumnDesc<uInt>("IFNO"));
249 // linear, circular, stokes
250 td.rwKeywordSet().define("POLTYPE", String("linear"));
251 td.addColumn(ScalarColumnDesc<uInt>("POLNO"));
252
253 td.addColumn(ScalarColumnDesc<uInt>("FREQ_ID"));
254 td.addColumn(ScalarColumnDesc<uInt>("MOLECULE_ID"));
255
256 ScalarColumnDesc<Int> refbeamnoColumn("REFBEAMNO");
257 refbeamnoColumn.setDefault(Int(-1));
258 td.addColumn(refbeamnoColumn);
259
260 ScalarColumnDesc<uInt> flagrowColumn("FLAGROW");
261 flagrowColumn.setDefault(uInt(0));
262 td.addColumn(flagrowColumn);
263
264 td.addColumn(ScalarColumnDesc<Double>("TIME"));
265 TableMeasRefDesc measRef(MEpoch::UTC); // UTC as default
266 TableMeasValueDesc measVal(td, "TIME");
267 TableMeasDesc<MEpoch> mepochCol(measVal, measRef);
268 mepochCol.write(td);
269
270 td.addColumn(ScalarColumnDesc<Double>("INTERVAL"));
271
272 td.addColumn(ScalarColumnDesc<String>("SRCNAME"));
273 // Type of source (on=0, off=1, other=-1)
274 ScalarColumnDesc<Int> stypeColumn("SRCTYPE");
275 stypeColumn.setDefault(Int(-1));
276 td.addColumn(stypeColumn);
277 td.addColumn(ScalarColumnDesc<String>("FIELDNAME"));
278
279 //The actual Data Vectors
280 td.addColumn(ArrayColumnDesc<Float>("SPECTRA"));
281 td.addColumn(ArrayColumnDesc<uChar>("FLAGTRA"));
282 td.addColumn(ArrayColumnDesc<Float>("TSYS"));
283
284 td.addColumn(ArrayColumnDesc<Double>("DIRECTION",
285 IPosition(1,2),
286 ColumnDesc::Direct));
287 TableMeasRefDesc mdirRef(MDirection::J2000); // default
288 TableMeasValueDesc tmvdMDir(td, "DIRECTION");
289 // the TableMeasDesc gives the column a type
290 TableMeasDesc<MDirection> mdirCol(tmvdMDir, mdirRef);
291 // a uder set table type e.g. GALCTIC, B1950 ...
292 td.rwKeywordSet().define("DIRECTIONREF", String("J2000"));
293 // writing create the measure column
294 mdirCol.write(td);
295 td.addColumn(ScalarColumnDesc<Float>("AZIMUTH"));
296 td.addColumn(ScalarColumnDesc<Float>("ELEVATION"));
297 td.addColumn(ScalarColumnDesc<Float>("OPACITY"));
298
299 td.addColumn(ScalarColumnDesc<uInt>("TCAL_ID"));
300 ScalarColumnDesc<Int> fitColumn("FIT_ID");
301 fitColumn.setDefault(Int(-1));
302 td.addColumn(fitColumn);
303
304 td.addColumn(ScalarColumnDesc<uInt>("FOCUS_ID"));
305 td.addColumn(ScalarColumnDesc<uInt>("WEATHER_ID"));
306
307 // columns which just get dragged along, as they aren't used in asap
308 td.addColumn(ScalarColumnDesc<Double>("SRCVELOCITY"));
309 td.addColumn(ArrayColumnDesc<Double>("SRCPROPERMOTION"));
310 td.addColumn(ArrayColumnDesc<Double>("SRCDIRECTION"));
311 td.addColumn(ArrayColumnDesc<Double>("SCANRATE"));
312
313 td.rwKeywordSet().define("OBSMODE", String(""));
314
315 // Now create Table SetUp from the description.
316 SetupNewTable aNewTab(generateName(), td, Table::Scratch);
317 table_ = Table(aNewTab, type_, 0);
318 originalTable_ = table_;
319}
320
321void Scantable::attach()
322{
323 timeCol_.attach(table_, "TIME");
324 srcnCol_.attach(table_, "SRCNAME");
325 srctCol_.attach(table_, "SRCTYPE");
326 specCol_.attach(table_, "SPECTRA");
327 flagsCol_.attach(table_, "FLAGTRA");
328 tsysCol_.attach(table_, "TSYS");
329 cycleCol_.attach(table_,"CYCLENO");
330 scanCol_.attach(table_, "SCANNO");
331 beamCol_.attach(table_, "BEAMNO");
332 ifCol_.attach(table_, "IFNO");
333 polCol_.attach(table_, "POLNO");
334 integrCol_.attach(table_, "INTERVAL");
335 azCol_.attach(table_, "AZIMUTH");
336 elCol_.attach(table_, "ELEVATION");
337 dirCol_.attach(table_, "DIRECTION");
338 fldnCol_.attach(table_, "FIELDNAME");
339 rbeamCol_.attach(table_, "REFBEAMNO");
340
341 mweatheridCol_.attach(table_,"WEATHER_ID");
342 mfitidCol_.attach(table_,"FIT_ID");
343 mfreqidCol_.attach(table_, "FREQ_ID");
344 mtcalidCol_.attach(table_, "TCAL_ID");
345 mfocusidCol_.attach(table_, "FOCUS_ID");
346 mmolidCol_.attach(table_, "MOLECULE_ID");
347
348 //Add auxiliary column for row-based flagging (CAS-1433 Wataru Kawasaki)
349 attachAuxColumnDef(flagrowCol_, "FLAGROW", 0);
350
351}
352
353template<class T, class T2>
354void Scantable::attachAuxColumnDef(ScalarColumn<T>& col,
355 const String& colName,
356 const T2& defValue)
357{
358 try {
359 col.attach(table_, colName);
360 } catch (TableError& err) {
361 String errMesg = err.getMesg();
362 if (errMesg == "Table column " + colName + " is unknown") {
363 table_.addColumn(ScalarColumnDesc<T>(colName));
364 col.attach(table_, colName);
365 col.fillColumn(static_cast<T>(defValue));
366 } else {
367 throw;
368 }
369 } catch (...) {
370 throw;
371 }
372}
373
374template<class T, class T2>
375void Scantable::attachAuxColumnDef(ArrayColumn<T>& col,
376 const String& colName,
377 const Array<T2>& defValue)
378{
379 try {
380 col.attach(table_, colName);
381 } catch (TableError& err) {
382 String errMesg = err.getMesg();
383 if (errMesg == "Table column " + colName + " is unknown") {
384 table_.addColumn(ArrayColumnDesc<T>(colName));
385 col.attach(table_, colName);
386
387 int size = 0;
388 ArrayIterator<T2>& it = defValue.begin();
389 while (it != defValue.end()) {
390 ++size;
391 ++it;
392 }
393 IPosition ip(1, size);
394 Array<T>& arr(ip);
395 for (int i = 0; i < size; ++i)
396 arr[i] = static_cast<T>(defValue[i]);
397
398 col.fillColumn(arr);
399 } else {
400 throw;
401 }
402 } catch (...) {
403 throw;
404 }
405}
406
407void Scantable::setHeader(const STHeader& sdh)
408{
409 table_.rwKeywordSet().define("nIF", sdh.nif);
410 table_.rwKeywordSet().define("nBeam", sdh.nbeam);
411 table_.rwKeywordSet().define("nPol", sdh.npol);
412 table_.rwKeywordSet().define("nChan", sdh.nchan);
413 table_.rwKeywordSet().define("Observer", sdh.observer);
414 table_.rwKeywordSet().define("Project", sdh.project);
415 table_.rwKeywordSet().define("Obstype", sdh.obstype);
416 table_.rwKeywordSet().define("AntennaName", sdh.antennaname);
417 table_.rwKeywordSet().define("AntennaPosition", sdh.antennaposition);
418 table_.rwKeywordSet().define("Equinox", sdh.equinox);
419 table_.rwKeywordSet().define("FreqRefFrame", sdh.freqref);
420 table_.rwKeywordSet().define("FreqRefVal", sdh.reffreq);
421 table_.rwKeywordSet().define("Bandwidth", sdh.bandwidth);
422 table_.rwKeywordSet().define("UTC", sdh.utc);
423 table_.rwKeywordSet().define("FluxUnit", sdh.fluxunit);
424 table_.rwKeywordSet().define("Epoch", sdh.epoch);
425 table_.rwKeywordSet().define("POLTYPE", sdh.poltype);
426}
427
428STHeader Scantable::getHeader() const
429{
430 STHeader sdh;
431 table_.keywordSet().get("nBeam",sdh.nbeam);
432 table_.keywordSet().get("nIF",sdh.nif);
433 table_.keywordSet().get("nPol",sdh.npol);
434 table_.keywordSet().get("nChan",sdh.nchan);
435 table_.keywordSet().get("Observer", sdh.observer);
436 table_.keywordSet().get("Project", sdh.project);
437 table_.keywordSet().get("Obstype", sdh.obstype);
438 table_.keywordSet().get("AntennaName", sdh.antennaname);
439 table_.keywordSet().get("AntennaPosition", sdh.antennaposition);
440 table_.keywordSet().get("Equinox", sdh.equinox);
441 table_.keywordSet().get("FreqRefFrame", sdh.freqref);
442 table_.keywordSet().get("FreqRefVal", sdh.reffreq);
443 table_.keywordSet().get("Bandwidth", sdh.bandwidth);
444 table_.keywordSet().get("UTC", sdh.utc);
445 table_.keywordSet().get("FluxUnit", sdh.fluxunit);
446 table_.keywordSet().get("Epoch", sdh.epoch);
447 table_.keywordSet().get("POLTYPE", sdh.poltype);
448 return sdh;
449}
450
451void Scantable::setSourceType( int stype )
452{
453 if ( stype < 0 || stype > 1 )
454 throw(AipsError("Illegal sourcetype."));
455 TableVector<Int> tabvec(table_, "SRCTYPE");
456 tabvec = Int(stype);
457}
458
459void Scantable::setSourceName( const std::string& name )
460{
461 TableVector<String> tabvec(table_, "SRCNAME");
462 tabvec = name;
463}
464
465bool Scantable::conformant( const Scantable& other )
466{
467 return this->getHeader().conformant(other.getHeader());
468}
469
470
471
472std::string Scantable::formatSec(Double x) const
473{
474 Double xcop = x;
475 MVTime mvt(xcop/24./3600.); // make days
476
477 if (x < 59.95)
478 return String(" ") + mvt.string(MVTime::TIME_CLEAN_NO_HM, 7)+"s";
479 else if (x < 3599.95)
480 return String(" ") + mvt.string(MVTime::TIME_CLEAN_NO_H,7)+" ";
481 else {
482 ostringstream oss;
483 oss << setw(2) << std::right << setprecision(1) << mvt.hour();
484 oss << ":" << mvt.string(MVTime::TIME_CLEAN_NO_H,7) << " ";
485 return String(oss);
486 }
487};
488
489 std::string Scantable::formatDirection(const MDirection& md, Int prec) const
490{
491 Vector<Double> t = md.getAngle(Unit(String("rad"))).getValue();
492 if (prec<0)
493 prec = 7;
494
495 String ref = md.getRefString();
496 MVAngle mvLon(t[0]);
497 String sLon = mvLon.string(MVAngle::TIME,prec);
498 uInt tp = md.getRef().getType();
499 if (tp == MDirection::GALACTIC ||
500 tp == MDirection::SUPERGAL ) {
501 sLon = mvLon(0.0).string(MVAngle::ANGLE_CLEAN,prec);
502 }
503 MVAngle mvLat(t[1]);
504 String sLat = mvLat.string(MVAngle::ANGLE+MVAngle::DIG2,prec);
505 return ref + String(" ") + sLon + String(" ") + sLat;
506}
507
508
509std::string Scantable::getFluxUnit() const
510{
511 return table_.keywordSet().asString("FluxUnit");
512}
513
514void Scantable::setFluxUnit(const std::string& unit)
515{
516 String tmp(unit);
517 Unit tU(tmp);
518 if (tU==Unit("K") || tU==Unit("Jy")) {
519 table_.rwKeywordSet().define(String("FluxUnit"), tmp);
520 } else {
521 throw AipsError("Illegal unit - must be compatible with Jy or K");
522 }
523}
524
525void Scantable::setInstrument(const std::string& name)
526{
527 bool throwIt = true;
528 // create an Instrument to see if this is valid
529 STAttr::convertInstrument(name, throwIt);
530 String nameU(name);
531 nameU.upcase();
532 table_.rwKeywordSet().define(String("AntennaName"), nameU);
533}
534
535void Scantable::setFeedType(const std::string& feedtype)
536{
537 if ( Scantable::factories_.find(feedtype) == Scantable::factories_.end() ) {
538 std::string msg = "Illegal feed type "+ feedtype;
539 throw(casa::AipsError(msg));
540 }
541 table_.rwKeywordSet().define(String("POLTYPE"), feedtype);
542}
543
544MPosition Scantable::getAntennaPosition() const
545{
546 Vector<Double> antpos;
547 table_.keywordSet().get("AntennaPosition", antpos);
548 MVPosition mvpos(antpos(0),antpos(1),antpos(2));
549 return MPosition(mvpos);
550}
551
552void Scantable::makePersistent(const std::string& filename)
553{
554 String inname(filename);
555 Path path(inname);
556 /// @todo reindex SCANNO, recompute nbeam, nif, npol
557 inname = path.expandedName();
558 // 2011/03/04 TN
559 // We can comment out this workaround since the essential bug is
560 // fixed in casacore (r20889 in google code).
561 table_.deepCopy(inname, Table::New);
562// // WORKAROUND !!! for Table bug
563// // Remove when fixed in casacore
564// if ( table_.tableType() == Table::Memory && !selector_.empty() ) {
565// Table tab = table_.copyToMemoryTable(generateName());
566// tab.deepCopy(inname, Table::New);
567// tab.markForDelete();
568//
569// } else {
570// table_.deepCopy(inname, Table::New);
571// }
572}
573
574int Scantable::nbeam( int scanno ) const
575{
576 if ( scanno < 0 ) {
577 Int n;
578 table_.keywordSet().get("nBeam",n);
579 return int(n);
580 } else {
581 // take the first POLNO,IFNO,CYCLENO as nbeam shouldn't vary with these
582 Table t = table_(table_.col("SCANNO") == scanno);
583 ROTableRow row(t);
584 const TableRecord& rec = row.get(0);
585 Table subt = t( t.col("IFNO") == Int(rec.asuInt("IFNO"))
586 && t.col("POLNO") == Int(rec.asuInt("POLNO"))
587 && t.col("CYCLENO") == Int(rec.asuInt("CYCLENO")) );
588 ROTableVector<uInt> v(subt, "BEAMNO");
589 return int(v.nelements());
590 }
591 return 0;
592}
593
594int Scantable::nif( int scanno ) const
595{
596 if ( scanno < 0 ) {
597 Int n;
598 table_.keywordSet().get("nIF",n);
599 return int(n);
600 } else {
601 // take the first POLNO,BEAMNO,CYCLENO as nbeam shouldn't vary with these
602 Table t = table_(table_.col("SCANNO") == scanno);
603 ROTableRow row(t);
604 const TableRecord& rec = row.get(0);
605 Table subt = t( t.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
606 && t.col("POLNO") == Int(rec.asuInt("POLNO"))
607 && t.col("CYCLENO") == Int(rec.asuInt("CYCLENO")) );
608 if ( subt.nrow() == 0 ) return 0;
609 ROTableVector<uInt> v(subt, "IFNO");
610 return int(v.nelements());
611 }
612 return 0;
613}
614
615int Scantable::npol( int scanno ) const
616{
617 if ( scanno < 0 ) {
618 Int n;
619 table_.keywordSet().get("nPol",n);
620 return n;
621 } else {
622 // take the first POLNO,IFNO,CYCLENO as nbeam shouldn't vary with these
623 Table t = table_(table_.col("SCANNO") == scanno);
624 ROTableRow row(t);
625 const TableRecord& rec = row.get(0);
626 Table subt = t( t.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
627 && t.col("IFNO") == Int(rec.asuInt("IFNO"))
628 && t.col("CYCLENO") == Int(rec.asuInt("CYCLENO")) );
629 if ( subt.nrow() == 0 ) return 0;
630 ROTableVector<uInt> v(subt, "POLNO");
631 return int(v.nelements());
632 }
633 return 0;
634}
635
636int Scantable::ncycle( int scanno ) const
637{
638 if ( scanno < 0 ) {
639 Block<String> cols(2);
640 cols[0] = "SCANNO";
641 cols[1] = "CYCLENO";
642 TableIterator it(table_, cols);
643 int n = 0;
644 while ( !it.pastEnd() ) {
645 ++n;
646 ++it;
647 }
648 return n;
649 } else {
650 Table t = table_(table_.col("SCANNO") == scanno);
651 ROTableRow row(t);
652 const TableRecord& rec = row.get(0);
653 Table subt = t( t.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
654 && t.col("POLNO") == Int(rec.asuInt("POLNO"))
655 && t.col("IFNO") == Int(rec.asuInt("IFNO")) );
656 if ( subt.nrow() == 0 ) return 0;
657 return int(subt.nrow());
658 }
659 return 0;
660}
661
662
663int Scantable::nrow( int /*scanno*/ ) const
664{
665 return int(table_.nrow());
666}
667
668int Scantable::nchan( int ifno ) const
669{
670 if ( ifno < 0 ) {
671 Int n;
672 table_.keywordSet().get("nChan",n);
673 return int(n);
674 } else {
675 // take the first SCANNO,POLNO,BEAMNO,CYCLENO as nbeam shouldn't
676 // vary with these
677 Table t = table_(table_.col("IFNO") == ifno, 1);
678 if ( t.nrow() == 0 ) return 0;
679 ROArrayColumn<Float> v(t, "SPECTRA");
680 return v.shape(0)(0);
681 }
682 return 0;
683}
684
685int Scantable::nscan() const {
686 Vector<uInt> scannos(scanCol_.getColumn());
687 uInt nout = genSort( scannos, Sort::Ascending,
688 Sort::QuickSort|Sort::NoDuplicates );
689 return int(nout);
690}
691
692int Scantable::getChannels(int whichrow) const
693{
694 return specCol_.shape(whichrow)(0);
695}
696
697int Scantable::getBeam(int whichrow) const
698{
699 return beamCol_(whichrow);
700}
701
702std::vector<uint> Scantable::getNumbers(const ScalarColumn<uInt>& col) const
703{
704 Vector<uInt> nos(col.getColumn());
705 uInt n = genSort( nos, Sort::Ascending, Sort::QuickSort|Sort::NoDuplicates );
706 nos.resize(n, True);
707 std::vector<uint> stlout;
708 nos.tovector(stlout);
709 return stlout;
710}
711
712int Scantable::getIF(int whichrow) const
713{
714 return ifCol_(whichrow);
715}
716
717int Scantable::getPol(int whichrow) const
718{
719 return polCol_(whichrow);
720}
721
722std::string Scantable::formatTime(const MEpoch& me, bool showdate) const
723{
724 return formatTime(me, showdate, 0);
725}
726
727std::string Scantable::formatTime(const MEpoch& me, bool showdate, uInt prec) const
728{
729 MVTime mvt(me.getValue());
730 if (showdate)
731 //mvt.setFormat(MVTime::YMD);
732 mvt.setFormat(MVTime::YMD, prec);
733 else
734 //mvt.setFormat(MVTime::TIME);
735 mvt.setFormat(MVTime::TIME, prec);
736 ostringstream oss;
737 oss << mvt;
738 return String(oss);
739}
740
741void Scantable::calculateAZEL()
742{
743 LogIO os( LogOrigin( "Scantable", "calculateAZEL()", WHERE ) ) ;
744 MPosition mp = getAntennaPosition();
745 MEpoch::ROScalarColumn timeCol(table_, "TIME");
746 ostringstream oss;
747 oss << mp;
748 os << "Computed azimuth/elevation using " << endl
749 << String(oss) << endl;
750 for (Int i=0; i<nrow(); ++i) {
751 MEpoch me = timeCol(i);
752 MDirection md = getDirection(i);
753 os << " Time: " << formatTime(me,False)
754 << " Direction: " << formatDirection(md)
755 << endl << " => ";
756 MeasFrame frame(mp, me);
757 Vector<Double> azel =
758 MDirection::Convert(md, MDirection::Ref(MDirection::AZEL,
759 frame)
760 )().getAngle("rad").getValue();
761 azCol_.put(i,Float(azel[0]));
762 elCol_.put(i,Float(azel[1]));
763 os << "azel: " << azel[0]/C::pi*180.0 << " "
764 << azel[1]/C::pi*180.0 << " (deg)" << LogIO::POST;
765 }
766}
767
768void Scantable::clip(const Float uthres, const Float dthres, bool clipoutside, bool unflag)
769{
770 Vector<uInt> flagrow = flagrowCol_.getColumn();
771 for (uInt i=0; i<table_.nrow(); ++i) {
772 // apply flag only when specified row is vaild
773 if (flagrow[i] == 0) {
774 Vector<uChar> flgs = flagsCol_(i);
775 srchChannelsToClip(i, uthres, dthres, clipoutside, unflag, flgs);
776 flagsCol_.put(i, flgs);
777 }
778 }
779}
780
781std::vector<bool> Scantable::getClipMask(int whichrow, const Float uthres, const Float dthres, bool clipoutside, bool unflag)
782{
783 Vector<uChar> flags;
784 flagsCol_.get(uInt(whichrow), flags);
785 srchChannelsToClip(uInt(whichrow), uthres, dthres, clipoutside, unflag, flags);
786 Vector<Bool> bflag(flags.shape());
787 convertArray(bflag, flags);
788 //bflag = !bflag;
789
790 std::vector<bool> mask;
791 bflag.tovector(mask);
792 return mask;
793}
794
795void Scantable::srchChannelsToClip(uInt whichrow, const Float uthres, const Float dthres, bool clipoutside, bool unflag,
796 Vector<uChar> flgs)
797{
798 Vector<Float> spcs = specCol_(whichrow);
799 uInt nchannel = spcs.nelements();
800 if (spcs.nelements() != nchannel) {
801 throw(AipsError("Data has incorrect number of channels"));
802 }
803 uChar userflag = 1 << 7;
804 if (unflag) {
805 userflag = 0 << 7;
806 }
807 if (clipoutside) {
808 for (uInt j = 0; j < nchannel; ++j) {
809 Float spc = spcs(j);
810 if ((spc >= uthres) || (spc <= dthres)) {
811 flgs(j) = userflag;
812 }
813 }
814 } else {
815 for (uInt j = 0; j < nchannel; ++j) {
816 Float spc = spcs(j);
817 if ((spc < uthres) && (spc > dthres)) {
818 flgs(j) = userflag;
819 }
820 }
821 }
822}
823
824
825void Scantable::flag( int whichrow, const std::vector<bool>& msk, bool unflag ) {
826 std::vector<bool>::const_iterator it;
827 uInt ntrue = 0;
828 if (whichrow >= int(table_.nrow()) ) {
829 throw(AipsError("Invalid row number"));
830 }
831 for (it = msk.begin(); it != msk.end(); ++it) {
832 if ( *it ) {
833 ntrue++;
834 }
835 }
836 //if ( selector_.empty() && (msk.size() == 0 || msk.size() == ntrue) )
837 if ( whichrow == -1 && !unflag && selector_.empty() && (msk.size() == 0 || msk.size() == ntrue) )
838 throw(AipsError("Trying to flag whole scantable."));
839 uChar userflag = 1 << 7;
840 if ( unflag ) {
841 userflag = 0 << 7;
842 }
843 if (whichrow > -1 ) {
844 // apply flag only when specified row is vaild
845 if (flagrowCol_(whichrow) == 0) {
846 applyChanFlag(uInt(whichrow), msk, userflag);
847 }
848 } else {
849 Vector<uInt> flagrow = flagrowCol_.getColumn();
850 for ( uInt i=0; i<table_.nrow(); ++i) {
851 // apply flag only when specified row is vaild
852 if (flagrow[i] == 0) {
853 applyChanFlag(i, msk, userflag);
854 }
855 }
856 }
857}
858
859void Scantable::applyChanFlag( uInt whichrow, const std::vector<bool>& msk, uChar flagval )
860{
861 if (whichrow >= table_.nrow() ) {
862 throw( casa::indexError<int>( whichrow, "asap::Scantable::applyChanFlag: Invalid row number" ) );
863 }
864 Vector<uChar> flgs = flagsCol_(whichrow);
865 if ( msk.size() == 0 ) {
866 flgs = flagval;
867 flagsCol_.put(whichrow, flgs);
868 return;
869 }
870 if ( int(msk.size()) != nchan( getIF(whichrow) ) ) {
871 throw(AipsError("Mask has incorrect number of channels."));
872 }
873 if ( flgs.nelements() != msk.size() ) {
874 throw(AipsError("Mask has incorrect number of channels."
875 " Probably varying with IF. Please flag per IF"));
876 }
877 std::vector<bool>::const_iterator it;
878 uInt j = 0;
879 for (it = msk.begin(); it != msk.end(); ++it) {
880 if ( *it ) {
881 flgs(j) = flagval;
882 }
883 ++j;
884 }
885 flagsCol_.put(whichrow, flgs);
886}
887
888void Scantable::flagRow(const std::vector<uInt>& rows, bool unflag)
889{
890 if (selector_.empty() && (rows.size() == table_.nrow()) && !unflag)
891 throw(AipsError("Trying to flag whole scantable."));
892
893 uInt rowflag = (unflag ? 0 : 1);
894 std::vector<uInt>::const_iterator it;
895 for (it = rows.begin(); it != rows.end(); ++it)
896 flagrowCol_.put(*it, rowflag);
897}
898
899std::vector<bool> Scantable::getMask(int whichrow) const
900{
901 Vector<uChar> flags;
902 flagsCol_.get(uInt(whichrow), flags);
903 Vector<Bool> bflag(flags.shape());
904 convertArray(bflag, flags);
905 bflag = !bflag;
906 std::vector<bool> mask;
907 bflag.tovector(mask);
908 return mask;
909}
910
911std::vector<float> Scantable::getSpectrum( int whichrow,
912 const std::string& poltype ) const
913{
914 LogIO os( LogOrigin( "Scantable", "getSpectrum()", WHERE ) ) ;
915
916 String ptype = poltype;
917 if (poltype == "" ) ptype = getPolType();
918 if ( whichrow < 0 || whichrow >= nrow() )
919 throw(AipsError("Illegal row number."));
920 std::vector<float> out;
921 Vector<Float> arr;
922 uInt requestedpol = polCol_(whichrow);
923 String basetype = getPolType();
924 if ( ptype == basetype ) {
925 specCol_.get(whichrow, arr);
926 } else {
927 CountedPtr<STPol> stpol(STPol::getPolClass(Scantable::factories_,
928 basetype));
929 uInt row = uInt(whichrow);
930 stpol->setSpectra(getPolMatrix(row));
931 Float fang,fhand;
932 fang = focusTable_.getTotalAngle(mfocusidCol_(row));
933 fhand = focusTable_.getFeedHand(mfocusidCol_(row));
934 stpol->setPhaseCorrections(fang, fhand);
935 arr = stpol->getSpectrum(requestedpol, ptype);
936 }
937 if ( arr.nelements() == 0 )
938
939 os << "Not enough polarisations present to do the conversion."
940 << LogIO::POST;
941 arr.tovector(out);
942 return out;
943}
944
945void Scantable::setSpectrum( const std::vector<float>& spec,
946 int whichrow )
947{
948 Vector<Float> spectrum(spec);
949 Vector<Float> arr;
950 specCol_.get(whichrow, arr);
951 if ( spectrum.nelements() != arr.nelements() )
952 throw AipsError("The spectrum has incorrect number of channels.");
953 specCol_.put(whichrow, spectrum);
954}
955
956
957String Scantable::generateName()
958{
959 return (File::newUniqueName("./","temp")).baseName();
960}
961
962const casa::Table& Scantable::table( ) const
963{
964 return table_;
965}
966
967casa::Table& Scantable::table( )
968{
969 return table_;
970}
971
972std::string Scantable::getPolType() const
973{
974 return table_.keywordSet().asString("POLTYPE");
975}
976
977void Scantable::unsetSelection()
978{
979 table_ = originalTable_;
980 attach();
981 selector_.reset();
982}
983
984void Scantable::setSelection( const STSelector& selection )
985{
986 Table tab = const_cast<STSelector&>(selection).apply(originalTable_);
987 if ( tab.nrow() == 0 ) {
988 throw(AipsError("Selection contains no data. Not applying it."));
989 }
990 table_ = tab;
991 attach();
992// tab.rwKeywordSet().define("nBeam",(Int)(getBeamNos().size())) ;
993// vector<uint> selectedIFs = getIFNos() ;
994// Int newnIF = selectedIFs.size() ;
995// tab.rwKeywordSet().define("nIF",newnIF) ;
996// if ( newnIF != 0 ) {
997// Int newnChan = 0 ;
998// for ( Int i = 0 ; i < newnIF ; i++ ) {
999// Int nChan = nchan( selectedIFs[i] ) ;
1000// if ( newnChan > nChan )
1001// newnChan = nChan ;
1002// }
1003// tab.rwKeywordSet().define("nChan",newnChan) ;
1004// }
1005// tab.rwKeywordSet().define("nPol",(Int)(getPolNos().size())) ;
1006 selector_ = selection;
1007}
1008
1009
1010std::string Scantable::headerSummary()
1011{
1012 // Format header info
1013// STHeader sdh;
1014// sdh = getHeader();
1015// sdh.print();
1016 ostringstream oss;
1017 oss.flags(std::ios_base::left);
1018 String tmp;
1019 // Project
1020 table_.keywordSet().get("Project", tmp);
1021 oss << setw(15) << "Project:" << tmp << endl;
1022 // Observation date
1023 oss << setw(15) << "Obs Date:" << getTime(-1,true) << endl;
1024 // Observer
1025 oss << setw(15) << "Observer:"
1026 << table_.keywordSet().asString("Observer") << endl;
1027 // Antenna Name
1028 table_.keywordSet().get("AntennaName", tmp);
1029 oss << setw(15) << "Antenna Name:" << tmp << endl;
1030 // Obs type
1031 table_.keywordSet().get("Obstype", tmp);
1032 // Records (nrow)
1033 oss << setw(15) << "Data Records:" << table_.nrow() << " rows" << endl;
1034 oss << setw(15) << "Obs. Type:" << tmp << endl;
1035 // Beams, IFs, Polarizations, and Channels
1036 oss << setw(15) << "Beams:" << setw(4) << nbeam() << endl
1037 << setw(15) << "IFs:" << setw(4) << nif() << endl
1038 << setw(15) << "Polarisations:" << setw(4) << npol()
1039 << "(" << getPolType() << ")" << endl
1040 << setw(15) << "Channels:" << nchan() << endl;
1041 // Flux unit
1042 table_.keywordSet().get("FluxUnit", tmp);
1043 oss << setw(15) << "Flux Unit:" << tmp << endl;
1044 // Abscissa Unit
1045 oss << setw(15) << "Abscissa:" << getAbcissaLabel(0) << endl;
1046 // Selection
1047 oss << selector_.print() << endl;
1048
1049 return String(oss);
1050}
1051
1052void Scantable::summary( const std::string& filename )
1053{
1054 ostringstream oss;
1055 ofstream ofs;
1056 LogIO ols(LogOrigin("Scantable", "summary", WHERE));
1057
1058 if (filename != "")
1059 ofs.open( filename.c_str(), ios::out );
1060
1061 oss << endl;
1062 oss << asap::SEPERATOR << endl;
1063 oss << " Scan Table Summary" << endl;
1064 oss << asap::SEPERATOR << endl;
1065
1066 // Format header info
1067 oss << headerSummary();
1068 oss << endl;
1069
1070 if (table_.nrow() <= 0){
1071 oss << asap::SEPERATOR << endl;
1072 oss << "The MAIN table is empty: there are no data!!!" << endl;
1073 oss << asap::SEPERATOR << endl;
1074
1075 ols << String(oss) << LogIO::POST;
1076 if (ofs) {
1077 ofs << String(oss) << flush;
1078 ofs.close();
1079 }
1080 return;
1081 }
1082
1083
1084
1085 // main table
1086 String dirtype = "Position ("
1087 + getDirectionRefString()
1088 + ")";
1089 oss.flags(std::ios_base::left);
1090 oss << setw(5) << "Scan"
1091 << setw(15) << "Source"
1092 << setw(35) << "Time range"
1093 << setw(2) << "" << setw(7) << "Int[s]"
1094 << setw(7) << "Record"
1095 << setw(8) << "SrcType"
1096 << setw(8) << "FreqIDs"
1097 << setw(7) << "MolIDs" << endl;
1098 oss << setw(7)<< "" << setw(6) << "Beam"
1099 << setw(23) << dirtype << endl;
1100
1101 oss << asap::SEPERATOR << endl;
1102
1103 // Flush summary and clear up the string
1104 ols << String(oss) << LogIO::POST;
1105 if (ofs) ofs << String(oss) << flush;
1106 oss.str("");
1107 oss.clear();
1108
1109
1110 // Get Freq_ID map
1111 ROScalarColumn<uInt> ftabIds(frequencies().table(), "ID");
1112 Int nfid = ftabIds.nrow();
1113 if (nfid <= 0){
1114 oss << "FREQUENCIES subtable is empty: there are no data!!!" << endl;
1115 oss << asap::SEPERATOR << endl;
1116
1117 ols << String(oss) << LogIO::POST;
1118 if (ofs) {
1119 ofs << String(oss) << flush;
1120 ofs.close();
1121 }
1122 return;
1123 }
1124 // Storages of overall IFNO, POLNO, and nchan per FREQ_ID
1125 // the orders are identical to ID in FREQ subtable
1126 Block< Vector<uInt> > ifNos(nfid), polNos(nfid);
1127 Vector<Int> fIdchans(nfid,-1);
1128 Vector<Double> fIdfreq0(nfid,-1);
1129 Vector<Double> fIdfcent(nfid,-1);
1130 map<uInt, Int> fidMap; // (FREQ_ID, row # in FREQ subtable) pair
1131 for (Int i=0; i < nfid; i++){
1132 // fidMap[freqId] returns row number in FREQ subtable
1133 fidMap.insert(pair<uInt, Int>(ftabIds(i),i));
1134 ifNos[i] = Vector<uInt>();
1135 polNos[i] = Vector<uInt>();
1136 }
1137
1138 TableIterator iter(table_, "SCANNO");
1139
1140 // Vars for keeping track of time, freqids, molIds in a SCANNO
1141 //Vector<uInt> freqids;
1142 //Vector<uInt> molids;
1143 Vector<uInt> beamids(1,0);
1144 Vector<MDirection> beamDirs;
1145 Vector<Int> stypeids(1,0);
1146 Vector<String> stypestrs;
1147 Int nfreq(1);
1148 Int nmol(1);
1149 uInt nbeam(1);
1150 uInt nstype(1);
1151
1152 Double btime(0.0), etime(0.0);
1153 Double meanIntTim(0.0);
1154
1155 uInt currFreqId(0), ftabRow(0);
1156 Int iflen(0), pollen(0);
1157
1158 while (!iter.pastEnd()) {
1159 Table subt = iter.table();
1160 uInt snrow = subt.nrow();
1161 ROTableRow row(subt);
1162 const TableRecord& rec = row.get(0);
1163
1164 // relevant columns
1165 ROScalarColumn<Double> mjdCol(subt,"TIME");
1166 ROScalarColumn<Double> intervalCol(subt,"INTERVAL");
1167 MDirection::ROScalarColumn dirCol(subt,"DIRECTION");
1168
1169 ScalarColumn<uInt> freqIdCol(subt,"FREQ_ID");
1170 ScalarColumn<uInt> molIdCol(subt,"MOLECULE_ID");
1171 ROScalarColumn<uInt> beamCol(subt,"BEAMNO");
1172 ROScalarColumn<Int> stypeCol(subt,"SRCTYPE");
1173
1174 ROScalarColumn<uInt> ifNoCol(subt,"IFNO");
1175 ROScalarColumn<uInt> polNoCol(subt,"POLNO");
1176
1177
1178 // Times
1179 meanIntTim = sum(intervalCol.getColumn()) / (double) snrow;
1180 minMax(btime, etime, mjdCol.getColumn());
1181 double shiftInDay(0.5*meanIntTim/C::day);
1182 btime -= shiftInDay;
1183 etime += shiftInDay;
1184
1185 // MOLECULE_ID and FREQ_ID
1186 Vector<uInt> molids(getNumbers(molIdCol));
1187 molids.shape(nmol);
1188
1189 Vector<uInt> freqids(getNumbers(freqIdCol));
1190 freqids.shape(nfreq);
1191
1192 // Add first beamid, and srcNames
1193 beamids.resize(1,False);
1194 beamDirs.resize(1,False);
1195 beamids(0)=beamCol(0);
1196 beamDirs(0)=dirCol(0);
1197 nbeam = 1;
1198
1199 stypeids.resize(1,False);
1200 stypeids(0)=stypeCol(0);
1201 nstype = 1;
1202
1203 // Global listings of nchan/IFNO/POLNO per FREQ_ID
1204 currFreqId=freqIdCol(0);
1205 ftabRow = fidMap[currFreqId];
1206 // Assumes an identical number of channels per FREQ_ID
1207 if (fIdchans(ftabRow) < 0 ) {
1208 RORecordFieldPtr< Array<Float> > spec(rec, "SPECTRA");
1209 fIdchans(ftabRow)=(*spec).shape()(0);
1210 }
1211 if (fIdfreq0(ftabRow) < 0 ) {
1212 SpectralCoordinate spc = frequencies().getSpectralCoordinate(ftabRow);
1213 Double fs, fe;
1214 spc.toWorld(fs, 0);
1215 spc.toWorld(fe, fIdchans(ftabRow)-1);
1216 fIdfreq0(ftabRow) = fs;
1217 fIdfcent(ftabRow) = 0.5 * ( fs + fe );
1218 }
1219 // Should keep ifNos and polNos form the previous SCANNO
1220 if ( !anyEQ(ifNos[ftabRow],ifNoCol(0)) ) {
1221 ifNos[ftabRow].shape(iflen);
1222 iflen++;
1223 ifNos[ftabRow].resize(iflen,True);
1224 ifNos[ftabRow](iflen-1) = ifNoCol(0);
1225 }
1226 if ( !anyEQ(polNos[ftabRow],polNoCol(0)) ) {
1227 polNos[ftabRow].shape(pollen);
1228 pollen++;
1229 polNos[ftabRow].resize(pollen,True);
1230 polNos[ftabRow](pollen-1) = polNoCol(0);
1231 }
1232
1233 for (uInt i=1; i < snrow; i++){
1234 // Need to list BEAMNO and DIRECTION in the same order
1235 if ( !anyEQ(beamids,beamCol(i)) ) {
1236 nbeam++;
1237 beamids.resize(nbeam,True);
1238 beamids(nbeam-1)=beamCol(i);
1239 beamDirs.resize(nbeam,True);
1240 beamDirs(nbeam-1)=dirCol(i);
1241 }
1242
1243 // SRCTYPE is Int (getNumber takes only uInt)
1244 if ( !anyEQ(stypeids,stypeCol(i)) ) {
1245 nstype++;
1246 stypeids.resize(nstype,True);
1247 stypeids(nstype-1)=stypeCol(i);
1248 }
1249
1250 // Global listings of nchan/IFNO/POLNO per FREQ_ID
1251 currFreqId=freqIdCol(i);
1252 ftabRow = fidMap[currFreqId];
1253 if (fIdchans(ftabRow) < 0 ) {
1254 const TableRecord& rec = row.get(i);
1255 RORecordFieldPtr< Array<Float> > spec(rec, "SPECTRA");
1256 fIdchans(ftabRow) = (*spec).shape()(0);
1257 }
1258 if (fIdfreq0(ftabRow) < 0 ) {
1259 SpectralCoordinate spc = frequencies().getSpectralCoordinate(ftabRow);
1260 Double fs, fe;
1261 spc.toWorld(fs, 0);
1262 spc.toWorld(fe, fIdchans(ftabRow)-1);
1263 fIdfreq0(ftabRow) = fs;
1264 fIdfcent(ftabRow) = 5.e-1 * ( fs + fe );
1265 }
1266 if ( !anyEQ(ifNos[ftabRow],ifNoCol(i)) ) {
1267 ifNos[ftabRow].shape(iflen);
1268 iflen++;
1269 ifNos[ftabRow].resize(iflen,True);
1270 ifNos[ftabRow](iflen-1) = ifNoCol(i);
1271 }
1272 if ( !anyEQ(polNos[ftabRow],polNoCol(i)) ) {
1273 polNos[ftabRow].shape(pollen);
1274 pollen++;
1275 polNos[ftabRow].resize(pollen,True);
1276 polNos[ftabRow](pollen-1) = polNoCol(i);
1277 }
1278 } // end of row iteration
1279
1280 stypestrs.resize(nstype,False);
1281 for (uInt j=0; j < nstype; j++)
1282 stypestrs(j) = SrcType::getName(stypeids(j));
1283
1284 // Format Scan summary
1285 oss << setw(4) << std::right << rec.asuInt("SCANNO")
1286 << std::left << setw(1) << ""
1287 << setw(15) << rec.asString("SRCNAME")
1288 << setw(21) << MVTime(btime).string(MVTime::YMD,8)
1289 << setw(3) << " - " << MVTime(etime).string(MVTime::TIME,8)
1290 << setw(3) << "" << setw(6) << meanIntTim << setw(1) << ""
1291 << std::right << setw(5) << snrow << setw(2) << ""
1292 << std::left << stypestrs << setw(1) << ""
1293 << freqids << setw(1) << ""
1294 << molids << endl;
1295 // Format Beam summary
1296 for (uInt j=0; j < nbeam; j++) {
1297 oss << setw(7) << "" << setw(6) << beamids(j) << setw(1) << ""
1298 << formatDirection(beamDirs(j),9) << endl;
1299 }
1300 // Flush summary every scan and clear up the string
1301 ols << String(oss) << LogIO::POST;
1302 if (ofs) ofs << String(oss) << flush;
1303 oss.str("");
1304 oss.clear();
1305
1306 ++iter;
1307 } // end of scan iteration
1308 oss << asap::SEPERATOR << endl;
1309
1310 // List FRECUENCIES Table (using STFrequencies.print may be slow)
1311 oss << "FREQUENCIES: " << nfreq << endl;
1312// oss << std::right << setw(5) << "ID" << setw(2) << ""
1313// << std::left << setw(5) << "IFNO" << setw(2) << ""
1314// << setw(8) << "Frame"
1315// << setw(16) << "RefVal"
1316// << setw(7) << "RefPix"
1317// << setw(15) << "Increment"
1318// << setw(9) << "Channels"
1319// << setw(6) << "POLNOs" << endl;
1320// Int tmplen;
1321// for (Int i=0; i < nfid; i++){
1322// // List row=i of FREQUENCIES subtable
1323// ifNos[i].shape(tmplen);
1324// if (tmplen >= 1) {
1325// oss << std::right << setw(5) << ftabIds(i) << setw(2) << ""
1326// << setw(3) << ifNos[i](0) << setw(1) << ""
1327// << std::left << setw(46) << frequencies().print(ftabIds(i))
1328// << setw(2) << ""
1329// << std::right << setw(8) << fIdchans[i] << setw(2) << ""
1330// << std::left << polNos[i];
1331// if (tmplen > 1) {
1332// oss << " (" << tmplen << " chains)";
1333// }
1334// oss << endl;
1335// }
1336 oss << std::right << setw(4) << "ID" << setw(2) << ""
1337 << std::left << setw(9) << "IFNO(SPW)" << setw(2) << ""
1338 << setw(8) << "#Chans"
1339 << setw(8) << "Frame"
1340 << setw(12) << "Ch0[MHz]"
1341 << setw(14) << "ChanWid[kHz]"
1342 << setw(14) << "Center[MHz]"
1343 << setw(6) << "POLNOs" << endl;
1344 Int tmplen;
1345 for (Int i=0; i < nfid; i++){
1346 // List row=i of FREQUENCIES subtable
1347 ifNos[i].shape(tmplen);
1348 Double refpix, refval, increment ;
1349 if (tmplen >= 1) {
1350 freqTable_.getEntry( refpix, refval, increment, ftabIds(i) ) ;
1351 oss << std::right << setw(4) << ftabIds(i) << setw(2) << ""
1352 << std::left << setw(9) << ifNos[i](0) << setw(2) << ""
1353 << std::right << setw(6) << fIdchans[i] << setw(2) << ""
1354 << setw(6) << frequencies().getFrameString(true)
1355 << setw(2) << ""
1356 << setw(10) << std::setprecision(9) << (fIdfreq0[i]*1.e-6) << setw(2) << ""
1357 << setw(12) << (increment*1.e-3) << setw(2) << ""
1358 << setw(12) << (fIdfcent[i]*1.e-6) << setw(2) << ""
1359 << std::left << polNos[i];
1360 if (tmplen > 1) {
1361 oss << " (" << tmplen << " chains)";
1362 }
1363 oss << endl;
1364 }
1365
1366 }
1367 oss << asap::SEPERATOR << endl;
1368
1369 // List MOLECULES Table (currently lists all rows)
1370 oss << "MOLECULES: " << endl;
1371 if (molecules().nrow() <= 0) {
1372 oss << " MOLECULES subtable is empty: there are no data" << endl;
1373 } else {
1374 ROTableRow row(molecules().table());
1375 oss << std::right << setw(5) << "ID"
1376 << std::left << setw(3) << ""
1377 << setw(18) << "RestFreq"
1378 << setw(15) << "Name" << endl;
1379 for (Int i=0; i < molecules().nrow(); i++){
1380 const TableRecord& rec=row.get(i);
1381 oss << std::right << setw(5) << rec.asuInt("ID")
1382 << std::left << setw(3) << ""
1383 << rec.asArrayDouble("RESTFREQUENCY") << setw(1) << ""
1384 << rec.asArrayString("NAME") << endl;
1385 }
1386 }
1387 oss << asap::SEPERATOR << endl;
1388 ols << String(oss) << LogIO::POST;
1389 if (ofs) {
1390 ofs << String(oss) << flush;
1391 ofs.close();
1392 }
1393 // return String(oss);
1394}
1395
1396
1397std::string Scantable::oldheaderSummary()
1398{
1399 // Format header info
1400// STHeader sdh;
1401// sdh = getHeader();
1402// sdh.print();
1403 ostringstream oss;
1404 oss.flags(std::ios_base::left);
1405 oss << setw(15) << "Beams:" << setw(4) << nbeam() << endl
1406 << setw(15) << "IFs:" << setw(4) << nif() << endl
1407 << setw(15) << "Polarisations:" << setw(4) << npol()
1408 << "(" << getPolType() << ")" << endl
1409 << setw(15) << "Channels:" << nchan() << endl;
1410 String tmp;
1411 oss << setw(15) << "Observer:"
1412 << table_.keywordSet().asString("Observer") << endl;
1413 oss << setw(15) << "Obs Date:" << getTime(-1,true) << endl;
1414 table_.keywordSet().get("Project", tmp);
1415 oss << setw(15) << "Project:" << tmp << endl;
1416 table_.keywordSet().get("Obstype", tmp);
1417 oss << setw(15) << "Obs. Type:" << tmp << endl;
1418 table_.keywordSet().get("AntennaName", tmp);
1419 oss << setw(15) << "Antenna Name:" << tmp << endl;
1420 table_.keywordSet().get("FluxUnit", tmp);
1421 oss << setw(15) << "Flux Unit:" << tmp << endl;
1422 int nid = moleculeTable_.nrow();
1423 Bool firstline = True;
1424 oss << setw(15) << "Rest Freqs:";
1425 for (int i=0; i<nid; i++) {
1426 Table t = table_(table_.col("MOLECULE_ID") == i, 1);
1427 if (t.nrow() > 0) {
1428 Vector<Double> vec(moleculeTable_.getRestFrequency(i));
1429 if (vec.nelements() > 0) {
1430 if (firstline) {
1431 oss << setprecision(10) << vec << " [Hz]" << endl;
1432 firstline=False;
1433 }
1434 else{
1435 oss << setw(15)<<" " << setprecision(10) << vec << " [Hz]" << endl;
1436 }
1437 } else {
1438 oss << "none" << endl;
1439 }
1440 }
1441 }
1442
1443 oss << setw(15) << "Abcissa:" << getAbcissaLabel(0) << endl;
1444 oss << selector_.print() << endl;
1445 return String(oss);
1446}
1447
1448 //std::string Scantable::summary( const std::string& filename )
1449void Scantable::oldsummary( const std::string& filename )
1450{
1451 ostringstream oss;
1452 ofstream ofs;
1453 LogIO ols(LogOrigin("Scantable", "summary", WHERE));
1454
1455 if (filename != "")
1456 ofs.open( filename.c_str(), ios::out );
1457
1458 oss << endl;
1459 oss << asap::SEPERATOR << endl;
1460 oss << " Scan Table Summary" << endl;
1461 oss << asap::SEPERATOR << endl;
1462
1463 // Format header info
1464 oss << oldheaderSummary();
1465 oss << endl;
1466
1467 // main table
1468 String dirtype = "Position ("
1469 + getDirectionRefString()
1470 + ")";
1471 oss.flags(std::ios_base::left);
1472 oss << setw(5) << "Scan" << setw(15) << "Source"
1473 << setw(10) << "Time" << setw(18) << "Integration"
1474 << setw(15) << "Source Type" << endl;
1475 oss << setw(5) << "" << setw(5) << "Beam" << setw(3) << "" << dirtype << endl;
1476 oss << setw(10) << "" << setw(3) << "IF" << setw(3) << ""
1477 << setw(8) << "Frame" << setw(16)
1478 << "RefVal" << setw(10) << "RefPix" << setw(12) << "Increment"
1479 << setw(7) << "Channels"
1480 << endl;
1481 oss << asap::SEPERATOR << endl;
1482
1483 // Flush summary and clear up the string
1484 ols << String(oss) << LogIO::POST;
1485 if (ofs) ofs << String(oss) << flush;
1486 oss.str("");
1487 oss.clear();
1488
1489 TableIterator iter(table_, "SCANNO");
1490 while (!iter.pastEnd()) {
1491 Table subt = iter.table();
1492 ROTableRow row(subt);
1493 MEpoch::ROScalarColumn timeCol(subt,"TIME");
1494 const TableRecord& rec = row.get(0);
1495 oss << setw(4) << std::right << rec.asuInt("SCANNO")
1496 << std::left << setw(1) << ""
1497 << setw(15) << rec.asString("SRCNAME")
1498 << setw(10) << formatTime(timeCol(0), false);
1499 // count the cycles in the scan
1500 TableIterator cyciter(subt, "CYCLENO");
1501 int nint = 0;
1502 while (!cyciter.pastEnd()) {
1503 ++nint;
1504 ++cyciter;
1505 }
1506 oss << setw(3) << std::right << nint << setw(3) << " x " << std::left
1507 << setw(11) << formatSec(rec.asFloat("INTERVAL")) << setw(1) << ""
1508 << setw(15) << SrcType::getName(rec.asInt("SRCTYPE")) << endl;
1509
1510 TableIterator biter(subt, "BEAMNO");
1511 while (!biter.pastEnd()) {
1512 Table bsubt = biter.table();
1513 ROTableRow brow(bsubt);
1514 const TableRecord& brec = brow.get(0);
1515 uInt row0 = bsubt.rowNumbers(table_)[0];
1516 oss << setw(5) << "" << setw(4) << std::right << brec.asuInt("BEAMNO")<< std::left;
1517 oss << setw(4) << "" << formatDirection(getDirection(row0)) << endl;
1518 TableIterator iiter(bsubt, "IFNO");
1519 while (!iiter.pastEnd()) {
1520 Table isubt = iiter.table();
1521 ROTableRow irow(isubt);
1522 const TableRecord& irec = irow.get(0);
1523 oss << setw(9) << "";
1524 oss << setw(3) << std::right << irec.asuInt("IFNO") << std::left
1525 << setw(1) << "" << frequencies().print(irec.asuInt("FREQ_ID"))
1526 << setw(3) << "" << nchan(irec.asuInt("IFNO"))
1527 << endl;
1528
1529 ++iiter;
1530 }
1531 ++biter;
1532 }
1533 // Flush summary every scan and clear up the string
1534 ols << String(oss) << LogIO::POST;
1535 if (ofs) ofs << String(oss) << flush;
1536 oss.str("");
1537 oss.clear();
1538
1539 ++iter;
1540 }
1541 oss << asap::SEPERATOR << endl;
1542 ols << String(oss) << LogIO::POST;
1543 if (ofs) {
1544 ofs << String(oss) << flush;
1545 ofs.close();
1546 }
1547 // return String(oss);
1548}
1549
1550// std::string Scantable::getTime(int whichrow, bool showdate) const
1551// {
1552// MEpoch::ROScalarColumn timeCol(table_, "TIME");
1553// MEpoch me;
1554// if (whichrow > -1) {
1555// me = timeCol(uInt(whichrow));
1556// } else {
1557// Double tm;
1558// table_.keywordSet().get("UTC",tm);
1559// me = MEpoch(MVEpoch(tm));
1560// }
1561// return formatTime(me, showdate);
1562// }
1563
1564std::string Scantable::getTime(int whichrow, bool showdate, uInt prec) const
1565{
1566 MEpoch me;
1567 me = getEpoch(whichrow);
1568 return formatTime(me, showdate, prec);
1569}
1570
1571MEpoch Scantable::getEpoch(int whichrow) const
1572{
1573 if (whichrow > -1) {
1574 return timeCol_(uInt(whichrow));
1575 } else {
1576 Double tm;
1577 table_.keywordSet().get("UTC",tm);
1578 return MEpoch(MVEpoch(tm));
1579 }
1580}
1581
1582std::string Scantable::getDirectionString(int whichrow) const
1583{
1584 return formatDirection(getDirection(uInt(whichrow)));
1585}
1586
1587
1588SpectralCoordinate Scantable::getSpectralCoordinate(int whichrow) const {
1589 const MPosition& mp = getAntennaPosition();
1590 const MDirection& md = getDirection(whichrow);
1591 const MEpoch& me = timeCol_(whichrow);
1592 //Double rf = moleculeTable_.getRestFrequency(mmolidCol_(whichrow));
1593 Vector<Double> rf = moleculeTable_.getRestFrequency(mmolidCol_(whichrow));
1594 return freqTable_.getSpectralCoordinate(md, mp, me, rf,
1595 mfreqidCol_(whichrow));
1596}
1597
1598std::vector< double > Scantable::getAbcissa( int whichrow ) const
1599{
1600 if ( whichrow > int(table_.nrow()) ) throw(AipsError("Illegal row number"));
1601 std::vector<double> stlout;
1602 int nchan = specCol_(whichrow).nelements();
1603 String us = freqTable_.getUnitString();
1604 if ( us == "" || us == "pixel" || us == "channel" ) {
1605 for (int i=0; i<nchan; ++i) {
1606 stlout.push_back(double(i));
1607 }
1608 return stlout;
1609 }
1610 SpectralCoordinate spc = getSpectralCoordinate(whichrow);
1611 Vector<Double> pixel(nchan);
1612 Vector<Double> world;
1613 indgen(pixel);
1614 if ( Unit(us) == Unit("Hz") ) {
1615 for ( int i=0; i < nchan; ++i) {
1616 Double world;
1617 spc.toWorld(world, pixel[i]);
1618 stlout.push_back(double(world));
1619 }
1620 } else if ( Unit(us) == Unit("km/s") ) {
1621 Vector<Double> world;
1622 spc.pixelToVelocity(world, pixel);
1623 world.tovector(stlout);
1624 }
1625 return stlout;
1626}
1627void Scantable::setDirectionRefString( const std::string & refstr )
1628{
1629 MDirection::Types mdt;
1630 if (refstr != "" && !MDirection::getType(mdt, refstr)) {
1631 throw(AipsError("Illegal Direction frame."));
1632 }
1633 if ( refstr == "" ) {
1634 String defaultstr = MDirection::showType(dirCol_.getMeasRef().getType());
1635 table_.rwKeywordSet().define("DIRECTIONREF", defaultstr);
1636 } else {
1637 table_.rwKeywordSet().define("DIRECTIONREF", String(refstr));
1638 }
1639}
1640
1641std::string Scantable::getDirectionRefString( ) const
1642{
1643 return table_.keywordSet().asString("DIRECTIONREF");
1644}
1645
1646MDirection Scantable::getDirection(int whichrow ) const
1647{
1648 String usertype = table_.keywordSet().asString("DIRECTIONREF");
1649 String type = MDirection::showType(dirCol_.getMeasRef().getType());
1650 if ( usertype != type ) {
1651 MDirection::Types mdt;
1652 if (!MDirection::getType(mdt, usertype)) {
1653 throw(AipsError("Illegal Direction frame."));
1654 }
1655 return dirCol_.convert(uInt(whichrow), mdt);
1656 } else {
1657 return dirCol_(uInt(whichrow));
1658 }
1659}
1660
1661std::string Scantable::getAbcissaLabel( int whichrow ) const
1662{
1663 if ( whichrow > int(table_.nrow()) ) throw(AipsError("Illegal ro number"));
1664 const MPosition& mp = getAntennaPosition();
1665 const MDirection& md = getDirection(whichrow);
1666 const MEpoch& me = timeCol_(whichrow);
1667 //const Double& rf = mmolidCol_(whichrow);
1668 const Vector<Double> rf = moleculeTable_.getRestFrequency(mmolidCol_(whichrow));
1669 SpectralCoordinate spc =
1670 freqTable_.getSpectralCoordinate(md, mp, me, rf, mfreqidCol_(whichrow));
1671
1672 String s = "Channel";
1673 Unit u = Unit(freqTable_.getUnitString());
1674 if (u == Unit("km/s")) {
1675 s = CoordinateUtil::axisLabel(spc, 0, True,True, True);
1676 } else if (u == Unit("Hz")) {
1677 Vector<String> wau(1);wau = u.getName();
1678 spc.setWorldAxisUnits(wau);
1679 s = CoordinateUtil::axisLabel(spc, 0, True, True, False);
1680 }
1681 return s;
1682
1683}
1684
1685/**
1686void asap::Scantable::setRestFrequencies( double rf, const std::string& name,
1687 const std::string& unit )
1688**/
1689void Scantable::setRestFrequencies( vector<double> rf, const vector<std::string>& name,
1690 const std::string& unit )
1691
1692{
1693 ///@todo lookup in line table to fill in name and formattedname
1694 Unit u(unit);
1695 //Quantum<Double> urf(rf, u);
1696 Quantum<Vector<Double> >urf(rf, u);
1697 Vector<String> formattedname(0);
1698 //cerr<<"Scantable::setRestFrequnecies="<<urf<<endl;
1699
1700 //uInt id = moleculeTable_.addEntry(urf.getValue("Hz"), name, "");
1701 uInt id = moleculeTable_.addEntry(urf.getValue("Hz"), mathutil::toVectorString(name), formattedname);
1702 TableVector<uInt> tabvec(table_, "MOLECULE_ID");
1703 tabvec = id;
1704}
1705
1706/**
1707void asap::Scantable::setRestFrequencies( const std::string& name )
1708{
1709 throw(AipsError("setRestFrequencies( const std::string& name ) NYI"));
1710 ///@todo implement
1711}
1712**/
1713
1714void Scantable::setRestFrequencies( const vector<std::string>& name )
1715{
1716 (void) name; // suppress unused warning
1717 throw(AipsError("setRestFrequencies( const vector<std::string>& name ) NYI"));
1718 ///@todo implement
1719}
1720
1721std::vector< unsigned int > Scantable::rownumbers( ) const
1722{
1723 std::vector<unsigned int> stlout;
1724 Vector<uInt> vec = table_.rowNumbers();
1725 vec.tovector(stlout);
1726 return stlout;
1727}
1728
1729
1730Matrix<Float> Scantable::getPolMatrix( uInt whichrow ) const
1731{
1732 ROTableRow row(table_);
1733 const TableRecord& rec = row.get(whichrow);
1734 Table t =
1735 originalTable_( originalTable_.col("SCANNO") == Int(rec.asuInt("SCANNO"))
1736 && originalTable_.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
1737 && originalTable_.col("IFNO") == Int(rec.asuInt("IFNO"))
1738 && originalTable_.col("CYCLENO") == Int(rec.asuInt("CYCLENO")) );
1739 ROArrayColumn<Float> speccol(t, "SPECTRA");
1740 return speccol.getColumn();
1741}
1742
1743std::vector< std::string > Scantable::columnNames( ) const
1744{
1745 Vector<String> vec = table_.tableDesc().columnNames();
1746 return mathutil::tovectorstring(vec);
1747}
1748
1749MEpoch::Types Scantable::getTimeReference( ) const
1750{
1751 return MEpoch::castType(timeCol_.getMeasRef().getType());
1752}
1753
1754void Scantable::addFit( const STFitEntry& fit, int row )
1755{
1756 //cout << mfitidCol_(uInt(row)) << endl;
1757 LogIO os( LogOrigin( "Scantable", "addFit()", WHERE ) ) ;
1758 os << mfitidCol_(uInt(row)) << LogIO::POST ;
1759 uInt id = fitTable_.addEntry(fit, mfitidCol_(uInt(row)));
1760 mfitidCol_.put(uInt(row), id);
1761}
1762
1763void Scantable::shift(int npix)
1764{
1765 Vector<uInt> fids(mfreqidCol_.getColumn());
1766 genSort( fids, Sort::Ascending,
1767 Sort::QuickSort|Sort::NoDuplicates );
1768 for (uInt i=0; i<fids.nelements(); ++i) {
1769 frequencies().shiftRefPix(npix, fids[i]);
1770 }
1771}
1772
1773String Scantable::getAntennaName() const
1774{
1775 String out;
1776 table_.keywordSet().get("AntennaName", out);
1777 String::size_type pos1 = out.find("@") ;
1778 String::size_type pos2 = out.find("//") ;
1779 if ( pos2 != String::npos )
1780 out = out.substr(pos2+2,pos1-pos2-2) ;
1781 else if ( pos1 != String::npos )
1782 out = out.substr(0,pos1) ;
1783 return out;
1784}
1785
1786int Scantable::checkScanInfo(const std::vector<int>& scanlist) const
1787{
1788 String tbpath;
1789 int ret = 0;
1790 if ( table_.keywordSet().isDefined("GBT_GO") ) {
1791 table_.keywordSet().get("GBT_GO", tbpath);
1792 Table t(tbpath,Table::Old);
1793 // check each scan if other scan of the pair exist
1794 int nscan = scanlist.size();
1795 for (int i = 0; i < nscan; i++) {
1796 Table subt = t( t.col("SCAN") == scanlist[i] );
1797 if (subt.nrow()==0) {
1798 //cerr <<"Scan "<<scanlist[i]<<" cannot be found in the scantable."<<endl;
1799 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1800 os <<LogIO::WARN<<"Scan "<<scanlist[i]<<" cannot be found in the scantable."<<LogIO::POST;
1801 ret = 1;
1802 break;
1803 }
1804 ROTableRow row(subt);
1805 const TableRecord& rec = row.get(0);
1806 int scan1seqn = rec.asuInt("PROCSEQN");
1807 int laston1 = rec.asuInt("LASTON");
1808 if ( rec.asuInt("PROCSIZE")==2 ) {
1809 if ( i < nscan-1 ) {
1810 Table subt2 = t( t.col("SCAN") == scanlist[i+1] );
1811 if ( subt2.nrow() == 0) {
1812 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1813
1814 //cerr<<"Scan "<<scanlist[i+1]<<" cannot be found in the scantable."<<endl;
1815 os<<LogIO::WARN<<"Scan "<<scanlist[i+1]<<" cannot be found in the scantable."<<LogIO::POST;
1816 ret = 1;
1817 break;
1818 }
1819 ROTableRow row2(subt2);
1820 const TableRecord& rec2 = row2.get(0);
1821 int scan2seqn = rec2.asuInt("PROCSEQN");
1822 int laston2 = rec2.asuInt("LASTON");
1823 if (scan1seqn == 1 && scan2seqn == 2) {
1824 if (laston1 == laston2) {
1825 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1826 //cerr<<"A valid scan pair ["<<scanlist[i]<<","<<scanlist[i+1]<<"]"<<endl;
1827 os<<"A valid scan pair ["<<scanlist[i]<<","<<scanlist[i+1]<<"]"<<LogIO::POST;
1828 i +=1;
1829 }
1830 else {
1831 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1832 //cerr<<"Incorrect scan pair ["<<scanlist[i]<<","<<scanlist[i+1]<<"]"<<endl;
1833 os<<LogIO::WARN<<"Incorrect scan pair ["<<scanlist[i]<<","<<scanlist[i+1]<<"]"<<LogIO::POST;
1834 }
1835 }
1836 else if (scan1seqn==2 && scan2seqn == 1) {
1837 if (laston1 == laston2) {
1838 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1839 //cerr<<"["<<scanlist[i]<<","<<scanlist[i+1]<<"] is a valid scan pair but in incorrect order."<<endl;
1840 os<<LogIO::WARN<<"["<<scanlist[i]<<","<<scanlist[i+1]<<"] is a valid scan pair but in incorrect order."<<LogIO::POST;
1841 ret = 1;
1842 break;
1843 }
1844 }
1845 else {
1846 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1847 //cerr<<"The other scan for "<<scanlist[i]<<" appears to be missing. Check the input scan numbers."<<endl;
1848 os<<LogIO::WARN<<"The other scan for "<<scanlist[i]<<" appears to be missing. Check the input scan numbers."<<LogIO::POST;
1849 ret = 1;
1850 break;
1851 }
1852 }
1853 }
1854 else {
1855 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1856 //cerr<<"The scan does not appear to be standard obsevation."<<endl;
1857 os<<LogIO::WARN<<"The scan does not appear to be standard obsevation."<<LogIO::POST;
1858 }
1859 //if ( i >= nscan ) break;
1860 }
1861 }
1862 else {
1863 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1864 //cerr<<"No reference to GBT_GO table."<<endl;
1865 os<<LogIO::WARN<<"No reference to GBT_GO table."<<LogIO::POST;
1866 ret = 1;
1867 }
1868 return ret;
1869}
1870
1871std::vector<double> Scantable::getDirectionVector(int whichrow) const
1872{
1873 Vector<Double> Dir = dirCol_(whichrow).getAngle("rad").getValue();
1874 std::vector<double> dir;
1875 Dir.tovector(dir);
1876 return dir;
1877}
1878
1879void asap::Scantable::reshapeSpectrum( int nmin, int nmax )
1880 throw( casa::AipsError )
1881{
1882 // assumed that all rows have same nChan
1883 Vector<Float> arr = specCol_( 0 ) ;
1884 int nChan = arr.nelements() ;
1885
1886 // if nmin < 0 or nmax < 0, nothing to do
1887 if ( nmin < 0 ) {
1888 throw( casa::indexError<int>( nmin, "asap::Scantable::reshapeSpectrum: Invalid range. Negative index is specified." ) ) ;
1889 }
1890 if ( nmax < 0 ) {
1891 throw( casa::indexError<int>( nmax, "asap::Scantable::reshapeSpectrum: Invalid range. Negative index is specified." ) ) ;
1892 }
1893
1894 // if nmin > nmax, exchange values
1895 if ( nmin > nmax ) {
1896 int tmp = nmax ;
1897 nmax = nmin ;
1898 nmin = tmp ;
1899 LogIO os( LogOrigin( "Scantable", "reshapeSpectrum()", WHERE ) ) ;
1900 os << "Swap values. Applied range is ["
1901 << nmin << ", " << nmax << "]" << LogIO::POST ;
1902 }
1903
1904 // if nmin exceeds nChan, nothing to do
1905 if ( nmin >= nChan ) {
1906 throw( casa::indexError<int>( nmin, "asap::Scantable::reshapeSpectrum: Invalid range. Specified minimum exceeds nChan." ) ) ;
1907 }
1908
1909 // if nmax exceeds nChan, reset nmax to nChan
1910 if ( nmax >= nChan-1 ) {
1911 if ( nmin == 0 ) {
1912 // nothing to do
1913 LogIO os( LogOrigin( "Scantable", "reshapeSpectrum()", WHERE ) ) ;
1914 os << "Whole range is selected. Nothing to do." << LogIO::POST ;
1915 return ;
1916 }
1917 else {
1918 LogIO os( LogOrigin( "Scantable", "reshapeSpectrum()", WHERE ) ) ;
1919 os << "Specified maximum exceeds nChan. Applied range is ["
1920 << nmin << ", " << nChan-1 << "]." << LogIO::POST ;
1921 nmax = nChan - 1 ;
1922 }
1923 }
1924
1925 // reshape specCol_ and flagCol_
1926 for ( int irow = 0 ; irow < nrow() ; irow++ ) {
1927 reshapeSpectrum( nmin, nmax, irow ) ;
1928 }
1929
1930 // update FREQUENCIES subtable
1931 Vector<uInt> freqIdArray = mfreqidCol_.getColumn();
1932 uInt numFreqId = GenSort<uInt>::sort(freqIdArray, Sort::Ascending,
1933 Sort::HeapSort | Sort::NoDuplicates);
1934 Double refpix ;
1935 Double refval ;
1936 Double increment ;
1937 for (uInt irow = 0; irow < numFreqId; irow++) {
1938 freqTable_.getEntry( refpix, refval, increment, freqIdArray[irow] ) ;
1939 /***
1940 * need to shift refpix to nmin
1941 * note that channel nmin in old index will be channel 0 in new one
1942 ***/
1943 refval = refval - ( refpix - nmin ) * increment ;
1944 refpix = 0 ;
1945 freqTable_.setEntry( refpix, refval, increment, freqIdArray[irow] ) ;
1946 }
1947
1948 // update nchan
1949 int newsize = nmax - nmin + 1 ;
1950 table_.rwKeywordSet().define( "nChan", newsize ) ;
1951
1952 // update bandwidth
1953 // assumed all spectra in the scantable have same bandwidth
1954 table_.rwKeywordSet().define( "Bandwidth", increment * newsize ) ;
1955
1956 return ;
1957}
1958
1959void asap::Scantable::reshapeSpectrum( int nmin, int nmax, int irow )
1960{
1961 // reshape specCol_ and flagCol_
1962 Vector<Float> oldspec = specCol_( irow ) ;
1963 Vector<uChar> oldflag = flagsCol_( irow ) ;
1964 Vector<Float> oldtsys = tsysCol_( irow ) ;
1965 uInt newsize = nmax - nmin + 1 ;
1966 Slice slice( nmin, newsize, 1 ) ;
1967 specCol_.put( irow, oldspec( slice ) ) ;
1968 flagsCol_.put( irow, oldflag( slice ) ) ;
1969 if ( oldspec.size() == oldtsys.size() )
1970 tsysCol_.put( irow, oldtsys( slice ) ) ;
1971
1972 return ;
1973}
1974
1975void asap::Scantable::regridSpecChannel( double dnu, int nChan )
1976{
1977 LogIO os( LogOrigin( "Scantable", "regridChannel()", WHERE ) ) ;
1978 os << "Regrid abcissa with spectral resoultion " << dnu << " " << freqTable_.getUnitString() << " with channel number " << ((nChan>0)? String(nChan) : "covering band width")<< LogIO::POST ;
1979 int freqnrow = freqTable_.table().nrow() ;
1980 Vector<bool> firstTime( freqnrow, true ) ;
1981 double oldincr, factor;
1982 uInt currId;
1983 Double refpix ;
1984 Double refval ;
1985 Double increment ;
1986 for ( int irow = 0 ; irow < nrow() ; irow++ ) {
1987 currId = mfreqidCol_(irow);
1988 vector<double> abcissa = getAbcissa( irow ) ;
1989 if (nChan < 0) {
1990 int oldsize = abcissa.size() ;
1991 double bw = (abcissa[oldsize-1]-abcissa[0]) + \
1992 0.5 * (abcissa[1]-abcissa[0] + abcissa[oldsize-1]-abcissa[oldsize-2]) ;
1993 nChan = int( ceil( abs(bw/dnu) ) ) ;
1994 }
1995 // actual regridding
1996 regridChannel( nChan, dnu, irow ) ;
1997
1998 // update FREQUENCIES subtable
1999 if (firstTime[currId]) {
2000 oldincr = abcissa[1]-abcissa[0] ;
2001 factor = dnu/oldincr ;
2002 firstTime[currId] = false ;
2003 freqTable_.getEntry( refpix, refval, increment, currId ) ;
2004
2005 //refval = refval - ( refpix + 0.5 * (1 - factor) ) * increment ;
2006 if (factor > 0 ) {
2007 refpix = (refpix + 0.5)/factor - 0.5;
2008 } else {
2009 refpix = (abcissa.size() - 0.5 - refpix)/abs(factor) - 0.5;
2010 }
2011 freqTable_.setEntry( refpix, refval, increment*factor, currId ) ;
2012 //os << "ID" << currId << ": channel width (Orig) = " << oldincr << " [" << freqTable_.getUnitString() << "], scale factor = " << factor << LogIO::POST ;
2013 //os << " frequency increment (Orig) = " << increment << "-> (New) " << increment*factor << LogIO::POST ;
2014 }
2015 }
2016}
2017
2018void asap::Scantable::regridChannel( int nChan, double dnu )
2019{
2020 LogIO os( LogOrigin( "Scantable", "regridChannel()", WHERE ) ) ;
2021 os << "Regrid abcissa with channel number " << nChan << " and spectral resoultion " << dnu << "Hz." << LogIO::POST ;
2022 // assumed that all rows have same nChan
2023 Vector<Float> arr = specCol_( 0 ) ;
2024 int oldsize = arr.nelements() ;
2025
2026 // if oldsize == nChan, nothing to do
2027 if ( oldsize == nChan ) {
2028 os << "Specified channel number is same as current one. Nothing to do." << LogIO::POST ;
2029 return ;
2030 }
2031
2032 // if oldChan < nChan, unphysical operation
2033 if ( oldsize < nChan ) {
2034 os << "Unphysical operation. Nothing to do." << LogIO::POST ;
2035 return ;
2036 }
2037
2038 // change channel number for specCol_, flagCol_, and tsysCol_ (if necessary)
2039 vector<string> coordinfo = getCoordInfo() ;
2040 string oldinfo = coordinfo[0] ;
2041 coordinfo[0] = "Hz" ;
2042 setCoordInfo( coordinfo ) ;
2043 for ( int irow = 0 ; irow < nrow() ; irow++ ) {
2044 regridChannel( nChan, dnu, irow ) ;
2045 }
2046 coordinfo[0] = oldinfo ;
2047 setCoordInfo( coordinfo ) ;
2048
2049
2050 // NOTE: this method does not update metadata such as
2051 // FREQUENCIES subtable, nChan, Bandwidth, etc.
2052
2053 return ;
2054}
2055
2056void asap::Scantable::regridChannel( int nChan, double dnu, int irow )
2057{
2058 // logging
2059 //ofstream ofs( "average.log", std::ios::out | std::ios::app ) ;
2060 //ofs << "IFNO = " << getIF( irow ) << " irow = " << irow << endl ;
2061
2062 Vector<Float> oldspec = specCol_( irow ) ;
2063 Vector<uChar> oldflag = flagsCol_( irow ) ;
2064 Vector<Float> oldtsys = tsysCol_( irow ) ;
2065 Vector<Float> newspec( nChan, 0 ) ;
2066 Vector<uChar> newflag( nChan, true ) ;
2067 Vector<Float> newtsys ;
2068 bool regridTsys = false ;
2069 if (oldtsys.size() == oldspec.size()) {
2070 regridTsys = true ;
2071 newtsys.resize(nChan,false) ;
2072 newtsys = 0 ;
2073 }
2074
2075 // regrid
2076 vector<double> abcissa = getAbcissa( irow ) ;
2077 int oldsize = abcissa.size() ;
2078 double olddnu = abcissa[1] - abcissa[0] ;
2079 //int ichan = 0 ;
2080 double wsum = 0.0 ;
2081 Vector<double> zi( nChan+1 ) ;
2082 Vector<double> yi( oldsize + 1 ) ;
2083 yi[0] = abcissa[0] - 0.5 * olddnu ;
2084 for ( int ii = 1 ; ii < oldsize ; ii++ )
2085 yi[ii] = 0.5* (abcissa[ii-1] + abcissa[ii]) ;
2086 yi[oldsize] = abcissa[oldsize-1] \
2087 + 0.5 * (abcissa[oldsize-1] - abcissa[oldsize-2]) ;
2088 //zi[0] = abcissa[0] - 0.5 * olddnu ;
2089 zi[0] = ((olddnu*dnu > 0) ? yi[0] : yi[oldsize]) ;
2090 for ( int ii = 1 ; ii < nChan ; ii++ )
2091 zi[ii] = zi[0] + dnu * ii ;
2092 zi[nChan] = zi[nChan-1] + dnu ;
2093 // Access zi and yi in ascending order
2094 int izs = ((dnu > 0) ? 0 : nChan ) ;
2095 int ize = ((dnu > 0) ? nChan : 0 ) ;
2096 int izincr = ((dnu > 0) ? 1 : -1 ) ;
2097 int ichan = ((olddnu > 0) ? 0 : oldsize ) ;
2098 int iye = ((olddnu > 0) ? oldsize : 0 ) ;
2099 int iyincr = ((olddnu > 0) ? 1 : -1 ) ;
2100 //for ( int ii = izs ; ii != ize ; ii+=izincr ){
2101 int ii = izs ;
2102 while (ii != ize) {
2103 // always zl < zr
2104 double zl = zi[ii] ;
2105 double zr = zi[ii+izincr] ;
2106 // Need to access smaller index for the new spec, flag, and tsys.
2107 // Values between zi[k] and zi[k+1] should be stored in newspec[k], etc.
2108 int i = min(ii, ii+izincr) ;
2109 //for ( int jj = ichan ; jj != iye ; jj+=iyincr ) {
2110 int jj = ichan ;
2111 while (jj != iye) {
2112 // always yl < yr
2113 double yl = yi[jj] ;
2114 double yr = yi[jj+iyincr] ;
2115 // Need to access smaller index for the original spec, flag, and tsys.
2116 // Values between yi[k] and yi[k+1] are stored in oldspec[k], etc.
2117 int j = min(jj, jj+iyincr) ;
2118 if ( yr <= zl ) {
2119 jj += iyincr ;
2120 continue ;
2121 }
2122 else if ( yl <= zl ) {
2123 if ( yr < zr ) {
2124 if (!oldflag[j]) {
2125 newspec[i] += oldspec[j] * ( yr - zl ) ;
2126 if (regridTsys) newtsys[i] += oldtsys[j] * ( yr - zl ) ;
2127 wsum += ( yr - zl ) ;
2128 }
2129 newflag[i] = (newflag[i] && oldflag[j]) ? 1 << 7 : 0 ;
2130 }
2131 else {
2132 if (!oldflag[j]) {
2133 newspec[i] += oldspec[j] * abs(dnu) ;
2134 if (regridTsys) newtsys[i] += oldtsys[j] * abs(dnu) ;
2135 wsum += abs(dnu) ;
2136 }
2137 newflag[i] = (newflag[i] && oldflag[j]) ? 1 << 7 : 0 ;
2138 ichan = jj ;
2139 break ;
2140 }
2141 }
2142 else if ( yl < zr ) {
2143 if ( yr <= zr ) {
2144 if (!oldflag[j]) {
2145 newspec[i] += oldspec[j] * ( yr - yl ) ;
2146 if (regridTsys) newtsys[i] += oldtsys[j] * ( yr - yl ) ;
2147 wsum += ( yr - yl ) ;
2148 }
2149 newflag[i] = (newflag[i] && oldflag[j]) ? 1 << 7 : 0 ;
2150 }
2151 else {
2152 if (!oldflag[j]) {
2153 newspec[i] += oldspec[j] * ( zr - yl ) ;
2154 if (regridTsys) newtsys[i] += oldtsys[j] * ( zr - yl ) ;
2155 wsum += ( zr - yl ) ;
2156 }
2157 newflag[i] = (newflag[i] && oldflag[j]) ? 1 << 7 : 0 ;
2158 ichan = jj ;
2159 break ;
2160 }
2161 }
2162 else {
2163 ichan = jj - iyincr ;
2164 break ;
2165 }
2166 jj += iyincr ;
2167 }
2168 if ( wsum != 0.0 ) {
2169 newspec[i] /= wsum ;
2170 if (regridTsys) newtsys[i] /= wsum ;
2171 }
2172 wsum = 0.0 ;
2173 ii += izincr ;
2174 }
2175// if ( dnu > 0.0 ) {
2176// for ( int ii = 0 ; ii < nChan ; ii++ ) {
2177// double zl = zi[ii] ;
2178// double zr = zi[ii+1] ;
2179// for ( int j = ichan ; j < oldsize ; j++ ) {
2180// double yl = yi[j] ;
2181// double yr = yi[j+1] ;
2182// if ( yl <= zl ) {
2183// if ( yr <= zl ) {
2184// continue ;
2185// }
2186// else if ( yr <= zr ) {
2187// if (!oldflag[j]) {
2188// newspec[ii] += oldspec[j] * ( yr - zl ) ;
2189// if (regridTsys) newtsys[ii] += oldtsys[j] * ( yr - zl ) ;
2190// wsum += ( yr - zl ) ;
2191// }
2192// newflag[ii] = newflag[ii] && oldflag[j] ;
2193// }
2194// else {
2195// if (!oldflag[j]) {
2196// newspec[ii] += oldspec[j] * dnu ;
2197// if (regridTsys) newtsys[ii] += oldtsys[j] * dnu ;
2198// wsum += dnu ;
2199// }
2200// newflag[ii] = newflag[ii] && oldflag[j] ;
2201// ichan = j ;
2202// break ;
2203// }
2204// }
2205// else if ( yl < zr ) {
2206// if ( yr <= zr ) {
2207// if (!oldflag[j]) {
2208// newspec[ii] += oldspec[j] * ( yr - yl ) ;
2209// if (regridTsys) newtsys[ii] += oldtsys[j] * ( yr - yl ) ;
2210// wsum += ( yr - yl ) ;
2211// }
2212// newflag[ii] = newflag[ii] && oldflag[j] ;
2213// }
2214// else {
2215// if (!oldflag[j]) {
2216// newspec[ii] += oldspec[j] * ( zr - yl ) ;
2217// if (regridTsys) newtsys[ii] += oldtsys[j] * ( zr - yl ) ;
2218// wsum += ( zr - yl ) ;
2219// }
2220// newflag[ii] = newflag[ii] && oldflag[j] ;
2221// ichan = j ;
2222// break ;
2223// }
2224// }
2225// else {
2226// ichan = j - 1 ;
2227// break ;
2228// }
2229// }
2230// if ( wsum != 0.0 ) {
2231// newspec[ii] /= wsum ;
2232// if (regridTsys) newtsys[ii] /= wsum ;
2233// }
2234// wsum = 0.0 ;
2235// }
2236// }
2237// else if ( dnu < 0.0 ) {
2238// for ( int ii = 0 ; ii < nChan ; ii++ ) {
2239// double zl = zi[ii] ;
2240// double zr = zi[ii+1] ;
2241// for ( int j = ichan ; j < oldsize ; j++ ) {
2242// double yl = yi[j] ;
2243// double yr = yi[j+1] ;
2244// if ( yl >= zl ) {
2245// if ( yr >= zl ) {
2246// continue ;
2247// }
2248// else if ( yr >= zr ) {
2249// if (!oldflag[j]) {
2250// newspec[ii] += oldspec[j] * abs( yr - zl ) ;
2251// if (regridTsys) newtsys[ii] += oldtsys[j] * abs( yr - zl ) ;
2252// wsum += abs( yr - zl ) ;
2253// }
2254// newflag[ii] = newflag[ii] && oldflag[j] ;
2255// }
2256// else {
2257// if (!oldflag[j]) {
2258// newspec[ii] += oldspec[j] * abs( dnu ) ;
2259// if (regridTsys) newtsys[ii] += oldtsys[j] * abs( dnu ) ;
2260// wsum += abs( dnu ) ;
2261// }
2262// newflag[ii] = newflag[ii] && oldflag[j] ;
2263// ichan = j ;
2264// break ;
2265// }
2266// }
2267// else if ( yl > zr ) {
2268// if ( yr >= zr ) {
2269// if (!oldflag[j]) {
2270// newspec[ii] += oldspec[j] * abs( yr - yl ) ;
2271// if (regridTsys) newtsys[ii] += oldtsys[j] * abs( yr - yl ) ;
2272// wsum += abs( yr - yl ) ;
2273// }
2274// newflag[ii] = newflag[ii] && oldflag[j] ;
2275// }
2276// else {
2277// if (!oldflag[j]) {
2278// newspec[ii] += oldspec[j] * abs( zr - yl ) ;
2279// if (regridTsys) newtsys[ii] += oldtsys[j] * abs( zr - yl ) ;
2280// wsum += abs( zr - yl ) ;
2281// }
2282// newflag[ii] = newflag[ii] && oldflag[j] ;
2283// ichan = j ;
2284// break ;
2285// }
2286// }
2287// else {
2288// ichan = j - 1 ;
2289// break ;
2290// }
2291// }
2292// if ( wsum != 0.0 ) {
2293// newspec[ii] /= wsum ;
2294// if (regridTsys) newtsys[ii] /= wsum ;
2295// }
2296// wsum = 0.0 ;
2297// }
2298// }
2299// // //ofs << "olddnu = " << olddnu << ", dnu = " << dnu << endl ;
2300// // pile += dnu ;
2301// // wedge = olddnu * ( refChan + 1 ) ;
2302// // while ( wedge < pile ) {
2303// // newspec[0] += olddnu * oldspec[refChan] ;
2304// // newflag[0] = newflag[0] || oldflag[refChan] ;
2305// // //ofs << "channel " << refChan << " is included in new channel 0" << endl ;
2306// // refChan++ ;
2307// // wedge += olddnu ;
2308// // wsum += olddnu ;
2309// // //ofs << "newspec[0] = " << newspec[0] << " wsum = " << wsum << endl ;
2310// // }
2311// // frac = ( wedge - pile ) / olddnu ;
2312// // wsum += ( 1.0 - frac ) * olddnu ;
2313// // newspec[0] += ( 1.0 - frac ) * olddnu * oldspec[refChan] ;
2314// // newflag[0] = newflag[0] || oldflag[refChan] ;
2315// // //ofs << "channel " << refChan << " is partly included in new channel 0" << " with fraction of " << ( 1.0 - frac ) << endl ;
2316// // //ofs << "newspec[0] = " << newspec[0] << " wsum = " << wsum << endl ;
2317// // newspec[0] /= wsum ;
2318// // //ofs << "newspec[0] = " << newspec[0] << endl ;
2319// // //ofs << "wedge = " << wedge << ", pile = " << pile << endl ;
2320
2321// // /***
2322// // * ichan = 1 - nChan-2
2323// // ***/
2324// // for ( int ichan = 1 ; ichan < nChan - 1 ; ichan++ ) {
2325// // pile += dnu ;
2326// // newspec[ichan] += frac * olddnu * oldspec[refChan] ;
2327// // newflag[ichan] = newflag[ichan] || oldflag[refChan] ;
2328// // //ofs << "channel " << refChan << " is partly included in new channel " << ichan << " with fraction of " << frac << endl ;
2329// // refChan++ ;
2330// // wedge += olddnu ;
2331// // wsum = frac * olddnu ;
2332// // //ofs << "newspec[" << ichan << "] = " << newspec[ichan] << " wsum = " << wsum << endl ;
2333// // while ( wedge < pile ) {
2334// // newspec[ichan] += olddnu * oldspec[refChan] ;
2335// // newflag[ichan] = newflag[ichan] || oldflag[refChan] ;
2336// // //ofs << "channel " << refChan << " is included in new channel " << ichan << endl ;
2337// // refChan++ ;
2338// // wedge += olddnu ;
2339// // wsum += olddnu ;
2340// // //ofs << "newspec[" << ichan << "] = " << newspec[ichan] << " wsum = " << wsum << endl ;
2341// // }
2342// // frac = ( wedge - pile ) / olddnu ;
2343// // wsum += ( 1.0 - frac ) * olddnu ;
2344// // newspec[ichan] += ( 1.0 - frac ) * olddnu * oldspec[refChan] ;
2345// // newflag[ichan] = newflag[ichan] || oldflag[refChan] ;
2346// // //ofs << "channel " << refChan << " is partly included in new channel " << ichan << " with fraction of " << ( 1.0 - frac ) << endl ;
2347// // //ofs << "wedge = " << wedge << ", pile = " << pile << endl ;
2348// // //ofs << "newspec[" << ichan << "] = " << newspec[ichan] << " wsum = " << wsum << endl ;
2349// // newspec[ichan] /= wsum ;
2350// // //ofs << "newspec[" << ichan << "] = " << newspec[ichan] << endl ;
2351// // }
2352
2353// // /***
2354// // * ichan = nChan-1
2355// // ***/
2356// // // NOTE: Assumed that all spectra have the same bandwidth
2357// // pile += dnu ;
2358// // newspec[nChan-1] += frac * olddnu * oldspec[refChan] ;
2359// // newflag[nChan-1] = newflag[nChan-1] || oldflag[refChan] ;
2360// // //ofs << "channel " << refChan << " is partly included in new channel " << nChan-1 << " with fraction of " << frac << endl ;
2361// // refChan++ ;
2362// // wedge += olddnu ;
2363// // wsum = frac * olddnu ;
2364// // //ofs << "newspec[" << nChan - 1 << "] = " << newspec[nChan-1] << " wsum = " << wsum << endl ;
2365// // for ( int jchan = refChan ; jchan < oldsize ; jchan++ ) {
2366// // newspec[nChan-1] += olddnu * oldspec[jchan] ;
2367// // newflag[nChan-1] = newflag[nChan-1] || oldflag[jchan] ;
2368// // wsum += olddnu ;
2369// // //ofs << "channel " << jchan << " is included in new channel " << nChan-1 << " with fraction of " << frac << endl ;
2370// // //ofs << "newspec[" << nChan - 1 << "] = " << newspec[nChan-1] << " wsum = " << wsum << endl ;
2371// // }
2372// // //ofs << "wedge = " << wedge << ", pile = " << pile << endl ;
2373// // //ofs << "newspec[" << nChan - 1 << "] = " << newspec[nChan-1] << " wsum = " << wsum << endl ;
2374// // newspec[nChan-1] /= wsum ;
2375// // //ofs << "newspec[" << nChan - 1 << "] = " << newspec[nChan-1] << endl ;
2376
2377// // // ofs.close() ;
2378
2379 specCol_.put( irow, newspec ) ;
2380 flagsCol_.put( irow, newflag ) ;
2381 if (regridTsys) tsysCol_.put( irow, newtsys );
2382
2383 return ;
2384}
2385
2386void Scantable::regridChannel( int nChan, double dnu, double fmin, int irow )
2387{
2388 Vector<Float> oldspec = specCol_( irow ) ;
2389 Vector<uChar> oldflag = flagsCol_( irow ) ;
2390 Vector<Float> oldtsys = tsysCol_( irow ) ;
2391 Vector<Float> newspec( nChan, 0 ) ;
2392 Vector<uChar> newflag( nChan, true ) ;
2393 Vector<Float> newtsys ;
2394 bool regridTsys = false ;
2395 if (oldtsys.size() == oldspec.size()) {
2396 regridTsys = true ;
2397 newtsys.resize(nChan,false) ;
2398 newtsys = 0 ;
2399 }
2400
2401 // regrid
2402 vector<double> abcissa = getAbcissa( irow ) ;
2403 int oldsize = abcissa.size() ;
2404 double olddnu = abcissa[1] - abcissa[0] ;
2405 //int ichan = 0 ;
2406 double wsum = 0.0 ;
2407 Vector<double> zi( nChan+1 ) ;
2408 Vector<double> yi( oldsize + 1 ) ;
2409 Block<uInt> count( nChan, 0 ) ;
2410 yi[0] = abcissa[0] - 0.5 * olddnu ;
2411 for ( int ii = 1 ; ii < oldsize ; ii++ )
2412 yi[ii] = 0.5* (abcissa[ii-1] + abcissa[ii]) ;
2413 yi[oldsize] = abcissa[oldsize-1] \
2414 + 0.5 * (abcissa[oldsize-1] - abcissa[oldsize-2]) ;
2415// cout << "olddnu=" << olddnu << ", dnu=" << dnu << " (diff=" << olddnu-dnu << ")" << endl ;
2416// cout << "yi[0]=" << yi[0] << ", fmin=" << fmin << " (diff=" << yi[0]-fmin << ")" << endl ;
2417// cout << "oldsize=" << oldsize << ", nChan=" << nChan << endl ;
2418
2419 // do not regrid if input parameters are almost same as current
2420 // spectral setup
2421 double dnuDiff = abs( ( dnu - olddnu ) / olddnu ) ;
2422 double oldfmin = min( yi[0], yi[oldsize] ) ;
2423 double fminDiff = abs( ( fmin - oldfmin ) / oldfmin ) ;
2424 double nChanDiff = nChan - oldsize ;
2425 double eps = 1.0e-8 ;
2426 if ( nChanDiff == 0 && dnuDiff < eps && fminDiff < eps )
2427 return ;
2428
2429 //zi[0] = abcissa[0] - 0.5 * olddnu ;
2430 //zi[0] = ((olddnu*dnu > 0) ? yi[0] : yi[oldsize]) ;
2431 if ( dnu > 0 )
2432 zi[0] = fmin - 0.5 * dnu ;
2433 else
2434 zi[0] = fmin + nChan * abs(dnu) ;
2435 for ( int ii = 1 ; ii < nChan ; ii++ )
2436 zi[ii] = zi[0] + dnu * ii ;
2437 zi[nChan] = zi[nChan-1] + dnu ;
2438 // Access zi and yi in ascending order
2439 int izs = ((dnu > 0) ? 0 : nChan ) ;
2440 int ize = ((dnu > 0) ? nChan : 0 ) ;
2441 int izincr = ((dnu > 0) ? 1 : -1 ) ;
2442 int ichan = ((olddnu > 0) ? 0 : oldsize ) ;
2443 int iye = ((olddnu > 0) ? oldsize : 0 ) ;
2444 int iyincr = ((olddnu > 0) ? 1 : -1 ) ;
2445 //for ( int ii = izs ; ii != ize ; ii+=izincr ){
2446 int ii = izs ;
2447 while (ii != ize) {
2448 // always zl < zr
2449 double zl = zi[ii] ;
2450 double zr = zi[ii+izincr] ;
2451 // Need to access smaller index for the new spec, flag, and tsys.
2452 // Values between zi[k] and zi[k+1] should be stored in newspec[k], etc.
2453 int i = min(ii, ii+izincr) ;
2454 //for ( int jj = ichan ; jj != iye ; jj+=iyincr ) {
2455 int jj = ichan ;
2456 while (jj != iye) {
2457 // always yl < yr
2458 double yl = yi[jj] ;
2459 double yr = yi[jj+iyincr] ;
2460 // Need to access smaller index for the original spec, flag, and tsys.
2461 // Values between yi[k] and yi[k+1] are stored in oldspec[k], etc.
2462 int j = min(jj, jj+iyincr) ;
2463 if ( yr <= zl ) {
2464 jj += iyincr ;
2465 continue ;
2466 }
2467 else if ( yl <= zl ) {
2468 if ( yr < zr ) {
2469 if (!oldflag[j]) {
2470 newspec[i] += oldspec[j] * ( yr - zl ) ;
2471 if (regridTsys) newtsys[i] += oldtsys[j] * ( yr - zl ) ;
2472 wsum += ( yr - zl ) ;
2473 count[i]++ ;
2474 }
2475 newflag[i] = newflag[i] && oldflag[j] ;
2476 }
2477 else {
2478 if (!oldflag[j]) {
2479 newspec[i] += oldspec[j] * abs(dnu) ;
2480 if (regridTsys) newtsys[i] += oldtsys[j] * abs(dnu) ;
2481 wsum += abs(dnu) ;
2482 count[i]++ ;
2483 }
2484 newflag[i] = newflag[i] && oldflag[j] ;
2485 ichan = jj ;
2486 break ;
2487 }
2488 }
2489 else if ( yl < zr ) {
2490 if ( yr <= zr ) {
2491 if (!oldflag[j]) {
2492 newspec[i] += oldspec[j] * ( yr - yl ) ;
2493 if (regridTsys) newtsys[i] += oldtsys[j] * ( yr - yl ) ;
2494 wsum += ( yr - yl ) ;
2495 count[i]++ ;
2496 }
2497 newflag[i] = newflag[i] && oldflag[j] ;
2498 }
2499 else {
2500 if (!oldflag[j]) {
2501 newspec[i] += oldspec[j] * ( zr - yl ) ;
2502 if (regridTsys) newtsys[i] += oldtsys[j] * ( zr - yl ) ;
2503 wsum += ( zr - yl ) ;
2504 count[i]++ ;
2505 }
2506 newflag[i] = newflag[i] && oldflag[j] ;
2507 ichan = jj ;
2508 break ;
2509 }
2510 }
2511 else {
2512 //ichan = jj - iyincr ;
2513 break ;
2514 }
2515 jj += iyincr ;
2516 }
2517 if ( wsum != 0.0 ) {
2518 newspec[i] /= wsum ;
2519 if (regridTsys) newtsys[i] /= wsum ;
2520 }
2521 wsum = 0.0 ;
2522 ii += izincr ;
2523 }
2524
2525 // flag out channels without data
2526 // this is tentative since there is no specific definition
2527 // on bit flag...
2528 uChar noData = 1 << 7 ;
2529 for ( Int i = 0 ; i < nChan ; i++ ) {
2530 if ( count[i] == 0 )
2531 newflag[i] = noData ;
2532 }
2533
2534 specCol_.put( irow, newspec ) ;
2535 flagsCol_.put( irow, newflag ) ;
2536 if (regridTsys) tsysCol_.put( irow, newtsys );
2537
2538 return ;
2539}
2540
2541std::vector<float> Scantable::getWeather(int whichrow) const
2542{
2543 std::vector<float> out(5);
2544 //Float temperature, pressure, humidity, windspeed, windaz;
2545 weatherTable_.getEntry(out[0], out[1], out[2], out[3], out[4],
2546 mweatheridCol_(uInt(whichrow)));
2547
2548
2549 return out;
2550}
2551
2552bool Scantable::isAllChannelsFlagged(uInt whichrow)
2553{
2554 uInt rflag;
2555 flagrowCol_.get(whichrow, rflag);
2556 if (rflag > 0)
2557 return true;
2558 bool flag;
2559 Vector<uChar> flags;
2560 flagsCol_.get(whichrow, flags);
2561 flag = (flags[0]>0);
2562 for (uInt i = 1; i < flags.size(); ++i) {
2563 flag &= (flags[i]>0);
2564 }
2565 // return ((flag >> 7) == 1);
2566 return (flag > 0);
2567}
2568
2569std::size_t Scantable::nValidMask(const std::vector<bool>& mask)
2570{
2571 std::size_t nvalid=0;
2572 // the assertion lines had better be replaced with static_assert when c++11 is supported
2573 AlwaysAssert(static_cast<std::size_t>(true)==1, AipsError);
2574 AlwaysAssert(static_cast<std::size_t>(false)==0, AipsError);
2575 for (uInt i = 1; i < mask.size(); ++i) {
2576 nvalid += static_cast<std::size_t>(mask[i]);
2577 }
2578 return nvalid;
2579}
2580
2581
2582std::vector<std::string> Scantable::applyBaselineTable(const std::string& bltable, const bool returnfitresult, const std::string& outbltable, const bool outbltableexists, const bool overwrite)
2583{
2584 STBaselineTable btin = STBaselineTable(bltable);
2585
2586 Vector<Bool> applyCol = btin.getApply();
2587 int nRowBl = applyCol.size();
2588 if (nRowBl != nrow()) {
2589 throw(AipsError("Scantable and bltable have different number of rows."));
2590 }
2591
2592 std::vector<std::string> res;
2593 res.clear();
2594
2595 bool outBaselineTable = ((outbltable != "") && (!outbltableexists || overwrite));
2596 bool bltableidentical = (bltable == outbltable);
2597 STBaselineTable btout = STBaselineTable(*this);
2598 ROScalarColumn<Double> tcol = ROScalarColumn<Double>(table_, "TIME");
2599 Vector<Double> timeSecCol = tcol.getColumn();
2600
2601 for (int whichrow = 0; whichrow < nRowBl; ++whichrow) {
2602 if (applyCol[whichrow]) {
2603 std::vector<float> spec = getSpectrum(whichrow);
2604
2605 std::vector<bool> mask = btin.getMask(whichrow); //use mask_bltable only
2606
2607 STBaselineFunc::FuncName ftype = btin.getFunctionName(whichrow);
2608 std::vector<int> fpar = btin.getFuncParam(whichrow);
2609 std::vector<float> params;
2610 float rms;
2611 std::vector<float> resfit = doApplyBaselineTable(spec, mask, ftype, fpar, params, rms, whichrow);
2612 setSpectrum(resfit, whichrow);
2613
2614 if (returnfitresult) {
2615 res.push_back(packFittingResults(whichrow, params, rms));
2616 }
2617
2618 if (outBaselineTable) {
2619 if (outbltableexists) {
2620 if (overwrite) {
2621 if (bltableidentical) {
2622 btin.setresult(uInt(whichrow), Vector<Float>(params), Float(rms));
2623 } else {
2624 btout.setresult(uInt(whichrow), Vector<Float>(params), Float(rms));
2625 }
2626 }
2627 } else {
2628 btout.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
2629 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
2630 true, ftype, fpar, std::vector<float>(),
2631 getMaskListFromMask(mask), params, rms, spec.size(),
2632 3.0, 0, 0.0, 0, std::vector<int>());
2633 }
2634 }
2635 }
2636 }
2637
2638 if (outBaselineTable) {
2639 if (bltableidentical) {
2640 btin.save(outbltable);
2641 } else {
2642 btout.save(outbltable);
2643 }
2644 }
2645
2646 return res;
2647}
2648
2649std::vector<std::string> Scantable::subBaseline(const std::vector<std::string>& blInfoList, const bool returnfitresult, const std::string& outbltable, const bool outbltableexists, const bool overwrite)
2650{
2651 int nRowBl = blInfoList.size();
2652 int nRowSt = nrow();
2653
2654 std::vector<std::string> res;
2655 res.clear();
2656
2657 bool outBaselineTable = ((outbltable != "") && (!outbltableexists || overwrite));
2658 if ((outbltable != "") && outbltableexists && !overwrite) {
2659 throw(AipsError("Cannot overwrite bltable. Set overwrite=True."));
2660 }
2661
2662 STBaselineTable* btp = NULL;
2663 ROScalarColumn<Double> tcol = ROScalarColumn<Double>(table_, "TIME");
2664 Vector<Double> timeSecCol = tcol.getColumn();
2665
2666 if (outBaselineTable) {
2667 if (outbltableexists) {
2668 btp = new STBaselineTable((String)outbltable);
2669 } else {
2670 btp = new STBaselineTable(*this);
2671 // for (int i = 0; i < nRowSt; ++i) {
2672 // btp->appendbasedata(getScan(i), getCycle(i), getBeam(i), getIF(i), getPol(i),
2673 // 0, timeSecCol[i]);
2674 // btp->setApply(i, false);
2675 // }
2676 }
2677 int nrow = btp->nrow();
2678 for (int i = nrow; i < nRowSt; ++i) {
2679 btp->appendbasedata(getScan(i), getCycle(i), getBeam(i), getIF(i), getPol(i),
2680 0, timeSecCol[i]);
2681 btp->setApply(i, false);
2682 }
2683 }
2684
2685 for (int i = 0; i < nRowBl; ++i) {
2686 int irow;
2687 STBaselineFunc::FuncName ftype;
2688 std::vector<bool> mask;
2689 std::vector<int> fpar;
2690 float clipth;
2691 int clipn;
2692 bool uself;
2693 float lfth;
2694 std::vector<int> lfedge;
2695 int lfavg;
2696 parseBlInfo(blInfoList[i], irow, ftype, fpar, mask, clipth, clipn, uself, lfth, lfedge, lfavg);
2697
2698 if (irow < nRowSt) {
2699 std::vector<float> spec = getSpectrum(irow);
2700 std::vector<float> params;
2701 float rms;
2702 std::vector<bool> finalmask;
2703 Bool doApply = True;
2704
2705 if (!isAllChannelsFlagged(irow)) {
2706 std::vector<float> resfit = doSubtractBaseline(spec, mask, ftype, fpar, params, rms, finalmask, clipth, clipn, uself, irow, lfth, lfedge, lfavg);
2707 setSpectrum(resfit, irow);
2708 }
2709 else {
2710 doApply = False;
2711 }
2712
2713 if (returnfitresult) {
2714 res.push_back(packFittingResults(irow, params, rms));
2715 }
2716
2717 if (outBaselineTable) {
2718 Vector<Int> fparam(fpar.size());
2719 for (uInt j = 0; j < fparam.size(); ++j) {
2720 fparam[j] = (Int)fpar[j];
2721 }
2722
2723 btp->setdata(uInt(irow),
2724 uInt(getScan(irow)), uInt(getCycle(irow)),
2725 uInt(getBeam(irow)), uInt(getIF(irow)), uInt(getPol(irow)),
2726 uInt(0), timeSecCol[irow], doApply, ftype, fparam,
2727 Vector<Float>(), getMaskListFromMask(finalmask), Vector<Float>(params),
2728 Float(rms), uInt(spec.size()), Float(clipth), uInt(clipn),
2729 Float(0.0), uInt(0), Vector<uInt>());
2730 }
2731
2732 }
2733 }
2734
2735 if (outBaselineTable) {
2736 btp->save(outbltable);
2737 }
2738
2739 if (btp != NULL) {
2740 delete btp;
2741 }
2742
2743 return res;
2744}
2745
2746std::vector<float> Scantable::doApplyBaselineTable(std::vector<float>& spec,
2747 std::vector<bool>& mask,
2748 const STBaselineFunc::FuncName ftype,
2749 std::vector<int>& fpar,
2750 std::vector<float>& params,
2751 float&rms,
2752 int irow)
2753{
2754 std::vector<bool> finalmask;
2755 std::vector<int> lfedge;
2756 return doSubtractBaseline(spec, mask, ftype, fpar, params, rms, finalmask, 0.0, 0, false, irow, 0.0, lfedge, 0);
2757}
2758
2759std::vector<float> Scantable::doSubtractBaseline(std::vector<float>& spec,
2760 std::vector<bool>& mask,
2761 const STBaselineFunc::FuncName ftype,
2762 std::vector<int>& fpar,
2763 std::vector<float>& params,
2764 float&rms,
2765 std::vector<bool>& finalmask,
2766 float clipth,
2767 int clipn,
2768 bool uself,
2769 int irow,
2770 float lfth,
2771 std::vector<int>& lfedge,
2772 int lfavg)
2773{
2774 if (uself) {
2775 STLineFinder lineFinder = STLineFinder();
2776 initLineFinder(lfedge, lfth, lfavg, lineFinder);
2777 std::vector<int> currentEdge;
2778 mask = getCompositeChanMask(irow, mask, lfedge, currentEdge, lineFinder);
2779 } else {
2780 mask = getCompositeChanMask(irow, mask);
2781 }
2782
2783 std::vector<float> res;
2784 if (ftype == STBaselineFunc::Polynomial) {
2785 res = doPolynomialFitting(spec, mask, fpar[0], params, rms, finalmask, clipth, clipn);
2786 } else if (ftype == STBaselineFunc::Chebyshev) {
2787 res = doChebyshevFitting(spec, mask, fpar[0], params, rms, finalmask, clipth, clipn);
2788 } else if (ftype == STBaselineFunc::CSpline) {
2789 int nclip = 0;
2790 size_t numChan = spec.size();
2791 if (cubicSplineModelPool_.find(numChan) == cubicSplineModelPool_.end()) {
2792 cubicSplineModelPool_[numChan] = getPolynomialModel(3, numChan, &Scantable::getNormalPolynomial);
2793 }
2794 if (fpar.size() > 1) { // reading from baseline table in which pieceEdges are already calculated and stored.
2795 //res = doCubicSplineFitting(spec, mask, fpar, params, rms, finalmask, clipth, clipn);
2796 res = doCubicSplineLeastSquareFitting(spec, mask,
2797 cubicSplineModelPool_[numChan],
2798 fpar.size()-1, true, fpar, params,
2799 rms, finalmask, nclip, clipth,
2800 clipn);
2801 } else { // usual cspline fitting by giving nPiece only. fpar will be replaced with pieceEdges.
2802 //res = doCubicSplineFitting(spec, mask, fpar[0], fpar, params, rms, finalmask, clipth, clipn);
2803 res = doCubicSplineLeastSquareFitting(spec, mask,
2804 cubicSplineModelPool_[numChan],
2805 fpar[0], false, fpar, params,
2806 rms, finalmask, nclip, clipth,
2807 clipn);
2808 }
2809 } else if (ftype == STBaselineFunc::Sinusoid) {
2810 res = doSinusoidFitting(spec, mask, fpar, params, rms, finalmask, clipth, clipn);
2811 }
2812
2813 return res;
2814}
2815
2816std::string Scantable::packFittingResults(const int irow, const std::vector<float>& params, const float rms)
2817{
2818 // returned value: "irow:params[0],params[1],..,params[n-1]:rms"
2819 ostringstream os;
2820 os << irow << ':';
2821 for (uInt i = 0; i < params.size(); ++i) {
2822 if (i > 0) {
2823 os << ',';
2824 }
2825 os << params[i];
2826 }
2827 os << ':' << rms;
2828
2829 return os.str();
2830}
2831
2832void Scantable::parseBlInfo(const std::string& blInfo, int& irow, STBaselineFunc::FuncName& ftype, std::vector<int>& fpar, std::vector<bool>& mask, float& thresClip, int& nIterClip, bool& useLineFinder, float& thresLF, std::vector<int>& edgeLF, int& avgLF)
2833{
2834 // The baseline info to be parsed must be column-delimited string like
2835 // "0:chebyshev:5:3,5,169,174,485,487" where the elements are
2836 // row number, funcType, funcOrder, maskList, clipThreshold, clipNIter,
2837 // useLineFinder, lfThreshold, lfEdge and lfChanAvgLimit.
2838
2839 std::vector<string> res = splitToStringList(blInfo, ':');
2840 if (res.size() < 4) {
2841 throw(AipsError("baseline info has bad format")) ;
2842 }
2843
2844 string ftype0, fpar0, masklist0, uself0, edge0;
2845 std::vector<int> masklist;
2846
2847 stringstream ss;
2848 ss << res[0];
2849 ss >> irow;
2850 ss.clear(); ss.str("");
2851
2852 ss << res[1];
2853 ss >> ftype0;
2854 if (ftype0 == "poly") {
2855 ftype = STBaselineFunc::Polynomial;
2856 } else if (ftype0 == "cspline") {
2857 ftype = STBaselineFunc::CSpline;
2858 } else if (ftype0 == "sinusoid") {
2859 ftype = STBaselineFunc::Sinusoid;
2860 } else if (ftype0 == "chebyshev") {
2861 ftype = STBaselineFunc::Chebyshev;
2862 } else {
2863 throw(AipsError("invalid function type."));
2864 }
2865 ss.clear(); ss.str("");
2866
2867 ss << res[2];
2868 ss >> fpar0;
2869 fpar = splitToIntList(fpar0, ',');
2870 ss.clear(); ss.str("");
2871
2872 ss << res[3];
2873 ss >> masklist0;
2874 mask = getMaskFromMaskList(nchan(getIF(irow)), splitToIntList(masklist0, ','));
2875 ss.clear(); ss.str("");
2876
2877 ss << res[4];
2878 ss >> thresClip;
2879 ss.clear(); ss.str("");
2880
2881 ss << res[5];
2882 ss >> nIterClip;
2883 ss.clear(); ss.str("");
2884
2885 ss << res[6];
2886 ss >> uself0;
2887 if (uself0 == "true") {
2888 useLineFinder = true;
2889 } else {
2890 useLineFinder = false;
2891 }
2892 ss.clear(); ss.str("");
2893
2894 if (useLineFinder) {
2895 ss << res[7];
2896 ss >> thresLF;
2897 ss.clear(); ss.str("");
2898
2899 ss << res[8];
2900 ss >> edge0;
2901 edgeLF = splitToIntList(edge0, ',');
2902 ss.clear(); ss.str("");
2903
2904 ss << res[9];
2905 ss >> avgLF;
2906 ss.clear(); ss.str("");
2907 }
2908
2909}
2910
2911std::vector<int> Scantable::splitToIntList(const std::string& s, const char delim)
2912{
2913 istringstream iss(s);
2914 string tmp;
2915 int tmpi;
2916 std::vector<int> res;
2917 stringstream ss;
2918 while (getline(iss, tmp, delim)) {
2919 ss << tmp;
2920 ss >> tmpi;
2921 res.push_back(tmpi);
2922 ss.clear(); ss.str("");
2923 }
2924
2925 return res;
2926}
2927
2928std::vector<string> Scantable::splitToStringList(const std::string& s, const char delim)
2929{
2930 istringstream iss(s);
2931 std::string tmp;
2932 std::vector<string> res;
2933 while (getline(iss, tmp, delim)) {
2934 res.push_back(tmp);
2935 }
2936
2937 return res;
2938}
2939
2940std::vector<bool> Scantable::getMaskFromMaskList(const int nchan, const std::vector<int>& masklist)
2941{
2942 if (masklist.size() % 2 != 0) {
2943 throw(AipsError("masklist must have even number of elements."));
2944 }
2945
2946 std::vector<bool> res(nchan);
2947
2948 for (int i = 0; i < nchan; ++i) {
2949 res[i] = false;
2950 }
2951 for (uInt j = 0; j < masklist.size(); j += 2) {
2952 for (int i = masklist[j]; i <= min(nchan-1, masklist[j+1]); ++i) {
2953 res[i] = true;
2954 }
2955 }
2956
2957 return res;
2958}
2959
2960Vector<uInt> Scantable::getMaskListFromMask(const std::vector<bool>& mask)
2961{
2962 std::vector<int> masklist;
2963 masklist.clear();
2964
2965 for (uInt i = 0; i < mask.size(); ++i) {
2966 if (mask[i]) {
2967 if ((i == 0)||(i == mask.size()-1)) {
2968 masklist.push_back(i);
2969 } else {
2970 if ((mask[i])&&(!mask[i-1])) {
2971 masklist.push_back(i);
2972 }
2973 if ((mask[i])&&(!mask[i+1])) {
2974 masklist.push_back(i);
2975 }
2976 }
2977 }
2978 }
2979
2980 Vector<uInt> res(masklist.size());
2981 for (uInt i = 0; i < masklist.size(); ++i) {
2982 res[i] = (uInt)masklist[i];
2983 }
2984
2985 return res;
2986}
2987
2988void Scantable::initialiseBaselining(const std::string& blfile,
2989 ofstream& ofs,
2990 const bool outLogger,
2991 bool& outTextFile,
2992 bool& csvFormat,
2993 String& coordInfo,
2994 bool& hasSameNchan,
2995 const std::string& progressInfo,
2996 bool& showProgress,
2997 int& minNRow,
2998 Vector<Double>& timeSecCol)
2999{
3000 csvFormat = false;
3001 outTextFile = false;
3002
3003 if (blfile != "") {
3004 csvFormat = (blfile.substr(0, 1) == "T");
3005 ofs.open(blfile.substr(1).c_str(), ios::out | ios::app);
3006 if (ofs) outTextFile = true;
3007 }
3008
3009 coordInfo = "";
3010 hasSameNchan = true;
3011
3012 if (outLogger || outTextFile) {
3013 coordInfo = getCoordInfo()[0];
3014 if (coordInfo == "") coordInfo = "channel";
3015 hasSameNchan = hasSameNchanOverIFs();
3016 }
3017
3018 parseProgressInfo(progressInfo, showProgress, minNRow);
3019
3020 ROScalarColumn<Double> tcol = ROScalarColumn<Double>(table_, "TIME");
3021 timeSecCol = tcol.getColumn();
3022}
3023
3024void Scantable::finaliseBaselining(const bool outBaselineTable,
3025 STBaselineTable* pbt,
3026 const string& bltable,
3027 const bool outTextFile,
3028 ofstream& ofs)
3029{
3030 if (outBaselineTable) {
3031 pbt->save(bltable);
3032 }
3033
3034 if (outTextFile) ofs.close();
3035}
3036
3037void Scantable::initLineFinder(const std::vector<int>& edge,
3038 const float threshold,
3039 const int chanAvgLimit,
3040 STLineFinder& lineFinder)
3041{
3042 if ((edge.size() > 2) && (edge.size() < getIFNos().size()*2)) {
3043 throw(AipsError("Length of edge element info is less than that of IFs"));
3044 }
3045
3046 lineFinder.setOptions(threshold, 3, chanAvgLimit);
3047}
3048
3049void Scantable::polyBaseline(const std::vector<bool>& mask, int order,
3050 float thresClip, int nIterClip,
3051 bool getResidual,
3052 const std::string& progressInfo,
3053 const bool outLogger, const std::string& blfile,
3054 const std::string& bltable)
3055{
3056 /****
3057 double TimeStart = mathutil::gettimeofday_sec();
3058 ****/
3059
3060 try {
3061 ofstream ofs;
3062 String coordInfo;
3063 bool hasSameNchan, outTextFile, csvFormat, showProgress;
3064 int minNRow;
3065 int nRow = nrow();
3066 std::vector<bool> chanMask, finalChanMask;
3067 float rms;
3068 bool outBaselineTable = (bltable != "");
3069 STBaselineTable bt = STBaselineTable(*this);
3070 Vector<Double> timeSecCol;
3071 size_t flagged=0;
3072
3073 initialiseBaselining(blfile, ofs, outLogger, outTextFile, csvFormat,
3074 coordInfo, hasSameNchan,
3075 progressInfo, showProgress, minNRow,
3076 timeSecCol);
3077
3078 std::vector<int> nChanNos;
3079 std::vector<std::vector<std::vector<double> > > modelReservoir;
3080 modelReservoir = getPolynomialModelReservoir(order,
3081 &Scantable::getNormalPolynomial,
3082 nChanNos);
3083 int nModel = modelReservoir.size();
3084
3085 for (int whichrow = 0; whichrow < nRow; ++whichrow) {
3086 std::vector<float> sp = getSpectrum(whichrow);
3087 chanMask = getCompositeChanMask(whichrow, mask);
3088 std::vector<float> params;
3089
3090 //if (flagrowCol_(whichrow) == 0) {
3091 if (flagrowCol_(whichrow)==0 && nValidMask(chanMask)>0) {
3092 int nClipped = 0;
3093 std::vector<float> res;
3094 res = doLeastSquareFitting(sp, chanMask,
3095 modelReservoir[getIdxOfNchan(sp.size(), nChanNos)],
3096 params, rms, finalChanMask,
3097 nClipped, thresClip, nIterClip, getResidual);
3098
3099 if (outBaselineTable) {
3100 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
3101 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
3102 true, STBaselineFunc::Polynomial, order, std::vector<float>(),
3103 getMaskListFromMask(finalChanMask), params, rms, sp.size(),
3104 thresClip, nIterClip, 0.0, 0, std::vector<int>());
3105 } else {
3106 setSpectrum(res, whichrow);
3107 }
3108
3109 outputFittingResult(outLogger, outTextFile, csvFormat, chanMask, whichrow,
3110 coordInfo, hasSameNchan, ofs, "polyBaseline()",
3111 params, nClipped);
3112 } else {
3113 // no valid channels to fit (flag the row)
3114 flagrowCol_.put(whichrow, 1);
3115 ++flagged;
3116 if (outBaselineTable) {
3117 params.resize(nModel);
3118 for (uInt i = 0; i < params.size(); ++i) {
3119 params[i] = 0.0;
3120 }
3121 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
3122 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
3123 true, STBaselineFunc::Polynomial, order, std::vector<float>(),
3124 getMaskListFromMask(chanMask), params, 0.0, sp.size(),
3125 thresClip, nIterClip, 0.0, 0, std::vector<int>());
3126 }
3127 }
3128
3129 showProgressOnTerminal(whichrow, nRow, showProgress, minNRow);
3130 }
3131
3132 finaliseBaselining(outBaselineTable, &bt, bltable, outTextFile, ofs);
3133 if (flagged > 0) {
3134 LogIO os( LogOrigin( "Scantable", "polyBaseline()") ) ;
3135 os << LogIO::WARN << "Baseline subtraction is skipped for " << flagged << " spectra due to too few valid channels to operate fit. The spectra will be flagged in output data." << LogIO::POST;
3136 }
3137 } catch (...) {
3138 throw;
3139 }
3140
3141 /****
3142 double TimeEnd = mathutil::gettimeofday_sec();
3143 double elapse1 = TimeEnd - TimeStart;
3144 std::cout << "poly-new : " << elapse1 << " (sec.)" << endl;
3145 ****/
3146}
3147
3148void Scantable::autoPolyBaseline(const std::vector<bool>& mask, int order,
3149 float thresClip, int nIterClip,
3150 const std::vector<int>& edge,
3151 float threshold, int chanAvgLimit,
3152 bool getResidual,
3153 const std::string& progressInfo,
3154 const bool outLogger, const std::string& blfile,
3155 const std::string& bltable)
3156{
3157 try {
3158 ofstream ofs;
3159 String coordInfo;
3160 bool hasSameNchan, outTextFile, csvFormat, showProgress;
3161 int minNRow;
3162 int nRow = nrow();
3163 std::vector<bool> chanMask, finalChanMask;
3164 float rms;
3165 bool outBaselineTable = (bltable != "");
3166 STBaselineTable bt = STBaselineTable(*this);
3167 Vector<Double> timeSecCol;
3168 STLineFinder lineFinder = STLineFinder();
3169 size_t flagged=0;
3170
3171 initialiseBaselining(blfile, ofs, outLogger, outTextFile, csvFormat,
3172 coordInfo, hasSameNchan,
3173 progressInfo, showProgress, minNRow,
3174 timeSecCol);
3175
3176 initLineFinder(edge, threshold, chanAvgLimit, lineFinder);
3177
3178 std::vector<int> nChanNos;
3179 std::vector<std::vector<std::vector<double> > > modelReservoir;
3180 modelReservoir = getPolynomialModelReservoir(order,
3181 &Scantable::getNormalPolynomial,
3182 nChanNos);
3183 int nModel = modelReservoir.size();
3184
3185 for (int whichrow = 0; whichrow < nRow; ++whichrow) {
3186 std::vector<float> sp = getSpectrum(whichrow);
3187 std::vector<int> currentEdge;
3188 chanMask = getCompositeChanMask(whichrow, mask, edge, currentEdge, lineFinder);
3189 std::vector<float> params;
3190
3191 //if (flagrowCol_(whichrow) == 0) {
3192 if (flagrowCol_(whichrow)==0 && nValidMask(chanMask)>0) {
3193 int nClipped = 0;
3194 std::vector<float> res;
3195 res = doLeastSquareFitting(sp, chanMask,
3196 modelReservoir[getIdxOfNchan(sp.size(), nChanNos)],
3197 params, rms, finalChanMask,
3198 nClipped, thresClip, nIterClip, getResidual);
3199
3200 if (outBaselineTable) {
3201 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
3202 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
3203 true, STBaselineFunc::Polynomial, order, std::vector<float>(),
3204 getMaskListFromMask(finalChanMask), params, rms, sp.size(),
3205 thresClip, nIterClip, threshold, chanAvgLimit, currentEdge);
3206 } else {
3207 setSpectrum(res, whichrow);
3208 }
3209
3210 outputFittingResult(outLogger, outTextFile, csvFormat, chanMask, whichrow,
3211 coordInfo, hasSameNchan, ofs, "autoPolyBaseline()",
3212 params, nClipped);
3213 } else {
3214 // no valid channels to fit (flag the row)
3215 flagrowCol_.put(whichrow, 1);
3216 ++flagged;
3217 if (outBaselineTable) {
3218 params.resize(nModel);
3219 for (uInt i = 0; i < params.size(); ++i) {
3220 params[i] = 0.0;
3221 }
3222 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
3223 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
3224 true, STBaselineFunc::Polynomial, order, std::vector<float>(),
3225 getMaskListFromMask(chanMask), params, 0.0, sp.size(),
3226 thresClip, nIterClip, threshold, chanAvgLimit, currentEdge);
3227 }
3228 }
3229
3230 showProgressOnTerminal(whichrow, nRow, showProgress, minNRow);
3231 }
3232
3233 finaliseBaselining(outBaselineTable, &bt, bltable, outTextFile, ofs);
3234 if (flagged > 0) {
3235 LogIO os( LogOrigin( "Scantable", "autoPolyBaseline()") ) ;
3236 os << LogIO::WARN << "Baseline subtraction is skipped for " << flagged << " spectra due to too few valid channels to operate fit. The spectra will be flagged in output data." << LogIO::POST;
3237 }
3238 } catch (...) {
3239 throw;
3240 }
3241}
3242
3243void Scantable::chebyshevBaseline(const std::vector<bool>& mask, int order,
3244 float thresClip, int nIterClip,
3245 bool getResidual,
3246 const std::string& progressInfo,
3247 const bool outLogger, const std::string& blfile,
3248 const std::string& bltable)
3249{
3250 /*
3251 double TimeStart = mathutil::gettimeofday_sec();
3252 */
3253
3254 try {
3255 ofstream ofs;
3256 String coordInfo;
3257 bool hasSameNchan, outTextFile, csvFormat, showProgress;
3258 int minNRow;
3259 int nRow = nrow();
3260 std::vector<bool> chanMask, finalChanMask;
3261 float rms;
3262 bool outBaselineTable = (bltable != "");
3263 STBaselineTable bt = STBaselineTable(*this);
3264 Vector<Double> timeSecCol;
3265 size_t flagged=0;
3266
3267 initialiseBaselining(blfile, ofs, outLogger, outTextFile, csvFormat,
3268 coordInfo, hasSameNchan,
3269 progressInfo, showProgress, minNRow,
3270 timeSecCol);
3271
3272 std::vector<int> nChanNos;
3273 std::vector<std::vector<std::vector<double> > > modelReservoir;
3274 modelReservoir = getPolynomialModelReservoir(order,
3275 &Scantable::getChebyshevPolynomial,
3276 nChanNos);
3277 int nModel = modelReservoir.size();
3278
3279 for (int whichrow = 0; whichrow < nRow; ++whichrow) {
3280 std::vector<float> sp = getSpectrum(whichrow);
3281 chanMask = getCompositeChanMask(whichrow, mask);
3282 std::vector<float> params;
3283
3284 // if (flagrowCol_(whichrow) == 0) {
3285 if (flagrowCol_(whichrow)==0 && nValidMask(chanMask)>0) {
3286 int nClipped = 0;
3287 std::vector<float> res;
3288 res = doLeastSquareFitting(sp, chanMask,
3289 modelReservoir[getIdxOfNchan(sp.size(), nChanNos)],
3290 params, rms, finalChanMask,
3291 nClipped, thresClip, nIterClip, getResidual);
3292
3293 if (outBaselineTable) {
3294 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
3295 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
3296 true, STBaselineFunc::Chebyshev, order, std::vector<float>(),
3297 getMaskListFromMask(finalChanMask), params, rms, sp.size(),
3298 thresClip, nIterClip, 0.0, 0, std::vector<int>());
3299 } else {
3300 setSpectrum(res, whichrow);
3301 }
3302
3303 outputFittingResult(outLogger, outTextFile, csvFormat, chanMask, whichrow,
3304 coordInfo, hasSameNchan, ofs, "chebyshevBaseline()",
3305 params, nClipped);
3306 } else {
3307 // no valid channels to fit (flag the row)
3308 flagrowCol_.put(whichrow, 1);
3309 ++flagged;
3310 if (outBaselineTable) {
3311 params.resize(nModel);
3312 for (uInt i = 0; i < params.size(); ++i) {
3313 params[i] = 0.0;
3314 }
3315 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
3316 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
3317 true, STBaselineFunc::Chebyshev, order, std::vector<float>(),
3318 getMaskListFromMask(chanMask), params, 0.0, sp.size(),
3319 thresClip, nIterClip, 0.0, 0, std::vector<int>());
3320 }
3321 }
3322
3323 showProgressOnTerminal(whichrow, nRow, showProgress, minNRow);
3324 }
3325
3326 finaliseBaselining(outBaselineTable, &bt, bltable, outTextFile, ofs);
3327
3328 if (flagged > 0) {
3329 LogIO os( LogOrigin( "Scantable", "chebyshevBaseline()") ) ;
3330 os << LogIO::WARN << "Baseline subtraction is skipped for " << flagged << " spectra due to too few valid channels to operate fit. The spectra will be flagged in output data." << LogIO::POST;
3331 }
3332 } catch (...) {
3333 throw;
3334 }
3335
3336 /*
3337 double TimeEnd = mathutil::gettimeofday_sec();
3338 double elapse1 = TimeEnd - TimeStart;
3339 std::cout << "cheby : " << elapse1 << " (sec.)" << endl;
3340 */
3341}
3342
3343void Scantable::autoChebyshevBaseline(const std::vector<bool>& mask, int order,
3344 float thresClip, int nIterClip,
3345 const std::vector<int>& edge,
3346 float threshold, int chanAvgLimit,
3347 bool getResidual,
3348 const std::string& progressInfo,
3349 const bool outLogger, const std::string& blfile,
3350 const std::string& bltable)
3351{
3352 try {
3353 ofstream ofs;
3354 String coordInfo;
3355 bool hasSameNchan, outTextFile, csvFormat, showProgress;
3356 int minNRow;
3357 int nRow = nrow();
3358 std::vector<bool> chanMask, finalChanMask;
3359 float rms;
3360 bool outBaselineTable = (bltable != "");
3361 STBaselineTable bt = STBaselineTable(*this);
3362 Vector<Double> timeSecCol;
3363 STLineFinder lineFinder = STLineFinder();
3364 size_t flagged=0;
3365
3366 initialiseBaselining(blfile, ofs, outLogger, outTextFile, csvFormat,
3367 coordInfo, hasSameNchan,
3368 progressInfo, showProgress, minNRow,
3369 timeSecCol);
3370
3371 initLineFinder(edge, threshold, chanAvgLimit, lineFinder);
3372
3373 std::vector<int> nChanNos;
3374 std::vector<std::vector<std::vector<double> > > modelReservoir;
3375 modelReservoir = getPolynomialModelReservoir(order,
3376 &Scantable::getChebyshevPolynomial,
3377 nChanNos);
3378 int nModel = modelReservoir.size();
3379
3380 for (int whichrow = 0; whichrow < nRow; ++whichrow) {
3381 std::vector<float> sp = getSpectrum(whichrow);
3382 std::vector<int> currentEdge;
3383 chanMask = getCompositeChanMask(whichrow, mask, edge, currentEdge, lineFinder);
3384 std::vector<float> params;
3385
3386 // if (flagrowCol_(whichrow) == 0) {
3387 if (flagrowCol_(whichrow)==0 && nValidMask(chanMask)>0) {
3388 int nClipped = 0;
3389 std::vector<float> res;
3390 res = doLeastSquareFitting(sp, chanMask,
3391 modelReservoir[getIdxOfNchan(sp.size(), nChanNos)],
3392 params, rms, finalChanMask,
3393 nClipped, thresClip, nIterClip, getResidual);
3394
3395 if (outBaselineTable) {
3396 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
3397 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
3398 true, STBaselineFunc::Chebyshev, order, std::vector<float>(),
3399 getMaskListFromMask(finalChanMask), params, rms, sp.size(),
3400 thresClip, nIterClip, threshold, chanAvgLimit, currentEdge);
3401 } else {
3402 setSpectrum(res, whichrow);
3403 }
3404
3405 outputFittingResult(outLogger, outTextFile, csvFormat, chanMask, whichrow,
3406 coordInfo, hasSameNchan, ofs, "autoChebyshevBaseline()",
3407 params, nClipped);
3408 } else {
3409 // no valid channels to fit (flag the row)
3410 flagrowCol_.put(whichrow, 1);
3411 ++flagged;
3412 if (outBaselineTable) {
3413 params.resize(nModel);
3414 for (uInt i = 0; i < params.size(); ++i) {
3415 params[i] = 0.0;
3416 }
3417 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
3418 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
3419 true, STBaselineFunc::Chebyshev, order, std::vector<float>(),
3420 getMaskListFromMask(chanMask), params, 0.0, sp.size(),
3421 thresClip, nIterClip, threshold, chanAvgLimit, currentEdge);
3422 }
3423 }
3424
3425 showProgressOnTerminal(whichrow, nRow, showProgress, minNRow);
3426 }
3427
3428 finaliseBaselining(outBaselineTable, &bt, bltable, outTextFile, ofs);
3429
3430 if (flagged > 0) {
3431 LogIO os( LogOrigin( "Scantable", "autoChebyshevBaseline()") ) ;
3432 os << LogIO::WARN << "Baseline subtraction is skipped for " << flagged << " spectra due to too few valid channels to operate fit. The spectra will be flagged in output data." << LogIO::POST;
3433 }
3434 } catch (...) {
3435 throw;
3436 }
3437}
3438
3439double Scantable::calculateModelSelectionCriteria(const std::string& valname,
3440 const std::string& blfunc,
3441 int order,
3442 const std::vector<bool>& inMask,
3443 int whichrow,
3444 bool useLineFinder,
3445 const std::vector<int>& edge,
3446 float threshold,
3447 int chanAvgLimit)
3448{
3449 std::vector<float> sp = getSpectrum(whichrow);
3450 std::vector<bool> chanMask;
3451 chanMask.clear();
3452
3453 if (useLineFinder) {
3454 STLineFinder lineFinder = STLineFinder();
3455 initLineFinder(edge, threshold, chanAvgLimit, lineFinder);
3456 std::vector<int> currentEdge;
3457 chanMask = getCompositeChanMask(whichrow, inMask, edge, currentEdge, lineFinder);
3458 } else {
3459 chanMask = getCompositeChanMask(whichrow, inMask);
3460 }
3461
3462 return doCalculateModelSelectionCriteria(valname, sp, chanMask, blfunc, order);
3463}
3464
3465double Scantable::doCalculateModelSelectionCriteria(const std::string& valname, const std::vector<float>& spec, const std::vector<bool>& mask, const std::string& blfunc, int order)
3466{
3467 int nparam;
3468 std::vector<float> params;
3469 std::vector<bool> finalChanMask;
3470 float rms;
3471 int nClipped = 0;
3472 std::vector<float> res;
3473 if (blfunc == "poly") {
3474 nparam = order + 1;
3475 res = doPolynomialFitting(spec, mask, order, params, rms, finalChanMask, nClipped);
3476 } else if (blfunc == "chebyshev") {
3477 nparam = order + 1;
3478 res = doChebyshevFitting(spec, mask, order, params, rms, finalChanMask, nClipped);
3479 } else if (blfunc == "cspline") {
3480 std::vector<int> pieceEdges;//(order+1); //order = npiece
3481 nparam = order + 3;
3482 res = doCubicSplineFitting(spec, mask, order, false, pieceEdges, params, rms, finalChanMask, nClipped);
3483 } else if (blfunc == "sinusoid") {
3484 std::vector<int> nWaves;
3485 nWaves.clear();
3486 for (int i = 0; i <= order; ++i) {
3487 nWaves.push_back(i);
3488 }
3489 nparam = 2*order + 1; // order = nwave
3490 res = doSinusoidFitting(spec, mask, nWaves, params, rms, finalChanMask, nClipped);
3491 } else {
3492 throw(AipsError("blfunc must be poly, chebyshev, cspline or sinusoid."));
3493 }
3494
3495 double msq = 0.0;
3496 int nusedchan = 0;
3497 int nChan = res.size();
3498 for (int i = 0; i < nChan; ++i) {
3499 if (mask[i]) {
3500 msq += (double)res[i]*(double)res[i];
3501 nusedchan++;
3502 }
3503 }
3504 if (nusedchan == 0) {
3505 throw(AipsError("all channels masked."));
3506 }
3507 msq /= (double)nusedchan;
3508
3509 nparam++; //add 1 for sigma of Gaussian distribution
3510 const double PI = 6.0 * asin(0.5); // PI (= 3.141592653...)
3511
3512 if (valname.find("aic") == 0) {
3513 // Original Akaike Information Criterion (AIC)
3514 double aic = nusedchan * (log(2.0 * PI * msq) + 1.0) + 2.0 * nparam;
3515
3516 // Corrected AIC by Sugiura(1978) (AICc)
3517 if (valname == "aicc") {
3518 if (nusedchan - nparam - 1 <= 0) {
3519 throw(AipsError("channel size is too small to calculate AICc."));
3520 }
3521 aic += 2.0*nparam*(nparam + 1)/(double)(nusedchan - nparam - 1);
3522 }
3523
3524 return aic;
3525
3526 } else if (valname == "bic") {
3527 // Bayesian Information Criterion (BIC)
3528 double bic = nusedchan * log(msq) + nparam * log((double)nusedchan);
3529 return bic;
3530
3531 } else if (valname == "gcv") {
3532 // Generalised Cross Validation
3533 double x = 1.0 - (double)nparam / (double)nusedchan;
3534 double gcv = msq / (x * x);
3535 return gcv;
3536
3537 } else {
3538 throw(AipsError("valname must be aic, aicc, bic or gcv."));
3539 }
3540}
3541
3542double Scantable::getNormalPolynomial(int n, double x) {
3543 if (n == 0) {
3544 return 1.0;
3545 } else if (n > 0) {
3546 double res = 1.0;
3547 for (int i = 0; i < n; ++i) {
3548 res *= x;
3549 }
3550 return res;
3551 } else {
3552 if (x == 0.0) {
3553 throw(AipsError("infinity result: x=0 given for negative power."));
3554 } else {
3555 return pow(x, (double)n);
3556 }
3557 }
3558}
3559
3560double Scantable::getChebyshevPolynomial(int n, double x) {
3561 if ((x < -1.0)||(x > 1.0)) {
3562 throw(AipsError("out of definition range (-1 <= x <= 1)."));
3563 } else if (x == 1.0) {
3564 return 1.0;
3565 } else if (x == 0.0) {
3566 double res;
3567 if (n%2 == 0) {
3568 if (n%4 == 0) {
3569 res = 1.0;
3570 } else {
3571 res = -1.0;
3572 }
3573 } else {
3574 res = 0.0;
3575 }
3576 return res;
3577 } else if (x == -1.0) {
3578 double res = (n%2 == 0 ? 1.0 : -1.0);
3579 return res;
3580 } else if (n < 0) {
3581 throw(AipsError("the order must be zero or positive."));
3582 } else if (n == 0) {
3583 return 1.0;
3584 } else if (n == 1) {
3585 return x;
3586 } else {
3587 double res[n+1];
3588 for (int i = 0; i < n+1; ++i) {
3589 double res0 = 0.0;
3590 if (i == 0) {
3591 res0 = 1.0;
3592 } else if (i == 1) {
3593 res0 = x;
3594 } else {
3595 res0 = 2.0 * x * res[i-1] - res[i-2];
3596 }
3597 res[i] = res0;
3598 }
3599 return res[n];
3600 }
3601}
3602
3603std::vector<float> Scantable::doPolynomialFitting(const std::vector<float>& data,
3604 const std::vector<bool>& mask,
3605 int order,
3606 std::vector<float>& params,
3607 float& rms,
3608 std::vector<bool>& finalmask,
3609 float clipth,
3610 int clipn)
3611{
3612 int nClipped = 0;
3613 return doPolynomialFitting(data, mask, order, params, rms, finalmask, nClipped, clipth, clipn);
3614}
3615
3616std::vector<float> Scantable::doPolynomialFitting(const std::vector<float>& data,
3617 const std::vector<bool>& mask,
3618 int order,
3619 std::vector<float>& params,
3620 float& rms,
3621 std::vector<bool>& finalMask,
3622 int& nClipped,
3623 float thresClip,
3624 int nIterClip,
3625 bool getResidual)
3626{
3627 return doLeastSquareFitting(data, mask,
3628 getPolynomialModel(order, data.size(), &Scantable::getNormalPolynomial),
3629 params, rms, finalMask,
3630 nClipped, thresClip, nIterClip,
3631 getResidual);
3632}
3633
3634std::vector<float> Scantable::doChebyshevFitting(const std::vector<float>& data,
3635 const std::vector<bool>& mask,
3636 int order,
3637 std::vector<float>& params,
3638 float& rms,
3639 std::vector<bool>& finalmask,
3640 float clipth,
3641 int clipn)
3642{
3643 int nClipped = 0;
3644 return doChebyshevFitting(data, mask, order, params, rms, finalmask, nClipped, clipth, clipn);
3645}
3646
3647std::vector<float> Scantable::doChebyshevFitting(const std::vector<float>& data,
3648 const std::vector<bool>& mask,
3649 int order,
3650 std::vector<float>& params,
3651 float& rms,
3652 std::vector<bool>& finalMask,
3653 int& nClipped,
3654 float thresClip,
3655 int nIterClip,
3656 bool getResidual)
3657{
3658 return doLeastSquareFitting(data, mask,
3659 getPolynomialModel(order, data.size(), &Scantable::getChebyshevPolynomial),
3660 params, rms, finalMask,
3661 nClipped, thresClip, nIterClip,
3662 getResidual);
3663}
3664
3665std::vector<std::vector<double> > Scantable::getPolynomialModel(int order, int nchan, double (Scantable::*pfunc)(int, double))
3666{
3667 // model : contains model values for computing the least-square matrix.
3668 // model.size() is nmodel and model[*].size() is nchan.
3669 // Each model element are as follows:
3670 //
3671 // (for normal polynomials)
3672 // model[0] = {1.0, 1.0, 1.0, ..., 1.0},
3673 // model[1] = {0.0, 1.0, 2.0, ..., (nchan-1)}
3674 // model[n-1] = ...,
3675 // model[n] = {0.0^n, 1.0^n, 2.0^n, ..., (nchan-1)^n}
3676 // where (0 <= n <= order)
3677 //
3678 // (for Chebyshev polynomials)
3679 // model[0] = {T0(-1), T0(2/(nchan-1)-1), T0(4/(nchan-1)-1), ..., T0(1)},
3680 // model[n-1] = ...,
3681 // model[n] = {Tn(-1), Tn(2/(nchan-1)-1), Tn(4/(nchan-1)-1), ..., Tn(1)}
3682 // where (0 <= n <= order),
3683
3684 int nmodel = order + 1;
3685 std::vector<std::vector<double> > model(nmodel, std::vector<double>(nchan));
3686
3687 double stretch, shift;
3688 if (pfunc == &Scantable::getChebyshevPolynomial) {
3689 stretch = 2.0/(double)(nchan - 1);
3690 shift = -1.0;
3691 } else {
3692 stretch = 1.0;
3693 shift = 0.0;
3694 }
3695
3696 for (int i = 0; i < nmodel; ++i) {
3697 for (int j = 0; j < nchan; ++j) {
3698 model[i][j] = (this->*pfunc)(i, stretch*(double)j + shift);
3699 }
3700 }
3701
3702 return model;
3703}
3704
3705std::vector<std::vector<std::vector<double> > > Scantable::getPolynomialModelReservoir(int order,
3706 double (Scantable::*pfunc)(int, double),
3707 std::vector<int>& nChanNos)
3708{
3709 std::vector<std::vector<std::vector<double> > > res;
3710 res.clear();
3711 nChanNos.clear();
3712
3713 std::vector<uint> ifNos = getIFNos();
3714 for (uint i = 0; i < ifNos.size(); ++i) {
3715 int currNchan = nchan(ifNos[i]);
3716 bool hasDifferentNchan = (i == 0);
3717 for (uint j = 0; j < i; ++j) {
3718 if (currNchan != nchan(ifNos[j])) {
3719 hasDifferentNchan = true;
3720 break;
3721 }
3722 }
3723 if (hasDifferentNchan) {
3724 res.push_back(getPolynomialModel(order, currNchan, pfunc));
3725 nChanNos.push_back(currNchan);
3726 }
3727 }
3728
3729 return res;
3730}
3731
3732std::vector<float> Scantable::doLeastSquareFitting(const std::vector<float>& data,
3733 const std::vector<bool>& mask,
3734 const std::vector<std::vector<double> >& model,
3735 std::vector<float>& params,
3736 float& rms,
3737 std::vector<bool>& finalMask,
3738 int& nClipped,
3739 float thresClip,
3740 int nIterClip,
3741 bool getResidual)
3742{
3743 int nDOF = model.size();
3744 int nChan = data.size();
3745
3746 if (nDOF == 0) {
3747 throw(AipsError("no model data given"));
3748 }
3749 if (nChan < 2) {
3750 throw(AipsError("data size is too few"));
3751 }
3752 if (nChan != (int)mask.size()) {
3753 throw(AipsError("data and mask sizes are not identical"));
3754 }
3755 for (int i = 0; i < nDOF; ++i) {
3756 if (nChan != (int)model[i].size()) {
3757 throw(AipsError("data and model sizes are not identical"));
3758 }
3759 }
3760
3761 params.clear();
3762 params.resize(nDOF);
3763
3764 finalMask.clear();
3765 finalMask.resize(nChan);
3766
3767 std::vector<int> maskArray(nChan);
3768 int j = 0;
3769 for (int i = 0; i < nChan; ++i) {
3770 maskArray[i] = mask[i] ? 1 : 0;
3771 if (isnan(data[i])) maskArray[i] = 0;
3772 if (isinf(data[i])) maskArray[i] = 0;
3773
3774 finalMask[i] = (maskArray[i] == 1);
3775 if (finalMask[i]) {
3776 j++;
3777 }
3778
3779 /*
3780 maskArray[i] = mask[i] ? 1 : 0;
3781 if (mask[i]) {
3782 j++;
3783 }
3784 finalMask[i] = mask[i];
3785 */
3786 }
3787
3788 int initNData = j;
3789 int nData = initNData;
3790
3791 std::vector<double> z1(nChan), r1(nChan), residual(nChan);
3792 for (int i = 0; i < nChan; ++i) {
3793 z1[i] = (double)data[i];
3794 r1[i] = 0.0;
3795 residual[i] = 0.0;
3796 }
3797
3798 for (int nClip = 0; nClip < nIterClip+1; ++nClip) {
3799 // xMatrix : horizontal concatenation of
3800 // the least-sq. matrix (left) and an
3801 // identity matrix (right).
3802 // the right part is used to calculate the inverse matrix of the left part.
3803 double xMatrix[nDOF][2*nDOF];
3804 double zMatrix[nDOF];
3805 for (int i = 0; i < nDOF; ++i) {
3806 for (int j = 0; j < 2*nDOF; ++j) {
3807 xMatrix[i][j] = 0.0;
3808 }
3809 xMatrix[i][nDOF+i] = 1.0;
3810 zMatrix[i] = 0.0;
3811 }
3812
3813 int nUseData = 0;
3814 for (int k = 0; k < nChan; ++k) {
3815 if (maskArray[k] == 0) continue;
3816
3817 for (int i = 0; i < nDOF; ++i) {
3818 for (int j = i; j < nDOF; ++j) {
3819 xMatrix[i][j] += model[i][k] * model[j][k];
3820 }
3821 zMatrix[i] += z1[k] * model[i][k];
3822 }
3823
3824 nUseData++;
3825 }
3826
3827 if (nUseData < 1) {
3828 throw(AipsError("all channels clipped or masked. can't execute fitting anymore."));
3829 }
3830
3831 for (int i = 0; i < nDOF; ++i) {
3832 for (int j = 0; j < i; ++j) {
3833 xMatrix[i][j] = xMatrix[j][i];
3834 }
3835 }
3836
3837 //compute inverse matrix of the left half of xMatrix
3838 std::vector<double> invDiag(nDOF);
3839 for (int i = 0; i < nDOF; ++i) {
3840 invDiag[i] = 1.0 / xMatrix[i][i];
3841 for (int j = 0; j < nDOF; ++j) {
3842 xMatrix[i][j] *= invDiag[i];
3843 }
3844 }
3845
3846 for (int k = 0; k < nDOF; ++k) {
3847 for (int i = 0; i < nDOF; ++i) {
3848 if (i != k) {
3849 double factor1 = xMatrix[k][k];
3850 double invfactor1 = 1.0 / factor1;
3851 double factor2 = xMatrix[i][k];
3852 for (int j = k; j < 2*nDOF; ++j) {
3853 xMatrix[i][j] *= factor1;
3854 xMatrix[i][j] -= xMatrix[k][j]*factor2;
3855 xMatrix[i][j] *= invfactor1;
3856 }
3857 }
3858 }
3859 double invXDiag = 1.0 / xMatrix[k][k];
3860 for (int j = k; j < 2*nDOF; ++j) {
3861 xMatrix[k][j] *= invXDiag;
3862 }
3863 }
3864
3865 for (int i = 0; i < nDOF; ++i) {
3866 for (int j = 0; j < nDOF; ++j) {
3867 xMatrix[i][nDOF+j] *= invDiag[j];
3868 }
3869 }
3870 //compute a vector y in which coefficients of the best-fit
3871 //model functions are stored.
3872 //in case of polynomials, y consists of (a0,a1,a2,...)
3873 //where ai is the coefficient of the term x^i.
3874 //in case of sinusoids, y consists of (a0,s1,c1,s2,c2,...)
3875 //where a0 is constant term and s* and c* are of sine
3876 //and cosine functions, respectively.
3877 std::vector<double> y(nDOF);
3878 for (int i = 0; i < nDOF; ++i) {
3879 y[i] = 0.0;
3880 for (int j = 0; j < nDOF; ++j) {
3881 y[i] += xMatrix[i][nDOF+j]*zMatrix[j];
3882 }
3883 params[i] = (float)y[i];
3884 }
3885
3886 for (int i = 0; i < nChan; ++i) {
3887 r1[i] = y[0];
3888 for (int j = 1; j < nDOF; ++j) {
3889 r1[i] += y[j]*model[j][i];
3890 }
3891 residual[i] = z1[i] - r1[i];
3892 }
3893
3894 double mean = 0.0;
3895 double mean2 = 0.0;
3896 for (int i = 0; i < nChan; ++i) {
3897 if (maskArray[i] == 0) continue;
3898 mean += residual[i];
3899 mean2 += residual[i]*residual[i];
3900 }
3901 mean /= (double)nData;
3902 mean2 /= (double)nData;
3903 double rmsd = sqrt(mean2 - mean*mean);
3904 rms = (float)rmsd;
3905
3906 if ((nClip == nIterClip) || (thresClip <= 0.0)) {
3907 break;
3908 } else {
3909
3910 double thres = rmsd * thresClip;
3911 int newNData = 0;
3912 for (int i = 0; i < nChan; ++i) {
3913 if (abs(residual[i]) >= thres) {
3914 maskArray[i] = 0;
3915 finalMask[i] = false;
3916 }
3917 if (maskArray[i] > 0) {
3918 newNData++;
3919 }
3920 }
3921 if (newNData == nData) {
3922 break; //no more flag to add. stop iteration.
3923 } else {
3924 nData = newNData;
3925 }
3926
3927 }
3928 }
3929
3930 nClipped = initNData - nData;
3931
3932 std::vector<float> result(nChan);
3933 if (getResidual) {
3934 for (int i = 0; i < nChan; ++i) {
3935 result[i] = (float)residual[i];
3936 }
3937 } else {
3938 for (int i = 0; i < nChan; ++i) {
3939 result[i] = (float)r1[i];
3940 }
3941 }
3942
3943 return result;
3944} //xMatrix
3945
3946void Scantable::cubicSplineBaseline(const std::vector<bool>& mask, int nPiece,
3947 float thresClip, int nIterClip,
3948 bool getResidual,
3949 const std::string& progressInfo,
3950 const bool outLogger, const std::string& blfile,
3951 const std::string& bltable)
3952{
3953 /****
3954 double TimeStart = mathutil::gettimeofday_sec();
3955 ****/
3956
3957 try {
3958 ofstream ofs;
3959 String coordInfo;
3960 bool hasSameNchan, outTextFile, csvFormat, showProgress;
3961 int minNRow;
3962 int nRow = nrow();
3963 std::vector<bool> chanMask, finalChanMask;
3964 float rms;
3965 bool outBaselineTable = (bltable != "");
3966 STBaselineTable bt = STBaselineTable(*this);
3967 Vector<Double> timeSecCol;
3968 size_t flagged=0;
3969
3970 initialiseBaselining(blfile, ofs, outLogger, outTextFile, csvFormat,
3971 coordInfo, hasSameNchan,
3972 progressInfo, showProgress, minNRow,
3973 timeSecCol);
3974
3975 std::vector<int> nChanNos;
3976 std::vector<std::vector<std::vector<double> > > modelReservoir;
3977 modelReservoir = getPolynomialModelReservoir(3,
3978 &Scantable::getNormalPolynomial,
3979 nChanNos);
3980 int nDOF = nPiece + 3;
3981
3982 for (int whichrow = 0; whichrow < nRow; ++whichrow) {
3983 std::vector<float> sp = getSpectrum(whichrow);
3984 chanMask = getCompositeChanMask(whichrow, mask);
3985 std::vector<int> pieceEdges;
3986 std::vector<float> params;
3987
3988 //if (flagrowCol_(whichrow) == 0) {
3989 if (flagrowCol_(whichrow)==0 && nValidMask(chanMask)>0) {
3990 int nClipped = 0;
3991 std::vector<float> res;
3992 res = doCubicSplineLeastSquareFitting(sp, chanMask,
3993 modelReservoir[getIdxOfNchan(sp.size(), nChanNos)],
3994 nPiece, false, pieceEdges, params, rms, finalChanMask,
3995 nClipped, thresClip, nIterClip, getResidual);
3996
3997 if (outBaselineTable) {
3998 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
3999 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
4000 true, STBaselineFunc::CSpline, pieceEdges, std::vector<float>(),
4001 getMaskListFromMask(finalChanMask), params, rms, sp.size(),
4002 thresClip, nIterClip, 0.0, 0, std::vector<int>());
4003 } else {
4004 setSpectrum(res, whichrow);
4005 }
4006
4007 outputFittingResult(outLogger, outTextFile, csvFormat, chanMask, whichrow,
4008 coordInfo, hasSameNchan, ofs, "cubicSplineBaseline()",
4009 pieceEdges, params, nClipped);
4010 } else {
4011 // no valid channels to fit (flag the row)
4012 flagrowCol_.put(whichrow, 1);
4013 ++flagged;
4014 if (outBaselineTable) {
4015 pieceEdges.resize(nPiece+1);
4016 for (uInt i = 0; i < pieceEdges.size(); ++i) {
4017 pieceEdges[i] = 0;
4018 }
4019 params.resize(nDOF);
4020 for (uInt i = 0; i < params.size(); ++i) {
4021 params[i] = 0.0;
4022 }
4023 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
4024 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
4025 true, STBaselineFunc::CSpline, pieceEdges, std::vector<float>(),
4026 getMaskListFromMask(chanMask), params, 0.0, sp.size(),
4027 thresClip, nIterClip, 0.0, 0, std::vector<int>());
4028 }
4029 }
4030
4031 showProgressOnTerminal(whichrow, nRow, showProgress, minNRow);
4032 }
4033
4034 finaliseBaselining(outBaselineTable, &bt, bltable, outTextFile, ofs);
4035
4036 if (flagged > 0) {
4037 LogIO os( LogOrigin( "Scantable", "cubicSplineBaseline()") ) ;
4038 os << LogIO::WARN << "Baseline subtraction is skipped for " << flagged << " spectra due to too few valid channels to operate fit. The spectra will be flagged in output data." << LogIO::POST;
4039 }
4040 } catch (...) {
4041 throw;
4042 }
4043
4044 /****
4045 double TimeEnd = mathutil::gettimeofday_sec();
4046 double elapse1 = TimeEnd - TimeStart;
4047 std::cout << "cspline-new : " << elapse1 << " (sec.)" << endl;
4048 ****/
4049}
4050
4051void Scantable::autoCubicSplineBaseline(const std::vector<bool>& mask, int nPiece,
4052 float thresClip, int nIterClip,
4053 const std::vector<int>& edge,
4054 float threshold, int chanAvgLimit,
4055 bool getResidual,
4056 const std::string& progressInfo,
4057 const bool outLogger, const std::string& blfile,
4058 const std::string& bltable)
4059{
4060 try {
4061 ofstream ofs;
4062 String coordInfo;
4063 bool hasSameNchan, outTextFile, csvFormat, showProgress;
4064 int minNRow;
4065 int nRow = nrow();
4066 std::vector<bool> chanMask, finalChanMask;
4067 float rms;
4068 bool outBaselineTable = (bltable != "");
4069 STBaselineTable bt = STBaselineTable(*this);
4070 Vector<Double> timeSecCol;
4071 STLineFinder lineFinder = STLineFinder();
4072 size_t flagged=0;
4073
4074 initialiseBaselining(blfile, ofs, outLogger, outTextFile, csvFormat,
4075 coordInfo, hasSameNchan,
4076 progressInfo, showProgress, minNRow,
4077 timeSecCol);
4078
4079 initLineFinder(edge, threshold, chanAvgLimit, lineFinder);
4080
4081 std::vector<int> nChanNos;
4082 std::vector<std::vector<std::vector<double> > > modelReservoir;
4083 modelReservoir = getPolynomialModelReservoir(3,
4084 &Scantable::getNormalPolynomial,
4085 nChanNos);
4086 int nDOF = nPiece + 3;
4087
4088 for (int whichrow = 0; whichrow < nRow; ++whichrow) {
4089 std::vector<float> sp = getSpectrum(whichrow);
4090 std::vector<int> currentEdge;
4091 chanMask = getCompositeChanMask(whichrow, mask, edge, currentEdge, lineFinder);
4092 std::vector<int> pieceEdges;
4093 std::vector<float> params;
4094
4095 //if (flagrowCol_(whichrow) == 0) {
4096 if (flagrowCol_(whichrow)==0 && nValidMask(chanMask)>0) {
4097 int nClipped = 0;
4098 std::vector<float> res;
4099 res = doCubicSplineLeastSquareFitting(sp, chanMask,
4100 modelReservoir[getIdxOfNchan(sp.size(), nChanNos)],
4101 nPiece, false, pieceEdges, params, rms, finalChanMask,
4102 nClipped, thresClip, nIterClip, getResidual);
4103
4104 if (outBaselineTable) {
4105 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
4106 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
4107 true, STBaselineFunc::CSpline, pieceEdges, std::vector<float>(),
4108 getMaskListFromMask(finalChanMask), params, rms, sp.size(),
4109 thresClip, nIterClip, threshold, chanAvgLimit, currentEdge);
4110 } else {
4111 setSpectrum(res, whichrow);
4112 }
4113
4114 outputFittingResult(outLogger, outTextFile, csvFormat, chanMask, whichrow,
4115 coordInfo, hasSameNchan, ofs, "autoCubicSplineBaseline()",
4116 pieceEdges, params, nClipped);
4117 } else {
4118 // no valid channels to fit (flag the row)
4119 flagrowCol_.put(whichrow, 1);
4120 ++flagged;
4121 if (outBaselineTable) {
4122 pieceEdges.resize(nPiece+1);
4123 for (uInt i = 0; i < pieceEdges.size(); ++i) {
4124 pieceEdges[i] = 0;
4125 }
4126 params.resize(nDOF);
4127 for (uInt i = 0; i < params.size(); ++i) {
4128 params[i] = 0.0;
4129 }
4130 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
4131 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
4132 true, STBaselineFunc::CSpline, pieceEdges, std::vector<float>(),
4133 getMaskListFromMask(chanMask), params, 0.0, sp.size(),
4134 thresClip, nIterClip, threshold, chanAvgLimit, currentEdge);
4135 }
4136 }
4137
4138 showProgressOnTerminal(whichrow, nRow, showProgress, minNRow);
4139 }
4140
4141 finaliseBaselining(outBaselineTable, &bt, bltable, outTextFile, ofs);
4142
4143 if (flagged > 0) {
4144 LogIO os( LogOrigin( "Scantable", "autoCubicSplineBaseline()") ) ;
4145 os << LogIO::WARN << "Baseline subtraction is skipped for " << flagged << " spectra due to too few valid channels to operate fit. The spectra will be flagged in output data." << LogIO::POST;
4146 }
4147 } catch (...) {
4148 throw;
4149 }
4150}
4151
4152std::vector<float> Scantable::doCubicSplineFitting(const std::vector<float>& data,
4153 const std::vector<bool>& mask,
4154 std::vector<int>& idxEdge,
4155 std::vector<float>& params,
4156 float& rms,
4157 std::vector<bool>& finalmask,
4158 float clipth,
4159 int clipn)
4160{
4161 int nClipped = 0;
4162 return doCubicSplineFitting(data, mask, idxEdge.size()-1, true, idxEdge, params, rms, finalmask, nClipped, clipth, clipn);
4163}
4164
4165std::vector<float> Scantable::doCubicSplineFitting(const std::vector<float>& data,
4166 const std::vector<bool>& mask,
4167 int nPiece,
4168 std::vector<int>& idxEdge,
4169 std::vector<float>& params,
4170 float& rms,
4171 std::vector<bool>& finalmask,
4172 float clipth,
4173 int clipn)
4174{
4175 int nClipped = 0;
4176 return doCubicSplineFitting(data, mask, nPiece, false, idxEdge, params, rms, finalmask, nClipped, clipth, clipn);
4177}
4178
4179std::vector<float> Scantable::doCubicSplineFitting(const std::vector<float>& data,
4180 const std::vector<bool>& mask,
4181 int nPiece,
4182 bool useGivenPieceBoundary,
4183 std::vector<int>& idxEdge,
4184 std::vector<float>& params,
4185 float& rms,
4186 std::vector<bool>& finalMask,
4187 int& nClipped,
4188 float thresClip,
4189 int nIterClip,
4190 bool getResidual)
4191{
4192 return doCubicSplineLeastSquareFitting(data, mask,
4193 getPolynomialModel(3, data.size(), &Scantable::getNormalPolynomial),
4194 nPiece, useGivenPieceBoundary, idxEdge,
4195 params, rms, finalMask,
4196 nClipped, thresClip, nIterClip,
4197 getResidual);
4198}
4199
4200std::vector<float> Scantable::doCubicSplineLeastSquareFitting(const std::vector<float>& data,
4201 const std::vector<bool>& mask,
4202 const std::vector<std::vector<double> >& model,
4203 int nPiece,
4204 bool useGivenPieceBoundary,
4205 std::vector<int>& idxEdge,
4206 std::vector<float>& params,
4207 float& rms,
4208 std::vector<bool>& finalMask,
4209 int& nClipped,
4210 float thresClip,
4211 int nIterClip,
4212 bool getResidual)
4213{
4214 int nDOF = nPiece + 3; //number of independent parameters to solve, namely, 4+(nPiece-1).
4215 int nModel = model.size();
4216 int nChan = data.size();
4217
4218 if (nModel != 4) {
4219 throw(AipsError("model size must be 4."));
4220 }
4221 if (nPiece < 1) {
4222 throw(AipsError("number of the sections must be one or more"));
4223 }
4224 if (nChan < 2*nPiece) {
4225 throw(AipsError("data size is too few"));
4226 }
4227 if (nChan != (int)mask.size()) {
4228 throw(AipsError("data and mask sizes are not identical"));
4229 }
4230 for (int i = 0; i < nModel; ++i) {
4231 if (nChan != (int)model[i].size()) {
4232 throw(AipsError("data and model sizes are not identical"));
4233 }
4234 }
4235
4236 params.clear();
4237 params.resize(nPiece*nModel);
4238
4239 finalMask.clear();
4240 finalMask.resize(nChan);
4241
4242 std::vector<int> maskArray(nChan);
4243 std::vector<int> x(nChan);
4244 int j = 0;
4245 for (int i = 0; i < nChan; ++i) {
4246 maskArray[i] = mask[i] ? 1 : 0;
4247 if (isnan(data[i])) maskArray[i] = 0;
4248 if (isinf(data[i])) maskArray[i] = 0;
4249
4250 finalMask[i] = (maskArray[i] == 1);
4251 if (finalMask[i]) {
4252 x[j] = i;
4253 j++;
4254 }
4255
4256 /*
4257 maskArray[i] = mask[i] ? 1 : 0;
4258 if (mask[i]) {
4259 x[j] = i;
4260 j++;
4261 }
4262 finalMask[i] = mask[i];
4263 */
4264 }
4265
4266 int initNData = j;
4267 int nData = initNData;
4268
4269 if (initNData < nPiece) {
4270 throw(AipsError("too few non-flagged channels"));
4271 }
4272
4273 int nElement = (int)(floor(floor((double)(initNData/nPiece))+0.5));
4274 std::vector<double> invEdge(nPiece-1);
4275
4276 if (useGivenPieceBoundary) {
4277 if ((int)idxEdge.size() != nPiece+1) {
4278 throw(AipsError("pieceEdge.size() must be equal to nPiece+1."));
4279 }
4280 } else {
4281 idxEdge.clear();
4282 idxEdge.resize(nPiece+1);
4283 idxEdge[0] = x[0];
4284 }
4285 for (int i = 1; i < nPiece; ++i) {
4286 int valX = x[nElement*i];
4287 if (!useGivenPieceBoundary) {
4288 idxEdge[i] = valX;
4289 }
4290 invEdge[i-1] = 1.0/(double)valX;
4291 }
4292 if (!useGivenPieceBoundary) {
4293 idxEdge[nPiece] = x[initNData-1]+1;
4294 }
4295
4296 std::vector<double> z1(nChan), r1(nChan), residual(nChan);
4297 for (int i = 0; i < nChan; ++i) {
4298 z1[i] = (double)data[i];
4299 r1[i] = 0.0;
4300 residual[i] = 0.0;
4301 }
4302
4303 for (int nClip = 0; nClip < nIterClip+1; ++nClip) {
4304 // xMatrix : horizontal concatenation of
4305 // the least-sq. matrix (left) and an
4306 // identity matrix (right).
4307 // the right part is used to calculate the inverse matrix of the left part.
4308
4309 double xMatrix[nDOF][2*nDOF];
4310 double zMatrix[nDOF];
4311 for (int i = 0; i < nDOF; ++i) {
4312 for (int j = 0; j < 2*nDOF; ++j) {
4313 xMatrix[i][j] = 0.0;
4314 }
4315 xMatrix[i][nDOF+i] = 1.0;
4316 zMatrix[i] = 0.0;
4317 }
4318
4319 for (int n = 0; n < nPiece; ++n) {
4320 int nUseDataInPiece = 0;
4321 for (int k = idxEdge[n]; k < idxEdge[n+1]; ++k) {
4322
4323 if (maskArray[k] == 0) continue;
4324
4325 for (int i = 0; i < nModel; ++i) {
4326 for (int j = i; j < nModel; ++j) {
4327 xMatrix[i][j] += model[i][k] * model[j][k];
4328 }
4329 zMatrix[i] += z1[k] * model[i][k];
4330 }
4331
4332 for (int i = 0; i < n; ++i) {
4333 double q = 1.0 - model[1][k]*invEdge[i];
4334 q = q*q*q;
4335 for (int j = 0; j < nModel; ++j) {
4336 xMatrix[j][i+nModel] += q * model[j][k];
4337 }
4338 for (int j = 0; j < i; ++j) {
4339 double r = 1.0 - model[1][k]*invEdge[j];
4340 r = r*r*r;
4341 xMatrix[j+nModel][i+nModel] += r*q;
4342 }
4343 xMatrix[i+nModel][i+nModel] += q*q;
4344 zMatrix[i+nModel] += q*z1[k];
4345 }
4346
4347 nUseDataInPiece++;
4348 }
4349
4350 if (nUseDataInPiece < 1) {
4351 std::vector<string> suffixOfPieceNumber(4);
4352 suffixOfPieceNumber[0] = "th";
4353 suffixOfPieceNumber[1] = "st";
4354 suffixOfPieceNumber[2] = "nd";
4355 suffixOfPieceNumber[3] = "rd";
4356 int idxNoDataPiece = (n % 10 <= 3) ? n : 0;
4357 ostringstream oss;
4358 oss << "all channels clipped or masked in " << n << suffixOfPieceNumber[idxNoDataPiece];
4359 oss << " piece of the spectrum. can't execute fitting anymore.";
4360 throw(AipsError(String(oss)));
4361 }
4362 }
4363
4364 for (int i = 0; i < nDOF; ++i) {
4365 for (int j = 0; j < i; ++j) {
4366 xMatrix[i][j] = xMatrix[j][i];
4367 }
4368 }
4369
4370 std::vector<double> invDiag(nDOF);
4371 for (int i = 0; i < nDOF; ++i) {
4372 invDiag[i] = 1.0 / xMatrix[i][i];
4373 for (int j = 0; j < nDOF; ++j) {
4374 xMatrix[i][j] *= invDiag[i];
4375 }
4376 }
4377
4378 for (int k = 0; k < nDOF; ++k) {
4379 for (int i = 0; i < nDOF; ++i) {
4380 if (i != k) {
4381 double factor1 = xMatrix[k][k];
4382 double invfactor1 = 1.0 / factor1;
4383 double factor2 = xMatrix[i][k];
4384 for (int j = k; j < 2*nDOF; ++j) {
4385 xMatrix[i][j] *= factor1;
4386 xMatrix[i][j] -= xMatrix[k][j]*factor2;
4387 xMatrix[i][j] *= invfactor1;
4388 }
4389 }
4390 }
4391 double invXDiag = 1.0 / xMatrix[k][k];
4392 for (int j = k; j < 2*nDOF; ++j) {
4393 xMatrix[k][j] *= invXDiag;
4394 }
4395 }
4396
4397 for (int i = 0; i < nDOF; ++i) {
4398 for (int j = 0; j < nDOF; ++j) {
4399 xMatrix[i][nDOF+j] *= invDiag[j];
4400 }
4401 }
4402
4403 //compute a vector y which consists of the coefficients of the best-fit spline curves
4404 //(a0,a1,a2,a3(,b3,c3,...)), namely, the ones for the leftmost piece and the ones of
4405 //cubic terms for the other pieces (in case nPiece>1).
4406 std::vector<double> y(nDOF);
4407 for (int i = 0; i < nDOF; ++i) {
4408 y[i] = 0.0;
4409 for (int j = 0; j < nDOF; ++j) {
4410 y[i] += xMatrix[i][nDOF+j]*zMatrix[j];
4411 }
4412 }
4413
4414 std::vector<double> a(nModel);
4415 for (int i = 0; i < nModel; ++i) {
4416 a[i] = y[i];
4417 }
4418
4419 int j = 0;
4420 for (int n = 0; n < nPiece; ++n) {
4421 for (int i = idxEdge[n]; i < idxEdge[n+1]; ++i) {
4422 r1[i] = 0.0;
4423 for (int j = 0; j < nModel; ++j) {
4424 r1[i] += a[j] * model[j][i];
4425 }
4426 }
4427 for (int i = 0; i < nModel; ++i) {
4428 params[j+i] = a[i];
4429 }
4430 j += nModel;
4431
4432 if (n == nPiece-1) break;
4433
4434 double d = y[n+nModel];
4435 double iE = invEdge[n];
4436 a[0] += d;
4437 a[1] -= 3.0 * d * iE;
4438 a[2] += 3.0 * d * iE * iE;
4439 a[3] -= d * iE * iE * iE;
4440 }
4441
4442 //subtract constant value for masked regions at the edge of spectrum
4443 if (idxEdge[0] > 0) {
4444 int n = idxEdge[0];
4445 for (int i = 0; i < idxEdge[0]; ++i) {
4446 //--cubic extrapolate--
4447 //r1[i] = params[0] + params[1]*x1[i] + params[2]*x2[i] + params[3]*x3[i];
4448 //--linear extrapolate--
4449 //r1[i] = (r1[n+1] - r1[n])/(x1[n+1] - x1[n])*(x1[i] - x1[n]) + r1[n];
4450 //--constant--
4451 r1[i] = r1[n];
4452 }
4453 }
4454
4455 if (idxEdge[nPiece] < nChan) {
4456 int n = idxEdge[nPiece]-1;
4457 for (int i = idxEdge[nPiece]; i < nChan; ++i) {
4458 //--cubic extrapolate--
4459 //int m = 4*(nPiece-1);
4460 //r1[i] = params[m] + params[m+1]*x1[i] + params[m+2]*x2[i] + params[m+3]*x3[i];
4461 //--linear extrapolate--
4462 //r1[i] = (r1[n-1] - r1[n])/(x1[n-1] - x1[n])*(x1[i] - x1[n]) + r1[n];
4463 //--constant--
4464 r1[i] = r1[n];
4465 }
4466 }
4467
4468 for (int i = 0; i < nChan; ++i) {
4469 residual[i] = z1[i] - r1[i];
4470 }
4471
4472 double mean = 0.0;
4473 double mean2 = 0.0;
4474 for (int i = 0; i < nChan; ++i) {
4475 if (maskArray[i] == 0) continue;
4476 mean += residual[i];
4477 mean2 += residual[i]*residual[i];
4478 }
4479 mean /= (double)nData;
4480 mean2 /= (double)nData;
4481 double rmsd = sqrt(mean2 - mean*mean);
4482 rms = (float)rmsd;
4483
4484 if ((nClip == nIterClip) || (thresClip <= 0.0)) {
4485 break;
4486 } else {
4487
4488 double thres = rmsd * thresClip;
4489 int newNData = 0;
4490 for (int i = 0; i < nChan; ++i) {
4491 if (abs(residual[i]) >= thres) {
4492 maskArray[i] = 0;
4493 finalMask[i] = false;
4494 }
4495 if (maskArray[i] > 0) {
4496 newNData++;
4497 }
4498 }
4499 if (newNData == nData) {
4500 break; //no more flag to add. iteration stops.
4501 } else {
4502 nData = newNData;
4503 }
4504
4505 }
4506 }
4507
4508 nClipped = initNData - nData;
4509
4510 std::vector<float> result(nChan);
4511 if (getResidual) {
4512 for (int i = 0; i < nChan; ++i) {
4513 result[i] = (float)residual[i];
4514 }
4515 } else {
4516 for (int i = 0; i < nChan; ++i) {
4517 result[i] = (float)r1[i];
4518 }
4519 }
4520
4521 return result;
4522}
4523
4524std::vector<int> Scantable::selectWaveNumbers(const std::vector<int>& addNWaves,
4525 const std::vector<int>& rejectNWaves)
4526{
4527 std::vector<bool> chanMask;
4528 std::string fftMethod;
4529 std::string fftThresh;
4530
4531 return selectWaveNumbers(0, chanMask, false, fftMethod, fftThresh, addNWaves, rejectNWaves);
4532}
4533
4534std::vector<int> Scantable::selectWaveNumbers(const int whichrow,
4535 const std::vector<bool>& chanMask,
4536 const bool applyFFT,
4537 const std::string& fftMethod,
4538 const std::string& fftThresh,
4539 const std::vector<int>& addNWaves,
4540 const std::vector<int>& rejectNWaves)
4541{
4542 std::vector<int> nWaves;
4543 nWaves.clear();
4544
4545 if (applyFFT) {
4546 string fftThAttr;
4547 float fftThSigma;
4548 int fftThTop;
4549 parseFFTThresholdInfo(fftThresh, fftThAttr, fftThSigma, fftThTop);
4550 doSelectWaveNumbers(whichrow, chanMask, fftMethod, fftThSigma, fftThTop, fftThAttr, nWaves);
4551 }
4552
4553 addAuxWaveNumbers(whichrow, addNWaves, rejectNWaves, nWaves);
4554
4555 return nWaves;
4556}
4557
4558int Scantable::getIdxOfNchan(const int nChan, const std::vector<int>& nChanNos)
4559{
4560 int idx = -1;
4561 for (uint i = 0; i < nChanNos.size(); ++i) {
4562 if (nChan == nChanNos[i]) {
4563 idx = i;
4564 break;
4565 }
4566 }
4567
4568 if (idx < 0) {
4569 throw(AipsError("nChan not found in nChhanNos."));
4570 }
4571
4572 return idx;
4573}
4574
4575void Scantable::parseFFTInfo(const std::string& fftInfo, bool& applyFFT, std::string& fftMethod, std::string& fftThresh)
4576{
4577 istringstream iss(fftInfo);
4578 std::string tmp;
4579 std::vector<string> res;
4580 while (getline(iss, tmp, ',')) {
4581 res.push_back(tmp);
4582 }
4583 if (res.size() < 3) {
4584 throw(AipsError("wrong value in 'fftinfo' parameter")) ;
4585 }
4586 applyFFT = (res[0] == "true");
4587 fftMethod = res[1];
4588 fftThresh = res[2];
4589}
4590
4591void Scantable::parseFFTThresholdInfo(const std::string& fftThresh, std::string& fftThAttr, float& fftThSigma, int& fftThTop)
4592{
4593 uInt idxSigma = fftThresh.find("sigma");
4594 uInt idxTop = fftThresh.find("top");
4595
4596 if (idxSigma == fftThresh.size() - 5) {
4597 std::istringstream is(fftThresh.substr(0, fftThresh.size() - 5));
4598 is >> fftThSigma;
4599 fftThAttr = "sigma";
4600 } else if (idxTop == 0) {
4601 std::istringstream is(fftThresh.substr(3));
4602 is >> fftThTop;
4603 fftThAttr = "top";
4604 } else {
4605 bool isNumber = true;
4606 for (uInt i = 0; i < fftThresh.size()-1; ++i) {
4607 char ch = (fftThresh.substr(i, 1).c_str())[0];
4608 if (!(isdigit(ch) || (fftThresh.substr(i, 1) == "."))) {
4609 isNumber = false;
4610 break;
4611 }
4612 }
4613 if (isNumber) {
4614 std::istringstream is(fftThresh);
4615 is >> fftThSigma;
4616 fftThAttr = "sigma";
4617 } else {
4618 throw(AipsError("fftthresh has a wrong value"));
4619 }
4620 }
4621}
4622
4623void Scantable::doSelectWaveNumbers(const int whichrow, const std::vector<bool>& chanMask, const std::string& fftMethod, const float fftThSigma, const int fftThTop, const std::string& fftThAttr, std::vector<int>& nWaves)
4624{
4625 std::vector<float> fspec;
4626 if (fftMethod == "fft") {
4627 fspec = execFFT(whichrow, chanMask, false, true);
4628 //} else if (fftMethod == "lsp") {
4629 // fspec = lombScarglePeriodogram(whichrow);
4630 }
4631
4632 if (fftThAttr == "sigma") {
4633 float mean = 0.0;
4634 float mean2 = 0.0;
4635 for (uInt i = 0; i < fspec.size(); ++i) {
4636 mean += fspec[i];
4637 mean2 += fspec[i]*fspec[i];
4638 }
4639 mean /= float(fspec.size());
4640 mean2 /= float(fspec.size());
4641 float thres = mean + fftThSigma * float(sqrt(mean2 - mean*mean));
4642
4643 for (uInt i = 0; i < fspec.size(); ++i) {
4644 if (fspec[i] >= thres) {
4645 nWaves.push_back(i);
4646 }
4647 }
4648
4649 } else if (fftThAttr == "top") {
4650 for (int i = 0; i < fftThTop; ++i) {
4651 float max = 0.0;
4652 int maxIdx = 0;
4653 for (uInt j = 0; j < fspec.size(); ++j) {
4654 if (fspec[j] > max) {
4655 max = fspec[j];
4656 maxIdx = j;
4657 }
4658 }
4659 nWaves.push_back(maxIdx);
4660 fspec[maxIdx] = 0.0;
4661 }
4662
4663 }
4664
4665 if (nWaves.size() > 1) {
4666 sort(nWaves.begin(), nWaves.end());
4667 }
4668}
4669
4670void Scantable::addAuxWaveNumbers(const int whichrow, const std::vector<int>& addNWaves, const std::vector<int>& rejectNWaves, std::vector<int>& nWaves)
4671{
4672 std::vector<int> tempAddNWaves, tempRejectNWaves;
4673 tempAddNWaves.clear();
4674 tempRejectNWaves.clear();
4675
4676 for (uInt i = 0; i < addNWaves.size(); ++i) {
4677 tempAddNWaves.push_back(addNWaves[i]);
4678 }
4679 if ((tempAddNWaves.size() == 2) && (tempAddNWaves[1] == -999)) {
4680 setWaveNumberListUptoNyquistFreq(whichrow, tempAddNWaves);
4681 }
4682
4683 for (uInt i = 0; i < rejectNWaves.size(); ++i) {
4684 tempRejectNWaves.push_back(rejectNWaves[i]);
4685 }
4686 if ((tempRejectNWaves.size() == 2) && (tempRejectNWaves[1] == -999)) {
4687 setWaveNumberListUptoNyquistFreq(whichrow, tempRejectNWaves);
4688 }
4689
4690 for (uInt i = 0; i < tempAddNWaves.size(); ++i) {
4691 bool found = false;
4692 for (uInt j = 0; j < nWaves.size(); ++j) {
4693 if (nWaves[j] == tempAddNWaves[i]) {
4694 found = true;
4695 break;
4696 }
4697 }
4698 if (!found) nWaves.push_back(tempAddNWaves[i]);
4699 }
4700
4701 for (uInt i = 0; i < tempRejectNWaves.size(); ++i) {
4702 for (std::vector<int>::iterator j = nWaves.begin(); j != nWaves.end(); ) {
4703 if (*j == tempRejectNWaves[i]) {
4704 j = nWaves.erase(j);
4705 } else {
4706 ++j;
4707 }
4708 }
4709 }
4710
4711 if (nWaves.size() > 1) {
4712 sort(nWaves.begin(), nWaves.end());
4713 unique(nWaves.begin(), nWaves.end());
4714 }
4715}
4716
4717void Scantable::setWaveNumberListUptoNyquistFreq(const int whichrow, std::vector<int>& nWaves)
4718{
4719 int val = nWaves[0];
4720 int nyquistFreq = nchan(getIF(whichrow))/2+1;
4721 nWaves.clear();
4722 if (val > nyquistFreq) { // for safety, at least nWaves contains a constant; CAS-3759
4723 nWaves.push_back(0);
4724 }
4725 while (val <= nyquistFreq) {
4726 nWaves.push_back(val);
4727 val++;
4728 }
4729}
4730
4731void Scantable::sinusoidBaseline(const std::vector<bool>& mask, const std::string& fftInfo,
4732 const std::vector<int>& addNWaves,
4733 const std::vector<int>& rejectNWaves,
4734 float thresClip, int nIterClip,
4735 bool getResidual,
4736 const std::string& progressInfo,
4737 const bool outLogger, const std::string& blfile,
4738 const std::string& bltable)
4739{
4740 /****
4741 double TimeStart = mathutil::gettimeofday_sec();
4742 ****/
4743
4744 try {
4745 ofstream ofs;
4746 String coordInfo;
4747 bool hasSameNchan, outTextFile, csvFormat, showProgress;
4748 int minNRow;
4749 int nRow = nrow();
4750 std::vector<bool> chanMask, finalChanMask;
4751 float rms;
4752 bool outBaselineTable = (bltable != "");
4753 STBaselineTable bt = STBaselineTable(*this);
4754 Vector<Double> timeSecCol;
4755 size_t flagged=0;
4756
4757 initialiseBaselining(blfile, ofs, outLogger, outTextFile, csvFormat,
4758 coordInfo, hasSameNchan,
4759 progressInfo, showProgress, minNRow,
4760 timeSecCol);
4761
4762 bool applyFFT;
4763 std::string fftMethod, fftThresh;
4764 parseFFTInfo(fftInfo, applyFFT, fftMethod, fftThresh);
4765
4766 std::vector<int> nWaves;
4767 std::vector<int> nChanNos;
4768 std::vector<std::vector<std::vector<double> > > modelReservoir;
4769 if (!applyFFT) {
4770 nWaves = selectWaveNumbers(addNWaves, rejectNWaves);
4771 if (nWaves.size()==0) //no wave numbers to fit
4772 throw(AipsError("No valid wave numbers to fit"));
4773 modelReservoir = getSinusoidModelReservoir(nWaves, nChanNos);
4774 }
4775
4776 for (int whichrow = 0; whichrow < nRow; ++whichrow) {
4777 std::vector<float> sp = getSpectrum(whichrow);
4778 chanMask = getCompositeChanMask(whichrow, mask);
4779 std::vector<std::vector<double> > model;
4780 bool canfit = true;
4781 if (applyFFT) {
4782 nWaves = selectWaveNumbers(whichrow, chanMask, true, fftMethod, fftThresh,
4783 addNWaves, rejectNWaves);
4784 if (nWaves.size()==0) {// no wave numbers to fit.
4785 canfit = false;
4786 break;
4787 }
4788 model = getSinusoidModel(nWaves, sp.size());
4789 } else {
4790 model = modelReservoir[getIdxOfNchan(sp.size(), nChanNos)];
4791 }
4792 int nModel = modelReservoir.size();
4793
4794 std::vector<float> params;
4795
4796 //if (flagrowCol_(whichrow) == 0) {
4797 if (canfit && flagrowCol_(whichrow)==0 && nValidMask(chanMask)>0) {
4798 int nClipped = 0;
4799 std::vector<float> res;
4800 res = doLeastSquareFitting(sp, chanMask, model,
4801 params, rms, finalChanMask,
4802 nClipped, thresClip, nIterClip, getResidual);
4803
4804 if (outBaselineTable) {
4805 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
4806 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
4807 true, STBaselineFunc::Sinusoid, nWaves, std::vector<float>(),
4808 getMaskListFromMask(finalChanMask), params, rms, sp.size(),
4809 thresClip, nIterClip, 0.0, 0, std::vector<int>());
4810 } else {
4811 setSpectrum(res, whichrow);
4812 }
4813
4814 outputFittingResult(outLogger, outTextFile, csvFormat, chanMask, whichrow,
4815 coordInfo, hasSameNchan, ofs, "sinusoidBaseline()",
4816 params, nClipped);
4817 } else {
4818 // no valid channels to fit (flag the row)
4819 flagrowCol_.put(whichrow, 1);
4820 ++flagged;
4821 if (outBaselineTable) {
4822 params.resize(nModel);
4823 for (uInt i = 0; i < params.size(); ++i) {
4824 params[i] = 0.0;
4825 }
4826 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
4827 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
4828 true, STBaselineFunc::Sinusoid, nWaves, std::vector<float>(),
4829 getMaskListFromMask(chanMask), params, 0.0, sp.size(),
4830 thresClip, nIterClip, 0.0, 0, std::vector<int>());
4831 }
4832 }
4833
4834 showProgressOnTerminal(whichrow, nRow, showProgress, minNRow);
4835 }
4836
4837 finaliseBaselining(outBaselineTable, &bt, bltable, outTextFile, ofs);
4838
4839 if (flagged > 0) {
4840 LogIO os( LogOrigin( "Scantable", "sinusoidBaseline()") ) ;
4841 os << LogIO::WARN << "Baseline subtraction is skipped for " << flagged << " spectra due to too few valid channels to operate fit. The spectra will be flagged in output data." << LogIO::POST;
4842 }
4843 } catch (...) {
4844 throw;
4845 }
4846
4847 /****
4848 double TimeEnd = mathutil::gettimeofday_sec();
4849 double elapse1 = TimeEnd - TimeStart;
4850 std::cout << "sinusoid-old : " << elapse1 << " (sec.)" << endl;
4851 ****/
4852}
4853
4854void Scantable::autoSinusoidBaseline(const std::vector<bool>& mask, const std::string& fftInfo,
4855 const std::vector<int>& addNWaves,
4856 const std::vector<int>& rejectNWaves,
4857 float thresClip, int nIterClip,
4858 const std::vector<int>& edge,
4859 float threshold, int chanAvgLimit,
4860 bool getResidual,
4861 const std::string& progressInfo,
4862 const bool outLogger, const std::string& blfile,
4863 const std::string& bltable)
4864{
4865 try {
4866 ofstream ofs;
4867 String coordInfo;
4868 bool hasSameNchan, outTextFile, csvFormat, showProgress;
4869 int minNRow;
4870 int nRow = nrow();
4871 std::vector<bool> chanMask, finalChanMask;
4872 float rms;
4873 bool outBaselineTable = (bltable != "");
4874 STBaselineTable bt = STBaselineTable(*this);
4875 Vector<Double> timeSecCol;
4876 STLineFinder lineFinder = STLineFinder();
4877 size_t flagged=0;
4878
4879 initialiseBaselining(blfile, ofs, outLogger, outTextFile, csvFormat,
4880 coordInfo, hasSameNchan,
4881 progressInfo, showProgress, minNRow,
4882 timeSecCol);
4883
4884 initLineFinder(edge, threshold, chanAvgLimit, lineFinder);
4885
4886 bool applyFFT;
4887 string fftMethod, fftThresh;
4888 parseFFTInfo(fftInfo, applyFFT, fftMethod, fftThresh);
4889
4890 std::vector<int> nWaves;
4891 std::vector<int> nChanNos;
4892 std::vector<std::vector<std::vector<double> > > modelReservoir;
4893 if (!applyFFT) {
4894 nWaves = selectWaveNumbers(addNWaves, rejectNWaves);
4895 if (nWaves.size()==0) //no wave numbers to fit
4896 throw(AipsError("No valid wave numbers to fit"));
4897 modelReservoir = getSinusoidModelReservoir(nWaves, nChanNos);
4898 }
4899
4900 for (int whichrow = 0; whichrow < nRow; ++whichrow) {
4901 std::vector<float> sp = getSpectrum(whichrow);
4902 std::vector<int> currentEdge;
4903 chanMask = getCompositeChanMask(whichrow, mask, edge, currentEdge, lineFinder);
4904 std::vector<std::vector<double> > model;
4905 bool canfit=true;
4906 if (applyFFT) {
4907 nWaves = selectWaveNumbers(whichrow, chanMask, true, fftMethod, fftThresh,
4908 addNWaves, rejectNWaves);
4909 if (nWaves.size()==0) { // no wave numbers to fit.
4910 canfit = false;
4911 break;
4912 }
4913 model = getSinusoidModel(nWaves, sp.size());
4914 } else {
4915 model = modelReservoir[getIdxOfNchan(sp.size(), nChanNos)];
4916 }
4917 int nModel = modelReservoir.size();
4918
4919 std::vector<float> params;
4920
4921 //if (flagrowCol_(whichrow) == 0) {
4922 if (canfit && flagrowCol_(whichrow)==0 && nValidMask(chanMask)>0) {
4923 int nClipped = 0;
4924 std::vector<float> res;
4925 res = doLeastSquareFitting(sp, chanMask, model,
4926 params, rms, finalChanMask,
4927 nClipped, thresClip, nIterClip, getResidual);
4928
4929 if (outBaselineTable) {
4930 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
4931 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
4932 true, STBaselineFunc::Sinusoid, nWaves, std::vector<float>(),
4933 getMaskListFromMask(finalChanMask), params, rms, sp.size(),
4934 thresClip, nIterClip, threshold, chanAvgLimit, currentEdge);
4935 } else {
4936 setSpectrum(res, whichrow);
4937 }
4938
4939 outputFittingResult(outLogger, outTextFile, csvFormat, chanMask, whichrow,
4940 coordInfo, hasSameNchan, ofs, "autoSinusoidBaseline()",
4941 params, nClipped);
4942 } else {
4943 // no valid channels to fit (flag the row)
4944 flagrowCol_.put(whichrow, 1);
4945 ++flagged;
4946 if (outBaselineTable) {
4947 params.resize(nModel);
4948 for (uInt i = 0; i < params.size(); ++i) {
4949 params[i] = 0.0;
4950 }
4951 bt.appenddata(getScan(whichrow), getCycle(whichrow), getBeam(whichrow),
4952 getIF(whichrow), getPol(whichrow), 0, timeSecCol[whichrow],
4953 true, STBaselineFunc::Sinusoid, nWaves, std::vector<float>(),
4954 getMaskListFromMask(chanMask), params, 0.0, sp.size(),
4955 thresClip, nIterClip, threshold, chanAvgLimit, currentEdge);
4956 }
4957 }
4958
4959 showProgressOnTerminal(whichrow, nRow, showProgress, minNRow);
4960 }
4961
4962 finaliseBaselining(outBaselineTable, &bt, bltable, outTextFile, ofs);
4963
4964 if (flagged > 0) {
4965 LogIO os( LogOrigin( "Scantable", "autoSinusoidBaseline()") ) ;
4966 os << LogIO::WARN << "Baseline subtraction is skipped for " << flagged << " spectra due to too few valid channels to operate fit. The spectra will be flagged in output data." << LogIO::POST;
4967 }
4968 } catch (...) {
4969 throw;
4970 }
4971}
4972
4973std::vector<float> Scantable::doSinusoidFitting(const std::vector<float>& data,
4974 const std::vector<bool>& mask,
4975 const std::vector<int>& waveNumbers,
4976 std::vector<float>& params,
4977 float& rms,
4978 std::vector<bool>& finalmask,
4979 float clipth,
4980 int clipn)
4981{
4982 int nClipped = 0;
4983 return doSinusoidFitting(data, mask, waveNumbers, params, rms, finalmask, nClipped, clipth, clipn);
4984}
4985
4986std::vector<float> Scantable::doSinusoidFitting(const std::vector<float>& data,
4987 const std::vector<bool>& mask,
4988 const std::vector<int>& waveNumbers,
4989 std::vector<float>& params,
4990 float& rms,
4991 std::vector<bool>& finalMask,
4992 int& nClipped,
4993 float thresClip,
4994 int nIterClip,
4995 bool getResidual)
4996{
4997 return doLeastSquareFitting(data, mask,
4998 getSinusoidModel(waveNumbers, data.size()),
4999 params, rms, finalMask,
5000 nClipped, thresClip, nIterClip,
5001 getResidual);
5002}
5003
5004std::vector<std::vector<std::vector<double> > > Scantable::getSinusoidModelReservoir(const std::vector<int>& waveNumbers,
5005 std::vector<int>& nChanNos)
5006{
5007 std::vector<std::vector<std::vector<double> > > res;
5008 res.clear();
5009 nChanNos.clear();
5010
5011 std::vector<uint> ifNos = getIFNos();
5012 for (uint i = 0; i < ifNos.size(); ++i) {
5013 int currNchan = nchan(ifNos[i]);
5014 bool hasDifferentNchan = (i == 0);
5015 for (uint j = 0; j < i; ++j) {
5016 if (currNchan != nchan(ifNos[j])) {
5017 hasDifferentNchan = true;
5018 break;
5019 }
5020 }
5021 if (hasDifferentNchan) {
5022 res.push_back(getSinusoidModel(waveNumbers, currNchan));
5023 nChanNos.push_back(currNchan);
5024 }
5025 }
5026
5027 return res;
5028}
5029
5030std::vector<std::vector<double> > Scantable::getSinusoidModel(const std::vector<int>& waveNumbers, int nchan)
5031{
5032 // model : contains elemental values for computing the least-square matrix.
5033 // model.size() is nmodel and model[*].size() is nchan.
5034 // Each model element are as follows:
5035 // model[0] = {1.0, 1.0, 1.0, ..., 1.0},
5036 // model[2n-1] = {sin(nPI/L*x[0]), sin(nPI/L*x[1]), ..., sin(nPI/L*x[nchan])},
5037 // model[2n] = {cos(nPI/L*x[0]), cos(nPI/L*x[1]), ..., cos(nPI/L*x[nchan])},
5038 // where (1 <= n <= nMaxWavesInSW),
5039 // or,
5040 // model[2n-1] = {sin(wn[n]PI/L*x[0]), sin(wn[n]PI/L*x[1]), ..., sin(wn[n]PI/L*x[nchan])},
5041 // model[2n] = {cos(wn[n]PI/L*x[0]), cos(wn[n]PI/L*x[1]), ..., cos(wn[n]PI/L*x[nchan])},
5042 // where wn[n] denotes waveNumbers[n] (1 <= n <= waveNumbers.size()).
5043
5044 std::vector<int> nWaves; // sorted and uniqued array of wave numbers
5045 nWaves.reserve(waveNumbers.size());
5046 copy(waveNumbers.begin(), waveNumbers.end(), back_inserter(nWaves));
5047 sort(nWaves.begin(), nWaves.end());
5048 std::vector<int>::iterator end_it = unique(nWaves.begin(), nWaves.end());
5049 nWaves.erase(end_it, nWaves.end());
5050
5051 if (nWaves.size()==0)
5052 throw(AipsError("No valid wavenumbers to fit."));
5053
5054 int minNWaves = nWaves[0];
5055 if (minNWaves < 0) {
5056 throw(AipsError("wave number must be positive or zero (i.e. constant)"));
5057 }
5058 bool hasConstantTerm = (minNWaves == 0);
5059 int nmodel = nWaves.size() * 2 - (hasConstantTerm ? 1 : 0); //number of parameters to solve.
5060
5061 std::vector<std::vector<double> > model(nmodel, std::vector<double>(nchan));
5062
5063 if (hasConstantTerm) {
5064 for (int j = 0; j < nchan; ++j) {
5065 model[0][j] = 1.0;
5066 }
5067 }
5068
5069 const double PI = 6.0 * asin(0.5); // PI (= 3.141592653...)
5070 double stretch0 = 2.0*PI/(double)(nchan-1);
5071
5072 for (uInt i = (hasConstantTerm ? 1 : 0); i < nWaves.size(); ++i) {
5073 int sidx = hasConstantTerm ? 2*i-1 : 2*i;
5074 int cidx = sidx + 1;
5075 double stretch = stretch0*(double)nWaves[i];
5076
5077 for (int j = 0; j < nchan; ++j) {
5078 model[sidx][j] = sin(stretch*(double)j);
5079 model[cidx][j] = cos(stretch*(double)j);
5080 }
5081 }
5082
5083 return model;
5084}
5085
5086std::vector<bool> Scantable::getCompositeChanMask(int whichrow,
5087 const std::vector<bool>& inMask)
5088{
5089 std::vector<bool> mask = getMask(whichrow);
5090 uInt maskSize = mask.size();
5091 if (inMask.size() != 0) {
5092 if (maskSize != inMask.size()) {
5093 throw(AipsError("mask sizes are not the same."));
5094 }
5095 for (uInt i = 0; i < maskSize; ++i) {
5096 mask[i] = mask[i] && inMask[i];
5097 }
5098 }
5099
5100 return mask;
5101}
5102
5103std::vector<bool> Scantable::getCompositeChanMask(int whichrow,
5104 const std::vector<bool>& inMask,
5105 const std::vector<int>& edge,
5106 std::vector<int>& currEdge,
5107 STLineFinder& lineFinder)
5108{
5109 if (isAllChannelsFlagged(whichrow)) {//all channels flagged
5110 std::vector<bool> res_mask(nchan(getIF(whichrow)),false);
5111 return res_mask;
5112 } else if (inMask.size() != 0 && nValidMask(inMask)==0){ //no valid mask channels
5113 std::vector<bool> res_mask(inMask);
5114 return res_mask;
5115 }
5116
5117 std::vector<uint> ifNos = getIFNos();
5118 if ((edge.size() > 2) && (edge.size() < ifNos.size()*2)) {
5119 throw(AipsError("Length of edge element info is less than that of IFs"));
5120 }
5121
5122 uint idx = 0;
5123 if (edge.size() > 2) {
5124 int ifVal = getIF(whichrow);
5125 bool foundIF = false;
5126 for (uint i = 0; i < ifNos.size(); ++i) {
5127 if (ifVal == (int)ifNos[i]) {
5128 idx = 2*i;
5129 foundIF = true;
5130 break;
5131 }
5132 }
5133 if (!foundIF) {
5134 throw(AipsError("bad IF number"));
5135 }
5136 }
5137
5138 currEdge.clear();
5139 currEdge.resize(2);
5140 currEdge[0] = edge[idx];
5141 currEdge[1] = edge[idx+1];
5142
5143 lineFinder.setData(getSpectrum(whichrow));
5144 lineFinder.findLines(getCompositeChanMask(whichrow, inMask), currEdge, whichrow);
5145 return lineFinder.getMask();
5146}
5147
5148/* for cspline. will be merged once cspline is available in fitter (2011/3/10 WK) */
5149void Scantable::outputFittingResult(bool outLogger,
5150 bool outTextFile,
5151 bool csvFormat,
5152 const std::vector<bool>& chanMask,
5153 int whichrow,
5154 const casa::String& coordInfo,
5155 bool hasSameNchan,
5156 ofstream& ofs,
5157 const casa::String& funcName,
5158 const std::vector<int>& edge,
5159 const std::vector<float>& params,
5160 const int nClipped)
5161{
5162 if (outLogger || outTextFile) {
5163 float rms = getRms(chanMask, whichrow);
5164 String masklist = getMaskRangeList(chanMask, whichrow, coordInfo, hasSameNchan);
5165 std::vector<bool> fixed;
5166 fixed.clear();
5167
5168 if (outLogger) {
5169 LogIO ols(LogOrigin("Scantable", funcName, WHERE));
5170 ols << formatPiecewiseBaselineParams(edge, params, fixed, rms, nClipped,
5171 masklist, whichrow, false, csvFormat) << LogIO::POST ;
5172 }
5173 if (outTextFile) {
5174 ofs << formatPiecewiseBaselineParams(edge, params, fixed, rms, nClipped,
5175 masklist, whichrow, true, csvFormat) << flush;
5176 }
5177 }
5178}
5179
5180/* for poly/chebyshev/sinusoid. */
5181void Scantable::outputFittingResult(bool outLogger,
5182 bool outTextFile,
5183 bool csvFormat,
5184 const std::vector<bool>& chanMask,
5185 int whichrow,
5186 const casa::String& coordInfo,
5187 bool hasSameNchan,
5188 ofstream& ofs,
5189 const casa::String& funcName,
5190 const std::vector<float>& params,
5191 const int nClipped)
5192{
5193 if (outLogger || outTextFile) {
5194 float rms = getRms(chanMask, whichrow);
5195 String masklist = getMaskRangeList(chanMask, whichrow, coordInfo, hasSameNchan);
5196 std::vector<bool> fixed;
5197 fixed.clear();
5198
5199 if (outLogger) {
5200 LogIO ols(LogOrigin("Scantable", funcName, WHERE));
5201 ols << formatBaselineParams(params, fixed, rms, nClipped,
5202 masklist, whichrow, false, csvFormat) << LogIO::POST ;
5203 }
5204 if (outTextFile) {
5205 ofs << formatBaselineParams(params, fixed, rms, nClipped,
5206 masklist, whichrow, true, csvFormat) << flush;
5207 }
5208 }
5209}
5210
5211void Scantable::parseProgressInfo(const std::string& progressInfo, bool& showProgress, int& minNRow)
5212{
5213 int idxDelimiter = progressInfo.find(",");
5214 if (idxDelimiter < 0) {
5215 throw(AipsError("wrong value in 'showprogress' parameter")) ;
5216 }
5217 showProgress = (progressInfo.substr(0, idxDelimiter) == "true");
5218 std::istringstream is(progressInfo.substr(idxDelimiter+1));
5219 is >> minNRow;
5220}
5221
5222void Scantable::showProgressOnTerminal(const int nProcessed, const int nTotal, const bool showProgress, const int nTotalThreshold)
5223{
5224 if (showProgress && (nTotal >= nTotalThreshold)) {
5225 int nInterval = int(floor(double(nTotal)/100.0));
5226 if (nInterval == 0) nInterval++;
5227
5228 if (nProcessed % nInterval == 0) {
5229 printf("\r"); //go to the head of line
5230 printf("\x1b[31m\x1b[1m"); //set red color, highlighted
5231 printf("[%3d%%]", (int)(100.0*(double(nProcessed+1))/(double(nTotal))) );
5232 printf("\x1b[39m\x1b[0m"); //set default attributes
5233 fflush(NULL);
5234 }
5235
5236 if (nProcessed == nTotal - 1) {
5237 printf("\r\x1b[K"); //clear
5238 fflush(NULL);
5239 }
5240
5241 }
5242}
5243
5244std::vector<float> Scantable::execFFT(const int whichrow, const std::vector<bool>& inMask, bool getRealImag, bool getAmplitudeOnly)
5245{
5246 std::vector<bool> mask = getMask(whichrow);
5247
5248 if (inMask.size() > 0) {
5249 uInt maskSize = mask.size();
5250 if (maskSize != inMask.size()) {
5251 throw(AipsError("mask sizes are not the same."));
5252 }
5253 for (uInt i = 0; i < maskSize; ++i) {
5254 mask[i] = mask[i] && inMask[i];
5255 }
5256 }
5257
5258 Vector<Float> spec = getSpectrum(whichrow);
5259 mathutil::doZeroOrderInterpolation(spec, mask);
5260
5261 FFTServer<Float,Complex> ffts;
5262 Vector<Complex> fftres;
5263 ffts.fft0(fftres, spec);
5264
5265 std::vector<float> res;
5266 float norm = float(2.0/double(spec.size()));
5267
5268 if (getRealImag) {
5269 for (uInt i = 0; i < fftres.size(); ++i) {
5270 res.push_back(real(fftres[i])*norm);
5271 res.push_back(imag(fftres[i])*norm);
5272 }
5273 } else {
5274 for (uInt i = 0; i < fftres.size(); ++i) {
5275 res.push_back(abs(fftres[i])*norm);
5276 if (!getAmplitudeOnly) res.push_back(arg(fftres[i]));
5277 }
5278 }
5279
5280 return res;
5281}
5282
5283
5284float Scantable::getRms(const std::vector<bool>& mask, int whichrow)
5285{
5286 /****
5287 double ms1TimeStart, ms1TimeEnd;
5288 double elapse1 = 0.0;
5289 ms1TimeStart = mathutil::gettimeofday_sec();
5290 ****/
5291
5292 Vector<Float> spec;
5293 specCol_.get(whichrow, spec);
5294
5295 /****
5296 ms1TimeEnd = mathutil::gettimeofday_sec();
5297 elapse1 = ms1TimeEnd - ms1TimeStart;
5298 std::cout << "rm1 : " << elapse1 << " (sec.)" << endl;
5299 ****/
5300
5301 return (float)doGetRms(mask, spec);
5302}
5303
5304double Scantable::doGetRms(const std::vector<bool>& mask, const Vector<Float>& spec)
5305{
5306 double mean = 0.0;
5307 double smean = 0.0;
5308 int n = 0;
5309 for (uInt i = 0; i < spec.nelements(); ++i) {
5310 if (mask[i]) {
5311 double val = (double)spec[i];
5312 mean += val;
5313 smean += val*val;
5314 n++;
5315 }
5316 }
5317
5318 mean /= (double)n;
5319 smean /= (double)n;
5320
5321 return sqrt(smean - mean*mean);
5322}
5323
5324std::string Scantable::formatBaselineParamsHeader(int whichrow, const std::string& masklist, bool verbose, bool csvformat) const
5325{
5326 if (verbose) {
5327 ostringstream oss;
5328
5329 if (csvformat) {
5330 oss << getScan(whichrow) << ",";
5331 oss << getBeam(whichrow) << ",";
5332 oss << getIF(whichrow) << ",";
5333 oss << getPol(whichrow) << ",";
5334 oss << getCycle(whichrow) << ",";
5335 String commaReplacedMasklist = masklist;
5336 string::size_type pos = 0;
5337 while (pos = commaReplacedMasklist.find(","), pos != string::npos) {
5338 commaReplacedMasklist.replace(pos, 1, ";");
5339 pos++;
5340 }
5341 oss << commaReplacedMasklist << ",";
5342 } else {
5343 oss << " Scan[" << getScan(whichrow) << "]";
5344 oss << " Beam[" << getBeam(whichrow) << "]";
5345 oss << " IF[" << getIF(whichrow) << "]";
5346 oss << " Pol[" << getPol(whichrow) << "]";
5347 oss << " Cycle[" << getCycle(whichrow) << "]: " << endl;
5348 oss << "Fitter range = " << masklist << endl;
5349 oss << "Baseline parameters" << endl;
5350 }
5351 oss << flush;
5352
5353 return String(oss);
5354 }
5355
5356 return "";
5357}
5358
5359std::string Scantable::formatBaselineParamsFooter(float rms, int nClipped, bool verbose, bool csvformat) const
5360{
5361 if (verbose) {
5362 ostringstream oss;
5363
5364 if (csvformat) {
5365 oss << rms << ",";
5366 if (nClipped >= 0) {
5367 oss << nClipped;
5368 }
5369 } else {
5370 oss << "Results of baseline fit" << endl;
5371 oss << " rms = " << setprecision(6) << rms << endl;
5372 if (nClipped >= 0) {
5373 oss << " Number of clipped channels = " << nClipped << endl;
5374 }
5375 for (int i = 0; i < 60; ++i) {
5376 oss << "-";
5377 }
5378 }
5379 oss << endl;
5380 oss << flush;
5381
5382 return String(oss);
5383 }
5384
5385 return "";
5386}
5387
5388std::string Scantable::formatBaselineParams(const std::vector<float>& params,
5389 const std::vector<bool>& fixed,
5390 float rms,
5391 int nClipped,
5392 const std::string& masklist,
5393 int whichrow,
5394 bool verbose,
5395 bool csvformat,
5396 int start, int count,
5397 bool resetparamid) const
5398{
5399 int nParam = (int)(params.size());
5400
5401 if (nParam < 1) {
5402 return(" Not fitted");
5403 } else {
5404
5405 ostringstream oss;
5406 oss << formatBaselineParamsHeader(whichrow, masklist, verbose, csvformat);
5407
5408 if (start < 0) start = 0;
5409 if (count < 0) count = nParam;
5410 int end = start + count;
5411 if (end > nParam) end = nParam;
5412 int paramidoffset = (resetparamid) ? (-start) : 0;
5413
5414 for (int i = start; i < end; ++i) {
5415 if (i > start) {
5416 oss << ",";
5417 }
5418 std::string sFix = ((fixed.size() > 0) && (fixed[i]) && verbose) ? "(fixed)" : "";
5419 if (csvformat) {
5420 oss << params[i] << sFix;
5421 } else {
5422 oss << " p" << (i+paramidoffset) << sFix << "= " << right << setw(13) << setprecision(6) << params[i];
5423 }
5424 }
5425
5426 if (csvformat) {
5427 oss << ",";
5428 } else {
5429 oss << endl;
5430 }
5431 oss << formatBaselineParamsFooter(rms, nClipped, verbose, csvformat);
5432
5433 return String(oss);
5434 }
5435
5436}
5437
5438std::string Scantable::formatPiecewiseBaselineParams(const std::vector<int>& ranges, const std::vector<float>& params, const std::vector<bool>& fixed, float rms, int nClipped, const std::string& masklist, int whichrow, bool verbose, bool csvformat) const
5439{
5440 int nOutParam = (int)(params.size());
5441 int nPiece = (int)(ranges.size()) - 1;
5442
5443 if (nOutParam < 1) {
5444 return(" Not fitted");
5445 } else if (nPiece < 0) {
5446 return formatBaselineParams(params, fixed, rms, nClipped, masklist, whichrow, verbose, csvformat);
5447 } else if (nPiece < 1) {
5448 return(" Bad count of the piece edge info");
5449 } else if (nOutParam % nPiece != 0) {
5450 return(" Bad count of the output baseline parameters");
5451 } else {
5452
5453 int nParam = nOutParam / nPiece;
5454
5455 ostringstream oss;
5456 oss << formatBaselineParamsHeader(whichrow, masklist, verbose, csvformat);
5457
5458 if (csvformat) {
5459 for (int i = 0; i < nPiece; ++i) {
5460 oss << ranges[i] << "," << (ranges[i+1]-1) << ",";
5461 oss << formatBaselineParams(params, fixed, rms, 0, masklist, whichrow, false, csvformat, i*nParam, nParam, true);
5462 }
5463 } else {
5464 stringstream ss;
5465 ss << ranges[nPiece] << flush;
5466 int wRange = ss.str().size() * 2 + 5;
5467
5468 for (int i = 0; i < nPiece; ++i) {
5469 ss.str("");
5470 ss << " [" << ranges[i] << "," << (ranges[i+1]-1) << "]";
5471 oss << left << setw(wRange) << ss.str();
5472 oss << formatBaselineParams(params, fixed, rms, 0, masklist, whichrow, false, csvformat, i*nParam, nParam, true);
5473 //oss << endl;
5474 }
5475 }
5476
5477 oss << formatBaselineParamsFooter(rms, nClipped, verbose, csvformat);
5478
5479 return String(oss);
5480 }
5481
5482}
5483
5484bool Scantable::hasSameNchanOverIFs()
5485{
5486 int nIF = nif(-1);
5487 int nCh;
5488 int totalPositiveNChan = 0;
5489 int nPositiveNChan = 0;
5490
5491 for (int i = 0; i < nIF; ++i) {
5492 nCh = nchan(i);
5493 if (nCh > 0) {
5494 totalPositiveNChan += nCh;
5495 nPositiveNChan++;
5496 }
5497 }
5498
5499 return (totalPositiveNChan == (nPositiveNChan * nchan(0)));
5500}
5501
5502std::string Scantable::getMaskRangeList(const std::vector<bool>& mask, int whichrow, const casa::String& coordInfo, bool hasSameNchan, bool verbose)
5503{
5504 if (mask.size() <= 0) {
5505 throw(AipsError("The mask elements should be > 0"));
5506 }
5507 int IF = getIF(whichrow);
5508 if (mask.size() != (uInt)nchan(IF)) {
5509 throw(AipsError("Number of channels in scantable != number of mask elements"));
5510 }
5511
5512 if (verbose) {
5513 LogIO logOs(LogOrigin("Scantable", "getMaskRangeList()", WHERE));
5514 logOs << LogIO::WARN << "The current mask window unit is " << coordInfo;
5515 if (!hasSameNchan) {
5516 logOs << endl << "This mask is only valid for IF=" << IF;
5517 }
5518 logOs << LogIO::POST;
5519 }
5520
5521 std::vector<double> abcissa = getAbcissa(whichrow);
5522 std::vector<int> edge = getMaskEdgeIndices(mask);
5523
5524 ostringstream oss;
5525 oss.setf(ios::fixed);
5526 oss << setprecision(1) << "[";
5527 for (uInt i = 0; i < edge.size(); i+=2) {
5528 if (i > 0) oss << ",";
5529 oss << "[" << (float)abcissa[edge[i]] << "," << (float)abcissa[edge[i+1]] << "]";
5530 }
5531 oss << "]" << flush;
5532
5533 return String(oss);
5534}
5535
5536std::vector<int> Scantable::getMaskEdgeIndices(const std::vector<bool>& mask)
5537{
5538 if (mask.size() <= 0) {
5539 throw(AipsError("The mask elements should be > 0"));
5540 }
5541
5542 std::vector<int> out, startIndices, endIndices;
5543 int maskSize = mask.size();
5544
5545 startIndices.clear();
5546 endIndices.clear();
5547
5548 if (mask[0]) {
5549 startIndices.push_back(0);
5550 }
5551 for (int i = 1; i < maskSize; ++i) {
5552 if ((!mask[i-1]) && mask[i]) {
5553 startIndices.push_back(i);
5554 } else if (mask[i-1] && (!mask[i])) {
5555 endIndices.push_back(i-1);
5556 }
5557 }
5558 if (mask[maskSize-1]) {
5559 endIndices.push_back(maskSize-1);
5560 }
5561
5562 if (startIndices.size() != endIndices.size()) {
5563 throw(AipsError("Inconsistent Mask Size: bad data?"));
5564 }
5565 for (uInt i = 0; i < startIndices.size(); ++i) {
5566 if (startIndices[i] > endIndices[i]) {
5567 throw(AipsError("Mask start index > mask end index"));
5568 }
5569 }
5570
5571 out.clear();
5572 for (uInt i = 0; i < startIndices.size(); ++i) {
5573 out.push_back(startIndices[i]);
5574 out.push_back(endIndices[i]);
5575 }
5576
5577 return out;
5578}
5579
5580void Scantable::setTsys(const std::vector<float>& newvals, int whichrow) {
5581 Vector<Float> tsys(newvals);
5582 if (whichrow > -1) {
5583 if (tsysCol_.shape(whichrow) != tsys.shape())
5584 throw(AipsError("Given Tsys values are not of the same shape"));
5585 tsysCol_.put(whichrow, tsys);
5586 } else {
5587 tsysCol_.fillColumn(tsys);
5588 }
5589}
5590
5591vector<float> Scantable::getTsysSpectrum( int whichrow ) const
5592{
5593 Vector<Float> tsys( tsysCol_(whichrow) ) ;
5594 vector<float> stlTsys ;
5595 tsys.tovector( stlTsys ) ;
5596 return stlTsys ;
5597}
5598
5599vector<uint> Scantable::getMoleculeIdColumnData() const
5600{
5601 Vector<uInt> molIds(mmolidCol_.getColumn());
5602 vector<uint> res;
5603 molIds.tovector(res);
5604 return res;
5605}
5606
5607void Scantable::setMoleculeIdColumnData(const std::vector<uint>& molids)
5608{
5609 Vector<uInt> molIds(molids);
5610 Vector<uInt> arr(mmolidCol_.getColumn());
5611 if ( molIds.nelements() != arr.nelements() )
5612 throw AipsError("The input data size must be the number of rows.");
5613 mmolidCol_.putColumn(molIds);
5614}
5615
5616
5617std::vector<uint> Scantable::getRootTableRowNumbers() const
5618{
5619 Vector<uInt> rowIds(table_.rowNumbers());
5620 vector<uint> res;
5621 rowIds.tovector(res);
5622 return res;
5623}
5624
5625
5626void Scantable::dropXPol()
5627{
5628 if (npol() <= 2) {
5629 return;
5630 }
5631 if (!selector_.empty()) {
5632 throw AipsError("Can only operate with empty selection");
5633 }
5634 std::string taql = "SELECT FROM $1 WHERE POLNO IN [0,1]";
5635 Table tab = tableCommand(taql, table_);
5636 table_ = tab;
5637 table_.rwKeywordSet().define("nPol", Int(2));
5638 originalTable_ = table_;
5639 attach();
5640}
5641
5642}
5643//namespace asap
Note: See TracBrowser for help on using the repository browser.