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 mout.warn("no dataset's selected" );
141 }
142 else {
143 mout.debug3("populate the dataset map, paths=" , dataPaths.size() );
144 }
145
146 ODIM dstODIM;
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 & parentElem = path.front();
159
160 if (!parentElem.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 = srcRoot(parentElem);
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 const ODIM srcODIM(srcDataSet.data.image);
173 std::string datetime = srcODIM.startdate + srcODIM.starttime;
174
175 dstODIM.updateLenient(srcODIM);
176 mout.attention<LOG_DEBUG>(dstODIM.startdate, '+', dstODIM.starttime, " ?== ", datetime, " < ", dstODIM.enddate, '+', dstODIM.endtime);
177
178 if (sweeps.find(datetime) == sweeps.end()){
179 mout.debug2("adding time=", datetime, ':', parentElem);
180 // Consider removing RegExp form datasets?
181 //sweeps.insert(DataSetMap<PolarSrc>::value_type(datetime, DataSet<PolarSrc>(srcDataSet, drain::RegExp(this->dataSelector.getQuantity()))));
182 sweeps.insert(DataSetMap<PolarSrc>::value_type(datetime, DataSet<PolarSrc>(srcDataSet, this->dataSelector.getQuantitySelector())));
183 }
184 else {
185 // mout.warn("datetime =", datetime, " already added?, skipping ", parent);
186 }
187
188 /*
189 if (sweeps.find(elangle) == sweeps.end()){
190 mout.debug3("add " , elangle , ':' , parent , " quantity RegExp:" , this->dataSelector.quantity );
191 sweeps.insert(DataSetMap<PolarSrc>::value_type(elangle, DataSet<PolarSrc>(srcDataSet, drain::RegExp(this->dataSelector.quantity) ))); // Something like: sweeps[elangle] = src[parent] .
192 // elangles << elangle;
193 //mout.warn("add " , DataSet<PolarSrc>(src(parent), drain::RegExp(this->dataSelector.quantity) ) );
194 }
195 else {
196 mout.note("elange =" , elangle , " already added, skipping " , parent );
197 }
198 */
199 }
200
201 //mout.note("first elange =" , sweeps.begin()->first , " DS =" , sweeps.begin()->second );
202 //mout.note("first qty =" , sweeps.begin()->second.begin()->first , " D =" , sweeps.begin()->second.getFirstData() );
203
204
205 ODIMPathElem dataSetPathElem(ODIMPathElem::DATASET); // ,1) // 2024/11
206 //if (!DataTools::getNextDescendant(dst, ProductBase::appendResults.getType(), dataSetPath))
207
208 if (ProductBase::appendResults.is(ODIMPathElem::DATASET)){
209 if (ProductBase::appendResults.getIndex()){
210 dataSetPathElem.index = ProductBase::appendResults.getIndex();
211 }
212 else {
213 ODIMPathTools::getNextChild(dstRoot, dataSetPathElem);
214 }
215 }
216 else if (ProductBase::appendResults.is(ODIMPathElem::DATA)){
217 //mout.info("appending to next available data group in " , dataSetPath ); // ALWAYS dataset1, then ?
218 }
219 else if (ProductBase::appendResults.is(ODIMPathElem::ROOT)){
220 if (!dstRoot.empty() && (&srcRoot != &dstRoot)){ // latter is ANDRE test... (kludge)
221 mout.info("clearing previous result, use --append [data|dataset] to avoid");
222 dstRoot.clear();
223 }
224 }
225 else {
226 dataSetPathElem = ProductBase::appendResults;
227 mout.warn("non-standard path location '", dataSetPathElem, "', consider --help append ");
228 }
229 //++dataSetPath.index;
230
231 //mout.warn("FAILED: " , dataSetPath );
232 //dataSetPath.push_back(ODIMPathElem(ODIMPathElem::DATASET, 1));
233
234 mout.debug("storing product in path: ", dataSetPathElem);
235
236 //Hi5Tree & dstProduct = dst[dataSetPath];
237 /* /// WARNING: Root odim has to be modified explicitly, otherwise remains empty.
238 RootData<DstType<M> > root(dst);
239 drain::VariableMap & whatRoot = root.getWhat();
240 whatRoot["object"] = this->odim.object;
241 whatRoot["version"] = this->odim.version;
242 */
243
244
246 Hi5Tree & dstDataSet = dstRoot[dataSetPathElem];
247 { // SCOPE
248 DataSet<DstType<M> > dstProductDataset(dstDataSet); // PATH
249 this->computeSingleProduct(sweeps, dstProductDataset);
250
251 drain::VariableMap & how = dstProductDataset.getHow();
252 ProductBase::setRackVersion(how);
253 if (!dstProductDataset.empty()){
255 how["angles"] = dstProductDataset.getFirstData().odim.angles; // FIX: this may be some tmp data, not main [odim.quantity]
256 }
257 }
258
259 /* keep for debugging
260 for (const auto & entry: dstDataSet){
261 mout.warn(entry.first, ": ", entry.second[ODIMPathElem::ARRAY].data.image.getProperties());
262 }
263 */
264
265
266 // Copy metadata from the input volume (note that dst may have been cleared above)
267 mout.revised<LOG_DEBUG>("check DataSet metadata");
268 // drain::TreeUtils::dump(dstRoot, std::cout, DataTools::treeToStream);
269
270 // Root level
271 for (const ODIMPathElem::group_t group: {ODIMPathElem::WHAT, ODIMPathElem::WHERE, ODIMPathElem::HOW}){
272 dstRoot[group].data.attributes = srcRoot[group].data.attributes;
273 }
274 drain::VariableMap & rootWhat = dstRoot[ODIMPathElem::WHAT].data.attributes; // dstProduct["what"].data.attributes;
276 rootWhat["object"] = this->odim.object; // ?
277 rootWhat["version"] = this->odim.version;
278
279 dstDataSet[ODIMPathElem::WHAT].data.attributes["product"] = this->odim.product;
280 dstDataSet[ODIMPathElem::WHAT].data.attributes["startdate"] = dstODIM.startdate;
281 dstDataSet[ODIMPathElem::WHAT].data.attributes["starttime"] = dstODIM.starttime;
282 dstDataSet[ODIMPathElem::WHAT].data.attributes["enddate"] = dstODIM.enddate;
283 dstDataSet[ODIMPathElem::WHAT].data.attributes["endtime"] = dstODIM.endtime;
284
285 // PRODPAR ... complicated! Fix at Sprinter level, getKeyList()
286 if (ODIM::versionFlagger.isSet(ODIM::RACK_EXTENSIONS)){
287
288 dstDataSet[ODIMPathElem::WHAT].data.attributes["product2"] = dstODIM.product;
289
290 // keep scope, even if condition removed
291 std::stringstream sstr;
292 char sep = 0;
293 const drain::ReferenceMap & params = this->getParameters();
294 for (const std::string & key: params.getKeyList()){
295 if (sep){
296 sstr << sep;
297 }
298 else {
299 sep = ',';
300 }
301 sstr << key << '=' << params[key]; // TODO: escape \" ?
302 }
303 dstDataSet[ODIMPathElem::WHAT].data.attributes["rack_prodpar"] = sstr.str();
304 //dstDataSet[ODIMPathElem::WHAT].data.attributes["prodpar"] = drain::sprinter(this->getParameters(), drain::Sprinter::cmdLineLayout);
305 }
306
307 return dstDataSet;
308
309}
310
311
312} // namespace rack
313
314
315#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:296
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