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_TerrainMetrics.H"
16 #include "ERF_PBLHeight.H"
17 #include "ERF_MicrophysicsUtils.H"
18 #include "ERF_EB.H"
19 
20 /** Abstraction layer for different surface layer schemes (e.g. MOST, Cd)
21  *
22  * van der Laan, P., Kelly, M. C., & Sørensen, N. N. (2017). A new k-epsilon
23  * model consistent with Monin-Obukhov similarity theory. Wind Energy,
24  * 20(3), 479–amrex::Real(489.) https://doi.org/amrex::Real(10.1002)/we.2017
25  *
26  * Consistent with Dyer (1974) formulation from page 57, Chapter 2, Modeling
27  * the vertical ABL structure in Modelling of Atmospheric Flow Fields,
28  * Demetri P Lalas and Corrado F Ratto, January 1996,
29  * https://doi.org/amrex::Real(10.1142)/amrex::Real(2975.)
30  */
32 {
33 
34 public:
35  // Constructor
36  explicit SurfaceLayer (const amrex::Vector<amrex::Geometry>& geom,
37  bool& use_rot_surface_flux,
38  std::string a_pp_prefix,
39  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Qv_prim,
40  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& z_phys_nd,
41  const MeshType& a_mesh_type,
42  const TerrainType& a_terrain_type,
43  const TurbChoice& a_turb_choice,
44  amrex::Real start_low_time,
45  amrex::Real final_low_time,
46  amrex::Real low_time_interval = zero)
47  : m_geom(geom),
48  m_rotate(use_rot_surface_flux),
49  m_start_low_time(start_low_time),
50  m_final_low_time(final_low_time),
51  m_low_time_interval(low_time_interval),
52  m_ma(geom, (z_phys_nd[0] != nullptr), a_pp_prefix, a_mesh_type, a_terrain_type)
53  {
54  // We have a moisture model if Qv_prim is a valid pointer
55  use_moisture = (Qv_prim[0].get());
56 
57  // Get roughness
58  amrex::ParmParse pp("erf");
59  pp.query("most.z0", z0_const);
60 
61  // Specify how to compute the flux
62  if (use_rot_surface_flux) {
64  } else {
65  std::string flux_string_in;
66  std::string flux_string{"moeng"};
67  auto read_flux = pp.query("surface_layer.flux_type", flux_string_in);
68  if (read_flux) {
69  flux_string = amrex::toLower(flux_string_in);
70  }
71  if (flux_string == "donelan") {
73  } else if (flux_string == "moeng") {
75  } else if (flux_string == "rico") {
77  } else if (flux_string == "bulk_coeff") {
79  } else if (flux_string == "custom") {
81  } else {
82  amrex::Abort("Undefined MOST flux type!");
83  }
84  }
85 
86  // Include w* to handle free convection (Beljaars 1995, QJRMS)
87  pp.query("most.include_wstar", m_include_wstar);
88 
89  std::string pblh_string_in;
90  std::string pblh_string{"none"};
91  auto read_pblh = pp.query("most.pblh_calc", pblh_string_in);
92  if (read_pblh) {
93  pblh_string = amrex::toLower(pblh_string_in);
94  }
95  if (pblh_string == "none") {
97  } else if (pblh_string == "mynn25") {
99  } else if (pblh_string == "mynnedmf") {
101  } else if (pblh_string == "ysu") {
103  } else if (pblh_string == "mrf") {
105  } else {
106  amrex::Abort("Undefined PBLH calc type!");
107  }
108 
109  // Get surface temperature
110  auto erf_st = pp.query("most.surf_temp", surf_temp);
111  if (erf_st) { default_land_surf_temp = surf_temp; }
112 
113  // Get surface moisture
114  bool erf_sq = false;
115  if (use_moisture) { erf_sq = pp.query("most.surf_moist", surf_moist); }
116  if (erf_sq) { default_land_surf_moist = surf_moist; }
117 
118  // Custom type user must specify the fluxes
123  pp.get("most.ustar", custom_ustar);
124  pp.get("most.tstar", custom_tstar);
125  pp.get("most.qstar", custom_qstar);
126  pp.query("most.rhosurf", custom_rhosurf);
127  if (custom_qstar != 0) {
129  "Specified custom MOST qv flux without moisture model!");
130  }
131  amrex::Print() << "Using specified ustar, tstar, qstar for MOST = "
132  << custom_ustar << " " << custom_tstar << " "
133  << custom_qstar << std::endl;
134 
135  // Bulk transfer coefficient (must specify coeffs and surface values)
136  } else if (flux_type == FluxCalcType::BULK_COEFF) {
137  pp.get("most.Cd", m_Cd);
138  pp.get("most.Ch", m_Ch);
139  pp.get("most.Cq", m_Cq);
140  pp.get("most.surf_temp", default_land_surf_temp);
141  pp.get("most.surf_moist", default_land_surf_moist);
142  amrex::Print() << "Using specified Cd, Ch, Cq for MOST = "
143  << m_Cd << " " << m_Ch << " "
144  << m_Cq << std::endl;
145 
146  // Specify surface temperature/moisture or surface flux
147  } else {
148  if (erf_st) {
150  pp.query("most.surf_heating_rate", surf_heating_rate); // [K/h]
151  surf_heating_rate = surf_heating_rate / amrex::Real(3600.0); // [K/s]
152  if (pp.query("most.surf_temp_flux", surf_temp_flux)) {
153  amrex::Abort("Can only specify one of surf_temp_flux or surf_heating_rate");
154  }
155  } else {
156  pp.query("most.surf_temp_flux", surf_temp_flux);
157 
158  if (pp.query("most.surf_heating_rate", surf_heating_rate)) {
159  amrex::Abort("Can only specify one of surf_temp_flux or surf_heating_rate");
160  }
161  if (std::abs(surf_temp_flux) >
164  } else {
166  }
167  }
168 
169  if (erf_sq) {
171  } else {
172  pp.query("most.surf_moist_flux", surf_moist_flux);
173  if (std::abs(surf_moist_flux) >
176  } else {
178  }
179  }
180  }
181 
183  {
184  pp.query("most.rico.theta_z0", rico_theta_z0);
185  pp.query("most.rico.qsat_z0", rico_qsat_z0);
186  }
187 
188  // Make sure the inputs file doesn't try to use most.roughness_type
189  std::string bogus_input;
190  if (pp.query("most.roughness_type", bogus_input) > 0) {
191  amrex::Abort("most.roughness_type is deprecated; use "
192  "most.roughness_type_land and/or most.roughness_type_sea");
193  }
194 
195  // Specify how to compute the surface flux over land (if there is any)
196  std::string rough_land_string_in;
197  std::string rough_land_string{"constant"};
198  auto read_rough_land =
199  pp.query("most.roughness_type_land", rough_land_string_in);
200  if (read_rough_land) {
201  rough_land_string = amrex::toLower(rough_land_string_in);
202  }
203  if (rough_land_string == "constant") {
205  } else {
206  amrex::Abort("Undefined MOST roughness type for land!");
207  }
208 
209  // Specify how to compute the surface flux over sea (if there is any)
210  std::string rough_sea_string_in;
211  std::string rough_sea_string{"charnock"};
212  auto read_rough_sea = pp.query("most.roughness_type_sea", rough_sea_string_in);
213  if (read_rough_sea) {
214  rough_sea_string = amrex::toLower(rough_sea_string_in);
215  }
216  if (rough_sea_string == "charnock") {
218  pp.query("most.charnock_constant", cnk_a);
219  pp.query("most.charnock_viscosity", cnk_visc);
220  if (cnk_a > 0) {
221  amrex::Print() << "If there is water, Charnock relation with C_a="
222  << cnk_a << (cnk_visc ? " and viscosity" : "")
223  << " will be used" << std::endl;
224  } else {
225  amrex::Print() << "If there is water, Charnock relation with variable "
226  "Charnock parameter (COARE3.0)"
227  << (cnk_visc ? " and viscosity" : "") << " will be used"
228  << std::endl;
229  }
230  } else if (rough_sea_string == "coare3.0") {
232  amrex::Print() << "If there is water, Charnock relation with variable "
233  "Charnock parameter (COARE3.0)"
234  << (cnk_visc ? " and viscosity" : "") << " will be used"
235  << std::endl;
236  cnk_a = -1;
237  } else if (rough_sea_string == "donelan") {
239  } else if (rough_sea_string == "modified_charnock") {
241  pp.query("most.modified_charnock_depth", depth);
242  } else if (rough_sea_string == "wave_coupled") {
244  } else if (rough_sea_string == "constant") {
246  } else {
247  amrex::Abort("Undefined MOST roughness type for sea!");
248  }
249 
250  // use skin temperature instead of sea-surface temperature
251  // (wrfinput data may have lower resolution SST data)
252  pp.query("most.ignore_sst", m_ignore_sst);
253 
254  // If we're using the RANS k model, then we need to update the dirichlet
255  // BC based on the instantaneous u* and θ*; the turbulence modeling
256  // choices can vary per level but for now, assume that if specified then
257  // all levels are using the same RANS model.
258  m_update_k_rans = (a_turb_choice.rans_type == RANSType::kEqn &&
259  a_turb_choice.dirichlet_k == true);
260  if (m_update_k_rans) {
261  inv_Cmu2 = one / (a_turb_choice.Cmu0 * a_turb_choice.Cmu0);
262  theta_ref = a_turb_choice.theta_ref;
263  }
264 
265  } // constructor
266 
267  void make_SurfaceLayer_at_level (const int& lev,
268  int nlevs,
269  const amrex::Vector<amrex::MultiFab*>& mfv,
270  std::unique_ptr<amrex::MultiFab>& Theta_prim,
271  std::unique_ptr<amrex::MultiFab>& Qv_prim,
272  std::unique_ptr<amrex::MultiFab>& Qr_prim,
273  std::unique_ptr<amrex::MultiFab>& z_phys_nd,
274  amrex::MultiFab* Hwave,
275  amrex::MultiFab* Lwave,
276  amrex::MultiFab* eddyDiffs,
277  amrex::Vector<amrex::MultiFab*> lsm_data,
278  amrex::Vector<std::string> lsm_data_name,
279  amrex::Vector<amrex::MultiFab*> lsm_flux,
280  amrex::Vector<std::string> lsm_flux_name,
281  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& sst_lev,
282  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& tsk_lev,
283  amrex::Vector<std::unique_ptr<amrex::iMultiFab>>& lmask_lev)
284  {
285  // Update MOST Average
287  Theta_prim, Qv_prim, Qr_prim,
288  z_phys_nd);
289 
290  // Get CC vars
291  amrex::MultiFab& mf = *(mfv[0]);
292 
293  amrex::ParmParse pp("erf");
294 
295  // Do we have a time-varying surface roughness that needs to be saved?
296  if (lev == 0) {
297  const int nghost = 0; // ghost cells not included
298  int lmask_min = lmask_min_reduce(*lmask_lev[0].get(), nghost);
299  amrex::ParallelDescriptor::ReduceIntMin(lmask_min);
300 
301  m_var_z0 = (lmask_min < 1) & (rough_type_sea != RoughCalcType::CONSTANT);
302  if (m_var_z0) {
303  std::string rough_sea_string{"charnock"};
304  pp.query("most.roughness_type_sea", rough_sea_string);
305  amrex::Print() << "Variable sea roughness (type " << rough_sea_string
306  << ")" << std::endl;
307  }
308  }
309 
310  if (m_eddyDiffs_lev.size() < lev+1) {
311  m_Hwave_lev.resize(nlevs);
312  m_Lwave_lev.resize(nlevs);
313  m_eddyDiffs_lev.resize(nlevs);
314 
315  m_lsm_data_lev.resize(nlevs);
316  m_lsm_flux_lev.resize(nlevs);
317 
318  m_sst_lev.resize(nlevs);
319  m_tsk_lev.resize(nlevs);
320  m_lmask_lev.resize(nlevs);
321 
322  // Size the MOST params for all levels
323  z_0.resize(nlevs);
324  u_star.resize(nlevs);
325  w_star.resize(nlevs);
326  t_star.resize(nlevs);
327  q_star.resize(nlevs);
328  t_surf.resize(nlevs);
329  q_surf.resize(nlevs);
330  olen.resize(nlevs);
331  pblh.resize(nlevs);
332  }
333 
334  // Get pointers to SST,TSK and LANDMASK data
335  int nt_tot_sst = sst_lev.size();
336  m_sst_lev[lev].resize(nt_tot_sst);
337  for (int nt(0); nt < nt_tot_sst; ++nt) {
338  m_sst_lev[lev][nt] = sst_lev[nt].get();
339  }
340  int nt_tot_tsk = static_cast<int>(tsk_lev.size());
341  m_tsk_lev[lev].resize(nt_tot_tsk);
342  for (int nt(0); nt < nt_tot_tsk; ++nt) {
343  m_tsk_lev[lev][nt] = tsk_lev[nt].get();
344  }
345  int nt_tot_lmask = static_cast<int>(lmask_lev.size());
346  m_lmask_lev[lev].resize(nt_tot_lmask);
347  for (int nt(0); nt < nt_tot_lmask; ++nt) {
348  m_lmask_lev[lev][nt] = lmask_lev[nt].get();
349  }
350 
351  // Get pointers to wave data
352  m_Hwave_lev[lev] = Hwave;
353  m_Lwave_lev[lev] = Lwave;
354  m_eddyDiffs_lev[lev] = eddyDiffs;
355 
356  // Get pointers to LSM data and Fluxes
357  int ndata = static_cast<int>(lsm_data.size());
358  int nflux = static_cast<int>(lsm_flux.size());
359  m_lsm_data_name.resize(ndata);
360  m_lsm_data_lev[lev].resize(ndata);
361  m_lsm_flux_name.resize(nflux);
362  m_lsm_flux_lev[lev].resize(nflux);
363  for (int n(0); n < ndata; ++n) {
364  m_lsm_data_name[n] = lsm_data_name[n];
365  m_lsm_data_lev[lev][n] = lsm_data[n];
366  if (amrex::toLower(lsm_data_name[n]) == "theta") {
367  m_has_lsm_tsurf = true;
368  m_lsm_tsurf_indx = n;
369  }
370  }
371  for (int n(0); n < nflux; ++n) {
372  m_lsm_flux_name[n] = lsm_flux_name[n];
373  m_lsm_flux_lev[lev][n] = lsm_flux[n];
374  }
375 
376  // Check if there is a user-specified roughness file to be read
377  std::string fname;
378  bool read_z0 = false;
379  if ( (flux_type == FluxCalcType::MOENG) ||
381  int count = pp.countval("most.roughness_file_name");
382  if (count > 1) {
383  AMREX_ALWAYS_ASSERT(count >= lev+1);
384  pp.query("most.roughness_file_name", fname, lev);
385  read_z0 = true;
386  } else if (count == 1) {
387  if (lev == 0) {
388  pp.query("most.roughness_file_name", fname);
389  } else {
390  // we will interpolate from the coarsest level
391  fname = "";
392  }
393  read_z0 = true;
394  }
395  // else use z0_const
396  }
397 
398  // Attributes for MFs and FABs
399  //--------------------------------------------------------
400  // Create a 2D ba, dm, & ghost cells
401  amrex::BoxArray ba = mf.boxArray();
402  amrex::BoxList bl2d = ba.boxList();
403  for (auto& b : bl2d) { b.setRange(2,0); }
404  amrex::BoxArray ba2d(std::move(bl2d));
405  const amrex::DistributionMapping& dm = mf.DistributionMap();
406  const int ncomp = 1;
407  amrex::IntVect ng{1,1,0};
408 
409  // Z0 heights FAB
410  //--------------------------------------------------------
411  z_0[lev].define(ba2d, dm, ncomp, ng);
412  z_0[lev].setVal(z0_const);
413  if (read_z0) {
414  read_custom_roughness(lev, fname);
415  }
416 
417  // 2D MFs for U*, T*, T_surf
418  //--------------------------------------------------------
419  u_star[lev] = std::make_unique<amrex::MultiFab>(ba2d, dm, ncomp, ng);
420  u_star[lev]->setVal(1.E34);
421 
422  w_star[lev] = std::make_unique<amrex::MultiFab>(ba2d, dm, ncomp, ng);
423  w_star[lev]->setVal(1.E34);
424 
425  t_star[lev] = std::make_unique<amrex::MultiFab>(ba2d, dm, ncomp, ng);
426  t_star[lev]->setVal(0.0); // default to neutral
427 
428  q_star[lev] = std::make_unique<amrex::MultiFab>(ba2d, dm, ncomp, ng);
429  q_star[lev]->setVal(0.0); // default to dry
430 
431  olen[lev] = std::make_unique<amrex::MultiFab>(ba2d, dm, ncomp, ng);
432  olen[lev]->setVal(1.E34);
433 
434  pblh[lev] = std::make_unique<amrex::MultiFab>(ba2d, dm, ncomp, ng);
435  pblh[lev]->setVal(1.E34);
436 
437  t_surf[lev] = std::make_unique<amrex::MultiFab>(ba2d, dm, ncomp, ng);
438  t_surf[lev]->setVal(default_land_surf_temp);
439 
440  q_surf[lev] = std::make_unique<amrex::MultiFab>(ba2d, dm, ncomp, ng);
441  q_surf[lev]->setVal(default_land_surf_moist);
442 
443  // TODO: Do we want an enum struct for indexing?
444 
445  bool use_sst = (!m_sst_lev[lev].empty() && m_sst_lev[lev][0]);
446  bool use_tsk = (!m_tsk_lev[lev].empty() && m_tsk_lev[lev][0]);
447  if (use_sst || use_tsk || m_has_lsm_tsurf) {
448  // Valid SST, TSK or LSM data; t_surf set before computing fluxes (avoids
449  // extended lambda capture) Note that land temp will be set from m_tsk_lev
450  // while sea temp will be set from m_sst_lev
452 
453  // Pathways in fill_tsurf_with_sst_and_tsk
454  amrex::Print() << "Using MOST with specified surface temperature ";
455  // NOTE: SST from the LOW file populates TSK in update_sst_tsk.
456  // So if we have TSK, it contains everything and has been
457  // sanity checked for valid SST values.
458  if (use_tsk) { m_ignore_sst = true; }
459  if (use_tsk) {
460  amrex::Print() << "(land: TSK, ";
461  } else {
462  amrex::Print() << "(land: T0, ";
463  }
464  if (use_tsk && !use_sst) {
465  amrex::Print() << "sea: TSK)" << std::endl;
466  } else {
467  amrex::Print() << "sea: SST)" << std::endl;
469  }
470  }
471  }
472 
473  void
474  update_fluxes (const int& lev,
475  const amrex::Real& elapsed_time_since_start_low,
476  amrex::MultiFab& cons_in,
477  const std::unique_ptr<amrex::MultiFab>& z_phys_nd,
478  const std::unique_ptr<amrex::MultiFab>& walldist,
479  int max_iters = 100);
480 
481  template <typename FluxIter>
482  void compute_fluxes (const int& lev,
483  const int& max_iters,
484  amrex::MultiFab& cons_in,
485  const FluxIter& most_flux,
486  bool is_land);
487 
488  void init_tke_from_ustar (const int& lev,
489  amrex::MultiFab& cons,
490  const std::unique_ptr<amrex::MultiFab>& z_phys_nd,
491  const amrex::Real tkefac = one,
492  const amrex::Real zscale = amrex::Real(700.0));
493 
494  void impose_SurfaceLayer_bcs (const int& lev,
495  amrex::Vector<const amrex::MultiFab*> mfs,
496  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Tau_lev,
497  amrex::MultiFab* xheat_flux,
498  amrex::MultiFab* yheat_flux,
499  amrex::MultiFab* zheat_flux,
500  amrex::MultiFab* xqv_flux,
501  amrex::MultiFab* yqv_flux,
502  amrex::MultiFab* zqv_flux,
503  const amrex::MultiFab* z_phys);
504 
505  void impose_SurfaceLayer_bcs_EB (const int& lev,
506  amrex::Vector<const amrex::MultiFab*> mfs,
507  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Tau_lev,
508  amrex::MultiFab* xheat_flux,
509  amrex::MultiFab* yheat_flux,
510  amrex::MultiFab* zheat_flux,
511  amrex::MultiFab* xqv_flux,
512  amrex::MultiFab* yqv_flux,
513  amrex::MultiFab* zqv_flux,
514  const eb_& ebfact);
515  template <typename FluxCalc>
516  void compute_SurfaceLayer_bcs (const int& lev,
517  amrex::Vector<const amrex::MultiFab*> mfs,
518  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Tau_lev,
519  amrex::MultiFab* xheat_flux,
520  amrex::MultiFab* yheat_flux,
521  amrex::MultiFab* zheat_flux,
522  amrex::MultiFab* xqv_flux,
523  amrex::MultiFab* yqv_flux,
524  amrex::MultiFab* zqv_flux,
525  const amrex::MultiFab* z_phys,
526  const FluxCalc& flux_comp);
527 
528  template <typename FluxCalc>
529  void compute_SurfaceLayer_bcs_EB (const int& lev,
530  amrex::Vector<const amrex::MultiFab*> mfs,
531  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Tau_lev,
532  amrex::MultiFab* xheat_flux,
533  amrex::MultiFab* yheat_flux,
534  amrex::MultiFab* zheat_flux,
535  amrex::MultiFab* xqv_flux,
536  amrex::MultiFab* yqv_flux,
537  amrex::MultiFab* zqv_flux,
538  const eb_& ebfact,
539  const FluxCalc& flux_comp);
540 
541  void fill_tsurf_with_sst_and_tsk (const int& lev,
542  const amrex::Real& time);
543 
544  void fill_qsurf_with_qsat (const int& lev,
545  const amrex::MultiFab& cons_in,
546  const std::unique_ptr<amrex::MultiFab>& z_phys_nd);
547 
548  void get_lsm_tsurf (const int& lev);
549 
550  /* wrapper around compute_pblh */
551  void update_pblh (const int& lev,
552  amrex::Vector<amrex::Vector<amrex::MultiFab>>& vars,
553  amrex::MultiFab* z_phys_cc,
554  const MoistureComponentIndices& moisture_indices);
555 
556  template <typename PBLHeightEstimator>
557  void compute_pblh (const int& lev,
558  amrex::Vector<amrex::Vector<amrex::MultiFab>>& vars,
559  amrex::MultiFab* z_phys_cc,
560  const PBLHeightEstimator& est,
561  const MoistureComponentIndices& moisture_indice);
562 
563  void read_custom_roughness (const int& lev,
564  const std::string& fname);
565 
566  void update_surf_temp (const amrex::Real& time)
567  {
568  if (surf_heating_rate != 0) {
569  int nlevs = static_cast<int>(m_geom.size());
570  for (int lev = 0; lev < nlevs; lev++) {
571  t_surf[lev]->setVal(surf_temp + surf_heating_rate * time);
572  amrex::Print() << "Surface temp at t=" << time << ": "
573  << surf_temp + surf_heating_rate * time << std::endl;
574  }
575  }
576  }
577 
578  void update_mac_ptrs (const int& lev,
579  amrex::Vector<amrex::Vector<amrex::MultiFab>>& vars_old,
580  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Theta_prim,
581  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Qv_prim,
582  amrex::Vector<std::unique_ptr<amrex::MultiFab>>& Qr_prim)
583  {
584  m_ma.update_field_ptrs(lev, vars_old, Theta_prim, Qv_prim, Qr_prim);
585  }
586 
587  amrex::MultiFab* get_u_star (const int& lev) { return u_star[lev].get(); }
588 
589  amrex::MultiFab* get_w_star (const int& lev) { return w_star[lev].get(); }
590 
591  amrex::MultiFab* get_t_star (const int& lev) { return t_star[lev].get(); }
592 
593  amrex::MultiFab* get_q_star (const int& lev) { return q_star[lev].get(); }
594 
595  amrex::MultiFab* get_olen (const int& lev) { return olen[lev].get(); }
596 
597  amrex::MultiFab* get_pblh (const int& lev) { return pblh[lev].get(); }
598 
599  const amrex::MultiFab* get_mac_avg (const int& lev, int comp)
600  {
601  return m_ma.get_average(lev, comp);
602  }
603 
604  amrex::MultiFab* get_t_surf (const int& lev) { return t_surf[lev].get(); }
605  void set_t_surf(const int& lev, const amrex::Real tsurf) { t_surf[lev]->setVal(tsurf); }
606 
607  amrex::MultiFab* get_q_surf (const int& lev) { return q_surf[lev].get(); }
608  void set_q_surf(const int& lev, const amrex::Real qsurf) { q_surf[lev]->setVal(qsurf); }
609 
610  amrex::Real get_zref (const int& lev) { return (m_ma.get_zref(lev))->min(0); }
611 
612  amrex::MultiFab* get_z0 (const int& lev) { return &z_0[lev]; }
613 
615 
616  amrex::iMultiFab* get_lmask (const int& lev) { return m_lmask_lev[lev][0]; }
617 
618  int lmask_min_reduce (amrex::iMultiFab& lmask,
619  const int& nghost)
620  {
621  int lmask_min = amrex::ReduceMin(lmask, nghost, [=] AMREX_GPU_HOST_DEVICE(
622  amrex::Box const& bx, amrex::Array4<int const> const& lm_arr) -> int
623  {
624  int locmin = std::numeric_limits<int>::max();
625  const auto lo = lbound(bx);
626  const auto hi = ubound(bx);
627  for (int j = lo.y; j <= hi.y; ++j) {
628  for (int i = lo.x; i <= hi.x; ++i) {
629  locmin = std::min(locmin, lm_arr(i, j, 0));
630  }
631  }
632  return locmin;
633  });
634 
635  return lmask_min;
636  }
637 
638  void update_sst_ptr(const int lev, const int itime, amrex::MultiFab* sst_ptr) {
639  m_sst_lev[lev][itime] = sst_ptr;
640  }
641 
642  void update_tsk_ptr(const int lev, const int itime, amrex::MultiFab* tsk_ptr) {
643  m_tsk_lev[lev][itime] = tsk_ptr;
644  }
645 
646  enum struct FluxCalcType {
647  MOENG = 0, ///< Moeng functional form
648  DONELAN, ///< Donelan functional form
649  CUSTOM, ///< Custom constant flux functional form
650  BULK_COEFF, ///< Bulk transfer coefficient functional form
651  ROTATE, ///< Terrain rotation flux functional form
652  RICO
653  };
654 
655  enum struct ThetaCalcType {
656  ADIABATIC = 0,
657  HEAT_FLUX, ///< Heat-flux specified
658  SURFACE_TEMPERATURE ///< Surface temperature specified
659  };
660 
661  enum struct MoistCalcType {
662  ADIABATIC = 0,
663  MOISTURE_FLUX, ///< Qv-flux specified
664  SURFACE_MOISTURE ///< Surface Qv specified
665  };
666 
667  enum struct RoughCalcType {
668  CONSTANT = 0, ///< Constant z0
669  CHARNOCK,
671  DONELAN,
673  };
674 
675  enum struct PBLHeightCalcType { None, MYNN25, YSU, MRF };
676 
683 
684 private:
685  // Set in constructor
686  amrex::Vector<amrex::Geometry> m_geom;
687  bool m_rotate = false;
691 
692  bool m_include_wstar = false;
704  amrex::Real custom_rhosurf{0}; // use specified value instead of rho from first cell
705  bool specified_rho_surf{false};
707  bool cnk_visc{false};
709  amrex::Vector<amrex::MultiFab> z_0;
710  bool m_var_z0{false};
711 
714 
716  bool m_has_lsm_tsurf = false;
718 
722 
723  bool m_ignore_sst = false;
724 
726  amrex::Vector<std::unique_ptr<amrex::MultiFab>> u_star;
727  amrex::Vector<std::unique_ptr<amrex::MultiFab>> w_star;
728  amrex::Vector<std::unique_ptr<amrex::MultiFab>> t_star;
729  amrex::Vector<std::unique_ptr<amrex::MultiFab>> q_star;
730  amrex::Vector<std::unique_ptr<amrex::MultiFab>> olen;
731  amrex::Vector<std::unique_ptr<amrex::MultiFab>> pblh;
732  amrex::Vector<std::unique_ptr<amrex::MultiFab>> t_surf;
733  amrex::Vector<std::unique_ptr<amrex::MultiFab>> q_surf;
734 
735  amrex::Vector<amrex::Vector<amrex::MultiFab*>> m_sst_lev;
736  amrex::Vector<amrex::Vector<amrex::MultiFab*>> m_tsk_lev;
737  amrex::Vector<amrex::Vector<amrex::iMultiFab*>> m_lmask_lev;
738  amrex::Vector<amrex::Vector<amrex::MultiFab*>> m_lsm_data_lev;
739  amrex::Vector<amrex::Vector<amrex::MultiFab*>> m_lsm_flux_lev;
740  amrex::Vector<std::string> m_lsm_data_name;
741  amrex::Vector<std::string> m_lsm_flux_name;
742  amrex::Vector<amrex::MultiFab*> m_Hwave_lev;
743  amrex::Vector<amrex::MultiFab*> m_Lwave_lev;
744  amrex::Vector<amrex::MultiFab*> m_eddyDiffs_lev;
745 
746  bool m_update_k_rans = false;
749 };
750 
751 #endif /* SURFACELAYER_H */
constexpr amrex::Real one
Definition: ERF_Constants.H:7
constexpr amrex::Real zero
Definition: ERF_Constants.H:6
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:14
amrex::MultiFab * get_zref(const int &lev) const
Definition: ERF_MOSTAverage.H:108
const amrex::MultiFab * get_average(const int &lev, const int &comp) const
Definition: ERF_MOSTAverage.H:105
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:269
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:85
Definition: ERF_SurfaceLayer.H:32
ThetaCalcType theta_type
Definition: ERF_SurfaceLayer.H:678
int lmask_min_reduce(amrex::iMultiFab &lmask, const int &nghost)
Definition: ERF_SurfaceLayer.H:618
amrex::Vector< std::string > m_lsm_data_name
Definition: ERF_SurfaceLayer.H:740
bool m_include_wstar
Definition: ERF_SurfaceLayer.H:692
bool specified_rho_surf
Definition: ERF_SurfaceLayer.H:705
void set_q_surf(const int &lev, const amrex::Real qsurf)
Definition: ERF_SurfaceLayer.H:608
bool m_rotate
Definition: ERF_SurfaceLayer.H:687
PBLHeightCalcType pblh_type
Definition: ERF_SurfaceLayer.H:682
amrex::Vector< amrex::Vector< amrex::iMultiFab * > > m_lmask_lev
Definition: ERF_SurfaceLayer.H:737
amrex::iMultiFab * get_lmask(const int &lev)
Definition: ERF_SurfaceLayer.H:616
bool use_moisture
Definition: ERF_SurfaceLayer.H:715
amrex::MultiFab * get_q_surf(const int &lev)
Definition: ERF_SurfaceLayer.H:607
bool m_has_lsm_tsurf
Definition: ERF_SurfaceLayer.H:716
amrex::MultiFab * get_w_star(const int &lev)
Definition: ERF_SurfaceLayer.H:589
void update_surf_temp(const amrex::Real &time)
Definition: ERF_SurfaceLayer.H:566
amrex::Real m_Cq
Definition: ERF_SurfaceLayer.H:721
RoughCalcType rough_type_land
Definition: ERF_SurfaceLayer.H:680
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:893
amrex::Vector< std::unique_ptr< amrex::MultiFab > > t_surf
Definition: ERF_SurfaceLayer.H:732
amrex::Real z0_const
Definition: ERF_SurfaceLayer.H:693
amrex::Real cnk_a
Definition: ERF_SurfaceLayer.H:706
amrex::Real m_Ch
Definition: ERF_SurfaceLayer.H:720
amrex::Real m_start_low_time
Definition: ERF_SurfaceLayer.H:688
amrex::Real surf_temp
Definition: ERF_SurfaceLayer.H:695
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:578
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:729
int m_lsm_tsurf_indx
Definition: ERF_SurfaceLayer.H:717
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, amrex::Real start_low_time, amrex::Real final_low_time, amrex::Real low_time_interval=zero)
Definition: ERF_SurfaceLayer.H:36
amrex::Real rico_qsat_z0
Definition: ERF_SurfaceLayer.H:713
void impose_SurfaceLayer_bcs_EB(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 eb_ &ebfact)
Definition: ERF_SurfaceLayer.cpp:370
bool m_update_k_rans
Definition: ERF_SurfaceLayer.H:746
amrex::Vector< amrex::MultiFab * > m_Lwave_lev
Definition: ERF_SurfaceLayer.H:743
void get_lsm_tsurf(const int &lev)
Definition: ERF_SurfaceLayer.cpp:858
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:815
amrex::Real get_zref(const int &lev)
Definition: ERF_SurfaceLayer.H:610
amrex::MultiFab * get_olen(const int &lev)
Definition: ERF_SurfaceLayer.H:595
amrex::Vector< amrex::MultiFab > z_0
Definition: ERF_SurfaceLayer.H:709
amrex::Real surf_moist_flux
Definition: ERF_SurfaceLayer.H:700
void compute_SurfaceLayer_bcs_EB(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 eb_ &ebfact, const FluxCalc &flux_comp)
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:681
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:920
amrex::Real surf_moist
Definition: ERF_SurfaceLayer.H:699
amrex::Vector< std::unique_ptr< amrex::MultiFab > > w_star
Definition: ERF_SurfaceLayer.H:727
bool m_ignore_sst
Definition: ERF_SurfaceLayer.H:723
amrex::MultiFab * get_u_star(const int &lev)
Definition: ERF_SurfaceLayer.H:587
void compute_fluxes(const int &lev, const int &max_iters, amrex::MultiFab &cons_in, const FluxIter &most_flux, bool is_land)
void update_fluxes(const int &lev, const amrex::Real &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:12
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_lsm_data_lev
Definition: ERF_SurfaceLayer.H:738
void set_t_surf(const int &lev, const amrex::Real tsurf)
Definition: ERF_SurfaceLayer.H:605
amrex::Real custom_qstar
Definition: ERF_SurfaceLayer.H:703
amrex::Vector< std::unique_ptr< amrex::MultiFab > > u_star
Definition: ERF_SurfaceLayer.H:726
void update_tsk_ptr(const int lev, const int itime, amrex::MultiFab *tsk_ptr)
Definition: ERF_SurfaceLayer.H:642
amrex::Real custom_rhosurf
Definition: ERF_SurfaceLayer.H:704
amrex::Vector< std::unique_ptr< amrex::MultiFab > > q_surf
Definition: ERF_SurfaceLayer.H:733
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_sst_lev
Definition: ERF_SurfaceLayer.H:735
FluxCalcType
Definition: ERF_SurfaceLayer.H:646
@ 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:661
@ SURFACE_MOISTURE
Surface Qv specified.
@ MOISTURE_FLUX
Qv-flux specified.
amrex::Real depth
Definition: ERF_SurfaceLayer.H:708
amrex::Vector< amrex::MultiFab * > m_Hwave_lev
Definition: ERF_SurfaceLayer.H:742
amrex::Real default_land_surf_moist
Definition: ERF_SurfaceLayer.H:698
bool m_var_z0
Definition: ERF_SurfaceLayer.H:710
amrex::MultiFab * get_t_star(const int &lev)
Definition: ERF_SurfaceLayer.H:591
bool have_variable_sea_roughness()
Definition: ERF_SurfaceLayer.H:614
amrex::MultiFab * get_q_star(const int &lev)
Definition: ERF_SurfaceLayer.H:593
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_lsm_flux_lev
Definition: ERF_SurfaceLayer.H:739
PBLHeightCalcType
Definition: ERF_SurfaceLayer.H:675
amrex::MultiFab * get_pblh(const int &lev)
Definition: ERF_SurfaceLayer.H:597
amrex::Real rico_theta_z0
Definition: ERF_SurfaceLayer.H:712
void fill_tsurf_with_sst_and_tsk(const int &lev, const amrex::Real &time)
Definition: ERF_SurfaceLayer.cpp:728
amrex::Real surf_temp_flux
Definition: ERF_SurfaceLayer.H:697
amrex::Vector< amrex::Geometry > m_geom
Definition: ERF_SurfaceLayer.H:686
amrex::Vector< std::unique_ptr< amrex::MultiFab > > t_star
Definition: ERF_SurfaceLayer.H:728
amrex::Real theta_ref
Definition: ERF_SurfaceLayer.H:748
amrex::MultiFab * get_z0(const int &lev)
Definition: ERF_SurfaceLayer.H:612
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_tsk_lev
Definition: ERF_SurfaceLayer.H:736
amrex::Real custom_tstar
Definition: ERF_SurfaceLayer.H:702
amrex::Real m_final_low_time
Definition: ERF_SurfaceLayer.H:689
bool cnk_visc
Definition: ERF_SurfaceLayer.H:707
amrex::Real surf_heating_rate
Definition: ERF_SurfaceLayer.H:696
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:267
RoughCalcType
Definition: ERF_SurfaceLayer.H:667
FluxCalcType flux_type
Definition: ERF_SurfaceLayer.H:677
MoistCalcType moist_type
Definition: ERF_SurfaceLayer.H:679
amrex::Real inv_Cmu2
Definition: ERF_SurfaceLayer.H:747
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:310
amrex::Vector< amrex::MultiFab * > m_eddyDiffs_lev
Definition: ERF_SurfaceLayer.H:744
const amrex::MultiFab * get_mac_avg(const int &lev, int comp)
Definition: ERF_SurfaceLayer.H:599
void update_sst_ptr(const int lev, const int itime, amrex::MultiFab *sst_ptr)
Definition: ERF_SurfaceLayer.H:638
amrex::Real custom_ustar
Definition: ERF_SurfaceLayer.H:701
amrex::Vector< std::unique_ptr< amrex::MultiFab > > olen
Definition: ERF_SurfaceLayer.H:730
amrex::MultiFab * get_t_surf(const int &lev)
Definition: ERF_SurfaceLayer.H:604
amrex::Real m_Cd
Definition: ERF_SurfaceLayer.H:719
amrex::Vector< std::unique_ptr< amrex::MultiFab > > pblh
Definition: ERF_SurfaceLayer.H:731
amrex::Real default_land_surf_temp
Definition: ERF_SurfaceLayer.H:694
ThetaCalcType
Definition: ERF_SurfaceLayer.H:655
@ 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:989
amrex::Vector< std::string > m_lsm_flux_name
Definition: ERF_SurfaceLayer.H:741
amrex::Real m_low_time_interval
Definition: ERF_SurfaceLayer.H:690
MOSTAverage m_ma
Definition: ERF_SurfaceLayer.H:725
Definition: ERF_EB.H:13
@ ng
Definition: ERF_Morrison.H:48
@ cons
Definition: ERF_IndexDefines.H:158
real(c_double), parameter epsilon
Definition: ERF_module_model_constants.F90:12
Definition: ERF_DataStruct.H:106
Definition: ERF_TurbStruct.H:42
RANSType rans_type
Definition: ERF_TurbStruct.H:413
bool dirichlet_k
Definition: ERF_TurbStruct.H:415
amrex::Real Cmu0
Definition: ERF_TurbStruct.H:391
amrex::Real theta_ref
Definition: ERF_TurbStruct.H:402