ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ABLMost Class Reference

#include <ABLMost.H>

Collaboration diagram for ABLMost:

Public Types

enum class  FluxCalcType { MOENG = 0 , DONELAN , CUSTOM }
 
enum class  ThetaCalcType { ADIABATIC = 0 , HEAT_FLUX , SURFACE_TEMPERATURE }
 
enum class  RoughCalcType { CONSTANT = 0 , CHARNOCK , MODIFIED_CHARNOCK }
 

Public Member Functions

 ABLMost (const amrex::Vector< amrex::Geometry > &geom, bool &use_exp_most, 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 >> &z_phys_nd, amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab >>> &sst_lev, amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab >>> &lmask_lev, amrex::Vector< amrex::Vector< amrex::MultiFab * >> lsm_data, amrex::Vector< amrex::Vector< amrex::MultiFab * >> lsm_flux, amrex::Real start_bdy_time=0.0, amrex::Real bdy_time_interval=0.0)
 
void update_fluxes (const int &lev, const amrex::Real &time, int max_iters=25)
 
template<typename FluxIter >
void compute_fluxes (const int &lev, const int &max_iters, const FluxIter &most_flux)
 
void impose_most_bcs (const int &lev, const amrex::Vector< amrex::MultiFab * > &mfs, amrex::MultiFab *xzmom_flux, amrex::MultiFab *zxmom_flux, amrex::MultiFab *yzmom_flux, amrex::MultiFab *zymom_flux, amrex::MultiFab *heat_flux, amrex::MultiFab *eddyDiffs, amrex::MultiFab *z_phys)
 
template<typename FluxCalc >
void compute_most_bcs (const int &lev, const amrex::Vector< amrex::MultiFab * > &mfs, amrex::MultiFab *xzmom_flux, amrex::MultiFab *zxmom_flux, amrex::MultiFab *yzmom_flux, amrex::MultiFab *zymom_flux, amrex::MultiFab *heat_flux, amrex::MultiFab *eddyDiffs, amrex::MultiFab *z_phys, const amrex::Real &dz_no_terrain, const FluxCalc &flux_comp)
 
void time_interp_sst (const int &lev, const amrex::Real &time)
 
void get_lsm_tsurf (const int &lev)
 
void update_surf_temp (const amrex::Real &time)
 
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)
 
const amrex::MultiFab * get_u_star (const int &lev)
 
const amrex::MultiFab * get_t_star (const int &lev)
 
const amrex::MultiFab * get_olen (const int &lev)
 
const amrex::MultiFab * get_mac_avg (const int &lev, int comp)
 
const amrex::MultiFab * get_t_surf (const int &lev)
 
amrex::Real get_zref ()
 
const amrex::FArrayBox * get_z0 (const int &lev)
 
template<typename FluxCalc >
void compute_most_bcs (const int &lev, const Vector< MultiFab * > &mfs, MultiFab *xzmom_flux, MultiFab *zxmom_flux, MultiFab *yzmom_flux, MultiFab *zymom_flux, MultiFab *heat_flux, MultiFab *eddyDiffs, MultiFab *z_phys, const Real &dz_no_terrain, const FluxCalc &flux_comp)
 

Public Attributes

FluxCalcType flux_type {FluxCalcType::MOENG}
 
ThetaCalcType theta_type {ThetaCalcType::ADIABATIC}
 
RoughCalcType rough_type {RoughCalcType::CONSTANT}
 

Private Attributes

bool use_moisture
 
bool m_exp_most = false
 
amrex::Real z0_const
 
amrex::Real surf_temp
 
amrex::Real surf_heating_rate {0}
 
amrex::Real surf_temp_flux {0}
 
amrex::Real custom_ustar {0}
 
amrex::Real custom_tstar {0}
 
amrex::Real custom_qstar {0}
 
amrex::Real cnk_a {0.0185}
 
amrex::Real depth {30.0}
 
amrex::Real m_start_bdy_time
 
amrex::Real m_bdy_time_interval
 
amrex::Vector< amrex::Geometry > m_geom
 
amrex::Vector< amrex::FArrayBox > z_0
 
MOSTAverage m_ma
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > u_star
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > t_star
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > q_star
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > olen
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > t_surf
 
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_sst_lev
 
amrex::Vector< amrex::Vector< amrex::iMultiFab * > > m_lmask_lev
 
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_lsm_data_lev
 
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_lsm_flux_lev
 

Detailed Description

Monin-Obukhov surface layer profile

van der Laan, P., Kelly, M. C., & Sørensen, N. N. (2017). A new k-epsilon model consistent with Monin-Obukhov similarity theory. Wind Energy, 20(3), 479–489. https://doi.org/10.1002/we.2017

Consistent with Dyer (1974) formulation from page 57, Chapter 2, Modeling the vertical ABL structure in Modelling of Atmospheric Flow Fields, Demetri P Lalas and Corrado F Ratto, January 1996, https://doi.org/10.1142/2975.

Member Enumeration Documentation

◆ FluxCalcType

enum ABLMost::FluxCalcType
strong
Enumerator
MOENG 

Moeng functional form.

DONELAN 

Donelan functional form.

CUSTOM 

Custom constant flux functional form.

