source: trunk/src/Scantable.cpp@ 2345

Last change on this file since 2345 was 2344, checked in by WataruKawasaki, 13 years ago

New Development: No

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): xmlcasa

Description: The cubic spline fitting was returning zero values both for the fitted results and the residual within masked regions touching the edge of the given spetrum. For such masked regions, the value of the fitted result at the nearest unmasked channel is now adopted, and residual is correctly computed also.


  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 109.6 KB
Line 
1//
2// C++ Implementation: Scantable
3//
4// Description:
5//
6//
7// Author: Malte Marquarding <asap@atnf.csiro.au>, (C) 2005
8//
9// Copyright: See COPYING file that comes with this distribution
10//
11//
12#include <map>
13#include <mcheck.h>
14
15#include <atnf/PKSIO/SrcType.h>
16
17#include <casa/aips.h>
18#include <casa/iomanip.h>
19#include <casa/iostream.h>
20#include <casa/OS/File.h>
21#include <casa/OS/Path.h>
22#include <casa/Arrays/Array.h>
23#include <casa/Arrays/ArrayAccessor.h>
24#include <casa/Arrays/ArrayLogical.h>
25#include <casa/Arrays/ArrayMath.h>
26#include <casa/Arrays/MaskArrMath.h>
27#include <casa/Arrays/Slice.h>
28#include <casa/Arrays/Vector.h>
29#include <casa/Arrays/VectorSTLIterator.h>
30#include <casa/BasicMath/Math.h>
31#include <casa/BasicSL/Constants.h>
32#include <casa/Containers/RecordField.h>
33#include <casa/Logging/LogIO.h>
34#include <casa/Quanta/MVAngle.h>
35#include <casa/Quanta/MVTime.h>
36#include <casa/Utilities/GenSort.h>
37
38#include <coordinates/Coordinates/CoordinateUtil.h>
39
40// needed to avoid error in .tcc
41#include <measures/Measures/MCDirection.h>
42//
43#include <measures/Measures/MDirection.h>
44#include <measures/Measures/MEpoch.h>
45#include <measures/Measures/MFrequency.h>
46#include <measures/Measures/MeasRef.h>
47#include <measures/Measures/MeasTable.h>
48#include <measures/TableMeasures/ScalarMeasColumn.h>
49#include <measures/TableMeasures/TableMeasDesc.h>
50#include <measures/TableMeasures/TableMeasRefDesc.h>
51#include <measures/TableMeasures/TableMeasValueDesc.h>
52
53#include <tables/Tables/ArrColDesc.h>
54#include <tables/Tables/ExprNode.h>
55#include <tables/Tables/ScaColDesc.h>
56#include <tables/Tables/SetupNewTab.h>
57#include <tables/Tables/TableCopy.h>
58#include <tables/Tables/TableDesc.h>
59#include <tables/Tables/TableIter.h>
60#include <tables/Tables/TableParse.h>
61#include <tables/Tables/TableRecord.h>
62#include <tables/Tables/TableRow.h>
63#include <tables/Tables/TableVector.h>
64
65#include "MathUtils.h"
66#include "STAttr.h"
67#include "STLineFinder.h"
68#include "STPolCircular.h"
69#include "STPolLinear.h"
70#include "STPolStokes.h"
71#include "STUpgrade.h"
72#include "Scantable.h"
73
74using namespace casa;
75
76namespace asap {
77
78std::map<std::string, STPol::STPolFactory *> Scantable::factories_;
79
80void Scantable::initFactories() {
81 if ( factories_.empty() ) {
82 Scantable::factories_["linear"] = &STPolLinear::myFactory;
83 Scantable::factories_["circular"] = &STPolCircular::myFactory;
84 Scantable::factories_["stokes"] = &STPolStokes::myFactory;
85 }
86}
87
88Scantable::Scantable(Table::TableType ttype) :
89 type_(ttype)
90{
91 initFactories();
92 setupMainTable();
93 freqTable_ = new STFrequencies(*this);
94 table_.rwKeywordSet().defineTable("FREQUENCIES", freqTable_->table());
95 weatherTable_ = STWeather(*this);
96 table_.rwKeywordSet().defineTable("WEATHER", weatherTable_.table());
97 focusTable_ = STFocus(*this);
98 table_.rwKeywordSet().defineTable("FOCUS", focusTable_.table());
99 tcalTable_ = STTcal(*this);
100 table_.rwKeywordSet().defineTable("TCAL", tcalTable_.table());
101 moleculeTable_ = STMolecules(*this);
102 table_.rwKeywordSet().defineTable("MOLECULES", moleculeTable_.table());
103 historyTable_ = STHistory(*this);
104 table_.rwKeywordSet().defineTable("HISTORY", historyTable_.table());
105 fitTable_ = STFit(*this);
106 table_.rwKeywordSet().defineTable("FIT", fitTable_.table());
107 table_.tableInfo().setType( "Scantable" ) ;
108 originalTable_ = table_;
109 attach();
110}
111
112Scantable::Scantable(const std::string& name, Table::TableType ttype) :
113 type_(ttype)
114{
115 initFactories();
116
117 Table tab(name, Table::Update);
118 uInt version = tab.keywordSet().asuInt("VERSION");
119 if (version != version_) {
120 STUpgrade upgrader(version_);
121 LogIO os( LogOrigin( "Scantable" ) ) ;
122 os << LogIO::WARN
123 << name << " data format version " << version
124 << " is deprecated" << endl
125 << "Running upgrade."<< endl
126 << LogIO::POST ;
127 std::string outname = upgrader.upgrade(name);
128 if ( outname != name ) {
129 os << LogIO::WARN
130 << "Data will be loaded from " << outname << " instead of "
131 << name << LogIO::POST ;
132 tab = Table(outname, Table::Update ) ;
133 }
134 }
135 if ( type_ == Table::Memory ) {
136 table_ = tab.copyToMemoryTable(generateName());
137 } else {
138 table_ = tab;
139 }
140 table_.tableInfo().setType( "Scantable" ) ;
141
142 attachSubtables();
143 originalTable_ = table_;
144 attach();
145}
146/*
147Scantable::Scantable(const std::string& name, Table::TableType ttype) :
148 type_(ttype)
149{
150 initFactories();
151 Table tab(name, Table::Update);
152 uInt version = tab.keywordSet().asuInt("VERSION");
153 if (version != version_) {
154 throw(AipsError("Unsupported version of ASAP file."));
155 }
156 if ( type_ == Table::Memory ) {
157 table_ = tab.copyToMemoryTable(generateName());
158 } else {
159 table_ = tab;
160 }
161
162 attachSubtables();
163 originalTable_ = table_;
164 attach();
165}
166*/
167
168Scantable::Scantable( const Scantable& other, bool clear ):
169 Logger()
170{
171 // with or without data
172 String newname = String(generateName());
173 type_ = other.table_.tableType();
174 if ( other.table_.tableType() == Table::Memory ) {
175 if ( clear ) {
176 table_ = TableCopy::makeEmptyMemoryTable(newname,
177 other.table_, True);
178 } else
179 table_ = other.table_.copyToMemoryTable(newname);
180 } else {
181 other.table_.deepCopy(newname, Table::New, False,
182 other.table_.endianFormat(),
183 Bool(clear));
184 table_ = Table(newname, Table::Update);
185 table_.markForDelete();
186 }
187 table_.tableInfo().setType( "Scantable" ) ;
188 /// @todo reindex SCANNO, recompute nbeam, nif, npol
189 if ( clear ) copySubtables(other);
190 attachSubtables();
191 originalTable_ = table_;
192 attach();
193}
194
195void Scantable::copySubtables(const Scantable& other) {
196 Table t = table_.rwKeywordSet().asTable("FREQUENCIES");
197 TableCopy::copyRows(t, other.freqTable_->table());
198 t = table_.rwKeywordSet().asTable("FOCUS");
199 TableCopy::copyRows(t, other.focusTable_.table());
200 t = table_.rwKeywordSet().asTable("WEATHER");
201 TableCopy::copyRows(t, other.weatherTable_.table());
202 t = table_.rwKeywordSet().asTable("TCAL");
203 TableCopy::copyRows(t, other.tcalTable_.table());
204 t = table_.rwKeywordSet().asTable("MOLECULES");
205 TableCopy::copyRows(t, other.moleculeTable_.table());
206 t = table_.rwKeywordSet().asTable("HISTORY");
207 TableCopy::copyRows(t, other.historyTable_.table());
208 t = table_.rwKeywordSet().asTable("FIT");
209 TableCopy::copyRows(t, other.fitTable_.table());
210}
211
212void Scantable::attachSubtables()
213{
214 freqTable_ = new STFrequencies(table_);
215 focusTable_ = STFocus(table_);
216 weatherTable_ = STWeather(table_);
217 tcalTable_ = STTcal(table_);
218 moleculeTable_ = STMolecules(table_);
219 historyTable_ = STHistory(table_);
220 fitTable_ = STFit(table_);
221}
222
223Scantable::~Scantable()
224{
225 delete freqTable_;
226}
227
228void Scantable::setupMainTable()
229{
230 TableDesc td("", "1", TableDesc::Scratch);
231 td.comment() = "An ASAP Scantable";
232 td.rwKeywordSet().define("VERSION", uInt(version_));
233
234 // n Cycles
235 td.addColumn(ScalarColumnDesc<uInt>("SCANNO"));
236 // new index every nBeam x nIF x nPol
237 td.addColumn(ScalarColumnDesc<uInt>("CYCLENO"));
238
239 td.addColumn(ScalarColumnDesc<uInt>("BEAMNO"));
240 td.addColumn(ScalarColumnDesc<uInt>("IFNO"));
241 // linear, circular, stokes
242 td.rwKeywordSet().define("POLTYPE", String("linear"));
243 td.addColumn(ScalarColumnDesc<uInt>("POLNO"));
244
245 td.addColumn(ScalarColumnDesc<uInt>("FREQ_ID"));
246 td.addColumn(ScalarColumnDesc<uInt>("MOLECULE_ID"));
247
248 ScalarColumnDesc<Int> refbeamnoColumn("REFBEAMNO");
249 refbeamnoColumn.setDefault(Int(-1));
250 td.addColumn(refbeamnoColumn);
251
252 ScalarColumnDesc<uInt> flagrowColumn("FLAGROW");
253 flagrowColumn.setDefault(uInt(0));
254 td.addColumn(flagrowColumn);
255
256 td.addColumn(ScalarColumnDesc<Double>("TIME"));
257 TableMeasRefDesc measRef(MEpoch::UTC); // UTC as default
258 TableMeasValueDesc measVal(td, "TIME");
259 TableMeasDesc<MEpoch> mepochCol(measVal, measRef);
260 mepochCol.write(td);
261
262 td.addColumn(ScalarColumnDesc<Double>("INTERVAL"));
263
264 td.addColumn(ScalarColumnDesc<String>("SRCNAME"));
265 // Type of source (on=0, off=1, other=-1)
266 ScalarColumnDesc<Int> stypeColumn("SRCTYPE");
267 stypeColumn.setDefault(Int(-1));
268 td.addColumn(stypeColumn);
269 td.addColumn(ScalarColumnDesc<String>("FIELDNAME"));
270
271 //The actual Data Vectors
272 td.addColumn(ArrayColumnDesc<Float>("SPECTRA"));
273 td.addColumn(ArrayColumnDesc<uChar>("FLAGTRA"));
274 td.addColumn(ArrayColumnDesc<Float>("TSYS"));
275
276 td.addColumn(ArrayColumnDesc<Double>("DIRECTION",
277 IPosition(1,2),
278 ColumnDesc::Direct));
279 TableMeasRefDesc mdirRef(MDirection::J2000); // default
280 TableMeasValueDesc tmvdMDir(td, "DIRECTION");
281 // the TableMeasDesc gives the column a type
282 TableMeasDesc<MDirection> mdirCol(tmvdMDir, mdirRef);
283 // a uder set table type e.g. GALCTIC, B1950 ...
284 td.rwKeywordSet().define("DIRECTIONREF", String("J2000"));
285 // writing create the measure column
286 mdirCol.write(td);
287 td.addColumn(ScalarColumnDesc<Float>("AZIMUTH"));
288 td.addColumn(ScalarColumnDesc<Float>("ELEVATION"));
289 td.addColumn(ScalarColumnDesc<Float>("OPACITY"));
290
291 td.addColumn(ScalarColumnDesc<uInt>("TCAL_ID"));
292 ScalarColumnDesc<Int> fitColumn("FIT_ID");
293 fitColumn.setDefault(Int(-1));
294 td.addColumn(fitColumn);
295
296 td.addColumn(ScalarColumnDesc<uInt>("FOCUS_ID"));
297 td.addColumn(ScalarColumnDesc<uInt>("WEATHER_ID"));
298
299 // columns which just get dragged along, as they aren't used in asap
300 td.addColumn(ScalarColumnDesc<Double>("SRCVELOCITY"));
301 td.addColumn(ArrayColumnDesc<Double>("SRCPROPERMOTION"));
302 td.addColumn(ArrayColumnDesc<Double>("SRCDIRECTION"));
303 td.addColumn(ArrayColumnDesc<Double>("SCANRATE"));
304
305 td.rwKeywordSet().define("OBSMODE", String(""));
306
307 // Now create Table SetUp from the description.
308 SetupNewTable aNewTab(generateName(), td, Table::Scratch);
309 table_ = Table(aNewTab, type_, 0);
310 originalTable_ = table_;
311}
312
313void Scantable::attach()
314{
315 timeCol_.attach(table_, "TIME");
316 srcnCol_.attach(table_, "SRCNAME");
317 srctCol_.attach(table_, "SRCTYPE");
318 specCol_.attach(table_, "SPECTRA");
319 flagsCol_.attach(table_, "FLAGTRA");
320 tsysCol_.attach(table_, "TSYS");
321 cycleCol_.attach(table_,"CYCLENO");
322 scanCol_.attach(table_, "SCANNO");
323 beamCol_.attach(table_, "BEAMNO");
324 ifCol_.attach(table_, "IFNO");
325 polCol_.attach(table_, "POLNO");
326 integrCol_.attach(table_, "INTERVAL");
327 azCol_.attach(table_, "AZIMUTH");
328 elCol_.attach(table_, "ELEVATION");
329 dirCol_.attach(table_, "DIRECTION");
330 fldnCol_.attach(table_, "FIELDNAME");
331 rbeamCol_.attach(table_, "REFBEAMNO");
332
333 mweatheridCol_.attach(table_,"WEATHER_ID");
334 mfitidCol_.attach(table_,"FIT_ID");
335 mfreqidCol_.attach(table_, "FREQ_ID");
336 mtcalidCol_.attach(table_, "TCAL_ID");
337 mfocusidCol_.attach(table_, "FOCUS_ID");
338 mmolidCol_.attach(table_, "MOLECULE_ID");
339
340 //Add auxiliary column for row-based flagging (CAS-1433 Wataru Kawasaki)
341 attachAuxColumnDef(flagrowCol_, "FLAGROW", 0);
342
343}
344
345template<class T, class T2>
346void Scantable::attachAuxColumnDef(ScalarColumn<T>& col,
347 const String& colName,
348 const T2& defValue)
349{
350 try {
351 col.attach(table_, colName);
352 } catch (TableError& err) {
353 String errMesg = err.getMesg();
354 if (errMesg == "Table column " + colName + " is unknown") {
355 table_.addColumn(ScalarColumnDesc<T>(colName));
356 col.attach(table_, colName);
357 col.fillColumn(static_cast<T>(defValue));
358 } else {
359 throw;
360 }
361 } catch (...) {
362 throw;
363 }
364}
365
366template<class T, class T2>
367void Scantable::attachAuxColumnDef(ArrayColumn<T>& col,
368 const String& colName,
369 const Array<T2>& defValue)
370{
371 try {
372 col.attach(table_, colName);
373 } catch (TableError& err) {
374 String errMesg = err.getMesg();
375 if (errMesg == "Table column " + colName + " is unknown") {
376 table_.addColumn(ArrayColumnDesc<T>(colName));
377 col.attach(table_, colName);
378
379 int size = 0;
380 ArrayIterator<T2>& it = defValue.begin();
381 while (it != defValue.end()) {
382 ++size;
383 ++it;
384 }
385 IPosition ip(1, size);
386 Array<T>& arr(ip);
387 for (int i = 0; i < size; ++i)
388 arr[i] = static_cast<T>(defValue[i]);
389
390 col.fillColumn(arr);
391 } else {
392 throw;
393 }
394 } catch (...) {
395 throw;
396 }
397}
398
399void Scantable::setHeader(const STHeader& sdh)
400{
401 table_.rwKeywordSet().define("nIF", sdh.nif);
402 table_.rwKeywordSet().define("nBeam", sdh.nbeam);
403 table_.rwKeywordSet().define("nPol", sdh.npol);
404 table_.rwKeywordSet().define("nChan", sdh.nchan);
405 table_.rwKeywordSet().define("Observer", sdh.observer);
406 table_.rwKeywordSet().define("Project", sdh.project);
407 table_.rwKeywordSet().define("Obstype", sdh.obstype);
408 table_.rwKeywordSet().define("AntennaName", sdh.antennaname);
409 table_.rwKeywordSet().define("AntennaPosition", sdh.antennaposition);
410 table_.rwKeywordSet().define("Equinox", sdh.equinox);
411 table_.rwKeywordSet().define("FreqRefFrame", sdh.freqref);
412 table_.rwKeywordSet().define("FreqRefVal", sdh.reffreq);
413 table_.rwKeywordSet().define("Bandwidth", sdh.bandwidth);
414 table_.rwKeywordSet().define("UTC", sdh.utc);
415 table_.rwKeywordSet().define("FluxUnit", sdh.fluxunit);
416 table_.rwKeywordSet().define("Epoch", sdh.epoch);
417 table_.rwKeywordSet().define("POLTYPE", sdh.poltype);
418}
419
420STHeader Scantable::getHeader() const
421{
422 STHeader sdh;
423 table_.keywordSet().get("nBeam",sdh.nbeam);
424 table_.keywordSet().get("nIF",sdh.nif);
425 table_.keywordSet().get("nPol",sdh.npol);
426 table_.keywordSet().get("nChan",sdh.nchan);
427 table_.keywordSet().get("Observer", sdh.observer);
428 table_.keywordSet().get("Project", sdh.project);
429 table_.keywordSet().get("Obstype", sdh.obstype);
430 table_.keywordSet().get("AntennaName", sdh.antennaname);
431 table_.keywordSet().get("AntennaPosition", sdh.antennaposition);
432 table_.keywordSet().get("Equinox", sdh.equinox);
433 table_.keywordSet().get("FreqRefFrame", sdh.freqref);
434 table_.keywordSet().get("FreqRefVal", sdh.reffreq);
435 table_.keywordSet().get("Bandwidth", sdh.bandwidth);
436 table_.keywordSet().get("UTC", sdh.utc);
437 table_.keywordSet().get("FluxUnit", sdh.fluxunit);
438 table_.keywordSet().get("Epoch", sdh.epoch);
439 table_.keywordSet().get("POLTYPE", sdh.poltype);
440 return sdh;
441}
442
443void Scantable::setSourceType( int stype )
444{
445 if ( stype < 0 || stype > 1 )
446 throw(AipsError("Illegal sourcetype."));
447 TableVector<Int> tabvec(table_, "SRCTYPE");
448 tabvec = Int(stype);
449}
450
451bool Scantable::conformant( const Scantable& other )
452{
453 return this->getHeader().conformant(other.getHeader());
454}
455
456
457
458std::string Scantable::formatSec(Double x) const
459{
460 Double xcop = x;
461 MVTime mvt(xcop/24./3600.); // make days
462
463 if (x < 59.95)
464 return String(" ") + mvt.string(MVTime::TIME_CLEAN_NO_HM, 7)+"s";
465 else if (x < 3599.95)
466 return String(" ") + mvt.string(MVTime::TIME_CLEAN_NO_H,7)+" ";
467 else {
468 ostringstream oss;
469 oss << setw(2) << std::right << setprecision(1) << mvt.hour();
470 oss << ":" << mvt.string(MVTime::TIME_CLEAN_NO_H,7) << " ";
471 return String(oss);
472 }
473};
474
475std::string Scantable::formatDirection(const MDirection& md) const
476{
477 Vector<Double> t = md.getAngle(Unit(String("rad"))).getValue();
478 Int prec = 7;
479
480 MVAngle mvLon(t[0]);
481 String sLon = mvLon.string(MVAngle::TIME,prec);
482 uInt tp = md.getRef().getType();
483 if (tp == MDirection::GALACTIC ||
484 tp == MDirection::SUPERGAL ) {
485 sLon = mvLon(0.0).string(MVAngle::ANGLE_CLEAN,prec);
486 }
487 MVAngle mvLat(t[1]);
488 String sLat = mvLat.string(MVAngle::ANGLE+MVAngle::DIG2,prec);
489 return sLon + String(" ") + sLat;
490}
491
492
493std::string Scantable::getFluxUnit() const
494{
495 return table_.keywordSet().asString("FluxUnit");
496}
497
498void Scantable::setFluxUnit(const std::string& unit)
499{
500 String tmp(unit);
501 Unit tU(tmp);
502 if (tU==Unit("K") || tU==Unit("Jy")) {
503 table_.rwKeywordSet().define(String("FluxUnit"), tmp);
504 } else {
505 throw AipsError("Illegal unit - must be compatible with Jy or K");
506 }
507}
508
509void Scantable::setInstrument(const std::string& name)
510{
511 bool throwIt = true;
512 // create an Instrument to see if this is valid
513 STAttr::convertInstrument(name, throwIt);
514 String nameU(name);
515 nameU.upcase();
516 table_.rwKeywordSet().define(String("AntennaName"), nameU);
517}
518
519void Scantable::setFeedType(const std::string& feedtype)
520{
521 if ( Scantable::factories_.find(feedtype) == Scantable::factories_.end() ) {
522 std::string msg = "Illegal feed type "+ feedtype;
523 throw(casa::AipsError(msg));
524 }
525 table_.rwKeywordSet().define(String("POLTYPE"), feedtype);
526}
527
528MPosition Scantable::getAntennaPosition() const
529{
530 Vector<Double> antpos;
531 table_.keywordSet().get("AntennaPosition", antpos);
532 MVPosition mvpos(antpos(0),antpos(1),antpos(2));
533 return MPosition(mvpos);
534}
535
536void Scantable::makePersistent(const std::string& filename)
537{
538 String inname(filename);
539 Path path(inname);
540 /// @todo reindex SCANNO, recompute nbeam, nif, npol
541 inname = path.expandedName();
542 // 2011/03/04 TN
543 // We can comment out this workaround since the essential bug is
544 // fixed in casacore (r20889 in google code).
545 table_.deepCopy(inname, Table::New);
546// // WORKAROUND !!! for Table bug
547// // Remove when fixed in casacore
548// if ( table_.tableType() == Table::Memory && !selector_.empty() ) {
549// Table tab = table_.copyToMemoryTable(generateName());
550// tab.deepCopy(inname, Table::New);
551// tab.markForDelete();
552//
553// } else {
554// table_.deepCopy(inname, Table::New);
555// }
556}
557
558int Scantable::nbeam( int scanno ) const
559{
560 if ( scanno < 0 ) {
561 Int n;
562 table_.keywordSet().get("nBeam",n);
563 return int(n);
564 } else {
565 // take the first POLNO,IFNO,CYCLENO as nbeam shouldn't vary with these
566 Table t = table_(table_.col("SCANNO") == scanno);
567 ROTableRow row(t);
568 const TableRecord& rec = row.get(0);
569 Table subt = t( t.col("IFNO") == Int(rec.asuInt("IFNO"))
570 && t.col("POLNO") == Int(rec.asuInt("POLNO"))
571 && t.col("CYCLENO") == Int(rec.asuInt("CYCLENO")) );
572 ROTableVector<uInt> v(subt, "BEAMNO");
573 return int(v.nelements());
574 }
575 return 0;
576}
577
578int Scantable::nif( int scanno ) const
579{
580 if ( scanno < 0 ) {
581 Int n;
582 table_.keywordSet().get("nIF",n);
583 return int(n);
584 } else {
585 // take the first POLNO,BEAMNO,CYCLENO as nbeam shouldn't vary with these
586 Table t = table_(table_.col("SCANNO") == scanno);
587 ROTableRow row(t);
588 const TableRecord& rec = row.get(0);
589 Table subt = t( t.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
590 && t.col("POLNO") == Int(rec.asuInt("POLNO"))
591 && t.col("CYCLENO") == Int(rec.asuInt("CYCLENO")) );
592 if ( subt.nrow() == 0 ) return 0;
593 ROTableVector<uInt> v(subt, "IFNO");
594 return int(v.nelements());
595 }
596 return 0;
597}
598
599int Scantable::npol( int scanno ) const
600{
601 if ( scanno < 0 ) {
602 Int n;
603 table_.keywordSet().get("nPol",n);
604 return n;
605 } else {
606 // take the first POLNO,IFNO,CYCLENO as nbeam shouldn't vary with these
607 Table t = table_(table_.col("SCANNO") == scanno);
608 ROTableRow row(t);
609 const TableRecord& rec = row.get(0);
610 Table subt = t( t.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
611 && t.col("IFNO") == Int(rec.asuInt("IFNO"))
612 && t.col("CYCLENO") == Int(rec.asuInt("CYCLENO")) );
613 if ( subt.nrow() == 0 ) return 0;
614 ROTableVector<uInt> v(subt, "POLNO");
615 return int(v.nelements());
616 }
617 return 0;
618}
619
620int Scantable::ncycle( int scanno ) const
621{
622 if ( scanno < 0 ) {
623 Block<String> cols(2);
624 cols[0] = "SCANNO";
625 cols[1] = "CYCLENO";
626 TableIterator it(table_, cols);
627 int n = 0;
628 while ( !it.pastEnd() ) {
629 ++n;
630 ++it;
631 }
632 return n;
633 } else {
634 Table t = table_(table_.col("SCANNO") == scanno);
635 ROTableRow row(t);
636 const TableRecord& rec = row.get(0);
637 Table subt = t( t.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
638 && t.col("POLNO") == Int(rec.asuInt("POLNO"))
639 && t.col("IFNO") == Int(rec.asuInt("IFNO")) );
640 if ( subt.nrow() == 0 ) return 0;
641 return int(subt.nrow());
642 }
643 return 0;
644}
645
646
647int Scantable::nrow( int scanno ) const
648{
649 return int(table_.nrow());
650}
651
652int Scantable::nchan( int ifno ) const
653{
654 if ( ifno < 0 ) {
655 Int n;
656 table_.keywordSet().get("nChan",n);
657 return int(n);
658 } else {
659 // take the first SCANNO,POLNO,BEAMNO,CYCLENO as nbeam shouldn't
660 // vary with these
661 Table t = table_(table_.col("IFNO") == ifno, 1);
662 if ( t.nrow() == 0 ) return 0;
663 ROArrayColumn<Float> v(t, "SPECTRA");
664 return v.shape(0)(0);
665 }
666 return 0;
667}
668
669int Scantable::nscan() const {
670 Vector<uInt> scannos(scanCol_.getColumn());
671 uInt nout = genSort( scannos, Sort::Ascending,
672 Sort::QuickSort|Sort::NoDuplicates );
673 return int(nout);
674}
675
676int Scantable::getChannels(int whichrow) const
677{
678 return specCol_.shape(whichrow)(0);
679}
680
681int Scantable::getBeam(int whichrow) const
682{
683 return beamCol_(whichrow);
684}
685
686std::vector<uint> Scantable::getNumbers(const ScalarColumn<uInt>& col) const
687{
688 Vector<uInt> nos(col.getColumn());
689 uInt n = genSort( nos, Sort::Ascending, Sort::QuickSort|Sort::NoDuplicates );
690 nos.resize(n, True);
691 std::vector<uint> stlout;
692 nos.tovector(stlout);
693 return stlout;
694}
695
696int Scantable::getIF(int whichrow) const
697{
698 return ifCol_(whichrow);
699}
700
701int Scantable::getPol(int whichrow) const
702{
703 return polCol_(whichrow);
704}
705
706std::string Scantable::formatTime(const MEpoch& me, bool showdate) const
707{
708 return formatTime(me, showdate, 0);
709}
710
711std::string Scantable::formatTime(const MEpoch& me, bool showdate, uInt prec) const
712{
713 MVTime mvt(me.getValue());
714 if (showdate)
715 //mvt.setFormat(MVTime::YMD);
716 mvt.setFormat(MVTime::YMD, prec);
717 else
718 //mvt.setFormat(MVTime::TIME);
719 mvt.setFormat(MVTime::TIME, prec);
720 ostringstream oss;
721 oss << mvt;
722 return String(oss);
723}
724
725void Scantable::calculateAZEL()
726{
727 MPosition mp = getAntennaPosition();
728 MEpoch::ROScalarColumn timeCol(table_, "TIME");
729 ostringstream oss;
730 oss << "Computed azimuth/elevation using " << endl
731 << mp << endl;
732 for (Int i=0; i<nrow(); ++i) {
733 MEpoch me = timeCol(i);
734 MDirection md = getDirection(i);
735 oss << " Time: " << formatTime(me,False) << " Direction: " << formatDirection(md)
736 << endl << " => ";
737 MeasFrame frame(mp, me);
738 Vector<Double> azel =
739 MDirection::Convert(md, MDirection::Ref(MDirection::AZEL,
740 frame)
741 )().getAngle("rad").getValue();
742 azCol_.put(i,Float(azel[0]));
743 elCol_.put(i,Float(azel[1]));
744 oss << "azel: " << azel[0]/C::pi*180.0 << " "
745 << azel[1]/C::pi*180.0 << " (deg)" << endl;
746 }
747 pushLog(String(oss));
748}
749
750void Scantable::clip(const Float uthres, const Float dthres, bool clipoutside, bool unflag)
751{
752 for (uInt i=0; i<table_.nrow(); ++i) {
753 Vector<uChar> flgs = flagsCol_(i);
754 srchChannelsToClip(i, uthres, dthres, clipoutside, unflag, flgs);
755 flagsCol_.put(i, flgs);
756 }
757}
758
759std::vector<bool> Scantable::getClipMask(int whichrow, const Float uthres, const Float dthres, bool clipoutside, bool unflag)
760{
761 Vector<uChar> flags;
762 flagsCol_.get(uInt(whichrow), flags);
763 srchChannelsToClip(uInt(whichrow), uthres, dthres, clipoutside, unflag, flags);
764 Vector<Bool> bflag(flags.shape());
765 convertArray(bflag, flags);
766 //bflag = !bflag;
767
768 std::vector<bool> mask;
769 bflag.tovector(mask);
770 return mask;
771}
772
773void Scantable::srchChannelsToClip(uInt whichrow, const Float uthres, const Float dthres, bool clipoutside, bool unflag,
774 Vector<uChar> flgs)
775{
776 Vector<Float> spcs = specCol_(whichrow);
777 uInt nchannel = nchan();
778 if (spcs.nelements() != nchannel) {
779 throw(AipsError("Data has incorrect number of channels"));
780 }
781 uChar userflag = 1 << 7;
782 if (unflag) {
783 userflag = 0 << 7;
784 }
785 if (clipoutside) {
786 for (uInt j = 0; j < nchannel; ++j) {
787 Float spc = spcs(j);
788 if ((spc >= uthres) || (spc <= dthres)) {
789 flgs(j) = userflag;
790 }
791 }
792 } else {
793 for (uInt j = 0; j < nchannel; ++j) {
794 Float spc = spcs(j);
795 if ((spc < uthres) && (spc > dthres)) {
796 flgs(j) = userflag;
797 }
798 }
799 }
800}
801
802
803void Scantable::flag( int whichrow, const std::vector<bool>& msk, bool unflag ) {
804 std::vector<bool>::const_iterator it;
805 uInt ntrue = 0;
806 if (whichrow >= int(table_.nrow()) ) {
807 throw(AipsError("Invalid row number"));
808 }
809 for (it = msk.begin(); it != msk.end(); ++it) {
810 if ( *it ) {
811 ntrue++;
812 }
813 }
814 //if ( selector_.empty() && (msk.size() == 0 || msk.size() == ntrue) )
815 if ( whichrow == -1 && !unflag && selector_.empty() && (msk.size() == 0 || msk.size() == ntrue) )
816 throw(AipsError("Trying to flag whole scantable."));
817 uChar userflag = 1 << 7;
818 if ( unflag ) {
819 userflag = 0 << 7;
820 }
821 if (whichrow > -1 ) {
822 applyChanFlag(uInt(whichrow), msk, userflag);
823 } else {
824 for ( uInt i=0; i<table_.nrow(); ++i) {
825 applyChanFlag(i, msk, userflag);
826 }
827 }
828}
829
830void Scantable::applyChanFlag( uInt whichrow, const std::vector<bool>& msk, uChar flagval )
831{
832 if (whichrow >= table_.nrow() ) {
833 throw( casa::indexError<int>( whichrow, "asap::Scantable::applyChanFlag: Invalid row number" ) );
834 }
835 Vector<uChar> flgs = flagsCol_(whichrow);
836 if ( msk.size() == 0 ) {
837 flgs = flagval;
838 flagsCol_.put(whichrow, flgs);
839 return;
840 }
841 if ( int(msk.size()) != nchan() ) {
842 throw(AipsError("Mask has incorrect number of channels."));
843 }
844 if ( flgs.nelements() != msk.size() ) {
845 throw(AipsError("Mask has incorrect number of channels."
846 " Probably varying with IF. Please flag per IF"));
847 }
848 std::vector<bool>::const_iterator it;
849 uInt j = 0;
850 for (it = msk.begin(); it != msk.end(); ++it) {
851 if ( *it ) {
852 flgs(j) = flagval;
853 }
854 ++j;
855 }
856 flagsCol_.put(whichrow, flgs);
857}
858
859void Scantable::flagRow(const std::vector<uInt>& rows, bool unflag)
860{
861 if ( selector_.empty() && (rows.size() == table_.nrow()) )
862 throw(AipsError("Trying to flag whole scantable."));
863
864 uInt rowflag = (unflag ? 0 : 1);
865 std::vector<uInt>::const_iterator it;
866 for (it = rows.begin(); it != rows.end(); ++it)
867 flagrowCol_.put(*it, rowflag);
868}
869
870std::vector<bool> Scantable::getMask(int whichrow) const
871{
872 Vector<uChar> flags;
873 flagsCol_.get(uInt(whichrow), flags);
874 Vector<Bool> bflag(flags.shape());
875 convertArray(bflag, flags);
876 bflag = !bflag;
877 std::vector<bool> mask;
878 bflag.tovector(mask);
879 return mask;
880}
881
882std::vector<float> Scantable::getSpectrum( int whichrow,
883 const std::string& poltype ) const
884{
885 String ptype = poltype;
886 if (poltype == "" ) ptype = getPolType();
887 if ( whichrow < 0 || whichrow >= nrow() )
888 throw(AipsError("Illegal row number."));
889 std::vector<float> out;
890 Vector<Float> arr;
891 uInt requestedpol = polCol_(whichrow);
892 String basetype = getPolType();
893 if ( ptype == basetype ) {
894 specCol_.get(whichrow, arr);
895 } else {
896 CountedPtr<STPol> stpol(STPol::getPolClass(Scantable::factories_,
897 basetype));
898 uInt row = uInt(whichrow);
899 stpol->setSpectra(getPolMatrix(row));
900 Float fang,fhand;
901 fang = focusTable_.getTotalAngle(mfocusidCol_(row));
902 fhand = focusTable_.getFeedHand(mfocusidCol_(row));
903 stpol->setPhaseCorrections(fang, fhand);
904 arr = stpol->getSpectrum(requestedpol, ptype);
905 }
906 if ( arr.nelements() == 0 )
907 pushLog("Not enough polarisations present to do the conversion.");
908 arr.tovector(out);
909 return out;
910}
911
912void Scantable::setSpectrum( const std::vector<float>& spec,
913 int whichrow )
914{
915 Vector<Float> spectrum(spec);
916 Vector<Float> arr;
917 specCol_.get(whichrow, arr);
918 if ( spectrum.nelements() != arr.nelements() )
919 throw AipsError("The spectrum has incorrect number of channels.");
920 specCol_.put(whichrow, spectrum);
921}
922
923
924String Scantable::generateName()
925{
926 return (File::newUniqueName("./","temp")).baseName();
927}
928
929const casa::Table& Scantable::table( ) const
930{
931 return table_;
932}
933
934casa::Table& Scantable::table( )
935{
936 return table_;
937}
938
939std::string Scantable::getPolType() const
940{
941 return table_.keywordSet().asString("POLTYPE");
942}
943
944void Scantable::unsetSelection()
945{
946 table_ = originalTable_;
947 attach();
948 selector_.reset();
949}
950
951void Scantable::setSelection( const STSelector& selection )
952{
953 Table tab = const_cast<STSelector&>(selection).apply(originalTable_);
954 if ( tab.nrow() == 0 ) {
955 throw(AipsError("Selection contains no data. Not applying it."));
956 }
957 table_ = tab;
958 attach();
959// tab.rwKeywordSet().define("nBeam",(Int)(getBeamNos().size())) ;
960// vector<uint> selectedIFs = getIFNos() ;
961// Int newnIF = selectedIFs.size() ;
962// tab.rwKeywordSet().define("nIF",newnIF) ;
963// if ( newnIF != 0 ) {
964// Int newnChan = 0 ;
965// for ( Int i = 0 ; i < newnIF ; i++ ) {
966// Int nChan = nchan( selectedIFs[i] ) ;
967// if ( newnChan > nChan )
968// newnChan = nChan ;
969// }
970// tab.rwKeywordSet().define("nChan",newnChan) ;
971// }
972// tab.rwKeywordSet().define("nPol",(Int)(getPolNos().size())) ;
973 selector_ = selection;
974}
975
976
977std::string Scantable::headerSummary()
978{
979 // Format header info
980// STHeader sdh;
981// sdh = getHeader();
982// sdh.print();
983 ostringstream oss;
984 oss.flags(std::ios_base::left);
985 String tmp;
986 // Project
987 table_.keywordSet().get("Project", tmp);
988 oss << setw(15) << "Project:" << tmp << endl;
989 // Observation date
990 oss << setw(15) << "Obs Date:" << getTime(-1,true) << endl;
991 // Observer
992 oss << setw(15) << "Observer:"
993 << table_.keywordSet().asString("Observer") << endl;
994 // Antenna Name
995 table_.keywordSet().get("AntennaName", tmp);
996 oss << setw(15) << "Antenna Name:" << tmp << endl;
997 // Obs type
998 table_.keywordSet().get("Obstype", tmp);
999 // Records (nrow)
1000 oss << setw(15) << "Data Records:" << table_.nrow() << " rows" << endl;
1001 oss << setw(15) << "Obs. Type:" << tmp << endl;
1002 // Beams, IFs, Polarizations, and Channels
1003 oss << setw(15) << "Beams:" << setw(4) << nbeam() << endl
1004 << setw(15) << "IFs:" << setw(4) << nif() << endl
1005 << setw(15) << "Polarisations:" << setw(4) << npol()
1006 << "(" << getPolType() << ")" << endl
1007 << setw(15) << "Channels:" << nchan() << endl;
1008 // Flux unit
1009 table_.keywordSet().get("FluxUnit", tmp);
1010 oss << setw(15) << "Flux Unit:" << tmp << endl;
1011 // Abscissa Unit
1012 oss << setw(15) << "Abscissa:" << getAbcissaLabel(0) << endl;
1013 // Selection
1014 oss << selector_.print() << endl;
1015
1016 return String(oss);
1017}
1018
1019void Scantable::summary( const std::string& filename )
1020{
1021 ostringstream oss;
1022 ofstream ofs;
1023 LogIO ols(LogOrigin("Scantable", "summary", WHERE));
1024
1025 if (filename != "")
1026 ofs.open( filename.c_str(), ios::out );
1027
1028 oss << endl;
1029 oss << asap::SEPERATOR << endl;
1030 oss << " Scan Table Summary" << endl;
1031 oss << asap::SEPERATOR << endl;
1032
1033 // Format header info
1034 oss << headerSummary();
1035 oss << endl;
1036
1037 if (table_.nrow() <= 0){
1038 oss << asap::SEPERATOR << endl;
1039 oss << "The MAIN table is empty: there are no data!!!" << endl;
1040 oss << asap::SEPERATOR << endl;
1041
1042 ols << String(oss) << LogIO::POST;
1043 if (ofs) {
1044 ofs << String(oss) << flush;
1045 ofs.close();
1046 }
1047 return;
1048 }
1049
1050
1051
1052 // main table
1053 String dirtype = "Position ("
1054 + getDirectionRefString()
1055 + ")";
1056 oss.flags(std::ios_base::left);
1057 oss << setw(5) << "Scan"
1058 << setw(15) << "Source"
1059 << setw(35) << "Time range"
1060 << setw(2) << "" << setw(7) << "Int[s]"
1061 << setw(7) << "Record"
1062 << setw(8) << "SrcType"
1063 << setw(8) << "FreqIDs"
1064 << setw(7) << "MolIDs" << endl;
1065 oss << setw(7)<< "" << setw(6) << "Beam"
1066 << setw(23) << dirtype << endl;
1067
1068 oss << asap::SEPERATOR << endl;
1069
1070 // Flush summary and clear up the string
1071 ols << String(oss) << LogIO::POST;
1072 if (ofs) ofs << String(oss) << flush;
1073 oss.str("");
1074 oss.clear();
1075
1076
1077 // Get Freq_ID map
1078 ROScalarColumn<uInt> ftabIds(frequencies().table(), "ID");
1079 Int nfid = ftabIds.nrow();
1080 if (nfid <= 0){
1081 oss << "FREQUENCIES subtable is empty: there are no data!!!" << endl;
1082 oss << asap::SEPERATOR << endl;
1083
1084 ols << String(oss) << LogIO::POST;
1085 if (ofs) {
1086 ofs << String(oss) << flush;
1087 ofs.close();
1088 }
1089 return;
1090 }
1091 // Storages of overall IFNO, POLNO, and nchan per FREQ_ID
1092 // the orders are identical to ID in FREQ subtable
1093 Block< Vector<uInt> > ifNos(nfid), polNos(nfid);
1094 Vector<Int> fIdchans(nfid,-1);
1095 map<uInt, Int> fidMap; // (FREQ_ID, row # in FREQ subtable) pair
1096 for (Int i=0; i < nfid; i++){
1097 // fidMap[freqId] returns row number in FREQ subtable
1098 fidMap.insert(pair<uInt, Int>(ftabIds(i),i));
1099 ifNos[i] = Vector<uInt>();
1100 polNos[i] = Vector<uInt>();
1101 }
1102
1103 TableIterator iter(table_, "SCANNO");
1104
1105 // Vars for keeping track of time, freqids, molIds in a SCANNO
1106 Vector<uInt> freqids;
1107 Vector<uInt> molids;
1108 Vector<uInt> beamids(1,0);
1109 Vector<MDirection> beamDirs;
1110 Vector<Int> stypeids(1,0);
1111 Vector<String> stypestrs;
1112 Int nfreq(1);
1113 Int nmol(1);
1114 uInt nbeam(1);
1115 uInt nstype(1);
1116
1117 Double btime(0.0), etime(0.0);
1118 Double meanIntTim(0.0);
1119
1120 uInt currFreqId(0), ftabRow(0);
1121 Int iflen(0), pollen(0);
1122
1123 while (!iter.pastEnd()) {
1124 Table subt = iter.table();
1125 uInt snrow = subt.nrow();
1126 ROTableRow row(subt);
1127 const TableRecord& rec = row.get(0);
1128
1129 // relevant columns
1130 ROScalarColumn<Double> mjdCol(subt,"TIME");
1131 ROScalarColumn<Double> intervalCol(subt,"INTERVAL");
1132 MDirection::ROScalarColumn dirCol(subt,"DIRECTION");
1133
1134 ScalarColumn<uInt> freqIdCol(subt,"FREQ_ID");
1135 ScalarColumn<uInt> molIdCol(subt,"MOLECULE_ID");
1136 ROScalarColumn<uInt> beamCol(subt,"BEAMNO");
1137 ROScalarColumn<Int> stypeCol(subt,"SRCTYPE");
1138
1139 ROScalarColumn<uInt> ifNoCol(subt,"IFNO");
1140 ROScalarColumn<uInt> polNoCol(subt,"POLNO");
1141
1142
1143 // Times
1144 meanIntTim = sum(intervalCol.getColumn()) / (double) snrow;
1145 minMax(btime, etime, mjdCol.getColumn());
1146 etime += meanIntTim/C::day;
1147
1148 // MOLECULE_ID and FREQ_ID
1149 molids = getNumbers(molIdCol);
1150 molids.shape(nmol);
1151
1152 freqids = getNumbers(freqIdCol);
1153 freqids.shape(nfreq);
1154
1155 // Add first beamid, and srcNames
1156 beamids.resize(1,False);
1157 beamDirs.resize(1,False);
1158 beamids(0)=beamCol(0);
1159 beamDirs(0)=dirCol(0);
1160 nbeam = 1;
1161
1162 stypeids.resize(1,False);
1163 stypeids(0)=stypeCol(0);
1164 nstype = 1;
1165
1166 // Global listings of nchan/IFNO/POLNO per FREQ_ID
1167 currFreqId=freqIdCol(0);
1168 ftabRow = fidMap[currFreqId];
1169 // Assumes an identical number of channels per FREQ_ID
1170 if (fIdchans(ftabRow) < 0 ) {
1171 RORecordFieldPtr< Array<Float> > spec(rec, "SPECTRA");
1172 fIdchans(ftabRow)=(*spec).shape()(0);
1173 }
1174 // Should keep ifNos and polNos form the previous SCANNO
1175 if ( !anyEQ(ifNos[ftabRow],ifNoCol(0)) ) {
1176 ifNos[ftabRow].shape(iflen);
1177 iflen++;
1178 ifNos[ftabRow].resize(iflen,True);
1179 ifNos[ftabRow](iflen-1) = ifNoCol(0);
1180 }
1181 if ( !anyEQ(polNos[ftabRow],polNoCol(0)) ) {
1182 polNos[ftabRow].shape(pollen);
1183 pollen++;
1184 polNos[ftabRow].resize(pollen,True);
1185 polNos[ftabRow](pollen-1) = polNoCol(0);
1186 }
1187
1188 for (uInt i=1; i < snrow; i++){
1189 // Need to list BEAMNO and DIRECTION in the same order
1190 if ( !anyEQ(beamids,beamCol(i)) ) {
1191 nbeam++;
1192 beamids.resize(nbeam,True);
1193 beamids(nbeam-1)=beamCol(i);
1194 beamDirs.resize(nbeam,True);
1195 beamDirs(nbeam-1)=dirCol(i);
1196 }
1197
1198 // SRCTYPE is Int (getNumber takes only uInt)
1199 if ( !anyEQ(stypeids,stypeCol(i)) ) {
1200 nstype++;
1201 stypeids.resize(nstype,True);
1202 stypeids(nstype-1)=stypeCol(i);
1203 }
1204
1205 // Global listings of nchan/IFNO/POLNO per FREQ_ID
1206 currFreqId=freqIdCol(i);
1207 ftabRow = fidMap[currFreqId];
1208 if (fIdchans(ftabRow) < 0 ) {
1209 const TableRecord& rec = row.get(i);
1210 RORecordFieldPtr< Array<Float> > spec(rec, "SPECTRA");
1211 fIdchans(ftabRow) = (*spec).shape()(0);
1212 }
1213 if ( !anyEQ(ifNos[ftabRow],ifNoCol(i)) ) {
1214 ifNos[ftabRow].shape(iflen);
1215 iflen++;
1216 ifNos[ftabRow].resize(iflen,True);
1217 ifNos[ftabRow](iflen-1) = ifNoCol(i);
1218 }
1219 if ( !anyEQ(polNos[ftabRow],polNoCol(i)) ) {
1220 polNos[ftabRow].shape(pollen);
1221 pollen++;
1222 polNos[ftabRow].resize(pollen,True);
1223 polNos[ftabRow](pollen-1) = polNoCol(i);
1224 }
1225 } // end of row iteration
1226
1227 stypestrs.resize(nstype,False);
1228 for (uInt j=0; j < nstype; j++)
1229 stypestrs(j) = SrcType::getName(stypeids(j));
1230
1231 // Format Scan summary
1232 oss << setw(4) << std::right << rec.asuInt("SCANNO")
1233 << std::left << setw(1) << ""
1234 << setw(15) << rec.asString("SRCNAME")
1235 << setw(21) << MVTime(btime).string(MVTime::YMD,7)
1236 << setw(3) << " - " << MVTime(etime).string(MVTime::TIME,7)
1237 << setw(3) << "" << setw(6) << meanIntTim << setw(1) << ""
1238 << std::right << setw(5) << snrow << setw(2) << ""
1239 << std::left << stypestrs << setw(1) << ""
1240 << freqids << setw(1) << ""
1241 << molids << endl;
1242 // Format Beam summary
1243 for (uInt j=0; j < nbeam; j++) {
1244 oss << setw(7) << "" << setw(6) << beamids(j) << setw(1) << ""
1245 << formatDirection(beamDirs(j)) << endl;
1246 }
1247 // Flush summary every scan and clear up the string
1248 ols << String(oss) << LogIO::POST;
1249 if (ofs) ofs << String(oss) << flush;
1250 oss.str("");
1251 oss.clear();
1252
1253 ++iter;
1254 } // end of scan iteration
1255 oss << asap::SEPERATOR << endl;
1256
1257 // List FRECUENCIES Table (using STFrequencies.print may be slow)
1258 oss << "FREQUENCIES: " << nfreq << endl;
1259 oss << std::right << setw(5) << "ID" << setw(2) << ""
1260 << std::left << setw(5) << "IFNO" << setw(2) << ""
1261 << setw(8) << "Frame"
1262 << setw(16) << "RefVal"
1263 << setw(7) << "RefPix"
1264 << setw(15) << "Increment"
1265 << setw(9) << "Channels"
1266 << setw(6) << "POLNOs" << endl;
1267 Int tmplen;
1268 for (Int i=0; i < nfid; i++){
1269 // List row=i of FREQUENCIES subtable
1270 ifNos[i].shape(tmplen);
1271 if (tmplen == 1) {
1272 oss << std::right << setw(5) << ftabIds(i) << setw(2) << ""
1273 << setw(3) << ifNos[i](0) << setw(1) << ""
1274 << std::left << setw(46) << frequencies().print(ftabIds(i))
1275 << setw(2) << ""
1276 << std::right << setw(8) << fIdchans[i] << setw(2) << ""
1277 << std::left << polNos[i] << endl;
1278 } else if (tmplen > 0 ) {
1279 // You shouldn't come here
1280 oss << std::left
1281 << "Multiple IFNOs in FREQ_ID = " << ftabIds(i)
1282 << " !!!" << endl;
1283 }
1284 }
1285 oss << asap::SEPERATOR << endl;
1286
1287 // List MOLECULES Table (currently lists all rows)
1288 oss << "MOLECULES: " << endl;
1289 if (molecules().nrow() <= 0) {
1290 oss << " MOLECULES subtable is empty: there are no data" << endl;
1291 } else {
1292 ROTableRow row(molecules().table());
1293 oss << std::right << setw(5) << "ID"
1294 << std::left << setw(3) << ""
1295 << setw(18) << "RestFreq"
1296 << setw(15) << "Name" << endl;
1297 for (Int i=0; i < molecules().nrow(); i++){
1298 const TableRecord& rec=row.get(i);
1299 oss << std::right << setw(5) << rec.asuInt("ID")
1300 << std::left << setw(3) << ""
1301 << rec.asArrayDouble("RESTFREQUENCY") << setw(1) << ""
1302 << rec.asArrayString("NAME") << endl;
1303 }
1304 }
1305 oss << asap::SEPERATOR << endl;
1306 ols << String(oss) << LogIO::POST;
1307 if (ofs) {
1308 ofs << String(oss) << flush;
1309 ofs.close();
1310 }
1311 // return String(oss);
1312}
1313
1314
1315std::string Scantable::oldheaderSummary()
1316{
1317 // Format header info
1318// STHeader sdh;
1319// sdh = getHeader();
1320// sdh.print();
1321 ostringstream oss;
1322 oss.flags(std::ios_base::left);
1323 oss << setw(15) << "Beams:" << setw(4) << nbeam() << endl
1324 << setw(15) << "IFs:" << setw(4) << nif() << endl
1325 << setw(15) << "Polarisations:" << setw(4) << npol()
1326 << "(" << getPolType() << ")" << endl
1327 << setw(15) << "Channels:" << nchan() << endl;
1328 String tmp;
1329 oss << setw(15) << "Observer:"
1330 << table_.keywordSet().asString("Observer") << endl;
1331 oss << setw(15) << "Obs Date:" << getTime(-1,true) << endl;
1332 table_.keywordSet().get("Project", tmp);
1333 oss << setw(15) << "Project:" << tmp << endl;
1334 table_.keywordSet().get("Obstype", tmp);
1335 oss << setw(15) << "Obs. Type:" << tmp << endl;
1336 table_.keywordSet().get("AntennaName", tmp);
1337 oss << setw(15) << "Antenna Name:" << tmp << endl;
1338 table_.keywordSet().get("FluxUnit", tmp);
1339 oss << setw(15) << "Flux Unit:" << tmp << endl;
1340 int nid = moleculeTable_.nrow();
1341 Bool firstline = True;
1342 oss << setw(15) << "Rest Freqs:";
1343 for (int i=0; i<nid; i++) {
1344 Table t = table_(table_.col("MOLECULE_ID") == i, 1);
1345 if (t.nrow() > 0) {
1346 Vector<Double> vec(moleculeTable_.getRestFrequency(i));
1347 if (vec.nelements() > 0) {
1348 if (firstline) {
1349 oss << setprecision(10) << vec << " [Hz]" << endl;
1350 firstline=False;
1351 }
1352 else{
1353 oss << setw(15)<<" " << setprecision(10) << vec << " [Hz]" << endl;
1354 }
1355 } else {
1356 oss << "none" << endl;
1357 }
1358 }
1359 }
1360
1361 oss << setw(15) << "Abcissa:" << getAbcissaLabel(0) << endl;
1362 oss << selector_.print() << endl;
1363 return String(oss);
1364}
1365
1366 //std::string Scantable::summary( const std::string& filename )
1367void Scantable::oldsummary( const std::string& filename )
1368{
1369 ostringstream oss;
1370 ofstream ofs;
1371 LogIO ols(LogOrigin("Scantable", "summary", WHERE));
1372
1373 if (filename != "")
1374 ofs.open( filename.c_str(), ios::out );
1375
1376 oss << endl;
1377 oss << asap::SEPERATOR << endl;
1378 oss << " Scan Table Summary" << endl;
1379 oss << asap::SEPERATOR << endl;
1380
1381 // Format header info
1382 oss << oldheaderSummary();
1383 oss << endl;
1384
1385 // main table
1386 String dirtype = "Position ("
1387 + getDirectionRefString()
1388 + ")";
1389 oss.flags(std::ios_base::left);
1390 oss << setw(5) << "Scan" << setw(15) << "Source"
1391 << setw(10) << "Time" << setw(18) << "Integration"
1392 << setw(15) << "Source Type" << endl;
1393 oss << setw(5) << "" << setw(5) << "Beam" << setw(3) << "" << dirtype << endl;
1394 oss << setw(10) << "" << setw(3) << "IF" << setw(3) << ""
1395 << setw(8) << "Frame" << setw(16)
1396 << "RefVal" << setw(10) << "RefPix" << setw(12) << "Increment"
1397 << setw(7) << "Channels"
1398 << endl;
1399 oss << asap::SEPERATOR << endl;
1400
1401 // Flush summary and clear up the string
1402 ols << String(oss) << LogIO::POST;
1403 if (ofs) ofs << String(oss) << flush;
1404 oss.str("");
1405 oss.clear();
1406
1407 TableIterator iter(table_, "SCANNO");
1408 while (!iter.pastEnd()) {
1409 Table subt = iter.table();
1410 ROTableRow row(subt);
1411 MEpoch::ROScalarColumn timeCol(subt,"TIME");
1412 const TableRecord& rec = row.get(0);
1413 oss << setw(4) << std::right << rec.asuInt("SCANNO")
1414 << std::left << setw(1) << ""
1415 << setw(15) << rec.asString("SRCNAME")
1416 << setw(10) << formatTime(timeCol(0), false);
1417 // count the cycles in the scan
1418 TableIterator cyciter(subt, "CYCLENO");
1419 int nint = 0;
1420 while (!cyciter.pastEnd()) {
1421 ++nint;
1422 ++cyciter;
1423 }
1424 oss << setw(3) << std::right << nint << setw(3) << " x " << std::left
1425 << setw(11) << formatSec(rec.asFloat("INTERVAL")) << setw(1) << ""
1426 << setw(15) << SrcType::getName(rec.asInt("SRCTYPE")) << endl;
1427
1428 TableIterator biter(subt, "BEAMNO");
1429 while (!biter.pastEnd()) {
1430 Table bsubt = biter.table();
1431 ROTableRow brow(bsubt);
1432 const TableRecord& brec = brow.get(0);
1433 uInt row0 = bsubt.rowNumbers(table_)[0];
1434 oss << setw(5) << "" << setw(4) << std::right << brec.asuInt("BEAMNO")<< std::left;
1435 oss << setw(4) << "" << formatDirection(getDirection(row0)) << endl;
1436 TableIterator iiter(bsubt, "IFNO");
1437 while (!iiter.pastEnd()) {
1438 Table isubt = iiter.table();
1439 ROTableRow irow(isubt);
1440 const TableRecord& irec = irow.get(0);
1441 oss << setw(9) << "";
1442 oss << setw(3) << std::right << irec.asuInt("IFNO") << std::left
1443 << setw(1) << "" << frequencies().print(irec.asuInt("FREQ_ID"))
1444 << setw(3) << "" << nchan(irec.asuInt("IFNO"))
1445 << endl;
1446
1447 ++iiter;
1448 }
1449 ++biter;
1450 }
1451 // Flush summary every scan and clear up the string
1452 ols << String(oss) << LogIO::POST;
1453 if (ofs) ofs << String(oss) << flush;
1454 oss.str("");
1455 oss.clear();
1456
1457 ++iter;
1458 }
1459 oss << asap::SEPERATOR << endl;
1460 ols << String(oss) << LogIO::POST;
1461 if (ofs) {
1462 ofs << String(oss) << flush;
1463 ofs.close();
1464 }
1465 // return String(oss);
1466}
1467
1468// std::string Scantable::getTime(int whichrow, bool showdate) const
1469// {
1470// MEpoch::ROScalarColumn timeCol(table_, "TIME");
1471// MEpoch me;
1472// if (whichrow > -1) {
1473// me = timeCol(uInt(whichrow));
1474// } else {
1475// Double tm;
1476// table_.keywordSet().get("UTC",tm);
1477// me = MEpoch(MVEpoch(tm));
1478// }
1479// return formatTime(me, showdate);
1480// }
1481
1482std::string Scantable::getTime(int whichrow, bool showdate, uInt prec) const
1483{
1484 MEpoch me;
1485 me = getEpoch(whichrow);
1486 return formatTime(me, showdate, prec);
1487}
1488
1489MEpoch Scantable::getEpoch(int whichrow) const
1490{
1491 if (whichrow > -1) {
1492 return timeCol_(uInt(whichrow));
1493 } else {
1494 Double tm;
1495 table_.keywordSet().get("UTC",tm);
1496 return MEpoch(MVEpoch(tm));
1497 }
1498}
1499
1500std::string Scantable::getDirectionString(int whichrow) const
1501{
1502 return formatDirection(getDirection(uInt(whichrow)));
1503}
1504
1505
1506SpectralCoordinate Scantable::getSpectralCoordinate(int whichrow) const {
1507 const MPosition& mp = getAntennaPosition();
1508 const MDirection& md = getDirection(whichrow);
1509 const MEpoch& me = timeCol_(whichrow);
1510 //Double rf = moleculeTable_.getRestFrequency(mmolidCol_(whichrow));
1511 Vector<Double> rf = moleculeTable_.getRestFrequency(mmolidCol_(whichrow));
1512 return freqTable_->getSpectralCoordinate(md, mp, me, rf,
1513 mfreqidCol_(whichrow));
1514}
1515
1516std::vector< double > Scantable::getAbcissa( int whichrow ) const
1517{
1518 if ( whichrow > int(table_.nrow()) ) throw(AipsError("Illegal row number"));
1519 std::vector<double> stlout;
1520 int nchan = specCol_(whichrow).nelements();
1521 String us = freqTable_->getUnitString();
1522 if ( us == "" || us == "pixel" || us == "channel" ) {
1523 for (int i=0; i<nchan; ++i) {
1524 stlout.push_back(double(i));
1525 }
1526 return stlout;
1527 }
1528 SpectralCoordinate spc = getSpectralCoordinate(whichrow);
1529 Vector<Double> pixel(nchan);
1530 Vector<Double> world;
1531 indgen(pixel);
1532 if ( Unit(us) == Unit("Hz") ) {
1533 for ( int i=0; i < nchan; ++i) {
1534 Double world;
1535 spc.toWorld(world, pixel[i]);
1536 stlout.push_back(double(world));
1537 }
1538 } else if ( Unit(us) == Unit("km/s") ) {
1539 Vector<Double> world;
1540 spc.pixelToVelocity(world, pixel);
1541 world.tovector(stlout);
1542 }
1543 return stlout;
1544}
1545void Scantable::setDirectionRefString( const std::string & refstr )
1546{
1547 MDirection::Types mdt;
1548 if (refstr != "" && !MDirection::getType(mdt, refstr)) {
1549 throw(AipsError("Illegal Direction frame."));
1550 }
1551 if ( refstr == "" ) {
1552 String defaultstr = MDirection::showType(dirCol_.getMeasRef().getType());
1553 table_.rwKeywordSet().define("DIRECTIONREF", defaultstr);
1554 } else {
1555 table_.rwKeywordSet().define("DIRECTIONREF", String(refstr));
1556 }
1557}
1558
1559std::string Scantable::getDirectionRefString( ) const
1560{
1561 return table_.keywordSet().asString("DIRECTIONREF");
1562}
1563
1564MDirection Scantable::getDirection(int whichrow ) const
1565{
1566 String usertype = table_.keywordSet().asString("DIRECTIONREF");
1567 String type = MDirection::showType(dirCol_.getMeasRef().getType());
1568 if ( usertype != type ) {
1569 MDirection::Types mdt;
1570 if (!MDirection::getType(mdt, usertype)) {
1571 throw(AipsError("Illegal Direction frame."));
1572 }
1573 return dirCol_.convert(uInt(whichrow), mdt);
1574 } else {
1575 return dirCol_(uInt(whichrow));
1576 }
1577}
1578
1579std::string Scantable::getAbcissaLabel( int whichrow ) const
1580{
1581 if ( whichrow > int(table_.nrow()) ) throw(AipsError("Illegal ro number"));
1582 const MPosition& mp = getAntennaPosition();
1583 const MDirection& md = getDirection(whichrow);
1584 const MEpoch& me = timeCol_(whichrow);
1585 //const Double& rf = mmolidCol_(whichrow);
1586 const Vector<Double> rf = moleculeTable_.getRestFrequency(mmolidCol_(whichrow));
1587 SpectralCoordinate spc =
1588 freqTable_->getSpectralCoordinate(md, mp, me, rf, mfreqidCol_(whichrow));
1589
1590 String s = "Channel";
1591 Unit u = Unit(freqTable_->getUnitString());
1592 if (u == Unit("km/s")) {
1593 s = CoordinateUtil::axisLabel(spc, 0, True,True, True);
1594 } else if (u == Unit("Hz")) {
1595 Vector<String> wau(1);wau = u.getName();
1596 spc.setWorldAxisUnits(wau);
1597 s = CoordinateUtil::axisLabel(spc, 0, True, True, False);
1598 }
1599 return s;
1600
1601}
1602
1603/**
1604void asap::Scantable::setRestFrequencies( double rf, const std::string& name,
1605 const std::string& unit )
1606**/
1607void Scantable::setRestFrequencies( vector<double> rf, const vector<std::string>& name,
1608 const std::string& unit )
1609
1610{
1611 ///@todo lookup in line table to fill in name and formattedname
1612 Unit u(unit);
1613 //Quantum<Double> urf(rf, u);
1614 Quantum<Vector<Double> >urf(rf, u);
1615 Vector<String> formattedname(0);
1616 //cerr<<"Scantable::setRestFrequnecies="<<urf<<endl;
1617
1618 //uInt id = moleculeTable_.addEntry(urf.getValue("Hz"), name, "");
1619 uInt id = moleculeTable_.addEntry(urf.getValue("Hz"), mathutil::toVectorString(name), formattedname);
1620 TableVector<uInt> tabvec(table_, "MOLECULE_ID");
1621 tabvec = id;
1622}
1623
1624/**
1625void asap::Scantable::setRestFrequencies( const std::string& name )
1626{
1627 throw(AipsError("setRestFrequencies( const std::string& name ) NYI"));
1628 ///@todo implement
1629}
1630**/
1631
1632void Scantable::setRestFrequencies( const vector<std::string>& name )
1633{
1634 (void) name; // suppress unused warning
1635 throw(AipsError("setRestFrequencies( const vector<std::string>& name ) NYI"));
1636 ///@todo implement
1637}
1638
1639std::vector< unsigned int > Scantable::rownumbers( ) const
1640{
1641 std::vector<unsigned int> stlout;
1642 Vector<uInt> vec = table_.rowNumbers();
1643 vec.tovector(stlout);
1644 return stlout;
1645}
1646
1647
1648Matrix<Float> Scantable::getPolMatrix( uInt whichrow ) const
1649{
1650 ROTableRow row(table_);
1651 const TableRecord& rec = row.get(whichrow);
1652 Table t =
1653 originalTable_( originalTable_.col("SCANNO") == Int(rec.asuInt("SCANNO"))
1654 && originalTable_.col("BEAMNO") == Int(rec.asuInt("BEAMNO"))
1655 && originalTable_.col("IFNO") == Int(rec.asuInt("IFNO"))
1656 && originalTable_.col("CYCLENO") == Int(rec.asuInt("CYCLENO")) );
1657 ROArrayColumn<Float> speccol(t, "SPECTRA");
1658 return speccol.getColumn();
1659}
1660
1661std::vector< std::string > Scantable::columnNames( ) const
1662{
1663 Vector<String> vec = table_.tableDesc().columnNames();
1664 return mathutil::tovectorstring(vec);
1665}
1666
1667MEpoch::Types Scantable::getTimeReference( ) const
1668{
1669 return MEpoch::castType(timeCol_.getMeasRef().getType());
1670}
1671
1672void Scantable::addFit( const STFitEntry& fit, int row )
1673{
1674 //cout << mfitidCol_(uInt(row)) << endl;
1675 LogIO os( LogOrigin( "Scantable", "addFit()", WHERE ) ) ;
1676 os << mfitidCol_(uInt(row)) << LogIO::POST ;
1677 uInt id = fitTable_.addEntry(fit, mfitidCol_(uInt(row)));
1678 mfitidCol_.put(uInt(row), id);
1679}
1680
1681void Scantable::shift(int npix)
1682{
1683 Vector<uInt> fids(mfreqidCol_.getColumn());
1684 genSort( fids, Sort::Ascending,
1685 Sort::QuickSort|Sort::NoDuplicates );
1686 for (uInt i=0; i<fids.nelements(); ++i) {
1687 frequencies().shiftRefPix(npix, fids[i]);
1688 }
1689}
1690
1691String Scantable::getAntennaName() const
1692{
1693 String out;
1694 table_.keywordSet().get("AntennaName", out);
1695 String::size_type pos1 = out.find("@") ;
1696 String::size_type pos2 = out.find("//") ;
1697 if ( pos2 != String::npos )
1698 out = out.substr(pos2+2,pos1-pos2-2) ;
1699 else if ( pos1 != String::npos )
1700 out = out.substr(0,pos1) ;
1701 return out;
1702}
1703
1704int Scantable::checkScanInfo(const std::vector<int>& scanlist) const
1705{
1706 String tbpath;
1707 int ret = 0;
1708 if ( table_.keywordSet().isDefined("GBT_GO") ) {
1709 table_.keywordSet().get("GBT_GO", tbpath);
1710 Table t(tbpath,Table::Old);
1711 // check each scan if other scan of the pair exist
1712 int nscan = scanlist.size();
1713 for (int i = 0; i < nscan; i++) {
1714 Table subt = t( t.col("SCAN") == scanlist[i]+1 );
1715 if (subt.nrow()==0) {
1716 //cerr <<"Scan "<<scanlist[i]<<" cannot be found in the scantable."<<endl;
1717 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1718 os <<LogIO::WARN<<"Scan "<<scanlist[i]<<" cannot be found in the scantable."<<LogIO::POST;
1719 ret = 1;
1720 break;
1721 }
1722 ROTableRow row(subt);
1723 const TableRecord& rec = row.get(0);
1724 int scan1seqn = rec.asuInt("PROCSEQN");
1725 int laston1 = rec.asuInt("LASTON");
1726 if ( rec.asuInt("PROCSIZE")==2 ) {
1727 if ( i < nscan-1 ) {
1728 Table subt2 = t( t.col("SCAN") == scanlist[i+1]+1 );
1729 if ( subt2.nrow() == 0) {
1730 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1731
1732 //cerr<<"Scan "<<scanlist[i+1]<<" cannot be found in the scantable."<<endl;
1733 os<<LogIO::WARN<<"Scan "<<scanlist[i+1]<<" cannot be found in the scantable."<<LogIO::POST;
1734 ret = 1;
1735 break;
1736 }
1737 ROTableRow row2(subt2);
1738 const TableRecord& rec2 = row2.get(0);
1739 int scan2seqn = rec2.asuInt("PROCSEQN");
1740 int laston2 = rec2.asuInt("LASTON");
1741 if (scan1seqn == 1 && scan2seqn == 2) {
1742 if (laston1 == laston2) {
1743 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1744 //cerr<<"A valid scan pair ["<<scanlist[i]<<","<<scanlist[i+1]<<"]"<<endl;
1745 os<<"A valid scan pair ["<<scanlist[i]<<","<<scanlist[i+1]<<"]"<<LogIO::POST;
1746 i +=1;
1747 }
1748 else {
1749 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1750 //cerr<<"Incorrect scan pair ["<<scanlist[i]<<","<<scanlist[i+1]<<"]"<<endl;
1751 os<<LogIO::WARN<<"Incorrect scan pair ["<<scanlist[i]<<","<<scanlist[i+1]<<"]"<<LogIO::POST;
1752 }
1753 }
1754 else if (scan1seqn==2 && scan2seqn == 1) {
1755 if (laston1 == laston2) {
1756 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1757 //cerr<<"["<<scanlist[i]<<","<<scanlist[i+1]<<"] is a valid scan pair but in incorrect order."<<endl;
1758 os<<LogIO::WARN<<"["<<scanlist[i]<<","<<scanlist[i+1]<<"] is a valid scan pair but in incorrect order."<<LogIO::POST;
1759 ret = 1;
1760 break;
1761 }
1762 }
1763 else {
1764 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1765 //cerr<<"The other scan for "<<scanlist[i]<<" appears to be missing. Check the input scan numbers."<<endl;
1766 os<<LogIO::WARN<<"The other scan for "<<scanlist[i]<<" appears to be missing. Check the input scan numbers."<<LogIO::POST;
1767 ret = 1;
1768 break;
1769 }
1770 }
1771 }
1772 else {
1773 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1774 //cerr<<"The scan does not appear to be standard obsevation."<<endl;
1775 os<<LogIO::WARN<<"The scan does not appear to be standard obsevation."<<LogIO::POST;
1776 }
1777 //if ( i >= nscan ) break;
1778 }
1779 }
1780 else {
1781 LogIO os( LogOrigin( "Scantable", "checkScanInfo()", WHERE ) ) ;
1782 //cerr<<"No reference to GBT_GO table."<<endl;
1783 os<<LogIO::WARN<<"No reference to GBT_GO table."<<LogIO::POST;
1784 ret = 1;
1785 }
1786 return ret;
1787}
1788
1789std::vector<double> Scantable::getDirectionVector(int whichrow) const
1790{
1791 Vector<Double> Dir = dirCol_(whichrow).getAngle("rad").getValue();
1792 std::vector<double> dir;
1793 Dir.tovector(dir);
1794 return dir;
1795}
1796
1797void asap::Scantable::reshapeSpectrum( int nmin, int nmax )
1798 throw( casa::AipsError )
1799{
1800 // assumed that all rows have same nChan
1801 Vector<Float> arr = specCol_( 0 ) ;
1802 int nChan = arr.nelements() ;
1803
1804 // if nmin < 0 or nmax < 0, nothing to do
1805 if ( nmin < 0 ) {
1806 throw( casa::indexError<int>( nmin, "asap::Scantable::reshapeSpectrum: Invalid range. Negative index is specified." ) ) ;
1807 }
1808 if ( nmax < 0 ) {
1809 throw( casa::indexError<int>( nmax, "asap::Scantable::reshapeSpectrum: Invalid range. Negative index is specified." ) ) ;
1810 }
1811
1812 // if nmin > nmax, exchange values
1813 if ( nmin > nmax ) {
1814 int tmp = nmax ;
1815 nmax = nmin ;
1816 nmin = tmp ;
1817 LogIO os( LogOrigin( "Scantable", "reshapeSpectrum()", WHERE ) ) ;
1818 os << "Swap values. Applied range is ["
1819 << nmin << ", " << nmax << "]" << LogIO::POST ;
1820 }
1821
1822 // if nmin exceeds nChan, nothing to do
1823 if ( nmin >= nChan ) {
1824 throw( casa::indexError<int>( nmin, "asap::Scantable::reshapeSpectrum: Invalid range. Specified minimum exceeds nChan." ) ) ;
1825 }
1826
1827 // if nmax exceeds nChan, reset nmax to nChan
1828 if ( nmax >= nChan ) {
1829 if ( nmin == 0 ) {
1830 // nothing to do
1831 LogIO os( LogOrigin( "Scantable", "reshapeSpectrum()", WHERE ) ) ;
1832 os << "Whole range is selected. Nothing to do." << LogIO::POST ;
1833 return ;
1834 }
1835 else {
1836 LogIO os( LogOrigin( "Scantable", "reshapeSpectrum()", WHERE ) ) ;
1837 os << "Specified maximum exceeds nChan. Applied range is ["
1838 << nmin << ", " << nChan-1 << "]." << LogIO::POST ;
1839 nmax = nChan - 1 ;
1840 }
1841 }
1842
1843 // reshape specCol_ and flagCol_
1844 for ( int irow = 0 ; irow < nrow() ; irow++ ) {
1845 reshapeSpectrum( nmin, nmax, irow ) ;
1846 }
1847
1848 // update FREQUENCIES subtable
1849 Double refpix ;
1850 Double refval ;
1851 Double increment ;
1852 int freqnrow = freqTable_->table().nrow() ;
1853 Vector<uInt> oldId( freqnrow ) ;
1854 Vector<uInt> newId( freqnrow ) ;
1855 for ( int irow = 0 ; irow < freqnrow ; irow++ ) {
1856 freqTable_->getEntry( refpix, refval, increment, irow ) ;
1857 /***
1858 * need to shift refpix to nmin
1859 * note that channel nmin in old index will be channel 0 in new one
1860 ***/
1861 refval = refval - ( refpix - nmin ) * increment ;
1862 refpix = 0 ;
1863 freqTable_->setEntry( refpix, refval, increment, irow ) ;
1864 }
1865
1866 // update nchan
1867 int newsize = nmax - nmin + 1 ;
1868 table_.rwKeywordSet().define( "nChan", newsize ) ;
1869
1870 // update bandwidth
1871 // assumed all spectra in the scantable have same bandwidth
1872 table_.rwKeywordSet().define( "Bandwidth", increment * newsize ) ;
1873
1874 return ;
1875}
1876
1877void asap::Scantable::reshapeSpectrum( int nmin, int nmax, int irow )
1878{
1879 // reshape specCol_ and flagCol_
1880 Vector<Float> oldspec = specCol_( irow ) ;
1881 Vector<uChar> oldflag = flagsCol_( irow ) ;
1882 uInt newsize = nmax - nmin + 1 ;
1883 specCol_.put( irow, oldspec( Slice( nmin, newsize, 1 ) ) ) ;
1884 flagsCol_.put( irow, oldflag( Slice( nmin, newsize, 1 ) ) ) ;
1885
1886 return ;
1887}
1888
1889void asap::Scantable::regridChannel( int nChan, double dnu )
1890{
1891 LogIO os( LogOrigin( "Scantable", "regridChannel()", WHERE ) ) ;
1892 os << "Regrid abcissa with channel number " << nChan << " and spectral resoultion " << dnu << "Hz." << LogIO::POST ;
1893 // assumed that all rows have same nChan
1894 Vector<Float> arr = specCol_( 0 ) ;
1895 int oldsize = arr.nelements() ;
1896
1897 // if oldsize == nChan, nothing to do
1898 if ( oldsize == nChan ) {
1899 os << "Specified channel number is same as current one. Nothing to do." << LogIO::POST ;
1900 return ;
1901 }
1902
1903 // if oldChan < nChan, unphysical operation
1904 if ( oldsize < nChan ) {
1905 os << "Unphysical operation. Nothing to do." << LogIO::POST ;
1906 return ;
1907 }
1908
1909 // change channel number for specCol_ and flagCol_
1910 Vector<Float> newspec( nChan, 0 ) ;
1911 Vector<uChar> newflag( nChan, false ) ;
1912 vector<string> coordinfo = getCoordInfo() ;
1913 string oldinfo = coordinfo[0] ;
1914 coordinfo[0] = "Hz" ;
1915 setCoordInfo( coordinfo ) ;
1916 for ( int irow = 0 ; irow < nrow() ; irow++ ) {
1917 regridChannel( nChan, dnu, irow ) ;
1918 }
1919 coordinfo[0] = oldinfo ;
1920 setCoordInfo( coordinfo ) ;
1921
1922
1923 // NOTE: this method does not update metadata such as
1924 // FREQUENCIES subtable, nChan, Bandwidth, etc.
1925
1926 return ;
1927}
1928
1929void asap::Scantable::regridChannel( int nChan, double dnu, int irow )
1930{
1931 // logging
1932 //ofstream ofs( "average.log", std::ios::out | std::ios::app ) ;
1933 //ofs << "IFNO = " << getIF( irow ) << " irow = " << irow << endl ;
1934
1935 Vector<Float> oldspec = specCol_( irow ) ;
1936 Vector<uChar> oldflag = flagsCol_( irow ) ;
1937 Vector<Float> newspec( nChan, 0 ) ;
1938 Vector<uChar> newflag( nChan, false ) ;
1939
1940 // regrid
1941 vector<double> abcissa = getAbcissa( irow ) ;
1942 int oldsize = abcissa.size() ;
1943 double olddnu = abcissa[1] - abcissa[0] ;
1944 //int refChan = 0 ;
1945 //double frac = 0.0 ;
1946 //double wedge = 0.0 ;
1947 //double pile = 0.0 ;
1948 int ichan = 0 ;
1949 double wsum = 0.0 ;
1950 Vector<Float> zi( nChan+1 ) ;
1951 Vector<Float> yi( oldsize + 1 ) ;
1952 zi[0] = abcissa[0] - 0.5 * olddnu ;
1953 zi[1] = zi[1] + dnu ;
1954 for ( int ii = 2 ; ii < nChan ; ii++ )
1955 zi[ii] = zi[0] + dnu * ii ;
1956 zi[nChan] = zi[nChan-1] + dnu ;
1957 yi[0] = abcissa[0] - 0.5 * olddnu ;
1958 yi[1] = abcissa[1] + 0.5 * olddnu ;
1959 for ( int ii = 2 ; ii < oldsize ; ii++ )
1960 yi[ii] = abcissa[ii-1] + olddnu ;
1961 yi[oldsize] = abcissa[oldsize-1] + 0.5 * olddnu ;
1962 if ( dnu > 0.0 ) {
1963 for ( int ii = 0 ; ii < nChan ; ii++ ) {
1964 double zl = zi[ii] ;
1965 double zr = zi[ii+1] ;
1966 for ( int j = ichan ; j < oldsize ; j++ ) {
1967 double yl = yi[j] ;
1968 double yr = yi[j+1] ;
1969 if ( yl <= zl ) {
1970 if ( yr <= zl ) {
1971 continue ;
1972 }
1973 else if ( yr <= zr ) {
1974 newspec[ii] += oldspec[j] * ( yr - zl ) ;
1975 newflag[ii] = newflag[ii] || oldflag[j] ;
1976 wsum += ( yr - zl ) ;
1977 }
1978 else {
1979 newspec[ii] += oldspec[j] * dnu ;
1980 newflag[ii] = newflag[ii] || oldflag[j] ;
1981 wsum += dnu ;
1982 ichan = j ;
1983 break ;
1984 }
1985 }
1986 else if ( yl < zr ) {
1987 if ( yr <= zr ) {
1988 newspec[ii] += oldspec[j] * ( yr - yl ) ;
1989 newflag[ii] = newflag[ii] || oldflag[j] ;
1990 wsum += ( yr - yl ) ;
1991 }
1992 else {
1993 newspec[ii] += oldspec[j] * ( zr - yl ) ;
1994 newflag[ii] = newflag[ii] || oldflag[j] ;
1995 wsum += ( zr - yl ) ;
1996 ichan = j ;
1997 break ;
1998 }
1999 }
2000 else {
2001 ichan = j - 1 ;
2002 break ;
2003 }
2004 }
2005 if ( wsum != 0.0 )
2006 newspec[ii] /= wsum ;
2007 wsum = 0.0 ;
2008 }
2009 }
2010 else if ( dnu < 0.0 ) {
2011 for ( int ii = 0 ; ii < nChan ; ii++ ) {
2012 double zl = zi[ii] ;
2013 double zr = zi[ii+1] ;
2014 for ( int j = ichan ; j < oldsize ; j++ ) {
2015 double yl = yi[j] ;
2016 double yr = yi[j+1] ;
2017 if ( yl >= zl ) {
2018 if ( yr >= zl ) {
2019 continue ;
2020 }
2021 else if ( yr >= zr ) {
2022 newspec[ii] += oldspec[j] * abs( yr - zl ) ;
2023 newflag[ii] = newflag[ii] || oldflag[j] ;
2024 wsum += abs( yr - zl ) ;
2025 }
2026 else {
2027 newspec[ii] += oldspec[j] * abs( dnu ) ;
2028 newflag[ii] = newflag[ii] || oldflag[j] ;
2029 wsum += abs( dnu ) ;
2030 ichan = j ;
2031 break ;
2032 }
2033 }
2034 else if ( yl > zr ) {
2035 if ( yr >= zr ) {
2036 newspec[ii] += oldspec[j] * abs( yr - yl ) ;
2037 newflag[ii] = newflag[ii] || oldflag[j] ;
2038 wsum += abs( yr - yl ) ;
2039 }
2040 else {
2041 newspec[ii] += oldspec[j] * abs( zr - yl ) ;
2042 newflag[ii] = newflag[ii] || oldflag[j] ;
2043 wsum += abs( zr - yl ) ;
2044 ichan = j ;
2045 break ;
2046 }
2047 }
2048 else {
2049 ichan = j - 1 ;
2050 break ;
2051 }
2052 }
2053 if ( wsum != 0.0 )
2054 newspec[ii] /= wsum ;
2055 wsum = 0.0 ;
2056 }
2057 }
2058// * ichan = 0
2059// ***/
2060// //ofs << "olddnu = " << olddnu << ", dnu = " << dnu << endl ;
2061// pile += dnu ;
2062// wedge = olddnu * ( refChan + 1 ) ;
2063// while ( wedge < pile ) {
2064// newspec[0] += olddnu * oldspec[refChan] ;
2065// newflag[0] = newflag[0] || oldflag[refChan] ;
2066// //ofs << "channel " << refChan << " is included in new channel 0" << endl ;
2067// refChan++ ;
2068// wedge += olddnu ;
2069// wsum += olddnu ;
2070// //ofs << "newspec[0] = " << newspec[0] << " wsum = " << wsum << endl ;
2071// }
2072// frac = ( wedge - pile ) / olddnu ;
2073// wsum += ( 1.0 - frac ) * olddnu ;
2074// newspec[0] += ( 1.0 - frac ) * olddnu * oldspec[refChan] ;
2075// newflag[0] = newflag[0] || oldflag[refChan] ;
2076// //ofs << "channel " << refChan << " is partly included in new channel 0" << " with fraction of " << ( 1.0 - frac ) << endl ;
2077// //ofs << "newspec[0] = " << newspec[0] << " wsum = " << wsum << endl ;
2078// newspec[0] /= wsum ;
2079// //ofs << "newspec[0] = " << newspec[0] << endl ;
2080// //ofs << "wedge = " << wedge << ", pile = " << pile << endl ;
2081
2082// /***
2083// * ichan = 1 - nChan-2
2084// ***/
2085// for ( int ichan = 1 ; ichan < nChan - 1 ; ichan++ ) {
2086// pile += dnu ;
2087// newspec[ichan] += frac * olddnu * oldspec[refChan] ;
2088// newflag[ichan] = newflag[ichan] || oldflag[refChan] ;
2089// //ofs << "channel " << refChan << " is partly included in new channel " << ichan << " with fraction of " << frac << endl ;
2090// refChan++ ;
2091// wedge += olddnu ;
2092// wsum = frac * olddnu ;
2093// //ofs << "newspec[" << ichan << "] = " << newspec[ichan] << " wsum = " << wsum << endl ;
2094// while ( wedge < pile ) {
2095// newspec[ichan] += olddnu * oldspec[refChan] ;
2096// newflag[ichan] = newflag[ichan] || oldflag[refChan] ;
2097// //ofs << "channel " << refChan << " is included in new channel " << ichan << endl ;
2098// refChan++ ;
2099// wedge += olddnu ;
2100// wsum += olddnu ;
2101// //ofs << "newspec[" << ichan << "] = " << newspec[ichan] << " wsum = " << wsum << endl ;
2102// }
2103// frac = ( wedge - pile ) / olddnu ;
2104// wsum += ( 1.0 - frac ) * olddnu ;
2105// newspec[ichan] += ( 1.0 - frac ) * olddnu * oldspec[refChan] ;
2106// newflag[ichan] = newflag[ichan] || oldflag[refChan] ;
2107// //ofs << "channel " << refChan << " is partly included in new channel " << ichan << " with fraction of " << ( 1.0 - frac ) << endl ;
2108// //ofs << "wedge = " << wedge << ", pile = " << pile << endl ;
2109// //ofs << "newspec[" << ichan << "] = " << newspec[ichan] << " wsum = " << wsum << endl ;
2110// newspec[ichan] /= wsum ;
2111// //ofs << "newspec[" << ichan << "] = " << newspec[ichan] << endl ;
2112// }
2113
2114// /***
2115// * ichan = nChan-1
2116// ***/
2117// // NOTE: Assumed that all spectra have the same bandwidth
2118// pile += dnu ;
2119// newspec[nChan-1] += frac * olddnu * oldspec[refChan] ;
2120// newflag[nChan-1] = newflag[nChan-1] || oldflag[refChan] ;
2121// //ofs << "channel " << refChan << " is partly included in new channel " << nChan-1 << " with fraction of " << frac << endl ;
2122// refChan++ ;
2123// wedge += olddnu ;
2124// wsum = frac * olddnu ;
2125// //ofs << "newspec[" << nChan - 1 << "] = " << newspec[nChan-1] << " wsum = " << wsum << endl ;
2126// for ( int jchan = refChan ; jchan < oldsize ; jchan++ ) {
2127// newspec[nChan-1] += olddnu * oldspec[jchan] ;
2128// newflag[nChan-1] = newflag[nChan-1] || oldflag[jchan] ;
2129// wsum += olddnu ;
2130// //ofs << "channel " << jchan << " is included in new channel " << nChan-1 << " with fraction of " << frac << endl ;
2131// //ofs << "newspec[" << nChan - 1 << "] = " << newspec[nChan-1] << " wsum = " << wsum << endl ;
2132// }
2133// //ofs << "wedge = " << wedge << ", pile = " << pile << endl ;
2134// //ofs << "newspec[" << nChan - 1 << "] = " << newspec[nChan-1] << " wsum = " << wsum << endl ;
2135// newspec[nChan-1] /= wsum ;
2136// //ofs << "newspec[" << nChan - 1 << "] = " << newspec[nChan-1] << endl ;
2137
2138// // ofs.close() ;
2139
2140 specCol_.put( irow, newspec ) ;
2141 flagsCol_.put( irow, newflag ) ;
2142
2143 return ;
2144}
2145
2146std::vector<float> Scantable::getWeather(int whichrow) const
2147{
2148 std::vector<float> out(5);
2149 //Float temperature, pressure, humidity, windspeed, windaz;
2150 weatherTable_.getEntry(out[0], out[1], out[2], out[3], out[4],
2151 mweatheridCol_(uInt(whichrow)));
2152
2153
2154 return out;
2155}
2156
2157bool Scantable::getFlagtraFast(uInt whichrow)
2158{
2159 uChar flag;
2160 Vector<uChar> flags;
2161 flagsCol_.get(whichrow, flags);
2162 flag = flags[0];
2163 for (uInt i = 1; i < flags.size(); ++i) {
2164 flag &= flags[i];
2165 }
2166 return ((flag >> 7) == 1);
2167}
2168
2169void Scantable::polyBaseline(const std::vector<bool>& mask, int order, bool getResidual, const std::string& progressInfo, const bool outLogger, const std::string& blfile)
2170{
2171 try {
2172 ofstream ofs;
2173 String coordInfo = "";
2174 bool hasSameNchan = true;
2175 bool outTextFile = false;
2176
2177 if (blfile != "") {
2178 ofs.open(blfile.c_str(), ios::out | ios::app);
2179 if (ofs) outTextFile = true;
2180 }
2181
2182 if (outLogger || outTextFile) {
2183 coordInfo = getCoordInfo()[0];
2184 if (coordInfo == "") coordInfo = "channel";
2185 hasSameNchan = hasSameNchanOverIFs();
2186 }
2187
2188 Fitter fitter = Fitter();
2189 fitter.setExpression("poly", order);
2190 //fitter.setIterClipping(thresClip, nIterClip);
2191
2192 int nRow = nrow();
2193 std::vector<bool> chanMask;
2194 bool showProgress;
2195 int minNRow;
2196 parseProgressInfo(progressInfo, showProgress, minNRow);
2197
2198 for (int whichrow = 0; whichrow < nRow; ++whichrow) {
2199 chanMask = getCompositeChanMask(whichrow, mask);
2200 fitBaseline(chanMask, whichrow, fitter);
2201 setSpectrum((getResidual ? fitter.getResidual() : fitter.getFit()), whichrow);
2202 outputFittingResult(outLogger, outTextFile, chanMask, whichrow, coordInfo, hasSameNchan, ofs, "polyBaseline()", fitter);
2203 showProgressOnTerminal(whichrow, nRow, showProgress, minNRow);
2204 }
2205
2206 if (outTextFile) ofs.close();
2207
2208 } catch (...) {
2209 throw;
2210 }
2211}
2212
2213void Scantable::autoPolyBaseline(const std::vector<bool>& mask, int order, const std::vector<int>& edge, float threshold, int chanAvgLimit, bool getResidual, const std::string& progressInfo, const bool outLogger, const std::string& blfile)
2214{
2215 try {
2216 ofstream ofs;
2217 String coordInfo = "";
2218 bool hasSameNchan = true;
2219 bool outTextFile = false;
2220
2221 if (blfile != "") {
2222 ofs.open(blfile.c_str(), ios::out | ios::app);
2223 if (ofs) outTextFile = true;
2224 }
2225
2226 if (outLogger || outTextFile) {
2227 coordInfo = getCoordInfo()[0];
2228 if (coordInfo == "") coordInfo = "channel";
2229 hasSameNchan = hasSameNchanOverIFs();
2230 }
2231
2232 Fitter fitter = Fitter();
2233 fitter.setExpression("poly", order);
2234 //fitter.setIterClipping(thresClip, nIterClip);
2235
2236 int nRow = nrow();
2237 std::vector<bool> chanMask;
2238 int minEdgeSize = getIFNos().size()*2;
2239 STLineFinder lineFinder = STLineFinder();
2240 lineFinder.setOptions(threshold, 3, chanAvgLimit);
2241
2242 bool showProgress;
2243 int minNRow;
2244 parseProgressInfo(progressInfo, showProgress, minNRow);
2245
2246 for (int whichrow = 0; whichrow < nRow; ++whichrow) {
2247
2248 //-------------------------------------------------------
2249 //chanMask = getCompositeChanMask(whichrow, mask, edge, minEdgeSize, lineFinder);
2250 //-------------------------------------------------------
2251 int edgeSize = edge.size();
2252 std::vector<int> currentEdge;
2253 if (edgeSize >= 2) {
2254 int idx = 0;
2255 if (edgeSize > 2) {
2256 if (edgeSize < minEdgeSize) {
2257 throw(AipsError("Length of edge element info is less than that of IFs"));
2258 }
2259 idx = 2 * getIF(whichrow);
2260 }
2261 currentEdge.push_back(edge[idx]);
2262 currentEdge.push_back(edge[idx+1]);
2263 } else {
2264 throw(AipsError("Wrong length of edge element"));
2265 }
2266 lineFinder.setData(getSpectrum(whichrow));
2267 lineFinder.findLines(getCompositeChanMask(whichrow, mask), currentEdge, whichrow);
2268 chanMask = lineFinder.getMask();
2269 //-------------------------------------------------------
2270
2271 fitBaseline(chanMask, whichrow, fitter);
2272 setSpectrum((getResidual ? fitter.getResidual() : fitter.getFit()), whichrow);
2273
2274 outputFittingResult(outLogger, outTextFile, chanMask, whichrow, coordInfo, hasSameNchan, ofs, "autoPolyBaseline()", fitter);
2275 showProgressOnTerminal(whichrow, nRow, showProgress, minNRow);
2276 }
2277
2278 if (outTextFile) ofs.close();
2279
2280 } catch (...) {
2281 throw;
2282 }
2283}
2284
2285void Scantable::cubicSplineBaseline(const std::vector<bool>& mask, int nPiece, float thresClip, int nIterClip, bool getResidual, const std::string& progressInfo, const bool outLogger, const std::string& blfile)
2286{
2287 try {
2288 ofstream ofs;
2289 String coordInfo = "";
2290 bool hasSameNchan = true;
2291 bool outTextFile = false;
2292
2293 if (blfile != "") {
2294 ofs.open(blfile.c_str(), ios::out | ios::app);
2295 if (ofs) outTextFile = true;
2296 }
2297
2298 if (outLogger || outTextFile) {
2299 coordInfo = getCoordInfo()[0];
2300 if (coordInfo == "") coordInfo = "channel";
2301 hasSameNchan = hasSameNchanOverIFs();
2302 }
2303
2304 //Fitter fitter = Fitter();
2305 //fitter.setExpression("cspline", nPiece);
2306 //fitter.setIterClipping(thresClip, nIterClip);
2307
2308 bool showProgress;
2309 int minNRow;
2310 parseProgressInfo(progressInfo, showProgress, minNRow);
2311
2312 int nRow = nrow();
2313 std::vector<bool> chanMask;
2314
2315 //--------------------------------
2316 for (int whichrow = 0; whichrow < nRow; ++whichrow) {
2317 chanMask = getCompositeChanMask(whichrow, mask);
2318 //fitBaseline(chanMask, whichrow, fitter);
2319 //setSpectrum((getResidual ? fitter.getResidual() : fitter.getFit()), whichrow);
2320 std::vector<int> pieceEdges(nPiece+1);
2321 std::vector<float> params(nPiece*4);
2322 int nClipped = 0;
2323 std::vector<float> res = doCubicSplineFitting(getSpectrum(whichrow), chanMask, nPiece, pieceEdges, params, nClipped, thresClip, nIterClip, getResidual);
2324 setSpectrum(res, whichrow);
2325 //
2326
2327 outputFittingResult(outLogger, outTextFile, chanMask, whichrow, coordInfo, hasSameNchan, ofs, "cubicSplineBaseline()", pieceEdges, params, nClipped);
2328 showProgressOnTerminal(whichrow, nRow, showProgress, minNRow);
2329 }
2330 //--------------------------------
2331
2332 if (outTextFile) ofs.close();
2333
2334 } catch (...) {
2335 throw;
2336 }
2337}
2338
2339void Scantable::autoCubicSplineBaseline(const std::vector<bool>& mask, int nPiece, float thresClip, int nIterClip, const std::vector<int>& edge, float threshold, int chanAvgLimit, bool getResidual, const std::string& progressInfo, const bool outLogger, const std::string& blfile)
2340{
2341 try {
2342 ofstream ofs;
2343 String coordInfo = "";
2344 bool hasSameNchan = true;
2345 bool outTextFile = false;
2346
2347 if (blfile != "") {
2348 ofs.open(blfile.c_str(), ios::out | ios::app);
2349 if (ofs) outTextFile = true;
2350 }
2351
2352 if (outLogger || outTextFile) {
2353 coordInfo = getCoordInfo()[0];
2354 if (coordInfo == "") coordInfo = "channel";
2355 hasSameNchan = hasSameNchanOverIFs();
2356 }
2357
2358 //Fitter fitter = Fitter();
2359 //fitter.setExpression("cspline", nPiece);
2360 //fitter.setIterClipping(thresClip, nIterClip);
2361
2362 int nRow = nrow();
2363 std::vector<bool> chanMask;
2364 int minEdgeSize = getIFNos().size()*2;
2365 STLineFinder lineFinder = STLineFinder();
2366 lineFinder.setOptions(threshold, 3, chanAvgLimit);
2367
2368 bool showProgress;
2369 int minNRow;
2370 parseProgressInfo(progressInfo, showProgress, minNRow);
2371
2372 for (int whichrow = 0; whichrow < nRow; ++whichrow) {
2373
2374 //-------------------------------------------------------
2375 //chanMask = getCompositeChanMask(whichrow, mask, edge, minEdgeSize, lineFinder);
2376 //-------------------------------------------------------
2377 int edgeSize = edge.size();
2378 std::vector<int> currentEdge;
2379 if (edgeSize >= 2) {
2380 int idx = 0;
2381 if (edgeSize > 2) {
2382 if (edgeSize < minEdgeSize) {
2383 throw(AipsError("Length of edge element info is less than that of IFs"));
2384 }
2385 idx = 2 * getIF(whichrow);
2386 }
2387 currentEdge.push_back(edge[idx]);
2388 currentEdge.push_back(edge[idx+1]);
2389 } else {
2390 throw(AipsError("Wrong length of edge element"));
2391 }
2392 lineFinder.setData(getSpectrum(whichrow));
2393 lineFinder.findLines(getCompositeChanMask(whichrow, mask), currentEdge, whichrow);
2394 chanMask = lineFinder.getMask();
2395 //-------------------------------------------------------
2396
2397
2398 //fitBaseline(chanMask, whichrow, fitter);
2399 //setSpectrum((getResidual ? fitter.getResidual() : fitter.getFit()), whichrow);
2400 std::vector<int> pieceEdges(nPiece+1);
2401 std::vector<float> params(nPiece*4);
2402 int nClipped = 0;
2403 std::vector<float> res = doCubicSplineFitting(getSpectrum(whichrow), chanMask, nPiece, pieceEdges, params, nClipped, thresClip, nIterClip, getResidual);
2404 setSpectrum(res, whichrow);
2405 //
2406
2407 outputFittingResult(outLogger, outTextFile, chanMask, whichrow, coordInfo, hasSameNchan, ofs, "autoCubicSplineBaseline()", pieceEdges, params, nClipped);
2408 showProgressOnTerminal(whichrow, nRow, showProgress, minNRow);
2409 }
2410
2411 if (outTextFile) ofs.close();
2412
2413 } catch (...) {
2414 throw;
2415 }
2416}
2417
2418std::vector<float> Scantable::doCubicSplineFitting(const std::vector<float>& data, const std::vector<bool>& mask, int nPiece, std::vector<int>& idxEdge, std::vector<float>& params, int& nClipped, float thresClip, int nIterClip, bool getResidual)
2419{
2420 if (data.size() != mask.size()) {
2421 throw(AipsError("data and mask sizes are not identical"));
2422 }
2423 if (nPiece < 1) {
2424 throw(AipsError("number of the sections must be one or more"));
2425 }
2426
2427 int nChan = data.size();
2428 std::vector<int> maskArray(nChan);
2429 std::vector<int> x(nChan);
2430 int j = 0;
2431 for (int i = 0; i < nChan; ++i) {
2432 maskArray[i] = mask[i] ? 1 : 0;
2433 if (mask[i]) {
2434 x[j] = i;
2435 j++;
2436 }
2437 }
2438 int initNData = j;
2439
2440 if (initNData < nPiece) {
2441 throw(AipsError("too few non-flagged channels"));
2442 }
2443
2444 int nElement = (int)(floor(floor((double)(initNData/nPiece))+0.5));
2445 std::vector<double> invEdge(nPiece-1);
2446 idxEdge[0] = x[0];
2447 for (int i = 1; i < nPiece; ++i) {
2448 int valX = x[nElement*i];
2449 idxEdge[i] = valX;
2450 invEdge[i-1] = 1.0/(double)valX;
2451 }
2452 idxEdge[nPiece] = x[initNData-1]+1;
2453
2454 int nData = initNData;
2455 int nDOF = nPiece + 3; //number of parameters to solve, namely, 4+(nPiece-1).
2456
2457 std::vector<double> x1(nChan), x2(nChan), x3(nChan);
2458 std::vector<double> z1(nChan), x1z1(nChan), x2z1(nChan), x3z1(nChan);
2459 std::vector<double> r1(nChan), residual(nChan);
2460 for (int i = 0; i < nChan; ++i) {
2461 double di = (double)i;
2462 double dD = (double)data[i];
2463 x1[i] = di;
2464 x2[i] = di*di;
2465 x3[i] = di*di*di;
2466 z1[i] = dD;
2467 x1z1[i] = dD*di;
2468 x2z1[i] = dD*di*di;
2469 x3z1[i] = dD*di*di*di;
2470 r1[i] = 0.0;
2471 residual[i] = 0.0;
2472 }
2473
2474 for (int nClip = 0; nClip < nIterClip+1; ++nClip) {
2475 // xMatrix : horizontal concatenation of
2476 // the least-sq. matrix (left) and an
2477 // identity matrix (right).
2478 // the right part is used to calculate the inverse matrix of the left part.
2479 double xMatrix[nDOF][2*nDOF];
2480 double zMatrix[nDOF];
2481 for (int i = 0; i < nDOF; ++i) {
2482 for (int j = 0; j < 2*nDOF; ++j) {
2483 xMatrix[i][j] = 0.0;
2484 }
2485 xMatrix[i][nDOF+i] = 1.0;
2486 zMatrix[i] = 0.0;
2487 }
2488
2489 for (int n = 0; n < nPiece; ++n) {
2490 int nUseDataInPiece = 0;
2491 for (int i = idxEdge[n]; i < idxEdge[n+1]; ++i) {
2492
2493 if (maskArray[i] == 0) continue;
2494
2495 xMatrix[0][0] += 1.0;
2496 xMatrix[0][1] += x1[i];
2497 xMatrix[0][2] += x2[i];
2498 xMatrix[0][3] += x3[i];
2499 xMatrix[1][1] += x2[i];
2500 xMatrix[1][2] += x3[i];
2501 xMatrix[1][3] += x2[i]*x2[i];
2502 xMatrix[2][2] += x2[i]*x2[i];
2503 xMatrix[2][3] += x3[i]*x2[i];
2504 xMatrix[3][3] += x3[i]*x3[i];
2505 zMatrix[0] += z1[i];
2506 zMatrix[1] += x1z1[i];
2507 zMatrix[2] += x2z1[i];
2508 zMatrix[3] += x3z1[i];
2509
2510 for (int j = 0; j < n; ++j) {
2511 double q = 1.0 - x1[i]*invEdge[j];
2512 q = q*q*q;
2513 xMatrix[0][j+4] += q;
2514 xMatrix[1][j+4] += q*x1[i];
2515 xMatrix[2][j+4] += q*x2[i];
2516 xMatrix[3][j+4] += q*x3[i];
2517 for (int k = 0; k < j; ++k) {
2518 double r = 1.0 - x1[i]*invEdge[k];
2519 r = r*r*r;
2520 xMatrix[k+4][j+4] += r*q;
2521 }
2522 xMatrix[j+4][j+4] += q*q;
2523 zMatrix[j+4] += q*z1[i];
2524 }
2525
2526 nUseDataInPiece++;
2527 }
2528
2529 if (nUseDataInPiece < 1) {
2530 std::vector<string> suffixOfPieceNumber(4);
2531 suffixOfPieceNumber[0] = "th";
2532 suffixOfPieceNumber[1] = "st";
2533 suffixOfPieceNumber[2] = "nd";
2534 suffixOfPieceNumber[3] = "rd";
2535 int idxNoDataPiece = (n % 10 <= 3) ? n : 0;
2536 ostringstream oss;
2537 oss << "all channels clipped or masked in " << n << suffixOfPieceNumber[idxNoDataPiece];
2538 oss << " piece of the spectrum. can't execute fitting anymore.";
2539 throw(AipsError(String(oss)));
2540 }
2541 }
2542
2543 for (int i = 0; i < nDOF; ++i) {
2544 for (int j = 0; j < i; ++j) {
2545 xMatrix[i][j] = xMatrix[j][i];
2546 }
2547 }
2548
2549 std::vector<double> invDiag(nDOF);
2550 for (int i = 0; i < nDOF; ++i) {
2551 invDiag[i] = 1.0/xMatrix[i][i];
2552 for (int j = 0; j < nDOF; ++j) {
2553 xMatrix[i][j] *= invDiag[i];
2554 }
2555 }
2556
2557 for (int k = 0; k < nDOF; ++k) {
2558 for (int i = 0; i < nDOF; ++i) {
2559 if (i != k) {
2560 double factor1 = xMatrix[k][k];
2561 double factor2 = xMatrix[i][k];
2562 for (int j = k; j < 2*nDOF; ++j) {
2563 xMatrix[i][j] *= factor1;
2564 xMatrix[i][j] -= xMatrix[k][j]*factor2;
2565 xMatrix[i][j] /= factor1;
2566 }
2567 }
2568 }
2569 double xDiag = xMatrix[k][k];
2570 for (int j = k; j < 2*nDOF; ++j) {
2571 xMatrix[k][j] /= xDiag;
2572 }
2573 }
2574
2575 for (int i = 0; i < nDOF; ++i) {
2576 for (int j = 0; j < nDOF; ++j) {
2577 xMatrix[i][nDOF+j] *= invDiag[j];
2578 }
2579 }
2580 //compute a vector y which consists of the coefficients of the best-fit spline curves
2581 //(a0,a1,a2,a3(,b3,c3,...)), namely, the ones for the leftmost piece and the ones of
2582 //cubic terms for the other pieces (in case nPiece>1).
2583 std::vector<double> y(nDOF);
2584 for (int i = 0; i < nDOF; ++i) {
2585 y[i] = 0.0;
2586 for (int j = 0; j < nDOF; ++j) {
2587 y[i] += xMatrix[i][nDOF+j]*zMatrix[j];
2588 }
2589 }
2590
2591 double a0 = y[0];
2592 double a1 = y[1];
2593 double a2 = y[2];
2594 double a3 = y[3];
2595
2596 int j = 0;
2597 for (int n = 0; n < nPiece; ++n) {
2598 for (int i = idxEdge[n]; i < idxEdge[n+1]; ++i) {
2599 r1[i] = a0 + a1*x1[i] + a2*x2[i] + a3*x3[i];
2600 }
2601 params[j] = a0;
2602 params[j+1] = a1;
2603 params[j+2] = a2;
2604 params[j+3] = a3;
2605 j += 4;
2606
2607 if (n == nPiece-1) break;
2608
2609 double d = y[4+n];
2610 double iE = invEdge[n];
2611 a0 += d;
2612 a1 -= 3.0*d*iE;
2613 a2 += 3.0*d*iE*iE;
2614 a3 -= d*iE*iE*iE;
2615 }
2616
2617 //subtract constant value for masked regions at the edge of spectrum
2618 if (idxEdge[0] > 0) {
2619 int n = idxEdge[0];
2620 for (int i = 0; i < idxEdge[0]; ++i) {
2621 //--cubic extrapolate--
2622 //r1[i] = params[0] + params[1]*x1[i] + params[2]*x2[i] + params[3]*x3[i];
2623 //--linear extrapolate--
2624 //r1[i] = (r1[n+1] - r1[n])/(x1[n+1] - x1[n])*(x1[i] - x1[n]) + r1[n];
2625 //--constant--
2626 r1[i] = r1[n];
2627 }
2628 }
2629 if (idxEdge[nPiece] < nChan) {
2630 int n = idxEdge[nPiece]-1;
2631 for (int i = idxEdge[nPiece]; i < nChan; ++i) {
2632 //--cubic extrapolate--
2633 //int m = 4*(nPiece-1);
2634 //r1[i] = params[m] + params[m+1]*x1[i] + params[m+2]*x2[i] + params[m+3]*x3[i];
2635 //--linear extrapolate--
2636 //r1[i] = (r1[n-1] - r1[n])/(x1[n-1] - x1[n])*(x1[i] - x1[n]) + r1[n];
2637 //--constant--
2638 r1[i] = r1[n];
2639 }
2640 }
2641
2642 for (int i = 0; i < nChan; ++i) {
2643 residual[i] = z1[i] - r1[i];
2644 }
2645
2646 if ((nClip == nIterClip) || (thresClip <= 0.0)) {
2647 break;
2648 } else {
2649 double stdDev = 0.0;
2650 for (int i = 0; i < nChan; ++i) {
2651 stdDev += residual[i]*residual[i]*(double)maskArray[i];
2652 }
2653 stdDev = sqrt(stdDev/(double)nData);
2654
2655 double thres = stdDev * thresClip;
2656 int newNData = 0;
2657 for (int i = 0; i < nChan; ++i) {
2658 if (abs(residual[i]) >= thres) {
2659 maskArray[i] = 0;
2660 }
2661 if (maskArray[i] > 0) {
2662 newNData++;
2663 }
2664 }
2665 if (newNData == nData) {
2666 break; //no more flag to add. iteration stops.
2667 } else {
2668 nData = newNData;
2669 }
2670 }
2671 }
2672
2673 nClipped = initNData - nData;
2674
2675 std::vector<float> result(nChan);
2676 if (getResidual) {
2677 for (int i = 0; i < nChan; ++i) {
2678 result[i] = (float)residual[i];
2679 }
2680 } else {
2681 for (int i = 0; i < nChan; ++i) {
2682 result[i] = (float)r1[i];
2683 }
2684 }
2685
2686 return result;
2687}
2688
2689void Scantable::selectWaveNumbers(const int whichrow, const std::vector<bool>& chanMask, const bool applyFFT, const std::string& fftMethod, const std::string& fftThresh, const std::vector<int>& addNWaves, const std::vector<int>& rejectNWaves, std::vector<int>& nWaves)
2690{
2691 nWaves.clear();
2692
2693 if (applyFFT) {
2694 string fftThAttr;
2695 float fftThSigma;
2696 int fftThTop;
2697 parseThresholdExpression(fftThresh, fftThAttr, fftThSigma, fftThTop);
2698 doSelectWaveNumbers(whichrow, chanMask, fftMethod, fftThSigma, fftThTop, fftThAttr, nWaves);
2699 }
2700
2701 addAuxWaveNumbers(addNWaves, rejectNWaves, nWaves);
2702}
2703
2704void Scantable::parseThresholdExpression(const std::string& fftThresh, std::string& fftThAttr, float& fftThSigma, int& fftThTop)
2705{
2706 uInt idxSigma = fftThresh.find("sigma");
2707 uInt idxTop = fftThresh.find("top");
2708
2709 if (idxSigma == fftThresh.size() - 5) {
2710 std::istringstream is(fftThresh.substr(0, fftThresh.size() - 5));
2711 is >> fftThSigma;
2712 fftThAttr = "sigma";
2713 } else if (idxTop == 0) {
2714 std::istringstream is(fftThresh.substr(3));
2715 is >> fftThTop;
2716 fftThAttr = "top";
2717 } else {
2718 bool isNumber = true;
2719 for (uInt i = 0; i < fftThresh.size()-1; ++i) {
2720 char ch = (fftThresh.substr(i, 1).c_str())[0];
2721 if (!(isdigit(ch) || (fftThresh.substr(i, 1) == "."))) {
2722 isNumber = false;
2723 break;
2724 }
2725 }
2726 if (isNumber) {
2727 std::istringstream is(fftThresh);
2728 is >> fftThSigma;
2729 fftThAttr = "sigma";
2730 } else {
2731 throw(AipsError("fftthresh has a wrong value"));
2732 }
2733 }
2734}
2735
2736void 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)
2737{
2738 std::vector<float> fspec;
2739 if (fftMethod == "fft") {
2740 fspec = execFFT(whichrow, chanMask, false, true);
2741 //} else if (fftMethod == "lsp") {
2742 // fspec = lombScarglePeriodogram(whichrow);
2743 }
2744
2745 if (fftThAttr == "sigma") {
2746 float mean = 0.0;
2747 float mean2 = 0.0;
2748 for (uInt i = 0; i < fspec.size(); ++i) {
2749 mean += fspec[i];
2750 mean2 += fspec[i]*fspec[i];
2751 }
2752 mean /= float(fspec.size());
2753 mean2 /= float(fspec.size());
2754 float thres = mean + fftThSigma * float(sqrt(mean2 - mean*mean));
2755
2756 for (uInt i = 0; i < fspec.size(); ++i) {
2757 if (fspec[i] >= thres) {
2758 nWaves.push_back(i);
2759 }
2760 }
2761
2762 } else if (fftThAttr == "top") {
2763 for (int i = 0; i < fftThTop; ++i) {
2764 float max = 0.0;
2765 int maxIdx = 0;
2766 for (uInt j = 0; j < fspec.size(); ++j) {
2767 if (fspec[j] > max) {
2768 max = fspec[j];
2769 maxIdx = j;
2770 }
2771 }
2772 nWaves.push_back(maxIdx);
2773 fspec[maxIdx] = 0.0;
2774 }
2775
2776 }
2777
2778 if (nWaves.size() > 1) {
2779 sort(nWaves.begin(), nWaves.end());
2780 }
2781}
2782
2783void Scantable::addAuxWaveNumbers(const std::vector<int>& addNWaves, const std::vector<int>& rejectNWaves, std::vector<int>& nWaves)
2784{
2785 for (uInt i = 0; i < addNWaves.size(); ++i) {
2786 bool found = false;
2787 for (uInt j = 0; j < nWaves.size(); ++j) {
2788 if (nWaves[j] == addNWaves[i]) {
2789 found = true;
2790 break;
2791 }
2792 }
2793 if (!found) nWaves.push_back(addNWaves[i]);
2794 }
2795
2796 for (uInt i = 0; i < rejectNWaves.size(); ++i) {
2797 for (std::vector<int>::iterator j = nWaves.begin(); j != nWaves.end(); ) {
2798 if (*j == rejectNWaves[i]) {
2799 j = nWaves.erase(j);
2800 } else {
2801 ++j;
2802 }
2803 }
2804 }
2805
2806 if (nWaves.size() > 1) {
2807 sort(nWaves.begin(), nWaves.end());
2808 unique(nWaves.begin(), nWaves.end());
2809 }
2810}
2811
2812void Scantable::sinusoidBaseline(const std::vector<bool>& mask, const bool applyFFT, const std::string& fftMethod, const std::string& fftThresh, const std::vector<int>& addNWaves, const std::vector<int>& rejectNWaves, float thresClip, int nIterClip, bool getResidual, const std::string& progressInfo, const bool outLogger, const std::string& blfile)
2813{
2814 try {
2815 ofstream ofs;
2816 String coordInfo = "";
2817 bool hasSameNchan = true;
2818 bool outTextFile = false;
2819
2820 if (blfile != "") {
2821 ofs.open(blfile.c_str(), ios::out | ios::app);
2822 if (ofs) outTextFile = true;
2823 }
2824
2825 if (outLogger || outTextFile) {
2826 coordInfo = getCoordInfo()[0];
2827 if (coordInfo == "") coordInfo = "channel";
2828 hasSameNchan = hasSameNchanOverIFs();
2829 }
2830
2831 //Fitter fitter = Fitter();
2832 //fitter.setExpression("sinusoid", nWaves);
2833 //fitter.setIterClipping(thresClip, nIterClip);
2834
2835 int nRow = nrow();
2836 std::vector<bool> chanMask;
2837 std::vector<int> nWaves;
2838
2839 bool showProgress;
2840 int minNRow;
2841 parseProgressInfo(progressInfo, showProgress, minNRow);
2842
2843 for (int whichrow = 0; whichrow < nRow; ++whichrow) {
2844 chanMask = getCompositeChanMask(whichrow, mask);
2845 selectWaveNumbers(whichrow, chanMask, applyFFT, fftMethod, fftThresh, addNWaves, rejectNWaves, nWaves);
2846
2847 //FOR DEBUGGING------------
2848 if (whichrow < 0) {// == nRow -1) {
2849 cout << "+++ i=" << setw(3) << whichrow << ", IF=" << setw(2) << getIF(whichrow);
2850 if (applyFFT) {
2851 cout << "[ ";
2852 for (uInt j = 0; j < nWaves.size(); ++j) {
2853 cout << nWaves[j] << ", ";
2854 }
2855 cout << " ] " << endl;
2856 }
2857 cout << flush;
2858 }
2859 //-------------------------
2860
2861 //fitBaseline(chanMask, whichrow, fitter);
2862 //setSpectrum((getResidual ? fitter.getResidual() : fitter.getFit()), whichrow);
2863 std::vector<float> params;
2864 int nClipped = 0;
2865 std::vector<float> res = doSinusoidFitting(getSpectrum(whichrow), chanMask, nWaves, params, nClipped, thresClip, nIterClip, getResidual);
2866 setSpectrum(res, whichrow);
2867 //
2868
2869 outputFittingResult(outLogger, outTextFile, chanMask, whichrow, coordInfo, hasSameNchan, ofs, "sinusoidBaseline()", params, nClipped);
2870 showProgressOnTerminal(whichrow, nRow, showProgress, minNRow);
2871 }
2872
2873 if (outTextFile) ofs.close();
2874
2875 } catch (...) {
2876 throw;
2877 }
2878}
2879
2880void Scantable::autoSinusoidBaseline(const std::vector<bool>& mask, const bool applyFFT, const std::string& fftMethod, const std::string& fftThresh, const std::vector<int>& addNWaves, const std::vector<int>& rejectNWaves, float thresClip, int nIterClip, const std::vector<int>& edge, float threshold, int chanAvgLimit, bool getResidual, const std::string& progressInfo, const bool outLogger, const std::string& blfile)
2881{
2882 try {
2883 ofstream ofs;
2884 String coordInfo = "";
2885 bool hasSameNchan = true;
2886 bool outTextFile = false;
2887
2888 if (blfile != "") {
2889 ofs.open(blfile.c_str(), ios::out | ios::app);
2890 if (ofs) outTextFile = true;
2891 }
2892
2893 if (outLogger || outTextFile) {
2894 coordInfo = getCoordInfo()[0];
2895 if (coordInfo == "") coordInfo = "channel";
2896 hasSameNchan = hasSameNchanOverIFs();
2897 }
2898
2899 //Fitter fitter = Fitter();
2900 //fitter.setExpression("sinusoid", nWaves);
2901 //fitter.setIterClipping(thresClip, nIterClip);
2902
2903 int nRow = nrow();
2904 std::vector<bool> chanMask;
2905 std::vector<int> nWaves;
2906
2907 int minEdgeSize = getIFNos().size()*2;
2908 STLineFinder lineFinder = STLineFinder();
2909 lineFinder.setOptions(threshold, 3, chanAvgLimit);
2910
2911 bool showProgress;
2912 int minNRow;
2913 parseProgressInfo(progressInfo, showProgress, minNRow);
2914
2915 for (int whichrow = 0; whichrow < nRow; ++whichrow) {
2916
2917 //-------------------------------------------------------
2918 //chanMask = getCompositeChanMask(whichrow, mask, edge, minEdgeSize, lineFinder);
2919 //-------------------------------------------------------
2920 int edgeSize = edge.size();
2921 std::vector<int> currentEdge;
2922 if (edgeSize >= 2) {
2923 int idx = 0;
2924 if (edgeSize > 2) {
2925 if (edgeSize < minEdgeSize) {
2926 throw(AipsError("Length of edge element info is less than that of IFs"));
2927 }
2928 idx = 2 * getIF(whichrow);
2929 }
2930 currentEdge.push_back(edge[idx]);
2931 currentEdge.push_back(edge[idx+1]);
2932 } else {
2933 throw(AipsError("Wrong length of edge element"));
2934 }
2935 lineFinder.setData(getSpectrum(whichrow));
2936 lineFinder.findLines(getCompositeChanMask(whichrow, mask), currentEdge, whichrow);
2937 chanMask = lineFinder.getMask();
2938 //-------------------------------------------------------
2939
2940 selectWaveNumbers(whichrow, chanMask, applyFFT, fftMethod, fftThresh, addNWaves, rejectNWaves, nWaves);
2941
2942 //fitBaseline(chanMask, whichrow, fitter);
2943 //setSpectrum((getResidual ? fitter.getResidual() : fitter.getFit()), whichrow);
2944 std::vector<float> params;
2945 int nClipped = 0;
2946 std::vector<float> res = doSinusoidFitting(getSpectrum(whichrow), chanMask, nWaves, params, nClipped, thresClip, nIterClip, getResidual);
2947 setSpectrum(res, whichrow);
2948 //
2949
2950 outputFittingResult(outLogger, outTextFile, chanMask, whichrow, coordInfo, hasSameNchan, ofs, "autoSinusoidBaseline()", params, nClipped);
2951 showProgressOnTerminal(whichrow, nRow, showProgress, minNRow);
2952 }
2953
2954 if (outTextFile) ofs.close();
2955
2956 } catch (...) {
2957 throw;
2958 }
2959}
2960
2961std::vector<float> Scantable::doSinusoidFitting(const std::vector<float>& data, const std::vector<bool>& mask, const std::vector<int>& waveNumbers, std::vector<float>& params, int& nClipped, float thresClip, int nIterClip, bool getResidual)
2962{
2963 if (data.size() != mask.size()) {
2964 throw(AipsError("data and mask sizes are not identical"));
2965 }
2966 if (data.size() < 2) {
2967 throw(AipsError("data size is too short"));
2968 }
2969 if (waveNumbers.size() == 0) {
2970 throw(AipsError("no wave numbers given"));
2971 }
2972 std::vector<int> nWaves; // sorted and uniqued array of wave numbers
2973 nWaves.reserve(waveNumbers.size());
2974 copy(waveNumbers.begin(), waveNumbers.end(), back_inserter(nWaves));
2975 sort(nWaves.begin(), nWaves.end());
2976 std::vector<int>::iterator end_it = unique(nWaves.begin(), nWaves.end());
2977 nWaves.erase(end_it, nWaves.end());
2978
2979 int minNWaves = nWaves[0];
2980 if (minNWaves < 0) {
2981 throw(AipsError("wave number must be positive or zero (i.e. constant)"));
2982 }
2983 bool hasConstantTerm = (minNWaves == 0);
2984
2985 int nChan = data.size();
2986 std::vector<int> maskArray;
2987 std::vector<int> x;
2988 for (int i = 0; i < nChan; ++i) {
2989 maskArray.push_back(mask[i] ? 1 : 0);
2990 if (mask[i]) {
2991 x.push_back(i);
2992 }
2993 }
2994
2995 int initNData = x.size();
2996
2997 int nData = initNData;
2998 int nDOF = nWaves.size() * 2 - (hasConstantTerm ? 1 : 0); //number of parameters to solve.
2999
3000 const double PI = 6.0 * asin(0.5); // PI (= 3.141592653...)
3001 double baseXFactor = 2.0*PI/(double)(nChan-1); //the denominator (nChan-1) should be changed to (xdata[nChan-1]-xdata[0]) for accepting x-values given in velocity or frequency when this function is moved to fitter. (2011/03/30 WK)
3002
3003 // xArray : contains elemental values for computing the least-square matrix.
3004 // xArray.size() is nDOF and xArray[*].size() is nChan.
3005 // Each xArray element are as follows:
3006 // xArray[0] = {1.0, 1.0, 1.0, ..., 1.0},
3007 // xArray[2n-1] = {sin(nPI/L*x[0]), sin(nPI/L*x[1]), ..., sin(nPI/L*x[nChan])},
3008 // xArray[2n] = {cos(nPI/L*x[0]), cos(nPI/L*x[1]), ..., cos(nPI/L*x[nChan])},
3009 // where (1 <= n <= nMaxWavesInSW),
3010 // or,
3011 // xArray[2n-1] = {sin(wn[n]PI/L*x[0]), sin(wn[n]PI/L*x[1]), ..., sin(wn[n]PI/L*x[nChan])},
3012 // xArray[2n] = {cos(wn[n]PI/L*x[0]), cos(wn[n]PI/L*x[1]), ..., cos(wn[n]PI/L*x[nChan])},
3013 // where wn[n] denotes waveNumbers[n] (1 <= n <= waveNumbers.size()).
3014 std::vector<std::vector<double> > xArray;
3015 if (hasConstantTerm) {
3016 std::vector<double> xu;
3017 for (int j = 0; j < nChan; ++j) {
3018 xu.push_back(1.0);
3019 }
3020 xArray.push_back(xu);
3021 }
3022 for (uInt i = (hasConstantTerm ? 1 : 0); i < nWaves.size(); ++i) {
3023 double xFactor = baseXFactor*(double)nWaves[i];
3024 std::vector<double> xs, xc;
3025 xs.clear();
3026 xc.clear();
3027 for (int j = 0; j < nChan; ++j) {
3028 xs.push_back(sin(xFactor*(double)j));
3029 xc.push_back(cos(xFactor*(double)j));
3030 }
3031 xArray.push_back(xs);
3032 xArray.push_back(xc);
3033 }
3034
3035 std::vector<double> z1, r1, residual;
3036 for (int i = 0; i < nChan; ++i) {
3037 z1.push_back((double)data[i]);
3038 r1.push_back(0.0);
3039 residual.push_back(0.0);
3040 }
3041
3042 for (int nClip = 0; nClip < nIterClip+1; ++nClip) {
3043 // xMatrix : horizontal concatenation of
3044 // the least-sq. matrix (left) and an
3045 // identity matrix (right).
3046 // the right part is used to calculate the inverse matrix of the left part.
3047 double xMatrix[nDOF][2*nDOF];
3048 double zMatrix[nDOF];
3049 for (int i = 0; i < nDOF; ++i) {
3050 for (int j = 0; j < 2*nDOF; ++j) {
3051 xMatrix[i][j] = 0.0;
3052 }
3053 xMatrix[i][nDOF+i] = 1.0;
3054 zMatrix[i] = 0.0;
3055 }
3056
3057 int nUseData = 0;
3058 for (int k = 0; k < nChan; ++k) {
3059 if (maskArray[k] == 0) continue;
3060
3061 for (int i = 0; i < nDOF; ++i) {
3062 for (int j = i; j < nDOF; ++j) {
3063 xMatrix[i][j] += xArray[i][k] * xArray[j][k];
3064 }
3065 zMatrix[i] += z1[k] * xArray[i][k];
3066 }
3067
3068 nUseData++;
3069 }
3070
3071 if (nUseData < 1) {
3072 throw(AipsError("all channels clipped or masked. can't execute fitting anymore."));
3073 }
3074
3075 for (int i = 0; i < nDOF; ++i) {
3076 for (int j = 0; j < i; ++j) {
3077 xMatrix[i][j] = xMatrix[j][i];
3078 }
3079 }
3080
3081 std::vector<double> invDiag;
3082 for (int i = 0; i < nDOF; ++i) {
3083 invDiag.push_back(1.0/xMatrix[i][i]);
3084 for (int j = 0; j < nDOF; ++j) {
3085 xMatrix[i][j] *= invDiag[i];
3086 }
3087 }
3088
3089 for (int k = 0; k < nDOF; ++k) {
3090 for (int i = 0; i < nDOF; ++i) {
3091 if (i != k) {
3092 double factor1 = xMatrix[k][k];
3093 double factor2 = xMatrix[i][k];
3094 for (int j = k; j < 2*nDOF; ++j) {
3095 xMatrix[i][j] *= factor1;
3096 xMatrix[i][j] -= xMatrix[k][j]*factor2;
3097 xMatrix[i][j] /= factor1;
3098 }
3099 }
3100 }
3101 double xDiag = xMatrix[k][k];
3102 for (int j = k; j < 2*nDOF; ++j) {
3103 xMatrix[k][j] /= xDiag;
3104 }
3105 }
3106
3107 for (int i = 0; i < nDOF; ++i) {
3108 for (int j = 0; j < nDOF; ++j) {
3109 xMatrix[i][nDOF+j] *= invDiag[j];
3110 }
3111 }
3112 //compute a vector y which consists of the coefficients of the sinusoids forming the
3113 //best-fit curves (a0,s1,c1,s2,c2,...), where a0 is constant and s* and c* are of sine
3114 //and cosine functions, respectively.
3115 std::vector<double> y;
3116 params.clear();
3117 for (int i = 0; i < nDOF; ++i) {
3118 y.push_back(0.0);
3119 for (int j = 0; j < nDOF; ++j) {
3120 y[i] += xMatrix[i][nDOF+j]*zMatrix[j];
3121 }
3122 params.push_back(y[i]);
3123 }
3124
3125 for (int i = 0; i < nChan; ++i) {
3126 r1[i] = y[0];
3127 for (int j = 1; j < nDOF; ++j) {
3128 r1[i] += y[j]*xArray[j][i];
3129 }
3130 residual[i] = z1[i] - r1[i];
3131 }
3132
3133 if ((nClip == nIterClip) || (thresClip <= 0.0)) {
3134 break;
3135 } else {
3136 double stdDev = 0.0;
3137 for (int i = 0; i < nChan; ++i) {
3138 stdDev += residual[i]*residual[i]*(double)maskArray[i];
3139 }
3140 stdDev = sqrt(stdDev/(double)nData);
3141
3142 double thres = stdDev * thresClip;
3143 int newNData = 0;
3144 for (int i = 0; i < nChan; ++i) {
3145 if (abs(residual[i]) >= thres) {
3146 maskArray[i] = 0;
3147 }
3148 if (maskArray[i] > 0) {
3149 newNData++;
3150 }
3151 }
3152 if (newNData == nData) {
3153 break; //no more flag to add. iteration stops.
3154 } else {
3155 nData = newNData;
3156 }
3157 }
3158 }
3159
3160 nClipped = initNData - nData;
3161
3162 std::vector<float> result;
3163 if (getResidual) {
3164 for (int i = 0; i < nChan; ++i) {
3165 result.push_back((float)residual[i]);
3166 }
3167 } else {
3168 for (int i = 0; i < nChan; ++i) {
3169 result.push_back((float)r1[i]);
3170 }
3171 }
3172
3173 return result;
3174}
3175
3176void Scantable::fitBaseline(const std::vector<bool>& mask, int whichrow, Fitter& fitter)
3177{
3178 std::vector<double> dAbcissa = getAbcissa(whichrow);
3179 std::vector<float> abcissa;
3180 for (uInt i = 0; i < dAbcissa.size(); ++i) {
3181 abcissa.push_back((float)dAbcissa[i]);
3182 }
3183 std::vector<float> spec = getSpectrum(whichrow);
3184
3185 fitter.setData(abcissa, spec, mask);
3186 fitter.lfit();
3187}
3188
3189std::vector<bool> Scantable::getCompositeChanMask(int whichrow, const std::vector<bool>& inMask)
3190{
3191 std::vector<bool> mask = getMask(whichrow);
3192 uInt maskSize = mask.size();
3193 if (maskSize != inMask.size()) {
3194 throw(AipsError("mask sizes are not the same."));
3195 }
3196 for (uInt i = 0; i < maskSize; ++i) {
3197 mask[i] = mask[i] && inMask[i];
3198 }
3199
3200 return mask;
3201}
3202
3203/*
3204std::vector<bool> Scantable::getCompositeChanMask(int whichrow, const std::vector<bool>& inMask, const std::vector<int>& edge, const int minEdgeSize, STLineFinder& lineFinder)
3205{
3206 int edgeSize = edge.size();
3207 std::vector<int> currentEdge;
3208 if (edgeSize >= 2) {
3209 int idx = 0;
3210 if (edgeSize > 2) {
3211 if (edgeSize < minEdgeSize) {
3212 throw(AipsError("Length of edge element info is less than that of IFs"));
3213 }
3214 idx = 2 * getIF(whichrow);
3215 }
3216 currentEdge.push_back(edge[idx]);
3217 currentEdge.push_back(edge[idx+1]);
3218 } else {
3219 throw(AipsError("Wrong length of edge element"));
3220 }
3221
3222 lineFinder.setData(getSpectrum(whichrow));
3223 lineFinder.findLines(getCompositeChanMask(whichrow, inMask), currentEdge, whichrow);
3224
3225 return lineFinder.getMask();
3226}
3227*/
3228
3229/* for poly. the variations of outputFittingResult() should be merged into one eventually (2011/3/10 WK) */
3230void Scantable::outputFittingResult(bool outLogger, bool outTextFile, const std::vector<bool>& chanMask, int whichrow, const casa::String& coordInfo, bool hasSameNchan, ofstream& ofs, const casa::String& funcName, Fitter& fitter)
3231{
3232 if (outLogger || outTextFile) {
3233 std::vector<float> params = fitter.getParameters();
3234 std::vector<bool> fixed = fitter.getFixedParameters();
3235 float rms = getRms(chanMask, whichrow);
3236 String masklist = getMaskRangeList(chanMask, whichrow, coordInfo, hasSameNchan);
3237
3238 if (outLogger) {
3239 LogIO ols(LogOrigin("Scantable", funcName, WHERE));
3240 ols << formatBaselineParams(params, fixed, rms, -1, masklist, whichrow, false) << LogIO::POST ;
3241 }
3242 if (outTextFile) {
3243 ofs << formatBaselineParams(params, fixed, rms, -1, masklist, whichrow, true) << flush;
3244 }
3245 }
3246}
3247
3248/* for cspline. will be merged once cspline is available in fitter (2011/3/10 WK) */
3249void Scantable::outputFittingResult(bool outLogger, bool outTextFile, const std::vector<bool>& chanMask, int whichrow, const casa::String& coordInfo, bool hasSameNchan, ofstream& ofs, const casa::String& funcName, const std::vector<int>& edge, const std::vector<float>& params, const int nClipped)
3250{
3251 if (outLogger || outTextFile) {
3252 float rms = getRms(chanMask, whichrow);
3253 String masklist = getMaskRangeList(chanMask, whichrow, coordInfo, hasSameNchan);
3254 std::vector<bool> fixed;
3255 fixed.clear();
3256
3257 if (outLogger) {
3258 LogIO ols(LogOrigin("Scantable", funcName, WHERE));
3259 ols << formatPiecewiseBaselineParams(edge, params, fixed, rms, nClipped, masklist, whichrow, false) << LogIO::POST ;
3260 }
3261 if (outTextFile) {
3262 ofs << formatPiecewiseBaselineParams(edge, params, fixed, rms, nClipped, masklist, whichrow, true) << flush;
3263 }
3264 }
3265}
3266
3267/* for sinusoid. will be merged once sinusoid is available in fitter (2011/3/10 WK) */
3268void Scantable::outputFittingResult(bool outLogger, bool outTextFile, const std::vector<bool>& chanMask, int whichrow, const casa::String& coordInfo, bool hasSameNchan, ofstream& ofs, const casa::String& funcName, const std::vector<float>& params, const int nClipped)
3269{
3270 if (outLogger || outTextFile) {
3271 float rms = getRms(chanMask, whichrow);
3272 String masklist = getMaskRangeList(chanMask, whichrow, coordInfo, hasSameNchan);
3273 std::vector<bool> fixed;
3274 fixed.clear();
3275
3276 if (outLogger) {
3277 LogIO ols(LogOrigin("Scantable", funcName, WHERE));
3278 ols << formatBaselineParams(params, fixed, rms, nClipped, masklist, whichrow, false) << LogIO::POST ;
3279 }
3280 if (outTextFile) {
3281 ofs << formatBaselineParams(params, fixed, rms, nClipped, masklist, whichrow, true) << flush;
3282 }
3283 }
3284}
3285
3286void Scantable::parseProgressInfo(const std::string& progressInfo, bool& showProgress, int& minNRow)
3287{
3288 int idxDelimiter = progressInfo.find(",");
3289 if (idxDelimiter < 0) {
3290 throw(AipsError("wrong value in 'showprogress' parameter")) ;
3291 }
3292 showProgress = (progressInfo.substr(0, idxDelimiter) == "true");
3293 std::istringstream is(progressInfo.substr(idxDelimiter+1));
3294 is >> minNRow;
3295}
3296
3297void Scantable::showProgressOnTerminal(const int nProcessed, const int nTotal, const bool showProgress, const int nTotalThreshold)
3298{
3299 if (showProgress && (nTotal >= nTotalThreshold)) {
3300 int nInterval = int(floor(double(nTotal)/100.0));
3301 if (nInterval == 0) nInterval++;
3302
3303 if (nProcessed % nInterval == 0) {
3304 printf("\r"); //go to the head of line
3305 printf("\x1b[31m\x1b[1m"); //set red color, highlighted
3306 printf("[%3d%%]", (int)(100.0*(double(nProcessed+1))/(double(nTotal))) );
3307 printf("\x1b[39m\x1b[0m"); //set default attributes
3308 fflush(NULL);
3309 }
3310
3311 if (nProcessed == nTotal - 1) {
3312 printf("\r\x1b[K"); //clear
3313 fflush(NULL);
3314 }
3315
3316 }
3317}
3318
3319std::vector<float> Scantable::execFFT(const int whichrow, const std::vector<bool>& inMask, bool getRealImag, bool getAmplitudeOnly)
3320{
3321 std::vector<bool> mask = getMask(whichrow);
3322
3323 if (inMask.size() > 0) {
3324 uInt maskSize = mask.size();
3325 if (maskSize != inMask.size()) {
3326 throw(AipsError("mask sizes are not the same."));
3327 }
3328 for (uInt i = 0; i < maskSize; ++i) {
3329 mask[i] = mask[i] && inMask[i];
3330 }
3331 }
3332
3333 Vector<Float> spec = getSpectrum(whichrow);
3334 mathutil::doZeroOrderInterpolation(spec, mask);
3335
3336 FFTServer<Float,Complex> ffts;
3337 Vector<Complex> fftres;
3338 ffts.fft0(fftres, spec);
3339
3340 std::vector<float> res;
3341 float norm = float(2.0/double(spec.size()));
3342
3343 if (getRealImag) {
3344 for (uInt i = 0; i < fftres.size(); ++i) {
3345 res.push_back(real(fftres[i])*norm);
3346 res.push_back(imag(fftres[i])*norm);
3347 }
3348 } else {
3349 for (uInt i = 0; i < fftres.size(); ++i) {
3350 res.push_back(abs(fftres[i])*norm);
3351 if (!getAmplitudeOnly) res.push_back(arg(fftres[i]));
3352 }
3353 }
3354
3355 return res;
3356}
3357
3358
3359float Scantable::getRms(const std::vector<bool>& mask, int whichrow)
3360{
3361 Vector<Float> spec;
3362 specCol_.get(whichrow, spec);
3363
3364 float mean = 0.0;
3365 float smean = 0.0;
3366 int n = 0;
3367 for (uInt i = 0; i < spec.nelements(); ++i) {
3368 if (mask[i]) {
3369 mean += spec[i];
3370 smean += spec[i]*spec[i];
3371 n++;
3372 }
3373 }
3374
3375 mean /= (float)n;
3376 smean /= (float)n;
3377
3378 return sqrt(smean - mean*mean);
3379}
3380
3381
3382std::string Scantable::formatBaselineParamsHeader(int whichrow, const std::string& masklist, bool verbose) const
3383{
3384 ostringstream oss;
3385
3386 if (verbose) {
3387 oss << " Scan[" << getScan(whichrow) << "]";
3388 oss << " Beam[" << getBeam(whichrow) << "]";
3389 oss << " IF[" << getIF(whichrow) << "]";
3390 oss << " Pol[" << getPol(whichrow) << "]";
3391 oss << " Cycle[" << getCycle(whichrow) << "]: " << endl;
3392 oss << "Fitter range = " << masklist << endl;
3393 oss << "Baseline parameters" << endl;
3394 oss << flush;
3395 }
3396
3397 return String(oss);
3398}
3399
3400std::string Scantable::formatBaselineParamsFooter(float rms, int nClipped, bool verbose) const
3401{
3402 ostringstream oss;
3403
3404 if (verbose) {
3405 oss << "Results of baseline fit" << endl;
3406 oss << " rms = " << setprecision(6) << rms << endl;
3407 if (nClipped >= 0) {
3408 oss << " Number of clipped channels = " << nClipped << endl;
3409 }
3410 for (int i = 0; i < 60; ++i) {
3411 oss << "-";
3412 }
3413 oss << endl;
3414 oss << flush;
3415 }
3416
3417 return String(oss);
3418}
3419
3420std::string Scantable::formatBaselineParams(const std::vector<float>& params,
3421 const std::vector<bool>& fixed,
3422 float rms,
3423 int nClipped,
3424 const std::string& masklist,
3425 int whichrow,
3426 bool verbose,
3427 int start, int count,
3428 bool resetparamid) const
3429{
3430 int nParam = (int)(params.size());
3431
3432 if (nParam < 1) {
3433 return(" Not fitted");
3434 } else {
3435
3436 ostringstream oss;
3437 oss << formatBaselineParamsHeader(whichrow, masklist, verbose);
3438
3439 if (start < 0) start = 0;
3440 if (count < 0) count = nParam;
3441 int end = start + count;
3442 if (end > nParam) end = nParam;
3443 int paramidoffset = (resetparamid) ? (-start) : 0;
3444
3445 for (int i = start; i < end; ++i) {
3446 if (i > start) {
3447 oss << ",";
3448 }
3449 std::string sFix = ((fixed.size() > 0) && (fixed[i]) && verbose) ? "(fixed)" : "";
3450 oss << " p" << (i+paramidoffset) << sFix << "= " << right << setw(13) << setprecision(6) << params[i];
3451 }
3452
3453 oss << endl;
3454 oss << formatBaselineParamsFooter(rms, nClipped, verbose);
3455
3456 return String(oss);
3457 }
3458
3459}
3460
3461 std::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) const
3462{
3463 int nOutParam = (int)(params.size());
3464 int nPiece = (int)(ranges.size()) - 1;
3465
3466 if (nOutParam < 1) {
3467 return(" Not fitted");
3468 } else if (nPiece < 0) {
3469 return formatBaselineParams(params, fixed, rms, nClipped, masklist, whichrow, verbose);
3470 } else if (nPiece < 1) {
3471 return(" Bad count of the piece edge info");
3472 } else if (nOutParam % nPiece != 0) {
3473 return(" Bad count of the output baseline parameters");
3474 } else {
3475
3476 int nParam = nOutParam / nPiece;
3477
3478 ostringstream oss;
3479 oss << formatBaselineParamsHeader(whichrow, masklist, verbose);
3480
3481 stringstream ss;
3482 ss << ranges[nPiece] << flush;
3483 int wRange = ss.str().size() * 2 + 5;
3484
3485 for (int i = 0; i < nPiece; ++i) {
3486 ss.str("");
3487 ss << " [" << ranges[i] << "," << (ranges[i+1]-1) << "]";
3488 oss << left << setw(wRange) << ss.str();
3489 oss << formatBaselineParams(params, fixed, rms, 0, masklist, whichrow, false, i*nParam, nParam, true);
3490 }
3491
3492 oss << formatBaselineParamsFooter(rms, nClipped, verbose);
3493
3494 return String(oss);
3495 }
3496
3497}
3498
3499bool Scantable::hasSameNchanOverIFs()
3500{
3501 int nIF = nif(-1);
3502 int nCh;
3503 int totalPositiveNChan = 0;
3504 int nPositiveNChan = 0;
3505
3506 for (int i = 0; i < nIF; ++i) {
3507 nCh = nchan(i);
3508 if (nCh > 0) {
3509 totalPositiveNChan += nCh;
3510 nPositiveNChan++;
3511 }
3512 }
3513
3514 return (totalPositiveNChan == (nPositiveNChan * nchan(0)));
3515}
3516
3517std::string Scantable::getMaskRangeList(const std::vector<bool>& mask, int whichrow, const casa::String& coordInfo, bool hasSameNchan, bool verbose)
3518{
3519 if (mask.size() < 2) {
3520 throw(AipsError("The mask elements should be > 1"));
3521 }
3522 int IF = getIF(whichrow);
3523 if (mask.size() != (uInt)nchan(IF)) {
3524 throw(AipsError("Number of channels in scantable != number of mask elements"));
3525 }
3526
3527 if (verbose) {
3528 LogIO logOs(LogOrigin("Scantable", "getMaskRangeList()", WHERE));
3529 logOs << LogIO::WARN << "The current mask window unit is " << coordInfo;
3530 if (!hasSameNchan) {
3531 logOs << endl << "This mask is only valid for IF=" << IF;
3532 }
3533 logOs << LogIO::POST;
3534 }
3535
3536 std::vector<double> abcissa = getAbcissa(whichrow);
3537 std::vector<int> edge = getMaskEdgeIndices(mask);
3538
3539 ostringstream oss;
3540 oss.setf(ios::fixed);
3541 oss << setprecision(1) << "[";
3542 for (uInt i = 0; i < edge.size(); i+=2) {
3543 if (i > 0) oss << ",";
3544 oss << "[" << (float)abcissa[edge[i]] << "," << (float)abcissa[edge[i+1]] << "]";
3545 }
3546 oss << "]" << flush;
3547
3548 return String(oss);
3549}
3550
3551std::vector<int> Scantable::getMaskEdgeIndices(const std::vector<bool>& mask)
3552{
3553 if (mask.size() < 2) {
3554 throw(AipsError("The mask elements should be > 1"));
3555 }
3556
3557 std::vector<int> out, startIndices, endIndices;
3558 int maskSize = mask.size();
3559
3560 startIndices.clear();
3561 endIndices.clear();
3562
3563 if (mask[0]) {
3564 startIndices.push_back(0);
3565 }
3566 for (int i = 1; i < maskSize; ++i) {
3567 if ((!mask[i-1]) && mask[i]) {
3568 startIndices.push_back(i);
3569 } else if (mask[i-1] && (!mask[i])) {
3570 endIndices.push_back(i-1);
3571 }
3572 }
3573 if (mask[maskSize-1]) {
3574 endIndices.push_back(maskSize-1);
3575 }
3576
3577 if (startIndices.size() != endIndices.size()) {
3578 throw(AipsError("Inconsistent Mask Size: bad data?"));
3579 }
3580 for (uInt i = 0; i < startIndices.size(); ++i) {
3581 if (startIndices[i] > endIndices[i]) {
3582 throw(AipsError("Mask start index > mask end index"));
3583 }
3584 }
3585
3586 out.clear();
3587 for (uInt i = 0; i < startIndices.size(); ++i) {
3588 out.push_back(startIndices[i]);
3589 out.push_back(endIndices[i]);
3590 }
3591
3592 return out;
3593}
3594
3595vector<float> Scantable::getTsysSpectrum( int whichrow ) const
3596{
3597 Vector<Float> tsys( tsysCol_(whichrow) ) ;
3598 vector<float> stlTsys ;
3599 tsys.tovector( stlTsys ) ;
3600 return stlTsys ;
3601}
3602
3603
3604}
3605//namespace asap
Note: See TracBrowser for help on using the repository browser.