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