294  {
295  MOENG = 0, ///< Moeng functional form
296  DONELAN, ///< Donelan functional form
297  CUSTOM ///< Custom constant flux functional form
298  };

◆ RoughCalcType

Enumerator
CONSTANT 

Constant z0.

CHARNOCK 
MODIFIED_CHARNOCK 
306  {
307  CONSTANT = 0, ///< Constant z0
308  CHARNOCK,
309  MODIFIED_CHARNOCK
310  };

◆ ThetaCalcType

Enumerator
ADIABATIC 
HEAT_FLUX 

Heat-flux specified.

SURFACE_TEMPERATURE 

Surface temperature specified.

300  {
301  ADIABATIC = 0,
302  HEAT_FLUX, ///< Heat-flux specified
303  SURFACE_TEMPERATURE ///< Surface temperature specified
304  };

Constructor & Destructor Documentation

◆ ABLMost()

ABLMost::ABLMost ( const amrex::Vector< amrex::Geometry > &  geom,
bool &  use_exp_most,
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 >> &  z_phys_nd,
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab >>> &  sst_lev,
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab >>> &  lmask_lev,
amrex::Vector< amrex::Vector< amrex::MultiFab * >>  lsm_data,
amrex::Vector< amrex::Vector< amrex::MultiFab * >>  lsm_flux,
amrex::Real  start_bdy_time = 0.0,
amrex::Real  bdy_time_interval = 0.0 
)
inlineexplicit
44  : m_exp_most(use_exp_most),
45  m_start_bdy_time(start_bdy_time),
46  m_bdy_time_interval(bdy_time_interval),
47  m_geom(geom),
48  m_ma(geom,vars_old,Theta_prim,Qv_prim,z_phys_nd)
49  {
50  // We have a moisture model if Qv_prim is a valid pointer
51  use_moisture = (Qv_prim[0].get());
52 
53  // Get roughness
54  amrex::ParmParse pp("erf");
55  pp.query("most.z0", z0_const);
56 
57  // Specify how to compute the flux
58  std::string flux_string{"moeng"};
59  pp.query("most.flux_type", flux_string);
60  if (flux_string == "donelan") {
62  } else if (flux_string == "moeng") {
64  } else if (flux_string == "custom") {
66  } else {
67  amrex::Abort("Undefined MOST flux type!");
68  }
69 
70  // Get surface temperature
71  auto erf_st = pp.query("most.surf_temp", surf_temp);
72 
73  // Custom type user must specify the fluxes
76  pp.query("most.ustar", custom_ustar);
77  pp.query("most.tstar", custom_tstar);
78  pp.query("most.qstar", custom_qstar);
79  if (custom_qstar != 0) {
80  AMREX_ASSERT_WITH_MESSAGE(use_moisture, "Specified custom MOST qv flux without moisture model!");
81  }
82  amrex::Print() << "Using specified ustar, tstar, qstar for MOST = "
83  << custom_ustar << " "
84  << custom_tstar << " "
85  << custom_qstar << std::endl;
86 
87  // Specify surface temperature or surface flux
88  } else {
89  if (erf_st) {
91  pp.query("most.surf_heating_rate", surf_heating_rate); // [K/h]
92  surf_heating_rate = surf_heating_rate / 3600.0; // [K/s]
93  if (pp.query("most.surf_temp_flux", surf_temp_flux)) {
94  amrex::Abort("Can only specify one of surf_temp_flux or surf_heating_rate");
95  }
96  } else {
97  pp.query("most.surf_temp_flux", surf_temp_flux);
98  if (pp.query("most.surf_heating_rate", surf_heating_rate)) {
99  amrex::Abort("Can only specify one of surf_temp_flux or surf_heating_rate");
100  }
101  if (std::abs(surf_temp_flux) > std::numeric_limits<amrex::Real>::epsilon()) {
103  } else {
105  }
106  }
107  }
108 
109  // Specify how to compute the flux
110  std::string rough_string{"constant"};
111  pp.query("most.roughness_type", rough_string);
112  if (rough_string == "constant") {
114  } else if (rough_string == "charnock") {
116  pp.query("most.charnock_constant",cnk_a);
117  } else if (rough_string == "modified_charnock") {
119  pp.query("most.modified_charnock_depth",depth);
120  } else {
121  amrex::Abort("Undefined MOST roughness type!");
122  }
123 
124  // Size the MOST params for all levels
125  int nlevs = m_geom.size();
126  z_0.resize(nlevs);
127  u_star.resize(nlevs);
128  t_star.resize(nlevs);
129  q_star.resize(nlevs);
130  t_surf.resize(nlevs);
131  olen.resize(nlevs);
132 
133  // Get pointers to SST and LANDMASK data
134  m_sst_lev.resize(nlevs);
135  m_lmask_lev.resize(nlevs);
136  for (int lev(0); lev<nlevs; ++lev) {
137  int nt_tot = sst_lev[lev].size();
138  m_sst_lev[lev].resize(nt_tot);
139  m_lmask_lev[lev].resize(nt_tot);
140  for (int nt(0); nt<nt_tot; ++nt) {
141  m_sst_lev[lev][nt] = sst_lev[lev][nt].get();
142  m_lmask_lev[lev][nt] = lmask_lev[lev][nt].get();
143  }
144  }
145 
146  // Get pointers to LSM data and Fluxes
147  m_lsm_data_lev.resize(nlevs);
148  m_lsm_flux_lev.resize(nlevs);
149  for (int lev(0); lev<nlevs; ++lev) {
150  int nvar = lsm_data[lev].size();
151  m_lsm_data_lev[lev].resize(nvar);
152  m_lsm_flux_lev[lev].resize(nvar);
153  for (int n(0); n<nvar; ++n) {
154  m_lsm_data_lev[lev][n] = lsm_data[lev][n];
155  m_lsm_flux_lev[lev][n] = lsm_flux[lev][n];
156  }
157  }
158 
159  for (int lev = 0; lev < nlevs; lev++) {
160  // Attributes for MFs and FABs
161  //--------------------------------------------------------
162  auto& mf = vars_old[lev][Vars::cons];
163  // Create a 2D ba, dm, & ghost cells
164  amrex::BoxArray ba = mf.boxArray();
165  amrex::BoxList bl2d = ba.boxList();
166  for (auto& b : bl2d) {
167  b.setRange(2,0);
168  }
169  amrex::BoxArray ba2d(std::move(bl2d));
170  const amrex::DistributionMapping& dm = mf.DistributionMap();
171  const int ncomp = 1;
172  amrex::IntVect ng = mf.nGrowVect(); ng[2]=0;
173 
174  // Z0 heights FAB
175  //--------------------------------------------------------
176  amrex::Box bx = amrex::grow(m_geom[lev].Domain(),ng);
177  bx.setSmall(2,0);
178  bx.setBig(2,0);
179  z_0[lev].resize(bx,1);
180  z_0[lev].setVal<amrex::RunOn::Device>(z0_const);
181 
182  // 2D MFs for U*, T*, T_surf
183  //--------------------------------------------------------
184  u_star[lev] = std::make_unique<amrex::MultiFab>(ba2d,dm,ncomp,ng);
185  u_star[lev]->setVal(1.E34);
186 
187  t_star[lev] = std::make_unique<amrex::MultiFab>(ba2d,dm,ncomp,ng);
188  t_star[lev]->setVal(1.E34);
189 
190  q_star[lev] = std::make_unique<amrex::MultiFab>(ba2d,dm,ncomp,ng);
191  q_star[lev]->setVal(1.E34);
192 
193  olen[lev] = std::make_unique<amrex::MultiFab>(ba2d,dm,ncomp,ng);
194  olen[lev]->setVal(1.E34);
195 
196  t_surf[lev] = std::make_unique<amrex::MultiFab>(ba2d,dm,ncomp,ng);
197 
198  // TODO: Do we want lsm_data to have theta at 0 index always?
199  // Do we want an external enum struct for indexing?
200  if (m_sst_lev[lev][0] || m_lsm_data_lev[lev][0]) {
201  // Valid SST or LSM data; t_surf set before computing fluxes (avoids extended lambda capture)
203  } else if (erf_st) {
204  t_surf[lev]->setVal(surf_temp);
205  } else {
206  t_surf[lev]->setVal(0.0);
207  }
208  }// lev
209  }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real pp(amrex::Real y)
Definition: Microphysics_Utils.H:183
amrex::Real m_bdy_time_interval
Definition: ABLMost.H:329
amrex::Vector< std::unique_ptr< amrex::MultiFab > > q_star
Definition: ABLMost.H:336
amrex::Vector< std::unique_ptr< amrex::MultiFab > > olen
Definition: ABLMost.H:337
amrex::Vector< amrex::FArrayBox > z_0
Definition: ABLMost.H:331
amrex::Vector< amrex::Geometry > m_geom
Definition: ABLMost.H:330
amrex::Real custom_ustar
Definition: ABLMost.H:323
amrex::Vector< std::unique_ptr< amrex::MultiFab > > t_surf
Definition: ABLMost.H:338
amrex::Real custom_qstar
Definition: ABLMost.H:325
amrex::Real depth
Definition: ABLMost.H:327
amrex::Real surf_heating_rate
Definition: ABLMost.H:321
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_lsm_flux_lev
Definition: ABLMost.H:343
MOSTAverage m_ma
Definition: ABLMost.H:333
@ SURFACE_TEMPERATURE
Surface temperature specified.
@ HEAT_FLUX
Heat-flux specified.
amrex::Real m_start_bdy_time
Definition: ABLMost.H:328
amrex::Real surf_temp
Definition: ABLMost.H:320
amrex::Real cnk_a
Definition: ABLMost.H:326
ThetaCalcType theta_type
Definition: ABLMost.H:313
@ MOENG
Moeng functional form.
@ CUSTOM
Custom constant flux functional form.
@ DONELAN
Donelan functional form.
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_lsm_data_lev
Definition: ABLMost.H:342
RoughCalcType rough_type
Definition: ABLMost.H:314
amrex::Real surf_temp_flux
Definition: ABLMost.H:322
amrex::Vector< amrex::Vector< amrex::iMultiFab * > > m_lmask_lev
Definition: ABLMost.H:341
bool use_moisture
Definition: ABLMost.H:317
bool m_exp_most
Definition: ABLMost.H:318
amrex::Vector< std::unique_ptr< amrex::MultiFab > > t_star
Definition: ABLMost.H:335
amrex::Vector< std::unique_ptr< amrex::MultiFab > > u_star
Definition: ABLMost.H:334
amrex::Real z0_const
Definition: ABLMost.H:319
FluxCalcType flux_type
Definition: ABLMost.H:312
amrex::Vector< amrex::Vector< amrex::MultiFab * > > m_sst_lev
Definition: ABLMost.H:340
@ CONSTANT
Constant z0.
amrex::Real custom_tstar
Definition: ABLMost.H:324
@ cons
Definition: IndexDefines.H:99
Here is the call graph for this function:

