ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_EBMOSTStress.H
Go to the documentation of this file.
1 /**
2  * \file ERF_EBMOSTStress.H
3  * \brief Defines EB Monin-Obukhov surface-layer flux functors.
4  */
5 #ifndef ERF_EBMOSTStress_H
6 #define ERF_EBMOSTStress_H
7 
8 #include <ERF_Constants.H>
9 #include <ERF_IndexDefines.H>
10 
11 
12 //! EB surface-layer model for adiabatic constant-roughness fluxes.
14 {
15  /**
16  * \brief Construct an adiabatic EB flux functor.
17  * \param Tflux Prescribed surface temperature flux.
18  * \param Qvflux Prescribed surface moisture flux.
19  */
21  amrex::Real Qvflux)
22  {
23  mdata.surf_temp_flux = Tflux;
24  mdata.surf_moist_flux = Qvflux;
25  }
26 
27  //! Populate neutral MOST flux scales for an adiabatic EB surface.
28  AMREX_GPU_DEVICE
29  AMREX_FORCE_INLINE
30  void
31  iterate_flux (const int& i,
32  const int& j,
33  const int& k,
34  const int& /*max_iters*/,
35  const amrex::Array4<const amrex::Real>& zref_arr,
36  const amrex::Array4<const amrex::Real>& z0_arr,
37  const amrex::Array4<const amrex::Real>& umm_arr,
38  const amrex::Array4<const amrex::Real>& /*tm_arr*/,
39  const amrex::Array4<const amrex::Real>& /*tvm_arr*/,
40  const amrex::Array4<const amrex::Real>& /*qvm_arr*/,
41  const amrex::Array4<amrex::Real>& u_star_arr,
42  const amrex::Array4<amrex::Real>& /*w_star_arr*/,
43  const amrex::Array4<amrex::Real>& t_star_arr,
44  const amrex::Array4<amrex::Real>& q_star_arr,
45  const amrex::Array4<amrex::Real>& /*t_surf_arr*/,
46  const amrex::Array4<amrex::Real>& /*q_surf_arr*/,
47  const amrex::Array4<amrex::Real>& olen_arr,
48  const amrex::Array4<amrex::Real>& /*pblh_arr*/,
49  const amrex::Array4<amrex::Real>& /*Hwave_arr*/,
50  const amrex::Array4<amrex::Real>& /*Lwave_arr*/,
51  const amrex::Array4<amrex::Real>& /*eta_arr*/) const
52  {
53  olen_arr(i,j,k) = bogus_large_value;
54  u_star_arr(i,j,k) = mdata.kappa * umm_arr(i,j,0) /
55  most_bracket(std::log(zref_arr(i,j,0) / z0_arr(i,j,k)), zero);
56  t_star_arr(i,j,k) = zero;
57  q_star_arr(i,j,k) = zero;
58  }
59 
60 private:
63 };
64 
65 
66 //! EB surface-layer model with prescribed surface temperature and constant roughness.
68 {
69  /**
70  * \brief Construct a prescribed-temperature EB flux functor.
71  * \param Tflux Prescribed surface temperature flux.
72  * \param Qvflux Prescribed surface moisture flux.
73  * \param cons_qflux Whether the moisture flux is prescribed directly.
74  */
76  amrex::Real Qvflux,
77  bool cons_qflux)
78  {
79  mdata.surf_temp_flux = Tflux;
80  mdata.surf_moist_flux = Qvflux;
81  spec_qflux = cons_qflux;
82  }
83 
84  //! Iterate MOST stability functions and update surface flux scales.
85  AMREX_GPU_DEVICE
86  AMREX_FORCE_INLINE
87  void
88  iterate_flux (const int& i,
89  const int& j,
90  const int& k,
91  const int& max_iters,
92  const amrex::Array4<const amrex::Real>& zref_arr,
93  const amrex::Array4<const amrex::Real>& z0_arr,
94  const amrex::Array4<const amrex::Real>& umm_arr,
95  const amrex::Array4<const amrex::Real>& tm_arr,
96  const amrex::Array4<const amrex::Real>& tvm_arr,
97  const amrex::Array4<const amrex::Real>& qvm_arr,
98  const amrex::Array4<amrex::Real>& u_star_arr,
99  const amrex::Array4<amrex::Real>& w_star_arr,
100  const amrex::Array4<amrex::Real>& t_star_arr,
101  const amrex::Array4<amrex::Real>& q_star_arr,
102  const amrex::Array4<amrex::Real>& t_surf_arr,
103  const amrex::Array4<amrex::Real>& q_surf_arr,
104  const amrex::Array4<amrex::Real>& olen_arr,
105  const amrex::Array4<amrex::Real>& pblh_arr,
106  const amrex::Array4<amrex::Real>& /*Hwave_arr*/,
107  const amrex::Array4<amrex::Real>& /*Lwave_arr*/,
108  const amrex::Array4<amrex::Real>& /*eta_arr*/) const
109  {
110  amrex::Real Rib = zero;
111  amrex::Real zeta = zero;
112  amrex::Real zeta_old = zero;
113  amrex::Real psi_m = zero;
114  amrex::Real psi_h = zero;
115  amrex::Real CmPsim = zero;
116  amrex::Real CmPsih = zero;
117  amrex::Real zref = zref_arr(i,j,0);
118  amrex::Real z0 = z0_arr(i,j,k);
119  amrex::Real umm = std::max(umm_arr(i,j,0), WSMIN);
120  amrex::Real C = std::log(zref / z0);
121 
122  // First iteration we assume neutral (L -> inf)
123  if (u_star_arr(i,j,k) == bogus_large_value) {
124  olen_arr(i,j,k) = amrex::Real(1000);
125  }
126  zeta = zref / olen_arr(i,j,k);
127 
128  // Water vapor in atmos and surface
129  amrex::Real qv_s, qv_a;
130  if (q_surf_arr(i,j,k) > zero) {
131  qv_s = q_surf_arr(i,j,k);
132  } else {
133  // First iteration and no qv_surf was specified
134  // Use mean since there will be no flux
135  qv_s = qvm_arr(i,j,0);
136  }
137  qv_a = qvm_arr(i,j,0);
138 
139  // update w* and Umagmean from Beljaars (1995)
140  if (w_star_arr) {
141  // NOTE: Thv flux is lagged, similar to WRF
142  psi_m = sfuns.calc_psi_m2(zeta);
143  psi_h = sfuns.calc_psi_h2(zeta);
144  amrex::Real ustar = mdata.kappa * umm / most_bracket(C, psi_m);
145  amrex::Real tstar = mdata.kappa * (tm_arr(i,j,0) - t_surf_arr(i,j,k)) / most_bracket(C, psi_h);
147  -ustar * mdata.kappa * (qv_a - qv_s) / most_bracket(C, psi_h);
148  amrex::Real tflux = -ustar*tstar*(one + epsv*qvm_arr(i,j,0)) + epsv*tm_arr(i,j,0)*qflux;
149  w_star_arr(i,j,k) = calc_wstar(tflux, pblh_arr(i,j,k), tvm_arr(i,j,0));
150  amrex::Real wstar = mdata.Bjr_beta * w_star_arr(i,j,k);
151  umm = std::sqrt(umm_arr(i,j,0)*umm_arr(i,j,0) + wstar*wstar);
152  umm = std::max(umm, WSMIN);
153  }
154 
155  // Bulk Richardson number w/ moisture
156  amrex::Real thv_s = t_surf_arr(i,j,k) * (one + epsv*qv_s);
157  amrex::Real thv_a = tm_arr(i,j,0) * (one + epsv*qv_a);
158  Rib = ( (mdata.gravity * zref) / tm_arr(i,j,0) ) *
159  ( (thv_a - thv_s) / (umm * umm) );
160  Rib = std::min(std::max(Rib,-amrex::Real(4.0)),amrex::Real(4.0));
161 
162  // Fixed point iteration on zeta
163  const amrex::Real zeta_start = zeta;
164  int iter = 0;
165  do {
166  // Transfer curr to old
167  zeta_old = zeta;
168 
169  // Stability functions
170  psi_m = sfuns.calc_psi_m2(zeta_old);
171  psi_h = sfuns.calc_psi_h2(zeta_old);
172 
173  // Limiting
174  CmPsim = most_bracket(C, psi_m);
175  CmPsih = most_bracket(C, psi_h);
176 
177  // Update with under relaxation
178  zeta = (one - alpha) * zeta_old + alpha * Rib * CmPsim * CmPsim / CmPsih;
179 
180  ++iter;
181  } while ( (std::abs(zeta - zeta_old) > tol) && (iter <= max_iters) );
182  if (iter > max_iters ||
183  !most_rib_zeta_is_root(sfuns, C, Rib, zeta, amrex::Real(10.0) * tol)) {
184  // The relaxed iteration stalls, or stops where no root is near, where its residual
185  // nearly touches zero (z0 comparable to zref); solve the same equation by bracketing
186  zeta = most_rib_zeta_bracketed(sfuns, C, Rib, zeta_start, tol);
187  CmPsim = most_bracket(C, sfuns.calc_psi_m2(zeta));
188  CmPsih = most_bracket(C, sfuns.calc_psi_h2(zeta));
189  }
190 
191  // Populate the stored MOST arrays
192  olen_arr(i,j,k) = zref / zeta;
193  u_star_arr(i,j,k) = mdata.kappa * umm / CmPsim;
194  t_star_arr(i,j,k) = mdata.kappa * (tm_arr(i,j,0) - t_surf_arr(i,j,k)) / CmPsih;
195  if (spec_qflux) {
196  q_surf_arr(i,j,k) = mdata.surf_moist_flux * CmPsih /
197  (u_star_arr(i,j,k) * mdata.kappa) + qvm_arr(i,j,0);
198  q_star_arr(i,j,k) = -mdata.surf_moist_flux / u_star_arr(i,j,k);
199  } else {
200  q_star_arr(i,j,k) = mdata.kappa * (qvm_arr(i,j,0) - q_surf_arr(i,j,k)) / CmPsih;
201  }
202  }
203 
204 private:
208  const amrex::Real tol = amrex::Real(1.0e-3);
210  const amrex::Real WSMIN = amrex::Real(0.1); // minimum wind speed
211 };
212 
213 //! EB surface-layer model with prescribed surface fluxes and constant roughness.
215 {
216  /**
217  * \brief Construct a prescribed-flux EB functor.
218  * \param Tflux Prescribed surface temperature flux.
219  * \param Qvflux Prescribed surface moisture flux.
220  * \param cons_qflux Whether the moisture flux is prescribed directly.
221  */
223  amrex::Real Qvflux,
224  bool cons_qflux)
225  {
226  mdata.surf_temp_flux = Tflux;
227  mdata.surf_moist_flux = Qvflux;
228  spec_qflux = cons_qflux;
229  }
230 
231  //! Iterate MOST stability functions and update implied surface values.
232  AMREX_GPU_DEVICE
233  AMREX_FORCE_INLINE
234  void
235  iterate_flux (const int& i,
236  const int& j,
237  const int& k,
238  const int& max_iters,
239  const amrex::Array4<const amrex::Real>& zref_arr,
240  const amrex::Array4<const amrex::Real>& z0_arr,
241  const amrex::Array4<const amrex::Real>& umm_arr,
242  const amrex::Array4<const amrex::Real>& tm_arr,
243  const amrex::Array4<const amrex::Real>& tvm_arr,
244  const amrex::Array4<const amrex::Real>& qvm_arr,
245  const amrex::Array4<amrex::Real>& u_star_arr,
246  const amrex::Array4<amrex::Real>& w_star_arr,
247  const amrex::Array4<amrex::Real>& t_star_arr,
248  const amrex::Array4<amrex::Real>& q_star_arr,
249  const amrex::Array4<amrex::Real>& t_surf_arr,
250  const amrex::Array4<amrex::Real>& q_surf_arr,
251  const amrex::Array4<amrex::Real>& olen_arr,
252  const amrex::Array4<amrex::Real>& pblh_arr,
253  const amrex::Array4<amrex::Real>& /*Hwave_arr*/,
254  const amrex::Array4<amrex::Real>& /*Lwave_arr*/,
255  const amrex::Array4<amrex::Real>& /*eta_arr*/) const
256  {
257  int iter = 0;
259  amrex::Real wstar = zero;
260  amrex::Real tflux = zero;
261  amrex::Real qflux = zero;
262  amrex::Real zeta = zero;
263  amrex::Real psi_m = zero;
264  amrex::Real psi_h = zero;
265  amrex::Real Olen = zero;
266  amrex::Real zref = zref_arr(i,j,0);
267  amrex::Real C = std::log(zref / z0_arr(i,j,k));
268  amrex::Real zeta_fold = sfuns.calc_zeta_fold(C);
269  bool at_fold = false;
270  amrex::Real umm = std::max(umm_arr(i,j,0), WSMIN);
271  if (u_star_arr(i,j,k) == bogus_large_value) {
272  u_star_arr(i,j,k) = mdata.kappa * umm / most_bracket(C, zero);
273  } else {
274  Olen = olen_arr(i,j,k);
275  zeta = most_clamp_zeta(zref / Olen, zeta_fold, at_fold);
276  psi_m = sfuns.calc_psi_m(zeta);
277  psi_h = sfuns.calc_psi_h(zeta);
278  }
279  most_aitken accel;
280  do {
281  ustar = u_star_arr(i,j,k);
282  qflux = (spec_qflux) ? mdata.surf_moist_flux :
283  -(qvm_arr(i,j,0) - q_surf_arr(i,j,k)) * ustar * mdata.kappa /
284  most_bracket(C, psi_h); // <w'Qv'>
285  tflux = mdata.surf_temp_flux*(one + epsv*qvm_arr(i,j,0)) + qflux*epsv*tm_arr(i,j,0);
286  if (w_star_arr) {
287  // update w* and Umagmean
288  w_star_arr(i,j,k) = calc_wstar(tflux, pblh_arr(i,j,k), tvm_arr(i,j,0));
289  wstar = mdata.Bjr_beta * w_star_arr(i,j,k);
290  umm = std::sqrt(umm_arr(i,j,0)*umm_arr(i,j,0) + wstar*wstar);
291  umm = std::max(umm, WSMIN);
292  }
293  Olen = -ustar * ustar * ustar * tvm_arr(i,j,0) / (mdata.kappa * mdata.gravity * tflux);
294  // Stable side bounded at the fold, where the prescribed flux stops having a solution
295  zeta = most_clamp_zeta(zref / Olen, zeta_fold, at_fold);
296  psi_m = sfuns.calc_psi_m(zeta);
297  psi_h = sfuns.calc_psi_h(zeta);
298  {
299  amrex::Real ustar_new = mdata.kappa * umm / most_bracket(C, psi_m);
300  u_star_arr(i,j,k) = (one - alpha) * ustar + alpha * ustar_new;
301  }
302  ++iter;
303  u_star_arr(i,j,k) = accel.update(u_star_arr(i,j,k), iter);
304  } while ((accel.extrapolated || std::abs(u_star_arr(i,j,k) - ustar) > tol) &&
305  iter <= max_iters);
306  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(iter <= max_iters,
307  "Maximum number of MOST iterations reached.");
308 
309  // Populate the stored MOST arrays; below the fold, apply the flux the wind can carry
310  most_flux_outputs(mdata, spec_qflux, at_fold, zeta_fold, C, psi_h, u_star_arr(i,j,k), zref,
311  tm_arr(i,j,0), tvm_arr(i,j,0), qvm_arr(i,j,0), qflux, Olen,
312  t_surf_arr(i,j,k), t_star_arr(i,j,k), q_surf_arr(i,j,k), q_star_arr(i,j,k));
313  olen_arr(i,j,k) = Olen;
314  }
315 
316 private:
320  const amrex::Real tol = amrex::Real(1.0e-5);
321  const amrex::Real alpha = amrex::Real(0.5); // under-relaxation factor for the u* iteration
322  const amrex::Real WSMIN = amrex::Real(0.1); // minimum wind speed
323 };
324 
325 //! EB implementation of the Moeng surface-flux formulation.
327 {
328  //! Construct a Moeng EB flux functor.
330 
331  //! Compute the EB moisture flux at a cell-centered cut-cell surface.
332  AMREX_GPU_DEVICE
333  AMREX_FORCE_INLINE
335  compute_q_flux (const int& i,
336  const int& j,
337  const int& k,
338  const amrex::Array4<const amrex::Real>& cons_arr,
339  const amrex::Array4<const amrex::Real>& velx_arr,
340  const amrex::Array4<const amrex::Real>& vely_arr,
341  const amrex::Array4<const amrex::Real>& umm_arr,
342  const amrex::Array4<const amrex::Real>& qvm_arr,
343  const amrex::Array4<const amrex::Real>& u_star_arr,
344  const amrex::Array4<const amrex::Real>& q_star_arr,
345  const amrex::Array4<const amrex::Real>& q_surf_arr,
346  const amrex::Array4<const amrex::Real>& u_vfrac_arr,
347  const amrex::Array4<const amrex::Real>& v_vfrac_arr) const
348  {
349  amrex::Real rho = cons_arr(i,j,k,Rho_comp);
350  amrex::Real qv = cons_arr(i,j,k,RhoQ1_comp) / rho;
351 
352  // Volume-weighted average of x-face velocities to cell center
353  amrex::Real u_vfrac_sum = u_vfrac_arr(i,j,k) + u_vfrac_arr(i+1,j,k);
354  amrex::Real velx = (u_vfrac_sum > eps) ?
355  (velx_arr(i,j,k) * u_vfrac_arr(i,j,k) + velx_arr(i+1,j,k) * u_vfrac_arr(i+1,j,k))
356  / u_vfrac_sum : zero;
357 
358  // Volume-weighted average of y-face velocities to cell center
359  amrex::Real v_vfrac_sum = v_vfrac_arr(i,j,k) + v_vfrac_arr(i,j+1,k);
360  amrex::Real vely = (v_vfrac_sum > eps) ?
361  (vely_arr(i,j,k) * v_vfrac_arr(i,j,k) + vely_arr(i,j+1,k) * v_vfrac_arr(i,j+1,k))
362  / v_vfrac_sum : zero;
363 
364  amrex::Real qv_mean = qvm_arr(i,j,0);
365  amrex::Real ustar = u_star_arr(i,j,k);
366  amrex::Real qstar = q_star_arr(i,j,k);
367  amrex::Real qv_surf = q_surf_arr(i,j,k);
368  amrex::Real wsp_mean = umm_arr(i,j,0);
369  wsp_mean = std::max(wsp_mean, WSMIN);
370 
371  amrex::Real wsp = std::sqrt(velx*velx+vely*vely);
372  amrex::Real num1 = wsp * (qv_mean-qv_surf);
373  amrex::Real num2 = wsp_mean * (qv-qv_mean);
374 
375  // NOTE: this is rho*<Qv'w'> = -K dQvdz
376  amrex::Real moflux = (std::abs(qstar) > eps) ?
377  -rho*qstar*ustar*(num1+num2)/((qv_mean-qv_surf)*wsp_mean) : zero;
378 
379  return moflux;
380  }
381 
382  //! Compute the EB temperature flux at a cell-centered cut-cell surface.
383  AMREX_GPU_DEVICE
384  AMREX_FORCE_INLINE
386  compute_t_flux (const int& i,
387  const int& j,
388  const int& k,
389  const amrex::Array4<const amrex::Real>& cons_arr,
390  const amrex::Array4<const amrex::Real>& velx_arr,
391  const amrex::Array4<const amrex::Real>& vely_arr,
392  const amrex::Array4<const amrex::Real>& velz_arr,
393  const amrex::Array4<const amrex::Real>& umm_arr,
394  const amrex::Array4<const amrex::Real>& tm_arr,
395  const amrex::Array4<const amrex::Real>& u_star_arr,
396  const amrex::Array4<const amrex::Real>& t_star_arr,
397  const amrex::Array4<const amrex::Real>& t_surf_arr,
398  const amrex::Array4<const amrex::Real>& u_vfrac_arr,
399  const amrex::Array4<const amrex::Real>& v_vfrac_arr,
400  const amrex::Array4<const amrex::Real>& w_vfrac_arr,
401  const amrex::Array4<const amrex::Real>& bnorm_arr) const
402  {
403  amrex::Real rho = cons_arr(i,j,k,Rho_comp);
404  amrex::Real theta = cons_arr(i,j,k,RhoTheta_comp) / rho;
405 
406  // Volume-weighted average of x-face velocities to cell center
407  amrex::Real u_vfrac_sum = u_vfrac_arr(i,j,k) + u_vfrac_arr(i+1,j,k);
408  amrex::Real velx = (u_vfrac_sum > eps) ?
409  (velx_arr(i,j,k) * u_vfrac_arr(i,j,k) + velx_arr(i+1,j,k) * u_vfrac_arr(i+1,j,k))
410  / u_vfrac_sum : zero;
411 
412  // Volume-weighted average of y-face velocities to cell center
413  amrex::Real v_vfrac_sum = v_vfrac_arr(i,j,k) + v_vfrac_arr(i,j+1,k);
414  amrex::Real vely = (v_vfrac_sum > eps) ?
415  (vely_arr(i,j,k) * v_vfrac_arr(i,j,k) + vely_arr(i,j+1,k) * v_vfrac_arr(i,j+1,k))
416  / v_vfrac_sum : zero;
417 
418  // Volume-weighted average of z-face velocities to cell center
419  amrex::Real w_vfrac_sum = w_vfrac_arr(i,j,k) + w_vfrac_arr(i,j,k+1);
420  amrex::Real velz = (w_vfrac_sum > eps) ?
421  (velz_arr(i,j,k) * w_vfrac_arr(i,j,k) + velz_arr(i,j,k+1) * w_vfrac_arr(i,j,k+1))
422  / w_vfrac_sum : zero;
423 
424  // Get boundary normal components
425  amrex::Real nx = bnorm_arr(i,j,k,0);
426  amrex::Real ny = bnorm_arr(i,j,k,1);
427  amrex::Real nz = bnorm_arr(i,j,k,2);
428 
429  // Project velocity onto tangent plane (remove normal component)
430  amrex::Real v_dot_n = velx*nx + vely*ny + velz*nz;
431  amrex::Real velx_tangent = velx - v_dot_n * nx;
432  amrex::Real vely_tangent = vely - v_dot_n * ny;
433 
434  amrex::Real theta_mean = tm_arr(i,j,0);
435  amrex::Real ustar = u_star_arr(i,j,k);
436  amrex::Real tstar = t_star_arr(i,j,k);
437  amrex::Real theta_surf = t_surf_arr(i,j,k);
438  amrex::Real wsp_mean = umm_arr(i,j,0);
439  wsp_mean = std::max(wsp_mean, WSMIN);
440 
441  // Use tangential velocity magnitude instead of Cartesian
442  amrex::Real wsp = std::sqrt(velx_tangent*velx_tangent+vely_tangent*vely_tangent);
443  amrex::Real num1 = wsp * (theta_mean-theta_surf);
444  amrex::Real num2 = wsp_mean * (theta-theta_mean);
445 
446  // NOTE: this is rho*<T'w'> = -K dTdz
447  amrex::Real moflux = (std::abs(tstar) > eps) ?
448  -rho*tstar*ustar*(num1+num2)/((theta_mean-theta_surf)*wsp_mean) : zero;
449 
450  return moflux;
451  }
452 
453  //! Compute the EB x-momentum stress on a staggered face.
454  AMREX_GPU_DEVICE
455  AMREX_FORCE_INLINE
458  int j,
459  int k,
460  const amrex::Array4<const amrex::Real>& cons_arr,
461  const amrex::Array4<const amrex::Real>& velx_arr,
462  const amrex::Array4<const amrex::Real>& vely_arr,
463  const amrex::Array4<const amrex::Real>& velz_arr,
464  const amrex::Array4<const amrex::Real>& umm_arr,
465  const amrex::Array4<const amrex::Real>& um_arr,
466  const amrex::Array4<const amrex::Real>& u_star_arr,
467  const amrex::Array4<const amrex::Real>& u_vfrac_arr,
468  const amrex::Array4<const amrex::Real>& v_vfrac_arr,
469  const amrex::Array4<const amrex::Real>& w_vfrac_arr,
470  const amrex::Array4<const amrex::Real>& cc_vfrac_arr,
471  const amrex::Array4<const amrex::EBCellFlag>& cc_flag_arr,
472  const amrex::Array4<const amrex::Real>& bnorm_arr,
473  int idir = 0) const
474  {
475  amrex::Real velx, vely, rho, ustar, wsp_mean;
476  amrex::Real velx_tangent, vely_tangent;
477 
478  if (idir == 0) {
479  // x-face: average to x-face
480  velx = velx_arr(i,j,k);
481 
482  // Volume-weighted average of y-face velocities to x-face
483  amrex::Real v_vfrac_sum = v_vfrac_arr(i,j,k) + v_vfrac_arr(i,j+1,k) +
484  v_vfrac_arr(i-1,j,k) + v_vfrac_arr(i-1,j+1,k);
485  vely = (v_vfrac_sum > eps) ?
486  (vely_arr(i,j,k) * v_vfrac_arr(i,j,k) + vely_arr(i,j+1,k) * v_vfrac_arr(i,j+1,k) +
487  vely_arr(i-1,j,k) * v_vfrac_arr(i-1,j,k) + vely_arr(i-1,j+1,k) * v_vfrac_arr(i-1,j+1,k))
488  / v_vfrac_sum : zero;
489 
490  // Volume-weighted average of z-face velocities to x-face
491  amrex::Real w_vfrac_sum = w_vfrac_arr(i,j,k) + w_vfrac_arr(i,j,k+1) +
492  w_vfrac_arr(i-1,j,k) + w_vfrac_arr(i-1,j,k+1);
493  amrex::Real velz = (w_vfrac_sum > eps) ?
494  (velz_arr(i,j,k) * w_vfrac_arr(i,j,k) + velz_arr(i,j,k+1) * w_vfrac_arr(i,j,k+1) +
495  velz_arr(i-1,j,k) * w_vfrac_arr(i-1,j,k) + velz_arr(i-1,j,k+1) * w_vfrac_arr(i-1,j,k+1))
496  / w_vfrac_sum : zero;
497 
498  // Get boundary normal at x-face (already at correct staggered location)
499  amrex::Real nx = bnorm_arr(i,j,k,0);
500  amrex::Real ny = bnorm_arr(i,j,k,1);
501  amrex::Real nz = bnorm_arr(i,j,k,2);
502 
503  // Project velocity onto tangent plane
504  amrex::Real v_dot_n = velx*nx + vely*ny + velz*nz;
505  velx_tangent = velx - v_dot_n * nx;
506  vely_tangent = vely - v_dot_n * ny;
507 
508  // Volume-weighted average of cell-centered density to x-face
509  amrex::Real cc_vfrac_sum = cc_vfrac_arr(i-1,j,k) + cc_vfrac_arr(i,j,k);
510  rho = (cc_vfrac_sum > eps) ?
511  (cons_arr(i-1,j,k,Rho_comp) * cc_vfrac_arr(i-1,j,k) + cons_arr(i,j,k,Rho_comp) * cc_vfrac_arr(i,j,k))
512  / cc_vfrac_sum : zero;
513 
514  // Average cell-centered u_star and wsp_mean to x-face, using only valid (SingleValued) cells
515  bool low_valid = cc_flag_arr(i-1,j,k).isSingleValued();
516  bool high_valid = cc_flag_arr(i,j,k).isSingleValued();
517 
518  if (low_valid && high_valid) {
519  ustar = myhalf * (u_star_arr(i-1,j,k) + u_star_arr(i,j,k));
520  wsp_mean = myhalf * (umm_arr(i-1,j,0) + umm_arr(i,j,0));
521  } else if (low_valid) {
522  ustar = u_star_arr(i-1,j,k);
523  wsp_mean = umm_arr(i-1,j,0);
524  } else if (high_valid) {
525  ustar = u_star_arr(i,j,k);
526  wsp_mean = umm_arr(i,j,0);
527  } else {
528  ustar = zero;
529  wsp_mean = WSMIN;
530  }
531 
532  } else if (idir == 1) {
533  // y-face: average to y-face
534  vely = vely_arr(i,j,k);
535 
536  // Volume-weighted average of x-face velocities to y-face
537  amrex::Real u_vfrac_sum = u_vfrac_arr(i,j,k) + u_vfrac_arr(i+1,j,k) +
538  u_vfrac_arr(i,j-1,k) + u_vfrac_arr(i+1,j-1,k);
539  velx = (u_vfrac_sum > eps) ?
540  (velx_arr(i,j,k) * u_vfrac_arr(i,j,k) + velx_arr(i+1,j,k) * u_vfrac_arr(i+1,j,k) +
541  velx_arr(i,j-1,k) * u_vfrac_arr(i,j-1,k) + velx_arr(i+1,j-1,k) * u_vfrac_arr(i+1,j-1,k))
542  / u_vfrac_sum : zero;
543 
544  // Volume-weighted average of z-face velocities to y-face
545  amrex::Real w_vfrac_sum = w_vfrac_arr(i,j,k) + w_vfrac_arr(i,j,k+1) +
546  w_vfrac_arr(i,j-1,k) + w_vfrac_arr(i,j-1,k+1);
547  amrex::Real velz = (w_vfrac_sum > eps) ?
548  (velz_arr(i,j,k) * w_vfrac_arr(i,j,k) + velz_arr(i,j,k+1) * w_vfrac_arr(i,j,k+1) +
549  velz_arr(i,j-1,k) * w_vfrac_arr(i,j-1,k) + velz_arr(i,j-1,k+1) * w_vfrac_arr(i,j-1,k+1))
550  / w_vfrac_sum : zero;
551 
552  // Get boundary normal at y-face (already at correct staggered location)
553  amrex::Real nx = bnorm_arr(i,j,k,0);
554  amrex::Real ny = bnorm_arr(i,j,k,1);
555  amrex::Real nz = bnorm_arr(i,j,k,2);
556 
557  // Project velocity onto tangent plane
558  amrex::Real v_dot_n = velx*nx + vely*ny + velz*nz;
559  velx_tangent = velx - v_dot_n * nx;
560  vely_tangent = vely - v_dot_n * ny;
561 
562  // Volume-weighted average of cell-centered density to y-face
563  amrex::Real cc_vfrac_sum = cc_vfrac_arr(i,j-1,k) + cc_vfrac_arr(i,j,k);
564  rho = (cc_vfrac_sum > eps) ?
565  (cons_arr(i,j-1,k,Rho_comp) * cc_vfrac_arr(i,j-1,k) + cons_arr(i,j,k,Rho_comp) * cc_vfrac_arr(i,j,k))
566  / cc_vfrac_sum : zero;
567 
568  // Average cell-centered u_star and wsp_mean to y-face, using only valid (SingleValued) cells
569  bool low_valid = cc_flag_arr(i,j-1,k).isSingleValued();
570  bool high_valid = cc_flag_arr(i,j,k).isSingleValued();
571 
572  if (low_valid && high_valid) {
573  ustar = myhalf * (u_star_arr(i,j-1,k) + u_star_arr(i,j,k));
574  wsp_mean = myhalf * (umm_arr(i,j-1,0) + umm_arr(i,j,0));
575  } else if (low_valid) {
576  ustar = u_star_arr(i,j-1,k);
577  wsp_mean = umm_arr(i,j-1,0);
578  } else if (high_valid) {
579  ustar = u_star_arr(i,j,k);
580  wsp_mean = umm_arr(i,j,0);
581  } else {
582  ustar = zero;
583  wsp_mean = WSMIN;
584  }
585 
586  } else {
587  // z-face: average to z-face
588  // Volume-weighted average of x-face velocities to z-face
589  amrex::Real u_vfrac_sum = u_vfrac_arr(i,j,k-1) + u_vfrac_arr(i+1,j,k-1) +
590  u_vfrac_arr(i,j,k) + u_vfrac_arr(i+1,j,k);
591  velx = (u_vfrac_sum > eps) ?
592  (velx_arr(i,j,k-1) * u_vfrac_arr(i,j,k-1) + velx_arr(i+1,j,k-1) * u_vfrac_arr(i+1,j,k-1) +
593  velx_arr(i,j,k) * u_vfrac_arr(i,j,k) + velx_arr(i+1,j,k) * u_vfrac_arr(i+1,j,k))
594  / u_vfrac_sum : zero;
595 
596  // Volume-weighted average of y-face velocities to z-face
597  amrex::Real v_vfrac_sum = v_vfrac_arr(i,j,k-1) + v_vfrac_arr(i,j+1,k-1) +
598  v_vfrac_arr(i,j,k) + v_vfrac_arr(i,j+1,k);
599  vely = (v_vfrac_sum > eps) ?
600  (vely_arr(i,j,k-1) * v_vfrac_arr(i,j,k-1) + vely_arr(i,j+1,k-1) * v_vfrac_arr(i,j+1,k-1) +
601  vely_arr(i,j,k) * v_vfrac_arr(i,j,k) + vely_arr(i,j+1,k) * v_vfrac_arr(i,j+1,k))
602  / v_vfrac_sum : zero;
603 
604  // z-velocity is already at z-face
605  amrex::Real velz = velz_arr(i,j,k);
606 
607  // Get boundary normal at z-face (already at correct staggered location)
608  amrex::Real nx = bnorm_arr(i,j,k,0);
609  amrex::Real ny = bnorm_arr(i,j,k,1);
610  amrex::Real nz = bnorm_arr(i,j,k,2);
611 
612  // Project velocity onto tangent plane
613  amrex::Real v_dot_n = velx*nx + vely*ny + velz*nz;
614  velx_tangent = velx - v_dot_n * nx;
615  vely_tangent = vely - v_dot_n * ny;
616 
617  // Volume-weighted average of cell-centered density to z-face
618  amrex::Real cc_vfrac_sum = cc_vfrac_arr(i,j,k-1) + cc_vfrac_arr(i,j,k);
619  rho = (cc_vfrac_sum > eps) ?
620  (cons_arr(i,j,k-1,Rho_comp) * cc_vfrac_arr(i,j,k-1) + cons_arr(i,j,k,Rho_comp) * cc_vfrac_arr(i,j,k))
621  / cc_vfrac_sum : zero;
622 
623  // Average cell-centered u_star and wsp_mean to z-face, using only valid (SingleValued) cells
624  bool low_valid = cc_flag_arr(i,j,k-1).isSingleValued();
625  bool high_valid = cc_flag_arr(i,j,k).isSingleValued();
626 
627  if (low_valid && high_valid) {
628  ustar = myhalf * (u_star_arr(i,j,k-1) + u_star_arr(i,j,k));
629  wsp_mean = myhalf * (umm_arr(i,j,0) + umm_arr(i,j,0));
630  } else if (low_valid) {
631  ustar = u_star_arr(i,j,k-1);
632  wsp_mean = umm_arr(i,j,0);
633  } else if (high_valid) {
634  ustar = u_star_arr(i,j,k);
635  wsp_mean = umm_arr(i,j,0);
636  } else {
637  ustar = zero;
638  wsp_mean = WSMIN;
639  }
640  }
641 
642  wsp_mean = std::max(wsp_mean, WSMIN);
643  amrex::Real umean = um_arr(i,j,0);
644 
645  // Note: The surface mean shear stress is decomposed into tau_xz by
646  // multiplying the modeled shear stress (rho*ustar^2) with
647  // a factor of umean/wsp_mean for directionality; this factor
648  // modifies the denominator from what is in Moeng amrex::Real(1984.)
649  amrex::Real wsp = std::sqrt(velx_tangent*velx_tangent+vely_tangent*vely_tangent);
650  amrex::Real num1 = wsp * umean;
651  amrex::Real num2 = wsp_mean * (velx_tangent-umean);
652 
653  // NOTE: this is rho*<u'w'> = -K dudz
654  amrex::Real stressx = -rho*ustar*ustar * (num1+num2)/(wsp_mean*wsp_mean);
655 
656  return stressx;
657  }
658 
659  //! Compute the EB y-momentum stress on a staggered face.
660  AMREX_GPU_DEVICE
661  AMREX_FORCE_INLINE
664  int j,
665  int k,
666  const amrex::Array4<const amrex::Real>& cons_arr,
667  const amrex::Array4<const amrex::Real>& velx_arr,
668  const amrex::Array4<const amrex::Real>& vely_arr,
669  const amrex::Array4<const amrex::Real>& velz_arr,
670  const amrex::Array4<const amrex::Real>& umm_arr,
671  const amrex::Array4<const amrex::Real>& vm_arr,
672  const amrex::Array4<const amrex::Real>& u_star_arr,
673  const amrex::Array4<const amrex::Real>& u_vfrac_arr,
674  const amrex::Array4<const amrex::Real>& v_vfrac_arr,
675  const amrex::Array4<const amrex::Real>& w_vfrac_arr,
676  const amrex::Array4<const amrex::Real>& cc_vfrac_arr,
677  const amrex::Array4<const amrex::EBCellFlag>& cc_flag_arr,
678  const amrex::Array4<const amrex::Real>& bnorm_arr,
679  int idir = 0) const
680  {
681  amrex::Real velx, vely, rho, ustar, wsp_mean;
682  amrex::Real velx_tangent, vely_tangent;
683 
684  if (idir == 0) {
685  // x-face: average from cells (i-1) and (i)
686  // Volume-weighted average of y-face velocities to x-face
687  amrex::Real v_vfrac_sum = v_vfrac_arr(i,j,k) + v_vfrac_arr(i,j+1,k) +
688  v_vfrac_arr(i-1,j,k) + v_vfrac_arr(i-1,j+1,k);
689  vely = (v_vfrac_sum > eps) ?
690  (vely_arr(i,j,k) * v_vfrac_arr(i,j,k) + vely_arr(i,j+1,k) * v_vfrac_arr(i,j+1,k) +
691  vely_arr(i-1,j,k) * v_vfrac_arr(i-1,j,k) + vely_arr(i-1,j+1,k) * v_vfrac_arr(i-1,j+1,k))
692  / v_vfrac_sum : zero;
693 
694  velx = velx_arr(i,j,k);
695 
696  // Volume-weighted average of z-face velocities to x-face
697  amrex::Real w_vfrac_sum = w_vfrac_arr(i,j,k) + w_vfrac_arr(i,j,k+1) +
698  w_vfrac_arr(i-1,j,k) + w_vfrac_arr(i-1,j,k+1);
699  amrex::Real velz = (w_vfrac_sum > eps) ?
700  (velz_arr(i,j,k) * w_vfrac_arr(i,j,k) + velz_arr(i,j,k+1) * w_vfrac_arr(i,j,k+1) +
701  velz_arr(i-1,j,k) * w_vfrac_arr(i-1,j,k) + velz_arr(i-1,j,k+1) * w_vfrac_arr(i-1,j,k+1))
702  / w_vfrac_sum : zero;
703 
704  // Get boundary normal at x-face (already at correct staggered location)
705  amrex::Real nx = bnorm_arr(i,j,k,0);
706  amrex::Real ny = bnorm_arr(i,j,k,1);
707  amrex::Real nz = bnorm_arr(i,j,k,2);
708 
709  // Project velocity onto tangent plane
710  amrex::Real v_dot_n = velx*nx + vely*ny + velz*nz;
711  velx_tangent = velx - v_dot_n * nx;
712  vely_tangent = vely - v_dot_n * ny;
713 
714  // Volume-weighted average of cell-centered density to x-face
715  amrex::Real cc_vfrac_sum = cc_vfrac_arr(i-1,j,k) + cc_vfrac_arr(i,j,k);
716  rho = (cc_vfrac_sum > eps) ?
717  (cons_arr(i-1,j,k,Rho_comp) * cc_vfrac_arr(i-1,j,k) + cons_arr(i,j,k,Rho_comp) * cc_vfrac_arr(i,j,k))
718  / cc_vfrac_sum : zero;
719 
720  // Average cell-centered u_star and wsp_mean to x-face, using only valid (SingleValued) cells
721  bool low_valid = cc_flag_arr(i-1,j,k).isSingleValued();
722  bool high_valid = cc_flag_arr(i,j,k).isSingleValued();
723 
724  if (low_valid && high_valid) {
725  ustar = myhalf * (u_star_arr(i-1,j,k) + u_star_arr(i,j,k));
726  wsp_mean = myhalf * (umm_arr(i-1,j,0) + umm_arr(i,j,0));
727  } else if (low_valid) {
728  ustar = u_star_arr(i-1,j,k);
729  wsp_mean = umm_arr(i-1,j,0);
730  } else if (high_valid) {
731  ustar = u_star_arr(i,j,k);
732  wsp_mean = umm_arr(i,j,0);
733  } else {
734  ustar = zero;
735  wsp_mean = WSMIN;
736  }
737 
738  } else if (idir == 1) {
739  // y-face: average from cells (j-1) and (j)
740  // Volume-weighted average of x-face velocities to y-face
741  amrex::Real u_vfrac_sum = u_vfrac_arr(i,j,k) + u_vfrac_arr(i+1,j,k) +
742  u_vfrac_arr(i,j-1,k) + u_vfrac_arr(i+1,j-1,k);
743  velx = (u_vfrac_sum > eps) ?
744  (velx_arr(i,j,k) * u_vfrac_arr(i,j,k) + velx_arr(i+1,j,k) * u_vfrac_arr(i+1,j,k) +
745  velx_arr(i,j-1,k) * u_vfrac_arr(i,j-1,k) + velx_arr(i+1,j-1,k) * u_vfrac_arr(i+1,j-1,k))
746  / u_vfrac_sum : zero;
747 
748  vely = vely_arr(i,j,k);
749 
750  // Volume-weighted average of z-face velocities to y-face
751  amrex::Real w_vfrac_sum = w_vfrac_arr(i,j,k) + w_vfrac_arr(i,j,k+1) +
752  w_vfrac_arr(i,j-1,k) + w_vfrac_arr(i,j-1,k+1);
753  amrex::Real velz = (w_vfrac_sum > eps) ?
754  (velz_arr(i,j,k) * w_vfrac_arr(i,j,k) + velz_arr(i,j,k+1) * w_vfrac_arr(i,j,k+1) +
755  velz_arr(i,j-1,k) * w_vfrac_arr(i,j-1,k) + velz_arr(i,j-1,k+1) * w_vfrac_arr(i,j-1,k+1))
756  / w_vfrac_sum : zero;
757 
758  // Get boundary normal at y-face (already at correct staggered location)
759  amrex::Real nx = bnorm_arr(i,j,k,0);
760  amrex::Real ny = bnorm_arr(i,j,k,1);
761  amrex::Real nz = bnorm_arr(i,j,k,2);
762 
763  // Project velocity onto tangent plane
764  amrex::Real v_dot_n = velx*nx + vely*ny + velz*nz;
765  velx_tangent = velx - v_dot_n * nx;
766  vely_tangent = vely - v_dot_n * ny;
767 
768  // Volume-weighted average of cell-centered density to y-face
769  amrex::Real cc_vfrac_sum = cc_vfrac_arr(i,j-1,k) + cc_vfrac_arr(i,j,k);
770  rho = (cc_vfrac_sum > eps) ?
771  (cons_arr(i,j-1,k,Rho_comp) * cc_vfrac_arr(i,j-1,k) + cons_arr(i,j,k,Rho_comp) * cc_vfrac_arr(i,j,k))
772  / cc_vfrac_sum : zero;
773 
774  // Average cell-centered u_star and wsp_mean to y-face, using only valid (SingleValued) cells
775  bool low_valid = cc_flag_arr(i,j-1,k).isSingleValued();
776  bool high_valid = cc_flag_arr(i,j,k).isSingleValued();
777 
778  if (low_valid && high_valid) {
779  ustar = myhalf * (u_star_arr(i,j-1,k) + u_star_arr(i,j,k));
780  wsp_mean = myhalf * (umm_arr(i,j-1,0) + umm_arr(i,j,0));
781  } else if (low_valid) {
782  ustar = u_star_arr(i,j-1,k);
783  wsp_mean = umm_arr(i,j-1,0);
784  } else if (high_valid) {
785  ustar = u_star_arr(i,j,k);
786  wsp_mean = umm_arr(i,j,0);
787  } else {
788  ustar = zero;
789  wsp_mean = WSMIN;
790  }
791 
792  } else {
793  // z-face: average from cells (k-1) and (k)
794  // Volume-weighted average of x-face velocities to z-face
795  amrex::Real u_vfrac_sum = u_vfrac_arr(i,j,k-1) + u_vfrac_arr(i+1,j,k-1) +
796  u_vfrac_arr(i,j,k) + u_vfrac_arr(i+1,j,k);
797  velx = (u_vfrac_sum > eps) ?
798  (velx_arr(i,j,k-1) * u_vfrac_arr(i,j,k-1) + velx_arr(i+1,j,k-1) * u_vfrac_arr(i+1,j,k-1) +
799  velx_arr(i,j,k) * u_vfrac_arr(i,j,k) + velx_arr(i+1,j,k) * u_vfrac_arr(i+1,j,k))
800  / u_vfrac_sum : zero;
801 
802  // Volume-weighted average of y-face velocities to z-face
803  amrex::Real v_vfrac_sum = v_vfrac_arr(i,j,k-1) + v_vfrac_arr(i,j+1,k-1) +
804  v_vfrac_arr(i,j,k) + v_vfrac_arr(i,j+1,k);
805  vely = (v_vfrac_sum > eps) ?
806  (vely_arr(i,j,k-1) * v_vfrac_arr(i,j,k-1) + vely_arr(i,j+1,k-1) * v_vfrac_arr(i,j+1,k-1) +
807  vely_arr(i,j,k) * v_vfrac_arr(i,j,k) + vely_arr(i,j+1,k) * v_vfrac_arr(i,j+1,k))
808  / v_vfrac_sum : zero;
809 
810  // z-velocity is already at z-face
811  amrex::Real velz = velz_arr(i,j,k);
812 
813  // Get boundary normal at z-face (already at correct staggered location)
814  amrex::Real nx = bnorm_arr(i,j,k,0);
815  amrex::Real ny = bnorm_arr(i,j,k,1);
816  amrex::Real nz = bnorm_arr(i,j,k,2);
817 
818  // Project velocity onto tangent plane
819  amrex::Real v_dot_n = velx*nx + vely*ny + velz*nz;
820  velx_tangent = velx - v_dot_n * nx;
821  vely_tangent = vely - v_dot_n * ny;
822 
823  // Volume-weighted average of cell-centered density to z-face
824  amrex::Real cc_vfrac_sum = cc_vfrac_arr(i,j,k-1) + cc_vfrac_arr(i,j,k);
825  rho = (cc_vfrac_sum > eps) ?
826  (cons_arr(i,j,k-1,Rho_comp) * cc_vfrac_arr(i,j,k-1) + cons_arr(i,j,k,Rho_comp) * cc_vfrac_arr(i,j,k))
827  / cc_vfrac_sum : zero;
828 
829  // Average cell-centered u_star and wsp_mean to z-face, using only valid (SingleValued) cells
830  bool low_valid = cc_flag_arr(i,j,k-1).isSingleValued();
831  bool high_valid = cc_flag_arr(i,j,k).isSingleValued();
832 
833  if (low_valid && high_valid) {
834  ustar = myhalf * (u_star_arr(i,j,k-1) + u_star_arr(i,j,k));
835  wsp_mean = myhalf * (umm_arr(i,j,0) + umm_arr(i,j,0));
836  } else if (low_valid) {
837  ustar = u_star_arr(i,j,k-1);
838  wsp_mean = umm_arr(i,j,0);
839  } else if (high_valid) {
840  ustar = u_star_arr(i,j,k);
841  wsp_mean = umm_arr(i,j,0);
842  } else {
843  ustar = zero;
844  wsp_mean = WSMIN;
845  }
846  }
847 
848  wsp_mean = std::max(wsp_mean, WSMIN);
849  amrex::Real vmean = vm_arr(i,j,0);
850 
851  // Note: The surface mean shear stress is decomposed into tau_yz by
852  // multiplying the modeled shear stress (rho*ustar^2) with
853  // a factor of vmean/wsp_mean for directionality; this factor
854  // modifies the denominator from what is in Moeng amrex::Real(1984.)
855  amrex::Real wsp = std::sqrt(velx_tangent*velx_tangent+vely_tangent*vely_tangent);
856  amrex::Real num1 = wsp * vmean;
857  amrex::Real num2 = wsp_mean * (vely_tangent-vmean);
858 
859  // NOTE: this is rho*<v'w'> = -K dvdz
860  amrex::Real stressy = -rho*ustar*ustar * (num1+num2)/(wsp_mean*wsp_mean);
861 
862  return stressy;
863  }
864 
865 private:
866 #ifdef AMREX_USE_FLOAT
867  const amrex::Real eps = amrex::Real(1e-6);
868 #else
869  const amrex::Real eps = amrex::Real(1e-12);
870 #endif
871  const amrex::Real WSMIN = amrex::Real(0.1); // minimum wind speed
872 };
873 #endif
constexpr amrex::Real epsv
Definition: ERF_Constants.H:56
constexpr amrex::Real bogus_large_value
Definition: ERF_Constants.H:19
#define Rho_comp
Definition: ERF_IndexDefines.H:53
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:54
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:66
const int nx
Definition: ERF_InitCustomPertVels_CloudChamber.H:14
const int ny
Definition: ERF_InitCustomPertVels_CloudChamber.H:15
Real z0
Definition: ERF_InitCustomPertVels_ScalarAdvDiff.H:12
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(axis >=0 &&axis< AMREX_SPACEDIM, "prob.axis must be 0, 1 or 2")
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real most_rib_zeta_bracketed(const similarity_funs &sfuns, amrex::Real C, amrex::Real Rib, amrex::Real zeta0, amrex::Real tol)
Definition: ERF_MOSTUtils.H:330
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real most_bracket(amrex::Real C, amrex::Real psi)
Definition: ERF_MOSTUtils.H:255
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void most_flux_outputs(const most_data &mdata, bool spec_qflux, bool at_fold, amrex::Real zeta_fold, amrex::Real C, amrex::Real psi_h, amrex::Real ustar, amrex::Real zref, amrex::Real tm, amrex::Real tvm, amrex::Real qvm, amrex::Real qflux, amrex::Real &olen, amrex::Real &t_surf, amrex::Real &t_star, amrex::Real &q_surf, amrex::Real &q_star)
Definition: ERF_MOSTUtils.H:492
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool most_rib_zeta_is_root(const similarity_funs &sfuns, amrex::Real C, amrex::Real Rib, amrex::Real zeta, amrex::Real delta)
Definition: ERF_MOSTUtils.H:300
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real most_clamp_zeta(amrex::Real zeta, amrex::Real zeta_fold, bool &at_fold)
Definition: ERF_MOSTUtils.H:396
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:37
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:36
constexpr amrex::Real myhalf
Definition: ERF_NumericalConstants.H:41
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_wstar(const amrex::Real &ust, const amrex::Real &tst, const amrex::Real &qst, const amrex::Real &pblh, const amrex::Real &th, const amrex::Real &thv, const amrex::Real &qv=amrex::Real(0))
Definition: ERF_Wstar.H:27
@ ustar
Definition: ERF_SLM.H:28
@ qstar
Definition: ERF_SLM.H:30
@ tstar
Definition: ERF_SLM.H:29
@ rho
Definition: ERF_Kessler.H:25
@ theta
Definition: ERF_Kessler.H:26
@ qv
Definition: ERF_Kessler.H:31
EB surface-layer model for adiabatic constant-roughness fluxes.
Definition: ERF_EBMOSTStress.H:14
AMREX_GPU_DEVICE AMREX_FORCE_INLINE void iterate_flux(const int &i, const int &j, const int &k, const int &, const amrex::Array4< const amrex::Real > &zref_arr, const amrex::Array4< const amrex::Real > &z0_arr, const amrex::Array4< const amrex::Real > &umm_arr, const amrex::Array4< const amrex::Real > &, const amrex::Array4< const amrex::Real > &, const amrex::Array4< const amrex::Real > &, const amrex::Array4< amrex::Real > &u_star_arr, const amrex::Array4< amrex::Real > &, const amrex::Array4< amrex::Real > &t_star_arr, const amrex::Array4< amrex::Real > &q_star_arr, const amrex::Array4< amrex::Real > &, const amrex::Array4< amrex::Real > &, const amrex::Array4< amrex::Real > &olen_arr, const amrex::Array4< amrex::Real > &, const amrex::Array4< amrex::Real > &, const amrex::Array4< amrex::Real > &, const amrex::Array4< amrex::Real > &) const
Populate neutral MOST flux scales for an adiabatic EB surface.
Definition: ERF_EBMOSTStress.H:31
adiabatic_eb(amrex::Real Tflux, amrex::Real Qvflux)
Construct an adiabatic EB flux functor.
Definition: ERF_EBMOSTStress.H:20
most_data mdata
Definition: ERF_EBMOSTStress.H:61
similarity_funs sfuns
Definition: ERF_EBMOSTStress.H:62
EB implementation of the Moeng surface-flux formulation.
Definition: ERF_EBMOSTStress.H:327
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real compute_u_flux(int i, int j, int k, const amrex::Array4< const amrex::Real > &cons_arr, const amrex::Array4< const amrex::Real > &velx_arr, const amrex::Array4< const amrex::Real > &vely_arr, const amrex::Array4< const amrex::Real > &velz_arr, const amrex::Array4< const amrex::Real > &umm_arr, const amrex::Array4< const amrex::Real > &um_arr, const amrex::Array4< const amrex::Real > &u_star_arr, const amrex::Array4< const amrex::Real > &u_vfrac_arr, const amrex::Array4< const amrex::Real > &v_vfrac_arr, const amrex::Array4< const amrex::Real > &w_vfrac_arr, const amrex::Array4< const amrex::Real > &cc_vfrac_arr, const amrex::Array4< const amrex::EBCellFlag > &cc_flag_arr, const amrex::Array4< const amrex::Real > &bnorm_arr, int idir=0) const
Compute the EB x-momentum stress on a staggered face.
Definition: ERF_EBMOSTStress.H:457
const amrex::Real WSMIN
Definition: ERF_EBMOSTStress.H:871
moeng_flux_eb()
Construct a Moeng EB flux functor.
Definition: ERF_EBMOSTStress.H:329
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real compute_t_flux(const int &i, const int &j, const int &k, const amrex::Array4< const amrex::Real > &cons_arr, const amrex::Array4< const amrex::Real > &velx_arr, const amrex::Array4< const amrex::Real > &vely_arr, const amrex::Array4< const amrex::Real > &velz_arr, const amrex::Array4< const amrex::Real > &umm_arr, const amrex::Array4< const amrex::Real > &tm_arr, const amrex::Array4< const amrex::Real > &u_star_arr, const amrex::Array4< const amrex::Real > &t_star_arr, const amrex::Array4< const amrex::Real > &t_surf_arr, const amrex::Array4< const amrex::Real > &u_vfrac_arr, const amrex::Array4< const amrex::Real > &v_vfrac_arr, const amrex::Array4< const amrex::Real > &w_vfrac_arr, const amrex::Array4< const amrex::Real > &bnorm_arr) const
Compute the EB temperature flux at a cell-centered cut-cell surface.
Definition: ERF_EBMOSTStress.H:386
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real compute_v_flux(int i, int j, int k, const amrex::Array4< const amrex::Real > &cons_arr, const amrex::Array4< const amrex::Real > &velx_arr, const amrex::Array4< const amrex::Real > &vely_arr, const amrex::Array4< const amrex::Real > &velz_arr, const amrex::Array4< const amrex::Real > &umm_arr, const amrex::Array4< const amrex::Real > &vm_arr, const amrex::Array4< const amrex::Real > &u_star_arr, const amrex::Array4< const amrex::Real > &u_vfrac_arr, const amrex::Array4< const amrex::Real > &v_vfrac_arr, const amrex::Array4< const amrex::Real > &w_vfrac_arr, const amrex::Array4< const amrex::Real > &cc_vfrac_arr, const amrex::Array4< const amrex::EBCellFlag > &cc_flag_arr, const amrex::Array4< const amrex::Real > &bnorm_arr, int idir=0) const
Compute the EB y-momentum stress on a staggered face.
Definition: ERF_EBMOSTStress.H:663
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real compute_q_flux(const int &i, const int &j, const int &k, const amrex::Array4< const amrex::Real > &cons_arr, const amrex::Array4< const amrex::Real > &velx_arr, const amrex::Array4< const amrex::Real > &vely_arr, const amrex::Array4< const amrex::Real > &umm_arr, const amrex::Array4< const amrex::Real > &qvm_arr, const amrex::Array4< const amrex::Real > &u_star_arr, const amrex::Array4< const amrex::Real > &q_star_arr, const amrex::Array4< const amrex::Real > &q_surf_arr, const amrex::Array4< const amrex::Real > &u_vfrac_arr, const amrex::Array4< const amrex::Real > &v_vfrac_arr) const
Compute the EB moisture flux at a cell-centered cut-cell surface.
Definition: ERF_EBMOSTStress.H:335
const amrex::Real eps
Definition: ERF_EBMOSTStress.H:869
Definition: ERF_MOSTUtils.H:530
bool extrapolated
whether the last update returned an extrapolated value
Definition: ERF_MOSTUtils.H:564
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real update(amrex::Real u_new, int iter)
Definition: ERF_MOSTUtils.H:540
Definition: ERF_MOSTUtils.H:13
amrex::Real surf_moist_flux
Moisture flux.
Definition: ERF_MOSTUtils.H:19
amrex::Real kappa
von Karman constant
Definition: ERF_MOSTUtils.H:16
amrex::Real gravity
Acceleration due to gravity (m/s^2)
Definition: ERF_MOSTUtils.H:17
const amrex::Real Bjr_beta
Definition: ERF_MOSTUtils.H:32
amrex::Real surf_temp_flux
Heat flux TODO: decide whether this is <θ'w'> or <θv'w'> under moist conditions.
Definition: ERF_MOSTUtils.H:18
Definition: ERF_MOSTUtils.H:67
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_psi_m(amrex::Real zeta) const
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:104
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_zeta_fold(amrex::Real C) const
Definition: ERF_MOSTUtils.H:227
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_psi_h(amrex::Real zeta) const
Definition: ERF_MOSTUtils.H:151
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real calc_psi_m2(amrex::Real zeta) const
Definition: ERF_MOSTUtils.H:79
EB surface-layer model with prescribed surface fluxes and constant roughness.
Definition: ERF_EBMOSTStress.H:215
const amrex::Real WSMIN
Definition: ERF_EBMOSTStress.H:322
similarity_funs sfuns
Definition: ERF_EBMOSTStress.H:319
const amrex::Real tol
Definition: ERF_EBMOSTStress.H:320
most_data mdata
Definition: ERF_EBMOSTStress.H:317
AMREX_GPU_DEVICE AMREX_FORCE_INLINE void iterate_flux(const int &i, const int &j, const int &k, const int &max_iters, const amrex::Array4< const amrex::Real > &zref_arr, const amrex::Array4< const amrex::Real > &z0_arr, const amrex::Array4< const amrex::Real > &umm_arr, const amrex::Array4< const amrex::Real > &tm_arr, const amrex::Array4< const amrex::Real > &tvm_arr, const amrex::Array4< const amrex::Real > &qvm_arr, const amrex::Array4< amrex::Real > &u_star_arr, const amrex::Array4< amrex::Real > &w_star_arr, const amrex::Array4< amrex::Real > &t_star_arr, const amrex::Array4< amrex::Real > &q_star_arr, const amrex::Array4< amrex::Real > &t_surf_arr, const amrex::Array4< amrex::Real > &q_surf_arr, const amrex::Array4< amrex::Real > &olen_arr, const amrex::Array4< amrex::Real > &pblh_arr, const amrex::Array4< amrex::Real > &, const amrex::Array4< amrex::Real > &, const amrex::Array4< amrex::Real > &) const
Iterate MOST stability functions and update implied surface values.
Definition: ERF_EBMOSTStress.H:235
const amrex::Real alpha
Definition: ERF_EBMOSTStress.H:321
bool spec_qflux
Definition: ERF_EBMOSTStress.H:318
surface_flux_eb(amrex::Real Tflux, amrex::Real Qvflux, bool cons_qflux)
Construct a prescribed-flux EB functor.
Definition: ERF_EBMOSTStress.H:222
EB surface-layer model with prescribed surface temperature and constant roughness.
Definition: ERF_EBMOSTStress.H:68
AMREX_GPU_DEVICE AMREX_FORCE_INLINE void iterate_flux(const int &i, const int &j, const int &k, const int &max_iters, const amrex::Array4< const amrex::Real > &zref_arr, const amrex::Array4< const amrex::Real > &z0_arr, const amrex::Array4< const amrex::Real > &umm_arr, const amrex::Array4< const amrex::Real > &tm_arr, const amrex::Array4< const amrex::Real > &tvm_arr, const amrex::Array4< const amrex::Real > &qvm_arr, const amrex::Array4< amrex::Real > &u_star_arr, const amrex::Array4< amrex::Real > &w_star_arr, const amrex::Array4< amrex::Real > &t_star_arr, const amrex::Array4< amrex::Real > &q_star_arr, const amrex::Array4< amrex::Real > &t_surf_arr, const amrex::Array4< amrex::Real > &q_surf_arr, const amrex::Array4< amrex::Real > &olen_arr, const amrex::Array4< amrex::Real > &pblh_arr, const amrex::Array4< amrex::Real > &, const amrex::Array4< amrex::Real > &, const amrex::Array4< amrex::Real > &) const
Iterate MOST stability functions and update surface flux scales.
Definition: ERF_EBMOSTStress.H:88
const amrex::Real tol
Definition: ERF_EBMOSTStress.H:208
const amrex::Real alpha
Definition: ERF_EBMOSTStress.H:209
const amrex::Real WSMIN
Definition: ERF_EBMOSTStress.H:210
similarity_funs sfuns
Definition: ERF_EBMOSTStress.H:207
surface_temp_eb(amrex::Real Tflux, amrex::Real Qvflux, bool cons_qflux)
Construct a prescribed-temperature EB flux functor.
Definition: ERF_EBMOSTStress.H:75
bool spec_qflux
Definition: ERF_EBMOSTStress.H:206
most_data mdata
Definition: ERF_EBMOSTStress.H:205