source: trunk/src/Scantable.cpp @ 3048

Last change on this file since 3048 was 3048, checked in by Kana Sugimoto, 9 years ago

New Development: No

JIRA Issue: Yes (CAS-6572)

Ready for Test: Yes

Interface Changes: Yes

What Interface Changed: Added a parameter to define rowid to Scantable::doApplyBaselineTable.

Test Programs:

Put in Release Notes: No

Module(s): sdbaseline2

Description: A bug fix in mask definition.


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