Loading...
Searching...
No Matches
RadarAccumulator.h
1/*
2
3MIT License
4
5Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26/*
27Part of Rack development has been done in the BALTRAD projects part-financed
28by the European Union (European Regional Development Fund and European
29Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30*/
31#ifndef RADAR_ACCUMULATOR_H
32#define RADAR_ACCUMULATOR_H
33
34
35#include <sstream>
36
37
38#include <drain/image/Sampler.h>
39//#include <drain/util/Proj4.h>
40#include <drain/image/AccumulatorGeo.h>
41#include <product/RadarProductOp.h>
42#include "data/ODIM.h"
43#include "data/ODIMPath.h"
44#include "data/Data.h"
45#include "data/DataSelector.h"
46#include "data/DataCoder.h"
47#include "data/QuantityMap.h"
48#include "Geometry.h"
49
50
51namespace rack {
52
54
60template <class AC, class OD>
61class RadarAccumulator : public AC {
62
63public:
64
68
70 RadarAccumulator() : dataSelector(ODIMPathElem::DATA|ODIMPathElem::QUALITY), defaultQuality(0.5), counter(0) { // , undetectValue(-52.0) {
71 odim.type.clear();
72 odim.ACCnum = 0; // NEW
73 }
74
75 virtual
77
79 /*
80 * Counter example: this method is \i not called when polar data is added to a Cartesian composite.
81 *
82 * \param i0 - offset in horizontal direction
83 * \param j0 - offset in vertical direction
84 */
85 void addData(const pdata_src_t & srcData, const pdata_src_t & srcQuality, double weight, int i0, int j0);
86
88 /*
89 *
90 * Counter example: this method is \i not called when polar data is added to a Cartesian composite.
91 */
92 void addData(const pdata_src_t & srcData, const pdata_src_t & srcQuality, const pdata_src_t & srcCount);
93
98 void extractOLD(const OD & odimOut, DataSet<DstType<OD> > & dstProduct,
99 const std::string & fields, const drain::Rectangle<int> & crop = {0,0,0,0}) const;
100
103 // DataSelector dataSelector(ODIMPathElem::DATA);
104 // dataSelector.pathMatcher.setElems(ODIMPathElem::DATA);
105
106
108 /*
109 * Helps in warning if input data does not match the expected / potential targetEncoding
110 */
112
115
117
120 size_t counter;
121
122
124 inline
125 void setTargetEncoding(const std::string & encoding){
126 targetEncoding = encoding;
127 if (odim.quantity.empty()){
128 //drain::ReferenceMap m;
129 ODIM m;
130 m.link("what:quantity", odim.quantity); // appends
131 m.addShortKeys();
132 m.updateValues(encoding);
133 }
134 //odim.setValues(encoding); // experimental
135 }
136
137 inline
138 void consumeTargetEncoding(std::string & encoding){
139 if (!encoding.empty()){
140 targetEncoding = encoding;
141 if (odim.quantity.empty()){
142 //drain::ReferenceMap m;
143 ODIM m;
144 m.link("what:quantity", odim.quantity); // appends
145 m.addShortKeys();
146 m.updateValues(encoding);
147 }
148 }
149 encoding.clear();
150 }
151
152
153 inline
154 const std::string & getTargetEncoding(){
155 return targetEncoding;
156 }
157
158 virtual inline
159 std::ostream & toStream(std::ostream & ostr) const {
160
161 // std::cerr << __FILE__ << '@' << __LINE__ << std::endl;
162 this->AC::toStream(ostr);
163 ostr << ' ';
164 // std::cerr << __FILE__ << '@' << __LINE__ << std::endl;
165 odim.toStream(ostr);
166 // std::cerr << __FILE__ << '@' << __LINE__ << " (end)" << std::endl;
167 return ostr;
168 }
169
171 bool checkCompositingMethod(const ODIM & srcODIM) const;
172
173
174protected:
175
176 std::string targetEncoding;
177
178};
179
180
181template <class AC, class OD>
182void RadarAccumulator<AC,OD>::addData(const pdata_src_t & srcData, const pdata_src_t & srcQuality, double weight, int i0, int j0){
183
184 drain::Logger mout(__FILE__, __FUNCTION__);
185
186 // mout.attention("START ", EncodingODIM(srcData.odim));
187
188 if (!srcQuality.data.isEmpty()){
189 mout.info("Quality data available with input; using quality as weights in compositing.");
190 DataCoder converter(srcData.odim, srcQuality.odim);
191 // uses also DataCoder::undetectQualityCoeff
192 AC::addData(srcData.data, srcQuality.data, converter, weight, i0, j0);
193 }
194 else {
195 mout.info("No quality data available with input, ok.");
196 ODIM qualityOdim; // dummy
197 getQuantityMap().setQuantityDefaults(qualityOdim, "QIND");
198
199 DataCoder converter(srcData.odim, qualityOdim);
200 // uses also DataCoder::undetectQualityCoeff
201 AC::addData(srcData.data, converter, weight, i0, j0);
202 }
203
204 // mout.attention("END1 ", EncodingODIM(this->odim));
205 odim.updateLenient(srcData.odim); // Time, date, new
206 // mout.attention("END2 ", EncodingODIM(this->odim));
207
208 counter += std::max(1L, srcData.odim.ACCnum);
209 // odim.ACCnum += std::max(1L, srcData.odim.ACCnum); wrong
210 // odim.ACCnum = counter; // TODO remove counter?
211
212 //mout.note("after: " , this->odim );
213
214}
215
216template <class AC, class OD>
217void RadarAccumulator<AC,OD>::addData(const pdata_src_t & srcData, const pdata_src_t & srcQuality, const pdata_src_t & srcCount){
218
219 drain::Logger mout(__FILE__, __FUNCTION__);
220 // mout.info("Quality data available with input; using quality as weights in compositing.");
221 DataCoder converter(srcData.odim, srcQuality.odim);
222 AC::addData(srcData.data, srcQuality.data, srcCount.data, converter);
223
224 odim.updateLenient(srcData.odim); // Time, date, new
225 counter = std::max(1L, srcData.odim.ACCnum); // correct
226 // odim.ACCnum += std::max(1L, srcData.odim.ACCnum); // wrong
227}
228
229
230template <class AC, class OD>
232
233 drain::Logger mout(__FILE__, __FUNCTION__);
234
235 mout.debug("start, quantity=" , dataODIM.quantity );
236
237 const AccumulationMethod & rule = this->getMethod();
238 if (rule.getName() == "WAVG"){
239
240 const drain::ReferenceMap & wavgParams = rule.getParameters();
241 const double p = wavgParams.get("p", 1.0);
242 const double p2 = p/2.0;
243 mout.info(rule , ", min=", dataODIM.getMin() );
244
245 if ((p2 - floor(p2)) == 0.0){
246 mout.info("WAVG with p=" , p , " = 2N, positive pow() results" );
247 const Quantity & q = getQuantityMap().get(dataODIM.quantity);
248 if (q.hasUndetectValue()){
249 const double bias = wavgParams.get("bias", 0.0);
250 if (bias > q.undetectValue){
251 mout.warn("WAVG with p=" , p ," = 2N, undetectValue=" , q.undetectValue , " < bias=", bias );
252 mout.warn("consider adjusting bias(", bias ,") down to quantity (" , dataODIM.quantity , ") zero: " , q.undetectValue );
253 //rule.setParameter("bias", q.undetectValue);
254 return true;
255 }
256 }
257 }
258 }
259
260 return false;
261
262
263}
264
265
266
267template <class AC, class OD>
268void RadarAccumulator<AC,OD>::extractOLD(const OD & odimOut, DataSet<DstType<OD> > & dstProduct,
269 const std::string & fields, const drain::Rectangle<int> & crop) const {
270 // , const drain::Rectangle<double> & bbox) const {
271
272 drain::Logger mout(__FILE__, __FUNCTION__);
273
274 const std::type_info & t = drain::Type::getTypeInfo(odimOut.type);
275
276 typedef enum {DATA,QUALITY} datatype;
277
278 OD odimData;
279 odimData = odimOut;
280 odimData.scaling.scale = 0.0; // ?
281
282 const QuantityMap & qm = getQuantityMap();
283
289 bool DATA_SPECIFIC_QUALITY = false;
290
291 // Consider redesign, with a map of objects {quantity, type,}
292 for (size_t i = 0; i < fields.length(); ++i) {
293
294 ODIM odimQuality;
295 odimQuality.quantity = "QIND";
296
297 // std::stringstream dataPath;
298
299 datatype type = DATA;
300 char field = fields.at(i);
301 switch (field) {
302 case '/':
303 DATA_SPECIFIC_QUALITY = true;
304 continue;
305 break; // unneeded?
306 case 'm': // ???
307 case 'D':
308 case 'p': // ???
309 mout.warn() << "non-standard layer code; use 'd' for 'data' instead" << mout.endl;
310 // no break
311 case 'd':
312 type = DATA;
313 odimData = odimOut; // consider update
314 qm.setQuantityDefaults(odimQuality, "QIND"); // ?
315 odimQuality.quantity = "QIND";
316 break;
317 case 'c':
318 type = QUALITY;
319 qm.setQuantityDefaults(odimQuality, "COUNT");
320 odimQuality.quantity = "COUNT";
321 break;
322 case 'C':
323 type = QUALITY;
324 qm.setQuantityDefaults(odimQuality, "COUNT", "d");
325 odimQuality.quantity = "COUNT";
326 break;
327 // case 'q': // consider
328 case 'w':
329 // no break
330 type = QUALITY;
331 odimData = odimOut; // (Because converter needs both data and weight to encode weight?)
332 qm.setQuantityDefaults(odimQuality, "QIND", "C");
333 odimQuality.quantity = "QIND";
334 //odimQuality.undetect = 256;
335 //odimQuality.nodata = -1; // this is good, because otherwise nearly-undetectValue-quality CAPPI areas become no-data.
336 break;
337 case 'W':
338 mout.warn("experimental: quality [QIND] type copied from data [" , odimOut.quantity , ']' );
339 // no break
340 type = QUALITY;
341 odimData = odimOut; // (Because converted needs both data and weight to encode weight?)
342 qm.setQuantityDefaults(odimQuality, "QIND", odimOut.type);
343 odimQuality.quantity = "QIND";
344 //odimQuality.undetect = 256;
345 //odimQuality.nodata = -1; // this is good, because otherwise nearly-undetectValue-quality CAPPI areas become no-data.
346 break;
347 case 's':
348 type = QUALITY;
349 odimQuality = odimOut;
350 odimQuality.quantity += "DEV";
351 if (qm.hasQuantity(odimQuality.quantity)){
352 qm.setQuantityDefaults(odimQuality, odimQuality.quantity, odimQuality.type);
353 mout.accept<LOG_NOTICE>("found quantyConf[", odimQuality.quantity, "], type=", odimQuality.type);
354 //mout.special("Quality: ", EncodingODIM(odimQuality));
355 mout.special("Quality: ", EncodingODIM(odimQuality));
356 mout.special("Quality: ", odimQuality);
357 }
358 else {
359 odimQuality.scaling.scale *= 20.0; // ?
360 //const std::type_info & t = Type::getType(odimFinal.type);
361 odimQuality.scaling.offset = round(drain::Type::call<drain::typeMin, double>(t) + drain::Type::call<drain::typeMax, double>(t))/2.0;
362 //odimQuality.offset = round(drain::Type::call<drain::typeMax,double>(t) + drain::Type::getMin<double>(t))/2.0; // same as data!
363 mout.warn("quantyConf[" , odimQuality.quantity , "] not found, using somewhat arbitary scaling:" );
364 mout.special("Quality: ", EncodingODIM(odimQuality));
365 }
366 break;
367 default:
368 mout.error("Unsupported field code: '", field, "'");
369 break;
370 }
371
372 mout.debug("extracting field ", field);
373
374 if (!crop.empty()){
375 mout.experimental("Applying cropping: bbox=", crop, " [pix]");
376 }
377
378 if (type == DATA){
379 mout.debug("target: " , EncodingODIM(odimData) );
380 }
381 else if (type == QUALITY){
382 mout.debug("target: " , EncodingODIM(odimQuality) );
383 }
384
385 if (odimData.quantity.empty()){
386 odimData.quantity = "UNKNOWN"; // ok; for example --cPlotFile carries no information on quantity
387 mout.note("quantity=", odimData.quantity);
388 }
389
390 //PlainData<DstType<OD> >
391 mout.debug("searching dstData... DATA=", (type == DATA));
392 //pdata_dst_t & dstData = (type == DATA) ? dstProduct.getData(odimFinal.quantity) : dstProduct.getQualityData(odimQuality.quantity);
393 //mout .debug3() << "dstData: " << dstData << mout.endl;
394
395 //DataDst dstData(dataGroup); // FIXME "qualityN" instead of dataN creates: /dataset1/qualityN/quality1/data
396 //mout.warn("odimFinal: " , odimFinal );
397 mout.debug("odimData: " , EncodingODIM(odimData) );
398 DataCoder dataCoder(odimData, odimQuality); // (will use only either odim!)
399 mout.debug("dataCoder: ", dataCoder);
400 mout.debug2("dataCoder: data: ", dataCoder.dataODIM);
401 mout.debug2("dataCoder: qind: ", dataCoder.qualityODIM);
402
403 if (!crop.empty()){
404 mout.unimplemented("crop ", crop, ", dstData.data resize + Accumulator::extractField ");
405 }
406
407 if (type == DATA){
408 mout.debug("DATA/" , field, " [", odimData.quantity, ']');
409 //mout.warn(dstData.odim );
410 pdata_dst_t & dstData = dstProduct.getData(odimData.quantity);
411 dstData.odim.importMap(odimData);
412 dstData.data.setType(odimData.type);
413 mout.debug3("dstData: " , dstData );
414 //mout.debug("quantity=" , dstData.odim.quantity );
415 this->Accumulator::extractField(field, dataCoder, dstData.data, crop);
416 }
417 else {
418 mout.debug("QUALITY/" , field , " [", odimQuality.quantity, ']');
419 //pdata_dst_t & dstData = dstProduct.getData(odimFinal.quantity);
420 typedef QualityDataSupport<DstType<OD> > q_data_t;
421 q_data_t & qualityOwner = (DATA_SPECIFIC_QUALITY) ? (q_data_t &) dstProduct.getData(odimData.quantity) : (q_data_t &) dstProduct;
422 pdata_dst_t & dstData = qualityOwner.getQualityData(odimQuality.quantity);
423 dstData.odim.updateFromMap(odimQuality);
424 mout.debug3("dstData: " , dstData );
425 this->Accumulator::extractField(field, dataCoder, dstData.data, crop);
426 }
427
428
429 // mout.debug("updating local tree attributes");
430
431 }
432
433
434 // mout.debug("updating local tree attributes" );
435 // mout.debug("finished" );
436
437}
438
439
440} // rack::
441
442
443#endif /* RADAR_ACCUMULATOR */
444
445// Rack
virtual const std::string & getName() const
Return the name of an instance.
Definition BeanLike.h:82
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:312
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition Log.h:430
Logger & debug(const TT &... args)
Debug information.
Definition Log.h:666
Logger & note(const TT &... args)
For top-level information.
Definition Log.h:489
Logger & special(const TT &... args)
Other useful information.
Definition Log.h:531
Logger & error(const TT &... args)
Echoes.
Definition Log.h:416
Logger & accept(const TT &... args)
Some input has been accepted, for example by a syntax.
Definition Log.h:582
Logger & unimplemented(const TT &... args)
Feature to be done. Special type of Logger::note().
Definition Log.h:511
Logger & debug2(const TT &... args)
Debug information.
Definition Log.h:676
Definition ReferenceMap.h:207
void updateValues(const std::string &entries, char assignmentSymbol='=', char separatorSymbol=0)
Sets applicable values ie. modifies existing entries only. In ordered maps, skips extra entries silen...
Definition SmartMap.h:326
std::string get(const std::string &key, const std::string &defaultValue) const
Retrieves a value, or default value if value is unset.
Definition SmartMap.h:127
static const std::type_info & getTypeInfo(char t)
Returns the base type associated with a character key.
Definition Type.h:134
double & scale
Multiplicative coefficient \i a in: y = ax + b.
Definition ValueScaling.h:68
double & offset
Additive coefficient \i b in: y = ax + b.
Definition ValueScaling.h:71
Function for accumulating data: maximum, average, weighted average etc.
Definition AccumulationMethods.h:65
void extractField(char field, const AccumulationConverter &converter, Image &dst, const drain::Rectangle< int > &crop) const
Extracts the accumulated quantity or secondary quantities like weight and standard deviation.
Definition Accumulator.cpp:209
Converts ODIM encoded data (with markers) to natural values and backwards.
Definition DataCoder.h:61
Tool for selecting datasets based on paths, quantities and min/max elevations.
Definition DataSelector.h:112
A map of radar data, indexed by quantity code (DBZH, VRAD, etc).
Definition Data.h:1215
Structure for data storage type, scaling and marker codes. Does not contain quantity.
Definition EncodingODIM.h:75
void addShortKeys()
Creates a short alias (attrib) for each (group):(attrib). Example: "gain" => "what:gain".
Definition EncodingODIM.h:290
std::string type
This is non-standard (not in ODIM), but a practical means of handling storage type of datasets.
Definition EncodingODIM.h:152
double getMin() const
Returns the minimum physical value that can be returned using current storage type,...
Definition EncodingODIM.cpp:394
Definition ODIMPath.h:82
ODIM metadata (quantity, gain, offset, undetect, nodata, date, time)
Definition ODIM.h:79
std::string quantity
dataX/what (obligatory)
Definition ODIM.h:181
Essential class for storing radar data.
Definition Data.h:300
Base class providing quality support for Dataand DataSet
Definition Data.h:1034
Definition QuantityMap.h:50
bool setQuantityDefaults(EncodingODIM &dst, const std::string &quantity, const std::string &values="") const
Sets default values of given quantity without assigning the quantity. Optionally overrides with user ...
Definition QuantityMap.cpp:207
bool hasQuantity(const std::string &key) const
Checks if an exact match or a variant, is found.
Definition QuantityMap.h:102
Structure for defining quantity.
Definition Quantity.h:55
double undetectValue
A physical value corresponding a very small (unmeasurable) value has been defined.
Definition Quantity.h:84
bool hasUndetectValue() const
True, if a value corresponding a very small (unmeasurable) value has been defined.
Definition Quantity.h:174
Data array for creating composites and accumulated polar products (Surface rain fall or cluttermaps)
Definition RadarAccumulator.h:61
OD odim
For storing the scaling and encoding of (1st) input or user-defined values. Also for bookkeeping of d...
Definition RadarAccumulator.h:111
void addData(const pdata_src_t &srcData, const pdata_src_t &srcQuality, double weight, int i0, int j0)
Adds data that is in the same coordinate system as the accumulator. Weighted with quality.
Definition RadarAccumulator.h:182
size_t counter
Book-keeping for new data. Finally, in extraction phase, added to odim.ACCnum .
Definition RadarAccumulator.h:120
DataSelector dataSelector
Input data selector.
Definition RadarAccumulator.h:102
void extractOLD(const OD &odimOut, DataSet< DstType< OD > > &dstProduct, const std::string &fields, const drain::Rectangle< int > &crop={0, 0, 0, 0}) const
Definition RadarAccumulator.h:268
RadarAccumulator()
Default constructor.
Definition RadarAccumulator.h:70
void addData(const pdata_src_t &srcData, const pdata_src_t &srcQuality, const pdata_src_t &srcCount)
Adds data that is in the same coordinate system as the accumulator.
Definition RadarAccumulator.h:217
PlainData< SrcType< OD const > > pdata_src_t
Input data type.
Definition RadarAccumulator.h:66
bool checkCompositingMethod(const ODIM &srcODIM) const
Warns if data scaling involves risks in using WAVG (weighted averaging)
Definition RadarAccumulator.h:231
void setTargetEncoding(const std::string &encoding)
Not critical. If set, needed to warn if input data does not match the expected / potential targetEnco...
Definition RadarAccumulator.h:125
double defaultQuality
If source data has no quality field, this value is applied for (detected) data.
Definition RadarAccumulator.h:114
Definition DataSelector.cpp:44
QuantityMap & getQuantityMap()
Definition QuantityMap.cpp:279
Rectange defined through lower left and upper right coordinates.
Definition Rectangle.h:65
bool empty() const
Return true if the area is zero.
Definition Rectangle.h:111
Writable data type.
Definition Data.h:120