ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ERF_MicrophysicsUtils.H
Go to the documentation of this file.
1 /*
2  * utility tools for microphysics
3  *
4  */
5 #ifndef ERF_Microphysics_Utils_H
6 #define ERF_Microphysics_Utils_H
7 
8 #include <cmath>
9 #include <vector>
10 #include <AMReX_REAL.H>
11 #include <AMReX_Array.H>
12 #include <ERF_Constants.H>
13 
14 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
15 amrex::Real erf_gammafff (amrex::Real x){
16  return std::exp(lgamma(x));
17 }
18 
19 // From Flatau et al. (1992):
20 // https://doi.org/10.1175/1520-0450(1992)031<1507:PFTSVP>2.0.CO;2
21 // Coefficients come from Table 4 and the data is valid over a
22 // temperature range of [-90 0] C. Return 0 if above this temp range.
23 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
24 amrex::Real erf_esati (amrex::Real t) {
25  amrex::Real const a0 = 6.11147274;
26  amrex::Real const a1 = 0.503160820;
27  amrex::Real const a2 = 0.188439774e-1;
28  amrex::Real const a3 = 0.420895665e-3;
29  amrex::Real const a4 = 0.615021634e-5;
30  amrex::Real const a5 = 0.602588177e-7;
31  amrex::Real const a6 = 0.385852041e-9;
32  amrex::Real const a7 = 0.146898966e-11;
33  amrex::Real const a8 = 0.252751365e-14;
34 
35  amrex::Real dtt = t-273.16;
36  AMREX_ALWAYS_ASSERT(dtt>-85);
37 
38  amrex::Real esati;
39  if (dtt > 0.0) {
40  esati = 0.0;
41  } else {
42  esati = a0 + dtt*(a1+dtt*(a2+dtt*(a3+dtt*(a4+dtt*(a5+dtt*(a6+dtt*(a7+a8*dtt)))))));
43  }
44  return esati;
45 }
46 
47 // From Clausius-Clapeyron
48 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
49 amrex::Real erf_esatw_cc (amrex::Real t) {
50  constexpr amrex::Real svp1 = 0.6112;
51  constexpr amrex::Real svp2 = 17.67;
52  constexpr amrex::Real svp3 = 29.65;
53  constexpr amrex::Real svpt0 = 273.15;
54  // NOTE: units of
55  amrex::Real esatw = 10.0 * svp1 * std::exp(svp2 * (t - svpt0) / (t - svp3));
56  return esatw;
57 }
58 
59 // Saturation vapor pressure of water vapor [mbar]
60 // From Flatau et al. (1992):
61 // https://doi.org/10.1175/1520-0450(1992)031<1507:PFTSVP>2.0.CO;2
62 // Coefficients come from Table 4 and the data is valid over a
63 // temperature range of [-85 70] C. Assert we are in this temp range.
64 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
65 amrex::Real erf_esatw (amrex::Real t) {
66  amrex::Real const a0 = 6.11239921;
67  amrex::Real const a1 = 0.443987641;
68  amrex::Real const a2 = 0.142986287e-1;
69  amrex::Real const a3 = 0.264847430e-3;
70  amrex::Real const a4 = 0.302950461e-5;
71  amrex::Real const a5 = 0.206739458e-7;
72  amrex::Real const a6 = 0.640689451e-10;
73  amrex::Real const a7 = -0.952447341e-13;
74  amrex::Real const a8 = -0.976195544e-15;
75 
76  amrex::Real dtt = t-273.16;
77  amrex::Real esatw;
78  if (dtt>-85 && dtt<70.0) {
79  esatw = a0 + dtt*(a1+dtt*(a2+dtt*(a3+dtt*(a4+dtt*(a5+dtt*(a6+dtt*(a7+a8*dtt)))))));
80  } else {
81  esatw = erf_esatw_cc(t);
82  }
83  return esatw;
84 }
85 
86 // From Flatau et al. (1992):
87 // https://doi.org/10.1175/1520-0450(1992)031<1507:PFTSVP>2.0.CO;2
88 // Coefficients come from Table 4 and the data is valid over a
89 // temperature range of [-90 0] C. Return 0 if above this temp range.
90 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
91 amrex::Real erf_dtesati (amrex::Real t) {
92  amrex::Real const a0 = 0.503223089;
93  amrex::Real const a1 = 0.377174432e-1;
94  amrex::Real const a2 = 0.126710138e-2;
95  amrex::Real const a3 = 0.249065913e-4;
96  amrex::Real const a4 = 0.312668753e-6;
97  amrex::Real const a5 = 0.255653718e-8;
98  amrex::Real const a6 = 0.132073448e-10;
99  amrex::Real const a7 = 0.390204672e-13;
100  amrex::Real const a8 = 0.497275778e-16;
101 
102  amrex::Real dtt = t-273.16;
103  AMREX_ALWAYS_ASSERT(dtt>-85);
104  amrex::Real dtesati;
105  if (dtt > 0.0) {
106  dtesati = 0.0;
107  } else {
108  dtesati = a0 + dtt*(a1+dtt*(a2+dtt*(a3+dtt*(a4+dtt*(a5+dtt*(a6+dtt*(a7+a8*dtt)))))));
109  }
110  return dtesati;
111 }
112 
113 // From Clausius-Clapeyron
114 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
115 amrex::Real erf_dtesatw_cc (amrex::Real t) {
116  constexpr amrex::Real svp1 = 0.6112;
117  constexpr amrex::Real svp2 = 17.67;
118  constexpr amrex::Real svp3 = 29.65;
119  constexpr amrex::Real svpt0 = 273.15;
120  amrex::Real dtesatw = 10.0 * svp1 * svp2 * std::exp(svp2 * (t - svpt0) / (t - svp3))
121  * (svpt0 - svp3) / ((t - svp3) * (t - svp3));
122  return dtesatw;
123 }
124 
125 // From Flatau et al. (1992):
126 // https://doi.org/10.1175/1520-0450(1992)031<1507:PFTSVP>2.0.CO;2
127 // Coefficients come from Table 4 and the data is valid over a
128 // temperature range of [-85 70] C. Assert we are in this temp range.
129 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
130 amrex::Real erf_dtesatw (amrex::Real t) {
131  amrex::Real const a0 = 0.443956472;
132  amrex::Real const a1 = 0.285976452e-1;
133  amrex::Real const a2 = 0.794747212e-3;
134  amrex::Real const a3 = 0.121167162e-4;
135  amrex::Real const a4 = 0.103167413e-6;
136  amrex::Real const a5 = 0.385208005e-9;
137  amrex::Real const a6 = -0.604119582e-12;
138  amrex::Real const a7 = -0.792933209e-14;
139  amrex::Real const a8 = -0.599634321e-17;
140 
141  amrex::Real dtt = t-273.16; // Goff-Gratch
142  amrex::Real dtesatw;
143  if (dtt>-85.0 && dtt<70.) {
144  dtesatw = a0 + dtt*(a1+dtt*(a2+dtt*(a3+dtt*(a4+dtt*(a5+dtt*(a6+dtt*(a7+a8*dtt)))))));
145  } else {
146  dtesatw = erf_dtesatw_cc(t);
147  }
148  return dtesatw;
149 }
150 
151 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
152 void erf_qsati (amrex::Real t, amrex::Real p, amrex::Real &qsati) {
153  amrex::Real esati;
154  esati = erf_esati(t);
155  qsati = Rd_on_Rv*esati/std::max(esati,p-esati);
156 }
157 
158 /* saturated water vapor mixing ratio
159  * t: temperature [K]
160  * p: pressure [mbar]
161  */
162 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
163 void erf_qsatw (amrex::Real t, amrex::Real p, amrex::Real &qsatw) {
164  amrex::Real esatw;
165  esatw = erf_esatw(t);
166  qsatw = Rd_on_Rv*esatw/std::max(esatw,p-esatw);
167 }
168 
169 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
170 void erf_dtqsati (amrex::Real t, amrex::Real p, amrex::Real &dtqsati) {
171  amrex::Real esati = erf_esati(t);
172  amrex::Real dtesati = erf_dtesati(t);
173  amrex::Real denom = p - esati;
174  dtqsati = Rd_on_Rv * dtesati * p / (denom * denom);
175 }
176 
177 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
178 void erf_dtqsatw (amrex::Real t, amrex::Real p, amrex::Real &dtqsatw) {
179  amrex::Real esatw = erf_esatw(t);
180  amrex::Real dtesatw = erf_dtesatw(t);
181  amrex::Real denom = p - esatw;
182  dtqsatw = Rd_on_Rv * dtesatw * p / (denom * denom);
183 }
184 
185 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
186 void z0_est (amrex::Real z, amrex::Real bflx, amrex::Real wnd, amrex::Real ustar, amrex::Real &z0) {
187  amrex::Real vonk = 0.4;
188  amrex::Real eps = 1.0e-10;
189  amrex::Real am = 4.8;
190  amrex::Real bm = 19.3;
191  amrex::Real c1 = 3.14159/2.0 - 3.0*log(2.0);
192  amrex::Real rlmo = -bflx*vonk/(ustar*ustar*ustar+eps);
193  amrex::Real zeta = std::min(1.0,z*rlmo);
194  amrex::Real x;
195  amrex::Real psi1;
196  if(zeta >= 0.0) {
197  psi1 = -am*zeta;
198  }
199  else {
200  x = std::sqrt(sqrt(1.0-bm*zeta));
201  psi1 = 2.0*std::log(1.0+x) + std::log(1.0+x*x) -2.0*std::atan(x) + c1;
202  }
203  amrex::Real lnz = std::max(0.0, vonk*wnd/(ustar+eps) +psi1);
204  z0 = z*std::exp(-lnz);
205 }
206 
207 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
208 amrex::Real term_vel_qp (amrex::Real qploc,
209  amrex::Real vrain,
210  amrex::Real vsnow,
211  amrex::Real vgrau,
212  amrex::Real rho,
213  amrex::Real tabs)
214 {
215  amrex::Real term_vel = 0.0;
216  if(qploc > qp_threshold) {
217  amrex::Real omp = std::max(0.0,std::min(1.0,(tabs-tprmin)*a_pr));
218  amrex::Real omg = std::max(0.0,std::min(1.0,(tabs-tgrmin)*a_gr));
219  amrex::Real qrr = omp*qploc;
220  amrex::Real qss = (1.0-omp)*(1.0-omg)*qploc;
221  amrex::Real qgg = (1.0-omp)*(omg)*qploc;
222  term_vel = omp*vrain*std::pow(rho*qrr,crain)
223  + (1.0-omp)*( (1.0-omg)*vsnow*std::pow(rho*qss,csnow)
224  + omg *vgrau*std::pow(rho*qgg,cgrau) );
225  }
226  return term_vel;
227 }
228 
229 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
230 amrex::Real pp (amrex::Real y) {
231  return std::max(0.0,y);
232 }
233 
234 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
235 amrex::Real pn (amrex::Real y) {
236  return -std::min(0.0,y);
237 }
238 #endif
constexpr amrex::Real csnow
Definition: ERF_Constants.H:82
constexpr amrex::Real a_gr
Definition: ERF_Constants.H:79
constexpr amrex::Real Rd_on_Rv
Definition: ERF_Constants.H:87
constexpr amrex::Real cgrau
Definition: ERF_Constants.H:83
constexpr amrex::Real tprmin
Definition: ERF_Constants.H:33
constexpr amrex::Real qp_threshold
Definition: ERF_Constants.H:60
constexpr amrex::Real crain
Definition: ERF_Constants.H:81
constexpr amrex::Real tgrmin
Definition: ERF_Constants.H:35
constexpr amrex::Real a_pr
Definition: ERF_Constants.H:78
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esatw(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:65
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_dtesatw(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:130
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_dtqsatw(amrex::Real t, amrex::Real p, amrex::Real &dtqsatw)
Definition: ERF_MicrophysicsUtils.H:178
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_dtesati(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:91
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esati(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:24
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real pn(amrex::Real y)
Definition: ERF_MicrophysicsUtils.H:235
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void z0_est(amrex::Real z, amrex::Real bflx, amrex::Real wnd, amrex::Real ustar, amrex::Real &z0)
Definition: ERF_MicrophysicsUtils.H:186
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_dtesatw_cc(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:115
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_dtqsati(amrex::Real t, amrex::Real p, amrex::Real &dtqsati)
Definition: ERF_MicrophysicsUtils.H:170
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real term_vel_qp(amrex::Real qploc, amrex::Real vrain, amrex::Real vsnow, amrex::Real vgrau, amrex::Real rho, amrex::Real tabs)
Definition: ERF_MicrophysicsUtils.H:208
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsatw(amrex::Real t, amrex::Real p, amrex::Real &qsatw)
Definition: ERF_MicrophysicsUtils.H:163
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_gammafff(amrex::Real x)
Definition: ERF_MicrophysicsUtils.H:15
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void erf_qsati(amrex::Real t, amrex::Real p, amrex::Real &qsati)
Definition: ERF_MicrophysicsUtils.H:152
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real pp(amrex::Real y)
Definition: ERF_MicrophysicsUtils.H:230
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real erf_esatw_cc(amrex::Real t)
Definition: ERF_MicrophysicsUtils.H:49
@ tabs
Definition: ERF_Kessler.H:24
@ rho
Definition: ERF_Kessler.H:22
real(c_double), parameter svp1
Definition: ERF_module_model_constants.F90:78
real(c_double), parameter a2
Definition: ERF_module_model_constants.F90:95
real(c_double), parameter a3
Definition: ERF_module_model_constants.F90:96
real(c_double), parameter svp3
Definition: ERF_module_model_constants.F90:80
real(c_double), parameter svp2
Definition: ERF_module_model_constants.F90:79
real(c_double), parameter a4
Definition: ERF_module_model_constants.F90:97
real(c_double), parameter svpt0
Definition: ERF_module_model_constants.F90:81
real(c_double), private c1
Definition: ERF_module_mp_morr_two_moment.F90:211