Loading...
Searching...
No Matches
VolumeOp.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/*
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#include <product/RadarProductOp.h> // NEW
48
49
50
51//#include "main/rack.h"
52#include "hi5/Hi5.h"
53#include "data/DataSelector.h"
54#include "data/Data.h"
55#include "data/ODIM.h"
56#include "data/ODIMPathTools.h"
57#include "data/Quantity.h" // NEW
58
59#include "hi5/Hi5Write.h" // debugging
60
61
62
63namespace rack {
64
65using namespace drain::image;
66
68
70
86// TODO: generalize for Cart
87template <class M>
88class VolumeOp : public RadarProductOp<const PolarODIM, M> {
89
90public:
91
92 VolumeOp(const std::string & name, const std::string &description="") : RadarProductOp<const PolarODIM, M>(name, description){
93 };
94
95 virtual inline
96 ~VolumeOp(){};
97
98
100
107 virtual
108 Hi5Tree & processVolume(const Hi5Tree &srcRoot, Hi5Tree &dstRoot) const final;
109
110
111
112protected:
113
114
115
116};
117
118
119
120template <class M>
121Hi5Tree & VolumeOp<M>::processVolume(const Hi5Tree &srcRoot, Hi5Tree &dstRoot) 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/)
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(srcRoot, dataPaths);
138
139 if (dataPaths.empty()){
140 if (!this->dataSelector.getQuantitySelector().test("HGHT")){
141 mout.experimental<LOG_INFO>("no dataset's selected, but height=[HGHT] requested, continuing");
142 }
143 else {
144 mout.warn("no dataset's selected");
145 }
146 }
147 else {
148 mout.debug3("populate the dataset map, paths=" , dataPaths.size() );
149 }
150
151 ODIM dstODIM;
152
153 for (ODIMPath & path: dataPaths){
154
155 if (!path.front().is(ODIMPathElem::DATASET)){
156 path.pop_front();
157 if (path.empty()){
158 mout.warn("odd 1st path elem (..), with selector: ", this->dataSelector);
159 continue;
160 }
161 }
162
163 const ODIMPathElem & parentElem = path.front();
164
165 if (!parentElem.is(ODIMPathElem::DATASET)){
166 mout.warn("path does not start with /dataset.. :", path, ", with selector: ", this->dataSelector);
167 continue;
168 }
169
170 // mout.debug3("elangles (this far> " , elangles );
171 const Hi5Tree & srcDataSet = srcRoot(parentElem);
172
173 // const double elangle = srcDataSet[ODIMPathElem::WHERE].data.attributes["elangle"]; // PATH
174 // mout.deprecating("no more testing ", parent, ", elangle=", elangle, ':', srcDataSet.data.dataSet);
175
176
177 const ODIM srcODIM(srcDataSet.data.image);
178 std::string datetime = srcODIM.startdate + srcODIM.starttime;
179
180 dstODIM.updateLenient(srcODIM);
181 mout.attention<LOG_DEBUG>(dstODIM.startdate, '+', dstODIM.starttime, " ?== ", datetime, " < ", dstODIM.enddate, '+', dstODIM.endtime);
182
183 if (sweeps.find(datetime) == sweeps.end()){
184 mout.debug2("adding time=", datetime, ':', parentElem);
185 // Consider removing RegExp form datasets?
186 //sweeps.insert(DataSetMap<PolarSrc>::value_type(datetime, DataSet<PolarSrc>(srcDataSet, drain::RegExp(this->dataSelector.getQuantity()))));
187 sweeps.insert(DataSetMap<PolarSrc>::value_type(datetime, DataSet<PolarSrc>(srcDataSet, this->dataSelector.getQuantitySelector())));
188 }
189 else {
190 // mout.warn("datetime =", datetime, " already added?, skipping ", parent);
191 }
192
193 /*
194 if (sweeps.find(elangle) == sweeps.end()){
195 mout.debug3("add " , elangle , ':' , parent , " quantity RegExp:" , this->dataSelector.quantity );
196 sweeps.insert(DataSetMap<PolarSrc>::value_type(elangle, DataSet<PolarSrc>(srcDataSet, drain::RegExp(this->dataSelector.quantity) ))); // Something like: sweeps[elangle] = src[parent] .
197 // elangles << elangle;
198 //mout.warn("add " , DataSet<PolarSrc>(src(parent), drain::RegExp(this->dataSelector.quantity) ) );
199 }
200 else {
201 mout.note("elange =" , elangle , " already added, skipping " , parent );
202 }
203 */
204 }
205
206 //mout.note("first elange =" , sweeps.begin()->first , " DS =" , sweeps.begin()->second );
207 //mout.note("first qty =" , sweeps.begin()->second.begin()->first , " D =" , sweeps.begin()->second.getFirstData() );
208
209
210 ODIMPathElem dataSetPathElem(ODIMPathElem::DATASET); // ,1) // 2024/11
211 //if (!DataTools::getNextDescendant(dst, ProductBase::appendResults.getType(), dataSetPath))
212
213 if (ProductBase::appendResults.is(ODIMPathElem::DATASET)){
214 if (ProductBase::appendResults.getIndex()){
215 dataSetPathElem.index = ProductBase::appendResults.getIndex();
216 }
217 else {
218 ODIMPathTools::getNextChild(dstRoot, dataSetPathElem);
219 }
220 }
221 else if (ProductBase::appendResults.is(ODIMPathElem::DATA)){
222 //mout.info("appending to next available data group in " , dataSetPath ); // ALWAYS dataset1, then ?
223 }
224 else if (ProductBase::appendResults.is(ODIMPathElem::ROOT)){
225 if (!dstRoot.empty() && (&srcRoot != &dstRoot)){ // latter is ANDRE test... (kludge)
226 mout.info("clearing previous result, use --append [data|dataset] to avoid");
227 dstRoot.clear();
228 }
229 }
230 else {
231 dataSetPathElem = ProductBase::appendResults;
232 mout.warn("non-standard path location '", dataSetPathElem, "', consider --help append ");
233 }
234 //++dataSetPath.index;
235
236 //mout.warn("FAILED: " , dataSetPath );
237 //dataSetPath.push_back(ODIMPathElem(ODIMPathElem::DATASET, 1));
238
239 mout.debug("storing product in path: ", dataSetPathElem);
240
241 //Hi5Tree & dstProduct = dst[dataSetPath];
242 /* /// WARNING: Root odim has to be modified explicitly, otherwise remains empty.
243 RootData<DstType<M> > root(dst);
244 drain::VariableMap & whatRoot = root.getWhat();
245 whatRoot["object"] = this->odim.object;
246 whatRoot["version"] = this->odim.version;
247 */
248
249
251 Hi5Tree & dstDataSet = dstRoot[dataSetPathElem];
252 { // SCOPE
253 DataSet<DstType<M> > dstProductDataset(dstDataSet); // PATH
254 this->computeSingleProduct(sweeps, dstProductDataset);
255
256 drain::VariableMap & how = dstProductDataset.getHow();
257 ProductBase::setRackVersion(how);
258 if (!dstProductDataset.empty()){
260 how["angles"] = dstProductDataset.getFirstData().odim.angles; // FIX: this may be some tmp data, not main [odim.quantity]
261 }
262 }
263
264 /* keep for debugging
265 for (const auto & entry: dstDataSet){
266 mout.warn(entry.first, ": ", entry.second[ODIMPathElem::ARRAY].data.image.getProperties());
267 }
268 */
269
270
271 // Copy metadata from the input volume (note that dst may have been cleared above)
272 mout.revised<LOG_DEBUG>("check DataSet metadata");
273 // drain::TreeUtils::dump(dstRoot, std::cout, DataTools::treeToStream);
274
275 // Root level
276 for (const ODIMPathElem::group_t group: {ODIMPathElem::WHAT, ODIMPathElem::WHERE, ODIMPathElem::HOW}){
277 dstRoot[group].data.attributes = srcRoot[group].data.attributes;
278 }
279 drain::VariableMap & rootWhat = dstRoot[ODIMPathElem::WHAT].data.attributes; // dstProduct["what"].data.attributes;
281 rootWhat["object"] = this->odim.object; // ?
282 rootWhat["version"] = this->odim.version;
283
284 dstDataSet[ODIMPathElem::WHAT].data.attributes["product"] = this->odim.product;
285 dstDataSet[ODIMPathElem::WHAT].data.attributes["startdate"] = dstODIM.startdate;
286 dstDataSet[ODIMPathElem::WHAT].data.attributes["starttime"] = dstODIM.starttime;
287 dstDataSet[ODIMPathElem::WHAT].data.attributes["enddate"] = dstODIM.enddate;
288 dstDataSet[ODIMPathElem::WHAT].data.attributes["endtime"] = dstODIM.endtime;
289
290 // PRODPAR ... complicated! Fix at Sprinter level, getKeyList()
291 if (ODIM::versionFlagger.isSet(ODIM::RACK_EXTENSIONS)){
292
293 dstDataSet[ODIMPathElem::WHAT].data.attributes["product2"] = dstODIM.product;
294
295 // keep scope, even if condition removed
296 std::stringstream sstr;
297 char sep = 0;
298 const drain::ReferenceMap & params = this->getParameters();
299 for (const std::string & key: params.getKeyList()){
300 if (sep){
301 sstr << sep;
302 }
303 else {
304 sep = ',';
305 }
306 sstr << key << '=' << params[key]; // TODO: escape \" ?
307 }
308 dstDataSet[ODIMPathElem::WHAT].data.attributes["rack_prodpar"] = sstr.str();
309 //dstDataSet[ODIMPathElem::WHAT].data.attributes["prodpar"] = drain::sprinter(this->getParameters(), drain::Sprinter::cmdLineLayout);
310 }
311
312 return dstDataSet;
313
314}
315
316
317} // namespace rack
318
319
320#endif
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 & attention(const TT &... args)
Possible error, but execution can continue. Special type of Logger::warn().
Definition Log.h:476
Logger & debug2(const TT &... args)
Debug information.
Definition Log.h:676
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
Definition Data.h:1370
A map of radar data, indexed by quantity code (DBZH, VRAD, etc).
Definition Data.h:1215
Definition ODIMPath.h:82
bool is(group_t g) const
Abbreviation of (group == NONE)
Definition ODIMPath.h:294
unsigned int group_t
In H5, "groups" correspond to directories or folders in file system.
Definition ODIMPath.h:92
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:374
Polar and Cartesian products.
Definition RadarProductOp.h:78
Base class for radar data processors.
Definition VolumeOp.h:88
virtual Hi5Tree & processVolume(const Hi5Tree &srcRoot, Hi5Tree &dstRoot) 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