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 "AMReX_Geometry.H"
5 #include "AMReX_ParmParse.H"
6 #include "AMReX_FArrayBox.H"
7 #include "AMReX_MultiFab.H"
8 #include "AMReX_iMultiFab.H"
9 #include "AMReX_MFInterpolater.H"
10 
11 #include "ERF_IndexDefines.H"
12 #include "ERF_Constants.H"
13 #include "ERF_MOSTAverage.H"
14 #include "ERF_MOSTStress.H"
15 #include "ERF_EBMOSTStress.H"
17 #include "ERF_TerrainMetrics.H"
18 #include "ERF_PBLHeight.H"
19 #include "ERF_MicrophysicsUtils.H"
20 #include "ERF_EB.H"
21 
22 /** Abstraction layer for different surface layer schemes (e.g. MOST, Cd)
23  *
24  * van der Laan, P., Kelly, M. C., & Sørensen, N. N. (2017). A new k-epsilon
25  * model consistent with Monin-Obukhov similarity theory. Wind Energy,
26  * 20(3), 479–amrex::Real(489.) https://doi.org/amrex::Real(10.1002)/we.2017
27  *
28  * Consistent with Dyer (1974) formulation from page 57, Chapter 2, Modeling
29  * the vertical ABL structure in Modelling of Atmospheric Flow Fields,
30  * Demetri P Lalas and Corrado F Ratto, January 1996,
31  * https://doi.org/amrex::Real(10.1142)/amrex::Real(2975.)
32  */
34 {
35 
36 public:
37  /**
38  * Construct the surface-layer interface.
39  *
40  * @param[in] geom geometry for all AMR levels
41  * @param[in,out] use_rot_surface_flux whether to use rotated surface fluxes
42  * @param[in] a_pp_prefix ParmParse prefix used by MOST averages
43  * @param[in] Qv_prim primitive water-vapor fields by level
44  * @param[in] z_phys_nd nodal physical-height fields by level
45  * @param[in] a_mesh_type mesh type
46  * @param[in] a_terrain_type terrain representation
47  * @param[in] a_turb_choice turbulence-model options
48  * @param[in] start_low_time first available low-boundary-data time
49  * @param[in] final_low_time final available low-boundary-data time
50  * @param[in] low_time_interval low-boundary-data time interval
51  * @param[in] eb_vec optional embedded-boundary geometry data
52  */
53  explicit SurfaceLayer (const amrex::Vector<amrex::Geometry>& geom,
54  bool& use_rot_surface_flux,
55  std::string a_pp_prefix,
56  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Qv_prim,
57  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& z_phys_nd,
58  const MeshType& a_mesh_type,
59  const TerrainType& a_terrain_type,
60  const TurbChoice& a_turb_choice,
61  double start_low_time,
62  double final_low_time,
63  double low_time_interval = 0.0,
64  const amrex::Vector<const eb_*>& eb_vec = {})
65  : m_geom(geom),
66  m_rotate(use_rot_surface_flux),
67  m_start_low_time(start_low_time),
68  m_final_low_time(final_low_time),
69  m_low_time_interval(low_time_interval),
70  m_eb_vec(eb_vec),
71  m_terrain_type(a_terrain_type),
72  m_ma(geom, (z_phys_nd[0] != nullptr), a_pp_prefix, a_mesh_type, a_terrain_type, eb_vec)
73  {
74  // We have a moisture model if Qv_prim is a valid pointer
75  use_moisture = (Qv_prim[0].get());
76 
77  // Get roughness
78  amrex::ParmParse pp("erf");
79  pp.query("most.z0", z0_const);
80 
81  // Specify how to compute the flux
82  if (use_rot_surface_flux) {
84  } else {
85  std::string flux_string_in;
86  std::string flux_string{"moeng"};
87  auto read_flux = pp.query("surface_layer.flux_type", flux_string_in);
88  if (read_flux) {
89  flux_string = amrex::toLower(flux_string_in);
90  }
91  if (flux_string == "donelan") {
93  } else if (flux_string == "moeng") {
95  } else if (flux_string == "rico") {
97  } else if (flux_string == "bulk_coeff") {
99  } else if (flux_string == "custom") {
101  } else {
102  amrex::Abort("Undefined MOST flux type!");
103  }
104  }
105 
106  // Include w* to handle free convection (Beljaars 1995, QJRMS)
107  pp.query("most.include_wstar", m_include_wstar);
108 
109  std::string pblh_string_in;
110  std::string pblh_string{"none"};
111  auto read_pblh = pp.query("most.pblh_calc", pblh_string_in);
112  if (read_pblh) {
113  pblh_string = amrex::toLower(pblh_string_in);
114  }
115  if (pblh_string == "none") {
117  } else if (pblh_string == "mynn25") {
119  } else if (pblh_string == "mynnedmf") {
121  } else if (pblh_string == "ysu") {
123  } else if (pblh_string == "mrf") {
125  } else {
126  amrex::Abort("Undefined PBLH calc type!");
127  }
128 
129  // Get surface temperature
130  auto erf_st = pp.query("most.surf_temp", surf_temp);
131  if (erf_st) { default_land_surf_temp = surf_temp; }
132 
133  // Get surface moisture
134  bool erf_sq = false;
135  if (use_moisture) { erf_sq = pp.query("most.surf_moist", surf_moist); }
136  if (erf_sq) { default_land_surf_moist = surf_moist; }
137 
138  // Custom type user must specify the fluxes
143  pp.get("most.ustar", custom_ustar);
144  pp.get("most.tstar", custom_tstar);
145  pp.get("most.qstar", custom_qstar);
146  pp.query("most.rhosurf", custom_rhosurf);
147  if (custom_qstar != 0) {
149  "Specified custom MOST qv flux without moisture model!");
150  }
151  amrex::Print() << "Using specified ustar, tstar, qstar for MOST = "
152  << custom_ustar << " " << custom_tstar << " "
153  << custom_qstar << std::endl;
154 
155  // Bulk transfer coefficient (must specify coeffs and surface values)
156  } else if (flux_type == FluxCalcType::BULK_COEFF) {
157  pp.get("most.Cd", m_Cd);
158  pp.get("most.Ch", m_Ch);
159  pp.get("most.Cq", m_Cq);
160  pp.get("most.surf_temp", default_land_surf_temp);
161  pp.get("most.surf_moist", default_land_surf_moist);
162  amrex::Print() << "Using specified Cd, Ch, Cq for MOST = "
163  << m_Cd << " " << m_Ch << " "
164  << m_Cq << std::endl;
165 
166  // Specify surface temperature/moisture or surface flux
167  } else {
168  if (erf_st) {
170  pp.query("most.surf_heating_rate", surf_heating_rate); // [K/h]
171 
172  // Modify rate to be in units of K / s rather than K / hr
173  surf_heating_rate /= amrex::Real(3600.0); // [K/s]
174 
175  if (pp.query("most.surf_temp_flux", surf_temp_flux)) {
176  amrex::Abort("Can only specify one of surf_temp_flux or surf_heating_rate");
177  }
178  } else {
179  pp.query("most.surf_temp_flux", surf_temp_flux);
180 
181  if (pp.query("most.surf_heating_rate", surf_heating_rate)) {
182  amrex::Abort("Can only specify one of surf_temp_flux or surf_heating_rate");
183  }
184  if (std::abs(surf_temp_flux) >
187  } else {
189  }
190  }
191 
192  if (erf_sq) {
194  } else {
195  pp.query("most.surf_moist_flux", surf_moist_flux);
196  if (std::abs(surf_moist_flux) >
199  } else {
201  }
202  }
203  }
204 
206  {
207  pp.query("most.rico.theta_z0", rico_theta_z0);
208  pp.query("most.rico.qsat_z0", rico_qsat_z0);
209  }
210 
211  // Make sure the inputs file doesn't try to use most.roughness_type
212  std::string bogus_input;
213  if (pp.query("most.roughness_type", bogus_input) > 0) {
214  amrex::Abort("most.roughness_type is deprecated; use "
215  "most.roughness_type_land and/or most.roughness_type_sea");
216  }
217 
218  // Specify how to compute the surface flux over land (if there is any)
219  std::string rough_land_string_in;
220  std::string rough_land_string{"constant"};
221  auto read_rough_land =
222  pp.query("most.roughness_type_land", rough_land_string_in);
223  if (read_rough_land) {
224  rough_land_string = amrex::toLower(rough_land_string_in);
225  }
226  if (rough_land_string == "constant") {
228  } else {
229  amrex::Abort("Undefined MOST roughness type for land!");
230  }
231 
232  // Specify how to compute the surface flux over sea (if there is any)
233  std::string rough_sea_string_in;
234  std::string rough_sea_string{"charnock"};
235  auto read_rough_sea = pp.query("most.roughness_type_sea", rough_sea_string_in);
236  if (read_rough_sea) {
237  rough_sea_string = amrex::toLower(rough_sea_string_in);
238  }
239  if (rough_sea_string == "charnock") {
241  pp.query("most.charnock_constant", cnk_a);
242  pp.query("most.charnock_viscosity", cnk_visc);
243  if (cnk_a > 0) {
244  amrex::Print() << "If there is water, Charnock relation with C_a="
245  << cnk_a << (cnk_visc ? " and viscosity" : "")
246  << " will be used" << std::endl;
247  } else {
248  amrex::Print() << "If there is water, Charnock relation with variable "
249  "Charnock parameter (COARE3.0)"
250  << (cnk_visc ? " and viscosity" : "") << " will be used"
251  << std::endl;
252  }
253  } else if (rough_sea_string == "coare3.0") {
255  amrex::Print() << "If there is water, Charnock relation with variable "
256  "Charnock parameter (COARE3.0)"
257  << (cnk_visc ? " and viscosity" : "") << " will be used"
258  << std::endl;
259  cnk_a = -1;
260  } else if (rough_sea_string == "donelan") {
262  } else if (rough_sea_string == "modified_charnock") {
264  pp.query("most.modified_charnock_depth", depth);
265  } else if (rough_sea_string == "wave_coupled") {
267  } else if (rough_sea_string == "constant") {
269  } else {
270  amrex::Abort("Undefined MOST roughness type for sea!");
271  }
272 
273  // use skin temperature instead of sea-surface temperature
274  // (wrfinput data may have lower resolution SST data)
275  pp.query("most.ignore_sst", m_ignore_sst);
276 
277  // If we're using the RANS k model, then we need to update the dirichlet
278  // BC based on the instantaneous u* and θ*; the turbulence modeling
279  // choices can vary per level but for now, assume that if specified then
280  // all levels are using the same RANS model.
281  m_update_k_rans = (a_turb_choice.rans_type == RANSType::kEqn &&
282  a_turb_choice.dirichlet_k == true);
283  if (m_update_k_rans) {
284  inv_Cmu2 = one / (a_turb_choice.Cmu0 * a_turb_choice.Cmu0);
285  theta_ref = a_turb_choice.theta_ref;
286  }
287 
288  } // constructor
289 
290  /**
291  * Allocate and initialize surface-layer data for one AMR level.
292  *
293  * @param[in] lev level index
294  * @param[in] nlevs number of AMR levels
295  * @param[in] mfv conserved and velocity MultiFabs for this level
296  * @param[in] Theta_prim primitive potential-temperature field
297  * @param[in] Qv_prim primitive water-vapor field
298  * @param[in] Qr_prim primitive rain-water field
299  * @param[in] z_phys_nd nodal physical-height field
300  * @param[in] Hwave wave-height field
301  * @param[in] Lwave wavelength field
302  * @param[in] eddyDiffs eddy-diffusivity field
303  * @param[in] lsm_data land-surface-model data fields
304  * @param[in] lsm_data_name names for lsm_data entries
305  * @param[in] lsm_flux land-surface-model flux fields
306  * @param[in] lsm_flux_name names for lsm_flux entries
307  * @param[in] sst_lev sea-surface-temperature data by time
308  * @param[in] tsk_lev skin-temperature data by time
309  * @param[in] lmask_lev land-mask data by time
310  */
311  void make_SurfaceLayer_at_level (const int& lev,
312  int nlevs,
313  const amrex::Vector<amrex::MultiFab*>& mfv,
314  std::unique_ptr<amrex::MultiFab>& Theta_prim,
315  std::unique_ptr<amrex::MultiFab>& Qv_prim,
316  std::unique_ptr<amrex::MultiFab>& Qr_prim,
317  std::unique_ptr<amrex::MultiFab>& z_phys_nd,
318  amrex::MultiFab* Hwave,
319  amrex::MultiFab* Lwave,
320  amrex::MultiFab* eddyDiffs,
321  amrex::Vector<amrex::MultiFab*> lsm_data,
322  amrex::Vector<std::string> lsm_data_name,
323  amrex::Vector<amrex::MultiFab*> lsm_flux,
324  amrex::Vector<std::string> lsm_flux_name,
325  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& sst_lev,
326  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& tsk_lev,
327  amrex::Vector<std::unique_ptr<amrex::iMultiFab>>& lmask_lev)
328  {
329  // Update MOST Average
331  Theta_prim, Qv_prim, Qr_prim,
332  z_phys_nd);
333 
334  // Get CC vars
335  amrex::MultiFab& mf = *(mfv[0]);
336 
337  amrex::ParmParse pp("erf");
338 
339  // Do we have a time-varying surface roughness that needs to be saved?
340  if (lev == 0) {
341  const int nghost = 0; // ghost cells not included
342  int lmask_min = lmask_min_reduce(*lmask_lev[0].get(), nghost);
343  amrex::ParallelDescriptor::ReduceIntMin(lmask_min);
344 
345  m_var_z0 = (lmask_min < 1) & (rough_type_sea != RoughCalcType::CONSTANT);
346  if (m_var_z0) {
347  std::string rough_sea_string{"charnock"};
348  pp.query("most.roughness_type_sea", rough_sea_string);
349  amrex::Print() << "Variable sea roughness (type " << rough_sea_string
350  << ")" << std::endl;
351  }
352  }
353 
354  if (m_eddyDiffs_lev.size() < lev+1) {
355  m_Hwave_lev.resize(nlevs);
356  m_Lwave_lev.resize(nlevs);
357  m_eddyDiffs_lev.resize(nlevs);
358 
359  m_lsm_data_lev.resize(nlevs);
360  m_lsm_flux_lev.resize(nlevs);
361 
362  m_sst_lev.resize(nlevs);
363  m_tsk_lev.resize(nlevs);
364  m_lmask_lev.resize(nlevs);
365 
366  // Size the MOST params for all levels
367  z_0.resize(nlevs);
368  u_star.resize(nlevs);
369  w_star.resize(nlevs);
370  t_star.resize(nlevs);
371  q_star.resize(nlevs);
372  t_surf.resize(nlevs);
373  q_surf.resize(nlevs);
374  surface_diagnostic_source.resize(nlevs);
375  olen.resize(nlevs);
376  pblh.resize(nlevs);
377  }
378 
379  // Get pointers to SST,TSK and LANDMASK data
380  int nt_tot_sst = sst_lev.size();
381  m_sst_lev[lev].resize(nt_tot_sst);
382  for (int nt(0); nt < nt_tot_sst; ++nt) {
383  m_sst_lev[lev][nt] = sst_lev[nt].get();
384  }
385  int nt_tot_tsk = static_cast<int>(tsk_lev.size());
386  m_tsk_lev[lev].resize(nt_tot_tsk);
387  for (int nt(0); nt < nt_tot_tsk; ++nt) {
388  m_tsk_lev[lev][nt] = tsk_lev[nt].get();
389  }
390  int nt_tot_lmask = static_cast<int>(lmask_lev.size());
391  m_lmask_lev[lev].resize(nt_tot_lmask);
392  for (int nt(0); nt < nt_tot_lmask; ++nt) {
393  m_lmask_lev[lev][nt] = lmask_lev[nt].get();
394  }
395 
396  // Get pointers to wave data
397  m_Hwave_lev[lev] = Hwave;
398  m_Lwave_lev[lev] = Lwave;
399  m_eddyDiffs_lev[lev] = eddyDiffs;
400 
401  // Get pointers to LSM data and Fluxes
402  int ndata = static_cast<int>(lsm_data.size());
403  int nflux = static_cast<int>(lsm_flux.size());
404  m_lsm_data_name.resize(ndata);
405  m_lsm_data_lev[lev].resize(ndata);
406  m_lsm_flux_name.resize(nflux);
407  m_lsm_flux_lev[lev].resize(nflux);
408  for (int n(0); n < ndata; ++n) {
409  m_lsm_data_name[n] = lsm_data_name[n];
410  m_lsm_data_lev[lev][n] = lsm_data[n];
411  const std::string lc_name = amrex::toLower(lsm_data_name[n]);
412  if (lc_name == "theta" || lc_name == "t_surf") {
413  m_has_lsm_tsurf = true;
414  m_lsm_tsurf_indx = n;
415  m_has_ocean_lsm_tsurf = (lc_name == "t_surf");
416  }
417  }
418  int n_valid_lsm_flux = 0;
419  bool has_soil_t_flux = false;
420  for (int n(0); n < nflux; ++n) {
421  m_lsm_flux_name[n] = lsm_flux_name[n];
422  m_lsm_flux_lev[lev][n] = lsm_flux[n];
423  if (m_lsm_flux_lev[lev][n]) { ++n_valid_lsm_flux; }
424  if (amrex::toLower(m_lsm_flux_name[n]) == "soil_t_flux") {
425  has_soil_t_flux = true;
426  }
427  }
428  AMREX_ALWAYS_ASSERT((n_valid_lsm_flux==0 || n_valid_lsm_flux>=4 ||
429  (n_valid_lsm_flux==1 && has_soil_t_flux)));
430  if (n_valid_lsm_flux>=4) { m_has_lsm_fluxes = true; }
431 
432  // Check if there is a user-specified roughness file to be read
433  std::string fname;
434  bool read_z0 = false;
435  if ( (flux_type == FluxCalcType::MOENG) ||
437  int count = pp.countval("most.roughness_file_name");
438  if (count > 1) {
439  AMREX_ALWAYS_ASSERT(count >= lev+1);
440  pp.query("most.roughness_file_name", fname, lev);
441  read_z0 = true;
442  } else if (count == 1) {
443  if (lev == 0) {
444  pp.query("most.roughness_file_name", fname);
445  } else {
446  // we will interpolate from the coarsest level
447  fname = "";
448  }
449  read_z0 = true;
450  }
451  // else use z0_const
452  }
453 
454  // Attributes for MFs and FABs
455  //--------------------------------------------------------
456  // Create a 2D ba for planar terrain, 3D for EB terrain
457  amrex::BoxArray ba = mf.boxArray();
458  amrex::BoxArray ba_flux;
459  amrex::IntVect ng{1,1,0};
460 
461  if (m_terrain_type == TerrainType::EB) {
462  // Use full 3D BoxArray for EB terrain
463  ba_flux = ba;
464  ng = amrex::IntVect{1,1,1}; // Include z ghost cells
465  } else {
466  // Collapse to 2D for planar terrain
467  amrex::BoxList bl2d = ba.boxList();
468  for (auto& b : bl2d) { b.setRange(2,0); }
469  ba_flux = amrex::BoxArray(std::move(bl2d));
470  }
471 
472  const amrex::DistributionMapping& dm = mf.DistributionMap();
473  const int ncomp = 1;
474 
475  // Z0 heights FAB
476  //--------------------------------------------------------
477  z_0[lev].define(ba_flux, dm, ncomp, ng);
478  z_0[lev].setVal(z0_const);
479  if (read_z0) {
480  read_custom_roughness(lev, fname);
481  }
482 
483  // 2D MFs for U*, T*, T_surf
484  //--------------------------------------------------------
485  u_star[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
486  u_star[lev]->setVal(bogus_large_value);
487 
488  w_star[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
489  w_star[lev]->setVal(bogus_large_value);
490 
491  t_star[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
492  t_star[lev]->setVal(zero); // default to neutral
493 
494  q_star[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
495  q_star[lev]->setVal(zero); // default to dry
496 
497  olen[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
498  olen[lev]->setVal(bogus_large_value);
499 
500  pblh[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
501  pblh[lev]->setVal(bogus_large_value);
502 
503  t_surf[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
504  t_surf[lev]->setVal(default_land_surf_temp);
505 
506  q_surf[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
507  q_surf[lev]->setVal(default_land_surf_moist);
508 
509  surface_diagnostic_source[lev] = std::make_unique<amrex::MultiFab>(ba_flux, dm, ncomp, ng);
510  surface_diagnostic_source[lev]->setVal(
512 
513  // TODO: Do we want an enum struct for indexing?
514 
515  bool use_sst = (!m_sst_lev[lev].empty() && m_sst_lev[lev][0]);
516  bool use_tsk = (!m_tsk_lev[lev].empty() && m_tsk_lev[lev][0]);
517  if (use_sst || use_tsk || m_has_lsm_tsurf) {
518  // Valid SST, TSK or LSM data; t_surf set before computing fluxes (avoids
519  // extended lambda capture) Note that land temp will be set from m_tsk_lev
520  // while sea temp will be set from m_sst_lev
522 
523  // Pathways in fill_tsurf_with_sst_and_tsk
524  amrex::Print() << "Using MOST with specified surface temperature ";
525  if (m_has_ocean_lsm_tsurf) {
526  amrex::Print() << "(OceanSurf: t_surf)" << std::endl;
527  } else if (m_has_lsm_tsurf && !use_sst && !use_tsk) {
528  amrex::Print() << "(SLM: theta)" << std::endl;
529  } else {
530  // NOTE: SST from the LOW file populates TSK in update_sst_tsk.
531  // So if we have TSK, it contains everything and has been
532  // sanity checked for valid SST values.
533  if (use_tsk) { m_ignore_sst = true; }
534  if (use_tsk) {
535  amrex::Print() << "(land: TSK, ";
536  } else {
537  amrex::Print() << "(land: T0, ";
538  }
539  if (use_tsk && !use_sst) {
540  amrex::Print() << "sea: TSK)" << std::endl;
541  } else {
542  amrex::Print() << "sea: SST)" << std::endl;
544  }
545  }
546  }
547  }
548 
549  /**
550  * Update surface fluxes and related surface-layer state.
551  *
552  * @param[in] lev level index
553  * @param[in] elapsed_time current elapsed simulation time
554  * @param[in] elapsed_time_since_start_low elapsed time relative to low-data start
555  * @param[in,out] cons_in conserved state used by the flux update
556  * @param[in] z_phys_nd nodal physical-height field
557  * @param[in] walldist wall-distance field
558  * @param[in] max_iters maximum MOST iteration count
559  */
560  void
561  update_fluxes (const int& lev,
562  const double& elapsed_time,
563  const double& elapsed_time_since_start_low,
564  amrex::MultiFab& cons_in,
565  const std::unique_ptr<amrex::MultiFab>& z_phys_nd,
566  const std::unique_ptr<amrex::MultiFab>& walldist,
567  int max_iters = 100);
568 
569  /**
570  * Compute MOST fluxes with a selected flux-iteration functor.
571  *
572  * @param[in] lev level index
573  * @param[in] max_iters maximum MOST iteration count
574  * @param[in,out] cons_in conserved state used by the flux computation
575  * @param[in] most_flux flux-iteration functor
576  * @param[in] is_land whether the land-surface branch is active
577  */
578  template <typename FluxIter>
579  void compute_fluxes (const int& lev,
580  const int& max_iters,
581  amrex::MultiFab& cons_in,
582  const FluxIter& most_flux,
583  bool is_land);
584 
585  /**
586  * Initialize TKE from the current surface friction velocity.
587  *
588  * @param[in] lev level index
589  * @param[in,out] cons conserved state whose TKE component is initialized
590  * @param[in] z_phys_nd nodal physical-height field
591  * @param[in] tkefac scale factor applied to the initialized TKE
592  * @param[in] zscale vertical decay scale
593  */
594  void init_tke_from_ustar (const int& lev,
595  amrex::MultiFab& cons,
596  const std::unique_ptr<amrex::MultiFab>& z_phys_nd,
597  const amrex::Real tkefac = one,
598  const amrex::Real zscale = amrex::Real(700.0));
599 
600  /**
601  * Impose surface-layer boundary conditions for planar terrain.
602  *
603  * @param[in] lev level index
604  * @param[in] mfs state and velocity fields used by the BC computation
605  * @param[in,out] Tau_lev stress fields to fill
606  * @param[in,out] xheat_flux x-face heat flux field
607  * @param[in,out] yheat_flux y-face heat flux field
608  * @param[in,out] zheat_flux z-face heat flux field
609  * @param[in,out] xqv_flux x-face moisture flux field
610  * @param[in,out] yqv_flux y-face moisture flux field
611  * @param[in,out] zqv_flux z-face moisture flux field
612  * @param[in] z_phys physical-height field
613  */
614  void impose_SurfaceLayer_bcs (const int& lev,
615  amrex::Vector<const amrex::MultiFab*> mfs,
616  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Tau_lev,
617  amrex::MultiFab* xheat_flux,
618  amrex::MultiFab* yheat_flux,
619  amrex::MultiFab* zheat_flux,
620  amrex::MultiFab* xqv_flux,
621  amrex::MultiFab* yqv_flux,
622  amrex::MultiFab* zqv_flux,
623  const amrex::MultiFab* z_phys);
624 
625  /**
626  * Impose surface-layer boundary conditions for embedded-boundary terrain.
627  *
628  * @param[in] lev level index
629  * @param[in] mfs state and velocity fields used by the BC computation
630  * @param[in,out] Tau_lev EB stress fields to fill
631  * @param[in,out] xheat_flux x-face heat flux field
632  * @param[in,out] yheat_flux y-face heat flux field
633  * @param[in,out] zheat_flux z-face heat flux field
634  * @param[in,out] xqv_flux x-face moisture flux field
635  * @param[in,out] yqv_flux y-face moisture flux field
636  * @param[in,out] zqv_flux z-face moisture flux field
637  */
638  void impose_SurfaceLayer_bcs_EB (const int& lev,
639  amrex::Vector<const amrex::MultiFab*> mfs,
640  amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab>>>& Tau_lev,
641  amrex::MultiFab* xheat_flux,
642  amrex::MultiFab* yheat_flux,
643  amrex::MultiFab* zheat_flux,
644  amrex::MultiFab* xqv_flux,
645  amrex::MultiFab* yqv_flux,
646  amrex::MultiFab* zqv_flux);
647 
648  /**
649  * Compute planar-terrain surface-layer flux boundary conditions.
650  *
651  * @param[in] lev level index
652  * @param[in] mfs state and velocity fields used by the BC computation
653  * @param[in,out] Tau_lev stress fields to fill
654  * @param[in,out] xheat_flux x-face heat flux field
655  * @param[in,out] yheat_flux y-face heat flux field
656  * @param[in,out] zheat_flux z-face heat flux field
657  * @param[in,out] xqv_flux x-face moisture flux field
658  * @param[in,out] yqv_flux y-face moisture flux field
659  * @param[in,out] zqv_flux z-face moisture flux field
660  * @param[in] z_phys physical-height field
661  * @param[in] flux_comp flux-computation functor
662  */
663  template <typename FluxCalc>
664  void compute_SurfaceLayer_bcs (const int& lev,
665  amrex::Vector<const amrex::MultiFab*> mfs,
666  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Tau_lev,
667  amrex::MultiFab* xheat_flux,
668  amrex::MultiFab* yheat_flux,
669  amrex::MultiFab* zheat_flux,
670  amrex::MultiFab* xqv_flux,
671  amrex::MultiFab* yqv_flux,
672  amrex::MultiFab* zqv_flux,
673  const amrex::MultiFab* z_phys,
674  const FluxCalc& flux_comp);
675 
676  /**
677  * Compute embedded-boundary surface-layer flux boundary conditions.
678  *
679  * @param[in] lev level index
680  * @param[in] mfs state and velocity fields used by the BC computation
681  * @param[in,out] Tau_lev EB stress fields to fill
682  * @param[in,out] xheat_flux x-face heat flux field
683  * @param[in,out] yheat_flux y-face heat flux field
684  * @param[in,out] zheat_flux z-face heat flux field
685  * @param[in,out] xqv_flux x-face moisture flux field
686  * @param[in,out] yqv_flux y-face moisture flux field
687  * @param[in,out] zqv_flux z-face moisture flux field
688  * @param[in] flux_comp flux-computation functor
689  */
690  template <typename FluxCalc>
691  void compute_SurfaceLayer_bcs_EB (const int& lev,
692  amrex::Vector<const amrex::MultiFab*> mfs,
693  amrex::Vector<amrex::Vector<std::unique_ptr<amrex::MultiFab>>>& Tau_lev,
694  amrex::MultiFab* xheat_flux,
695  amrex::MultiFab* yheat_flux,
696  amrex::MultiFab* zheat_flux,
697  amrex::MultiFab* xqv_flux,
698  amrex::MultiFab* yqv_flux,
699  amrex::MultiFab* zqv_flux,
700  const FluxCalc& flux_comp);
701 
702  /**
703  * Derive MOST surface parameters from LSM fluxes.
704  *
705  * @param[in] lev level index
706  * @param[in,out] cons_in conserved state used by the surface-parameter computation
707  */
708  void compute_sfc_params_from_lsm_fluxes(const int& lev,
709  amrex::MultiFab& cons_in);
710 
711  /**
712  * Fill surface temperature from available SST and TSK data.
713  *
714  * @param[in] lev level index
715  * @param[in] time interpolation time
716  */
717  void fill_tsurf_with_sst_and_tsk (const int& lev,
718  const double& time);
719 
720  /**
721  * Fill surface moisture from saturation specific humidity.
722  *
723  * @param[in] lev level index
724  * @param[in] cons_in conserved state used to evaluate surface pressure
725  * @param[in] z_phys_nd nodal physical-height field
726  */
727  void fill_qsurf_with_qsat (const int& lev,
728  const amrex::MultiFab& cons_in,
729  const std::unique_ptr<amrex::MultiFab>& z_phys_nd);
730 
731  /**
732  * Fill surface temperature from the LSM surface-temperature field.
733  *
734  * @param[in] lev level index
735  */
736  void get_lsm_tsurf (const int& lev);
737 
738  /**
739  * Wrapper around compute_pblh.
740  *
741  * @param[in] lev level index
742  * @param[in,out] vars state variables used by the PBL-height calculation
743  * @param[in] z_phys_cc cell-centered physical-height field
744  * @param[in] moisture_indices indices for moisture components
745  */
746  void update_pblh (const int& lev,
747  amrex::Vector<amrex::Vector<amrex::MultiFab>>& vars,
748  amrex::MultiFab* z_phys_cc,
749  const MoistureComponentIndices& moisture_indices);
750 
751  /**
752  * Compute planetary-boundary-layer height with the selected estimator.
753  *
754  * @param[in] lev level index
755  * @param[in,out] vars state variables used by the PBL-height calculation
756  * @param[in] z_phys_cc cell-centered physical-height field
757  * @param[in] est PBL-height estimator functor
758  * @param[in] moisture_indice indices for moisture components
759  */
760  template <typename PBLHeightEstimator>
761  void compute_pblh (const int& lev,
762  amrex::Vector<amrex::Vector<amrex::MultiFab>>& vars,
763  amrex::MultiFab* z_phys_cc,
764  const PBLHeightEstimator& est,
765  const MoistureComponentIndices& moisture_indice);
766 
767  /**
768  * Read custom roughness data for one level.
769  *
770  * @param[in] lev level index
771  * @param[in] fname roughness-data file name
772  */
773  void read_custom_roughness (const int& lev,
774  const std::string& fname);
775 
776  /**
777  * Update prescribed surface temperature from the configured heating rate.
778  *
779  * @param[in] time elapsed simulation time
780  */
781  void update_surf_temp (const double& time)
782  {
783  if (m_has_ocean_lsm_tsurf) {
784  return;
785  }
786  if (surf_heating_rate != 0) {
787  int nlevs = static_cast<int>(m_geom.size());
788  for (int lev = 0; lev < nlevs; lev++) {
789  t_surf[lev]->setVal(surf_temp + surf_heating_rate * static_cast<amrex::Real>(time));
790  amrex::Print() << "Surface temp at t=" << time << ": "
791  << surf_temp + surf_heating_rate * time << std::endl;
792  }
793  }
794  }
795 
796  /**
797  * Update MOST-average field pointers.
798  *
799  * @param[in] lev level index
800  * @param[in] vars_old old-time state variables
801  * @param[in] Theta_prim primitive potential-temperature fields by level
802  * @param[in] Qv_prim primitive water-vapor fields by level
803  * @param[in] Qr_prim primitive rain-water fields by level
804  */
805  void update_mac_ptrs (const int& lev,
806  amrex::Vector<amrex::Vector<amrex::MultiFab>>& vars_old,
807  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Theta_prim,
808  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Qv_prim,
809  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Qr_prim)
810  {
811  m_ma.update_field_ptrs(lev, vars_old, Theta_prim, Qv_prim, Qr_prim);
812  }
813 
814  /**
815  * Return the friction-velocity field.
816  *
817  * @param[in] lev level index
818  */
819  amrex::MultiFab* get_u_star (const int& lev) { return u_star[lev].get(); }
820 
821  /**
822  * Return the convective velocity scale field.
823  *
824  * @param[in] lev level index
825  */
826  amrex::MultiFab* get_w_star (const int& lev) { return w_star[lev].get(); }
827 
828  /**
829  * Return the temperature scale field.
830  *
831  * @param[in] lev level index
832  */
833  amrex::MultiFab* get_t_star (const int& lev) { return t_star[lev].get(); }
834 
835  /**
836  * Return the moisture scale field.
837  *
838  * @param[in] lev level index
839  */
840  amrex::MultiFab* get_q_star (const int& lev) { return q_star[lev].get(); }
841 
842  /**
843  * Return the Obukhov length field.
844  *
845  * @param[in] lev level index
846  */
847  amrex::MultiFab* get_olen (const int& lev) { return olen[lev].get(); }
848 
849  /**
850  * Return the planetary-boundary-layer-height field.
851  *
852  * @param[in] lev level index
853  */
854  amrex::MultiFab* get_pblh (const int& lev) { return pblh[lev].get(); }
855 
856  /**
857  * Return a MOST-average field.
858  *
859  * @param[in] lev level index
860  * @param[in] comp component index
861  */
862  const amrex::MultiFab* get_mac_avg (const int& lev, int comp)
863  {
864  return m_ma.get_average(lev, comp);
865  }
866 
867  /**
868  * Return the surface-temperature field.
869  *
870  * @param[in] lev level index
871  */
872  amrex::MultiFab* get_t_surf (const int& lev) { return t_surf[lev].get(); }
873 
874  /**
875  * Set the surface-temperature field to a constant value.
876  *
877  * @param[in] lev level index
878  * @param[in] tsurf surface temperature
879  */
880  void set_t_surf(const int& lev, const amrex::Real tsurf) { t_surf[lev]->setVal(tsurf); }
881 
882  /**
883  * Return the surface-moisture field.
884  *
885  * @param[in] lev level index
886  */
887  amrex::MultiFab* get_q_surf (const int& lev) { return q_surf[lev].get(); }
888 
889  /**
890  * Set the surface-moisture field to a constant value.
891  *
892  * @param[in] lev level index
893  * @param[in] qsurf surface moisture
894  */
895  void set_q_surf(const int& lev, const amrex::Real qsurf) { q_surf[lev]->setVal(qsurf); }
896 
897  /**
898  * Return the surface-diagnostic provenance field.
899  *
900  * @param[in] lev level index
901  */
902  amrex::MultiFab* get_surface_diagnostic_source (const int& lev) { return surface_diagnostic_source[lev].get(); }
903 
904  /**
905  * Return the minimum reference height for one level.
906  *
907  * @param[in] lev level index
908  */
909  amrex::Real get_zref (const int& lev) { return (m_ma.get_zref(lev))->min(0); }
910 
911  /**
912  * Return the roughness-height field.
913  *
914  * @param[in] lev level index
915  */
916  amrex::MultiFab* get_z0 (const int& lev) { return &z_0[lev]; }
917 
918  /**
919  * Return whether variable sea roughness is active.
920  */
922 
923  /**
924  * Return the land-mask field.
925  *
926  * @param[in] lev level index
927  */
928  amrex::iMultiFab* get_lmask (const int& lev) { return m_lmask_lev[lev][0]; }
929 
930  /**
931  * Compute the minimum land-mask value over valid and optional ghost cells.
932  *
933  * @param[in] lmask land-mask field
934  * @param[in] nghost number of ghost cells included in the reduction
935  */
936  int lmask_min_reduce (amrex::iMultiFab& lmask,
937  const int& nghost)
938  {
939  int lmask_min = amrex::ReduceMin(lmask, nghost, [=] AMREX_GPU_HOST_DEVICE(
940  amrex::Box const& bx, amrex::Array4<int const> const& lm_arr) -> int
941  {
942  int locmin = std::numeric_limits<int>::max();
943  const auto lo = lbound(bx);
944  const auto hi = ubound(bx);
945  for (int j = lo.y; j <= hi.y; ++j) {
946  for (int i = lo.x; i <= hi.x; ++i) {
947  locmin = std::min(locmin, lm_arr(i, j, 0));
948  }
949  }
950  return locmin;
951  });
952 
953  return lmask_min;
954  }
955 
956  /**
957  * Update one stored sea-surface-temperature pointer.
958  *
959  * @param[in] lev level index
960  * @param[in] itime time-slice index
961  * @param[in] sst_ptr sea-surface-temperature field pointer
962  */
963  void update_sst_ptr(const int lev, const int itime, amrex::MultiFab* sst_ptr) {
964  m_sst_lev[lev][itime] = sst_ptr;
965  }
966 
967  /**
968  * Update one stored skin-temperature pointer.
969  *
970  * @param[in] lev level index
971  * @param[in] itime time-slice index
972  * @param[in] tsk_ptr skin-temperature field pointer
973  */
974  void update_tsk_ptr(const int lev, const int itime, amrex::MultiFab* tsk_ptr) {
975  m_tsk_lev[lev][itime] = tsk_ptr;
976  }
977 
978  enum struct FluxCalcType {
979  MOENG = 0, ///< Moeng functional form
980  DONELAN, ///< Donelan functional form
981  CUSTOM, ///< Custom constant flux functional form
982  BULK_COEFF, ///< Bulk transfer coefficient functional form
983  ROTATE, ///< Terrain rotation flux functional form
984  RICO
985  };
986 
987  enum struct ThetaCalcType {
988  ADIABATIC = 0,
989  HEAT_FLUX, ///< Heat-flux specified
990  SURFACE_TEMPERATURE ///< Surface temperature specified
991  };
992 
993  enum struct MoistCalcType {
994  ADIABATIC = 0,
995  MOISTURE_FLUX, ///< Qv-flux specified
996  SURFACE_MOISTURE ///< Surface Qv specified
997  };
998 
999  enum struct RoughCalcType {
1000  CONSTANT = 0, ///< Constant z0
1001  CHARNOCK,
1003  DONELAN,
1004  WAVE_COUPLED
1005  };
1006 
1008 
1015 
1016 private:
1017  // Set in constructor
1018  amrex::Vector<amrex::Geometry> m_geom;
1019  bool m_rotate = false;
1023 
1024  bool m_include_wstar = false;
1036  amrex::Real custom_rhosurf{0}; // use specified value instead of rho from first cell
1037  bool specified_rho_surf{false};
1039  bool cnk_visc{false};
1041  amrex::Vector<amrex::MultiFab> z_0;
1042  bool m_var_z0{false};
1043 
1046 
1048  bool m_has_lsm_fluxes = false;
1049  bool m_has_lsm_tsurf = false;
1052 
1056 
1057  bool m_ignore_sst = false;
1058 
1059  amrex::Vector<const eb_*> m_eb_vec;
1060  TerrainType m_terrain_type;
1062  amrex::Vector<std::unique_ptr<amrex::MultiFab>> u_star;
1063  amrex::Vector<std::unique_ptr<amrex::MultiFab>> w_star;
1064  amrex::Vector<std::unique_ptr<amrex::MultiFab>> t_star;
1065  amrex::Vector<std::unique_ptr<amrex::MultiFab>> q_star;
1066  amrex::Vector<std::unique_ptr<amrex::MultiFab>> olen;
1067  amrex::Vector<std::unique_ptr<amrex::MultiFab>> pblh;
1068  amrex::Vector<std::unique_ptr<amrex::MultiFab>> t_surf;
1069  amrex::Vector<std::unique_ptr<amrex::MultiFab>> q_surf;
1070  // Diagnostic-only provenance mask. This records the cell-centered source
1071  // path used by the SurfaceLayer scalar diagnostic path. It must not feed
1072  // back into flux calculations, boundary conditions, or model state.
1073  amrex::Vector<std::unique_ptr<amrex::MultiFab>> surface_diagnostic_source;
1074 
1075  amrex::Vector<amrex::Vector<amrex::MultiFab*>> m_sst_lev;
1076  amrex::Vector<amrex::Vector<amrex::MultiFab*>> m_tsk_lev;
1077  amrex::Vector<amrex::Vector<amrex::iMultiFab*>> m_lmask_lev;
1078  amrex::Vector<amrex::Vector<amrex::MultiFab*>> m_lsm_data_lev;
1079  amrex::Vector<amrex::Vector<amrex::MultiFab*>> m_lsm_flux_lev;
1080  amrex::Vector<std::string> m_lsm_data_name;
1081  amrex::Vector<std::string> m_lsm_flux_name;
1082  amrex::Vector<amrex::MultiFab*> m_Hwave_lev;
1083  amrex::Vector<amrex::MultiFab*> m_Lwave_lev;
1084  amrex::Vector<amrex::MultiFab*> m_eddyDiffs_lev;
1085 
1086  bool m_update_k_rans = false;
1089 };
1090 
1091 #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
amrex::MultiFab * get_zref(const int &lev) const
Definition: ERF_MOSTAverage.H:242
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:293
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:104
Definition: ERF_SurfaceLayer.H:34
ThetaCalcType theta_type
Definition: ERF_SurfaceLayer.H:1010
int lmask_min_reduce(amrex::iMultiFab &lmask, const int &nghost)
Definition: ERF_SurfaceLayer.H:936
amrex::Vector< std::string > m_lsm_data_name
Definition: ERF_SurfaceLayer.H:1080
bool m_include_wstar
Definition: ERF_SurfaceLayer.H:1024
bool specified_rho_surf
Definition: ERF_SurfaceLayer.H:1037
void set_q_surf(const int &lev, const amrex::Real qsurf)
Definition: ERF_SurfaceLayer.H:895
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:1019
PBLHeightCalcType pblh_type
Definition: ERF_SurfaceLayer.H:1014
amrex::Vector< amrex::Vector< amrex::iMultiFab * > > m_lmask_lev
Definition: ERF_SurfaceLayer.H:1077
double m_final_low_time
Definition: ERF_SurfaceLayer.H:1021
amrex::iMultiFab * get_lmask(const int &lev)
Definition: ERF_SurfaceLayer.H:928
bool use_moisture
Definition: ERF_SurfaceLayer.H:1047
amrex::MultiFab * get_q_surf(const int &lev)
Definition: ERF_SurfaceLayer.H:887
bool m_has_lsm_tsurf
Definition: ERF_SurfaceLayer.H:1049
amrex::MultiFab * get_w_star(const int &lev)
Definition: ERF_SurfaceLayer.H:826
amrex::Real m_Cq
Definition: ERF_SurfaceLayer.H:1055
amrex::Vector< const eb_ * > m_eb_vec
Definition: ERF_SurfaceLayer.H:1059
RoughCalcType rough_type_land
Definition: ERF_SurfaceLayer.H:1012
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:1325
amrex::Vector< std::unique_ptr< amrex::MultiFab > > t_surf
Definition: ERF_SurfaceLayer.H:1068
amrex::Real z0_const
Definition: ERF_SurfaceLayer.H:1025
amrex::Vector< std::unique_ptr< amrex::MultiFab > > surface_diagnostic_source
Definition: ERF_SurfaceLayer.H:1073
amrex::Real cnk_a
Definition: ERF_SurfaceLayer.H:1038
amrex::Real m_Ch
Definition: ERF_SurfaceLayer.H:1054
amrex::Real surf_temp
Definition: ERF_SurfaceLayer.H:1027
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:805
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:1065
int m_lsm_tsurf_indx
Definition: ERF_SurfaceLayer.H:1051
double m_start_low_time
Definition: ERF_SurfaceLayer.H:1020
amrex::Real rico_qsat_z0
Definition: ERF_SurfaceLayer.H:1045
bool m_has_lsm_fluxes
Definition: ERF_SurfaceLayer.H:1048
bool m_update_k_rans
Definition: ERF_SurfaceLayer.H:1086
amrex::Vector< amrex::MultiFab * > m_Lwave_lev
Definition: ERF_SurfaceLayer.H:1083
void get_lsm_tsurf(const int &lev)
Definition: ERF_SurfaceLayer.cpp:1279
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:1231
amrex::Real get_zref(const int &lev)
Definition: ERF_SurfaceLayer.H:909
amrex::MultiFab * get_olen(const int &lev)
Definition: ERF_SurfaceLayer.H:847
amrex::Vector< amrex::MultiFab > z_0
Definition: ERF_SurfaceLayer.H:1041
amrex::Real surf_moist_flux
Definition: ERF_SurfaceLayer.H:1032
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:1013
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:1370
amrex::Real surf_moist
Definition: ERF_SurfaceLayer.H:1031
amrex::Vector< std::unique_ptr< amrex::MultiFab > > w_star
Definition: ERF_SurfaceLayer.H:1063
bool m_ignore_sst
Definition: ERF_SurfaceLayer.H:1057
amrex::MultiFab * get_u_star(const int &lev)
Definition: ERF_SurfaceLayer.H:819
double m_low_time_interval
Definition: ERF_SurfaceLayer.H:1022
void compute_fluxes(const int &lev, const int &max_iters, amrex::MultiFab &cons_in, const FluxIter &most_flux, bool is_land)
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_lsm_data_lev
Definition: ERF_SurfaceLayer.H:1078
void set_t_surf(const int &lev, const amrex::Real tsurf)
Definition: ERF_SurfaceLayer.H:880
amrex::Real custom_qstar
Definition: ERF_SurfaceLayer.H:1035
amrex::Vector< std::unique_ptr< amrex::MultiFab > > u_star
Definition: ERF_SurfaceLayer.H:1062
void update_tsk_ptr(const int lev, const int itime, amrex::MultiFab *tsk_ptr)
Definition: ERF_SurfaceLayer.H:974
amrex::Real custom_rhosurf
Definition: ERF_SurfaceLayer.H:1036
amrex::Vector< std::unique_ptr< amrex::MultiFab > > q_surf
Definition: ERF_SurfaceLayer.H:1069
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_sst_lev
Definition: ERF_SurfaceLayer.H:1075
FluxCalcType
Definition: ERF_SurfaceLayer.H:978
@ 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:993
@ SURFACE_MOISTURE
Surface Qv specified.
@ MOISTURE_FLUX
Qv-flux specified.
amrex::Real depth
Definition: ERF_SurfaceLayer.H:1040
amrex::Vector< amrex::MultiFab * > m_Hwave_lev
Definition: ERF_SurfaceLayer.H:1082
amrex::Real default_land_surf_moist
Definition: ERF_SurfaceLayer.H:1030
bool m_var_z0
Definition: ERF_SurfaceLayer.H:1042
amrex::MultiFab * get_surface_diagnostic_source(const int &lev)
Definition: ERF_SurfaceLayer.H:902
amrex::MultiFab * get_t_star(const int &lev)
Definition: ERF_SurfaceLayer.H:833
bool have_variable_sea_roughness()
Definition: ERF_SurfaceLayer.H:921
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:469
amrex::MultiFab * get_q_star(const int &lev)
Definition: ERF_SurfaceLayer.H:840
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_lsm_flux_lev
Definition: ERF_SurfaceLayer.H:1079
PBLHeightCalcType
Definition: ERF_SurfaceLayer.H:1007
amrex::MultiFab * get_pblh(const int &lev)
Definition: ERF_SurfaceLayer.H:854
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:1044
amrex::Real surf_temp_flux
Definition: ERF_SurfaceLayer.H:1029
amrex::Vector< amrex::Geometry > m_geom
Definition: ERF_SurfaceLayer.H:1018
amrex::Vector< std::unique_ptr< amrex::MultiFab > > t_star
Definition: ERF_SurfaceLayer.H:1064
amrex::Real theta_ref
Definition: ERF_SurfaceLayer.H:1088
amrex::MultiFab * get_z0(const int &lev)
Definition: ERF_SurfaceLayer.H:916
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_tsk_lev
Definition: ERF_SurfaceLayer.H:1076
void update_surf_temp(const double &time)
Definition: ERF_SurfaceLayer.H:781
void fill_tsurf_with_sst_and_tsk(const int &lev, const double &time)
Definition: ERF_SurfaceLayer.cpp:1137
amrex::Real custom_tstar
Definition: ERF_SurfaceLayer.H:1034
bool cnk_visc
Definition: ERF_SurfaceLayer.H:1039
amrex::Real surf_heating_rate
Definition: ERF_SurfaceLayer.H:1028
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:311
bool m_has_ocean_lsm_tsurf
Definition: ERF_SurfaceLayer.H:1050
RoughCalcType
Definition: ERF_SurfaceLayer.H:999
FluxCalcType flux_type
Definition: ERF_SurfaceLayer.H:1009
MoistCalcType moist_type
Definition: ERF_SurfaceLayer.H:1011
void compute_sfc_params_from_lsm_fluxes(const int &lev, amrex::MultiFab &cons_in)
Definition: ERF_SurfaceLayer.cpp:1064
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:53
amrex::Real inv_Cmu2
Definition: ERF_SurfaceLayer.H:1087
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:403
amrex::Vector< amrex::MultiFab * > m_eddyDiffs_lev
Definition: ERF_SurfaceLayer.H:1084
const amrex::MultiFab * get_mac_avg(const int &lev, int comp)
Definition: ERF_SurfaceLayer.H:862
void update_sst_ptr(const int lev, const int itime, amrex::MultiFab *sst_ptr)
Definition: ERF_SurfaceLayer.H:963
amrex::Real custom_ustar
Definition: ERF_SurfaceLayer.H:1033
amrex::Vector< std::unique_ptr< amrex::MultiFab > > olen
Definition: ERF_SurfaceLayer.H:1066
amrex::MultiFab * get_t_surf(const int &lev)
Definition: ERF_SurfaceLayer.H:872
amrex::Real m_Cd
Definition: ERF_SurfaceLayer.H:1053
amrex::Vector< std::unique_ptr< amrex::MultiFab > > pblh
Definition: ERF_SurfaceLayer.H:1067
amrex::Real default_land_surf_temp
Definition: ERF_SurfaceLayer.H:1026
ThetaCalcType
Definition: ERF_SurfaceLayer.H:987
@ 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:1445
TerrainType m_terrain_type
Definition: ERF_SurfaceLayer.H:1060
amrex::Vector< std::string > m_lsm_flux_name
Definition: ERF_SurfaceLayer.H:1081
MOSTAverage m_ma
Definition: ERF_SurfaceLayer.H:1061
@ ng
Definition: ERF_Morrison.H:49
@ cons
Definition: ERF_IndexDefines.H:176
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
Component indices for moisture species in the conserved state.
Definition: ERF_DataStruct.H:166
Definition: ERF_TurbStruct.H:114
RANSType rans_type
Selected RANS closure.
Definition: ERF_TurbStruct.H:599
amrex::Real theta_ref
Reference potential temperature for stable stratification.
Definition: ERF_TurbStruct.H:588
bool dirichlet_k
Whether TKE uses Dirichlet boundary treatment.
Definition: ERF_TurbStruct.H:601
amrex::Real Cmu0
One-equation RANS Cmu0 coefficient.
Definition: ERF_TurbStruct.H:577