NASA Logo
Ocean Color Science Software

ocssw V2022
Product.hpp
Go to the documentation of this file.
1 
2 #ifndef FOCS_PRODUCT
3 #define FOCS_PRODUCT
4 
5 
6 #include "StringUtils.hpp"
7 
8 #include <iostream>
9 #include <rapidjson/document.h>
10 #include <rapidjson/istreamwrapper.h>
11 #include <rapidjson/writer.h>
12 #include <rapidjson/stringbuffer.h>
13 #include <rapidjson/ostreamwrapper.h>
14 #include "rapidjson/error/en.h"
15 #include <algorithm>
16 #include <complex>
17 #include <cstdint>
18 #include <functional>
19 #include <set>
20 #include <string>
21 #include <typeinfo>
22 #include <vector>
23 #include <memory>
24 #include <type_traits>
25 #include <typeindex>
26 #include <typeinfo>
27 // #include <boost/algorithm/string.hpp>
28 #include <boost/algorithm/string/predicate.hpp>
29 #include <unordered_set>
30 #include <utility>
31 #include <netcdf>
32 #define ROUND_ERROR 0.000001
33 #ifndef ANY_NOEXP
34  #include <experimental/any>
35  #define ANY_CAST std::experimental::any_cast
36  #define ANY std::experimental::any
37 #else
38  #include <any>
39  #define ANY_CAST std::any_cast
40  #define ANY std::any
41 #endif
42 namespace focs {
43  template <typename T, size_t N>
44  struct LinkedList {
45  const T* val;
46  LinkedList<T, N - 1> next;
47  LinkedList() = default;
48  LinkedList(T* arr) {
49  val = arr;
50  next = LinkedList<T, N - 1>(arr + 1);
51  }
52  template <typename... Ts>
53  LinkedList(const T& _val, Ts&... args) {
54  val = &_val;
55  next = LinkedList<T, N - 1>(args...);
56  }
57 
58  T get() const { return *val; }
59  const T* data() const { return val; }
60  };
61 
62  template <typename T>
63  struct LinkedList<T, 0> {
64  const T* val;
65  LinkedList() = default;
66  LinkedList(T* arr) { val = arr; }
67  template <typename... Ts>
68  LinkedList(const T& _val, [[maybe_unused]] Ts&... args) {
69  val = &_val;
70  }
71  T get() const { return *val; }
72  const T* data() const { return val; }
73  };
74  template<typename T>
75  void insert(std::unordered_set<std::type_index> & found_types)
76  {
77  if(found_types.count(std::type_index(typeid(T)))>0)
78  {
79  std::cout << "Error : types are already defined " << typeid(T).name() << std::endl;
80  exit(EXIT_FAILURE);
81  }
82  else
83  {
84  found_types.insert(std::type_index(typeid(T)));
85  }
86  }
87 
88 
89  template<typename ... Ts>
90  struct VisitorAny
91  {
92  std::unordered_set<std::type_index> found_types;
94  {
95  ((insert<Ts>(found_types)),...);
96  }
97  using first_type = std::tuple_element_t<0, std::tuple<Ts...>>;
98 
99  template <typename T>
100  constexpr auto convert(T) const {
101  return first_type{};
102  }
103 
104  template <typename Callable, size_t S, typename... Ps>
105  void visit(Callable&& callable, LinkedList<ANY, S>& list,
106  Ps... params) const {
107  if constexpr (S > 0) {
108  const ANY* any = list.data();
109  (void)(((any->type() == typeid(Ts))
110  ? ((visit(callable, list.next, ANY_CAST<Ts>(any),
111  params...)),
112  false)
113  : true) &&
114  ...);
115  } else {
116  std::forward<Callable>(callable)(*params...);
117  }
118  }
119 
120  template <typename Callable, typename R, size_t S, typename... Ps>
121  void visit(Callable&& callable, R& ret, LinkedList<ANY, S>& list,
122  Ps... params) const {
123  if constexpr (S > 0) {
124  const ANY* any = list.data();
125  (void)(((any->type() == typeid(Ts))
126  ? ((visit(callable, ret, list.next, ANY_CAST<Ts>(any),
127  params...)),
128  false)
129  : true) &&
130  ...);
131  } else {
132  ret = std::forward<Callable>(callable)(*params...);
133  }
134  }
135 
136  template <typename Callable, typename... Tanys>
137  auto apply_visitor(Callable&& callable, Tanys&&... anys) const {
138  using R = decltype(std::declval<Callable>()((convert(anys))...));
139  constexpr size_t N = sizeof...(Tanys);
140  LinkedList<ANY, N> link = LinkedList<ANY, N>(anys...);
141  if constexpr (!std::is_void_v<R>) {
142  R ret{};
143  visit(callable, ret, link);
144  return ret;
145  } else {
146  visit(callable, link);
147  }
148  }
149 
150  };
151  template <typename, typename = void>
152  constexpr bool is_iterable{};
153 
154  template <typename T>
155  constexpr bool is_iterable<T, std::void_t<decltype(std::declval<T>().begin()),
156  decltype(std::declval<T>().end())>> =
157  true;
158  template <typename T>
159  std::ostream& operator<<(std::ostream& os, const std::vector<T>& data) noexcept {
160  for (auto it = data.begin(); it != data.end(); it++) {
161  os << *it << " ";
162  }
163 
164  return os;
165  }
166 
167  template<class T, class F>
168  inline std::pair<const std::type_index, std::function<void(ANY const&)>>
170  {
171  return
172  {
173  std::type_index(typeid(T)),
174  [g = f](ANY const &a)
175  {
176  if constexpr (std::is_void_v<T>)
177  g();
178  else
179  g(ANY_CAST<T const&>(a));
180  }
181  };
182  }
183  // TODO: change attributes to use std::multimap, which will take care of the vector crap
184  // (assuming I don't need more than one dimension for an attribute)?
185  // For now, the NetCdf reader just makes a comma-separated string out of non-scalar attributes.
186  // Stuff downstream can use the StringUtils::stov functions to undo it.
187  // std::vector<std::string>, std::vector<long double>,
188  // std::vector<int8_t>, std::vector<int16_t>, std::vector<int32_t>, std::vector<int64_t>,
189  // std::vector<uint8_t>, std::vector<uint16_t>, std::vector<uint32_t>, std::vector<uint64_t>>;
190  static VisitorAny<char, std::string, float, double, long double, int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t, uint64_t,std::vector<int8_t>,
191  std::vector<int16_t>, std::vector<int32_t>, std::vector<int64_t>, std::vector<float>, std::vector<double>,std::vector<uint8_t>, std::vector<uint16_t>, std::vector<uint32_t>, std::vector<uint64_t>> _visitorAny{};
192  // class that needs to be changed
193  class Attribute {
194  public:
195  Attribute() = default;
196  virtual ~Attribute() = default;
198  const std::string& name() const {return name_;}
199  const ANY & a_value() const {return a_value_;}
200  size_t attr_len() const {return attr_len_;}
201  static Attribute parse_attribute(const netCDF::NcAtt& att);
202  static Attribute parse_attribute(const rapidjson::Value::ConstMemberIterator &data);
203  double as_double() const {
204  return _visitorAny.apply_visitor(AsDouble{},a_value_); //return boost::apply_visitor(AsDouble{}, value_);
205  }
206 
208  return _visitorAny.apply_visitor(AsString{}, a_value_);
209  }
210 
211  template<typename T>
212  std::vector<T> as_vector() const {
213  return _visitorAny.apply_visitor(AsVector<T>{}, a_value_);
214  }
215 
216  friend std::ostream& operator<<(std::ostream& out, const Attribute& attribute){
217  out << attribute.name_ << "=";
218  _visitorAny.apply_visitor(Print{out}, attribute.a_value_);
219  return out;
220  }
221 
222  friend bool operator<(const Attribute& left, const Attribute& right){
223  // if (left.name_ != right.name_){
224  if (!boost::iequals(left.name_, right.name_)){
225  return left.name_ < right.name_;
226  }
227  return _visitorAny.apply_visitor(LessThan{}, left.a_value(), right.a_value());
228  }
229 
230  friend bool operator==(const Attribute& left, const std::string& name){
231  // return (left.name_ == name);
232  return boost::iequals(left.name_, name);
233  }
234  friend bool operator==(const Attribute& left, const Attribute& right){
235  // if (left.name_ != right.name_){
236  if (!boost::iequals(left.name_, right.name_)){
237  return false;
238  }
239  return _visitorAny.apply_visitor(Equals{}, left.a_value(), right.a_value());
240  }
241  static Attribute parse(const std::string& input){
242  auto equals = input.find_first_of('=');
243  size_t name_start = 0;
244  while (input[name_start] == ' '){
245  name_start++;
246  }
247  size_t name_end = equals;
248  while (input[name_end - 1] == ' '){
249  name_end--;
250  }
251  std::string name(input, name_start, name_end - name_start);
252 
253  while (input[++equals] == ' ');
254 
255  switch (input[equals]){
256  case '"':
257  return Attribute{name, input.substr(equals+1, input.size() - equals - 2),1};
258  case '\'':
259  return Attribute{name, input[equals+1],1};
260  default:
261  // TODO
262  // This should probably utilize value suffixes, like C (e.g., to force float, 5f)
263  // I also should check for bad parses
264  if (input.substr(equals) == "true"){
265  return Attribute{name, true,1};
266  } else if (input.substr(equals) == "false"){
267  return Attribute{name, false,1};
268  } else if (input.find_first_of('.') == std::string::npos){
269  return Attribute{name, std::stoi(input.substr(equals)),1};
270  } else {
271  return Attribute{name, std::stof(input.substr(equals)),1};
272  }
273  }
274  }
275 
276 
277  protected:
278  // Attribute name
280  // AttributeType value_;
282  // Attribute length
283  size_t attr_len_;
284  private:
285  struct Print {
286  public:
287  Print(std::ostream& out_) : out{out_} {}
288 
289  void operator()(std::string s) const {
290  out << '"' << s << '"';
291  }
292  void operator()(uint8_t i) const {
293  out << static_cast<int>(i);
294  }
295  void operator()(int8_t i) const {
296  out << static_cast<int>(i);
297  }
298  void operator()(char c) const {
299  out << '\'' << c << '\'';
300  }
301  template <typename T>
302  void operator()(T s) const {
303  out << s;
304  }
305  private:
306  std::ostream& out{std::cout};
307  };
308  struct AsDouble {
309  public:
310  AsDouble() {}
311  template <typename T, std::enable_if_t<!is_iterable<T> && !std::is_same_v<T, std::string>, bool> = true>
312  double operator()(T s) const {
313  return s;
314  }
315  template <typename T, std::enable_if_t<is_iterable<T> && !std::is_same_v<T, std::string>, bool> = true>
316  double operator()(T s) const {
317  return *s.begin();
318  }
319  double operator()(std::string s) const {
320  return std::stod(s);
321  }
322  };
323  struct AsString {
324  public:
325  AsString() {}
326  template <typename T, std::enable_if_t<!is_iterable<T> && !std::is_same_v<T, std::string>, bool> = true>
327  std::string operator()(T s) const {
328  return std::to_string(s);
329  }
330  template <typename T, std::enable_if_t<is_iterable<T> && !std::is_same_v<T, std::string>, bool> = true>
331  std::string operator()(T s) const {
332  std::string out = "";
333  for (const auto& v : s)
334  {
335  out += std::to_string(v);
336  }
337  return out;
338  }
339  std::string operator()(std::string s) const {
340  return s;
341  }
342  };
343  template<typename T>
344  struct AsVector {
345  public:
346  AsVector() {}
347  template <typename I>
348  std::vector<T> operator()(I s) const {
349  return std::vector<T>(s);
350  }
351  std::vector<T> operator()(std::string s) const {
352  return focs::StringUtils::stov<T>(s);
353  }
354  };
355 
356  struct Equals {
357  template <typename T, typename U, std::enable_if_t<(is_iterable<T> && !is_iterable <U>) && (!std::is_same_v<T, std::string> || !std::is_same_v<U, std::string>), bool> = true>
358  bool operator() (T a, U b) const { return operator()( a.at(0), b); }
359  template <typename T, typename U, std::enable_if_t<(!is_iterable<T> && is_iterable <U>) && (!std::is_same_v<T, std::string> || !std::is_same_v<U, std::string>), bool> = true>
360  bool operator() (T a, U b) const { return operator()(a , b.at(0)); }
361  template <typename T, typename U, std::enable_if_t<(is_iterable<T> && is_iterable <U>) && (!std::is_same_v<T, std::string> || !std::is_same_v<U, std::string>), bool> = true>
362  bool operator() (T a, U b) const { return operator()(a.at(0) , b.at(0)); }
363  template <typename T, std::enable_if_t<!is_iterable<T> && !std::is_same_v<T, std::string>, bool> = true>
364  bool operator() (T a, T b) const { return a == b; }
365  bool operator()(const std::string& a, const std::string& b) const { return a == b; }
366 
367  template <typename T, std::enable_if_t<!is_iterable<T> && !std::is_same_v<T, std::string>, bool> = true>
368  bool operator()(std::string, T) const { return false; /* throw std::invalid_argument("Can't compare std::string to non-std::string"); */ }
369  template <typename T, std::enable_if_t<!is_iterable<T> && !std::is_same_v<T, std::string>, bool> = true>
370  bool operator()(T, std::string) const { return false; /* throw std::invalid_argument("Can't compare std::string to non-std::string"); */ }
371 
372  // Integer comparison (extra work to avoid signed/unsigned comparison)
374  bool operator() (T a, U b) const { return a == b; }
376  bool operator() (T a, U b) const {
377  if (b < 0){
378  return false;
379  }
380  return static_cast<U>(a) == b;
381  }
383  bool operator() (T a, U b) const {
384  if (a < 0){
385  return false;
386  }
387  return a == static_cast<T>(b);
388  }
389 
390  // Non-integer comparison
392  bool operator() (T a, U b) const { return std::abs(a - b) < ROUND_ERROR; }
394  bool operator() (T a, U b) const { return std::abs(static_cast<double>(a) - b) < ROUND_ERROR; }
396  bool operator() (T a, U b) const { return std::abs(a - static_cast<double>(b)) < ROUND_ERROR; }
397  };
398  struct LessThan {
399  template <typename T, typename U, std::enable_if_t<(is_iterable<T> && !is_iterable <U>) && (!std::is_same_v<T, std::string> || !std::is_same_v<U, std::string>), bool> = true>
400  bool operator() (T a, U b) const { return operator()( a.at(0), b); }
401  template <typename T, typename U, std::enable_if_t<(!is_iterable<T> && is_iterable <U>) && (!std::is_same_v<T, std::string> || !std::is_same_v<U, std::string>), bool> = true>
402  bool operator() (T a, U b) const { return operator()(a , b.at(0)); }
403  template <typename T, typename U, std::enable_if_t<(is_iterable<T> && is_iterable <U>) && (!std::is_same_v<T, std::string> || !std::is_same_v<U, std::string>), bool> = true>
404  bool operator() (T a, U b) const { return operator()(a.at(0) , b.at(0)); }
405 
406  template <typename T, std::enable_if_t<!is_iterable<T> && !std::is_same_v<T, std::string>, bool> = true>
407  bool operator() (T a, T b) const { return a < b; }
408  bool operator()(const std::string& a, const std::string& b) const { return a < b; }
409 
410  template <typename T, std::enable_if_t<!is_iterable<T> && !std::is_same_v<T, std::string>, bool> = true>
411  bool operator()(std::string, T) const { return false; /* throw std::invalid_argument("Can't compare std::string to non-std::string"); */ }
412  template <typename T, std::enable_if_t<!is_iterable<T> && !std::is_same_v<T, std::string>, bool> = true>
413  bool operator()(T, std::string) const { return false; /* throw std::invalid_argument("Can't compare std::string to non-std::string"); */ }
414 
415  // Integer comparison (extra work to avoid signed/unsigned comparison)
417  bool operator() (T a, U b) const { return a < b; }
419  bool operator() (T a, U b) const {
420  if (b < 0){
421  return false;
422  }
423  return static_cast<U>(a) < b;
424  }
426  bool operator() (T a, U b) const {
427  if (a < 0){
428  return true;
429  }
430  return a < static_cast<T>(b);
431  }
432 
433  // Non-integer comparison
435  bool operator() (T a, U b) const { return a < b; }
437  bool operator() (T a, U b) const { return static_cast<double>(a) < b; }
439  bool operator() (T a, U b) const { return a < static_cast<double>(b); }
440  };
441  };
443  public:
445  virtual bool matches(const Attribute& attribute) const {(void)attribute; return false;}
446  friend std::ostream& operator<<(std::ostream& out, const AttributeCondition&){return out << "unknown condition";}
447  };
449  public:
450  AttributeWild(const std::string& name) : name_{name} {}
451  virtual ~AttributeWild() override {}
452  bool matches(const Attribute& attribute) const override {
453  return attribute.name() == name_;
454  }
455  friend std::ostream& operator<<(std::ostream& out, const AttributeWild& condition){
456  return out << condition.name_ << "=*";
457  }
458  private:
459  std::string name_;
460  };
461  template<typename T=double>
463  public:
464  // AttributeRange(const std::string& name, T min, T max) : name_{name}, min_{min}, max_{max} {}
465  AttributeRange(const std::string& name, T min, T max) : name_{name}, between_{Between<T>(min, max)} {}
466  virtual ~AttributeRange() override {}
467  bool matches(const Attribute& attribute) const override {
468  return attribute.name() == name_ && _visitorAny.apply_visitor(between_, attribute.a_value());
469  }
470  // friend std::ostream& operator<<(std::ostream& out, const AttributeRange& condition){
471  // // return out name_ << ": " << condition.between_.min_ << " - " << condition.between_.max_;
472  // return out name_ << " between stuff";
473  // }
474  private:
475  template<typename B>
476  struct Between {
477  Between(B min, B max) : min_{min}, max_{max} {}
478  B min_;
479  B max_;
480 
481  bool operator()(const std::string&) const { return false; }
482  template <typename V, std::enable_if_t<!is_iterable<V> && !std::is_same_v<V, std::string>, bool> = true>
483  bool operator() (V a) const { return !(a < min_ || a > max_); }
484  template <typename V, std::enable_if_t<is_iterable<V> && !std::is_same_v<V, std::string>, bool> = true>
485  bool operator() (V a) const { return !(a.at(0) < min_ || a.at(0) > max_); }
486  };
487 
488  std::string name_;
489  Between<T> between_;
490  };
491  class BaseVariable;
492 
493 
494  template <typename T>
495  static Attribute parse_attribute_any(const rapidjson::Value::ConstMemberIterator &itr, T (*get_attr_rj)(const rapidjson::Value &))
496  {
497  const std::string attr_name = itr->name.GetString();
498  const rapidjson::Value &data = itr->value;
499  const rapidjson::Value &value = data["value"];
500  if (!value.IsArray())
501  {
502  return Attribute{attr_name, get_attr_rj(value) , 1};
503  }
504  else
505  {
506  auto arr = value.GetArray();
507  size_t attr_len = arr.Size();
508  std::vector<T> vec;
509  std::transform(arr.begin(),arr.end(),std::back_inserter(vec),[&](auto &v){return get_attr_rj(v);});
510  return Attribute{attr_name,vec , attr_len};
511  }
512 
513  }
514  template <typename T>
515  static Attribute parse_attribute_any(const netCDF::NcAtt& att)
516  {
517  if (att.getAttLength() == 1){
518  T v;
519  att.getValues(&v);
520  const ANY val = v;
521  return Attribute{att.getName(), val , 1};
522  }
523  else
524  {
525  std::vector<T> value{};
526  value.resize(att.getAttLength());
527  att.getValues(value.data());
528  ANY val;
529  size_t att_len_to_pass = att.getAttLength();
530  if constexpr(std::is_same_v<T,char>)
531  {
532  val = std::string(value.cbegin(), value.cend());
533  att_len_to_pass = 1;
534  }
535  else
536  {
537  val = std::move(value);
538  }
539 
540  return Attribute{att.getName(), val , att_len_to_pass};
541  }
542 
543  }
544  class Product {
545  public:
548 
549  Product(std::string name, const std::initializer_list<Attribute>&& attributes) : name_{name}, attributes_{attributes} {}
550  Product(std::string name, const std::set<Attribute>& attributes) : name_{name}, attributes_{attributes} {}
551 
552  Product(std::string name, const std::set<Attribute>&& attributes, std::vector<std::shared_ptr<AttributeCondition>>&& conditions) : name_{name}, attributes_{attributes}, conditions_{std::move(conditions)} {}
553  Product(std::string name, const std::set<Attribute>& attributes, const std::vector<std::shared_ptr<AttributeCondition>>&& conditions) : name_{name}, attributes_{attributes}, conditions_{conditions} {}
554 
555  Product(std::string name, const std::vector<std::shared_ptr<AttributeCondition>>& conditions) : name_{name}, conditions_{conditions} {}
556  Product(std::string name, std::vector<std::shared_ptr<AttributeCondition>>&& conditions) : name_{name}, conditions_{std::move(conditions)} {}
557 
558 
559  // void name(const std::string& name) {name_.assign(name);}
560  void name(std::string name) {name_ = name;}
561  const std::string& name() const {return name_;}
562 
563  auto& attributes() {return attributes_;}
564  auto& conditions() {return conditions_;}
565 
566  auto& attributes() const {return attributes_;}
567  auto& conditions() const {return conditions_;}
568 
569  // void add_attribute(std::unique_ptr<Attribute> attr){attributes_.insert(attributes_.end(), std::move(attr));}
570  void add_attribute(const Attribute& attr){attributes_.insert(attributes_.end(), attr);}
571 
572  friend bool operator==(const Product& me, const Product& other){
573  // return me.name() == other.name() &&
574  return boost::iequals(me.name(), other.name()) &&
575  std::is_permutation(other.attributes().cbegin(), other.attributes().cend(), me.attributes().cbegin(), me.attributes().cend()) &&
576  std::is_permutation(other.conditions().cbegin(), other.conditions().cend(), me.conditions().cbegin(), me.conditions().cend());
577  }
578  bool matches(const std::vector<Product>& other) const {
579  for (const auto& o : other){
580  if (matches(o)){
581  return true;
582  }
583  }
584  return false;
585  }
586  bool matches(const Product& other) const {
587  // std::cout << "product.matches\n";
588  // std::cout << "other name: " << other.name() << "\n";
589  // std::cout << "this name length: " << name().length() << "\n";
590  // std::cout << "this name substr: " << name().substr(0, 1) << "\n";
591  // std::cout << "this name: " << name() << "\n";
592  if (boost::iequals(name(), other.name())){
593  // if (name() == other.name()){
594  // std::cout << "names match\n";
595  const auto& match_atts = other.attributes();
596 
597  bool all_matches = std::all_of(match_atts.cbegin(), match_atts.cend(), [this](const auto& o){return attributes_.find(o) != attributes_.end();});
598  // bool all_matches = true;
599  // for (const auto& a : match_atts){
600  // if (attributes_.find(a) == attributes_.end()){
601  // std::cout << "Missing " << a << "\n";
602  // return false;
603  // }
604  // }
605  if (all_matches){
606  // std::cout << "all attributes matched, checking conditions\n";
607  all_matches = std::all_of(conditions_.cbegin(), conditions_.cend(), [&match_atts](const auto& c){
608  auto i = std::find_if(match_atts.cbegin(), match_atts.cend(), [&c](const auto& o){return c->matches(o);});
609  return i != match_atts.end();
610  });
611  }
612  return all_matches;
613  }
614  // std::cout << "no match\n";
615  return false;
616  }
617  friend std::ostream& operator<<(std::ostream& out, const Product& product){
618  out << product.name_;
619  if (product.attributes().size() != 0 || product.conditions().size()){
620  out << "[";
621  bool printed_first = false;
622  for (auto it = product.attributes().cbegin(); it != product.attributes().cend(); ++it){
623  if (printed_first){
624  out << ',';
625  }
626  out << *it;
627  printed_first = true;
628  }
629  for (auto it = product.conditions().cbegin(); it != product.conditions().cend(); ++it){
630  if (printed_first){
631  out << ',';
632  }
633  out << **it;
634  printed_first = true;
635  }
636  out << "]";
637  }
638  return out;
639  }
640  void variable(BaseVariable* variable) {variable_ = variable;}
641  BaseVariable* variable() const {return variable_;}
642 
643  static size_t skip_passed_char(const std::string& input, size_t pos, char c, bool in_quotes=false){
644  while (pos < input.size()){
645  if (input[pos] == c){
646  return pos + 1;
647  } else if (input[pos] == '\\'){
648  pos += 2;
649  } else if (in_quotes){
650  pos++;
651  } else {
652  switch (input[pos]){
653  case '\'':
654  pos = skip_passed_char(input, pos + 1, '\'', true);
655  break;
656  case '"':
657  pos = skip_passed_char(input, pos + 1, '"', true);
658  break;
659  default:
660  pos++;
661  }
662  }
663  }
664  return std::string::npos;
665  }
666  static std::vector<Product> parse_list(const std::string& input){
667  std::vector<Product> ret{};
668 
669  size_t product_start = 0;
670  auto current_pos = product_start;
671  while (current_pos != std::string::npos && current_pos < input.size()){
672  if (input[current_pos] == ','){
673  ret.push_back(parse(input.substr(product_start, current_pos - product_start)));
674  current_pos++;
675  product_start = current_pos;
676  } else if (input[current_pos] == '\''){
677  current_pos = skip_passed_char(input, current_pos + 1, '\'', true);
678  } else if (input[current_pos] == '"'){
679  current_pos = skip_passed_char(input, current_pos + 1, '"', true);
680  } else if (input[current_pos] == '['){
681  current_pos = skip_passed_char(input, current_pos + 1, ']');
682  } else {
683  current_pos++;
684  }
685  }
686  if (current_pos != product_start){
687  ret.push_back(parse(input.substr(product_start, current_pos - product_start)));
688  }
689  {
690  std::unordered_set<std::string> prodnames;
691  for(const auto &pr : ret)
692  {
693  prodnames.insert(pr.name());
694  }
695  for (const auto & pr : default_products)
696  {
697  if(prodnames.count(pr) == 0)
698  {
699  ret.push_back(Product(pr));
700  }
701  }
702  }
703  return ret;
704  }
705  static Product parse(const std::string& input){
706  auto attribute_bracket = input.find_first_of('[');
707 
708  size_t name_start = 0;
709  while (input[name_start] == ' '){
710  name_start++;
711  }
712  size_t name_end = attribute_bracket;
713  if (attribute_bracket == std::string::npos){
714  name_end = input.size();
715  }
716  while (input[name_end - 1] == ' '){
717  name_end--;
718  }
719 
720  if (attribute_bracket == std::string::npos){
721  if (name_start == 0 && name_end == attribute_bracket){
722  return Product{input};
723  }
724  return Product{input.substr(name_start, name_end - name_start)};
725  }
726  std::string name(input, name_start, name_end - name_start);
727 
728  std::set<Attribute> attributes{};
729 
730  auto param_start = attribute_bracket + 1;
731  auto current_pos = param_start;
732  while (current_pos != std::string::npos && current_pos < input.size()){
733  if (input[current_pos] == ']'){
734  if (current_pos != param_start){
735  attributes.insert(Attribute::parse(input.substr(param_start, current_pos - param_start)));
736  }
737  break;
738  }
739  if (input[current_pos] == ','){
740  attributes.insert(Attribute::parse(input.substr(param_start, current_pos - param_start)));
741  current_pos++;
742  param_start = current_pos;
743  } else if (input[current_pos] == '\''){
744  current_pos = skip_passed_char(input, current_pos + 1, '\'', true);
745  } else if (input[current_pos] == '"'){
746  current_pos = skip_passed_char(input, current_pos + 1, '"', true);
747  } else {
748  current_pos++;
749  }
750  }
751  return Product{name, attributes};
752  }
753  private:
754  std::string name_{"unspecified"};
755  std::set<Attribute> attributes_{};
756  std::vector<std::shared_ptr<AttributeCondition>> conditions_{}; // pointer for hierarchy, shared for copy-able
757  std::set<Attribute> configuration_{};
758  BaseVariable* variable_{nullptr};
759  const static std::unordered_set<std::string> default_products;
760 
761  // static bool attributes_equal( const std::unique_ptr<Attribute>& left, const std::unique_ptr<Attribute>& right){return *left == *right;}
762  // static bool attributes_equal( const Attribute& left, const Attribute& right){return left == right;}
763  // static bool attributes_equal( const std::unique_ptr<Attribute>& left, const std::unique_ptr<Attribute>& right){return *left == *right;}
764  // static bool attributes_equal( const std::unique_ptr<Attribute>& left, const std::unique_ptr<Attribute>& right){return *left == *right;}
765 
766 
767  };
768 } // namespace focs
769 
770 #endif // FOCS_PRODUCT
771 
int32 value
Definition: Granule.c:1235
virtual ~Attribute()=default
Product(std::string name, const std::set< Attribute > &attributes, const std::vector< std::shared_ptr< AttributeCondition >> &&conditions)
Definition: Product.hpp:553
friend std::ostream & operator<<(std::ostream &out, const Attribute &attribute)
Definition: Product.hpp:216
void visit(Callable &&callable, LinkedList< ANY, S > &list, Ps... params) const
Definition: Product.hpp:105
float * vector(long nl, long nh)
Definition: nrutil.c:15
std::vector< T > as_vector() const
Definition: Product.hpp:212
bool matches(const Attribute &attribute) const override
Definition: Product.hpp:467
AttributeRange(const std::string &name, T min, T max)
Definition: Product.hpp:465
bool matches(const Product &other) const
Definition: Product.hpp:586
void name(std::string name)
Definition: Product.hpp:560
AttributeWild(const std::string &name)
Definition: Product.hpp:450
int N
Definition: Usds.c:60
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in out
Definition: HISTORY.txt:422
double as_double() const
Definition: Product.hpp:203
std::pair< const std::type_index, std::function< void(ANY const &)> > to_any_visitor(F const &f)
Definition: Product.hpp:169
LinkedList(const T &_val, [[maybe_unused]] Ts &... args)
Definition: Product.hpp:68
constexpr auto convert(T) const
Definition: Product.hpp:100
friend bool operator<(const Attribute &left, const Attribute &right)
Definition: Product.hpp:222
virtual ~AttributeCondition()
Definition: Product.hpp:444
void visit(Callable &&callable, R &ret, LinkedList< ANY, S > &list, Ps... params) const
Definition: Product.hpp:121
float32 * pos
Definition: l1_czcs_hdf.c:35
friend std::ostream & operator<<(std::ostream &out, const AttributeCondition &)
Definition: Product.hpp:446
std::string name_
Definition: Product.hpp:279
@ string
bool matches(const std::vector< Product > &other) const
Definition: Product.hpp:578
LinkedList(T *arr)
Definition: Product.hpp:48
constexpr bool is_iterable
Definition: Product.hpp:152
friend bool operator==(const Attribute &left, const std::string &name)
Definition: Product.hpp:230
instr * input
static Attribute parse_attribute(const netCDF::NcAtt &att)
const double F
Attribute(const std::string &name, const ANY &value, size_t attr_len)
Definition: Product.hpp:197
Product(std::string name)
Definition: Product.hpp:547
std::ostream & operator<<(std::ostream &os, const std::vector< T > &data) noexcept
Definition: Product.hpp:159
std::tuple_element_t< 0, std::tuple< Ts... > > first_type
Definition: Product.hpp:97
#define ROUND_ERROR
Definition: Product.hpp:32
friend std::ostream & operator<<(std::ostream &out, const AttributeWild &condition)
Definition: Product.hpp:455
double precision function f(R1)
Definition: tmd.lp.f:1454
const std::string & name() const
Definition: Product.hpp:561
Product(std::string name, const std::set< Attribute > &attributes)
Definition: Product.hpp:550
list(APPEND LIBS ${NETCDF_LIBRARIES}) find_package(GSL REQUIRED) include_directories($
Definition: CMakeLists.txt:8
subroutine os(tamoy, trmoy, pizmoy, tamoyp, trmoyp, palt, phirad, nt, mu, np, rm, gb, rp, xl)
Definition: 6sm1.f:5484
static size_t skip_passed_char(const std::string &input, size_t pos, char c, bool in_quotes=false)
Definition: Product.hpp:643
#define I
virtual ~AttributeRange() override
Definition: Product.hpp:466
const ANY & a_value() const
Definition: Product.hpp:199
const T * data() const
Definition: Product.hpp:72
#define max(A, B)
Definition: main_biosmap.c:61
static std::vector< Product > parse_list(const std::string &input)
Definition: Product.hpp:666
Product(std::string name, const std::initializer_list< Attribute > &&attributes)
Definition: Product.hpp:549
void variable(BaseVariable *variable)
Definition: Product.hpp:640
const std::string & name() const
Definition: Product.hpp:198
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude data
Definition: HISTORY.txt:356
#define min(A, B)
Definition: main_biosmap.c:62
const T * val
Definition: Product.hpp:45
static Attribute parse(const std::string &input)
Definition: Product.hpp:241
T get() const
Definition: Product.hpp:58
data_t b[NROOTS+1]
Definition: decode_rs.h:77
LinkedList< T, N - 1 > next
Definition: Product.hpp:46
auto & conditions()
Definition: Product.hpp:564
void insert(std::unordered_set< std::type_index > &found_types)
Definition: Product.hpp:75
const float B
Definition: calc_par.c:101
bool matches(const Attribute &attribute) const override
Definition: Product.hpp:452
virtual ~AttributeWild() override
Definition: Product.hpp:451
friend std::ostream & operator<<(std::ostream &out, const Product &product)
Definition: Product.hpp:617
virtual bool matches(const Attribute &attribute) const
Definition: Product.hpp:445
std::unordered_set< std::type_index > found_types
Definition: Product.hpp:92
#define Between(a, x, b)
Definition: setflags_l2.c:122
Product(std::string name, const std::set< Attribute > &&attributes, std::vector< std::shared_ptr< AttributeCondition >> &&conditions)
Definition: Product.hpp:552
auto apply_visitor(Callable &&callable, Tanys &&... anys) const
Definition: Product.hpp:137
auto & conditions() const
Definition: Product.hpp:567
data_t s[NROOTS]
Definition: decode_rs.h:75
auto & attributes() const
Definition: Product.hpp:566
auto & attributes()
Definition: Product.hpp:563
friend bool operator==(const Product &me, const Product &other)
Definition: Product.hpp:572
static Product parse(const std::string &input)
Definition: Product.hpp:705
size_t attr_len_
Definition: Product.hpp:283
Product(std::string name, std::vector< std::shared_ptr< AttributeCondition >> &&conditions)
Definition: Product.hpp:556
void add_attribute(const Attribute &attr)
Definition: Product.hpp:570
#define R
Definition: make_L3_v1.1.c:96
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in per delivery and then split off a new MYD_PR03 pcf file for Aqua Added AssociatedPlatformInstrumentSensor to the inventory metadata in MOD01 mcf and MOD03 mcf Created new versions named MYD01 mcf and MYD03 where AssociatedPlatformShortName is rather than Terra The program itself has been changed to read the Satellite Instrument validate it against the input L1A and LUT and to use it determine the correct files to retrieve the ephemeris and attitude data from Changed to produce a LocalGranuleID starting with MYD03 if run on Aqua data Added the Scan Type file attribute to the Geolocation copied from the L1A and attitude_angels to radians rather than degrees The accumulation of Cumulated gflags was moved from GEO_validate_earth_location c to GEO_locate_one_scan c
Definition: HISTORY.txt:464
size_t attr_len() const
Definition: Product.hpp:200
#define abs(a)
Definition: misc.h:90
int i
Definition: decode_rs.h:71
friend bool operator==(const Attribute &left, const Attribute &right)
Definition: Product.hpp:234
std::string as_string() const
Definition: Product.hpp:207
PGE01 indicating that PGE02 PGE01 V6 for and PGE01 V2 for MOD03 were used to produce the granule By convention adopted in all MODIS Terra PGE02 code versions are The fourth digit of the PGE02 version denotes the LUT version used to produce the granule The source of the metadata environment variable ProcessingCenter was changed from a QA LUT value to the Process Configuration A sign used in error in the second order term was changed to a
Definition: HISTORY.txt:424
HISTORY txt for MOD_PR01(step one of PGE01) History follows the following convention needed due to new Aqua ReprocessingActual and the expected LUT revision number from PCF Changed to use PGE version for ProductionHistory Added Archive including ProcessingEnvironment Corrected handling of bad to resovle GSFcd02514 Changed to check staged LUT revision number versus the expected LUT revision number from thereby resolving defect report MODxl02056 This change also avoids the memory access violation reported in MODur00039 Changed the way output arrays were initialized with fill to be more but placed into the L1A output product and thought of as valid packets These packets had an invalid frame count in them and since only the last valid packet of any specific type gets it frame count data written to the output product
Definition: HISTORY.txt:176
LinkedList()=default
LinkedList(const T &_val, Ts &... args)
Definition: Product.hpp:53
Attribute()=default
BaseVariable * variable() const
Definition: Product.hpp:641
#define ANY
Definition: Product.hpp:36
Product(std::string name, const std::vector< std::shared_ptr< AttributeCondition >> &conditions)
Definition: Product.hpp:555
const T * data() const
Definition: Product.hpp:59
a context in which it is NOT documented to do so subscript which cannot be easily calculated when extracting TONS attitude data from the Terra L0 files Corrected several defects in extraction of entrained ephemeris and and as HDF file attributes
Definition: HISTORY.txt:65