UFO
ProfileAveragePressure.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 
14 
17 
19 
20 namespace ufo {
21 
22  static ProfileCheckMaker<ProfileAveragePressure>
23  makerProfileAveragePressure_("AveragePressure");
24 
27  : ProfileCheckBase(options)
28  {}
29 
30  void ProfileAveragePressure::logPressure(const std::vector <float> &pressures,
31  std::vector <float> &logP)
32  {
33  logP = pressures;
34  std::transform(logP.begin(), logP.end(), logP.begin(),
35  [this](float PLev){return PLev > 0 ? std::log(PLev) : missingValueFloat;});
36  }
37 
38  void ProfileAveragePressure::ExnerPressure(const std::vector <float> &pressures,
39  std::vector <float> &ExnerP)
40  {
41  ExnerP = pressures;
42  std::transform(ExnerP.begin(), ExnerP.end(), ExnerP.begin(),
43  [this](float PLev){return PLev > 0 ?
44  std::pow(PLev / ufo::Constants::pref, ufo::Constants::rd_over_cp) :
45  missingValueFloat;});
46  }
47 
48  void ProfileAveragePressure::bigPressureGaps(const std::vector <float> &pressures,
49  const int ObsType,
50  std::vector <float> &bigPgaps)
51  {
52  bigPgaps = pressures;
53  const float GapSize = std::log(10.0f);
54  const float GapFactor = ObsType == ufo::MetOfficeObsIDs::AtmosphericProfile::WindProf ?
55  options_.AvgP_WinProGapFactor.value() * GapSize :
56  options_.AvgP_SondeGapFactor.value() * GapSize;
57  const float GapLogPDiffMin = options_.AvgP_GapLogPDiffMin.value();
58  // Subtracting log(100.0) from PLev effectively converts the pressure to hPa.
59  std::transform(bigPgaps.begin(), bigPgaps.end(), bigPgaps.begin(),
60  [this, GapFactor, GapLogPDiffMin](float PLev){return PLev > 0.0 ?
61  GapFactor / std::max(std::log(PLev) - std::log(100.0f), GapLogPDiffMin) :
62  missingValueFloat;});
63  }
64 
66  {
67  oops::Log::debug() << " Pressure transformation" << std::endl;
68 
69  // Produce vector of profiles containing data for the pressure transformation.
70  std::vector <std::string> variableNamesFloat =
78  std::vector <std::string> variableNamesGeoVaLs =
81 
82  if (options_.compareWithOPS.value()) {
83  variableNamesFloat.insert
84  (variableNamesFloat.end(),
85  {"OPS_" + std::string(ufo::VariableNames::modellevels_logP_rho_derived),
86  "OPS_" + std::string(ufo::VariableNames::modellevels_logP_derived),
87  "OPS_" + std::string(ufo::VariableNames::modellevels_ExnerP_rho_derived),
88  "OPS_" + std::string(ufo::VariableNames::modellevels_ExnerP_derived)});
89  variableNamesGeoVaLs.insert
90  (variableNamesGeoVaLs.end(),
91  {ufo::VariableNames::geovals_logP_rho,
92  ufo::VariableNames::geovals_logP,
93  ufo::VariableNames::geovals_ExnerP_rho,
94  ufo::VariableNames::geovals_ExnerP});
95  }
96 
97  std::vector <ProfileDataHolder> profiles =
98  profileDataHandler.produceProfileVector
102  variableNamesFloat,
103  {},
104  variableNamesGeoVaLs,
105  {});
106 
107  // Run pressure transformation on each profile in the original ObsSpace,
108  // saving transformed output to the equivalent extended profile.
109  const size_t halfnprofs = profileDataHandler.getObsdb().nrecs() / 2;
110  for (size_t jprof = 0; jprof < halfnprofs; ++jprof) {
111  oops::Log::debug() << " Profile " << (jprof + 1) << " / " << halfnprofs << std::endl;
112  auto& profileOriginal = profiles[jprof];
113  auto& profileExtended = profiles[jprof + halfnprofs];
114  runCheckOnProfiles(profileOriginal, profileExtended);
115  }
116 
117  // Fill validation information if required.
118  if (options_.compareWithOPS.value()) {
119  for (size_t jprof = 0; jprof < halfnprofs * 2; ++jprof)
120  fillValidationData(profiles[jprof]);
121  }
122 
123  // Update data handler with profile information.
124  oops::Log::debug() << " Updating data handler" << std::endl;
125  profileDataHandler.updateAllProfiles(profiles);
126  }
127 
129  ProfileDataHolder &profileExtended)
130  {
131  // Check the two profiles are in the correct section of the ObsSpace.
134 
135  const size_t numProfileLevels = profileOriginal.getNumProfileLevels();
136  const std::vector <float> &pressures =
137  profileOriginal.get<float>(ufo::VariableNames::obs_air_pressure);
138  const std::vector <int> &ObsType =
139  profileOriginal.get<int>(ufo::VariableNames::ObsType);
140  const std::vector <int> &ReportFlags =
142 
143  if (!oops::allVectorsSameNonZeroSize(pressures, ObsType, ReportFlags)) {
144  std::stringstream errorMessage;
145  errorMessage << "At least one vector is the wrong size. "
146  << "Pressure transformation will not be performed." << std::endl;
147  errorMessage << "Vector sizes: "
148  << oops::listOfVectorSizes(pressures, ObsType, ReportFlags)
149  << std::endl;
150  throw eckit::BadValue(errorMessage.str(), Here());
151  }
152 
153  // Initialise vectors on reported levels.
154  std::vector <float> logP(numProfileLevels, missingValueFloat); // log(pressure)
155  std::vector <float> bigPgaps(numProfileLevels, missingValueFloat); // Big gaps in pressure
156 
157  // Initialise vectors on model rho levels.
158  const size_t numModelLevels_rho = options_.DHParameters.ModParameters.numModelLevels_rho();
159  std::vector <float> geovals_logP_rho(numModelLevels_rho, missingValueFloat); // log(pressure)
160  std::vector <float> geovals_ExnerP_rho
161  (numModelLevels_rho, missingValueFloat); // Exner pressure
162 
163  // Initialise vectors on model theta levels.
164  const size_t numModelLevels = options_.DHParameters.ModParameters.numModelLevels();
165  std::vector <float> geovals_logP(numModelLevels, missingValueFloat); // log(pressure)
166  std::vector <float> geovals_ExnerP(numModelLevels, missingValueFloat); // Exner pressure
167 
168  // Determine transformed pressures, unless:
169  // - there are zero or one reported levels in the profile, or
170  // - certain QC flags have previously been set.
171  if (numProfileLevels > 1 &&
174  // Determine log(P) on reported levels.
175  logPressure(pressures, logP);
176 
177  // Determine size of big gaps for each reported level.
178  bigPressureGaps(pressures, ObsType[0], bigPgaps);
179 
180  // Calculate log(P) and Exner pressure for GeoVaLs on rho levels.
181  const std::vector <float> &geovals_pressure_rho =
183  logPressure(geovals_pressure_rho, geovals_logP_rho);
184  ExnerPressure(geovals_pressure_rho, geovals_ExnerP_rho);
185 
186  // Calculate log(P) and Exner pressure for GeoVaLs on theta levels.
187  const std::vector <float> &geovals_pressure =
189  // Require these GeoVaLs to be present (unlike the case on rho levels).
190  if (geovals_pressure.empty())
191  throw eckit::BadValue("geovals_pressure is empty", Here());
192  logPressure(geovals_pressure, geovals_logP);
193  ExnerPressure(geovals_pressure, geovals_ExnerP);
194  }
195 
196  // Store the transformed pressures on reported levels.
197  profileOriginal.set<float>(ufo::VariableNames::LogP_derived, std::move(logP));
198  profileOriginal.set<float>(ufo::VariableNames::bigPgaps_derived, std::move(bigPgaps));
199 
200  // Store the transformed pressures on model levels.
202  std::move(geovals_logP_rho));
203  profileExtended.set<float>(ufo::VariableNames::modellevels_logP_derived,
204  std::move(geovals_logP));
206  std::move(geovals_ExnerP_rho));
208  std::move(geovals_ExnerP));
209  }
210 
212  {
213  // Retrieve, then save, the OPS versions of the transformed pressures on model levels.
214  profile.set<float>
216  std::move(profile.getGeoVaLVector
218  profile.set<float>
219  ("OPS_" + std::string(ufo::VariableNames::modellevels_logP_derived),
220  std::move(profile.getGeoVaLVector
222  profile.set<float>
224  std::move(profile.getGeoVaLVector
226  profile.set<float>
227  ("OPS_" + std::string(ufo::VariableNames::modellevels_ExnerP_derived),
228  std::move(profile.getGeoVaLVector
230  }
231 
232 } // namespace ufo
Options controlling the operation of the ConventionalProfileProcessing filter.
oops::Parameter< bool > compareWithOPS
Compare with OPS values?
DataHandlerParameters DHParameters
Parameters related to profile data handler.
ModelParameters ModParameters
Parameters related to the model.
size_t numModelLevels() const
Number of model theta levels.
size_t numModelLevels_rho() const
void ExnerPressure(const std::vector< float > &pressures, std::vector< float > &ExnerP)
Calculate Exner pressure.
void bigPressureGaps(const std::vector< float > &pressures, const int ObsType, std::vector< float > &bigPgaps)
Calculate big gap for each pressure.
void runCheckOnProfiles(ProfileDataHolder &profileOriginal, ProfileDataHolder &profileExtended)
ProfileAveragePressure(const ConventionalProfileProcessingParameters &options)
void logPressure(const std::vector< float > &pressures, std::vector< float > &logP)
Calculate log(pressure).
void fillValidationData(ProfileDataHolder &profileDataHolder)
Fill variables in validator.
void runCheck(ProfileDataHandler &profileDataHandler) override
Run check on all profiles.
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).
@ FinalRejectReport
One of flags 1-6 set.
@ OutOfAreaReport
Outside analysis area/time.
constexpr int profile
Definition: QCflags.h:34
Definition: RunCRTM.h:27
static ProfileCheckMaker< ProfileAveragePressure > makerProfileAveragePressure_("AveragePressure")
static constexpr const char *const extended_obs_space
Definition: VariableNames.h:94
static constexpr const char *const qcflags_observation_report
Definition: VariableNames.h:98
static constexpr const char *const modellevels_ExnerP_derived
static constexpr const char *const geovals_ExnerP
static constexpr const char *const bigPgaps_derived
static constexpr const char *const modellevels_logP_derived
static constexpr const char *const LogP_derived
static constexpr const char *const modellevels_logP_rho_derived
static constexpr const char *const geovals_pressure
static constexpr const char *const modellevels_ExnerP_rho_derived
static constexpr const char *const geovals_logP
static constexpr const char *const ObsType
Definition: VariableNames.h:87
static constexpr const char *const obs_air_pressure
Definition: VariableNames.h:18
static constexpr const char *const geovals_pressure_rho
static constexpr const char *const geovals_ExnerP_rho
static constexpr const char *const geovals_logP_rho