ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_SurfaceLayer.H
Go to the documentation of this file.
1 #ifndef ERF_SURFACELAYER_H
2 #define ERF_SURFACELAYER_H
3 
4 #include <fstream>
5 #include <sstream>
6 #include <string>
7 
8 #include "AMReX_Geometry.H"
9 #include "AMReX_ParmParse.H"
10 #include "AMReX_FArrayBox.H"
11 #include "AMReX_MultiFab.H"
12 #include "AMReX_iMultiFab.H"
13 #include "AMReX_MFInterpolater.H"
14 
15 #include "ERF_IndexDefines.H"
16 #include "ERF_Constants.H"
17 #include "ERF_MOSTAverage.H"
18 #include "ERF_MOSTStress.H"
19 #include "ERF_EBMOSTStress.H"
21 #include "ERF_TerrainMetrics.H"
22 #include "ERF_PBLHeight.H"
23 #include "ERF_MicrophysicsUtils.H"
24 #include "ERF_EB.H"
25 
26 
27 /** Abstraction layer for different surface layer schemes (e.g. MOST, Cd)
28  *
29  * van der Laan, P., Kelly, M. C., & Sørensen, N. N. (2017). A new k-epsilon
30  * model consistent with Monin-Obukhov similarity theory. Wind Energy,
31  * 20(3), 479–amrex::Real(489.) https://doi.org/amrex::Real(10.1002)/we.2017
32  *
33  * Consistent with Dyer (1974) formulation from page 57, Chapter 2, Modeling
34  * the vertical ABL structure in Modelling of Atmospheric Flow Fields,
35  * Demetri P Lalas and Corrado F Ratto, January 1996,
36  * https://doi.org/amrex::Real(10.1142)/amrex::Real(2975.)
37  */
39 {
40 
41 public:
42  /**
43  * Construct the surface-layer interface.
44  *
45  * @param[in] geom geometry for all AMR levels
46  * @param[in,out] use_rot_surface_flux whether to use rotated surface fluxes
47  * @param[in] a_pp_prefix ParmParse prefix used by MOST averages
48  * @param[in] Qv_prim primitive water-vapor fields by level
49  * @param[in] z_phys_nd nodal physical-height fields by level
50  * @param[in] a_mesh_type mesh type
51  * @param[in] a_terrain_type terrain representation
52  * @param[in] a_turb_choice turbulence-model options
53  * @param[in] start_low_time first available low-boundary-data time
54  * @param[in] final_low_time final available low-boundary-data time
55  * @param[in] low_time_interval low-boundary-data time interval
56  * @param[in] eb_vec optional embedded-boundary geometry data
57  */
58  explicit SurfaceLayer (const amrex::Vector<amrex::Geometry>& geom,
59  bool& use_rot_surface_flux,
60  std::string a_pp_prefix,
61  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Qv_prim,
62  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& z_phys_nd,
63  const MeshType& a_mesh_type,
64  const TerrainType& a_terrain_type,
65  const TurbChoice& a_turb_choice,
66  double start_low_time,
67  double final_low_time,
68  double low_time_interval = 0.0,
69  const amrex::Vector<const eb_*>& eb_vec = {})
70  : m_geom(geom),
71  m_rotate(use_rot_surface_flux),
72  m_start_low_time(start_low_time),
73  m_final_low_time(final_low_time),
74  m_low_time_interval(low_time_interval),
75  m_eb_vec(eb_vec),
76  m_terrain_type(a_terrain_type),
77  m_ma(geom, (z_phys_nd[0] != nullptr), a_pp_prefix, a_mesh_type, a_terrain_type, eb_vec)
78  {
79  // We have a moisture model if Qv_prim is a valid pointer
80  use_moisture = (Qv_prim[0].get());
81 
82  // Get roughness
83  amrex::ParmParse pp("erf");
84  pp.queryAdd("most.z0", z0_const);
85 
86  // Specify how to compute the flux
87  if (use_rot_surface_flux) {
89  } else {
90  std::string flux_string_in;
91  std::string flux_string{"moeng"};
92  auto read_flux = pp.queryAdd("surface_layer.flux_type", flux_string_in);
93  if (read_flux) {
94  flux_string = amrex::toLower(flux_string_in);
95  }
96  if (flux_string == "donelan") {
98  } else if (flux_string == "moeng") {
100  } else if (flux_string == "rico") {
102  } else if (flux_string == "bulk_coeff") {
104  } else if (flux_string == "custom") {
106  } else {
107  amrex::Abort("Undefined MOST flux type!");
108  }
109  }
110 
111  // Include w* to handle free convection (Beljaars 1995, QJRMS)
112  pp.queryAdd("most.include_wstar", m_include_wstar);
113 
114  std::string pblh_string_in;
115  std::string pblh_string{"none"};
116  auto read_pblh = pp.queryAdd("most.pblh_calc", pblh_string_in);
117  if (read_pblh) {
118  pblh_string = amrex::toLower(pblh_string_in);
119  }
120  if (pblh_string == "none") {
122  } else if (pblh_string == "mynn25") {
124  } else if (pblh_string == "mynnedmf") {
126  } else if (pblh_string == "ysu") {
128  } else if (pblh_string == "mrf") {
130  } else {
131  amrex::Abort("Undefined PBLH calc type!");
132  }
133 
134  // The w* correction is computed from the PBL height, so it needs a scheme that
135  // actually diagnoses one. With pblh_calc = "none" the pblh MultiFab keeps the
136  // bogus_large_value it was initialized with and calc_wstar turns that into a
137  // convective velocity scale of ~1e50, which destroys the surface fluxes.
139  amrex::Abort("erf.most.include_wstar requires a PBL height: set "
140  "erf.most.pblh_calc (MYNN25 is the only scheme implemented)");
141  }
142 
143  // Get surface temperature. surf_temp and surf_moist are declared with negative
144  // sentinels (see below) so that "did the user set this" is a property of the
145  // value rather than of the queryAdd return value, which only reports whether the
146  // key existed before the call and so stops being meaningful once anything has
147  // parsed the key. Both most.surf_temp and most.surf_moist are also parsed by
148  // ERF_InputSoundingData.H, so the two sites would poison each other otherwise.
149  pp.queryAdd("most.surf_temp", surf_temp);
150  const bool erf_st = (surf_temp > amrex::Real(0));
151  if (erf_st) { default_land_surf_temp = surf_temp; }
152 
153  // Get surface moisture
154  bool erf_sq = false;
155  if (use_moisture) {
156  pp.queryAdd("most.surf_moist", surf_moist);
157  erf_sq = (surf_moist >= amrex::Real(0));
158  }
159  if (erf_sq) { default_land_surf_moist = surf_moist; }
160 
161  // Custom type user must specify the fluxes
166  pp.get("most.ustar", custom_ustar);
167  pp.get("most.tstar", custom_tstar);
168  pp.get("most.qstar", custom_qstar);
169  pp.queryAdd("most.rhosurf", custom_rhosurf);
170  if (custom_qstar != 0) {
172  "Specified custom MOST qv flux without moisture model!");
173  }
174  amrex::Print() << "Using specified ustar, tstar, qstar for MOST = "
175  << custom_ustar << " " << custom_tstar << " "
176  << custom_qstar << std::endl;
177 
178  // Bulk transfer coefficient (must specify coeffs and surface values)
179  } else if (flux_type == FluxCalcType::BULK_COEFF) {
180  pp.get("most.Cd", m_Cd);
181  pp.get("most.Ch", m_Ch);
182  pp.get("most.Cq", m_Cq);
183  pp.get("most.surf_temp", default_land_surf_temp);
184  pp.get("most.surf_moist", default_land_surf_moist);
185  amrex::Print() << "Using specified Cd, Ch, Cq for MOST = "
186  << m_Cd << " " << m_Ch << " "
187  << m_Cq << std::endl;
188 
189  // Specify surface temperature/moisture or surface flux
190  } else {
191  if (erf_st) {
193  pp.queryAdd("most.surf_heating_rate", surf_heating_rate); // [K/h]
194 
195  // Modify rate to be in units of K / s rather than K / hr
196  surf_heating_rate /= amrex::Real(3600.0); // [K/s]
197 
198  if (pp.query("most.surf_temp_flux", surf_temp_flux)) {
199  amrex::Abort("Can only specify one of surf_temp_flux or surf_heating_rate");
200  }
201  } else {
202  pp.queryAdd("most.surf_temp_flux", surf_temp_flux);
203 
204  if (pp.query("most.surf_heating_rate", surf_heating_rate)) {
205  amrex::Abort("Can only specify one of surf_temp_flux or surf_heating_rate");
206  }
207  if (std::abs(surf_temp_flux) >
210  } else {
212  }
213  }
214 
215  if (erf_sq) {
217  } else {
218  pp.queryAdd("most.surf_moist_flux", surf_moist_flux);
219  if (std::abs(surf_moist_flux) >
222  } else {
224  }
225  }
226  }
227 
229  {
230  pp.queryAdd("most.rico.theta_z0", rico_theta_z0);
231  pp.queryAdd("most.rico.qsat_z0", rico_qsat_z0);
232  }
233 
234  // Make sure the inputs file doesn't try to use most.roughness_type
235  std::string bogus_input;
236  if (pp.queryAdd("most.roughness_type", bogus_input) > 0) {
237  amrex::Abort("most.roughness_type is deprecated; use "
238  "most.roughness_type_land and/or most.roughness_type_sea");
239  }
240 
241  // Specify how to compute the surface flux over land (if there is any)
242  std::string rough_land_string_in;
243  std::string rough_land_string{"constant"};
244  auto read_rough_land =
245  pp.queryAdd("most.roughness_type_land", rough_land_string_in);
246  if (read_rough_land) {
247  rough_land_string = amrex::toLower(rough_land_string_in);
248  }
249  if (rough_land_string == "constant") {
251  } else {
252  amrex::Abort("Undefined MOST roughness type for land!");
253  }
254 
255  // Specify how to compute the surface flux over sea (if there is any)
256  std::string rough_sea_string_in;
257  std::string rough_sea_string{"charnock"};
258  auto read_rough_sea = pp.queryAdd("most.roughness_type_sea", rough_sea_string_in);
259  if (read_rough_sea) {
260  rough_sea_string = amrex::toLower(rough_sea_string_in);
261  }
262  if (rough_sea_string == "charnock") {
264  pp.queryAdd("most.charnock_constant", cnk_a);
265  pp.queryAdd("most.charnock_viscosity", cnk_visc);
266  if (cnk_a > 0) {
267  amrex::Print() << "If there is water, Charnock relation with C_a="
268  << cnk_a << (cnk_visc ? " and viscosity" : "")
269  << " will be used" << std::endl;
270  } else {
271  amrex::Print() << "If there is water, Charnock relation with variable "
272  "Charnock parameter (COARE3.0)"
273  << (cnk_visc ? " and viscosity" : "") << " will be used"
274  << std::endl;
275  }
276  } else if (rough_sea_string == "coare3.0") {
278  amrex::Print() << "If there is water, Charnock relation with variable "
279  "Charnock parameter (COARE3.0)"
280  << (cnk_visc ? " and viscosity" : "") << " will be used"
281  << std::endl;
282  cnk_a = -1;
283  } else if (rough_sea_string == "donelan") {
285  } else if (rough_sea_string == "modified_charnock") {
287  pp.queryAdd("most.modified_charnock_depth", depth);
288  } else if (rough_sea_string == "wave_coupled") {
290  } else if (rough_sea_string == "constant") {
292  } else {
293  amrex::Abort("Undefined MOST roughness type for sea!");
294  }
295 
296  // use skin temperature instead of sea-surface temperature
297  // (wrfinput data may have lower resolution SST data)
298  pp.queryAdd("most.ignore_sst", m_ignore_sst);
299 
300  // If we're using the RANS k model, then we need to update the dirichlet
301  // BC based on the instantaneous u* and θ*; the turbulence modeling
302  // choices can vary per level but for now, assume that if specified then
303  // all levels are using the same RANS model.
304  m_update_k_rans = (a_turb_choice.rans_type == RANSType::kEqn &&
305  a_turb_choice.dirichlet_k == true);
306  if (m_update_k_rans) {
307  inv_Cmu2 = one / (a_turb_choice.Cmu0 * a_turb_choice.Cmu0);
308  theta_ref = a_turb_choice.theta_ref;
309  }
310 
311  } // constructor
312 
313  /**
314  * Allocate and initialize surface-layer data for one AMR level.
315  *
316  * @param[in] lev level index
317  * @param[in] nlevs number of AMR levels
318  * @param[in] mfv conserved and velocity MultiFabs for this level
319  * @param[in] Theta_prim primitive potential-temperature field
320  * @param[in] Qv_prim primitive water-vapor field
321  * @param[in] Qr_prim primitive rain-water field
322  * @param[in] z_phys_nd nodal physical-height field
323  * @param[in] Hwave wave-height field
324  * @param[in] Lwave wavelength field
325  * @param[in] eddyDiffs eddy-diffusivity field
326  * @param[in] lsm_data land-surface-model data fields
327  * @param[in] lsm_data_name names for lsm_data entries
328  * @param[in] lsm_flux land-surface-model flux fields
329  * @param[in] lsm_flux_name names for lsm_flux entries
330  * @param[in] sst_lev sea-surface-temperature data by time
331  * @param[in] tsk_lev skin-temperature data by time
332  * @param[in] lmask_lev land-mask data by time
333  */
334  void make_SurfaceLayer_at_level (const int& lev,
335  int nlevs,
336  const amrex::Vector<amrex::MultiFab*>& mfv,
337  std::unique_ptr<amrex::MultiFab>& Theta_prim,
338  std::unique_ptr<amrex::MultiFab>& Qv_prim,
339  std::unique_ptr<amrex::MultiFab>& Qr_prim,
340  std::unique_ptr<amrex::MultiFab>& z_phys_nd,
341  amrex::MultiFab* Hwave,
342  amrex::MultiFab* Lwave,
343  amrex::MultiFab* eddyDiffs,
344  amrex::Vector<amrex::MultiFab*> lsm_data,
345  amrex::Vector<std::string> lsm_data_name,
346  amrex::Vector<amrex::MultiFab*> lsm_flux,
347  amrex::Vector<std::string> lsm_flux_name,
348  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& sst_lev,
349  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& tsk_lev,
350  amrex::Vector<std::unique_ptr<amrex::iMultiFab>>& lmask_lev)
351  {
352  // Update MOST Average
354  Theta_prim, Qv_prim, Qr_prim,
355  z_phys_nd);
356 
357  // Get CC vars
358  amrex::MultiFab& mf = *(mfv[0]);
359 
360  amrex::ParmParse pp("erf");
361 
362  // Do we have a time-varying surface roughness that needs to be saved?
363  if (lev == 0) {
364  const int nghost = 0; // ghost cells not included
365  int lmask_min = lmask_min_reduce(*lmask_lev[0].get(), nghost);
366  amrex::ParallelDescriptor::ReduceIntMin(lmask_min);
367 
368  m_var_z0 = (lmask_min < 1) & (rough_type_sea != RoughCalcType::CONSTANT);
369  if (m_var_z0) {
370  std::string rough_sea_string{"charnock"};
371  pp.queryAdd("most.roughness_type_sea", rough_sea_string);
372  amrex::Print() << "Variable sea roughness (type " << rough_sea_string
373  << ")" << std::endl;
374  }
375  }
376 
377  if (m_eddyDiffs_lev.size() < lev+1) {
378  m_Hwave_lev.resize(nlevs);
379  m_Lwave_lev.resize(nlevs);
380  m_eddyDiffs_lev.resize(nlevs);
381 
382  m_lsm_data_lev.resize(nlevs);
383  m_lsm_flux_lev.resize(nlevs);
384 
385  m_sst_lev.resize(nlevs);
386  m_tsk_lev.resize(nlevs);
387  m_lmask_lev.resize(nlevs);
388 
389  m_coupled_sst_lev.resize(nlevs, nullptr);
390  m_coupled_sst_valid_lev.resize(nlevs, nullptr);
391 
392  // Size the MOST params for all levels
393  z_0.resize(nlevs);
394  u_star.resize(nlevs);
395  w_star.resize(nlevs);
396  t_star.resize(nlevs);
397  q_star.resize(nlevs);
398  t_surf.resize(nlevs);
399  q_surf.resize(nlevs);
400  surface_diagnostic_source.resize(nlevs);
401  olen.resize(nlevs);
402  pblh.resize(nlevs);
403  }
404 
405  // Get pointers to SST,TSK and LANDMASK data
406  int nt_tot_sst = sst_lev.size();
407  m_sst_lev[lev].resize(nt_tot_sst);
408  for (int nt(0); nt < nt_tot_sst; ++nt) {
409  m_sst_lev[lev][nt] = sst_lev[nt].get();
410  }
411  int nt_tot_tsk = static_cast<int>(tsk_lev.size());
412  m_tsk_lev[lev].resize(nt_tot_tsk);
413  for (int nt(0); nt < nt_tot_tsk; ++nt) {
414  m_tsk_lev[lev][nt] = tsk_lev[nt].get();
415  }
416  int nt_tot_lmask = static_cast<int>(lmask_lev.size());
417  m_lmask_lev[lev].resize(nt_tot_lmask);
418  for (int nt(0); nt < nt_tot_lmask; ++nt) {
419  m_lmask_lev[lev][nt] = lmask_lev[nt].get();
420  }
421 
422  // Get pointers to wave data
423  m_Hwave_lev[lev] = Hwave;
424  m_Lwave_lev[lev] = Lwave;
425  m_eddyDiffs_lev[lev] = eddyDiffs;
426 
427  // Text-file driven surface forcing modes. The file always contains at
428  // least time(day) and sst(K); prescribed-flux mode also uses H, LE, USTAR.
429  pp.queryAdd("most.use_sfc_fluxes", m_use_sfc_fluxes);
430  pp.queryAdd("most.use_sfc_sst", m_use_sfc_sst);
432  amrex::Abort("Only one of most.use_sfc_fluxes and most.use_sfc_sst may be enabled");
433  }
435  if (m_terrain_type == TerrainType::EB) {
436  amrex::Abort("Text-file surface forcing is not supported with EB terrain");
437  }
438 
439  // load sensible and latent heat fluxes from sfc to prescribe
440  std::string sfc_file = "";
441  pp.queryAdd("most.sfc_file", sfc_file);
442  if (sfc_file.empty()) {
443  amrex::Abort("most.sfc_file must be set when using text-file surface forcing");
444  }
445 
446  // sfc contains: time(day) sst(K) H(W/m2) LE(W/m2) TAU(m2/s2)
447  sfc = read_cols(sfc_file, 1);
448 
449  const int min_cols = m_use_sfc_fluxes ? 5 : 2;
450  if (static_cast<int>(sfc.size()) < min_cols) {
451  amrex::Abort("Surface forcing file does not contain the required number of columns");
452  }
453 
454  // shift time column in days to be relative to current elapsed time
455  const amrex::Real start_day = sfc[0][0];
456  for (int i = 0; i < static_cast<int>(sfc[0].size()); ++i) {
457  sfc[0][i] = 86400.0 * (sfc[0][i] - start_day);
458  }
459 
460  if (m_use_sfc_sst) {
462  amrex::Abort("most.use_sfc_sst cannot be combined with prescribed heat flux or surf_heating_rate");
463  }
465  amrex::Abort("most.use_sfc_sst cannot be combined with prescribed moisture flux");
466  }
468  amrex::Print() << "Using MOST with prescribed SST from most.sfc_file '" << sfc_file << "' over sea" << std::endl;
469  }
470 
471  if (m_use_sfc_fluxes) {
473  amrex::Print() << "Using MOST with prescribed time-varying surface fluxes from '" << sfc_file << "'" << std::endl;
474  }
475  }
476 
477  // Get pointers to LSM data and Fluxes
478  int ndata = static_cast<int>(lsm_data.size());
479  int nflux = static_cast<int>(lsm_flux.size());
480  m_lsm_data_name.resize(ndata);
481  m_lsm_data_lev[lev].resize(ndata);
482  m_lsm_flux_name.resize(nflux);
483  m_lsm_flux_lev[lev].resize(nflux);
484  for (int n(0); n < ndata; ++n) {
485  m_lsm_data_name[n] = lsm_data_name[n];
486  m_lsm_data_lev[lev][n] = lsm_data[n];
487  const std::string lc_name = amrex::toLower(lsm_data_name[n]);
488  if (lc_name == "theta" || lc_name == "t_surf") {
489  m_has_lsm_tsurf = true;
490  m_lsm_tsurf_indx = n;
491  }
492  }
494  amrex::Abort("most.use_sfc_sst cannot be combined with an ocean LSM t_surf input");
495  }
496  int n_valid_lsm_flux = 0;
497  bool has_soil_t_flux = false;
498  for (int n(0); n < nflux; ++n) {
499  m_lsm_flux_name[n] = lsm_flux_name[n];
500  m_lsm_flux_lev[lev][n] = lsm_flux[n];
501  if (m_lsm_flux_lev[lev][n]) { ++n_valid_lsm_flux; }
502  if (amrex::toLower(m_lsm_flux_name[n]) == "soil_t_flux") {
503  has_soil_t_flux = true;
504  }
505  }
506  AMREX_ALWAYS_ASSERT((n_valid_lsm_flux==0 || n_valid_lsm_flux>=4 ||
507  (n_valid_lsm_flux==1 && has_soil_t_flux)));
508  if (n_valid_lsm_flux>=4) { m_has_lsm_fluxes = true; }
509 
510  // Check if there is a user-specified roughness file to be read
511  std::string fname;
512  bool read_z0 = false;
513  if ( (flux_type == FluxCalcType::MOENG) ||
515  int count = pp.countval("most.roughness_file_name");
516  if (count > 1) {
517  AMREX_ALWAYS_ASSERT(count >= lev+1);
518  pp.query("most.roughness_file_name", fname, lev);
519  read_z0 = true;
520  } else if (count == 1) {
521  if (lev == 0) {
522  pp.queryAdd("most.roughness_file_name", fname);
523  } else {
524  // we will interpolate from the coarsest level
525  fname = "";
526  }
527  read_z0 = true;
528  }
529  // else use z0_const
530  }
531 
532  // Attributes for MFs and FABs
533  //--------------------------------------------------------
534  // Create a 2D ba for planar terrain, 3D for EB terrain
535  amrex::BoxArray ba = mf.boxArray();
536  amrex::BoxArray ba_flux;
537  amrex::IntVect ng{1,1,0};
538 
539  if (m_terrain_type == TerrainType::EB) {
540  // Use full 3D BoxArray for EB terrain
541  ba_flux = ba;
542  ng = amrex::IntVect{1,1,1}; // Include z ghost cells
543  } else {
544  // Collapse to 2D for planar terrain
545  amrex::BoxList bl2d = ba.boxList();
546  for (auto& b : bl2d) { b.setRange(2,0); }
547  ba_flux = amrex::BoxArray(std::move(bl2d));
548  }
549 
550  const amrex::DistributionMapping& dm = mf.DistributionMap();
551  const int ncomp = 1;
552 
553  // Z0 heights FAB
554  //--------------------------------------------------------
555  z_0[lev].define(ba_flux, dm, ncomp, ng);
556  z_0[lev].setVal(z0_const);
557  if (read_z0) {
558  read_custom_roughness(lev, fname);
559  }
560 
561  // 2D MFs for U*, T*, T_surf
562  //--------------------------------------------------------
563  u_star[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
564  u_star[lev]->setVal(bogus_large_value);
565 
566  w_star[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
567  w_star[lev]->setVal(bogus_large_value);
568 
569  t_star[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
570  t_star[lev]->setVal(zero); // default to neutral
571 
572  q_star[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
573  q_star[lev]->setVal(zero); // default to dry
574 
575  olen[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
576  olen[lev]->setVal(bogus_large_value);
577 
578  pblh[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
579  pblh[lev]->setVal(bogus_large_value);
580 
581  t_surf[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
582  t_surf[lev]->setVal(default_land_surf_temp);
583 
584  q_surf[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
585  q_surf[lev]->setVal(default_land_surf_moist);
586 
587  surface_diagnostic_source[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
588  surface_diagnostic_source[lev]->setVal(
590 
591  // TODO: Do we want an enum struct for indexing?
592 
593  bool use_sst = (!m_sst_lev[lev].empty() && m_sst_lev[lev][0]);
594  bool use_tsk = (!m_tsk_lev[lev].empty() && m_tsk_lev[lev][0]);
595  if (use_sst || use_tsk || m_has_lsm_tsurf || m_use_coupled_sst) {
596  // Valid SST, TSK, LSM or coupled-ocean data; t_surf set before computing
597  // fluxes (avoids extended lambda capture) Note that land temp will be set
598  // from m_tsk_lev while sea temp will be set from m_sst_lev
600 
601  // Pathways in fill_tsurf_with_sst_and_tsk
602  amrex::Print() << "Using MOST with specified surface temperature ";
603  if (m_has_lsm_tsurf && !use_sst && !use_tsk) {
604  amrex::Print() << "(LSM: " << m_lsm_data_name[m_lsm_tsurf_indx] << ")";
605  } else if (!use_sst && !use_tsk) {
606  amrex::Print() << "(land: T0, sea: none)";
607  } else {
608  // NOTE: SST from the LOW file populates TSK in update_sst_tsk.
609  // So if we have TSK, it contains everything and has been
610  // sanity checked for valid SST values.
611  if (use_tsk) { m_ignore_sst = true; }
612  if (use_tsk) {
613  amrex::Print() << "(land: TSK, ";
614  } else {
615  amrex::Print() << "(land: T0, ";
616  }
617  if (use_tsk && !use_sst) {
618  amrex::Print() << "sea: TSK)";
619  } else {
620  amrex::Print() << "sea: SST)";
622  }
623  }
624  // The coupler is layered on top of whatever the above selected: it
625  // overwrites only the water cells it actually covers, so the pathway
626  // named above remains the value for land and for uncovered water.
627  if (m_use_coupled_sst) {
628  amrex::Print() << " + coupled ocean SST where covered";
629  }
630  amrex::Print() << std::endl;
631  }
632  }
633 
634  /**
635  * Update surface fluxes and related surface-layer state.
636  *
637  * @param[in] lev level index
638  * @param[in] elapsed_time current elapsed simulation time
639  * @param[in] elapsed_time_since_start_low elapsed time relative to low-data start
640  * @param[in,out] cons_in conserved state used by the flux update
641  * @param[in] z_phys_nd nodal physical-height field
642  * @param[in] walldist wall-distance field
643  * @param[in] max_iters maximum MOST iteration count
644  */
645  void
646  update_fluxes (const int& lev,
647  const double& elapsed_time,
648  const double& elapsed_time_since_start_low,
649  amrex::MultiFab& cons_in,
650  const std::unique_ptr<amrex::MultiFab>& z_phys_nd,
651  const std::unique_ptr<amrex::MultiFab>& walldist,
652  int max_iters = 100);
653 
654  /**
655  * Compute MOST fluxes with a selected flux-iteration functor.
656  *
657  * @param[in] lev level index
658  * @param[in] max_iters maximum MOST iteration count
659  * @param[in,out] cons_in conserved state used by the flux computation
660  * @param[in] most_flux flux-iteration functor
661  * @param[in] is_land whether the land-surface branch is active
662  */
663  template <typename FluxIter>
664  void compute_fluxes (const int& lev,
665  const int& max_iters,
666  amrex::MultiFab& cons_in,
667  const FluxIter& most_flux,
668  bool is_land);
669 
670  /**
671  * Initialize TKE from the current surface friction velocity.
672  *
673  * @param[in] lev level index
674  * @param[in,out] cons conserved state whose TKE component is initialized
675  * @param[in] z_phys_nd nodal physical-height field
676  * @param[in] tkefac scale factor applied to the initialized TKE
677  * @param[in] zscale vertical decay scale
678  */
679  void init_tke_from_ustar (const int& lev,
680  amrex::MultiFab& cons,
681  const std::unique_ptr<amrex::MultiFab>& z_phys_nd,
682  const amrex::Real tkefac = one,
683  const amrex::Real zscale = amrex::Real(700.0));
684 
685  /**
686  * Impose surface-layer boundary conditions for planar terrain.
687  *
688  * @param[in] lev level index
689  * @param[in] mfs state and velocity fields used by the BC computation
690  * @param[in,out] Tau_lev stress fields to fill
691  * @param[in,out] xheat_flux x-face heat flux field
692  * @param[in,out] yheat_flux y-face heat flux field
693  * @param[in,out] zheat_flux z-face heat flux field
694  * @param[in,out] xqv_flux x-face moisture flux field
695  * @param[in,out] yqv_flux y-face moisture flux field
696  * @param[in,out] zqv_flux z-face moisture flux field
697  * @param[in] z_phys physical-height field
698  */
699  void impose_SurfaceLayer_bcs (const int& lev,
700  amrex::Vector<const amrex::MultiFab*> mfs,
701  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Tau_lev,
702  amrex::MultiFab* xheat_flux,
703  amrex::MultiFab* yheat_flux,
704  amrex::MultiFab* zheat_flux,
705  amrex::MultiFab* xqv_flux,
706  amrex::MultiFab* yqv_flux,
707  amrex::MultiFab* zqv_flux,
708  const amrex::MultiFab* z_phys);
709 
710  /**
711  * Impose surface-layer boundary conditions for embedded-boundary terrain.
712  *
713  * @param[in] lev level index
714  * @param[in] mfs state and velocity fields used by the BC computation
715  * @param[in,out] Tau_lev EB stress fields to fill
716  * @param[in,out] xheat_flux x-face heat flux field
717  * @param[in,out] yheat_flux y-face heat flux field
718  * @param[in,out] zheat_flux z-face heat flux field
719  * @param[in,out] xqv_flux x-face moisture flux field
720  * @param[in,out] yqv_flux y-face moisture flux field
721  * @param[in,out] zqv_flux z-face moisture flux field
722  */
723  void impose_SurfaceLayer_bcs_EB (const int& lev,
724  amrex::Vector<const amrex::MultiFab*> mfs,
725  amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab>>>& Tau_lev,
726  amrex::MultiFab* xheat_flux,
727  amrex::MultiFab* yheat_flux,
728  amrex::MultiFab* zheat_flux,
729  amrex::MultiFab* xqv_flux,
730  amrex::MultiFab* yqv_flux,
731  amrex::MultiFab* zqv_flux);
732 
733  /**
734  * Compute planar-terrain surface-layer flux boundary conditions.
735  *
736  * @param[in] lev level index
737  * @param[in] mfs state and velocity fields used by the BC computation
738  * @param[in,out] Tau_lev stress fields to fill
739  * @param[in,out] xheat_flux x-face heat flux field
740  * @param[in,out] yheat_flux y-face heat flux field
741  * @param[in,out] zheat_flux z-face heat flux field
742  * @param[in,out] xqv_flux x-face moisture flux field
743  * @param[in,out] yqv_flux y-face moisture flux field
744  * @param[in,out] zqv_flux z-face moisture flux field
745  * @param[in] z_phys physical-height field
746  * @param[in] flux_comp flux-computation functor
747  */
748  template <typename FluxCalc>
749  void compute_SurfaceLayer_bcs (const int& lev,
750  amrex::Vector<const amrex::MultiFab*> mfs,
751  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Tau_lev,
752  amrex::MultiFab* xheat_flux,
753  amrex::MultiFab* yheat_flux,
754  amrex::MultiFab* zheat_flux,
755  amrex::MultiFab* xqv_flux,
756  amrex::MultiFab* yqv_flux,
757  amrex::MultiFab* zqv_flux,
758  const amrex::MultiFab* z_phys,
759  const FluxCalc& flux_comp);
760 
761  /**
762  * Compute embedded-boundary surface-layer flux boundary conditions.
763  *
764  * @param[in] lev level index
765  * @param[in] mfs state and velocity fields used by the BC computation
766  * @param[in,out] Tau_lev EB stress fields to fill
767  * @param[in,out] xheat_flux x-face heat flux field
768  * @param[in,out] yheat_flux y-face heat flux field
769  * @param[in,out] zheat_flux z-face heat flux field
770  * @param[in,out] xqv_flux x-face moisture flux field
771  * @param[in,out] yqv_flux y-face moisture flux field
772  * @param[in,out] zqv_flux z-face moisture flux field
773  * @param[in] flux_comp flux-computation functor
774  */
775  template <typename FluxCalc>
776  void compute_SurfaceLayer_bcs_EB (const int& lev,
777  amrex::Vector<const amrex::MultiFab*> mfs,
778  amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab>>>& Tau_lev,
779  amrex::MultiFab* xheat_flux,
780  amrex::MultiFab* yheat_flux,
781  amrex::MultiFab* zheat_flux,
782  amrex::MultiFab* xqv_flux,
783  amrex::MultiFab* yqv_flux,
784  amrex::MultiFab* zqv_flux,
785  const FluxCalc& flux_comp);
786 
787  /**
788  * Derive MOST surface parameters from LSM fluxes.
789  *
790  * @param[in] lev level index
791  * @param[in,out] cons_in conserved state used by the surface-parameter computation
792  */
793  void compute_sfc_params_from_lsm_fluxes(const int& lev,
794  amrex::MultiFab& cons_in);
795 
796  /**
797  * Fill surface temperature from available SST and TSK data.
798  *
799  * @param[in] lev level index
800  * @param[in] time interpolation time
801  */
802  void fill_tsurf_with_sst_and_tsk (const int& lev,
803  const double& time);
804 
805  /**
806  * Fill surface temperature interpolated from time varying SST file
807  *
808  * @param[in] lev level index
809  * @param[in] time interpolation time
810  */
811  void fill_tsurf_with_sfc_sst (const int& lev,
812  const double& time);
813 
814  /**
815  * Overwrite surface temperature with coupled ocean SST where the coupler
816  * covers the cell.
817  *
818  * Runs after fill_tsurf_with_sst_and_tsk so that the lower-boundary data is
819  * the base layer: land cells, and water cells with no ocean donor, keep the
820  * value written there.
821  *
822  * @param[in] lev level index
823  */
824  void fill_tsurf_with_coupled_sst (const int& lev);
825 
826  /**
827  * Fill surface moisture from saturation specific humidity.
828  *
829  * @param[in] lev level index
830  * @param[in] cons_in conserved state used to evaluate surface pressure
831  * @param[in] z_phys_nd nodal physical-height field
832  */
833  void fill_qsurf_with_qsat (const int& lev,
834  const amrex::MultiFab& cons_in,
835  const std::unique_ptr<amrex::MultiFab>& z_phys_nd);
836 
837  /**
838  * Updates current time index for interpolating data from SFC/SST file.
839  *
840  * @param[in] time elapsed time
841  */
842  void update_sfc_time_index (const amrex::Real& time);
843 
844  /**
845  * Interpolates the SFC/SST data at the given column and time
846  *
847  * @param[in] time elapsed time
848  * @param[in] col column index of file data
849  */
851  int col) const;
852 
853  /**
854  * Fill surface temperature from the LSM surface-temperature field.
855  *
856  * @param[in] lev level index
857  */
858  void get_lsm_tsurf (const int& lev);
859 
860  /**
861  * Wrapper around compute_pblh.
862  *
863  * @param[in] lev level index
864  * @param[in,out] vars state variables used by the PBL-height calculation
865  * @param[in] z_phys_cc cell-centered physical-height field
866  * @param[in] moisture_indices indices for moisture components
867  */
868  void update_pblh (const int& lev,
869  amrex::Vector<amrex::Vector<amrex::MultiFab>>& vars,
870  amrex::MultiFab* z_phys_cc,
871  const MoistureComponentIndices& moisture_indices);
872 
873  /**
874  * Compute planetary-boundary-layer height with the selected estimator.
875  *
876  * @param[in] lev level index
877  * @param[in,out] vars state variables used by the PBL-height calculation
878  * @param[in] z_phys_cc cell-centered physical-height field
879  * @param[in] est PBL-height estimator functor
880  * @param[in] moisture_indice indices for moisture components
881  */
882  template <typename PBLHeightEstimator>
883  void compute_pblh (const int& lev,
884  amrex::Vector<amrex::Vector<amrex::MultiFab>>& vars,
885  amrex::MultiFab* z_phys_cc,
886  const PBLHeightEstimator& est,
887  const MoistureComponentIndices& moisture_indice);
888 
889  /**
890  * Read custom roughness data for one level.
891  *
892  * @param[in] lev level index
893  * @param[in] fname roughness-data file name
894  */
895  void read_custom_roughness (const int& lev,
896  const std::string& fname);
897 
898  /**
899  * Update prescribed surface temperature from the configured heating rate.
900  *
901  * @param[in] time elapsed simulation time
902  */
903  void update_surf_temp (const double& time)
904  {
905  // NOTE: this is a whole-domain setVal, so it overwrites the SST/TSK fill
906  // done earlier in update_fluxes. Coupled SST is applied after this
907  // call and therefore still wins on the water cells it covers.
908  if (surf_heating_rate != 0) {
909  // Use the actual size of t_surf, not m_geom.size(), which is always
910  // max_level+1 and so runs past the levels that exist. t_surf is sized for
911  // all levels up front but filled one level at a time, so we also have to
912  // skip the entries that have not been allocated yet.
913  int nlevs = static_cast<int>(t_surf.size());
914  for (int lev = 0; lev < nlevs; lev++) {
915  if (!t_surf[lev]) { continue; }
916  t_surf[lev]->setVal(surf_temp + surf_heating_rate * static_cast<amrex::Real>(time));
917  amrex::Print() << "Surface temp at t=" << time << ": "
918  << surf_temp + surf_heating_rate * time << std::endl;
919  }
920  }
921  }
922 
923  /**
924  * Update MOST-average field pointers.
925  *
926  * @param[in] lev level index
927  * @param[in] vars_old old-time state variables
928  * @param[in] Theta_prim primitive potential-temperature fields by level
929  * @param[in] Qv_prim primitive water-vapor fields by level
930  * @param[in] Qr_prim primitive rain-water fields by level
931  */
932  void update_mac_ptrs (const int& lev,
933  amrex::Vector<amrex::Vector<amrex::MultiFab>>& vars_old,
934  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Theta_prim,
935  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Qv_prim,
936  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Qr_prim)
937  {
938  m_ma.update_field_ptrs(lev, vars_old, Theta_prim, Qv_prim, Qr_prim);
939  }
940 
941  /**
942  * Return the friction-velocity field.
943  *
944  * @param[in] lev level index
945  */
946  amrex::MultiFab* get_u_star (const int& lev) { return u_star[lev].get(); }
947 
948  /**
949  * Return the convective velocity scale field.
950  *
951  * @param[in] lev level index
952  */
953  amrex::MultiFab* get_w_star (const int& lev) { return w_star[lev].get(); }
954 
955  /**
956  * Do we actually compute w*? If not then the field returned by get_w_star holds
957  * only the value it was initialized with, and must not be reported as a diagnostic.
958  */
959  [[nodiscard]] bool computes_w_star () const { return m_include_wstar; }
960 
961  /**
962  * Do we actually compute the PBL height? If not then the field returned by get_pblh
963  * holds only the value it was initialized with, and must not be reported as a diagnostic.
964  */
965  [[nodiscard]] bool computes_pblh () const { return (pblh_type != PBLHeightCalcType::None); }
966 
967  /**
968  * Return the temperature scale field.
969  *
970  * @param[in] lev level index
971  */
972  amrex::MultiFab* get_t_star (const int& lev) { return t_star[lev].get(); }
973 
974  /**
975  * Return the moisture scale field.
976  *
977  * @param[in] lev level index
978  */
979  amrex::MultiFab* get_q_star (const int& lev) { return q_star[lev].get(); }
980 
981  /**
982  * Return the Obukhov length field.
983  *
984  * @param[in] lev level index
985  */
986  amrex::MultiFab* get_olen (const int& lev) { return olen[lev].get(); }
987 
988  /**
989  * Return the planetary-boundary-layer-height field.
990  *
991  * @param[in] lev level index
992  */
993  amrex::MultiFab* get_pblh (const int& lev) { return pblh[lev].get(); }
994 
995  /**
996  * Return a MOST-average field.
997  *
998  * @param[in] lev level index
999  * @param[in] comp component index
1000  */
1001  const amrex::MultiFab* get_mac_avg (const int& lev, int comp)
1002  {
1003  return m_ma.get_average(lev, comp);
1004  }
1005 
1006  /**
1007  * Return whether the MOST averages are filtered in time.
1008  */
1010 
1011  /**
1012  * Return the number of MOST-average components.
1013  */
1014  int get_num_mac_avg () const { return m_ma.get_navg(); }
1015 
1016  /**
1017  * Return whether the time filter at this level holds meaningful history.
1018  *
1019  * @param[in] lev level index
1020  */
1021  bool mac_avg_is_initialized (const int& lev) const { return m_ma.time_avg_is_initialized(lev); }
1022 
1023  /**
1024  * Declare the time filter at this level to hold meaningful history (restart).
1025  *
1026  * @param[in] lev level index
1027  */
1029 
1030  /**
1031  * Return a MOST-average field for modification (restart).
1032  *
1033  * @param[in] lev level index
1034  * @param[in] comp component index
1035  */
1036  amrex::MultiFab* get_mac_avg_ptr (const int& lev, int comp) { return m_ma.get_average(lev, comp); }
1037 
1038  /**
1039  * Return the filtered plane averages, which hold the filter state for the
1040  * plane and EB averaging policies.
1041  *
1042  * @param[in] lev level index
1043  */
1044  amrex::Vector<amrex::Real> get_mac_plane_avg (const int& lev) const { return m_ma.get_plane_average(lev); }
1045 
1046  /**
1047  * Restore the filtered plane averages from a checkpoint; returns false if the
1048  * checkpoint does not hold what this run expects.
1049  *
1050  * @param[in] lev level index
1051  * @param[in] pavg filtered plane averages, one per average component
1052  */
1053  bool set_mac_plane_avg (const int& lev, const amrex::Vector<amrex::Real>& pavg) { return m_ma.set_plane_average(lev, pavg); }
1054 
1055  /**
1056  * Return the surface-temperature field.
1057  *
1058  * @param[in] lev level index
1059  */
1060  amrex::MultiFab* get_t_surf (const int& lev) { return t_surf[lev].get(); }
1061 
1062  /**
1063  * Set the surface-temperature field to a constant value.
1064  *
1065  * @param[in] lev level index
1066  * @param[in] tsurf surface temperature
1067  */
1068  void set_t_surf(const int& lev, const amrex::Real tsurf) { t_surf[lev]->setVal(tsurf); }
1069 
1070  /**
1071  * Return the surface-moisture field.
1072  *
1073  * @param[in] lev level index
1074  */
1075  amrex::MultiFab* get_q_surf (const int& lev) { return q_surf[lev].get(); }
1076 
1077  /**
1078  * Set the surface-moisture field to a constant value.
1079  *
1080  * @param[in] lev level index
1081  * @param[in] qsurf surface moisture
1082  */
1083  void set_q_surf(const int& lev, const amrex::Real qsurf) { q_surf[lev]->setVal(qsurf); }
1084 
1085  /**
1086  * Return the surface-diagnostic provenance field.
1087  *
1088  * @param[in] lev level index
1089  */
1090  amrex::MultiFab* get_surface_diagnostic_source (const int& lev) { return surface_diagnostic_source[lev].get(); }
1091 
1092  /**
1093  * Return the minimum reference height for one level.
1094  *
1095  * @param[in] lev level index
1096  */
1097  amrex::Real get_zref (const int& lev) { return (m_ma.get_zref(lev))->min(0); }
1098 
1099  /**
1100  * Return the roughness-height field.
1101  *
1102  * @param[in] lev level index
1103  */
1104  amrex::MultiFab* get_z0 (const int& lev) { return &z_0[lev]; }
1105 
1106  /**
1107  * Return whether variable sea roughness is active.
1108  */
1110 
1111  /**
1112  * Return the land-mask field.
1113  *
1114  * @param[in] lev level index
1115  */
1116  amrex::iMultiFab* get_lmask (const int& lev) { return m_lmask_lev[lev][0]; }
1117 
1118  /**
1119  * Compute the minimum land-mask value over valid and optional ghost cells.
1120  *
1121  * @param[in] lmask land-mask field
1122  * @param[in] nghost number of ghost cells included in the reduction
1123  */
1124  int lmask_min_reduce (amrex::iMultiFab& lmask,
1125  const int& nghost)
1126  {
1127  int lmask_min = amrex::ReduceMin(lmask, nghost, [=] AMREX_GPU_HOST_DEVICE(
1128  amrex::Box const& bx, amrex::Array4<int const> const& lm_arr) -> int
1129  {
1130  int locmin = std::numeric_limits<int>::max();
1131  const auto lo = lbound(bx);
1132  const auto hi = ubound(bx);
1133  for (int j = lo.y; j <= hi.y; ++j) {
1134  for (int i = lo.x; i <= hi.x; ++i) {
1135  locmin = std::min(locmin, lm_arr(i, j, 0));
1136  }
1137  }
1138  return locmin;
1139  });
1140 
1141  return lmask_min;
1142  }
1143 
1144  /**
1145  * Update one stored sea-surface-temperature pointer.
1146  *
1147  * @param[in] lev level index
1148  * @param[in] itime time-slice index
1149  * @param[in] sst_ptr sea-surface-temperature field pointer
1150  */
1151  void update_sst_ptr(const int lev, const int itime, amrex::MultiFab* sst_ptr) {
1152  m_sst_lev[lev][itime] = sst_ptr;
1153  }
1154 
1155  /**
1156  * Update one stored skin-temperature pointer.
1157  *
1158  * @param[in] lev level index
1159  * @param[in] itime time-slice index
1160  * @param[in] tsk_ptr skin-temperature field pointer
1161  */
1162  void update_tsk_ptr(const int lev, const int itime, amrex::MultiFab* tsk_ptr) {
1163  m_tsk_lev[lev][itime] = tsk_ptr;
1164  }
1165 
1166  /**
1167  * Hand over the coupled sea-surface temperature and its per-cell coverage flag.
1168  *
1169  * Both pointers stay owned by the caller and must remain valid, and on the same
1170  * layout, until replaced. Passing a null sst_ptr retracts the coupled lane, so
1171  * the lower-boundary SST/TSK value stands everywhere again.
1172  *
1173  * @param[in] lev level index
1174  * @param[in] sst_ptr coupled sea-surface temperature [K]
1175  * @param[in] valid_ptr per-cell coverage flag; nonzero where the coupler
1176  * supplied a value. Null means no cell is covered.
1177  */
1178  void update_coupled_sst_ptr (const int lev,
1179  amrex::MultiFab* sst_ptr,
1180  amrex::iMultiFab* valid_ptr) {
1181  m_coupled_sst_lev[lev] = sst_ptr;
1182  m_coupled_sst_valid_lev[lev] = valid_ptr;
1183  }
1184 
1185  /**
1186  * Declare that an ocean coupler will supply SST for this run.
1187  *
1188  * Must be called before make_SurfaceLayer_at_level, which uses it to select
1189  * ThetaCalcType::SURFACE_TEMPERATURE.
1190  *
1191  * @param[in] active whether coupled SST is configured
1192  */
1193  void set_coupled_sst_active (const bool active) { m_use_coupled_sst = active; }
1194 
1195  /**
1196  * Reads columns of data from a text file, returning each column in a vector.
1197  *
1198  * @param[in] fname path to text file
1199  * @param[in] skip_nlines number of lines to skip before reading data (e.g, header lines)
1200  * @return Vector containing each column in the file as a vector
1201  */
1202  static amrex::Vector<amrex::Vector<amrex::Real>>
1203  read_cols(const std::string& fname, const int skip_nlines = 1);
1204 
1205  enum struct FluxCalcType {
1206  MOENG = 0, ///< Moeng functional form
1207  DONELAN, ///< Donelan functional form
1208  CUSTOM, ///< Custom constant flux functional form
1209  BULK_COEFF, ///< Bulk transfer coefficient functional form
1210  ROTATE, ///< Terrain rotation flux functional form
1211  RICO
1212  };
1213 
1214  enum struct ThetaCalcType {
1215  ADIABATIC = 0,
1216  HEAT_FLUX, ///< Heat-flux specified
1217  SURFACE_TEMPERATURE ///< Surface temperature specified
1218  };
1219 
1220  enum struct MoistCalcType {
1221  ADIABATIC = 0,
1222  MOISTURE_FLUX, ///< Qv-flux specified
1223  SURFACE_MOISTURE ///< Surface Qv specified
1224  };
1225 
1226  enum struct RoughCalcType {
1227  CONSTANT = 0, ///< Constant z0
1228  CHARNOCK,
1230  DONELAN,
1231  WAVE_COUPLED
1232  };
1233 
1235 
1242 
1243 private:
1244  // Set in constructor
1245  amrex::Vector<amrex::Geometry> m_geom;
1246  bool m_rotate = false;
1250 
1251  bool m_include_wstar = false;
1254  // Negative sentinels: a surface temperature is absolute and a surface moisture is a
1255  // mixing ratio, so neither can legitimately be negative. The constructor probes
1256  // most.surf_temp / most.surf_moist with these and tests the resulting value to decide
1257  // whether the user supplied them. They were previously left uninitialized, which was
1258  // safe only because a plain query() leaves them untouched on a miss.
1268  amrex::Real custom_rhosurf{0}; // use specified value instead of rho from first cell
1269  bool specified_rho_surf{false};
1271  bool cnk_visc{false};
1273  amrex::Vector<amrex::MultiFab> z_0;
1274  bool m_var_z0{false};
1275 
1278 
1280  bool m_has_lsm_fluxes = false;
1281  bool m_has_lsm_tsurf = false;
1283 
1284  // variables for sfc/sst forcing from file
1285  bool m_use_sfc_fluxes = false;
1286  bool m_use_sfc_sst = false;
1287  int sfc_time_ind = 0;
1288  amrex::Vector<amrex::Vector<amrex::Real>> sfc;
1292 
1293  // Set from solverChoice.use_coupled_sst before the per-level Define runs.
1294  // Configuration only: true means an ocean coupler will supply SST on some
1295  // subset of the water cells, not that it has supplied any yet.
1296  bool m_use_coupled_sst = false;
1297 
1301 
1302  bool m_ignore_sst = false;
1303 
1304  amrex::Vector<const eb_*> m_eb_vec;
1305  TerrainType m_terrain_type;
1307  amrex::Vector<std::unique_ptr<amrex::MultiFab>> u_star;
1308  amrex::Vector<std::unique_ptr<amrex::MultiFab>> w_star;
1309  amrex::Vector<std::unique_ptr<amrex::MultiFab>> t_star;
1310  amrex::Vector<std::unique_ptr<amrex::MultiFab>> q_star;
1311  amrex::Vector<std::unique_ptr<amrex::MultiFab>> olen;
1312  amrex::Vector<std::unique_ptr<amrex::MultiFab>> pblh;
1313  amrex::Vector<std::unique_ptr<amrex::MultiFab>> t_surf;
1314  amrex::Vector<std::unique_ptr<amrex::MultiFab>> q_surf;
1315  // Diagnostic-only provenance mask. This records the cell-centered source
1316  // path used by the SurfaceLayer scalar diagnostic path. It must not feed
1317  // back into flux calculations, boundary conditions, or model state.
1318  amrex::Vector<std::unique_ptr<amrex::MultiFab>> surface_diagnostic_source;
1319 
1320  amrex::Vector<amrex::Vector<amrex::MultiFab*>> m_sst_lev;
1321  amrex::Vector<amrex::Vector<amrex::MultiFab*>> m_tsk_lev;
1322  amrex::Vector<amrex::Vector<amrex::iMultiFab*>> m_lmask_lev;
1323 
1324  // Coupled SST from an external ocean model, plus the per-cell coverage flag
1325  // that says whether the coupler actually supplied a value for that cell.
1326  // Both are owned by ERF and borrowed here, exactly like m_sst_lev. A null
1327  // m_coupled_sst_lev[lev] means "no coupled SST has arrived yet"; a zero entry in
1328  // m_coupled_sst_valid_lev means "this cell has no ocean donor", and in both cases the
1329  // lower-boundary SST/TSK value filled earlier in update_fluxes stands.
1330  amrex::Vector<amrex::MultiFab*> m_coupled_sst_lev;
1331  amrex::Vector<amrex::iMultiFab*> m_coupled_sst_valid_lev;
1332  amrex::Vector<amrex::Vector<amrex::MultiFab*>> m_lsm_data_lev;
1333  amrex::Vector<amrex::Vector<amrex::MultiFab*>> m_lsm_flux_lev;
1334  amrex::Vector<std::string> m_lsm_data_name;
1335  amrex::Vector<std::string> m_lsm_flux_name;
1336  amrex::Vector<amrex::MultiFab*> m_Hwave_lev;
1337  amrex::Vector<amrex::MultiFab*> m_Lwave_lev;
1338  amrex::Vector<amrex::MultiFab*> m_eddyDiffs_lev;
1339 
1340  bool m_update_k_rans = false;
1343 };
1344 
1345 #endif /* SURFACELAYER_H */
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
Defines EB Monin-Obukhov surface-layer flux functors.
Declares the embedded-boundary factory manager used by ERF levels.
ParmParse pp("prob")
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
pp get("wavelength", wavelength)
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_ASSERT_WITH_MESSAGE(wbar_cutoff_min > wbar_cutoff_max, "ERROR: wbar_cutoff_min < wbar_cutoff_max")
Definition: ERF_MOSTAverage.H:15
bool set_plane_average(const int &lev, const amrex::Vector< amrex::Real > &pavg)
Definition: ERF_MOSTAverage.H:299
amrex::Vector< amrex::Real > get_plane_average(const int &lev) const
Definition: ERF_MOSTAverage.H:285
bool do_time_averaging() const
Definition: ERF_MOSTAverage.H:249
amrex::MultiFab * get_zref(const int &lev) const
Definition: ERF_MOSTAverage.H:313
void set_time_avg_initialized(const int &lev)
Definition: ERF_MOSTAverage.H:273
int get_navg() const
Definition: ERF_MOSTAverage.H:254
const amrex::MultiFab * get_average(const int &lev, const int &comp) const
Definition: ERF_MOSTAverage.H:235
void update_field_ptrs(const int &lev, amrex::Vector< amrex::Vector< amrex::MultiFab >> &vars_old, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &Theta_prim, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &Qv_prim, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &Qr_prim)
Definition: ERF_MOSTAverage.cpp:308
void make_MOSTAverage_at_level(const int &lev, const amrex::Vector< amrex::MultiFab * > &vars_old, std::unique_ptr< amrex::MultiFab > &Theta_prim, std::unique_ptr< amrex::MultiFab > &Qv_prim, std::unique_ptr< amrex::MultiFab > &Qr_prim, std::unique_ptr< amrex::MultiFab > &z_phys_nd)
Definition: ERF_MOSTAverage.cpp:111
bool time_avg_is_initialized(const int &lev) const
Definition: ERF_MOSTAverage.H:262
Definition: ERF_SurfaceLayer.H:39
ThetaCalcType theta_type
Definition: ERF_SurfaceLayer.H:1237
int lmask_min_reduce(amrex::iMultiFab &lmask, const int &nghost)
Definition: ERF_SurfaceLayer.H:1124
amrex::Vector< std::string > m_lsm_data_name
Definition: ERF_SurfaceLayer.H:1334
bool m_include_wstar
Definition: ERF_SurfaceLayer.H:1251
amrex::Real interpolate_sfc_column(const amrex::Real &time, int col) const
Definition: ERF_SurfaceLayer.cpp:324
bool specified_rho_surf
Definition: ERF_SurfaceLayer.H:1269
void set_q_surf(const int &lev, const amrex::Real qsurf)
Definition: ERF_SurfaceLayer.H:1083
void update_fluxes(const int &lev, const double &elapsed_time, const double &elapsed_time_since_start_low, amrex::MultiFab &cons_in, const std::unique_ptr< amrex::MultiFab > &z_phys_nd, const std::unique_ptr< amrex::MultiFab > &walldist, int max_iters=100)
Definition: ERF_SurfaceLayer.cpp:18
bool m_rotate
Definition: ERF_SurfaceLayer.H:1246
amrex::Real sfc_tflux
Definition: ERF_SurfaceLayer.H:1290
PBLHeightCalcType pblh_type
Definition: ERF_SurfaceLayer.H:1241
amrex::Vector< amrex::Vector< amrex::iMultiFab * > > m_lmask_lev
Definition: ERF_SurfaceLayer.H:1322
double m_final_low_time
Definition: ERF_SurfaceLayer.H:1248
void fill_tsurf_with_sfc_sst(const int &lev, const double &time)
Definition: ERF_SurfaceLayer.cpp:1302
amrex::iMultiFab * get_lmask(const int &lev)
Definition: ERF_SurfaceLayer.H:1116
bool use_moisture
Definition: ERF_SurfaceLayer.H:1279
amrex::MultiFab * get_q_surf(const int &lev)
Definition: ERF_SurfaceLayer.H:1075
bool m_has_lsm_tsurf
Definition: ERF_SurfaceLayer.H:1281
amrex::MultiFab * get_w_star(const int &lev)
Definition: ERF_SurfaceLayer.H:953
amrex::Real m_Cq
Definition: ERF_SurfaceLayer.H:1300
amrex::Vector< const eb_ * > m_eb_vec
Definition: ERF_SurfaceLayer.H:1304
RoughCalcType rough_type_land
Definition: ERF_SurfaceLayer.H:1239
void update_pblh(const int &lev, amrex::Vector< amrex::Vector< amrex::MultiFab >> &vars, amrex::MultiFab *z_phys_cc, const MoistureComponentIndices &moisture_indices)
Definition: ERF_SurfaceLayer.cpp:1495
amrex::Real sfc_qflux
Definition: ERF_SurfaceLayer.H:1289
amrex::Vector< std::unique_ptr< amrex::MultiFab > > t_surf
Definition: ERF_SurfaceLayer.H:1313
bool m_use_sfc_fluxes
Definition: ERF_SurfaceLayer.H:1285
amrex::Real z0_const
Definition: ERF_SurfaceLayer.H:1252
amrex::Vector< std::unique_ptr< amrex::MultiFab > > surface_diagnostic_source
Definition: ERF_SurfaceLayer.H:1318
amrex::Real cnk_a
Definition: ERF_SurfaceLayer.H:1270
amrex::Real m_Ch
Definition: ERF_SurfaceLayer.H:1299
amrex::Real surf_temp
Definition: ERF_SurfaceLayer.H:1259
void update_mac_ptrs(const int &lev, amrex::Vector< amrex::Vector< amrex::MultiFab >> &vars_old, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &Theta_prim, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &Qv_prim, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &Qr_prim)
Definition: ERF_SurfaceLayer.H:932
void compute_pblh(const int &lev, amrex::Vector< amrex::Vector< amrex::MultiFab >> &vars, amrex::MultiFab *z_phys_cc, const PBLHeightEstimator &est, const MoistureComponentIndices &moisture_indice)
amrex::Vector< std::unique_ptr< amrex::MultiFab > > q_star
Definition: ERF_SurfaceLayer.H:1310
int m_lsm_tsurf_indx
Definition: ERF_SurfaceLayer.H:1282
double m_start_low_time
Definition: ERF_SurfaceLayer.H:1247
bool mac_avg_is_initialized(const int &lev) const
Definition: ERF_SurfaceLayer.H:1021
bool mac_avg_is_time_averaged() const
Definition: ERF_SurfaceLayer.H:1009
amrex::Real rico_qsat_z0
Definition: ERF_SurfaceLayer.H:1277
bool m_has_lsm_fluxes
Definition: ERF_SurfaceLayer.H:1280
bool m_update_k_rans
Definition: ERF_SurfaceLayer.H:1340
amrex::Vector< amrex::MultiFab * > m_Lwave_lev
Definition: ERF_SurfaceLayer.H:1337
void get_lsm_tsurf(const int &lev)
Definition: ERF_SurfaceLayer.cpp:1387
void fill_qsurf_with_qsat(const int &lev, const amrex::MultiFab &cons_in, const std::unique_ptr< amrex::MultiFab > &z_phys_nd)
Definition: ERF_SurfaceLayer.cpp:1339
amrex::Real get_zref(const int &lev)
Definition: ERF_SurfaceLayer.H:1097
amrex::MultiFab * get_olen(const int &lev)
Definition: ERF_SurfaceLayer.H:986
bool computes_w_star() const
Definition: ERF_SurfaceLayer.H:959
amrex::Vector< amrex::MultiFab > z_0
Definition: ERF_SurfaceLayer.H:1273
amrex::Real surf_moist_flux
Definition: ERF_SurfaceLayer.H:1264
void compute_SurfaceLayer_bcs(const int &lev, amrex::Vector< const amrex::MultiFab * > mfs, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &Tau_lev, amrex::MultiFab *xheat_flux, amrex::MultiFab *yheat_flux, amrex::MultiFab *zheat_flux, amrex::MultiFab *xqv_flux, amrex::MultiFab *yqv_flux, amrex::MultiFab *zqv_flux, const amrex::MultiFab *z_phys, const FluxCalc &flux_comp)
RoughCalcType rough_type_sea
Definition: ERF_SurfaceLayer.H:1240
void update_coupled_sst_ptr(const int lev, amrex::MultiFab *sst_ptr, amrex::iMultiFab *valid_ptr)
Definition: ERF_SurfaceLayer.H:1178
void init_tke_from_ustar(const int &lev, amrex::MultiFab &cons, const std::unique_ptr< amrex::MultiFab > &z_phys_nd, const amrex::Real tkefac=one, const amrex::Real zscale=amrex::Real(700.0))
Definition: ERF_SurfaceLayer.cpp:1540
amrex::Real surf_moist
Definition: ERF_SurfaceLayer.H:1263
amrex::Vector< std::unique_ptr< amrex::MultiFab > > w_star
Definition: ERF_SurfaceLayer.H:1308
bool m_ignore_sst
Definition: ERF_SurfaceLayer.H:1302
int get_num_mac_avg() const
Definition: ERF_SurfaceLayer.H:1014
amrex::Vector< amrex::Vector< amrex::Real > > sfc
Definition: ERF_SurfaceLayer.H:1288
amrex::MultiFab * get_u_star(const int &lev)
Definition: ERF_SurfaceLayer.H:946
double m_low_time_interval
Definition: ERF_SurfaceLayer.H:1249
void compute_fluxes(const int &lev, const int &max_iters, amrex::MultiFab &cons_in, const FluxIter &most_flux, bool is_land)
bool set_mac_plane_avg(const int &lev, const amrex::Vector< amrex::Real > &pavg)
Definition: ERF_SurfaceLayer.H:1053
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_lsm_data_lev
Definition: ERF_SurfaceLayer.H:1332
void set_t_surf(const int &lev, const amrex::Real tsurf)
Definition: ERF_SurfaceLayer.H:1068
amrex::Real custom_qstar
Definition: ERF_SurfaceLayer.H:1267
amrex::Vector< std::unique_ptr< amrex::MultiFab > > u_star
Definition: ERF_SurfaceLayer.H:1307
void update_tsk_ptr(const int lev, const int itime, amrex::MultiFab *tsk_ptr)
Definition: ERF_SurfaceLayer.H:1162
amrex::Real custom_rhosurf
Definition: ERF_SurfaceLayer.H:1268
amrex::Vector< std::unique_ptr< amrex::MultiFab > > q_surf
Definition: ERF_SurfaceLayer.H:1314
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_sst_lev
Definition: ERF_SurfaceLayer.H:1320
FluxCalcType
Definition: ERF_SurfaceLayer.H:1205
@ MOENG
Moeng functional form.
@ BULK_COEFF
Bulk transfer coefficient functional form.
@ CUSTOM
Custom constant flux functional form.
@ ROTATE
Terrain rotation flux functional form.
@ DONELAN
Donelan functional form.
MoistCalcType
Definition: ERF_SurfaceLayer.H:1220
@ SURFACE_MOISTURE
Surface Qv specified.
@ MOISTURE_FLUX
Qv-flux specified.
amrex::Real depth
Definition: ERF_SurfaceLayer.H:1272
amrex::Vector< amrex::MultiFab * > m_coupled_sst_lev
Definition: ERF_SurfaceLayer.H:1330
amrex::Vector< amrex::MultiFab * > m_Hwave_lev
Definition: ERF_SurfaceLayer.H:1336
amrex::Real default_land_surf_moist
Definition: ERF_SurfaceLayer.H:1262
void update_sfc_time_index(const amrex::Real &time)
Definition: ERF_SurfaceLayer.cpp:307
bool m_var_z0
Definition: ERF_SurfaceLayer.H:1274
amrex::Vector< amrex::iMultiFab * > m_coupled_sst_valid_lev
Definition: ERF_SurfaceLayer.H:1331
amrex::MultiFab * get_surface_diagnostic_source(const int &lev)
Definition: ERF_SurfaceLayer.H:1090
amrex::MultiFab * get_t_star(const int &lev)
Definition: ERF_SurfaceLayer.H:972
bool have_variable_sea_roughness()
Definition: ERF_SurfaceLayer.H:1109
void impose_SurfaceLayer_bcs_EB(const int &lev, amrex::Vector< const amrex::MultiFab * > mfs, amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab >>> &Tau_lev, amrex::MultiFab *xheat_flux, amrex::MultiFab *yheat_flux, amrex::MultiFab *zheat_flux, amrex::MultiFab *xqv_flux, amrex::MultiFab *yqv_flux, amrex::MultiFab *zqv_flux)
Definition: ERF_SurfaceLayer.cpp:547
amrex::MultiFab * get_q_star(const int &lev)
Definition: ERF_SurfaceLayer.H:979
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_lsm_flux_lev
Definition: ERF_SurfaceLayer.H:1333
amrex::MultiFab * get_mac_avg_ptr(const int &lev, int comp)
Definition: ERF_SurfaceLayer.H:1036
amrex::Vector< amrex::Real > get_mac_plane_avg(const int &lev) const
Definition: ERF_SurfaceLayer.H:1044
PBLHeightCalcType
Definition: ERF_SurfaceLayer.H:1234
amrex::MultiFab * get_pblh(const int &lev)
Definition: ERF_SurfaceLayer.H:993
void compute_SurfaceLayer_bcs_EB(const int &lev, amrex::Vector< const amrex::MultiFab * > mfs, amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab >>> &Tau_lev, amrex::MultiFab *xheat_flux, amrex::MultiFab *yheat_flux, amrex::MultiFab *zheat_flux, amrex::MultiFab *xqv_flux, amrex::MultiFab *yqv_flux, amrex::MultiFab *zqv_flux, const FluxCalc &flux_comp)
amrex::Real rico_theta_z0
Definition: ERF_SurfaceLayer.H:1276
amrex::Real sfc_ustar
Definition: ERF_SurfaceLayer.H:1291
amrex::Real surf_temp_flux
Definition: ERF_SurfaceLayer.H:1261
amrex::Vector< amrex::Geometry > m_geom
Definition: ERF_SurfaceLayer.H:1245
amrex::Vector< std::unique_ptr< amrex::MultiFab > > t_star
Definition: ERF_SurfaceLayer.H:1309
int sfc_time_ind
Definition: ERF_SurfaceLayer.H:1287
bool computes_pblh() const
Definition: ERF_SurfaceLayer.H:965
amrex::Real theta_ref
Definition: ERF_SurfaceLayer.H:1342
amrex::MultiFab * get_z0(const int &lev)
Definition: ERF_SurfaceLayer.H:1104
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_tsk_lev
Definition: ERF_SurfaceLayer.H:1321
void update_surf_temp(const double &time)
Definition: ERF_SurfaceLayer.H:903
void set_coupled_sst_active(const bool active)
Definition: ERF_SurfaceLayer.H:1193
void fill_tsurf_with_sst_and_tsk(const int &lev, const double &time)
Definition: ERF_SurfaceLayer.cpp:1215
amrex::Real custom_tstar
Definition: ERF_SurfaceLayer.H:1266
static amrex::Vector< amrex::Vector< amrex::Real > > read_cols(const std::string &fname, const int skip_nlines=1)
Definition: ERF_SurfaceLayer.cpp:1743
bool cnk_visc
Definition: ERF_SurfaceLayer.H:1271
amrex::Real surf_heating_rate
Definition: ERF_SurfaceLayer.H:1260
void make_SurfaceLayer_at_level(const int &lev, int nlevs, const amrex::Vector< amrex::MultiFab * > &mfv, std::unique_ptr< amrex::MultiFab > &Theta_prim, std::unique_ptr< amrex::MultiFab > &Qv_prim, std::unique_ptr< amrex::MultiFab > &Qr_prim, std::unique_ptr< amrex::MultiFab > &z_phys_nd, amrex::MultiFab *Hwave, amrex::MultiFab *Lwave, amrex::MultiFab *eddyDiffs, amrex::Vector< amrex::MultiFab * > lsm_data, amrex::Vector< std::string > lsm_data_name, amrex::Vector< amrex::MultiFab * > lsm_flux, amrex::Vector< std::string > lsm_flux_name, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &sst_lev, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &tsk_lev, amrex::Vector< std::unique_ptr< amrex::iMultiFab >> &lmask_lev)
Definition: ERF_SurfaceLayer.H:334
RoughCalcType
Definition: ERF_SurfaceLayer.H:1226
FluxCalcType flux_type
Definition: ERF_SurfaceLayer.H:1236
MoistCalcType moist_type
Definition: ERF_SurfaceLayer.H:1238
void fill_tsurf_with_coupled_sst(const int &lev)
Definition: ERF_SurfaceLayer.cpp:1427
bool m_use_sfc_sst
Definition: ERF_SurfaceLayer.H:1286
void compute_sfc_params_from_lsm_fluxes(const int &lev, amrex::MultiFab &cons_in)
Definition: ERF_SurfaceLayer.cpp:1142
SurfaceLayer(const amrex::Vector< amrex::Geometry > &geom, bool &use_rot_surface_flux, std::string a_pp_prefix, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &Qv_prim, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &z_phys_nd, const MeshType &a_mesh_type, const TerrainType &a_terrain_type, const TurbChoice &a_turb_choice, double start_low_time, double final_low_time, double low_time_interval=0.0, const amrex::Vector< const eb_ * > &eb_vec={})
Definition: ERF_SurfaceLayer.H:58
amrex::Real inv_Cmu2
Definition: ERF_SurfaceLayer.H:1341
void impose_SurfaceLayer_bcs(const int &lev, amrex::Vector< const amrex::MultiFab * > mfs, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &Tau_lev, amrex::MultiFab *xheat_flux, amrex::MultiFab *yheat_flux, amrex::MultiFab *zheat_flux, amrex::MultiFab *xqv_flux, amrex::MultiFab *yqv_flux, amrex::MultiFab *zqv_flux, const amrex::MultiFab *z_phys)
Definition: ERF_SurfaceLayer.cpp:480
amrex::Vector< amrex::MultiFab * > m_eddyDiffs_lev
Definition: ERF_SurfaceLayer.H:1338
const amrex::MultiFab * get_mac_avg(const int &lev, int comp)
Definition: ERF_SurfaceLayer.H:1001
void update_sst_ptr(const int lev, const int itime, amrex::MultiFab *sst_ptr)
Definition: ERF_SurfaceLayer.H:1151
amrex::Real custom_ustar
Definition: ERF_SurfaceLayer.H:1265
amrex::Vector< std::unique_ptr< amrex::MultiFab > > olen
Definition: ERF_SurfaceLayer.H:1311
bool m_use_coupled_sst
Definition: ERF_SurfaceLayer.H:1296
amrex::MultiFab * get_t_surf(const int &lev)
Definition: ERF_SurfaceLayer.H:1060
amrex::Real m_Cd
Definition: ERF_SurfaceLayer.H:1298
void set_mac_avg_initialized(const int &lev)
Definition: ERF_SurfaceLayer.H:1028
amrex::Vector< std::unique_ptr< amrex::MultiFab > > pblh
Definition: ERF_SurfaceLayer.H:1312
amrex::Real default_land_surf_temp
Definition: ERF_SurfaceLayer.H:1253
ThetaCalcType
Definition: ERF_SurfaceLayer.H:1214
@ SURFACE_TEMPERATURE
Surface temperature specified.
@ HEAT_FLUX
Heat-flux specified.
void read_custom_roughness(const int &lev, const std::string &fname)
Definition: ERF_SurfaceLayer.cpp:1615
TerrainType m_terrain_type
Definition: ERF_SurfaceLayer.H:1305
amrex::Vector< std::string > m_lsm_flux_name
Definition: ERF_SurfaceLayer.H:1335
MOSTAverage m_ma
Definition: ERF_SurfaceLayer.H:1306
@ ng
Definition: ERF_Morrison.H:49
@ cons
Definition: ERF_IndexDefines.H:214
real(c_double), parameter epsilon
Definition: ERF_module_model_constants.F90:12
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real to_plot_value(SurfaceDiagnosticSource source) noexcept
Definition: ERF_SurfaceDiagnosticSource.H:45
The moisture data carried by the active microphysics scheme.
Definition: ERF_DataStruct.H:195
Definition: ERF_TurbStruct.H:114
RANSType rans_type
Selected RANS closure.
Definition: ERF_TurbStruct.H:604
amrex::Real theta_ref
Reference potential temperature for stable stratification.
Definition: ERF_TurbStruct.H:593
bool dirichlet_k
Whether TKE uses Dirichlet boundary treatment.
Definition: ERF_TurbStruct.H:606
amrex::Real Cmu0
One-equation RANS Cmu0 coefficient.
Definition: ERF_TurbStruct.H:582