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/ReferenceMap.h>
43
44#include "data/DataSelector.h"
45#include "data/Data.h"
46#include "data/ODIM.h"
47#include "data/ODIMPathTools.h"
48#include "data/Quantity.h" // NEW
49
50#include "hi5/Hi5.h"
51#include "hi5/Hi5Write.h" // debugging
52
53
54#include "radar/PolarSector.h"
55#include "RadarProductOp.h"
56
57namespace rack {
58
59using namespace drain::image;
60
62
64
80// TODO: generalize for Cart
81template <class M>
82class VolumeOp : public RadarProductOp<const PolarODIM, M> {
83
84public:
85
86 VolumeOp(const std::string & name, const std::string &description="") : RadarProductOp<const PolarODIM, M>(name, description){
87 };
88
89 virtual inline
90 ~VolumeOp(){};
91
92
94
101 virtual
102 Hi5Tree & processVolume(const Hi5Tree &srcRoot, Hi5Tree &dstRoot) const final;
103
104 virtual inline
105 void setPolarSelector(const PolarSelector & ps){
106 // polarSelector = ps;
107 if (ps.azimuth.range.empty() && ps.radius.range.empty()){
109 mout.info(this->getName(), ": no support for polar selector");
110 }
111 }
112
113protected:
114
115 // PolarSelector polarSelector;
116
117
118};
119
120
121
122template <class M>
123Hi5Tree & VolumeOp<M>::processVolume(const Hi5Tree &srcRoot, Hi5Tree &dstRoot) const{
124
126
127 mout.debug("start" );
128 mout.debug3(*this );
129 mout.debug2("DataSelector: " , this->dataSelector );
130
131 // Step 1: collect sweeps (/datasetN/)
133
135 mout.debug3("collect the applicable paths" );
136 ODIMPathList dataPaths; // Down to ../dataN/ level, eg. /dataset5/data4
137 //this->dataSelector.getPaths(src, dataPaths, ODIMPathElem::DATASET); // RE2
138
139 this->dataSelector.getPaths(srcRoot, dataPaths);
140
141 if (dataPaths.empty()){
142 if (!this->dataSelector.getQuantitySelector().test("HGHT")){
143 mout.experimental<LOG_INFO>("no dataset's selected, but height=[HGHT] requested, continuing");
144 }
145 else {
146 mout.warn("no dataset's selected");
147 }
148 }
149 else {
150 mout.debug3("populate the dataset map, paths=" , dataPaths.size() );
151 }
152
154
155 for (ODIMPath & path: dataPaths){
156
157 if (!path.front().is(ODIMPathElem::DATASET)){
158 path.pop_front();
159 if (path.empty()){
160 mout.warn("odd 1st path elem (..), with selector: ", this->dataSelector);
161 continue;
162 }
163 }
164
165 const ODIMPathElem & parentElem = path.front();
166
168 mout.warn("path does not start with /dataset.. :", path, ", with selector: ", this->dataSelector);
169 continue;
170 }
171
172 // mout.debug3("elangles (this far> " , elangles );
173 const Hi5Tree & srcDataSet = srcRoot(parentElem);
174
175 // const double elangle = srcDataSet[ODIMPathElem::WHERE].data.attributes["elangle"]; // PATH
176 // mout.deprecating("no more testing ", parent, ", elangle=", elangle, ':', srcDataSet.data.dataSet);
177
178
179 const ODIM srcODIM(srcDataSet.data.image);
180 std::string datetime = srcODIM.startdate + srcODIM.starttime;
181
182 dstODIM.updateLenient(srcODIM);
183 mout.attention<LOG_DEBUG+1>("start=", dstODIM.startdate, '+', dstODIM.starttime, " nominal<", datetime, "> end==", dstODIM.enddate, '+', dstODIM.endtime);
184
185 if (sweeps.find(datetime) == sweeps.end()){
186 mout.debug2("adding time=", datetime, ':', parentElem);
187 // Consider removing RegExp form datasets?
188 //sweeps.insert(DataSetMap<PolarSrc>::value_type(datetime, DataSet<PolarSrc>(srcDataSet, drain::RegExp(this->dataSelector.getQuantity()))));
189 sweeps.insert(DataSetMap<PolarSrc>::value_type(datetime, DataSet<PolarSrc>(srcDataSet, this->dataSelector.getQuantitySelector())));
190 }
191 else {
192 // mout.warn("datetime =", datetime, " already added?, skipping ", parent);
193 }
194
195 /*
196 if (sweeps.find(elangle) == sweeps.end()){
197 mout.debug3("add " , elangle , ':' , parent , " quantity RegExp:" , this->dataSelector.quantity );
198 sweeps.insert(DataSetMap<PolarSrc>::value_type(elangle, DataSet<PolarSrc>(srcDataSet, drain::RegExp(this->dataSelector.quantity) ))); // Something like: sweeps[elangle] = src[parent] .
199 // elangles << elangle;
200 //mout.warn("add " , DataSet<PolarSrc>(src(parent), drain::RegExp(this->dataSelector.quantity) ) );
201 }
202 else {
203 mout.note("elange =" , elangle , " already added, skipping " , parent );
204 }
205 */
206 }
207
208 //mout.note("first elange =" , sweeps.begin()->first , " DS =" , sweeps.begin()->second );
209 //mout.note("first qty =" , sweeps.begin()->second.begin()->first , " D =" , sweeps.begin()->second.getFirstData() );
210
211
213 //if (!DataTools::getNextDescendant(dst, ProductBase::appendResults.getType(), dataSetPath))
214
216 if (ProductBase::appendResults.getIndex()){
218 }
219 else {
221 }
222 }
224 //mout.info("appending to next available data group in " , dataSetPath ); // ALWAYS dataset1, then ?
225 }
227 if (!dstRoot.empty() && (&srcRoot != &dstRoot)){ // latter is ANDRE test... (kludge)
228 mout.info("clearing previous result, use --append [data|dataset] to avoid");
229 dstRoot.clear();
230 }
231 }
232 else {
234 mout.warn("non-standard path location '", dataSetPathElem, "', consider --help append ");
235 }
236 //++dataSetPath.index;
237
238 //mout.warn("FAILED: " , dataSetPath );
239 //dataSetPath.push_back(ODIMPathElem(ODIMPathElem::DATASET, 1));
240
241 mout.debug("storing product in path: ", dataSetPathElem);
242
243 //Hi5Tree & dstProduct = dst[dataSetPath];
244 /* /// WARNING: Root odim has to be modified explicitly, otherwise remains empty.
245 RootData<DstType<M> > root(dst);
246 drain::VariableMap & whatRoot = root.getWhat();
247 whatRoot["object"] = this->odim.object;
248 whatRoot["version"] = this->odim.version;
249 */
250
251
254 { // SCOPE
256 this->computeSingleProduct(sweeps, dstProductDataset);
257
259 ProductBase::setRackVersion(how);
260 if (!dstProductDataset.empty()){
262 how["angles"] = dstProductDataset.getFirstData().odim.angles; // FIX: this may be some tmp data, not main [odim.quantity]
263 }
264 }
265
266 /* keep for debugging
267 for (const auto & entry: dstDataSet){
268 mout.warn(entry.first, ": ", entry.second[ODIMPathElem::ARRAY].data.image.getProperties());
269 }
270 */
271
272
273 // Copy metadata from the input volume (note that dst may have been cleared above)
274 mout.revised<LOG_DEBUG>("check DataSet metadata");
275 // drain::TreeUtils::dump(dstRoot, std::cout, DataTools::treeToStream);
276
277 // Root level
279 dstRoot[group].data.attributes = srcRoot[group].data.attributes;
280 }
281 drain::VariableMap & rootWhat = dstRoot[ODIMPathElem::WHAT].data.attributes; // dstProduct["what"].data.attributes;
283 rootWhat["object"] = this->odim.object; // ?
284 rootWhat["version"] = this->odim.version;
285
286 dstDataSet[ODIMPathElem::WHAT].data.attributes["product"] = this->odim.product;
287 dstDataSet[ODIMPathElem::WHAT].data.attributes["startdate"] = dstODIM.startdate;
288 dstDataSet[ODIMPathElem::WHAT].data.attributes["starttime"] = dstODIM.starttime;
289 dstDataSet[ODIMPathElem::WHAT].data.attributes["enddate"] = dstODIM.enddate;
290 dstDataSet[ODIMPathElem::WHAT].data.attributes["endtime"] = dstODIM.endtime;
291
292 // PRODPAR ... complicated! Fix at Sprinter level, getKeyList()
293 if (ODIM::versionFlagger.isSet(ODIM::RACK_EXTENSIONS)){
294
295 dstDataSet[ODIMPathElem::WHAT].data.attributes["product2"] = dstODIM.product;
296
297 // keep scope, even if condition removed
298 std::stringstream sstr;
299 char sep = 0;
300 const drain::ReferenceMap & params = this->getParameters();
301 for (const std::string & key: params.getKeyList()){
302 if (sep){
303 sstr << sep;
304 }
305 else {
306 sep = ',';
307 }
308 sstr << key << '=' << params[key]; // TODO: escape \" ?
309 }
310 dstDataSet[ODIMPathElem::WHAT].data.attributes["rack_prodpar"] = sstr.str();
311 //dstDataSet[ODIMPathElem::WHAT].data.attributes["prodpar"] = drain::sprinter(this->getParameters(), drain::Sprinter::cmdLineLayout);
312 }
313
314 return dstDataSet;
315
316}
317
318
319} // namespace rack
320
321
322#endif
const std::string description
Brief, human-readable description of this bean.
Definition BeanLike.h:309
virtual const std::string & getName() const
Return the name of an instance.
Definition BeanLike.h:89
const std::string name
Name of this bean, typically also the name of the (derived) class.
Definition BeanLike.h:306
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:326
Definition Path.h:135
Definition ReferenceMap.h:215
virtual const keylist_t & getKeyList() const
Derived versions may produce an ordered set of keys.
Definition SmartMap.h:201
A map of Variables.
Definition VariableMap.h:61
Definition Data.h:1459
A map of radar data, indexed by quantity code (DBZH, VRAD, etc).
Definition Data.h:1293
DOC: Add class description.
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
static const group_t ROOT
Definition ODIMPath.h:102
static const group_t HOW
Metadata group /how , at any depth.
Definition ODIMPath.h:133
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:106
ODIM metadata (quantity, gain, offset, undetect, nodata, date, time)
Definition ODIM.h:79
ODIMPathElem appendResults
If set, appends outputs in an hdf5 structure instead of overwriting.
Definition ProductConf.h:92
Polar and Cartesian products.
Definition RadarProductOp.h:78
Base class for radar data processors.
Definition VolumeOp.h:82
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:123
Namespace for images and image processing tools.
Definition AccumulationArray.cpp:45
Definition AltitudeOp.cpp:42
Definition PolarSector.h:109