Loading...
Searching...
No Matches
Data.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// Thanks to: Mikael Kilpeläinen
32
33#ifndef DATA_H_
34#define DATA_H_
35
36#include <data/QuantitySelector.h>
37#include <list>
38#include <map>
39
40#include <drain/util/ReferenceMap.h>
41
42#include "DataSelector.h"
43#include "DataTools.h"
44#include "PolarODIM.h"
45#include "CartesianODIM.h"
46#include "VerticalODIM.h"
47
48
49using namespace drain::image;
50
51namespace rack {
52
76
82template <typename T, typename TI, typename D>
83struct DataType {
84 typedef T tree_t;
85 typedef TI tree_iter_t;
86 typedef D image_t;
87};
88
89
90/*
91template <class T, size_t N>
92struct TypeName<UniTuple<T,N> > {
93
94 static const std::string & str(){
95 static std::string name = drain::StringBuilder<>("UniTuple<", drain::TypeName<T>::str(), ',', N, ">");
96 return name;
97 }
98
99};
100*/
101
103
106template <typename M = PolarODIM const>
107struct SrcType : public DataType<Hi5Tree const, Hi5Tree::const_iterator, Image const> {
108 typedef M odim_t;
109};
110
111
113
116template <typename M = PolarODIM>
117struct DstType : public DataType<Hi5Tree, Hi5Tree::iterator, Image> {
118 typedef M odim_t;
119};
120
123
126
129
130
131typedef DstType<ODIM> BasicDst;
132
135
138
141
144
145
146
148
154template <typename DT>
156public:
157
158 typedef DT datatype_t;
159 typedef typename DT::tree_t tree_t;
160 typedef typename DT::tree_iter_t tree_iter_t;
161
162 inline
163 const drain::VariableMap & getWhat() const {
164 return getAttr<ODIMPathElem::WHAT>();
165 }
166
167 inline
168 drain::VariableMap & getWhat() {
169 return getAttr<ODIMPathElem::WHAT>();
170 }
171
172 inline
173 const drain::VariableMap & getWhere() const {
174 return getAttr<ODIMPathElem::WHERE>();
175 }
176
177 inline
178 drain::VariableMap & getWhere() {
179 return getAttr<ODIMPathElem::WHERE>();
180 }
181
182
183 inline
184 const drain::VariableMap & getHow() const {
185 return getAttr<ODIMPathElem::HOW>();
186 }
187
188 inline
189 drain::VariableMap & getHow() { // ODIMPathElem(ODIMPathElem::HOW)
190 return getAttr<ODIMPathElem::HOW>();
191 }
192
193 // Mark this data temporary so that it will not be save by Hi5::write().
194 inline
195 void setExcluded(bool exclude = true){
196 this->tree.data.exclude = exclude;
197 };
198
199 // Mark this data temporary so that it will not be save by Hi5::write().
200 inline
201 bool isExcluded() const {
202 return this->tree.data.exclude;
203 };
204
205 //typename DT::odim_t odim;
206
207 virtual inline
208 const tree_t & getTree() const { return this->tree; };
209
210 // expected public, at least by DetectorOp::storeDebugData()
211 virtual inline
212 tree_t & getTree(){ return this->tree; } ;
213
214
215protected:
216
218 tree_t & tree;
219
220 TreeWrapper(tree_t & tree) : tree(tree){
221 };
222
223 //TreeWrapper(tree_t & tree, const odim_t & odim) tree(tree), odim(odim) {};
224 TreeWrapper(const TreeWrapper & d) : tree(d.tree){}; //, image(d.data), odim(d.odim) {};
225
226
227 ~TreeWrapper(){
228 /*
229 drain::Logger mout("TreeWrapper", __FUNCTION__);
230 if (this->tree.data.exclude){
231 mout.note("deleting (children only?)" );
232 this->tree.clear();
233 }
234 */
235 };
236
237
238 template <ODIMPathElem::group_t G>
239 const drain::VariableMap & getAttr() const {
240 return this->tree[ODIMPathElem(G)].data.attributes;
241 }
242
243 template <ODIMPathElem::group_t G>
244 drain::VariableMap & getAttr(){
245 return this->tree[ODIMPathElem(G)].data.attributes;
246 }
247
248
249};
250
251// In future, could be the interface for wrapping the whole structure?
252
254
260template <typename DT>
261class RootData : public TreeWrapper<DT> {
262
263public:
264
265 /*
266 RootData(typename DT::tree_t & tree) : TreeWrapper<DT>(tree) { // This could be good: odim(ODIMPathElem::ROOT) ... but failed with current design
267 // experimental
268 this->odim.copyFrom(tree.data.image); // <- works (only) if updateInternalAttributes() has been called?
269 };
270 */
271
272 RootData(typename DT::tree_t & tree) : TreeWrapper<DT>(tree), odim(tree.data.image) { // This could be good: odim(ODIMPathElem::ROOT) ... but failed with current design
273 // experimental
274 // this->odim.copyFrom(tree.data.image); // <- works (only) if updateInternalAttributes() has been called?
275 };
276
277 /* error
278 RootData(const typename DT::tree_t & tree) : TreeWrapper<DT>(tree) { // This could be good: odim(ODIMPathElem::ROOT) ... but failed with current design
279 // experimental
280 this->odim.copyFrom(tree.data.image); // <- works (only) if updateInternalAttributes() has been called?
281 };
282 */
283
284 virtual inline
285 ~RootData(){
286
287 drain::Logger mout(__FILE__, __FUNCTION__);
288 mout.experimental<LOG_DEBUG>("invoking ODIM::updateH5AttributeGroups<ODIMPathElem::ROOT>()");
289 mout.experimental<LOG_DEBUG+1>("root odim: ", this->odim);
290
291 ODIM::updateH5AttributeGroups<ODIMPathElem::ROOT>(this->odim, this->tree);
292 DataTools::updateInternalAttributes(this->tree); // overrides anything?
293 };
294
295 // Metadata structure
296 typename DT::odim_t odim;
297
298};
299
300
302
310template <typename DT>
311class PlainData : public TreeWrapper<DT> {
312public:
313
314 typedef typename DT::tree_t tree_t;
315 typedef typename DT::image_t image_t;
316 typedef typename DT::odim_t odim_t;
317
318 // NEW
319 inline
320 PlainData(typename DT::tree_t & tree) :
322 data(tree[ODIMPathElem::ARRAY].data.image), // "data"
323 odim(data, data.properties.get("what:quantity",""))
324 {
325 //data.setScaling(odim.scaling.scale, odim.scaling.offset);
326 }
327
329 PlainData(typename DT::tree_t & tree, const std::string & quantity) :
330 TreeWrapper<DT>(tree),
331 data(tree[ODIMPathElem::ARRAY].data.image), // "data"
332 odim(data, quantity) // reads data.properties?
333 {
334 //data.setScaling(odim.scaling.scale, odim.scaling.offset);
335 }
336
338
347 template <typename DT2>
348 PlainData(const PlainData<DT2> & d) : TreeWrapper<DT>(d.getTree()),
349 data(this->tree[ODIMPathElem::ARRAY].data.image), // "data"
350 // odim(d.odim) // OLD
351 odim(data) // NEW
352 {
353 //odim.updateFromMap(d.odim); // NEW
354 //odim.updateFromCastableMap(d.odim); // NEW
355 //data.setScaling(odim.scaling.scale, odim.scaling.offset);
356 }
357
358 inline
359 ~PlainData(){
360 //drain::Logger mout("PlainData", __FUNCTION__);
361 //mout.debug2("calling updateTree2, odim: " , odim );
362 updateTree2();
363 }
364
366 template <class T>
367 inline
368 void setEncoding(const T & type, const std::string & values = ""){
369 //odim.type = drain::Type::getTypeChar(type);
370 this->odim.type = drain::Type::getTypeChar(drain::Type(type));
371 this->odim.setTypeDefaults(type, values);
372 data.setType(type);
373 // TODO: data.setScaling(odim.scaling); ??
374 }
375
377 inline
378 void copyEncoding(const EncodingODIM & odim){
379 this->odim.importMap(odim);
380 data.setType(this->odim.type);
381 data.setScaling(this->odim.scaling); // needed?
382 }
383
384
385 template <class DT2>
386 inline
387 void copyEncoding(const PlainData<DT2> & srcData){
388 this->odim.importMap(srcData.odim);
389 data.setType(this->odim.type);
390 data.setScaling(this->odim.scaling); // needed?
391 }
392
393 inline
394 void setPhysicalRange(double min, double max){
395 //data.setPhysicalScale(min, max);
396 data.setPhysicalRange(min, max, true);
397 // data.setOptimalScale();
398 this->odim.scaling.assignSequence(data.getScaling());
399 // odim.scaling.scale = data.getScaling().scale; // needed?
400 // odim.scaling.offset = data.getScaling().offset; // needed?
401 }
402
403
404
406 inline
407 void setGeometry(size_t cols, size_t rows){
408 this->odim.setGeometry(cols, rows);
409 data.setGeometry(cols, rows);
410 }
411
413 inline
415 this->odim.setGeometry(geometry.getWidth(), geometry.getHeight());
416 data.setGeometry(geometry);
417 }
418
420
423 inline
424 void setGeometry(const odim_t & odim){
425 this->odim.setGeometry(odim.area);
426 data.setGeometry(odim.area);
427 // Note:
428 this->odim.resolution = odim.resolution;
429 }
430
432
435 template <class DT2>
436 inline
437 void copyGeometry(const PlainData<DT2> & srcData){
438 setGeometry(srcData.odim);
439 /*
440 this->odim.setGeometry(srcData.odim.area);
441 data.setGeometry(srcData.odim.area);
442 // Note:
443 this->odim.resolution = srcData.odim.resolution;
444 */
445 }
446
448 template <class T>
449 inline
450 void initialize(const T & type, size_t cols, size_t rows){
451 setEncoding(type);
452 setGeometry(cols, rows);
453 }
454
455 template <class T>
456 inline
457 void initialize(const T & type, const drain::image::AreaGeometry & geometry){
458 setEncoding(type);
459 setGeometry(geometry);
460 }
461
462 // NEW policy.
464 inline
466 setEncoding(odim.type);
467 setGeometry(odim.area);
468 }
469
471 template <class ...T>
472 inline
473 void initializeBest(const std::type_info & type, const T & ...args){
474 odim.setType(type);
475 initializeBest(args...);
476 }
477
479 template <class ...T>
480 inline
481 void initializeBest(const std::string & type, const T & ...args){
482 odim.setType(type);
483 initializeBest(args...);
484 }
485
487 template <class ...T>
488 inline
489 void initializeBest(const drain::image::AreaGeometry & geometry, const T & ...args){
490 odim.area.set(geometry);
491 initializeBest(args...);
492 }
493
495 template <class ...T>
496 inline
497 void initializeBest(const EncodingODIM & encoding, const T & ...args){
498 odim.updateFromMap(encoding); // importMap can NOT be used because non-EncodingODIM arg will have a larger map
499 odim.scaling.physRange.set(encoding.scaling.physRange);
500 initializeBest(args...);
501 }
502
503
504 // inline
505 void setNyquist(double nyquistSpeed){
506 odim.NI = nyquistSpeed;
507 odim.setRange(-odim.NI, +odim.NI);
508 data.setScaling(odim.scaling);
509 }
510
511
512 // Data array
513 image_t & data;
514
515 // Metadata structure
516 odim_t odim; // 2023/01 considered ...raising to TreeContainer
517
518 //drain::Legend legend;
519
520 // Possibly this should be somewhere else? (Too specific here?)
522 void createSimpleQualityData(drain::image::Image & qualityImage, double dataQuality=1.0, double undetectQuality=0.5, double nodataQuality=0.0) const;
523
524 // Possibly this should be somewhere else? (Too specific here?)
526 inline
527 void createSimpleQualityData(PlainData<DT> & qualityData, double dataQuality=1.0, double undetectQuality=0.5, double nodataQuality=0.0) const { //, double dataQuality=1.0, double nodataQuality=0.0) const {
528 qualityData.setEncoding(typeid(unsigned char));
529 createSimpleQualityData(qualityData.data, dataQuality, undetectQuality, nodataQuality);
530 qualityData.odim.scaling.set(qualityData.data.getScaling());
531 //qualityData.odim.scaling.scale = qualityData.data.getScaling().scale;
532 //qualityData.odim.scaling.offset = qualityData.data.getScaling().offset;
533 }
534
536 inline
538 ODIM::updateH5AttributeGroups<ODIMPathElem::DATA>(this->odim, this->tree);
539 DataTools::updateInternalAttributes(this->tree); // Needed? The subtree is small... But for quality field perhaps.
540 }
541
542
543protected:
544
545
546};
547
551template <typename DT> // PlainData<DT> & quality
552void PlainData<DT>::createSimpleQualityData(drain::image::Image & quality, double dataQuality, double undetectQuality, double nodataQuality) const {
553
554 quality.setPhysicalRange(0.0, 1.0, true);
555
556 const drain::ValueScaling & scaling = quality.getScaling();
557
558 const bool DATA = !std::isnan(dataQuality);
559 const bool UNDETECT = !std::isnan(undetectQuality);
560 const bool NODATA = !std::isnan(nodataQuality);
561
562 // Default ie. unset values are non_signaling_NAN's, but maybe more elegant to skip calculations:
563 const double dataCode = DATA ? scaling.inv(dataQuality) : 0.0;
564 const double undetectCode = UNDETECT ? scaling.inv(undetectQuality) : 0.0;
565 const double nodataCode = NODATA ? scaling.inv(nodataQuality) : 0.0;
566
567 quality.setGeometry(data.getWidth(), data.getHeight());
568
569 Image::iterator it = data.begin();
570 Image::iterator wit = quality.begin();
571 while (it != data.end()){
572 //if ((*it != odim.nodata) && (*it != odim.undetect))
573 if (UNDETECT && (*it == this->odim.undetect))
574 *wit = undetectCode;
575 else if (NODATA && (*it == this->odim.nodata))
576 *wit = nodataCode;
577 else if (DATA)
578 *wit = dataCode;
579 ++it;
580 ++wit;
581 }
582
583 /*
584 const double d = scaling.inv(dataQuality);
585 const double nd = scaling.inv(nodataQuality);
586 const double un = scaling.inv(undetectQuality);
587
588 quality.setGeometry(data.getWidth(), data.getHeight());
589
590 Image::iterator it = data.begin();
591 Image::iterator wit = quality.begin();
592 while (it != data.end()){
593 //if ((*it != odim.nodata) && (*it != odim.undetect))
594 if (*it == odim.nodata)
595 *wit = nd;
596 else if (*it == odim.undetect)
597 *wit = un;
598 else
599 *wit = d;
600 ++it;
601 ++wit;
602 }
603 */
604
605}
606
607
608
612template <typename DT>
613inline
614std::ostream & operator<<(std::ostream & ostr, const PlainData<DT> & d){
615 ostr << d.data << ", ODIM:\t ";
616 ostr << d.odim << '\n';
617 ostr << "props: " << d.data.properties << '\n';
618 return ostr;
619}
620
621
623
635template <class DT, ODIMPathElem::group_t G>
636class DataGroup : public TreeWrapper<typename DT::datatype_t>, public std::map<std::string, DT > { // typename T::datatype_t
637public:
638
639 typedef DataGroup<DT,G> datagroup_t; // this type
640 typedef DT data_t;
641 typedef typename DT::datatype_t datatype_t;
642 typedef std::map<std::string, DT > map_t;
643
644 // Experimental. Mainly for geometry (width, height) - but also for date+time or elangle?
645 /*
646 typedef typename DT::odim_t odim_t;
647 odim_t baseODIM;
648
649
650 inline
651 void setGeometry(size_t width, size_t height){
652 baseODIM.setGeometry(width, height);
653 }
654
655 inline
656 void setGeometry(const drain::image::AreaGeometry & geometry){
657 baseODIM.setGeometry(geometry);
658 }
659 */
660 //typename DT::odim_t odim;// 2023/01 experimental
661
662
664
665 // DataGroup(typename DT::tree_t & tree, const drain::RegExp & quantityRegExp = drain::RegExp()) :
666 // TreeWrapper<typename DT::datatype_t>(tree), odim(tree.data.image) {
667 DataGroup(typename DT::tree_t & tree, const QuantitySelector & slct = QuantitySelector()) :
668 TreeWrapper<typename DT::datatype_t>(tree) { //, baseODIM(ODIMPathElem::DATASET) {
669 init(tree, *this, slct);
670 }
671 //init(tree, *this, quantityRegExp);
672
673 /*
674 DataGroup(typename DT::tree_t & tree, const drain::RegExp & quantityRegExp = drain::RegExp()) :
675 TreeWrapper<typename DT::datatype_t>(tree) {
676 init(tree, *this, quantityRegExp);
677 }
678 */
679
680 // TreeWrapper<typename DT::datatype_t>(src.tree), odim(src.tree.data.image) {
681
682 DataGroup(const datagroup_t & src) :
683 TreeWrapper<typename DT::datatype_t>(src.tree) { // , baseODIM(ODIMPathElem::DATASET){
684 adapt(src, *this); // ALERT: includes all the quantities, even thoug src contained only some of them
685 }
686
687
688 virtual
689 ~DataGroup(){
690 /*
691 drain::Logger mout("DataGroup<" + ODIMPathElem::getKey(G)+">", __FUNCTION__);
692 switch (this->size()) {
693 case 0:
694 mout.debug3("no data<n> groups" );
695 break;
696 default:
697 mout.info("several Data groups, using: " , this->begin()->first );
698 // no break;
699 case 1:
700 mout.debug("updating from 1st data: " , this->begin()->first );
701 updateTree3(this->getFirstData().odim); // tree
702 }
703 */
704 };
705
706
707 bool has(const std::string & quantity) const {
708 return (this->find(quantity) != this->end());
709 }
710
711 inline
712 const data_t & getData(const char *quantity) const {
713 return getData(std::string(quantity));
714 //return getData(quantity.c_str());
715 }
716
717
718 const data_t & getData(const std::string & quantity) const {
719
720 //drain::Logger mout(__FILE__, __FUNCTION__); //
721 drain::Logger mout(__FUNCTION__, "DataGroup{" + ODIMPathElem::getKey(G) + "}");
722
723 typename datagroup_t::const_iterator it = this->find(quantity);
724
725 if (it != this->end()){
726 mout.debug3('[' , quantity , "]\t = " , it->first );
727 return it->second;
728 }
729 else {
730 mout.debug('[' , quantity , "] not found, returning empty" );
731 return getEmpty();
732 }
733 }
734
735 inline
736 data_t & getData(const char *quantity) {
737 return getData(std::string(quantity));
738 //return getData(quantity.c_str());
739 }
740
741
742 data_t & getData(const std::string & quantity) {
743
744 //drain::Logger mout(__FILE__, __FUNCTION__); //REPL "DataGroup." + ODIMPathElem::getKey(G), __FUNCTION__);
745 drain::Logger mout(__FUNCTION__, "DataGroup{" + ODIMPathElem::getKey(G) + "}");
746
747 //mout.warn("non-const " );
748 typename datagroup_t::iterator it;
749 #pragma omp critical //(h5insert)
750 {
751 it = this->find(quantity);
752 if (it != this->end()){
753 mout.debug3("found " , it->first );
754 }
755 else {
756 //mout.note("not found, creating new data array" );
757 ODIMPathElem child(G);
758 ODIMPathTools::getNextChild(this->tree, child);
759 mout.debug3("add: " , child , " [" , quantity , ']' );
760 it = this->insert(this->begin(), typename map_t::value_type(quantity, DT(this->getTree()[child], quantity))); // WAS [path]
761 // it->second.setGeometry(baseODIM.getGeometry());
762 }
763 }
764 return it->second;
765
766 }
767
768 //const data_t& getData(const drain::RegExp & regExp) const {
769 const data_t& getData(const QuantitySelector & slct) const {
770
771 //drain::Logger mout("DataGroup." + ODIMPathElem::getKey(G)+"(RegExp) {const}", __FUNCTION__);
772 drain::Logger mout(__FUNCTION__, "(KeySelector): ", "DataGroup{" + ODIMPathElem::getKey(G)+"}");
773
774 // NEW
775 for (const drain::StringMatcher & m: slct.getList()){
776 for (const auto & entry: *this){
777 if (m.test(entry.first)){
778 mout.debug("quantity " , entry.first , " matches " , slct);
779 return entry.second;
780 }
781 }
782 }
783
784 /* OLD
785 for (typename datagroup_t::const_iterator it = this->begin(); it != this->end(); ++it){
786 if (slct.testQuantity(it->first)){
787 mout.debug("quantity " , it->first , " matches " , slct);
788 return it->second;
789 }
790 }
791 */
792
793 mout.note("no quantity matched with " , slct);
794
795 return getEmpty();
796
797 }
798
800
805 data_t & create(const std::string & quantity) { // , const std::string & templateQuantity, const std::string & encodingParams) {
806 data_t & d = getData(quantity);
807 d.setGeometry(0, 0); // in case existed already
808 //getQuantityMap().setQuantityDefaults(d, templateQuantity, encodingParams);
809 return d;
810 }
811
812
813 data_t & getFirstData() {
814
815 for (auto & entry: *this){
816 if (!entry.second.isExcluded()){
817 return entry.second;
818 }
819 }
820
821 drain::Logger(__FILE__, __LINE__, "DataGroup{" + ODIMPathElem::getKey(G)+"}:", __FUNCTION__).error("no data");
822 //mout.error("no data" );
823 return this->getData(""); // empty?
824
825 /*
826 const typename datagroup_t::iterator it = this->begin();
827
828 if (it == this->end()){
829 //drain::Logger mout("DataGroup." + ODIMPathElem::getKey(G), __FUNCTION__);
830 drain::Logger mout(__FUNCTION__, "DataGroup{" + ODIMPathElem::getKey(G)+"}");
831
832 mout.error("no data" );
833 return this->getData("");
834 }
835 else
836 return it->second;
837 */
838 }
839
840 const data_t & getFirstData() const {
841
842 for (const auto & entry: *this){
843 if (!entry.second.isExcluded()){
844 return entry.second;
845 }
846 }
847
848 drain::Logger(__FILE__, __LINE__, "DataGroup{" + ODIMPathElem::getKey(G)+"}:", __FUNCTION__).error("no data");
849 return this->getData(""); // empty?
850
851
852 //drain::Logger mout("DataGroup." + ODIMPathElem::getKey(G) + " {const}", __FUNCTION__);
853 /*
854 drain::Logger mout(__FUNCTION__, "DataGroup{" + ODIMPathElem::getKey(G)+"}");
855
856 //mout.warn("const" );
857
858 typename datagroup_t::const_iterator it = this->begin();
859
860 if (it != this->end()){
861 mout.debug2("found: " , it->first );
862 return it->second;
863 }
864 else {
865 mout.note("not found, returning empty" );
866 return getEmpty();
867 }
868 */
869
870 }
871
872
873 // experimental
874 data_t & getLastData() {
875
876 const typename datagroup_t::reverse_iterator it = this->rend();
877
878 if (it == this->rbegin()){
879 drain::Logger mout(__FUNCTION__, "DataGroup{" + ODIMPathElem::getKey(G)+"}");
880 mout.error("no data" );
881 return this->getData("");
882 }
883 else
884 return it->second;
885
886 }
887
888 // experimental
889 const data_t & getLastData() const {
890
891 drain::Logger mout(__FUNCTION__, "DataGroup{" + ODIMPathElem::getKey(G) + "}-const");
892
893 //mout.warn("const" );
894
895 typename datagroup_t::const_reverse_iterator it = this->rend();
896
897 if (it != this->rbegin()){
898 mout.debug2("found: " , it->first );
899 return it->second;
900 }
901 else {
902 mout.note("not found, returning empty" );
903 return getEmpty();
904 }
905
906
907 }
908
909
910protected:
911
912 static
913 const data_t & getEmpty() {
914 static typename DT::tree_t t;
915 static data_t empty(t);
916 return empty;
917 }
918
920
925 static
926 typename DT::tree_t & init(typename DT::tree_t & t, datagroup_t & dst, const QuantitySelector & slct = QuantitySelector()){
927 // typename DT::tree_t & init(typename DT::tree_t & t, datagroup_t & dst, const drain::RegExp & quantityRegExp = drain::RegExp()){
928
929 //drain::Logger mout("DataGroup." + ODIMPathElem::getKey(G), __FUNCTION__);
930 drain::Logger mout(__FUNCTION__, "DataGroup{" + ODIMPathElem::getKey(G)+"}");
931
932 //const bool USE_REGEXP = quantityRegExp.isSet();
933 const bool USE_SELECTOR = slct.isSet();
934
935 // Number of potential groups for debug note at end
936 unsigned short counter = 0;
937
938 mout.debug3("collecting data items, selector='", slct, "'");
939 //if (USE_REGEXP)
940 // mout << ", regExp=" << quantityRegExp.toStr();
941 //mout << mout.endl;
942
943 // #pragma omp critical //(h5insert2)
944 {
945 // add UKMO
946
947 const std::string datasetQuantity = t[ODIMPathElem::WHAT].data.attributes.get("quantity", "");
948
949 //for (typename DT::tree_iter_t it=t.begin(); it!=t.end(); ++it){
950 for (auto & entry: t){
951
953 if (! (entry.first.is(G))){
954 //mout.warn("skip '" , it->first , "' \t group != " , G );
955 continue;
956 }
957
958 //const std::string dataQuantity = it->second["what"].data.attributes["quantity"];
959 //const std::string dataQuantity = it->second[ODIMPathElem::WHAT].data.attributes["quantity"];
960 const std::string dataQuantity = entry.second[ODIMPathElem::WHAT].data.attributes.get("quantity", ""); // otherways comes "null"
961
962 const std::string & quantity = !dataQuantity.empty() ? dataQuantity : datasetQuantity;
963
964 if (USE_SELECTOR){
965 ++counter; // candidate count
966 if (!slct.test(quantity)){
967 //if (!quantityRegExp.test(quantity)){
968 //if (it->second.hasChild("quality1"))
969 // mout.warn(it->first , "...rejecting, but has quality?" );
970 mout.debug3("rejected '" , entry.first , "' [" , quantity , "] !~" , slct ); // quantityRegExp.toStr()
971 continue;
972 }
973 }
974
975 /*
976 if (USE_REGEXP){
977 ++counter; // candidate count
978 if (!quantityRegExp.test(quantity)){
979 //if (it->second.hasChild("quality1"))
980 // mout.warn(it->first , "...rejecting, but has quality?" );
981 mout.debug3("rejected '" , entry.first , "' [" , quantity , "] !~" , quantityRegExp.toStr() );
982 continue;
983 }
984 }
985 */
986
987 mout.accept<LOG_DEBUG+2>("accept '", entry.first, "' [", quantity, ']' );
988
989 /*
990 mout.warn(entry.first, " 1st -> ", entry.second[ODIMPathElem::ARRAY].data.image);
991 mout.fail("type", drain::TypeName<DT>::get());
992 DT(entry.second, quantity);
993 mout.warn(entry.first, " 1bst-> ", entry.second[ODIMPathElem::ARRAY].data.image);
994 */
995
996 if (quantity.empty()){
997 //drain::Logger mout("DataSet", __FUNCTION__);
998 mout.info("quantities dataset:'", datasetQuantity, "', data:'", dataQuantity, "'");
999 mout.warn("undefined quantity in ", entry.first, ", using key=", entry.first );
1000 // Assign by path component "data3"
1001 dst.insert(typename map_t::value_type(entry.first, DT(entry.second, entry.first)));
1002 //associate(dst, it->first, it->second);
1003 }
1004 else {
1005 if (dst.find(quantity) != dst.end()){ // already created
1006 //drain::Logger mout("DataSet", __FUNCTION__);
1007 mout.warn("quantity '" , quantity , "' replaced same quantity at " , entry.first );
1008 }
1009 dst.insert(typename map_t::value_type(quantity, DT(entry.second, quantity)));
1010 //typename datagroup_t::reverse_iterator rit = dst.rend();
1011 //mout.warn("last '" , "' [" , quantity , '=' , rit->first , ']' , rit->second );
1012 //dst[quantity] = T(it->second);
1013 // mout.warn(entry.first, " 2nd -> ", entry.second[ODIMPathElem::ARRAY].data.image);
1014 }
1015 }
1016 } // end pragma
1017
1018 if (USE_SELECTOR)
1019 mout.debug3("matched " , dst.size() , "(out of " , counter , ") data items with selector: " , slct , '/' );
1020 //mout.debug3("matched " , dst.size() , "(out of " , counter , ") data items with RegExp=/" , quantityRegExp.toStr() , '/' );
1021 else
1022 mout.debug3("collected " , dst.size() , " data items" );
1023
1024 return t;
1025 };
1026
1027
1028 static
1029 //typename D::tree_t & adapt(typename D::tree_t & t, datagroup_t & dst, const datagroup_t & src){
1030 typename DT::tree_t & adapt(const datagroup_t & src, datagroup_t & dst){
1031
1032 drain::Logger mout(__FUNCTION__, "DataGroup{" + ODIMPathElem::getKey(G)+"}");
1033
1034 // drain::Logger mout("DataGroup." + ODIMPathElem::getKey(G), __FUNCTION__);
1035 // drain::Logger mout(__FILE__, __FUNCTION__);
1036
1037 if (src.empty()){
1038 mout.debug3("src empty" );
1039 return src.tree;
1040 }
1041 else {
1042 for (const auto & entry: src){
1043 dst.insert(entry);
1044 }
1045 }
1046
1047 /*
1048 for (typename datagroup_t::const_iterator it=src.begin(); it!=src.end(); ++it){
1049 //dst.insert(typename map_t::value_type(it->first, D(it->second, it->first)));
1050 //dst.insert(typename map_t::value_type(it->first, D(it->second)));
1051 dst.insert(typename map_t::value_type(it->first, it->second));
1052 }
1053 */
1054 mout.debug3("adapted ", dst.size(), " data items; ", src.begin()->first, "...");
1055
1056 //return t
1057 return src.tree;
1058 };
1059
1060
1061};
1062
1063template <class DT, ODIMPathElem::group_t G>
1064std::ostream & operator<<(std::ostream & ostr, const DataGroup<DT,G> & d){
1065 // ostr << "-- dataGroup ";
1066 char separator = 0;
1068 for (typename DataGroup<DT,G>::const_iterator it = d.begin(); it != d.end(); ++it){
1069 if (separator)
1070 ostr << separator;
1071 else {
1072 separator = ',';
1073 g.setGeometry(it->second.data.getGeometry());
1074 }
1075 ostr << it->first << '[' << drain::Type::getTypeChar(it->second.data.getType()) << ']';
1076 }
1077 ostr << " ("<< g << ")";
1078 /*
1079 ostr << d.data << ", ODIM:\t ";
1080 ostr << d.odim << '\n';
1081 ostr << "props: " << d.data.properties << '\n';
1082 */
1083 return ostr;
1084}
1085
1086
1088
1093template <typename DT>
1095
1096public:
1097
1098 typedef PlainData<DT> plaindata_t;
1099
1101
1102
1103 inline
1104 QualityDataSupport(typename plaindata_t::tree_t & tree) : quality(tree) {};
1105
1106 inline
1107 QualityDataSupport(const QualityDataSupport<DT> & qds) : quality(qds.quality) {};
1108
1109 virtual inline
1111
1113 /*
1114 * \param quantity - quality quantity, "QIND" by default.
1115 * \return - \c data[i]/quality[j] for which \c quantity=[quantity]
1116 *
1117 */
1118 inline
1119 const plaindata_t & getQualityData(const std::string & quantity = "QIND") const {
1120 return this->quality.getData(quantity);
1121 }
1122
1124 /*
1125 * \param quantity - quality quantity, "QIND" by default.
1126 * \return - \c data[i]/quality[j] for which \c quantity=[quantity]
1127 *
1128 */
1129 /*
1130 inline
1131 const plaindata_t & getQualityData(const drain::RegExp & quantityRE) const {
1132 return this->quality.getData(quantityRE);
1133 }
1134 */
1135
1136
1138 /*
1139 * \param quantity - quality quantity, "QIND" by default.
1140 * \return - \c data[i]/quality[j] for which \c quantity=[quantity]
1141 *
1142 */
1143 inline
1144 plaindata_t & getQualityData(const std::string & quantity = "QIND") {
1145 return this->quality.getData(quantity);
1146 }
1147
1148
1149 inline
1150 bool hasQuality() const {
1151 return !this->quality.empty();
1152 }
1153
1154 inline
1155 bool hasQuality(const std::string & quantity) const {
1156 return this->quality.find(quantity) != this->quality.end();
1157 }
1158
1159 inline
1160 const qualitygroup_t & getQuality() const {
1161 return this->quality;
1162 }
1163
1164 inline
1165 qualitygroup_t & getQuality(){
1166 return this->quality;
1167 }
1168
1169 /* Well, needs quantity, primarily. So best place perhaps not here.
1170 static
1171 void createSimpleQualityData(PlainData<DT> & data, drain::image::Image & qualityImage, double dataQuality=1.0, double undetectQuality=0.5, double nodataQuality=0.0) const;
1172
1173 static inline
1174 void createSimpleQualityData(PlainData<DT> & data, PlainData<DT> & qualityData, double dataQuality=1.0, double undetectQuality=0.5, double nodataQuality=0.0) const { //, double dataQuality=1.0, double nodataQuality=0.0) const {
1175 qualityData.setEncoding(typeid(unsigned char));
1176 createSimpleQualityData(qualityData.data, dataQuality, undetectQuality, nodataQuality);
1177 qualityData.odim.scaling.set(qualityData.data.getScaling());
1178 //qualityData.odim.scaling.offset = qualityData.data.getScaling().offset;
1179 }
1180 */
1181
1182protected:
1183
1184 qualitygroup_t quality;
1185
1186};
1187
1188
1189
1190/*
1191 * Data<PolarSrc> will return
1192 *
1193 * Quality field:
1194 * - NONE: reference to dummy.
1195 * - LAST: reference to last existing quality[1].
1196 * - NEXT: reference to new quality[N+1], where N is the last
1197 */
1198
1200
1205template <typename DT>
1206class Data : public PlainData<DT>, public QualityDataSupport<DT> {
1207public:
1208
1209 typedef PlainData<DT> plaindata_t;
1210
1211 Data(typename DT::tree_t & tree) : PlainData<DT>(tree), QualityDataSupport<DT>(tree) {
1212 }
1213
1214 Data(typename DT::tree_t & tree, const std::string & quantity) : PlainData<DT>(tree, quantity), QualityDataSupport<DT>(tree) {
1215 }
1216
1217 Data(const Data<DT> & d) : PlainData<DT>(d), QualityDataSupport<DT>(d) { // was: d.tree, d.tree
1218 }
1219
1220 // Data(const Hi5Tree & src, const std::string & quantity = "^DBZH$");
1221 virtual ~Data(){};
1222
1223 // Experimental
1224 void swap(Data<DT> &d){ // TODO: also for plaindata?
1225
1226 drain::Logger mout("Data<DT>", __FUNCTION__);
1227 mout.experimental("Swapping...");
1228 this->tree.swap(d.tree);
1229
1230 typename DT::odim_t odim;
1231 odim.updateFromMap(this->odim);
1232 this->odim.updateFromMap(d.odim);
1233 d.odim.updateFromMap(odim);
1234
1235 this->updateTree2();
1236 d.updateTree2();
1237 }
1238
1239protected:
1240
1241};
1242
1243
1244
1245
1246
1247template <typename DT>
1248inline
1249std::ostream & operator<<(std::ostream & ostr, const Data<DT> & d){
1250 ostr << d.data << ", ODIM:\t "; // .getGeometry()
1251 ostr << d.odim; // << '\n';
1252 //ostr << d.data.properties << '\n';
1253 if (d.hasQuality()){
1254 //ostr << " (has quality field)";
1255 ostr << "+q(" << d.getQuality() << ')';
1256 /*
1257 const PlainData<T,D,M> & q = d.getQuality();
1258 ostr << '\t' << q.data.getGeometry() << '\t';
1259 ostr << q.odim << '\n';
1260 ostr << '\t' << q.data.properties << '\n';
1261 */
1262 }
1263 ostr << '\n';
1264 return ostr;
1265}
1266
1267
1269
1274template <typename DT>
1275class DataSet : public DataGroup<Data<DT>,ODIMPathElem::DATA>, public QualityDataSupport<DT> { // typename T::data_t
1276public:
1277
1278 typedef Data<DT> data_t;
1279 typedef PlainData<DT> plaindata_t;
1280 typedef typename DataGroup<data_t,ODIMPathElem::DATA>::datagroup_t datagroup_t; // ODIMPathElem::DATA>
1281 typedef typename datagroup_t::map_t map_t;
1282
1283
1284 inline
1286 //DataSet(typename data_t::tree_t & tree, const drain::RegExp & quantityRegExp = drain::RegExp()) :
1287 DataSet(typename data_t::tree_t & tree, const QuantitySelector & slct =QuantitySelector()) :
1288 //datagroup_t(tree, quantityRegExp), QualityDataSupport<DT>(tree)
1290 {
1291 }
1292
1293 DataSet(const DataSet<DT> & ds) : datagroup_t(ds), QualityDataSupport<DT>(ds) {
1294 }
1295
1296 ~DataSet(){
1297
1298 drain::Logger mout(__FILE__, __FUNCTION__);
1299
1300 switch (this->size()) {
1301 case 0:
1302 mout.debug3("no data<n> groups" );
1303 break;
1304 default:
1305 mout.info("several Data groups, using: " , this->begin()->first );
1306 // no break;
1307 case 1:
1308 mout.debug2("updating from 1st data: " , this->begin()->first );
1309
1310
1311 const typename DT::odim_t & odim = this->getFirstData().odim;
1312
1313 /*
1314 // DEBUGGING 2024
1315 for (const auto & entry: this->baseODIM){
1316 if (odim[entry.first] == entry.second){
1317 mout.reject("BaseODIM differs: ", entry.first, ": ", entry.second, " vs ", odim[entry.first]);
1318 }
1319 }
1320 */
1321
1322 // updateTree3(this->getFirstData().odim);
1323 // mout.attention("start updateTree3");
1324 updateTree3(odim);
1325 // mout.attention("end updateTree3");
1326 }
1327
1328 }
1329
1330
1331 plaindata_t & getQualityData2(const std::string & quantity = "QIND", const std::string & dataQuantity = ""){ // , bool tmp = false
1332 if (dataQuantity.empty())
1333 return this->getQualityData(quantity);
1334 else {
1335 return this->getData(dataQuantity).getQualityData(quantity);
1336 }
1337 }
1338
1339
1340 const plaindata_t & getQualityData2(const std::string & quantity = "QIND", const std::string & dataQuantity = "") const { // , bool tmp = false
1341 if (dataQuantity.empty())
1342 return this->getQualityData(quantity);
1343 else {
1344 return this->getData(dataQuantity).getQualityData(quantity);
1345 }
1346 }
1347
1348
1349 inline
1350 void updateTree3(const typename DT::odim_t & odim){ //
1351 ODIM::updateH5AttributeGroups<ODIMPathElem::DATASET>(odim, this->tree);
1352 DataTools::updateInternalAttributes(this->tree); // TEST2019/09 // images, including DataSet.data, TODO: skip children
1353 //DataTools::updateInternalAttributes(this->tree, drain::FlexVariableMap()); // TEST2019/09 // images, including DataSet.data, TODO: skip children
1354 }
1355
1356 // TODO: consider this to destructor!
1357 inline
1358 void updateTree3(const typename DT::odim_t & odim) const { //
1359 std::cout << "updateTree3 const \n";
1360 //ODIM::updateH5AttributeGroups<ODIMPathElem::DATASET>(odim, tree);
1361 }
1362
1363
1364
1365protected:
1366
1367
1368
1370
1386};
1387
1389
1392template <typename DT>
1393std::ostream & operator<<(std::ostream & ostr, const DataSet<DT> & d){
1394 typedef DataSet<DT> dataset_t;
1395 ostr << "dataSet ";
1396 char separator = 0;
1398 for (typename dataset_t::const_iterator it = d.begin(); it != d.end(); ++it){
1399 if (separator)
1400 ostr << separator;
1401 else {
1402 separator = ',';
1403 g.setGeometry(it->second.data.getGeometry());
1404 }
1405 ostr << it->first << '[' << drain::Type::getTypeChar(it->second.data.getType()) << ']';
1406 if (it->second.hasQuality())
1407 ostr << "+Q(" << it->second.getQuality() << ')';
1408 }
1409 ostr << " ("<< g << ")";
1410 if (d.hasQuality())
1411 ostr << " +quality(" << d.getQuality() << ')';
1412 /*
1413 ostr << d.data << ", ODIM:\t ";
1414 ostr << d.odim << '\n';
1415 ostr << "props: " << d.data.properties << '\n';
1416 */
1417 return ostr;
1418}
1419
1420
1423// Becoming DEPRECATED
1424//template <typename DT>
1425//class DataSetMap : public std::map<double, DataSet<DT> > {
1426//};
1427
1428// TIMESTAMPED (what::date + what::time data) or path?
1429template <typename DT>
1430class DataSetMap : public std::map<std::string, DataSet<DT> > {
1431};
1432
1433
1434
1435template <typename DT>
1436class DataSetList : public std::list<DataSet<DT> > {
1437};
1438
1439
1440
1441
1442} // rack::
1443
1444namespace drain {
1445
1446template <class T, typename TI, typename D>
1447struct TypeName<rack::DataType<T,TI,D> > {
1448
1449 static const std::string & str(){
1450 static std::string name = drain::StringBuilder<>("DataType<", drain::TypeName<T>::str(), ',', drain::TypeName<TI>::str(), ',', drain::TypeName<D>::str(), ">");
1451 return name;
1452 }
1453
1454};
1455
1456}
1457
1458
1459#endif /* DATA_H_ */
1460
Definition CastableIterator.h:57
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:313
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition Log.h:431
Logger & error(const TT &... args)
Echoes.
Definition Log.h:417
Logger & accept(const TT &... args)
Some input has been accepted, for example by a syntax.
Definition Log.h:583
void importMap(const std::map< std::string, S > &m)
Assign values from a map, overriding existing entries.
Definition SmartMap.h:251
Definition StringBuilder.h:58
bool test(const std::string &key, bool defaultResult=true) const
Check if key is accepted.
Definition StringMatcherList.h:249
General-purpose key matcher: tests string equality, or regExp, if defined as such.
Definition StringMatcher.h:54
Utilities related to std::type_info.
Definition Type.h:48
Linear scaling and physical range for image intensities.
Definition ValueScaling.h:63
drain::Range< double > physRange
Minimum and maximum physical value of the imaged quantity (not limited to corresponding to minCodeVal...
Definition ValueScaling.h:73
double inv(double y) const
Inverse scaling: given physically meaningful value y, returns the corresponding code value.
Definition ValueScaling.h:300
A map of Variables.
Definition VariableMap.h:61
Definition Geometry.h:143
const iterator & begin()
Returns iterator pointing to the first image element.
Definition ImageFrame.h:114
void setPhysicalRange(const Range< double > &range, bool rescale=false)
Sets the supported range for physical values and optionally adjusts the scaling for maximal resolutio...
Definition ImageFrame.h:101
Class for multi-channel digital images. Supports dynamic typing with base types (char,...
Definition Image.h:183
virtual void setGeometry(size_t width, size_t height, size_t imageChannels=1, size_t alphaChannels=0)
Resizes the image, keeps the current type.
Definition Image.h:87
A map of "data type" group_t (DATA or QUALITY) where the data can be retrieved using quantity keys (s...
Definition Data.h:636
data_t & create(const std::string &quantity)
Creates (or overrides) data array for quantity and scales it.
Definition Data.h:805
static DT::tree_t & init(typename DT::tree_t &t, datagroup_t &dst, const QuantitySelector &slct=QuantitySelector())
Given a dataset h5 subtree, like tree["dataset3"], collects all (or desired) quantities to a data obj...
Definition Data.h:926
DataGroup(typename DT::tree_t &tree, const QuantitySelector &slct=QuantitySelector())
Given a dataset subtree, like tree["dataset3"], constructs a data map of desired quantities.
Definition Data.h:667
Definition Data.h:1436
Definition Data.h:1430
A map of radar data, indexed by quantity code (DBZH, VRAD, etc).
Definition Data.h:1275
DataSet(typename data_t::tree_t &tree, const QuantitySelector &slct=QuantitySelector())
Given a dataset subtree, like tree["dataset3"], constructs a data map of desired quantities.
Definition Data.h:1287
static void updateInternalAttributes(Hi5Tree &src)
Copies values of what , where and how attributes to internal attributes down to data[n] groups.
Definition DataTools.cpp:183
Data structure consisting of plain data and an optional quality data.
Definition Data.h:1206
Structure for data storage type, scaling and marker codes. Does not contain quantity.
Definition EncodingODIM.h:70
std::string type
This is non-standard (not in ODIM), but a practical means of handling storage type of datasets.
Definition EncodingODIM.h:157
Definition ODIMPath.h:81
const std::string & getKey() const
Debugging/logging. Returns standard name. Does not check if type is OTHER.
Definition ODIMPath.h:356
static const group_t WHAT
Metadata group /what , at any depth.
Definition ODIMPath.h:126
static const group_t ARRAY
Data group "data", at deepest level, like /dataset4/data2/quality1/data.
Definition ODIMPath.h:111
static bool getNextChild(const Hi5Tree &tree, ODIMPathElem &child)
Derive a child with index one greater than the largest index encountered.
Definition ODIMPathTools.cpp:96
Essential class for storing radar data.
Definition Data.h:311
void setEncoding(const T &type, const std::string &values="")
Saves type and sets the type of the actual data array as well.
Definition Data.h:368
PlainData(const PlainData< DT2 > &d)
Copy constructor, also for referencing non-const as const.
Definition Data.h:348
void setGeometry(const odim_t &odim)
Copy dimensions of data array and resolution (rscale or xscale,yscale)
Definition Data.h:424
void initializeBest(const EncodingODIM &encoding, const T &...args)
Set encoding and other properties.
Definition Data.h:497
void setGeometry(size_t cols, size_t rows)
Sets dimensions of data array and metadata.
Definition Data.h:407
void copyGeometry(const PlainData< DT2 > &srcData)
Copy dimensions of data array and resolution (rscale or xscale,yscale)
Definition Data.h:437
void copyEncoding(const EncodingODIM &odim)
New, experimental.
Definition Data.h:378
void initializeBest(const std::string &type, const T &...args)
Set storage type and other properties.
Definition Data.h:481
void initializeBest(const drain::image::AreaGeometry &geometry, const T &...args)
Set width and height of the data array, and set other properties.
Definition Data.h:489
void createSimpleQualityData(PlainData< DT > &qualityData, double dataQuality=1.0, double undetectQuality=0.5, double nodataQuality=0.0) const
For this data, creates an on-off quality data.
Definition Data.h:527
void initializeBest(const std::type_info &type, const T &...args)
Set storage type and other properties.
Definition Data.h:473
void createSimpleQualityData(drain::image::Image &qualityImage, double dataQuality=1.0, double undetectQuality=0.5, double nodataQuality=0.0) const
For this data, creates an on-off quality data.
Definition Data.h:552
void updateTree2()
TODO: consider this to destructor.
Definition Data.h:537
void initializeBest()
Terminal step in initialisation: set actual data storage type and resize.
Definition Data.h:465
void setGeometry(const drain::image::AreaGeometry &geometry)
Sets dimensions of data array and metadata.
Definition Data.h:414
PlainData(typename DT::tree_t &tree, const std::string &quantity)
Constructor referring to HDF5 structure.
Definition Data.h:329
void initialize(const T &type, size_t cols, size_t rows)
Calls setEncoding() and setGeometry().
Definition Data.h:450
Base class providing quality support for Dataand DataSet
Definition Data.h:1094
const plaindata_t & getQualityData(const std::string &quantity="QIND") const
Finds associated quality data - maybe empty and unscaled.
Definition Data.h:1119
plaindata_t & getQualityData(const std::string &quantity="QIND")
Finds associated quality data - maybe empty and unscaled.
Definition Data.h:1144
Experimental structure, designed only for accessing root level metadata.
Definition Data.h:261
Base class for all kinds of radar data.
Definition Data.h:155
tree_t & tree
General HDF5 data structure.
Definition Data.h:218
Namespace for images and image processing tools.
Definition AccumulationArray.cpp:45
Definition DataSelector.cpp:1277
Definition DataSelector.cpp:44
Default implementation.
Definition TypeName.h:54
Container that couples together a tree structure and a data array (drain::image::Image),...
Definition Data.h:83
Writable data type.
Definition Data.h:117
Read-only data type.
Definition Data.h:107