ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_PBLModels.H
Go to the documentation of this file.
1 #ifndef ERF_PBLMODELS_H_
2 #define ERF_PBLMODELS_H_
3 
4 #include <AMReX_Periodicity.H>
5 #include "ERF_Constants.H"
6 #include "ERF_DataStruct.H"
7 
8 /**
9  * Compute eddy diffusivities of momentum (eddy viscosity) and heat using the
10  * Mellor-Yamada-Janjić (MYJ) boundary layer scheme.
11  * Reference: Janjić, Z. I., 1994: The Step-Mountain Eta Coordinate Model:
12  * Further Developments of the Convection, Viscous Sublayer, and Turbulence
13  * Closure Schemes. Monthly Weather Review, 122, 927–945.
14  * https://doi.org/10.1175/1520-0493(1994)122<0927:TSMECM>2.0.CO;2
15  *
16  * @param[in] xvel Velocity in x-dir
17  * @param[in] yvel Velocity in y-dir
18  * @param[in] cons_in Cell center conserved quantities
19  * @param[out] eddyViscosity Holds turbulent viscosity
20  * @param[in] geom Problem geometry
21  * @param[in] turbChoice Container with turbulence parameters
22  * @param[in] SurfLayer Pointer to Monin-Obukhov class if instantiated
23  * @param[in] use_moisture If we have microphysics enabled
24  * @param[in] level Current level
25  * @param[in] bc_ptr Pointer to array with boundary condition info
26  * @param[in] vert_only Only compute vertical eddy diffusivities
27  * @param[in] z_phys_nd Physical location of grid nodes, if terrain (or grid stretching) is enabled
28  * @param[in] z_phys_cc Physical location of cell centers
29  */
30 void
32  const amrex::MultiFab& xvel,
33  const amrex::MultiFab& yvel,
34  amrex::MultiFab& cons_in,
35  amrex::MultiFab& eddyViscosity,
36  const amrex::Geometry& geom,
37  const TurbChoice& turbChoice,
38  std::unique_ptr<SurfaceLayer>& SurfLayer,
39  bool use_terrain_fitted_coords,
40  bool use_moisture,
41  int level,
42  const amrex::BCRec* bc_ptr,
43  bool /*vert_only*/,
44  const std::unique_ptr<amrex::MultiFab>& z_phys_nd,
45  const std::unique_ptr<amrex::MultiFab>& z_phys_cc,
46  const MoistureComponentIndices& moisture_indices);
47 
48 /**
49  * Compute eddy diffusivities of momentum (eddy viscosity) and heat using the
50  * Mellor-Yamada-Nakanishi-Niino Level amrex::Real(2.5) PBL scheme
51  *
52  * @param[in] xvel Velocity in x-dir
53  * @param[in] yvel Velocity in y-dir
54  * @param[in] cons_in Cell center conserved quantities
55  * @param[out] eddyViscosity Holds turbulent viscosity
56  * @param[in] geom Problem geometry
57  * @param[in] turbChoice Container with turbulence parameters
58  * @param[in] SurfLayer Pointer to Monin-Obukhov class if instantiated
59  * @param[in] use_moisture If we have microphysics enabled
60  * @param[in] level Current level
61  * @param[in] bc_ptr Pointer to array with boundary condition info
62  * @param[in] vert_only Only compute vertical eddy diffusivities
63  * @param[in] z_phys_nd Physical location of grid nodes, if terrain (or grid stretching) is enabled
64  * @param[in] z_phys_cc Physical location of cell centers
65  */
66 void
67 ComputeDiffusivityMYNN25 (const amrex::MultiFab& xvel,
68  const amrex::MultiFab& yvel,
69  const amrex::MultiFab& cons_in,
70  amrex::MultiFab& eddyViscosity,
71  const amrex::Geometry& geom,
72  const TurbChoice& turbChoice,
73  std::unique_ptr<SurfaceLayer>& SurfLayer,
74  bool use_terrain_fitted_coords,
75  bool use_moisture,
76  int level,
77  const amrex::BCRec* bc_ptr,
78  bool /*vert_only*/,
79  const std::unique_ptr<amrex::MultiFab>& z_phys_nd,
80  const std::unique_ptr<amrex::MultiFab>& z_phys_cc,
81  const MoistureComponentIndices& moisture_indices);
82 
83 /**
84  * Compute eddy diffusivities of momentum (eddy viscosity) and heat using the
85  * Mellor-Yamada-Nakanishi-Niino Level amrex::Real(2.5) PBL scheme
86  *
87  * @param[in] xvel Velocity in x-dir
88  * @param[in] yvel Velocity in y-dir
89  * @param[in] cons_in Cell center conserved quantities
90  * @param[out] eddyViscosity Holds turbulent viscosity
91  * @param[in] geom Problem geometry
92  * @param[in] turbChoice Container with turbulence parameters
93  * @param[in] SurfLayer Pointer to Monin-Obukhov class if instantiated
94  * @param[in] use_moisture If we have microphysics enabled
95  * @param[in] level Current level
96  * @param[in] bc_ptr Pointer to array with boundary condition info
97  * @param[in] vert_only Only compute vertical eddy diffusivities
98  * @param[in] z_phys_nd Physical location of grid nodes, if terrain (or grid stretching) is enabled
99  * @param[in] z_phys_cc Physical location of cell centers
100  */
101 void
102 ComputeDiffusivityMYNNEDMF (const amrex::MultiFab& xvel,
103  const amrex::MultiFab& yvel,
104  const amrex::MultiFab& cons_in,
105  amrex::MultiFab& eddyViscosity,
106  const amrex::Geometry& geom,
107  const TurbChoice& turbChoice,
108  std::unique_ptr<SurfaceLayer>& SurfLayer,
109  bool use_terrain_fitted_coords,
110  bool use_moisture,
111  int level,
112  const amrex::BCRec* bc_ptr,
113  bool /*vert_only*/,
114  const std::unique_ptr<amrex::MultiFab>& z_phys_nd,
115  const std::unique_ptr<amrex::MultiFab>& z_phys_cc,
116  const MoistureComponentIndices& moisture_indices);
117 
118 /**
119  * Compute eddy diffusivities of momentum (eddy viscosity) and heat using the
120  * Yonsei University PBL scheme
121  *
122  * @param[in] xvel Velocity in x-dir
123  * @param[in] yvel Velocity in y-dir
124  * @param[in] cons_in Cell center conserved quantities
125  * @param[out] eddyViscosity Holds turbulent viscosity
126  * @param[in] geom Problem geometry
127  * @param[in] turbChoice Container with turbulence parameters
128  * @param[in] SurfLayer Pointer to Monin-Obukhov class if instantiated
129  * @param[in] use_moisture If we have microphysics enabled
130  * @param[in] level Current level
131  * @param[in] bc_ptr Pointer to array with boundary condition info
132  * @param[in] vert_only Only compute vertical eddy diffusivities
133  * @param[in] z_phys_nd Physical location of grid nodes, if terrain (or grid stretching) is enabled
134  * @param[in] z_phys_cc Physical location of cell centers
135  */
136 void
137 ComputeDiffusivityYSU (const amrex::MultiFab& xvel,
138  const amrex::MultiFab& yvel,
139  const amrex::MultiFab& cons_in,
140  amrex::MultiFab& eddyViscosity,
141  const amrex::Geometry& geom,
142  const TurbChoice& turbChoice,
143  std::unique_ptr<SurfaceLayer>& SurfLayer,
144  bool use_terrain_fitted_coords,
145  bool use_moisture,
146  int level,
147  const amrex::BCRec* bc_ptr,
148  bool /*vert_only*/,
149  const std::unique_ptr<amrex::MultiFab>& z_phys_nd,
150  const std::unique_ptr<amrex::MultiFab>& z_phys_cc,
151  const MoistureComponentIndices& moisture_indices);
152 /**
153  * Compute eddy diffusivities of momentum (eddy viscosity) and heat using the
154  * Medium Range Forecast (MRF) boundary layer scheme based on Hong and Pan (1996).
155  * Reference: Hong, S. Y., and H.-L. Pan, 1996: Nonlocal Boundary Layer Vertical
156  * Diffusion in a Medium-Range Forecast Model. Monthly Weather Review, 124,
157  * 2322-2339. https://doi.org/10.1175/1520-0493(1996)124<2322:NBLVDI>2.0.CO;2
158  *
159  * @param[in] xvel Velocity in x-dir
160  * @param[in] yvel Velocity in y-dir
161  * @param[in] cons_in Cell center conserved quantities
162  * @param[out] eddyViscosity Holds turbulent viscosity
163  * @param[in] geom Problem geometry
164  * @param[in] turbChoice Container with turbulence parameters
165  * @param[in] SurfLayer Pointer to Monin-Obukhov class if instantiated
166  * @param[in] use_moisture If we have microphysics enabled
167  * @param[in] level Current level
168  * @param[in] bc_ptr Pointer to array with boundary condition info
169  * @param[in] vert_only Only compute vertical eddy diffusivities
170  * @param[in] z_phys_nd Physical location of grid nodes, if terrain (or grid stretching) is enabled
171  * @param[in] z_phys_cc Physical location of cell centers
172  */
173 void
174 ComputeDiffusivityMRF (const amrex::MultiFab& xvel,
175  const amrex::MultiFab& yvel,
176  const amrex::MultiFab& cons_in,
177  amrex::MultiFab& eddyViscosity,
178  const amrex::Geometry& geom,
179  const TurbChoice& turbChoice,
180  std::unique_ptr<SurfaceLayer>& SurfLayer,
181  bool use_terrain_fitted_coords,
182  bool use_moisture,
183  int level,
184  const amrex::BCRec* bc_ptr,
185  bool /*vert_only*/,
186  const std::unique_ptr<amrex::MultiFab>& z_phys_nd,
187  const std::unique_ptr<amrex::MultiFab>& z_phys_cc,
188  const MoistureComponentIndices& moisture_indices,
189  const amrex::MultiFab* terrain_blank = nullptr);
190 
191 /**
192  * Compute eddy diffusivities of momentum (eddy viscosity) and heat using the
193  * WRF Yonsei University (YSU) PBL scheme.
194  *
195  * Based on:
196  * Hong, Noh &amp; Dudhia (2006), MWR, https://doi.org/10.1175/MWR3250.1
197  * Hong (2010), QJRMS, https://doi.org/10.1002/qj.665
198  *
199  * Features: three-pass bulk-Richardson PBLH diagnosis, nonlocal
200  * countergradient fluxes, explicit entrainment at PBL top, and
201  * grid-adaptive Richardson-number mixing in free atmosphere.
202  *
203  * @param[in] xvel x-direction velocity
204  * @param[in] yvel y-direction velocity
205  * @param[in] cons_in cell-center conserved quantities
206  * @param[out] eddyViscosity turbulent eddy viscosity
207  * @param[in] geom problem geometry
208  * @param[in] turbChoice turbulence parameter container
209  * @param[in] SurfLayer Monin-Obukhov surface layer object
210  * @param[in] use_terrain_fitted_coords flag for terrain coordinates
211  * @param[in] use_moisture flag for moisture active
212  * @param[in] level AMR level
213  * @param[in] bc_ptr boundary condition array
214  * @param[in] vert_only compute vertical diffusivity only
215  * @param[in] z_phys_nd physical node heights (terrain)
216  * @param[in] z_phys_cc physical cell-center heights
217  * @param[in] moisture_indices component index mapping for moisture variables
218  * @param[in] qheating_rates radiation heating rates (SW, LW components); optional
219  */
220 void
221 ComputeDiffusivityYSUNew (const amrex::MultiFab& xvel,
222  const amrex::MultiFab& yvel,
223  const amrex::MultiFab& cons_in,
224  amrex::MultiFab& eddyViscosity,
225  const amrex::Geometry& geom,
226  const TurbChoice& turbChoice,
227  std::unique_ptr<SurfaceLayer>& SurfLayer,
228  bool use_terrain_fitted_coords,
229  bool use_moisture,
230  int level,
231  const amrex::BCRec* bc_ptr,
232  bool /*vert_only*/,
233  const std::unique_ptr<amrex::MultiFab>& z_phys_nd,
234  const std::unique_ptr<amrex::MultiFab>& z_phys_cc,
235  const MoistureComponentIndices& moisture_indices,
236  const amrex::MultiFab* qheating_rates = nullptr,
237  const amrex::MultiFab* terrain_blank = nullptr);
238 
239 /**
240  * Function for computing vertical derivatives for use in PBL model
241  *
242  * @param[in] u velocity in x-dir
243  * @param[in] v velocity in y-dir
244  * @param[in] cell_data conserved cell center vars
245  */
247 {
248  // Each value is the inverse physical distance between the two samples
249  // used by its corresponding derivative stencil.
253 };
254 
255 /**
256  * Compute vertical derivatives of potential temperature and velocity for PBL models.
257  *
258  * @param i x-index
259  * @param j y-index
260  * @param k z-index
261  * @param[in] uvel x-velocity
262  * @param[in] vvel y-velocity
263  * @param[in] cell_data conserved cell-center variables
264  * @param[in] izmin lower z-index limit
265  * @param[in] izmax upper z-index limit
266  * @param[in] dz_inv inverse physical distance spacings
267  * @param[in] c_ext_dir_on_zlo Dirichlet condition on z-low face for cell data
268  * @param[in] c_ext_dir_on_zhi Dirichlet condition on z-high face for cell data
269  * @param[in] u_ext_dir_on_zlo Dirichlet condition on z-low face for u-velocity
270  * @param[in] u_ext_dir_on_zhi Dirichlet condition on z-high face for u-velocity
271  * @param[in] v_ext_dir_on_zlo Dirichlet condition on z-low face for v-velocity
272  * @param[in] v_ext_dir_on_zhi Dirichlet condition on z-high face for v-velocity
273  * @param[out] dthetadz computed vertical derivative of potential temperature
274  * @param[out] dudz computed vertical derivative of x-velocity
275  * @param[out] dvdz computed vertical derivative of y-velocity
276  * @param[in] moisture_indices moisture variable component indices
277  */
278 AMREX_GPU_DEVICE
279 AMREX_FORCE_INLINE
280 void
281 ComputeVerticalDerivativesPBL (int i, int j, int k,
282  const amrex::Array4<const amrex::Real>& uvel,
283  const amrex::Array4<const amrex::Real>& vvel,
284  const amrex::Array4<const amrex::Real>& cell_data,
285  const int izmin,
286  const int izmax,
287  const PBLDerivativeDzInv& dz_inv,
288  const bool c_ext_dir_on_zlo,
289  const bool c_ext_dir_on_zhi,
290  const bool u_ext_dir_on_zlo,
291  const bool u_ext_dir_on_zhi,
292  const bool v_ext_dir_on_zlo,
293  const bool v_ext_dir_on_zhi,
294  amrex::Real& dthetadz,
295  amrex::Real& dudz,
296  amrex::Real& dvdz,
297  const MoistureComponentIndices& moisture_indices)
298 {
299  // ext_dir ghost values hold the value at the physical boundary, which is
300  // half a ghost-center spacing from the adjacent cell center. Use a
301  // two-point, first-order boundary-to-center difference with inverse
302  // distance 2/dz.
303  if ( k==izmax && c_ext_dir_on_zhi ) {
304  dthetadz = ( GetThetav(i,j,k+1,cell_data,moisture_indices)
305  -GetThetav(i,j,k ,cell_data,moisture_indices) )*dz_inv.dirichlet_hi;
306  } else if ( k==izmin && c_ext_dir_on_zlo ) {
307  dthetadz = ( GetThetav(i,j,k ,cell_data,moisture_indices)
308  -GetThetav(i,j,k-1,cell_data,moisture_indices) )*dz_inv.dirichlet_lo;
309  } else {
310  dthetadz = ( GetThetav(i,j,k+1,cell_data,moisture_indices)
311  -GetThetav(i,j,k-1,cell_data,moisture_indices) )*dz_inv.interior;
312  }
313 
314  if ( k==izmax && u_ext_dir_on_zhi ) {
315  dudz = myhalf*( uvel(i ,j,k+1) - uvel(i ,j,k)
316  +uvel(i+1,j,k+1) - uvel(i+1,j,k) )*dz_inv.dirichlet_hi;
317  } else if ( k==izmin && u_ext_dir_on_zlo ) {
318  dudz = myhalf*( uvel(i ,j,k) - uvel(i ,j,k-1)
319  +uvel(i+1,j,k) - uvel(i+1,j,k-1) )*dz_inv.dirichlet_lo;
320  } else {
321  dudz = myhalf*( uvel(i ,j,k+1) - uvel(i ,j,k-1)
322  +uvel(i+1,j,k+1) - uvel(i+1,j,k-1) )*dz_inv.interior;
323  }
324 
325  if ( k==izmax && v_ext_dir_on_zhi ) {
326  dvdz = myhalf*( vvel(i,j ,k+1) - vvel(i,j ,k)
327  +vvel(i,j+1,k+1) - vvel(i,j+1,k) )*dz_inv.dirichlet_hi;
328  } else if ( k==izmin && v_ext_dir_on_zlo ) {
329  dvdz = myhalf*( vvel(i,j ,k) - vvel(i,j ,k-1)
330  +vvel(i,j+1,k) - vvel(i,j+1,k-1) )*dz_inv.dirichlet_lo;
331  } else {
332  dvdz = myhalf*( vvel(i,j ,k+1) - vvel(i,j ,k-1)
333  +vvel(i,j+1,k+1) - vvel(i,j+1,k-1) )*dz_inv.interior;
334  }
335 }
336 
337 /**
338  * Function for computing the QKE source terms (NN09, Eqn. 5).
339  *
340  * @param[in] u velocity in x-dir
341  * @param[in] v velocity in y-dir
342  * @param[in] cell_data conserved cell center vars
343  * @param[in] cell_prim primitive cell center vars
344  * @param[in] K_turb turbulent viscosity
345  * @param[in] domain box of the whole domain
346  * @param[in] dz_inv inverse spacings for interior and Dirichlet-boundary differences
347  * @param[in] pbl_mynn_B1_l a parameter
348  * @param[in] theta_mean average theta
349  */
350 AMREX_GPU_DEVICE
351 AMREX_FORCE_INLINE
353 ComputeQKESourceTerms (int i, int j, int k,
354  const amrex::Array4<const amrex::Real>& uvel,
355  const amrex::Array4<const amrex::Real>& vvel,
356  const amrex::Array4<const amrex::Real>& cell_data,
357  const amrex::Array4<const amrex::Real>& cell_prim,
358  const amrex::Array4<const amrex::Real>& K_turb,
359  const amrex::Box& domain,
360  const PBLDerivativeDzInv dz_inv,
361  amrex::Real pbl_mynn_B1_l,
362  const amrex::Real theta_mean,
363  const MoistureComponentIndices& moisture_indices,
364  bool c_ext_dir_on_zlo,
365  bool c_ext_dir_on_zhi,
366  bool u_ext_dir_on_zlo,
367  bool u_ext_dir_on_zhi,
368  bool v_ext_dir_on_zlo,
369  bool v_ext_dir_on_zhi)
370 {
371  // Compute some relevant derivatives
372  amrex::Real dthetadz, dudz, dvdz;
373  amrex::Real source_term = zero;
374 
375  int izmin = domain.smallEnd(2);
376  int izmax = domain.bigEnd(2);
377 
379  uvel, vvel, cell_data, izmin, izmax, dz_inv,
380  c_ext_dir_on_zlo, c_ext_dir_on_zhi,
381  u_ext_dir_on_zlo, u_ext_dir_on_zhi,
382  v_ext_dir_on_zlo, v_ext_dir_on_zhi,
383  dthetadz, dudz, dvdz,
384  moisture_indices);
385 
386  // Notes:
387  // - We transport TKE = myhalf*QKE rather than QKE, so the RHS terms do not
388  // have a factor of two.
389  // - Transport terms due to turbulence and pressure are included when
390  // DiffusionSrcForState_* is called from ERF_slow_rhs_post.
391  // - Eddy diffusivities are updated at the beginning of each time step only.
392 
393  // Second-order turbulent fluxes, e.g.:
394  // -<uw> = L q SM dU/dz (NN09, Eqn. 18)
395  // = Kmv/rho dU/dz
396 
397  // Shear Production
398  source_term += K_turb(i,j,k,EddyDiff::Mom_v) * (dudz*dudz + dvdz*dvdz);
399 
400  // Buoyancy Production
401  source_term -= (CONST_GRAV/theta_mean)*K_turb(i,j,k,EddyDiff::Theta_v)*dthetadz;
402 
403  // Dissipation (NN09, Eqn. 12)
404  amrex::Real qke = two * cell_prim(i,j,k,PrimKE_comp);
405  if (std::abs(qke) > zero) {
406  source_term -= cell_data(i,j,k,Rho_comp) * std::pow(qke,amrex::Real(1.5)) /
407  (pbl_mynn_B1_l * K_turb(i,j,k,EddyDiff::Turb_lengthscale));
408  }
409 
410  return source_term;
411 }
412 
413 /**
414  * @brief Functor for inverse vertical spacings with constant grid spacing.
415  */
417 {
419 
420  /**
421  * Return inverse vertical spacings for constant grid spacing.
422  * @return PBLDerivativeDzInv inverse spacing values
423  */
424  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
425  PBLDerivativeDzInv operator() (int, int, int) const noexcept
426  {
427  return {myhalf*value, two*value, two*value};
428  }
429 };
430 
431 /**
432  * @brief Functor for inverse vertical spacings for stretched grids using a spacing array.
433  */
435 {
436  const amrex::Real* dz;
437  int klo;
438  int khi;
439 
440  /**
441  * Return inverse vertical spacings for stretched grids.
442  * @param k z-index
443  * @return PBLDerivativeDzInv inverse spacing values
444  */
445  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
446  PBLDerivativeDzInv operator() (int, int, int k) const noexcept
447  {
448  // Adjacent cell centers are separated by half the sum of their widths.
449  const amrex::Real dz_lo = dz[(k > klo) ? k-1 : k];
450  const amrex::Real dz_hi = dz[(k < khi) ? k+1 : k];
451  return {two / (dz_lo + two*dz[k] + dz_hi),
452  two / dz[k],
453  two / dz[k]};
454  }
455 };
456 
457 /**
458  * @brief Functor for inverse vertical spacings for terrain-following grids using cell-center heights.
459  */
461 {
462  amrex::Array4<const amrex::Real> z_cc;
463 
464  /**
465  * Return inverse vertical spacings for terrain-following grids.
466  * @param i x-index
467  * @param j y-index
468  * @param k z-index
469  * @return PBLDerivativeDzInv inverse spacing values
470  */
471  AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
472  PBLDerivativeDzInv operator() (int i, int j, int k) const noexcept
473  {
474  return {one / (z_cc(i,j,k+1) - z_cc(i,j,k-1)),
475  two / (z_cc(i,j,k ) - z_cc(i,j,k-1)),
476  two / (z_cc(i,j,k+1) - z_cc(i,j,k ))};
477  }
478 };
479 
480 /**
481  * @brief Apply spatial smoothing to PBLH field using 5-point stencil.
482  *
483  * Applies a simple 5-point spatial averaging to reduce grid-to-grid noise in
484  * the diagnosed PBLH field. This is standard post-processing practice for
485  * discrete Rib-crossing detection as described in Seibert et al. (2000):
486  * "Review and intercomparison of operational methods for the determination of
487  * the mixing height", Atmospheric Environment, 34, 1001-1027.
488  *
489  * Stencil: PBLH_smooth(i,j) = w * PBLH(i,j) + (1-w)/4 * [PBLH(i+-1,j) + PBLH(i,j+-1)]
490  *
491  * The stencil reads one column outside the region it writes, so the result on a
492  * cell depends on columns that a single tile -- or a single box -- does not own.
493  * The caller therefore names the region it wants smoothed (xybx_valid, normally
494  * the planar tile box) inside a work array carrying `passes` columns of halo
495  * around it, filled from the same inputs. Pass p writes the region grown by
496  * passes-1-p and reads the one grown by passes-p, so each pass consumes one
497  * column of halo and the last lands exactly on xybx_valid. Every read stays
498  * inside the array, and the result does not depend on how the domain is divided
499  * into boxes or tiles.
500  *
501  * At a non-periodic domain edge there is no column to read, so the stencil reuses
502  * the cell's own value (reflective/Neumann). Across a periodic edge the halo holds
503  * the wrapped columns and is read directly, which is why the periodicity has to be
504  * passed in: clamping there would fold an edge into a domain that has none.
505  *
506  * @param[in,out] pblh_fab FArrayBox holding the 2D PBLH field (component 0),
507  * sized to contain xybx_valid grown by `passes` in x and y
508  * @param[in] xybx_valid Region to smooth (x,y indices only)
509  * @param[in] weight Center cell weight in stencil (must be in [0,1])
510  * @param[in] passes Number of smoothing iterations
511  * @param[in] domain Domain box, for the reflective edge condition
512  * @param[in] periodicity Domain periodicity, so periodic edges read the halo
513  */
514 inline void
515 ApplyPBLHSmoothing (amrex::FArrayBox& pblh_fab,
516  const amrex::Box& xybx_valid,
517  const amrex::Real weight,
518  const int passes,
519  const amrex::Box& domain,
520  const amrex::Periodicity& periodicity)
521 {
522  if (passes <= 0) { return; }
523 
524  // The caller must supply the halo the passes will consume; see the note above.
526  pblh_fab.box().contains(amrex::grow(xybx_valid, amrex::IntVect(passes,passes,0))),
527  "ApplyPBLHSmoothing: the PBLH work array needs `passes` columns of halo "
528  "around the region being smoothed");
529 
530  // Use a temporary to hold intermediate results
531  amrex::FArrayBox pblh_temp(pblh_fab.box(), 1, amrex::The_Async_Arena());
532  auto pblh = pblh_fab.array();
533  auto pblh_tmp = pblh_temp.array();
534 
535  const auto& dom_lo = amrex::lbound(domain);
536  const auto& dom_hi = amrex::ubound(domain);
537 
538  const bool per_x = periodicity.isPeriodic(0);
539  const bool per_y = periodicity.isPeriodic(1);
540 
541  const amrex::Real wt_side = (one - weight) / four; // Weight for each of 4 neighbors
542 
543  // Apply smoothing passes
544  for (int pass = 0; pass < passes; ++pass) {
545  const int halo = passes - 1 - pass;
546  const amrex::Box bx = amrex::grow(xybx_valid, amrex::IntVect(halo,halo,0));
547 
548  amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int) noexcept
549  {
550  // Reflective (Neumann) at a non-periodic domain edge: reuse the cell's
551  // own value. Everywhere else -- including across a periodic edge, where
552  // the halo holds the wrapped column -- read the neighbour.
553  const int i_xlo = (per_x || i > dom_lo.x) ? (i - 1) : i;
554  const int i_xhi = (per_x || i < dom_hi.x) ? (i + 1) : i;
555  const int j_ylo = (per_y || j > dom_lo.y) ? (j - 1) : j;
556  const int j_yhi = (per_y || j < dom_hi.y) ? (j + 1) : j;
557 
558  // 5-point stencil
559  pblh_tmp(i, j, 0) = weight * pblh(i, j, 0)
560  + wt_side * (pblh(i_xlo, j, 0) + pblh(i_xhi, j, 0) +
561  pblh(i, j_ylo, 0) + pblh(i, j_yhi, 0));
562  });
563 
564  // Copy back only what this pass computed: outside bx the array still holds
565  // the previous pass, which no later pass reads.
566  pblh_fab.copy<amrex::RunOn::Device>(pblh_temp, bx, 0, bx, 0, 1);
567  }
568 }
569 
570 #endif
constexpr amrex::Real CONST_GRAV
Definition: ERF_Constants.H:56
#define Rho_comp
Definition: ERF_IndexDefines.H:39
#define PrimKE_comp
Definition: ERF_IndexDefines.H:59
const bool use_moisture
Definition: ERF_InitCustomPert_ABL.H:71
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(m_cloud_chamber_config.active, "Cloud Chamber: initializer reached without a parsed configuration")
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real GetThetav(const int &i, const int &j, const int &k, const amrex::Array4< amrex::Real const > &cell_data, const MoistureComponentIndices &moisture_indices)
Definition: ERF_MoistUtils.H:74
ParallelFor(fab_box, [=] AMREX_GPU_DEVICE(int i, int j, int k) { qrcuten_arr(i, j, k)=Real(0);qscuten_arr(i, j, k)=Real(0);qicuten_arr(i, j, k)=Real(0);})
constexpr amrex::Real four
Definition: ERF_NumericalConstants.H:33
constexpr amrex::Real two
Definition: ERF_NumericalConstants.H:31
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:30
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:29
constexpr amrex::Real myhalf
Definition: ERF_NumericalConstants.H:34
void ComputeDiffusivityYSU(const amrex::MultiFab &xvel, const amrex::MultiFab &yvel, const amrex::MultiFab &cons_in, amrex::MultiFab &eddyViscosity, const amrex::Geometry &geom, const TurbChoice &turbChoice, std::unique_ptr< SurfaceLayer > &SurfLayer, bool use_terrain_fitted_coords, bool use_moisture, int level, const amrex::BCRec *bc_ptr, bool, const std::unique_ptr< amrex::MultiFab > &z_phys_nd, const std::unique_ptr< amrex::MultiFab > &z_phys_cc, const MoistureComponentIndices &moisture_indices)
void ComputeDiffusivityMYNNEDMF(const amrex::MultiFab &xvel, const amrex::MultiFab &yvel, const amrex::MultiFab &cons_in, amrex::MultiFab &eddyViscosity, const amrex::Geometry &geom, const TurbChoice &turbChoice, std::unique_ptr< SurfaceLayer > &SurfLayer, bool use_terrain_fitted_coords, bool use_moisture, int level, const amrex::BCRec *bc_ptr, bool, const std::unique_ptr< amrex::MultiFab > &z_phys_nd, const std::unique_ptr< amrex::MultiFab > &z_phys_cc, const MoistureComponentIndices &moisture_indices)
AMREX_GPU_DEVICE AMREX_FORCE_INLINE void ComputeVerticalDerivativesPBL(int i, int j, int k, const amrex::Array4< const amrex::Real > &uvel, const amrex::Array4< const amrex::Real > &vvel, const amrex::Array4< const amrex::Real > &cell_data, const int izmin, const int izmax, const PBLDerivativeDzInv &dz_inv, const bool c_ext_dir_on_zlo, const bool c_ext_dir_on_zhi, const bool u_ext_dir_on_zlo, const bool u_ext_dir_on_zhi, const bool v_ext_dir_on_zlo, const bool v_ext_dir_on_zhi, amrex::Real &dthetadz, amrex::Real &dudz, amrex::Real &dvdz, const MoistureComponentIndices &moisture_indices)
Definition: ERF_PBLModels.H:281
void ComputeDiffusivityMRF(const amrex::MultiFab &xvel, const amrex::MultiFab &yvel, const amrex::MultiFab &cons_in, amrex::MultiFab &eddyViscosity, const amrex::Geometry &geom, const TurbChoice &turbChoice, std::unique_ptr< SurfaceLayer > &SurfLayer, bool use_terrain_fitted_coords, bool use_moisture, int level, const amrex::BCRec *bc_ptr, bool, const std::unique_ptr< amrex::MultiFab > &z_phys_nd, const std::unique_ptr< amrex::MultiFab > &z_phys_cc, const MoistureComponentIndices &moisture_indices, const amrex::MultiFab *terrain_blank=nullptr)
void ComputeDiffusivityMYNN25(const amrex::MultiFab &xvel, const amrex::MultiFab &yvel, const amrex::MultiFab &cons_in, amrex::MultiFab &eddyViscosity, const amrex::Geometry &geom, const TurbChoice &turbChoice, std::unique_ptr< SurfaceLayer > &SurfLayer, bool use_terrain_fitted_coords, bool use_moisture, int level, const amrex::BCRec *bc_ptr, bool, const std::unique_ptr< amrex::MultiFab > &z_phys_nd, const std::unique_ptr< amrex::MultiFab > &z_phys_cc, const MoistureComponentIndices &moisture_indices)
void ApplyPBLHSmoothing(amrex::FArrayBox &pblh_fab, const amrex::Box &xybx_valid, const amrex::Real weight, const int passes, const amrex::Box &domain, const amrex::Periodicity &periodicity)
Apply spatial smoothing to PBLH field using 5-point stencil.
Definition: ERF_PBLModels.H:515
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real ComputeQKESourceTerms(int i, int j, int k, const amrex::Array4< const amrex::Real > &uvel, const amrex::Array4< const amrex::Real > &vvel, const amrex::Array4< const amrex::Real > &cell_data, const amrex::Array4< const amrex::Real > &cell_prim, const amrex::Array4< const amrex::Real > &K_turb, const amrex::Box &domain, const PBLDerivativeDzInv dz_inv, amrex::Real pbl_mynn_B1_l, const amrex::Real theta_mean, const MoistureComponentIndices &moisture_indices, bool c_ext_dir_on_zlo, bool c_ext_dir_on_zhi, bool u_ext_dir_on_zlo, bool u_ext_dir_on_zhi, bool v_ext_dir_on_zlo, bool v_ext_dir_on_zhi)
Definition: ERF_PBLModels.H:353
void ComputeDiffusivityYSUNew(const amrex::MultiFab &xvel, const amrex::MultiFab &yvel, const amrex::MultiFab &cons_in, amrex::MultiFab &eddyViscosity, const amrex::Geometry &geom, const TurbChoice &turbChoice, std::unique_ptr< SurfaceLayer > &SurfLayer, bool use_terrain_fitted_coords, bool use_moisture, int level, const amrex::BCRec *bc_ptr, bool, const std::unique_ptr< amrex::MultiFab > &z_phys_nd, const std::unique_ptr< amrex::MultiFab > &z_phys_cc, const MoistureComponentIndices &moisture_indices, const amrex::MultiFab *qheating_rates=nullptr, const amrex::MultiFab *terrain_blank=nullptr)
void ComputeDiffusivityMYJ(double dt, const amrex::MultiFab &xvel, const amrex::MultiFab &yvel, amrex::MultiFab &cons_in, amrex::MultiFab &eddyViscosity, const amrex::Geometry &geom, const TurbChoice &turbChoice, std::unique_ptr< SurfaceLayer > &SurfLayer, bool use_terrain_fitted_coords, bool use_moisture, int level, const amrex::BCRec *bc_ptr, bool, const std::unique_ptr< amrex::MultiFab > &z_phys_nd, const std::unique_ptr< amrex::MultiFab > &z_phys_cc, const MoistureComponentIndices &moisture_indices)
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ Theta_v
Definition: ERF_IndexDefines.H:250
@ Turb_lengthscale
Definition: ERF_IndexDefines.H:254
@ Mom_v
Definition: ERF_IndexDefines.H:249
@ xvel
Definition: ERF_IndexDefines.H:215
@ yvel
Definition: ERF_IndexDefines.H:216
The moisture data carried by the active microphysics scheme.
Definition: ERF_DataStruct.H:223
Functor for inverse vertical spacings with constant grid spacing.
Definition: ERF_PBLModels.H:417
amrex::Real value
Definition: ERF_PBLModels.H:418
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE PBLDerivativeDzInv operator()(int, int, int) const noexcept
Definition: ERF_PBLModels.H:425
Functor for inverse vertical spacings for stretched grids using a spacing array.
Definition: ERF_PBLModels.H:435
const amrex::Real * dz
Definition: ERF_PBLModels.H:436
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE PBLDerivativeDzInv operator()(int, int, int k) const noexcept
Definition: ERF_PBLModels.H:446
int klo
Definition: ERF_PBLModels.H:437
int khi
Definition: ERF_PBLModels.H:438
Functor for inverse vertical spacings for terrain-following grids using cell-center heights.
Definition: ERF_PBLModels.H:461
amrex::Array4< const amrex::Real > z_cc
Definition: ERF_PBLModels.H:462
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE PBLDerivativeDzInv operator()(int i, int j, int k) const noexcept
Definition: ERF_PBLModels.H:472
Definition: ERF_PBLModels.H:247
amrex::Real dirichlet_hi
Definition: ERF_PBLModels.H:252
amrex::Real interior
Definition: ERF_PBLModels.H:250
amrex::Real dirichlet_lo
Definition: ERF_PBLModels.H:251
Definition: ERF_TurbStruct.H:115