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 private:
132  amrex::Real beta_m{amrex::Real(5.0)}; ///< Constants from Dyer, BLM, 1974
133  amrex::Real beta_h{amrex::Real(5.0)}; ///< https://doi.org/amrex::Real(10.1007)/BF00240838
136 };
137 
138 
139 /**
140  * Empirical kinematic viscosity [m2/s] formula from Andreas (1989) CRREL Rep.
141  * 89-11, valid between -173 and 277 deg C.
142  *
143  * @param[in] T_degK air temperature in Kelvin
144  */
145 AMREX_GPU_DEVICE
146 AMREX_FORCE_INLINE
149 {
150  amrex::Real TC = T_degK - amrex::Real(273.15);
151  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);
152 }
153 
154 /**
155  * Charnock roughness with optional aerodynamically-smooth contribution
156  *
157  * Smooth-flow limit follows z0 = 0.11 nu / u* (Smith 1988; ECMWF; WRF)
158  *
159  * @param[in] ustar friction velocity
160  * @param[in] cnk_a charnock constant
161  * @param[in] nu intrinsic fluid viscosity
162  * @param[in] visc flag to apply smooth flow limit
163  */
164 AMREX_GPU_DEVICE
165 AMREX_FORCE_INLINE
168  amrex::Real Cnk_a,
169  amrex::Real nu,
170  bool visc)
171 {
172  amrex::Real z0 = (Cnk_a / CONST_GRAV) * ustar * ustar;
173  if (visc) {
174  z0 += amrex::Real(0.11) * nu / std::max(ustar, amrex::Real(0.01));
175  }
176  // From Davis et al 2008 MWR
177  return std::min(std::max(z0, amrex::Real(1.27e-7)), amrex::Real(2.85e-3));
178 }
179 
180 /**
181  * Modified Charnock roughness
182  *
183  * Smooth-flow limit is intrinsic.
184  *
185  * @param[in] ustar friction velocity
186  * @param[in] cnk_b modified charnock constant
187  */
188 AMREX_GPU_DEVICE
189 AMREX_FORCE_INLINE
192  amrex::Real Cnk_b)
193 {
194  amrex::Real z0 = std::exp( (amrex::Real(2.7)*ustar - amrex::Real(1.8)/Cnk_b) / (ustar + amrex::Real(0.17)/Cnk_b) );
195  return std::min(std::max(z0, amrex::Real(1.27e-7)), amrex::Real(1.0e-2));
196 }
197 
198 /**
199  * COARE3.0, following WRF phys/module_sf_mynn.F
200  *
201  * Smooth-flow limit follows z0 = 0.11 nu / u* (Smith 1988; ECMWF; WRF)
202  *
203  * @param[in] zref reference height for the wind speed
204  * @param[in] umm horizontal wind speed magnitude at zref
205  * @param[in] ustar friction velocity
206  * @param[in] nu intrinsic fluid viscosity
207  * @param[in] visc flag to apply smooth flow limit
208  */
209 AMREX_GPU_DEVICE
210 AMREX_FORCE_INLINE
213  amrex::Real umm,
214  amrex::Real ustar,
215  amrex::Real nu,
216  bool visc)
217 {
218  amrex::Real ws10m = umm*std::log(amrex::Real(10.)/amrex::Real(1e-4)) / std::log(zref/amrex::Real(1e-4));
219  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));
220  amrex::Real z0 = (Czc / CONST_GRAV) * ustar * ustar;
221  if (visc) {
222  z0 += amrex::Real(0.11) * nu / std::max(ustar, amrex::Real(0.01));
223  }
224  // From Davis et al 2008 MWR
225  return std::min(std::max(z0, amrex::Real(1.27e-7)), amrex::Real(2.85e-3));
226 }
227 
228 /**
229  * Updated Donelan 2004 as found in AHW
230  *
231  * Matches implementations in WRF phys/physics_mmm/sf_sfclayrev.F90 and
232  * phys/module_sf_mynn.F
233  *
234  * Smooth flow limit is intrinsic in zn2.
235  *
236  * @param[in] ustar friction velocity
237  * @param[in] nu intrinsic fluid viscosity
238  * @param[in] visc flag to apply smooth flow limit
239  */
240 AMREX_GPU_DEVICE
241 AMREX_FORCE_INLINE
244  amrex::Real nu,
245  bool visc)
246 {
247  constexpr amrex::Real ozo{amrex::Real(1.59e-5)};
248  amrex::Real zw = std::min(std::pow(ustar/amrex::Real(1.06), amrex::Real(0.3)),amrex::Real(1.0));
249  amrex::Real zn1 = amrex::Real(0.011)*ustar*ustar/CONST_GRAV + ozo;
250  amrex::Real zn2 = amrex::Real(10.)*std::exp(-amrex::Real(9.5)*std::pow(ustar, -amrex::Real(.3333)));
251  if (visc) {
252  zn2 += amrex::Real(0.11) * nu / std::max(ustar, amrex::Real(0.01));
253  }
254  amrex::Real z0 = (amrex::Real(1.0)-zw) * zn1 + zw * zn2;
255  // From Davis et al 2008 MWR
256  return std::min(std::max(z0, amrex::Real(1.27e-7)), amrex::Real(2.85e-3));
257 }
258 
259 
260 /**
261  * Wave coupled roughness
262  *
263  * Smooth-flow limit follows z0 = 0.11 nu / u* (Smith 1988; ECMWF; WRF)
264  *
265  * @param[in] Hwave wave height
266  * @param[in] Lwave wave length
267  * @param[in] eps avoid divide by zero
268  * @param[in] ustar friction velocity
269  * @param[in] nu intrinsic fluid viscosity
270  * @param[in] visc flag to apply smooth flow limit
271  */
272 AMREX_GPU_DEVICE
273 AMREX_FORCE_INLINE
276  amrex::Real Lwave,
277  amrex::Real eps,
278  amrex::Real ustar,
279  amrex::Real nu,
280  bool visc)
281 {
282 
283  amrex::Real z0 = amrex::Real(1200.0) * Hwave * std::pow( Hwave/(Lwave+eps), amrex::Real(4.5) );
284  if (visc) {
285  z0 += amrex::Real(0.11) * nu / std::max(ustar, amrex::Real(0.01));
286  }
287  return std::min(std::max(z0, amrex::Real(1.27e-7)), amrex::Real(1.0e-2));
288 }
289 
290 
291 /**
292  * Invert log-law to get roughness
293  *
294  * @param[in] zref reference height for the wind speed
295  * @param[in] Olen Obukhov length
296  * @param[in] umm horizontal wind speed magnitude at zref
297  * @param[in] ustar friction velocity
298  */
299 AMREX_GPU_DEVICE
300 AMREX_FORCE_INLINE
303  amrex::Real Olen,
304  amrex::Real umm,
305  amrex::Real ustar)
306 {
307  similarity_funs sfuns;
308  amrex::Real zeta = zref / Olen;
309  amrex::Real psi_m = sfuns.calc_psi_m2(zeta);
310  amrex::Real z0 = zref / std::exp(KAPPA*umm/ustar + psi_m);
311  return std::max(z0, amrex::Real(1.0e-7));
312 }
313 #endif
constexpr amrex::Real KAPPA
Definition: ERF_Constants.H:55
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:56
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:275
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:212
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:302
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Mod_Charnock_roughness(amrex::Real ustar, amrex::Real Cnk_b)
Definition: ERF_MOSTUtils.H:191
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real air_viscosity(amrex::Real T_degK)
Definition: ERF_MOSTUtils.H:148
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Donelan_roughness(amrex::Real ustar, amrex::Real nu, bool visc)
Definition: ERF_MOSTUtils.H:243
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:167
constexpr amrex::Real three
Definition: ERF_NumericalConstants.H:32
constexpr amrex::Real two
Definition: ERF_NumericalConstants.H:31
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:30
constexpr amrex::Real fourth
Definition: ERF_NumericalConstants.H:35
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:29
constexpr amrex::Real myhalf
Definition: ERF_NumericalConstants.H:34
constexpr amrex::Real PI
Definition: ERF_NumericalConstants.H:39
constexpr amrex::Real PIoTwo
Definition: ERF_NumericalConstants.H:40
amrex::Real Real
Definition: ERF_ShocInterface.H:19
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_psi_m(amrex::Real zeta) const
Definition: ERF_MOSTUtils.H:102
amrex::Real beta_m
Constants from Dyer, BLM, 1974.
Definition: ERF_MOSTUtils.H:132
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:133
amrex::Real gamma_h
Definition: ERF_MOSTUtils.H:135
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_psi_h(amrex::Real zeta) const
Definition: ERF_MOSTUtils.H:121
amrex::Real gamma_m
Definition: ERF_MOSTUtils.H:134
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_psi_m2(amrex::Real zeta) const
Definition: ERF_MOSTUtils.H:49