ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_Sat_methods.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 class SatMethods {
38 public:
39  // Get saturation specific humidity given pressure and SVP.
40  // Specific humidity is limited to range 0-1.
41  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
42  static amrex::Real wv_sat_svp_to_qsat (const amrex::Real& es, const amrex::Real& p) {
43  // If pressure is less than SVP, set qs to maximum of 1.
44  if ( (p - es) <= 0. )
45  return 1.0;
46  else
47  return epsilo*es / (p - omeps*es);
48  }
49 
50  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
51  static void wv_sat_qsat_water (const amrex::Real& t, const amrex::Real& p,
52  amrex::Real &es, amrex::Real &qs, const int idx = 1) {
53  // Purpose:
54  // Calculate SVP over water at a given temperature, and then
55  // calculate and return saturation specific humidity.
56 
57  es = wv_sat_svp_water(t, idx);
58 
59  qs = wv_sat_svp_to_qsat(es, p);
60 
61  // Ensures returned es is consistent with limiters on qs.
62  es = std::min(es, p);
63  }
64 
65  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
66  static void wv_sat_qsat_ice (const amrex::Real& t, const amrex::Real& p,
67  amrex::Real &es, amrex::Real &qs, const int idx = 1) {
68  // Purpose:
69  // Calculate SVP over ice at a given temperature, and then
70  // calculate and return saturation specific humidity.
71 
72  es = wv_sat_svp_ice(t, idx);
73 
74  qs = wv_sat_svp_to_qsat(es, p);
75 
76  // Ensures returned es is consistent with limiters on qs.
77  es = std::min(es, p);
78  }
79 
80  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
81  static void wv_sat_qsat_trans (const amrex::Real& t, const amrex::Real& p,
82  amrex::Real &es, amrex::Real &qs, const int idx = 1) {
83  // Purpose:
84  // Calculate SVP over ice at a given temperature, and then
85  // calculate and return saturation specific humidity.
86 
87  es = wv_sat_svp_trans(t, idx);
88 
89  qs = wv_sat_svp_to_qsat(es, p);
90 
91  // Ensures returned es is consistent with limiters on qs.
92  es = std::min(es, p);
93  }
94 
95  // SVP INTERFACE FUNCTIONS
96  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
97  static amrex::Real wv_sat_svp_water (const amrex::Real& t, const int idx = 1) {
98  amrex::Real es;
99  switch(idx)
100  {
101  case GoffGratch:
102  es = GoffGratch_svp_water(t); break;
103  case MurphyKoop:
104  es = MurphyKoop_svp_water(t); break;
105  case OldGoffGratch:
106  es = OldGoffGratch_svp_water(t); break;
107  case Bolton:
108  es = Bolton_svp_water(t); break;
109  }
110  return es;
111  }
112 
113  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
114  static amrex::Real wv_sat_svp_ice (const amrex::Real& t, const int idx = 1) {
115  amrex::Real es;
116  switch(idx)
117  {
118  case GoffGratch:
119  es = GoffGratch_svp_ice(t); break;
120  case MurphyKoop:
121  es = MurphyKoop_svp_ice(t); break;
122  case OldGoffGratch:
123  es = OldGoffGratch_svp_ice(t); break;
124  case Bolton:
125  es = Bolton_svp_water(t); break;
126  }
127  return es;
128  }
129 
130  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
131  static amrex::Real wv_sat_svp_trans (const amrex::Real& t, const int idx = 1) {
132  amrex::Real esice; // Saturation vapor pressure over ice
133  amrex::Real weight; // Intermediate scratch variable for es transition
134  amrex::Real es;
135 
136  // Water
137  if (t >= (tmelt - ttrice))
138  es = wv_sat_svp_water(t,idx);
139  else
140  es = 0.0;
141 
142  // Ice
143  if (t < tmelt) {
144  esice = wv_sat_svp_ice(t,idx);
145  if ( (tmelt - t) > ttrice )
146  weight = 1.0;
147  else
148  weight = (tmelt - t)/ttrice;
149 
150  es = weight*esice + (1.0 - weight)*es;
151  }
152  return es;
153  }
154 
155 
156  // Goff & Gratch (1946)
157  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
158  static amrex::Real GoffGratch_svp_water (const amrex::Real& t) {
159  // uncertain below -70 C
160  return pow(10., (-7.90298*(tboil/t-1.)+
161  5.02808*std::log10(tboil/t)-
162  1.3816e-7*(pow(10., (11.344*(1.-t/tboil)))-1.)+
163  8.1328e-3*(pow(10., (-3.49149*(tboil/t-1.)))-1.)+
164  std::log10(1013.246)))*100.;
165  }
166 
167  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
168  static amrex::Real GoffGratch_svp_ice (const amrex::Real& t) {
169  // good down to -100 C
170  return pow(10., (-9.09718*(h2otrip/t-1.)-3.56654*
171  log10(h2otrip/t)+0.876793*(1.-t/h2otrip)+
172  log10(6.1071)))*100.;
173  }
174 
175  // Murphy & Koop (2005)
176  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
177  static amrex::Real MurphyKoop_svp_water (const amrex::Real& t) {
178  // (good for 123 < T < 332 K)
179  return exp(54.842763 - (6763.22 / t) - (4.210 * log(t)) +
180  (0.000367 * t) + (tanh(0.0415 * (t - 218.8)) *
181  (53.878 - (1331.22 / t) - (9.44523 * log(t)) +
182  0.014025 * t)));
183  }
184 
185  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
186  static amrex::Real MurphyKoop_svp_ice (const amrex::Real& t) {
187  // (good down to 110 K)
188  return exp(9.550426 - (5723.265 / t) + (3.53068 * log(t))
189  - (0.00728332 * t));
190  }
191 
192 
193  // Old CAM implementation, also labelled Goff & Gratch (1946)
194 
195  // The water formula differs only due to compiler-dependent order of
196  // operations, so differences are roundoff level, usually 0.
197 
198  // The ice formula gives fairly close answers to the current
199  // implementation, but has been rearranged, and uses the
200  // 1 atm melting point of water as the triple point.
201  // Differences are thus small but above roundoff.
202 
203  // A curious fact: although using the melting point of water was
204  // probably a mistake, it mildly improves accuracy for ice svp,
205  // since it compensates for a systematic error in Goff & Gratch.
206  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
207  static amrex::Real OldGoffGratch_svp_water (const amrex::Real& t) {
208  auto ps = 1013.246;
209  auto e1 = 11.344*(1.0 - t/tboil);
210  auto e2 = -3.49149*(tboil/t - 1.0);
211  auto f1 = -7.90298*(tboil/t - 1.0);
212  auto f2 = 5.02808*log10(tboil/t);
213  auto f3 = -1.3816*(pow(10.0, e1) - 1.0)/10000000.0;
214  auto f4 = 8.1328*(pow(10.0, e2) - 1.0)/1000.0;
215  auto f5 = log10(ps);
216  auto f = f1 + f2 + f3 + f4 + f5;
217  return (pow(10.0, f))*100.0;
218  }
219 
220  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
221  static amrex::Real OldGoffGratch_svp_ice (const amrex::Real& t) {
222  auto term1 = 2.01889049/(tmelt/t);
223  auto term2 = 3.56654*log(tmelt/t);
224  auto term3 = 20.947031*(tmelt/t);
225  return 575.185606e10*exp(-(term1 + term2 + term3));
226  }
227 
228  // Bolton (1980)
229  // zm_conv deep convection scheme contained this SVP calculation.
230  // It appears to be from D. Bolton, 1980, Monthly Weather Review.
231  // Unlike the other schemes, no distinct ice formula is associated
232  // with it. (However, a Bolton ice formula exists in CLUBB.)
233 
234  // The original formula used degrees C, but this function
235  // takes Kelvin and internally converts.
236  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
237  static amrex::Real Bolton_svp_water (const amrex::Real& t) {
238  constexpr auto c1 = 611.2;
239  constexpr auto c2 = 17.67;
240  constexpr auto c3 = 243.5;
241  return c1*exp( (c2*(t - tmelt))/((t - tmelt)+c3) );
242  }
243 
244  // private data
245 private:
246  // Indices representing individual schemes
247  enum Type {
248  Invalid = -1,
252  Bolton = 3
253  };
254 };
255 #endif
constexpr amrex::Real tboil
Definition: ERF_Constants.H:90
constexpr amrex::Real epsilo
Definition: ERF_Constants.H:92
constexpr amrex::Real tmelt
Definition: ERF_Constants.H:88
constexpr amrex::Real ttrice
Definition: ERF_Constants.H:91
constexpr amrex::Real omeps
Definition: ERF_Constants.H:93
constexpr amrex::Real h2otrip
Definition: ERF_Constants.H:89
Definition: ERF_Sat_methods.H:37
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)
Definition: ERF_Sat_methods.H:81
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real Bolton_svp_water(const amrex::Real &t)
Definition: ERF_Sat_methods.H:237
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real OldGoffGratch_svp_ice(const amrex::Real &t)
Definition: ERF_Sat_methods.H:221
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real wv_sat_svp_water(const amrex::Real &t, const int idx=1)
Definition: ERF_Sat_methods.H:97
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real wv_sat_svp_to_qsat(const amrex::Real &es, const amrex::Real &p)
Definition: ERF_Sat_methods.H:42
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real GoffGratch_svp_water(const amrex::Real &t)
Definition: ERF_Sat_methods.H:158
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)
Definition: ERF_Sat_methods.H:51
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)
Definition: ERF_Sat_methods.H:66
Type
Definition: ERF_Sat_methods.H:247
@ MurphyKoop
Definition: ERF_Sat_methods.H:251
@ Invalid
Definition: ERF_Sat_methods.H:248
@ Bolton
Definition: ERF_Sat_methods.H:252
@ GoffGratch
Definition: ERF_Sat_methods.H:250
@ OldGoffGratch
Definition: ERF_Sat_methods.H:249
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real OldGoffGratch_svp_water(const amrex::Real &t)
Definition: ERF_Sat_methods.H:207
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real MurphyKoop_svp_ice(const amrex::Real &t)
Definition: ERF_Sat_methods.H:186
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real GoffGratch_svp_ice(const amrex::Real &t)
Definition: ERF_Sat_methods.H:168
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real MurphyKoop_svp_water(const amrex::Real &t)
Definition: ERF_Sat_methods.H:177
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real wv_sat_svp_trans(const amrex::Real &t, const int idx=1)
Definition: ERF_Sat_methods.H:131
AMREX_GPU_HOST_DEVICE static AMREX_FORCE_INLINE amrex::Real wv_sat_svp_ice(const amrex::Real &t, const int idx=1)
Definition: ERF_Sat_methods.H:114