ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_CanopyTurbStruct.H
Go to the documentation of this file.
1 #ifndef ERF_CANOPY_TURB_STRUCT_H_
2 #define ERF_CANOPY_TURB_STRUCT_H_
3 
4 #include <cmath>
5 #include <string>
6 
7 #include <AMReX_ParmParse.H>
8 #include <AMReX_REAL.H>
9 #include <AMReX_Utility.H>
10 
11 /**
12  * Inputs of the canopy terms of the k-eqn RANS model (erf.forest_canopy_*).
13  * The terms themselves are in Source/SourceTerms/ERF_CanopyTurbulence.H.
14  */
16 {
17  //! erf.forest_canopy_tke: add the canopy terms to the k-eqn RANS model
18  bool enabled = false;
19  //! erf.forest_canopy_beta_p: fraction of the drag work that becomes TKE
21  //! erf.forest_canopy_beta_d: short-circuit dissipation coefficient
23  //! erf.forest_canopy_length_alpha: length scale cap L <= alpha / f;
24  //! zero disables the cap and keeps the TKE source
26 
27  /**
28  * Read the erf.forest_canopy_* inputs and check their ranges. The checks
29  * that need the rest of the configuration (a forest and the k-eqn model)
30  * are in check_config.
31  */
32  void init_params (amrex::ParmParse& pp)
33  {
34  pp.query("forest_canopy_tke", enabled);
35  const bool has_beta_p = pp.query("forest_canopy_beta_p", beta_p);
36  const bool has_beta_d = pp.query("forest_canopy_beta_d", beta_d);
37  const bool has_alpha = pp.query("forest_canopy_length_alpha", length_alpha);
38 
39  // Unused coefficients are left in place (with a warning) so that a deck
40  // can switch the canopy terms on and off with erf.forest_canopy_tke alone;
41  // their ranges are still checked below
42  if (!enabled && (has_beta_p || has_beta_d || has_alpha)) {
43  amrex::Warning("erf.forest_canopy_beta_p, erf.forest_canopy_beta_d and "
44  "erf.forest_canopy_length_alpha are not used without "
45  "erf.forest_canopy_tke = true");
46  }
47  if (!(beta_p >= amrex::Real(0.0) && beta_p <= amrex::Real(1.0))) {
48  amrex::Abort("erf.forest_canopy_beta_p must be in [0, 1], the fraction of the "
49  "drag work that becomes TKE; got " + std::to_string(beta_p));
50  }
51  if (!(beta_d >= amrex::Real(0.0) && std::isfinite(beta_d))) {
52  amrex::Abort("erf.forest_canopy_beta_d must be finite and not negative; got " +
53  std::to_string(beta_d));
54  }
55  if (!(length_alpha >= amrex::Real(0.0) && length_alpha <= amrex::Real(1.0))) {
56  amrex::Abort("erf.forest_canopy_length_alpha must be in [0, 1] (0 disables the "
57  "length scale cap); got " + std::to_string(length_alpha));
58  }
59  if (enabled && beta_p == amrex::Real(0.0) && beta_d == amrex::Real(0.0) &&
60  length_alpha == amrex::Real(0.0)) {
61  amrex::Abort("erf.forest_canopy_tke = true with erf.forest_canopy_beta_p, "
62  "erf.forest_canopy_beta_d and erf.forest_canopy_length_alpha all "
63  "zero would change nothing; set erf.forest_canopy_tke = false");
64  }
65  }
66 
67  /**
68  * The canopy terms act on the forest drag field and on the k-eqn RANS
69  * model only: abort when either is missing, rather than ignore the input,
70  * and when the length cap would meet the explicit TKE dissipation.
71  * @param do_forest_drag a forest is configured (erf.forest_file or gridded)
72  * @param keqn_on_every_level erf.rans_type = kEqn on every level
73  * @param implicit_diss_on_every_level erf.implicit_tke_dissipation on every level
74  */
75  void check_config (bool do_forest_drag, bool keqn_on_every_level,
76  bool implicit_diss_on_every_level) const
77  {
78  if (!enabled) { return; }
79  if (!do_forest_drag) {
80  amrex::Abort("erf.forest_canopy_tke = true needs a forest: set erf.forest_file, "
81  "or the gridded erf.forest_lai_file/forest_height_file inputs");
82  }
83  if (!keqn_on_every_level) {
84  amrex::Abort("erf.forest_canopy_tke = true needs erf.rans_type = kEqn on every "
85  "level");
86  }
87  // The cap makes the explicit dissipation rho Cmu0^3 k^1.5 / L stiff: with
88  // L = alpha / f its rate Cmu0^3 sqrt(k) f / alpha exceeds 1/dt, and k can go
89  // negative in one step, at time steps of a fraction of a second in a dense
90  // canopy (f = 0.6 1/m and k = 5 m^2/s^2 give 5.8 1/s). The implicit form has
91  // no such limit, so the cap requires it rather than warning about it.
92  if (length_alpha > amrex::Real(0.0) && !implicit_diss_on_every_level) {
93  amrex::Abort("erf.forest_canopy_tke = true with erf.forest_canopy_length_alpha > 0 "
94  "needs erf.implicit_tke_dissipation = true on every level: the canopy "
95  "length cap makes the explicit TKE dissipation stiff (see the Forest "
96  "model section of the docs)");
97  }
98  }
99 };
100 
101 #endif
ParmParse pp("prob")
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_CanopyTurbStruct.H:16
amrex::Real length_alpha
Definition: ERF_CanopyTurbStruct.H:25
amrex::Real beta_d
erf.forest_canopy_beta_d: short-circuit dissipation coefficient
Definition: ERF_CanopyTurbStruct.H:22
void init_params(amrex::ParmParse &pp)
Definition: ERF_CanopyTurbStruct.H:32
amrex::Real beta_p
erf.forest_canopy_beta_p: fraction of the drag work that becomes TKE
Definition: ERF_CanopyTurbStruct.H:20
bool enabled
erf.forest_canopy_tke: add the canopy terms to the k-eqn RANS model
Definition: ERF_CanopyTurbStruct.H:18
void check_config(bool do_forest_drag, bool keqn_on_every_level, bool implicit_diss_on_every_level) const
Definition: ERF_CanopyTurbStruct.H:75