ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_ImmersedWallStability.H
Go to the documentation of this file.
1 #ifndef ERF_IMMERSED_WALL_STABILITY_H_
2 #define ERF_IMMERSED_WALL_STABILITY_H_
3 
4 #include <AMReX_Algorithm.H>
5 #include <AMReX_GpuQualifiers.H>
6 #include <AMReX_REAL.H>
7 
8 #include <cmath>
9 
10 /**
11  * Bounds on the stability estimate of the immersed-forcing wall law. Without them a zero
12  * tangential wind one cell from the wall gives u* = 0, an Obukhov length of zero and zeta = z/0
13  * (erf-model/ERF#4016).
14  *
15  * Always on:
16  * - An Obukhov length derived from u* and the heat flux is held at |L| >= z_ref / 100, and every
17  * zeta = z / L at |zeta| <= 100, as on flat ground (ERF_MOSTStress.H). A prescribed
18  * erf.if_Olen is used as given: only its zeta is held, so one input means one L on every face
19  * and at every height.
20  *
21  * Opt-in (WRF's revised surface layer, sf_sfclayrev):
22  * - erf.if_stability_wind_floor (default 0, WRF and the flat-ground WSMIN use 0.1 m/s) floors the
23  * wind behind the friction velocity of the stability estimate.
24  * - erf.if_psi_cap_factor (default 1, WRF uses 0.9) caps psi_m at factor ln(z / z0) in the
25  * velocity target and before it forms the friction velocity of the momentum law. The
26  * temperature forcing keeps caps of ln(z / z0): its surface-flux branch forms theta* from an
27  * Obukhov length that is not consistent with u*, which those caps keep from reaching the target
28  * in strongly unstable air.
29  */
30 namespace ib_stability
31 {
32  /** Largest |zeta| = |z / L| the wall law uses. */
33  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
34  amrex::Real zeta_max () noexcept { return amrex::Real(100.0); }
35 
36  /** The wind speed the stability estimate uses: the speed, floored at wind_floor (>= 0). */
37  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
38  amrex::Real floored_wind (amrex::Real speed, amrex::Real wind_floor) noexcept
39  {
40  return amrex::max(speed, wind_floor);
41  }
42 
43  /**
44  * An Obukhov length derived from u* and the heat flux, with |L| no smaller than
45  * z_ref / zeta_max(), so that z / L lies within +-zeta_max() for every z <= z_ref and the
46  * zero L of a zero u* is never divided by. The sign is kept: L = -0 is the unstable bound and
47  * L = +0 the stable one. Unchanged, bit for bit, when |L| >= z_ref / zeta_max(). Not for a
48  * prescribed L, whose bound would then depend on the local cell size; see bounded_zeta.
49  */
50  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
52  {
53  return std::copysign(amrex::max(std::abs(Olen), z_ref / zeta_max()), Olen);
54  }
55 
56  /**
57  * zeta = z / L held within +-zeta_max(), for an L that is not zero (a prescribed erf.if_Olen,
58  * which start-up refuses at 0, or one from bounded_obukhov_length). Unchanged, bit for bit,
59  * when |z / L| <= zeta_max(); a NaN stays NaN.
60  */
61  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
63  {
64  // z / L first in both, so a NaN propagates instead of becoming a bound
65  return amrex::min(amrex::max(z / Olen, -zeta_max()), zeta_max());
66  }
67 
68  /**
69  * The largest psi (momentum or heat) the wall law uses at height z: factor ln(z / z0) for
70  * 0 < factor <= 1, and never more than ln(z / z0). For z > z0 a factor below 1 keeps
71  * ln(z / z0) - psi at no less than (1 - factor) ln(z / z0) > 0, so strongly unstable air
72  * still carries momentum and heat between the wall and the cell above; a cap of ln(z / z0)
73  * itself makes the target zero (momentum) or the value above (heat). For z <= z0, where the
74  * log law does not hold, the cap stays ln(z / z0).
75  */
76  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
78  {
79  const amrex::Real ln = std::log(z / z0);
80  return amrex::min(factor * ln, ln);
81  }
82 
83  /** psi held at or below psi_cap(z, z0, factor). */
84  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
86  {
87  return amrex::min(psi, psi_cap(z, z0, factor));
88  }
89 
90  /**
91  * psi_m in the friction velocity u* = U kappa / (ln(z / z0) - psi_m) at height z: held at or
92  * below factor ln(z / z0), as WRF caps PSIM before it forms UST, so the denominator stays at
93  * least (1 - factor) ln(z / z0) > 0 and strongly unstable air keeps a positive u*. Uncapped for
94  * factor = 1 (a cap of ln(z / z0) would zero the denominator) and for z <= z0, where the log law
95  * does not hold; there the wall law's u* clamp handles a denominator of either sign.
96  */
97  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
99  {
100  const amrex::Real ln = std::log(z / z0);
101  return (factor < amrex::Real(1.0) && ln > amrex::Real(0.0)) ? amrex::min(psi_m, factor * ln) : psi_m;
102  }
103 
104  /**
105  * The friction velocity held within [0, 2] m/s, a NaN going to 0: the wall law's guard
106  * against a log-law denominator that cancels or changes sign.
107  */
108  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
110  {
111  if (!(ustar > amrex::Real(0.0) && !std::isnan(ustar))) { ustar = amrex::Real(0.0); }
112  if (!(ustar < amrex::Real(2.0) && !std::isnan(ustar))) { ustar = amrex::Real(2.0); }
113  return ustar;
114  }
115 }
116 
117 #endif
Real z0
Definition: ERF_InitCustomPertVels_ScalarAdvDiff.H:8
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ ustar
Definition: ERF_SLM.H:28
Definition: ERF_ImmersedWallStability.H:31
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real psi_cap(amrex::Real z, amrex::Real z0, amrex::Real factor) noexcept
Definition: ERF_ImmersedWallStability.H:77
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real bounded_zeta(amrex::Real z, amrex::Real Olen) noexcept
Definition: ERF_ImmersedWallStability.H:62
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real floored_wind(amrex::Real speed, amrex::Real wind_floor) noexcept
Definition: ERF_ImmersedWallStability.H:38
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real capped_psi(amrex::Real psi, amrex::Real z, amrex::Real z0, amrex::Real factor) noexcept
Definition: ERF_ImmersedWallStability.H:85
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real bounded_obukhov_length(amrex::Real Olen, amrex::Real z_ref) noexcept
Definition: ERF_ImmersedWallStability.H:51
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real psi_m_for_ustar(amrex::Real psi_m, amrex::Real z, amrex::Real z0, amrex::Real factor) noexcept
Definition: ERF_ImmersedWallStability.H:98
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real clamped_ustar(amrex::Real ustar) noexcept
Definition: ERF_ImmersedWallStability.H:109
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real zeta_max() noexcept
Definition: ERF_ImmersedWallStability.H:34