source: tags/asap-4.1.0/src/Scantable.cpp @ 2662

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

merge from trunk into release candidate

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