ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_RANSClosure.H
Go to the documentation of this file.
1 /** \file ERF_RANSClosure.H
2  *
3  * Closure relations of the one-equation k RANS model of
4  * Axell & Liungman (2001), Environ. Fluid Mech. 1, 71-106 (AL01), as
5  * device-inline functions so that ComputeTurbulentViscosityRANS and the
6  * unit tests evaluate exactly the same expressions.
7  */
8 #ifndef ERF_RANS_CLOSURE_H_
9 #define ERF_RANS_CLOSURE_H_
10 
11 #include <cmath>
12 #include <limits>
13 #include <AMReX_REAL.H>
14 #include <AMReX_GpuQualifiers.H>
15 #include <AMReX_Algorithm.H>
16 #include "ERF_NumericalConstants.H"
17 
18 namespace AL01 {
19 
20 /** Geometric length scale with the harmonic cap (AL01 Eq. 22 plus limiter).
21  * @param l_g_raw kappa times (wall distance + z0)
22  * @param l_g_max upper bound, about kappa times 0.1 zi
23  */
24 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
26 {
27  return l_g_max * l_g_raw / (l_g_max + l_g_raw);
28 }
29 
30 /** Burchard & Petersen smoothing of Rt below Rt_crit, which maps
31  * (-inf, Rt_crit) onto (Rt_min, Rt_crit) so the stability functions stay
32  * finite in strongly unstable air:
33  * Rt_s = Rt - (Rt - Rt_crit)^2 / (Rt + Rt_min - 2 Rt_crit).
34  * Written with x = Rt - Rt_crit and a = Rt_min - Rt_crit as
35  * Rt_s = Rt_crit + a x / (x + a),
36  * which is the same function without the cancellation of two O(|Rt|)
37  * terms that returned garbage for |Rt| beyond about 1e15 (tiny k under a
38  * strong unstable N^2). Limits: Rt_crit as x -> 0, Rt_min as x -> -inf. */
39 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
41 {
42  if (Rt >= Rt_crit) { return Rt; }
43  const amrex::Real x = Rt - Rt_crit; // < 0
44  const amrex::Real a = Rt_min - Rt_crit; // < 0 by input validation
45  return Rt_crit + a * x / (x + a);
46 }
47 
48 /** Turbulent length scale: neutral (l_g), stable (Eq. 26) or unstable
49  * (Eq. 28).
50  *
51  * Unstable: Eq. 28 is Eq. 26 rewritten with the dissipation of Eq. 19 on
52  * the right-hand side. Iterating it (dissipation from the new length,
53  * length from the new Rt) is the fixed-point map of Eq. 26 with N^2 < 0,
54  * which has no fixed point once l_g^2 |N^2| exceeds Cb^2 k (AL01, p. 78),
55  * so the length grows without bound in strongly convective, weakly
56  * turbulent air. Here Eq. 28 is evaluated once with the dissipation of the
57  * geometric length and the Burchard & Petersen smoothed Rt, as in the
58  * Kynema KLAxell implementation, which bounds the unstable length by
59  * l_g sqrt(1 + Cmu0^6 |Rt_min| / Cb^2), about 1.31 l_g for the defaults.
60  *
61  * @param l_g capped geometric length
62  * @param N2 Brunt-Vaisala frequency squared
63  * @param tke turbulent kinetic energy (floored, > 0)
64  * @param Cmu0_pow3 Cmu0 cubed
65  * @param inv_Cb_sq one over Cb squared
66  * @param Rt_crit, Rt_min smoothing parameters
67  * @param eps threshold below which N2 counts as neutral
68  */
69 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
71  amrex::Real Cmu0_pow3, amrex::Real inv_Cb_sq,
72  amrex::Real Rt_crit, amrex::Real Rt_min,
73  amrex::Real eps)
74 {
76  if (std::abs(N2) <= eps) {
77  length = l_g;
78  } else if (N2 > eps) {
79  // Stable (AL01, Eqn. 26)
80  length = std::sqrt(one /
81  (one / (l_g * l_g) + inv_Cb_sq * N2 / tke));
82  } else {
83  // Unstable (AL01, Eqn. 28) with Rt from the geometric length
84  // (Eq. 29 with Eq. 19: Rt = l_g^2 N^2 / (k Cmu0^6)), smoothed
85  const amrex::Real Rt = smooth_Rt(l_g*l_g * N2 / (tke * Cmu0_pow3 * Cmu0_pow3),
86  Rt_crit, Rt_min);
87  length = l_g * std::sqrt(one - Cmu0_pow3*Cmu0_pow3 * inv_Cb_sq * Rt);
88  }
89  return length;
90 }
91 
92 /** Upper bound of the unstable length for given smoothing parameters. */
93 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
95  amrex::Real inv_Cb_sq, amrex::Real Rt_min)
96 {
97  return l_g * std::sqrt(one - Cmu0_pow3*Cmu0_pow3 * inv_Cb_sq * Rt_min);
98 }
99 
100 /** Dissipation rate per unit volume, rho Cmu0^3 k^1.5 / L (AL01 Eq. 19). */
101 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
104 {
105  return rho * Cmu0_pow3 * std::pow(tke,amrex::Real(1.5)) / length;
106 }
107 
108 /** Turbulent Richardson number, Eq. 29 combined with Eq. 19:
109  * Rt = k^2 N^2 / eps^2 = L^2 N^2 / (k Cmu0^6). */
110 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
112  amrex::Real Cmu0_pow3)
113 {
114  return length*length * N2 / (tke * Cmu0_pow3 * Cmu0_pow3);
115 }
116 
117 
118 /** Momentum stability function (AL01 Eq. 31). */
119 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
121 {
122  return (Cmu0 + amrex::Real(0.108)*Rt)
123  / (one + amrex::Real(0.308)*Rt + amrex::Real(0.00837)*Rt*Rt);
124 }
125 
126 /** Scalar stability function (AL01 Eq. 32). */
127 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
129 {
130  return Cmu0 / (1 + amrex::Real(0.277)*Rt);
131 }
132 
133 /** Lowest admissible Rt_min (exclusive). The pole of cmu is the larger root
134  * of 1 + 0.308 Rt + 0.00837 Rt^2,
135  * (-0.308 + sqrt(0.308^2 - 4 * 0.00837)) / (2 * 0.00837) = -3.5986889850,
136  * and the pole of cmu' (-1/0.277 = -3.6101) lies below it. Just below the
137  * pole of cmu its denominator is negative, so cmu and the eddy viscosity are
138  * negative (down to the numerator's zero, -Cmu0/0.108). The literal is the
139  * root rounded toward zero, which keeps it above the pole in both double and
140  * single precision. Values just above it are accepted but give a very large
141  * cmu (about 980 at -3.598). */
143 
144 /** Zero of the numerator of cmu, -Cmu0/0.108 (-5.15 for the default Cmu0).
145  * Below it cmu is negative even above the pole, so Rt_min must also lie
146  * above it; this is the tighter of the two limits when Cmu0 < 0.3887. */
147 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
149 {
150  return -Cmu0 / amrex::Real(0.108);
151 }
152 
153 /** Realizability cap on the eddy viscosity (erf.rans_realizability = C_r > 0):
154  *
155  * nu_t <- min(nu_t, C_r k / S), S = sqrt(2 S_ij S_ij).
156  *
157  * This is the form of the SST limiter. The closure gives
158  * nu_t S / k = sqrt(cmu Cmu0^3 P / eps) (AL01 Eqs. 11 and 19), which in a
159  * neutral equilibrium layer (cmu = Cmu0, P = eps) is Cmu0^2 = 0.3094, so
160  * C_r = Cmu0^2 leaves neutral equilibrium shear untouched and acts where
161  * P / eps > Cmu0 / cmu, as in the shear layer that leaves a crest. The cap
162  * on nu_t carries over to nu_t' (the scalar diffusivity keeps the ratio
163  * cmu'/cmu of the uncapped closure).
164  *
165  * @param nut uncapped eddy viscosity cmu sqrt(k) L
166  * @param tke turbulent kinetic energy k (already floored)
167  * @param S strain-rate magnitude sqrt(2 S_ij S_ij)
168  * @param Cr cap constant C_r > 0 (the caller skips the cap, and the strain
169  * read, when erf.rans_realizability is 0)
170  * @param ratio out: nu_t / (C_r k / S), the plotfile diagnostic cap_ratio;
171  * above 1 the cap is active
172  * @return the capped eddy viscosity
173  *
174  * S is floored at machine epsilon before the division so the cap evaluates
175  * (to a value far above nu_t) without a divide-by-zero trap in cells of
176  * uniform flow; the compiler may evaluate both sides of a select.
177  */
178 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
180  amrex::Real Cr, amrex::Real& ratio)
181 {
183  AMREX_ASSERT(Cr > amrex::Real(0));
184  const amrex::Real cap = Cr * tke / amrex::max(S, eps);
185  ratio = nut / cap;
186  return amrex::min(nut, cap);
187 }
188 
189 } // namespace AL01
190 
191 #endif
const Real length
Definition: ERF_InitCustomPert_AnelasticWallDiffusion.H:16
Dimensionless numeric literals and pure mathematical constants.
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:37
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_RANSClosure.H:18
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real cmu_prime(amrex::Real Rt, amrex::Real Cmu0)
Definition: ERF_RANSClosure.H:128
constexpr amrex::Real Rt_min_lower_bound
Definition: ERF_RANSClosure.H:142
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real turb_length(amrex::Real l_g, amrex::Real N2, amrex::Real tke, amrex::Real Cmu0_pow3, amrex::Real inv_Cb_sq, amrex::Real Rt_crit, amrex::Real Rt_min, amrex::Real eps)
Definition: ERF_RANSClosure.H:70
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real richardson(amrex::Real length, amrex::Real N2, amrex::Real tke, amrex::Real Cmu0_pow3)
Definition: ERF_RANSClosure.H:111
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real realizable_nut(amrex::Real nut, amrex::Real tke, amrex::Real S, amrex::Real Cr, amrex::Real &ratio)
Definition: ERF_RANSClosure.H:179
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real cmu_numerator_root(amrex::Real Cmu0)
Definition: ERF_RANSClosure.H:148
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real cmu(amrex::Real Rt, amrex::Real Cmu0)
Definition: ERF_RANSClosure.H:120
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real smooth_Rt(amrex::Real Rt, amrex::Real Rt_crit, amrex::Real Rt_min)
Definition: ERF_RANSClosure.H:40
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real geom_length(amrex::Real l_g_raw, amrex::Real l_g_max)
Definition: ERF_RANSClosure.H:25
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real unstable_length_bound(amrex::Real l_g, amrex::Real Cmu0_pow3, amrex::Real inv_Cb_sq, amrex::Real Rt_min)
Definition: ERF_RANSClosure.H:94
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real dissipation(amrex::Real rho, amrex::Real Cmu0_pow3, amrex::Real tke, amrex::Real length)
Definition: ERF_RANSClosure.H:102
@ rho
Definition: ERF_Kessler.H:25
constexpr int S
Definition: ERF_TwoStreamColumn.H:604
real(c_double), parameter epsilon
Definition: ERF_module_model_constants.F90:12