ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_SatMethods.H
Go to the documentation of this file.
1 // This class contains all methods for estimating
2 // the saturation vapor pressure of water.
3 //
4 // wv_saturation provides specific interfaces and utilities
5 // based on these formulae.
6 //
7 // Typical usage of this module:
8 //
9 // Init:
10 // call wv_sat_methods_init(r8, <constants>, errstring)
11 //
12 // Get scheme index from a name string:
13 // scheme_idx = wv_sat_get_scheme_idx(scheme_name)
14 // if (.not. wv_sat_valid_idx(scheme_idx)) <throw some error>
15 //
16 // Get pressures:
17 // es = wv_sat_svp_water(t, scheme_idx)
18 // es = wv_sat_svp_ice(t, scheme_idx)
19 //
20 // Use ice/water transition range:
21 // es = wv_sat_svp_trice(t, ttrice, scheme_idx)
22 //
23 // Note that elemental functions cannot be pointed to, nor passed
24 // as arguments. If you need to do either, it is recommended to
25 // wrap the function so that it can be given an explicit (non-
26 // elemental) interface.
27 #ifndef ERF_SAT_METHOD_H_
28 #define ERF_SAT_METHOD_H_
29 
30 #include <string>
31 #include <vector>
32 #include <memory>
33 #include <cmath>
34 
35 #include "ERF_Constants.H"
36 
37 /**
38  * @brief Methods for estimating the saturation vapor pressure of water.
39  */
40 class SatMethods {
41 public:
42  // Get saturation specific humidity given pressure and SVP.
43  // Specific humidity is limited to range 0-1
44  /**
45  * @brief Get saturation specific humidity given pressure and SVP.
46  * @param[in] es Saturation vapor pressure.
47  * @param[in] p Total pressure.
48  * @return Saturation specific humidity.
49  */
50  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
52  // If pressure is less than SVP, set qs to maximum of amrex::Real(1)
53  if ( (p - es) <= amrex::Real(0) )
54  return amrex::Real(1);
55  else
56  return epsilo*es / (p - omeps*es);
57  }
58 
59  /**
60  * @brief Calculate SVP over water and saturation specific humidity.
61  * @param[in] t Temperature.
62  * @param[in] p Total pressure.
63  * @param[out] es Saturation vapor pressure.
64  * @param[out] qs Saturation specific humidity.
65  * @param[in] idx Scheme index.
66  */
67  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
68  static void wv_sat_qsat_water (const amrex::Real& t, const amrex::Real& p,
69  amrex::Real &es, amrex::Real &qs, const int idx = 1) {
70  // Purpose:
71  // Calculate SVP over water at a given temperature, and then
72  // calculate and return saturation specific humidity.
73 
74  es = wv_sat_svp_water(t, idx);
75 
76  qs = wv_sat_svp_to_qsat(es, p);
77 
78  // Ensures returned es is consistent with limiters on qs.
79  es = std::min(es, p);
80  }
81 
82  /**
83  * @brief Calculate SVP over ice and saturation specific humidity.
84  * @param[in] t Temperature.
85  * @param[in] p Total pressure.
86  * @param[out] es Saturation vapor pressure.
87  * @param[out] qs Saturation specific humidity.
88  * @param[in] idx Scheme index.
89  */
90  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
91  static void wv_sat_qsat_ice (const amrex::Real& t, const amrex::Real& p,
92  amrex::Real &es, amrex::Real &qs, const int idx = 1) {
93  // Purpose:
94  // Calculate SVP over ice at a given temperature, and then
95  // calculate and return saturation specific humidity.
96 
97  es = wv_sat_svp_ice(t, idx);
98 
99  qs = wv_sat_svp_to_qsat(es, p);
100 
101  // Ensures returned es is consistent with limiters on qs.
102  es = std::min(es, p);
103  }
104 
105  /**
106  * @brief Calculate transition SVP and saturation specific humidity.
107  * @param[in] t Temperature.
108  * @param[in] p Total pressure.
109  * @param[out] es Saturation vapor pressure.
110  * @param[out] qs Saturation specific humidity.
111  * @param[in] idx Scheme index.
112  */
113  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
114  static void wv_sat_qsat_trans (const amrex::Real& t, const amrex::Real& p,
115  amrex::Real &es, amrex::Real &qs, const int idx = 1) {
116  // Purpose:
117  // Calculate SVP over ice at a given temperature, and then
118  // calculate and return saturation specific humidity.
119 
120  es = wv_sat_svp_trans(t, idx);
121 
122  qs = wv_sat_svp_to_qsat(es, p);
123 
124  // Ensures returned es is consistent with limiters on qs.
125  es = std::min(es, p);
126  }
127 
128  // SVP INTERFACE FUNCTIONS
129  /**
130  * @brief Dispatcher for saturation vapor pressure over water.
131  * @param[in] t Temperature.
132  * @param[in] idx Scheme index.
133  * @return Saturation vapor pressure over water.
134  */
135  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
136  static amrex::Real wv_sat_svp_water (const amrex::Real& t, const int idx = 1) {
137  amrex::Real es;
138  switch(idx)
139  {
140  case GoffGratch:
141  es = GoffGratch_svp_water(t); break;
142  case MurphyKoop:
143  es = MurphyKoop_svp_water(t); break;
144  case OldGoffGratch:
145  es = OldGoffGratch_svp_water(t); break;
146  case Bolton:
147  es = Bolton_svp_water(t); break;
148  }
149  return es;
150  }
151 
152  /**
153  * @brief Dispatcher for saturation vapor pressure over ice.
154  * @param[in] t Temperature.
155  * @param[in] idx Scheme index.
156  * @return Saturation vapor pressure over ice.
157  */
158  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
159  static amrex::Real wv_sat_svp_ice (const amrex::Real& t, const int idx = 1) {
160  amrex::Real es;
161  switch(idx)
162  {
163  case GoffGratch:
164  es = GoffGratch_svp_ice(t); break;
165  case MurphyKoop:
166  es = MurphyKoop_svp_ice(t); break;
167  case OldGoffGratch:
168  es = OldGoffGratch_svp_ice(t); break;
169  case Bolton:
170  es = Bolton_svp_water(t); break;
171  }
172  return es;
173  }
174 
175  /**
176  * @brief Calculate transition saturation vapor pressure.
177  * @param[in] t Temperature.
178  * @param[in] idx Scheme index.
179  * @return Transition saturation vapor pressure.
180  */
181  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
182  static amrex::Real wv_sat_svp_trans (const amrex::Real& t, const int idx = 1) {
183  amrex::Real esice; // Saturation vapor pressure over ice
184  amrex::Real weight; // Intermediate scratch variable for es transition
185  amrex::Real es;
186 
187  // Water
188  if (t >= (tmelt - ttrice))
189  es = wv_sat_svp_water(t,idx);
190  else
191  es = amrex::Real(0);
192 
193  // Ice
194  if (t < tmelt) {
195  esice = wv_sat_svp_ice(t,idx);
196  if ( (tmelt - t) > ttrice )
197  weight = amrex::Real(1);
198  else
199  weight = (tmelt - t)/ttrice;
200 
201  es = weight*esice + (amrex::Real(1) - weight)*es;
202  }
203  return es;
204  }
205 
206 
207  // Goff & Gratch (1946)
208  /**
209  * @brief Goff & Gratch (1946) saturation vapor pressure over water.
210  * @param[in] t Temperature.
211  * @return Saturation vapor pressure.
212  */
213  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
215  // uncertain below -70 C
216  return pow(amrex::Real(10.), (-amrex::Real(7.90298)*(tboil/t-amrex::Real(1))+
217  amrex::Real(5.02808)*std::log10(tboil/t)-
218  amrex::Real(1.3816e-7)*(pow(amrex::Real(10.), (amrex::Real(11.344)*(amrex::Real(1)-t/tboil)))-amrex::Real(1))+
219  amrex::Real(8.1328e-3)*(pow(amrex::Real(10.), (-amrex::Real(3.49149)*(tboil/t-amrex::Real(1))))-amrex::Real(1))+
220  std::log10(amrex::Real(1013.246))))*amrex::Real(100.);
221  }
222 
223  /**
224  * @brief Goff & Gratch (1946) saturation vapor pressure over ice.
225  * @param[in] t Temperature.
226  * @return Saturation vapor pressure.
227  */
228  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
230  // good down to -100 C
231  return pow(amrex::Real(10.), (-amrex::Real(9.09718)*(h2otrip/t-amrex::Real(1))-amrex::Real(3.56654)*
232  log10(h2otrip/t)+amrex::Real(0.876793)*(amrex::Real(1)-t/h2otrip)+
233  log10(amrex::Real(6.1071))))*amrex::Real(100.);
234  }
235 
236  // Murphy & Koop (2005)
237  /**
238  * @brief Murphy & Koop (2005) saturation vapor pressure over water.
239  * @param[in] t Temperature.
240  * @return Saturation vapor pressure.
241  */
242  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
244  // (good for 123 < T < 332 K)
245  return exp(amrex::Real(54.842763) - (amrex::Real(6763.22) / t) - (amrex::Real(4.210) * log(t)) +
246  (amrex::Real(0.000367) * t) + (tanh(amrex::Real(0.0415) * (t - amrex::Real(218.8))) *
247  (amrex::Real(53.878) - (amrex::Real(1331.22) / t) - (amrex::Real(9.44523) * log(t)) +
248  amrex::Real(0.014025) * t)));
249  }
250 
251  /**
252  * @brief Murphy & Koop (2005) saturation vapor pressure over ice.
253  * @param[in] t Temperature.
254  * @return Saturation vapor pressure.
255  */
256  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
258  // (good down to 110 K)
259  return exp(amrex::Real(9.550426) - (amrex::Real(5723.265) / t) + (amrex::Real(3.53068) * log(t))
260  - (amrex::Real(0.00728332) * t));
261  }
262 
263 
264  // Old CAM implementation, also labeled Goff & Gratch (1946)
265 
266  // The water formula differs only due to compiler-dependent order of
267  // operations, so differences are roundoff level, usually zero
268 
269  // The ice formula gives fairly close answers to the current
270  // implementation, but has been rearranged, and uses the
271  // 1 atm melting point of water as the triple point.
272  // Differences are thus small but above roundoff.
273 
274  // A curious fact: although using the melting point of water was
275  // probably a mistake, it mildly improves accuracy for ice svp,
276  // since it compensates for a systematic error in Goff & Gratch.
277  /**
278  * @brief Old CAM implementation of Goff & Gratch (1946) SVP over water.
279  * @param[in] t Temperature.
280  * @return Saturation vapor pressure.
281  */
282  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
284  auto ps = amrex::Real(1013.246);
285  auto e1 = amrex::Real(11.344)*(amrex::Real(1) - t/tboil);
286  auto e2 = -amrex::Real(3.49149)*(tboil/t - amrex::Real(1));
287  auto f1 = -amrex::Real(7.90298)*(tboil/t - amrex::Real(1));
288  auto f2 = amrex::Real(5.02808)*log10(tboil/t);
289  auto f3 = -amrex::Real(1.3816)*(pow(amrex::Real(10.0), e1) - amrex::Real(1))/amrex::Real(10000000.0);
290  auto f4 = amrex::Real(8.1328)*(pow(amrex::Real(10.0), e2) - amrex::Real(1))/amrex::Real(1000.0);
291  auto f5 = log10(ps);
292  auto f = f1 + f2 + f3 + f4 + f5;
293  return (pow(amrex::Real(10.0), f))*amrex::Real(100.0);
294  }
295 
296  /**
297  * @brief Old CAM implementation of Goff & Gratch (1946) SVP over ice.
298  * @param[in] t Temperature.
299  * @return Saturation vapor pressure.
300  */
301  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
303  auto term1 = amrex::Real(2.01889049)/(tmelt/t);
304  auto term2 = amrex::Real(3.56654)*log(tmelt/t);
305  auto term3 = amrex::Real(20.947031)*(tmelt/t);
306  return amrex::Real(575.185606e10)*exp(-(term1 + term2 + term3));
307  }
308 
309  // Bolton (1980)
310  // zm_conv deep convection scheme contained this SVP calculation.
311  // It appears to be from D. Bolton, 1980, Monthly Weather Review.
312  // Unlike the other schemes, no distinct ice formula is associated
313  // with it. (However, a Bolton ice formula exists in CLUBB.)
314 
315  // The original formula used degrees C, but this function
316  // takes Kelvin and internally converts.
317  /**
318  * @brief Bolton (1980) saturation vapor pressure over water.
319  * @param[in] t Temperature.
320  * @return Saturation vapor pressure.
321  */
322  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
324  constexpr auto c1 = amrex::Real(611.2);
325  constexpr auto c2 = amrex::Real(17.67);
326  constexpr auto c3 = amrex::Real(243.5);
327  return c1*exp( (c2*(t - tmelt))/((t - tmelt)+c3) );
328  }
329 
330  // private data
331 private:
332  // Indices representing individual schemes
333  enum Type {
334  Invalid = -1,
338  Bolton = 3
339  };
340 };
341 #endif
constexpr amrex::Real tboil
Definition: ERF_Constants.H:132
constexpr amrex::Real epsilo
Definition: ERF_Constants.H:134
constexpr amrex::Real tmelt
Definition: ERF_Constants.H:130
constexpr amrex::Real ttrice
Definition: ERF_Constants.H:133
constexpr amrex::Real omeps
Definition: ERF_Constants.H:135
constexpr amrex::Real h2otrip
Definition: ERF_Constants.H:131
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int idx(int i, int j, int k, int nx, int ny)
Definition: ERF_InitForEnsemble.cpp:365
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Methods for estimating the saturation vapor pressure of water.
Definition: ERF_SatMethods.H:40
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE void wv_sat_qsat_trans(const amrex::Real &t, const amrex::Real &p, amrex::Real &es, amrex::Real &qs, const int idx=1)
Calculate transition SVP and saturation specific humidity.
Definition: ERF_SatMethods.H:114
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real Bolton_svp_water(const amrex::Real &t)
Bolton (1980) saturation vapor pressure over water.
Definition: ERF_SatMethods.H:323
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real OldGoffGratch_svp_ice(const amrex::Real &t)
Old CAM implementation of Goff & Gratch (1946) SVP over ice.
Definition: ERF_SatMethods.H:302
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real wv_sat_svp_water(const amrex::Real &t, const int idx=1)
Dispatcher for saturation vapor pressure over water.
Definition: ERF_SatMethods.H:136
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real wv_sat_svp_to_qsat(const amrex::Real &es, const amrex::Real &p)
Get saturation specific humidity given pressure and SVP.
Definition: ERF_SatMethods.H:51
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real GoffGratch_svp_water(const amrex::Real &t)
Goff & Gratch (1946) saturation vapor pressure over water.
Definition: ERF_SatMethods.H:214
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE void wv_sat_qsat_water(const amrex::Real &t, const amrex::Real &p, amrex::Real &es, amrex::Real &qs, const int idx=1)
Calculate SVP over water and saturation specific humidity.
Definition: ERF_SatMethods.H:68
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE void wv_sat_qsat_ice(const amrex::Real &t, const amrex::Real &p, amrex::Real &es, amrex::Real &qs, const int idx=1)
Calculate SVP over ice and saturation specific humidity.
Definition: ERF_SatMethods.H:91
Type
Definition: ERF_SatMethods.H:333
@ MurphyKoop
Definition: ERF_SatMethods.H:337
@ Invalid
Definition: ERF_SatMethods.H:334
@ Bolton
Definition: ERF_SatMethods.H:338
@ GoffGratch
Definition: ERF_SatMethods.H:336
@ OldGoffGratch
Definition: ERF_SatMethods.H:335
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real OldGoffGratch_svp_water(const amrex::Real &t)
Old CAM implementation of Goff & Gratch (1946) SVP over water.
Definition: ERF_SatMethods.H:283
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real MurphyKoop_svp_ice(const amrex::Real &t)
Murphy & Koop (2005) saturation vapor pressure over ice.
Definition: ERF_SatMethods.H:257
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real GoffGratch_svp_ice(const amrex::Real &t)
Goff & Gratch (1946) saturation vapor pressure over ice.
Definition: ERF_SatMethods.H:229
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real MurphyKoop_svp_water(const amrex::Real &t)
Murphy & Koop (2005) saturation vapor pressure over water.
Definition: ERF_SatMethods.H:243
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real wv_sat_svp_trans(const amrex::Real &t, const int idx=1)
Calculate transition saturation vapor pressure.
Definition: ERF_SatMethods.H:182
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real wv_sat_svp_ice(const amrex::Real &t, const int idx=1)
Dispatcher for saturation vapor pressure over ice.
Definition: ERF_SatMethods.H:159
@ qs
Definition: ERF_WDM6.H:29
@ t
Definition: ERF_WSM6.H:183
@ p
Definition: ERF_WSM6.H:191
real(c_double), parameter c2
Definition: ERF_module_model_constants.F90:35
real(c_double), private c1
Definition: ERF_module_mp_morr_two_moment.F90:212