ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_TurbStruct.H
Go to the documentation of this file.
1 #ifndef ERF_TURB_STRUCT_H_
2 #define ERF_TURB_STRUCT_H_
3 
4 #include <AMReX_ParallelDescriptor.H>
5 #include <ERF_MYNNStruct.H>
6 #include <ERF_RANSClosure.H>
7 
8 #include <iomanip>
9 #include <sstream>
10 
11 /**
12  * @brief Large-eddy simulation closure type.
13  */
14 AMREX_ENUM(LESType, None, Smagorinsky, Smagorinsky2D, Deardorff);
15 
16 /**
17  * @brief Reynolds-averaged turbulence closure type.
18  */
19 AMREX_ENUM(RANSType, None, kEqn);
20 
21 /**
22  * @brief Planetary boundary-layer closure type.
23  */
24 AMREX_ENUM(PBLType, None, MYJ, MYNN25, MYNNEDMF, YSU, YSUNew, MRF, SHOC, EAMXX_SHOC, NATIVE_SHOC);
25 
26 /**
27  * @brief Thermodynamic variable used for stability stratification.
28  */
29 AMREX_ENUM(StratType, theta, thetav, thetal);
30 
31 /**
32  * @brief Query a scalar or per-level input value.
33  * @tparam T Value type accepted by ParmParse::query.
34  * @param pp ParmParse object to query.
35  * @param query_string Input key to query.
36  * @param query_var Destination value for the requested level.
37  * @param lev AMR level index.
38  * @param maxlev Maximum AMR level configured for the run.
39  * @return ParmParse query result, or zero if the key is absent.
40  */
41 template <typename T>
42 int
44  const amrex::ParmParse& pp,
45  const char* query_string,
46  T& query_var,
47  const int lev,
48  const int maxlev)
49 {
50  int count = pp.countval(query_string);
51  if (count == 0) {
52  return 0; // nothing to do
53  } else if (count == 1) {
54  // In this case, we assume the same value is used at every level
55  return pp.query(query_string, query_var);
56  } else if (count >= maxlev + 1) {
57  // In this case, there may be more values than levels so we
58  // will just read the number of values we need and ignore the
59  // extra levels
60  return pp.query(query_string, query_var, lev);
61  } else {
62  // In this case, there is more than one value AND there
63  // are more levels than values; as an example, if max_level = 2
64  // but count = 2 so we have three levels but only two values --
65  // it is not clear how to interpret this so we abort
66  amrex::Error(
67  "For parmparse variable " + pp.prefixedName(query_string) +
68  ": if specified, specify once total or at least once for each level");
69  return 0; // avoid compiler warning
70  }
71 }
72 
73 /**
74  * @brief Query a scalar or per-level enum input value using case-insensitive matching.
75  * @tparam T Enum type accepted by ParmParse::query_enum_case_insensitive.
76  * @param pp ParmParse object to query.
77  * @param query_string Input key to query.
78  * @param query_var Destination enum value for the requested level.
79  * @param lev AMR level index.
80  * @param maxlev Maximum AMR level configured for the run.
81  * @return ParmParse query result, or zero if the key is absent.
82  */
83 template <typename T>
84 int
86  const amrex::ParmParse& pp,
87  const char* query_string,
88  T& query_var,
89  const int lev,
90  const int maxlev)
91 {
92  int count = pp.countval(query_string);
93  if (count == 0) {
94  return 0; // nothing to do
95  } else if (count == 1) {
96  // In this case, we assume the same value is used at every level
97  return pp.query_enum_case_insensitive(query_string, query_var);
98  } else if (count >= maxlev + 1) {
99  // In this case, there may be more values than levels so we
100  // will just read the number of values we need and ignore the
101  // extra levels
102  return pp.query_enum_case_insensitive(query_string, query_var, lev);
103  } else {
104  // In this case, there is more than one value AND there
105  // are more levels than values; as an example, if max_level = 2
106  // but count = 2 so we have three levels but only two values --
107  // it is not clear how to interpret this so we abort
108  amrex::Error(
109  "For parmparse variable " + pp.prefixedName(query_string) +
110  ": if specified, specify once total or at least once for each level");
111  return 0; // avoid compiler warning
112  }
113 }
114 
115 /**
116  * Container holding quantities related to turbulence parametrizations
117  */
119 {
120 public:
121  /**
122  * @brief Read turbulence options for one AMR level from the input parameter database.
123  * @param lev AMR level index.
124  * @param max_level Maximum AMR level configured for the run.
125  * @param pp_prefix ParmParse prefix for the ERF input namespace.
126  */
127  void init_params (int lev, int max_level, std::string pp_prefix)
128  {
129  amrex::ParmParse pp(pp_prefix);
130 
131  // Which LES closure?
132  query_one_or_per_level(pp, "les_type", les_type, lev, max_level);
133  // Immersed-boundary awareness of the MRF and YSUNew schemes (off by default):
134  // the surface of a column with immersed solid cells is the first fluid cell
135  // above them, heights and the boundary-layer depth are measured from it,
136  // the eddy diffusivities are zero inside the solid, and the surface
137  // scales over such a column come from a neutral log law at its top with
138  // the roughness pbl_ib_z0. Only MRF and YSUNew honour it.
139  query_one_or_per_level(pp, "pbl_ib_aware", pbl_ib_aware, lev, max_level);
140  query_one_or_per_level(pp, "pbl_ib_z0", pbl_ib_z0, lev, max_level);
141 
142  // Handle 2-D Smag
143  if (les_type == LESType::Smagorinsky2D) {
144  les_type = LESType::Smagorinsky;
145  smag2d = true;
146  }
147 
148  // Which RANS closure?
149  query_one_or_per_level(pp, "rans_type", rans_type, lev, max_level);
150 
151  if ((rans_type != RANSType::None) && (les_type != LESType::None)) {
152  amrex::Error("Hybrid RANS-LES not implemented");
153  }
154 
155  // Which PBL Closure
156  query_one_or_per_level_enum_case_insensitive(pp, "pbl_type", pbl_type, lev, max_level);
157  if (pbl_type == PBLType::SHOC) {
158  static bool warned_legacy_shoc = false;
159  if (!warned_legacy_shoc) {
160  amrex::Warning("erf.pbl_type = SHOC is deprecated; use erf.pbl_type = EAMXX_SHOC");
161  warned_legacy_shoc = true;
162  }
163  pbl_type = PBLType::EAMXX_SHOC;
164  }
165 
166  // Do some more stuff for PBL Modeling
167  if (pbl_type != PBLType::None) {
168  // Check for compatibility between PBL, LES, Molec Transport
169  if (les_type != LESType::None) {
170  amrex::Print() << "Selected a PBL model and an LES model: "
171  << "Using PBL for vertical transport, LES for horizontal"
172  << std::endl;
173  }
174  if (les_type == LESType::Smagorinsky) {
175  if (!smag2d)
176  amrex::Error("If using Smagorinsky with a PBL model, the 2-D "
177  "formulation should be used");
178  } else if (les_type == LESType::Deardorff) {
179  amrex::Error(
180  "It is not recommended to use Deardorff LES and a PBL model");
181  }
182  // Both the k-eqn RANS closure and these PBL schemes transport RhoKE
183  if ((rans_type == RANSType::kEqn) &&
184  ((pbl_type == PBLType::MYJ) || (pbl_type == PBLType::MYNN25) ||
185  (pbl_type == PBLType::MYNNEDMF) || uses_shoc_family())) {
186  amrex::Error("erf.rans_type = kEqn cannot be combined with erf.pbl_type = " +
187  std::string(amrex::getEnumNameString(pbl_type)) +
188  ": both transport the turbulent kinetic energy");
189  }
190 
191  if (pbl_type == PBLType::MYNN25 || pbl_type == PBLType::MYNNEDMF) {
193  pp, "pbl_mynn_Lt_taper_exp", pbl_mynn.Lt_taper_exp, lev, max_level);
194  if (pbl_mynn.Lt_taper_exp < 0) {
195  amrex::Error("erf.pbl_mynn_Lt_taper_exp must be >= 0 "
196  "(0 disables the taper)");
197  }
198  // NN09 (the default) uses Lt_alpha = 0.23 and a 1/l sum for the master
199  // length scale; Chen2021 uses Lt_alpha = 0.10 and a 1/l^2 sum.
201  pp, "pbl_mynn_config", pbl_mynn.config, lev, max_level);
202  // l_T = Lt_alpha*<zq>/<q> follows the config unless set explicitly.
203  pbl_mynn.Lt_alpha = (pbl_mynn.config == MYNNConfigType::Chen2021)
204  ? amrex::Real(0.1) : amrex::Real(0.23);
206  pp, "pbl_mynn_Lt_alpha", pbl_mynn.Lt_alpha, lev, max_level);
207  query_one_or_per_level(pp, "pbl_mynn_A1", pbl_mynn.A1, lev, max_level);
208  query_one_or_per_level(pp, "pbl_mynn_A2", pbl_mynn.A2, lev, max_level);
209  query_one_or_per_level(pp, "pbl_mynn_B1", pbl_mynn.B1, lev, max_level);
210  query_one_or_per_level(pp, "pbl_mynn_B2", pbl_mynn.B2, lev, max_level);
211  query_one_or_per_level(pp, "pbl_mynn_C1", pbl_mynn.C1, lev, max_level);
212  query_one_or_per_level(pp, "pbl_mynn_C2", pbl_mynn.C2, lev, max_level);
213  query_one_or_per_level(pp, "pbl_mynn_C3", pbl_mynn.C3, lev, max_level);
214  query_one_or_per_level(pp, "pbl_mynn_C4", pbl_mynn.C4, lev, max_level);
215  query_one_or_per_level(pp, "pbl_mynn_C5", pbl_mynn.C5, lev, max_level);
219  // Moisture is now always diffused by MYNN, as it is by every other
220  // PBL scheme; catch the retired flag rather than ignoring it silently.
221  if (pp.contains("pbl_mynn_diffuse_moistvars")) {
222  amrex::Abort("erf.pbl_mynn_diffuse_moistvars has been removed. "
223  "MYNN always diffuses the moisture variables now, as "
224  "MYJ, YSU, MRF and SHOC always have; there is no "
225  "longer a way to turn it off.");
226  }
228  pp, "pbl_mynn_SMmin", pbl_mynn.SMmin, lev, max_level);
230  pp, "pbl_mynn_SMmax", pbl_mynn.SMmax, lev, max_level);
232  pp, "pbl_mynn_SHmin", pbl_mynn.SHmin, lev, max_level);
234  pp, "pbl_mynn_SHmax", pbl_mynn.SHmax, lev, max_level);
236  pp, "pbl_mynn_SQfactor", pbl_mynn.SQfac, lev, max_level);
237 
238  // SQ = SQfac*SM, so its bound is tied to SHmax and SQfac; the default member
239  // initializer was evaluated before either could be overridden here.
241 
242  } else if (pbl_type == PBLType::YSU || pbl_type == PBLType::YSUNew) {
244  pp, "pbl_ysu_coriolis_freq", pbl_ysu_coriolis_freq, lev, max_level);
246  pp, "pbl_ysu_use_consistent_coriolis",
247  pbl_ysu_use_consistent_coriolis, lev, max_level);
249  pp, "pbl_ysu_force_over_water", pbl_ysu_force_over_water, lev,
250  max_level);
252  pp, "pbl_ysu_land_Ribcr", pbl_ysu_land_Ribcr, lev, max_level);
254  pp, "pbl_ysu_unst_Ribcr", pbl_ysu_unst_Ribcr, lev, max_level);
255  // YSU now uses theta_v at WRF's thvx sites and theta_l at its thlix
256  // sites; catch the retired switch between them rather than ignoring it.
257  if (pp.contains("enable_ysu_liquid_theta")) {
258  amrex::Abort("erf.enable_ysu_liquid_theta has been removed. YSU uses "
259  "theta_v (all condensate loading) for the bulk Richardson "
260  "number and clear-sky entrainment, and theta_l (cloud "
261  "liquid and ice) for the cloud-top extension scan and "
262  "cloudy entrainment, as WRF does with thvx and thlix.");
263  }
265  pp, "enable_ysu_countergradient", enable_ysu_countergradient, lev, max_level);
267  pp, "enable_ysu_terrain_pblh_floor", enable_ysu_terrain_pblh_floor, lev, max_level);
269  pp, "enable_ysu_sat_limiter", enable_ysu_sat_limiter, lev, max_level);
271  pp, "enable_ysu_topdown", enable_ysu_topdown, lev, max_level);
273  pp, "enable_ysu_entrainment", enable_ysu_entrainment, lev, max_level);
275  pp, "enable_ysu_cloud_pblh", enable_ysu_cloud_pblh, lev, max_level);
277  pp, "enable_mrf_unbounded_vpert", enable_mrf_unbounded_vpert, lev, max_level);
279  pp, "ysu_qcloud_threshold", ysu_qcloud_threshold, lev, max_level);
281  pp, "ysu_moistvars", ysu_moistvars, lev, max_level);
283  pp, "pbl_ysunew_highres_bounds", pbl_ysunew_highres_bounds, lev, max_level);
284  // Radiative tendency limiter (YSUNew-only)
286  pp, "enable_ysu_rad_tend_limiter", enable_ysu_rad_tend_limiter, lev, max_level);
288  pp, "ysu_rad_tend_limiter_magnitude", ysu_rad_tend_limiter_magnitude, lev, max_level);
289  if (!(ysu_rad_tend_limiter_magnitude > 0.0)) {
290  if (amrex::ParallelDescriptor::IOProcessor()) {
291  amrex::Print() << "WARNING: erf.ysu_rad_tend_limiter_magnitude = "
293  << " is not positive; using the default of 1.0 K/s\n";
294  }
296  }
297  // Vogelezang & Holtslag (1996) shear correction
299  pp, "enable_vh96_shear_correction", enable_vh96_shear_correction, lev, max_level);
301  pp, "vh96_shear_const_b", vh96_shear_const_b, lev, max_level);
302  // PBLH spatial smoothing
304  pp, "enable_pblh_smoothing", enable_pblh_smoothing, lev, max_level);
306  pp, "pblh_smoothing_passes", pblh_smoothing_passes, lev, max_level);
308  pp, "pblh_smoothing_weight", pblh_smoothing_weight, lev, max_level);
309  // Validate pblh_smoothing_weight is in [0,1]
310  if (enable_pblh_smoothing && (pblh_smoothing_weight < 0 || pblh_smoothing_weight > 1)) {
311  amrex::Error("pblh_smoothing_weight must be in [0, 1]");
312  }
313  // QNSE stable stability functions (Sukoriansky et al. 2005)
315  pp, "enable_qnse_stable_functions", enable_qnse_stable_functions, lev, max_level);
317  pp, "qnse_am", qnse_am, lev, max_level);
319  pp, "qnse_bm", qnse_bm, lev, max_level);
321  pp, "qnse_ah", qnse_ah, lev, max_level);
323  pp, "qnse_bh", qnse_bh, lev, max_level);
324  } else if (pbl_type == PBLType::MRF) {
326  pp, "pbl_mrf_coriolis_freq", pbl_mrf_coriolis_freq, lev, max_level);
328  pp, "pbl_mrf_Ribcr", pbl_mrf_Ribcr, lev, max_level);
330  pp, "pbl_mrf_const_b", pbl_mrf_const_b, lev, max_level);
331  query_one_or_per_level(pp, "pbl_mrf_sf", pbl_mrf_sf, lev, max_level);
333  pp, "enable_mrf_countergradient", enable_mrf_countergradient, lev, max_level);
335  pp, "enable_mrf_cloud_adjustment", enable_mrf_cloud_adjustment, lev, max_level);
337  pp, "pbl_mrf_highres_bounds", pbl_mrf_highres_bounds, lev, max_level);
339  pp, "enable_mrf_unbounded_vpert", enable_mrf_unbounded_vpert, lev, max_level);
341  pp, "pbl_mrf_use_zero_ri_extent", pbl_mrf_use_zero_ri_extent, lev, max_level);
342  // QNSE stable stability functions (Sukoriansky et al. 2005)
344  pp, "enable_qnse_stable_functions", enable_qnse_stable_functions, lev, max_level);
346  pp, "qnse_am", qnse_am, lev, max_level);
348  pp, "qnse_bm", qnse_bm, lev, max_level);
350  pp, "qnse_ah", qnse_ah, lev, max_level);
352  pp, "qnse_bh", qnse_bh, lev, max_level);
353  // Scale-aware PBL-LES blending parameters.
355  pp, "pbl_blend_length", pbl_blend_length, lev, max_level);
357  pp, "pbl_blend_cs", pbl_blend_cs, lev, max_level);
359  pp, "pbl_blend_c_max", pbl_blend_c_max, lev, max_level);
361  pp, "pbl_blend_use_smag", pbl_blend_use_smag, lev, max_level);
362  // Vogelezang & Holtslag (1996) shear correction
364  pp, "enable_vh96_shear_correction", enable_vh96_shear_correction, lev, max_level);
366  pp, "vh96_shear_const_b", vh96_shear_const_b, lev, max_level);
367  // PBLH spatial smoothing
369  pp, "enable_pblh_smoothing", enable_pblh_smoothing, lev, max_level);
371  pp, "pblh_smoothing_passes", pblh_smoothing_passes, lev, max_level);
373  pp, "pblh_smoothing_weight", pblh_smoothing_weight, lev, max_level);
374  // Validate pblh_smoothing_weight is in [0,1]
375  if (enable_pblh_smoothing && (pblh_smoothing_weight < 0 || pblh_smoothing_weight > 1)) {
376  amrex::Error("pblh_smoothing_weight must be in [0, 1]");
377  }
378  }
379  if (uses_eamxx_shoc()) {
380 #ifndef ERF_USE_EAMXX_SHOC
381  amrex::Abort("PBLType::EAMXX_SHOC requested, but ERF was not built with ERF_ENABLE_EAMXX_SHOC=ON");
382 #endif
383  }
384 
386  std::string zlo_bc = "none";
387  amrex::ParmParse pp_bc("zlo");
388  pp_bc.get("type",zlo_bc);
389  if (amrex::toLower(zlo_bc) != "surface_layer") {
390  amrex::Abort("You must use the surface_layer BC at zlo with the selected PBL.");
391  }
392  }
393  }
394 
395  // Flags for QKE/TKE equation
396  if (pbl_type == PBLType::MYJ || pbl_type == PBLType::MYNN25 || pbl_type == PBLType::MYNNEDMF) {
397  // Add sources/sinks to QKE/TKE? (MYJ does this inline)
398  if (pbl_type == PBLType::MYNN25 || pbl_type == PBLType::MYNNEDMF) {
399  use_pbl_tke = true;
400  }
401  // Advect QKE/TKE?
402  query_one_or_per_level(pp, "advect_tke" , advect_tke , lev, max_level);
403  // Apply numerical diffusion to QKE/TKE?
404  query_one_or_per_level(pp, "diffuse_tke_3D", diffuse_tke_3D, lev, max_level);
405  }
406 
407  // There is a default value of 1e-6 but the user can override the value here,
408  // and in addition can add perturbational values. and in addition can add perturbational values.
409  pp.queryAdd("tke_min",tke_min);
410 
411  // LES constants...
412  query_one_or_per_level(pp, "Cs", Cs, lev, max_level);
413 
414  query_one_or_per_level(pp, "Pr_t", Pr_t, lev, max_level);
415  query_one_or_per_level(pp, "Sc_t", Sc_t, lev, max_level);
416 
417  // Compute relevant forms of diffusion parameters
418  Pr_t_inv = one / Pr_t;
419  Sc_t_inv = one / Sc_t;
420 
421  if (les_type == LESType::Deardorff) {
422  query_one_or_per_level(pp, "Ck", Ck, lev, max_level);
423  query_one_or_per_level(pp, "Ce", Ce, lev, max_level);
424  query_one_or_per_level(pp, "Ce_wall", Ce_wall, lev, max_level);
425  }
426 
427  // To quantify atmospheric stability for subgrid modeling
428  const bool strat_type_set = (pp.countval("thermal_stratification") > 0);
429  query_one_or_per_level(pp, "thermal_stratification", strat_type, lev, max_level);
430  // The PBL schemes have always used theta_v for their buoyancy gradient,
431  // which is the physically right choice there. Honour an explicit
432  // erf.thermal_stratification everywhere, but when the user has not set it
433  // keep the historical split: theta for the LES closures, theta_v for the
434  // PBL ones. That way the knob reaches the PBL schemes without silently
435  // changing any existing moist answer.
436  pbl_strat_type = strat_type_set ? strat_type : StratType::thetav;
437  amrex::Print() << "PBL thermal stratification variable: "
438  << amrex::getEnumNameString(pbl_strat_type) << std::endl;
439  if (strat_type == StratType::theta) {
440  amrex::Print() << "Thermal stratification based on gradient of potential temperature" << std::endl;
441  } else if (strat_type == StratType::thetav) {
442  amrex::Print() << "Thermal stratification based on gradient of virtual potential temperature" << std::endl;
443  } else if (strat_type == StratType::thetal) {
444  amrex::Print() << "Thermal stratification based on gradient of linearized liquid-water potential temperature" << std::endl;
445  }
446 
447  // k-eqn constants
448  query_one_or_per_level(pp, "Cmu0", Cmu0, lev, max_level);
449  query_one_or_per_level(pp, "Cb", Cb, lev, max_level);
450  query_one_or_per_level(pp, "Rt_crit", Rt_crit, lev, max_level);
451  query_one_or_per_level(pp, "Rt_min", Rt_min, lev, max_level);
452  query_one_or_per_level(pp, "max_geom_lscale", l_g_max, lev, max_level);
453  query_one_or_per_level(pp, "dirichlet_k", dirichlet_k, lev, max_level);
454  query_one_or_per_level(pp, "tke_floor", tke_floor, lev, max_level);
455  query_one_or_per_level(pp, "implicit_tke_dissipation", implicit_tke_dissipation, lev, max_level);
456  query_one_or_per_level(pp, "rans_consistent_diffusivities", rans_consistent_diffusivities, lev, max_level);
457  query_one_or_per_level(pp, "rans_lscale_from_pblh", rans_lscale_from_pblh, lev, max_level);
458  query_one_or_per_level(pp, "rans_lscale_min", rans_lscale_min, lev, max_level);
459  query_one_or_per_level(pp, "rans_realizability", rans_realizability, lev, max_level);
460  if (rans_realizability != zero) {
461  if (!(rans_realizability >= amrex::Real(0.01) && rans_realizability <= amrex::Real(10))) {
462  amrex::Error("erf.rans_realizability must be 0 (off) or in [0.01, 10]; Cmu0^2 = 0.309 is the neutral equilibrium value");
463  }
464  if (rans_type != RANSType::kEqn) {
465  // One value for the whole hierarchy (a single entry, or a list whose entries are all
466  // equal) is meant for the levels that run the k-eqn closure and is reset here; a list
467  // with different entries names this level on purpose and must not switch the cap on
468  // where there is no closure.
469  amrex::Vector<amrex::Real> all_levels;
470  pp.getarr("rans_realizability", all_levels);
471  bool uniform = true;
472  for (auto v : all_levels) { uniform = uniform && (v == all_levels[0]); }
473  if (uniform) {
474  amrex::Print() << "erf.rans_realizability reset to 0 on level " << lev
475  << " (no k-eqn closure there)" << std::endl;
477  } else {
478  amrex::Error("erf.rans_realizability needs erf.rans_type = kEqn (it caps the k-eqn eddy viscosity; level "
479  + std::to_string(lev) + ")");
480  }
481  }
482  }
483  // After the reset above, so a hierarchy with a PBL scheme on an LES level and the cap on
484  // its k-eqn level is accepted
485  if ((rans_realizability != zero) && (pbl_type != PBLType::None)) {
486  amrex::Error("erf.rans_realizability needs erf.pbl_type = None: a PBL scheme overwrites the vertical "
487  "diffusivities the cap acts on (level " + std::to_string(lev) + ")");
488  }
489  if (rans_lscale_from_pblh && !(rans_lscale_min > 0)) {
490  amrex::Error("erf.rans_lscale_min must be > 0 with erf.rans_lscale_from_pblh");
491  }
492 
493  if (rans_type == RANSType::kEqn) {
494  // The stability functions (AL01 Eqs. 31, 32) have poles at Rt = -3.59869
495  // (cmu) and -3.61011 (cmu'); the Burchard & Petersen smoothing maps
496  // Rt < Rt_crit onto (Rt_min, Rt_crit) and needs Rt_min < Rt_crit <= 0,
497  // with Rt_min above the pole of cmu (AL01::Rt_min_lower_bound) and above
498  // the zero of its numerator (AL01::cmu_numerator_root), so cmu > 0.
499  if (!(Cmu0 > 0)) { amrex::Error("erf.Cmu0 must be > 0 for the k-eqn RANS"); }
500  if (!(Cb > 0)) { amrex::Error("erf.Cb must be > 0 for the k-eqn RANS"); }
501  if (!(l_g_max > 0)) { amrex::Error("erf.max_geom_lscale must be > 0 for the k-eqn RANS"); }
502  if (!(Rt_crit <= 0)) { amrex::Error("erf.Rt_crit must be <= 0 for the k-eqn RANS"); }
503  if (!(Rt_min < Rt_crit)) { amrex::Error("erf.Rt_min must be < erf.Rt_crit for the k-eqn RANS"); }
504  if (!(Rt_min > AL01::Rt_min_lower_bound)) {
505  std::ostringstream msg;
506  msg << std::setprecision(8) << "erf.Rt_min must be > " << AL01::Rt_min_lower_bound
507  << " for the k-eqn RANS: the momentum stability function cmu has a pole at Rt = -3.5986889850,"
508  << " and just below it cmu and the eddy viscosity are negative (level " << lev << ")";
509  amrex::Error(msg.str());
510  }
512  std::ostringstream msg;
513  msg << std::setprecision(8) << "erf.Rt_min must be > -erf.Cmu0/0.108 = " << AL01::cmu_numerator_root(Cmu0)
514  << " for the k-eqn RANS: below it the numerator Cmu0 + 0.108 Rt of cmu is negative;"
515  << " raise erf.Cmu0 or erf.Rt_min (level " << lev << ")";
516  amrex::Error(msg.str());
517  }
518  }
519  if (tke_floor < 0) { amrex::Error("erf.tke_floor must be >= 0"); }
520 
521  // Common inputs (LES or RANS)
522  if (!query_one_or_per_level(pp, "sigma_k", sigma_k, lev, max_level) && rans_type == RANSType::kEqn) {
523  amrex::Print() << "Overriding default sigma_k for k-eqn RANS" << std::endl;
524  sigma_k = one;
525  };
526  query_one_or_per_level(pp, "theta_ref", theta_ref, lev, max_level);
527 
528  query_one_or_per_level(pp, "mix_isotropic", mix_isotropic, lev, max_level);
529  query_one_or_per_level(pp, "use_Ri_correction", use_Ri_correction, lev, max_level);
530  query_one_or_per_level(pp, "Ri_crit", Ri_crit, lev, max_level);
531 
532  // Set common flags
533  use_kturb =
535  (pbl_type != PBLType::None));
536  use_keqn =
537  ((les_type == LESType::Deardorff) || (rans_type == RANSType::kEqn));
538  use_tke =
539  ((les_type == LESType::Deardorff) || (rans_type == RANSType::kEqn) ||
540  (pbl_type == PBLType::MYJ) || (pbl_type == PBLType::MYNN25) ||
541  (pbl_type == PBLType::MYNNEDMF) || uses_shoc_family());
542 
543  if (use_tke) {
544  query_one_or_per_level(pp, "init_tke_from_ustar", init_tke_from_ustar, lev, max_level);
545  }
546 
547  // Validate inputs
548  if (les_type == LESType::Smagorinsky) {
549  if (Cs == 0) {
550  amrex::Error("Need to specify Cs for Smagorsinky LES");
551  }
552  if (smag2d && mix_isotropic) {
553  amrex::Print() << "Turning off mix_isotropic for 2-D Smagorinsky" << std::endl;
554  mix_isotropic = false;
555  }
556  }
557 
558  // Opt-in limits of WRF's Smagorinsky-2D closure (dyn_em/module_diffusion_em.F, smag2d_km):
559  // the slope limiter, which divides K_h by alpha or alpha^2 on terrain-fitted meshes, and the
560  // cap K_h <= smag2d_kh_cap * Delta_h (WRF: 10 m/s). Both are off by default. The mesh check
561  // for the slope limiter is in SolverChoice::init_params, where the terrain type is known.
562  query_one_or_per_level(pp, "smag2d_slope_limiter", smag2d_slope_limiter, lev, max_level);
563  query_one_or_per_level(pp, "smag2d_kh_cap", smag2d_kh_cap, lev, max_level);
564  if (!(smag2d_kh_cap >= zero)) {
565  amrex::Error("erf.smag2d_kh_cap must be >= 0 (0 = no cap; WRF uses 10 m/s)");
566  }
568  if (!smag2d) {
569  // A single value applies to every level; it is meant for the levels that run
570  // Smagorinsky2D (SolverChoice aborts if none does). A per-level list must not
571  // switch the limits on at a level that does not.
572  if (pp.countval("smag2d_slope_limiter") == 1) { smag2d_slope_limiter = false; }
573  if (pp.countval("smag2d_kh_cap") == 1) { smag2d_kh_cap = zero; }
575  amrex::Error("erf.smag2d_slope_limiter and erf.smag2d_kh_cap apply only to "
576  "erf.les_type = Smagorinsky2D (level " + std::to_string(lev) + ")");
577  }
578  }
579  }
580 
581  /**
582  * @brief Validate turbulence options against physical boundary conditions.
583  * @param phys_bc_type Physical boundary-condition types.
584  */
585  void check_params (amrex::GpuArray<ERF_BC, AMREX_SPACEDIM*2>& phys_bc_type)
586  {
587  // BC compatibility
589  phys_bc_type[amrex::Orientation(amrex::Direction::z,amrex::Orientation::low)] != ERF_BC::surface_layer ) {
590  amrex::Abort("The selected PBL model requires MOST at lower boundary");
591  }
592  if ( (les_type == LESType::Deardorff) && (Ce_wall > 0) &&
593  (phys_bc_type[amrex::Orientation(amrex::Direction::z,amrex::Orientation::low)] != ERF_BC::surface_layer) &&
594  (phys_bc_type[amrex::Orientation(amrex::Direction::z,amrex::Orientation::low)] != ERF_BC::slip_wall) &&
595  (phys_bc_type[amrex::Orientation(amrex::Direction::z,amrex::Orientation::low)] != ERF_BC::no_slip_wall) )
596  {
597  amrex::Warning("Deardorff LES assumes wall at zlo when applying Ce_wall");
598  }
599  }
600 
601  /**
602  * @brief Print turbulence settings for one AMR level.
603  * @param lev AMR level index.
604  */
605  void display (int lev)
606  {
607  amrex::Print() << "Turbulence Settings at level " << lev << std::endl;
608 
609  if (
611  pbl_type == PBLType::None) {
612  amrex::Print() << " Using DNS model at level " << lev << std::endl;
613  } else if (les_type == LESType::Smagorinsky) {
614  if (smag2d) {
615  amrex::Print() << " Using 2D Smagorinsky LES model at level " << lev << std::endl;
616  } else {
617  amrex::Print() << " Using Smagorinsky LES model at level " << lev << std::endl;
618  }
619  if (use_Ri_correction) {
620  amrex::Print() << " Smagorinsky uses Richardson number correction with Ri_crit = "
621  << Ri_crit << std::endl;
622  }
623  if (smag2d) {
624  amrex::Print() << " WRF slope limiter : " << smag2d_slope_limiter << std::endl;
625  if (smag2d_kh_cap > zero) {
626  amrex::Print() << " K_h cap : " << smag2d_kh_cap << " * Delta_h" << std::endl;
627  } else {
628  amrex::Print() << " K_h cap : none" << std::endl;
629  }
630  }
631  } else if (les_type == LESType::Deardorff) {
632  amrex::Print() << " Using Deardorff LES model at level " << lev << std::endl;
633  } else if (rans_type == RANSType::kEqn) {
634  amrex::Print()
635  << " Using Axell & Liungman one-equation RANS k model at level " << lev
636  << std::endl;
637  } else if (pbl_type == PBLType::MYJ) {
638  amrex::Print() << " Using MYJ PBL model at level " << lev << std::endl;
639  } else if (pbl_type == PBLType::MYNN25) {
640  amrex::Print() << " Using MYNN2.5 PBL model at level " << lev << std::endl;
641  } else if (pbl_type == PBLType::MYNNEDMF) {
642  amrex::Print() << " Using MYNNEDMF PBL model at level " << lev << std::endl;
643  } else if (pbl_type == PBLType::YSU) {
644  amrex::Print() << " Using YSU PBL model at level " << lev << std::endl;
645  } else if (pbl_type == PBLType::YSUNew) {
646  amrex::Print() << " Using YSU PBL model at level " << lev << std::endl;
647  } else if (pbl_type == PBLType::MRF) {
648  amrex::Print() << " Using MRF PBL model at level " << lev << std::endl;
649  } else if (pbl_type == PBLType::EAMXX_SHOC) {
650  amrex::Print() << " Using EAMxx SHOC PBL model at level " << lev << std::endl;
651  } else if (pbl_type == PBLType::NATIVE_SHOC) {
652  amrex::Print() << " Using native SHOC PBL model at level " << lev << std::endl;
653  } else {
654  amrex::Error("Unknown turbulence model");
655  }
656 
657  if (les_type != LESType::None) {
658  if (les_type == LESType::Smagorinsky) {
659  amrex::Print() << " Cs : " << Cs << std::endl;
660  }
661  if (les_type == LESType::Deardorff) {
662  amrex::Print() << " Ce : " << Ce << std::endl;
663  amrex::Print() << " Ce at wall : " << Ce_wall << std::endl;
664  amrex::Print() << " Ck : " << Ck << std::endl;
665  amrex::Print() << " sigma_k : " << sigma_k << std::endl;
666 
667  // Sullivan et al 1994, Eqn 14
668  amrex::Real Cs_equiv = std::sqrt(Ck * std::sqrt(Ck / Ce));
669  amrex::Print() << " equivalent Cs : " << Cs_equiv
670  << std::endl;
671  }
672  amrex::Print() << " isotropic mixing : " << mix_isotropic
673  << std::endl;
674  }
675 
676  if (rans_type != RANSType::None) {
677  if (rans_type == RANSType::kEqn) {
678  amrex::Print() << "Cmu0 : " << Cmu0 << std::endl;
679  amrex::Print() << "sigma_k : " << sigma_k << std::endl;
680  amrex::Print() << "Cb : " << Cb << std::endl;
681  amrex::Print() << "Rt_crit : " << Rt_crit << std::endl;
682  amrex::Print() << "Rt_min : " << Rt_min << std::endl;
683  amrex::Print() << "max_geom_lscale : " << l_g_max << std::endl;
684  amrex::Print() << "rans_realizability : " << rans_realizability << std::endl;
685  amrex::Print() << "dirichlet_k : " << dirichlet_k << std::endl;
686  amrex::Print() << "tke_floor : " << tke_floor << std::endl;
687  amrex::Print() << "implicit_tke_dissipation : " << implicit_tke_dissipation << std::endl;
688  amrex::Print() << "consistent diffusivities : " << rans_consistent_diffusivities << std::endl;
689  amrex::Print() << "lscale cap from PBL height : " << rans_lscale_from_pblh
690  << " (floor " << rans_lscale_min << " m)" << std::endl;
691  }
692  }
693 
694  if ((les_type == LESType::Deardorff) ||
695  (rans_type == RANSType::kEqn)) {
696  if (theta_ref > 0) {
697  amrex::Print() << " reference theta : " << theta_ref << std::endl;
698  } else {
699  amrex::Print() << " reference theta : n/a" << std::endl;
700  }
701  }
702 
703  if ((les_type != LESType::None) || (rans_type != RANSType::None)) {
704  amrex::Print() << " Pr_t : " << Pr_t << std::endl;
705  amrex::Print() << " Sc_t : " << Sc_t << std::endl;
706  }
707 
708  if (pbl_type == PBLType::MYNN25 || pbl_type == PBLType::MYNNEDMF) {
709  amrex::Print() << " pbl_mynn_Lt_taper_exp : "
710  << pbl_mynn.Lt_taper_exp << std::endl;
711  amrex::Print() << " pbl_mynn_config : "
712  << amrex::getEnumNameString(pbl_mynn.config) << std::endl;
713  amrex::Print() << " pbl_mynn_Lt_alpha : " << pbl_mynn.Lt_alpha << std::endl;
714  amrex::Print() << " pbl_mynn_A1 : " << pbl_mynn.A1 << std::endl;
715  amrex::Print() << " pbl_mynn_A2 : " << pbl_mynn.A2 << std::endl;
716  amrex::Print() << " pbl_mynn_B1 : " << pbl_mynn.B1 << std::endl;
717  amrex::Print() << " pbl_mynn_B2 : " << pbl_mynn.B2 << std::endl;
718  amrex::Print() << " pbl_mynn_C1 : " << pbl_mynn.C1 << std::endl;
719  amrex::Print() << " pbl_mynn_C2 : " << pbl_mynn.C2 << std::endl;
720  amrex::Print() << " pbl_mynn_C3 : " << pbl_mynn.C3 << std::endl;
721  amrex::Print() << " pbl_mynn_C4 : " << pbl_mynn.C4 << std::endl;
722  amrex::Print() << " pbl_mynn_C5 : " << pbl_mynn.C5 << std::endl;
723  } else if (pbl_type == PBLType::YSU || pbl_type == PBLType::YSUNew) {
724  amrex::Print() << " pbl_ysu_coriolis_freq : "
725  << pbl_ysu_coriolis_freq << std::endl;
726  amrex::Print() << " pbl_ysu_use_consistent_coriolis : "
727  << pbl_ysu_use_consistent_coriolis << std::endl;
728  amrex::Print() << " pbl_ysu_force_over_water : "
729  << pbl_ysu_force_over_water << std::endl;
730  amrex::Print() << " pbl_ysu_land_Ribcr : "
731  << pbl_ysu_land_Ribcr << std::endl;
732  amrex::Print() << " pbl_ysu_unst_Ribcr : "
733  << pbl_ysu_unst_Ribcr << std::endl;
734  amrex::Print() << " enable_ysu_countergradient : "
735  << enable_ysu_countergradient << std::endl;
736  amrex::Print() << " enable_ysu_terrain_pblh_floor : "
737  << enable_ysu_terrain_pblh_floor << std::endl;
738  amrex::Print() << " enable_ysu_sat_limiter : "
739  << enable_ysu_sat_limiter << std::endl;
740  amrex::Print() << " enable_ysu_topdown : "
741  << enable_ysu_topdown << std::endl;
742  amrex::Print() << " enable_ysu_entrainment : "
743  << enable_ysu_entrainment << std::endl;
744  amrex::Print() << " enable_ysu_cloud_pblh : "
745  << enable_ysu_cloud_pblh << std::endl;
746  amrex::Print() << " ysu_qcloud_threshold : "
747  << ysu_qcloud_threshold << std::endl;
748  amrex::Print() << " ysu_moistvars : "
749  << ysu_moistvars << std::endl;
750  amrex::Print() << " pbl_ysunew_highres_bounds : "
751  << pbl_ysunew_highres_bounds << std::endl;
752  // Radiative tendency limiter/smoothing (YSUNew-only)
753  amrex::Print() << " enable_ysu_rad_tend_limiter : "
754  << enable_ysu_rad_tend_limiter << std::endl;
755  amrex::Print() << " ysu_rad_tend_limiter_magnitude : "
756  << ysu_rad_tend_limiter_magnitude << std::endl;
757  amrex::Print() << " enable_vh96_shear_correction : "
758  << enable_vh96_shear_correction << std::endl;
759  amrex::Print() << " vh96_shear_const_b : "
760  << vh96_shear_const_b << std::endl;
761  amrex::Print() << " enable_pblh_smoothing : "
762  << enable_pblh_smoothing << std::endl;
763  amrex::Print() << " pblh_smoothing_passes : "
764  << pblh_smoothing_passes << std::endl;
765  amrex::Print() << " pblh_smoothing_weight : "
766  << pblh_smoothing_weight << std::endl;
767  amrex::Print() << " enable_mrf_unbounded_vpert : "
768  << enable_mrf_unbounded_vpert << std::endl;
769  amrex::Print() << " enable_qnse_stable_functions : "
770  << enable_qnse_stable_functions << std::endl;
772  amrex::Print() << " qnse_am (momentum coeff) : " << qnse_am << std::endl;
773  amrex::Print() << " qnse_bm (momentum coeff) : " << qnse_bm << std::endl;
774  amrex::Print() << " qnse_ah (heat coeff) : " << qnse_ah << std::endl;
775  amrex::Print() << " qnse_bh (heat coeff) : " << qnse_bh << std::endl;
776  }
777  } else if (pbl_type == PBLType::MRF) {
778  amrex::Print() << " pbl_mrf_coriolis_freq : " << pbl_mrf_coriolis_freq
779  << std::endl;
780  amrex::Print() << " pbl_mrf_Ribcr : " << pbl_mrf_Ribcr
781  << std::endl;
782  amrex::Print() << " pbl_mrf_const_b : " << pbl_mrf_const_b
783  << std::endl;
784  amrex::Print() << " pbl_mrf_sf : " << pbl_mrf_sf
785  << std::endl;
786  amrex::Print() << " enable_mrf_countergradient : " << enable_mrf_countergradient
787  << std::endl;
788  amrex::Print() << " enable_mrf_cloud_adjustment : " << enable_mrf_cloud_adjustment
789  << std::endl;
790  amrex::Print() << " pbl_mrf_highres_bounds : " << pbl_mrf_highres_bounds
791  << std::endl;
792  amrex::Print() << " enable_mrf_unbounded_vpert : " << enable_mrf_unbounded_vpert
793  << std::endl;
794  amrex::Print() << " pbl_mrf_use_zero_ri_extent : " << pbl_mrf_use_zero_ri_extent
795  << std::endl;
796  amrex::Print() << " pbl_blend_length : " << pbl_blend_length
797  << std::endl;
798  amrex::Print() << " pbl_blend_cs : " << pbl_blend_cs
799  << std::endl;
800  amrex::Print() << " pbl_blend_c_max : " << pbl_blend_c_max
801  << std::endl;
802  amrex::Print() << " pbl_blend_use_smag : " << pbl_blend_use_smag
803  << std::endl;
804  amrex::Print() << " enable_vh96_shear_correction : " << enable_vh96_shear_correction
805  << std::endl;
806  amrex::Print() << " vh96_shear_const_b : " << vh96_shear_const_b
807  << std::endl;
808  amrex::Print() << " enable_pblh_smoothing : " << enable_pblh_smoothing
809  << std::endl;
810  amrex::Print() << " pblh_smoothing_passes : " << pblh_smoothing_passes
811  << std::endl;
812  amrex::Print() << " pblh_smoothing_weight : " << pblh_smoothing_weight
813  << std::endl;
814  amrex::Print() << " enable_qnse_stable_functions : "
815  << enable_qnse_stable_functions << std::endl;
817  amrex::Print() << " qnse_am (momentum coeff) : " << qnse_am << std::endl;
818  amrex::Print() << " qnse_bm (momentum coeff) : " << qnse_bm << std::endl;
819  amrex::Print() << " qnse_ah (heat coeff) : " << qnse_ah << std::endl;
820  amrex::Print() << " qnse_bh (heat coeff) : " << qnse_bh << std::endl;
821  }
822  }
823  }
824 
825  // LES model
827 
828  // Turbulent Prandtl number
831 
832  // Turbulent Schmidt number
835 
836  // Smagorinsky
838  bool smag2d = false;
839  // WRF smag2d_km limits (opt-in): slope limiter K_h /= alpha or alpha^2 on terrain-fitted
840  // meshes, and the cap K_h <= smag2d_kh_cap * Delta_h (m/s; 0 = no cap)
841  bool smag2d_slope_limiter = false;
843  // whether either limit was given as on for this level, before a single value is
844  // dropped at a level without Smagorinsky2D
846 
847  // Deardorff
849  amrex::Real Ce_wall = zero; // if > 0, then set Ce to this at k=0
851 
852  // k-eqn RANS coefficients (Axell & Liungman 2001)
857  amrex::Real l_g_max = amrex::Real(30.0); // ~ kappa * (amrex::Real(0.1) * zi)
858 
859  // Deardorff or k-eqn RANS
860  // - diffusivity of tke is 1/sigma_k times the eddy viscosity
862  // - reference potential temperature used to quantify the stratification in
863  // a stable region
865  // - how to quantify stratification effects
867  // Stratification variable used by the PBL schemes; see init_params.
868  StratType pbl_strat_type = StratType::thetav;
869 
870  // Anisotropic length scales
871  bool mix_isotropic = true;
872 
873  bool use_Ri_correction = true;
875 
876  // RANS type
878 
879  bool dirichlet_k = false;
880 
881  // Runtime floor on the turbulent kinetic energy [m2/s2] in the k-equation
882  // update and the RANS closure; 0 means machine epsilon on rho*k (the
883  // historical floor). Distinct from tke_min, the initial TKE value.
885 
886  // Treat the TKE dissipation implicitly: eps = (Cmu0^3 sqrt(k_old)/L) * k_new
887  // folded into the update (Deardorff and k-eqn RANS)
889 
890  // k-eqn RANS: horizontal heat, scalar and moisture diffusivities follow the
891  // AL01 scalar stability function (cmu') like the vertical heat diffusivity,
892  // instead of Pr_t and Sc_t times the eddy viscosity
894 
895  // k-eqn RANS: cap the geometric length at kappa * 0.1 * PBL height (from
896  // erf.most.pblh_calc), clamped to [rans_lscale_min, max_geom_lscale],
897  // instead of the fixed max_geom_lscale
898  bool rans_lscale_from_pblh = false;
900 
901  // k-eqn RANS: realizability cap nu_t <= C_r k / S on the eddy viscosity
902  // (and every eddy diffusivity through the same ratio), 0 = off. C_r = Cmu0^2
903  // leaves a neutral equilibrium surface layer untouched and limits the
904  // viscosity in the shear layer that leaves a crest (AL01 Eqs. 11 and 19;
905  // the SST limiter form).
907 
908  // PBL model
910 
911  /**
912  * @brief Query whether this level uses the EAMxx SHOC PBL scheme.
913  * @return True if PBLType::EAMXX_SHOC is selected.
914  */
915  bool uses_eamxx_shoc () const noexcept
916  {
917  return pbl_type == PBLType::EAMXX_SHOC;
918  }
919 
920  /**
921  * @brief Query whether this level uses the native SHOC PBL scheme.
922  * @return True if PBLType::NATIVE_SHOC is selected.
923  */
924  bool uses_native_shoc () const noexcept
925  {
926  return pbl_type == PBLType::NATIVE_SHOC;
927  }
928 
929  /**
930  * @brief Query whether this level uses any SHOC-family PBL scheme.
931  * @return True if native or EAMxx SHOC is selected.
932  */
933  bool uses_shoc_family () const noexcept
934  {
935  return uses_eamxx_shoc() || uses_native_shoc();
936  }
937 
938  /**
939  * @brief Query whether the horizontal and vertical eddy viscosities can differ on this level.
940  * @return True for Smagorinsky-2D, anisotropic Smagorinsky or Deardorff, and any PBL scheme
941  * (which sets the vertical diffusivities on its own).
942  */
943  bool kh_kv_can_differ () const noexcept
944  {
945  return ( (les_type == LESType::Smagorinsky && (smag2d || !mix_isotropic)) ||
946  (les_type == LESType::Deardorff && !mix_isotropic) ||
947  (pbl_type != PBLType::None) );
948  }
949 
950  /**
951  * @brief Query whether the selected PBL scheme requires surface-layer boundary conditions.
952  * @return True if the PBL scheme requires a lower surface-layer boundary.
953  */
954  bool pbl_requires_surface_layer () const noexcept
955  {
956  return (pbl_type == PBLType::MYNN25) ||
957  (pbl_type == PBLType::MYNNEDMF) ||
958  (pbl_type == PBLType::YSU) ||
959  (pbl_type == PBLType::YSUNew) ||
960  (pbl_type == PBLType::MRF) ||
962  }
963 
964  /**
965  * @brief Query whether the selected PBL scheme suppresses microphysics condensation.
966  * @return True when the PBL scheme owns condensation handling.
967  */
969  {
970  return uses_shoc_family();
971  }
972 
974  MYNNLevel2 pbl_mynn_level2; // limiting in the decaying turbulence regime
975 
976  // Common Flags
977  bool use_kturb = false; // Any turbulence modeling?
978  bool use_keqn =
979  false; // Any microscale turbulence modeling (LES, RANS) with TKE closure?
980  // Then need to populate SmnSmn_lev for production term.
981  bool use_pbl_tke =
982  false; // Any mesoscale turbulence modeling (PBL) with TKE closure?
983  bool use_tke = false; // Any TKE closure (meso or microscale)?
984 
985  // Initialize TKE/QKE with linear profiles whose surface values are a
986  // function of the friction velocity calculated by the surface layer scheme
987  // (e.g., as done in MYNN-EDMF)
988  bool init_tke_from_ustar = false;
989 
990  // This is the value of tke_min in WRF 4.5
992 
993  // Model coefficients - YSU
994  // TODO: Add parmparse for all of these above
996  amrex::Real(1.0e-4); // 1e-4 is hardcoded in WRF, we let the user specify or take the
997  // value from ERF coriolis forcing
999  false; // ignore input pbl_ysu_coriolis_freq, take value from ERF coriolis
1000  // forcing instead
1002  false; // Force YSU to act as if it is over water regardless of other inputs
1003  // (for testing)
1005  fourth; // Critical Bulk Richardson number of Land for stable conditions
1007  zero; // Critical Bulk Richardson number for unstable conditions
1009  true; // if true, apply YSU-style HGAMT/HGAMQ/HGAMU/HGAMV countergradient correction
1011  true; // if true, apply terrain-following floor on PBL height
1013  false; // if true, apply saturation limiter to moisture countergradient
1015  true; // if true, enable top-down mixing for cloud-topped boundary layers
1017  true; // if true, enable entrainment layer parameterization
1019  true; // if true, enable cloud-based PBL height detection
1021  amrex::Real(1.0e-4); // Cloud liquid water threshold for YSUNew (kg/kg)
1022  bool ysu_moistvars = false; // if true, adds turbulence to moisture
1023  bool pbl_ysunew_highres_bounds = false; // if true, apply high-resolution grid-dependent diffusivity bounds
1024  // Radiative tendency limiter (YSUNew-only)
1025  bool enable_ysu_rad_tend_limiter = false; // if true, guard and bound the qheating_rates top-down forcing
1026  amrex::Real ysu_rad_tend_limiter_magnitude = amrex::Real(1.0); // Bound on the limited radiative tendency (K/s)
1027  // Vogelezang & Holtslag (1996) shear correction and PBLH smoothing for YSU/YSUNew
1028  bool enable_vh96_shear_correction = false; // if true, use VH96 shear correction term instead of ad-hoc floor
1029  amrex::Real vh96_shear_const_b = amrex::Real(100.0); // VH96 shear correction constant b
1030  bool enable_pblh_smoothing = false; // if true, apply spatial smoothing to diagnosed PBLH
1031  int pblh_smoothing_passes = 1; // number of smoothing iterations
1032  amrex::Real pblh_smoothing_weight = amrex::Real(0.5); // center-cell weight in smoothing stencil
1033  // Model coefficients - MRF
1035  amrex::Real pbl_mrf_Ribcr = amrex::Real(0.5); // Critical Bulk Richardson number for MRF PBL model
1036  amrex::Real pbl_mrf_const_b = amrex::Real(7.8); // Constant b in MRF PBL model, used to compute the PBL height
1037  amrex::Real pbl_mrf_sf = amrex::Real(0.1); // MRF surface flux, used to compute the PBL height
1038  // Scale-aware PBL-LES blending parameters.
1039  // Boutle et al. (2014): https://doi.org/10.1175/MWR-D-13-00229.1
1040  // Set pbl_blend_length = 0 to disable (default). Recovers original behaviour.
1041  amrex::Real pbl_blend_length = amrex::Real(0.0); ///< Boutle blending length L [m]. 0 = off.
1042  amrex::Real pbl_blend_cs = amrex::Real(0.17); ///< Smagorinsky coeff for K_h ceiling.
1043  amrex::Real pbl_blend_c_max = amrex::Real(0.1); ///< Power-law ceiling coeff [m^(2/3)/s].
1044  bool pbl_blend_use_smag = true; ///< Use Smagorinsky ceiling (else power-law).
1045  bool enable_mrf_countergradient = false; // if true, apply WRF-style HGAMT/HGAMQ correction to PBL height
1046  bool pbl_ib_aware = false; // MRF / YSUNew: measure heights from the top of immersed solid columns
1047  amrex::Real pbl_ib_z0 = amrex::Real(0.01); // roughness [m] of the neutral log law at the top of an immersed column
1048  bool enable_mrf_cloud_adjustment = false; // if true, apply cloud-aware stability function adjustments in MRF scheme
1049  bool pbl_mrf_highres_bounds = false; // if true, apply high-resolution grid-dependent diffusivity bounds instead of global forecast bounds
1050  bool enable_mrf_unbounded_vpert = false; // if true, does not limit VPERT to GAMCRT
1051  bool pbl_mrf_use_zero_ri_extent = false; // if true, use Ri=0 (pbli_zero_arr) for K-profile extent; default false uses Ri=0.5 corrector (pbli_arr) for WRF compatibility
1052  // QNSE (Quasi-Normal Scale Elimination) spectral stable stability functions
1053  // Sukoriansky, S., B. Galperin, and V. Perov, 2005: Application of a New Spectral
1054  // Theory of Stably Stratified Turbulence to the Atmospheric Boundary Layer over
1055  // Sea Ice. Boundary-Layer Meteorology, 117, 231–257.
1056  // https://doi.org/10.1007/s10546-004-6848-4
1057  bool enable_qnse_stable_functions = false; // if true, use QNSE spectral stability functions
1058  // instead of linear Businger-Dyer form for stable conditions
1059  amrex::Real qnse_am = amrex::Real(2.5); // QNSE momentum stability function coefficient (dimensionless)
1060  amrex::Real qnse_bm = amrex::Real(0.2); // QNSE momentum stability function coefficient (dimensionless)
1061  amrex::Real qnse_ah = amrex::Real(2.5); // QNSE heat stability function coefficient (dimensionless)
1062  amrex::Real qnse_bh = amrex::Real(0.2); // QNSE heat stability function coefficient (dimensionless)
1063  // MYNN2.5 PBL model
1064  // TKE/QKE stuff
1065  bool advect_tke = true; // if MYNN2.5 PBL is used default is turb transport in
1066  // Z-direction only
1067  bool diffuse_tke_3D = true; // if numerical diffusion is turned on
1068 };
1069 
1070 /**
1071  * @var TurbChoice::les_type
1072  * @brief Selected LES closure.
1073  * @var TurbChoice::Pr_t
1074  * @brief Turbulent Prandtl number.
1075  * @var TurbChoice::Pr_t_inv
1076  * @brief Inverse turbulent Prandtl number.
1077  * @var TurbChoice::Sc_t
1078  * @brief Turbulent Schmidt number.
1079  * @var TurbChoice::Sc_t_inv
1080  * @brief Inverse turbulent Schmidt number.
1081  * @var TurbChoice::Cs
1082  * @brief Smagorinsky model coefficient.
1083  * @var TurbChoice::smag2d
1084  * @brief Whether the 2-D Smagorinsky formulation is used.
1085  * @var TurbChoice::smag2d_slope_limiter
1086  * @brief Apply WRF's Smagorinsky-2D slope limiter (K_h / alpha or / alpha^2) on terrain-fitted meshes.
1087  * @var TurbChoice::smag2d_kh_cap
1088  * @brief Cap K_h <= smag2d_kh_cap * Delta_h for Smagorinsky-2D (m/s); 0 means no cap.
1089  * @var TurbChoice::smag2d_limits_requested
1090  * @brief Whether either Smagorinsky-2D limit was given as on for this level.
1091  * @var TurbChoice::Ce
1092  * @brief Deardorff dissipation coefficient.
1093  * @var TurbChoice::Ce_wall
1094  * @brief Wall value for the Deardorff dissipation coefficient.
1095  * @var TurbChoice::Ck
1096  * @brief Deardorff eddy-viscosity coefficient.
1097  * @var TurbChoice::Cmu0
1098  * @brief One-equation RANS Cmu0 coefficient.
1099  * @var TurbChoice::Cb
1100  * @brief One-equation RANS buoyancy coefficient.
1101  * @var TurbChoice::Rt_crit
1102  * @brief Critical turbulent Reynolds number.
1103  * @var TurbChoice::Rt_min
1104  * @brief Minimum turbulent Reynolds number.
1105  * @var TurbChoice::l_g_max
1106  * @brief Maximum geometric length scale.
1107  * @var TurbChoice::sigma_k
1108  * @brief TKE diffusivity coefficient denominator.
1109  * @var TurbChoice::theta_ref
1110  * @brief Reference potential temperature for stable stratification.
1111  * @var TurbChoice::strat_type
1112  * @brief Thermodynamic variable used for stability stratification.
1113  * @var TurbChoice::mix_isotropic
1114  * @brief Whether subgrid mixing uses isotropic length scales.
1115  * @var TurbChoice::use_Ri_correction
1116  * @brief Whether Richardson-number correction is applied.
1117  * @var TurbChoice::Ri_crit
1118  * @brief Critical Richardson number for stability correction.
1119  * @var TurbChoice::rans_type
1120  * @brief Selected RANS closure.
1121  * @var TurbChoice::dirichlet_k
1122  * @brief Whether TKE uses Dirichlet boundary treatment.
1123  * @var TurbChoice::pbl_type
1124  * @brief Selected PBL closure.
1125  * @var TurbChoice::pbl_mynn
1126  * @brief MYNN level-2.5 closure coefficients.
1127  * @var TurbChoice::pbl_mynn_level2
1128  * @brief MYNN level-2 closure coefficients for limiting.
1129  * @var TurbChoice::use_kturb
1130  * @brief Whether any turbulence model is active.
1131  * @var TurbChoice::use_keqn
1132  * @brief Whether a microscale TKE closure is active.
1133  * @var TurbChoice::use_pbl_tke
1134  * @brief Whether a mesoscale PBL TKE closure is active.
1135  * @var TurbChoice::use_tke
1136  * @brief Whether any TKE or QKE closure is active.
1137  * @var TurbChoice::init_tke_from_ustar
1138  * @brief Whether initial TKE/QKE profiles are based on surface friction velocity.
1139  * @var TurbChoice::tke_min
1140  * @brief Minimum TKE/QKE value.
1141  * @var TurbChoice::pbl_ysu_coriolis_freq
1142  * @brief Coriolis frequency used by YSU-family PBL schemes.
1143  * @var TurbChoice::pbl_ysu_use_consistent_coriolis
1144  * @brief Whether YSU uses the ERF Coriolis frequency.
1145  * @var TurbChoice::pbl_ysu_force_over_water
1146  * @brief Whether YSU is forced to use over-water behavior.
1147  * @var TurbChoice::pbl_ysu_land_Ribcr
1148  * @brief Critical bulk Richardson number over land for stable YSU conditions.
1149  * @var TurbChoice::pbl_ysu_unst_Ribcr
1150  * @brief Critical bulk Richardson number for unstable YSU conditions.
1151  * @var TurbChoice::enable_ysu_countergradient
1152  * @brief Whether YSU countergradient corrections are enabled.
1153  * @var TurbChoice::enable_ysu_terrain_pblh_floor
1154  * @brief Whether YSU applies a terrain-following PBL-height floor.
1155  * @var TurbChoice::enable_ysu_sat_limiter
1156  * @brief Whether YSU applies a saturation limiter to moisture countergradient terms.
1157  * @var TurbChoice::enable_ysu_topdown
1158  * @brief Whether YSU top-down mixing is enabled.
1159  * @var TurbChoice::enable_ysu_entrainment
1160  * @brief Whether YSU entrainment-layer parameterization is enabled.
1161  * @var TurbChoice::enable_ysu_cloud_pblh
1162  * @brief Whether YSU cloud-based PBL-height detection is enabled.
1163  * @var TurbChoice::ysu_qcloud_threshold
1164  * @brief Cloud liquid water threshold for YSUNew [kg/kg].
1165  * @var TurbChoice::ysu_moistvars
1166  * @brief Whether YSU applies turbulence to moisture variables.
1167  * @var TurbChoice::pbl_ysunew_highres_bounds
1168  * @brief Whether YSUNew applies high-resolution grid-dependent diffusivity bounds.
1169  * @var TurbChoice::enable_vh96_shear_correction
1170  * @brief Whether Vogelezang & Holtslag (1996) shear-correction term is enabled.
1171  * @var TurbChoice::vh96_shear_const_b
1172  * @brief Vogelezang & Holtslag (1996) shear-correction constant b.
1173  * @var TurbChoice::enable_pblh_smoothing
1174  * @brief Whether spatial smoothing of diagnosed PBLH is enabled.
1175  * @var TurbChoice::pblh_smoothing_passes
1176  * @brief Number of PBLH smoothing iterations to apply.
1177  * @var TurbChoice::pblh_smoothing_weight
1178  * @brief Center-cell weight in PBLH smoothing stencil (must be in [0,1]).
1179  * @var TurbChoice::pbl_mrf_coriolis_freq
1180  * @brief Coriolis frequency used by the MRF PBL scheme.
1181  * @var TurbChoice::pbl_mrf_Ribcr
1182  * @brief Critical bulk Richardson number for the MRF PBL scheme.
1183  * @var TurbChoice::pbl_mrf_const_b
1184  * @brief MRF constant used to compute PBL height.
1185  * @var TurbChoice::pbl_mrf_sf
1186  * @brief MRF surface flux value used to compute PBL height.
1187  * @var TurbChoice::enable_mrf_countergradient
1188  * @brief Whether MRF countergradient corrections are enabled.
1189  * @var TurbChoice::pbl_ib_aware
1190  * When true, the MRF and YSUNew schemes treat the first fluid cell above the
1191  * immersed solid of a column (buildings or terrain by immersed forcing) as
1192  * that column's surface: the bulk Richardson heights, the boundary-layer
1193  * depth and the K profile are measured from it, the diffusivities vanish
1194  * inside the solid, and the surface scales of such a column are a neutral
1195  * log law at its top (u* from the wind there and pbl_ib_z0, theta* = 0). The
1196  * boundary-layer height both schemes store (pblh, Lturb) stays the absolute
1197  * height above the domain bottom; with enable_pblh_smoothing the stencil runs
1198  * on that absolute height, and the smoothed value is kept at or above each
1199  * column's own floor (half a cell above its surface, at least 10 m). Off by
1200  * default; without immersed cells the results are identical. Not supported
1201  * with terrain-fitted coordinates.
1202  * @var TurbChoice::pbl_ib_z0
1203  * Roughness length [m] of that log law.
1204  * @var TurbChoice::enable_mrf_cloud_adjustment
1205  * @brief Whether MRF cloud-aware stability adjustments are enabled.
1206  * @var TurbChoice::pbl_mrf_highres_bounds
1207  * @brief Whether MRF applies high-resolution grid-dependent diffusivity bounds.
1208  * @var TurbChoice::enable_mrf_unbounded_vpert
1209  * @brief Whether MRF leaves VPERT unlimited by GAMCRT.
1210  * @var TurbChoice::pbl_mrf_use_zero_ri_extent
1211  * @brief Whether MRF uses the Ri=0 K-profile extent.
1212  * @var TurbChoice::advect_tke
1213  * @brief Whether TKE/QKE is advected.
1214  * @var TurbChoice::diffuse_tke_3D
1215  * @brief Whether three-dimensional numerical diffusion is applied to TKE/QKE.
1216  */
1217 #endif
@ no_slip_wall
@ surface_layer
ParmParse pp("prob")
constexpr amrex::Real three
Definition: ERF_NumericalConstants.H:39
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:37
constexpr amrex::Real fourth
Definition: ERF_NumericalConstants.H:42
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:36
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_ENUM(LESType, None, Smagorinsky, Smagorinsky2D, Deardorff)
Large-eddy simulation closure type.
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:85
int query_one_or_per_level(const amrex::ParmParse &pp, const char *query_string, T &query_var, const int lev, const int maxlev)
Query a scalar or per-level input value.
Definition: ERF_TurbStruct.H:43
constexpr amrex::Real Rt_min_lower_bound
Definition: ERF_RANSClosure.H:142
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real cmu_numerator_root(amrex::Real Cmu0)
Definition: ERF_RANSClosure.H:148
@ None
Definition: ERF_LSM_Types.H:6
@ theta
Definition: ERF_Kessler.H:26
@ T
Definition: ERF_IndexDefines.H:168
Coefficients and stability functions for the Level 2.5 MYNN closure.
Definition: ERF_MYNNStruct.H:18
amrex::Real SMmax
Definition: ERF_MYNNStruct.H:65
amrex::Real SHmax
Definition: ERF_MYNNStruct.H:67
amrex::Real Lt_alpha
Definition: ERF_MYNNStruct.H:77
amrex::Real SQfac
Definition: ERF_MYNNStruct.H:61
amrex::Real C4
Definition: ERF_MYNNStruct.H:57
amrex::Real C1
Definition: ERF_MYNNStruct.H:54
MYNNConfigType config
Definition: ERF_MYNNStruct.H:71
amrex::Real C3
Definition: ERF_MYNNStruct.H:56
amrex::Real C2
Definition: ERF_MYNNStruct.H:55
amrex::Real A2
Definition: ERF_MYNNStruct.H:51
amrex::Real SHmin
Definition: ERF_MYNNStruct.H:66
amrex::Real B1
Definition: ERF_MYNNStruct.H:52
amrex::Real Lt_taper_exp
Definition: ERF_MYNNStruct.H:89
amrex::Real B2
Definition: ERF_MYNNStruct.H:53
amrex::Real C5
Definition: ERF_MYNNStruct.H:58
amrex::Real SMmin
Definition: ERF_MYNNStruct.H:64
amrex::Real A1
Definition: ERF_MYNNStruct.H:50
amrex::Real SQmax
Definition: ERF_MYNNStruct.H:69
Coefficients and stability functions for the Level 2 MYNN closure.
Definition: ERF_MYNNStruct.H:95
void init_coeffs(amrex::Real A1_lvl25, amrex::Real A2_lvl25, amrex::Real B1, amrex::Real B2, amrex::Real C1, amrex::Real C2, amrex::Real C3, amrex::Real, amrex::Real C5)
Initialize Level 2 closure coefficients from Level 2.5 coefficients.
Definition: ERF_MYNNStruct.H:107
Definition: ERF_TurbStruct.H:119
bool advect_tke
Whether TKE/QKE is advected.
Definition: ERF_TurbStruct.H:1065
bool pbl_ysu_force_over_water
Whether YSU is forced to use over-water behavior.
Definition: ERF_TurbStruct.H:1001
bool implicit_tke_dissipation
Definition: ERF_TurbStruct.H:888
StratType strat_type
Thermodynamic variable used for stability stratification.
Definition: ERF_TurbStruct.H:866
bool rans_consistent_diffusivities
Definition: ERF_TurbStruct.H:893
amrex::Real Ce
Deardorff dissipation coefficient.
Definition: ERF_TurbStruct.H:848
bool enable_mrf_unbounded_vpert
Whether MRF leaves VPERT unlimited by GAMCRT.
Definition: ERF_TurbStruct.H:1050
amrex::Real Sc_t
Turbulent Schmidt number.
Definition: ERF_TurbStruct.H:833
MYNNLevel2 pbl_mynn_level2
MYNN level-2 closure coefficients for limiting.
Definition: ERF_TurbStruct.H:974
bool diffuse_tke_3D
Whether three-dimensional numerical diffusion is applied to TKE/QKE.
Definition: ERF_TurbStruct.H:1067
bool use_tke
Whether any TKE or QKE closure is active.
Definition: ERF_TurbStruct.H:983
amrex::Real sigma_k
TKE diffusivity coefficient denominator.
Definition: ERF_TurbStruct.H:861
bool use_Ri_correction
Whether Richardson-number correction is applied.
Definition: ERF_TurbStruct.H:873
bool pbl_ysu_use_consistent_coriolis
Whether YSU uses the ERF Coriolis frequency.
Definition: ERF_TurbStruct.H:998
amrex::Real pbl_blend_length
Boutle blending length L [m]. 0 = off.
Definition: ERF_TurbStruct.H:1041
amrex::Real Ck
Deardorff eddy-viscosity coefficient.
Definition: ERF_TurbStruct.H:850
bool pbl_mrf_use_zero_ri_extent
Whether MRF uses the Ri=0 K-profile extent.
Definition: ERF_TurbStruct.H:1051
amrex::Real Ce_wall
Wall value for the Deardorff dissipation coefficient.
Definition: ERF_TurbStruct.H:849
amrex::Real qnse_ah
Definition: ERF_TurbStruct.H:1061
RANSType rans_type
Selected RANS closure.
Definition: ERF_TurbStruct.H:877
StratType pbl_strat_type
Definition: ERF_TurbStruct.H:868
void check_params(amrex::GpuArray< ERF_BC, AMREX_SPACEDIM *2 > &phys_bc_type)
Validate turbulence options against physical boundary conditions.
Definition: ERF_TurbStruct.H:585
bool enable_vh96_shear_correction
Whether Vogelezang & Holtslag (1996) shear-correction term is enabled.
Definition: ERF_TurbStruct.H:1028
amrex::Real theta_ref
Reference potential temperature for stable stratification.
Definition: ERF_TurbStruct.H:864
amrex::Real Sc_t_inv
Inverse turbulent Schmidt number.
Definition: ERF_TurbStruct.H:834
amrex::Real l_g_max
Maximum geometric length scale.
Definition: ERF_TurbStruct.H:857
bool enable_mrf_cloud_adjustment
Whether MRF cloud-aware stability adjustments are enabled.
Definition: ERF_TurbStruct.H:1048
bool use_keqn
Whether a microscale TKE closure is active.
Definition: ERF_TurbStruct.H:978
bool uses_eamxx_shoc() const noexcept
Query whether this level uses the EAMxx SHOC PBL scheme.
Definition: ERF_TurbStruct.H:915
bool enable_ysu_entrainment
Whether YSU entrainment-layer parameterization is enabled.
Definition: ERF_TurbStruct.H:1016
bool enable_ysu_sat_limiter
Whether YSU applies a saturation limiter to moisture countergradient terms.
Definition: ERF_TurbStruct.H:1012
bool enable_ysu_cloud_pblh
Whether YSU cloud-based PBL-height detection is enabled.
Definition: ERF_TurbStruct.H:1018
amrex::Real pbl_mrf_const_b
MRF constant used to compute PBL height.
Definition: ERF_TurbStruct.H:1036
amrex::Real pblh_smoothing_weight
Center-cell weight in PBLH smoothing stencil (must be in [0,1]).
Definition: ERF_TurbStruct.H:1032
amrex::Real pbl_blend_cs
Smagorinsky coeff for K_h ceiling.
Definition: ERF_TurbStruct.H:1042
amrex::Real tke_floor
Definition: ERF_TurbStruct.H:884
bool uses_shoc_family() const noexcept
Query whether this level uses any SHOC-family PBL scheme.
Definition: ERF_TurbStruct.H:933
amrex::Real ysu_qcloud_threshold
Cloud liquid water threshold for YSUNew [kg/kg].
Definition: ERF_TurbStruct.H:1020
amrex::Real qnse_bm
Definition: ERF_TurbStruct.H:1060
amrex::Real pbl_blend_c_max
Power-law ceiling coeff [m^(2/3)/s].
Definition: ERF_TurbStruct.H:1043
bool init_tke_from_ustar
Whether initial TKE/QKE profiles are based on surface friction velocity.
Definition: ERF_TurbStruct.H:988
amrex::Real qnse_bh
Definition: ERF_TurbStruct.H:1062
bool enable_qnse_stable_functions
Definition: ERF_TurbStruct.H:1057
bool enable_mrf_countergradient
Whether MRF countergradient corrections are enabled.
Definition: ERF_TurbStruct.H:1045
bool enable_ysu_countergradient
Whether YSU countergradient corrections are enabled.
Definition: ERF_TurbStruct.H:1008
bool mix_isotropic
Whether subgrid mixing uses isotropic length scales.
Definition: ERF_TurbStruct.H:871
bool enable_pblh_smoothing
Whether spatial smoothing of diagnosed PBLH is enabled.
Definition: ERF_TurbStruct.H:1030
bool uses_native_shoc() const noexcept
Query whether this level uses the native SHOC PBL scheme.
Definition: ERF_TurbStruct.H:924
amrex::Real smag2d_kh_cap
Cap K_h <= smag2d_kh_cap * Delta_h for Smagorinsky-2D (m/s); 0 means no cap.
Definition: ERF_TurbStruct.H:842
bool kh_kv_can_differ() const noexcept
Query whether the horizontal and vertical eddy viscosities can differ on this level.
Definition: ERF_TurbStruct.H:943
bool dirichlet_k
Whether TKE uses Dirichlet boundary treatment.
Definition: ERF_TurbStruct.H:879
int pblh_smoothing_passes
Number of PBLH smoothing iterations to apply.
Definition: ERF_TurbStruct.H:1031
LESType les_type
Selected LES closure.
Definition: ERF_TurbStruct.H:826
amrex::Real rans_realizability
Definition: ERF_TurbStruct.H:906
void init_params(int lev, int max_level, std::string pp_prefix)
Read turbulence options for one AMR level from the input parameter database.
Definition: ERF_TurbStruct.H:127
amrex::Real pbl_ib_z0
Definition: ERF_TurbStruct.H:1047
bool enable_ysu_topdown
Whether YSU top-down mixing is enabled.
Definition: ERF_TurbStruct.H:1014
bool rans_lscale_from_pblh
Definition: ERF_TurbStruct.H:898
bool pbl_ib_aware
Definition: ERF_TurbStruct.H:1046
amrex::Real ysu_rad_tend_limiter_magnitude
Definition: ERF_TurbStruct.H:1026
amrex::Real rans_lscale_min
Definition: ERF_TurbStruct.H:899
bool pbl_mrf_highres_bounds
Whether MRF applies high-resolution grid-dependent diffusivity bounds.
Definition: ERF_TurbStruct.H:1049
amrex::Real Rt_min
Minimum turbulent Reynolds number.
Definition: ERF_TurbStruct.H:856
bool pbl_blend_use_smag
Use Smagorinsky ceiling (else power-law).
Definition: ERF_TurbStruct.H:1044
MYNNLevel25 pbl_mynn
MYNN level-2.5 closure coefficients.
Definition: ERF_TurbStruct.H:973
amrex::Real pbl_ysu_land_Ribcr
Critical bulk Richardson number over land for stable YSU conditions.
Definition: ERF_TurbStruct.H:1004
amrex::Real Cb
One-equation RANS buoyancy coefficient.
Definition: ERF_TurbStruct.H:854
amrex::Real Ri_crit
Critical Richardson number for stability correction.
Definition: ERF_TurbStruct.H:874
amrex::Real pbl_ysu_unst_Ribcr
Critical bulk Richardson number for unstable YSU conditions.
Definition: ERF_TurbStruct.H:1006
amrex::Real Rt_crit
Critical turbulent Reynolds number.
Definition: ERF_TurbStruct.H:855
amrex::Real vh96_shear_const_b
Vogelezang & Holtslag (1996) shear-correction constant b.
Definition: ERF_TurbStruct.H:1029
bool smag2d_limits_requested
Whether either Smagorinsky-2D limit was given as on for this level.
Definition: ERF_TurbStruct.H:845
bool pbl_suppresses_microphysics_condensation() const noexcept
Query whether the selected PBL scheme suppresses microphysics condensation.
Definition: ERF_TurbStruct.H:968
amrex::Real pbl_mrf_Ribcr
Critical bulk Richardson number for the MRF PBL scheme.
Definition: ERF_TurbStruct.H:1035
amrex::Real qnse_am
Definition: ERF_TurbStruct.H:1059
amrex::Real pbl_mrf_sf
MRF surface flux value used to compute PBL height.
Definition: ERF_TurbStruct.H:1037
amrex::Real Cmu0
One-equation RANS Cmu0 coefficient.
Definition: ERF_TurbStruct.H:853
amrex::Real Cs
Smagorinsky model coefficient.
Definition: ERF_TurbStruct.H:837
amrex::Real Pr_t
Turbulent Prandtl number.
Definition: ERF_TurbStruct.H:829
bool smag2d_slope_limiter
Apply WRF's Smagorinsky-2D slope limiter (K_h / alpha or / alpha^2) on terrain-fitted meshes.
Definition: ERF_TurbStruct.H:841
amrex::Real pbl_mrf_coriolis_freq
Coriolis frequency used by the MRF PBL scheme.
Definition: ERF_TurbStruct.H:1034
bool pbl_ysunew_highres_bounds
Whether YSUNew applies high-resolution grid-dependent diffusivity bounds.
Definition: ERF_TurbStruct.H:1023
amrex::Real tke_min
Minimum TKE/QKE value.
Definition: ERF_TurbStruct.H:991
amrex::Real pbl_ysu_coriolis_freq
Coriolis frequency used by YSU-family PBL schemes.
Definition: ERF_TurbStruct.H:995
void display(int lev)
Print turbulence settings for one AMR level.
Definition: ERF_TurbStruct.H:605
bool use_kturb
Whether any turbulence model is active.
Definition: ERF_TurbStruct.H:977
bool ysu_moistvars
Whether YSU applies turbulence to moisture variables.
Definition: ERF_TurbStruct.H:1022
PBLType pbl_type
Selected PBL closure.
Definition: ERF_TurbStruct.H:909
amrex::Real Pr_t_inv
Inverse turbulent Prandtl number.
Definition: ERF_TurbStruct.H:830
bool enable_ysu_terrain_pblh_floor
Whether YSU applies a terrain-following PBL-height floor.
Definition: ERF_TurbStruct.H:1010
bool smag2d
Whether the 2-D Smagorinsky formulation is used.
Definition: ERF_TurbStruct.H:838
bool enable_ysu_rad_tend_limiter
Definition: ERF_TurbStruct.H:1025
bool pbl_requires_surface_layer() const noexcept
Query whether the selected PBL scheme requires surface-layer boundary conditions.
Definition: ERF_TurbStruct.H:954
bool use_pbl_tke
Whether a mesoscale PBL TKE closure is active.
Definition: ERF_TurbStruct.H:981