Line data Source code
1 : #include <algorithm>
2 : #include <cstdlib>
3 : #include <iostream>
4 : #include <map>
5 : #include <string>
6 : #include <sys/time.h>
7 : #include <vector>
8 :
9 : #include <casacore/casa/Arrays/ArrayMath.h>
10 : #include <casacore/casa/Arrays/Vector.h>
11 : #include <casacore/casa/Containers/Allocator.h>
12 : #include <casacore/casa/Containers/Block.h>
13 : #include <casacore/casa/Logging/LogIO.h>
14 : #include <casacore/casa/Logging/LogOrigin.h>
15 : #include <casacore/casa/Quanta/MVTime.h>
16 : #include <casacore/casa/Utilities/Assert.h>
17 : #include <casacore/casa/Utilities/GenSort.h>
18 : #include <casacore/ms/MeasurementSets/MSSpectralWindow.h>
19 : #include <casacore/ms/MSSel/MSSelection.h>
20 : #include <casacore/ms/MSSel/MSSelectionTools.h>
21 : #include <msvis/MSVis/VisibilityIterator2.h>
22 : #include <msvis/MSVis/VisSetUtil.h>
23 : #include <casacore/scimath/Fitting/GenericL2Fit.h>
24 : #include <casacore/scimath/Fitting/NonLinearFitLM.h>
25 : #include <casacore/scimath/Functionals/CompiledFunction.h>
26 : #include <casacore/scimath/Functionals/CompoundFunction.h>
27 : #include <casacore/scimath/Functionals/Function.h>
28 : #include <casacore/scimath/Functionals/Gaussian1D.h>
29 : #include <casacore/scimath/Functionals/Lorentzian1D.h>
30 : #include <casacore/scimath/Mathematics/Convolver.h>
31 : #include <casacore/scimath/Mathematics/VectorKernel.h>
32 : #include <singledish/SingleDish/BaselineTable.h>
33 : #include <singledish/SingleDish/BLParameterParser.h>
34 : #include <singledish/SingleDish/LineFinder.h>
35 : #include <singledish/SingleDish/SingleDishMS.h>
36 : #include <stdcasa/StdCasa/CasacSupport.h>
37 : #include <casacore/tables/Tables/ScalarColumn.h>
38 : #include <casa_sakura/SakuraAlignedArray.h>
39 :
40 : // for importasap and importnro
41 : #include <singledishfiller/Filler/NRO2MSReader.h>
42 : #include <singledishfiller/Filler/Scantable2MSReader.h>
43 : #include <singledishfiller/Filler/SingleDishMSFiller.h>
44 :
45 : #define _ORIGIN LogOrigin("SingleDishMS", __func__, WHERE)
46 :
47 : namespace {
48 : // Max number of rows to get in each iteration
49 : constexpr casacore::Int kNRowBlocking = 1000;
50 : // Sinusoid
51 : constexpr int SinusoidWaveNumber_kUpperLimit = -999;
52 : // Weight
53 : constexpr size_t WeightIndex_kStddev = 0;
54 : constexpr size_t WeightIndex_kRms = 1;
55 : constexpr size_t WeightIndex_kNum = 2;
56 :
57 0 : double gettimeofday_sec() {
58 : struct timeval tv;
59 0 : gettimeofday(&tv, NULL);
60 0 : return tv.tv_sec + (double) tv.tv_usec * 1.0e-6;
61 : }
62 :
63 : using casa::vi::VisBuffer2;
64 : using casacore::Matrix;
65 : using casacore::Cube;
66 : using casacore::Float;
67 : using casacore::Complex;
68 : using casacore::AipsError;
69 :
70 : template<class CUBE_ACCESSOR>
71 : struct DataAccessorInterface {
72 0 : static void GetCube(VisBuffer2 const &vb, Cube<Float> &cube) {
73 0 : real(cube, CUBE_ACCESSOR::GetVisCube(vb));
74 0 : }
75 : static void GetSlice(VisBuffer2 const &vb, size_t const iPol,
76 : Matrix<Float> &cubeSlice) {
77 : real(cubeSlice, CUBE_ACCESSOR::GetVisCube(vb).yzPlane(iPol));
78 : }
79 : };
80 :
81 : struct DataAccessor: public DataAccessorInterface<DataAccessor> {
82 0 : static Cube<Complex> GetVisCube(VisBuffer2 const &vb) {
83 0 : return vb.visCube();
84 : }
85 : };
86 :
87 : struct CorrectedDataAccessor: public DataAccessorInterface<CorrectedDataAccessor> {
88 0 : static Cube<Complex> GetVisCube(VisBuffer2 const &vb) {
89 0 : return vb.visCubeCorrected();
90 : }
91 : };
92 :
93 : struct FloatDataAccessor {
94 0 : static void GetCube(VisBuffer2 const &vb, Cube<Float> &cube) {
95 0 : cube = GetVisCube(vb);
96 0 : }
97 : static void GetSlice(VisBuffer2 const &vb, size_t const iPol,
98 : Matrix<Float> &cubeSlice) {
99 : cubeSlice = GetVisCube(vb).yzPlane(iPol);
100 : }
101 : private:
102 0 : static Cube<Float> GetVisCube(VisBuffer2 const &vb) {
103 0 : return vb.visCubeFloat();
104 : }
105 : };
106 :
107 0 : inline void GetCubeFromData(VisBuffer2 const &vb, Cube<Float> &cube) {
108 0 : DataAccessor::GetCube(vb, cube);
109 0 : }
110 :
111 0 : inline void GetCubeFromCorrected(VisBuffer2 const &vb, Cube<Float> &cube) {
112 0 : CorrectedDataAccessor::GetCube(vb, cube);
113 0 : }
114 :
115 0 : inline void GetCubeFromFloat(VisBuffer2 const &vb, Cube<Float> &cube) {
116 0 : FloatDataAccessor::GetCube(vb, cube);
117 0 : }
118 :
119 0 : inline void GetCubeDefault(VisBuffer2 const& /*vb*/, Cube<Float>& /*cube*/) {
120 0 : throw AipsError("Data accessor for VB2 is not properly configured.");
121 : }
122 :
123 0 : inline void compute_weight(size_t const num_data,
124 : float const data[/*num_data*/],
125 : bool const mask[/*num_data*/],
126 : std::vector<float>& weight) {
127 0 : for (size_t i = 0; i < WeightIndex_kNum; ++i) {
128 0 : weight[i] = 0.0;
129 : }
130 :
131 0 : int num_data_effective = 0;
132 0 : double sum = 0.0;
133 0 : double sum_sq = 0.0;
134 0 : for (size_t i = 0; i < num_data; ++i) {
135 0 : if (mask[i]) {
136 0 : num_data_effective++;
137 0 : sum += data[i];
138 0 : sum_sq += data[i] * data[i];
139 : }
140 : }
141 :
142 0 : if (num_data_effective > 0) {
143 0 : double factor = 1.0 / static_cast<double>(num_data_effective);
144 0 : double mean = sum * factor;
145 0 : double mean_sq = sum_sq * factor;
146 :
147 0 : std::vector<double> variance(WeightIndex_kNum);
148 0 : variance[WeightIndex_kStddev] = mean_sq - mean * mean;
149 0 : variance[WeightIndex_kRms] = mean_sq;
150 :
151 0 : auto do_compute_weight = [&](size_t idx) {
152 0 : if (variance[idx] > 0.0) {
153 0 : weight[idx] = static_cast<float>(1.0 / variance[idx]);
154 : } else {
155 0 : LogIO os(_ORIGIN);
156 0 : os << "Weight set to 0 for a bad data." << LogIO::WARN;
157 : }
158 0 : };
159 :
160 0 : do_compute_weight(WeightIndex_kStddev);
161 0 : do_compute_weight(WeightIndex_kRms);
162 : }
163 0 : }
164 :
165 : } // anonymous namespace
166 :
167 : using namespace casacore;
168 : namespace casa {
169 :
170 0 : SingleDishMS::SingleDishMS() : msname_(""), sdh_(0) {
171 0 : initialize();
172 0 : }
173 :
174 0 : SingleDishMS::SingleDishMS(string const& ms_name) : msname_(ms_name), sdh_(0) {
175 0 : LogIO os(_ORIGIN);
176 0 : initialize();
177 0 : }
178 :
179 0 : SingleDishMS::~SingleDishMS() {
180 0 : if (sdh_) {
181 0 : delete sdh_;
182 0 : sdh_ = 0;
183 : }
184 0 : msname_ = "";
185 0 : }
186 :
187 0 : void SingleDishMS::initialize() {
188 0 : in_column_ = MS::UNDEFINED_COLUMN;
189 : // out_column_ = MS::UNDEFINED_COLUMN;
190 0 : doSmoothing_ = false;
191 0 : doAtmCor_ = false;
192 0 : visCubeAccessor_ = GetCubeDefault;
193 0 : }
194 :
195 0 : bool SingleDishMS::close() {
196 0 : LogIO os(_ORIGIN);
197 0 : os << "Detaching from SingleDishMS" << LogIO::POST;
198 :
199 0 : if (sdh_) {
200 0 : delete sdh_;
201 0 : sdh_ = 0;
202 : }
203 0 : msname_ = "";
204 :
205 0 : return true;
206 : }
207 :
208 : ////////////////////////////////////////////////////////////////////////
209 : ///// Common utility functions
210 : ////////////////////////////////////////////////////////////////////////
211 0 : void SingleDishMS::setSelection(Record const &selection, bool const verbose) {
212 0 : LogIO os(_ORIGIN);
213 0 : if (!selection_.empty()) // selection is set before
214 0 : os << "Discard old selection and setting new one." << LogIO::POST;
215 0 : if (selection.empty()) // empty selection is passed
216 0 : os << "Resetting selection." << LogIO::POST;
217 :
218 0 : selection_ = selection;
219 : // Verbose output
220 0 : bool any_selection(false);
221 0 : if (verbose && !selection_.empty()) {
222 0 : String timeExpr(""), antennaExpr(""), fieldExpr(""), spwExpr(""),
223 0 : uvDistExpr(""), taQLExpr(""), polnExpr(""), scanExpr(""), arrayExpr(""),
224 0 : obsExpr(""), intentExpr("");
225 0 : timeExpr = get_field_as_casa_string(selection_, "timerange");
226 0 : antennaExpr = get_field_as_casa_string(selection_, "antenna");
227 0 : fieldExpr = get_field_as_casa_string(selection_, "field");
228 0 : spwExpr = get_field_as_casa_string(selection_, "spw");
229 0 : uvDistExpr = get_field_as_casa_string(selection_, "uvdist");
230 0 : taQLExpr = get_field_as_casa_string(selection_, "taql");
231 0 : polnExpr = get_field_as_casa_string(selection_, "correlation");
232 0 : scanExpr = get_field_as_casa_string(selection_, "scan");
233 0 : arrayExpr = get_field_as_casa_string(selection_, "array");
234 0 : intentExpr = get_field_as_casa_string(selection_, "intent");
235 0 : obsExpr = get_field_as_casa_string(selection_, "observation");
236 : // selection Summary
237 0 : os << "[Selection Summary]" << LogIO::POST;
238 0 : if (obsExpr != "") {
239 0 : any_selection = true;
240 0 : os << "- Observation: " << obsExpr << LogIO::POST;
241 : }
242 0 : if (antennaExpr != "") {
243 0 : any_selection = true;
244 0 : os << "- Antenna: " << antennaExpr << LogIO::POST;
245 : }
246 0 : if (fieldExpr != "") {
247 0 : any_selection = true;
248 0 : os << "- Field: " << fieldExpr << LogIO::POST;
249 : }
250 0 : if (spwExpr != "") {
251 0 : any_selection = true;
252 0 : os << "- SPW: " << spwExpr << LogIO::POST;
253 : }
254 0 : if (polnExpr != "") {
255 0 : any_selection = true;
256 0 : os << "- Pol: " << polnExpr << LogIO::POST;
257 : }
258 0 : if (scanExpr != "") {
259 0 : any_selection = true;
260 0 : os << "- Scan: " << scanExpr << LogIO::POST;
261 : }
262 0 : if (timeExpr != "") {
263 0 : any_selection = true;
264 0 : os << "- Time: " << timeExpr << LogIO::POST;
265 : }
266 0 : if (intentExpr != "") {
267 0 : any_selection = true;
268 0 : os << "- Intent: " << intentExpr << LogIO::POST;
269 : }
270 0 : if (arrayExpr != "") {
271 0 : any_selection = true;
272 0 : os << "- Array: " << arrayExpr << LogIO::POST;
273 : }
274 0 : if (uvDistExpr != "") {
275 0 : any_selection = true;
276 0 : os << "- UVDist: " << uvDistExpr << LogIO::POST;
277 : }
278 0 : if (taQLExpr != "") {
279 0 : any_selection = true;
280 0 : os << "- TaQL: " << taQLExpr << LogIO::POST;
281 : }
282 : {// reindex
283 : Int ifield;
284 0 : ifield = selection_.fieldNumber(String("reindex"));
285 0 : if (ifield > -1) {
286 0 : Bool reindex = selection_.asBool(ifield);
287 0 : os << "- Reindex: " << (reindex ? "ON" : "OFF" ) << LogIO::POST;
288 : }
289 : }
290 0 : if (!any_selection)
291 0 : os << "No valid selection parameter is set." << LogIO::WARN;
292 : }
293 0 : }
294 :
295 0 : void SingleDishMS::setAverage(Record const &average, bool const verbose) {
296 0 : LogIO os(_ORIGIN);
297 0 : if (!average_.empty()) // average is set before
298 0 : os << "Discard old average and setting new one." << LogIO::POST;
299 0 : if (average.empty()) // empty average is passed
300 0 : os << "Resetting average." << LogIO::POST;
301 :
302 0 : average_ = average;
303 :
304 0 : if (verbose && !average_.empty()) {
305 0 : LogIO os(_ORIGIN);
306 : Int ifield;
307 0 : ifield = average_.fieldNumber(String("timeaverage"));
308 0 : os << "[Averaging Settings]" << LogIO::POST;
309 0 : if (ifield < 0 || !average_.asBool(ifield)) {
310 0 : os << "No averaging will be done" << LogIO::POST;
311 0 : return;
312 : }
313 :
314 0 : String timebinExpr(""), timespanExpr(""), tweightExpr("");
315 0 : timebinExpr = get_field_as_casa_string(average_, "timebin");
316 0 : timespanExpr = get_field_as_casa_string(average_, "timespan");
317 0 : tweightExpr = get_field_as_casa_string(average_, "tweight");
318 0 : if (timebinExpr != "") {
319 0 : os << "- Time bin: " << timebinExpr << LogIO::POST;
320 : }
321 0 : if (timespanExpr != "") {
322 0 : os << "- Time span: " << timespanExpr << LogIO::POST;
323 : }
324 0 : if (tweightExpr != "") {
325 0 : os << "- Averaging weight: " << tweightExpr << LogIO::POST;
326 : }
327 :
328 : }
329 : }
330 :
331 0 : void SingleDishMS::setPolAverage(Record const &average, bool const verbose) {
332 0 : LogIO os(_ORIGIN);
333 0 : if (!pol_average_.empty()) // polaverage is set before
334 0 : os << "Discard old average and setting new one." << LogIO::POST;
335 0 : if (average.empty()) // empty polaverage is passed
336 0 : os << "Resetting average." << LogIO::POST;
337 :
338 0 : pol_average_ = average;
339 :
340 0 : if (verbose && !pol_average_.empty()) {
341 0 : LogIO os(_ORIGIN);
342 : Int ifield;
343 0 : ifield = pol_average_.fieldNumber(String("polaverage"));
344 0 : os << "[Polarization Averaging Settings]" << LogIO::POST;
345 0 : if (ifield < 0 || !pol_average_.asBool(ifield)) {
346 0 : os << "No polarization averaging will be done" << LogIO::POST;
347 0 : return;
348 : }
349 :
350 0 : String polAverageModeExpr("");
351 0 : polAverageModeExpr = get_field_as_casa_string(pol_average_, "polaveragemode");
352 0 : if (polAverageModeExpr != "") {
353 0 : os << "- Mode: " << polAverageModeExpr << LogIO::POST;
354 : }
355 : }
356 : }
357 :
358 0 : String SingleDishMS::get_field_as_casa_string(Record const &in_data,
359 : string const &field_name) {
360 : Int ifield;
361 0 : ifield = in_data.fieldNumber(String(field_name));
362 0 : if (ifield > -1)
363 0 : return in_data.asString(ifield);
364 0 : return "";
365 : }
366 :
367 0 : bool SingleDishMS::prepare_for_process(string const &in_column_name,
368 : string const &out_ms_name) {
369 : // Sort by single dish default
370 0 : return prepare_for_process(in_column_name, out_ms_name, Block<Int>(), true);
371 : }
372 :
373 0 : bool SingleDishMS::prepare_for_process(string const &in_column_name,
374 : string const &out_ms_name,
375 : Block<Int> const &sortColumns,
376 : bool const addDefaultSortCols) {
377 0 : LogIO os(_ORIGIN);
378 0 : AlwaysAssert(msname_ != "", AipsError);
379 : // define a column to read data from
380 0 : string in_column_name_lower = in_column_name;
381 : std::transform(
382 : in_column_name_lower.begin(),
383 : in_column_name_lower.end(),
384 : in_column_name_lower.begin(),
385 0 : [](unsigned char c) {return std::tolower(c);}
386 0 : );
387 0 : if (in_column_name_lower == "float_data") {
388 0 : in_column_ = MS::FLOAT_DATA;
389 0 : visCubeAccessor_ = GetCubeFromFloat;
390 0 : } else if (in_column_name_lower == "corrected") {
391 0 : in_column_ = MS::CORRECTED_DATA;
392 0 : visCubeAccessor_ = GetCubeFromCorrected;
393 0 : } else if (in_column_name_lower == "data") {
394 0 : in_column_ = MS::DATA;
395 0 : visCubeAccessor_ = GetCubeFromData;
396 : } else {
397 0 : throw(AipsError("Invalid data column name"));
398 : }
399 : // destroy SDMSManager
400 0 : if (sdh_)
401 0 : delete sdh_;
402 : // Configure record
403 0 : Record configure_param(selection_);
404 0 : format_selection(configure_param);
405 0 : configure_param.define("inputms", msname_);
406 0 : configure_param.define("outputms", out_ms_name);
407 0 : String in_name(in_column_name);
408 0 : in_name.upcase();
409 0 : configure_param.define("datacolumn", in_name);
410 : // merge averaging parameters
411 0 : configure_param.merge(average_);
412 : // The other available keys
413 : // - buffermode, realmodelcol, usewtspectrum, tileshape,
414 : // - chanaverage, chanbin, useweights,
415 : // - ddistart, hanning
416 : // - regridms, phasecenter, restfreq, outframe, interpolation, nspw,
417 : // - mode, nchan, start, width, veltype,
418 : // - timeaverage, timebin, timespan, maxuvwdistance
419 :
420 : // smoothing
421 0 : configure_param.define("smoothFourier", doSmoothing_);
422 :
423 : // merge polarization averaging parameters
424 0 : configure_param.merge(pol_average_);
425 :
426 : // offline ATM correction
427 0 : configure_param.define("atmCor", doAtmCor_);
428 0 : configure_param.merge(atmCorConfig_);
429 :
430 : // Generate SDMSManager
431 0 : sdh_ = new SDMSManager();
432 :
433 : // Configure SDMSManager
434 0 : sdh_->configure(configure_param);
435 :
436 0 : ostringstream oss;
437 0 : configure_param.print(oss);
438 0 : String str(oss.str());
439 0 : os << LogIO::DEBUG1 << " Configuration Record " << LogIO::POST;
440 0 : os << LogIO::DEBUG1 << str << LogIO::POST;
441 : // Open the MS and select data
442 0 : sdh_->open();
443 0 : sdh_->getOutputMs()->flush();
444 : // set large timebin if not averaging
445 : Double timeBin;
446 0 : int exists = configure_param.fieldNumber("timebin");
447 0 : if (exists < 0) {
448 : // Avoid TIME col being added to sort columns in MSIter::construct.
449 : // TIME is automatically added to sort column when
450 : // timebin is not 0, even if addDefaultSortCols=false.
451 0 : timeBin = 0.0;
452 : } else {
453 0 : String timebin_string;
454 0 : configure_param.get(exists, timebin_string);
455 0 : timeBin = casaQuantity(timebin_string).get("s").getValue();
456 :
457 : Int ifield;
458 0 : ifield = configure_param.fieldNumber(String("timeaverage"));
459 0 : Bool average_time = ifield < 0 ? false : configure_param.asBool(ifield);
460 0 : if (timeBin < 0 || (average_time && timeBin == 0.0))
461 0 : throw(AipsError("time bin should be positive"));
462 : }
463 : // set sort column
464 0 : sdh_->setSortColumns(sortColumns, addDefaultSortCols, timeBin);
465 : // Set up the Data Handler
466 0 : sdh_->setup();
467 0 : return true;
468 : }
469 :
470 0 : void SingleDishMS::finalize_process() {
471 0 : initialize();
472 0 : if (sdh_) {
473 0 : sdh_->close();
474 0 : delete sdh_;
475 0 : sdh_ = 0;
476 : }
477 0 : }
478 :
479 0 : void SingleDishMS::format_selection(Record &selection) {
480 : // At this moment sdh_ is not supposed to be generated yet.
481 0 : LogIO os(_ORIGIN);
482 : // format spw
483 0 : String const spwSel(get_field_as_casa_string(selection, "spw"));
484 0 : selection.define("spw", spwSel == "" ? "*" : spwSel);
485 :
486 : // Select only auto-correlation
487 0 : String autoCorrSel("");
488 : os << "Formatting antenna selection to select only auto-correlation"
489 0 : << LogIO::POST;
490 0 : String const antennaSel(get_field_as_casa_string(selection, "antenna"));
491 : os << LogIO::DEBUG1 << "Input antenna expression = " << antennaSel
492 0 : << LogIO::POST;
493 0 : if (antennaSel == "") { //Antenna selection is NOT set
494 0 : autoCorrSel = String("*&&&");
495 : } else { //User defined antenna selection
496 0 : MeasurementSet MSobj = MeasurementSet(msname_);
497 0 : MeasurementSet* theMS = &MSobj;
498 0 : MSSelection theSelection;
499 0 : theSelection.setAntennaExpr(antennaSel);
500 0 : TableExprNode exprNode = theSelection.toTableExprNode(theMS);
501 0 : Vector<Int> ant1Vec = theSelection.getAntenna1List();
502 : os << LogIO::DEBUG1 << ant1Vec.nelements()
503 0 : << " antenna(s) are selected. ID = ";
504 0 : for (uInt i = 0; i < ant1Vec.nelements(); ++i) {
505 0 : os << ant1Vec[i] << ", ";
506 0 : if (autoCorrSel != "")
507 0 : autoCorrSel += ";";
508 0 : autoCorrSel += String::toString(ant1Vec[i]) + "&&&";
509 : }
510 0 : os << LogIO::POST;
511 : }
512 : os << LogIO::DEBUG1 << "Auto-correlation selection string: " << autoCorrSel
513 0 : << LogIO::POST;
514 :
515 0 : selection.define("antenna", autoCorrSel);
516 0 : }
517 :
518 0 : void SingleDishMS::get_data_cube_float(vi::VisBuffer2 const &vb,
519 : Cube<Float> &data_cube) {
520 : // if (in_column_ == MS::FLOAT_DATA) {
521 : // data_cube = vb.visCubeFloat();
522 : // } else { //need to convert Complex cube to Float
523 : // Cube<Complex> cdata_cube(data_cube.shape());
524 : // if (in_column_ == MS::DATA) {
525 : // cdata_cube = vb.visCube();
526 : // } else { //MS::CORRECTED_DATA
527 : // cdata_cube = vb.visCubeCorrected();
528 : // }
529 : // // convert Complext to Float
530 : // convertArrayC2F(data_cube, cdata_cube);
531 : // }
532 0 : (*visCubeAccessor_)(vb, data_cube);
533 0 : }
534 :
535 0 : void SingleDishMS::convertArrayC2F(Array<Float> &to,
536 : Array<Complex> const &from) {
537 0 : if (to.nelements() == 0 && from.nelements() == 0) {
538 0 : return;
539 : }
540 0 : if (to.shape() != from.shape()) {
541 0 : throw(ArrayConformanceError("Array shape differs"));
542 : }
543 0 : Array<Complex>::const_iterator endFrom = from.end();
544 0 : Array<Complex>::const_iterator iterFrom = from.begin();
545 0 : for (Array<Float>::iterator iterTo = to.begin(); iterFrom != endFrom; ++iterFrom, ++iterTo) {
546 0 : *iterTo = iterFrom->real();
547 : }
548 : }
549 :
550 0 : std::vector<string> SingleDishMS::split_string(string const &s, char delim) {
551 0 : std::vector<string> elems;
552 0 : string item;
553 0 : for (size_t i = 0; i < s.size(); ++i) {
554 0 : char ch = s.at(i);
555 0 : if (ch == delim) {
556 0 : if (!item.empty()) {
557 0 : elems.push_back(item);
558 : }
559 0 : item.clear();
560 : } else {
561 0 : item += ch;
562 : }
563 : }
564 0 : if (!item.empty()) {
565 0 : elems.push_back(item);
566 : }
567 0 : return elems;
568 : }
569 :
570 0 : bool SingleDishMS::file_exists(string const &filename) {
571 : FILE *fp;
572 0 : if ((fp = fopen(filename.c_str(), "r")) == NULL)
573 0 : return false;
574 0 : fclose(fp);
575 0 : return true;
576 : }
577 :
578 0 : void SingleDishMS::parse_spw(string const &in_spw,
579 : Vector<Int> &rec_spw,
580 : Matrix<Int> &rec_chan,
581 : Vector<size_t> &nchan,
582 : Vector<Vector<Bool> > &mask,
583 : Vector<bool> &nchan_set) {
584 0 : Record selrec = sdh_->getSelRec(in_spw);
585 0 : rec_spw = selrec.asArrayInt("spw");
586 0 : rec_chan = selrec.asArrayInt("channel");
587 0 : nchan.resize(rec_spw.nelements());
588 0 : mask.resize(rec_spw.nelements());
589 0 : nchan_set.resize(rec_spw.nelements());
590 0 : for (size_t i = 0; i < nchan_set.nelements(); ++i) {
591 0 : nchan_set(i) = false;
592 : }
593 0 : }
594 :
595 0 : void SingleDishMS::get_nchan_and_mask(Vector<Int> const &rec_spw,
596 : Vector<Int> const &data_spw,
597 : Matrix<Int> const &rec_chan,
598 : size_t const num_chan,
599 : Vector<size_t> &nchan,
600 : Vector<Vector<Bool> > &mask,
601 : Vector<bool> &nchan_set,
602 : bool &new_nchan) {
603 0 : new_nchan = false;
604 0 : for (size_t i = 0; i < rec_spw.nelements(); ++i) {
605 : //get nchan by spwid and set to nchan[]
606 0 : for (size_t j = 0; j < data_spw.nelements(); ++j) {
607 0 : if ((!nchan_set(i)) && (data_spw(j) == rec_spw(i))) {
608 0 : bool found = false;
609 0 : for (size_t k = 0; k < nchan.nelements(); ++k) {
610 0 : if (!nchan_set(k))
611 0 : continue;
612 0 : if (nchan(k) == num_chan)
613 0 : found = true;
614 : }
615 0 : if (!found) {
616 0 : new_nchan = true;
617 : }
618 0 : nchan(i) = num_chan;
619 0 : nchan_set(i) = true;
620 0 : break;
621 : }
622 : }
623 0 : if (!nchan_set(i))
624 0 : continue;
625 0 : mask(i).resize(nchan(i));
626 : // generate mask
627 0 : get_mask_from_rec(rec_spw(i), rec_chan, mask(i), true);
628 : }
629 0 : }
630 :
631 0 : void SingleDishMS::get_mask_from_rec(Int spwid,
632 : Matrix<Int> const &rec_chan,
633 : Vector<Bool> &mask,
634 : bool initialize) {
635 0 : if (initialize) {
636 0 : for (size_t j = 0; j < mask.nelements(); ++j) {
637 0 : mask(j) = false;
638 : }
639 : }
640 : //construct a list of (start, end, stride, start, end, stride, ...)
641 : //from rec_chan for the spwid
642 0 : std::vector<uInt> edge;
643 0 : edge.clear();
644 0 : for (size_t j = 0; j < rec_chan.nrow(); ++j) {
645 0 : if (rec_chan.row(j)(0) == spwid) {
646 0 : edge.push_back(rec_chan.row(j)(1));
647 0 : edge.push_back(rec_chan.row(j)(2));
648 0 : edge.push_back(rec_chan.row(j)(3));
649 : }
650 : }
651 : //generate mask
652 0 : for (size_t j = 0; j < edge.size()-2; j += 3) {
653 0 : for (size_t k = edge[j]; k <= edge[j + 1] && k < mask.size(); k += edge[j + 2]) {
654 0 : mask(k) = true;
655 : }
656 : }
657 0 : }
658 :
659 0 : void SingleDishMS::get_masklist_from_mask(size_t const num_chan,
660 : bool const *mask,
661 : Vector<uInt> &masklist) {
662 0 : size_t const max_num_masklist = num_chan + 1;
663 0 : masklist.resize(max_num_masklist); // clear
664 0 : uInt last_idx = num_chan - 1;
665 0 : uInt num_masklist = 0;
666 0 : auto append = [&](uInt i){
667 0 : masklist[num_masklist] = i;
668 0 : num_masklist++;
669 0 : };
670 :
671 0 : if (mask[0]) {
672 0 : append(0);
673 : }
674 0 : for (uInt i = 1; i < last_idx; ++i) {
675 0 : if (!mask[i]) continue;
676 :
677 : // The following if-statements must be judged independently.
678 : // Don't put them together as a single statement by connecting with '||'.
679 0 : if (!mask[i - 1]) {
680 0 : append(i);
681 : }
682 0 : if (!mask[i + 1]) {
683 0 : append(i);
684 : }
685 : }
686 0 : if (mask[last_idx]) {
687 0 : if ((1 <= last_idx) && (!mask[last_idx - 1])) {
688 0 : append(last_idx);
689 : }
690 0 : append(last_idx);
691 : }
692 0 : masklist.resize(num_masklist, true);
693 0 : }
694 :
695 0 : void SingleDishMS::get_baseline_context(size_t const bltype,
696 : uint16_t order,
697 : size_t num_chan,
698 : Vector<size_t> const &nchan,
699 : Vector<bool> const &nchan_set,
700 : Vector<size_t> &ctx_indices,
701 : std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *> &bl_contexts) {
702 0 : size_t idx = 0;
703 0 : bool found = false;
704 0 : for (size_t i = 0; i < nchan.nelements(); ++i) {
705 0 : if ((nchan_set[i])&&(nchan[i] == num_chan)) {
706 0 : idx = bl_contexts.size();
707 0 : found = true;
708 0 : break;
709 : }
710 : }
711 0 : if (found) {
712 0 : for (size_t i = 0; i < nchan.nelements(); ++i) {
713 0 : if ((nchan_set[i])&&(nchan[i] == num_chan)) {
714 0 : ctx_indices[i] = idx;
715 : }
716 : }
717 :
718 : LIBSAKURA_SYMBOL(LSQFitContextFloat) *context;
719 0 : LIBSAKURA_SYMBOL(Status) status = LIBSAKURA_SYMBOL(Status_kNG);
720 0 : if ((bltype == BaselineType_kPolynomial)||(bltype == BaselineType_kChebyshev)) {
721 0 : status = LIBSAKURA_SYMBOL(CreateLSQFitContextPolynomialFloat)(static_cast<LIBSAKURA_SYMBOL(LSQFitType)>(bltype),
722 : static_cast<uint16_t>(order),
723 : num_chan, &context);
724 0 : } else if (bltype == BaselineType_kCubicSpline) {
725 0 : status = LIBSAKURA_SYMBOL(CreateLSQFitContextCubicSplineFloat)(static_cast<uint16_t>(order),
726 : num_chan, &context);
727 0 : } else if (bltype == BaselineType_kSinusoid) {
728 0 : status = LIBSAKURA_SYMBOL(CreateLSQFitContextSinusoidFloat)(static_cast<uint16_t>(order),
729 : num_chan, &context);
730 : }
731 0 : check_sakura_status("sakura_CreateLSQFitContextFloat", status);
732 0 : bl_contexts.push_back(context);
733 : }
734 0 : }
735 :
736 0 : void SingleDishMS::get_baseline_context(size_t const bltype,
737 : uint16_t order,
738 : size_t num_chan,
739 : size_t ispw,
740 : Vector<size_t> &ctx_indices,
741 : std::vector<size_t> & ctx_nchans,
742 : std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *> &bl_contexts) {
743 0 : AlwaysAssert(bl_contexts.size() == ctx_nchans.size() || bl_contexts.size() == ctx_nchans.size()-1 , AipsError);
744 0 : size_t idx = 0;
745 0 : bool found = false;
746 0 : for (size_t i = 0; i < bl_contexts.size(); ++i) {
747 0 : if (ctx_nchans[i] == num_chan) {
748 0 : idx = i;
749 0 : found = true;
750 0 : break;
751 : }
752 : }
753 0 : if (found) {
754 : // contexts with the valid number of channels already exists.
755 : // just update idx to bl_contexts and return.
756 0 : ctx_indices[ispw] = idx;
757 0 : return;
758 : }
759 : // contexts with the number of channels is not yet in bl_contexts.
760 : // Need to create a new context.
761 0 : ctx_indices[ispw] = bl_contexts.size();
762 : LIBSAKURA_SYMBOL(LSQFitContextFloat) *context;
763 0 : LIBSAKURA_SYMBOL(Status) status = LIBSAKURA_SYMBOL(Status_kNG);
764 0 : if ((bltype == BaselineType_kPolynomial)||(bltype == BaselineType_kChebyshev)) {
765 0 : status = LIBSAKURA_SYMBOL(CreateLSQFitContextPolynomialFloat)(static_cast<LIBSAKURA_SYMBOL(LSQFitType)>(bltype),
766 : static_cast<uint16_t>(order),
767 : num_chan, &context);
768 0 : } else if (bltype == BaselineType_kCubicSpline) {
769 0 : status = LIBSAKURA_SYMBOL(CreateLSQFitContextCubicSplineFloat)(static_cast<uint16_t>(order),
770 : num_chan, &context);
771 0 : } else if (bltype == BaselineType_kSinusoid) {
772 0 : status = LIBSAKURA_SYMBOL(CreateLSQFitContextSinusoidFloat)(static_cast<uint16_t>(order),
773 : num_chan, &context);
774 : }
775 0 : check_sakura_status("sakura_CreateLSQFitContextFloat", status);
776 0 : bl_contexts.push_back(context);
777 0 : if (ctx_nchans.size() != bl_contexts.size()) {
778 0 : ctx_nchans.push_back(num_chan);
779 : }
780 0 : AlwaysAssert(bl_contexts.size() == ctx_nchans.size(), AipsError);
781 : }
782 :
783 0 : void SingleDishMS::destroy_baseline_contexts(std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *> &bl_contexts) {
784 : LIBSAKURA_SYMBOL(Status) status;
785 0 : for (size_t i = 0; i < bl_contexts.size(); ++i) {
786 0 : status = LIBSAKURA_SYMBOL(DestroyLSQFitContextFloat)(bl_contexts[i]);
787 0 : check_sakura_status("sakura_DestoyBaselineContextFloat", status);
788 : }
789 0 : }
790 :
791 0 : void SingleDishMS::check_sakura_status(string const &name,
792 : LIBSAKURA_SYMBOL(Status) const status) {
793 0 : if (status == LIBSAKURA_SYMBOL(Status_kOK)) return;
794 :
795 0 : ostringstream oss;
796 0 : oss << name << "() failed -- ";
797 0 : if (status == LIBSAKURA_SYMBOL(Status_kNG)) {
798 0 : oss << "NG";
799 0 : } else if (status == LIBSAKURA_SYMBOL(Status_kInvalidArgument)) {
800 0 : oss << "InvalidArgument";
801 0 : } else if (status == LIBSAKURA_SYMBOL(Status_kNoMemory)) {
802 0 : oss << "NoMemory";
803 0 : } else if (status == LIBSAKURA_SYMBOL(Status_kUnknownError)) {
804 0 : oss << "UnknownError";
805 : }
806 0 : throw(AipsError(oss.str()));
807 : }
808 :
809 0 : void SingleDishMS::check_baseline_status(LIBSAKURA_SYMBOL(LSQFitStatus) const bl_status) {
810 0 : if (bl_status != LIBSAKURA_SYMBOL(LSQFitStatus_kOK)) {
811 0 : throw(AipsError("baseline fitting isn't successful."));
812 : }
813 0 : }
814 :
815 0 : void SingleDishMS::get_spectrum_from_cube(Cube<Float> &data_cube,
816 : size_t const row,
817 : size_t const plane,
818 : size_t const num_data,
819 : float out_data[]) {
820 0 : AlwaysAssert(static_cast<size_t>(data_cube.ncolumn()) == num_data, AipsError);
821 0 : for (size_t i = 0; i < num_data; ++i)
822 0 : out_data[i] = static_cast<float>(data_cube(plane, i, row));
823 0 : }
824 :
825 0 : void SingleDishMS::set_spectrum_to_cube(Cube<Float> &data_cube,
826 : size_t const row,
827 : size_t const plane,
828 : size_t const num_data,
829 : float *in_data) {
830 0 : AlwaysAssert(static_cast<size_t>(data_cube.ncolumn()) == num_data, AipsError);
831 0 : for (size_t i = 0; i < num_data; ++i)
832 0 : data_cube(plane, i, row) = static_cast<Float>(in_data[i]);
833 0 : }
834 :
835 0 : void SingleDishMS::get_weight_matrix(vi::VisBuffer2 const &vb,
836 : Matrix<Float> &weight_matrix) {
837 0 : weight_matrix = vb.weight();
838 0 : }
839 :
840 0 : void SingleDishMS::set_weight_to_matrix(Matrix<Float> &weight_matrix,
841 : size_t const row,
842 : size_t const plane,
843 : float in_weight) {
844 0 : weight_matrix(plane, row) = static_cast<Float>(in_weight);
845 0 : }
846 :
847 0 : void SingleDishMS::get_flag_cube(vi::VisBuffer2 const &vb,
848 : Cube<Bool> &flag_cube) {
849 0 : flag_cube = vb.flagCube();
850 0 : }
851 :
852 0 : void SingleDishMS::get_flag_from_cube(Cube<Bool> &flag_cube,
853 : size_t const row,
854 : size_t const plane,
855 : size_t const num_flag,
856 : bool out_flag[]) {
857 0 : AlwaysAssert(static_cast<size_t>(flag_cube.ncolumn()) == num_flag, AipsError);
858 0 : for (size_t i = 0; i < num_flag; ++i)
859 0 : out_flag[i] = static_cast<bool>(flag_cube(plane, i, row));
860 0 : }
861 :
862 0 : void SingleDishMS::set_flag_to_cube(Cube<Bool> &flag_cube,
863 : size_t const row,
864 : size_t const plane,
865 : size_t const num_flag,
866 : bool *in_flag) {
867 0 : AlwaysAssert(static_cast<size_t>(flag_cube.ncolumn()) == num_flag, AipsError);
868 0 : for (size_t i = 0; i < num_flag; ++i)
869 0 : flag_cube(plane, i, row) = static_cast<Bool>(in_flag[i]);
870 0 : }
871 :
872 0 : void SingleDishMS::flag_spectrum_in_cube(Cube<Bool> &flag_cube,
873 : size_t const row,
874 : size_t const plane) {
875 0 : uInt const num_flag = flag_cube.ncolumn();
876 0 : for (uInt ichan = 0; ichan < num_flag; ++ichan)
877 0 : flag_cube(plane, ichan, row) = true;
878 0 : }
879 :
880 0 : bool SingleDishMS::allchannels_flagged(size_t const num_flag,
881 : bool const* flag) {
882 0 : bool res = true;
883 0 : for (size_t i = 0; i < num_flag; ++i) {
884 0 : if (!flag[i]) {
885 0 : res = false;
886 0 : break;
887 : }
888 : }
889 0 : return res;
890 : }
891 :
892 0 : size_t SingleDishMS::NValidMask(size_t const num_mask, bool const* mask) {
893 0 : std::size_t nvalid = 0;
894 : // the assertion lines had better be replaced with static_assert when c++11 is supported
895 0 : AlwaysAssert(static_cast<std::size_t>(true) == 1, AipsError);
896 0 : AlwaysAssert(static_cast<std::size_t>(false) == 0, AipsError);
897 0 : for (size_t i = 0; i < num_mask; ++i) {
898 0 : nvalid += static_cast<std::size_t>(mask[i]);
899 : }
900 0 : return nvalid;
901 : }
902 :
903 0 : void SingleDishMS::split_bloutputname(string str) {
904 0 : char key = ',';
905 0 : vector<size_t> v;
906 0 : for (size_t i = 0; i < str.size(); ++i) {
907 0 : char target = str[i];
908 0 : if (key == target) {
909 0 : v.push_back(i);
910 : }
911 : }
912 :
913 : //cout << "comma " << v.size() << endl;
914 : //cout << "v[1] " << v[1] << endl;
915 : //cout << "v.size()-1 " << v.size()-1 << endl;
916 : //cout << "v[1]+1 " << v[1]+1 << endl;
917 : //cout << "str.size()-v[1]-1 " << str.size()-v[1]-1 << endl;
918 : //cout << "str.substr(v[1]+1, str.size()-v[1]-1) " << str.substr(v[1]+1, str.size()-v[1]-1) << endl;
919 :
920 0 : string ss;
921 0 : bloutputname_csv.clear();
922 0 : bloutputname_text.clear();
923 0 : bloutputname_table.clear();
924 :
925 0 : if (0 != v[0]) {
926 0 : bloutputname_csv = str.substr(0, v[0]);
927 0 : ss = str.substr(0, v[0]);
928 : }
929 0 : if (v[0] + 1 != v[1]) {
930 0 : bloutputname_text = str.substr(v[0] + 1, v[1] - v[0] - 1);
931 : }
932 0 : if (v[1] != str.size() - 1) {
933 0 : bloutputname_table = str.substr(v[1] + 1, str.size() - v[1] - 1);
934 : }
935 0 : }
936 :
937 0 : size_t SingleDishMS::get_num_coeff_bloutput(size_t const bltype,
938 : size_t order,
939 : size_t &num_coeff_max) {
940 0 : size_t num_coeff = 0;
941 0 : switch (bltype) {
942 0 : case BaselineType_kPolynomial:
943 : case BaselineType_kChebyshev:
944 0 : break;
945 0 : case BaselineType_kCubicSpline:
946 0 : num_coeff = order + 1;
947 0 : break;
948 0 : case BaselineType_kSinusoid:
949 0 : break;
950 0 : default:
951 0 : throw(AipsError("Unsupported baseline type."));
952 : }
953 0 : if (num_coeff_max < num_coeff) {
954 0 : num_coeff_max = num_coeff;
955 : }
956 :
957 0 : return num_coeff;
958 : }
959 :
960 0 : vector<int> SingleDishMS::string_to_list(string const &wn_str, char const delim) {
961 0 : vector<int> wn_list;
962 0 : wn_list.clear();
963 0 : vector<size_t> delim_position;
964 0 : delim_position.clear();
965 0 : for (size_t i = 0; i < wn_str.size(); ++i) {
966 0 : if (wn_str[i] == delim) {
967 0 : delim_position.push_back(i);
968 : }
969 : }
970 0 : delim_position.push_back(wn_str.size());
971 0 : size_t start_position = 0;
972 0 : for (size_t i = 0; i < delim_position.size(); ++i) {
973 0 : size_t end_position = delim_position[i];
974 0 : size_t length = end_position - start_position;
975 0 : if (length > 0) {
976 0 : wn_list.push_back(std::atoi(wn_str.substr(start_position, length).c_str()));
977 : }
978 0 : start_position = end_position + 1;
979 : }
980 0 : return wn_list;
981 : }
982 :
983 0 : void SingleDishMS::get_effective_nwave(std::vector<int> const &addwn,
984 : std::vector<int> const &rejwn,
985 : int const wn_ulimit,
986 : std::vector<int> &effwn) {
987 0 : effwn.clear();
988 0 : if (addwn.size() < 1) {
989 0 : throw AipsError("addwn has no elements.");
990 : }
991 :
992 0 : auto up_to_nyquist_limit = [&](std::vector<int> const &v){ return ((v.size() == 2) && (v[1] == SinusoidWaveNumber_kUpperLimit)); };
993 0 : auto check_rejwn_add = [&](int const v){
994 0 : bool add = (0 <= v) && (v <= wn_ulimit); // check v in range
995 0 : for (size_t i = 0; i < rejwn.size(); ++i) {
996 0 : if (rejwn[i] == v) {
997 0 : add = false;
998 0 : break;
999 : }
1000 : }
1001 0 : if (add) {
1002 0 : effwn.push_back(v);
1003 : }
1004 0 : };
1005 :
1006 0 : if (up_to_nyquist_limit(addwn)) {
1007 0 : if (up_to_nyquist_limit(rejwn)) {
1008 0 : if (addwn[0] < rejwn[0]) {
1009 0 : for (int wn = addwn[0]; wn < rejwn[0]; ++wn) {
1010 0 : if ((0 <= wn) && (wn <= wn_ulimit)) {
1011 0 : effwn.push_back(wn);
1012 : }
1013 : }
1014 : } else {
1015 0 : throw(AipsError("No effective wave number given for sinusoidal fitting."));
1016 : }
1017 : } else {
1018 0 : for (int wn = addwn[0]; wn <= wn_ulimit; ++wn) {
1019 0 : check_rejwn_add(wn);
1020 : }
1021 : }
1022 : } else {
1023 0 : if (up_to_nyquist_limit(rejwn)) {
1024 0 : int maxwn = rejwn[0] - 1;
1025 0 : if (maxwn < 0) {
1026 0 : throw(AipsError("No effective wave number given for sinusoidal fitting."));
1027 : }
1028 0 : for (size_t i = 0; i < addwn.size(); ++i) {
1029 0 : if ((0 <= addwn[i]) && (addwn[i] <= maxwn)) {
1030 0 : effwn.push_back(addwn[i]);
1031 : }
1032 : }
1033 : } else {
1034 0 : for (size_t i = 0; i < addwn.size(); ++i) {
1035 0 : check_rejwn_add(addwn[i]);
1036 : }
1037 : }
1038 : }
1039 0 : if (effwn.size() == 0) {
1040 0 : throw(AipsError("No effective wave number given for sinusoidal fitting."));
1041 : }
1042 0 : }
1043 :
1044 0 : void SingleDishMS::finalise_effective_nwave(std::vector<int> const &blparam_eff_base,
1045 : std::vector<int> const &blparam_exclude,
1046 : int const &blparam_upperlimit,
1047 : size_t const &num_chan,
1048 : float const *spec,
1049 : bool const *mask,
1050 : bool const &applyfft,
1051 : string const &fftmethod,
1052 : string const &fftthresh_str,
1053 : std::vector<size_t> &blparam_eff) {
1054 0 : blparam_eff.resize(blparam_eff_base.size());
1055 0 : copy(blparam_eff_base.begin(), blparam_eff_base.end(), blparam_eff.begin());
1056 :
1057 0 : if (applyfft) {
1058 0 : string fftthresh_attr;
1059 : float fftthresh_sigma;
1060 : int fftthresh_top;
1061 0 : parse_fftthresh(fftthresh_str, fftthresh_attr, fftthresh_sigma, fftthresh_top);
1062 0 : std::vector<int> blparam_fft;
1063 0 : select_wavenumbers_via_fft(num_chan, spec, mask, fftmethod, fftthresh_attr,
1064 : fftthresh_sigma, fftthresh_top, blparam_upperlimit,
1065 : blparam_fft);
1066 0 : merge_wavenumbers(blparam_eff_base, blparam_fft, blparam_exclude, blparam_eff);
1067 : }
1068 0 : }
1069 :
1070 0 : void SingleDishMS::parse_fftthresh(string const& fftthresh_str,
1071 : string& fftthresh_attr,
1072 : float& fftthresh_sigma,
1073 : int& fftthresh_top) {
1074 0 : size_t idx_sigma = fftthresh_str.find("sigma");
1075 0 : size_t idx_top = fftthresh_str.find("top");
1076 :
1077 0 : if (idx_top == 0) {
1078 0 : std::istringstream is(fftthresh_str.substr(3));
1079 0 : is >> fftthresh_top;
1080 0 : fftthresh_attr = "top";
1081 0 : } else if (idx_sigma == fftthresh_str.size() - 5) {
1082 0 : std::istringstream is(fftthresh_str.substr(0, fftthresh_str.size() - 5));
1083 0 : is >> fftthresh_sigma;
1084 0 : fftthresh_attr = "sigma";
1085 : } else {
1086 0 : bool is_number = true;
1087 0 : for (size_t i = 0; i < fftthresh_str.size()-1; ++i) {
1088 0 : char ch = (fftthresh_str.substr(i, 1).c_str())[0];
1089 0 : if (!(isdigit(ch) || (fftthresh_str.substr(i, 1) == "."))) {
1090 0 : is_number = false;
1091 0 : break;
1092 : }
1093 : }
1094 0 : if (is_number) {
1095 0 : std::istringstream is(fftthresh_str);
1096 0 : is >> fftthresh_sigma;
1097 0 : fftthresh_attr = "sigma";
1098 : } else {
1099 0 : throw(AipsError("fftthresh has a wrong value"));
1100 : }
1101 : }
1102 0 : }
1103 :
1104 0 : void SingleDishMS::select_wavenumbers_via_fft(size_t const num_chan,
1105 : float const *spec,
1106 : bool const *mask,
1107 : string const &fftmethod,
1108 : string const &fftthresh_attr,
1109 : float const fftthresh_sigma,
1110 : int const fftthresh_top,
1111 : int const blparam_upperlimit,
1112 : std::vector<int> &blparam_fft) {
1113 0 : blparam_fft.clear();
1114 0 : std::vector<float> fourier_spec;
1115 0 : if (fftmethod == "fft") {
1116 0 : exec_fft(num_chan, spec, mask, false, true, fourier_spec);
1117 : } else {
1118 0 : throw AipsError("fftmethod must be 'fft' for now.");
1119 : }
1120 :
1121 0 : int fourier_spec_size = static_cast<int>(fourier_spec.size());
1122 0 : if (fftthresh_attr == "sigma") {
1123 0 : float mean = 0.0;
1124 0 : float mean2 = 0.0;
1125 0 : for (int i = 0; i < fourier_spec_size; ++i) {
1126 0 : mean += fourier_spec[i];
1127 0 : mean2 += fourier_spec[i] * fourier_spec[i];
1128 : }
1129 0 : mean /= static_cast<float>(fourier_spec_size);
1130 0 : mean2 /= static_cast<float>(fourier_spec_size);
1131 0 : float thres = mean + fftthresh_sigma * float(sqrt(mean2 - mean * mean));
1132 :
1133 0 : for (int i = 0; i < fourier_spec_size; ++i) {
1134 0 : if ((i <= blparam_upperlimit)&&(thres <= fourier_spec[i])) {
1135 0 : blparam_fft.push_back(i);
1136 : }
1137 : }
1138 0 : } else if (fftthresh_attr == "top") {
1139 0 : int i = 0;
1140 0 : while (i < fftthresh_top) {
1141 0 : float max = 0.0;
1142 0 : int max_idx = 0;
1143 0 : for (int j = 0; j < fourier_spec_size; ++j) {
1144 0 : if (max < fourier_spec[j]) {
1145 0 : max = fourier_spec[j];
1146 0 : max_idx = j;
1147 : }
1148 : }
1149 0 : fourier_spec[max_idx] = 0.0;
1150 0 : if (max_idx <= blparam_upperlimit) {
1151 0 : blparam_fft.push_back(max_idx);
1152 0 : ++i;
1153 : }
1154 : }
1155 : } else {
1156 0 : throw AipsError("fftthresh is wrong.");
1157 : }
1158 0 : }
1159 :
1160 0 : void SingleDishMS::exec_fft(size_t const num_chan,
1161 : float const *in_spec,
1162 : bool const *in_mask,
1163 : bool const get_real_imag,
1164 : bool const get_ampl_only,
1165 : std::vector<float> &fourier_spec) {
1166 0 : Vector<Float> spec;
1167 0 : interpolate_constant(static_cast<int>(num_chan), in_spec, in_mask, spec);
1168 :
1169 0 : FFTServer<Float, Complex> ffts;
1170 0 : Vector<Complex> fftres;
1171 0 : ffts.fft0(fftres, spec);
1172 :
1173 0 : float norm = static_cast<float>(2.0/static_cast<double>(num_chan));
1174 0 : fourier_spec.clear();
1175 0 : if (get_real_imag) {
1176 0 : for (size_t i = 0; i < fftres.size(); ++i) {
1177 0 : fourier_spec.push_back(real(fftres[i]) * norm);
1178 0 : fourier_spec.push_back(imag(fftres[i]) * norm);
1179 : }
1180 : } else {
1181 0 : for (size_t i = 0; i < fftres.size(); ++i) {
1182 0 : fourier_spec.push_back(abs(fftres[i]) * norm);
1183 0 : if (!get_ampl_only) fourier_spec.push_back(arg(fftres[i]));
1184 : }
1185 : }
1186 0 : }
1187 :
1188 0 : void SingleDishMS::interpolate_constant(int const num_chan,
1189 : float const *in_spec,
1190 : bool const *in_mask,
1191 : Vector<Float> &spec) {
1192 0 : spec.resize(num_chan);
1193 0 : for (int i = 0; i < num_chan; ++i) {
1194 0 : spec[i] = in_spec[i];
1195 : }
1196 0 : int idx_left = -1;
1197 0 : int idx_right = -1;
1198 0 : bool masked_region = false;
1199 :
1200 0 : for (int i = 0; i < num_chan; ++i) {
1201 0 : if (!in_mask[i]) {
1202 0 : masked_region = true;
1203 0 : idx_left = i;
1204 0 : while (i < num_chan) {
1205 0 : if (in_mask[i]) break;
1206 0 : idx_right = i;
1207 0 : ++i;
1208 : }
1209 : }
1210 :
1211 0 : if (masked_region) {
1212 : // execute interpolation as the following criteria:
1213 : // (1) for a masked region inside the spectrum, replace the spectral
1214 : // values with the mean of those at the two channels just outside
1215 : // the both edges of the masked region.
1216 : // (2) for a masked region at the spectral edge, replace the values
1217 : // with the one at the nearest non-masked channel.
1218 : // (ZOH, but bilateral)
1219 0 : Float interp = 0.0;
1220 0 : int idx_left_next = idx_left - 1;
1221 0 : int idx_right_next = idx_right + 1;
1222 0 : if (idx_left_next < 0) {
1223 0 : if (idx_right_next < num_chan) {
1224 0 : interp = in_spec[idx_right_next];
1225 : } else {
1226 0 : throw AipsError("Bad data. all channels are masked.");
1227 : }
1228 : } else {
1229 0 : interp = in_spec[idx_left_next];
1230 0 : if (idx_right_next < num_chan) {
1231 0 : interp = (interp + in_spec[idx_right_next]) / 2.0;
1232 : }
1233 : }
1234 :
1235 0 : if ((0 <= idx_left) && (idx_left < num_chan) && (0 <= idx_right) && (idx_right < num_chan)) {
1236 0 : for (int j = idx_left; j <= idx_right; ++j) {
1237 0 : spec[j] = interp;
1238 : }
1239 : }
1240 :
1241 0 : masked_region = false;
1242 : }
1243 : }
1244 0 : }
1245 :
1246 0 : void SingleDishMS::merge_wavenumbers(std::vector<int> const &blparam_eff_base,
1247 : std::vector<int> const &blparam_fft,
1248 : std::vector<int> const &blparam_exclude,
1249 : std::vector<size_t> &blparam_eff) {
1250 0 : for (size_t i = 0; i < blparam_fft.size(); ++i) {
1251 0 : bool found = false;
1252 0 : for (size_t j = 0; j < blparam_eff_base.size(); ++j) {
1253 0 : if (blparam_eff_base[j] == blparam_fft[i]) {
1254 0 : found = true;
1255 0 : break;
1256 : }
1257 : }
1258 0 : if (!found) { //new value to add
1259 : //but still need to check if it is to be excluded
1260 0 : bool found_exclude = false;
1261 0 : for (size_t j = 0; j < blparam_exclude.size(); ++j) {
1262 0 : if (blparam_exclude[j] == blparam_fft[i]) {
1263 0 : found_exclude = true;
1264 0 : break;
1265 : }
1266 : }
1267 0 : if (!found_exclude) {
1268 0 : blparam_eff.push_back(blparam_fft[i]);
1269 : }
1270 : }
1271 : }
1272 :
1273 0 : if (1 < blparam_eff.size()) {
1274 0 : sort(blparam_eff.begin(), blparam_eff.end());
1275 0 : unique(blparam_eff.begin(), blparam_eff.end());
1276 : }
1277 0 : }
1278 :
1279 : template<typename Func0, typename Func1, typename Func2, typename Func3>
1280 0 : void SingleDishMS::doSubtractBaseline(string const& in_column_name,
1281 : string const& out_ms_name,
1282 : string const& out_bloutput_name,
1283 : bool const& do_subtract,
1284 : string const& in_spw,
1285 : bool const& update_weight,
1286 : string const& sigma_value,
1287 : LIBSAKURA_SYMBOL(Status)& status,
1288 : std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *> &bl_contexts,
1289 : size_t const bltype,
1290 : vector<int> const& blparam,
1291 : vector<int> const& blparam_exclude,
1292 : bool const& applyfft,
1293 : string const& fftmethod,
1294 : string const& fftthresh,
1295 : float const clip_threshold_sigma,
1296 : int const num_fitting_max,
1297 : bool const linefinding,
1298 : float const threshold,
1299 : int const avg_limit,
1300 : int const minwidth,
1301 : vector<int> const& edge,
1302 : Func0 func0,
1303 : Func1 func1,
1304 : Func2 func2,
1305 : Func3 func3,
1306 : LogIO os) {
1307 0 : os << LogIO::DEBUG2 << "Calling SingleDishMS::doSubtractBaseline " << LogIO::POST;
1308 :
1309 : // in_ms = out_ms
1310 : // in_column = [FLOAT_DATA|DATA|CORRECTED_DATA], out_column=new MS
1311 : // no iteration is necessary for the processing.
1312 : // procedure
1313 : // 1. iterate over MS
1314 : // 2. pick single spectrum from in_column (this is not actually necessary for simple scaling but for exibision purpose)
1315 : // 3. fit baseline to each spectrum and subtract it
1316 : // 4. put single spectrum (or a block of spectra) to out_column
1317 :
1318 0 : Block<Int> columns(1);
1319 0 : columns[0] = MS::DATA_DESC_ID;
1320 0 : prepare_for_process(in_column_name, out_ms_name, columns, false);
1321 0 : vi::VisibilityIterator2 *vi = sdh_->getVisIter();
1322 0 : vi->setRowBlocking(kNRowBlocking);
1323 0 : vi::VisBuffer2 *vb = vi->getVisBuffer();
1324 :
1325 0 : split_bloutputname(out_bloutput_name);
1326 0 : bool write_baseline_csv = (bloutputname_csv != "");
1327 0 : bool write_baseline_text = (bloutputname_text != "");
1328 0 : bool write_baseline_table = (bloutputname_table != "");
1329 0 : ofstream ofs_csv;
1330 0 : ofstream ofs_txt;
1331 0 : BaselineTable *bt = 0;
1332 :
1333 0 : if (write_baseline_csv) {
1334 0 : ofs_csv.open(bloutputname_csv.c_str());
1335 : }
1336 0 : if (write_baseline_text) {
1337 0 : ofs_txt.open(bloutputname_text.c_str(), std::ios_base::out | std::ios_base::app);
1338 : }
1339 0 : if (write_baseline_table) {
1340 0 : bt = new BaselineTable(vi->ms());
1341 : }
1342 :
1343 0 : Vector<Int> recspw;
1344 0 : Matrix<Int> recchan;
1345 0 : Vector<size_t> nchan;
1346 0 : Vector<Vector<Bool> > in_mask;
1347 0 : Vector<bool> nchan_set;
1348 0 : parse_spw(in_spw, recspw, recchan, nchan, in_mask, nchan_set);
1349 :
1350 0 : Vector<size_t> ctx_indices(nchan.nelements(), 0ul);
1351 0 : std::vector<int> blparam_eff_base;
1352 0 : auto wn_ulimit_by_rejwn = [&](){
1353 0 : return ((blparam_exclude.size() == 2) &&
1354 0 : (blparam_exclude[1] == SinusoidWaveNumber_kUpperLimit)); };
1355 :
1356 0 : std::vector<float> weight(WeightIndex_kNum);
1357 0 : size_t const var_index = (sigma_value == "stddev") ? WeightIndex_kStddev : WeightIndex_kRms;
1358 :
1359 0 : for (vi->originChunks(); vi->moreChunks(); vi->nextChunk()) {
1360 0 : for (vi->origin(); vi->more(); vi->next()) {
1361 0 : Vector<Int> scans = vb->scan();
1362 0 : Vector<Double> times = vb->time();
1363 0 : Vector<Int> beams = vb->feed1();
1364 0 : Vector<Int> antennas = vb->antenna1();
1365 0 : Vector<Int> data_spw = vb->spectralWindows();
1366 0 : size_t const num_chan = static_cast<size_t>(vb->nChannels());
1367 0 : size_t const num_pol = static_cast<size_t>(vb->nCorrelations());
1368 0 : size_t const num_row = static_cast<size_t>(vb->nRows());
1369 0 : Cube<Float> data_chunk(num_pol, num_chan, num_row, Array<Float>::uninitialized);
1370 0 : SakuraAlignedArray<float> spec(num_chan);
1371 0 : Cube<Bool> flag_chunk(num_pol, num_chan, num_row, Array<Bool>::uninitialized);
1372 0 : SakuraAlignedArray<bool> flag(num_chan);
1373 0 : SakuraAlignedArray<bool> mask(num_chan);
1374 0 : SakuraAlignedArray<bool> mask_after_clipping(num_chan);
1375 0 : float *spec_data = spec.data();
1376 0 : bool *flag_data = flag.data();
1377 0 : bool *mask_data = mask.data();
1378 0 : bool *mask_after_clipping_data = mask_after_clipping.data();
1379 0 : Matrix<Float> weight_matrix(num_pol, num_row, Array<Float>::uninitialized);
1380 :
1381 0 : auto get_wavenumber_upperlimit = [&](){ return static_cast<int>(num_chan) / 2 - 1; };
1382 :
1383 0 : uInt final_mask[num_pol];
1384 0 : uInt final_mask_after_clipping[num_pol];
1385 0 : final_mask[0] = 0;
1386 0 : final_mask[1] = 0;
1387 0 : final_mask_after_clipping[0] = 0;
1388 0 : final_mask_after_clipping[1] = 0;
1389 :
1390 0 : bool new_nchan = false;
1391 0 : get_nchan_and_mask(recspw, data_spw, recchan, num_chan, nchan, in_mask, nchan_set, new_nchan);
1392 0 : if (new_nchan) {
1393 0 : int blparam_max = blparam[blparam.size() - 1];
1394 0 : if (bltype == BaselineType_kSinusoid) {
1395 0 : int nwave_ulimit = get_wavenumber_upperlimit();
1396 0 : get_effective_nwave(blparam, blparam_exclude, nwave_ulimit, blparam_eff_base);
1397 0 : blparam_max = blparam_eff_base[blparam_eff_base.size() - 1];
1398 : }
1399 0 : if ((bltype != BaselineType_kSinusoid) || (!applyfft) || wn_ulimit_by_rejwn()) {
1400 0 : get_baseline_context(bltype,
1401 : static_cast<uint16_t>(blparam_max),
1402 : num_chan, nchan, nchan_set,
1403 : ctx_indices, bl_contexts);
1404 : }
1405 : } else {
1406 0 : int last_nchan_set_idx = nchan_set.size() - 1;
1407 0 : for (int i = nchan_set.size()-1; i >= 0; --i) {
1408 0 : if (nchan_set[i]) break;
1409 0 : --last_nchan_set_idx;
1410 : }
1411 0 : if (0 < last_nchan_set_idx) {
1412 0 : for (int i = 0; i < last_nchan_set_idx; ++i) {
1413 0 : if (nchan[i] == nchan[last_nchan_set_idx]) {
1414 0 : ctx_indices[last_nchan_set_idx] = ctx_indices[i];
1415 0 : break;
1416 : }
1417 : }
1418 : }
1419 : }
1420 :
1421 : // get data/flag cubes (npol*nchan*nrow) from VisBuffer
1422 0 : get_data_cube_float(*vb, data_chunk);
1423 0 : get_flag_cube(*vb, flag_chunk);
1424 :
1425 : // get weight matrix (npol*nrow) from VisBuffer
1426 0 : if (update_weight) {
1427 0 : get_weight_matrix(*vb, weight_matrix);
1428 : }
1429 :
1430 : // loop over MS rows
1431 0 : for (size_t irow = 0; irow < num_row; ++irow) {
1432 0 : size_t idx = 0;
1433 0 : for (size_t ispw = 0; ispw < recspw.nelements(); ++ispw) {
1434 0 : if (data_spw[irow] == recspw[ispw]) {
1435 0 : idx = ispw;
1436 0 : break;
1437 : }
1438 : }
1439 :
1440 : //prepare variables for writing baseline table
1441 0 : Array<Bool> apply_mtx(IPosition(2, num_pol, 1), true);
1442 0 : Array<uInt> bltype_mtx(IPosition(2, num_pol, 1), (uInt)bltype);
1443 : //Array<Int> fpar_mtx(IPosition(2, num_pol, 1), (Int)blparam[blparam.size()-1]);
1444 0 : std::vector<std::vector<size_t> > fpar_mtx_tmp(num_pol);
1445 0 : std::vector<std::vector<double> > ffpar_mtx_tmp(num_pol);
1446 0 : std::vector<std::vector<uInt> > masklist_mtx_tmp(num_pol);
1447 0 : std::vector<std::vector<double> > coeff_mtx_tmp(num_pol);
1448 :
1449 0 : Array<Float> rms_mtx(IPosition(2, num_pol, 1), (Float)0);
1450 0 : Array<Float> cthres_mtx(IPosition(2, num_pol, 1), Array<Float>::uninitialized);
1451 0 : Array<uInt> citer_mtx(IPosition(2, num_pol, 1), Array<uInt>::uninitialized);
1452 0 : Array<Bool> uself_mtx(IPosition(2, num_pol, 1), Array<Bool>::uninitialized);
1453 0 : Array<Float> lfthres_mtx(IPosition(2, num_pol, 1), Array<Float>::uninitialized);
1454 0 : Array<uInt> lfavg_mtx(IPosition(2, num_pol, 1), Array<uInt>::uninitialized);
1455 0 : Array<uInt> lfedge_mtx(IPosition(2, num_pol, 2), Array<uInt>::uninitialized);
1456 :
1457 0 : size_t num_apply_true = 0;
1458 0 : size_t num_fpar_max = 0;
1459 0 : size_t num_ffpar_max = 0;
1460 0 : size_t num_masklist_max = 0;
1461 0 : size_t num_coeff_max = 0;
1462 :
1463 : // loop over polarization
1464 0 : for (size_t ipol = 0; ipol < num_pol; ++ipol) {
1465 : // get a channel mask from data cube
1466 : // (note that the variable 'mask' is flag in the next line
1467 : // actually, then it will be converted to real mask when
1468 : // taking AND with user-given mask info. this is just for
1469 : // saving memory usage...)
1470 0 : get_flag_from_cube(flag_chunk, irow, ipol, num_chan, flag_data);
1471 : // skip spectrum if all channels flagged
1472 0 : if (allchannels_flagged(num_chan, flag_data)) {
1473 0 : apply_mtx[0][ipol] = false;
1474 0 : continue;
1475 : }
1476 :
1477 : // convert flag to mask by taking logical NOT of flag
1478 : // and then operate logical AND with in_mask
1479 0 : for (size_t ichan = 0; ichan < num_chan; ++ichan) {
1480 0 : mask_data[ichan] = in_mask[idx][ichan] && (!(flag_data[ichan]));
1481 : }
1482 : // get a spectrum from data cube
1483 0 : get_spectrum_from_cube(data_chunk, irow, ipol, num_chan, spec_data);
1484 : // line finding. get baseline mask (invert=true)
1485 0 : if (linefinding) {
1486 0 : findLineAndGetMask(num_chan, spec_data, mask_data, threshold,
1487 : avg_limit, minwidth, edge, true, mask_data);
1488 : }
1489 :
1490 0 : std::vector<size_t> blparam_eff;
1491 :
1492 : size_t num_coeff;
1493 0 : if (bltype == BaselineType_kSinusoid) {
1494 0 : int nwave_ulimit = get_wavenumber_upperlimit();
1495 0 : finalise_effective_nwave(blparam_eff_base, blparam_exclude,
1496 : nwave_ulimit,
1497 : num_chan, spec_data, mask_data,
1498 : applyfft, fftmethod, fftthresh,
1499 : blparam_eff);
1500 0 : size_t blparam_eff_size = blparam_eff.size();
1501 0 : if (blparam_eff[0] == 0) {
1502 0 : num_coeff = blparam_eff_size * 2 - 1;
1503 : } else {
1504 0 : num_coeff = blparam_eff_size * 2;
1505 : }
1506 0 : } else if (bltype == BaselineType_kCubicSpline) {
1507 0 : blparam_eff.resize(1);
1508 0 : blparam_eff[0] = blparam[blparam.size() - 1];
1509 0 : num_coeff = blparam_eff[0] * 4;
1510 : } else { // poly, chebyshev
1511 0 : blparam_eff.resize(1);
1512 0 : blparam_eff[0] = blparam[blparam.size() - 1];
1513 0 : status =
1514 0 : LIBSAKURA_SYMBOL(GetNumberOfCoefficientsFloat)(bl_contexts[ctx_indices[idx]],
1515 : blparam_eff[0],
1516 : &num_coeff);
1517 0 : check_sakura_status("sakura_GetNumberOfCoefficients", status);
1518 : }
1519 :
1520 : // Final check of the valid number of channels
1521 0 : size_t num_min =
1522 0 : (bltype == BaselineType_kCubicSpline) ? blparam[blparam.size()-1] + 3 : num_coeff;
1523 0 : if (NValidMask(num_chan, mask_data) < num_min) {
1524 0 : flag_spectrum_in_cube(flag_chunk, irow, ipol);
1525 0 : apply_mtx[0][ipol] = false;
1526 : os << LogIO::WARN
1527 : << "Too few valid channels to fit. Skipping Antenna "
1528 0 : << antennas[irow] << ", Beam " << beams[irow] << ", SPW "
1529 0 : << data_spw[irow] << ", Pol " << ipol << ", Time "
1530 0 : << MVTime(times[irow] / 24. / 3600.).string(MVTime::YMD, 8)
1531 0 : << LogIO::POST;
1532 0 : continue;
1533 : }
1534 : // actual execution of single spectrum
1535 : float rms;
1536 0 : if (write_baseline_text || write_baseline_csv || write_baseline_table) {
1537 0 : num_apply_true++;
1538 :
1539 0 : if (num_coeff_max < num_coeff) {
1540 0 : num_coeff_max = num_coeff;
1541 : }
1542 0 : SakuraAlignedArray<double> coeff(num_coeff);
1543 0 : double *coeff_data = coeff.data();
1544 :
1545 : //---GetBestFitBaselineCoefficientsFloat()...
1546 : //func0(ctx_indices[idx], num_chan, blparam_eff, spec_data, mask_data, num_coeff, coeff_data, mask_after_clipping_data, &rms);
1547 0 : LIBSAKURA_SYMBOL(LSQFitContextFloat) *context = nullptr;
1548 0 : if ((bltype != BaselineType_kSinusoid) || (!applyfft) || wn_ulimit_by_rejwn()) {
1549 0 : context = bl_contexts[ctx_indices[idx]];
1550 : }
1551 0 : func0(context, num_chan, blparam_eff, spec_data, mask_data, num_coeff, coeff_data, mask_after_clipping_data, &rms);
1552 :
1553 0 : for (size_t i = 0; i < num_chan; ++i) {
1554 0 : if (mask_data[i] == false) {
1555 0 : final_mask[ipol] += 1;
1556 : }
1557 0 : if (mask_after_clipping_data[i] == false) {
1558 0 : final_mask_after_clipping[ipol] += 1;
1559 : }
1560 : }
1561 :
1562 : //set_array_for_bltable(fpar_mtx_tmp)
1563 0 : size_t num_fpar = blparam_eff.size();
1564 0 : fpar_mtx_tmp[ipol].resize(num_fpar);
1565 0 : if (num_fpar_max < num_fpar) {
1566 0 : num_fpar_max = num_fpar;
1567 : }
1568 0 : fpar_mtx_tmp[ipol].resize(num_fpar);
1569 0 : for (size_t ifpar = 0; ifpar < num_fpar; ++ifpar) {
1570 0 : fpar_mtx_tmp[ipol][ifpar] = blparam_eff[ifpar];
1571 : }
1572 :
1573 : //---set_array_for_bltable(ffpar_mtx_tmp)
1574 0 : func1(ipol, ffpar_mtx_tmp, num_ffpar_max);
1575 :
1576 : //set_array_for_bltable<double, Float>(ipol, num_coeff, coeff_data, coeff_mtx);
1577 0 : coeff_mtx_tmp[ipol].resize(num_coeff);
1578 0 : for (size_t icoeff = 0; icoeff < num_coeff; ++icoeff) {
1579 0 : coeff_mtx_tmp[ipol][icoeff] = coeff_data[icoeff];
1580 : }
1581 :
1582 0 : Vector<uInt> masklist;
1583 0 : get_masklist_from_mask(num_chan, mask_after_clipping_data, masklist);
1584 0 : if (masklist.size() > num_masklist_max) {
1585 0 : num_masklist_max = masklist.size();
1586 : }
1587 0 : masklist_mtx_tmp[ipol].clear();
1588 0 : for (size_t imask = 0; imask < masklist.size(); ++imask) {
1589 0 : masklist_mtx_tmp[ipol].push_back(masklist[imask]);
1590 : }
1591 :
1592 : //---SubtractBaselineUsingCoefficientsFloat()...
1593 : //func2(ctx_indices[idx], num_chan, fpar_mtx_tmp[ipol], spec_data, num_coeff, coeff_data);
1594 0 : func2(context, num_chan, fpar_mtx_tmp[ipol], spec_data, num_coeff, coeff_data);
1595 :
1596 0 : rms_mtx[0][ipol] = rms;
1597 :
1598 0 : cthres_mtx[0][ipol] = clip_threshold_sigma;
1599 0 : citer_mtx[0][ipol] = (uInt)num_fitting_max - 1;
1600 0 : uself_mtx[0][ipol] = false;
1601 0 : lfthres_mtx[0][ipol] = 0.0;
1602 0 : lfavg_mtx[0][ipol] = 0;
1603 0 : for (size_t iedge = 0; iedge < 2; ++iedge) {
1604 0 : lfedge_mtx[iedge][ipol] = 0;
1605 0 : }
1606 : } else {
1607 : //---SubtractBaselineFloat()...
1608 : //func3(ctx_indices[idx], num_chan, blparam_eff, num_coeff, spec_data, mask_data, &rms);
1609 0 : LIBSAKURA_SYMBOL(LSQFitContextFloat) *context = nullptr;
1610 0 : if ((bltype != BaselineType_kSinusoid) || (!applyfft) || wn_ulimit_by_rejwn()) {
1611 0 : context = bl_contexts[ctx_indices[idx]];
1612 : }
1613 0 : func3(context, num_chan, blparam_eff, num_coeff, spec_data, mask_data, mask_after_clipping_data, &rms);
1614 : }
1615 : // set back a spectrum to data cube
1616 0 : if (do_subtract) {
1617 0 : set_spectrum_to_cube(data_chunk, irow, ipol, num_chan, spec_data);
1618 : }
1619 :
1620 0 : if (update_weight) {
1621 0 : compute_weight(num_chan, spec_data, mask_after_clipping_data, weight);
1622 0 : set_weight_to_matrix(weight_matrix, irow, ipol, weight.at(var_index));
1623 : }
1624 :
1625 : } // end of polarization loop
1626 :
1627 : // output results of fitting
1628 0 : if (num_apply_true == 0) continue;
1629 :
1630 0 : Array<Int> fpar_mtx(IPosition(2, num_pol, num_fpar_max),
1631 : Array<Int>::uninitialized);
1632 0 : set_matrix_for_bltable<size_t, Int>(num_pol, num_fpar_max,
1633 : fpar_mtx_tmp, fpar_mtx);
1634 0 : Array<Float> ffpar_mtx(IPosition(2, num_pol, num_ffpar_max),
1635 : Array<Float>::uninitialized);
1636 0 : set_matrix_for_bltable<double, Float>(num_pol, num_ffpar_max,
1637 : ffpar_mtx_tmp, ffpar_mtx);
1638 0 : Array<uInt> masklist_mtx(IPosition(2, num_pol, num_masklist_max),
1639 : Array<uInt>::uninitialized);
1640 0 : set_matrix_for_bltable<uInt, uInt>(num_pol, num_masklist_max,
1641 : masklist_mtx_tmp, masklist_mtx);
1642 0 : Array<Float> coeff_mtx(IPosition(2, num_pol, num_coeff_max),
1643 : Array<Float>::uninitialized);
1644 0 : set_matrix_for_bltable<double, Float>(num_pol, num_coeff_max,
1645 : coeff_mtx_tmp, coeff_mtx);
1646 0 : Matrix<uInt> masklist_mtx2 = masklist_mtx;
1647 0 : Matrix<Bool> apply_mtx2 = apply_mtx;
1648 :
1649 0 : if (write_baseline_table) {
1650 0 : bt->appenddata((uInt)scans[irow], (uInt)beams[irow], (uInt)antennas[irow],
1651 0 : (uInt)data_spw[irow], 0, times[irow],
1652 : apply_mtx, bltype_mtx, fpar_mtx, ffpar_mtx, masklist_mtx,
1653 : coeff_mtx, rms_mtx, (uInt)num_chan, cthres_mtx, citer_mtx,
1654 : uself_mtx, lfthres_mtx, lfavg_mtx, lfedge_mtx);
1655 : }
1656 :
1657 0 : if (write_baseline_text) {
1658 0 : for (size_t ipol = 0; ipol < num_pol; ++ipol) {
1659 0 : if (apply_mtx2(ipol, 0) == false) continue;
1660 :
1661 0 : ofs_txt << "Scan" << '[' << (uInt)scans[irow] << ']' << ' '
1662 0 : << "Beam" << '[' << (uInt)beams[irow] << ']' << ' '
1663 0 : << "Spw" << '[' << (uInt)data_spw[irow] << ']' << ' '
1664 0 : << "Pol" << '[' << ipol << ']' << ' '
1665 0 : << "Time" << '[' << MVTime(times[irow]/ 24. / 3600.).string(MVTime::YMD, 8) << ']'
1666 0 : << endl;
1667 0 : ofs_txt << endl;
1668 0 : ofs_txt << "Fitter range = " << '[';
1669 :
1670 0 : for (size_t imasklist = 0; imasklist < num_masklist_max/2; ++imasklist) {
1671 0 : if (imasklist == 0) {
1672 0 : ofs_txt << '[' << masklist_mtx2(ipol, 2 * imasklist) << ';'
1673 0 : << masklist_mtx2(ipol, 2 * imasklist + 1) << ']';
1674 : }
1675 0 : if (imasklist >= 1
1676 0 : && (0 != masklist_mtx2(ipol, 2 * imasklist)
1677 0 : && 0 != masklist_mtx2(ipol, 2 * imasklist + 1))) {
1678 0 : ofs_txt << ",[" << masklist_mtx2(ipol, 2 * imasklist) << ','
1679 0 : << masklist_mtx2(ipol, 2 * imasklist + 1) << ']';
1680 : }
1681 : }
1682 :
1683 0 : ofs_txt << ']' << endl;
1684 0 : ofs_txt << endl;
1685 :
1686 0 : Matrix<uInt> bltype_mtx2 = bltype_mtx[0][ipol];
1687 0 : Matrix<Int> fpar_mtx2 = fpar_mtx[0][ipol];
1688 0 : Matrix<Float> rms_mtx2 = rms_mtx[0][ipol];
1689 0 : string bltype_name;
1690 :
1691 0 : string blparam_name ="order";
1692 0 : if (bltype_mtx2(0, 0) == (uInt)0) {
1693 0 : bltype_name = "poly";
1694 0 : } else if (bltype_mtx2(0, 0) == (uInt)1) {
1695 0 : bltype_name = "chebyshev";
1696 0 : } else if (bltype_mtx2(0, 0) == (uInt)2) {
1697 0 : blparam_name = "npiece";
1698 0 : bltype_name = "cspline";
1699 0 : } else if (bltype_mtx2(0, 0) == (uInt)3) {
1700 0 : blparam_name = "nwave";
1701 0 : bltype_name = "sinusoid";
1702 : }
1703 :
1704 : ofs_txt << "Baseline parameters Function = "
1705 0 : << bltype_name << " " << blparam_name << " = ";
1706 0 : Matrix<Int> fpar_mtx3 = fpar_mtx;
1707 0 : if (bltype_mtx2(0,0) == (uInt)3) {
1708 0 : for (size_t num = 0; num < num_fpar_max; ++num) {
1709 0 : ofs_txt << fpar_mtx3(ipol, num) << " ";
1710 : }
1711 0 : ofs_txt << endl;
1712 : } else {
1713 0 : ofs_txt << fpar_mtx2(0, 0) << endl;
1714 : }
1715 :
1716 0 : ofs_txt << endl;
1717 0 : ofs_txt << "Results of baseline fit" << endl;
1718 0 : ofs_txt << endl;
1719 0 : Matrix<Float> coeff_mtx2 = coeff_mtx;
1720 :
1721 0 : if (bltype_mtx2(0,0) == (uInt)0 || bltype_mtx2(0,0) == (uInt)1 || bltype_mtx2(0,0) == (uInt)2){
1722 0 : for (size_t icoeff = 0; icoeff < num_coeff_max; ++icoeff) {
1723 0 : ofs_txt << "p" << icoeff << " = " << setprecision(8) << coeff_mtx2(ipol, icoeff) << " ";
1724 : }
1725 0 : } else if (bltype_mtx2(0,0) == (uInt)3) {
1726 0 : size_t wn=0;
1727 0 : string c_s ="s";
1728 : //if (blparam[0] == 0) {
1729 0 : if (fpar_mtx3(ipol, wn) == 0) {
1730 0 : ofs_txt << "c" << fpar_mtx3(ipol, wn) << " = " <<setw(13)<<left<< setprecision(8) << coeff_mtx2(ipol, 0) << " ";
1731 0 : wn = 1;
1732 : //for (size_t icoeff = 1; icoeff < num_coeff_max; ++icoeff) {
1733 0 : for (size_t icoeff = 1; icoeff < coeff_mtx_tmp[ipol].size(); ++icoeff) {
1734 0 : ofs_txt << c_s << fpar_mtx3(ipol, wn) << " = " <<setw(13)<<left<< setprecision(8) << coeff_mtx2(ipol, icoeff) << " ";
1735 0 : c_s == "s" ? (c_s = "c") : (c_s = "s");
1736 0 : if (icoeff % 2 == 0) {
1737 0 : ++wn;
1738 : }
1739 : }
1740 : } else {
1741 0 : wn = 0;
1742 : //for (size_t icoeff = 0; icoeff < num_coeff_max; ++icoeff) {
1743 0 : for (size_t icoeff = 0; icoeff < coeff_mtx_tmp[ipol].size(); ++icoeff) {
1744 0 : ofs_txt << c_s << fpar_mtx3(ipol, wn) << " = " <<setw(13)<<left<< setprecision(8) << coeff_mtx2(ipol, icoeff) << " ";
1745 0 : c_s == "s" ? (c_s = "c") : (c_s = "s");
1746 0 : if (icoeff % 2 != 0) {
1747 0 : ++wn;
1748 : }
1749 : }
1750 : }
1751 : }
1752 :
1753 0 : ofs_txt << endl;
1754 0 : ofs_txt << endl;
1755 0 : ofs_txt << "rms = ";
1756 0 : ofs_txt << setprecision(8) << rms_mtx2(0, 0) << endl;
1757 0 : ofs_txt << endl;
1758 0 : ofs_txt << "Number of clipped channels = "
1759 0 : << final_mask_after_clipping[ipol] - final_mask[ipol] << endl;
1760 0 : ofs_txt << endl;
1761 0 : ofs_txt << "------------------------------------------------------"
1762 0 : << endl;
1763 0 : ofs_txt << endl;
1764 : }
1765 : }
1766 :
1767 0 : if (write_baseline_csv) {
1768 0 : for (size_t ipol = 0; ipol < num_pol; ++ipol) {
1769 0 : if (apply_mtx2(ipol, 0) == false) continue;
1770 :
1771 0 : ofs_csv << (uInt)scans[irow] << ',' << (uInt)beams[irow] << ','
1772 0 : << (uInt)data_spw[irow] << ',' << ipol << ','
1773 0 : << setprecision(12) << times[irow] << ',';
1774 0 : ofs_csv << '[';
1775 0 : for (size_t imasklist = 0; imasklist < num_masklist_max / 2; ++imasklist) {
1776 0 : if (imasklist == 0) {
1777 0 : ofs_csv << '[' << masklist_mtx2(ipol, 2 * imasklist) << ';'
1778 0 : << masklist_mtx2(ipol, 2 * imasklist + 1) << ']';
1779 : }
1780 0 : if (imasklist >= 1
1781 0 : && (0 != masklist_mtx2(ipol, 2 * imasklist)
1782 0 : && 0 != masklist_mtx2(ipol, 2 * imasklist + 1))) {
1783 0 : ofs_csv << ";[" << masklist_mtx2(ipol, 2 * imasklist) << ';'
1784 0 : << masklist_mtx2(ipol, 2 * imasklist + 1) << ']';
1785 : }
1786 : }
1787 0 : ofs_csv << ']' << ',';
1788 0 : Matrix<uInt> bltype_mtx2 = bltype_mtx[0][ipol];
1789 0 : string bltype_name;
1790 0 : if (bltype_mtx2(0, 0) == (uInt)0) {
1791 0 : bltype_name = "poly";
1792 0 : } else if (bltype_mtx2(0, 0) == (uInt)1) {
1793 0 : bltype_name = "chebyshev";
1794 0 : } else if (bltype_mtx2(0, 0) == (uInt)2) {
1795 0 : bltype_name = "cspline";
1796 0 : } else if (bltype_mtx2(0, 0) == (uInt)3) {
1797 0 : bltype_name = "sinusoid";
1798 : }
1799 :
1800 0 : Matrix<Int> fpar_mtx2 = fpar_mtx;
1801 0 : if (bltype_mtx2(0, 0) == (uInt)3) {
1802 0 : ofs_csv << bltype_name.c_str() << ',' << fpar_mtx2(ipol, 0);
1803 0 : for (size_t i = 1; i < num_fpar_max; ++i) {
1804 0 : ofs_csv << ';' << fpar_mtx2(ipol, i);
1805 : }
1806 0 : ofs_csv << ',';
1807 : } else {
1808 0 : ofs_csv << bltype_name.c_str() << ',' << fpar_mtx2(ipol, 0)
1809 0 : << ',';
1810 : }
1811 :
1812 0 : Matrix<Float> coeff_mtx2 = coeff_mtx;
1813 0 : if (bltype_mtx2(0, 0) == (uInt)3) {
1814 0 : for (size_t icoeff = 0; icoeff < coeff_mtx_tmp[ipol].size(); ++icoeff) {
1815 0 : ofs_csv << setprecision(8) << coeff_mtx2(ipol, icoeff) << ',';
1816 : }
1817 : } else {
1818 0 : for (size_t icoeff = 0; icoeff < num_coeff_max; ++icoeff) {
1819 0 : ofs_csv << setprecision(8) << coeff_mtx2(ipol, icoeff) << ',';
1820 : }
1821 : }
1822 :
1823 0 : Matrix<Float> rms_mtx2 = rms_mtx;
1824 0 : ofs_csv << setprecision(8) << rms_mtx2(ipol, 0) << ',';
1825 0 : ofs_csv << final_mask_after_clipping[ipol] - final_mask[ipol];
1826 0 : ofs_csv << endl;
1827 : }
1828 : }
1829 : } // end of chunk row loop
1830 : // write back data cube to VisBuffer
1831 0 : if (do_subtract) {
1832 0 : if (update_weight) {
1833 0 : sdh_->fillCubeToOutputMs(vb, data_chunk, &flag_chunk, &weight_matrix);
1834 : } else {
1835 0 : sdh_->fillCubeToOutputMs(vb, data_chunk, &flag_chunk);
1836 : }
1837 : }
1838 : } // end of vi loop
1839 : } // end of chunk loop
1840 :
1841 0 : if (write_baseline_table) {
1842 0 : bt->save(bloutputname_table);
1843 0 : delete bt;
1844 : }
1845 0 : if (write_baseline_csv) {
1846 0 : ofs_csv.close();
1847 : }
1848 0 : if (write_baseline_text) {
1849 0 : ofs_txt.close();
1850 : }
1851 :
1852 0 : finalize_process();
1853 0 : destroy_baseline_contexts(bl_contexts);
1854 :
1855 : //double tend = gettimeofday_sec();
1856 : //std::cout << "Elapsed time = " << (tend - tstart) << " sec." << std::endl;
1857 0 : }
1858 :
1859 : ////////////////////////////////////////////////////////////////////////
1860 : ///// Atcual processing functions
1861 : ////////////////////////////////////////////////////////////////////////
1862 :
1863 : //Subtract baseline using normal or Chebyshev polynomials
1864 0 : void SingleDishMS::subtractBaseline(string const& in_column_name,
1865 : string const& out_ms_name,
1866 : string const& out_bloutput_name,
1867 : bool const& do_subtract,
1868 : string const& in_spw,
1869 : bool const& update_weight,
1870 : string const& sigma_value,
1871 : string const& blfunc,
1872 : int const order,
1873 : float const clip_threshold_sigma,
1874 : int const num_fitting_max,
1875 : bool const linefinding,
1876 : float const threshold,
1877 : int const avg_limit,
1878 : int const minwidth,
1879 : vector<int> const& edge) {
1880 0 : vector<int> order_vect;
1881 0 : order_vect.push_back(order);
1882 0 : vector<int> blparam_exclude_dummy;
1883 0 : blparam_exclude_dummy.clear();
1884 :
1885 0 : LogIO os(_ORIGIN);
1886 : os << "Fitting and subtracting polynomial baseline order = " << order
1887 0 : << LogIO::POST;
1888 0 : if (order < 0) {
1889 0 : throw(AipsError("order must be positive or zero."));
1890 : }
1891 :
1892 : LIBSAKURA_SYMBOL(Status) status;
1893 : LIBSAKURA_SYMBOL(LSQFitStatus) bl_status;
1894 0 : std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *> bl_contexts;
1895 0 : bl_contexts.clear();
1896 0 : size_t bltype = BaselineType_kPolynomial;
1897 0 : string blfunc_lower = blfunc;
1898 : std::transform(
1899 : blfunc_lower.begin(),
1900 : blfunc_lower.end(),
1901 : blfunc_lower.begin(),
1902 0 : [](unsigned char c) {return std::tolower(c);}
1903 0 : );
1904 0 : if (blfunc_lower == "chebyshev") {
1905 0 : bltype = BaselineType_kChebyshev;
1906 : }
1907 :
1908 0 : doSubtractBaseline(in_column_name,
1909 : out_ms_name,
1910 : out_bloutput_name,
1911 : do_subtract,
1912 : in_spw,
1913 : update_weight,
1914 : sigma_value,
1915 : status,
1916 : bl_contexts,
1917 : bltype,
1918 : order_vect,
1919 : blparam_exclude_dummy,
1920 0 : false,
1921 : "",
1922 : "",
1923 : clip_threshold_sigma,
1924 : num_fitting_max,
1925 : linefinding,
1926 : threshold,
1927 : avg_limit,
1928 : minwidth,
1929 : edge,
1930 : [&](LIBSAKURA_SYMBOL(LSQFitContextFloat) const *context,
1931 : size_t const num_chan, std::vector<size_t> const &/*nwave*/,
1932 : float *spec, bool const *mask, size_t const /*num_coeff*/, double *coeff,
1933 0 : bool *mask_after_clipping, float *rms){
1934 0 : status = LIBSAKURA_SYMBOL(LSQFitPolynomialFloat)(
1935 0 : context, static_cast<uint16_t>(order_vect[0]),
1936 0 : num_chan, spec, mask, clip_threshold_sigma, num_fitting_max,
1937 0 : order_vect[0] + 1, coeff, nullptr, nullptr, mask_after_clipping, rms, &bl_status);
1938 0 : check_sakura_status("sakura_LSQFitPolynomialFloat", status);
1939 0 : if (bl_status != LIBSAKURA_SYMBOL(LSQFitStatus_kOK)) {
1940 0 : throw(AipsError("baseline fitting isn't successful."));
1941 : }
1942 0 : },
1943 0 : [&](size_t ipol, std::vector<std::vector<double> > &ffpar_mtx_tmp, size_t &num_ffpar_max) {
1944 0 : size_t num_ffpar = get_num_coeff_bloutput(bltype, 0, num_ffpar_max);
1945 0 : ffpar_mtx_tmp[ipol].resize(num_ffpar);
1946 0 : },
1947 : [&](LIBSAKURA_SYMBOL(LSQFitContextFloat) const *context,
1948 : size_t const num_chan, std::vector<size_t> const &/*nwave*/,
1949 0 : float *spec, size_t const /*num_coeff*/, double *coeff){
1950 0 : status = LIBSAKURA_SYMBOL(SubtractPolynomialFloat)(
1951 0 : context, num_chan, spec, order_vect[0] + 1, coeff, spec);
1952 0 : check_sakura_status("sakura_SubtractPolynomialFloat", status);},
1953 : [&](LIBSAKURA_SYMBOL(LSQFitContextFloat) const *context,
1954 : size_t const num_chan, std::vector<size_t> const &/*nwave*/,
1955 0 : size_t const /*num_coeff*/, float *spec, bool const *mask, bool *mask_after_clipping, float *rms){
1956 0 : status = LIBSAKURA_SYMBOL(LSQFitPolynomialFloat)(
1957 0 : context, static_cast<uint16_t>(order_vect[0]),
1958 0 : num_chan, spec, mask, clip_threshold_sigma, num_fitting_max,
1959 0 : order_vect[0] + 1, nullptr, nullptr, spec, mask_after_clipping, rms, &bl_status);
1960 0 : check_sakura_status("sakura_LSQFitPolynomialFloat", status);
1961 0 : if (bl_status != LIBSAKURA_SYMBOL(LSQFitStatus_kOK)) {
1962 0 : throw(AipsError("baseline fitting isn't successful."));
1963 : }
1964 0 : },
1965 : os
1966 : );
1967 0 : }
1968 :
1969 : //Subtract baseline using natural cubic spline
1970 0 : void SingleDishMS::subtractBaselineCspline(string const& in_column_name,
1971 : string const& out_ms_name,
1972 : string const& out_bloutput_name,
1973 : bool const& do_subtract,
1974 : string const& in_spw,
1975 : bool const& update_weight,
1976 : string const& sigma_value,
1977 : int const npiece,
1978 : float const clip_threshold_sigma,
1979 : int const num_fitting_max,
1980 : bool const linefinding,
1981 : float const threshold,
1982 : int const avg_limit,
1983 : int const minwidth,
1984 : vector<int> const& edge) {
1985 0 : vector<int> npiece_vect;
1986 0 : npiece_vect.push_back(npiece);
1987 0 : vector<int> blparam_exclude_dummy;
1988 0 : blparam_exclude_dummy.clear();
1989 :
1990 0 : LogIO os(_ORIGIN);
1991 : os << "Fitting and subtracting cubic spline baseline npiece = " << npiece
1992 0 : << LogIO::POST;
1993 0 : if (npiece <= 0) {
1994 0 : throw(AipsError("npiece must be positive."));
1995 : }
1996 :
1997 : LIBSAKURA_SYMBOL(Status) status;
1998 : LIBSAKURA_SYMBOL(LSQFitStatus) bl_status;
1999 0 : std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *> bl_contexts;
2000 0 : bl_contexts.clear();
2001 0 : size_t const bltype = BaselineType_kCubicSpline;
2002 0 : SakuraAlignedArray<size_t> boundary(npiece+1);
2003 0 : size_t *boundary_data = boundary.data();
2004 :
2005 0 : doSubtractBaseline(in_column_name,
2006 : out_ms_name,
2007 : out_bloutput_name,
2008 : do_subtract,
2009 : in_spw,
2010 : update_weight,
2011 : sigma_value,
2012 : status,
2013 : bl_contexts,
2014 : bltype,
2015 : npiece_vect,
2016 : blparam_exclude_dummy,
2017 0 : false,
2018 : "",
2019 : "",
2020 : clip_threshold_sigma,
2021 : num_fitting_max,
2022 : linefinding,
2023 : threshold,
2024 : avg_limit,
2025 : minwidth,
2026 : edge,
2027 : [&](LIBSAKURA_SYMBOL(LSQFitContextFloat) const *context,
2028 : size_t const num_chan, std::vector<size_t> const &/*nwave*/,
2029 : float *spec, bool const *mask, size_t const /*num_coeff*/, double *coeff,
2030 0 : bool *mask_after_clipping, float *rms) {
2031 0 : status = LIBSAKURA_SYMBOL(LSQFitCubicSplineFloat)(
2032 0 : context, static_cast<uint16_t>(npiece_vect[0]),
2033 0 : num_chan, spec, mask, clip_threshold_sigma, num_fitting_max,
2034 : reinterpret_cast<double (*)[4]>(coeff), nullptr, nullptr,
2035 0 : mask_after_clipping, rms, boundary_data, &bl_status);
2036 0 : check_sakura_status("sakura_LSQFitCubicSplineFloat", status);
2037 0 : if (bl_status != LIBSAKURA_SYMBOL(LSQFitStatus_kOK)) {
2038 0 : throw(AipsError("baseline fitting isn't successful."));
2039 : }
2040 0 : },
2041 0 : [&](size_t ipol, std::vector<std::vector<double> > &ffpar_mtx_tmp, size_t &num_ffpar_max) {
2042 0 : size_t num_ffpar = get_num_coeff_bloutput(
2043 0 : bltype, npiece_vect[0], num_ffpar_max);
2044 0 : ffpar_mtx_tmp[ipol].resize(num_ffpar);
2045 0 : for (size_t ipiece = 0; ipiece < num_ffpar; ++ipiece) {
2046 0 : ffpar_mtx_tmp[ipol][ipiece] = boundary_data[ipiece];
2047 : }
2048 0 : },
2049 : [&](LIBSAKURA_SYMBOL(LSQFitContextFloat) const *context,
2050 : size_t const num_chan, std::vector<size_t> const &/*nwave*/,
2051 0 : float *spec, size_t const /*num_coeff*/, double *coeff) {
2052 0 : status = LIBSAKURA_SYMBOL(SubtractCubicSplineFloat)(
2053 0 : context, num_chan, spec, npiece_vect[0],
2054 0 : reinterpret_cast<double (*)[4]>(coeff), boundary_data, spec);
2055 0 : check_sakura_status("sakura_SubtractCubicSplineFloat", status);},
2056 : [&](LIBSAKURA_SYMBOL(LSQFitContextFloat) const *context,
2057 : size_t const num_chan, std::vector<size_t> const &/*nwave*/,
2058 0 : size_t const /*num_coeff*/, float *spec, bool const *mask, bool *mask_after_clipping, float *rms) {
2059 0 : status = LIBSAKURA_SYMBOL(LSQFitCubicSplineFloat)(
2060 0 : context, static_cast<uint16_t>(npiece_vect[0]),
2061 0 : num_chan, spec, mask, clip_threshold_sigma, num_fitting_max,
2062 0 : nullptr, nullptr, spec, mask_after_clipping, rms, boundary_data, &bl_status);
2063 0 : check_sakura_status("sakura_LSQFitCubicSplineFloat", status);
2064 0 : if (bl_status != LIBSAKURA_SYMBOL(LSQFitStatus_kOK)) {
2065 0 : throw(AipsError("baseline fitting isn't successful."));
2066 : }
2067 0 : },
2068 : os
2069 : );
2070 0 : }
2071 :
2072 :
2073 0 : void SingleDishMS::subtractBaselineSinusoid(string const& in_column_name,
2074 : string const& out_ms_name,
2075 : string const& out_bloutput_name,
2076 : bool const& do_subtract,
2077 : string const& in_spw,
2078 : bool const& update_weight,
2079 : string const& sigma_value,
2080 : string const& addwn0,
2081 : string const& rejwn0,
2082 : bool const applyfft,
2083 : string const fftmethod,
2084 : string const fftthresh,
2085 : float const clip_threshold_sigma,
2086 : int const num_fitting_max,
2087 : bool const linefinding,
2088 : float const threshold,
2089 : int const avg_limit,
2090 : int const minwidth,
2091 : vector<int> const& edge) {
2092 0 : char const delim = ',';
2093 0 : vector<int> addwn = string_to_list(addwn0, delim);
2094 0 : vector<int> rejwn = string_to_list(rejwn0, delim);
2095 :
2096 0 : LogIO os(_ORIGIN);
2097 0 : os << "Fitting and subtracting sinusoid baseline with wave numbers " << addwn0 << LogIO::POST;
2098 0 : if (addwn.size() == 0) {
2099 0 : throw(AipsError("addwn must contain at least one element."));
2100 : }
2101 :
2102 : LIBSAKURA_SYMBOL(Status) status;
2103 : LIBSAKURA_SYMBOL(LSQFitStatus) bl_status;
2104 0 : std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *> bl_contexts;
2105 0 : bl_contexts.clear();
2106 0 : LIBSAKURA_SYMBOL(LSQFitContextFloat) *context = nullptr;
2107 0 : size_t bltype = BaselineType_kSinusoid;
2108 :
2109 0 : auto wn_ulimit_by_rejwn = [&](){
2110 0 : return ((rejwn.size() == 2) &&
2111 0 : (rejwn[1] == SinusoidWaveNumber_kUpperLimit)); };
2112 0 : auto par_spectrum_context = [&](){
2113 0 : return (applyfft && !wn_ulimit_by_rejwn());
2114 0 : };
2115 : auto prepare_context = [&](LIBSAKURA_SYMBOL(LSQFitContextFloat) const *context0,
2116 0 : size_t const num_chan, std::vector<size_t> const &nwave){
2117 0 : if (par_spectrum_context()) {
2118 0 : status = LIBSAKURA_SYMBOL(CreateLSQFitContextSinusoidFloat)(
2119 0 : static_cast<uint16_t>(nwave[nwave.size()-1]),
2120 0 : num_chan, &context);
2121 0 : check_sakura_status("sakura_CreateLSQFitContextSinusoidFloat", status);
2122 : } else {
2123 0 : context = const_cast<LIBSAKURA_SYMBOL(LSQFitContextFloat) *>(context0);
2124 : }
2125 0 : };
2126 0 : auto clear_context = [&](){
2127 0 : if (par_spectrum_context()) {
2128 0 : status = LIBSAKURA_SYMBOL(DestroyLSQFitContextFloat)(context);
2129 0 : check_sakura_status("sakura_DestoyBaselineContextFloat", status);
2130 0 : context = nullptr;
2131 : }
2132 0 : };
2133 :
2134 0 : doSubtractBaseline(in_column_name,
2135 : out_ms_name,
2136 : out_bloutput_name,
2137 : do_subtract,
2138 : in_spw,
2139 : update_weight,
2140 : sigma_value,
2141 : status,
2142 : bl_contexts,
2143 : bltype,
2144 : addwn,
2145 : rejwn,
2146 : applyfft,
2147 : fftmethod,
2148 : fftthresh,
2149 : clip_threshold_sigma,
2150 : num_fitting_max,
2151 : linefinding,
2152 : threshold,
2153 : avg_limit,
2154 : minwidth,
2155 : edge,
2156 : [&](LIBSAKURA_SYMBOL(LSQFitContextFloat) const *context0,
2157 : size_t const num_chan, std::vector<size_t> const &nwave,
2158 : float *spec, bool const *mask, size_t const num_coeff, double *coeff,
2159 0 : bool *mask_after_clipping, float *rms) {
2160 0 : prepare_context(context0, num_chan, nwave);
2161 0 : status = LIBSAKURA_SYMBOL(LSQFitSinusoidFloat)(
2162 0 : context, nwave.size(), &nwave[0],
2163 0 : num_chan, spec, mask, clip_threshold_sigma, num_fitting_max,
2164 0 : num_coeff, coeff, nullptr, nullptr, mask_after_clipping, rms, &bl_status);
2165 0 : check_sakura_status("sakura_LSQFitSinusoidFloat", status);
2166 0 : check_baseline_status(bl_status);
2167 0 : },
2168 0 : [&](size_t ipol, std::vector<std::vector<double> > &ffpar_mtx_tmp, size_t &num_ffpar_max) {
2169 0 : size_t num_ffpar = get_num_coeff_bloutput(bltype, addwn.size(), num_ffpar_max);
2170 0 : ffpar_mtx_tmp[ipol].resize(num_ffpar);
2171 0 : },
2172 : [&](LIBSAKURA_SYMBOL(LSQFitContextFloat) const *context0,
2173 : size_t const num_chan, std::vector<size_t> const &nwave,
2174 0 : float *spec, size_t num_coeff, double *coeff) {
2175 0 : if (!par_spectrum_context()) {
2176 0 : context = const_cast<LIBSAKURA_SYMBOL(LSQFitContextFloat) *>(context0);
2177 : }
2178 0 : status = LIBSAKURA_SYMBOL(SubtractSinusoidFloat)(
2179 0 : context, num_chan, spec, nwave.size(), &nwave[0],
2180 : num_coeff, coeff, spec);
2181 0 : check_sakura_status("sakura_SubtractSinusoidFloat", status);
2182 0 : clear_context();
2183 0 : },
2184 : [&](LIBSAKURA_SYMBOL(LSQFitContextFloat) const *context0,
2185 : size_t const num_chan, std::vector<size_t> const &nwave,
2186 0 : size_t const num_coeff, float *spec, bool const *mask, bool *mask_after_clipping, float *rms) {
2187 0 : prepare_context(context0, num_chan, nwave);
2188 0 : status = LIBSAKURA_SYMBOL(LSQFitSinusoidFloat)(
2189 0 : context, nwave.size(), &nwave[0],
2190 0 : num_chan, spec, mask, clip_threshold_sigma, num_fitting_max,
2191 0 : num_coeff, nullptr, nullptr, spec, mask_after_clipping, rms, &bl_status);
2192 0 : check_sakura_status("sakura_LSQFitSinusoidFloat", status);
2193 0 : check_baseline_status(bl_status);
2194 0 : clear_context();
2195 0 : },
2196 : os
2197 : );
2198 0 : }
2199 :
2200 : // Apply baseline table to MS
2201 0 : void SingleDishMS::applyBaselineTable(string const& in_column_name,
2202 : string const& in_bltable_name,
2203 : string const& in_spw,
2204 : bool const& update_weight,
2205 : string const& sigma_value,
2206 : string const& out_ms_name) {
2207 0 : LogIO os(_ORIGIN);
2208 0 : os << "Apply baseline table " << in_bltable_name << " to MS. " << LogIO::POST;
2209 :
2210 0 : if (in_bltable_name == "") {
2211 0 : throw(AipsError("baseline table is not given."));
2212 : }
2213 :
2214 : // parse fitting parameters in the text file
2215 0 : BLTableParser parser(in_bltable_name);
2216 0 : std::vector<size_t> baseline_types = parser.get_function_types();
2217 0 : map<size_t const, uint16_t> max_orders;
2218 0 : for (size_t i = 0; i < baseline_types.size(); ++i) {
2219 0 : max_orders[baseline_types[i]] = parser.get_max_order(baseline_types[i]);
2220 : }
2221 : { //DEBUG output
2222 0 : os << LogIO::DEBUG1 << "spw ID = " << in_spw << LogIO::POST;
2223 0 : os << LogIO::DEBUG1 << "Baseline Types = " << baseline_types << LogIO::POST;
2224 0 : os << LogIO::DEBUG1 << "Max Orders:" << LogIO::POST;
2225 0 : map<size_t const, uint16_t>::iterator iter = max_orders.begin();
2226 0 : while (iter != max_orders.end()) {
2227 0 : os << LogIO::DEBUG1 << "- type " << (*iter).first << ": "
2228 0 : << (*iter).second << LogIO::POST;
2229 0 : ++iter;
2230 : }
2231 : }
2232 :
2233 0 : Block<Int> columns(1);
2234 0 : columns[0] = MS::DATA_DESC_ID; // (CAS-9918, 2017/4/27 WK) //columns[0] = MS::TIME;
2235 0 : prepare_for_process(in_column_name, out_ms_name, columns, false);
2236 0 : vi::VisibilityIterator2 *vi = sdh_->getVisIter();
2237 0 : vi->setRowBlocking(kNRowBlocking);
2238 0 : vi::VisBuffer2 *vb = vi->getVisBuffer();
2239 :
2240 0 : Vector<Int> recspw;
2241 0 : Matrix<Int> recchan;
2242 0 : Vector<size_t> nchan;
2243 0 : Vector<Vector<Bool> > in_mask;
2244 0 : Vector<bool> nchan_set;
2245 0 : parse_spw(in_spw, recspw, recchan, nchan, in_mask, nchan_set);
2246 :
2247 : // Baseline Contexts reservoir
2248 : // key: BaselineType
2249 : // value: a vector of Sakura_BaselineContextFloat for various nchans
2250 0 : Vector<size_t> ctx_indices(nchan.nelements(), 0ul);
2251 0 : map<size_t const, std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *> > context_reservoir;
2252 0 : map<size_t const, uint16_t>::iterator iter = max_orders.begin();
2253 0 : while (iter != max_orders.end()) {
2254 0 : context_reservoir[(*iter).first] = std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *>();
2255 0 : ++iter;
2256 : }
2257 :
2258 : LIBSAKURA_SYMBOL(Status) status;
2259 :
2260 0 : std::vector<float> weight(WeightIndex_kNum);
2261 0 : size_t const var_index = (sigma_value == "stddev") ? WeightIndex_kStddev : WeightIndex_kRms;
2262 :
2263 0 : for (vi->originChunks(); vi->moreChunks(); vi->nextChunk()) {
2264 0 : for (vi->origin(); vi->more(); vi->next()) {
2265 0 : Vector<Int> scans = vb->scan();
2266 0 : Vector<Double> times = vb->time();
2267 0 : Vector<Double> intervals = vb->timeInterval();
2268 0 : Vector<Int> beams = vb->feed1();
2269 0 : Vector<Int> antennas = vb->antenna1();
2270 0 : Vector<Int> data_spw = vb->spectralWindows();
2271 0 : size_t const num_chan = static_cast<size_t>(vb->nChannels());
2272 0 : size_t const num_pol = static_cast<size_t>(vb->nCorrelations());
2273 0 : size_t const num_row = static_cast<size_t>(vb->nRows());
2274 0 : Cube<Float> data_chunk(num_pol, num_chan, num_row);
2275 0 : SakuraAlignedArray<float> spec(num_chan);
2276 0 : float *spec_data = spec.data();
2277 0 : Cube<Bool> flag_chunk(num_pol, num_chan, num_row);
2278 0 : SakuraAlignedArray<bool> flag(num_chan);
2279 0 : bool *flag_data = flag.data();
2280 0 : SakuraAlignedArray<bool> mask(num_chan);
2281 0 : bool *mask_data = mask.data();
2282 0 : Matrix<Float> weight_matrix(num_pol, num_row, Array<Float>::uninitialized);
2283 :
2284 0 : bool new_nchan = false;
2285 0 : get_nchan_and_mask(recspw, data_spw, recchan, num_chan, nchan, in_mask, nchan_set, new_nchan);
2286 0 : if (new_nchan) {
2287 0 : map<size_t const, uint16_t>::iterator iter = max_orders.begin();
2288 0 : while (iter != max_orders.end()) {
2289 0 : get_baseline_context((*iter).first, (*iter).second,
2290 : num_chan, nchan, nchan_set,
2291 0 : ctx_indices, context_reservoir[(*iter).first]);
2292 0 : ++iter;
2293 : }
2294 : }
2295 : // get data/flag cubes (npol*nchan*nrow) from VisBuffer
2296 0 : get_data_cube_float(*vb, data_chunk);
2297 0 : get_flag_cube(*vb, flag_chunk);
2298 :
2299 : // get weight matrix (npol*nrow) from VisBuffer
2300 0 : if (update_weight) {
2301 0 : get_weight_matrix(*vb, weight_matrix);
2302 : }
2303 :
2304 : // loop over MS rows
2305 0 : for (size_t irow = 0; irow < num_row; ++irow) {
2306 0 : size_t idx = 0;
2307 0 : for (size_t ispw = 0; ispw < recspw.nelements(); ++ispw) {
2308 0 : if (data_spw[irow] == recspw[ispw]) {
2309 0 : idx = ispw;
2310 0 : break;
2311 : }
2312 : }
2313 :
2314 : // find a baseline table row (index) corresponding to this MS row
2315 : size_t idx_fit_param;
2316 0 : if (!parser.GetFitParameterIdx(times[irow], intervals[irow],
2317 0 : scans[irow], beams[irow], antennas[irow], data_spw[irow],
2318 : idx_fit_param)) {
2319 0 : for (size_t ipol = 0; ipol < num_pol; ++ipol) {
2320 0 : flag_spectrum_in_cube(flag_chunk, irow, ipol); //flag
2321 : }
2322 0 : continue;
2323 : }
2324 :
2325 : // loop over polarization
2326 0 : for (size_t ipol = 0; ipol < num_pol; ++ipol) {
2327 : bool apply;
2328 0 : Vector<double> coeff;
2329 0 : Vector<size_t> boundary;
2330 0 : std::vector<bool> mask_bltable;
2331 0 : BLParameterSet fit_param;
2332 0 : parser.GetFitParameterByIdx(idx_fit_param, ipol, apply, coeff, boundary,
2333 : mask_bltable, fit_param);
2334 0 : if (!apply) {
2335 0 : flag_spectrum_in_cube(flag_chunk, irow, ipol); //flag
2336 0 : continue;
2337 : }
2338 :
2339 : // get a channel mask from data cube
2340 : // (note that the variable 'mask' is flag in the next line
2341 : // actually, then it will be converted to real mask when
2342 : // taking AND with user-given mask info. this is just for
2343 : // saving memory usage...)
2344 0 : get_flag_from_cube(flag_chunk, irow, ipol, num_chan, flag_data);
2345 :
2346 : // skip spectrum if all channels flagged
2347 0 : if (allchannels_flagged(num_chan, flag_data)) {
2348 0 : continue;
2349 : }
2350 :
2351 : // get a spectrum from data cube
2352 0 : get_spectrum_from_cube(data_chunk, irow, ipol, num_chan, spec_data);
2353 :
2354 : // actual execution of single spectrum
2355 : map<size_t const, std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *> >::iterator
2356 0 : iter = context_reservoir.find(fit_param.baseline_type);
2357 0 : if (iter == context_reservoir.end())
2358 0 : throw(AipsError("Invalid baseline type detected!"));
2359 : LIBSAKURA_SYMBOL(LSQFitContextFloat) * context =
2360 0 : (*iter).second[ctx_indices[idx]];
2361 : //cout << "Got context for type " << (*iter).first << ": idx=" << ctx_indices[idx] << endl;
2362 :
2363 0 : SakuraAlignedArray<double> coeff_storage(coeff);
2364 0 : double *coeff_data = coeff_storage.data();
2365 0 : SakuraAlignedArray<size_t> boundary_storage(boundary);
2366 0 : size_t *boundary_data = boundary_storage.data();
2367 0 : string subtract_funcname;
2368 0 : switch (static_cast<size_t>(fit_param.baseline_type)) {
2369 0 : case BaselineType_kPolynomial:
2370 : case BaselineType_kChebyshev:
2371 0 : status = LIBSAKURA_SYMBOL(SubtractPolynomialFloat)(
2372 : context, num_chan, spec_data, coeff.size(), coeff_data, spec_data);
2373 0 : subtract_funcname = "sakura_SubtractPolynomialFloat";
2374 0 : break;
2375 0 : case BaselineType_kCubicSpline:
2376 0 : status = LIBSAKURA_SYMBOL(SubtractCubicSplineFloat)(
2377 0 : context, num_chan, spec_data, boundary.size()-1,
2378 : reinterpret_cast<double (*)[4]>(coeff_data),
2379 : boundary_data, spec_data);
2380 0 : subtract_funcname = "sakura_SubtractCubicSplineFloat";
2381 0 : break;
2382 0 : default:
2383 0 : throw(AipsError("Unsupported baseline type."));
2384 : }
2385 0 : check_sakura_status(subtract_funcname, status);
2386 :
2387 : // set back a spectrum to data cube
2388 0 : set_spectrum_to_cube(data_chunk, irow, ipol, num_chan, spec_data);
2389 :
2390 0 : if (update_weight) {
2391 : // convert flag to mask by taking logical NOT of flag
2392 : // and then operate logical AND with in_mask and with mask from bltable
2393 0 : for (size_t ichan = 0; ichan < num_chan; ++ichan) {
2394 0 : mask_data[ichan] = in_mask[idx][ichan] && (!(flag_data[ichan])) && mask_bltable[ichan];
2395 : }
2396 0 : compute_weight(num_chan, spec_data, mask_data, weight);
2397 0 : set_weight_to_matrix(weight_matrix, irow, ipol, weight.at(var_index));
2398 : }
2399 : } // end of polarization loop
2400 :
2401 : } // end of chunk row loop
2402 : // write back data and flag cube to VisBuffer
2403 0 : if (update_weight) {
2404 0 : sdh_->fillCubeToOutputMs(vb, data_chunk, &flag_chunk, &weight_matrix);
2405 : } else {
2406 0 : sdh_->fillCubeToOutputMs(vb, data_chunk, &flag_chunk);
2407 : }
2408 : } // end of vi loop
2409 : } // end of chunk loop
2410 :
2411 0 : finalize_process();
2412 : // destroy baseline contexts
2413 0 : map<size_t const, std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *> >::iterator ctxiter = context_reservoir.begin();
2414 0 : while (ctxiter != context_reservoir.end()) {
2415 0 : destroy_baseline_contexts (context_reservoir[(*ctxiter).first]);
2416 0 : ++ctxiter;
2417 : }
2418 0 : }
2419 :
2420 : // Fit line profile
2421 0 : void SingleDishMS::fitLine(string const& in_column_name,
2422 : string const& in_spw,
2423 : string const& /* in_pol */,
2424 : string const& fitfunc,
2425 : string const& in_nfit,
2426 : bool const linefinding,
2427 : float const threshold,
2428 : int const avg_limit,
2429 : int const minwidth,
2430 : vector<int> const& edge,
2431 : string const& tempfile_name,
2432 : string const& temp_out_ms_name) {
2433 :
2434 : // in_column = [FLOAT_DATA|DATA|CORRECTED_DATA]
2435 : // no iteration is necessary for the processing.
2436 : // procedure
2437 : // 1. iterate over MS
2438 : // 2. pick single spectrum from in_column (this is not actually necessary for simple scaling but for exibision purpose)
2439 : // 3. fit Gaussian or Lorentzian profile to each spectrum
2440 : // 4. write fitting results to outfile
2441 :
2442 0 : LogIO os(_ORIGIN);
2443 0 : os << "Fitting line profile with " << fitfunc << LogIO::POST;
2444 :
2445 0 : if (file_exists(temp_out_ms_name)) {
2446 0 : throw(AipsError("temporary ms file unexpectedly exists."));
2447 : }
2448 0 : if (file_exists(tempfile_name)) {
2449 0 : throw(AipsError("temporary file unexpectedly exists."));
2450 : }
2451 :
2452 0 : Block<Int> columns(1);
2453 0 : columns[0] = MS::DATA_DESC_ID;
2454 0 : prepare_for_process(in_column_name, temp_out_ms_name, columns, false);
2455 0 : vi::VisibilityIterator2 *vi = sdh_->getVisIter();
2456 0 : vi->setRowBlocking(kNRowBlocking);
2457 0 : vi::VisBuffer2 *vb = vi->getVisBuffer();
2458 0 : ofstream ofs(tempfile_name);
2459 :
2460 0 : Vector<Int> recspw;
2461 0 : Matrix<Int> recchan;
2462 0 : Vector<size_t> nchan;
2463 0 : Vector<Vector<Bool> > in_mask;
2464 0 : Vector<bool> nchan_set;
2465 0 : parse_spw(in_spw, recspw, recchan, nchan, in_mask, nchan_set);
2466 :
2467 0 : std::vector<size_t> nfit;
2468 0 : if (linefinding) {
2469 0 : os << "Defining line ranges using line finder. nfit will be ignored." << LogIO::POST;
2470 : } else {
2471 0 : std::vector<string> nfit_s = split_string(in_nfit, ',');
2472 0 : nfit.resize(nfit_s.size());
2473 0 : for (size_t i = 0; i < nfit_s.size(); ++i) {
2474 0 : nfit[i] = std::stoi(nfit_s[i]);
2475 : }
2476 : }
2477 :
2478 0 : size_t num_spec = 0;
2479 0 : size_t num_noline = 0;
2480 0 : for (vi->originChunks(); vi->moreChunks(); vi->nextChunk()) {
2481 0 : for (vi->origin(); vi->more(); vi->next()) {
2482 0 : Vector<Int> scans = vb->scan();
2483 0 : Vector<Double> times = vb->time();
2484 0 : Vector<Int> beams = vb->feed1();
2485 0 : Vector<Int> antennas = vb->antenna1();
2486 :
2487 0 : Vector<Int> data_spw = vb->spectralWindows();
2488 0 : size_t const num_chan = static_cast<size_t>(vb->nChannels());
2489 0 : size_t const num_pol = static_cast<size_t>(vb->nCorrelations());
2490 0 : size_t const num_row = static_cast<size_t>(vb->nRows());
2491 0 : Cube<Float> data_chunk(num_pol, num_chan, num_row);
2492 0 : SakuraAlignedArray<float> spec(num_chan);
2493 0 : Cube<Bool> flag_chunk(num_pol, num_chan, num_row);
2494 0 : SakuraAlignedArray<bool> mask(num_chan);
2495 : // CAUTION!!!
2496 : // data() method must be used with special care!!!
2497 0 : float *spec_data = spec.data();
2498 0 : bool *mask_data = mask.data();
2499 :
2500 0 : bool new_nchan = false;
2501 0 : get_nchan_and_mask(recspw, data_spw, recchan, num_chan, nchan, in_mask,
2502 : nchan_set, new_nchan);
2503 :
2504 : // get data/flag cubes (npol*nchan*nrow) from VisBuffer
2505 0 : get_data_cube_float(*vb, data_chunk);
2506 0 : get_flag_cube(*vb, flag_chunk);
2507 :
2508 : // loop over MS rows
2509 0 : for (size_t irow = 0; irow < num_row; ++irow) {
2510 0 : size_t idx = 0;
2511 0 : for (size_t ispw = 0; ispw < recspw.nelements(); ++ispw) {
2512 0 : if (data_spw[irow] == recspw[ispw]) {
2513 0 : idx = ispw;
2514 0 : break;
2515 : }
2516 : }
2517 :
2518 0 : std::vector<size_t> fitrange_start;
2519 0 : fitrange_start.clear();
2520 0 : std::vector<size_t> fitrange_end;
2521 0 : fitrange_end.clear();
2522 0 : for (size_t i = 0; i < recchan.nrow(); ++i) {
2523 0 : if (recchan.row(i)(0) == data_spw[irow]) {
2524 0 : fitrange_start.push_back(recchan.row(i)(1));
2525 0 : fitrange_end.push_back(recchan.row(i)(2));
2526 : }
2527 : }
2528 0 : if (!linefinding && nfit.size() != fitrange_start.size()) {
2529 : throw(AipsError(
2530 0 : "the number of elements of nfit and fitranges specified in spw must be identical."));
2531 : }
2532 :
2533 : // loop over polarization
2534 0 : for (size_t ipol = 0; ipol < num_pol; ++ipol) {
2535 : // get a channel mask from data cube
2536 : // (note that the variable 'mask' is flag in the next line
2537 : // actually, then it will be converted to real mask when
2538 : // taking AND with user-given mask info. this is just for
2539 : // saving memory usage...)
2540 0 : get_flag_from_cube(flag_chunk, irow, ipol, num_chan, mask_data);
2541 : // skip spectrum if all channels flagged
2542 0 : if (allchannels_flagged(num_chan, mask_data)) {
2543 0 : continue;
2544 : }
2545 0 : ++num_spec;
2546 :
2547 : // convert flag to mask by taking logical NOT of flag
2548 : // and then operate logical AND with in_mask
2549 0 : for (size_t ichan = 0; ichan < num_chan; ++ichan) {
2550 0 : mask_data[ichan] = in_mask[idx][ichan] && (!(mask_data[ichan]));
2551 : }
2552 : // get a spectrum from data cube
2553 0 : get_spectrum_from_cube(data_chunk, irow, ipol, num_chan, spec_data);
2554 :
2555 : // line finding. get fit mask (invert=false)
2556 0 : if (linefinding) {
2557 : list<pair<size_t, size_t>> line_ranges
2558 : = findLineAndGetRanges(num_chan, spec_data, mask_data,
2559 : threshold, avg_limit, minwidth,
2560 0 : edge, false);
2561 0 : if (line_ranges.size()==0) {
2562 0 : ++num_noline;
2563 0 : continue;
2564 : }
2565 0 : size_t nline = line_ranges.size();
2566 0 : fitrange_start.resize(nline);
2567 0 : fitrange_end.resize(nline);
2568 0 : nfit.resize(nline);
2569 0 : auto range=line_ranges.begin();
2570 0 : for (size_t iline=0; iline<nline; ++iline){
2571 0 : fitrange_start[iline] = (*range).first;
2572 0 : fitrange_end[iline] = (*range).second;
2573 0 : nfit[iline] = 1;
2574 0 : ++range;
2575 : }
2576 : }
2577 :
2578 0 : Vector<Float> x_;
2579 0 : x_.resize(num_chan);
2580 0 : Vector<Float> y_;
2581 0 : y_.resize(num_chan);
2582 0 : Vector<Bool> m_;
2583 0 : m_.resize(num_chan);
2584 0 : for (size_t ichan = 0; ichan < num_chan; ++ichan) {
2585 0 : x_[ichan] = static_cast<Float>(ichan);
2586 0 : y_[ichan] = spec_data[ichan];
2587 : }
2588 0 : Vector<Float> parameters_;
2589 0 : Vector<Float> error_;
2590 :
2591 0 : PtrBlock<Function<Float>*> funcs_;
2592 0 : std::vector<std::string> funcnames_;
2593 0 : std::vector<int> funccomponents_;
2594 0 : std::string expr;
2595 0 : if (fitfunc == "gaussian") {
2596 0 : expr = "gauss";
2597 0 : } else if (fitfunc == "lorentzian") {
2598 0 : expr = "lorentz";
2599 : }
2600 :
2601 0 : bool any_converged = false;
2602 0 : for (size_t ifit = 0; ifit < nfit.size(); ++ifit) {
2603 0 : if (nfit[ifit] == 0)
2604 0 : continue;
2605 :
2606 0 : if (0 < ifit)
2607 0 : ofs << ":";
2608 :
2609 : //extract spec/mask within fitrange
2610 0 : for (size_t ichan = 0; ichan < num_chan; ++ichan) {
2611 0 : if ((fitrange_start[ifit] <= ichan)
2612 0 : && (ichan <= fitrange_end[ifit])) {
2613 0 : m_[ichan] = mask_data[ichan];
2614 : } else {
2615 0 : m_[ichan] = false;
2616 : }
2617 : }
2618 :
2619 : //initial guesss
2620 0 : Vector<Float> peak;
2621 0 : Vector<Float> cent;
2622 0 : Vector<Float> fwhm;
2623 0 : peak.resize(nfit[ifit]);
2624 0 : cent.resize(nfit[ifit]);
2625 0 : fwhm.resize(nfit[ifit]);
2626 0 : if (nfit[ifit] == 1) {
2627 0 : Float sum = 0.0;
2628 0 : Float max_spec = fabs(y_[fitrange_start[ifit]]);
2629 0 : Float max_spec_x = x_[fitrange_start[ifit]];
2630 0 : bool is_positive = true;
2631 0 : for (size_t ichan = fitrange_start[ifit];
2632 0 : ichan <= fitrange_end[ifit]; ++ichan) {
2633 0 : sum += y_[ichan];
2634 0 : if (max_spec < fabs(y_[ichan])) {
2635 0 : max_spec = fabs(y_[ichan]);
2636 0 : max_spec_x = x_[ichan];
2637 0 : is_positive = (fabs(y_[ichan]) == y_[ichan]);
2638 : }
2639 : }
2640 0 : peak[0] = max_spec * (is_positive ? 1 : -1);
2641 0 : cent[0] = max_spec_x;
2642 0 : fwhm[0] = fabs(sum / max_spec * 0.7);
2643 : } else {
2644 0 : size_t x_start = fitrange_start[ifit];
2645 0 : size_t x_width = (fitrange_end[ifit] - fitrange_start[ifit]) / nfit[ifit];
2646 0 : size_t x_end = x_start + x_width;
2647 0 : for (size_t icomp = 0; icomp < nfit[ifit]; ++icomp) {
2648 0 : if (icomp == nfit[ifit] - 1) {
2649 0 : x_end = fitrange_end[ifit] + 1;
2650 : }
2651 :
2652 0 : Float sum = 0.0;
2653 0 : Float max_spec = fabs(y_[x_start]);
2654 0 : Float max_spec_x = x_[x_start];
2655 0 : bool is_positive = true;
2656 0 : for (size_t ichan = x_start; ichan < x_end; ++ichan) {
2657 0 : sum += y_[ichan];
2658 0 : if (max_spec < fabs(y_[ichan])) {
2659 0 : max_spec = fabs(y_[ichan]);
2660 0 : max_spec_x = x_[ichan];
2661 0 : is_positive = (fabs(y_[ichan]) == y_[ichan]);
2662 : }
2663 : }
2664 0 : peak[icomp] = max_spec * (is_positive ? 1 : -1);
2665 0 : cent[icomp] = max_spec_x;
2666 0 : fwhm[icomp] = fabs(sum / max_spec * 0.7);
2667 :
2668 0 : x_start += x_width;
2669 0 : x_end += x_width;
2670 : }
2671 : }
2672 :
2673 : //fitter setup
2674 0 : funcs_.resize(nfit[ifit]);
2675 0 : funcnames_.clear();
2676 0 : funccomponents_.clear();
2677 0 : for (size_t icomp = 0; icomp < funcs_.nelements(); ++icomp) {
2678 0 : if (expr == "gauss") {
2679 0 : funcs_[icomp] = new Gaussian1D<Float>();
2680 0 : } else if (expr == "lorentz") {
2681 0 : funcs_[icomp] = new Lorentzian1D<Float>();
2682 : }
2683 0 : (funcs_[icomp]->parameters())[0] = peak[icomp]; //initial guess (peak)
2684 0 : (funcs_[icomp]->parameters())[1] = cent[icomp]; //initial guess (centre)
2685 0 : (funcs_[icomp]->parameters())[2] = fwhm[icomp]; //initial guess (fwhm)
2686 0 : funcnames_.push_back(expr);
2687 0 : funccomponents_.push_back(3);
2688 : }
2689 :
2690 : //actual fitting
2691 0 : NonLinearFitLM<Float> fitter;
2692 0 : CompoundFunction<Float> func;
2693 0 : for (size_t icomp = 0; icomp < funcs_.nelements(); ++icomp) {
2694 0 : func.addFunction(*funcs_[icomp]);
2695 : }
2696 0 : fitter.setFunction(func);
2697 0 : fitter.setMaxIter(50 + 10 * funcs_.nelements());
2698 0 : fitter.setCriteria(0.001); // Convergence criterium
2699 :
2700 0 : parameters_.resize();
2701 0 : parameters_ = fitter.fit(x_, y_, &m_);
2702 0 : any_converged |= fitter.converged();
2703 : // if (!fitter.converged()) {
2704 : // throw(AipsError("Failed in fitting. Fitter did not converge."));
2705 : // }
2706 0 : error_.resize();
2707 0 : error_ = fitter.errors();
2708 :
2709 : //write best-fit parameters to tempfile/outfile
2710 0 : for (size_t icomp = 0; icomp < funcs_.nelements(); ++icomp) {
2711 0 : if (0 < icomp)
2712 0 : ofs << ":";
2713 0 : size_t offset = 3 * icomp;
2714 0 : ofs.precision(4);
2715 0 : ofs.setf(ios::fixed);
2716 0 : ofs << scans[irow] << "," // scanID
2717 0 : << times[irow] << "," // time
2718 0 : << antennas[irow] << "," // antennaID
2719 0 : << beams[irow] << "," // beamID
2720 0 : << data_spw[irow] << "," // spwID
2721 0 : << ipol << ","; // polID
2722 0 : ofs.precision(8);
2723 0 : ofs << parameters_[offset + 1] << "," << error_[offset + 1] << "," // cent
2724 0 : << parameters_[offset + 0] << "," << error_[offset + 0] << "," // peak
2725 0 : << parameters_[offset + 2] << "," << error_[offset + 2]; // fwhm
2726 : }
2727 : } //end of nfit loop
2728 0 : ofs << "\n";
2729 : // count up spectra w/o any line fit
2730 0 : if (!any_converged) ++num_noline;
2731 :
2732 : } //end of polarization loop
2733 : } // end of MS row loop
2734 : } //end of vi loop
2735 : } //end of chunk loop
2736 :
2737 0 : if (num_noline==num_spec) {
2738 : os << LogIO::WARN
2739 0 : << "Fitter did not converge on any fit components." << LogIO::POST;
2740 : }
2741 0 : else if (num_noline > 0) {
2742 : os << "No convergence for fitting to " << num_noline
2743 0 : << " out of " << num_spec << " spectra" << LogIO::POST;
2744 : }
2745 :
2746 0 : finalize_process();
2747 0 : ofs.close();
2748 0 : }
2749 :
2750 : //Subtract baseline by per spectrum fitting parameters
2751 0 : void SingleDishMS::subtractBaselineVariable(string const& in_column_name,
2752 : string const& out_ms_name,
2753 : string const& out_bloutput_name,
2754 : bool const& do_subtract,
2755 : string const& in_spw,
2756 : bool const& update_weight,
2757 : string const& sigma_value,
2758 : string const& param_file,
2759 : bool const& verbose) {
2760 :
2761 0 : LogIO os(_ORIGIN);
2762 : os << "Fitting and subtracting baseline using parameters in file "
2763 0 : << param_file << LogIO::POST;
2764 :
2765 0 : Block<Int> columns(1);
2766 0 : columns[0] = MS::DATA_DESC_ID;
2767 0 : prepare_for_process(in_column_name, out_ms_name, columns, false);
2768 0 : vi::VisibilityIterator2 *vi = sdh_->getVisIter();
2769 0 : vi->setRowBlocking(kNRowBlocking);
2770 0 : vi::VisBuffer2 *vb = vi->getVisBuffer();
2771 :
2772 0 : split_bloutputname(out_bloutput_name);
2773 0 : bool write_baseline_csv = (bloutputname_csv != "");
2774 0 : bool write_baseline_text = (bloutputname_text != "");
2775 0 : bool write_baseline_table = (bloutputname_table != "");
2776 0 : ofstream ofs_csv;
2777 0 : ofstream ofs_txt;
2778 0 : BaselineTable *bt = 0;
2779 :
2780 0 : if (write_baseline_csv) {
2781 0 : ofs_csv.open(bloutputname_csv.c_str());
2782 : }
2783 0 : if (write_baseline_text) {
2784 0 : ofs_txt.open(bloutputname_text.c_str(), std::ios::app);
2785 : }
2786 0 : if (write_baseline_table) {
2787 0 : bt = new BaselineTable(vi->ms());
2788 : }
2789 :
2790 0 : Vector<Int> recspw;
2791 0 : Matrix<Int> recchan;
2792 0 : Vector<size_t> nchan;
2793 0 : Vector<Vector<Bool> > in_mask;
2794 0 : Vector<bool> nchan_set;
2795 0 : parse_spw(in_spw, recspw, recchan, nchan, in_mask, nchan_set);
2796 :
2797 : // parse fitting parameters in the text file
2798 0 : BLParameterParser parser(param_file);
2799 0 : std::vector<size_t> baseline_types = parser.get_function_types();
2800 0 : map<size_t const, uint16_t> max_orders;
2801 0 : for (size_t i = 0; i < baseline_types.size(); ++i) {
2802 0 : max_orders[baseline_types[i]] = parser.get_max_order(baseline_types[i]);
2803 : }
2804 : { //DEBUG ouput
2805 0 : os << LogIO::DEBUG1 << "Baseline Types = " << baseline_types << LogIO::POST;
2806 0 : os << LogIO::DEBUG1 << "Max Orders:" << LogIO::POST;
2807 0 : map<size_t const, uint16_t>::iterator iter = max_orders.begin();
2808 0 : while (iter != max_orders.end()) {
2809 0 : os << LogIO::DEBUG1 << "- type " << (*iter).first << ": "
2810 0 : << (*iter).second << LogIO::POST;
2811 0 : ++iter;
2812 : }
2813 : }
2814 :
2815 : // Baseline Contexts reservoir
2816 : // key: Sakura_BaselineType enum,
2817 : // value: a vector of Sakura_BaselineContextFloat for various nchans
2818 0 : map<size_t const, std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *> > context_reservoir;
2819 : {
2820 0 : map<size_t const, uint16_t>::iterator iter = max_orders.begin();
2821 0 : while (iter != max_orders.end()) {
2822 0 : context_reservoir[(*iter).first] = std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *>();
2823 0 : ++iter;
2824 : }
2825 : }
2826 :
2827 0 : Vector<size_t> ctx_indices(recspw.size(), 0ul);
2828 : //stores the number of channels of corresponding elements in contexts list.
2829 : // WORKAROUND for absense of the way to get num_bases_data in context.
2830 0 : vector<size_t> ctx_nchans;
2831 :
2832 : LIBSAKURA_SYMBOL(Status) status;
2833 : LIBSAKURA_SYMBOL(LSQFitStatus) bl_status;
2834 :
2835 0 : std::vector<float> weight(WeightIndex_kNum);
2836 0 : size_t const var_index = (sigma_value == "stddev") ? WeightIndex_kStddev : WeightIndex_kRms;
2837 :
2838 0 : for (vi->originChunks(); vi->moreChunks(); vi->nextChunk()) {
2839 0 : for (vi->origin(); vi->more(); vi->next()) {
2840 0 : Vector<Int> scans = vb->scan();
2841 0 : Vector<Double> times = vb->time();
2842 0 : Vector<Int> beams = vb->feed1();
2843 0 : Vector<Int> antennas = vb->antenna1();
2844 0 : Vector<Int> data_spw = vb->spectralWindows();
2845 0 : size_t const num_chan = static_cast<size_t>(vb->nChannels());
2846 0 : size_t const num_pol = static_cast<size_t>(vb->nCorrelations());
2847 0 : size_t const num_row = static_cast<size_t>(vb->nRows());
2848 0 : auto orig_rows = vb->rowIds();
2849 0 : Cube<Float> data_chunk(num_pol, num_chan, num_row);
2850 0 : SakuraAlignedArray<float> spec(num_chan);
2851 0 : Cube<Bool> flag_chunk(num_pol, num_chan, num_row);
2852 0 : SakuraAlignedArray<bool> flag(num_chan);
2853 0 : SakuraAlignedArray<bool> mask(num_chan);
2854 0 : SakuraAlignedArray<bool> mask_after_clipping(num_chan);
2855 : // CAUTION!!!
2856 : // data() method must be used with special care!!!
2857 0 : float *spec_data = spec.data();
2858 0 : bool *flag_data = flag.data();
2859 0 : bool *mask_data = mask.data();
2860 0 : bool *mask_after_clipping_data = mask_after_clipping.data();
2861 0 : Matrix<Float> weight_matrix(num_pol, num_row, Array<Float>::uninitialized);
2862 :
2863 0 : uInt final_mask[num_pol];
2864 0 : uInt final_mask_after_clipping[num_pol];
2865 0 : final_mask[0] = 0;
2866 0 : final_mask[1] = 0;
2867 0 : final_mask_after_clipping[0] = 0;
2868 0 : final_mask_after_clipping[1] = 0;
2869 :
2870 0 : bool new_nchan = false;
2871 0 : get_nchan_and_mask(recspw, data_spw, recchan, num_chan, nchan, in_mask, nchan_set, new_nchan);
2872 : // check if context should be created once per chunk
2873 : // in the first actual excution of baseline.
2874 0 : bool check_context = true;
2875 :
2876 : // get data/flag cubes (npol*nchan*nrow) from VisBuffer
2877 0 : get_data_cube_float(*vb, data_chunk);
2878 0 : get_flag_cube(*vb, flag_chunk);
2879 :
2880 : // get weight matrix (npol*nrow) from VisBuffer
2881 0 : if (update_weight) {
2882 0 : get_weight_matrix(*vb, weight_matrix);
2883 : }
2884 :
2885 : // loop over MS rows
2886 0 : for (size_t irow = 0; irow < num_row; ++irow) {
2887 0 : size_t idx = 0;
2888 0 : for (size_t ispw = 0; ispw < recspw.nelements(); ++ispw) {
2889 0 : if (data_spw[irow] == recspw[ispw]) {
2890 0 : idx = ispw;
2891 0 : break;
2892 : }
2893 : }
2894 :
2895 : //prepare varables for writing baseline table
2896 0 : Array<Bool> apply_mtx(IPosition(2, num_pol, 1), true);
2897 0 : Array<uInt> bltype_mtx(IPosition(2, num_pol, 1));
2898 0 : Array<Int> fpar_mtx(IPosition(2, num_pol, 1));
2899 0 : std::vector<std::vector<double> > ffpar_mtx_tmp(num_pol);
2900 0 : std::vector<std::vector<uInt> > masklist_mtx_tmp(num_pol);
2901 0 : std::vector<std::vector<double> > coeff_mtx_tmp(num_pol);
2902 0 : Array<Float> rms_mtx(IPosition(2, num_pol, 1));
2903 0 : Array<Float> cthres_mtx(IPosition(2, num_pol, 1));
2904 0 : Array<uInt> citer_mtx(IPosition(2, num_pol, 1));
2905 0 : Array<Bool> uself_mtx(IPosition(2, num_pol, 1));
2906 0 : Array<Float> lfthres_mtx(IPosition(2, num_pol, 1));
2907 0 : Array<uInt> lfavg_mtx(IPosition(2, num_pol, 1));
2908 0 : Array<uInt> lfedge_mtx(IPosition(2, num_pol, 2));
2909 :
2910 0 : size_t num_apply_true = 0;
2911 0 : size_t num_ffpar_max = 0;
2912 0 : size_t num_masklist_max = 0;
2913 0 : size_t num_coeff_max = 0;
2914 0 : std::vector<size_t> numcoeff(num_pol);
2915 :
2916 : // loop over polarization
2917 0 : for (size_t ipol = 0; ipol < num_pol; ++ipol) {
2918 : // get a channel mask from data cube
2919 : // (note that the variable 'mask' is flag in the next line
2920 : // actually, then it will be converted to real mask when
2921 : // taking AND with user-given mask info. this is just for
2922 : // saving memory usage...)
2923 0 : get_flag_from_cube(flag_chunk, irow, ipol, num_chan, flag_data);
2924 : // skip spectrum if all channels flagged
2925 0 : if (allchannels_flagged(num_chan, flag_data)) {
2926 0 : os << LogIO::DEBUG1 << "Row " << orig_rows[irow] << ", Pol " << ipol
2927 0 : << ": All channels flagged. Skipping." << LogIO::POST;
2928 0 : apply_mtx[0][ipol] = false;
2929 0 : continue;
2930 : }
2931 :
2932 : // convert flag to mask by taking logical NOT of flag
2933 : // and then operate logical AND with in_mask
2934 0 : for (size_t ichan = 0; ichan < num_chan; ++ichan) {
2935 0 : mask_data[ichan] = in_mask[idx][ichan] && (!(flag_data[ichan]));
2936 : }
2937 : // get fitting parameter
2938 0 : BLParameterSet fit_param;
2939 0 : if (!parser.GetFitParameter(orig_rows[irow], ipol, fit_param)) { //no fit requrested
2940 0 : flag_spectrum_in_cube(flag_chunk, irow, ipol);
2941 0 : os << LogIO::DEBUG1 << "Row " << orig_rows[irow] << ", Pol " << ipol
2942 0 : << ": Fit not requested. Skipping." << LogIO::POST;
2943 0 : apply_mtx[0][ipol] = false;
2944 0 : continue;
2945 : }
2946 0 : if (verbose) {
2947 0 : os << "Fitting Parameter" << LogIO::POST;
2948 0 : os << "[ROW " << orig_rows[irow] << " (nchan " << num_chan << ")" << ", POL" << ipol << "]"
2949 0 : << LogIO::POST;
2950 0 : fit_param.PrintSummary();
2951 : }
2952 : // Create contexts when actually subtract baseine for the first time (if not yet exist)
2953 0 : if (check_context) {
2954 : // Generate context for all necessary baseline types
2955 0 : map<size_t const, uint16_t>::iterator iter = max_orders.begin();
2956 0 : while (iter != max_orders.end()) {
2957 0 : get_baseline_context((*iter).first, (*iter).second, num_chan, idx,
2958 0 : ctx_indices, ctx_nchans, context_reservoir[(*iter).first]);
2959 0 : ++iter;
2960 : }
2961 0 : check_context = false;
2962 : }
2963 : // get mask from BLParameterset and create composit mask
2964 0 : if (fit_param.baseline_mask != "") {
2965 0 : stringstream local_spw;
2966 0 : local_spw << data_spw[irow] << ":" << fit_param.baseline_mask;
2967 0 : Record selrec = sdh_->getSelRec(local_spw.str());
2968 0 : Matrix<Int> local_rec_chan = selrec.asArrayInt("channel");
2969 0 : Vector<Bool> local_mask(num_chan, false);
2970 0 : get_mask_from_rec(data_spw[irow], local_rec_chan, local_mask, false);
2971 0 : for (size_t ichan = 0; ichan < num_chan; ++ichan) {
2972 0 : mask_data[ichan] = mask_data[ichan] && local_mask[ichan];
2973 : }
2974 : }
2975 : // check for composit mask and flag if no valid channel to fit
2976 0 : if (NValidMask(num_chan, mask_data) == 0) {
2977 0 : flag_spectrum_in_cube(flag_chunk, irow, ipol);
2978 0 : apply_mtx[0][ipol] = false;
2979 0 : os << LogIO::DEBUG1 << "Row " << orig_rows[irow] << ", Pol " << ipol
2980 0 : << ": No valid channel to fit. Skipping" << LogIO::POST;
2981 0 : continue;
2982 : }
2983 : // get a spectrum from data cube
2984 0 : get_spectrum_from_cube(data_chunk, irow, ipol, num_chan, spec_data);
2985 :
2986 : // get baseline context
2987 : map<size_t const, std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *> >::iterator
2988 0 : iter = context_reservoir.find(fit_param.baseline_type);
2989 0 : if (iter == context_reservoir.end()) {
2990 0 : throw(AipsError("Invalid baseline type detected!"));
2991 : }
2992 0 : LIBSAKURA_SYMBOL(LSQFitContextFloat) * context = (*iter).second[ctx_indices[idx]];
2993 :
2994 : // Number of coefficients to fit this spectrum
2995 : size_t num_coeff;
2996 0 : size_t bltype = static_cast<size_t>(fit_param.baseline_type);
2997 0 : switch (bltype) {
2998 0 : case BaselineType_kPolynomial:
2999 : case BaselineType_kChebyshev:
3000 0 : status = LIBSAKURA_SYMBOL(GetNumberOfCoefficientsFloat)(context, fit_param.order, &num_coeff);
3001 0 : check_sakura_status("sakura_GetNumberOfCoefficientsFloat", status);
3002 0 : break;
3003 0 : case BaselineType_kCubicSpline:
3004 0 : num_coeff = 4 * fit_param.npiece;
3005 0 : break;
3006 0 : default:
3007 0 : throw(AipsError("Unsupported baseline type."));
3008 : }
3009 0 : numcoeff[ipol] = num_coeff;
3010 :
3011 : // Final check of the valid number of channels
3012 0 : size_t num_min = (bltype == BaselineType_kCubicSpline) ? fit_param.npiece + 3 : num_coeff;
3013 0 : if (NValidMask(num_chan, mask_data) < num_min) {
3014 0 : flag_spectrum_in_cube(flag_chunk, irow, ipol);
3015 0 : apply_mtx[0][ipol] = false;
3016 : os << LogIO::WARN
3017 : << "Too few valid channels to fit. Skipping Antenna "
3018 0 : << antennas[irow] << ", Beam " << beams[irow] << ", SPW "
3019 0 : << data_spw[irow] << ", Pol " << ipol << ", Time "
3020 0 : << MVTime(times[irow] / 24. / 3600.).string(MVTime::YMD, 8)
3021 0 : << LogIO::POST;
3022 0 : continue;
3023 : }
3024 :
3025 : // actual execution of single spectrum
3026 : float rms;
3027 0 : size_t num_boundary = 0;
3028 0 : if (bltype == BaselineType_kCubicSpline) {
3029 0 : num_boundary = fit_param.npiece+1;
3030 : }
3031 0 : SakuraAlignedArray<size_t> boundary(num_boundary);
3032 0 : size_t *boundary_data = boundary.data();
3033 :
3034 0 : if (write_baseline_text || write_baseline_csv || write_baseline_table) {
3035 0 : num_apply_true++;
3036 0 : bltype_mtx[0][ipol] = (uInt)fit_param.baseline_type;
3037 : Int fpar_tmp;
3038 0 : switch (bltype) {
3039 0 : case BaselineType_kPolynomial:
3040 : case BaselineType_kChebyshev:
3041 0 : fpar_tmp = (Int)fit_param.order;
3042 0 : break;
3043 0 : case BaselineType_kCubicSpline:
3044 0 : fpar_tmp = (Int)fit_param.npiece;
3045 0 : break;
3046 0 : default:
3047 0 : throw(AipsError("Unsupported baseline type."));
3048 : }
3049 0 : fpar_mtx[0][ipol] = fpar_tmp;
3050 :
3051 0 : if (num_coeff > num_coeff_max) {
3052 0 : num_coeff_max = num_coeff;
3053 : }
3054 0 : SakuraAlignedArray<double> coeff(num_coeff);
3055 : // CAUTION!!!
3056 : // data() method must be used with special care!!!
3057 0 : double *coeff_data = coeff.data();
3058 0 : string get_coeff_funcname;
3059 0 : switch (bltype) {
3060 0 : case BaselineType_kPolynomial:
3061 : case BaselineType_kChebyshev:
3062 0 : status = LIBSAKURA_SYMBOL(LSQFitPolynomialFloat)(
3063 0 : context, fit_param.order,
3064 : num_chan, spec_data, mask_data,
3065 0 : fit_param.clip_threshold_sigma, fit_param.num_fitting_max,
3066 : num_coeff, coeff_data, nullptr, nullptr,
3067 : mask_after_clipping_data, &rms, &bl_status);
3068 :
3069 0 : for (size_t i = 0; i < num_chan; ++i) {
3070 0 : if (mask_data[i] == false) {
3071 0 : final_mask[ipol] += 1;
3072 : }
3073 0 : if (mask_after_clipping_data[i] == false) {
3074 0 : final_mask_after_clipping[ipol] += 1;
3075 : }
3076 : }
3077 :
3078 0 : get_coeff_funcname = "sakura_LSQFitPolynomialFloat";
3079 0 : break;
3080 0 : case BaselineType_kCubicSpline:
3081 0 : status = LIBSAKURA_SYMBOL(LSQFitCubicSplineFloat)(
3082 : context, fit_param.npiece,
3083 : num_chan, spec_data, mask_data,
3084 0 : fit_param.clip_threshold_sigma, fit_param.num_fitting_max,
3085 : reinterpret_cast<double (*)[4]>(coeff_data), nullptr, nullptr,
3086 : mask_after_clipping_data, &rms, boundary_data, &bl_status);
3087 :
3088 0 : for (size_t i = 0; i < num_chan; ++i) {
3089 0 : if (mask_data[i] == false) {
3090 0 : final_mask[ipol] += 1;
3091 : }
3092 0 : if (mask_after_clipping_data[i] == false) {
3093 0 : final_mask_after_clipping[ipol] += 1;
3094 : }
3095 : }
3096 :
3097 0 : get_coeff_funcname = "sakura_LSQFitCubicSplineFloat";
3098 0 : break;
3099 0 : default:
3100 0 : throw(AipsError("Unsupported baseline type."));
3101 : }
3102 0 : check_sakura_status(get_coeff_funcname, status);
3103 :
3104 0 : size_t num_ffpar = get_num_coeff_bloutput(fit_param.baseline_type, fit_param.npiece, num_ffpar_max);
3105 0 : ffpar_mtx_tmp[ipol].clear();
3106 0 : for (size_t ipiece = 0; ipiece < num_ffpar; ++ipiece) {
3107 0 : ffpar_mtx_tmp[ipol].push_back(boundary_data[ipiece]);
3108 : }
3109 :
3110 0 : coeff_mtx_tmp[ipol].clear();
3111 0 : for (size_t icoeff = 0; icoeff < num_coeff; ++icoeff) {
3112 0 : coeff_mtx_tmp[ipol].push_back(coeff_data[icoeff]);
3113 : }
3114 :
3115 0 : Vector<uInt> masklist;
3116 0 : get_masklist_from_mask(num_chan, mask_after_clipping_data, masklist);
3117 0 : if (masklist.size() > num_masklist_max) {
3118 0 : num_masklist_max = masklist.size();
3119 : }
3120 0 : masklist_mtx_tmp[ipol].clear();
3121 0 : for (size_t imask = 0; imask < masklist.size(); ++imask) {
3122 0 : masklist_mtx_tmp[ipol].push_back(masklist[imask]);
3123 : }
3124 :
3125 0 : string subtract_funcname;
3126 0 : switch (fit_param.baseline_type) {
3127 0 : case BaselineType_kPolynomial:
3128 : case BaselineType_kChebyshev:
3129 0 : status = LIBSAKURA_SYMBOL(SubtractPolynomialFloat)(
3130 : context, num_chan, spec_data, num_coeff, coeff_data,
3131 : spec_data);
3132 0 : subtract_funcname = "sakura_SubtractPolynomialFloat";
3133 0 : break;
3134 0 : case BaselineType_kCubicSpline:
3135 0 : status = LIBSAKURA_SYMBOL(SubtractCubicSplineFloat)(
3136 : context,
3137 : num_chan, spec_data, fit_param.npiece, reinterpret_cast<double (*)[4]>(coeff_data),
3138 : boundary_data, spec_data);
3139 0 : subtract_funcname = "sakura_SubtractCubicSplineFloat";
3140 0 : break;
3141 0 : default:
3142 0 : throw(AipsError("Unsupported baseline type."));
3143 : }
3144 0 : check_sakura_status(subtract_funcname, status);
3145 :
3146 0 : rms_mtx[0][ipol] = rms;
3147 :
3148 0 : cthres_mtx[0][ipol] = fit_param.clip_threshold_sigma;
3149 0 : citer_mtx[0][ipol] = (uInt)fit_param.num_fitting_max - 1;
3150 0 : uself_mtx[0][ipol] = (Bool)fit_param.line_finder.use_line_finder;
3151 0 : lfthres_mtx[0][ipol] = fit_param.line_finder.threshold;
3152 0 : lfavg_mtx[0][ipol] = fit_param.line_finder.chan_avg_limit;
3153 0 : for (size_t iedge = 0; iedge < 2; ++iedge) {
3154 0 : lfedge_mtx[iedge][ipol] = fit_param.line_finder.edge[iedge];
3155 0 : }
3156 :
3157 : } else {
3158 0 : string subtract_funcname;
3159 0 : switch (fit_param.baseline_type) {
3160 0 : case BaselineType_kPolynomial:
3161 : case BaselineType_kChebyshev:
3162 0 : status = LIBSAKURA_SYMBOL(LSQFitPolynomialFloat)(
3163 0 : context, fit_param.order,
3164 : num_chan, spec_data, mask_data,
3165 0 : fit_param.clip_threshold_sigma, fit_param.num_fitting_max,
3166 : num_coeff, nullptr, nullptr, spec_data,
3167 : mask_after_clipping_data, &rms, &bl_status);
3168 0 : subtract_funcname = "sakura_LSQFitPolynomialFloat";
3169 0 : break;
3170 0 : case BaselineType_kCubicSpline:
3171 0 : status = LIBSAKURA_SYMBOL(LSQFitCubicSplineFloat)(
3172 : context, fit_param.npiece,
3173 : num_chan, spec_data, mask_data,
3174 0 : fit_param.clip_threshold_sigma, fit_param.num_fitting_max,
3175 : nullptr, nullptr, spec_data,
3176 : mask_after_clipping_data, &rms, boundary_data, &bl_status);
3177 0 : subtract_funcname = "sakura_LSQFitCubicSplineFloat";
3178 0 : break;
3179 0 : default:
3180 0 : throw(AipsError("Unsupported baseline type."));
3181 : }
3182 0 : check_sakura_status(subtract_funcname, status);
3183 : }
3184 : // set back a spectrum to data cube
3185 0 : if (do_subtract) {
3186 0 : set_spectrum_to_cube(data_chunk, irow, ipol, num_chan, spec_data);
3187 : }
3188 :
3189 0 : if (update_weight) {
3190 0 : compute_weight(num_chan, spec_data, mask_data, weight);
3191 0 : set_weight_to_matrix(weight_matrix, irow, ipol, weight.at(var_index));
3192 : }
3193 : } // end of polarization loop
3194 :
3195 : // output results of fitting
3196 0 : if (num_apply_true == 0) continue;
3197 :
3198 0 : Array<Float> ffpar_mtx(IPosition(2, num_pol, num_ffpar_max));
3199 0 : set_matrix_for_bltable<double, Float>(num_pol, num_ffpar_max,
3200 : ffpar_mtx_tmp, ffpar_mtx);
3201 0 : Array<uInt> masklist_mtx(IPosition(2, num_pol, num_masklist_max));
3202 0 : set_matrix_for_bltable<uInt, uInt>(num_pol, num_masklist_max,
3203 : masklist_mtx_tmp, masklist_mtx);
3204 0 : Array<Float> coeff_mtx(IPosition(2, num_pol, num_coeff_max));
3205 0 : set_matrix_for_bltable<double, Float>(num_pol, num_coeff_max,
3206 : coeff_mtx_tmp, coeff_mtx);
3207 0 : Matrix<uInt> masklist_mtx2 = masklist_mtx;
3208 0 : Matrix<Bool> apply_mtx2 = apply_mtx;
3209 :
3210 0 : if (write_baseline_table) {
3211 0 : bt->appenddata((uInt)scans[irow], (uInt)beams[irow], (uInt)antennas[irow],
3212 0 : (uInt)data_spw[irow], 0, times[irow],
3213 : apply_mtx, bltype_mtx, fpar_mtx, ffpar_mtx, masklist_mtx,
3214 : coeff_mtx, rms_mtx, (uInt)num_chan, cthres_mtx, citer_mtx,
3215 : uself_mtx, lfthres_mtx, lfavg_mtx, lfedge_mtx);
3216 : }
3217 :
3218 0 : if (write_baseline_text) {
3219 0 : for (size_t ipol = 0; ipol < num_pol; ++ipol) {
3220 0 : if (apply_mtx2(ipol, 0) == false) continue;
3221 :
3222 0 : ofs_txt << "Scan" << '[' << (uInt)scans[irow] << ']' << ' '
3223 0 : << "Beam" << '[' << (uInt)beams[irow] << ']' << ' '
3224 0 : << "Spw" << '[' << (uInt)data_spw[irow] << ']' << ' '
3225 0 : << "Pol" << '[' << ipol << ']' << ' '
3226 0 : << "Time" << '[' << MVTime(times[irow]/ 24. / 3600.).string(MVTime::YMD, 8) << ']'
3227 0 : << endl;
3228 0 : ofs_txt << endl;
3229 0 : ofs_txt << "Fitter range = " << '[';
3230 :
3231 0 : for (size_t imasklist = 0; imasklist < num_masklist_max / 2; ++imasklist) {
3232 0 : if (imasklist == 0) {
3233 0 : ofs_txt << '[' << masklist_mtx2(ipol, 2 * imasklist) << ';'
3234 0 : << masklist_mtx2(ipol, 2 * imasklist + 1) << ']';
3235 : }
3236 0 : if (imasklist >= 1
3237 0 : && (0 != masklist_mtx2(ipol, 2 * imasklist)
3238 0 : && 0 != masklist_mtx2(ipol, 2 * imasklist + 1))) {
3239 0 : ofs_txt << ",[" << masklist_mtx2(ipol, 2 * imasklist) << ','
3240 0 : << masklist_mtx2(ipol, 2 * imasklist + 1) << ']';
3241 : }
3242 : }
3243 :
3244 0 : ofs_txt << ']' << endl;
3245 0 : ofs_txt << endl;
3246 :
3247 0 : Matrix<uInt> bltype_mtx2 = bltype_mtx[0][ipol];
3248 0 : Matrix<Int> fpar_mtx2 = fpar_mtx[0][ipol];
3249 0 : Matrix<Float> rms_mtx2 = rms_mtx[0][ipol];
3250 0 : string bltype_name;
3251 0 : string blparam_name = "order";
3252 0 : if (bltype_mtx2(0, 0) == (uInt)0) {
3253 0 : bltype_name = "poly";
3254 0 : } else if (bltype_mtx2(0, 0) == (uInt)1) {
3255 0 : bltype_name = "chebyshev";
3256 0 : } else if (bltype_mtx2(0, 0) == (uInt)2) {
3257 0 : bltype_name = "cspline";
3258 0 : blparam_name = "npiece";
3259 : }
3260 :
3261 : ofs_txt << "Baseline parameters Function = "
3262 0 : << bltype_name << " " << blparam_name << " = "
3263 0 : << fpar_mtx2(0, 0) << endl;
3264 0 : ofs_txt << endl;
3265 0 : ofs_txt << "Results of baseline fit" << endl;
3266 0 : ofs_txt << endl;
3267 0 : Matrix<Float> coeff_mtx2 = coeff_mtx;
3268 0 : for (size_t icoeff = 0; icoeff < numcoeff[ipol]; ++icoeff) {
3269 0 : ofs_txt << "p" << icoeff << " = "
3270 0 : << setprecision(8) << coeff_mtx2(ipol, icoeff) << " ";
3271 : }
3272 0 : ofs_txt << endl;
3273 0 : ofs_txt << endl;
3274 0 : ofs_txt << "rms = ";
3275 0 : ofs_txt << setprecision(8) << rms_mtx2(0, 0) << endl;
3276 0 : ofs_txt << endl;
3277 0 : ofs_txt << "Number of clipped channels = "
3278 0 : << final_mask_after_clipping[ipol] - final_mask[ipol] << endl;
3279 0 : ofs_txt << endl;
3280 0 : ofs_txt << "------------------------------------------------------"
3281 0 : << endl;
3282 0 : ofs_txt << endl;
3283 : }
3284 : }
3285 :
3286 0 : if (write_baseline_csv) {
3287 0 : for (size_t ipol = 0; ipol < num_pol; ++ipol) {
3288 0 : if (apply_mtx2(ipol, 0) == false) continue;
3289 :
3290 0 : ofs_csv << (uInt)scans[irow] << ',' << (uInt)beams[irow] << ','
3291 0 : << (uInt)data_spw[irow] << ',' << ipol << ','
3292 0 : << setprecision(12) << times[irow] << ',';
3293 0 : ofs_csv << '[';
3294 0 : for (size_t imasklist = 0; imasklist < num_masklist_max / 2; ++imasklist) {
3295 0 : if (imasklist == 0) {
3296 0 : ofs_csv << '[' << masklist_mtx2(ipol, 2 * imasklist) << ';'
3297 0 : << masklist_mtx2(ipol, 2 * imasklist + 1) << ']';
3298 : }
3299 0 : if (imasklist >= 1
3300 0 : && (0 != masklist_mtx2(ipol, 2 * imasklist)
3301 0 : && 0 != masklist_mtx2(ipol, 2 * imasklist + 1))) {
3302 0 : ofs_csv << ";[" << masklist_mtx2(ipol, 2 * imasklist) << ';'
3303 0 : << masklist_mtx2(ipol, 2 * imasklist + 1) << ']';
3304 : }
3305 : }
3306 :
3307 0 : ofs_csv << ']' << ',';
3308 0 : Matrix<uInt> bltype_mtx2 = bltype_mtx[0][ipol];
3309 0 : string bltype_name;
3310 0 : if (bltype_mtx2(0, 0) == (uInt)0) {
3311 0 : bltype_name = "poly";
3312 0 : } else if (bltype_mtx2(0, 0) == (uInt)1) {
3313 0 : bltype_name = "chebyshev";
3314 0 : } else if (bltype_mtx2(0, 0) == (uInt)2) {
3315 0 : bltype_name = "cspline";
3316 : }
3317 :
3318 0 : Matrix<Int> fpar_mtx2 = fpar_mtx;
3319 0 : Matrix<Float> coeff_mtx2 = coeff_mtx;
3320 0 : ofs_csv << bltype_name.c_str() << ',' << fpar_mtx2(ipol, 0)
3321 0 : << ',';
3322 0 : for (size_t icoeff = 0; icoeff < numcoeff[ipol]; ++icoeff) {
3323 0 : ofs_csv << setprecision(8) << coeff_mtx2(ipol, icoeff) << ',';
3324 : }
3325 0 : Matrix<Float> rms_mtx2 = rms_mtx;
3326 0 : ofs_csv << setprecision(8) << rms_mtx2(ipol, 0) << ',';
3327 0 : ofs_csv << final_mask_after_clipping[ipol] - final_mask[ipol];
3328 0 : ofs_csv << endl;
3329 : }
3330 : }
3331 : } // end of chunk row loop
3332 : // write back data and flag cube to VisBuffer
3333 0 : if (update_weight) {
3334 0 : sdh_->fillCubeToOutputMs(vb, data_chunk, &flag_chunk, &weight_matrix);
3335 : } else {
3336 0 : sdh_->fillCubeToOutputMs(vb, data_chunk, &flag_chunk);
3337 : }
3338 0 : } // end of vi loop
3339 : } // end of chunk loop
3340 :
3341 0 : if (write_baseline_csv) {
3342 0 : ofs_csv.close();
3343 : }
3344 0 : if (write_baseline_text) {
3345 0 : ofs_txt.close();
3346 : }
3347 0 : if (write_baseline_table) {
3348 0 : bt->save(bloutputname_table);
3349 0 : delete bt;
3350 : }
3351 :
3352 0 : finalize_process();
3353 : // destroy baseline contexts
3354 0 : map<size_t const, std::vector<LIBSAKURA_SYMBOL(LSQFitContextFloat) *> >::iterator ctxiter = context_reservoir.begin();
3355 0 : while (ctxiter != context_reservoir.end()) {
3356 0 : destroy_baseline_contexts (context_reservoir[(*ctxiter).first]);
3357 0 : ++ctxiter;
3358 : }
3359 0 : } //end subtractBaselineVariable
3360 :
3361 0 : list<pair<size_t, size_t>> SingleDishMS::findLineAndGetRanges(size_t const num_data,
3362 : float const* data,
3363 : bool * mask,
3364 : float const threshold,
3365 : int const avg_limit,
3366 : int const minwidth,
3367 : vector<int> const& edge,
3368 : bool const invert) {
3369 : // input value check
3370 0 : AlwaysAssert(minwidth > 0, AipsError);
3371 0 : AlwaysAssert(avg_limit >= 0, AipsError);
3372 0 : size_t max_iteration = 10;
3373 0 : size_t maxwidth = num_data;
3374 0 : AlwaysAssert(maxwidth > static_cast<size_t>(minwidth), AipsError);
3375 : // edge handling
3376 0 : pair<size_t, size_t> lf_edge;
3377 0 : if (edge.size() == 0) {
3378 0 : lf_edge = pair<size_t, size_t>(0, 0);
3379 0 : } else if (edge.size() == 1) {
3380 0 : AlwaysAssert(edge[0] >= 0, AipsError);
3381 0 : lf_edge = pair<size_t, size_t>(static_cast<size_t>(edge[0]), static_cast<size_t>(edge[0]));
3382 : } else {
3383 0 : AlwaysAssert(edge[0] >= 0 && edge[1] >= 0, AipsError);
3384 0 : lf_edge = pair<size_t, size_t>(static_cast<size_t>(edge[0]), static_cast<size_t>(edge[1]));
3385 : }
3386 : // line detection
3387 : list<pair<size_t, size_t>> line_ranges = linefinder::MADLineFinder(num_data,
3388 : data, mask, threshold, max_iteration, static_cast<size_t>(minwidth),
3389 0 : maxwidth, static_cast<size_t>(avg_limit), lf_edge);
3390 : // debug output
3391 0 : LogIO os(_ORIGIN);
3392 0 : os << LogIO::DEBUG1 << line_ranges.size() << " lines found: ";
3393 0 : for (list<pair<size_t, size_t>>::iterator iter = line_ranges.begin();
3394 0 : iter != line_ranges.end(); ++iter) {
3395 0 : os << "[" << (*iter).first << ", " << (*iter).second << "] ";
3396 : }
3397 0 : os << LogIO::POST;
3398 0 : if (invert) { // eliminate edge channels from output mask
3399 0 : if (lf_edge.first > 0)
3400 0 : line_ranges.push_front(pair<size_t, size_t>(0, lf_edge.first - 1));
3401 0 : if (lf_edge.second > 0)
3402 0 : line_ranges.push_back(
3403 0 : pair<size_t, size_t>(num_data - lf_edge.second, num_data - 1));
3404 : }
3405 0 : return line_ranges;
3406 : }
3407 :
3408 0 : void SingleDishMS::findLineAndGetMask(size_t const num_data,
3409 : float const* data,
3410 : bool const* in_mask,
3411 : float const threshold,
3412 : int const avg_limit,
3413 : int const minwidth,
3414 : vector<int> const& edge,
3415 : bool const invert,
3416 : bool* out_mask) {
3417 : // copy input mask to output mask vector if necessary
3418 0 : if (in_mask != out_mask) {
3419 0 : for (size_t i = 0; i < num_data; ++i) {
3420 0 : out_mask[i] = in_mask[i];
3421 : }
3422 : }
3423 : // line finding
3424 : list<pair<size_t, size_t>> line_ranges
3425 : = findLineAndGetRanges(num_data, data, out_mask, threshold,
3426 0 : avg_limit, minwidth, edge, invert);
3427 : // line mask creation (do not initialize in case of baseline mask)
3428 0 : linefinder::getMask(num_data, out_mask, line_ranges, invert, !invert);
3429 0 : }
3430 :
3431 0 : void SingleDishMS::smooth(string const &kernelType,
3432 : float const kernelWidth,
3433 : string const &columnName,
3434 : string const &outMSName) {
3435 0 : LogIO os(_ORIGIN);
3436 : os << "Input parameter summary:" << endl << " kernelType = " << kernelType
3437 : << endl << " kernelWidth = " << kernelWidth << endl
3438 : << " columnName = " << columnName << endl << " outMSName = "
3439 0 : << outMSName << LogIO::POST;
3440 :
3441 : // Initialization
3442 0 : doSmoothing_ = true;
3443 0 : prepare_for_process(columnName, outMSName);
3444 :
3445 : // configure smoothing
3446 0 : sdh_->setSmoothing(kernelType, kernelWidth);
3447 0 : sdh_->initializeSmoothing();
3448 :
3449 : // get VI/VB2 access
3450 0 : vi::VisibilityIterator2 *visIter = sdh_->getVisIter();
3451 0 : visIter->setRowBlocking(kNRowBlocking);
3452 0 : vi::VisBuffer2 *vb = visIter->getVisBuffer();
3453 :
3454 0 : double startTime = gettimeofday_sec();
3455 :
3456 0 : for (visIter->originChunks(); visIter->moreChunks(); visIter->nextChunk()) {
3457 0 : for (visIter->origin(); visIter->more(); visIter->next()) {
3458 0 : sdh_->fillOutputMs(vb);
3459 : }
3460 : }
3461 :
3462 0 : double endTime = gettimeofday_sec();
3463 : os << LogIO::DEBUGGING
3464 : << "Elapsed time for VI/VB loop: " << endTime - startTime << " sec"
3465 0 : << LogIO::POST;
3466 :
3467 : // Finalization
3468 0 : finalize_process();
3469 0 : }
3470 :
3471 0 : void SingleDishMS::atmcor(Record const &config, string const &columnName, string const &outMSName) {
3472 0 : LogIO os(_ORIGIN);
3473 : os << LogIO::DEBUGGING
3474 : << "Input parameter summary:" << endl
3475 : << " columnName = " << columnName << endl << " outMSName = "
3476 0 : << outMSName << LogIO::POST;
3477 :
3478 : // Initialization
3479 0 : doAtmCor_ = true;
3480 0 : atmCorConfig_ = config;
3481 0 : os << LogIO::DEBUGGING << "config summry:";
3482 0 : atmCorConfig_.print(os.output(), 25, " ");
3483 0 : os << LogIO::POST;
3484 0 : Block<Int> sortCols(4);
3485 0 : sortCols[0] = MS::OBSERVATION_ID;
3486 0 : sortCols[1] = MS::ARRAY_ID;
3487 0 : sortCols[2] = MS::FEED1;
3488 0 : sortCols[3] = MS::DATA_DESC_ID;
3489 0 : prepare_for_process(columnName, outMSName, sortCols, False);
3490 :
3491 : // get VI/VB2 access
3492 0 : vi::VisibilityIterator2 *visIter = sdh_->getVisIter();
3493 : // for parallel processing: set row blocking (common multiple of 3 and 4)
3494 : // TODO: optimize row blocking size
3495 0 : constexpr rownr_t kNrowBlocking = 360u;
3496 0 : std::vector<Int> antenna1 = ScalarColumn<Int>(visIter->ms(), "ANTENNA1").getColumn().tovector();
3497 0 : std::sort(antenna1.begin(), antenna1.end());
3498 0 : auto const result = std::unique(antenna1.begin(), antenna1.end());
3499 0 : Int const nAntennas = std::distance(antenna1.begin(), result);
3500 0 : visIter->setRowBlocking(kNrowBlocking * nAntennas);
3501 : os << "There are " << nAntennas << " antennas in MAIN table. "
3502 : << "Set row-blocking size " << kNrowBlocking * nAntennas
3503 0 : << LogIO::POST;
3504 0 : vi::VisBuffer2 *vb = visIter->getVisBuffer();
3505 :
3506 0 : double startTime = gettimeofday_sec();
3507 :
3508 0 : for (visIter->originChunks(); visIter->moreChunks(); visIter->nextChunk()) {
3509 0 : for (visIter->origin(); visIter->more(); visIter->next()) {
3510 0 : sdh_->fillOutputMs(vb);
3511 : }
3512 : }
3513 :
3514 0 : double endTime = gettimeofday_sec();
3515 : os << LogIO::DEBUGGING
3516 : << "Elapsed time for VI/VB loop: " << endTime - startTime << " sec"
3517 0 : << LogIO::POST;
3518 :
3519 : // Finalization
3520 0 : finalize_process();
3521 0 : }
3522 :
3523 :
3524 0 : bool SingleDishMS::importAsap(string const &infile, string const &outfile, bool const parallel) {
3525 0 : bool status = true;
3526 : try {
3527 0 : SingleDishMSFiller<Scantable2MSReader> filler(infile, parallel);
3528 0 : filler.fill();
3529 0 : filler.save(outfile);
3530 0 : } catch (AipsError &e) {
3531 0 : LogIO os(_ORIGIN);
3532 0 : os << LogIO::SEVERE << "Exception occurred." << LogIO::POST;
3533 0 : os << LogIO::SEVERE << "Original Message: \n" << e.getMesg() << LogIO::POST;
3534 0 : os << LogIO::DEBUGGING << "Detailed Stack Trace: \n" << e.getStackTrace() << LogIO::POST;
3535 0 : status = false;
3536 0 : } catch (...) {
3537 0 : LogIO os(_ORIGIN);
3538 0 : os << LogIO::SEVERE << "Unknown exception occurred." << LogIO::POST;
3539 0 : status = false;
3540 : }
3541 0 : return status;
3542 : }
3543 :
3544 0 : bool SingleDishMS::importNRO(string const &infile, string const &outfile, bool const parallel) {
3545 0 : bool status = true;
3546 : try {
3547 0 : SingleDishMSFiller<NRO2MSReader> filler(infile, parallel);
3548 0 : filler.fill();
3549 0 : filler.save(outfile);
3550 0 : } catch (AipsError &e) {
3551 0 : LogIO os(_ORIGIN);
3552 0 : os << LogIO::SEVERE << "Exception occurred." << LogIO::POST;
3553 0 : os << LogIO::SEVERE << "Original Message: \n" << e.getMesg() << LogIO::POST;
3554 0 : os << LogIO::DEBUGGING << "Detailed Stack Trace: \n" << e.getStackTrace() << LogIO::POST;
3555 0 : status = false;
3556 0 : } catch (...) {
3557 0 : LogIO os(_ORIGIN);
3558 0 : os << LogIO::SEVERE << "Unknown exception occurred." << LogIO::POST;
3559 0 : status = false;
3560 : }
3561 0 : return status;
3562 : }
3563 :
3564 : } // End of casa namespace.
|