ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_InitZLevels.cpp File Reference
#include <ERF_TerrainMetrics.H>
#include <ERF_Utils.H>
#include <AMReX_ParmParse.H>
#include <ERF_NumericalConstants.H>
#include <ERF_Interpolation_1D.H>
#include <ERF_GridUtils.H>
#include <cmath>
Include dependency graph for ERF_InitZLevels.cpp:

Functions

void init_zlevels (Vector< Vector< Real >> &zlevels_stag, Vector< Vector< Real >> &stretched_dz_h, Vector< Gpu::DeviceVector< Real >> &stretched_dz_d, Vector< Geometry > const &geom, Vector< IntVect > const &ref_ratio, const Real grid_stretching_ratio, const Real dz0)
 
void update_stretched_dz (int lev, Vector< Vector< Real >> const &zlevels_stag, Vector< Vector< Real >> &stretched_dz_h, Vector< Gpu::DeviceVector< Real >> &stretched_dz_d)
 

Function Documentation

◆ init_zlevels()

void init_zlevels ( Vector< Vector< Real >> &  zlevels_stag,
Vector< Vector< Real >> &  stretched_dz_h,
Vector< Gpu::DeviceVector< Real >> &  stretched_dz_d,
Vector< Geometry > const &  geom,
Vector< IntVect > const &  ref_ratio,
const Real  grid_stretching_ratio,
const Real  dz0 
)

Initialize staggered z-levels and grid spacing for all levels.

Parameters
[out]zlevels_stagStaggered z-level coordinates.
[out]stretched_dz_hHost-side cell heights in z.
[out]stretched_dz_dDevice-side cell heights in z.
[in]geomGeometry describing the domain.
[in]ref_ratioRefinement ratios between levels.
[in]grid_stretching_ratioRatio used for stretching the vertical grid; if zero and dz0 is positive, the ratio is solved for so that the grid closes on the top of the domain.
[in]dz0Initial cell height at the surface.

Every grid starts at geometry.prob_lo[2]: the uniform and stretched grids are built up from it, and erf.terrain_z_levels must begin there.