Member Function Documentation

◆ compute_fluxes()

template<typename FluxIter >
void ABLMost::compute_fluxes ( const int &  lev,
const int &  max_iters,
const FluxIter &  most_flux 
)

Function to compute the fluxes (u^star and t^star) for Monin Obukhov similarity theory.

Parameters
[in]levCurrent level
[in]max_itersmaximum iterations to use
[in]most_fluxstructure to iteratively compute ustar and tstar
87 {
88  // Pointers to the computed averages
89  const auto *const tm_ptr = m_ma.get_average(lev,2);
90  const auto *const umm_ptr = m_ma.get_average(lev,4);
91 
92  for (MFIter mfi(*u_star[lev]); mfi.isValid(); ++mfi)
93  {
94  Box gtbx = mfi.growntilebox();
95 
96  auto u_star_arr = u_star[lev]->array(mfi);
97  auto t_star_arr = t_star[lev]->array(mfi);
98  auto t_surf_arr = t_surf[lev]->array(mfi);
99  auto olen_arr = olen[lev]->array(mfi);
100 
101  const auto tm_arr = tm_ptr->array(mfi);
102  const auto umm_arr = umm_ptr->array(mfi);
103  const auto z0_arr = z_0[lev].array();
104 
105  ParallelFor(gtbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
106  {
107  most_flux.iterate_flux(i, j, k, max_iters, z0_arr, umm_arr, tm_arr,
108  u_star_arr, t_star_arr, t_surf_arr, olen_arr);
109  });
110  }
111 }
const amrex::MultiFab * get_average(int lev, int comp) const
Definition: MOSTAverage.H:87

