ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_TimestepUtils.H
Go to the documentation of this file.
1 #ifndef ERF_TIMESTEP_UTILS_H_
2 #define ERF_TIMESTEP_UTILS_H_
3 
4 #include <ERF_Constants.H>
5 #include <ERF_TerrainMetrics.H>
6 #include <AMReX.H>
7 #include <AMReX_REAL.H>
8 #include <AMReX_Array.H>
9 #include <AMReX_Array4.H>
10 #include <AMReX_Algorithm.H>
11 #include <AMReX_Math.H>
12 #include <cmath>
13 
14 /**
15  * Pointwise inverse time step (1/dt, before the CFL is applied) for the
16  * compressible solver.
17  *
18  * The terrain metric terms are computed here from z_nd, so the same routine
19  * returns either the terrain aware or the terrain unaware estimate:
20  *
21  * terrain aware : h_xi and h_eta are retained and the vertical spacing is
22  * the local dxinv[2]/h_zeta -- w should be the contravariant
23  * (Omega) vertical velocity
24  * terrain unaware : h_xi = h_eta = 0 and the vertical spacing is dxinv[2]
25  * -- w should be the Cartesian vertical velocity
26  *
27  * Note that dxinv[2]*(h_xi/h_zeta) == h_xi*idz, which is why h_zeta only ever
28  * enters through idz.
29  *
30  * @param[in] i x-index
31  * @param[in] j y-index
32  * @param[in] k z-index
33  * @param[in] c sound speed
34  * @param[in] u cell-centered x-velocity
35  * @param[in] v cell-centered y-velocity
36  * @param[in] w cell-centered vertical velocity (Omega if terrain aware)
37  * @param[in] z_nd nodal physical height field (not accessed if terrain unaware)
38  * @param[in] dxinv inverse cell spacing of the computational mesh
39  * @param[in] l_terrain_aware true to include the metric terms
40  * @param[in] l_substepping true if implicit acoustic substepping is used
41  * @param[in] nxc number of cells in x on the level 0 domain
42  * @param[in] nyc number of cells in y on the level 0 domain
43  * @return 1/dt for this cell
44  */
45 AMREX_GPU_HOST_DEVICE
46 AMREX_FORCE_INLINE
48 Compute_InvDt_Compressible (const int i, const int j, const int k,
49  const amrex::Real c,
50  const amrex::Real u,
51  const amrex::Real v,
52  const amrex::Real w,
53  const amrex::Array4<const amrex::Real>& z_nd,
54  const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& dxinv,
55  const bool l_terrain_aware,
56  const bool l_substepping,
57  const int nxc=2,
58  const int nyc=2)
59 {
60  amrex::Real h_xi = zero;
61  amrex::Real h_eta = zero;
62  amrex::Real idz = dxinv[2];
63  if (l_terrain_aware) {
64  h_xi = Compute_h_xi_AtCellCenter(i,j,k,dxinv,z_nd);
65  h_eta = Compute_h_eta_AtCellCenter(i,j,k,dxinv,z_nd);
66  idz /= Compute_h_zeta_AtCellCenter(i,j,k,dxinv,z_nd);
67  }
68 
69  const amrex::Real abs_u = amrex::Math::abs(u);
70  const amrex::Real abs_v = amrex::Math::abs(v);
71  const amrex::Real abs_w = amrex::Math::abs(w);
72 
74 
75  // If we are doing implicit acoustic substepping, then the z-direction is not constrained
76  // by the speed of sound for the computation of the time step
77  if (l_substepping) {
78  // Implicit substepping removes the g33 metric
79  // Acoustic contribution limits dtau, whose max is in the first RK stage (1/3 dt)
80  const amrex::Real Uacoustic = third * c * std::sqrt( dxinv[0] * (dxinv[0] + two * idz * amrex::Math::abs(h_xi )) );
81  const amrex::Real Vacoustic = third * c * std::sqrt( dxinv[1] * (dxinv[1] + two * idz * amrex::Math::abs(h_eta)) );
82  if ((nxc > 1) && (nyc == 1)) {
83  // 2-D in x-z
84  inv_dt = amrex::max(abs_u*dxinv[0] + Uacoustic,
85  abs_w*idz );
86  } else if ((nyc > 1) && (nxc == 1)) {
87  // 2-D in y-z
88  inv_dt = amrex::max(abs_v*dxinv[1] + Vacoustic,
89  abs_w*idz );
90  } else {
91  // 3-D
92  inv_dt = amrex::max(abs_u*dxinv[0] + Uacoustic,
93  abs_v*dxinv[1] + Vacoustic,
94  abs_w*idz );
95  }
96 
97  // If we are not doing implicit acoustic substepping, then the z-direction is constrained
98  // by the speed of sound for the computation of the time step
99  } else {
100  // All the metric terms
101  const amrex::Real Uacoustic = c * amrex::Math::abs(dxinv[0] + idz * h_xi );
102  const amrex::Real Vacoustic = c * amrex::Math::abs(dxinv[1] + idz * h_eta);
103  const amrex::Real Oacoustic = c * amrex::Math::abs(idz);
104  if (nxc > 1 && nyc > 1) {
105  // 3-D
106  inv_dt = amrex::max(abs_u*dxinv[0] + Uacoustic,
107  abs_v*dxinv[1] + Vacoustic,
108  abs_w*idz + Oacoustic);
109  } else if (nxc > 1) {
110  // 2-D in x-z
111  inv_dt = amrex::max(abs_u*dxinv[0] + Uacoustic,
112  abs_w*idz + Oacoustic);
113  } else if (nyc > 1) {
114  // 2-D in y-z
115  inv_dt = amrex::max(abs_v*dxinv[1] + Vacoustic,
116  abs_w*idz + Oacoustic);
117  } else {
118  // 1-D in z
119  inv_dt = abs_w*idz + Oacoustic;
120  }
121  }
122 
123  return inv_dt;
124 }
125 
126 /**
127  * Pointwise inverse time step (1/dt, before the CFL is applied) for the
128  * anelastic (low Mach) solver -- this is a purely advective constraint.
129  *
130  * As above, the metric terms are computed here from z_nd:
131  *
132  * terrain aware : the vertical spacing is the local dxinv[2]/h_zeta and w
133  * should be the contravariant (Omega) vertical velocity
134  * terrain unaware : the vertical spacing is dxinv[2] and w should be the
135  * Cartesian vertical velocity
136  *
137  * The slope metrics h_xi and h_eta do not appear explicitly: for the advective
138  * constraint their effect is already carried by Omega, which is the vertical
139  * velocity relative to the terrain-following surfaces.
140  *
141  * @param[in] i x-index
142  * @param[in] j y-index
143  * @param[in] k z-index
144  * @param[in] u cell-centered x-velocity
145  * @param[in] v cell-centered y-velocity
146  * @param[in] w cell-centered vertical velocity (Omega if terrain aware)
147  * @param[in] z_nd nodal physical height field (not accessed if terrain unaware)
148  * @param[in] dxinv inverse cell spacing of the computational mesh
149  * @param[in] l_terrain_aware true to include the metric terms
150  * @return 1/dt for this cell
151  */
152 AMREX_GPU_HOST_DEVICE
153 AMREX_FORCE_INLINE
155 Compute_InvDt_Anelastic (const int i, const int j, const int k,
156  const amrex::Real u,
157  const amrex::Real v,
158  const amrex::Real w,
159  const amrex::Array4<const amrex::Real>& z_nd,
160  const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& dxinv,
161  const bool l_terrain_aware)
162 {
163  amrex::Real idz = dxinv[2];
164  if (l_terrain_aware) {
165  idz /= Compute_h_zeta_AtCellCenter(i,j,k,dxinv,z_nd);
166  }
167 
168  return amrex::max(amrex::Math::abs(u)*dxinv[0],
169  amrex::Math::abs(v)*dxinv[1],
170  amrex::Math::abs(w)*idz );
171 }
172 
173 #endif
constexpr amrex::Real two
Definition: ERF_Constants.H:10
constexpr amrex::Real bogus_large_value
Definition: ERF_Constants.H:26
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
constexpr amrex::Real third
Definition: ERF_Constants.H:15
Real w
Definition: ERF_Plotfile2DInterpolator.cpp:22
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_xi_AtCellCenter(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:204
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_eta_AtCellCenter(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:229
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_zeta_AtCellCenter(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:179
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_InvDt_Compressible(const int i, const int j, const int k, const amrex::Real c, const amrex::Real u, const amrex::Real v, const amrex::Real w, const amrex::Array4< const amrex::Real > &z_nd, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dxinv, const bool l_terrain_aware, const bool l_substepping, const int nxc=2, const int nyc=2)
Definition: ERF_TimestepUtils.H:48
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_InvDt_Anelastic(const int i, const int j, const int k, const amrex::Real u, const amrex::Real v, const amrex::Real w, const amrex::Array4< const amrex::Real > &z_nd, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dxinv, const bool l_terrain_aware)
Definition: ERF_TimestepUtils.H:155