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