◆ compute_most_bcs() [1/2]

template<typename FluxCalc >
void ABLMost::compute_most_bcs ( const int &  lev,
const amrex::Vector< amrex::MultiFab * > &  mfs,
amrex::MultiFab *  xzmom_flux,
amrex::MultiFab *  zxmom_flux,
amrex::MultiFab *  yzmom_flux,
amrex::MultiFab *  zymom_flux,
amrex::MultiFab *  heat_flux,
amrex::MultiFab *  eddyDiffs,
amrex::MultiFab *  z_phys,
const amrex::Real &  dz_no_terrain,
const FluxCalc &  flux_comp 
)

◆ compute_most_bcs() [2/2]

template<typename FluxCalc >
void ABLMost::compute_most_bcs ( const int &  lev,
const Vector< MultiFab * > &  mfs,
MultiFab *  xzmom_flux,
MultiFab *  zxmom_flux,
MultiFab *  yzmom_flux,
MultiFab *  zymom_flux,
MultiFab *  heat_flux,
MultiFab *  eddyDiffs,
MultiFab *  z_phys,
const Real &  dz_no_terrain,
const FluxCalc &  flux_comp 
)

Function to calculate MOST fluxes for populating ghost cells.

Parameters
[in]levCurrent level
[in,out]mfsMultifabs to populate
[in]eddyDiffsDiffusion coefficients from turbulence model
[in]flux_compstructure to compute fluxes
178 {
179  const int klo = 0;
180  const int icomp = 0;
181  for (MFIter mfi(*mfs[0]); mfi.isValid(); ++mfi)
182  {
183  // TODO: No LSM lateral ghost cells, should this change?
184  // Valid CC box
185  Box vbx = mfi.validbox(); vbx.makeSlab(2,klo-1);
186 
187  Box vbxx = surroundingNodes(vbx,0);
188  Box vbxy = surroundingNodes(vbx,1);
189 
190  // Expose for GPU
191  bool exp_most = m_exp_most;
192 
193  // Get field arrays
194  const auto cons_arr = mfs[Vars::cons]->array(mfi);
195  const auto velx_arr = mfs[Vars::xvel]->array(mfi);
196  const auto vely_arr = mfs[Vars::yvel]->array(mfi);
197 
198  auto t13_arr = (m_exp_most) ? xzmom_flux->array(mfi) : Array4<Real>{};
199  auto t23_arr = (m_exp_most) ? yzmom_flux->array(mfi) : Array4<Real>{};
200  auto t31_arr = (zxmom_flux && m_exp_most) ? zxmom_flux->array(mfi) : Array4<Real>{};
201  auto t32_arr = (zymom_flux && m_exp_most) ? zymom_flux->array(mfi) : Array4<Real>{};
202  auto hfx_arr = (m_exp_most) ? heat_flux->array(mfi) : Array4<Real>{};
203 
204  const auto eta_arr = eddyDiffs->array(mfi);
205 
206  const auto zphys_arr = (z_phys) ? z_phys->const_array(mfi) : Array4<const Real>{};
207 
208  // Get average arrays
209  const auto *const u_mean = m_ma.get_average(lev,0);
210  const auto *const v_mean = m_ma.get_average(lev,1);
211  const auto *const t_mean = m_ma.get_average(lev,2);
212  const auto *const q_mean = m_ma.get_average(lev,3);
213  const auto *const u_mag_mean = m_ma.get_average(lev,4);
214 
215  const auto um_arr = u_mean->array(mfi);
216  const auto vm_arr = v_mean->array(mfi);
217  const auto tm_arr = t_mean->array(mfi);
218  const auto qm_arr = q_mean->array(mfi);
219  const auto umm_arr = u_mag_mean->array(mfi);
220 
221  // Get derived arrays
222  const auto u_star_arr = u_star[lev]->array(mfi);
223  const auto t_star_arr = t_star[lev]->array(mfi);
224  const auto q_star_arr = q_star[lev]->array(mfi);
225  const auto t_surf_arr = t_surf[lev]->array(mfi);
226 
227  // Get LSM fluxes
228  auto lmask_arr = (m_lmask_lev[lev][0]) ? m_lmask_lev[lev][0]->array(mfi) :
229  Array4<int> {};
230  auto lsm_flux_arr = (m_lsm_flux_lev[lev][0]) ? m_lsm_flux_lev[lev][0]->array(mfi) :
231  Array4<Real> {};
232 
233  for (int var_idx = 0; var_idx < Vars::NumTypes; ++var_idx)
234  {
235  const Box& bx = (*mfs[var_idx])[mfi].box();
236  auto dest_arr = (*mfs[var_idx])[mfi].array();
237 
238  if (var_idx == Vars::cons) {
239  Box b2d = bx;
240  b2d.setBig(2,klo-1);
241  int n = RhoTheta_comp;
242  ParallelFor(b2d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
243  {
244  Real dz = (zphys_arr) ? ( zphys_arr(i,j,klo ) - zphys_arr(i,j,klo-1) ) : dz_no_terrain;
245  Real dz1 = (zphys_arr) ? ( zphys_arr(i,j,klo+1) - zphys_arr(i,j,klo ) ) : dz_no_terrain;
246  Real Tflux = flux_comp.compute_t_flux(i, j, k, n, icomp, dz, dz1, exp_most, eta_arr,
247  cons_arr, velx_arr, vely_arr,
248  umm_arr, tm_arr, u_star_arr, t_star_arr, t_surf_arr,
249  dest_arr);
250 
251 
252  // TODO: make sure not to double-count surface heat flux if using a LSM
253  int is_land = (lmask_arr) ? lmask_arr(i,j,klo) : 1;
254  if (is_land && lsm_flux_arr && vbx.contains(i,j,k)) {
255  lsm_flux_arr(i,j,klo) = Tflux;
256  }
257  else if ((k == klo-1) && vbx.contains(i,j,k) && exp_most) {
258  hfx_arr(i,j,klo-1) = Tflux;
259  }
260  });
261 
262  // TODO: Generalize MOST q flux with MOENG & DONELAN flux types
264  n = RhoQ1_comp;
265  ParallelFor(b2d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
266  {
267  Real dz = (zphys_arr) ? ( zphys_arr(i,j,klo ) - zphys_arr(i,j,klo-1) ) : dz_no_terrain;
268  Real dz1 = (zphys_arr) ? ( zphys_arr(i,j,klo+1) - zphys_arr(i,j,klo ) ) : dz_no_terrain;
269  Real Qflux = flux_comp.compute_q_flux(i, j, k, n, icomp, dz, dz1, exp_most, eta_arr,
270  cons_arr, velx_arr, vely_arr,
271  umm_arr, qm_arr, u_star_arr, q_star_arr, t_surf_arr,
272  dest_arr);
273  amrex::ignore_unused(Qflux);
274  });
275  }
276 
277  } else if (var_idx == Vars::xvel) {
278 
279  Box xb2d = surroundingNodes(bx,0);
280  xb2d.setBig(2,klo-1);
281 
282  ParallelFor(xb2d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
283  {
284  Real dz = (zphys_arr) ? ( zphys_arr(i,j,klo ) - zphys_arr(i,j,klo-1) ) : dz_no_terrain;
285  Real dz1 = (zphys_arr) ? ( zphys_arr(i,j,klo+1) - zphys_arr(i,j,klo ) ) : dz_no_terrain;
286  Real stressx = flux_comp.compute_u_flux(i, j, k, icomp, dz, dz1, exp_most, eta_arr,
287  cons_arr, velx_arr, vely_arr,
288  umm_arr, um_arr, u_star_arr,
289  dest_arr);
290  if ((k == klo-1) && vbxx.contains(i,j,k) && exp_most) {
291  t13_arr(i,j,klo) = -stressx;
292  if (t31_arr) t31_arr(i,j,klo) = -stressx;
293  }
294  amrex::ignore_unused(stressx);
295  });
296 
297  } else if (var_idx == Vars::yvel) {
298 
299  Box yb2d = surroundingNodes(bx,1);
300  yb2d.setBig(2,klo-1);
301 
302  ParallelFor(yb2d, [=] AMREX_GPU_DEVICE (int i, int j, int k)
303  {
304  Real dz = (zphys_arr) ? ( zphys_arr(i,j,klo ) - zphys_arr(i,j,klo-1) ) : dz_no_terrain;
305  Real dz1 = (zphys_arr) ? ( zphys_arr(i,j,klo+1) - zphys_arr(i,j,klo ) ) : dz_no_terrain;
306  Real stressy = flux_comp.compute_v_flux(i, j, k, icomp, dz, dz1, exp_most, eta_arr,
307  cons_arr, velx_arr, vely_arr,
308  umm_arr, vm_arr, u_star_arr,
309  dest_arr);
310  if ((k == klo-1) && vbxy.contains(i,j,k) && exp_most) {
311  t23_arr(i,j,klo) = -stressy;
312  if (t32_arr) t32_arr(i,j,klo) = -stressy;
313  }
314  amrex::ignore_unused(stressy);
315  });
316  }
317  } // var_idx
318  } // mfiter
319 }
#define RhoTheta_comp
Definition: IndexDefines.H:13
#define RhoQ1_comp
Definition: IndexDefines.H:17
@ xvel
Definition: IndexDefines.H:100
@ NumTypes
Definition: IndexDefines.H:103
@ yvel
Definition: IndexDefines.H:101

◆ get_lsm_tsurf()

void ABLMost::get_lsm_tsurf ( const int &  lev)
358 {
359  for (MFIter mfi(*t_surf[lev]); mfi.isValid(); ++mfi)
360  {
361  Box gtbx = mfi.growntilebox();
362 
363  // TODO: LSM does not carry lateral ghost cells.
364  // This copies the valid box into the ghost cells.
365  // Fillboundary is called after this to pick up the
366  // interior ghost and periodic directions. Is there
367  // a better approach?
368  Box vbx = mfi.validbox();
369  int i_lo = vbx.smallEnd(0); int i_hi = vbx.bigEnd(0);
370  int j_lo = vbx.smallEnd(1); int j_hi = vbx.bigEnd(1);
371 
372  auto t_surf_arr = t_surf[lev]->array(mfi);
373  auto lmask_arr = (m_lmask_lev[lev][0]) ? m_lmask_lev[lev][0]->array(mfi) :
374  Array4<int> {};
375  const auto lsm_arr = m_lsm_data_lev[lev][0]->const_array(mfi);
376 
377  ParallelFor(gtbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
378  {
379  int is_land = (lmask_arr) ? lmask_arr(i,j,k) : 1;
380  if (is_land) {
381  int li = amrex::min(amrex::max(i, i_lo), i_hi);
382  int lj = amrex::min(amrex::max(j, j_lo), j_hi);
383  t_surf_arr(i,j,k) = lsm_arr(li,lj,k);
384  }
385  });
386  }
387 }

