UFO
DrawValueFromFile.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2021 Met Office UK
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  */
7 #include "eckit/exception/Exceptions.h"
9 
10 
11 namespace ufo {
12 
13 namespace {
14 
15 // -----------------------------------------------------------------------------
16 typedef std::vector<std::pair<std::string, boost::variant<std::vector<int>,
17  std::vector<float>,
18  std::vector<std::string>>
19  >> ObData;
20 
21 
22 // -----------------------------------------------------------------------------
23 /// \brief This is a convenience function for updating our container for useful observation data
24 template <typename T>
25 void updateObData(const ObsFilterData &in, const Variable &var, ObData &obData) {
26  std::vector<T> dat;
27  in.get(var, dat);
28  obData.emplace_back(var.fullName(), std::move(dat));
29 }
30 
31 // -----------------------------------------------------------------------------
32 /// \brief Add datetime observation information data to our container.
33 /// \details We simply convert the datetimes to strings as our implementation does not discriminate
34 /// between the two types.
35 void updateObDataDateTime(const ObsFilterData &in, const Variable &var, ObData &obData) {
36  std::vector<util::DateTime> dat;
37  std::vector<std::string> datConv;
38  in.get(var, dat);
39  datConv.resize(dat.size());
40 
41  // Convert the vec. of datetime. to strings
42  std::transform(dat.begin(), dat.end(), datConv.begin(),
43  [](util::DateTime dt){return dt.toString();});
44  obData.emplace_back(var.fullName(), std::move(datConv));
45 }
46 
47 } // anonymous namespace
48 
49 // -----------------------------------------------------------------------------
51 constexpr util::NamedEnumerator<InterpMethod>
53 
54 // -----------------------------------------------------------------------------
58 
59 // -----------------------------------------------------------------------------
60 // Could be moved to a non-templated base class
61 template <typename T>
62 DrawValueFromFile<T>::DrawValueFromFile(const eckit::LocalConfiguration &config)
63  : allvars_() {
64  // Initialize options
65  options_.deserialize(config);
66 
67  std::vector<eckit::LocalConfiguration> interpSubConfs;
68  const std::vector<InterpolationParameters> &interpolationParameters =
69  options_.interpolation.value();
70  int nlin = 0;
71  for (auto intParam = interpolationParameters.begin();
72  intParam != interpolationParameters.end(); ++intParam) {
73  const ufo::InterpMethod & method = intParam->method.value();
74  if (method == InterpMethod::BILINEAR) {
75  nlin++;
76  } else if (nlin > 0) {
77  throw eckit::UserError("Bilinear interpolation can only be supplied as the final two "
78  "arguments.", Here());
79  } else if ((method == InterpMethod::LINEAR) &&
80  (intParam + 1 != interpolationParameters.end())) {
81  throw eckit::UserError("Linear interpolation can only be supplied as the very last "
82  "argument.", Here());
83  }
84  interpSubConfs.push_back(intParam->toConfiguration());
85  interpMethod_[intParam->name.value()] = method;
86  }
87  if (nlin > 0 && nlin != 2) {
88  throw eckit::UserError("Bilinear interpolation requires two variables.", Here());
89  }
90  // Get channels from options
91  if (options_.chlist.value() != boost::none) {
92  std::set<int> channels = options_.chlist.value().get();
93  channels_ = {std::make_move_iterator(std::begin(channels)),
94  std::make_move_iterator(std::end(channels))};
95  }
96  fpath_ = options_.fpath.value();
97  allvars_ = Variables(interpSubConfs);
98 }
99 
100 
101 // -----------------------------------------------------------------------------
102 template <typename ExtractedValue>
103 class ExtractVisitor : public boost::static_visitor<void> {
104  public:
106  const size_t &iloc) :
108 
109  template <typename T>
110  void operator()(const std::vector<T> &obDat) {
111  interpolator.extract(obDat[iloc]);
112  }
113 
114  template <typename T, typename R>
115  void operator()(const std::vector<T> &obDat1, const std::vector<R> &obDat2) {
116  interpolator.extract(obDat1[iloc], obDat2[iloc]);
117  }
118 
120  const size_t &iloc;
121 };
122 
123 
124 // -----------------------------------------------------------------------------
125 template <typename T>
127  ioda::ObsDataVector<T> & out) const {
128  DataExtractor<T> interpolator{fpath_, options_.group};
129 
130  // Channel number handling
131  if (options_.chlist.value() != boost::none)
132  interpolator.scheduleSort("channel_number@MetaData", InterpMethod::EXACT);
133 
134  ObData obData;
135  for (size_t ind=0; ind < allvars_.size(); ind++) {
136  oops::Log::debug() << "Extracting " << allvars_[ind].variable() <<
137  " from the obsSpace" << std::endl;
138 
139  const std::string varName = allvars_[ind].fullName();
140  const InterpMethod &interpolationMethod = interpMethod_.at(varName);
141  interpolator.scheduleSort(varName, interpolationMethod);
142  switch (in.dtype(allvars_[ind])) {
143  case ioda::ObsDtype::Integer:
144  updateObData<int>(in, allvars_[ind], obData);
145  break;
146  case ioda::ObsDtype::String:
147  updateObData<std::string>(in, allvars_[ind], obData);
148  break;
149  case ioda::ObsDtype::Float:
150  updateObData<float>(in, allvars_[ind], obData);
151  break;
152  case ioda::ObsDtype::DateTime:
153  updateObDataDateTime(in, allvars_[ind], obData);
154  break;
155  default:
156  throw eckit::UserError("Data type not yet handled.", Here());
157  }
158  }
159  // Finalise (apply) sort by calling with no arguments.
160  interpolator.sort();
161 
162  for (size_t jvar = 0; jvar < out.nvars(); ++jvar) {
163  for (size_t iloc = 0; iloc < in.nlocs(); ++iloc) {
164  if (options_.chlist.value() != boost::none)
165  interpolator.extract(channels_[jvar]);
166 
167  // Perform any extraction methods.
168  ExtractVisitor<T> visitor(interpolator, iloc);
169  for (size_t ind=0; ind < obData.size(); ind++) {
170  ufo::InterpMethod interpolationMethod = interpMethod_.at(obData[ind].first);
171  if ((interpolationMethod == InterpMethod::BILINEAR) && (ind == (obData.size()-2))) {
172  boost::apply_visitor(visitor, obData[ind].second, obData[ind+1].second);
173  break;
174  } else {
175  boost::apply_visitor(visitor, obData[ind].second);
176  }
177  }
178  out[jvar][iloc] = interpolator.getResult();
179  }
180  }
181 }
182 
183 // -----------------------------------------------------------------------------
184 template <typename T>
186  return allvars_;
187 }
188 
189 // -----------------------------------------------------------------------------
190 // Explicit instantiations
191 template class DrawValueFromFile<float>;
192 template class DrawValueFromFile<int>;
193 template class DrawValueFromFile<std::string>;
194 
195 } // namespace ufo
This class makes it possible to extract and interpolate data loaded from a file.
void scheduleSort(const std::string &varName, const InterpMethod &method)
Update the instruction on how to sort the data for the provided variable name.
const ufo::Variables & requiredVariables() const
geovals required to compute the function
std::unordered_map< std::string, InterpMethod > interpMethod_
void compute(const ObsFilterData &, ioda::ObsDataVector< T > &) const
compute the result of the function
std::vector< int > channels_
DrawValueFromFile(const eckit::LocalConfiguration &)
DrawValueFromFileParameters options_
oops::RequiredParameter< std::vector< InterpolationParameters > > interpolation
oops::RequiredParameter< std::string > fpath
Path to the file containing the data to interpolate.
oops::OptionalParameter< std::set< int > > chlist
void operator()(const std::vector< T > &obDat1, const std::vector< R > &obDat2)
ExtractVisitor(DataExtractor< ExtractedValue > &interpolator, const size_t &iloc)
DataExtractor< ExtractedValue > & interpolator
void operator()(const std::vector< T > &obDat)
ObsFilterData provides access to all data related to an ObsFilter.
size_t nlocs() const
Returns the number of locations in the associated ObsSpace.
ioda::ObsDtype dtype(const Variable &) const
Determines dtype of the provided variable.
void get(const Variable &varname, std::vector< float > &values) const
Fills a std::vector with values of the specified variable.
std::string fullName() const
Definition: Variable.cc:128
void updateObData(const ObsFilterData &in, const Variable &var, ObData &obData)
This is a convenience function for updating our container for useful observation data.
std::vector< std::pair< std::string, boost::variant< std::vector< int >, std::vector< float >, std::vector< std::string > > > > ObData
void updateObDataDateTime(const ObsFilterData &in, const Variable &var, ObData &obData)
Add datetime observation information data to our container.
Definition: RunCRTM.h:27
static ObsFunctionMaker< Conditional< std::string > > stringMaker("Conditional")
static ObsFunctionMaker< Conditional< float > > floatMaker("Conditional")
InterpMethod
Method used by the DataExtractor to map the value of an ObsSpace variable to a range of slices of the...
@ LINEAR
Perform a piecewise linear interpolation along the dimension indexed by the ObsSpace variable.
@ BILINEAR
Perform a bilinear interpolation along two dimensions indexed by the ObsSpace variables.
@ EXACT
Select slices where the indexing coordinate matches exactly the value of the corresponding ObsSpace v...
static ObsFunctionMaker< Conditional< int > > intMaker("Conditional")
static constexpr util::NamedEnumerator< InterpMethod > namedValues[]