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