◆ get_mac_avg()

const amrex::MultiFab* ABLMost::get_mac_avg ( const int &  lev,
int  comp 
)
inline
283 { return m_ma.get_average(lev,comp); }
Here is the call graph for this function:

◆ get_olen()

const amrex::MultiFab* ABLMost::get_olen ( const int &  lev)
inline
280 { return olen[lev].get(); }

◆ get_t_star()

const amrex::MultiFab* ABLMost::get_t_star ( const int &  lev)
inline
277 { return t_star[lev].get(); }

◆ get_t_surf()

const amrex::MultiFab* ABLMost::get_t_surf ( const int &  lev)
inline
286 { return t_surf[lev].get(); }

◆ get_u_star()

const amrex::MultiFab* ABLMost::get_u_star ( const int &  lev)
inline
274 { return u_star[lev].get(); }

◆ get_z0()

const amrex::FArrayBox* ABLMost::get_z0 ( const int &  lev)
inline
292 {return &z_0[lev];}

◆ get_zref()

amrex::Real ABLMost::get_zref ( )
inline
289 {return m_ma.get_zref();}
amrex::Real get_zref() const
Definition: MOSTAverage.H:90
Here is the call graph for this function:

◆ impose_most_bcs()

void ABLMost::impose_most_bcs ( const int &  lev,
const amrex::Vector< amrex::MultiFab * > &  mfs,
amrex::MultiFab *  xzmom_flux,
amrex::MultiFab *  zxmom_flux,
amrex::MultiFab *  yzmom_flux,
amrex::MultiFab *  zymom_flux,
amrex::MultiFab *  heat_flux,
amrex::MultiFab *  eddyDiffs,
amrex::MultiFab *  z_phys 
)

Wrapper to impose Monin Obukhov similarity theory fluxes by populating ghost cells.

