UFO
InflateError.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2019 UCAR
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 
9 
10 #include <algorithm>
11 
12 #include "ioda/ObsDataVector.h"
13 #include "oops/base/Variables.h"
15 #include "ufo/filters/QCflags.h"
16 #include "ufo/filters/Variables.h"
17 
18 namespace ufo {
19 
20 // -----------------------------------------------------------------------------
21 
23 
24 // -----------------------------------------------------------------------------
25 
26 void InflateErrorParameters::deserialize(util::CompositePath &path,
27  const eckit::Configuration &config) {
28  oops::Parameters::deserialize(path, config);
29 
30  // These checks should really be done at the validation stage (using JSON Schema),
31  // but this isn't supported yet, so this is better than nothing.
32  if ((inflationFactor.value() == boost::none && inflationVariable.value() == boost::none) ||
33  (inflationFactor.value() != boost::none && inflationVariable.value() != boost::none))
34  throw eckit::UserError(path.path() +
35  ": Exactly one of the 'inflation factor' and 'inflation variable' "
36  "options must be present");
37 }
38 
39 // -----------------------------------------------------------------------------
40 
42  : allvars_(), parameters_(parameters) {
43  if (parameters_.inflationVariable.value() != boost::none) {
45  }
46 }
47 
48 // -----------------------------------------------------------------------------
49 
50 /// Inflate ObsError by either a constant inflation factor, or by a varying
51 /// inflation variable.
52 /// \param vars variables that need to be inflated in the ObsError (filter variables)
53 /// \param flagged result of "where" statement: which variables/locations need to be
54 /// updated (has the same variables as \p vars, in the same order)
55 /// \param data accessor to obs filter data
56 /// \param flags QC flags (for all "simulated variables")
57 /// \param obserr ObsError (for all "simulated variables")
58 void InflateError::apply(const Variables & vars,
59  const std::vector<std::vector<bool>> & flagged,
60  const ObsFilterData & data,
61  int /*filterQCflag*/,
63  ioda::ObsDataVector<float> & obserr) const {
64  oops::Log::debug() << " InflateError input obserr: " << obserr << std::endl;
65  // If float factor is specified
66  if (parameters_.inflationFactor.value() != boost::none) {
67  float factor = *parameters_.inflationFactor.value();
68  for (size_t ifiltervar = 0; ifiltervar < vars.nvars(); ++ifiltervar) {
69  size_t iallvar = obserr.varnames().find(vars.variable(ifiltervar).variable());
70  for (size_t jobs = 0; jobs < obserr.nlocs(); ++jobs) {
71  if (flagged[ifiltervar][jobs] && flags[iallvar][jobs] == QCflags::pass) {
72  obserr[iallvar][jobs] *= factor;
73  }
74  }
75  }
76  // If variable is specified
77  } else if (parameters_.inflationVariable.value() != boost::none) {
78  const Variable &factorvar = *parameters_.inflationVariable.value();
79  ASSERT(factorvar.size() == 1 || factorvar.size() == vars.nvars());
80  ioda::ObsDataVector<float> factors(data.obsspace(), factorvar.toOopsVariables());
81  data.get(factorvar, factors);
82 
83  // if inflation factor is 1D variable, apply the same inflation factor to all variables
84  // factor_indices = {0, 0, 0, ..., 0} for all nvars
85  std::vector<size_t> factor_indices(vars.nvars(), 0);
86 
87  // if multiple variables are in the inflation factor, apply different factors to different
88  // variables
89  // factor_indices = {0, 1, 2, ..., nvars-1}
90  if (factorvar.size() == vars.nvars()) {
91  std::iota(factor_indices.begin(), factor_indices.end(), 0);
92  }
93 
94  // loop over all variables to update
95  for (size_t ifiltervar = 0; ifiltervar < vars.nvars(); ++ifiltervar) {
96  // find current variable index in obserr
97  size_t iallvar = obserr.varnames().find(vars.variable(ifiltervar).variable());
98  for (size_t jobs = 0; jobs < obserr.nlocs(); ++jobs) {
99  if (flagged[ifiltervar][jobs] && flags[iallvar][jobs] == QCflags::pass) {
100  obserr[iallvar][jobs] *= factors[factor_indices[ifiltervar]][jobs];
101  }
102  }
103  }
104  }
105  oops::Log::debug() << " InflateError output obserr: " << obserr << std::endl;
106 }
107 
108 // -----------------------------------------------------------------------------
109 
110 } // namespace ufo
Variables allvars_
Definition: InflateError.h:64
InflateError(const Parameters_ &)
Definition: InflateError.cc:41
void apply(const Variables &, const std::vector< std::vector< bool >> &, const ObsFilterData &, int, ioda::ObsDataVector< int > &, ioda::ObsDataVector< float > &) const override
Definition: InflateError.cc:58
Parameters_ parameters_
variables required to compute inflation
Definition: InflateError.h:65
oops::OptionalParameter< Variable > inflationVariable
Definition: InflateError.h:32
void deserialize(util::CompositePath &path, const eckit::Configuration &config) override
Definition: InflateError.cc:26
oops::OptionalParameter< float > inflationFactor
Definition: InflateError.h:31
ObsFilterData provides access to all data related to an ObsFilter.
ioda::ObsSpace & obsspace() const
Returns reference to ObsSpace associated with ObsFilterData.
void get(const Variable &varname, std::vector< float > &values) const
Fills a std::vector with values of the specified variable.
const std::string & variable() const
Definition: Variable.cc:99
oops::Variables toOopsVariables() const
Definition: Variable.cc:139
size_t size() const
Definition: Variable.cc:78
size_t nvars() const
Return the number of constituent "primitive" (single-channel) variables.
Definition: Variables.cc:104
Variable variable(const size_t) const
Return a given constituent "primitive" (single-channel) variable.
Definition: Variables.cc:114
constexpr int pass
Definition: QCflags.h:14
Definition: RunCRTM.h:27
static FilterActionMaker< InflateError > makerInflateErr_("inflate error")