UFO
ObsBoundsCheck.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2018-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 #include <set>
12 #include <vector>
13 
14 #include "eckit/config/Configuration.h"
15 
16 #include "ioda/ObsDataVector.h"
17 #include "ioda/ObsSpace.h"
18 #include "oops/util/abor1_cpp.h"
19 #include "oops/util/IntSetParser.h"
20 #include "oops/util/Logger.h"
21 #include "oops/util/missingValues.h"
23 #include "ufo/filters/QCflags.h"
24 #include "ufo/utils/StringUtils.h"
25 
26 namespace ufo {
27 
28 // -----------------------------------------------------------------------------
29 
30 ObsBoundsCheck::ObsBoundsCheck(ioda::ObsSpace & obsdb, const eckit::Configuration & config,
31  std::shared_ptr<ioda::ObsDataVector<int> > flags,
32  std::shared_ptr<ioda::ObsDataVector<float> > obserr)
33  : FilterBase(obsdb, config, flags, obserr)
34 {
35  if (config_.has("test variables")) {
36  std::vector<eckit::LocalConfiguration> testvarconf;
37  config_.get("test variables", testvarconf);
38  allvars_ += ufo::Variables(testvarconf);
39  }
40  oops::Log::debug() << "ObsBoundsCheck: config (constructor) = " << config_ << std::endl;
41 }
42 
43 // -----------------------------------------------------------------------------
44 
46 
47 // -----------------------------------------------------------------------------
48 
49 void ObsBoundsCheck::applyFilter(const std::vector<bool> & apply,
50  const Variables & filtervars,
51  std::vector<std::vector<bool>> & flagged) const {
52  const float missing = util::missingValue(missing);
53  const oops::Variables observed = obsdb_.obsvariables();
54 
55 // Find which variables are tested and the conditions
56  ufo::Variables testvars;
57 // Use variables specified in test variables/functions for testing, otherwise filter variables
58  if (config_.has("test variables")) {
59  std::vector<eckit::LocalConfiguration> varconfs;
60  config_.get("test variables", varconfs);
61  testvars += ufo::Variables(varconfs);
62  } else {
63  testvars += ufo::Variables(filtervars, "ObsValue");
64  }
65  const float vmin = config_.getFloat("minvalue", missing);
66  const float vmax = config_.getFloat("maxvalue", missing);
67 
68 // Sanity checks
69  if (filtervars.nvars() == 0) {
70  oops::Log::error() << "No variables will be filtered out in filter "
71  << config_ << std::endl;
72  ABORT("No variables specified to be filtered out in filter");
73  }
74 
75  oops::Log::debug() << "ObsBoundsCheck: filtering " << filtervars << " with "
76  << testvars << std::endl;
77 
78  oops::Log::debug() << " sizes of each: " << filtervars.size() << " and "
79  << testvars.size() << std::endl;
80 
81 // Initialize map from filtervars to observed variables
82  std::vector<size_t> filt2obs;
83  for (size_t jv = 0; jv < filtervars.nvars(); ++jv) {
84  filt2obs.push_back(observed.find(filtervars.variable(jv).variable()));
85  }
86 
87  if (filtervars.size() == testvars.size()) {
88  // Loop over all test variables to get data
89  for (size_t iv = 0; iv < testvars.size(); ++iv) {
90  const std::string grp = testvars[iv].group();
91  ioda::ObsDataVector<float> testdata(obsdb_, testvars[iv].toOopsVariables());
92  if (grp == "ObsFunction") {
93  data_.get(testvars[iv], testdata);
94  } else {
95  for (size_t ii = 0; ii < testvars[iv].size(); ++ii) {
96  size_t kv = ii + iv * testvars[iv].size();
97  data_.get(testvars.variable(kv), testdata[ii]);
98  }
99  }
100 
101  std::vector<size_t> test_jv(filtervars[iv].size(), 0);
102  if (testvars[iv].size() == filtervars[iv].size()) {
103  std::iota(test_jv.begin(), test_jv.end(), 0);
104  }
105 
106  // Loop over all variables to filter
107  for (size_t jv = 0; jv < filtervars[iv].size(); ++jv) {
108  for (size_t jobs = 0; jobs < obsdb_.nlocs(); ++jobs) {
109  if (apply[jobs] && (*flags_)[filt2obs[jv]][jobs] == QCflags::pass) {
110  ASSERT(testdata[test_jv[jv]][jobs] != missing);
111  size_t kv = jv + filtervars[iv].size() * iv;
112  if (vmin != missing && testdata[test_jv[jv]][jobs] < vmin) flagged[kv][jobs] = true;
113  if (vmax != missing && testdata[test_jv[jv]][jobs] > vmax) flagged[kv][jobs] = true;
114  }
115  }
116  }
117  }
118  } else {
119  int iv = 0;
120  if (testvars.size() != 1) {
121  oops::Log::error() << "When number filtervars not equal number of test vars, "
122  << "the latter can only be one." << config_ << std::endl;
123  ABORT("ONLY one testvar when filtervars>1 because its usage is ambiguous otherwise");
124  }
125 
126  ioda::ObsDataVector<float> testdata(obsdb_, testvars[iv].toOopsVariables());
127 
128  const std::string grp = testvars[iv].group();
129 
130  if (grp == "ObsFunction") {
131  data_.get(testvars[iv], testdata);
132  } else {
133  data_.get(testvars.variable(iv), testdata);
134  }
135 
136  for (size_t jv = 0; jv < filtervars.size(); ++jv) {
137  oops::Log::debug() << "ObsBoundsCheck: testing filter var with index " << jv << std::endl;
138  if (testvars[iv].size() != filtervars[jv].size()) {
139  oops::Log::error() << "Dimension of filtervar, " << filtervars[jv].size()
140  << " does not equal testvar dimension, " << testvars[iv].size() << std::endl;
141  ABORT("Aborting, sizes must be equivalent.");
142  }
143  for (size_t jobs = 0; jobs < obsdb_.nlocs(); ++jobs) {
144  if (apply[jobs] && (*flags_)[filt2obs[jv]][jobs] == QCflags::pass) {
145  ASSERT(testdata[iv][jobs] != missing);
146  if (vmin != missing && testdata[iv][jobs] < vmin) flagged[jv][jobs] = true;
147  if (vmax != missing && testdata[iv][jobs] > vmax) flagged[jv][jobs] = true;
148  }
149  }
150  }
151  }
152 }
153 
154 // -----------------------------------------------------------------------------
155 
156 void ObsBoundsCheck::print(std::ostream & os) const {
157  os << "ObsBoundsCheck: config = " << config_ << std::endl;
158 }
159 
160 // -----------------------------------------------------------------------------
161 
162 } // namespace ufo
ufo::Variables::nvars
size_t nvars() const
Definition: Variables.cc:104
ObsBoundsCheck.h
ufo::QCflags::pass
constexpr int pass
Definition: QCflags.h:14
ufo::Variables
Definition: src/ufo/filters/Variables.h:24
ufo_radiancerttov_utils_mod::debug
logical, public debug
Definition: ufo_radiancerttov_utils_mod.F90:100
ufo::FilterBase::obsdb_
ioda::ObsSpace & obsdb_
Definition: FilterBase.h:59
ufo::FilterBase
FilterBase: Base class for UFO QC filters.
Definition: FilterBase.h:42
ufo
Definition: RunCRTM.h:27
ufo::FilterBase::data_
ObsFilterData data_
Definition: FilterBase.h:65
ufo::FilterBase::allvars_
ufo::Variables allvars_
Definition: FilterBase.h:63
ufo::Variables::size
size_t size() const
Definition: Variables.cc:92
ufo::FilterBase::flags_
std::shared_ptr< ioda::ObsDataVector< int > > flags_
Definition: FilterBase.h:61
ufo::QCflags::missing
constexpr int missing
Definition: QCflags.h:15
ufo::ObsBoundsCheck::print
void print(std::ostream &) const override
Definition: ObsBoundsCheck.cc:156
QCflags.h
ufo::Variable::variable
const std::string & variable() const
Definition: Variable.cc:100
StringUtils.h
ObsFunction.h
ioda::ObsDataVector< int >
ufo::ObsBoundsCheck::applyFilter
void applyFilter(const std::vector< bool > &, const Variables &, std::vector< std::vector< bool >> &) const override
Definition: ObsBoundsCheck.cc:49
ufo::Variables::variable
Variable variable(const size_t) const
Definition: Variables.cc:114
ufo::FilterBase::config_
const eckit::LocalConfiguration config_
Definition: FilterBase.h:60
ufo::ObsFilterData::get
void get(const Variable &, std::vector< float > &) const
Gets requested data from ObsFilterData.
Definition: ObsFilterData.cc:130
ufo::ObsBoundsCheck::ObsBoundsCheck
ObsBoundsCheck(ioda::ObsSpace &, const eckit::Configuration &, std::shared_ptr< ioda::ObsDataVector< int > >, std::shared_ptr< ioda::ObsDataVector< float > >)
Definition: ObsBoundsCheck.cc:30
ufo::ObsBoundsCheck::~ObsBoundsCheck
~ObsBoundsCheck()
Definition: ObsBoundsCheck.cc:45