35 {
36  int max_level = zlevels_stag.size()-1;
37 
38  for (int lev = 0; lev <= max_level; lev++)
39  {
40  auto dx = geom[lev].CellSizeArray();
41  const Box& domain = geom[lev].Domain();
42  int nz = domain.length(2);
43 
44  zlevels_stag[lev].resize(nz+1);
45 
46  stretched_dz_h[lev].resize(domain.length(2));
47 
48  if (grid_stretching_ratio == 0 && !(dz0 > 0)) {
49  // This is the default for z_levels
50  const Real zsurf = geom[lev].ProbLo(2);
51  for (int k = 0; k < nz+1; k++)
52  {
53  zlevels_stag[lev][k] = zsurf + k * dx[2];
54  }
55  for (int k = 0; k < nz; k++)
56  {
57  stretched_dz_h[lev][k] = dx[2];
58  }
59  } else if (lev == 0 && grid_stretching_ratio == 0) {
60  // Solve for the geometric stretch factor that fills the domain above prob_lo with
61  // nz layers whose first is dz0 thick, as the wrfinput path does when it builds
62  // its grid by geometric stretching
63 #ifdef AMREX_USE_FLOAT
64  const Real tol = Real(1.e-4);
65 #else
66  const Real tol = Real(1.e-8);
67 #endif
68  const Real zsurf = geom[lev].ProbLo(2);
69  const Real depth = geom[lev].ProbHi(2) - zsurf;
71  erf_grid_utils::build_geometric_zlevels(zlevels_stag[lev], dz0, depth, tol);
73  "Newton iterations to determine the grid stretching factor failed!\n");
74  if (gs.uniform) {
75  Print() << "Note: erf.initial_dz = " << dz0 << " is no thinner than the uniform "
76  << "spacing, so the vertical grid is uniform with dz = " << gs.dz0 << std::endl;
77  }
78  Print() << "Building a stretched grid with dz0: " << gs.dz0
79  << " and stretching factor: " << gs.ratio << std::endl;
80 
81  Print() << "Stretched grid levels at level : " << lev << " is " << zsurf;
82  for (int k = 0; k < nz+1; k++)
83  {
84  zlevels_stag[lev][k] += zsurf;
85  if (k > 0) {
86  stretched_dz_h[lev][k-1] = zlevels_stag[lev][k] - zlevels_stag[lev][k-1];
87  Print() << " " << zlevels_stag[lev][k];
88  }
89  }
90  Print() << std::endl;
91  } else if (lev == 0) {
92  // Create stretched grid based on initial dz and stretching ratio
93  const Real zsurf = geom[lev].ProbLo(2);
94  zlevels_stag[lev][0] = zsurf;
95  Real dz = dz0;
96  Print() << "Stretched grid levels at level : " << lev << " is " << zsurf;
97  for (int k = 1; k < nz+1; k++)
98  {
99  stretched_dz_h[lev][k-1] = dz;
100  zlevels_stag[lev][k] = zlevels_stag[lev][k-1] + dz;
101  Print() << " " << zlevels_stag[lev][k];
102  dz *= grid_stretching_ratio;
103  }
104  Print() << std::endl;
105  } else if (lev > 0) {
106  int rr = ref_ratio[lev-1][2];
107  expand_and_interpolate_1d(zlevels_stag[lev], zlevels_stag[lev-1], rr, false);
108  for (int k = 0; k < nz; k++)
109  {
110  stretched_dz_h[lev][k] = (zlevels_stag[lev][k+1] - zlevels_stag[lev][k]);
111  }
112  }
113  }
114 
115  // Try reading in terrain_z_levels, which allows arbitrarily spaced grid
116  // levels to be specified and will take precedence over the
117  // grid_stretching_ratio parameter
118  ParmParse pp("erf");
119  int n_zlevels = pp.countval("terrain_z_levels");
120  if (n_zlevels > 0)
121  {
122  int nz = geom[0].Domain().length(2);
123  if (n_zlevels != nz+1) {
124  Print() << "You supplied " << n_zlevels << " staggered terrain_z_levels " << std::endl;
125  Print() << "but n_cell+1 in the z-direction is " << nz+1 << std::endl;
126  Abort("You must specify a z_level for every value of k");
127  }
128 
129  if (grid_stretching_ratio > 0) {
130  Print() << "Note: Found terrain_z_levels, ignoring grid_stretching_ratio" << std::endl;
131  } else if (dz0 > 0) {
132  Print() << "Note: Found terrain_z_levels, ignoring initial_dz" << std::endl;
133  }
134 
135  pp.getarr("terrain_z_levels", zlevels_stag[0], 0, nz+1);
136 
137  // These levels should range from geometry.prob_lo[2] at the surface to the
138  // height of the top of model domain (see the coordinate surface height, zeta,
139  // in Klemp 2011)
140  if (zlevels_stag[0][0] != geom[0].ProbLo(2)) {
141  Abort("erf.terrain_z_levels must start at geometry.prob_lo[2] = " +
142  std::to_string(geom[0].ProbLo(2)) + ", not at " +
143  std::to_string(zlevels_stag[0][0]));
144  }
145 
146  for (int lev = 1; lev <= max_level; lev++) {
147  int rr = ref_ratio[lev-1][2];
148  expand_and_interpolate_1d(zlevels_stag[lev], zlevels_stag[lev-1], rr, false);
149  }
150 
151  for (int lev = 0; lev <= max_level; lev++) {
152  int nz_zlevs = zlevels_stag[lev].size();
153  for (int k = 0; k < nz_zlevs-1; k++)
154  {
155  stretched_dz_h[lev][k] = (zlevels_stag[lev][k+1] - zlevels_stag[lev][k]);
156  }
157  }
158  }
159 
160  for (int lev = 0; lev <= max_level; lev++) {
161  stretched_dz_d[lev].resize(stretched_dz_h[lev].size());
162  Gpu::copy(Gpu::hostToDevice, stretched_dz_h[lev].begin(), stretched_dz_h[lev].end(), stretched_dz_d[lev].begin());
163  }
164 }
const Real dx
Definition: ERF_InitCustomPert_ABL.H:44
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(axis >=0 &&axis< AMREX_SPACEDIM, "prob.axis must be 0, 1 or 2")
ParmParse pp("prob")
AMREX_FORCE_INLINE void expand_and_interpolate_1d(amrex::Vector< amrex::Real > &znew, const amrex::Vector< amrex::Real > &zorig, int refine_fac, bool destag=false)
Definition: ERF_Interpolation_1D.H:95
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ dz
Definition: ERF_AdvanceWDM6.cpp:273
GeometricStretch build_geometric_zlevels(amrex::Vector< amrex::Real > &zlevels, amrex::Real dz0, amrex::Real z_top, amrex::Real tol)
Fill a staggered z-level array with a geometrically stretched grid.
Definition: ERF_GridUtils.H:274
real(c_double), private rr
Definition: ERF_module_mp_morr_two_moment.F90:224
A geometrically stretched vertical grid: dz_k = dz0 * ratio^k.
Definition: ERF_GridUtils.H:172
amrex::Real ratio
layer-to-layer stretch factor
Definition: ERF_GridUtils.H:174
bool converged
true when |residual| <= tol
Definition: ERF_GridUtils.H:177
bool uniform
true when the requested dz0 could not be honored
Definition: ERF_GridUtils.H:176
amrex::Real dz0
thickness of the first layer, as actually used
Definition: ERF_GridUtils.H:173

Referenced by ERF::ERF_shared().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_stretched_dz()

void update_stretched_dz ( int  lev,
Vector< Vector< Real >> const &  zlevels_stag,
Vector< Vector< Real >> &  stretched_dz_h,
Vector< Gpu::DeviceVector< Real >> &  stretched_dz_d 
)

Re-derive the cell heights at one level from the nominal staggered z-levels.

Parameters
[in]levLevel index.
[in]zlevels_stagStaggered z-level coordinates.
[out]stretched_dz_hHost-side cell heights in z.
[out]stretched_dz_dDevice-side cell heights in z.
179 {
180  AMREX_ALWAYS_ASSERT(lev < static_cast<int>(zlevels_stag.size()));
181  AMREX_ALWAYS_ASSERT(lev < static_cast<int>(stretched_dz_h.size()));
182  AMREX_ALWAYS_ASSERT(lev < static_cast<int>(stretched_dz_d.size()));
183 
184  const int nz = static_cast<int>(zlevels_stag[lev].size()) - 1;
185  AMREX_ALWAYS_ASSERT(nz > 0);
186 
187  stretched_dz_h[lev].resize(nz);
188  for (int k = 0; k < nz; k++) {
189  stretched_dz_h[lev][k] = zlevels_stag[lev][k+1] - zlevels_stag[lev][k];
190  }
191 
192  stretched_dz_d[lev].resize(nz);
193  Gpu::copy(Gpu::hostToDevice, stretched_dz_h[lev].begin(), stretched_dz_h[lev].end(),
194  stretched_dz_d[lev].begin());
195 }
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)

Referenced by ERF::ReadCheckpointFile().

Here is the call graph for this function:
Here is the caller graph for this function: