|
ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
|
#include <AMReX_Array4.H>#include <AMReX_Extension.H>#include <AMReX_GpuQualifiers.H>#include <AMReX_Algorithm.H>#include <AMReX_Array.H>#include <AMReX_Math.H>#include <AMReX_REAL.H>#include "ERF_NumericalConstants.H"#include "ERF_IndexDefines.H"#include <cmath>

Go to the source code of this file.
Classes | |
| struct | TerrainCellDrops |
| struct | DiffusiveRateSettings |
Functions | |
| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE TerrainCellDrops | ComputeTerrainCellDrops (int i, int j, int k, const amrex::Array4< const amrex::Real > &z_nd) noexcept |
| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real | TerrainSlopeFactor (const TerrainCellDrops &d) noexcept |
| 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 |
| 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 e_w, amrex::Real w_metric=one) noexcept |
| 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 |
| 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 |
| 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 |
| 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 |
| bool | SlopeReportEvaluate (bool new_grids, bool moving_terrain) |
| bool | SlopeReportPrint (bool force, amrex::Real alpha_max, amrex::Real alpha_last) |
| template<typename V > | |
| amrex::Real | ExplicitVerticalFraction (int nstages, const V &fac, bool implicit) |
Variables | |
| constexpr amrex::Real | smag2d_def_limit_speed = amrex::Real(10.0) |
| constexpr amrex::Real | smag2d_def_limit_min = amrex::Real(1.0e-3) |
|
noexcept |
Explicit eddy-diffusion rates of cell (i,j,k), momentum and scalars (1/s), as the diffusive time-step check reduces them: MomentumDiffusiveRate and ScalarDiffusiveRate with the largest diffusivities and the smallest positive density over the cell and its 26 neighbours. Both are zero in a cell without density (covered).
| [in] | s_arr | conserved state (Rho_comp), one ghost cell |
| [in] | k_arr | eddy diffusivities (EddyDiff components), one ghost cell |
| [in] | z_nd | nodal heights (read only when set.variable_dz) |
| [in] | mf_mx,mf_my | map factors of the cell |
| [in] | dxinv | inverse cell sizes |
Referenced by ERF::ComputeDiffusiveRates().


|
noexcept |
Compute the terrain drops across cell (i,j,k) from the nodal heights.
| [in] | i,j,k | cell-centered indices |
| [in] | z_nd | nodal physical heights |
Referenced by CellDiffusiveRates(), ComputeTurbulentViscosityLES(), and ERF::ReportTerrainSlopeFactor().

| amrex::Real ExplicitVerticalFraction | ( | int | nstages, |
| const V & | fac, | ||
| bool | implicit | ||
| ) |
Explicit fraction of the vertical diffusion for the diffusive time-step check: 0 if every stage of the partly implicit Runge-Kutta scheme stays bounded for the vertical diffusion, 1 otherwise (including every pattern for which that has not been shown).
Each stage k starts from S^n with stage step c_k dt; its explicit part (1 - f_k) acts on the previous stage's state and its implicit part f_k on its own, so for dS/dt = lambda S 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. Each stage's state feeds the next stage's explicit terms, so every |S_k| must stay <= 1, not only the last. The result is decided analytically:
Every other pattern returns 1: some are not bounded (0 0 1, 1 0 0, and 0.995 0.1 0.0666, whose last stage reaches 1.0008 near y = 23.5), and the rest are not shown to be.
| [in] | nstages | 3 for the compressible scheme, 2 for anelastic MidPoint |
| [in] | fac | implicit factor f_k of each stage (erf.vert_implicit_fac) |
| [in] | implicit | whether the implicit solve treats this component at all |
Referenced by ERF::ComputeDiffusiveRates().

