source: trunk/src/Scantable.cpp @ 2344

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

New Development: No

JIRA Issue: No

Ready for Test: Yes

Interface Changes: No

What Interface Changed:

Test Programs:

Put in Release Notes: No

Module(s): xmlcasa

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


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