ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_WallScalarBC.H
Go to the documentation of this file.
1 #ifndef ERF_WALL_SCALAR_BC_H_
2 #define ERF_WALL_SCALAR_BC_H_
3 
4 #include <AMReX_REAL.H>
5 #include <AMReX_ParmParse.H>
6 #include "ERF_IndexDefines.H"
7 
8 #include <string>
9 
10 namespace erf_wall_scalar_bc {
11 
12 // Host-side intent for a scalar supplied on one physical solid-wall face.
13 // Presence is represented by this value, never by the numerical value itself.
14 enum class WallScalarBCIntent : unsigned char {
18  Neumann
19 };
20 
21 /** Map the wall-input intent to ERF's logical conserved-scalar BC record. */
22 inline int
24 {
25  switch (intent) {
27  return ERFBCType::ext_dir;
31  return ERFBCType::neumann;
33  default:
34  return ERFBCType::foextrap;
35  }
36 }
37 
38 enum class SolidWallKind : unsigned char {
39  NoSlip,
40  Slip
41 };
42 
46 };
47 
52 };
53 
56  std::string error;
57 
58  /**
59  * Return whether parsing completed without an error.
60  */
61  [[nodiscard]] bool ok () const noexcept { return error.empty(); }
62 };
63 
64 /**
65  * Resolve a wall scalar value into primitive or conserved storage.
66  *
67  * @param[in] value_specified whether the scalar value was specified
68  * @param[in] primitive_value primitive scalar value from inputs
69  * @param[in] density_specified_on_same_face whether density was specified on the same face
70  * @param[in] density_value density value used for conserved conversion
71  */
72 inline ParsedWallScalarBC
73 resolve_wall_scalar_value (bool value_specified,
74  amrex::Real primitive_value,
75  bool density_specified_on_same_face,
76  amrex::Real density_value)
77 {
78  if (!value_specified) {
79  return {};
80  }
81 
82  if (density_specified_on_same_face) {
84  density_value * primitive_value};
85  }
86 
87  return {WallScalarBCIntent::DirichletPrimitive, primitive_value};
88 }
89 
90 /**
91  * Resolve a wall scalar gradient into Neumann storage.
92  *
93  * @param[in] gradient_specified whether the scalar gradient was specified
94  * @param[in] gradient gradient value from inputs
95  */
96 inline ParsedWallScalarBC
97 resolve_wall_scalar_gradient (bool gradient_specified,
98  amrex::Real gradient)
99 {
100  if (!gradient_specified) {
101  return {};
102  }
103  return {WallScalarBCIntent::Neumann, gradient};
104 }
105 
106 /**
107  * Test whether value and gradient inputs conflict.
108  *
109  * @param[in] value_specified whether a scalar value was specified
110  * @param[in] gradient_specified whether a scalar gradient was specified
111  */
112 inline bool
114  bool gradient_specified)
115 {
116  return value_specified && gradient_specified;
117 }
118 
119 /**
120  * Build the error message for mutually exclusive wall scalar inputs.
121  *
122  * @param[in] face face name used in the input keys
123  * @param[in] variable variable name used in the input keys
124  */
125 inline std::string
126 wall_scalar_value_gradient_error (const std::string& face,
127  const std::string& variable)
128 {
129  return face + "." + variable + " and " + face + "." + variable
130  + "_grad are mutually exclusive";
131 }
132 
133 /**
134  * Build the anelastic-mode density error message for a wall face.
135  *
136  * @param[in] face face name used in the input keys
137  * @param[in] density_specified whether density was specified
138  * @param[in] density_gradient_specified whether density_grad was specified
139  */
140 inline std::string
141 anelastic_wall_density_error (const std::string& face,
142  bool density_specified,
143  bool density_gradient_specified)
144 {
145  if (!density_specified && !density_gradient_specified) {
146  return {};
147  }
148 
149  std::string message = face + ": density and density_grad must be omitted "
150  "on solid walls in anelastic mode (density is fixed by the base state)";
151  if (density_specified && density_gradient_specified) {
152  message += "; both keywords were supplied";
153  } else if (density_specified) {
154  message += "; " + face + ".density was supplied";
155  } else {
156  message += "; " + face + ".density_grad was supplied";
157  }
158  return message;
159 }
160 
161 /**
162  * Build the unsupported no-slip density-gradient error message.
163  *
164  * @param[in] face face name used in the input keys
165  */
166 inline std::string
167 no_slip_density_gradient_error (const std::string& face)
168 {
169  return face + ".density_grad is not supported for NoSlipWall; use "
170  + face + ".density for a fixed compressible wall density or omit "
171  "wall density in anelastic mode";
172 }
173 
174 /**
175  * Parse scalar wall boundary-condition inputs for one face.
176  *
177  * @param[in] pp ParmParse object scoped to the wall face
178  * @param[in] face face name used in errors
179  * @param[in] wall_kind no-slip or slip wall type
180  * @param[in] anelastic whether anelastic mode is active
181  */
182 inline WallFaceParseResult
183 parse_wall_face_scalars (amrex::ParmParse& pp,
184  const std::string& face,
185  SolidWallKind wall_kind,
186  bool anelastic)
187 {
188  // The value-carrying keys are probed with negative sentinels and their presence is
189  // read off the resulting value, not off the queryAdd return value. queryAdd inserts
190  // the default into the (process-global) ParmParse table on a miss, so its return
191  // value means "did this key exist before this call" -- true for every call after the
192  // first. ERF::init_bcs() runs twice on restart, and ERF_InitBCs.cpp parses the same
193  // density/qv keys under the same face prefix, so a return-value test reports
194  // "user specified" with a value of zero on the second pass. That is what produced
195  // the spurious NoSlipWall density_grad abort in #3922.
196  //
197  // density_grad and theta_grad deliberately keep plain query(): every real value is a
198  // legal gradient, including zero and negatives, so no sentinel can encode "unset".
199  amrex::Real density = amrex::Real(-1.0);
200  pp.queryAdd("density", density);
201  const bool density_specified = (density > amrex::Real(0.0));
202  if (!density_specified) { density = amrex::Real(0.0); }
203 
204  amrex::Real density_grad = amrex::Real(0.0);
205  const bool density_gradient_specified = pp.query("density_grad", density_grad);
206 
207  amrex::Real theta = amrex::Real(-1.0);
208  pp.queryAdd("theta", theta);
209  const bool theta_specified = (theta > amrex::Real(0.0));
210  if (!theta_specified) { theta = amrex::Real(0.0); }
211 
212  amrex::Real theta_grad = amrex::Real(0.0);
213  const bool theta_gradient_specified = pp.query("theta_grad", theta_grad);
214 
215  amrex::Real qv = amrex::Real(-1.0);
216  if (wall_kind == SolidWallKind::NoSlip) { pp.queryAdd("qv", qv); }
217  const bool qv_specified = (wall_kind == SolidWallKind::NoSlip) &&
218  (qv >= amrex::Real(0.0));
219  if (!qv_specified) { qv = amrex::Real(0.0); }
220 
221  WallFaceParseResult result;
222  if (anelastic && (density_specified || density_gradient_specified)) {
224  face, density_specified, density_gradient_specified);
225  return result;
226  }
227 
228  if (wall_kind == SolidWallKind::NoSlip && density_gradient_specified) {
229  result.error = no_slip_density_gradient_error(face);
230  return result;
231  }
232 
233  if (wall_kind == SolidWallKind::Slip &&
234  wall_scalar_value_gradient_conflict(density_specified,
235  density_gradient_specified)) {
236  result.error = wall_scalar_value_gradient_error(face, "density");
237  return result;
238  }
239 
240  if (wall_scalar_value_gradient_conflict(theta_specified,
241  theta_gradient_specified)) {
242  result.error = wall_scalar_value_gradient_error(face, "theta");
243  return result;
244  }
245 
246  if (density_specified) {
247  result.scalars.density = {
249  }
251  theta_specified, theta, density_specified, density);
252  if (theta_gradient_specified) {
253  result.scalars.theta = resolve_wall_scalar_gradient(true, theta_grad);
254  }
255 
256  if (wall_kind == SolidWallKind::Slip && density_gradient_specified) {
257  result.scalars.density = resolve_wall_scalar_gradient(true, density_grad);
258  }
259 
260  if (qv_specified) {
262  true, qv, density_specified, density);
263  }
264 
265  return result;
266 }
267 
268 } // namespace erf_wall_scalar_bc
269 
270 #endif
ParmParse pp("prob")
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ neumann
Definition: ERF_IndexDefines.H:345
@ foextrap
Definition: ERF_IndexDefines.H:339
@ ext_dir
Definition: ERF_IndexDefines.H:340
@ ext_dir_prim
Definition: ERF_IndexDefines.H:343
@ theta
Definition: ERF_Kessler.H:26
@ qv
Definition: ERF_Kessler.H:31
Definition: ERF_WallScalarBC.H:10
WallScalarBCIntent
Definition: ERF_WallScalarBC.H:14
std::string wall_scalar_value_gradient_error(const std::string &face, const std::string &variable)
Definition: ERF_WallScalarBC.H:126
bool wall_scalar_value_gradient_conflict(bool value_specified, bool gradient_specified)
Definition: ERF_WallScalarBC.H:113
int logical_boundary_type(WallScalarBCIntent intent) noexcept
Definition: ERF_WallScalarBC.H:23
std::string anelastic_wall_density_error(const std::string &face, bool density_specified, bool density_gradient_specified)
Definition: ERF_WallScalarBC.H:141
ParsedWallScalarBC resolve_wall_scalar_value(bool value_specified, amrex::Real primitive_value, bool density_specified_on_same_face, amrex::Real density_value)
Definition: ERF_WallScalarBC.H:73
SolidWallKind
Definition: ERF_WallScalarBC.H:38
std::string no_slip_density_gradient_error(const std::string &face)
Definition: ERF_WallScalarBC.H:167
ParsedWallScalarBC resolve_wall_scalar_gradient(bool gradient_specified, amrex::Real gradient)
Definition: ERF_WallScalarBC.H:97
WallFaceParseResult parse_wall_face_scalars(amrex::ParmParse &pp, const std::string &face, SolidWallKind wall_kind, bool anelastic)
Definition: ERF_WallScalarBC.H:183
Definition: ERF_WallScalarBC.H:48
ParsedWallScalarBC qv
Definition: ERF_WallScalarBC.H:51
ParsedWallScalarBC theta
Definition: ERF_WallScalarBC.H:50
ParsedWallScalarBC density
Definition: ERF_WallScalarBC.H:49
Definition: ERF_WallScalarBC.H:43
WallScalarBCIntent intent
Definition: ERF_WallScalarBC.H:44
amrex::Real stored_value
Definition: ERF_WallScalarBC.H:45
Definition: ERF_WallScalarBC.H:54
bool ok() const noexcept
Definition: ERF_WallScalarBC.H:61
ParsedWallFaceScalars scalars
Definition: ERF_WallScalarBC.H:55
std::string error
Definition: ERF_WallScalarBC.H:56