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