source: trunk/src/Scantable.cpp@ 2665

Last change on this file since 2665 was 2658, checked in by Malte Marquarding, 12 years ago

Ticket #199: Excised Logger::pushLog; now everything is using LogIO

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