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