Parameters
[in]levCurrent level
[in,out]mfsMultifabs to populate
[in]eddyDiffsDiffusion coefficients from turbulence model
129 {
130  const int klo = 0;
132  moeng_flux flux_comp(klo);
133  compute_most_bcs(lev, mfs,
134  xzmom_flux, zxmom_flux,
135  yzmom_flux, zymom_flux,
136  heat_flux,
137  eddyDiffs,
138  z_phys, m_geom[lev].CellSize(2), flux_comp);
139  } else if (flux_type == FluxCalcType::DONELAN) {
140  donelan_flux flux_comp(klo);
141  compute_most_bcs(lev, mfs,
142  xzmom_flux, zxmom_flux,
143  yzmom_flux, zymom_flux,
144  heat_flux,
145  eddyDiffs,
146  z_phys, m_geom[lev].CellSize(2), flux_comp);
147  } else {
148  custom_flux flux_comp(klo);
149  compute_most_bcs(lev, mfs,
150  xzmom_flux, zxmom_flux,
151  yzmom_flux, zymom_flux,
152  heat_flux,
153  eddyDiffs,
154  z_phys, m_geom[lev].CellSize(2), flux_comp);
155  }
156 }
void compute_most_bcs(const int &lev, const amrex::Vector< amrex::MultiFab * > &mfs, amrex::MultiFab *xzmom_flux, amrex::MultiFab *zxmom_flux, amrex::MultiFab *yzmom_flux, amrex::MultiFab *zymom_flux, amrex::MultiFab *heat_flux, amrex::MultiFab *eddyDiffs, amrex::MultiFab *z_phys, const amrex::Real &dz_no_terrain, const FluxCalc &flux_comp)
Definition: MOSTStress.H:1150
Definition: MOSTStress.H:879
Definition: MOSTStress.H:589

◆ time_interp_sst()

void ABLMost::time_interp_sst ( const int &  lev,
const amrex::Real &  time 
)
324 {
325  // Time interpolation
326  Real dT = m_bdy_time_interval;
327  Real time_since_start = time - m_start_bdy_time;
328  int n_time = static_cast<int>( time_since_start / dT);
329  Real alpha = (time_since_start - n_time * dT) / dT;
330  AMREX_ALWAYS_ASSERT( alpha >= 0. && alpha <= 1.0);
331  Real oma = 1.0 - alpha;
332  AMREX_ALWAYS_ASSERT( (n_time >= 0) && (n_time < (m_sst_lev[lev].size()-1)));
333 
334  // Populate t_surf
335  for (MFIter mfi(*t_surf[lev]); mfi.isValid(); ++mfi)
336  {
337  Box gtbx = mfi.growntilebox();
338 
339  auto t_surf_arr = t_surf[lev]->array(mfi);
340  const auto sst_hi_arr = m_sst_lev[lev][n_time+1]->const_array(mfi);
341  const auto sst_lo_arr = m_sst_lev[lev][n_time ]->const_array(mfi);
342  auto lmask_arr = (m_lmask_lev[lev][0]) ? m_lmask_lev[lev][0]->array(mfi) :
343  Array4<int> {};
344 
345  ParallelFor(gtbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
346  {
347  int is_land = (lmask_arr) ? lmask_arr(i,j,k) : 1;
348  if (!is_land) {
349  t_surf_arr(i,j,k) = oma * sst_lo_arr(i,j,k)
350  + alpha * sst_hi_arr(i,j,k);
351  }
352  });
353  }
354 }

◆ update_fluxes()

void ABLMost::update_fluxes ( const int &  lev,
const amrex::Real &  time,
int  max_iters = 25 
)

Wrapper to update ustar and tstar for Monin Obukhov similarity theory.

Parameters
[in]levCurrent level
[in]max_itersmaximum iterations to use
16 {
17  // Update SST data if we have a valid pointer
18  if (m_sst_lev[lev][0]) time_interp_sst(lev, time);
19 
20  // TODO: we want 0 index to always be theta?
21  // Update land surface temp if we have a valid pointer
22  if (m_lsm_data_lev[lev][0]) get_lsm_tsurf(lev);
23 
24  // Fill interior ghost cells
25  t_surf[lev]->FillBoundary(m_geom[lev].periodicity());
26 
27  // Compute plane averages for all vars (regardless of flux type)
29 
30  // Iterate the fluxes if moeng type
35  compute_fluxes(lev, max_iters, most_flux);
36  } else if (rough_type == RoughCalcType::CHARNOCK) {
38  compute_fluxes(lev, max_iters, most_flux);
39  } else {
41  compute_fluxes(lev, max_iters, most_flux);
42  }
44  update_surf_temp(time);
47  compute_fluxes(lev, max_iters, most_flux);
48  } else if (rough_type == RoughCalcType::CHARNOCK) {
50  compute_fluxes(lev, max_iters, most_flux);
51  } else {
53  compute_fluxes(lev, max_iters, most_flux);
54  }
55  } else {
57  adiabatic most_flux(m_ma.get_zref(), surf_temp_flux);
58  compute_fluxes(lev, max_iters, most_flux);
59  } else if (rough_type == RoughCalcType::CHARNOCK) {
61  compute_fluxes(lev, max_iters, most_flux);
62  } else {
64  compute_fluxes(lev, max_iters, most_flux);
65  }
66  } // theta flux
67  } else if (flux_type == FluxCalcType::CUSTOM) {
68  u_star[lev]->setVal(custom_ustar);
69  t_star[lev]->setVal(custom_tstar);
70  q_star[lev]->setVal(custom_qstar);
71  }
72 }
void compute_fluxes(const int &lev, const int &max_iters, const FluxIter &most_flux)
Definition: ABLMost.cpp:84
void time_interp_sst(const int &lev, const amrex::Real &time)
Definition: ABLMost.cpp:322
void update_surf_temp(const amrex::Real &time)
Definition: ABLMost.H:251
void get_lsm_tsurf(const int &lev)
Definition: ABLMost.cpp:357
void compute_averages(int lev)
Definition: MOSTAverage.cpp:539
Definition: MOSTStress.H:108
Definition: MOSTStress.H:160
Definition: MOSTStress.H:70
Definition: MOSTStress.H:271
Definition: MOSTStress.H:334
Definition: MOSTStress.H:213
Definition: MOSTStress.H:458
Definition: MOSTStress.H:523
Definition: MOSTStress.H:398