|
noexcept |
Explicit diffusion rates of one cell, for the diffusive time-step estimate dt * rate <= Fourier limit (1/2 for forward Euler in 3-D; the three-stage Runge-Kutta scheme's real-axis bound is about 2.5 / 4 = 0.63).
Momentum: the largest of the three component rows, u: mu_h (2 a + b) + e_uv mu_v / dz^2 + mu_v sqrt(a c) v: mu_h (a + 2 b) + e_uv mu_v / dz^2 + mu_v sqrt(b c) w: mu_v (a + b) + 2 e_w mu_v / dz^2 + mu_v (sqrt(a c) + sqrt(b c)), with c = 1/dz^2, plus 2 mu_p h^2 / dz^2 for the terrain-metric part. The horizontal diffusion of w uses mu_v: tau31 and tau32 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 tau31, ...), which stay explicit whether or not the implicit solve takes the second vertical derivative; they are always counted, since with dz > dx/m they exceed the vertical term (dx = 100 m, dz = 500 m: five times). (The expansion rate in tau11 also couples u to dw/dz, with mu_h; that is covered by "an estimate when mu_h != mu_v" below.) The metric term is an upper bound: the projected horizontal stresses of the u and v fluxes carry mu_h (ComputeStressVarVisc_T), the w flux mu_v, hence mu_p = max(w_metric mu_h, mu_v).
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 TerrainDiffusionGz).
w_metric weights the K_h metric term: 1 when it is explicit, and with erf.implicit_terrain_metric the component's explicit fraction e, since its compact form K_h M d2/dz2 is then in the implicit solve (u, v and the scalars; w is not). The difference between the averaged and the compact forms stays explicit and is not counted, so with the option the rate is an estimate.
a = (m_x / dx)^2, b = (m_y / dy)^2 and h^2 = (m_x dx_drop / dx)^2 + (m_y dy_drop / dy)^2 is the squared physical slope; on a mesh without terrain pass h2 = 0. e is the explicit fraction of the vertical diffusion (ExplicitVerticalFraction): 0 when the implicit solve keeps every stage bounded, 1 otherwise. All diffusivities are dynamic (rho * nu); rates are in 1/s. The caller passes the largest diffusivities and the smallest density around the cell (NeighbourhoodMax, NeighbourhoodMinPositive), which bounds the row whatever face or edge averaging the operator uses.
Referenced by CellDiffusiveRates().

|
noexcept |
Largest value of component n over cell (i,j,k) and its 26 neighbours. The diffusion operators average the cell diffusivities to faces and edges, so a row of the operator never carries more than this. With NeighbourhoodMinPositive for the density and the coefficients frozen, the scalar rate is a Gershgorin bound on the centred interior stencil of the Cartesian operator (the higher-order one-sided gradients next to Dirichlet boundaries, ERF_ScalarDiffusion.H, whose row is about 4/3 larger, are not covered); for momentum it is a bound for uniform coefficients when mu_h = mu_v (tight on cubic cells) and an estimate otherwise, since the operator is then not symmetric. Needs one ghost cell.
Referenced by CellDiffusiveRates().

|
noexcept |
Smallest positive value of component n over cell (i,j,k) and its 26 neighbours; ghost cells that hold no density (<= 0) are skipped. Returns fallback if none is positive.
Referenced by CellDiffusiveRates().

|
noexcept |
Scalar counterpart of MomentumDiffusiveRate (see there).
Referenced by CellDiffusiveRates().

|
inline |
Whether the terrain slope-factor report is evaluated this coarse step: always on a new set of grids, and every step on a moving terrain (MovingFittedMesh), where alpha changes with time.
Referenced by ERF::ComputeDt().

|
inline |
Whether an evaluated slope-factor report is printed: always when forced (new grids), otherwise only if the largest alpha moved by more than 1 % from the last printed value. alpha >= 1 by construction, so the relative test never fires on changes below 0.01.
Referenced by ERF::ReportTerrainSlopeFactor().

|
noexcept |
Apply the opt-in limits of WRF's smag2d_km to a Smagorinsky-2D horizontal kinematic eddy viscosity, in WRF's order:
| [in] | nu | Cs^2 Delta_h^2 |D_h| (m^2/s) |
| [in] | strain | |D_h| (1/s) |
| [in] | DeltaH | horizontal filter width (m) |
| [in] | alpha | slope factor from TerrainSlopeFactor (>= 1) |
| [in] | kh_cap | cap speed (m/s); <= 0 leaves nu uncapped |
| [in] | use_slope | apply the slope limiter |
Referenced by ComputeTurbulentViscosityLES().

|
noexcept |
Slope factor alpha = max( sqrt(dx_drop^2 + dy_drop^2) / dz, 1 ) of a cell: the terrain drop across one cell measured in cell thicknesses, which is h * Delta_x / Delta_z with h the physical coordinate slope. This is the factor of WRF's Smagorinsky-2D slope limiter (dyn_em/module_diffusion_em.F, smag2d_km, diff_opt = 2). WRF averages |z_x| at the two x-faces and the two w-levels of the cell and multiplies by dx / msftx; here the drop is taken on the four x-edges of the cell (ERF heights are nodal) and carries no map factor, so that alpha is exactly h * Delta_x / Delta_z with the physical spacing. The two agree when the map factor is 1.
Referenced by ComputeTurbulentViscosityLES(), and ERF::ReportTerrainSlopeFactor().

|
constexpr |
Floor of WRF's deformation threshold (1/s).
Referenced by Smag2DLimitedViscosity().
|
constexpr |
Deformation threshold speed of WRF's slope limiter, def_limit = max(10/Delta_h, 1e-3) (m/s).
Referenced by Smag2DLimitedViscosity().