DopplerWindowOp.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 
32 
33 #ifndef DOPPLER_WIN_OP_H_
34 #define DOPPLER_WIN_OP_H_
35 
36 //#include "PolarSlidingWindowOp.h"
37 
38 #include <drain/Log.h>
39 #include <drain/Type.h>
40 #include <drain/TypeUtils.h>
41 #include "data/Data.h"
42 #include "data/DataSelector.h"
43 #include "data/PolarODIM.h"
44 #include "data/QuantityMap.h"
45 //#include "drain/imageops/SlidingWindowHistogramOp.h"
46 //#include "drain/imageops/SlidingWindowOp.h"
47 //#include "drain/util/Fuzzy.h"
48 //#include "drain/util/LookUp.h"
49 #include "drain/image/Geometry.h"
50 #include "drain/image/Image.h"
51 #include "drain/image/ImageChannel.h"
52 #include "drain/image/Window.h"
53 #include "drain/imageops/SlidingWindowOp.h"
54 #include "product/ProductOp.h"
55 #include "radar/Doppler.h"
56 #include "drain/util/Fuzzy.h"
57 #include "drain/util/SmartMap.h"
58 #include "DopplerOp.h"
59 //#include <cmath>
60 #include <string>
61 
62 
63 namespace rack {
64 
65 
66 
68 
71 template <class W>
72 class DopplerWindowOp : public DopplerOp {
73 
74 public:
75 
76 
77  typename W::conf_t conf;
78 
79 
80 
81 
82  virtual ~DopplerWindowOp(){};
83 
84 
85  // Outputs uField and vField both, so dst dataSET needed
86  virtual
87  void processDataSet(const DataSet<PolarSrc> & srcSweep, DataSet<PolarDst> & dstProduct) const ;
88  // virtual void processImage(const PolarODIM & odim, const Image &src, Image &dst) const;
89 
90  virtual
91  void processData(const Data<PolarSrc> & vradSrc, Data<PolarDst> & dstData) const;
92 
93 protected:
94 
99  DopplerWindowOp(const std::string & name, const std::string & description, int widthM, double heightD) :
100  DopplerOp(name, description), conf() { //, threshold(0.5), compensatePolar(true), relativeScale(relativeScale) {
101 
102  parameters.link("width", this->conf.widthM = widthM, "metres");
103  parameters.link("height", this->conf.heightD = heightD, "deg");
104  //parameters.append(conf, false); // TODO: Window::conf parameters ?
105  parameters.link("threshold", this->conf.contributionThreshold = 0.5, "percentage");
106  parameters.link("compensate", this->conf.invertPolar = false, "cart/polar[0|1]");
107  //parameters.link("relativeScale", this->conf.relativeScale = false, "0|1");
108 
109 
110  dataSelector.setMaxCount(1);
111  allowedEncoding.clear();
112  allowedEncoding.link("type", odim.type);
113  allowedEncoding.link("gain", odim.scaling.scale);
114 
115  };
116 
117  virtual
118  void setEncoding(const ODIM & inputODIM, PlainData<PolarDst> & dst) const;
119 
120 
121  virtual
122  double getTypicalMin(const PolarODIM & srcODIM) const = 0;
123 
124  virtual
125  double getTypicalMax(const PolarODIM & srcODIM) const = 0;
126 
128  /*
129  void setPixelConf(typename W::conf_t & pixelConf, const PolarODIM & inputODIM) const {
130  this->conf.setPixelConf(pixelConf, inputODIM);
131  }
132  */
133 
134 };
135 
136 
137 
138 template <class W>
139 void DopplerWindowOp<W>::setEncoding(const ODIM & inputODIM, PlainData<PolarDst> & dst) const {
140 
141  drain::Logger mout(__FILE__, __FUNCTION__);
142 
143  dst.odim.quantity = odim.quantity;
144 
145  drain::ReferenceMap typeRef;
146  typeRef.link("type", dst.odim.type = odim.type);
147  typeRef.updateValues(targetEncoding);
148  dst.data.setType(dst.odim.type);
149 
150  if (odim.scaling.scale != 0.0){ // NOTE: now dst.odim.scaling.scale at least default (1.0)
151  mout.warn("Init with ODIM: " , EncodingODIM(odim) );
152  //ProductOp::
153  applyODIM(dst.odim, odim);
154  }
155  else {
156  // const double max = (this->conf.relativeScale) ? 1.0 : inputODIM.NI;
157  if (drain::Type::call<drain::typeIsSmallInt>(dst.data.getType())){
158  dst.setPhysicalRange(getTypicalMin(inputODIM), getTypicalMax(inputODIM));
159  //mout.note(EncodingODIM(inputODIM) );
160  mout.debug("small int: " , EncodingODIM(dst.odim) );
161  mout.debug2("small int: " , dst.data );
162  // dstData.data.setScaling(dstData.odim.scaling.scale, dstData.odim.scaling.offset);
163  }
164  else {
165  if (drain::Type::call<drain::typeIsInteger>(dst.data.getType()))
166  mout.warn("large int" );
167  }
168  dst.odim.distinguishNodata(); // change undetect
169  }
170 
171  //ProductBase::applyODIM(dst.odim, inputODIM, true); // New. Use defaults if still unset
172  ProductBase::completeEncoding(dst.odim, targetEncoding);
173 
174  dst.data.setScaling(dst.odim.scaling); // needed?
175  //dst.data.setScaling(dst.odim.scaling.scale, dst.odim.scaling.offset);
176  mout.debug("final dst: " , dst.data );
177 }
178 
179 
180 template <class W>
181 void DopplerWindowOp<W>::processDataSet(const DataSet<PolarSrc> & srcSweep, DataSet<PolarDst> & dstProduct) const {
182 
183  drain::Logger mout(__FILE__, __FUNCTION__);
184 
185  //const drain::RegExp quantityRe(dataSelector.getQuantity()); // "VRADH?";
186 
187  const Data<PolarSrc> & vradSrc = srcSweep.getData(dataSelector.getQuantitySelector()); // (quantityRe); // consider data selector?
188 
189  if (vradSrc.data.isEmpty()){
190  mout.warn("VRAD missing" );
191  return;
192  }
193 
194  if (vradSrc.odim.getNyquist() == 0) {
195  mout.warn("VRAD unusable, vradSrc.odim.getNyquist() == 0" );
196  return;
197  }
198 
199  Data<PolarDst> & dstData = dstProduct.getData(odim.quantity); // quality data?
200 
201  dstData.odim.updateLenient(vradSrc.odim);
202  //dstData.odim.NI = vradSrc.odim.NI;
203  initDst(vradSrc.odim, dstData);
204 
205  dstData.data.fill(dstData.odim.undetect); // NEW 2019/11
206 
207  processData(vradSrc, dstData);
208  //mout.warn("after:" , dstData.data.getScaling() );
209 
210 
211  //@ dstProduct.updateTree(dstData.odim);
212 
213 
214 }
215 
216 /*
217 template <class W>
218 void DopplerWindowOp<W>::setPixelConf(typename W::conf_t & pixelConf, const PolarODIM & inputODIM) const {
219 
220  drain::Logger mout(__FILE__, __FUNCTION__);
221 
222  // pixelConf = this->conf; PROBLEM: ftor prevents op=
223  pixelConf.widthM = this->conf.widthM;
224  pixelConf.heightD = this->conf.heightD;
225  pixelConf.updatePixelSize(inputODIM);
226  pixelConf.invertPolar = this->conf.invertPolar;
227  pixelConf.contributionThreshold = this->conf.contributionThreshold;
228  pixelConf.relativeScale = this->conf.relativeScale;
229 
230  if (pixelConf.frame.width == 0){
231  mout.note(this->conf.frame.width );
232  mout.note(this->conf.widthM );
233  mout.note(*this );
234  mout.warn("Requested width (" , pixelConf.widthM , " meters) smaller than rscale (", inputODIM.rscale ,"), setting window width=1 " );
235  pixelConf.frame.width = 1;
236  }
237 
238  if (pixelConf.frame.height == 0){
239  mout.warn("Requested height (" , pixelConf.heightD , " degrees) smaller than 360/nrays (", (360.0/inputODIM.geometry.height) ,"), setting window height=1 " );
240  pixelConf.frame.height = 1;
241  }
242 
243 }
244 */
245 
246 // NOTE: window.write() may skip ftor! ?
247 template <class W>
248 void DopplerWindowOp<W>::processData(const Data<PolarSrc> & vradSrc, Data<PolarDst> & dstData) const {
249 
250  drain::Logger mout(__FILE__, __FUNCTION__);
251 
252  //DopplerDevWindow w;
253  //w.initialize();
254 
255  typename W::conf_t pixelConf;
256  this->conf.setPixelConf(pixelConf, vradSrc.odim);
257  //setPixelConf(pixelConf, vradSrc.odim);
258 
259  SlidingWindowOp<W> op(pixelConf);
260  mout.debug(op );
261  mout.special("provided functor: " , op.conf.getFunctorName() , '|' , op.conf.functorParameters );
262  mout.debug("pixelConf.contributionThreshold " , pixelConf.contributionThreshold );
263  mout.debug("op.conf.contributionThreshold " , op.conf.contributionThreshold );
264  //dstData.data.setGeometry(vradSrc.data.getGeometry()); // setDst() handles
265  //op.process(vradSrc.data, dstData.data);
266  //op.traverseChannel(vradSrc.data.getChannel(0), dstData.data.getChannel(0));
267  op.traverseChannel(vradSrc.data, dstData.data);
268 
269  dstData.odim.prodpar = this->parameters.getValues();
270  //@~ dstData.updateTree();
271 
272 }
273 
275 /*
276 class DopplerAvgOp : public DopplerWindowOp<DopplerAverageWindow> {
277 public:
278 
279  **
280  * \param width - radial extent of window, in metres
281  * \param height - azimuthal extent of window, in degrees
282  *
283  DopplerAvgOp(int width = 1500, double height = 3.0) :
284  DopplerWindowOp<DopplerAverageWindow>(__FUNCTION__, "Smoothens Doppler field", width, height) {
285  parameters.link("relativeScale", this->conf.relativeScale = false, "0|1");
286  odim.quantity = "VRAD"; // VRAD_C (corrected)?
287  };
288 
289  virtual ~DopplerAvgOp(){};
290 
291 protected:
292 
293  virtual inline
294  double getTypicalMin(const PolarODIM & srcODIM) const {
295  return (this->conf.relativeScale) ? -1.0 : -srcODIM.getNyquist();
296  }
297 
298  virtual inline
299  double getTypicalMax(const PolarODIM & srcODIM) const {
300  return (this->conf.relativeScale) ? +1.0 : +srcODIM.getNyquist();
301  }
302 
303 };
304 */
305 
306 class DopplerAvgOp : public DopplerWindowOp<DopplerAverageWindow2> {
307 public:
308 
313  DopplerAvgOp(int width = 1500, double height = 3.0) :
314  DopplerWindowOp<DopplerAverageWindow2>(__FUNCTION__, "Smoothens Doppler field, providing quality", width, height) {
315  parameters.link("relativeScale", this->conf.relativeScale = false, "false|true");
316  odim.quantity = "VRAD"; // VRAD_C (corrected)?
317  };
318 
319  virtual ~DopplerAvgOp(){};
320 
321  virtual inline
322  void processData(const Data<PolarSrc> & vradSrc, Data<PolarDst> & dstData) const {
323 
324  drain::Logger mout(__FILE__, __FUNCTION__);
325  drain::FuzzyBell2<double> deviationQuality(1.0, 0.125); // 50m/s
326  DopplerAverageWindow2::conf_t pixelConf(deviationQuality);
327  // setPixelConf(pixelConf, vradSrc.odim);
328  this->conf.setPixelConf(pixelConf, vradSrc.odim);
329 
330  mout.debug("radarConf: " , this->conf.widthM , 'x' , this->conf.heightD );
331  mout.debug("pixelConf: " , pixelConf.frame.width , 'x' , this->conf.frame.height );
332 
334  mout.debug(op );
335  mout.warn(op );
336  mout.special("provided functor: " , op.conf.getFunctorName() , '|' , op.conf.functorParameters );
337  //mout.debug("provided functor: " , op.conf.ftor );
338 
339  const drain::image::Geometry & g = vradSrc.data.getGeometry();
340 
341  drain::image::Image dummy(g.getWidth(), g.getHeight());
342 
343  PlainData<PolarDst> & dstQuality = dstData.getQualityData("QIND");
344  getQuantityMap().setQuantityDefaults(dstQuality, "QIND");
345  dstQuality.setGeometry(g.getWidth(), g.getHeight());
346 
347  op.traverseChannel(vradSrc.data, dummy, dstData.data, dstQuality.data);
348 
349  dstData.odim.prodpar = this->parameters.getValues();
350  }
351 
352 protected:
353 
354  virtual inline
355  double getTypicalMin(const PolarODIM & srcODIM) const {
356  return (this->conf.relativeScale) ? -1.0 : -srcODIM.getNyquist();
357  }
358 
359  virtual inline
360  double getTypicalMax(const PolarODIM & srcODIM) const {
361  return (this->conf.relativeScale) ? +1.0 : +srcODIM.getNyquist();
362  }
363 
364 };
365 
366 
367 
368 class DopplerEccentricityOp : public DopplerWindowOp<DopplerEccentricityWindow> {
369 public:
370 
375  DopplerEccentricityOp(int widthM = 1500, double heightD = 3.0) :
376  DopplerWindowOp<DopplerEccentricityWindow>(__FUNCTION__, "Magnitude of mean unit circle mapped Doppler speeds", widthM, heightD) {
377 
378  //parameters.link("relativeScale", this->conf.relativeScale = true, "true|false");
379 
380  //this->conf.relativeScale = true;
381  odim.quantity = "VRAD_DEV"; // VRAD_C ?
382  odim.scaling.scale = 1.0/200.0;
383  odim.scaling.offset = -odim.scaling.scale;
384  //odim.scaling.scale = 1.0/200.0;
385  odim.type = "C";
386  odim.nodata = 255; // TODO
387  };
388 
389  virtual ~DopplerEccentricityOp(){};
390 
391 protected:
392 
393  virtual inline
394  double getTypicalMin(const PolarODIM & srcODIM) const {
395  return 0.0;
396  }
397 
398  virtual inline
399  double getTypicalMax(const PolarODIM & srcODIM) const {
400  return +1.0;
401  //return (this->conf.relativeScale) ? +1.0 : +srcODIM.getNyquist();
402  }
403 
404 
405 };
406 
407 
408 
409 
410 }
411 
412 
413 #endif /* DOPPLERDevOP_H_ */
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition: Log.h:308
Definition: ReferenceMap.h:207
void getValues(std::ostream &ostr) const
Dumps the values.
Definition: SmartMap.h:353
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
Definition: Geometry.h:145
Class for multi-channel digital images. Supports dynamic typing with base types (char,...
Definition: Image.h:184
Template for operators applying pipeline-like sliding window.
Definition: SlidingWindowOp.h:59
A map of radar data, indexed by quantity code (DBZH, VRAD, etc).
Definition: Data.h:1213
Data structure consisting of plain data and an optional quality data.
Definition: Data.h:1144
Smoothens Doppler field, providing quality computed as eccentricity.
Definition: Doppler.h:238
Simple op not producing quality field.
Definition: DopplerWindowOp.h:306
DopplerAvgOp(int width=1500, double height=3.0)
Definition: DopplerWindowOp.h:313
Definition: DopplerWindowOp.h:368
DopplerEccentricityOp(int widthM=1500, double heightD=3.0)
Definition: DopplerWindowOp.h:375
Computes eccentrity of Doppler speeds mapped on a Nyquist-normalized unit window.
Definition: Doppler.h:322
Base class for computing products using Doppler speed [VRAD] data.
Definition: DopplerOp.h:49
Base class for Doppler average and variance.
Definition: DopplerWindowOp.h:72
DopplerWindowOp(const std::string &name, const std::string &description, int widthM, double heightD)
Definition: DopplerWindowOp.h:99
ODIM metadata (quantity, gain, offset, undetect, nodata, date, time)
Definition: ODIM.h:79
Essential class for storing radar data.
Definition: Data.h:302
Metadata structure for single-radar data (polar scans, volumes and products).
Definition: PolarODIM.h:45
static void completeEncoding(ODIM &productODIM, const std::string &targetEncoding)
Modifies encoding. If type is changed, resets scaling first.
Definition: ProductBase.cpp:183
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
Definition: DataSelector.cpp:44