Line data Source code
1 : //# BLParameterParser.cc: this code perses baseline fitting parameters
2 : //# Copyright (C) 2015
3 : //# National Astronomical Observatory of Japan
4 : //#
5 : //# This library is free software; you can redistribute it and/or modify it
6 : //# under the terms of the GNU Library General Public License as published by
7 : //# the Free Software Foundation; either version 2 of the License, or (at your
8 : //# option) any later version.
9 : //#
10 : //# This library is distributed in the hope that it will be useful, but WITHOUT
11 : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 : //# License for more details.
14 : //#
15 : //# You should have received a copy of the GNU Library General Public License
16 : //# along with this library; if not, write to the Free Software Foundation,
17 : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 : //#
19 : //# Correspondence concerning AIPS++ should be addressed as follows:
20 : //# Internet email: casa-feedback@nrao.edu.
21 : //# Postal address: AIPS++ Project Office
22 : //# National Radio Astronomy Observatory
23 : //# 520 Edgemont Road
24 : //# Charlottesville, VA 22903-2475 USA
25 : //#
26 : //# $Id$
27 : #include <fstream>
28 : #include <iostream>
29 : #include <regex>
30 :
31 : #include <casacore/casa/Utilities/Assert.h>
32 : #include <singledish/SingleDish/BLParameterParser.h>
33 :
34 : using namespace std;
35 :
36 : #define _ORIGIN LogOrigin("BLParameterParser", __func__, WHERE)
37 :
38 : using namespace casacore;
39 : using namespace casacore;
40 : using namespace casacore;
41 : using namespace casacore;
42 : using namespace casacore;
43 : using namespace casacore;
44 : using namespace casacore;
45 : namespace casa {
46 :
47 0 : BLParameterParser::BLParameterParser(string const file_name)
48 : {
49 0 : initialize();
50 0 : parse(file_name);
51 0 : blparam_file_ = file_name;
52 0 : }
53 :
54 0 : BLParameterParser::~BLParameterParser()
55 : {
56 0 : Clearup();
57 0 : }
58 :
59 0 : void BLParameterParser::Clearup()
60 : {
61 0 : if (!bl_parameters_.empty()) {
62 : map<const pair<size_t, size_t> , BLParameterSet*>::iterator
63 0 : iter = bl_parameters_.begin();
64 0 : while (iter != bl_parameters_.end()) {
65 0 : delete (*iter).second;
66 0 : ++iter;
67 : }
68 0 : bl_parameters_.clear();
69 : }
70 0 : }
71 :
72 0 : void BLParameterParser::initialize()
73 : {
74 0 : if (!bl_parameters_.empty()) Clearup();
75 0 : baseline_types_.resize(0);
76 : // initialize max orders
77 0 : size_t num_type = BaselineType_kNumElements;
78 0 : for (size_t i=0; i<num_type; ++i) {
79 0 : max_orders_[i] = 0;
80 : }
81 0 : }
82 :
83 0 : uint16_t BLParameterParser::get_max_order(size_t const bltype)
84 : {
85 :
86 0 : for (size_t i = 0; i < baseline_types_.size(); ++i) {
87 0 : if (bltype == baseline_types_[i]) {
88 : //bltype is in file
89 0 : return max_orders_[bltype];
90 : }
91 : }
92 : // bltype is not in file
93 0 : throw(AipsError("The baseline type is not in file."));
94 : }
95 :
96 0 : void BLParameterParser::parse(string const file_name)
97 : {
98 0 : LogIO os(_ORIGIN);
99 0 : ifstream ifs(file_name.c_str(),ifstream::in);
100 0 : AlwaysAssert(!ifs.fail(), AipsError);
101 0 : string linestr;
102 0 : while (getline(ifs, linestr)) {
103 : // parse line here to construct BLParameterSet
104 : // The order should be
105 : // ROW,POL,MASK,NITERATION,CLIP_THRES,LF,LF_THRES,LEDGE,REDGE,CHANAVG,BL_TYPE,ORDER,N_PIECE,NWAVE
106 : // size_t,1,string,uint16_t,float,bool,float,size_t,size_t,size_t,sinusoidal,uint16_t,size_t,vector<size_t>
107 : //skip line starting with '#'
108 0 : if (linestr.empty() || linestr[0]=='#') continue;
109 0 : BLParameterSet *bl_param = new BLParameterSet();
110 : size_t row_idx, pol_idx;
111 0 : ConvertLineToParam(linestr, row_idx, pol_idx, *bl_param);
112 0 : bl_parameters_[make_pair(row_idx, pol_idx)] = bl_param;
113 : //Parameter summary output (Debugging purpose only)
114 : if (false) {
115 : os << "Summary of parsed Parameter" << LogIO::POST;
116 : os << "[ROW" << row_idx << ", POL" << pol_idx << "]" << LogIO::POST;
117 : bl_param->PrintSummary();
118 : }
119 : // update bealine_types_ list
120 0 : size_t curr_type_idx = static_cast<size_t>(bl_param->baseline_type);
121 0 : bool new_type = true;
122 0 : for (size_t i=0; i<baseline_types_.size(); ++i){
123 0 : if (bl_param->baseline_type==baseline_types_[i]){
124 0 : new_type = false;
125 0 : break;
126 : }
127 : }
128 0 : if (new_type) baseline_types_.push_back(bl_param->baseline_type);
129 : // update max_orders_
130 0 : size_t curr_order = GetTypeOrder(*bl_param);
131 0 : if (curr_order > max_orders_[curr_type_idx])
132 0 : max_orders_[curr_type_idx] = curr_order;
133 : }
134 0 : }
135 :
136 0 : void BLParameterParser::SplitLine(string const &linestr,
137 : char const separator,
138 : vector<string> &strvec)
139 : {
140 0 : istringstream iss(linestr);
141 0 : string selem;
142 0 : size_t ielem(0);
143 0 : while(getline(iss, selem, separator)) {
144 0 : if (ielem >= strvec.size()) {
145 0 : strvec.resize(ielem+1);
146 : }
147 0 : strvec[ielem] = selem;
148 0 : ++ielem;
149 : }
150 0 : }
151 :
152 0 : void BLParameterParser::ConvertLineToParam(string const &linestr,
153 : size_t &rowid, size_t &polid,
154 : BLParameterSet ¶mset){
155 : //split a line by ',' and make a vector of strings
156 0 : std::vector<string> svec(BLParameters_kNumElements,"");
157 0 : SplitLine(linestr,',', svec);
158 : // parse mandatory data
159 0 : rowid = ConvertString<size_t>(svec[BLParameters_kRow]);
160 0 : polid = ConvertString<size_t>(svec[BLParameters_kPol]);
161 0 : paramset.baseline_mask = svec[BLParameters_kMask];
162 0 : size_t num_piece=USHRT_MAX;//SIZE_MAX;
163 0 : string const bltype_str = svec[BLParameters_kBaselineType];
164 0 : if (bltype_str == "cspline")
165 : {
166 0 : if (svec[BLParameters_kNPiece].size()==0)
167 0 : throw(AipsError("Baseline type 'cspline' requires num_piece value."));
168 0 : num_piece = ConvertString<size_t>(svec[BLParameters_kNPiece]);
169 : // CreateBaselineContext does not supoort elements number > max(uint16_t)
170 0 : if (num_piece > USHRT_MAX)
171 0 : throw(AipsError("num_piece is larger than max of uint16_t"));
172 0 : paramset.npiece = num_piece;
173 0 : paramset.baseline_type = static_cast<LIBSAKURA_SYMBOL(LSQFitType)>(BaselineType_kCubicSpline);
174 : }
175 0 : else if (bltype_str == "sinusoid")
176 : {
177 : //Find the occurrence of "[n1,n2...]"
178 0 : std::regex pattern("\\[(\\d+(?:,\\d+)*)\\]");
179 0 : std::smatch matches;
180 0 : std::regex_search(linestr, matches, pattern);
181 0 : if (matches.size()< 1)
182 0 : throw(AipsError("Incorrect format or empty nwave list given: " +
183 0 : std::string(matches[0]) +
184 0 : ". Please refer the sdbaseline documentation. Ex. [1,2]"));
185 : // Split, convert and fill in the paramset_nwave
186 0 : std::vector<string> tmp_nwave;
187 : // regex result: matches[0] is the entire match
188 : // matches[1] is the content inside the square brackets
189 0 : SplitLine(matches[1], ',', tmp_nwave);
190 0 : for(const auto& i : tmp_nwave)
191 0 : paramset.nwave.emplace_back(ConvertString<size_t>(i));
192 : //Sort just in case and erase duplicates
193 0 : std::sort(paramset.nwave.begin(), paramset.nwave.end());
194 0 : paramset.nwave.erase(std::unique(paramset.nwave.begin(),paramset.nwave.end()), paramset.nwave.end());
195 0 : paramset.baseline_type = static_cast<LIBSAKURA_SYMBOL(LSQFitType)>(BaselineType_kSinusoid);
196 0 : }
197 : else
198 : { // poly or chebyshev
199 0 : if (svec[BLParameters_kOrder].size()==0)
200 0 : throw(AipsError("Baseline type 'poly' and 'chebyshev' require order value."));
201 0 : paramset.baseline_type = bltype_str == "chebyshev" ?
202 : static_cast<LIBSAKURA_SYMBOL(LSQFitType)>(BaselineType_kChebyshev) :
203 : static_cast<LIBSAKURA_SYMBOL(LSQFitType)>(BaselineType_kPolynomial);
204 0 : paramset.order = ConvertString<uint16_t>(svec[BLParameters_kOrder]);
205 : }
206 : // parse clipping parameters
207 0 : if (svec[BLParameters_kNumIteration].size() == 0)
208 0 : throw(AipsError("Number of maximum clip iteration is mandatory"));
209 0 : paramset.num_fitting_max = ConvertString<uint16_t>(svec[BLParameters_kNumIteration]) + 1;
210 0 : if (svec[BLParameters_kClipThreshold].size()>0)
211 : paramset.clip_threshold_sigma
212 0 : = ConvertString<float>(svec[BLParameters_kClipThreshold]);
213 : // parse line finder parameter
214 0 : LineFinderParameter &lf_param = paramset.line_finder;
215 0 : lf_param.use_line_finder = svec[BLParameters_kLineFinder]=="true" ? true : false;;
216 0 : if (lf_param.use_line_finder)
217 : { // use line finder
218 0 : if (svec[BLParameters_kLFThreshold].size()>0)
219 : {
220 0 : lf_param.threshold = ConvertString<float>(svec[BLParameters_kLFThreshold]);
221 : }
222 0 : vector<size_t> edge(2,0);
223 0 : if (svec[BLParameters_kLeftEdge].size() > 0)
224 0 : lf_param.edge[0] = ConvertString<size_t>(svec[BLParameters_kLeftEdge]);
225 0 : if (svec[BLParameters_kRightEdge].size() > 0)
226 0 : lf_param.edge[1] = ConvertString<size_t>(svec[BLParameters_kRightEdge]);
227 0 : if (svec[BLParameters_kChanAverageLim].size()>0)
228 : {
229 0 : lf_param.chan_avg_limit = ConvertString<size_t>(svec[BLParameters_kChanAverageLim]);
230 : }
231 0 : }
232 0 : }
233 :
234 0 : uint16_t BLParameterParser::GetTypeOrder(BLParameterSet const &bl_param)
235 : {
236 0 : size_t const type = static_cast<size_t>(bl_param.baseline_type);
237 0 : switch (type)
238 : {
239 0 : case BaselineType_kPolynomial:
240 : case BaselineType_kChebyshev:
241 0 : return bl_param.order;
242 : break;
243 0 : case BaselineType_kCubicSpline:
244 0 : AlwaysAssert(bl_param.npiece<=USHRT_MAX, AipsError);//UINT16_MAX);
245 0 : return static_cast<uint16_t>(bl_param.npiece);
246 : break;
247 0 : case BaselineType_kSinusoid:
248 0 : return static_cast<uint16_t>(bl_param.nwave[bl_param.nwave.size() - 1]); //<== must be max of nwave elements
249 : break;
250 0 : default:
251 0 : throw(AipsError("Unsupported baseline type."));
252 : }
253 : }
254 :
255 0 : bool BLParameterParser::GetFitParameter(size_t const rowid,size_t const polid, BLParameterSet &bl_param)
256 : {
257 : map<const pair<size_t, size_t> ,BLParameterSet*>::iterator
258 0 : iter = bl_parameters_.begin();
259 0 : iter = bl_parameters_.find(make_pair(rowid, polid));
260 0 : if (iter==bl_parameters_.end()) {
261 : // no matching element
262 0 : return false;
263 : }
264 0 : bl_param = *(*iter).second;
265 0 : return true;
266 : }
267 :
268 0 : BLTableParser::BLTableParser(string const file_name) : BLParameterParser(file_name)
269 : {
270 0 : initialize();
271 0 : blparam_file_ = file_name;
272 0 : bt_ = new BaselineTable(file_name);
273 0 : parse();
274 0 : }
275 :
276 0 : BLTableParser::~BLTableParser()
277 : {
278 0 : delete bt_;
279 0 : bt_ = 0;
280 0 : }
281 :
282 0 : void BLTableParser::initialize()
283 : {
284 0 : baseline_types_.resize(0);
285 : // initialize max orders
286 0 : size_t num_type = BaselineType_kNumElements;
287 0 : for (size_t i = 0; i < num_type; ++i) {
288 0 : max_orders_[i] = 0;
289 : }
290 0 : }
291 :
292 0 : uint16_t BLTableParser::GetTypeOrder(size_t const &baseline_type,
293 : uInt const irow, uInt const ipol)
294 : {
295 0 : switch (baseline_type)
296 : {
297 0 : case BaselineType_kPolynomial:
298 : case BaselineType_kChebyshev:
299 : {
300 0 : return static_cast<uint16_t>(bt_->getFPar(irow, ipol));
301 : break;
302 : }
303 0 : case BaselineType_kCubicSpline:
304 : {
305 0 : uInt npiece = bt_->getFPar(irow, ipol);
306 0 : AlwaysAssert(npiece <= USHRT_MAX, AipsError);//UINT16_MAX);
307 0 : return static_cast<uint16_t>(npiece);
308 : break;
309 : }
310 0 : case BaselineType_kSinusoid:
311 : {
312 : // TODO: revisit this line in CAS-13671
313 0 : return static_cast<uint16_t>(bt_->getFPar(irow, ipol));
314 : break;
315 : }
316 : // Previous comment:
317 : // case BaselineType_kSinusoidal:
318 : // return static_cast<size_t>(nwave.size());
319 : // break;
320 0 : default:
321 0 : throw(AipsError("Unsupported baseline type."));
322 : }
323 : }
324 :
325 0 : void BLTableParser::parse()
326 : {
327 0 : uInt const npol = 2;
328 0 : size_t nrow = bt_->nrow();
329 0 : std::map<string, std::map<double, uInt> > sorted;
330 0 : for (uInt irow = 0; irow < nrow; ++irow) {
331 0 : stringstream ss;
332 0 : ss << bt_->getSpw(irow) << ","
333 0 : << bt_->getAntenna(irow) << ","
334 0 : << bt_->getBeam(irow);
335 0 : sorted[ss.str()][bt_->getTime(irow)] = irow;
336 0 : for (uInt ipol = 0; ipol < npol; ++ipol) {
337 0 : if (!bt_->getApply(irow, ipol)) continue;
338 : LIBSAKURA_SYMBOL(LSQFitType) curr_type_idx =
339 0 : static_cast<LIBSAKURA_SYMBOL(LSQFitType)>(bt_->getBaselineType(irow, ipol));
340 0 : bool new_type = true;
341 0 : for (size_t i = 0; i < baseline_types_.size(); ++i){
342 0 : if (curr_type_idx == baseline_types_[i]){
343 0 : new_type = false;
344 0 : break;
345 : }
346 : }
347 0 : if (new_type) baseline_types_.push_back(curr_type_idx);
348 : // update max_orders_
349 0 : size_t curr_order = GetTypeOrder(curr_type_idx, irow, ipol);
350 0 : if (curr_order > max_orders_[curr_type_idx]) {
351 0 : max_orders_[curr_type_idx] = curr_order;
352 : }
353 : }
354 0 : }
355 :
356 0 : for (std::map<string, std::map<double, uInt> >::iterator it = sorted.begin(); it != sorted.end(); ++it) {
357 0 : sortedTimes_[it->first].clear();
358 0 : timeSortedIdx_[it->first].clear();
359 0 : numRows_[it->first] = 0;
360 0 : size_t num_rows = 0;
361 0 : for (std::map<double, uInt>::iterator it0 = sorted[it->first].begin(); it0 != sorted[it->first].end(); ++it0) {
362 0 : sortedTimes_[it->first].push_back(it0->first);
363 0 : timeSortedIdx_[it->first].push_back(it0->second);
364 0 : num_rows++;
365 : }
366 0 : numRows_[it->first] = num_rows;
367 : }
368 0 : }
369 :
370 0 : bool BLTableParser::GetFitParameterIdx(double const time, double const interval,
371 : size_t const scanid, size_t const beamid,
372 : size_t const antid, size_t const spwid,
373 : size_t &idx)
374 : {
375 0 : bool found = false;
376 0 : stringstream ss;
377 0 : ss << spwid << "," << antid << "," << beamid;
378 0 : string key = ss.str();
379 0 : if (numRows_.count(key) == 0) {
380 0 : return false;
381 : }
382 0 : uInt idx_top = 0;
383 0 : uInt idx_end = numRows_[key] - 1;
384 0 : uInt idx_mid = (idx_top + idx_end)/2;
385 0 : double time_top = sortedTimes_[key][idx_top];
386 0 : double time_end = sortedTimes_[key][idx_end];
387 0 : double time_mid = sortedTimes_[key][idx_mid];
388 0 : if ((time < time_top)||(time_end < time)) { // out of range.
389 0 : return false;
390 : }
391 0 : size_t idx0 = 0;
392 : //binary search in time-sorted table.
393 0 : while (idx_end - idx_top > 1) {
394 0 : if (time_top == time) {
395 0 : idx0 = idx_top;
396 0 : found = true;
397 0 : break;
398 0 : } else if (time_mid == time) {
399 0 : idx0 = idx_mid;
400 0 : found = true;
401 0 : break;
402 0 : } else if (time_end == time) {
403 0 : idx0 = idx_end;
404 0 : found = true;
405 0 : break;
406 0 : } else if (time_mid < time) {
407 0 : idx_top = idx_mid;
408 0 : time_top = time_mid;
409 : } else {
410 0 : idx_end = idx_mid;
411 0 : time_end = time_mid;
412 : }
413 0 : idx_mid = (idx_top + idx_end)/2;
414 0 : time_mid = sortedTimes_[key][idx_mid];
415 : }
416 0 : if (!found) {
417 : //only one or two candidates should exist now.
418 : //check if there is one with time identical to the specified time
419 0 : for (size_t i = idx_top; i <= idx_end; ++i) {
420 0 : if ((time - interval < sortedTimes_[key][i])&&
421 0 : (sortedTimes_[key][i] < time + interval)) {
422 0 : idx0 = i;
423 0 : found = true;
424 0 : break;
425 : }
426 : }
427 0 : if (!found) {
428 0 : return false;
429 : }
430 : }
431 : //finally, validate the candidate using its ids.
432 0 : idx = timeSortedIdx_[key][idx0];
433 0 : found = (scanid == bt_->getScan(idx))&&
434 0 : (beamid == bt_->getBeam(idx))&&
435 0 : (spwid == bt_->getSpw(idx));
436 :
437 0 : return found;
438 0 : }
439 :
440 : /*
441 : //simply search from the first line. not using binary search.
442 : bool BLTableParser::GetFitParameterIdx(double const time, double const interval,
443 : size_t const scanid, size_t const beamid,
444 : size_t const spwid, size_t &idx)
445 : {
446 : bool found = false;
447 : uInt idx_end = bt_->nrow() - 1;
448 : double bt_time;
449 : uInt bt_scanid;
450 : uInt bt_beamid;
451 : uInt bt_spwid;
452 : for (uInt i = 0; i <= idx_end; ++i) {
453 : bt_time = bt_->getTime(i);
454 : bt_scanid = bt_->getScan(i);
455 : bt_beamid = bt_->getBeam(i);
456 : bt_spwid = bt_->getSpw(i);
457 : if ((bt_time-interval < time) && (time < bt_time+interval) &&
458 : (scanid == bt_scanid) && (beamid == bt_beamid) &&
459 : (spwid == bt_spwid)) {
460 : idx = i;
461 : found = true;
462 : break;
463 : }
464 : }
465 : return found;
466 : }
467 : */
468 :
469 0 : void BLTableParser::GetFitParameterByIdx(size_t const idx, size_t const ipol,
470 : bool &apply,
471 : Vector<double> &coeff,
472 : Vector<size_t> &boundary,
473 : std::vector<bool> &masklist,
474 : BLParameterSet &bl_param)
475 : {
476 0 : apply = bt_->getApply(idx, ipol);
477 0 : if (!apply) return;
478 0 : size_t const type = bt_->getBaselineType(idx, ipol);
479 0 : bl_param.baseline_type = type;
480 0 : Vector<Int> fpar(bt_->getFuncParam(idx)[0]);
481 0 : switch (type) {
482 0 : case BaselineType_kPolynomial:
483 : case BaselineType_kChebyshev:
484 0 : bl_param.order = fpar[ipol];
485 0 : coeff.resize(bl_param.order + 1);
486 0 : for (size_t i = 0; i < coeff.size(); ++i) {
487 0 : coeff[i] = bt_->getResult(idx).row(ipol)[i];
488 : }
489 0 : break;
490 0 : case BaselineType_kCubicSpline:
491 0 : bl_param.npiece = fpar[ipol];
492 0 : boundary.resize(bl_param.npiece + 1);
493 0 : for (size_t i = 0; i < boundary.size(); ++i) {
494 0 : boundary[i] = bt_->getFuncFParam(idx).row(ipol)[i];
495 : }
496 0 : coeff.resize(bl_param.npiece * 4);
497 0 : for (size_t i = 0; i < coeff.size(); ++i) {
498 0 : coeff[i] = bt_->getResult(idx).row(ipol)[i];
499 : }
500 0 : break;
501 0 : default:
502 0 : throw(AipsError("Unsupported baseline type."));
503 : }
504 0 : masklist = bt_->getMask(idx, ipol);
505 0 : }
506 :
507 :
508 : } //# NAMESPACE CASA - END
|