ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_TerrainDiffusionLimits.H
Go to the documentation of this file.
1 /** \file ERF_TerrainDiffusionLimits.H */
2 
3 #ifndef ERF_TERRAIN_DIFFUSION_LIMITS_H_
4 #define ERF_TERRAIN_DIFFUSION_LIMITS_H_
5 
6 #include <AMReX_Array4.H>
7 #include <AMReX_Extension.H>
8 #include <AMReX_GpuQualifiers.H>
9 #include <AMReX_Algorithm.H>
10 #include <AMReX_Array.H>
11 #include <AMReX_Math.H>
12 #include <AMReX_REAL.H>
13 
14 #include "ERF_NumericalConstants.H"
15 #include "ERF_IndexDefines.H"
16 
17 #include <cmath>
18 
19 /**
20  * Terrain drop across one cell of a terrain-fitted mesh.
21  *
22  * dx_drop and dy_drop are the height differences across the cell along the
23  * coordinate surfaces, each the mean of the absolute differences on the four
24  * cell edges in that direction; dz is the physical thickness of the cell, the
25  * mean of its four vertical edges (detJ * dz at the cell center). All three
26  * are in metres and read only the eight nodes of the cell.
27  */
29 {
33 };
34 
35 /**
36  * Compute the terrain drops across cell (i,j,k) from the nodal heights.
37  *
38  * @param[in] i,j,k cell-centered indices
39  * @param[in] z_nd nodal physical heights
40  */
41 AMREX_GPU_HOST_DEVICE
42 AMREX_FORCE_INLINE
44 ComputeTerrainCellDrops (int i, int j, int k,
45  const amrex::Array4<const amrex::Real>& z_nd) noexcept
46 {
47  using amrex::Math::abs;
49  d.dx_drop = fourth * ( abs(z_nd(i+1,j ,k ) - z_nd(i,j ,k ))
50  + abs(z_nd(i+1,j+1,k ) - z_nd(i,j+1,k ))
51  + abs(z_nd(i+1,j ,k+1) - z_nd(i,j ,k+1))
52  + abs(z_nd(i+1,j+1,k+1) - z_nd(i,j+1,k+1)) );
53  d.dy_drop = fourth * ( abs(z_nd(i ,j+1,k ) - z_nd(i ,j,k ))
54  + abs(z_nd(i+1,j+1,k ) - z_nd(i+1,j,k ))
55  + abs(z_nd(i ,j+1,k+1) - z_nd(i ,j,k+1))
56  + abs(z_nd(i+1,j+1,k+1) - z_nd(i+1,j,k+1)) );
57  d.dz = fourth * ( (z_nd(i ,j ,k+1) - z_nd(i ,j ,k))
58  + (z_nd(i+1,j ,k+1) - z_nd(i+1,j ,k))
59  + (z_nd(i ,j+1,k+1) - z_nd(i ,j+1,k))
60  + (z_nd(i+1,j+1,k+1) - z_nd(i+1,j+1,k)) );
61  return d;
62 }
63 
64 /**
65  * Slope factor alpha = max( sqrt(dx_drop^2 + dy_drop^2) / dz, 1 ) of a cell:
66  * the terrain drop across one cell measured in cell thicknesses, which is
67  * h * Delta_x / Delta_z with h the physical coordinate slope. This is the
68  * factor of WRF's Smagorinsky-2D slope limiter (dyn_em/module_diffusion_em.F,
69  * smag2d_km, diff_opt = 2). WRF averages |z_x| at the two x-faces and the two
70  * w-levels of the cell and multiplies by dx / msftx; here the drop is taken on
71  * the four x-edges of the cell (ERF heights are nodal) and carries no map
72  * factor, so that alpha is exactly h * Delta_x / Delta_z with the physical
73  * spacing. The two agree when the map factor is 1.
74  */
75 AMREX_GPU_HOST_DEVICE
76 AMREX_FORCE_INLINE
79 {
80  const amrex::Real a = std::sqrt(d.dx_drop*d.dx_drop + d.dy_drop*d.dy_drop) / d.dz;
81  return amrex::max(a, amrex::Real(1.0));
82 }
83 
84 /** Deformation threshold speed of WRF's slope limiter, def_limit = max(10/Delta_h, 1e-3) (m/s). */
86 /** Floor of WRF's deformation threshold (1/s). */
88 
89 /**
90  * Apply the opt-in limits of WRF's smag2d_km to a Smagorinsky-2D horizontal
91  * kinematic eddy viscosity, in WRF's order:
92  * 1. the cap nu <= kh_cap * Delta_h (only if kh_cap > 0; WRF uses 10 m/s);
93  * 2. the slope limiter (only if use_slope):
94  * nu /= alpha^2 if |D_h| > max(10/Delta_h, 1e-3),
95  * nu /= alpha otherwise.
96  * |D_h| is the horizontal deformation sqrt((u_x - v_y)^2 + (u_y + v_x)^2),
97  * which equals ERF's sqrt(2 S_mn S_mn) of ComputeSmnSmn2D and WRF's
98  * sqrt(def2). Delta_h = sqrt(dx/m_x * dy/m_y), WRF's mlen_h.
99  *
100  * @param[in] nu Cs^2 Delta_h^2 |D_h| (m^2/s)
101  * @param[in] strain |D_h| (1/s)
102  * @param[in] DeltaH horizontal filter width (m)
103  * @param[in] alpha slope factor from TerrainSlopeFactor (>= 1)
104  * @param[in] kh_cap cap speed (m/s); <= 0 leaves nu uncapped
105  * @param[in] use_slope apply the slope limiter
106  */
107 AMREX_GPU_HOST_DEVICE
108 AMREX_FORCE_INLINE
111  amrex::Real alpha, amrex::Real kh_cap, bool use_slope) noexcept
112 {
113  if (kh_cap > zero) {
114  const amrex::Real nu_max = kh_cap * DeltaH;
115  nu = (nu < nu_max) ? nu : nu_max;
116  }
117  if (use_slope) {
118  const amrex::Real def_limit = amrex::max(amrex::Real(smag2d_def_limit_speed) / DeltaH,
120  nu = (strain > def_limit) ? nu / (alpha*alpha) : nu / alpha;
121  }
122  return nu;
123 }
124 
125 /**
126  * Explicit diffusion rates of one cell, for the diffusive time-step estimate
127  * dt * rate <= Fourier limit (1/2 for forward Euler in 3-D; the three-stage
128  * Runge-Kutta scheme's real-axis bound is about 2.5 / 4 = 0.63).
129  *
130  * Momentum: the largest of the three component rows,
131  * u: mu_h (2 a + b) + e_uv mu_v / dz^2 + mu_v sqrt(a c)
132  * v: mu_h (a + 2 b) + e_uv mu_v / dz^2 + mu_v sqrt(b c)
133  * w: mu_v (a + b) + 2 mu_v / dz^2 + mu_v (sqrt(a c) + sqrt(b c)),
134  * with c = 1/dz^2, plus 2 mu_p h^2 / dz^2 for the terrain-metric part. The vertical
135  * diffusion of w is always explicit; its horizontal diffusion uses mu_v: tau31 and tau32
136  * carry the same edge-averaged mu_v as tau13 and tau23. The sqrt terms are the u-w and v-w cross derivatives (dw/dx in tau13, du/dz in
137  * tau31, ...), which stay explicit whether or not the implicit solve takes the second
138  * vertical derivative; they are always counted, since with dz > dx/m they exceed the
139  * vertical term (dx = 100 m, dz = 500 m: five times). (The expansion
140  * rate in tau11 also couples u to dw/dz, with mu_h; that is covered by "an estimate when
141  * mu_h != mu_v" below.) The metric term is an upper bound: the projected horizontal
142  * stresses of the u and v fluxes carry mu_h (ComputeStressVarVisc_T), the w flux mu_v, hence
143  * mu_p = max(w_metric mu_h, mu_v).
144  *
145  * Scalar: K_h (a + b) + w_metric K_h h^2 / dz^2 + e K_v / dz^2 (the K_h h^2 part is
146  * TerrainDiffusionGz).
147  *
148  * w_metric weights the K_h metric term: 1 when it is explicit, and with
149  * erf.implicit_terrain_metric the component's explicit fraction e, since its compact form
150  * K_h M d2/dz2 is then in the implicit solve (u, v and the scalars; w is not). The difference
151  * between the averaged and the compact forms stays explicit and is not counted, so with the
152  * option the rate is an estimate.
153  *
154  * a = (m_x / dx)^2, b = (m_y / dy)^2 and h^2 = (m_x dx_drop / dx)^2 +
155  * (m_y dy_drop / dy)^2 is the squared physical slope; on a mesh without
156  * terrain pass h2 = 0. e is the explicit fraction of the vertical diffusion
157  * (ExplicitVerticalFraction): 0 when the implicit solve keeps every stage bounded,
158  * 1 otherwise. All diffusivities are dynamic (rho * nu); rates are in 1/s.
159  * The caller passes the largest diffusivities and the smallest density around the
160  * cell (NeighbourhoodMax, NeighbourhoodMinPositive), which bounds the row whatever
161  * face or edge averaging the operator uses.
162  */
163 AMREX_GPU_HOST_DEVICE
164 AMREX_FORCE_INLINE
168  amrex::Real e_uv, amrex::Real w_metric = one) noexcept
169 {
170  const amrex::Real xa = std::sqrt(a * dzinv2);
171  const amrex::Real xb = std::sqrt(b * dzinv2);
172  const amrex::Real r_u = mu_h * (two*a + b) + e_uv * mu_v * dzinv2 + mu_v * xa;
173  const amrex::Real r_v = mu_h * (a + two*b) + e_uv * mu_v * dzinv2 + mu_v * xb;
174  const amrex::Real r_w = mu_v * (a + b) + two * mu_v * dzinv2 + mu_v * (xa + xb);
175  const amrex::Real r_uv = (r_u > r_v) ? r_u : r_v;
176  const amrex::Real row = (r_uv > r_w) ? r_uv : r_w;
177  const amrex::Real mu_hm = w_metric * mu_h;
178  const amrex::Real mu_p = (mu_hm > mu_v) ? mu_hm : mu_v;
179  return ( row + two * mu_p * h2 * dzinv2 ) / rho;
180 }
181 
182 /**
183  * Largest value of component n over cell (i,j,k) and its 26 neighbours. The diffusion
184  * operators average the cell diffusivities to faces and edges, so a row of the operator
185  * never carries more than this. With NeighbourhoodMinPositive for the density and the
186  * coefficients frozen, the scalar rate is a Gershgorin bound on the centred interior stencil
187  * of the Cartesian operator (the higher-order one-sided gradients next to Dirichlet
188  * boundaries, ERF_ScalarDiffusion.H, whose row is about 4/3 larger, are not covered); for
189  * momentum it is a bound for
190  * uniform coefficients when mu_h = mu_v (tight on
191  * cubic cells) and an estimate otherwise, since the operator is then not symmetric.
192  * Needs one ghost cell.
193  */
194 AMREX_GPU_HOST_DEVICE
195 AMREX_FORCE_INLINE
197 NeighbourhoodMax (int i, int j, int k, int n, const amrex::Array4<const amrex::Real>& a) noexcept
198 {
199  amrex::Real m = a(i,j,k,n);
200  for (int kk = -1; kk <= 1; ++kk) {
201  for (int jj = -1; jj <= 1; ++jj) {
202  for (int ii = -1; ii <= 1; ++ii) {
203  const amrex::Real v = a(i+ii,j+jj,k+kk,n);
204  m = (v > m) ? v : m;
205  }}}
206  return m;
207 }
208 
209 /**
210  * Smallest positive value of component n over cell (i,j,k) and its 26 neighbours; ghost
211  * cells that hold no density (<= 0) are skipped. Returns `fallback` if none is positive.
212  */
213 AMREX_GPU_HOST_DEVICE
214 AMREX_FORCE_INLINE
216 NeighbourhoodMinPositive (int i, int j, int k, int n, const amrex::Array4<const amrex::Real>& a,
217  amrex::Real fallback) noexcept
218 {
219  amrex::Real m = fallback;
220  bool found = false;
221  for (int kk = -1; kk <= 1; ++kk) {
222  for (int jj = -1; jj <= 1; ++jj) {
223  for (int ii = -1; ii <= 1; ++ii) {
224  const amrex::Real v = a(i+ii,j+jj,k+kk,n);
225  if (v > zero && (!found || v < m)) { m = v; found = true; }
226  }}}
227  return m;
228 }
229 
230 /** Scalar counterpart of MomentumDiffusiveRate (see there). */
231 AMREX_GPU_HOST_DEVICE
232 AMREX_FORCE_INLINE
236  amrex::Real e_vert, amrex::Real w_metric = one) noexcept
237 {
238  return ( K_h * (a + b) + w_metric * K_h * h2 * dzinv2 + e_vert * K_v * dzinv2 ) / rho;
239 }
240 
241 /** Which components carry diffusion, and their explicit vertical fractions, for CellDiffusiveRates. */
243 {
244  bool variable_dz = false; // terrain-fitted or stretched mesh: dz and slope from z_nd
245  bool has_q = false; // moisture carried
246  bool has_ke = false; // turbulent kinetic energy carried
247  bool has_scalar = false; // advected scalar carried
248  bool implicit_metric = false; // erf.implicit_terrain_metric: K_h metric term weighted by e
250  // Eddy diffusivities are carried (k_arr is read only then)
251  bool has_eddy = true;
252  // Molecular diffusivities, added to the eddy ones in both directions: momentum (the
253  // dynamic viscosity), theta (alpha_T) and moisture and the advected scalar (alpha_C).
254  // Dynamic values, or with mol_times_rho kinematic ones that are multiplied by the density
255  // (erf.molec_diff_type = ConstantAlpha). KE has none.
257  bool mol_times_rho = false;
258 };
259 
260 /**
261  * Explicit diffusion rates of cell (i,j,k), momentum and scalars (1/s), as the diffusive
262  * time-step check reduces them: MomentumDiffusiveRate and ScalarDiffusiveRate with the largest
263  * diffusivities -- eddy plus molecular -- and the smallest positive density over the cell and
264  * its 26 neighbours. Both are zero in a cell without density (covered).
265  *
266  * @param[in] s_arr conserved state (Rho_comp), one ghost cell
267  * @param[in] k_arr eddy diffusivities (EddyDiff components), one ghost cell; read only when
268  * set.has_eddy
269  * @param[in] z_nd nodal heights (read only when set.variable_dz)
270  * @param[in] mf_mx, mf_my map factors of the cell
271  * @param[in] dxinv inverse cell sizes
272  */
273 AMREX_GPU_HOST_DEVICE
274 AMREX_FORCE_INLINE
275 void
276 CellDiffusiveRates (int i, int j, int k,
277  const amrex::Array4<const amrex::Real>& s_arr,
278  const amrex::Array4<const amrex::Real>& k_arr,
279  const amrex::Array4<const amrex::Real>& z_nd,
280  amrex::Real mf_mx, amrex::Real mf_my,
281  const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& dxinv,
282  const DiffusiveRateSettings& set,
283  amrex::Real& rate_mom, amrex::Real& rate_scal) noexcept
284 {
285  const amrex::Real ax = mf_mx * dxinv[0];
286  const amrex::Real ay = mf_my * dxinv[1];
287  amrex::Real dzinv = dxinv[2];
288  amrex::Real h2 = zero;
289  if (set.variable_dz) {
290  const TerrainCellDrops d = ComputeTerrainCellDrops(i,j,k,z_nd);
291  dzinv = one / d.dz;
292  const amrex::Real hx = ax * d.dx_drop;
293  const amrex::Real hy = ay * d.dy_drop;
294  h2 = hx*hx + hy*hy;
295  }
296  const amrex::Real rho = s_arr(i,j,k,Rho_comp);
297  if (!(rho > zero)) { rate_mom = zero; rate_scal = zero; return; }
298  const amrex::Real rdiv = NeighbourhoodMinPositive(i,j,k,Rho_comp,s_arr,rho);
299  const amrex::Real a2 = ax*ax;
300  const amrex::Real b2 = ay*ay;
301  const amrex::Real dzinv2 = dzinv*dzinv;
302  // Largest eddy diffusivity around the cell, or none without a turbulence model
303  auto K = [&] (int n) -> amrex::Real {
304  return (set.has_eddy) ? NeighbourhoodMax(i,j,k,n,k_arr) : zero;
305  };
306  // Molecular diffusivities, made dynamic with the largest density around the cell for
307  // ConstantAlpha, so that divided by the smallest one they still bound the rate
308  const amrex::Real mol_rho = (set.mol_times_rho) ? NeighbourhoodMax(i,j,k,Rho_comp,s_arr) : one;
309  const amrex::Real m_mom = set.mol_mom * mol_rho;
310  const amrex::Real m_th = set.mol_th * mol_rho;
311  const amrex::Real m_c = set.mol_c * mol_rho;
312  // with erf.implicit_terrain_metric the K_h metric term counts with the explicit fraction
313  rate_mom = MomentumDiffusiveRate(rdiv, K(EddyDiff::Mom_h) + m_mom, K(EddyDiff::Mom_v) + m_mom,
314  a2, b2, h2, dzinv2, set.e_uv, (set.implicit_metric ? set.e_uv : one));
315  amrex::Real rs = ScalarDiffusiveRate(rdiv, K(EddyDiff::Theta_h) + m_th, K(EddyDiff::Theta_v) + m_th,
316  a2, b2, h2, dzinv2, set.e_th, (set.implicit_metric ? set.e_th : one));
317  if (set.has_q) {
318  rs = amrex::max(rs, ScalarDiffusiveRate(rdiv, K(EddyDiff::Q_h) + m_c, K(EddyDiff::Q_v) + m_c,
319  a2, b2, h2, dzinv2, set.e_q, (set.implicit_metric ? set.e_q : one)));
320  }
321  if (set.has_ke) {
322  rs = amrex::max(rs, ScalarDiffusiveRate(rdiv, K(EddyDiff::KE_h), K(EddyDiff::KE_v),
323  a2, b2, h2, dzinv2, set.e_ke, (set.implicit_metric ? set.e_ke : one)));
324  }
325  if (set.has_scalar) {
326  rs = amrex::max(rs, ScalarDiffusiveRate(rdiv, K(EddyDiff::Scalar_h) + m_c, K(EddyDiff::Scalar_v) + m_c,
327  a2, b2, h2, dzinv2, one));
328  }
329  rate_scal = rs;
330 }
331 
332 /**
333  * Whether the terrain slope-factor report is evaluated this coarse step: always on a new set
334  * of grids, and every step on a moving terrain (MovingFittedMesh), where alpha changes with time.
335  */
336 inline bool
337 SlopeReportEvaluate (bool new_grids, bool moving_terrain)
338 {
339  return new_grids || moving_terrain;
340 }
341 
342 /**
343  * Whether an evaluated slope-factor report is printed: always when forced (new grids),
344  * otherwise only if the largest alpha moved by more than 1 % from the last printed value.
345  * alpha >= 1 by construction, so the relative test never fires on changes below 0.01.
346  */
347 inline bool
348 SlopeReportPrint (bool force, amrex::Real alpha_max, amrex::Real alpha_last)
349 {
350  return force || std::abs(alpha_max - alpha_last) > amrex::Real(0.01) * alpha_last;
351 }
352 
353 /**
354  * Explicit fraction of the vertical diffusion for the diffusive time-step check: 0 if every
355  * stage of the partly implicit Runge-Kutta scheme stays bounded for the vertical diffusion,
356  * 1 otherwise (including every pattern for which that has not been shown).
357  *
358  * Each stage k starts from S^n with stage step c_k dt; its explicit part (1 - f_k) acts on
359  * the previous stage's state and its implicit part f_k on its own, so for dS/dt = lambda S
360  * and y = -lambda dt >= 0, S_k = (1 - (1 - f_k) c_k y S_{k-1}) / (1 + f_k c_k y), S_0 = 1.
361  * Each stage's state feeds the next stage's explicit terms, so every |S_k| must stay <= 1,
362  * not only the last. The result is decided analytically:
363  *
364  * - three stages (c = 1/3, 1/2, 1; compressible): bounded for f_1 >= 1/2, f_2 = 1 and any
365  * f_3 in [0,1]. |S_1| <= 1 iff f_1 >= 1/2: |1 - (1-f) x| <= 1 + (1-f) x <= 1 + f x for
366  * f >= 1/2, and for f < 1/2, S_1 -> -(1-f)/f < -1 as x -> infinity;
367  * S_2 = 1 / (1 + y/2); and S_3 = (1 + (f_3 - 1/2) y) / ((1 + y/2)(1 + f_3 y)), whose
368  * numerator is at most 1 + y/2 in size. The default 1 1 0 is Crank-Nicolson, 1 1 1
369  * backward Euler.
370  * - two stages (c = 1/2, 1; anelastic MidPoint): bounded for f_1 = 1 and any f_2 in [0,1]
371  * (the same S_3 form); with f_1 < 1 and f_2 = 0, as MidPoint forces, the second stage
372  * grows without bound.
373  *
374  * Every other pattern returns 1: some are not bounded (0 0 1, 1 0 0, and 0.995 0.1 0.0666,
375  * whose last stage reaches 1.0008 near y = 23.5), and the rest are not shown to be.
376  *
377  * @param[in] nstages 3 for the compressible scheme, 2 for anelastic MidPoint
378  * @param[in] fac implicit factor f_k of each stage (erf.vert_implicit_fac)
379  * @param[in] implicit whether the implicit solve treats this component at all
380  */
381 template <typename V>
383 ExplicitVerticalFraction (int nstages, const V& fac, bool implicit)
384 {
385  if (!implicit || static_cast<int>(fac.size()) < nstages) { return one; }
386  // The proof assumes factors in [0,1]; anything else (the inputs are not range-checked,
387  // and 1 1.5 0 amplifies by 4/3) counts as explicit rather than being clamped.
388  for (int k = 0; k < nstages; ++k) {
389  const double fk = static_cast<double>(fac[k]);
390  if (!(fk >= 0.0 && fk <= 1.0)) { return one; }
391  }
392  auto f = [&] (int k) { return static_cast<double>(fac[k]); };
393  if (nstages == 3) {
394  return (f(0) >= 0.5 && f(1) >= 1.0) ? zero : one;
395  }
396  if (nstages == 2) {
397  return (f(0) >= 1.0) ? zero : one;
398  }
399  return one;
400 }
401 
402 #endif
#define Rho_comp
Definition: ERF_IndexDefines.H:53
Dimensionless numeric literals and pure mathematical constants.
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
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real NeighbourhoodMinPositive(int i, int j, int k, int n, const amrex::Array4< const amrex::Real > &a, amrex::Real fallback) noexcept
Definition: ERF_TerrainDiffusionLimits.H:216
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void CellDiffusiveRates(int i, int j, int k, const amrex::Array4< const amrex::Real > &s_arr, const amrex::Array4< const amrex::Real > &k_arr, const amrex::Array4< const amrex::Real > &z_nd, amrex::Real mf_mx, amrex::Real mf_my, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dxinv, const DiffusiveRateSettings &set, amrex::Real &rate_mom, amrex::Real &rate_scal) noexcept
Definition: ERF_TerrainDiffusionLimits.H:276
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real Smag2DLimitedViscosity(amrex::Real nu, amrex::Real strain, amrex::Real DeltaH, amrex::Real alpha, amrex::Real kh_cap, bool use_slope) noexcept
Definition: ERF_TerrainDiffusionLimits.H:110
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real ScalarDiffusiveRate(amrex::Real rho, amrex::Real K_h, amrex::Real K_v, amrex::Real a, amrex::Real b, amrex::Real h2, amrex::Real dzinv2, amrex::Real e_vert, amrex::Real w_metric=one) noexcept
Definition: ERF_TerrainDiffusionLimits.H:234
amrex::Real ExplicitVerticalFraction(int nstages, const V &fac, bool implicit)
Definition: ERF_TerrainDiffusionLimits.H:383
constexpr amrex::Real smag2d_def_limit_speed
Definition: ERF_TerrainDiffusionLimits.H:85
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real TerrainSlopeFactor(const TerrainCellDrops &d) noexcept
Definition: ERF_TerrainDiffusionLimits.H:78
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE TerrainCellDrops ComputeTerrainCellDrops(int i, int j, int k, const amrex::Array4< const amrex::Real > &z_nd) noexcept
Definition: ERF_TerrainDiffusionLimits.H:44
constexpr amrex::Real smag2d_def_limit_min
Definition: ERF_TerrainDiffusionLimits.H:87
bool SlopeReportEvaluate(bool new_grids, bool moving_terrain)
Definition: ERF_TerrainDiffusionLimits.H:337
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real NeighbourhoodMax(int i, int j, int k, int n, const amrex::Array4< const amrex::Real > &a) noexcept
Definition: ERF_TerrainDiffusionLimits.H:197
bool SlopeReportPrint(bool force, amrex::Real alpha_max, amrex::Real alpha_last)
Definition: ERF_TerrainDiffusionLimits.H:348
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real MomentumDiffusiveRate(amrex::Real rho, amrex::Real mu_h, amrex::Real mu_v, amrex::Real a, amrex::Real b, amrex::Real h2, amrex::Real dzinv2, amrex::Real e_uv, amrex::Real w_metric=one) noexcept
Definition: ERF_TerrainDiffusionLimits.H:166
@ Theta_v
Definition: ERF_IndexDefines.H:290
@ Scalar_v
Definition: ERF_IndexDefines.H:292
@ Mom_h
Definition: ERF_IndexDefines.H:284
@ Q_v
Definition: ERF_IndexDefines.H:293
@ Q_h
Definition: ERF_IndexDefines.H:288
@ Mom_v
Definition: ERF_IndexDefines.H:289
@ Scalar_h
Definition: ERF_IndexDefines.H:287
@ KE_v
Definition: ERF_IndexDefines.H:291
@ Theta_h
Definition: ERF_IndexDefines.H:285
@ KE_h
Definition: ERF_IndexDefines.H:286
@ rho
Definition: ERF_Kessler.H:25
@ V
Definition: ERF_IndexDefines.H:167
@ alpha
Definition: ERF_SLM.H:151
real(c_double), parameter a2
Definition: ERF_module_model_constants.F90:95
real(c_double), parameter r_v
Definition: ERF_module_model_constants.F90:24
Definition: ERF_TerrainDiffusionLimits.H:243
amrex::Real e_uv
Definition: ERF_TerrainDiffusionLimits.H:249
amrex::Real mol_mom
Definition: ERF_TerrainDiffusionLimits.H:256
amrex::Real mol_th
Definition: ERF_TerrainDiffusionLimits.H:256
bool has_scalar
Definition: ERF_TerrainDiffusionLimits.H:247
amrex::Real mol_c
Definition: ERF_TerrainDiffusionLimits.H:256
bool mol_times_rho
Definition: ERF_TerrainDiffusionLimits.H:257
bool implicit_metric
Definition: ERF_TerrainDiffusionLimits.H:248
amrex::Real e_ke
Definition: ERF_TerrainDiffusionLimits.H:249
bool variable_dz
Definition: ERF_TerrainDiffusionLimits.H:244
bool has_q
Definition: ERF_TerrainDiffusionLimits.H:245
bool has_eddy
Definition: ERF_TerrainDiffusionLimits.H:251
amrex::Real e_th
Definition: ERF_TerrainDiffusionLimits.H:249
bool has_ke
Definition: ERF_TerrainDiffusionLimits.H:246
amrex::Real e_q
Definition: ERF_TerrainDiffusionLimits.H:249
Definition: ERF_TerrainDiffusionLimits.H:29
amrex::Real dz
Definition: ERF_TerrainDiffusionLimits.H:32
amrex::Real dy_drop
Definition: ERF_TerrainDiffusionLimits.H:31
amrex::Real dx_drop
Definition: ERF_TerrainDiffusionLimits.H:30