ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_MOSTUtils.H
Go to the documentation of this file.
1 #ifndef ERF_MOSTUtils_H
2 #define ERF_MOSTUtils_H
3 
4 #include "ERF_Constants.H"
5 
6 /**
7  * Structure of plain old data relevant to MOST BCs
8  */
9 struct most_data
10 {
11 public:
12  amrex::Real z0_const{amrex::Real(0.1)}; ///< Roughness height -- default constant value(m)
13  amrex::Real kappa{KAPPA}; ///< von Karman constant
14  amrex::Real gravity{CONST_GRAV}; ///< Acceleration due to gravity (m/s^2)
15  amrex::Real surf_temp_flux{zero}; ///< Heat flux TODO: decide whether this is <θ'w'> or <θv'w'> under moist conditions
16  amrex::Real surf_moist_flux{zero}; ///< Moisture flux
17 
18  amrex::Real Cnk_a{amrex::Real(0.0185)}; ///< Standard Charnock constant https://doi.org/amrex::Real(10.1175)/JAMC-D-17-amrex::Real(0137.1)
19  amrex::Real Cnk_b1{one/amrex::Real(30.0)}; ///< Modified Charnock Eq (4) https://doi.org/amrex::Real(10.1175)/JAMC-D-17-amrex::Real(0137.1)
20  amrex::Real Cnk_b2{amrex::Real(1260.0)}; ///< Modified Charnock Eq (4) https://doi.org/amrex::Real(10.1175)/JAMC-D-17-amrex::Real(0137.1)
21  amrex::Real Cnk_d{amrex::Real(30.0)}; ///< Modified Charnock Eq (4) https://doi.org/amrex::Real(10.1175)/JAMC-D-17-amrex::Real(0137.1)
22  amrex::Real Cnk_b = Cnk_b1 * std::log(Cnk_b2 / Cnk_d); ///< Modified Charnock derived quantity
23  bool visc{true}; ///< Use viscous Charnock formulation
24 
28 
29  const amrex::Real Bjr_beta = amrex::Real(1.2); // Empirical parameter from Beljaars 1995 QJRMS
30 };
31 
32 
33 /**
34  * Structure of similarity functions for Moeng formulation
35  */
37 {
38  //
39  // Similarity functions from Jimenez (2012)
40  //
41  /**
42  * Compute the Jimenez momentum stability correction.
43  *
44  * @param[in] zeta stability coordinate z/L
45  */
46  AMREX_GPU_HOST_DEVICE
47  AMREX_FORCE_INLINE
49  calc_psi_m2 (amrex::Real zeta) const
50  {
51  if (zeta > 0) {
52  amrex::Real x = std::pow(one + std::pow(zeta, amrex::Real(2.5)), one/amrex::Real(2.5));
53  return ( -amrex::Real(6.1)*std::log(zeta + x) );
54  } else {
55  amrex::Real x = std::pow(one - amrex::Real(16.0)*zeta, fourth);
56  amrex::Real psi_k_m = two * std::log(myhalf * (one + x)) + std::log(myhalf * (one + x * x)) -
57  two * std::atan(x) + PIoTwo;
58  amrex::Real y = std::pow(one - amrex::Real(10.0)*zeta, one/three);
59  amrex::Real psi_c_m = (three/two)*std::log((y*y + y + one)/three)
60  - std::sqrt(three)*std::atan((two*y + one)/std::sqrt(three))
61  + PI/std::sqrt(three);
62  return ( (psi_k_m + zeta*zeta*psi_c_m) / (one + zeta*zeta) );
63  }
64  }
65 
66  /**
67  * Compute the Jimenez heat stability correction.
68  *
69  * @param[in] zeta stability coordinate z/L
70  */
71  AMREX_GPU_HOST_DEVICE
72  AMREX_FORCE_INLINE
74  calc_psi_h2 (amrex::Real zeta) const
75  {
76  if (zeta > 0) {
77  amrex::Real x = std::pow(one + std::pow(zeta, amrex::Real(1.1)), one/amrex::Real(1.1));
78  return ( -amrex::Real(5.3)*std::log(zeta + x) );
79  } else {
80  amrex::Real x = std::sqrt(one - amrex::Real(16.0)*zeta);
81  amrex::Real psi_k_h = two * std::log(myhalf * (one + x));
82  amrex::Real y = std::pow(one - amrex::Real(34.0)*zeta, one/three);
83  amrex::Real psi_c_h = (three/two)*std::log((y*y + y + one)/three)
84  - std::sqrt(three)*std::atan((two*y + one)/std::sqrt(three))
85  + PI/std::sqrt(three);
86  return ( (psi_k_h + zeta*zeta*psi_c_h) / (one + zeta*zeta) );
87  }
88  }
89 
90 
91  //
92  // Similarity functions from Businger & Dyer (1966)
93  //
94  /**
95  * Compute the Businger-Dyer momentum stability correction.
96  *
97  * @param[in] zeta stability coordinate z/L
98  */
99  AMREX_GPU_HOST_DEVICE
100  AMREX_FORCE_INLINE
102  calc_psi_m (amrex::Real zeta) const
103  {
104  if (zeta > 0) {
105  return -beta_m * zeta;
106  } else {
107  amrex::Real x = std::sqrt(std::sqrt(one - gamma_m * zeta));
108  return two * std::log(myhalf * (one + x)) + std::log(myhalf * (one + x * x)) -
109  two * std::atan(x) + PIoTwo;
110  }
111  }
112 
113  /**
114  * Compute the Businger-Dyer heat stability correction.
115  *
116  * @param[in] zeta stability coordinate z/L
117  */
118  AMREX_GPU_HOST_DEVICE
119  AMREX_FORCE_INLINE
121  calc_psi_h (amrex::Real zeta) const
122  {
123  if (zeta > 0) {
124  return -beta_h * zeta;
125  } else {
126  amrex::Real x = std::sqrt(one - gamma_h * zeta);
127  return two * std::log(myhalf * (one + x));
128  }
129  }
130 
131  //
132  // Gradient (phi) functions
133  //
134  /**
135  * Compute the Businger-Dyer momentum gradient function.
136  *
137  * This is the exact companion of calc_psi_m: the two are tied by
138  * psi_m(zeta) = int_0^zeta (1 - phi_m(x))/x dx, so differentiating the MOST
139  * wind profile u(z) = (u_star/kappa)[ln(z/z0) - psi_m(z/L)] gives
140  * du/dz = u_* phi_m(zeta) / (kappa z).
141  *
142  * NOTE: the surface_temp* flux calculators use the Jimenez psi pair
143  * (calc_psi_m2/calc_psi_h2) rather than this one; their companions are
144  * not implemented yet, so a prescribed-surface-temperature run gets the
145  * Businger-Dyer gradient here.
146  *
147  * @param[in] zeta stability coordinate z/L
148  */
149  AMREX_GPU_HOST_DEVICE
150  AMREX_FORCE_INLINE
152  calc_phi_m (amrex::Real zeta) const
153  {
154  if (zeta > 0) {
155  return one + beta_m * zeta;
156  } else {
157  return one / std::sqrt(std::sqrt(one - gamma_m * zeta));
158  }
159  }
160 
161  /**
162  * Compute the Businger-Dyer heat gradient function, the exact companion of
163  * calc_psi_h: dtheta/dz = theta_* phi_h(zeta) / (kappa z).
164  *
165  * See the note in calc_phi_m about the Jimenez pair.
166  *
167  * @param[in] zeta stability coordinate z/L
168  */
169  AMREX_GPU_HOST_DEVICE
170  AMREX_FORCE_INLINE
172  calc_phi_h (amrex::Real zeta) const
173  {
174  if (zeta > 0) {
175  return one + beta_h * zeta;
176  } else {
177  return one / std::sqrt(one - gamma_h * zeta);
178  }
179  }
180 
181 private:
182  amrex::Real beta_m{amrex::Real(5.0)}; ///< Constants from Dyer, BLM, 1974
183  amrex::Real beta_h{amrex::Real(5.0)}; ///< https://doi.org/amrex::Real(10.1007)/BF00240838
186 };
187 
188 
189 /**
190  * Empirical kinematic viscosity [m2/s] formula from Andreas (1989) CRREL Rep.
191  * 89-11, valid between -173 and 277 deg C.
192  *
193  * @param[in] T_degK air temperature in Kelvin
194  */
195 AMREX_GPU_DEVICE
196 AMREX_FORCE_INLINE
199 {
200  amrex::Real TC = T_degK - amrex::Real(273.15);
201  return amrex::Real(1.326e-5)*(one + amrex::Real(6.542e-3)*TC + amrex::Real(8.301e-6)*TC*TC - amrex::Real(4.84e-9)*TC*TC*TC);
202 }
203 
204 /**
205  * Charnock roughness with optional aerodynamically-smooth contribution
206  *
207  * Smooth-flow limit follows z0 = 0.11 nu / u* (Smith 1988; ECMWF; WRF)
208  *
209  * @param[in] ustar friction velocity
210  * @param[in] cnk_a charnock constant
211  * @param[in] nu intrinsic fluid viscosity
212  * @param[in] visc flag to apply smooth flow limit
213  */
214 AMREX_GPU_DEVICE
215 AMREX_FORCE_INLINE
218  amrex::Real Cnk_a,
219  amrex::Real nu,
220  bool visc)
221 {
222  amrex::Real z0 = (Cnk_a / CONST_GRAV) * ustar * ustar;
223  if (visc) {
224  z0 += amrex::Real(0.11) * nu / std::max(ustar, amrex::Real(0.01));
225  }
226  // From Davis et al 2008 MWR
227  return std::min(std::max(z0, amrex::Real(1.27e-7)), amrex::Real(2.85e-3));
228 }
229 
230 /**
231  * Modified Charnock roughness
232  *
233  * Smooth-flow limit is intrinsic.
234  *
235  * @param[in] ustar friction velocity
236  * @param[in] cnk_b modified charnock constant
237  */
238 AMREX_GPU_DEVICE
239 AMREX_FORCE_INLINE
242  amrex::Real Cnk_b)
243 {
244  amrex::Real z0 = std::exp( (amrex::Real(2.7)*ustar - amrex::Real(1.8)/Cnk_b) / (ustar + amrex::Real(0.17)/Cnk_b) );
245  return std::min(std::max(z0, amrex::Real(1.27e-7)), amrex::Real(1.0e-2));
246 }
247 
248 /**
249  * COARE3.0, following WRF phys/module_sf_mynn.F
250  *
251  * Smooth-flow limit follows z0 = 0.11 nu / u* (Smith 1988; ECMWF; WRF)
252  *
253  * @param[in] zref reference height for the wind speed
254  * @param[in] umm horizontal wind speed magnitude at zref
255  * @param[in] ustar friction velocity
256  * @param[in] nu intrinsic fluid viscosity
257  * @param[in] visc flag to apply smooth flow limit
258  */
259 AMREX_GPU_DEVICE
260 AMREX_FORCE_INLINE
263  amrex::Real umm,
265  amrex::Real nu,
266  bool visc)
267 {
268  amrex::Real ws10m = umm*std::log(amrex::Real(10.)/amrex::Real(1e-4)) / std::log(zref/amrex::Real(1e-4));
269  amrex::Real Czc = amrex::Real(0.011) + amrex::Real(0.007)*std::min(std::max((ws10m-amrex::Real(10.))/amrex::Real(8.), amrex::Real(0.0)), amrex::Real(1.0));
270  amrex::Real z0 = (Czc / CONST_GRAV) * ustar * ustar;
271  if (visc) {
272  z0 += amrex::Real(0.11) * nu / std::max(ustar, amrex::Real(0.01));
273  }
274  // From Davis et al 2008 MWR
275  return std::min(std::max(z0, amrex::Real(1.27e-7)), amrex::Real(2.85e-3));
276 }
277 
278 /**
279  * Updated Donelan 2004 as found in AHW
280  *
281  * Matches implementations in WRF phys/physics_mmm/sf_sfclayrev.F90 and
282  * phys/module_sf_mynn.F
283  *
284  * Smooth flow limit is intrinsic in zn2.
285  *
286  * @param[in] ustar friction velocity
287  * @param[in] nu intrinsic fluid viscosity
288  * @param[in] visc flag to apply smooth flow limit
289  */
290 AMREX_GPU_DEVICE
291 AMREX_FORCE_INLINE
294  amrex::Real nu,
295  bool visc)
296 {
297  constexpr amrex::Real ozo{amrex::Real(1.59e-5)};
298  amrex::Real zw = std::min(std::pow(ustar/amrex::Real(1.06), amrex::Real(0.3)),amrex::Real(1.0));
299  amrex::Real zn1 = amrex::Real(0.011)*ustar*ustar/CONST_GRAV + ozo;
300  amrex::Real zn2 = amrex::Real(10.)*std::exp(-amrex::Real(9.5)*std::pow(ustar, -amrex::Real(.3333)));
301  if (visc) {
302  zn2 += amrex::Real(0.11) * nu / std::max(ustar, amrex::Real(0.01));
303  }
304  amrex::Real z0 = (amrex::Real(1.0)-zw) * zn1 + zw * zn2;
305  // From Davis et al 2008 MWR
306  return std::min(std::max(z0, amrex::Real(1.27e-7)), amrex::Real(2.85e-3));
307 }
308 
309 
310 /**
311  * Wave coupled roughness
312  *
313  * Smooth-flow limit follows z0 = 0.11 nu / u* (Smith 1988; ECMWF; WRF)
314  *
315  * @param[in] Hwave wave height
316  * @param[in] Lwave wave length
317  * @param[in] eps avoid divide by zero
318  * @param[in] ustar friction velocity
319  * @param[in] nu intrinsic fluid viscosity
320  * @param[in] visc flag to apply smooth flow limit
321  */
322 AMREX_GPU_DEVICE
323 AMREX_FORCE_INLINE
326  amrex::Real Lwave,
327  amrex::Real eps,
329  amrex::Real nu,
330  bool visc)
331 {
332 
333  amrex::Real z0 = amrex::Real(1200.0) * Hwave * std::pow( Hwave/(Lwave+eps), amrex::Real(4.5) );
334  if (visc) {
335  z0 += amrex::Real(0.11) * nu / std::max(ustar, amrex::Real(0.01));
336  }
337  return std::min(std::max(z0, amrex::Real(1.27e-7)), amrex::Real(1.0e-2));
338 }
339 
340 
341 /**
342  * Invert log-law to get roughness
343  *
344  * @param[in] zref reference height for the wind speed
345  * @param[in] Olen Obukhov length
346  * @param[in] umm horizontal wind speed magnitude at zref
347  * @param[in] ustar friction velocity
348  */
349 AMREX_GPU_DEVICE
350 AMREX_FORCE_INLINE
353  amrex::Real Olen,
354  amrex::Real umm,
356 {
357  similarity_funs sfuns;
358  amrex::Real zeta = zref / Olen;
359  amrex::Real psi_m = sfuns.calc_psi_m2(zeta);
360  amrex::Real z0 = zref / std::exp(KAPPA*umm/ustar + psi_m);
361  return std::max(z0, amrex::Real(1.0e-7));
362 }
363 #endif
constexpr amrex::Real KAPPA
Definition: ERF_Constants.H:67
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:68
Real z0
Definition: ERF_InitCustomPertVels_ScalarAdvDiff.H:8
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real WaveCoupled_roughness(amrex::Real Hwave, amrex::Real Lwave, amrex::Real eps, amrex::Real ustar, amrex::Real nu, bool visc)
Definition: ERF_MOSTUtils.H:325
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real COARE3_roughness(amrex::Real zref, amrex::Real umm, amrex::Real ustar, amrex::Real nu, bool visc)
Definition: ERF_MOSTUtils.H:262
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_roughness(amrex::Real zref, amrex::Real Olen, amrex::Real umm, amrex::Real ustar)
Definition: ERF_MOSTUtils.H:352
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Mod_Charnock_roughness(amrex::Real ustar, amrex::Real Cnk_b)
Definition: ERF_MOSTUtils.H:241
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real air_viscosity(amrex::Real T_degK)
Definition: ERF_MOSTUtils.H:198
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Donelan_roughness(amrex::Real ustar, amrex::Real nu, bool visc)
Definition: ERF_MOSTUtils.H:293
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Charnock_roughness(amrex::Real ustar, amrex::Real Cnk_a, amrex::Real nu, bool visc)
Definition: ERF_MOSTUtils.H:217
constexpr amrex::Real three
Definition: ERF_NumericalConstants.H:39
constexpr amrex::Real two
Definition: ERF_NumericalConstants.H:38
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:37
constexpr amrex::Real fourth
Definition: ERF_NumericalConstants.H:42
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:36
constexpr amrex::Real myhalf
Definition: ERF_NumericalConstants.H:41
constexpr amrex::Real PI
Definition: ERF_NumericalConstants.H:46
constexpr amrex::Real PIoTwo
Definition: ERF_NumericalConstants.H:47
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ ustar
Definition: ERF_SLM.H:28
Definition: ERF_MOSTUtils.H:10
amrex::Real surf_moist_flux
Moisture flux.
Definition: ERF_MOSTUtils.H:16
amrex::Real Cnk_b2
Modified Charnock Eq (4) https://doi.org/amrex::Real(10.1175)/JAMC-D-17-amrex::Real(0137....
Definition: ERF_MOSTUtils.H:20
amrex::Real Cnk_b
Modified Charnock derived quantity.
Definition: ERF_MOSTUtils.H:22
amrex::Real Ch
Definition: ERF_MOSTUtils.H:26
amrex::Real Cnk_d
Modified Charnock Eq (4) https://doi.org/amrex::Real(10.1175)/JAMC-D-17-amrex::Real(0137....
Definition: ERF_MOSTUtils.H:21
amrex::Real kappa
von Karman constant
Definition: ERF_MOSTUtils.H:13
amrex::Real gravity
Acceleration due to gravity (m/s^2)
Definition: ERF_MOSTUtils.H:14
amrex::Real Cnk_a
Standard Charnock constant https://doi.org/amrex::Real(10.1175)/JAMC-D-17-amrex::Real(0137....
Definition: ERF_MOSTUtils.H:18
amrex::Real Cd
Definition: ERF_MOSTUtils.H:25
amrex::Real Cq
Definition: ERF_MOSTUtils.H:27
const amrex::Real Bjr_beta
Definition: ERF_MOSTUtils.H:29
amrex::Real Cnk_b1
Modified Charnock Eq (4) https://doi.org/amrex::Real(10.1175)/JAMC-D-17-amrex::Real(0137....
Definition: ERF_MOSTUtils.H:19
amrex::Real z0_const
Roughness height – default constant value(m)
Definition: ERF_MOSTUtils.H:12
bool visc
Use viscous Charnock formulation.
Definition: ERF_MOSTUtils.H:23
amrex::Real surf_temp_flux
Heat flux TODO: decide whether this is <θ'w'> or <θv'w'> under moist conditions.
Definition: ERF_MOSTUtils.H:15
Definition: ERF_MOSTUtils.H:37
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_phi_h(amrex::Real zeta) const
Definition: ERF_MOSTUtils.H:172
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_psi_m(amrex::Real zeta) const
Definition: ERF_MOSTUtils.H:102
amrex::Real beta_m
Constants from Dyer, BLM, 1974.
Definition: ERF_MOSTUtils.H:182
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_psi_h2(amrex::Real zeta) const
Definition: ERF_MOSTUtils.H:74
amrex::Real beta_h
https://doi.org/amrex::Real(10.1007)/BF00240838
Definition: ERF_MOSTUtils.H:183
amrex::Real gamma_h
Definition: ERF_MOSTUtils.H:185
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_psi_h(amrex::Real zeta) const
Definition: ERF_MOSTUtils.H:121
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_phi_m(amrex::Real zeta) const
Definition: ERF_MOSTUtils.H:152
amrex::Real gamma_m
Definition: ERF_MOSTUtils.H:184
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_psi_m2(amrex::Real zeta) const
Definition: ERF_MOSTUtils.H:49