VolumeOp.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  * ProductOp.h
33  *
34  * Created on: Mar 7, 2011
35  * Author: mpeura
36  */
37 
38 #ifndef RACKOP_H_
39 #define RACKOP_H_
40 
41 
42 //#include "drain/util/DataScaling.h"
43 //#include "drain/util/StringMapper.h"
44 //#include "drain/util/Variable.h"
45 //#include "drain/util/TreeOrdered.h"
46 #include "drain/util/ReferenceMap.h"
47 
48 
49 
50 //#include "main/rack.h"
51 #include "hi5/Hi5.h"
52 #include "data/DataSelector.h"
53 #include "data/Data.h"
54 #include "data/ODIM.h"
55 #include "data/ODIMPathTools.h"
56 #include "data/Quantity.h" // NEW
57 
58 #include "hi5/Hi5Write.h" // debugging
59 
60 
61 #include "ProductOp.h" // NEW
62 
63 namespace rack {
64 
65 using namespace drain::image;
66 
68 
70 
86 // TODO: generalize for Cart
87 template <class M>
88 class VolumeOp : public ProductOp<const PolarODIM, M> {
89 
90 public:
91 
92  VolumeOp(const std::string & name, const std::string &description="") : ProductOp<const PolarODIM, M>(name, description){
93  };
94 
95  virtual inline
96  ~VolumeOp(){};
97 
98 
100 
105  virtual
106  void processVolume(const Hi5Tree &src, Hi5Tree &dst) const;
107 
108 
109 
110 protected:
111 
112 
113 
114 };
115 
116 
117 
118 
119 template <class M>
120 void VolumeOp<M>::processVolume(const Hi5Tree &src, Hi5Tree &dst) const {
121 
122  drain::Logger mout(__FILE__, __FUNCTION__);
123 
124  mout.debug("start" );
125  mout.debug3(*this );
126  mout.debug2("DataSelector: " , this->dataSelector );
127 
128  // Step 1: collect sweeps (/datasetN/)
129  //DataSetMap<PolarSrc> sweeps;
130  DataSetMap<PolarSrc> sweeps;
131 
133  mout.debug3("collect the applicable paths" );
134  ODIMPathList dataPaths; // Down to ../dataN/ level, eg. /dataset5/data4
135  //this->dataSelector.getPaths(src, dataPaths, ODIMPathElem::DATASET); // RE2
136 
137 
138  this->dataSelector.getPaths(src, dataPaths);
139 
140 
141  if (dataPaths.empty()){
142  mout.warn("no dataset's selected" );
143  }
144  else {
145  mout.debug3("populate the dataset map, paths=" , dataPaths.size() );
146  }
147 
148  for (ODIMPath & path: dataPaths){
149 
150  if (!path.front().is(ODIMPathElem::DATASET)){
151  path.pop_front();
152  if (path.empty()){
153  mout.warn("odd 1st path elem (..), with selector: ", this->dataSelector);
154  continue;
155  }
156  }
157 
158  const ODIMPathElem & parent = path.front();
159 
160  if (!parent.is(ODIMPathElem::DATASET)){
161  mout.warn("path does not start with /dataset.. :", path, ", with selector: ", this->dataSelector);
162  continue;
163  }
164 
165  // mout.debug3("elangles (this far> " , elangles );
166  const Hi5Tree & srcDataSet = src(parent);
167 
168  // const double elangle = srcDataSet[ODIMPathElem::WHERE].data.attributes["elangle"]; // PATH
169  // mout.deprecating("no more testing ", parent, ", elangle=", elangle, ':', srcDataSet.data.dataSet);
170 
171  const drain::VariableMap & what = srcDataSet[ODIMPathElem::WHAT].data.attributes;
172  std::string datetime = what["startdate"].toStr() + what["starttime"].toStr();
173 
174  if (sweeps.find(datetime) == sweeps.end()){
175  mout.debug2("adding time=", datetime, ':', parent);
176  // Consider removing RegExp form datasets?
177  //sweeps.insert(DataSetMap<PolarSrc>::value_type(datetime, DataSet<PolarSrc>(srcDataSet, drain::RegExp(this->dataSelector.getQuantity()))));
178  sweeps.insert(DataSetMap<PolarSrc>::value_type(datetime, DataSet<PolarSrc>(srcDataSet, this->dataSelector.getQuantitySelector())));
179  }
180  else {
181  mout.warn("datetime =", datetime, " already added?, skipping ", parent);
182  }
183 
184  /*
185  if (sweeps.find(elangle) == sweeps.end()){
186  mout.debug3("add " , elangle , ':' , parent , " quantity RegExp:" , this->dataSelector.quantity );
187  sweeps.insert(DataSetMap<PolarSrc>::value_type(elangle, DataSet<PolarSrc>(srcDataSet, drain::RegExp(this->dataSelector.quantity) ))); // Something like: sweeps[elangle] = src[parent] .
188  // elangles << elangle;
189  //mout.warn("add " , DataSet<PolarSrc>(src(parent), drain::RegExp(this->dataSelector.quantity) ) );
190  }
191  else {
192  mout.note("elange =" , elangle , " already added, skipping " , parent );
193  }
194  */
195  }
196 
197  //mout.note("first elange =" , sweeps.begin()->first , " DS =" , sweeps.begin()->second );
198  //mout.note("first qty =" , sweeps.begin()->second.begin()->first , " D =" , sweeps.begin()->second.getFirstData() );
199 
200 
201  ODIMPathElem dataSetPath(ODIMPathElem::DATASET, 1);
202  //if (!DataTools::getNextDescendant(dst, ProductBase::appendResults.getType(), dataSetPath))
203 
205  if (ProductBase::appendResults.getIndex()){
206  dataSetPath.index = ProductBase::appendResults.getIndex();
207  }
208  else {
209  ODIMPathTools::getNextChild(dst, dataSetPath);
210  }
211  }
213  //mout.info("appending to next available data group in " , dataSetPath );
214  }
216  if (!dst.empty() && (&src != &dst)){ // latter is ANDRE test... (kludge)
217  mout.info("clearing previous result, use --append [data|dataset] to avoid");
218  dst.clear();
219  }
220  }
221  else {
222  dataSetPath = ProductBase::appendResults;
223  mout.warn("non-standard path location '", dataSetPath, "', consider --help append ");
224  }
225  //++dataSetPath.index;
226 
227  //mout.warn("FAILED: " , dataSetPath );
228  //dataSetPath.push_back(ODIMPathElem(ODIMPathElem::DATASET, 1));
229 
230  mout.debug("storing product in path: ", dataSetPath);
231 
232  //Hi5Tree & dstProduct = dst[dataSetPath];
233 
234  /* /// WARNING: Root odim has to be modified explicitly, otherwise remains empty.
235  RootData<DstType<M> > root(dst);
236  drain::VariableMap & whatRoot = root.getWhat();
237  whatRoot["object"] = this->odim.object;
238  whatRoot["version"] = this->odim.version;
239  */
240 
241  DataSet<DstType<M> > dstProductDataset(dst[dataSetPath]); // PATH
242 
243  // Copy metadata from the input volume (note that dst may have been cleared above)
244  //dstProductDataset.getWhat();
245  //RootData<DstType<M> > root(dst);
246  //drain::VariableMap & rootWhat = root.getWhat();
247  drain::VariableMap & rootWhat = dst[ODIMPathElem::WHAT].data.attributes; // dstProduct["what"].data.attributes;
248  rootWhat = src[ODIMPathElem::WHAT].data.attributes;
249  rootWhat["object"] = this->odim.object; // ?
250  rootWhat["version"] = this->odim.version;
251 
252  // drain::VariableMap & where = dstProductDataset.getWhere(); // dstProduct["what"].data.attributes;
253  // drain::VariableMap & rootWhere = dst[ODIMPathElem::WHERE].data.attributes;
254  drain::VariableMap & rootWhere = dst[ODIMPathElem::WHERE].data.attributes; //root.getWhere();
255  //where["init0"] = {0.1, 2.2};
256  rootWhere = src[ODIMPathElem::WHERE].data.attributes;
257  //mout.warn(where );
258  //rootWhere.importCastableMap(src[ODIMPathElem::WHERE].data.attributes);
259  //where.importMap(src[ODIMPathElem::WHERE].data.attributes);
260  //where.importCastableMap(src[ODIMPathElem::WHERE].data.attributes);
261  //where = src[ODIMPathElem::WHERE].data.attributes;
262  mout.debug2("src /where/ : ", src[ODIMPathElem::WHERE].data.attributes);
263  mout.debug2("dst /where/ : ", rootWhere);
264 
265  drain::VariableMap & how = dstProductDataset.getHow(); //dstProduct["how"].data.attributes;
266  how = src[ODIMPathElem::HOW].data.attributes;
267  ProductBase::setRackVersion(how);
268 
269  // how["elangles"] = elangles; // This service could be lower in hierarchy (but for PseudoRHI and pCappi ok here)
270  // how["anglesV"] = elangles; // NEW 2021
271 
272 
273  // odim.copyToRoot(dst); NO! Mainly overwrites original data. fgrep 'declare(rootAttribute' odim/*.cpp
274 
276  this->computeSingleProduct(sweeps, dstProductDataset);
277  // this->processSweeps(sweeps, dstProductDataset);
278 
279  // mout.warn("MAIN eka: " , drain::sprinter(dstProductDataset.getFirstData().odim) );
280 
281  if (!dstProductDataset.empty()){
283  how["angles"] = dstProductDataset.getFirstData().odim.angles;
284  //how["anglesXX"] = dstProductDataset.getFirstData().odim.angles;
285  }
286  //mout.warn("MAIN toka:" , drain::sprinter(dstProductDataset.getFirstData().odim) );
287  //mout.warn("how how", how);
288  // mout.experimental("dst2", rootWhere);
289  // hi5::Writer::writeFile("test0.h5", dst);
290 
291  //}
292 
293  //hi5::Writer::writeFile("test0b.h5", dst);
294 
295 
296 }
297 
298 
299 } // namespace rack
300 
301 
302 #endif
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition: Log.h:308
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: Path.h:112
A map of Variables.
Definition: VariableMap.h:61
Computes dot product of intensities of two images.
Definition: PixelVectorOp.h:364
Definition: Data.h:1368
A map of radar data, indexed by quantity code (DBZH, VRAD, etc).
Definition: Data.h:1213
Definition: ODIMPath.h:82
static const group_t WHAT
Metadata group /what , at any depth.
Definition: ODIMPath.h:124
static const group_t DATASET
First level group, /dataset + digit .
Definition: ODIMPath.h:103
bool is(group_t g) const
Abbreviation of (group == NONE)
Definition: ODIMPath.h:291
static const group_t ROOT
Definition: ODIMPath.h:99
static const group_t HOW
Metadata group /how , at any depth.
Definition: ODIMPath.h:130
static const group_t DATA
Second level group, /data + digit .
Definition: ODIMPath.h:106
static const group_t WHERE
Metadata group /where , at any depth.
Definition: ODIMPath.h:127
static bool getNextChild(const Hi5Tree &tree, ODIMPathElem &child)
Derive a child with index one greater than the largest index encountered.
Definition: ODIMPathTools.cpp:96
ODIMPathElem appendResults
If set, appends outputs in an hdf5 structure instead of overwriting.
Definition: ProductConf.h:92
Base class for radar data processors.
Definition: VolumeOp.h:88
virtual void processVolume(const Hi5Tree &src, Hi5Tree &dst) const
Traverse through given volume and create new, processed data (volume or polar product).
Definition: VolumeOp.h:120
Namespace for images and image processing tools.
Definition: AccumulationArray.cpp:45
Definition: DataSelector.cpp:44