◆ update_mac_ptrs()

void ABLMost::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 
)
inline
271  { m_ma.update_field_ptrs(lev,vars_old,Theta_prim,Qv_prim); }
void update_field_ptrs(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)
Definition: MOSTAverage.cpp:181
Here is the call graph for this function:

◆ update_surf_temp()

void ABLMost::update_surf_temp ( const amrex::Real &  time)
inline
252  {
253  if (surf_heating_rate != 0) {
254  int nlevs = m_geom.size();
255  for (int lev = 0; lev < nlevs; lev++)
256  {
257  t_surf[lev]->setVal(surf_temp + surf_heating_rate*time);
258  amrex::Print() << "Surface temp at t=" << time
259  << ": "
260  << surf_temp + surf_heating_rate*time
261  << std::endl;
262  }
263  }
264  }

Member Data Documentation

◆ cnk_a

amrex::Real ABLMost::cnk_a {0.0185}
private

Referenced by ABLMost().

◆ custom_qstar

amrex::Real ABLMost::custom_qstar {0}
private

Referenced by ABLMost().

◆ custom_tstar

amrex::Real ABLMost::custom_tstar {0}
private

Referenced by ABLMost().

◆ custom_ustar

amrex::Real ABLMost::custom_ustar {0}
private

Referenced by ABLMost().

◆ depth

amrex::Real ABLMost::depth {30.0}
private

Referenced by ABLMost().

◆ flux_type

FluxCalcType ABLMost::flux_type {FluxCalcType::MOENG}

Referenced by ABLMost().

◆ m_bdy_time_interval

amrex::Real ABLMost::m_bdy_time_interval
private

◆ m_exp_most

bool ABLMost::m_exp_most = false
private

◆ m_geom

amrex::Vector<amrex::Geometry> ABLMost::m_geom
private

Referenced by ABLMost(), and update_surf_temp().

◆ m_lmask_lev

amrex::Vector<amrex::Vector<amrex::iMultiFab*> > ABLMost::m_lmask_lev
private

Referenced by ABLMost().

◆ m_lsm_data_lev

amrex::Vector<amrex::Vector<amrex::MultiFab*> > ABLMost::m_lsm_data_lev
private

Referenced by ABLMost().

◆ m_lsm_flux_lev

amrex::Vector<amrex::Vector<amrex::MultiFab*> > ABLMost::m_lsm_flux_lev
private

Referenced by ABLMost().

◆ m_ma

MOSTAverage ABLMost::m_ma
private

◆ m_sst_lev

amrex::Vector<amrex::Vector<amrex::MultiFab*> > ABLMost::m_sst_lev
private

Referenced by ABLMost().

◆ m_start_bdy_time

amrex::Real ABLMost::m_start_bdy_time
private

◆ olen

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ABLMost::olen
private

Referenced by ABLMost(), and get_olen().

◆ q_star

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ABLMost::q_star
private

Referenced by ABLMost().

◆ rough_type

RoughCalcType ABLMost::rough_type {RoughCalcType::CONSTANT}

Referenced by ABLMost().

◆ surf_heating_rate

amrex::Real ABLMost::surf_heating_rate {0}
private

Referenced by ABLMost(), and update_surf_temp().

◆ surf_temp

amrex::Real ABLMost::surf_temp
private

Referenced by ABLMost(), and update_surf_temp().

◆ surf_temp_flux

amrex::Real ABLMost::surf_temp_flux {0}
private

Referenced by ABLMost().

◆ t_star

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ABLMost::t_star
private

Referenced by ABLMost(), and get_t_star().

◆ t_surf

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ABLMost::t_surf
private

◆ theta_type

ThetaCalcType ABLMost::theta_type {ThetaCalcType::ADIABATIC}

Referenced by ABLMost().

◆ u_star

amrex::Vector<std::unique_ptr<amrex::MultiFab> > ABLMost::u_star
private

Referenced by ABLMost(), and get_u_star().

◆ use_moisture

bool ABLMost::use_moisture
private

Referenced by ABLMost().

◆ z0_const

amrex::Real ABLMost::z0_const
private

Referenced by ABLMost().

◆ z_0

amrex::Vector<amrex::FArrayBox> ABLMost::z_0
private

Referenced by ABLMost(), and get_z0().


The documentation for this class was generated from the following files: