RadarAccumulator.h
1 /*
2 
3 MIT License
4 
5 Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24 
25 */
26 /*
27 Part of Rack development has been done in the BALTRAD projects part-financed
28 by the European Union (European Regional Development Fund and European
29 Neighbourhood 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 "data/ODIM.h"
42 #include "data/ODIMPath.h"
43 #include "data/Data.h"
44 #include "data/DataSelector.h"
45 #include "data/DataCoder.h"
46 #include "data/QuantityMap.h"
47 #include "Geometry.h"
48 #include "product/ProductOp.h"
49 
50 
51 namespace rack {
52 
54 
60 template <class AC, class OD>
61 class RadarAccumulator : public AC {
62 
63 public:
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
76  ~RadarAccumulator(){};
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  */
111  OD odim;
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 
174 protected:
175 
176  std::string targetEncoding;
177 
178 };
179 
180 
181 template <class AC, class OD>
182 void 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  if (!srcQuality.data.isEmpty()){
187  mout.info("Quality data available with input; using quality as weights in compositing.");
188  DataCoder converter(srcData.odim, srcQuality.odim);
189  // uses also DataCoder::undetectQualityCoeff
190  AC::addData(srcData.data, srcQuality.data, converter, weight, i0, j0);
191  }
192  else {
193  mout.info("No quality data available with input, ok." );
194  ODIM qualityOdim;
195  getQuantityMap().setQuantityDefaults(qualityOdim, "QIND");
196 
197  DataCoder converter(srcData.odim, qualityOdim);
198  // uses also DataCoder::undetectQualityCoeff
199  AC::addData(srcData.data, converter, weight, i0, j0);
200  }
201 
202  odim.updateLenient(srcData.odim); // Time, date, new
203  counter += std::max(1L, srcData.odim.ACCnum);
204  // odim.ACCnum += std::max(1L, srcData.odim.ACCnum); wrong
205  // odim.ACCnum = counter; // TODO remove counter?
206 
207  //mout.note("after: " , this->odim );
208 
209 }
210 
211 template <class AC, class OD>
212 void RadarAccumulator<AC,OD>::addData(const pdata_src_t & srcData, const pdata_src_t & srcQuality, const pdata_src_t & srcCount){
213 
214  drain::Logger mout(__FILE__, __FUNCTION__);
215  // mout.info("Quality data available with input; using quality as weights in compositing.");
216  DataCoder converter(srcData.odim, srcQuality.odim);
217  AC::addData(srcData.data, srcQuality.data, srcCount.data, converter);
218 
219  odim.updateLenient(srcData.odim); // Time, date, new
220  counter = std::max(1L, srcData.odim.ACCnum); // correct
221  // odim.ACCnum += std::max(1L, srcData.odim.ACCnum); // wrong
222 }
223 
224 
225 template <class AC, class OD>
227 
228  drain::Logger mout(__FILE__, __FUNCTION__);
229 
230  mout.debug("start, quantity=" , dataODIM.quantity );
231 
232  const AccumulationMethod & rule = this->getMethod();
233  if (rule.getName() == "WAVG"){
234 
235  const drain::ReferenceMap & wavgParams = rule.getParameters();
236  const double p = wavgParams.get("p", 1.0);
237  const double p2 = p/2.0;
238  mout.info(rule , ", min=", dataODIM.getMin() );
239 
240  if ((p2 - floor(p2)) == 0.0){
241  mout.info("WAVG with p=" , p , " = 2N, positive pow() results" );
242  const Quantity & q = getQuantityMap().get(dataODIM.quantity);
243  if (q.hasUndetectValue()){
244  const double bias = wavgParams.get("bias", 0.0);
245  if (bias > q.undetectValue){
246  mout.warn("WAVG with p=" , p ," = 2N, undetectValue=" , q.undetectValue , " < bias=", bias );
247  mout.warn("consider adjusting bias(", bias ,") down to quantity (" , dataODIM.quantity , ") zero: " , q.undetectValue );
248  //rule.setParameter("bias", q.undetectValue);
249  return true;
250  }
251  }
252  }
253  }
254 
255  return false;
256 
257 
258 }
259 
260 
261 
262 template <class AC, class OD>
263 void RadarAccumulator<AC,OD>::extractOLD(const OD & odimOut, DataSet<DstType<OD> > & dstProduct,
264  const std::string & fields, const drain::Rectangle<int> & crop) const {
265  // , const drain::Rectangle<double> & bbox) const {
266 
267  drain::Logger mout(__FILE__, __FUNCTION__);
268 
269  const std::type_info & t = drain::Type::getTypeInfo(odimOut.type);
270 
271  typedef enum {DATA,QUALITY} datatype;
272 
273  OD odimData;
274  odimData = odimOut;
275  odimData.scaling.scale = 0.0; // ?
276 
277  const QuantityMap & qm = getQuantityMap();
278 
284  bool DATA_SPECIFIC_QUALITY = false;
285 
286  // Consider redesign, with a map of objects {quantity, type,}
287  for (size_t i = 0; i < fields.length(); ++i) {
288 
289  ODIM odimQuality;
290  odimQuality.quantity = "QIND";
291 
292  // std::stringstream dataPath;
293 
294  datatype type = DATA;
295  char field = fields.at(i);
296  switch (field) {
297  case '/':
298  DATA_SPECIFIC_QUALITY = true;
299  continue;
300  break; // unneeded?
301  case 'm': // ???
302  case 'D':
303  case 'p': // ???
304  mout.warn() << "non-standard layer code; use 'd' for 'data' instead" << mout.endl;
305  // no break
306  case 'd':
307  type = DATA;
308  odimData = odimOut; // consider update
309  qm.setQuantityDefaults(odimQuality, "QIND"); // ?
310  odimQuality.quantity = "QIND";
311  break;
312  case 'c':
313  type = QUALITY;
314  qm.setQuantityDefaults(odimQuality, "COUNT");
315  odimQuality.quantity = "COUNT";
316  break;
317  case 'C':
318  type = QUALITY;
319  qm.setQuantityDefaults(odimQuality, "COUNT", "d");
320  odimQuality.quantity = "COUNT";
321  break;
322  // case 'q': // consider
323  case 'w':
324  // no break
325  type = QUALITY;
326  odimData = odimOut; // (Because converter needs both data and weight to encode weight?)
327  qm.setQuantityDefaults(odimQuality, "QIND", "C");
328  odimQuality.quantity = "QIND";
329  //odimQuality.undetect = 256;
330  //odimQuality.nodata = -1; // this is good, because otherwise nearly-undetectValue-quality CAPPI areas become no-data.
331  break;
332  case 'W':
333  mout.warn("experimental: quality [QIND] type copied from data [" , odimOut.quantity , ']' );
334  // no break
335  type = QUALITY;
336  odimData = odimOut; // (Because converted needs both data and weight to encode weight?)
337  qm.setQuantityDefaults(odimQuality, "QIND", odimOut.type);
338  odimQuality.quantity = "QIND";
339  //odimQuality.undetect = 256;
340  //odimQuality.nodata = -1; // this is good, because otherwise nearly-undetectValue-quality CAPPI areas become no-data.
341  break;
342  case 's':
343  type = QUALITY;
344  odimQuality = odimOut;
345  odimQuality.quantity += "DEV";
346  if (qm.hasQuantity(odimQuality.quantity)){
347  qm.setQuantityDefaults(odimQuality, odimQuality.quantity, odimQuality.type);
348  mout.accept<LOG_NOTICE>("found quantyConf[", odimQuality.quantity, "], type=", odimQuality.type);
349  //mout.special("Quality: ", EncodingODIM(odimQuality));
350  mout.special("Quality: ", EncodingODIM(odimQuality));
351  mout.special("Quality: ", odimQuality);
352  }
353  else {
354  odimQuality.scaling.scale *= 20.0; // ?
355  //const std::type_info & t = Type::getType(odimFinal.type);
356  odimQuality.scaling.offset = round(drain::Type::call<drain::typeMin, double>(t) + drain::Type::call<drain::typeMax, double>(t))/2.0;
357  //odimQuality.offset = round(drain::Type::call<drain::typeMax,double>(t) + drain::Type::getMin<double>(t))/2.0; // same as data!
358  mout.warn("quantyConf[" , odimQuality.quantity , "] not found, using somewhat arbitary scaling:" );
359  mout.special("Quality: ", EncodingODIM(odimQuality));
360  }
361  break;
362  default:
363  mout.error("Unsupported field code: '", field, "'");
364  break;
365  }
366 
367  mout.debug("extracting field ", field);
368 
369  if (!crop.empty()){
370  mout.experimental("Applying cropping: bbox=", crop, " [pix]");
371  }
372 
373  if (type == DATA){
374  mout.debug("target: " , EncodingODIM(odimData) );
375  }
376  else if (type == QUALITY){
377  mout.debug("target: " , EncodingODIM(odimQuality) );
378  }
379 
380  if (odimData.quantity.empty()){
381  odimData.quantity = "UNKNOWN"; // ok; for example --cPlotFile carries no information on quantity
382  mout.note("quantity=", odimData.quantity);
383  }
384 
385  //PlainData<DstType<OD> >
386  mout.debug("searching dstData... DATA=", (type == DATA));
387  //pdata_dst_t & dstData = (type == DATA) ? dstProduct.getData(odimFinal.quantity) : dstProduct.getQualityData(odimQuality.quantity);
388  //mout .debug3() << "dstData: " << dstData << mout.endl;
389 
390  //DataDst dstData(dataGroup); // FIXME "qualityN" instead of dataN creates: /dataset1/qualityN/quality1/data
391  //mout.warn("odimFinal: " , odimFinal );
392  DataCoder dataCoder(odimData, odimQuality); // (will use only either odim!)
393  mout.debug("dataCoder: ", dataCoder);
394  mout.debug2("dataCoder: data: ", dataCoder.dataODIM);
395  mout.debug2("dataCoder: qind: ", dataCoder.qualityODIM);
396 
397  if (!crop.empty()){
398  mout.unimplemented("crop ", crop, ", dstData.data resize + Accumulator::extractField ");
399  }
400 
401  if (type == DATA){
402  mout.debug("DATA/" , field, " [", odimData.quantity, ']');
403  //mout.warn(dstData.odim );
404  pdata_dst_t & dstData = dstProduct.getData(odimData.quantity);
405  dstData.odim.importMap(odimData);
406  dstData.data.setType(odimData.type);
407  mout.debug3("dstData: " , dstData );
408  //mout.debug("quantity=" , dstData.odim.quantity );
409  this->Accumulator::extractField(field, dataCoder, dstData.data, crop);
410  }
411  else {
412  mout.debug("QUALITY/" , field , " [", odimQuality.quantity, ']');
413  //pdata_dst_t & dstData = dstProduct.getData(odimFinal.quantity);
414  typedef QualityDataSupport<DstType<OD> > q_data_t;
415  q_data_t & qualityOwner = (DATA_SPECIFIC_QUALITY) ? (q_data_t &) dstProduct.getData(odimData.quantity) : (q_data_t &) dstProduct;
416  pdata_dst_t & dstData = qualityOwner.getQualityData(odimQuality.quantity);
417  dstData.odim.updateFromMap(odimQuality);
418  mout.debug3("dstData: " , dstData );
419  this->Accumulator::extractField(field, dataCoder, dstData.data, crop);
420  }
421 
422 
423  // mout.debug("updating local tree attributes");
424 
425  }
426 
427 
428  // mout.debug("updating local tree attributes" );
429  // mout.debug("finished" );
430 
431 }
432 
433 
434 } // rack::
435 
436 
437 #endif /* RADAR_ACCUMULATOR */
438 
439 // Rack
virtual const std::string & getName() const
Return the name of an instance.
Definition: BeanLike.h:69
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition: Log.h:308
Logger & error(const TT &... args)
Echoes.
Definition: Log.h:412
Logger & accept(const TT &... args)
Some input has been accepted, for example by a syntax.
Definition: Log.h:578
Logger & special(const TT &... args)
Other useful information.
Definition: Log.h:527
Logger & unimplemented(const TT &... args)
Feature to be done. Special type of Logger::note().
Definition: Log.h:507
Logger & note(const TT &... args)
For top-level information.
Definition: Log.h:485
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition: Log.h:426
Logger & debug(const TT &... args)
Public, yet typically used "internally", when TIMING=true.
Definition: Log.h:676
Logger & debug2(const TT &... args)
Debug information.
Definition: Log.h:686
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:64
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:1213
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:286
std::string type
This is non-standard (not in ODIM), but a practical means of handling storage type of datasets.
Definition: EncodingODIM.h:146
double getMin() const
Returns the minimum physical value that can be returned using current storage type,...
Definition: EncodingODIM.cpp:375
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:302
Base class providing quality support for Dataand DataSet
Definition: Data.h:1032
Definition: QuantityMap.h:50
bool setQuantityDefaults(EncodingODIM &dst, const std::string &quantity, const std::string &values="") const
Sets default values of given quantity - but not the quantity itself. Optionally overrides with user v...
Definition: QuantityMap.cpp:398
Structure for defining.
Definition: Quantity.h:53
double undetectValue
A physical value corresponding a very small (unmeasurable) value has been defined.
Definition: Quantity.h:71
bool hasUndetectValue() const
True, if a value corresponding a very small (unmeasurable) value has been defined.
Definition: Quantity.h:140
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:263
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:212
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:226
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
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:122