UFO
Cal_PressureFromHeight.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 
9 #include "ufo/utils/Constants.h"
10 
11 namespace ufo {
12 /************************************************************************************/
13 // Cal_PressureFromHeightForProfile
14 /************************************************************************************/
15 
16 static TransformMaker<Cal_PressureFromHeightForProfile>
17  makerCal_PressureFromHeightForProfile_("PressureFromHeightForProfile");
18 
20  const VariableTransformsParameters &options, const ObsFilterData &data,
21  const std::shared_ptr<ioda::ObsDataVector<int>> &flags)
22  : TransformBase(options, data, flags) {}
23 
24 /************************************************************************************/
25 
26 void Cal_PressureFromHeightForProfile::runTransform(const std::vector<bool> &apply) {
27  oops::Log::trace() << " --> Retrieve Pressure From Height (Profile)"
28  << std::endl;
29  oops::Log::trace() << " --> method: " << method() << std::endl;
30  oops::Log::trace() << " --> formulation: " << formulation() << std::endl;
31  oops::Log::trace() << " --> obsName: " << obsName() << std::endl;
32 
33  // Get the right method
34  switch (method()) {
38  default: {
39  methodUKMO(apply);
40  break;
41  }
42  }
43 }
44 
45 /************************************************************************************/
46 
47 void Cal_PressureFromHeightForProfile::methodUKMO(const std::vector<bool> &apply) {
48  std::vector<float> airTemperature;
49  std::vector<float> airTemperatureSurface;
50  std::vector<float> geopotentialHeight;
51  std::vector<float> dewPointTemperature;
52  std::vector<float> dewPointTemperatureSurface;
53  std::vector<float> relativeHumidity;
54  std::vector<float> relativeHumiditySurface;
55  std::vector<float> pressureStation;
56  std::vector<float> stationElevation;
57  std::vector<float> airPressure;
58 
59  float Pvap = missingValueFloat; // Vapour pressure
60  float Zcurrent = missingValueFloat; // Current height value
61  float Tcurrent = missingValueFloat; // Current temperature value
62  float Pprev = missingValueFloat; // Previous pressure value [ps]
63  float Zprev = missingValueFloat; // Previous height value [m]
64  float Tprev = missingValueFloat; // Previous temperature value [k]
65 
66  bool hasBeenUpdated = false;
67 
68  const size_t nlocs_ = obsdb_.nlocs();
69  ioda::ObsSpace::RecIdxIter irec;
70 
71  // return if no data
72  if (obsdb_.nlocs() == 0) {
73  return;
74  }
75 
76  // Here we can only use data that have not been QCed
77  // so making sure UseValidDataOnly_ is set to True
78  SetUseValidDataOnly(true);
79 
80  // 0. Innitialise the ouput array
81  // -------------------------------------------------------------------------------
82  getObservation("MetaData", "air_pressure",
83  airPressure);
84  if (airPressure.empty()) {
85  airPressure = std::vector<float>(nlocs_);
86  std::fill(airPressure.begin(), airPressure.end(), missingValueFloat);
87  }
88 
89  // 1. get the right variables
90  // -------------------------------------------------------------------------------
91  // Compulsory meta-data
92  getObservation("MetaData", "station_elevation",
93  stationElevation, true);
94  // Compulsory surface observation
95  getObservation("ObsValue", "pressure_station",
96  pressureStation, true);
97  getObservation("ObsValue", "air_temperature_surface",
98  airTemperatureSurface, true);
99 
100  // Compulsory upper air observation
101  getObservation("ObsValue", "geopotential_height",
102  geopotentialHeight, true);
103  getObservation("ObsValue", "air_temperature",
104  airTemperature, true);
105 
106  // Here we have a choice between dew point temperature and relative humidity
107  // --> By default we chose dew point temperature first!
108  getObservation("ObsValue", "dew_point_temperature",
109  dewPointTemperature);
110  if (dewPointTemperature.empty()) {
111  // if we don't have dewpoint temperature, use relative humidity.
112  getObservation("ObsValue", "relative_humidity",
113  relativeHumidity, true);
114  getObservation("ObsValue", "relative_humidity_surface",
115  relativeHumiditySurface, true);
116  } else {
117  getObservation("ObsValue", "dew_point_temperature_surface",
118  dewPointTemperatureSurface, true);
119  }
120 
121  // 3. making sure we have what we need is here
122  // -------------------------------------------------------------------------------
123  if (dewPointTemperature.empty()) {
124  if (!oops::allVectorsSameNonZeroSize(geopotentialHeight, airTemperature, relativeHumidity)) {
125  oops::Log::warning() << "Vector sizes: "
126  << oops::listOfVectorSizes(geopotentialHeight, airTemperature,
127  relativeHumidity)
128  << std::endl;
129  throw eckit::BadValue("At least one vector is the wrong size or empty out of "
130  "Z, T and Rh", Here());
131  }
132  } else {
133  if (!oops::allVectorsSameNonZeroSize(geopotentialHeight, airTemperature, dewPointTemperature)) {
134  oops::Log::warning() << "Vector sizes: "
135  << oops::listOfVectorSizes(geopotentialHeight, airTemperature,
136  dewPointTemperature)
137  << std::endl;
138  throw eckit::BadValue("At least one vector is the wrong size or empty out of "
139  "Z, T and Td", Here());
140  }
141  }
142 
143  // 4. Starting the calculation
144  // Loop over each record
145  // -------------------------------------------------------------------------------------
146  for (irec = obsdb_.recidx_begin(); irec != obsdb_.recidx_end(); ++irec) {
147  const std::vector<std::size_t> &rSort = obsdb_.recidx_vector(irec);
148  size_t ilocs = 0;
149 
150  // 4.1 Initialise for surface values
151  Pprev = pressureStation[rSort[ilocs]];
152  Zprev = stationElevation[rSort[ilocs]];
153  Tprev = airTemperatureSurface[rSort[ilocs]];
154 
155  // Cycle if stationElevation or airTemperatureSurface or pressureStation is
156  // not valid
157  if (Zprev == missingValueFloat || Tprev == missingValueFloat ||
158  Pprev == missingValueFloat)
159  continue;
160 
161  // Update Tprev
162  if (dewPointTemperature.empty()) {
163  // Update Tprev if Rh is valid
164  if (relativeHumidity[rSort[ilocs]] != missingValueFloat) {
166  Pvap = formulas::SatVaporPres_correction(Pvap, Tprev, -1.0, formulation());
168  relativeHumiditySurface[rSort[ilocs]], Pvap, Pprev, Tprev, formulation());
169  }
170 
171  } else {
172  // Update Tprev if dew point positive
173  if (dewPointTemperature[rSort[ilocs]] != missingValueFloat) {
174  Pvap = formulas::SatVaporPres_fromTemp(dewPointTemperatureSurface[rSort[ilocs]],
175  formulation());
177  dewPointTemperatureSurface[rSort[ilocs]],
178  -1.0,
179  formulation());
180  Tprev = formulas::VirtualTemp_From_Psat_P_T(Pvap, Pprev, Tprev, formulation());
181  }
182  }
183 
184  // 4.2 Loop over the length of the profile
185  for (ilocs = 0; ilocs < rSort.size(); ++ilocs) {
186  // if the data have been excluded by the where statement
187  if (!apply[rSort[ilocs]]) continue;
188 
189  // Take current level values
190  Zcurrent = geopotentialHeight[rSort[ilocs]];
191  Tcurrent = airTemperature[rSort[ilocs]];
192 
193  // Cycle if airPressure is valid
194  if (airPressure[rSort[ilocs]] != missingValueFloat) continue;
195 
196  // Cycle if geopotentialHeight or airTemperatures is not valid
197  if (Zcurrent == missingValueFloat || Tcurrent == missingValueFloat) continue;
198 
199  // Update Tcurrent
200  if (dewPointTemperature.empty()) {
201  // Update Tcurrent if Rh is valid
202  if (relativeHumidity[rSort[ilocs]] != missingValueFloat) {
204  Pvap = formulas::SatVaporPres_correction(Pvap, Tprev, -1.0, formulation());
206  relativeHumidity[rSort[ilocs]], Pvap, Pprev, Tcurrent, formulation());
207  }
208  } else {
209  // Update Tcurrent if dew point positive
210  if (dewPointTemperature[rSort[ilocs]] != missingValueFloat) {
211  Pvap = formulas::SatVaporPres_fromTemp(dewPointTemperature[rSort[ilocs]],
212  formulation());
214  dewPointTemperature[rSort[ilocs]],
215  -1.0,
216  formulation());
217  Tcurrent = formulas::VirtualTemp_From_Psat_P_T(Pvap, Pprev, Tcurrent, formulation());
218  }
219  }
220  // Hydrostatic equation:
221  airPressure[rSort[ilocs]] =
222  Pprev * std::exp((Zprev - Zcurrent) * Constants::grav * 2.0 /
223  (Constants::rd * (Tprev + Tcurrent)));
224 
225  // update previous level for next level up
226  Pprev = airPressure[rSort[ilocs]];
227  Zprev = Zcurrent;
228  Tprev = Tcurrent;
229  hasBeenUpdated = true;
230  }
231  }
232 
233  if (hasBeenUpdated) {
234  // if updated the airPressure
235  // assign the derived air pressure as DerivedObsValue
236  putObservation("air_pressure", airPressure);
237  }
238 }
239 
240 /************************************************************************************/
241 // Cal_PressureFromHeightForICAO
242 /************************************************************************************/
244  makerCal_PressureFromHeightForICAO_("PressureFromHeightForICAO");
245 
247  const VariableTransformsParameters &options, const ObsFilterData &data,
248  const std::shared_ptr<ioda::ObsDataVector<int>> &flags)
249  : TransformBase(options, data, flags) {}
250 
251 /************************************************************************************/
252 
253 void Cal_PressureFromHeightForICAO::runTransform(const std::vector<bool> &apply) {
254  oops::Log::trace() << " Retrieve Pressure From Height (ICAO)" << std::endl;
255  oops::Log::trace() << " --> method: " << method() << std::endl;
256  oops::Log::trace() << " --> formulation: " << formulation() << std::endl;
257  oops::Log::trace() << " --> obsName: " << obsName() << std::endl;
258 
259  // Get the right method
260  switch (method()) {
264  default: {
265  methodUKMO(apply);
266  break;
267  }
268  }
269 }
270 /************************************************************************************/
271 
272 void Cal_PressureFromHeightForICAO::methodUKMO(const std::vector<bool> &apply) {
273  std::vector<float> geopotentialHeight;
274  std::vector<float> airPressure;
275  std::vector<float> airPressure_ref;
276  bool hasBeenUpdated = false;
277 
278  const size_t nlocs_ = obsdb_.nlocs();
279 
280  ioda::ObsSpace::RecIdxIter irec;
281 
282  // 0. Initialise the ouput array
283  // -------------------------------------------------------------------------------
284  getObservation("MetaData", "air_pressure",
285  airPressure);
286  if (airPressure.empty()) {
287  airPressure = std::vector<float>(nlocs_);
288  std::fill(airPressure.begin(), airPressure.end(), missingValueFloat);
289  }
290 
291  // 1. get the right variables
292  // -------------------------------------------------------------------------------
293  getObservation("ObsValue", "geopotential_height",
294  geopotentialHeight);
295 
296  // 2. making sure what we need is here
297  // -------------------------------------------------------------------------------
298  if (oops::anyVectorEmpty(geopotentialHeight)) {
299  oops::Log::warning() << "GeopotentialHeight vector is empty. "
300  << "Check will not be performed." << std::endl;
301  throw eckit::BadValue("GeopotentialHeight vector is the wrong size or empty ", Here());
302  }
303 
304  // 3. Loop over each record
305  // -------------------------------------------------------------------------------------
306  for (irec = obsdb_.recidx_begin(); irec != obsdb_.recidx_end(); ++irec) {
307  const std::vector<std::size_t> &rSort = obsdb_.recidx_vector(irec);
308  size_t ilocs = 0;
309 
310  // 3.1 Loop over each record
311  for (ilocs = 0; ilocs < rSort.size(); ++ilocs) {
312  // if the data have been excluded by the where statement
313  if (!apply[rSort[ilocs]]) continue;
314 
315  // Cycle if airPressure is valid
316  if (airPressure[rSort[ilocs]] != missingValueFloat) continue;
317 
318  airPressure[rSort[ilocs]] = formulas::Height_To_Pressure_ICAO_atmos(
319  geopotentialHeight[rSort[ilocs]], formulation());
320 
321  hasBeenUpdated = true;
322  }
323  }
324 
325  if (hasBeenUpdated) {
326  // if updated the airPressure
327  // assign the derived air pressure as DerivedObsValue
328  putObservation("air_pressure", airPressure);
329  }
330 }
331 } // namespace ufo
332 
void methodUKMO(const std::vector< bool > &apply)
void runTransform(const std::vector< bool > &apply) override
Run variable conversion.
Cal_PressureFromHeightForICAO(const VariableTransformsParameters &options, const ObsFilterData &data, const std::shared_ptr< ioda::ObsDataVector< int >> &flags)
void runTransform(const std::vector< bool > &apply) override
Run variable conversion.
Cal_PressureFromHeightForProfile(const VariableTransformsParameters &options, const ObsFilterData &data, const std::shared_ptr< ioda::ObsDataVector< int >> &flags)
void methodUKMO(const std::vector< bool > &apply)
ObsFilterData provides access to all data related to an ObsFilter.
Base class for variable conversion.
Definition: TransformBase.h:53
std::string obsName() const
subclasses to access the observation name
formulas::MethodFormulation method() const
subclasses to access Method and formualtion used for the calculation
void SetUseValidDataOnly(bool t)
void putObservation(const std::string &varName, const std::vector< T > &obsVector)
Save a transformed variable to the DerivedObsValue group of the obs space.
formulas::MethodFormulation formulation() const
const float missingValueFloat
Missing value (float)
ioda::ObsSpace & obsdb_
Observation space.
void getObservation(const std::string &originalTag, const std::string &varName, std::vector< T > &obsVector, bool require=false) const
templated function for float, int data types
Definition: TransformBase.h:94
Transform maker.
Options controlling the operation of the variablestansform filter.
float VirtualTemp_From_Rh_Psat_P_T(float Rh, float Psat, float P, float T, MethodFormulation formulation)
Derive Virtual Tempreture using Relative humidity, sat.
Definition: Formulas.cc:204
float SatVaporPres_correction(float e_sub_s, float temp_K, float pressure, MethodFormulation formulation)
Calculates saturated vapour pressure from temperature.
Definition: Formulas.cc:132
float VirtualTemp_From_Psat_P_T(float Psat, float P, float T, MethodFormulation formulation)
Derive Virtual Temperature from saturation vapour pressure, pressure and temperature.
Definition: Formulas.cc:187
float SatVaporPres_fromTemp(float temp_K, MethodFormulation formulation)
Calculates saturated vapour pressure from temperature.
Definition: Formulas.cc:45
@ NCAR
NCAR specific formulation.
Definition: Formulas.h:29
@ NOAA
NOAA specific formulation.
Definition: Formulas.h:30
@ UKMO
UKMO specific formulation.
Definition: Formulas.h:28
float Height_To_Pressure_ICAO_atmos(float height, MethodFormulation formulation)
Converts height to pressure using the International Civil Aviation Organization (ICAO) atmosphere.
Definition: Formulas.cc:224
Definition: RunCRTM.h:27
static TransformMaker< Cal_PressureFromHeightForICAO > makerCal_PressureFromHeightForICAO_("PressureFromHeightForICAO")
static TransformMaker< Cal_PressureFromHeightForProfile > makerCal_PressureFromHeightForProfile_("PressureFromHeightForProfile")
static constexpr double grav
Definition: Constants.h:23
static constexpr double rd
Definition: Constants.h:26