UFO
ModelObThreshold.cc
Go to the documentation of this file.
1 /* -----------------------------------------------------------------------------
2  * (C) British Crown Copyright 2021 Met Office
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 "eckit/config/Configuration.h"
11 
12 #include "ioda/ObsDataVector.h"
13 #include "ioda/ObsSpace.h"
14 
15 #include "oops/util/Logger.h"
16 #include "oops/util/PropertiesOfNVectors.h"
17 
18 #include "ufo/GeoVaLs.h"
20 
21 namespace ufo {
22 
24 constexpr util::NamedEnumerator<ThresholdType>
26 
27 // -----------------------------------------------------------------------------
28 
29 ModelObThreshold::ModelObThreshold(ioda::ObsSpace & obsdb, const Parameters_ & parameters,
30  std::shared_ptr<ioda::ObsDataVector<int> > flags,
31  std::shared_ptr<ioda::ObsDataVector<float> > obserr)
32  : FilterBase(obsdb, parameters, flags, obserr), parameters_(parameters)
33 {
34  oops::Log::trace() << "ModelObThreshold contructor starting" << std::endl;
38 }
39 
40 // -----------------------------------------------------------------------------
41 
43  oops::Log::trace() << "ModelObThreshold destructed" << std::endl;
44 }
45 
46 // -----------------------------------------------------------------------------
47 /*! \brief Filter to apply a threshold to a model profile interpolated to the
48  * observation height.
49  *
50  * \details The specified model profile variable is linearly (vertical) interpolated
51  * to the observation height using the specified model vertical coordinate variable.
52  * This is referred to as the "ModelOb". Note that the ModelOb is not necessarily
53  * one of the HofX variables.
54  *
55  * The observation height must be in the same coordinate system as that specified
56  * for the model vertical coordinate, e.g. both pressure.
57  *
58  * The thresholds to compare the ModelOb against is specified as height-dependent.
59  * We supply a vector of threshold values, and a vector of vertical coordinate
60  * values corresponding to those thresholds. The coordinate values must be in the same
61  * vertical coordinate as the observation, e.g. pressure. The threshold values are
62  * then linearly interpolated to the observation height.
63  *
64  * The observation is flagged for rejection if the ModelOb lies outside the threshold
65  * value according to threshold type - min or max. E.g. if the threshold type is min,
66  * then the observation is flagged if ModelOb is less than the interpolated threshold
67  * value.
68  *
69  * Example for relative humidity:
70  * \code{.unparsed}
71  * obs filters:
72  * - filter: ModelOb Threshold
73  * model profile:
74  * name: relative_humidity@GeoVaLs
75  * model vertical coordinate:
76  * name: air_pressure@GeoVaLs
77  * observation height:
78  * name: air_pressure_levels@MetaData
79  * thresholds: [50,50,40,30]
80  * coordinate values: [100000,80000,50000,20000]
81  * threshold type: min
82  * \endcode
83  *
84  * \author J.Cotton (Met Office)
85  *
86  * \date 12/03/2021: Created
87  */
88 
89 void ModelObThreshold::applyFilter(const std::vector<bool> & apply,
90  const Variables & filtervars,
91  std::vector<std::vector<bool>> & flagged) const {
92  oops::Log::trace() << "ModelObThreshold priorFilter" << std::endl;
93  print(oops::Log::trace());
94 
95  const float missing = util::missingValue(missing);
96  const size_t nlocs = obsdb_.nlocs();
97 
98 // Get piece-wise parameters from options.
99  const std::vector<double> coord_vals = parameters_.coord_vals.value();
100  const std::vector<double> thresholds = parameters_.thresholds.value();
101  oops::Log::debug() << "QC coord vals are " << coord_vals << std::endl;
102  oops::Log::debug() << "QC thresholds are " << thresholds << std::endl;
103 
104 // get names of GeoVal variables
105  const std::string model_profile_name = Variable(parameters_.model_profile).variable();
106  const std::string model_vcoord_name = Variable(parameters_.model_vcoord).variable();
107 
108  std::ostringstream errString;
109 // Ensure same size vectors (coord_vals and threshold); Also ensure more than one value in each.
110  if (coord_vals.size() <= 1 || coord_vals.size() != thresholds.size()) {
111  errString << "At least one of coord_vals, thresholds is wrong size - either unequal or < 2"
112  << oops::listOfVectorSizes(coord_vals, thresholds) << std::endl;
113  throw eckit::BadValue(errString.str());
114  }
115 
116 // Get variables from ObsSpace
117 // Get obs_height, the observation height
118  std::vector<float> obs_height;
119  data_.get(parameters_.obs_height, obs_height);
120 
121 // Get GeoVaLs
122  const ufo::GeoVaLs * gvals = data_.getGeoVaLs();
123 
124 // Setup interpolation of height-dependent thresholds
125 // N.B. inputs to interp must be double precision
126  ufo::PiecewiseLinearInterpolation interp_thresholds(coord_vals, thresholds);
127 
128 // Loop through locations
129  for (size_t iloc=0; iloc < nlocs; ++iloc) {
130  // interpolate threshold values to observation height
131  float bg_threshold = interp_thresholds(obs_height[iloc]);
132 
133  // Vectors storing GeoVaL column for current location.
134  std::vector <double> model_profile_column;
135  std::vector <double> model_vcoord_column;
136  model_profile_column.assign(gvals->nlevs(model_profile_name), 0.0);
137  model_vcoord_column.assign(gvals->nlevs(model_vcoord_name), 0.0);
138  // Get GeoVaLs at the specified location.
139  gvals->getAtLocation(model_profile_column, model_profile_name, iloc);
140  gvals->getAtLocation(model_vcoord_column, model_vcoord_name, iloc);
141 
142  // interpolate model profile values to observation height
143  ufo::PiecewiseLinearInterpolation interp_model(model_vcoord_column, model_profile_column);
144  float bg_model = interp_model(obs_height[iloc]);
145 
146  // Apply threshold
147  if (apply[iloc]) {
148  // check to see if one of the compared values is missing
149  if (bg_model == missing || bg_threshold == missing) {
150  for (size_t jv = 0; jv < filtervars.nvars(); ++jv) {
151  flagged[jv][iloc] = true;
152  }
153  } else {
154  // Check if model value is outside threshold and set flag
155  for (size_t jv = 0; jv < filtervars.nvars(); ++jv) {
157  if (bg_model < (bg_threshold)) {
158  flagged[jv][iloc] = true;
159  }
160  }
162  if (bg_model > (bg_threshold)) {
163  flagged[jv][iloc] = true;
164  }
165  }
166  }
167  }
168  }
169  }
170 }
171 
172 // -----------------------------------------------------------------------------
173 
174 void ModelObThreshold::print(std::ostream & os) const {
175  os << "ModelObThreshold: config = " << parameters_ << std::endl;
176 }
177 
178 // -----------------------------------------------------------------------------
179 
180 } // namespace ufo
Base class for UFO QC filters.
Definition: FilterBase.h:45
GeoVaLs: geophysical values at locations.
size_t nlevs(const std::string &var) const
Return number of levels for a specified variable.
Definition: GeoVaLs.cc:310
void getAtLocation(std::vector< double > &, const std::string &, const int) const
Get GeoVaLs at a specified location.
Definition: GeoVaLs.cc:380
void print(std::ostream &) const override
ModelObThreshold(ioda::ObsSpace &, const Parameters_ &, std::shared_ptr< ioda::ObsDataVector< int > >, std::shared_ptr< ioda::ObsDataVector< float > >)
void applyFilter(const std::vector< bool > &, const Variables &, std::vector< std::vector< bool >> &) const override
Filter to apply a threshold to a model profile interpolated to the observation height.
Parameters controlling the operation of the ModelObThreshold filter.
oops::RequiredParameter< Variable > obs_height
Name of the observation height variable to interpolate to.
oops::RequiredParameter< std::vector< double > > thresholds
Vector of threshold values.
oops::RequiredParameter< ThresholdType > threshold_type
Threshold type: min or max.
oops::RequiredParameter< Variable > model_vcoord
Name of the model vertical coordinate variable (GeoVal)
oops::RequiredParameter< std::vector< double > > coord_vals
Vector of vertical coordinates corresponding to vector of thresholds.
oops::RequiredParameter< Variable > model_profile
Name of the model profile variable (GeoVaLs)
const GeoVaLs * getGeoVaLs() const
Returns reference to GeoVaLs required by 1DVar.
void get(const Variable &varname, std::vector< float > &values) const
Fills a std::vector with values of the specified variable.
ufo::Variables allvars_
ioda::ObsSpace & obsdb_
Represents a piecewise linear interpolation of a set of data points.
const std::string & variable() const
Definition: Variable.cc:99
size_t nvars() const
Return the number of constituent "primitive" (single-channel) variables.
Definition: Variables.cc:104
constexpr int missing
Definition: QCflags.h:20
integer function nlocs(this)
Return the number of observational locations in this Locations object.
Definition: RunCRTM.h:27
static constexpr util::NamedEnumerator< ThresholdType > namedValues[]