UFO
ConventionalProfileProcessing.cc
Go to the documentation of this file.
1 /*
2  * (C) Crown copyright 2020, 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 
8 #include <algorithm>
9 #include <cmath>
10 #include <cstring>
11 #include <iomanip>
12 #include <limits>
13 #include <vector>
14 
15 #include "eckit/config/Configuration.h"
16 
17 #include "ioda/ObsDataVector.h"
18 #include "ioda/ObsSpace.h"
19 
20 #include "oops/util/abor1_cpp.h"
21 #include "oops/util/Logger.h"
22 
25 
26 #include "ufo/GeoVaLs.h"
27 
28 namespace ufo {
29 
30  // -----------------------------------------------------------------------------
31 
33  (ioda::ObsSpace & obsdb,
34  const Parameters_ & parameters,
35  std::shared_ptr<ioda::ObsDataVector<int> > flags,
36  std::shared_ptr<ioda::ObsDataVector<float> > obserr)
37  : FilterBase(obsdb, parameters, flags, obserr), options_(parameters)
38  {
39  allvars_ += Variables(filtervars_, "HofX");
40 
41  // Add the names of any required GeoVaLs to \c allvars_.
42  // This is performed here because \c allvars_ must be filled prior to the filter being run.
43  // The names of the required GeoVaLs are listed in the \c getGeoVaLNames() function
44  // of each check (which returns an empty set by default).
45  // The \c profileChecker class must be instantiated in order to do this.
46  const ProfileChecker profileChecker(options_);
47  const auto &requiredGeoVaLNames = profileChecker.getGeoVaLNames();
48  if (requiredGeoVaLNames.size() > 0) {
49  ufo::Variables reqGeoVaLs(requiredGeoVaLNames);
50  allvars_ += Variables(reqGeoVaLs, "GeoVaLs");
51  }
52 
53  // Add the names of any required obs diagnostics to \c allvars_.
54  // The names of the required obs diagnostics are listed in the \c getObsDiagNames() function
55  // of each check (which returns an empty set by default).
56  const auto &requiredObsDiagNames = profileChecker.getObsDiagNames();
57  if (requiredObsDiagNames.size() > 0) {
58  ufo::Variables reqObsDiags(requiredObsDiagNames);
59  allvars_ += Variables(reqObsDiags, "ObsDiag");
60  }
61 
62  if (options_.compareWithOPS.value()) {
63  const auto &validationGeoVaLNames = profileChecker.getValidationGeoVaLNames();
64  if (validationGeoVaLNames.size() > 0) {
65  ufo::Variables valGeoVaLs(validationGeoVaLNames);
66  allvars_ += Variables(valGeoVaLs, "GeoVaLs");
67  }
68  }
69 
70  // It is essential for observations to be grouped according to (e.g.) station ID
71  // (unless there is only one profile in the sample, which would be very unusual).
72  // Throw an exception if the "group variable" configuration option is missing.
73  if (obsdb.obs_group_vars().empty())
74  throw eckit::BadParameter("group variables configuration is empty.", Here());
75  }
76 
77  // -----------------------------------------------------------------------------
78 
80 
81  // -----------------------------------------------------------------------------
82 
84  (ProfileDataHandler &profileDataHandler,
85  ProfileCheckValidator &profileCheckValidator,
86  ProfileChecker &profileChecker,
87  const CheckSubgroup &subGroupChecks) const
88  {
89  const int nprofs = static_cast <int> (obsdb_.nrecs());
90 
91  // Reset profile indices prior to looping through entire sample.
92  profileDataHandler.resetProfileIndices();
93 
94  // Loop over profiles
95  oops::Log::debug() << "Starting loop over profiles..." << std::endl;
96 
97  for (int jprof = 0; jprof < nprofs; ++jprof) {
98  oops::Log::debug() << "Profile " << (jprof + 1) << " / " << nprofs << std::endl;
99 
100  // Initialise the next profile prior to applying checks.
101  profileDataHandler.initialiseNextProfile();
102 
103  // Print station ID if requested
104  if (options_.PrintStationID.value()) {
105  const std::vector <std::string> &station_ID =
106  profileDataHandler.get<std::string>(ufo::VariableNames::station_ID);
107  if (!station_ID.empty())
108  oops::Log::debug() << "Station ID: " << station_ID[0] << std::endl;
109  }
110 
111  // Run checks
112  profileChecker.runChecks(profileDataHandler,
113  subGroupChecks);
114 
115  // Update information, including the 'flagged' vector, for this profile.
116  profileDataHandler.updateProfileInformation();
117  }
118 
119  // Write various quantities to the obsdb.
120  profileDataHandler.writeQuantitiesToObsdb();
121 
122  oops::Log::debug() << "... Finished loop over profiles" << std::endl;
123  oops::Log::debug() << std::endl;
124  }
125 
126  // -----------------------------------------------------------------------------
127 
129  (ProfileDataHandler &profileDataHandler,
130  ProfileCheckValidator &profileCheckValidator,
131  ProfileChecker &profileChecker,
132  const CheckSubgroup &subGroupChecks) const
133  {
134  oops::Log::debug() << "Running checks on entire profile sample..." << std::endl;
135 
136  // Run checks
137  profileChecker.runChecks(profileDataHandler,
138  subGroupChecks);
139 
140  // Write various quantities to the obsdb.
141  profileDataHandler.writeQuantitiesToObsdb();
142 
143  oops::Log::debug() << "... Finished running checks" << std::endl;
144  oops::Log::debug() << std::endl;
145  }
146 
147  // -----------------------------------------------------------------------------
148 
150  (const std::vector<bool> & apply,
151  const Variables & filtervars,
152  std::vector<std::vector<bool>> & flagged) const
153  {
154  print(oops::Log::trace());
155 
156  // Handles individual profile data
157  ProfileDataHandler profileDataHandler(data_,
159  apply,
160  filtervars,
161  flagged);
162 
163  // (Optionally) validates check results against OPS values
164  ProfileCheckValidator profileCheckValidator(options_);
165 
166  // Applies checks to each profile
167  ProfileChecker profileChecker(options_);
168 
169  // Loop over each check subgroup in turn.
170  const auto checkSubgroups = profileChecker.getCheckSubgroups();
171  for (const auto& checkSubgroup : checkSubgroups) {
172  if (checkSubgroup.runOnEntireSample) {
173  // Run checks that use all of the profiles at once.
174  entireSampleChecks(profileDataHandler,
175  profileCheckValidator,
176  profileChecker,
177  checkSubgroup);
178  } else {
179  // Run checks on individual profiles sequentially.
180  individualProfileChecks(profileDataHandler,
181  profileCheckValidator,
182  profileChecker,
183  checkSubgroup);
184  }
185  }
186 
187  // Optionally compare check results with OPS values
188  if (options_.compareWithOPS.value()) {
189  profileDataHandler.resetProfileIndices();
190  for (int jprof = 0; jprof < obsdb_.nrecs(); ++jprof) {
191  profileDataHandler.initialiseNextProfile();
192  profileCheckValidator.validate(profileDataHandler, obsdb_.comm().size());
193  nMismatches_.emplace_back(profileCheckValidator.getMismatches());
194  }
195  }
196  }
197 
198  // -----------------------------------------------------------------------------
199 
200  void ConventionalProfileProcessing::print(std::ostream & os) const {
201  os << "ConventionalProfileProcessing: config = " << options_ << std::endl;
202  }
203 
204  // -----------------------------------------------------------------------------
205 
206 } // namespace ufo
ConventionalProfileProcessingParameters options_
Configurable options.
void individualProfileChecks(ProfileDataHandler &profileDataHandler, ProfileCheckValidator &profileCheckValidator, ProfileChecker &profileChecker, const CheckSubgroup &subGroupChecks) const
Run checks on individual profiles sequentially.
void print(std::ostream &) const override
void entireSampleChecks(ProfileDataHandler &profileDataHandler, ProfileCheckValidator &profileCheckValidator, ProfileChecker &profileChecker, const CheckSubgroup &subGroupChecks) const
Run checks that use all of the profiles at once.
void applyFilter(const std::vector< bool > &, const Variables &, std::vector< std::vector< bool >> &) const override
ConventionalProfileProcessing(ioda::ObsSpace &, const Parameters_ &, std::shared_ptr< ioda::ObsDataVector< int > >, std::shared_ptr< ioda::ObsDataVector< float > >)
Options controlling the operation of the ConventionalProfileProcessing filter.
oops::Parameter< bool > compareWithOPS
Compare with OPS values?
DataHandlerParameters DHParameters
Parameters related to profile data handler.
Base class for UFO QC filters.
Definition: FilterBase.h:45
ufo::Variables filtervars_
Definition: FilterBase.h:60
ufo::Variables allvars_
ioda::ObsSpace & obsdb_
Profile QC check validator.
void validate(ProfileDataHandler &profileDataHandler, size_t commSize)
Validate check results against OPS values.
int getMismatches() const
Get number of mismatches between values produced in this code and the OPS equivalents.
Profile QC checker.
void runChecks(ProfileDataHandler &profileDataHandler, const CheckSubgroup &subGroupChecks)
Run all checks requested.
oops::Variables getObsDiagNames() const
Get vector of obs diagnostic names for all checks.
oops::Variables getGeoVaLNames() const
Get vector of GeoVaL names for all checks.
oops::Variables getValidationGeoVaLNames() const
Get vector of validation GeoVaL names for all checks.
CheckSubgroupList getCheckSubgroups()
Get container of check subgroups.
Retrieve and store data for individual profiles. To do this, first the vector of values in the entire...
std::vector< T > & get(const std::string &fullname)
Definition: RunCRTM.h:27
Information on each subgroup of checks.
static constexpr const char *const station_ID
Definition: VariableNames.h:85