UFO
ProfileAverageRelativeHumidity.cc
Go to the documentation of this file.
1 /*
2  * (C) 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 
8 #include <set>
9 #include <sstream>
10 #include <string>
11 #include <utility>
12 
17 
19 
20 namespace ufo {
21 
22  static ProfileCheckMaker<ProfileAverageRelativeHumidity>
23  makerProfileAverageRelativeHumidity_("AverageRelativeHumidity");
24 
27  : ProfileCheckBase(options)
28  {}
29 
31  {
32  oops::Log::debug() << " Relative humidity averaging" << std::endl;
33 
34  // Produce vector of profiles containing data for the wind speed averaging.
35  std::vector <std::string> variableNamesInt =
41  std::vector <std::string> variableNamesFloat =
50  std::vector <std::string> variableNamesGeoVaLs =
52 
53  if (options_.compareWithOPS.value()) {
54  variableNamesInt.insert
55  (variableNamesInt.end(),
56  {"OPS_" +
57  std::string(ufo::VariableNames::modellevels_average_relative_humidity_qcflags)});
58  variableNamesFloat.insert
59  (variableNamesFloat.end(),
60  {"OPS_" +
61  std::string(ufo::VariableNames::modellevels_average_relative_humidity_derived)});
62  variableNamesGeoVaLs.insert
63  (variableNamesGeoVaLs.end(),
64  {ufo::VariableNames::geovals_average_relative_humidity,
65  ufo::VariableNames::geovals_average_relative_humidity_qcflags});
66  }
67 
68  std::vector <ProfileDataHolder> profiles =
69  profileDataHandler.produceProfileVector
70  (variableNamesInt,
71  variableNamesFloat,
72  {},
73  variableNamesGeoVaLs,
74  {});
75 
76  // Run relative humidity averaging on each profile in the original ObsSpace,
77  // saving averaged output to the equivalent extended profile.
78  const size_t halfnprofs = profileDataHandler.getObsdb().nrecs() / 2;
79  for (size_t jprof = 0; jprof < halfnprofs; ++jprof) {
80  oops::Log::debug() << " Profile " << (jprof + 1) << " / " << halfnprofs << std::endl;
81  auto& profileOriginal = profiles[jprof];
82  auto& profileExtended = profiles[jprof + halfnprofs];
83  runCheckOnProfiles(profileOriginal, profileExtended);
84  }
85 
86  // Fill validation information if required.
87  if (options_.compareWithOPS.value()) {
88  oops::Log::debug() << " Filling validation data" << std::endl;
89  for (size_t jprof = 0; jprof < halfnprofs * 2; ++jprof) {
90  fillValidationData(profiles[jprof]);
91  }
92  }
93 
94  // Update data handler with profile information.
95  oops::Log::debug() << " Updating data handler" << std::endl;
96  profileDataHandler.updateAllProfiles(profiles);
97  }
98 
100  ProfileDataHolder &profileExtended)
101  {
102  // Check the two profiles are in the correct section of the ObsSpace.
105 
106  const size_t numProfileLevels = profileOriginal.getNumProfileLevels();
107  // Do not perform averaging if there is just one reported level.
108  if (numProfileLevels <= 1)
109  return;
110 
111  const std::vector <float> &rhObs =
112  profileOriginal.get<float>(ufo::VariableNames::obs_relative_humidity);
113  std::vector <float> &rhPGEBd =
114  profileOriginal.get<float>(ufo::VariableNames::pgebd_relative_humidity);
115  std::vector <int> &rhFlags =
117  // Optional: vector of sonde instrument types.
118  const std::vector <int> &InstrType =
119  profileOriginal.get<int>(ufo::VariableNames::InstrType);
120  std::vector <int> &NumGapsRH =
121  profileOriginal.get<int>(ufo::VariableNames::counter_NumGapsRH);
122 
123  if (!oops::allVectorsSameNonZeroSize(rhObs, rhPGEBd, rhFlags)) {
124  oops::Log::warning() << "At least one vector is the wrong size. "
125  << "Relative humidity averaging will not be performed." << std::endl;
126  oops::Log::warning() << "Vector sizes: "
127  << oops::listOfVectorSizes(rhObs,
128  rhPGEBd,
129  rhFlags)
130  << std::endl;
131  // todo(ctgh): Revisit this (and other routines in which a similar choice has been made)
132  // when the organisation of the input data becomes clearer.
133  return;
134  }
135 
136  // Obtain GeoVaLs.
137  std::vector <float> &geovals_relative_humidity =
139  if (geovals_relative_humidity.empty())
140  throw eckit::BadValue("GeoVaLs vector is empty.", Here());
141 
142  // Obtain vectors that were produced in the AveragePressure routine.
143  const std::vector <float> &LogPA =
145  const std::vector <float> &LogPB =
146  profileExtended.get<float>(ufo::VariableNames::modellevels_logP_derived);
147  const std::vector <float> &RepLogP =
148  profileOriginal.get<float>(ufo::VariableNames::LogP_derived);
149  const std::vector <float> &BigGap =
150  profileOriginal.get<float>(ufo::VariableNames::bigPgaps_derived);
151  if (LogPA.empty() || LogPB.empty() ||
152  !oops::allVectorsSameNonZeroSize(RepLogP, BigGap)) {
153  std::stringstream errorMessage;
154  errorMessage << "At least one model-level vector is the wrong size. "
155  << "Ensure that the AveragePressure routine has been run before this one."
156  << std::endl;
157  errorMessage << "Vector sizes: "
158  << oops::listOfVectorSizes(LogPA, LogPB,
159  RepLogP, BigGap)
160  << std::endl;
161  throw eckit::BadValue(errorMessage.str(), Here());
162  }
163 
164  // Flag reported value if the probability of gross error is too large.
165  // Values which have been flagged here, or previously, are not used in the averaging routines.
166  for (size_t jlev = 0; jlev < numProfileLevels; ++jlev)
167  if (rhPGEBd[jlev] > options_.AvgRH_PGEskip.value())
169 
170  // Interpolate Sonde RH onto model levels? The alternative is to perform a vertical average.
171  const bool RHinterp = options_.AvgRH_Interp;
172 
173  // Select model values of log(pressure) to use depending on whether averaging or
174  // interpolation is required.
175  const std::vector <float> &LogPmodel = RHinterp ? LogPB : LogPA;
176 
177  // Average observed relative humidities onto model levels.
178  int NumGaps = 0; // Number of large gaps in reported profile.
179  std::vector <float> rhModObs;
180  std::vector <int> rhFlagsModObs;
181  // Minimum fraction of a model layer that must have been covered (in the vertical coordinate)
182  // by observed values in order for averaging onto that layer to be performed.
183  const float SondeDZFraction = options_.AvgRH_SondeDZFraction.value();
184  calculateVerticalAverage(rhFlags,
185  rhObs,
186  RepLogP,
187  BigGap,
188  LogPmodel,
189  SondeDZFraction,
190  RHinterp ?
193  rhFlagsModObs,
194  rhModObs,
195  NumGaps);
196 
197  // Increment relative humidity gap counter if necessary.
198  if (NumGaps > 0) NumGapsRH[0]++;
199 
200  // If the model values of RH are missing, set the equivalent observed values to missing.
201  for (size_t mlev = 0; mlev < geovals_relative_humidity.size(); ++mlev)
202  if (geovals_relative_humidity[mlev] == missingValueFloat)
203  rhModObs[mlev] = missingValueFloat;
204 
205  // If the temperature averaging was previously performed,
206  // potentially reject further relative humidity observations.
207  const std::vector <float> &tModObs =
208  profileExtended.get<float>
210  if (!tModObs.empty()) {
211  // Reject the average relative humidity if the equivalent averaged temperature
212  // is less than a particular threshold.
213  // There is a default value for the temperature threshold which can be overridden
214  // by instrument-dependent values.
215  float SondeRHminT = options_.AvgRH_AvgTThreshold.value();
216  // Overwrite the value if the instrument is a particular type.
217  if (!InstrType.empty()) {
218  const int profileInstr = InstrType[0];
219  const auto &InstrTThresholds = options_.AvgRH_InstrTThresholds.value();
220  if (InstrTThresholds.find(profileInstr) != InstrTThresholds.end())
221  SondeRHminT = InstrTThresholds.at(profileInstr);
222  }
223 
224  // Reject sonde RH?
225  bool RejectRH = false;
226  for (int mlev = 0; mlev < tModObs.size(); ++mlev) {
227  // Once RejectRH is true for one level it is true for the
228  // remaining levels in the profile. This is the OPS behaviour.
229  if (tModObs[mlev] != missingValueFloat &&
230  tModObs[mlev] <= ufo::Constants::t0c + SondeRHminT)
231  RejectRH = true;
232  if (RejectRH)
233  rhFlagsModObs[mlev] |= ufo::MetOfficeQCFlags::Elem::PermRejectFlag;
234  }
235  }
236 
237  // Store the relative humidity averaged onto model levels.
238  profileExtended.set<float>
240 
241  // Store the QC flags associated with the relative humidity averaging.
242  profileExtended.set<int>
244  }
245 
247  {
248  // Retrieve, then save, the OPS versions of relative humidity averaged onto model levels,
249  // and the QC flags associated with the averaging process.
250  profile.set<float>
252  std::move(profile.getGeoVaLVector
254 
255  // The QC flags are stored as floats but are converted to integers here.
256  // Due to the loss of precision, 5 must be added to the missing value.
257  const std::vector <float>& average_relative_humidity_qcflags_float =
258  profile.getGeoVaLVector
260  std::vector <int> average_relative_humidity_qcflags_int
261  (average_relative_humidity_qcflags_float.begin(),
262  average_relative_humidity_qcflags_float.end());
263  std::replace(average_relative_humidity_qcflags_int.begin(),
264  average_relative_humidity_qcflags_int.end(),
265  -2147483648L,
266  -2147483643L);
267  profile.set<int>
269  std::move(average_relative_humidity_qcflags_int));
270  }
271 } // namespace ufo
Options controlling the operation of the ConventionalProfileProcessing filter.
oops::Parameter< std::map< int, float > > AvgRH_InstrTThresholds
oops::Parameter< bool > compareWithOPS
Compare with OPS values?
oops::Parameter< bool > AvgRH_Interp
Perform interpolation or averaging of relative humidity observations?
void runCheck(ProfileDataHandler &profileDataHandler) override
ProfileAverageRelativeHumidity(const ConventionalProfileProcessingParameters &options)
void runCheckOnProfiles(ProfileDataHolder &profileOriginal, ProfileDataHolder &profileExtended)
void fillValidationData(ProfileDataHolder &profileDataHolder)
Fill variables in validator (for comparison with OPS output).
Profile QC checker base class.
const float missingValueFloat
Missing value (float)
const ConventionalProfileProcessingParameters & options_
Configurable parameters.
Retrieve and store data for individual profiles. To do this, first the vector of values in the entire...
void updateAllProfiles(std::vector< ProfileDataHolder > &profiles)
Read values from a collection of profiles and update information related to each one.
std::vector< ProfileDataHolder > produceProfileVector(const std::vector< std::string > &variableNamesInt, const std::vector< std::string > &variableNamesFloat, const std::vector< std::string > &variableNamesString, const std::vector< std::string > &variableNamesGeoVaLs, const std::vector< std::string > &variableNamesObsDiags)
Produce a vector of all profiles, loading the requested variables into each one.
ioda::ObsSpace & getObsdb()
Return obsdb.
Profile data holder class.
int getNumProfileLevels() const
Get number of profile levels for this profile.
std::vector< T > & get(const std::string &fullname)
Retrieve a vector if it is present. If not, throw an exception.
void set(const std::string &fullname, std::vector< T > &&vec_in)
Set values in a vector.
std::vector< float > & getGeoVaLVector(const std::string &fullname)
Retrieve a GeoVaL vector if it is present. If not, throw an exception.
void checkObsSpaceSection(ufo::ObsSpaceSection section)
Check this profile is in the expected ObsSpace section (original or extended).
@ FinalRejectFlag
Final QC flag.
@ PermRejectFlag
Blacklisted data.
constexpr int profile
Definition: QCflags.h:34
Definition: RunCRTM.h:27
void calculateVerticalAverage(const std::vector< int > &flagsIn, const std::vector< float > &valuesIn, const std::vector< float > &coordIn, const std::vector< float > &bigGap, const std::vector< float > &coordOut, float DZFrac, ProfileAveraging::Method method, std::vector< int > &flagsOut, std::vector< float > &valuesOut, int &numGaps, std::vector< float > *coordMax, std::vector< float > *coordMin)
Profile vertical averaging onto model levels.
static ProfileCheckMaker< ProfileAverageRelativeHumidity > makerProfileAverageRelativeHumidity_("AverageRelativeHumidity")
static constexpr double t0c
Definition: Constants.h:24
static constexpr const char *const geovals_relative_humidity
static constexpr const char *const extended_obs_space
Definition: VariableNames.h:94
static constexpr const char *const obs_relative_humidity
Definition: VariableNames.h:20
static constexpr const char *const bigPgaps_derived
static constexpr const char *const modellevels_logP_derived
static constexpr const char *const qcflags_relative_humidity
static constexpr const char *const geovals_average_relative_humidity
static constexpr const char *const modellevels_average_relative_humidity_derived
static constexpr const char *const LogP_derived
static constexpr const char *const InstrType
Definition: VariableNames.h:93
static constexpr const char *const modellevels_logP_rho_derived
static constexpr const char *const modellevels_average_relative_humidity_qcflags
static constexpr const char *const modellevels_average_air_temperature_derived
static constexpr const char *const counter_NumGapsRH
static constexpr const char *const pgebd_relative_humidity
Definition: VariableNames.h:74
static constexpr const char *const geovals_average_relative_humidity_qcflags