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 
107  virtual
108  Hi5Tree & processVolume(const Hi5Tree &src, Hi5Tree &dst) const final;
109 
110 
111 
112 protected:
113 
114 
115 
116 };
117 
118 
119 
120 template <class M>
121 Hi5Tree & VolumeOp<M>::processVolume(const Hi5Tree &src, Hi5Tree &dst) const{
122 
123  drain::Logger mout(__FILE__, __FUNCTION__);
124 
125  mout.debug("start" );
126  mout.debug3(*this );
127  mout.debug2("DataSelector: " , this->dataSelector );
128 
129  // Step 1: collect sweeps (/datasetN/)
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  this->dataSelector.getPaths(src, dataPaths);
138 
139  if (dataPaths.empty()){
140  mout.warn("no dataset's selected" );
141  }
142  else {
143  mout.debug3("populate the dataset map, paths=" , dataPaths.size() );
144  }
145 
146  ODIM extraInfo;
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 
172  ODIM odd(srcDataSet.data.image);
173  // TODO: elangles here!
174  //const drain::VariableMap & what = srcDataSet[ODIMPathElem::WHAT].data.attributes;
175  //std::string datetime = what["startdate"].toStr() + what["starttime"].toStr();
176  std::string datetime = odd.startdate + odd.starttime;
177 
178  extraInfo.updateLenient(odd);
179  mout.attention<LOG_DEBUG>(extraInfo.startdate, '+', extraInfo.starttime, " ?== ", datetime, " < ", extraInfo.enddate, '+', extraInfo.endtime);
180 
181  if (sweeps.find(datetime) == sweeps.end()){
182  mout.debug2("adding time=", datetime, ':', parent);
183  // Consider removing RegExp form datasets?
184  //sweeps.insert(DataSetMap<PolarSrc>::value_type(datetime, DataSet<PolarSrc>(srcDataSet, drain::RegExp(this->dataSelector.getQuantity()))));
185  sweeps.insert(DataSetMap<PolarSrc>::value_type(datetime, DataSet<PolarSrc>(srcDataSet, this->dataSelector.getQuantitySelector())));
186  }
187  else {
188  // mout.warn("datetime =", datetime, " already added?, skipping ", parent);
189  }
190 
191  /*
192  if (sweeps.find(elangle) == sweeps.end()){
193  mout.debug3("add " , elangle , ':' , parent , " quantity RegExp:" , this->dataSelector.quantity );
194  sweeps.insert(DataSetMap<PolarSrc>::value_type(elangle, DataSet<PolarSrc>(srcDataSet, drain::RegExp(this->dataSelector.quantity) ))); // Something like: sweeps[elangle] = src[parent] .
195  // elangles << elangle;
196  //mout.warn("add " , DataSet<PolarSrc>(src(parent), drain::RegExp(this->dataSelector.quantity) ) );
197  }
198  else {
199  mout.note("elange =" , elangle , " already added, skipping " , parent );
200  }
201  */
202  }
203 
204  //mout.note("first elange =" , sweeps.begin()->first , " DS =" , sweeps.begin()->second );
205  //mout.note("first qty =" , sweeps.begin()->second.begin()->first , " D =" , sweeps.begin()->second.getFirstData() );
206 
207 
208  ODIMPathElem dataSetPath(ODIMPathElem::DATASET); // ,1) // 2024/11
209  //if (!DataTools::getNextDescendant(dst, ProductBase::appendResults.getType(), dataSetPath))
210 
212  if (ProductBase::appendResults.getIndex()){
213  dataSetPath.index = ProductBase::appendResults.getIndex();
214  }
215  else {
216  ODIMPathTools::getNextChild(dst, dataSetPath);
217  }
218  }
220  //mout.info("appending to next available data group in " , dataSetPath ); // ALWAYS dataset1, then ?
221  }
223  if (!dst.empty() && (&src != &dst)){ // latter is ANDRE test... (kludge)
224  mout.info("clearing previous result, use --append [data|dataset] to avoid");
225  dst.clear();
226  }
227  }
228  else {
229  dataSetPath = ProductBase::appendResults;
230  mout.warn("non-standard path location '", dataSetPath, "', consider --help append ");
231  }
232  //++dataSetPath.index;
233 
234  //mout.warn("FAILED: " , dataSetPath );
235  //dataSetPath.push_back(ODIMPathElem(ODIMPathElem::DATASET, 1));
236 
237  mout.debug("storing product in path: ", dataSetPath);
238 
239  //Hi5Tree & dstProduct = dst[dataSetPath];
240  /* /// WARNING: Root odim has to be modified explicitly, otherwise remains empty.
241  RootData<DstType<M> > root(dst);
242  drain::VariableMap & whatRoot = root.getWhat();
243  whatRoot["object"] = this->odim.object;
244  whatRoot["version"] = this->odim.version;
245  */
246 
247 
249  Hi5Tree & dstDataSet = dst[dataSetPath];
250  {
251  DataSet<DstType<M> > dstProductDataset(dstDataSet); // PATH
252  this->computeSingleProduct(sweeps, dstProductDataset);
253 
254  drain::VariableMap & how = dstProductDataset.getHow();
255  ProductBase::setRackVersion(how);
256  if (!dstProductDataset.empty()){
258  how["angles"] = dstProductDataset.getFirstData().odim.angles; // FIX: this may be some tmp data, not main [odim.quantity]
259  }
260  }
261 
262  // Copy metadata from the input volume (note that dst may have been cleared above)
263 
264  mout.revised("check DataSet metadata");
265 
266  // Root level
268  dst[group].data.attributes = src[group].data.attributes;
269  }
270  drain::VariableMap & rootWhat = dst[ODIMPathElem::WHAT].data.attributes; // dstProduct["what"].data.attributes;
272  rootWhat["object"] = this->odim.object; // ?
273  rootWhat["version"] = this->odim.version;
274 
275  dstDataSet[ODIMPathElem::WHAT].data.attributes["product"] = this->odim.product;
276  dstDataSet[ODIMPathElem::WHAT].data.attributes["product2"] = extraInfo.product;
277 
278  dstDataSet[ODIMPathElem::WHAT].data.attributes["startdate"] = extraInfo.startdate;
279  dstDataSet[ODIMPathElem::WHAT].data.attributes["starttime"] = extraInfo.starttime;
280  dstDataSet[ODIMPathElem::WHAT].data.attributes["enddate"] = extraInfo.enddate;
281  dstDataSet[ODIMPathElem::WHAT].data.attributes["endtime"] = extraInfo.endtime;
282 
283  // PRODPAR ... complicated! Fix at Sprinter level, getKeyList()
284  if (ODIM::versionFlagger.isSet(ODIM::RACK_EXTENSIONS)){
285  // keep scope, even if condition removed
286  std::stringstream sstr;
287  char sep = 0;
288  const drain::ReferenceMap & params = this->getParameters();
289  for (const std::string & key: params.getKeyList()){
290  if (sep){
291  sstr << sep;
292  }
293  else {
294  sep = ',';
295  }
296  sstr << key << '=' << params[key]; // TODO: escape \" ?
297  }
298  dstDataSet[ODIMPathElem::WHAT].data.attributes["rack_prodpar"] = sstr.str();
299  //dstDataSet[ODIMPathElem::WHAT].data.attributes["prodpar"] = drain::sprinter(this->getParameters(), drain::Sprinter::cmdLineLayout);
300  }
301 
302  return dstDataSet;
303  /*
304  drain::VariableMap & rootWhere = dst[ODIMPathElem::WHERE].data.attributes; //root.getWhere();
305  rootWhere = src[ODIMPathElem::WHERE].data.attributes;
306  mout.debug2("src /where/ : ", src[ODIMPathElem::WHERE].data.attributes);
307  mout.debug2("dst /where/ : ", rootWhere);
308  drain::VariableMap & how = dstProductDataset.getHow(); //dstProduct["how"].data.attributes;
309  how = src[ODIMPathElem::HOW].data.attributes;
310  */
311  // odim.copyToRoot(dst); NO! Mainly overwrites original data. fgrep 'declare(rootAttribute' odim/*.cpp
313  // this->computeSingleProduct(sweeps, dstProductDataset);
314  // this->processSweeps(sweeps, dstProductDataset);
315 
316 }
317 
318 
319 } // namespace rack
320 
321 
322 #endif
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition: Log.h:310
Logger & attention(const TT &... args)
Possible error, but execution can continue. Special type of Logger::warn().
Definition: Log.h:474
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition: Log.h:428
Logger & debug(const TT &... args)
Public, yet typically used "internally", when TIMING=true.
Definition: Log.h:678
Logger & debug2(const TT &... args)
Debug information.
Definition: Log.h:688
Definition: Path.h:112
Definition: ReferenceMap.h:207
virtual const keylist_t & getKeyList() const
Derived versions may produce an ordered set of keys.
Definition: SmartMap.h:200
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:127
static const group_t DATASET
First level group, /dataset + digit .
Definition: ODIMPath.h:106
bool is(group_t g) const
Abbreviation of (group == NONE)
Definition: ODIMPath.h:294
static const group_t ROOT
Definition: ODIMPath.h:102
static const group_t HOW
Metadata group /how , at any depth.
Definition: ODIMPath.h:133
unsigned int group_t
In H5, "groups" correspond to directories or folders in file system.
Definition: ODIMPath.h:92
static const group_t DATA
Second level group, /data + digit .
Definition: ODIMPath.h:109
static const group_t WHERE
Metadata group /where , at any depth.
Definition: ODIMPath.h:130
static bool getNextChild(const Hi5Tree &tree, ODIMPathElem &child)
Derive a child with index one greater than the largest index encountered.
Definition: ODIMPathTools.cpp:96
ODIM metadata (quantity, gain, offset, undetect, nodata, date, time)
Definition: ODIM.h:79
virtual void updateLenient(const ODIM &odim)
Updates object, quantity, product and time information.
Definition: ODIM.cpp:290
ODIMPathElem appendResults
If set, appends outputs in an hdf5 structure instead of overwriting.
Definition: ProductConf.h:93
Base class for radar data processors.
Definition: VolumeOp.h:88
virtual Hi5Tree & processVolume(const Hi5Tree &src, Hi5Tree &dst) const final
Traverse through given volume and create new, processed data (volume or polar product).
Definition: VolumeOp.h:121
Namespace for images and image processing tools.
Definition: AccumulationArray.cpp:45
Definition: DataSelector.cpp:44