ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_TerrainImplicitMetric.H
Go to the documentation of this file.
1 #ifndef ERF_TERRAIN_IMPLICIT_METRIC_H_
2 #define ERF_TERRAIN_IMPLICIT_METRIC_H_
3 
4 #include <AMReX_REAL.H>
5 #include <AMReX_GpuQualifiers.H>
6 
7 /**
8  * Terrain-metric part of the vertical diffusion on a terrain-fitted mesh, for
9  * erf.implicit_terrain_metric.
10  *
11  * The flux through a zeta face projects the horizontal fluxes onto the face
12  * normal. Their h*d/dz parts add a vertical-diffusion term K_h * M * d/dz to the
13  * zeta flux, with the factors below. The explicit operator forms it from
14  * averaged horizontal fluxes; with the option on, the same term in compact form
15  * (face differences in zeta) is also put into the implicit vertical solve and
16  * subtracted explicitly at the state the explicit terms see, so the stages
17  * with an implicit solve treat the K_h * M * d2/dz2 stiffness implicitly. The
18  * factors are the exact du/dz (dphi/dz) content of the projected fluxes, so for
19  * smooth fields on a uniform slope the explicit remainder (averaged minus
20  * compact) is small; at the grid scale it is the whole compact term with the
21  * opposite sign, cancelled within the stage by the implicit solve, which is why
22  * every stage needs the solve (SolverChoice::check_params).
23  *
24  * h_xi and h_eta are the terrain slopes dz/dxi and dz/deta at the face, mx and my
25  * the map factors there.
26  */
27 
28 /**
29  * Momentum: the zeta flux of u holds -0.5 * mu_h_tot * M_u * du/dz with
30  * M_u = (4/3) (h_xi mx)^2 + (h_eta my)^2, from h_xi (S11 - er/3) and h_eta S12:
31  * S11 carries -h_xi mx du/dz, and the expansion rate er carries the same term
32  * through Omega, so the deviatoric S11 - er/3 carries -(2/3) h_xi mx du/dz. For
33  * v, M_v = (h_xi mx)^2 + (4/3) (h_eta my)^2, from h_xi S12 and h_eta (S22 - er/3).
34  *
35  * @param[in] stagdir 0 for u, 1 for v
36  */
37 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
39 TerrainMetricMomFactor (const int stagdir,
40  const amrex::Real h_xi, const amrex::Real h_eta,
41  const amrex::Real mx, const amrex::Real my) noexcept
42 {
43  const amrex::Real ax = h_xi * mx;
44  const amrex::Real ay = h_eta * my;
45  const amrex::Real four_thirds = amrex::Real(4.0) / amrex::Real(3.0);
46  return (stagdir == 0) ? four_thirds*ax*ax + ay*ay
47  : ax*ax + four_thirds*ay*ay;
48 }
49 
50 /**
51  * Scalars: G_z = F_z - h_xi mx Fx_bar - h_eta my Fy_bar holds
52  * -K_h * M_s * dphi/dz with M_s = (h_xi mx)^2 + (h_eta my)^2.
53  */
54 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
57  const amrex::Real mx, const amrex::Real my) noexcept
58 {
59  const amrex::Real ax = h_xi * mx;
60  const amrex::Real ay = h_eta * my;
61  return ax*ax + ay*ay;
62 }
63 
64 /**
65  * The split applies on the faces the implicit solve treats with a coefficient:
66  * every zeta face strictly inside the domain (dom_lo < kface <= dom_hi, with
67  * dom_hi the top cell). The bottom and top faces carry the boundary condition
68  * (wall, surface layer, Neumann) and stay explicit.
69  */
70 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
71 bool
72 TerrainMetricImplicitFace (const int kface, const int dom_lo, const int dom_hi) noexcept
73 {
74  return (kface > dom_lo) && (kface <= dom_hi);
75 }
76 
77 #endif
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool TerrainMetricImplicitFace(const int kface, const int dom_lo, const int dom_hi) noexcept
Definition: ERF_TerrainImplicitMetric.H:72
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real TerrainMetricMomFactor(const int stagdir, const amrex::Real h_xi, const amrex::Real h_eta, const amrex::Real mx, const amrex::Real my) noexcept
Definition: ERF_TerrainImplicitMetric.H:39
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real TerrainMetricScalarFactor(const amrex::Real h_xi, const amrex::Real h_eta, const amrex::Real mx, const amrex::Real my) noexcept
Definition: ERF_TerrainImplicitMetric.H:56