ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_DataStruct.H
Go to the documentation of this file.
1 #ifndef ERF_DATA_STRUCT_H_
2 #define ERF_DATA_STRUCT_H_
3 
4 #include <string>
5 #include <iostream>
6 
7 #include <AMReX_ParmParse.H>
8 #include <AMReX_Print.H>
9 #include <AMReX_Gpu.H>
10 #include <AMReX_Geometry.H>
11 
12 #include "ERF_Constants.H"
13 #include "ERF_IndexDefines.H"
14 #include "ERF_AdvStruct.H"
15 #include "ERF_DampingStruct.H"
16 #include "ERF_DiffStruct.H"
17 #include "ERF_EBStruct.H"
18 #include "ERF_SpongeStruct.H"
19 #include "ERF_TurbStruct.H"
20 #include "ERF_TurbPertStruct.H"
22 
23 /**
24  * @brief Indices for map scale factors on mass and face grids.
25  */
26 enum MapFacType {
27 // This version assumes isotropic
28  m_x, u_x, v_x, num,
29  m_y = 0, u_y = 1, v_y = 2
30 // This version allows for non-isotropic
31 // m_x, u_x, v_x,
32 // m_y, u_y, v_y, num
33 };
34 
35 /**
36  * @brief Stress tensor component indices.
37  */
38 enum TauType {
40 };
41 
42 /**
43  * @brief Initial-condition source used to populate the ERF state.
44  */
45 AMREX_ENUM(InitType,
46  None, Input_Sounding, NCFile, WRFInput, Metgrid, Uniform, ConstantDensity, ConstantDensityLinearTheta,
47  Isentropic, MoistBaseState, HindCast
48 );
49 
50 /**
51  * @brief Interpretation of input sounding profiles.
52  */
53 AMREX_ENUM(SoundingType,
54  ConstantDensity, Ideal, Isentropic, DryIsentropic
55 );
56 
57 /**
58  * @brief Large-scale atmospheric boundary-layer driver type.
59  */
60 AMREX_ENUM(ABLDriverType,
61  None, PressureGradient, GeostrophicWind
62 );
63 
64 /**
65  * @brief Multilevel coupling strategy.
66  */
67 AMREX_ENUM(CouplingType,
68  OneWay, TwoWay
69 );
70 
71 /**
72  * @brief Acoustic substepping strategy.
73  */
74 AMREX_ENUM(SubsteppingType,
75  None, Implicit
76 );
77 
78 /**
79  * @brief Vertical mesh representation.
80  */
81 AMREX_ENUM(MeshType,
82  ConstantDz, StretchedDz, VariableDz
83 );
84 
85 /**
86  * @brief Terrain and immersed-boundary representation.
87  */
88 AMREX_ENUM(TerrainType,
89  None, StaticFittedMesh, MovingFittedMesh, EB, ImmersedForcing
90 );
91 
92 /**
93  * @brief Building representation.
94  */
95 AMREX_ENUM(BuildingsType,
96  None, ImmersedForcing
97 );
98 
99 /**
100  * @brief Moisture transport representation.
101  */
102 AMREX_ENUM(MoistureModelType,
103  Eulerian, Lagrangian, Undefined
104 );
105 
106 /**
107  * @brief Moisture and microphysics model.
108  */
109 AMREX_ENUM(MoistureType,
110  SAM, SAM_NoIce, SAM_NoPrecip_NoIce, Kessler, Kessler_NoRain, SatAdj, Morrison, Morrison_NoIce, WSM6, WDM6, SuperDroplets, MoistNoCondensation, None
111 );
112 
113 /**
114  * @brief Wind-farm model.
115  */
116 AMREX_ENUM(WindFarmType,
117  Fitch, EWP, SimpleAD, GeneralAD, None
118 );
119 
120 /**
121  * @brief Coordinate system used for wind-farm locations.
122  */
123 AMREX_ENUM(WindFarmLocType,
124  lat_lon, x_y, None
125 );
126 
127 /**
128  * @brief Land-surface model.
129  */
130 AMREX_ENUM(LandSurfaceType,
131  SLM, NOAHMP, None
132 );
133 
134 /**
135  * @brief Radiation model.
136  */
137 AMREX_ENUM(RadiationType,
138  None, RRTMGP, Simple
139 );
140 
141 /**
142  * @brief Coordinate-axis selector.
143  */
144 enum struct Coord {
145  x, y, z
146 };
147 
148 // These are used as integers so must be enum not enum struct
149 /**
150  * @brief Rayleigh damping profile component indices.
151  */
152 enum Rayleigh {
154 };
155 
156 // These are used as integers so must be enum not enum struct
157 /**
158  * @brief Sponge reference-state component indices.
159  */
160 enum Sponge {
162 };
163 
164 /**
165  * @brief The moisture data carried by the active microphysics scheme.
166  *
167  * This struct is the single source of truth for the question "which moisture
168  * quantities does this run actually have?". Everything downstream of the
169  * microphysics -- source terms, turbulence closures, and every output path
170  * (3D plotfiles, 2D plotfiles, subvolumes) -- answers that question by querying
171  * this struct instead of enumerating MoistureType values, so a newly added
172  * scheme only has to declare its layout once, in from_moisture_model() below.
173  *
174  * Two kinds of index live here:
175  *
176  * 1. Conserved-state components (qv ... nn). Absolute component indices into
177  * the conserved state array, i.e. one of RhoQ1_comp ... RhoQ11_comp. They
178  * name the *rho-weighted* species: state(i,j,k,qv) is rho*qv, so an output
179  * path must divide by Rho_comp to recover the mixing ratio.
180  *
181  * 2. qmoist diagnostic slots (rain_accum ... cond_rate). Indices into the
182  * per-level qmoist vector that is filled from
183  * Microphysics::Get_Qmoist_Ptr(lev,idx). Each scheme chooses that
184  * layout independently, so the slot numbers differ between schemes and are
185  * recorded per scheme below.
186  *
187  * In both cases the value is `absent` when the active scheme does not carry the
188  * quantity, so `index >= 0` is the criterion for "this exists and is meaningful
189  * to write". That is deliberately *not* the same test as "the storage is
190  * allocated": several schemes allocate a wider state than they integrate (the
191  * Morrison class always allocates eleven moist components, so Morrison_NoIce
192  * owns ice slots it never fills), and writing those slots to a plotfile would
193  * publish untouched memory as if it were data.
194  */
196 
197  // Sentinel values shared by both kinds of index above.
198  static constexpr int absent = -1; //!< not carried by the active scheme
199  static constexpr int computed_from_state = -2; //!< carried, but derived at output
200  //!< time from the conserved state
201  //!< rather than read from a qmoist slot
202 
203  // ---------------------------------------------------------------------
204  // Conserved-state components: mass mixing ratios (rho-weighted)
205  // ---------------------------------------------------------------------
206  int qv = absent; //!< water vapor
207  int qc = absent; //!< cloud liquid water
208  int qi = absent; //!< cloud ice
209  int qr = absent; //!< rain
210  int qs = absent; //!< snow
211  int qg = absent; //!< graupel
212 
213  // ---------------------------------------------------------------------
214  // Conserved-state components: number concentrations (rho-weighted)
215  // ---------------------------------------------------------------------
216  int nc = absent; //!< cloud liquid water number
217  int ni = absent; //!< cloud ice number
218  int nr = absent; //!< rain number
219  int ns = absent; //!< snow number
220  int ng = absent; //!< graupel number
221  // CCN / total aerosol number. Unlike every other number concentration above,
222  // this has no companion mass species: it is an aerosol reservoir that
223  // exchanges number with nc and nr through activation and evaporation rather
224  // than a hydrometeor count. Kept distinct from ni, which is cloud ice number,
225  // even though some schemes place the two in the same conserved-state slot.
226  int nn = absent; //!< CCN / total aerosol number
227 
228  // ---------------------------------------------------------------------
229  // qmoist diagnostic slots
230  //
231  // These are *not* conserved-state components; they index the qmoist vector
232  // handed out by the microphysics interface. Slot numbers are scheme
233  // specific, which is exactly why they belong in this per-scheme map.
234  // ---------------------------------------------------------------------
235  int rain_accum = absent; //!< accumulated surface rain
236  int snow_accum = absent; //!< accumulated surface snow
237  int graup_accum = absent; //!< accumulated surface graupel
238  int rel_hum = absent; //!< relative humidity
239  int cond_rate = absent; //!< condensation rate
240 
241  /**
242  * @brief Construct the conserved-state component map.
243  *
244  * Prefer from_moisture_model() for production code: it fills in the qmoist
245  * diagnostic slots as well. This constructor exists for the callers -- unit
246  * tests and kernels exercised in isolation -- that only need the state map.
247  *
248  * @param qv_comp Water vapor component index.
249  * @param qc_comp Cloud liquid water component index.
250  * @param qi_comp Cloud ice component index.
251  * @param qr_comp Rain component index.
252  * @param qs_comp Snow component index.
253  * @param qg_comp Graupel component index.
254  * @param nc_comp Cloud liquid water number concentration component index.
255  * @param ni_comp Cloud ice number concentration component index.
256  * @param nr_comp Rain number concentration component index.
257  * @param ns_comp Snow number concentration component index.
258  * @param ng_comp Graupel number concentration component index.
259  * @param nn_comp CCN / total aerosol number concentration component index.
260  */
261  MoistureComponentIndices (int qv_comp, int qc_comp,
262  int qi_comp=absent,
263  int qr_comp=absent,
264  int qs_comp=absent,
265  int qg_comp=absent,
266  int nc_comp=absent,
267  int ni_comp=absent,
268  int nr_comp=absent,
269  int ns_comp=absent,
270  int ng_comp=absent,
271  int nn_comp=absent)
272  : qv(qv_comp), qc(qc_comp), qi(qi_comp), qr(qr_comp), qs(qs_comp), qg(qg_comp),
273  nc(nc_comp), ni(ni_comp), nr(nr_comp), ns(ns_comp), ng(ng_comp),
274  nn(nn_comp) {}
275 
276  /**
277  * @brief Construct an empty map, i.e. a dry run.
278  */
280 
281  /**
282  * @brief Build the complete index map -- conserved-state components and
283  * qmoist diagnostic slots -- for a moisture model.
284  *
285  * This is the one place a scheme declares what it carries. The conserved
286  * layout must match the component the scheme reads and writes in its
287  * Copy_State_to_Micro / Copy_Micro_to_State pair, and the qmoist slots must
288  * match the order the scheme installs in its MicVarMap. A slot that a
289  * scheme allocates but never fills is left `absent` on purpose: see the
290  * class comment for why allocation is not the criterion here.
291  *
292  * @param moisture_type Active moisture/microphysics model.
293  */
295  from_moisture_model (const MoistureType moisture_type)
296  {
298 
299  switch (moisture_type) {
300 
301  case MoistureType::None:
302  // Dry: no moisture data of any kind.
303  break;
304 
305  case MoistureType::MoistNoCondensation:
306  case MoistureType::SAM_NoPrecip_NoIce:
307  case MoistureType::Kessler_NoRain:
308  // Vapor plus suspended cloud water, no precipitation and no
309  // accumulation diagnostics.
310  mi.qv = RhoQ1_comp;
311  mi.qc = RhoQ2_comp;
312  break;
313 
314  case MoistureType::SatAdj:
315  // As above, but relative humidity is recovered from the state at
316  // output time rather than stored: SatAdj publishes no qmoist arrays.
317  mi.qv = RhoQ1_comp;
318  mi.qc = RhoQ2_comp;
320  break;
321 
322  case MoistureType::Kessler:
323  // Warm rain in three moist components; qmoist is {rain_accum}.
324  mi.qv = RhoQ1_comp;
325  mi.qc = RhoQ2_comp;
326  mi.qr = RhoQ3_comp;
327  mi.rain_accum = 0;
328  break;
329 
330  case MoistureType::SAM_NoIce:
331  // The SAM class always allocates six moist components, so rain sits
332  // in the fourth slot even with the ice species switched off.
333  mi.qv = RhoQ1_comp;
334  mi.qc = RhoQ2_comp;
335  mi.qr = RhoQ4_comp;
336  mi.rain_accum = 0;
337  break;
338 
339  case MoistureType::SAM:
340  case MoistureType::WSM6:
341  // Single-moment mixed phase; qmoist is
342  // {rain_accum, snow_accum, graup_accum}.
343  mi.qv = RhoQ1_comp;
344  mi.qc = RhoQ2_comp;
345  mi.qi = RhoQ3_comp;
346  mi.qr = RhoQ4_comp;
347  mi.qs = RhoQ5_comp;
348  mi.qg = RhoQ6_comp;
349  mi.rain_accum = 0;
350  mi.snow_accum = 1;
351  mi.graup_accum = 2;
352  break;
353 
354  case MoistureType::Morrison:
355  // Two-moment mixed phase: six mass species followed by five number
356  // concentrations.
357  mi.qv = RhoQ1_comp;
358  mi.qc = RhoQ2_comp;
359  mi.qi = RhoQ3_comp;
360  mi.qr = RhoQ4_comp;
361  mi.qs = RhoQ5_comp;
362  mi.qg = RhoQ6_comp;
363  mi.nc = RhoQ7_comp;
364  mi.ni = RhoQ8_comp;
365  mi.nr = RhoQ9_comp;
366  mi.ns = RhoQ10_comp;
367  mi.ng = RhoQ11_comp;
368  mi.rain_accum = 0;
369  mi.snow_accum = 1;
370  mi.graup_accum = 2;
371  break;
372 
373  case MoistureType::Morrison_NoIce:
374  // Liquid-only Morrison: the class still allocates all eleven moist
375  // components, but only vapor, cloud water and rain -- and the cloud
376  // and rain numbers -- are integrated, so the frozen species and
377  // their numbers stay absent here.
378  mi.qv = RhoQ1_comp;
379  mi.qc = RhoQ2_comp;
380  mi.qr = RhoQ4_comp;
381  mi.nc = RhoQ7_comp;
382  mi.nr = RhoQ9_comp;
383  mi.rain_accum = 0;
384  break;
385 
386  case MoistureType::WDM6:
387  // Double-moment warm phase on top of single-moment ice: nn is the
388  // aerosol reservoir and takes the slot Morrison uses for ice number,
389  // and there are no snow or graupel numbers.
390  mi.qv = RhoQ1_comp;
391  mi.qc = RhoQ2_comp;
392  mi.qi = RhoQ3_comp;
393  mi.qr = RhoQ4_comp;
394  mi.qs = RhoQ5_comp;
395  mi.qg = RhoQ6_comp;
396  mi.nc = RhoQ7_comp;
397  mi.nn = RhoQ8_comp;
398  mi.nr = RhoQ9_comp;
399  mi.rain_accum = 0;
400  mi.snow_accum = 1;
401  mi.graup_accum = 2;
402  break;
403 
404  case MoistureType::SuperDroplets:
405  // Lagrangian microphysics that still carries the six Eulerian mass
406  // species. Its qmoist layout is its own (see the MicVarMap in
407  // SuperDropletsMoist::Init): the graupel accumulation slot exists
408  // but is never filled, so it stays absent.
409  mi.qv = RhoQ1_comp;
410  mi.qc = RhoQ2_comp;
411  mi.qi = RhoQ3_comp;
412  mi.qr = RhoQ4_comp;
413  mi.qs = RhoQ5_comp;
414  mi.qg = RhoQ6_comp;
415  mi.cond_rate = 3;
416  mi.rel_hum = 7;
417  mi.rain_accum = 8;
418  mi.snow_accum = 10;
419  break;
420 
421  default:
422  amrex::Abort("Unknown MoistureType in MoistureComponentIndices::from_moisture_model");
423  }
424 
425  return mi;
426  }
427 
428  /**
429  * @brief An ordered list of conserved-state components forming an aggregate
430  * moisture output variable (qt, qn, qp, moist_density).
431  *
432  * Only the species the active scheme carries are appended, so a consumer can
433  * sum the list without first asking which ones exist.
434  */
435  struct CompList {
436  static constexpr int max_size = 6; //!< qv, qc, qi, qr, qs, qg
438  int size = 0;
439 
440  //! Append a component, ignoring the ones the scheme does not carry.
441  void append (int c) {
442  if ( (c >= 0) && (size < max_size) ) { comp[size++] = c; }
443  }
444  [[nodiscard]] bool empty () const { return (size == 0); }
445  };
446 
447  /**
448  * @brief Components summed for total water, "qt": every mass mixing ratio.
449  *
450  * Number concentrations are excluded -- they are counts, not masses.
451  */
452  [[nodiscard]] CompList total_water_comps () const {
453  CompList list;
454  list.append(qv); list.append(qc); list.append(qi);
455  list.append(qr); list.append(qs); list.append(qg);
456  return list;
457  }
458 
459  /**
460  * @brief Components summed for non-precipitating water, "qn": vapor plus the
461  * suspended condensate. Also the moist part of "moist_density".
462  */
463  [[nodiscard]] CompList nonprecipitating_comps () const {
464  CompList list;
465  list.append(qv); list.append(qc); list.append(qi);
466  return list;
467  }
468 
469  /**
470  * @brief Components summed for precipitating water, "qp": the falling species.
471  */
472  [[nodiscard]] CompList precipitating_comps () const {
473  CompList list;
474  list.append(qr); list.append(qs); list.append(qg);
475  return list;
476  }
477 
478  /**
479  * @brief Test whether a conserved-state component holds one of the moisture
480  * variables this scheme carries.
481  *
482  * Use this rather than enumerating moisture models when deciding whether a
483  * "rhoQn" state component is meaningful for the active scheme.
484  *
485  * @param comp Absolute component index into the conserved state array.
486  */
487  [[nodiscard]] bool has_comp (int comp) const {
488  return ( (comp >= 0) &&
489  ( (comp == qv) || (comp == qc) || (comp == qi) ||
490  (comp == qr) || (comp == qs) || (comp == qg) ||
491  (comp == nc) || (comp == ni) || (comp == nr) ||
492  (comp == ns) || (comp == ng) || (comp == nn) ) );
493  }
494 
495  /**
496  * @brief Test whether the active scheme carries rain, snow and graupel in the
497  * RhoQ4/RhoQ5/RhoQ6 slots assumed by erf_derreflectivity and
498  * erf_dermaxreflectivity.
499  *
500  * Those kernels read the precipitating species by hardcoded component, so this
501  * checks the layout and not just the presence of the species.
502  */
503  [[nodiscard]] bool has_reflectivity_species () const {
504  return ( (qr == RhoQ4_comp) && (qs == RhoQ5_comp) && (qg == RhoQ6_comp) );
505  }
506 
507  /**
508  * @brief Test whether the active scheme carries any moisture at all.
509  *
510  * Every moist scheme allocates water vapor, so this is equivalent to testing
511  * moisture_type != MoistureType::None without needing the enum.
512  */
513  [[nodiscard]] bool has_moisture () const { return (qv >= 0); }
514 
515  /**
516  * @brief The conserved-state component behind a single-species output name,
517  * or `absent` if the name is not a single species or the scheme does
518  * not carry it.
519  *
520  * An output path can use this to copy a species without repeating the
521  * name-to-component mapping.
522  *
523  * @param name Derived or plot variable name.
524  */
525  [[nodiscard]] int comp_for_var (const std::string& name) const {
526  if (name == "qv") { return qv; }
527  if (name == "qc") { return qc; }
528  if (name == "qi") { return qi; }
529  if (name == "qrain") { return qr; }
530  if (name == "qsnow") { return qs; }
531  if (name == "qgraup") { return qg; }
532  if (name == "nc") { return nc; }
533  if (name == "ni") { return ni; }
534  if (name == "nr") { return nr; }
535  if (name == "ns") { return ns; }
536  if (name == "ng") { return ng; }
537  if (name == "nn") { return nn; }
538  return absent;
539  }
540 
541  /**
542  * @brief The qmoist slot behind a moist diagnostic output name.
543  *
544  * Returns `absent` when the scheme does not provide the diagnostic, and
545  * `computed_from_state` when it does provide it but not through a qmoist
546  * array -- in that case the caller must derive it from the conserved state.
547  *
548  * @param name Derived or plot variable name.
549  */
550  [[nodiscard]] int qmoist_index_for_var (const std::string& name) const {
551  if (name == "rain_accum") { return rain_accum; }
552  if (name == "snow_accum") { return snow_accum; }
553  if (name == "graup_accum") { return graup_accum; }
554  if (name == "rel_humidity") { return rel_hum; }
555  if (name == "condensation_rate") { return cond_rate; }
556  return absent;
557  }
558 
559  /**
560  * @brief Whether this map decides a variable's availability, and if so
561  * whether the variable is available.
562  */
564  bool governed = false; //!< the name is a moisture output variable
565  bool available = false; //!< the active scheme carries the data behind it
566  };
567 
568  /**
569  * @brief Classify an output variable name against this index map.
570  *
571  * This is the one table pairing output names with the data behind them. It
572  * is driven off the scheme's index map rather than an enumerated list of
573  * moisture models, so it stays correct as schemes are added. Names with no
574  * moisture dependence come back not-governed, which lets a caller walk a
575  * mixed list of variable names and only defer to this map where it applies.
576  *
577  * @param name Derived or plot variable name.
578  */
579  [[nodiscard]] VarAvailability query_var (const std::string& name) const {
580 
581  // Single species, taken straight from the conserved state
582  if ( (name == "qv") || (name == "qc") || (name == "qi") ||
583  (name == "qrain") || (name == "qsnow") || (name == "qgraup") ||
584  (name == "nc") || (name == "ni") || (name == "nr") ||
585  (name == "ns") || (name == "ng") || (name == "nn") ) {
586  return {true, comp_for_var(name) >= 0};
587  }
588 
589  // Moist diagnostics, either from a qmoist array or derived at output time
590  if ( (name == "rain_accum") || (name == "snow_accum") ||
591  (name == "graup_accum") || (name == "rel_humidity") ||
592  (name == "condensation_rate") ) {
593  return {true, qmoist_index_for_var(name) != absent};
594  }
595 
596  // Aggregates over several species
597  if (name == "qt") { return {true, !total_water_comps().empty()}; }
598  if (name == "qp") { return {true, !precipitating_comps().empty()}; }
599 
600  // Non-precipitating water is vapor plus the suspended condensate, and
601  // moist density adds that same sum to the dry density
602  if ( (name == "qn") || (name == "moist_density") ) {
603  return {true, (qv >= 0) && (qc >= 0)};
604  }
605 
606  // Column and thermodynamic diagnostics that read vapor only
607  if ( (name == "qsat") || (name == "precipitable") ) {
608  return {true, has_moisture()};
609  }
610 
611  return {false, false};
612  }
613 
614  /**
615  * @brief Test whether the moist species behind a derived/plot variable name is
616  * carried by the active scheme.
617  *
618  * Names this map does not govern return true, so this can be used directly as
619  * a filter over a mixed list of variable names. Use query_var() instead when
620  * the caller needs to distinguish "not a moisture variable" from "available".
621  *
622  * @param name Derived or plot variable name.
623  */
624  [[nodiscard]] bool has_derived_var (const std::string& name) const {
625  const VarAvailability status = query_var(name);
626  return (!status.governed) || status.available;
627  }
628 };
629 
630 /**
631  * Container holding many of the algorithmic options and parameters
632  */
633 
634 struct SolverChoice {
635  public:
636  /**
637  * @brief Read solver-wide algorithmic options from the input parameter database.
638  * @param max_level Maximum AMR level configured for the run.
639  * @param pp_prefix ParmParse prefix for the ERF input namespace.
640  */
641  void init_params (int max_level, std::string pp_prefix)
642  {
643  amrex::ParmParse pp(pp_prefix);
644 
645  bool bogus_bool;
646  if (pp.query("use_terrain",bogus_bool) > 0) {
647  amrex::Error("The input use_terrain is deprecated. Set terrain_type instead.");
648  }
649 
650  if (pp.query("use_moist_background",bogus_bool) > 0) {
651  amrex::Error("The input use_moist_background is deprecated. Set init_type = MoistBaseState instead.");
652  }
653 
654  // Do we set map scale factors to myhalf instead of 1 for testing?
655  pp.queryAdd("test_mapfactor", test_mapfactor);
656 
657  // Which horizontal pressure gradient formulation to use with terrain fitted coords?
658  // 0: dp/dx with dp/dz correction (default)
659  // 1: gradient of vertically interpolated p, see Klemp 2011
660  pp.queryAdd("gradp_type", gradp_type);
662 
663  // For the lateral pressure gradient to be used in the momentum equation, should we
664  // take the x- and y-derivatives of the perturbational pressure or the full pressure?
665  pp.queryAdd("use_pert_pres_gradient", use_pert_pres_gradient);
666 
667  // What type of moisture model to use?
668  moisture_type = MoistureType::None; // Default
669  if (pp.query("moisture_type",moisture_type) > 0) {
670  amrex::Error("The input moisture_type is deprecated. Set moisture_model instead.");
671  }
672 
673  pp.query_enum_case_insensitive("moisture_model",moisture_type);
674 
675  // Register the moisture data this scheme carries: conserved-state
676  // components and qmoist diagnostic slots alike. MoistureComponentIndices
677  // is the one place that mapping lives, and every consumer -- source terms,
678  // turbulence closures, and the plotfile/subvolume writers -- queries it
679  // instead of testing moisture_type.
681 
682  // Set a default for both dry and moist
683  buoyancy_type.resize(max_level+1);
684  for (int i = 0; i <= max_level; ++i) {
685  buoyancy_type[i] = 1; // uses Rhoprime
686  }
687 
688  if (moisture_type != MoistureType::None) {
689  pp.queryAdd("moisture_tight_coupling",moisture_tight_coupling);
690  }
691 
692  // Which expression (1,2/3 or 4) to use for buoyancy
693  int default_buoyancy_type = buoyancy_type[0];
694  read_int_string(max_level, "buoyancy_type", buoyancy_type, default_buoyancy_type);
695 
696  // What type of land surface model to use
697  lsm_type = LandSurfaceType::None; // Default
698  pp.query_enum_case_insensitive("land_surface_model",lsm_type);
699 
700  // Will an external ocean coupler supply SST for part or all of the water
701  // cells this run? The surface layer needs to know this it in time to select
702  // ThetaCalcType::SURFACE_TEMPERATURE, which is long before the first
703  // ApplyOceanSurfaceState call.
704  pp.queryAdd("use_coupled_sst", use_coupled_sst);
705 
706  read_int_string(max_level, "is_land", is_land, 1);
707  for (int lev = 0; lev <= max_level; ++lev) {
708  if (is_land[lev] == 1) {
709  amrex::Print() << "Level " << lev << " is land" << std::endl;
710  } else if (is_land[lev] == 0) {
711  amrex::Print() << "Level " << lev << " is water" << std::endl;
712  } else {
713  amrex::Error("is_land should be 0 or 1");
714  }
715  }
716 
717  // What type of radiation model to use
718  rad_type = RadiationType::None; // Default
719  pp.query_enum_case_insensitive("radiation_model", rad_type);
720 
721  // Verify that radiation model cannot be RRTMGP if ERF was not compiled with RRTMGP
722 #ifndef ERF_USE_RRTMGP
723  if (rad_type == RadiationType::RRTMGP)
724  {
725  amrex::Error("ERF was not compiled with RRTMGP enabled!");
726  }
727 #endif
728 
729  // Is the terrain none, static or moving?
730  std::string terrain_type_temp = "";
731  pp.queryAdd("terrain_type", terrain_type_temp);
732  if (terrain_type_temp == "Moving") {
733  amrex::Warning("erf.terrain_type = Moving is deprecated; please replace Moving by MovingFittedMesh");
734  terrain_type = TerrainType::MovingFittedMesh;
735  } else if (terrain_type_temp == "Static") {
736  amrex::Warning("erf.terrain_type = Static is deprecated; please replace Static by StaticFittedMesh");
737  terrain_type = TerrainType::StaticFittedMesh;
738  } else {
739  pp.query_enum_case_insensitive("terrain_type",terrain_type);
740  }
741 
742  // Get buildings type
743  std::string buildings_type_temp = "";
744  pp.queryAdd("buildings_type", buildings_type_temp);
745  if (buildings_type_temp == "ImmersedForcing") {
746  buildings_type = BuildingsType::ImmersedForcing;
747  }
748 
749  //
750  // Read the init_type here to make sure we correctly set the mesh and terrain types
751  //
752  std::string init_type_temp_string;
753 
754  int found = pp.queryAdd("init_type",init_type_temp_string);
755 
756  if ( (init_type_temp_string == "Real") || (init_type_temp_string == "real") ) {
757  amrex::Error("erf.init_type = Real is deprecated; please replace Real by WRFInput");
758  } else if ( (init_type_temp_string == "Ideal") || (init_type_temp_string == "ideal") ) {
759  amrex::Error("erf.init_type = Ideal is deprecated; please replace Ideal by WRFInput");
760  } else {
761  pp.query_enum_case_insensitive("init_type",init_type);
762  use_real_bcs = ( (init_type == InitType::WRFInput) || (init_type == InitType::Metgrid) );
763  }
764 
765  if ( (init_type == InitType::WRFInput) || (init_type == InitType::Metgrid) ) {
766  if (terrain_type != TerrainType::StaticFittedMesh) {
767  amrex::Error("Only terrain_type = StaticFittedMesh are allowed with init_type = WRFInput or Metgrid");
768  }
769  }
770 
771  if (init_type == InitType::MoistBaseState) {
772  if (moisture_type == MoistureType::None) {
773  amrex::Error("Makes no sense to have moist base state with no moisture model");
774  }
775  }
776 
777  if (init_type == InitType::WRFInput) {
778  if (moisture_type == MoistureType::None) {
779  amrex::Error("Can't have moisture_type = None with init_type = WRFInput");
780  }
781 
782  // NetCDF wrfbdy lateral boundary file
783  std::string nc_bdy_file_temp_string;
784  bool has_bdy = pp.queryAdd("nc_bdy_file", nc_bdy_file_temp_string);
785  if (!has_bdy) use_real_bcs = false;
786 
787  bool use_real_bcs_temp = use_real_bcs;
788  pp.queryAdd("use_real_bcs", use_real_bcs_temp);
789  if (use_real_bcs && !use_real_bcs_temp) {
790  use_real_bcs = false;
791  }
792  }
793 
794  if (found == 0 || init_type == InitType::None) {
795  amrex::Print() << "init_type must now be set. The options are " << std::endl;
796  amrex::Print() << " Input_Sounding, NCFile, WRFInput, Metgrid, Uniform, " << std::endl;
797  amrex::Print() << " ConstantDensity, Isentropic, MoistBaseState, or HindCast " << std::endl;
798  amrex::Error("Please add a string for init_type to your inputs file or command line");
799  }
800 
801  // How to interpret input_sounding
802  if (init_type == InitType::Input_Sounding) {
803  pp.query_enum_case_insensitive("sounding_type",sounding_type);
804  }
805 
806  if (terrain_type == TerrainType::StaticFittedMesh ||
807  terrain_type == TerrainType::MovingFittedMesh) {
808  mesh_type = MeshType::VariableDz;
809  }
810 
811  if ( (moisture_type == MoistureType::SAM ||
812  moisture_type == MoistureType::SAM_NoIce ||
813  moisture_type == MoistureType::SAM_NoPrecip_NoIce ) &&
814  (mesh_type == MeshType::VariableDz) )
815  {
816  amrex::Abort("SAM is not correct with variable dz -- choose another moisture model");
817  }
818 
819  pp.queryAdd("grid_stretching_ratio", grid_stretching_ratio);
820  if (grid_stretching_ratio != 0) {
822  "The grid stretching ratio must be greater than 1");
823  }
824  if (grid_stretching_ratio >= 1) {
825  if (terrain_type == TerrainType::None) {
826  terrain_type = TerrainType::StaticFittedMesh;
827  }
828  if (mesh_type == MeshType::ConstantDz) {
829  mesh_type = MeshType::StretchedDz;
830  }
831  pp.queryAdd("zsurface", zsurf);
832  if (zsurf != zero) {
833  amrex::Print() << "Nominal zsurface height != 0, may result in unexpected behavior"
834  << std::endl;
835  }
836  pp.get("initial_dz", dz0);
837  }
838 
839  int n_zlevels = pp.countval("terrain_z_levels");
840  if (n_zlevels > 0)
841  {
842  if (terrain_type == TerrainType::None) {
843  terrain_type = TerrainType::StaticFittedMesh;
844  }
845  if (mesh_type == MeshType::ConstantDz) {
846  mesh_type = MeshType::StretchedDz;
847  }
848  }
849 
850  // Use lagged_delta_rt in the fast integrator?
851  pp.queryAdd("use_lagged_delta_rt", use_lagged_delta_rt);
852 
853  // Average the input z-face heights onto the nodes, or reconstruct our own
854  pp.queryAdd("avg_grid_faces_to_nodes",avg_grid_faces_to_nodes);
855 
856  // Catch the old name for the flag above so the error says what to do
857  // rather than silently ignoring the setting.
858  if (pp.contains("use_wrf_height_grid")) {
859  amrex::Abort("erf.use_wrf_height_grid has been renamed. "
860  "Set erf.avg_grid_faces_to_nodes instead; it carries "
861  "the same meaning (average the input z-face heights "
862  "onto the nodes rather than reconstructing them).");
863  }
864 
865  // Rebalance wrf state?
866  pp.queryAdd("rebalance_wrf_input", rebalance_wrf_input);
867 
868  // Must rebalance if the nodal heights were reconstructed rather than averaged
870  amrex::Print() << "Must rebalance when not averaging the input height grid. Setting rebalance_wrf_input to true \n";
871  rebalance_wrf_input = true;
872  }
873 
874  // These default to true but are used for unit testing
875  pp.queryAdd("use_gravity", use_gravity);
876 
877  // Initializing from Metgrid or WRFInput without gravity makes no sense
878  if ( !use_gravity && ( (init_type == InitType::WRFInput) || (init_type == InitType::Metgrid) ) ) {
879  amrex::Print() << "Setting use_gravity to true due to init_type = WRFInput / Metgrid " << std::endl;
880  use_gravity = true;
881  }
882 
884 
885  pp.queryAdd("c_p", c_p);
886  rdOcp = R_d / c_p;
887 
888  // *******************************************************************************
889  // Read anelastic etc and over-ride if necessary
890  // *******************************************************************************
891 
892  read_int_string(max_level, "anelastic", anelastic, 0);
893  read_int_string(max_level, "fixed_density", fixed_density, 0);
894  read_int_string(max_level, "project_initial_velocity", project_initial_velocity, 0);
895 
896  bool any_anelastic = false;
897  bool any_compress = false;
898  for (int i = 0; i <= max_level; ++i) {
899  if (anelastic[i] == 1) {
901  fixed_density[i] = 1; // We default to true but are allowed to override below
902  buoyancy_type[i] = 3; // (This isn't actually used when anelastic is set)
903  any_anelastic = true;
904  } else {
905  any_compress = true;
906  }
907  }
908 
909  // Want to have different immersed forcing defaults depending on anelastic or fully compressible.
910  // We should have different starting values because the stability of the method is dependent on dt.
911  // dt is coarser for anelastic --> need to loosen stiffness of immersed forcing.
912  if (any_anelastic) {
913  immersed_forcing_substep = false;
914  if_Cd_momentum = amrex::Real(50.0);
915  if_Cd_scalar = amrex::Real(5.0);
916  } else {
918  if_Cd_momentum = amrex::Real(500.0);
919  if_Cd_scalar = amrex::Real(50.0);
920  }
921 
922  // *******************************************************************************
923  // Read substepping_type and allow for different values at each level
924  // *******************************************************************************
925  substepping_type.resize(max_level+1);
926 
927  for (int i = 0; i <= max_level; i++) {
928  substepping_type[i] = SubsteppingType::Implicit;
929  }
930 
931  for (int i = 0; i <= max_level; i++) {
933  pp, "substepping_type", substepping_type[i], i, max_level);
934  }
935 
936  pp.queryAdd("substepping_diag", substepping_diag);
937 
938  pp.queryAdd("beta_s", beta_s);
939 
940 
941 
942  // *******************************************************************************
943  // Error check on deprecated input
944  // *******************************************************************************
945  int nvals_old = pp.countval("no_substepping");
946  if (nvals_old > 0) {
947  amrex::Error("The no_substepping flag is deprecated -- set substepping_type instead");
948  }
949 
950  // *******************************************************************************
951 
952  pp.queryAdd("ncorr", ncorr);
953  pp.queryAdd("poisson_abstol", poisson_abstol);
954  pp.queryAdd("poisson_reltol", poisson_reltol);
955 #ifdef AMREX_USE_FLOAT
956  poisson_abstol = amrex::max(poisson_abstol,amrex::Real(1e-6));
957  poisson_reltol = amrex::max(poisson_reltol,amrex::Real(1e-6));
958 #endif
959  for (int lev = 0; lev <= max_level; lev++) {
960  if (anelastic[lev] != 0)
961  {
962  substepping_type[lev] = SubsteppingType::None;
963  }
964  }
965 
966  pp.queryAdd("force_stage1_single_substep", force_stage1_single_substep);
967 
968  // Include Coriolis forcing?
969  pp.queryAdd("use_coriolis", use_coriolis);
970  pp.queryAdd("variable_coriolis", variable_coriolis);
971 
972  // Include four stream radiation approximation
973  pp.queryAdd("four_stream_radiation", four_stream_radiation);
974 
975  // flags for whether to apply other source terms in substep only
976  pp.queryAdd("immersed_forcing_substep", immersed_forcing_substep); // apply immersed forcing source terms in substep only
977  pp.queryAdd("forest_substep", forest_substep); // apply canopy-related source terms in substep only
978 
979  // Fixed-leaf-temperature canopy heat exchange
980  pp.query("forest_biophysics", forest_biophysics);
981  pp.query("forest_biophysics_heat", forest_biophysics_heat);
982  pp.query("forest_leaf_theta_fixed", forest_leaf_theta_fixed);
983 
986  "forest_biophysics_heat requires forest_biophysics = true");
990  "forest_biophysics_heat requires a positive forest_leaf_theta_fixed");
993  "forest_leaf_theta_fixed requires forest_biophysics_heat = true");
994 
995  // immersed forcing parameters
996  pp.queryAdd("if_Cd_momentum", if_Cd_momentum);
997  pp.queryAdd("if_Cd_scalar", if_Cd_scalar);
998  pp.queryAdd("if_implicit_drag", if_implicit_drag); // flag for implicit vs. explicit drag formulation
999  pp.queryAdd("if_z0", if_z0);
1000  pp.queryAdd("if_surf_temp_flux", if_surf_temp_flux);
1001  pp.queryAdd("if_init_surf_temp", if_init_surf_temp);
1002 
1003  pp.queryAdd("if_surf_heating_rate", if_surf_heating_rate);
1004 
1005  // Modify rate to be in units of K / s rather than K / hr
1006  if_surf_heating_rate /= amrex::Real(3600.0); // [K/s]
1007 
1008  pp.queryAdd("if_Olen", if_Olen_in);
1009  pp.queryAdd("if_use_most",if_use_most);
1010  pp.queryAdd("if_stability_correction",if_stability_correction);
1011  pp.queryAdd("if_ws_floor",if_ws_floor);
1012  pp.queryAdd("if_damp_alpha",if_damp_alpha);
1013 
1014  if ((if_init_surf_temp > zero && if_surf_temp_flux != amrex::Real(1e-8)) ||
1015  (if_init_surf_temp > zero && if_Olen_in != amrex::Real(1e-8)) ||
1016  (if_Olen_in != amrex::Real(1e-8) && if_surf_temp_flux != amrex::Real(1e-8)))
1017  {
1018  amrex::Error("Can only specify one of init_surf_temp, surf_temp_flux, or Olen");
1019  }
1020 
1021  // Flag to do MOST rotations with terrain
1022  pp.queryAdd("use_rotate_surface_flux",use_rotate_surface_flux);
1024  AMREX_ASSERT_WITH_MESSAGE(terrain_type != TerrainType::None,"MOST stress rotations are only valid with terrain!");
1025  }
1026 
1027  // Which external forcings?
1028  abl_driver_type = ABLDriverType::None; // Default: no ABL driver for simulating classical fluid dynamics problems
1029  pp.query_enum_case_insensitive("abl_driver_type",abl_driver_type);
1030  pp.queryAdd("const_massflux_u", const_massflux_u);
1031  pp.queryAdd("const_massflux_v", const_massflux_v);
1032  pp.queryAdd("const_massflux_tau", const_massflux_tau);
1033  pp.queryAdd("const_massflux_layer_lo", const_massflux_layer_lo);
1034  pp.queryAdd("const_massflux_layer_hi", const_massflux_layer_hi);
1035 
1036  // Which type of inflow turbulent generation
1037  pert_type.resize(max_level+1);
1038  for (int lev = 0; lev <= max_level; ++lev) {
1039  pert_type[lev] = PerturbationType::None; // Default
1041  pp, "perturbation_type", pert_type[lev], lev, max_level);
1042  }
1043 
1044  amrex::Vector<amrex::Real> abl_pressure_grad_in = {zero, zero, zero};
1045  pp.queryarr("abl_pressure_grad",abl_pressure_grad_in);
1046  for(int i = 0; i < AMREX_SPACEDIM; ++i) abl_pressure_grad[i] = abl_pressure_grad_in[i];
1047 
1048  amrex::Vector<amrex::Real> abl_geo_forcing_in = {zero, zero, zero};
1049  if(pp.queryarr("abl_geo_forcing",abl_geo_forcing_in)) {
1050  amrex::Print() << "Specified abl_geo_forcing: (";
1051  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
1052  abl_geo_forcing[i] = abl_geo_forcing_in[i];
1053  amrex::Print() << abl_geo_forcing[i] << " ";
1054  }
1055  amrex::Print() << ")" << std::endl;
1056  }
1057 
1058  if (use_coriolis)
1059  {
1061  }
1062 
1063  pp.queryAdd("add_custom_rhotheta_forcing", custom_rhotheta_forcing);
1064  pp.queryAdd("add_custom_moisture_forcing", custom_moisture_forcing);
1065  pp.queryAdd("add_custom_w_subsidence", custom_w_subsidence);
1066  pp.queryAdd("add_do_theta_advection", do_theta_advection); // If true, apply custom subsidence to (rho*theta) when add_custom_w_subsidence is used
1067  pp.queryAdd("add_do_mom_advection", do_mom_advection); // If true, apply custom subsidence to momentum when add_custom_w_subsidence is used
1068  pp.queryAdd("add_custom_geostrophic_profile", custom_geostrophic_profile);
1069  pp.queryAdd("custom_forcing_uses_primitive_vars", custom_forcing_prim_vars);
1070  pp.queryAdd("spatial_rhotheta_forcing", spatial_rhotheta_forcing);
1071  pp.queryAdd("spatial_moisture_forcing", spatial_moisture_forcing);
1072 
1073  pp.queryAdd("nudging_from_input_sounding", nudging_from_input_sounding);
1074 
1075  int nudging_u_z1_set = pp.queryAdd("nudging_u_z1", nudging_u_z1);
1076  int nudging_u_z2_set = pp.queryAdd("nudging_u_z2", nudging_u_z2);
1077  pp.queryAdd("nudging_t_z1", nudging_t_z1);
1078  pp.queryAdd("nudging_t_z2", nudging_t_z2);
1079  pp.queryAdd("nudging_q_z1", nudging_q_z1);
1080  pp.queryAdd("nudging_q_z2", nudging_q_z2);
1081 
1083  "nudging_u_z1 must be less than or equal to nudging_u_z2");
1085  "nudging_t_z1 must be less than or equal to nudging_t_z2");
1087  "nudging_q_z1 must be less than or equal to nudging_q_z2");
1088 
1089  pp.queryAdd("nudging_u", nudging_u);
1090  pp.queryAdd("nudging_t", nudging_t);
1091  pp.queryAdd("nudging_q", nudging_q);
1092 
1093  pp.queryAdd("large_scale_forcing", large_scale_forcing);
1094 
1096  if (!nudging_u) {
1097  amrex::Print() << "WARNING: erf.nudging_u = false has no effect when erf.large_scale_forcing "
1098  "= true; momentum nudging is then controlled solely by large_scale_forcing.\n";
1099  }
1100  if (nudging_u_z1_set || nudging_u_z2_set) {
1101  amrex::Print() << "WARNING: erf.nudging_u_z1/erf.nudging_u_z2 are ignored when "
1102  "erf.large_scale_forcing = true; momentum nudging is then applied "
1103  "at all heights.\n";
1104  }
1105  }
1106 
1109  "Should not have both abl_geo_wind_table and custom_geostrophic_profile set.");
1110 
1111  pp.queryAdd("Ave_Plane", ave_plane);
1112 
1113  // Use numerical diffusion?
1114  pp.queryAdd("num_diff_coeff",num_diff_coeff);
1116  "Numerical diffusion coefficient must be between 0 & one");
1117  use_num_diff = (num_diff_coeff > 0);
1118  if (use_num_diff) {
1119  amrex::Print() << "6th-order numerical diffusion turned on with coefficient = "
1120  << num_diff_coeff << std::endl;
1121  num_diff_coeff *= amrex::Math::powi<-6>(two);
1122  }
1123 
1124  advChoice.init_params(pp_prefix);
1125  diffChoice.init_params(pp_prefix);
1126  dampingChoice.init_params(pp_prefix);
1127  spongeChoice.init_params(pp_prefix);
1128  ebChoice.init_params(pp_prefix);
1129 
1130  turbChoice.resize(max_level+1);
1131  for (int lev = 0; lev <= max_level; lev++) {
1132  turbChoice[lev].init_params(lev,max_level,pp_prefix);
1133  }
1134 
1135  vert_implicit_fac.resize(max_level+1);
1136  for (int lev = 0; lev <= max_level; lev++) {
1137  vert_implicit_fac[lev].resize(3);
1138  vert_implicit_fac[lev][0] = one;
1139  vert_implicit_fac[lev][1] = one;
1140  vert_implicit_fac[lev][2] = zero;
1141  }
1142 
1143  // YSU PBL: use consistent coriolis frequency
1144  for (int lev = 0; lev <= max_level; lev++) {
1145  if (turbChoice[lev].pbl_ysu_use_consistent_coriolis) {
1146  if (use_coriolis) {
1147  turbChoice[lev].pbl_ysu_coriolis_freq = coriolis_factor * sinphi;
1148  if (lev == 0) {
1149  amrex::Print() << "YSU PBL using ERF coriolis frequency: " << turbChoice[lev].pbl_ysu_coriolis_freq << std::endl;
1150  }
1151  } else {
1152  amrex::Error("YSU cannot use ERF coriolis frequency if not using coriolis");
1153  }
1154  }
1155  }
1156  // MRF
1157  for (int lev = 0; lev <= max_level; lev++) {
1158  if (turbChoice[lev].pbl_ysu_use_consistent_coriolis) {
1159  if (use_coriolis) {
1160  turbChoice[lev].pbl_ysu_coriolis_freq = coriolis_factor * sinphi;
1161  if (lev == 0) {
1162  amrex::Print() << "MRF PBL using ERF coriolis frequency: " << turbChoice[lev].pbl_ysu_coriolis_freq << std::endl;
1163  }
1164  } else {
1165  amrex::Error("MRF cannot use ERF coriolis frequency if not using coriolis");
1166  }
1167  }
1168  }
1169 
1170  // What's the strength of the bdy nudging?
1171  pp.queryAdd("bdy_nudge_factor",bdy_nudge_factor);
1172 
1173  // Optionally use the dry-air density reconstructed from wrfbdy.
1174  pp.queryAdd("use_wrf_bdy_density", use_wrf_bdy_density);
1175 
1176  // Optionally ingest cloud water and cloud ice from wrfinput/wrfbdy.
1177  pp.queryAdd("use_wrf_bdy_qc_qi", use_wrf_bdy_qc_qi);
1178 
1179  if (!use_real_bcs || init_type != InitType::WRFInput) {
1180  use_wrf_bdy_density = false;
1181  }
1182 
1183  pp.queryAdd("bdy_rho_nudge_factor", bdy_rho_nudge_factor);
1184 
1185  // Which approach to nudging the moist variables in the boundary region?
1186  pp.queryAdd("bdy_moist_nudge_type",bdy_moist_nudge_type);
1187  if (bdy_moist_nudge_type < 0 || bdy_moist_nudge_type > 3) {
1188  amrex::Error("erf.bdy_moist_nudge_type must be one of 0, 1, 2, or 3");
1189  }
1190  if (bdy_moist_nudge_type == 3 && !use_wrf_bdy_qc_qi) {
1191  amrex::Error("erf.bdy_moist_nudge_type = 3 requires erf.use_wrf_bdy_qc_qi = true");
1192  }
1193  if (use_wrf_bdy_qc_qi) {
1194  if (moisture_type == MoistureType::None) {
1195  amrex::Error("erf.use_wrf_bdy_qc_qi requires an active moisture model");
1196  }
1197  if (!use_real_bcs || init_type != InitType::WRFInput) {
1198  amrex::Error("erf.use_wrf_bdy_qc_qi requires WRFInput real boundary conditions");
1199  }
1202  amrex::Error("erf.use_wrf_bdy_qc_qi requires active qv and qc component indices");
1203  }
1204  const int optional_moisture_comps[] = {moisture_indices.qi,
1208  for (const int comp : optional_moisture_comps) {
1209  if (comp != -1 && (comp < RhoQ1_comp || comp > RhoQ11_comp)) {
1210  amrex::Error("erf.use_wrf_bdy_qc_qi found an invalid active moisture component index");
1211  }
1212  }
1213  }
1214 
1215  // Are me transporting the scalar component?
1216  pp.queryAdd("transport_scalar",transport_scalar);
1217 
1218  for (int lev = 0; lev <= max_level; ++lev) {
1219  if (turbChoice[lev].uses_eamxx_shoc()) {
1220  use_eamxx_shoc = true;
1221  }
1222  if (turbChoice[lev].uses_native_shoc()) {
1223  use_native_shoc = true;
1225  }
1226  }
1227 
1228  // Set up the vertical implicit diffusion solve
1229  int n_impfac = pp.countval("vert_implicit_fac");
1230  AMREX_ALWAYS_ASSERT(n_impfac == 0 || n_impfac == 1 || n_impfac==3);
1231  if (n_impfac == 1) {
1232  amrex::Real fac_in;
1233  pp.get("vert_implicit_fac", fac_in);
1234  for (int lev = 0; lev <= max_level; lev++) {
1235  for (int i=0; i<3; ++i) {
1236  vert_implicit_fac[lev][i] = fac_in;
1237  }
1238  }
1239  } else if (n_impfac == 3) {
1240  for (int lev = 0; lev <= max_level; lev++) {
1241  pp.getarr("vert_implicit_fac", vert_implicit_fac[lev]);
1242  }
1243  }
1244 
1245  // Record whether the user explicitly requested these
1246  const bool user_set_imp_thermal = pp.contains("implicit_thermal_diffusion");
1247  const bool user_set_imp_moisture = pp.contains("implicit_moisture_diffusion");
1248  const bool user_set_imp_ke = pp.contains("implicit_ke_diffusion");
1249  const bool user_set_imp_momentum = pp.contains("implicit_momentum_diffusion");
1250 
1251  // If true (default), include implicit contributions to vertical thermal diffusion
1252  pp.queryAdd("implicit_thermal_diffusion", implicit_thermal_diffusion);
1253 
1254  // If true (default), include implicit contributions to vertical moisture diffusion
1255  pp.queryAdd("implicit_moisture_diffusion", implicit_moisture_diffusion);
1256 
1257  // If true (default), include implicit contributions to vertical KE diffusion
1258  pp.queryAdd("implicit_ke_diffusion", implicit_ke_diffusion);
1259 
1260  // If true (default), include implicit contributions in tau13, tau23,
1261  pp.queryAdd("implicit_momentum_diffusion", implicit_momentum_diffusion);
1262 
1263  // The default is true (i.e. that it happens before the acoustic substepping).
1264  pp.queryAdd("implicit_before_substep", implicit_before_substep);
1265  for (int lev = 0; lev <= max_level; lev++) {
1266  if ( (substepping_type[lev] == SubsteppingType::None) && !implicit_before_substep) {
1267  amrex::Print() << "implicit_before_substep cannot be false without substepping; setting to true." << "\n";
1268  implicit_before_substep = true;
1269  }
1270  }
1271 
1272  // Handle shoc case -- SHOC owns whatever vertical diffusion the host does not
1273  if (uses_shoc_family()) {
1274  const bool host_owns_scalars = host_owns_vertical_scalar_diffusion();
1275  const bool host_owns_momentum = host_owns_vertical_momentum_diffusion();
1276  if (!host_owns_scalars &&
1277  ( (user_set_imp_thermal && implicit_thermal_diffusion ) ||
1278  (user_set_imp_moisture && implicit_moisture_diffusion) ||
1279  (user_set_imp_ke && implicit_ke_diffusion ) ) ) {
1280  amrex::Print() << "Ignoring erf.implicit_{thermal,moisture,ke}_diffusion = true; "
1281  << "SHOC owns vertical scalar diffusion." << "\n";
1282  }
1283  if (!host_owns_momentum && user_set_imp_momentum && implicit_momentum_diffusion) {
1284  amrex::Print() << "Ignoring erf.implicit_momentum_diffusion = true; "
1285  << "SHOC owns vertical momentum diffusion." << "\n";
1286  }
1287 
1288  implicit_thermal_diffusion = (implicit_thermal_diffusion && host_owns_scalars);
1290  implicit_ke_diffusion = (implicit_ke_diffusion && host_owns_scalars);
1291  implicit_momentum_diffusion = (implicit_momentum_diffusion && host_owns_momentum);
1292 
1293  // Make the resulting configuration visible in the run log
1294  if (!host_owns_scalars && !host_owns_momentum) {
1295  amrex::Print() << "Turning off vertical implicit solve for all components since SHOC owns diffusion." << "\n";
1296  } else {
1297  amrex::Print() << "SHOC hands vertical diffusion of"
1298  << (host_owns_scalars ? " scalars" : "")
1299  << (host_owns_momentum ? " momentum" : "")
1300  << " to the host; keeping the vertical implicit solve on (theta = "
1302  << ", moisture = " << implicit_moisture_diffusion
1303  << ", tke = " << implicit_ke_diffusion
1304  << ", momenta = " << implicit_momentum_diffusion << ")." << "\n";
1305  }
1306  } // uses_shoc_family
1307 
1308  // Do not allow implicit vertical diff if user turns it off
1309  bool do_vert_implicit = true;
1310  pp.queryAdd("vert_implicit", do_vert_implicit);
1311  if (!do_vert_implicit) {
1312  for (int lev = 0; lev <= max_level; lev++) {
1313  amrex::Print() << "Turning off native vertical implicit solve from vert_implicit flag at level " << lev << std::endl;
1314  vert_implicit_fac[lev][0] = zero;
1315  vert_implicit_fac[lev][1] = zero;
1316  vert_implicit_fac[lev][2] = zero;
1317  }
1318  }
1319 
1320  // Do not allow implicit vertical diff with anelastic
1321  for (int lev = 0; lev <= max_level; lev++) {
1322  if (anelastic[lev]) {
1323  amrex::Print() << "Turning off native vertical implicit solve flag because anelastic at level " << lev << std::endl;
1324  vert_implicit_fac[lev][0] = zero;
1325  vert_implicit_fac[lev][1] = zero;
1326  vert_implicit_fac[lev][2] = zero;
1327  }
1328  }
1329 
1330  // Do not allow implicit vertical diff with EB
1331  if (terrain_type == TerrainType::EB) {
1332  for (int lev = 0; lev <= max_level; lev++) {
1333  if (do_vert_implicit) {
1334  amrex::Print() << "Implicit diffusion is not supported with EB; turning off at level " << lev << "\n";
1335  vert_implicit_fac[lev][0] = zero;
1336  vert_implicit_fac[lev][1] = zero;
1337  vert_implicit_fac[lev][2] = zero;
1338  }
1339  }
1340  }
1341 
1342  // Do not allow implicit vertical diff when all the components are false
1347  amrex::Print() << "Thermal, moisture, KE, and momentum diffusion are all turned off; turning off vertical implicit solve." << std::endl;
1348  for (int lev = 0; lev <= max_level; lev++) {
1349  vert_implicit_fac[lev][0] = zero;
1350  vert_implicit_fac[lev][1] = zero;
1351  vert_implicit_fac[lev][2] = zero;
1352  }
1353  }
1354 
1355  // Which type of multilevel coupling
1356  coupling_type = CouplingType::TwoWay; // Default
1357  pp.query_enum_case_insensitive("coupling_type",coupling_type);
1358 
1359  // Test for hybrid (compressible + anelastic) -- in this case we must use one-way coupling
1360  if (any_anelastic && any_compress) {
1361  coupling_type = CouplingType::OneWay;
1362  }
1363 
1364  // Which type of windfarm model
1365  windfarm_type = WindFarmType::None; // Default
1366  pp.query_enum_case_insensitive("windfarm_type",windfarm_type);
1367 
1368  windfarm_loc_type = WindFarmLocType::None;
1369  pp.query_enum_case_insensitive("windfarm_loc_type",windfarm_loc_type);
1370 
1371  pp.queryAdd("windfarm_loc_table", windfarm_loc_table);
1372  pp.queryAdd("windfarm_spec_table", windfarm_spec_table);
1373  pp.queryAdd("windfarm_blade_table", windfarm_blade_table);
1374  pp.queryAdd("windfarm_airfoil_tables", windfarm_airfoil_tables);
1375  pp.queryAdd("windfarm_spec_table_extra", windfarm_spec_table_extra);
1376 
1377  // Sampling distance upstream of the turbine to find the
1378  // incoming free stream velocity as a factor of the diameter of the
1379  // turbine. ie. the sampling distance will be this number multiplied
1380  // by the diameter of the turbine
1381  pp.queryAdd("sampling_distance_by_D", sampling_distance_by_D);
1382  pp.queryAdd("turb_disk_angle_from_x", turb_disk_angle);
1383 
1384  pp.queryAdd("windfarm_x_shift",windfarm_x_shift);
1385  pp.queryAdd("windfarm_y_shift",windfarm_y_shift);
1386  // Test if time averaged data is to be output
1387  pp.queryAdd("time_avg_vel",time_avg_vel);
1388 
1389  // Interval means and resolved turbulent moments for plotfile output
1390  pp.queryAdd("compute_mean_vars", compute_mean_vars);
1391  pp.queryAdd("mean_vars_reset_mode", mean_vars_reset_mode);
1392  pp.queryAdd("mean_vars_reset_time", mean_vars_reset_time);
1393 
1394  if (compute_mean_vars &&
1395  mean_vars_reset_mode != "plotfile" && mean_vars_reset_mode != "time") {
1396  amrex::Error("erf.mean_vars_reset_mode must be either 'plotfile' or 'time'");
1397  }
1398  if (compute_mean_vars && mean_vars_reset_mode == "time" &&
1400  amrex::Error("erf.mean_vars_reset_time must be non-negative when "
1401  "erf.mean_vars_reset_mode = 'time'");
1402  }
1403 
1404  pp.queryAdd("hindcast_lateral_forcing", hindcast_lateral_forcing);
1405 
1407  pp.queryAdd("hindcast_boundary_data_dir", hindcast_boundary_data_dir);
1408 
1409  if(hindcast_boundary_data_dir.empty()) {
1410  amrex::Error("ERROR: Missing input parameter 'erf.hindcast_boundary_data_dir' for boundary data for lateral forcing");
1411  }
1412  pp.queryAdd("hindcast_data_interval_in_hrs", hindcast_data_interval_in_hrs);
1414  amrex::Error("ERROR: Input parameter 'erf.hindcast_data_interval_in_hrs' which is the time interval between the "
1415  "data files is either missing or set to less than zero");
1416  }
1417  pp.queryAdd("hindcast_lateral_sponge_strength", hindcast_lateral_sponge_strength);
1418  pp.queryAdd("hindcast_lateral_sponge_length", hindcast_lateral_sponge_length);
1419 
1420  pp.queryAdd("hindcast_zhi_sponge_length", hindcast_zhi_sponge_length);
1421  pp.queryAdd("hindcast_zhi_sponge_strength", hindcast_zhi_sponge_strength);
1422 
1423  pp.queryAdd("hindcast_zhi_sponge_damping", hindcast_zhi_sponge_damping);
1424 
1426  amrex::Error("ERROR: Missing input parameter 'erf.hindcast_lateral_sponge_strength' or it is specified to be less than zero");
1427  }
1428 
1430  amrex::Error("ERROR: Missing input parameter 'erf.hindcast_lateral_sponge_length' or it is specified to be less than zero");
1431  }
1432 
1434  amrex::Error("ERROR: Missing input parameter 'erf.hindcast_zhi_sponge_length' or it is specified to be less than zero");
1435  }
1436 
1438  amrex::Error("ERROR: Missing input parameter 'erf.hindcast_zhi_sponge_strength' or it is specified to be less than zero");
1439  }
1440  }
1441 
1442  pp.queryAdd("hindcast_surface_bcs", hindcast_surface_bcs);
1443  if(hindcast_surface_bcs) {
1444  pp.queryAdd("hindcast_surface_data_dir", hindcast_surface_data_dir);
1445  }
1446 
1447  pp.queryAdd("io_hurricane_eye_tracker", io_hurricane_eye_tracker);
1449  pp.queryAdd("hurricane_eye_latitude", hurricane_eye_latitude);
1450  pp.queryAdd("hurricane_eye_longitude", hurricane_eye_longitude);
1452  amrex::Error("ERROR: You are using 'erf.io_hurricane_eye_tracker' to write out the files that track the eye of the hurricane"
1453  " but have not provided the initial location of the eye of the hurricane to be tracked. There has to be two"
1454  " options in the inputs - erf.hurricane_eye_latitude and erf.hurricane_eye_longitude that gives an approximate"
1455  " location of the eye in the initial condition");
1456  }
1457  }
1458 
1459  pp.queryAdd("is_init_for_ensemble", is_init_for_ensemble);
1460  if(is_init_for_ensemble) {
1461  amrex::ParmParse pp_ens("ensemble");
1462  pp_ens.queryAdd("n_members", n_ensemble);
1463  if(n_ensemble < 2) {
1464  amrex::Abort("You are using an ensemble run. There needs to be at least 2 ensemble members. "
1465  "erf.n_ensemble must be >=2.");
1466  }
1467  pp_ens.queryAdd("coarse_bckgnd_data_file", coarse_bckgnd_data_file);
1468  if (coarse_bckgnd_data_file.empty()) {
1469  amrex::Abort("coarse_bckgnd_data_file is empty! For ensmeble simulations, there needs to be a coarse background file which "
1470  "contains the data which will be interpolated onto the fine mesh. There has to a entry ensemble.coarse_bckgnd_data_file "
1471  "which contains the filename in the inputs.");
1472  }
1473  pp_ens.queryAdd("ens_pert_amplitude", ens_pert_amplitude);
1474  if(ens_pert_amplitude <= 0.0) {
1475  amrex::Error("You are using initialization for ensemble simulations using the inputs option "
1476  "ensemble.is_init_for_ensemble=true. In this case, there has to be an option "
1477  "ensemble.ens_pert_amplitude which is the value of the amplitude of the perturbation "
1478  "to be added to the background state and has to be greater than 0.0");
1479  }
1480  pp_ens.queryAdd("ens_pert_correlated_radius", ens_pert_correlated_radius);
1481  if(ens_pert_correlated_radius <= 0.0) {
1482  amrex::Error("You are using initialization with spatially correlated perturbations using the inputs option "
1483  "ensemble.is_init_for_ensemble=true. In this case, there has to be an option "
1484  "ensemble.ens_pert_correlated_radius which is the value of the the spatial correlation radius, "
1485  "and has to be greater than 0.0");
1486  }
1487  }
1488  }
1489 
1490  /**
1491  * @brief Validate solver options after geometry and boundary conditions are known.
1492  * @param max_level Maximum AMR level configured for the run.
1493  * @param geom_vect Geometry for each AMR level.
1494  * @param phys_bc_type Physical boundary-condition types.
1495  */
1496  void check_params (int max_level, const amrex::Vector<amrex::Geometry>& geom_vect, amrex::GpuArray<ERF_BC, AMREX_SPACEDIM*2> phys_bc_type)
1497  {
1498 #if 0
1499  // Warn for PBL models and moisture - these may not yet be compatible
1500  for (int lev = 0; lev <= max_level; lev++) {
1501  if ((moisture_type != MoistureType::None) && (turbChoice[lev].pbl_type != PBLType::None)) {
1502  amrex::Warning("\n*** WARNING: Moisture may not yet be compatible with PBL models, \n proceed with caution ***");
1503  }
1504  }
1505 #endif
1506  //
1507  // Buoyancy type check
1508  //
1509  for (int lev = 0; lev <= max_level; lev++) {
1510  if (buoyancy_type[lev] != 1 && buoyancy_type[lev] != 2 && buoyancy_type[lev] != 3 && buoyancy_type[lev] != 4) {
1511  amrex::Error("buoyancy_type must be 1, 2, 3 or 4");
1512  }
1513  }
1514 
1515  if (!use_lagged_delta_rt && !(terrain_type == TerrainType::MovingFittedMesh)) {
1516  amrex::Error("Can't turn off lagged_delta_rt when terrain not moving");
1517  }
1518 
1519  //
1520  // Wind farm checks
1521  //
1522  if (windfarm_type==WindFarmType::SimpleAD and sampling_distance_by_D < zero) {
1523  amrex::Error("To use simplified actuator disks, you need to provide a variable"
1524  " erf.sampling_distance_by_D in the inputs which specifies the upstream"
1525  " distance as a factor of the turbine diameter at which the incoming free stream"
1526  " velocity will be computed at.");
1527  }
1528  if ( (windfarm_type==WindFarmType::SimpleAD ||
1529  windfarm_type==WindFarmType::GeneralAD ) && turb_disk_angle < zero) {
1530  amrex::Error("To use simplified actuator disks, you need to provide a variable"
1531  " erf.turb_disk_angle_from_x in the inputs which is the angle of the face of the"
1532  " turbine disk from the x-axis. A turbine facing an oncoming flow in the x-direction"
1533  " will have turb_disk_angle value of 90 deg.");
1534  }
1535  if (windfarm_loc_type == WindFarmLocType::lat_lon and (windfarm_x_shift < zero or windfarm_y_shift < zero)) {
1536  amrex::Error("You are using windfarms with latitude-logitude option to position the turbines."
1537  " For this you should provide the inputs erf.windfarm_x_shift and"
1538  " erf.windfarm_y_shift which are the values by which the bounding box of the"
1539  " windfarm is shifted from the x and the y axes.");
1540  }
1541 
1542 
1543  if ( (const_massflux_u != 0) && !(geom_vect[0].isPeriodic(0)) ) {
1544  amrex::Error("Constant mass flux (in x) should be used with periodic boundaries");
1545  }
1546 
1547  if ( (const_massflux_v != 0) && !(geom_vect[0].isPeriodic(1)) ) {
1548  amrex::Error("Constant mass flux (in y) should be used with periodic boundaries");
1549  }
1550 
1551  // Mesoscale diffusion -- test if LES appropriate with this dx,dy
1552  for (int lev = 0; lev <= max_level; lev++) {
1553  if ((geom_vect[lev].CellSize(0) > amrex::Real(2000.)) || (geom_vect[lev].CellSize(1) > amrex::Real(2000.)))
1554  {
1555  if ( (turbChoice[lev].les_type == LESType::Smagorinsky) && !turbChoice[lev].smag2d ) {
1556  amrex::Warning("Should use 2-D Smagorinsky for mesoscale resolution");
1557  } else if (turbChoice[lev].les_type == LESType::Deardorff) {
1558  amrex::Warning("Should not use Deardorff LES for mesoscale resolution");
1559  }
1560  }
1561  }
1562 
1563  // Turn off implicit solve if we have no diffusion
1564  bool l_use_kturb = turbChoice[0].use_kturb;
1565  for (int lev = 1; lev <= max_level; lev++) {
1566  l_use_kturb = (l_use_kturb || turbChoice[lev].use_kturb);
1567  }
1568  bool l_use_diff = ( (diffChoice.molec_diff_type != MolecDiffType::None) || l_use_kturb );
1569 
1570  for (int lev = 0; lev <= max_level; lev++) {
1571  bool l_implicit_diff = (vert_implicit_fac[lev][0] > zero ||
1572  vert_implicit_fac[lev][1] > zero ||
1573  vert_implicit_fac[lev][2] > zero);
1574  if (l_implicit_diff && !l_use_diff) {
1575  amrex:: Print() << "No molecular or turbulent diffusion, turning off implicit solve at level " << lev << std::endl;
1576  vert_implicit_fac[lev][0] = zero;
1577  vert_implicit_fac[lev][1] = zero;
1578  vert_implicit_fac[lev][2] = zero;
1579  }
1580  }
1581 
1582  // Countergradient validation: ensure required implicit diffusion is enabled
1583  for (int lev = 0; lev <= max_level; lev++) {
1584  if (turbChoice[lev].enable_mrf_countergradient) {
1586  vert_implicit_fac[lev][0] > zero ||
1587  vert_implicit_fac[lev][1] > zero ||
1588  vert_implicit_fac[lev][2] > zero,
1589  "enable_mrf_countergradient requires vert_implicit_fac > 0");
1592  "enable_mrf_countergradient requires implicit_thermal_diffusion = true");
1593  if (moisture_type != MoistureType::None) {
1596  "enable_mrf_countergradient with moisture requires implicit_moisture_diffusion = true");
1597  }
1598  }
1599  }
1600 
1601  for (int lev = 0; lev <= max_level; lev++) {
1602  turbChoice[lev].check_params(phys_bc_type);
1603  }
1604  }
1605 
1606  /**
1607  * @brief Print the configured solver, physics, and transport options.
1608  * @param max_level Maximum AMR level configured for the run.
1609  * @param pp_prefix ParmParse prefix used to display nested choices.
1610  */
1611  void display (int max_level, std::string pp_prefix)
1612  {
1613  amrex::Print() << "SOLVER CHOICE: " << std::endl;
1614  for (int lev = 0; lev <= max_level; lev++) {
1615  amrex::Print() << "At level " << lev << " : " << std::endl;
1616  if (anelastic[lev]) {
1617  amrex::Print() << " anelastic with no substepping" << std::endl;
1618  } else {
1619  if (substepping_type[lev] == SubsteppingType::None) {
1620  amrex::Print() << " compressible with no substepping" << std::endl;
1621  } else if (substepping_type[lev] == SubsteppingType::Implicit) {
1622  amrex::Print() << " compressible with implicit substepping" << std::endl;
1623  }
1624  }
1625  if (fixed_density[lev]) {
1626  amrex::Print() << " and fixed density" << std::endl;
1627  }
1628  }
1629 
1630  for (int lev = 0; lev <= max_level; lev++) {
1631  amrex::Print() << "vert_implicit_fac at level " << lev << " : "
1632  << vert_implicit_fac[lev][0] << " "
1633  << vert_implicit_fac[lev][1] << " "
1634  << vert_implicit_fac[lev][2];
1635  if (vert_implicit_fac[lev][0] > zero ||
1636  vert_implicit_fac[lev][1] > zero ||
1637  vert_implicit_fac[lev][2] > zero)
1638  {
1639  amrex::Print() << " (theta = " << implicit_thermal_diffusion
1640  << ", moisture = " << implicit_moisture_diffusion
1641  << ", tke = " << implicit_ke_diffusion
1642  << ", momenta = " << implicit_momentum_diffusion;
1643 #ifdef ERF_IMPLICIT_W
1644  amrex::Print() << ", including w";
1645 #endif
1646  amrex::Print() << ")";
1647  }
1648  }
1649  amrex::Print() << std::endl;
1650  amrex::Print() << "use_coriolis : " << use_coriolis << std::endl;
1651  amrex::Print() << "use_gravity : " << use_gravity << std::endl;
1652 
1653  if (moisture_type == MoistureType::SAM) {
1654  amrex::Print() << "Moisture Model: SAM" << std::endl;
1655  } else if (moisture_type == MoistureType::SAM_NoIce) {
1656  amrex::Print() << "Moisture Model: SAM No Ice" << std::endl;
1657  } else if (moisture_type == MoistureType::SAM_NoPrecip_NoIce) {
1658  amrex::Print() << "Moisture Model: SAM No Precip No Ice" << std::endl;
1659  } else if (moisture_type == MoistureType::Morrison) {
1660  amrex::Print() << "Moisture Model: Morrison" << std::endl;
1661  } else if (moisture_type == MoistureType::Morrison_NoIce) {
1662  amrex::Print() << "Moisture Model: Morrison_NoIce" << std::endl;
1663  } else if (moisture_type == MoistureType::WSM6) {
1664  amrex::Print() << "Moisture Model: WSM6" << std::endl;
1665  } else if (moisture_type == MoistureType::WDM6) {
1666  amrex::Print() << "Moisture Model: WDM6" << std::endl;
1667  } else if (moisture_type == MoistureType::Kessler) {
1668  amrex::Print() << "Moisture Model: Kessler" << std::endl;
1669  } else if (moisture_type == MoistureType::Kessler_NoRain) {
1670  amrex::Print() << "Moisture Model: Kessler No Rain" << std::endl;
1671  } else if (moisture_type == MoistureType::SatAdj) {
1672  amrex::Print() << "Moisture Model: Saturation Adjustment" << std::endl;
1673  } else if (moisture_type == MoistureType::SuperDroplets) {
1674  amrex::Print() << "Moisture Model: SuperDroplets" << std::endl;
1675  } else if (moisture_type == MoistureType::MoistNoCondensation) {
1676  amrex::Print() << "Moisture Model: MoistNoCondensation" << std::endl;
1677  } else {
1678  amrex::Print() << "Moisture Model: None" << std::endl;
1679  }
1680 
1681  if (terrain_type == TerrainType::StaticFittedMesh) {
1682  amrex::Print() << "Terrain Type: StaticFittedMesh" << std::endl;
1683  } else if (terrain_type == TerrainType::MovingFittedMesh) {
1684  amrex::Print() << "Terrain Type: MovingFittedMesh" << std::endl;
1685  } else if (terrain_type == TerrainType::EB) {
1686  amrex::Print() << "Terrain Type: EB" << std::endl;
1687  ebChoice.display();
1688  } else if (terrain_type == TerrainType::ImmersedForcing) {
1689  amrex::Print() << "Terrain Type: ImmersedForcing" << std::endl;
1690  } else {
1691  amrex::Print() << "Terrain Type: None" << std::endl;
1692  }
1693 
1694  if (buildings_type == BuildingsType::ImmersedForcing) {
1695  amrex::Print() << "Buildings Type: ImmersedForcing" << std::endl;
1696  } else {
1697  amrex::Print() << "Buildings Type: None" << std::endl;
1698  }
1699 
1700  if (mesh_type == MeshType::ConstantDz) {
1701  amrex::Print() << " Mesh Type: ConstantDz" << std::endl;
1702  } else if (mesh_type == MeshType::StretchedDz) {
1703  amrex::Print() << " Mesh Type: StretchedDz" << std::endl;
1704  } else if (mesh_type == MeshType::VariableDz) {
1705  amrex::Print() << " Mesh Type: VariableDz" << std::endl;
1706  } else {
1707  amrex::Error("No mesh_type set!");
1708  }
1709 
1710  amrex::Print() << "ABL Driver Type: " << std::endl;
1711  if (abl_driver_type == ABLDriverType::None) {
1712  amrex::Print() << " None" << std::endl;
1713  } else if (abl_driver_type == ABLDriverType::PressureGradient) {
1714  amrex::Print() << " Pressure Gradient "
1715  << amrex::RealVect(abl_pressure_grad[0],abl_pressure_grad[1],abl_pressure_grad[2])
1716  << std::endl;
1717  } else if (abl_driver_type == ABLDriverType::GeostrophicWind) {
1718  amrex::Print() << " Geostrophic Wind "
1719  << amrex::RealVect(abl_geo_forcing[0],abl_geo_forcing[1],abl_geo_forcing[2])
1720  << std::endl;
1721  }
1722 
1723  if (max_level > 0) {
1724  amrex::Print() << "Coupling Type: " << std::endl;
1725  if (coupling_type == CouplingType::TwoWay) {
1726  amrex::Print() << " Two-way" << std::endl;
1727  } else if (coupling_type == CouplingType::OneWay) {
1728  amrex::Print() << " One-way" << std::endl;
1729  }
1730  }
1731 
1732  if (rad_type == RadiationType::RRTMGP) {
1733  amrex::Print() << "Radiation Model: RRTMGP" << std::endl;
1734  } else if (rad_type == RadiationType::Simple) {
1735  amrex::Print() << "Radiation Model: Simple" << std::endl;
1736  } else {
1737  amrex::Print() << "Radiation Model: None" << std::endl;
1738  }
1739 
1740  amrex::Print() << "Gradp_type : " << gradp_type << std::endl;
1741 
1742  for (int lev = 0; lev <= max_level; lev++) {
1743  amrex::Print() << "Buoyancy_type at level " << lev << " : " << buoyancy_type[lev] << std::endl;
1744  }
1745 
1746  advChoice.display(pp_prefix);
1747  diffChoice.display();
1750 
1751  for (int lev = 0; lev <= max_level; lev++) {
1752  turbChoice[lev].display(lev);
1753  }
1754  }
1755 
1756  /**
1757  * @brief Build constant-latitude Coriolis forcing parameters.
1758  * @param pp_prefix ParmParse prefix for the ERF input namespace.
1759  */
1760  void build_coriolis_forcings_const_lat (std::string pp_prefix)
1761  {
1762  amrex::ParmParse pp(pp_prefix);
1763 
1764  // Read the rotational time period (in seconds)
1765  double rot_time_period = 86400.0;
1766  pp.queryAdd("rotational_time_period", rot_time_period);
1767 
1768  coriolis_factor = static_cast<amrex::Real>(4.0 * PI / rot_time_period);
1769 
1770  pp.queryAdd("coriolis_3d", coriolis_3d);
1771 
1772  // Convert to radians
1773  amrex::Real latitude_for_coriolis = amrex::Real(90.0);
1774  pp.queryAdd("latitude", latitude_for_coriolis);
1775  latitude_for_coriolis *= (PI/amrex::Real(180.));
1776  sinphi = std::sin(latitude_for_coriolis);
1777 
1778  // Note: cosphi defaults to 0
1779  if (coriolis_3d) {
1780  cosphi = std::cos(latitude_for_coriolis);
1781  }
1782 
1783  amrex::Print() << "Coriolis frequency, f = " << coriolis_factor * sinphi << " 1/s" << std::endl;
1784 
1785  if (abl_driver_type == ABLDriverType::GeostrophicWind) {
1786  // Read in the geostrophic wind -- we only use this to construct
1787  // the forcing term so no need to keep it
1788  amrex::Vector<amrex::Real> abl_geo_wind(3);
1789  pp.queryarr("abl_geo_wind",abl_geo_wind);
1790 
1791  if(!pp.queryAdd("abl_geo_wind_table",abl_geo_wind_table)) {
1792  abl_geo_forcing = {
1793  -coriolis_factor * (abl_geo_wind[1]*sinphi - abl_geo_wind[2]*cosphi),
1794  coriolis_factor * abl_geo_wind[0]*sinphi,
1795  -coriolis_factor * abl_geo_wind[0]*cosphi
1796  };
1797  } else {
1798  amrex::Print() << "NOTE: abl_geo_wind_table provided, ignoring input abl_geo_wind" << std::endl;
1799  }
1800  }
1801  }
1802 
1803  /**
1804  * @brief Read one integer value or one value per AMR level.
1805  * @param max_level Maximum AMR level configured for the run.
1806  * @param string_to_read ParmParse key to read.
1807  * @param vec_to_fill Destination vector with one entry per level.
1808  * @param default_int Default value used when the key is absent.
1809  */
1810  void read_int_string (int max_level, const char* string_to_read,
1811  amrex::Vector<int>& vec_to_fill, int default_int)
1812  {
1813  amrex::ParmParse pp("erf");
1814  int nvals = pp.countval(string_to_read);
1815  AMREX_ALWAYS_ASSERT(nvals == 0 || nvals == 1 || nvals >= max_level+1);
1816  amrex::Vector<int> temp; temp.resize(nvals);
1817  pp.queryarr(string_to_read,temp);
1818 
1819  if (vec_to_fill.size() < max_level+1) {
1820  vec_to_fill.resize(max_level+1);
1821  }
1822 
1823  if (nvals == 0) {
1824  for (int i = 0; i <= max_level; ++i) vec_to_fill[i] = default_int;
1825  } else if (nvals == 1) {
1826  for (int i = 0; i <= max_level; ++i) vec_to_fill[i] = temp[0];
1827  } else {
1828  for (int i = 0; i <= max_level; ++i) vec_to_fill[i] = temp[i];
1829  }
1830  }
1831 
1832  inline static
1833  InitType init_type = InitType::None;
1834 
1835  inline static
1836  SoundingType sounding_type = SoundingType::Ideal;
1837 
1838  inline static
1839  TerrainType terrain_type = TerrainType::None;
1840 
1841  inline static
1842  BuildingsType buildings_type = BuildingsType::None;
1843 
1844  inline static
1845  bool use_real_bcs = false;
1846 
1847  inline static
1848  MeshType mesh_type = MeshType::ConstantDz;
1849 
1850  /**
1851  * @brief Override the globally selected mesh type.
1852  * @param new_mesh_type Mesh type to store.
1853  */
1854  static
1855  void set_mesh_type (MeshType new_mesh_type)
1856  {
1857  mesh_type = new_mesh_type;
1858  }
1859 
1864  amrex::Vector<TurbChoice> turbChoice;
1866 
1868 
1869  amrex::Vector<SubsteppingType> substepping_type;
1870  amrex::Vector<int> anelastic;
1871  amrex::Vector<int> fixed_density;
1872  amrex::Vector<int> project_initial_velocity;
1873  amrex::Vector<int> buoyancy_type;
1874  amrex::Vector<int> is_land;
1875 
1876  // do some extra CFL diagnostics for compressible with substepping
1877  bool substepping_diag = false;
1878 
1879  // time off-centering coefficient, > 0 for forward weighting (i.e., bias
1880  // towards the future time step)
1882 
1883  // This controls the time-centering of the *vertical* differences in the diffusive term for
1884  // theta, u, v (and w if ERF_IMPLICIT_W is set)
1885  // 0: fully explicit
1886  // 1: fully implicit
1887  amrex::Vector<amrex::Vector<amrex::Real>> vert_implicit_fac; // one value per RK stage
1888 
1889  // if any vert_implicit_fac > 0, then the following apply:
1895 
1896  int ncorr = 1;
1897 #ifdef AMREX_USE_FLOAT
1900 #else
1903 #endif
1904 
1905  bool test_mapfactor = false;
1906 
1907  int gradp_type = 0;
1908 
1910 
1911  // Specify what additional physics/forcing modules we use
1912  bool use_gravity = false;
1913  bool use_coriolis = false;
1914  bool coriolis_3d = true;
1915 
1917 
1918  // Specify whether to apply other various source terms on substep only
1920  bool forest_substep = false;
1921 
1922  // immersed forcing parameters
1925  // Use a point-implicit (linearly-implicit) formulation of the immersed-forcing
1926  // drag. Defaults to false (explicit forward-Euler source).
1927  bool if_implicit_drag = false;
1928  // immersed forcing MOST parameters.
1934  bool if_use_most = false;
1936  amrex::Real if_ws_floor = 0.001; // [m/s]
1938 
1939  // This defaults to true but can be set to false for moving terrain cases only
1940  bool use_lagged_delta_rt = true;
1941 
1942  // Flag to rebalance states from wrfinput and wrfbdy
1943  bool rebalance_wrf_input = true;
1944 
1945  // Constants
1947  amrex::Real c_p = Cp_d; // specific heat at constant pressure for dry air [J/(kg-K)]
1949 
1950  // Staggered z levels for vertical grid stretching
1954 
1955  // Coriolis forcing
1959 
1960  // User-specified forcings in problem definition
1963  bool custom_w_subsidence = false;
1964  bool do_theta_advection = true; // Apply custom vertical subsidence to (rho*theta) equation when using custom w subsidence
1965  bool do_mom_advection = true; // Apply custom vertical subsidence to momentum equations when using custom w subsidence
1970 
1971  // Do we use source terms to nudge the solution towards
1972  // the time-varying data provided in input sounding files?
1974 
1980  amrex::Real nudging_q_z2 = amrex::Real(10000.0); // TODO: reasonable defaults here?
1981 
1982  bool nudging_u = true; // Nudge u,v when nudging_from_input_sounding is true
1983  bool nudging_t = true; // Nudge potential temperature when nudging_from_input_sounding is true
1984  bool nudging_q = true; // Nudge water vapor when nudging_from_input_sounding is true
1985 
1986  bool large_scale_forcing = false;
1987  std::string lsf_file = "";
1989 
1990  // MOST stress rotations
1992 
1993  // Should we use SHOC?
1994  bool use_eamxx_shoc = false;
1995  bool use_native_shoc = false;
1996 
1997  // Native shoc transport mode
2000 
2001  // Transport the passive scalar?
2002  bool transport_scalar = true;
2003 
2004  // User wishes to output time averaged velocity fields
2005  bool time_avg_vel = false;
2006 
2007  // User wishes to output interval means and resolved turbulent moments
2008  bool compute_mean_vars = false;
2009 
2010  // Reset interval means after each plotfile or once at a requested time
2011  std::string mean_vars_reset_mode = "plotfile";
2013 
2014  /**
2015  * @brief Query whether any turbulent perturbation mode is enabled on a level.
2016  * @param lev AMR level index.
2017  * @return True if source, direct, CPM, or CPM_W perturbations are enabled.
2018  */
2019  bool use_perturbation (int lev) const
2020  {
2021  return pert_type[lev] == PerturbationType::Source ||
2022  pert_type[lev] == PerturbationType::Direct ||
2023  pert_type[lev] == PerturbationType::CPM ||
2024  pert_type[lev] == PerturbationType::CPM_W;
2025  }
2026 
2027  /**
2028  * @brief Query whether direct turbulent perturbations are enabled on a level.
2029  * @param lev AMR level index.
2030  * @return True if direct, CPM, or CPM_W perturbations are enabled.
2031  */
2032  bool use_direct_perturbation (int lev) const
2033  {
2034  return pert_type[lev] == PerturbationType::Direct ||
2035  pert_type[lev] == PerturbationType::CPM ||
2036  pert_type[lev] == PerturbationType::CPM_W;
2037  }
2038 
2039  /**
2040  * @brief Query whether source-term turbulent perturbations are enabled on a level.
2041  * @param lev AMR level index.
2042  * @return True if source perturbations are enabled.
2043  */
2044  bool use_source_perturbation (int lev) const
2045  {
2046  return pert_type[lev] == PerturbationType::Source;
2047  }
2048 
2049  /**
2050  * @brief Query whether vertical-velocity CPM perturbations are enabled on a level.
2051  * @param lev AMR level index.
2052  * @return True if CPM_W perturbations are enabled.
2053  */
2054  bool use_wvel_perturbation (int lev) const
2055  {
2056  return pert_type[lev] == PerturbationType::CPM_W;
2057  }
2058 
2059  /**
2060  * @brief Query whether any SHOC-family PBL scheme is active.
2061  * @return True if native or EAMxx SHOC is active.
2062  */
2063  bool uses_shoc_family () const noexcept
2064  {
2065  return (use_eamxx_shoc || use_native_shoc);
2066  }
2067 
2068  /**
2069  * @brief Test whether the host owns momentum diffusion.
2070  * @return True if ERF dycore does vertical diffusion of momentum.
2071  */
2073  {
2074  if (use_eamxx_shoc) { return false; }
2075  if (!use_native_shoc) { return true; }
2078  }
2079 
2080  /**
2081  * @brief Test whether the host owns scalar diffusion.
2082  * @return True if ERF dycore does vertical diffusion of scalars.
2083  */
2085  {
2086  if (use_eamxx_shoc) { return false; }
2087  if (!use_native_shoc) { return true; }
2089  }
2090 
2091  /**
2092  * @brief Query whether the active PBL scheme suppresses microphysics condensation.
2093  * @return True when the active PBL scheme owns condensation handling.
2094  */
2096  {
2097  return uses_shoc_family();
2098  }
2099 
2100  /**
2101  * @brief Query whether any level uses a turbulent perturbation mode.
2102  * @return True if at least one configured level has source, direct, or CPM perturbations.
2103  */
2104  bool any_perturbation () const
2105  {
2106  for (const auto& type : pert_type) {
2107  if (type == PerturbationType::Source ||
2108  type == PerturbationType::Direct ||
2109  type == PerturbationType::CPM) {
2110  return true;
2111  }
2112  }
2113  return false;
2114  }
2115 
2116  // Type of perturbation
2117  amrex::Vector<PerturbationType> pert_type;
2118 
2119  // Numerical diffusion
2120  bool use_num_diff{false};
2122 
2123  CouplingType coupling_type;
2124  MoistureType moisture_type;
2125  WindFarmType windfarm_type;
2126  WindFarmLocType windfarm_loc_type;
2127  LandSurfaceType lsm_type;
2128  RadiationType rad_type;
2129 
2130  // Does an external ocean coupler supply SST? See the query in init_params.
2131  bool use_coupled_sst = false;
2132 
2133  ABLDriverType abl_driver_type;
2134  amrex::GpuArray<amrex::Real, AMREX_SPACEDIM> abl_pressure_grad;
2135  amrex::GpuArray<amrex::Real, AMREX_SPACEDIM> abl_geo_forcing;
2136  std::string abl_geo_wind_table;
2138 
2139  bool variable_coriolis{false};
2140 
2141  int ave_plane {2};
2142 
2143  // Microphysics params
2145 
2147 
2154 
2155  // Nudging factor for bdy sponging : F1 = 1/(nudge_factor * dt)
2157 
2158  // Use density reconstructed from standard WRF lateral boundary data.
2159  bool use_wrf_bdy_density = true;
2160 
2161  // Ingest WRF cloud water and active cloud ice at initialization and lateral boundaries.
2162  bool use_wrf_bdy_qc_qi = false;
2163 
2164  // Density-specific Davies factor; non-positive means use bdy_nudge_factor.
2166 
2167  // Which approach to nudging the moist variables in the boundary region?
2169 
2170  // Average the input z-face heights onto the nodes rather than reconstructing them?
2172 
2173  // Use forest canopy model?
2174  bool do_forest_drag {false};
2175 
2176  // Fixed-leaf-temperature canopy heat exchange (disabled by default)
2177  bool forest_biophysics {false};
2180 
2181  // Enforce constant mass flux?
2187  int massflux_klo {0}; // these are updated in ERF.cpp
2188  int massflux_khi {0};
2189 
2193  bool hindcast_surface_bcs = false;
2197 
2200 
2201  bool is_init_for_ensemble = false;
2202  int n_ensemble = -1;
2206 };
2207 
2208 /**
2209  * @var SolverChoice::init_type
2210  * @brief Initial-condition source selected for the run.
2211  * @var SolverChoice::sounding_type
2212  * @brief Interpretation used for input sounding profiles.
2213  * @var SolverChoice::terrain_type
2214  * @brief Terrain or immersed-boundary representation.
2215  * @var SolverChoice::buildings_type
2216  * @brief Building representation.
2217  * @var SolverChoice::use_real_bcs
2218  * @brief Whether real-data lateral boundary conditions are used.
2219  * @var SolverChoice::mesh_type
2220  * @brief Vertical mesh representation.
2221  * @var SolverChoice::advChoice
2222  * @brief Advection-related options.
2223  * @var SolverChoice::diffChoice
2224  * @brief Diffusion-related options.
2225  * @var SolverChoice::dampingChoice
2226  * @brief Damping-related options.
2227  * @var SolverChoice::spongeChoice
2228  * @brief Sponge-layer options.
2229  * @var SolverChoice::turbChoice
2230  * @brief Turbulence options for each AMR level.
2231  * @var SolverChoice::ebChoice
2232  * @brief Embedded-boundary options.
2233  * @var SolverChoice::force_stage1_single_substep
2234  * @brief Flag forcing a single substep in the first RK stage.
2235  * @var SolverChoice::substepping_type
2236  * @brief Acoustic substepping type for each AMR level.
2237  * @var SolverChoice::anelastic
2238  * @brief Per-level flag selecting anelastic dynamics.
2239  * @var SolverChoice::fixed_density
2240  * @brief Per-level flag selecting fixed-density treatment.
2241  * @var SolverChoice::project_initial_velocity
2242  * @brief Per-level flag for projecting the initial velocity.
2243  * @var SolverChoice::buoyancy_type
2244  * @brief Per-level buoyancy formulation selector.
2245  * @var SolverChoice::is_land
2246  * @brief Per-level land/water selector.
2247  * @var SolverChoice::substepping_diag
2248  * @brief Whether to emit extra CFL diagnostics for compressible substepping.
2249  * @var SolverChoice::beta_s
2250  * @brief Time off-centering coefficient for forward weighting.
2251  * @var SolverChoice::vert_implicit_fac
2252  * @brief Per-level, per-stage implicit vertical diffusion factors.
2253  * @var SolverChoice::implicit_thermal_diffusion
2254  * @brief Whether implicit vertical thermal diffusion is included.
2255  * @var SolverChoice::implicit_moisture_diffusion
2256  * @brief Whether implicit vertical moisture diffusion is included.
2257  * @var SolverChoice::implicit_ke_diffusion
2258  * @brief Whether implicit vertical TKE diffusion is included.
2259  * @var SolverChoice::implicit_momentum_diffusion
2260  * @brief Whether implicit vertical momentum diffusion is included.
2261  * @var SolverChoice::implicit_before_substep
2262  * @brief Whether implicit diffusion is applied before acoustic substepping.
2263  * @var SolverChoice::ncorr
2264  * @brief Number of projection correction iterations.
2265  * @var SolverChoice::poisson_abstol
2266  * @brief Absolute tolerance for the Poisson solve.
2267  * @var SolverChoice::poisson_reltol
2268  * @brief Relative tolerance for the Poisson solve.
2269  * @var SolverChoice::test_mapfactor
2270  * @brief Whether to use test map scale factors.
2271  * @var SolverChoice::gradp_type
2272  * @brief Terrain-fitted horizontal pressure-gradient formulation.
2273  * @var SolverChoice::use_pert_pres_gradient
2274  * @brief Whether momentum equations use perturbational pressure gradients.
2275  * @var SolverChoice::use_gravity
2276  * @brief Whether gravitational forcing is enabled.
2277  * @var SolverChoice::use_coriolis
2278  * @brief Whether Coriolis forcing is enabled.
2279  * @var SolverChoice::coriolis_3d
2280  * @brief Whether the three-dimensional Coriolis terms are included.
2281  * @var SolverChoice::four_stream_radiation
2282  * @brief Whether the four-stream radiation approximation is enabled.
2283  * @var SolverChoice::immersed_forcing_substep
2284  * @brief Whether immersed-forcing source terms are applied only during substeps.
2285  * @var SolverChoice::forest_substep
2286  * @brief Whether canopy source terms are applied only during substeps.
2287  * @var SolverChoice::if_Cd_momentum
2288  * @brief Immersed-forcing drag coefficient for momentum.
2289  * @var SolverChoice::if_Cd_scalar
2290  * @brief Immersed-forcing drag coefficient for scalars.
2291  * @var SolverChoice::if_z0
2292  * @brief Immersed-forcing roughness length [m].
2293  * @var SolverChoice::if_surf_temp_flux
2294  * @brief Immersed-forcing surface temperature flux [K m/s].
2295  * @var SolverChoice::if_init_surf_temp
2296  * @brief Initial immersed-forcing surface temperature [K].
2297  * @var SolverChoice::if_surf_heating_rate
2298  * @brief Immersed-forcing surface heating rate [K/hr].
2299  * @var SolverChoice::if_Olen_in
2300  * @brief Input Obukhov length for immersed-forcing MOST [m].
2301  * @var SolverChoice::if_use_most
2302  * @brief Whether immersed-forcing MOST is enabled.
2303  * @var SolverChoice::if_stability_correction
2304  * @brief Whether immersed-forcing stability corrections are enabled.
2305  * @var SolverChoice::if_ws_floor
2306  * @brief Wind-speed floor for immersed-forcing MOST [m/s].
2307  * @var SolverChoice::if_damp_alpha
2308  * @brief Immersed-forcing damping coefficient.
2309  * @var SolverChoice::use_lagged_delta_rt
2310  * @brief Whether to use lagged delta terms for moving terrain.
2311  * @var SolverChoice::rebalance_wrf_input
2312  * @brief Whether to rebalance states from wrfinput and wrfbdy data.
2313  * @var SolverChoice::gravity
2314  * @brief Effective gravitational acceleration.
2315  * @var SolverChoice::c_p
2316  * @brief Specific heat at constant pressure for dry air [J/(kg-K)].
2317  * @var SolverChoice::rdOcp
2318  * @brief Ratio of dry-air gas constant to c_p.
2319  * @var SolverChoice::grid_stretching_ratio
2320  * @brief Vertical grid stretching ratio.
2321  * @var SolverChoice::zsurf
2322  * @brief Nominal surface height for stretched-grid setup.
2323  * @var SolverChoice::dz0
2324  * @brief Initial vertical grid spacing for stretched-grid setup.
2325  * @var SolverChoice::coriolis_factor
2326  * @brief Twice the planetary rotation rate used for Coriolis forcing.
2327  * @var SolverChoice::cosphi
2328  * @brief Cosine of the latitude used for Coriolis forcing.
2329  * @var SolverChoice::sinphi
2330  * @brief Sine of the latitude used for Coriolis forcing.
2331  * @var SolverChoice::custom_rhotheta_forcing
2332  * @brief Whether custom rho-theta forcing is enabled.
2333  * @var SolverChoice::custom_moisture_forcing
2334  * @brief Whether custom moisture forcing is enabled.
2335  * @var SolverChoice::custom_w_subsidence
2336  * @brief Whether custom vertical subsidence is enabled.
2337  * @var SolverChoice::do_theta_advection
2338  * @brief Whether custom vertical subsidence is applied to rho-theta.
2339  * @var SolverChoice::do_mom_advection
2340  * @brief Whether custom vertical subsidence is applied to momentum.
2341  * @var SolverChoice::custom_geostrophic_profile
2342  * @brief Whether a custom geostrophic wind profile is used.
2343  * @var SolverChoice::custom_forcing_prim_vars
2344  * @brief Whether custom forcing operates on primitive variables.
2345  * @var SolverChoice::spatial_rhotheta_forcing
2346  * @brief Whether spatially varying rho-theta forcing is enabled.
2347  * @var SolverChoice::spatial_moisture_forcing
2348  * @brief Whether spatially varying moisture forcing is enabled.
2349  * @var SolverChoice::nudging_from_input_sounding
2350  * @brief Whether solution fields are nudged toward input sounding data.
2351  * @var SolverChoice::use_rotate_surface_flux
2352  * @brief Whether MOST surface fluxes are rotated with terrain.
2353  * @var SolverChoice::use_eamxx_shoc
2354  * @brief Whether any level uses the EAMxx SHOC PBL scheme.
2355  * @var SolverChoice::use_native_shoc
2356  * @brief Whether any level uses the native SHOC PBL scheme.
2357  * @var SolverChoice::transport_scalar
2358  * @brief Whether the passive scalar component is transported.
2359  * @var SolverChoice::time_avg_vel
2360  * @brief Whether time-averaged velocity fields are output.
2361  * @var SolverChoice::pert_type
2362  * @brief Turbulent perturbation type for each AMR level.
2363  * @var SolverChoice::use_num_diff
2364  * @brief Whether sixth-order numerical diffusion is enabled.
2365  * @var SolverChoice::num_diff_coeff
2366  * @brief Numerical diffusion coefficient after input scaling.
2367  * @var SolverChoice::coupling_type
2368  * @brief Multilevel coupling strategy.
2369  * @var SolverChoice::moisture_type
2370  * @brief Moisture or microphysics model.
2371  * @var SolverChoice::windfarm_type
2372  * @brief Wind-farm model.
2373  * @var SolverChoice::windfarm_loc_type
2374  * @brief Coordinate system for wind-farm turbine locations.
2375  * @var SolverChoice::lsm_type
2376  * @brief Land-surface model.
2377  * @var SolverChoice::rad_type
2378  * @brief Radiation model.
2379  * @var SolverChoice::abl_driver_type
2380  * @brief Atmospheric boundary-layer driver type.
2381  * @var SolverChoice::abl_pressure_grad
2382  * @brief Applied ABL pressure-gradient forcing vector.
2383  * @var SolverChoice::abl_geo_forcing
2384  * @brief Applied geostrophic-wind forcing vector.
2385  * @var SolverChoice::abl_geo_wind_table
2386  * @brief Path to a time-varying geostrophic wind table.
2387  * @var SolverChoice::have_geo_wind_profile
2388  * @brief Whether a geostrophic wind profile has been configured.
2389  * @var SolverChoice::variable_coriolis
2390  * @brief Whether spatially varying Coriolis forcing is enabled.
2391  * @var SolverChoice::ave_plane
2392  * @brief Averaging plane index used by diagnostics.
2393  * @var SolverChoice::moisture_indices
2394  * @brief Index map of the moisture data carried by the active scheme: conserved-state
2395  * components for the species and qmoist slots for the moist diagnostics.
2396  * @var SolverChoice::moisture_tight_coupling
2397  * @brief Whether moisture updates use tight coupling.
2398  * @var SolverChoice::windfarm_loc_table
2399  * @brief Wind-farm location table path.
2400  * @var SolverChoice::windfarm_spec_table
2401  * @brief Wind-farm turbine specification table path.
2402  * @var SolverChoice::windfarm_spec_table_extra
2403  * @brief Additional wind-farm turbine specification table path.
2404  * @var SolverChoice::windfarm_blade_table
2405  * @brief Wind-farm blade table path.
2406  * @var SolverChoice::windfarm_airfoil_tables
2407  * @brief Wind-farm airfoil table paths.
2408  * @var SolverChoice::sampling_distance_by_D
2409  * @brief Turbine inflow sampling distance normalized by rotor diameter.
2410  * @var SolverChoice::turb_disk_angle
2411  * @brief Turbine disk angle from the x axis [deg].
2412  * @var SolverChoice::windfarm_x_shift
2413  * @brief Wind-farm x-coordinate shift.
2414  * @var SolverChoice::windfarm_y_shift
2415  * @brief Wind-farm y-coordinate shift.
2416  * @var SolverChoice::bdy_nudge_factor
2417  * @brief Boundary sponge nudging factor.
2418  * @var SolverChoice::use_wrf_bdy_qc_qi
2419  * @brief Whether WRF cloud water and active cloud ice are ingested at real boundaries.
2420  * @var SolverChoice::bdy_moist_nudge_type
2421  * @brief Moist-variable nudging strategy in boundary regions.
2422  * @var SolverChoice::do_forest_drag
2423  * @brief Whether forest canopy drag is enabled.
2424  * @var SolverChoice::const_massflux_u
2425  * @brief Target constant mass flux in the x direction.
2426  * @var SolverChoice::const_massflux_v
2427  * @brief Target constant mass flux in the y direction.
2428  * @var SolverChoice::const_massflux_tau
2429  * @brief Relaxation time scale for constant-mass-flux forcing.
2430  * @var SolverChoice::const_massflux_layer_lo
2431  * @brief Lower height of the constant-mass-flux forcing layer.
2432  * @var SolverChoice::const_massflux_layer_hi
2433  * @brief Upper height of the constant-mass-flux forcing layer.
2434  * @var SolverChoice::massflux_klo
2435  * @brief Lower vertical index for constant-mass-flux forcing.
2436  * @var SolverChoice::massflux_khi
2437  * @brief Upper vertical index for constant-mass-flux forcing.
2438  * @var SolverChoice::hindcast_boundary_data_dir
2439  * @brief Directory containing hindcast lateral boundary data.
2440  * @var SolverChoice::hindcast_surface_data_dir
2441  * @brief Directory containing hindcast surface boundary data.
2442  * @var SolverChoice::hindcast_data_interval_in_hrs
2443  * @brief Time interval between hindcast data files [hr].
2444  * @var SolverChoice::hindcast_lateral_forcing
2445  * @brief Whether hindcast lateral forcing is enabled.
2446  * @var SolverChoice::hindcast_surface_bcs
2447  * @brief Whether hindcast surface boundary conditions are enabled.
2448  * @var SolverChoice::hindcast_lateral_sponge_strength
2449  * @brief Strength of the hindcast lateral sponge layer.
2450  * @var SolverChoice::hindcast_lateral_sponge_length
2451  * @brief Length of the hindcast lateral sponge layer.
2452  * @var SolverChoice::hindcast_zhi_sponge_strength
2453  * @brief Strength of the upper hindcast sponge layer.
2454  * @var SolverChoice::hindcast_zhi_sponge_length
2455  * @brief Length of the upper hindcast sponge layer.
2456  * @var SolverChoice::hindcast_zhi_sponge_damping
2457  * @brief Whether upper-boundary hindcast sponge damping is enabled.
2458  * @var SolverChoice::io_hurricane_eye_tracker
2459  * @brief Whether hurricane-eye tracking output is enabled.
2460  * @var SolverChoice::hurricane_eye_latitude
2461  * @brief Initial hurricane-eye latitude.
2462  * @var SolverChoice::hurricane_eye_longitude
2463  * @brief Initial hurricane-eye longitude.
2464  * @var SolverChoice::is_init_for_ensemble
2465  * @brief Whether initialization is for an ensemble simulation.
2466  * @var SolverChoice::n_ensemble
2467  * @brief Number of ensemble members.
2468  * @var SolverChoice::ens_pert_correlated_radius
2469  * @brief Spatial correlation radius for ensemble perturbations.
2470  * @var SolverChoice::ens_pert_amplitude
2471  * @brief Amplitude of ensemble initialization perturbations.
2472  * @var SolverChoice::coarse_bckgnd_data_file
2473  * @brief Coarse background data file used for ensemble initialization.
2474  */
2475 #endif
constexpr amrex::Real Cp_d
Definition: ERF_Constants.H:49
constexpr amrex::Real two
Definition: ERF_Constants.H:10
constexpr amrex::Real bogus_large_value
Definition: ERF_Constants.H:26
constexpr amrex::Real one
Definition: ERF_Constants.H:9
constexpr amrex::Real zero
Definition: ERF_Constants.H:8
constexpr amrex::Real PI
Definition: ERF_Constants.H:42
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:64
constexpr amrex::Real R_d
Definition: ERF_Constants.H:47
TauType
Stress tensor component indices.
Definition: ERF_DataStruct.H:38
@ tau12
Definition: ERF_DataStruct.H:39
@ tau23
Definition: ERF_DataStruct.H:39
@ tau33
Definition: ERF_DataStruct.H:39
@ tau22
Definition: ERF_DataStruct.H:39
@ tau11
Definition: ERF_DataStruct.H:39
@ tau32
Definition: ERF_DataStruct.H:39
@ tau31
Definition: ERF_DataStruct.H:39
@ tau21
Definition: ERF_DataStruct.H:39
@ tau13
Definition: ERF_DataStruct.H:39
AMREX_ENUM(InitType, None, Input_Sounding, NCFile, WRFInput, Metgrid, Uniform, ConstantDensity, ConstantDensityLinearTheta, Isentropic, MoistBaseState, HindCast)
Initial-condition source used to populate the ERF state.
Rayleigh
Rayleigh damping profile component indices.
Definition: ERF_DataStruct.H:152
@ ubar
Definition: ERF_DataStruct.H:153
@ wbar
Definition: ERF_DataStruct.H:153
@ nvars
Definition: ERF_DataStruct.H:153
@ vbar
Definition: ERF_DataStruct.H:153
@ thetabar
Definition: ERF_DataStruct.H:153
Sponge
Sponge reference-state component indices.
Definition: ERF_DataStruct.H:160
@ nvars_sponge
Definition: ERF_DataStruct.H:161
@ vbar_sponge
Definition: ERF_DataStruct.H:161
@ ubar_sponge
Definition: ERF_DataStruct.H:161
MapFacType
Indices for map scale factors on mass and face grids.
Definition: ERF_DataStruct.H:26
@ v_x
Definition: ERF_DataStruct.H:28
@ num
Definition: ERF_DataStruct.H:28
@ u_y
Definition: ERF_DataStruct.H:29
@ v_y
Definition: ERF_DataStruct.H:29
@ m_y
Definition: ERF_DataStruct.H:29
@ u_x
Definition: ERF_DataStruct.H:28
@ m_x
Definition: ERF_DataStruct.H:28
Coord
Coordinate-axis selector.
Definition: ERF_DataStruct.H:144
#define RhoQ4_comp
Definition: ERF_IndexDefines.H:48
#define RhoQ2_comp
Definition: ERF_IndexDefines.H:46
#define RhoQ3_comp
Definition: ERF_IndexDefines.H:47
#define RhoQ11_comp
Definition: ERF_IndexDefines.H:55
#define RhoQ9_comp
Definition: ERF_IndexDefines.H:53
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:45
#define RhoQ6_comp
Definition: ERF_IndexDefines.H:50
#define RhoQ8_comp
Definition: ERF_IndexDefines.H:52
#define RhoQ5_comp
Definition: ERF_IndexDefines.H:49
#define RhoQ7_comp
Definition: ERF_IndexDefines.H:51
#define RhoQ10_comp
Definition: ERF_IndexDefines.H:54
ParmParse pp("prob")
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(m_cloud_chamber_config.active, "Cloud Chamber: initializer reached without a parsed configuration")
std::string name
Definition: ERF_Plotfile2DCatalog.cpp:101
amrex::Real Real
Definition: ERF_ShocInterface.H:19
ShocMomentumTransport
Definition: ERF_ShocTransportStruct.H:17
bool shoc_disables_momentum_transport(ShocMomentumTransport mode)
Definition: ERF_ShocTransportStruct.H:69
bool shoc_uses_host_diffusion(ShocTransportMode mode)
Definition: ERF_ShocTransportStruct.H:51
void read_shoc_transport_modes(ShocTransportMode &transport_mode, ShocMomentumTransport &momentum_transport)
Read the native SHOC transport modes from the erf.shoc input namespace.
Definition: ERF_ShocTransportStruct.H:138
bool shoc_uses_momentum_host_diffusion(ShocMomentumTransport mode)
Definition: ERF_ShocTransportStruct.H:63
ShocTransportMode
Definition: ERF_ShocTransportStruct.H:11
int query_one_or_per_level_enum_case_insensitive(const amrex::ParmParse &pp, const char *query_string, T &query_var, const int lev, const int maxlev)
Query a scalar or per-level enum input value using case-insensitive matching.
Definition: ERF_TurbStruct.H:80
AMREX_ASSERT_WITH_MESSAGE(wbar_cutoff_min > wbar_cutoff_max, "ERROR: wbar_cutoff_min < wbar_cutoff_max")
Definition: ERF_EWP.H:9
Definition: ERF_Fitch.H:9
Definition: ERF_GeneralAD.H:8
Definition: ERF_Kessler.H:40
Definition: ERF_MoistNoCondensation.H:13
Definition: ERF_Morrison.H:59
Definition: ERF_NOAHMP.H:57
Definition: ERF_SAM.H:55
Definition: ERF_SLM.H:26
Definition: ERF_SatAdj.H:46
Definition: ERF_SimpleAD.H:8
Definition: ERF_WDM6.H:57
Definition: ERF_WSM6.H:38
Definition: ERF_AdvStruct.H:19
void display(std::string &pp_prefix)
Print the configured advection choices.
Definition: ERF_AdvStruct.H:243
void init_params(std::string pp_prefix)
Read advection options from the input parameter database.
Definition: ERF_AdvStruct.H:25
Definition: ERF_DampingStruct.H:22
void init_params(std::string pp_prefix)
Read damping options from the input parameter database.
Definition: ERF_DampingStruct.H:28
void display()
Print the configured damping options.
Definition: ERF_DampingStruct.H:71
Definition: ERF_DiffStruct.H:22
MolecDiffType molec_diff_type
Selected molecular transport model.
Definition: ERF_DiffStruct.H:94
void init_params(std::string pp_prefix)
Read diffusion options from the input parameter database.
Definition: ERF_DiffStruct.H:28
void display()
Print the configured diffusion options.
Definition: ERF_DiffStruct.H:77
Definition: ERF_EBStruct.H:36
void init_params(std::string pp_prefix)
Read embedded-boundary options from the input parameter database.
Definition: ERF_EBStruct.H:42
void display()
Print the configured embedded-boundary options.
Definition: ERF_EBStruct.H:63
An ordered list of conserved-state components forming an aggregate moisture output variable (qt,...
Definition: ERF_DataStruct.H:435
int comp[max_size]
Definition: ERF_DataStruct.H:437
int size
Definition: ERF_DataStruct.H:438
bool empty() const
Definition: ERF_DataStruct.H:444
void append(int c)
Append a component, ignoring the ones the scheme does not carry.
Definition: ERF_DataStruct.H:441
static constexpr int max_size
qv, qc, qi, qr, qs, qg
Definition: ERF_DataStruct.H:436
Whether this map decides a variable's availability, and if so whether the variable is available.
Definition: ERF_DataStruct.H:563
bool available
the active scheme carries the data behind it
Definition: ERF_DataStruct.H:565
bool governed
the name is a moisture output variable
Definition: ERF_DataStruct.H:564
The moisture data carried by the active microphysics scheme.
Definition: ERF_DataStruct.H:195
int nc
cloud liquid water number
Definition: ERF_DataStruct.H:216
int qs
snow
Definition: ERF_DataStruct.H:210
int cond_rate
condensation rate
Definition: ERF_DataStruct.H:239
int comp_for_var(const std::string &name) const
The conserved-state component behind a single-species output name, or absent if the name is not a sin...
Definition: ERF_DataStruct.H:525
int nn
CCN / total aerosol number.
Definition: ERF_DataStruct.H:226
int qr
rain
Definition: ERF_DataStruct.H:209
static constexpr int absent
not carried by the active scheme
Definition: ERF_DataStruct.H:198
int graup_accum
accumulated surface graupel
Definition: ERF_DataStruct.H:237
bool has_comp(int comp) const
Test whether a conserved-state component holds one of the moisture variables this scheme carries.
Definition: ERF_DataStruct.H:487
MoistureComponentIndices()=default
Construct an empty map, i.e. a dry run.
int qi
cloud ice
Definition: ERF_DataStruct.H:208
int rel_hum
relative humidity
Definition: ERF_DataStruct.H:238
static constexpr int computed_from_state
Definition: ERF_DataStruct.H:199
int ni
cloud ice number
Definition: ERF_DataStruct.H:217
int qv
water vapor
Definition: ERF_DataStruct.H:206
int rain_accum
accumulated surface rain
Definition: ERF_DataStruct.H:235
CompList nonprecipitating_comps() const
Components summed for non-precipitating water, "qn": vapor plus the suspended condensate....
Definition: ERF_DataStruct.H:463
bool has_reflectivity_species() const
Test whether the active scheme carries rain, snow and graupel in the RhoQ4/RhoQ5/RhoQ6 slots assumed ...
Definition: ERF_DataStruct.H:503
int snow_accum
accumulated surface snow
Definition: ERF_DataStruct.H:236
CompList total_water_comps() const
Components summed for total water, "qt": every mass mixing ratio.
Definition: ERF_DataStruct.H:452
int nr
rain number
Definition: ERF_DataStruct.H:218
int qc
cloud liquid water
Definition: ERF_DataStruct.H:207
int ng
graupel number
Definition: ERF_DataStruct.H:220
CompList precipitating_comps() const
Components summed for precipitating water, "qp": the falling species.
Definition: ERF_DataStruct.H:472
int qg
graupel
Definition: ERF_DataStruct.H:211
bool has_moisture() const
Test whether the active scheme carries any moisture at all.
Definition: ERF_DataStruct.H:513
int ns
snow number
Definition: ERF_DataStruct.H:219
VarAvailability query_var(const std::string &name) const
Classify an output variable name against this index map.
Definition: ERF_DataStruct.H:579
bool has_derived_var(const std::string &name) const
Test whether the moist species behind a derived/plot variable name is carried by the active scheme.
Definition: ERF_DataStruct.H:624
static MoistureComponentIndices from_moisture_model(const MoistureType moisture_type)
Build the complete index map – conserved-state components and qmoist diagnostic slots – for a moistur...
Definition: ERF_DataStruct.H:295
MoistureComponentIndices(int qv_comp, int qc_comp, int qi_comp=absent, int qr_comp=absent, int qs_comp=absent, int qg_comp=absent, int nc_comp=absent, int ni_comp=absent, int nr_comp=absent, int ns_comp=absent, int ng_comp=absent, int nn_comp=absent)
Construct the conserved-state component map.
Definition: ERF_DataStruct.H:261
int qmoist_index_for_var(const std::string &name) const
The qmoist slot behind a moist diagnostic output name.
Definition: ERF_DataStruct.H:550
Definition: ERF_DataStruct.H:634
bool use_coupled_sst
Definition: ERF_DataStruct.H:2131
bool custom_geostrophic_profile
Whether a custom geostrophic wind profile is used.
Definition: ERF_DataStruct.H:1966
int n_ensemble
Number of ensemble members.
Definition: ERF_DataStruct.H:2202
WindFarmLocType windfarm_loc_type
Coordinate system for wind-farm turbine locations.
Definition: ERF_DataStruct.H:2126
bool implicit_before_substep
Whether implicit diffusion is applied before acoustic substepping.
Definition: ERF_DataStruct.H:1894
amrex::Real const_massflux_v
Target constant mass flux in the y direction.
Definition: ERF_DataStruct.H:2183
std::string hindcast_boundary_data_dir
Directory containing hindcast lateral boundary data.
Definition: ERF_DataStruct.H:2190
amrex::Real ens_pert_correlated_radius
Spatial correlation radius for ensemble perturbations.
Definition: ERF_DataStruct.H:2203
amrex::Real forest_leaf_theta_fixed
Definition: ERF_DataStruct.H:2179
static InitType init_type
Initial-condition source selected for the run.
Definition: ERF_DataStruct.H:1833
amrex::Real coriolis_factor
Twice the planetary rotation rate used for Coriolis forcing.
Definition: ERF_DataStruct.H:1956
bool io_hurricane_eye_tracker
Whether hurricane-eye tracking output is enabled.
Definition: ERF_DataStruct.H:2198
std::string abl_geo_wind_table
Path to a time-varying geostrophic wind table.
Definition: ERF_DataStruct.H:2136
amrex::Vector< int > fixed_density
Per-level flag selecting fixed-density treatment.
Definition: ERF_DataStruct.H:1871
amrex::Vector< TurbChoice > turbChoice
Turbulence options for each AMR level.
Definition: ERF_DataStruct.H:1864
amrex::Real const_massflux_layer_lo
Lower height of the constant-mass-flux forcing layer.
Definition: ERF_DataStruct.H:2185
amrex::Real hindcast_zhi_sponge_length
Length of the upper hindcast sponge layer.
Definition: ERF_DataStruct.H:2195
amrex::Real gravity
Effective gravitational acceleration.
Definition: ERF_DataStruct.H:1946
void check_params(int max_level, const amrex::Vector< amrex::Geometry > &geom_vect, amrex::GpuArray< ERF_BC, AMREX_SPACEDIM *2 > phys_bc_type)
Validate solver options after geometry and boundary conditions are known.
Definition: ERF_DataStruct.H:1496
bool pbl_suppresses_microphysics_condensation() const noexcept
Query whether the active PBL scheme suppresses microphysics condensation.
Definition: ERF_DataStruct.H:2095
bool variable_coriolis
Whether spatially varying Coriolis forcing is enabled.
Definition: ERF_DataStruct.H:2139
bool implicit_moisture_diffusion
Whether implicit vertical moisture diffusion is included.
Definition: ERF_DataStruct.H:1891
MoistureType moisture_type
Moisture or microphysics model.
Definition: ERF_DataStruct.H:2124
void display(int max_level, std::string pp_prefix)
Print the configured solver, physics, and transport options.
Definition: ERF_DataStruct.H:1611
amrex::Real poisson_abstol
Absolute tolerance for the Poisson solve.
Definition: ERF_DataStruct.H:1901
amrex::Real if_Cd_momentum
Immersed-forcing drag coefficient for momentum.
Definition: ERF_DataStruct.H:1923
bool nudging_t
Definition: ERF_DataStruct.H:1983
amrex::Real if_Olen_in
Input Obukhov length for immersed-forcing MOST [m].
Definition: ERF_DataStruct.H:1933
amrex::Vector< int > buoyancy_type
Per-level buoyancy formulation selector.
Definition: ERF_DataStruct.H:1873
bool forest_biophysics
Definition: ERF_DataStruct.H:2177
void build_coriolis_forcings_const_lat(std::string pp_prefix)
Build constant-latitude Coriolis forcing parameters.
Definition: ERF_DataStruct.H:1760
CouplingType coupling_type
Multilevel coupling strategy.
Definition: ERF_DataStruct.H:2123
bool use_pert_pres_gradient
Whether momentum equations use perturbational pressure gradients.
Definition: ERF_DataStruct.H:1909
amrex::Vector< int > project_initial_velocity
Per-level flag for projecting the initial velocity.
Definition: ERF_DataStruct.H:1872
int ave_plane
Averaging plane index used by diagnostics.
Definition: ERF_DataStruct.H:2141
amrex::Real const_massflux_u
Target constant mass flux in the x direction.
Definition: ERF_DataStruct.H:2182
void read_int_string(int max_level, const char *string_to_read, amrex::Vector< int > &vec_to_fill, int default_int)
Read one integer value or one value per AMR level.
Definition: ERF_DataStruct.H:1810
bool nudging_q
Definition: ERF_DataStruct.H:1984
int ncorr
Number of projection correction iterations.
Definition: ERF_DataStruct.H:1896
amrex::Real sampling_distance_by_D
Turbine inflow sampling distance normalized by rotor diameter.
Definition: ERF_DataStruct.H:2150
amrex::Real windfarm_y_shift
Wind-farm y-coordinate shift.
Definition: ERF_DataStruct.H:2153
bool use_rotate_surface_flux
Whether MOST surface fluxes are rotated with terrain.
Definition: ERF_DataStruct.H:1991
bool moisture_tight_coupling
Whether moisture updates use tight coupling.
Definition: ERF_DataStruct.H:2146
EBChoice ebChoice
Embedded-boundary options.
Definition: ERF_DataStruct.H:1865
bool compute_mean_vars
Definition: ERF_DataStruct.H:2008
amrex::Real beta_s
Time off-centering coefficient for forward weighting.
Definition: ERF_DataStruct.H:1881
bool implicit_ke_diffusion
Whether implicit vertical TKE diffusion is included.
Definition: ERF_DataStruct.H:1892
bool any_perturbation() const
Query whether any level uses a turbulent perturbation mode.
Definition: ERF_DataStruct.H:2104
amrex::Real if_z0
Immersed-forcing roughness length [m].
Definition: ERF_DataStruct.H:1929
bool forest_substep
Whether canopy source terms are applied only during substeps.
Definition: ERF_DataStruct.H:1920
bool use_wrf_bdy_density
Definition: ERF_DataStruct.H:2159
bool implicit_thermal_diffusion
Whether implicit vertical thermal diffusion is included.
Definition: ERF_DataStruct.H:1890
std::string mean_vars_reset_mode
Definition: ERF_DataStruct.H:2011
bool use_gravity
Whether gravitational forcing is enabled.
Definition: ERF_DataStruct.H:1912
amrex::Real num_diff_coeff
Numerical diffusion coefficient after input scaling.
Definition: ERF_DataStruct.H:2121
amrex::Real bdy_nudge_factor
Boundary sponge nudging factor.
Definition: ERF_DataStruct.H:2156
amrex::Real rdOcp
Ratio of dry-air gas constant to c_p.
Definition: ERF_DataStruct.H:1948
bool use_wvel_perturbation(int lev) const
Query whether vertical-velocity CPM perturbations are enabled on a level.
Definition: ERF_DataStruct.H:2054
bool hindcast_lateral_forcing
Whether hindcast lateral forcing is enabled.
Definition: ERF_DataStruct.H:2192
bool do_theta_advection
Whether custom vertical subsidence is applied to rho-theta.
Definition: ERF_DataStruct.H:1964
bool use_native_shoc
Whether any level uses the native SHOC PBL scheme.
Definition: ERF_DataStruct.H:1995
amrex::Real nudging_q_z2
Definition: ERF_DataStruct.H:1980
static bool use_real_bcs
Whether real-data lateral boundary conditions are used.
Definition: ERF_DataStruct.H:1845
bool spatial_moisture_forcing
Whether spatially varying moisture forcing is enabled.
Definition: ERF_DataStruct.H:1969
amrex::Vector< SubsteppingType > substepping_type
Acoustic substepping type for each AMR level.
Definition: ERF_DataStruct.H:1869
amrex::Real nudging_u_z2
Definition: ERF_DataStruct.H:1976
bool use_perturbation(int lev) const
Query whether any turbulent perturbation mode is enabled on a level.
Definition: ERF_DataStruct.H:2019
static SoundingType sounding_type
Interpretation used for input sounding profiles.
Definition: ERF_DataStruct.H:1836
int bdy_moist_nudge_type
Moist-variable nudging strategy in boundary regions.
Definition: ERF_DataStruct.H:2168
amrex::Real poisson_reltol
Relative tolerance for the Poisson solve.
Definition: ERF_DataStruct.H:1902
bool use_coriolis
Whether Coriolis forcing is enabled.
Definition: ERF_DataStruct.H:1913
amrex::Vector< PerturbationType > pert_type
Turbulent perturbation type for each AMR level.
Definition: ERF_DataStruct.H:2117
static MeshType mesh_type
Vertical mesh representation.
Definition: ERF_DataStruct.H:1848
AdvChoice advChoice
Advection-related options.
Definition: ERF_DataStruct.H:1860
SpongeChoice spongeChoice
Sponge-layer options.
Definition: ERF_DataStruct.H:1863
void init_params(int max_level, std::string pp_prefix)
Read solver-wide algorithmic options from the input parameter database.
Definition: ERF_DataStruct.H:641
bool time_avg_vel
Whether time-averaged velocity fields are output.
Definition: ERF_DataStruct.H:2005
bool use_direct_perturbation(int lev) const
Query whether direct turbulent perturbations are enabled on a level.
Definition: ERF_DataStruct.H:2032
bool have_geo_wind_profile
Whether a geostrophic wind profile has been configured.
Definition: ERF_DataStruct.H:2137
amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > abl_pressure_grad
Applied ABL pressure-gradient forcing vector.
Definition: ERF_DataStruct.H:2134
amrex::Vector< int > anelastic
Per-level flag selecting anelastic dynamics.
Definition: ERF_DataStruct.H:1870
bool four_stream_radiation
Whether the four-stream radiation approximation is enabled.
Definition: ERF_DataStruct.H:1916
int gradp_type
Terrain-fitted horizontal pressure-gradient formulation.
Definition: ERF_DataStruct.H:1907
DampingChoice dampingChoice
Damping-related options.
Definition: ERF_DataStruct.H:1862
amrex::Real if_damp_alpha
Immersed-forcing damping coefficient.
Definition: ERF_DataStruct.H:1937
bool rebalance_wrf_input
Whether to rebalance states from wrfinput and wrfbdy data.
Definition: ERF_DataStruct.H:1943
amrex::Real turb_disk_angle
Turbine disk angle from the x axis [deg].
Definition: ERF_DataStruct.H:2151
amrex::Real hindcast_data_interval_in_hrs
Time interval between hindcast data files [hr].
Definition: ERF_DataStruct.H:2191
amrex::Real const_massflux_layer_hi
Upper height of the constant-mass-flux forcing layer.
Definition: ERF_DataStruct.H:2186
bool avg_grid_faces_to_nodes
Definition: ERF_DataStruct.H:2171
std::string windfarm_spec_table_extra
Additional wind-farm turbine specification table path.
Definition: ERF_DataStruct.H:2148
amrex::Real if_ws_floor
Wind-speed floor for immersed-forcing MOST [m/s].
Definition: ERF_DataStruct.H:1936
amrex::Real lsf_timescale
Definition: ERF_DataStruct.H:1988
bool is_init_for_ensemble
Whether initialization is for an ensemble simulation.
Definition: ERF_DataStruct.H:2201
bool uses_shoc_family() const noexcept
Query whether any SHOC-family PBL scheme is active.
Definition: ERF_DataStruct.H:2063
bool test_mapfactor
Whether to use test map scale factors.
Definition: ERF_DataStruct.H:1905
amrex::Real nudging_u_z1
Definition: ERF_DataStruct.H:1975
std::string coarse_bckgnd_data_file
Coarse background data file used for ensemble initialization.
Definition: ERF_DataStruct.H:2205
bool do_forest_drag
Whether forest canopy drag is enabled.
Definition: ERF_DataStruct.H:2174
amrex::Real dz0
Initial vertical grid spacing for stretched-grid setup.
Definition: ERF_DataStruct.H:1953
amrex::Real windfarm_x_shift
Wind-farm x-coordinate shift.
Definition: ERF_DataStruct.H:2152
bool use_lagged_delta_rt
Whether to use lagged delta terms for moving terrain.
Definition: ERF_DataStruct.H:1940
amrex::Real ens_pert_amplitude
Amplitude of ensemble initialization perturbations.
Definition: ERF_DataStruct.H:2204
std::string windfarm_airfoil_tables
Wind-farm airfoil table paths.
Definition: ERF_DataStruct.H:2149
amrex::Real bdy_rho_nudge_factor
Definition: ERF_DataStruct.H:2165
amrex::Real nudging_q_z1
Definition: ERF_DataStruct.H:1979
amrex::Vector< amrex::Vector< amrex::Real > > vert_implicit_fac
Per-level, per-stage implicit vertical diffusion factors.
Definition: ERF_DataStruct.H:1887
bool transport_scalar
Whether the passive scalar component is transported.
Definition: ERF_DataStruct.H:2002
bool hindcast_zhi_sponge_damping
Whether upper-boundary hindcast sponge damping is enabled.
Definition: ERF_DataStruct.H:2196
amrex::Real hurricane_eye_longitude
Initial hurricane-eye longitude.
Definition: ERF_DataStruct.H:2199
LandSurfaceType lsm_type
Land-surface model.
Definition: ERF_DataStruct.H:2127
int massflux_khi
Upper vertical index for constant-mass-flux forcing.
Definition: ERF_DataStruct.H:2188
bool large_scale_forcing
Definition: ERF_DataStruct.H:1986
bool substepping_diag
Whether to emit extra CFL diagnostics for compressible substepping.
Definition: ERF_DataStruct.H:1877
static TerrainType terrain_type
Terrain or immersed-boundary representation.
Definition: ERF_DataStruct.H:1839
amrex::Real mean_vars_reset_time
Definition: ERF_DataStruct.H:2012
std::string windfarm_blade_table
Wind-farm blade table path.
Definition: ERF_DataStruct.H:2149
amrex::Vector< int > is_land
Per-level land/water selector.
Definition: ERF_DataStruct.H:1874
amrex::Real hindcast_lateral_sponge_strength
Strength of the hindcast lateral sponge layer.
Definition: ERF_DataStruct.H:2194
bool forest_biophysics_heat
Definition: ERF_DataStruct.H:2178
ShocTransportMode shoc_transport_mode
Definition: ERF_DataStruct.H:1998
amrex::Real hurricane_eye_latitude
Initial hurricane-eye latitude.
Definition: ERF_DataStruct.H:2199
amrex::Real cosphi
Cosine of the latitude used for Coriolis forcing.
Definition: ERF_DataStruct.H:1957
amrex::Real if_Cd_scalar
Immersed-forcing drag coefficient for scalars.
Definition: ERF_DataStruct.H:1924
static BuildingsType buildings_type
Building representation.
Definition: ERF_DataStruct.H:1842
std::string windfarm_loc_table
Wind-farm location table path.
Definition: ERF_DataStruct.H:2148
std::string hindcast_surface_data_dir
Directory containing hindcast surface boundary data.
Definition: ERF_DataStruct.H:2190
ShocMomentumTransport shoc_momentum_transport
Definition: ERF_DataStruct.H:1999
bool custom_rhotheta_forcing
Whether custom rho-theta forcing is enabled.
Definition: ERF_DataStruct.H:1961
amrex::Real zsurf
Nominal surface height for stretched-grid setup.
Definition: ERF_DataStruct.H:1952
amrex::Real if_init_surf_temp
Initial immersed-forcing surface temperature [K].
Definition: ERF_DataStruct.H:1931
amrex::Real nudging_t_z2
Definition: ERF_DataStruct.H:1978
int massflux_klo
Lower vertical index for constant-mass-flux forcing.
Definition: ERF_DataStruct.H:2187
std::string lsf_file
Definition: ERF_DataStruct.H:1987
std::string windfarm_spec_table
Wind-farm turbine specification table path.
Definition: ERF_DataStruct.H:2148
amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > abl_geo_forcing
Applied geostrophic-wind forcing vector.
Definition: ERF_DataStruct.H:2135
ABLDriverType abl_driver_type
Atmospheric boundary-layer driver type.
Definition: ERF_DataStruct.H:2133
DiffChoice diffChoice
Diffusion-related options.
Definition: ERF_DataStruct.H:1861
amrex::Real if_surf_temp_flux
Immersed-forcing surface temperature flux [K m/s].
Definition: ERF_DataStruct.H:1930
bool spatial_rhotheta_forcing
Whether spatially varying rho-theta forcing is enabled.
Definition: ERF_DataStruct.H:1968
WindFarmType windfarm_type
Wind-farm model.
Definition: ERF_DataStruct.H:2125
bool use_source_perturbation(int lev) const
Query whether source-term turbulent perturbations are enabled on a level.
Definition: ERF_DataStruct.H:2044
bool custom_w_subsidence
Whether custom vertical subsidence is enabled.
Definition: ERF_DataStruct.H:1963
bool custom_moisture_forcing
Whether custom moisture forcing is enabled.
Definition: ERF_DataStruct.H:1962
amrex::Real if_surf_heating_rate
Immersed-forcing surface heating rate [K/hr].
Definition: ERF_DataStruct.H:1932
MoistureComponentIndices moisture_indices
Index map of the moisture data carried by the active scheme: conserved-state components for the speci...
Definition: ERF_DataStruct.H:2144
RadiationType rad_type
Radiation model.
Definition: ERF_DataStruct.H:2128
amrex::Real grid_stretching_ratio
Vertical grid stretching ratio.
Definition: ERF_DataStruct.H:1951
bool hindcast_surface_bcs
Whether hindcast surface boundary conditions are enabled.
Definition: ERF_DataStruct.H:2193
bool host_owns_vertical_scalar_diffusion() const noexcept
Test whether the host owns scalar diffusion.
Definition: ERF_DataStruct.H:2084
bool immersed_forcing_substep
Whether immersed-forcing source terms are applied only during substeps.
Definition: ERF_DataStruct.H:1919
bool if_use_most
Whether immersed-forcing MOST is enabled.
Definition: ERF_DataStruct.H:1934
amrex::Real const_massflux_tau
Relaxation time scale for constant-mass-flux forcing.
Definition: ERF_DataStruct.H:2184
amrex::Real hindcast_lateral_sponge_length
Length of the hindcast lateral sponge layer.
Definition: ERF_DataStruct.H:2194
bool use_eamxx_shoc
Whether any level uses the EAMxx SHOC PBL scheme.
Definition: ERF_DataStruct.H:1994
amrex::Real sinphi
Sine of the latitude used for Coriolis forcing.
Definition: ERF_DataStruct.H:1958
bool host_owns_vertical_momentum_diffusion() const noexcept
Test whether the host owns momentum diffusion.
Definition: ERF_DataStruct.H:2072
amrex::Real hindcast_zhi_sponge_strength
Strength of the upper hindcast sponge layer.
Definition: ERF_DataStruct.H:2195
bool coriolis_3d
Whether the three-dimensional Coriolis terms are included.
Definition: ERF_DataStruct.H:1914
int force_stage1_single_substep
Flag forcing a single substep in the first RK stage.
Definition: ERF_DataStruct.H:1867
amrex::Real c_p
Specific heat at constant pressure for dry air [J/(kg-K)].
Definition: ERF_DataStruct.H:1947
bool if_implicit_drag
Definition: ERF_DataStruct.H:1927
bool implicit_momentum_diffusion
Whether implicit vertical momentum diffusion is included.
Definition: ERF_DataStruct.H:1893
bool do_mom_advection
Whether custom vertical subsidence is applied to momentum.
Definition: ERF_DataStruct.H:1965
bool if_stability_correction
Whether immersed-forcing stability corrections are enabled.
Definition: ERF_DataStruct.H:1935
amrex::Real nudging_t_z1
Definition: ERF_DataStruct.H:1977
bool custom_forcing_prim_vars
Whether custom forcing operates on primitive variables.
Definition: ERF_DataStruct.H:1967
bool nudging_u
Definition: ERF_DataStruct.H:1982
bool nudging_from_input_sounding
Whether solution fields are nudged toward input sounding data.
Definition: ERF_DataStruct.H:1973
static void set_mesh_type(MeshType new_mesh_type)
Override the globally selected mesh type.
Definition: ERF_DataStruct.H:1855
bool use_num_diff
Whether sixth-order numerical diffusion is enabled.
Definition: ERF_DataStruct.H:2120
bool use_wrf_bdy_qc_qi
Whether WRF cloud water and active cloud ice are ingested at real boundaries.
Definition: ERF_DataStruct.H:2162
Definition: ERF_SpongeStruct.H:22
void display()
Print the configured sponge-layer options.
Definition: ERF_SpongeStruct.H:85
void init_params(std::string pp_prefix)
Read sponge-layer options from the input parameter database.
Definition: ERF_SpongeStruct.H:28