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

#include <ERF_PhysBCFunct.H>

Collaboration diagram for ERFPhysBCFunct_w:

Public Member Functions

 ERFPhysBCFunct_w (const int lev, const amrex::Geometry &geom, const amrex::Vector< amrex::BCRec > &domain_bcs_type, const amrex::Gpu::DeviceVector< amrex::BCRec > &domain_bcs_type_d, amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > bc_extdir_vals, amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > bc_neumann_vals, const TerrainType &terrain_type, amrex::Vector< std::unique_ptr< amrex::MultiFab >> &mapfac_lev, std::unique_ptr< amrex::MultiFab > &z_phys_nd, const bool use_real_bcs, amrex::Real *w_bc_data)
 
 ~ERFPhysBCFunct_w ()
 
void operator() (amrex::MultiFab &mf, amrex::MultiFab &xvel, amrex::MultiFab &yvel, amrex::IntVect const &nghost, const double time, int bccomp, bool do_fb)
 
void impose_lateral_zvel_bcs (const amrex::Array4< amrex::Real > &dest_arr, const amrex::Array4< amrex::Real const > &xvel_arr, const amrex::Array4< amrex::Real const > &yvel_arr, const amrex::Box &bx, const amrex::Box &domain, const amrex::Array4< amrex::Real const > &mf_u, const amrex::Array4< amrex::Real const > &mf_v, const amrex::Array4< amrex::Real const > &z_nd, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > dxInv, TerrainType terrain_type, int bccomp, const double time)
 
void impose_vertical_zvel_bcs (const amrex::Array4< amrex::Real > &dest_arr, const amrex::Array4< amrex::Real const > &xvel_arr, const amrex::Array4< amrex::Real const > &yvel_arr, const amrex::Box &bx, const amrex::Box &domain, const amrex::Array4< amrex::Real const > &mf_u, const amrex::Array4< amrex::Real const > &mf_v, const amrex::Array4< amrex::Real const > &z_nd, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > dxInv, int bccomp_u, int bccomp_v, int bccomp_w, TerrainType terrain_type, const double time)
 

Private Attributes

int m_lev
 
amrex::Geometry m_geom
 
amrex::Vector< amrex::BCRec > m_domain_bcs_type
 
amrex::Gpu::DeviceVector< amrex::BCRec > m_domain_bcs_type_d
 
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_extdir_vals
 
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_neumann_vals
 
TerrainType m_terrain_type
 
amrex::MultiFab * m_mapfac_u
 
amrex::MultiFab * m_mapfac_v
 
amrex::MultiFab * m_z_phys_nd
 
bool m_use_real_bcs
 
amrex::Real * m_w_bc_data
 

Constructor & Destructor Documentation

◆ ERFPhysBCFunct_w()

ERFPhysBCFunct_w::ERFPhysBCFunct_w ( const int  lev,
const amrex::Geometry &  geom,
const amrex::Vector< amrex::BCRec > &  domain_bcs_type,
const amrex::Gpu::DeviceVector< amrex::BCRec > &  domain_bcs_type_d,
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max >  bc_extdir_vals,
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max >  bc_neumann_vals,
const TerrainType &  terrain_type,
amrex::Vector< std::unique_ptr< amrex::MultiFab >> &  mapfac_lev,
std::unique_ptr< amrex::MultiFab > &  z_phys_nd,
const bool  use_real_bcs,
amrex::Real *  w_bc_data 
)
inline

Construct the z-velocity physical boundary-condition functor.

Parameters
[in]levlevel index
[in]geomgeometry for the level
[in]domain_bcs_typehost boundary-condition records
[in]domain_bcs_type_ddevice boundary-condition records
[in]bc_extdir_valsexternal Dirichlet values for boundary faces
[in]bc_neumann_valsNeumann values for boundary faces
[in]terrain_typeterrain type for the level
[in]mapfac_levmap-factor MultiFabs for the level
[in]z_phys_ndnodal physical height MultiFab
[in]use_real_bcswhether real-data boundary conditions are active
[in]w_bc_dataoptional z-velocity boundary data
414  : m_lev(lev),
415  m_geom(geom), m_domain_bcs_type(domain_bcs_type),
416  m_domain_bcs_type_d(domain_bcs_type_d),
417  m_bc_extdir_vals(bc_extdir_vals),
418  m_bc_neumann_vals(bc_neumann_vals),
419  m_terrain_type(terrain_type),
420  m_z_phys_nd(z_phys_nd.get()),
421  m_use_real_bcs(use_real_bcs),
422  m_w_bc_data(w_bc_data)
423  {
424  m_mapfac_u = mapfac_lev[MapFacType::u_x].get();
425  m_mapfac_v = mapfac_lev[MapFacType::v_y].get();
426  }
@ v_y
Definition: ERF_DataStruct.H:39
@ u_x
Definition: ERF_DataStruct.H:38
amrex::Vector< amrex::BCRec > m_domain_bcs_type
Definition: ERF_PhysBCFunct.H:508
amrex::Geometry m_geom
Definition: ERF_PhysBCFunct.H:507
int m_lev
Definition: ERF_PhysBCFunct.H:506
amrex::Real * m_w_bc_data
Definition: ERF_PhysBCFunct.H:517
bool m_use_real_bcs
Definition: ERF_PhysBCFunct.H:516
amrex::Gpu::DeviceVector< amrex::BCRec > m_domain_bcs_type_d
Definition: ERF_PhysBCFunct.H:509
amrex::MultiFab * m_mapfac_v
Definition: ERF_PhysBCFunct.H:514
TerrainType m_terrain_type
Definition: ERF_PhysBCFunct.H:512
amrex::MultiFab * m_z_phys_nd
Definition: ERF_PhysBCFunct.H:515
amrex::MultiFab * m_mapfac_u
Definition: ERF_PhysBCFunct.H:513
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_neumann_vals
Definition: ERF_PhysBCFunct.H:511
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_extdir_vals
Definition: ERF_PhysBCFunct.H:510

◆ ~ERFPhysBCFunct_w()

ERFPhysBCFunct_w::~ERFPhysBCFunct_w ( )
inline

Destroy the z-velocity physical boundary-condition functor.

431 {}

Member Function Documentation

◆ impose_lateral_zvel_bcs()

void ERFPhysBCFunct_w::impose_lateral_zvel_bcs ( const amrex::Array4< amrex::Real > &  dest_arr,
const amrex::Array4< amrex::Real const > &  xvel_arr,
const amrex::Array4< amrex::Real const > &  yvel_arr,
const amrex::Box &  bx,
const amrex::Box &  domain,
const amrex::Array4< amrex::Real const > &  mf_u,
const amrex::Array4< amrex::Real const > &  mf_v,
const amrex::Array4< amrex::Real const > &  z_nd,
const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM >  dxInv,
TerrainType  terrain_type,
int  bccomp,
const double  time 
)

Impose lateral boundary conditions on z velocity.

Parameters
[in,out]dest_arrz-velocity data to be filled
[in]xvel_arrx-velocity used to determine upwind inflow
[in]yvel_arry-velocity used to determine upwind inflow
[in]bxbox holding data to be filled
[in]domainsimulation domain
[in]mf_ux map-factor field
[in]mf_vy map-factor field
[in]z_ndnodal physical height
[in]dxInvinverse cell size
[in]terrain_typeterrain representation
[in]bccompboundary-condition component
[in]timetime at which data should be filled

Impose lateral boundary conditions on z-component of velocity

Parameters
[in,out]dest_arrArray4 of the quantity to be filled
[in]xvel_arrx-velocity used to determine upwind Dirichlet inflow
[in]yvel_arry-velocity used to determine upwind Dirichlet inflow
[in]bxbox associated with this data
[in]domaincomputational domain
[in]mf_umetric-aware x-velocity used to convert omega to w
[in]mf_vmetric-aware y-velocity used to convert omega to w
[in]z_phys_ndheight coordinate at nodes
[in]dxInvinverse cell size array
[in]terrain_typeterrain type used to decide whether omega conversion is needed
[in]bccompindex into m_domain_bcs_type
[in]timetime at which the data should be filled
67 {
68  BL_PROFILE_VAR("impose_lateral_zvel_bcs()",impose_lateral_zvel_bcs);
69  const auto& dom_lo = lbound(domain);
70  const auto& dom_hi = ubound(domain);
71 
72  //
73  // An ext_dir_upwind face decides inflow against the face velocity, but the box we
74  // loop over does not always have a face velocity at every one of its cells: the
75  // state carries one more lateral ghost than the velocities do (ngrow_state =
76  // ComputeGhostCells()+1 against ngrow_vels = ComputeGhostCells()), and a velocity
77  // box is nodal in its own direction where the array being read is cell centered.
78  // Either way the outermost ghost cells have no velocity of their own, so sample
79  // the nearest one that exists. Cells already inside the velocity array are
80  // unaffected; only that outermost layer changes, and it previously read out of
81  // bounds.
82  //
83  const auto& xvel_lo = lbound(xvel_arr);
84  const auto& xvel_hi = ubound(xvel_arr);
85  const auto& yvel_lo = lbound(yvel_arr);
86  const auto& yvel_hi = ubound(yvel_arr);
87  const WFromOmegaRange wr = wfromomega_range(xvel_arr, yvel_arr, mf_u, mf_v, z_phys_nd);
88 
89  // Based on BCRec for the domain, we need to make BCRec for this Box
90  // bccomp is used as starting index for m_domain_bcs_type
91  // 0 is used as starting index for bcrs
92  Vector<BCRec> bcrs_w(1);
93  setBC(enclosedCells(bx), domain, bccomp, 0, 1, m_domain_bcs_type, bcrs_w);
94 
95  bool l_use_terrain_fitted_coords = ( (terrain_type == TerrainType::StaticFittedMesh) ||
96  (terrain_type == TerrainType::MovingFittedMesh) );
97 
98  // xlo: ori = 0
99  // ylo: ori = 1
100  // zlo: ori = 2
101  // xhi: ori = 3
102  // yhi: ori = 4
103  // zhi: ori = 5
104 
105  Gpu::DeviceVector<BCRec> bcrs_w_d(1);
106  Gpu::copyAsync(Gpu::hostToDevice, bcrs_w.begin(), bcrs_w.end(), bcrs_w_d.begin());
107  const BCRec* bc_ptr_w = bcrs_w_d.data();
108 
109  GpuArray<GpuArray<Real, AMREX_SPACEDIM*2>,1> l_bc_extdir_vals_d;
110 
111  for (int ori = 0; ori < 2*AMREX_SPACEDIM; ori++) {
112  l_bc_extdir_vals_d[0][ori] = m_bc_extdir_vals[bccomp][ori];
113  }
114 
115  GeometryData const& geomdata = m_geom.data();
116  bool is_periodic_in_x = geomdata.isPeriodic(0);
117  bool is_periodic_in_y = geomdata.isPeriodic(1);
118 
119  FArrayBox dhdtfab;
120 
121  // First do all ext_dir bcs
122  if (!is_periodic_in_x)
123  {
124  Real* zvel_bc_ptr = m_w_bc_data;
125  Box bx_xlo(bx); bx_xlo.setBig (0,dom_lo.x-1);
126  Box bx_xhi(bx); bx_xhi.setSmall(0,dom_hi.x+1);
127  ParallelFor(bx_xlo, bx_xhi,
128  [=] AMREX_GPU_DEVICE (int i, int j, int k) {
129  int iflip = 2*dom_lo.x - 1 - i;
130  if ( (bc_ptr_w[0].lo(0) == ERFBCType::ext_dir) ||
131  (bc_ptr_w[0].lo(0) == ERFBCType::ext_dir_upwind && xvel_arr(dom_lo.x,Clamp(j,xvel_lo.y,xvel_hi.y),Clamp(k,xvel_lo.z,xvel_hi.z)) >= zero) )
132  {
133  dest_arr(i,j,k) = (zvel_bc_ptr) ? zvel_bc_ptr[k] : l_bc_extdir_vals_d[0][0];
134  if (l_use_terrain_fitted_coords) {
135  int wi = Clamp(i,wr.ilo,wr.ihi), wj = Clamp(j,wr.jlo,wr.jhi), wk = Clamp(k,wr.klo,wr.khi);
136  dest_arr(i,j,k) = WFromOmega(wi,wj,wk,dest_arr(i,j,k),
137  xvel_arr,yvel_arr,
138  mf_u,mf_v,z_phys_nd,dxInv);
139  }
140  } else if (bc_ptr_w[0].lo(0) == ERFBCType::foextrap) {
141  dest_arr(i,j,k) = dest_arr(dom_lo.x,j,k);
142  } else if (bc_ptr_w[0].lo(0) == ERFBCType::open) {
143  dest_arr(i,j,k) = dest_arr(dom_lo.x,j,k);
144  } else if (bc_ptr_w[0].lo(0) == ERFBCType::reflect_even) {
145  dest_arr(i,j,k) = dest_arr(iflip,j,k);
146  } else if (bc_ptr_w[0].lo(0) == ERFBCType::reflect_odd) {
147  dest_arr(i,j,k) = -dest_arr(iflip,j,k);
148  }
149  },
150  [=] AMREX_GPU_DEVICE (int i, int j, int k) {
151  int iflip = 2*dom_hi.x + 1 - i;
152  if ( (bc_ptr_w[0].hi(0) == ERFBCType::ext_dir) ||
153  (bc_ptr_w[0].hi(0) == ERFBCType::ext_dir_upwind && xvel_arr(dom_hi.x+1,Clamp(j,xvel_lo.y,xvel_hi.y),Clamp(k,xvel_lo.z,xvel_hi.z)) <= zero) )
154  {
155  dest_arr(i,j,k) = (zvel_bc_ptr) ? zvel_bc_ptr[k] : l_bc_extdir_vals_d[0][3];
156  if (l_use_terrain_fitted_coords) {
157  int wi = Clamp(i,wr.ilo,wr.ihi), wj = Clamp(j,wr.jlo,wr.jhi), wk = Clamp(k,wr.klo,wr.khi);
158  dest_arr(i,j,k) = WFromOmega(wi,wj,wk,dest_arr(i,j,k),
159  xvel_arr,yvel_arr,
160  mf_u,mf_v,z_phys_nd,dxInv);
161  }
162  } else if (bc_ptr_w[0].hi(0) == ERFBCType::foextrap) {
163  dest_arr(i,j,k) = dest_arr(dom_hi.x,j,k);
164  } else if (bc_ptr_w[0].hi(0) == ERFBCType::open) {
165  dest_arr(i,j,k) = dest_arr(dom_hi.x,j,k);
166  } else if (bc_ptr_w[0].hi(0) == ERFBCType::reflect_even) {
167  dest_arr(i,j,k) = dest_arr(iflip,j,k);
168  } else if (bc_ptr_w[0].hi(0) == ERFBCType::reflect_odd) {
169  dest_arr(i,j,k) = -dest_arr(iflip,j,k);
170  }
171  }
172  );
173  }
174 
175  // First do all ext_dir bcs
176  if (!is_periodic_in_y)
177  {
178  Real* zvel_bc_ptr = m_w_bc_data;
179  Box bx_ylo(bx); bx_ylo.setBig (1,dom_lo.y-1);
180  Box bx_yhi(bx); bx_yhi.setSmall(1,dom_hi.y+1);
181  ParallelFor(bx_ylo, bx_yhi,
182  [=] AMREX_GPU_DEVICE (int i, int j, int k) {
183  int jflip = 2*dom_lo.y - 1 - j;
184  if ( (bc_ptr_w[0].lo(1) == ERFBCType::ext_dir) ||
185  (bc_ptr_w[0].lo(1) == ERFBCType::ext_dir_upwind && yvel_arr(Clamp(i,yvel_lo.x,yvel_hi.x),dom_lo.y,Clamp(k,yvel_lo.z,yvel_hi.z)) >= zero) )
186  {
187  dest_arr(i,j,k) = (zvel_bc_ptr) ? zvel_bc_ptr[k] : l_bc_extdir_vals_d[0][1];
188  if (l_use_terrain_fitted_coords) {
189  int wi = Clamp(i,wr.ilo,wr.ihi), wj = Clamp(j,wr.jlo,wr.jhi), wk = Clamp(k,wr.klo,wr.khi);
190  dest_arr(i,j,k) = WFromOmega(wi,wj,wk,dest_arr(i,j,k),
191  xvel_arr,yvel_arr,
192  mf_u,mf_v,z_phys_nd,dxInv);
193  }
194  } else if (bc_ptr_w[0].lo(1) == ERFBCType::foextrap) {
195  dest_arr(i,j,k) = dest_arr(i,dom_lo.y,k);
196  } else if (bc_ptr_w[0].lo(1) == ERFBCType::open) {
197  dest_arr(i,j,k) = dest_arr(i,dom_lo.y,k);
198  } else if (bc_ptr_w[0].lo(1) == ERFBCType::reflect_even) {
199  dest_arr(i,j,k) = dest_arr(i,jflip,k);
200  } else if (bc_ptr_w[0].lo(1) == ERFBCType::reflect_odd) {
201  dest_arr(i,j,k) = -dest_arr(i,jflip,k);
202  }
203  },
204  [=] AMREX_GPU_DEVICE (int i, int j, int k) {
205  int jflip = 2*dom_hi.y + 1 - j;
206  if ( (bc_ptr_w[0].hi(1) == ERFBCType::ext_dir) ||
207  (bc_ptr_w[0].hi(1) == ERFBCType::ext_dir_upwind && yvel_arr(Clamp(i,yvel_lo.x,yvel_hi.x),dom_hi.y+1,Clamp(k,yvel_lo.z,yvel_hi.z)) <= zero) )
208  {
209  dest_arr(i,j,k) = (zvel_bc_ptr) ? zvel_bc_ptr[k] : l_bc_extdir_vals_d[0][4];
210  if (l_use_terrain_fitted_coords) {
211  int wi = Clamp(i,wr.ilo,wr.ihi), wj = Clamp(j,wr.jlo,wr.jhi), wk = Clamp(k,wr.klo,wr.khi);
212  dest_arr(i,j,k) = WFromOmega(wi,wj,wk,dest_arr(i,j,k),
213  xvel_arr,yvel_arr,
214  mf_u,mf_v,z_phys_nd,dxInv);
215  }
216  } else if (bc_ptr_w[0].hi(1) == ERFBCType::foextrap) {
217  dest_arr(i,j,k) = dest_arr(i,dom_hi.y,k);
218  } else if (bc_ptr_w[0].hi(1) == ERFBCType::open) {
219  dest_arr(i,j,k) = dest_arr(i,dom_hi.y,k);
220  } else if (bc_ptr_w[0].hi(1) == ERFBCType::reflect_even) {
221  dest_arr(i,j,k) = dest_arr(i,jflip,k);
222  } else if (bc_ptr_w[0].hi(1) == ERFBCType::reflect_odd) {
223  dest_arr(i,j,k) = -dest_arr(i,jflip,k);
224  }
225  });
226  }
227  Gpu::streamSynchronize();
228 }
amrex::GpuArray< Real, AMREX_SPACEDIM > dxInv
Definition: ERF_InitCustomPertVels_ParticleTests.H:17
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 zero
Definition: ERF_NumericalConstants.H:36
amrex::Real Real
Definition: ERF_ShocInterface.H:19
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real WFromOmega(int &i, int &j, int &k, amrex::Real omega, const amrex::Array4< const amrex::Real > &u_arr, const amrex::Array4< const amrex::Real > &v_arr, const amrex::Array4< const amrex::Real > &mf_u, const amrex::Array4< const amrex::Real > &mf_v, const amrex::Array4< const amrex::Real > &z_nd, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dxInv)
Definition: ERF_TerrainMetrics.H:867
void impose_lateral_zvel_bcs(const amrex::Array4< amrex::Real > &dest_arr, const amrex::Array4< amrex::Real const > &xvel_arr, const amrex::Array4< amrex::Real const > &yvel_arr, const amrex::Box &bx, const amrex::Box &domain, const amrex::Array4< amrex::Real const > &mf_u, const amrex::Array4< amrex::Real const > &mf_v, const amrex::Array4< amrex::Real const > &z_nd, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > dxInv, TerrainType terrain_type, int bccomp, const double time)
Definition: ERF_BoundaryConditionsZvel.cpp:57
@ open
Definition: ERF_IndexDefines.H:347
@ reflect_odd
Definition: ERF_IndexDefines.H:336
@ foextrap
Definition: ERF_IndexDefines.H:339
@ ext_dir
Definition: ERF_IndexDefines.H:340
@ ext_dir_upwind
Definition: ERF_IndexDefines.H:348
@ reflect_even
Definition: ERF_IndexDefines.H:338
@ wi
Definition: ERF_AdvanceWDM6.cpp:277
Here is the call graph for this function:

◆ impose_vertical_zvel_bcs()

void ERFPhysBCFunct_w::impose_vertical_zvel_bcs ( const amrex::Array4< amrex::Real > &  dest_arr,
const amrex::Array4< amrex::Real const > &  xvel_arr,
const amrex::Array4< amrex::Real const > &  yvel_arr,
const amrex::Box &  bx,
const amrex::Box &  domain,
const amrex::Array4< amrex::Real const > &  mf_u,
const amrex::Array4< amrex::Real const > &  mf_v,
const amrex::Array4< amrex::Real const > &  z_nd,
const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM >  dxInv,
int  bccomp_u,
int  bccomp_v,
int  bccomp_w,
TerrainType  terrain_type,
const double  time 
)

Impose vertical boundary conditions on z velocity.

Parameters
[in,out]dest_arrz-velocity data to be filled
[in]xvel_arrx-velocity used by terrain-aware vertical BCs
[in]yvel_arry-velocity used by terrain-aware vertical BCs
[in]bxbox holding data to be filled
[in]domainsimulation domain
[in]mf_ux map-factor field
[in]mf_vy map-factor field
[in]z_ndnodal physical height
[in]dxInvinverse cell size
[in]bccomp_ux-velocity boundary-condition component
[in]bccomp_vy-velocity boundary-condition component
[in]bccomp_wz-velocity boundary-condition component
[in]terrain_typeterrain representation
[in]timetime at which data should be filled

Impose vertical boundary conditions on z-component of velocity

Parameters
[in,out]dest_arrArray4 of the quantity to be filled
[in]xvel_arrx-velocity used to convert omega to w
[in]yvel_arry-velocity used to convert omega to w
[in]bxbox associated with this data
[in]domaincomputational domain
[in]mf_umetric-aware x-velocity used to convert omega to w
[in]mf_vmetric-aware y-velocity used to convert omega to w
[in]z_phys_ndheight coordinate at nodes
[in]dxInvinverse cell size array
[in]bccomp_uindex into m_domain_bcs_type corresponding to u
[in]bccomp_vindex into m_domain_bcs_type corresponding to v
[in]bccomp_windex into m_domain_bcs_type corresponding to w
[in]terrain_typeif MovingFittedMesh then the terrain is moving; otherwise fixed
[in]timetime at which the data should be filled
260 {
261  BL_PROFILE_VAR("impose_vertical_zvel_bcs()",impose_vertical_zvel_bcs);
262  const auto& dom_lo = lbound(domain);
263  const auto& dom_hi = ubound(domain);
264  const WFromOmegaRange wr = wfromomega_range(xvel_arr, yvel_arr, mf_u, mf_v, z_phys_nd);
265 
266  // xlo: ori = 0
267  // ylo: ori = 1
268  // zlo: ori = 2
269  // xhi: ori = 3
270  // yhi: ori = 4
271  // zhi: ori = 5
272 
273  // Based on BCRec for the domain, we need to make BCRec for this Box
274  // bccomp is used as starting index for m_domain_bcs_type
275  // 0 is used as starting index for bcrs
276  Vector<BCRec> bcrs_u(1), bcrs_v(1), bcrs_w(1);
277  setBC(enclosedCells(bx), domain, bccomp_u, 0, 1, m_domain_bcs_type, bcrs_u);
278  setBC(enclosedCells(bx), domain, bccomp_v, 0, 1, m_domain_bcs_type, bcrs_v);
279  setBC(enclosedCells(bx), domain, bccomp_w, 0, 1, m_domain_bcs_type, bcrs_w);
280 
281  // We use these for the asserts below
282  const BCRec* bc_ptr_u_h = bcrs_u.data();
283  const BCRec* bc_ptr_v_h = bcrs_v.data();
284  const BCRec* bc_ptr_w_h = bcrs_w.data();
285 
286  bool l_use_terrain_fitted_coords = ( (terrain_type == TerrainType::StaticFittedMesh) ||
287  (terrain_type == TerrainType::MovingFittedMesh) );
288  bool l_moving_terrain = (terrain_type == TerrainType::MovingFittedMesh);
289 
290  GpuArray<GpuArray<Real, AMREX_SPACEDIM*2>,1> l_bc_extdir_vals_d;
291 
292  for (int ori = 0; ori < 2*AMREX_SPACEDIM; ori++) {
293  l_bc_extdir_vals_d[0][ori] = m_bc_extdir_vals[bccomp_w][ori];
294  }
295 
296  // *******************************************************
297  // Bottom boundary
298  // *******************************************************
299 
300  // *******************************************************
301  // Moving terrain
302  // *******************************************************
303  if (l_moving_terrain)
304  {
305  //************************************************************
306  // NOTE: z_t depends on the time interval in which it is
307  // evaluated so we can't arbitrarily define it at a
308  // given time, we must specify an interval
309  //************************************************************
310 
311  // Static terrain
312  } else if (l_use_terrain_fitted_coords) {
313 
314  if (m_lev == 0) {
315  AMREX_ALWAYS_ASSERT( (bc_ptr_u_h[0].lo(2) == ERFBCType::ext_dir && bc_ptr_v_h[0].lo(2) == ERFBCType::ext_dir) ||
316  (bc_ptr_u_h[0].lo(2) != ERFBCType::ext_dir && bc_ptr_v_h[0].lo(2) != ERFBCType::ext_dir) );
317  } else {
318  // If we do not reach to the top or bottom boundary then the z-vel should be
319  // filled by interpolation from the coarser grid using ERF_FillPatcher.
320  }
321  if (bx.smallEnd(2) == dom_lo.z) {
322  ParallelFor(makeSlab(bx,2,dom_lo.z), [=] AMREX_GPU_DEVICE (int i, int j, int k) {
323  int wi = Clamp(i,wr.ilo,wr.ihi), wj = Clamp(j,wr.jlo,wr.jhi), wk = Clamp(k,wr.klo,wr.khi);
324  dest_arr(i,j,k) = WFromOmega(wi,wj,wk,l_bc_extdir_vals_d[0][2],
325  xvel_arr,yvel_arr,
326  mf_u,mf_v,z_phys_nd,dxInv);
327  });
328  }
329 
330  // No terrain
331  } else {
332  if (bx.smallEnd(2) == dom_lo.z) {
333  ParallelFor(makeSlab(bx,2,dom_lo.z), [=] AMREX_GPU_DEVICE (int i, int j, int k) {
334  dest_arr(i,j,k) = l_bc_extdir_vals_d[0][2];
335  });
336  }
337  }
338 
339  // *******************************************************
340  // Top boundary
341  // *******************************************************
342 
343  // NOTE: if we set SlipWall at top, that generates ERFBCType::ext_dir which sets w=0 here
344  // NOTE: if we set Outflow at top, that generates ERFBCType::foextrap which doesn't touch w here
345  if (bx.bigEnd(2) == dom_hi.z+1) {
346  if (bc_ptr_w_h[0].hi(2) == ERFBCType::ext_dir) {
347  ParallelFor(makeSlab(bx,2,dom_hi.z+1), [=] AMREX_GPU_DEVICE (int i, int j, int k)
348  {
349  if (l_use_terrain_fitted_coords) {
350  int wi = Clamp(i,wr.ilo,wr.ihi), wj = Clamp(j,wr.jlo,wr.jhi), wk = Clamp(k,wr.klo,wr.khi);
351  dest_arr(i,j,k) = WFromOmega(wi,wj,wk,l_bc_extdir_vals_d[0][5],
352  xvel_arr,yvel_arr,
353  mf_u,mf_v,z_phys_nd,dxInv);
354  } else {
355  dest_arr(i,j,k) = l_bc_extdir_vals_d[0][5];
356  }
357  });
358  } else if (bc_ptr_w_h[0].hi(2) == ERFBCType::neumann_int) {
359  ParallelFor(makeSlab(bx,2,dom_hi.z+1), [=] AMREX_GPU_DEVICE (int i, int j, int k)
360  {
361  dest_arr(i,j,k) = (Real(4.0)*dest_arr(i,j,dom_hi.z) - dest_arr(i,j,dom_hi.z-1))/three;
362  });
363  }
364  }
365  Gpu::streamSynchronize();
366 }
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
constexpr amrex::Real three
Definition: ERF_NumericalConstants.H:39
void impose_vertical_zvel_bcs(const amrex::Array4< amrex::Real > &dest_arr, const amrex::Array4< amrex::Real const > &xvel_arr, const amrex::Array4< amrex::Real const > &yvel_arr, const amrex::Box &bx, const amrex::Box &domain, const amrex::Array4< amrex::Real const > &mf_u, const amrex::Array4< amrex::Real const > &mf_v, const amrex::Array4< amrex::Real const > &z_nd, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > dxInv, int bccomp_u, int bccomp_v, int bccomp_w, TerrainType terrain_type, const double time)
Definition: ERF_BoundaryConditionsZvel.cpp:249
@ neumann_int
Definition: ERF_IndexDefines.H:346
Here is the call graph for this function:

◆ operator()()

void ERFPhysBCFunct_w::operator() ( amrex::MultiFab &  mf,
amrex::MultiFab &  xvel,
amrex::MultiFab &  yvel,
amrex::IntVect const &  nghost,
const double  time,
int  bccomp,
bool  do_fb 
)

Impose physical boundary conditions at domain boundaries

Parameters
[in,out]mfz-velocity MultiFab to be filled
[in]xvelx-velocity MultiFab used by upwind boundary conditions
[in]yvely-velocity MultiFab used by upwind boundary conditions
[in]nghostnumber of ghost cells to be filled for velocity components
[in]timetime at which the data should be filled
[in]bccompindex into m_domain_bcs_type for z velocity
[in]do_fbwhether to fill periodic/interior ghost cells first

Impose physical boundary conditions on z velocity.

Parameters
[in,out]mfz-velocity MultiFab to be filled
[in]xvelx-velocity MultiFab used by upwind boundary conditions
[in]yvely-velocity MultiFab used by upwind boundary conditions
[in]nghostnumber of ghost cells to be filled
[in]timetime at which data should be filled
[in]bccomp_windex into m_domain_bcs_type for z velocity
[in]do_fbwhether to fill periodic/interior ghost cells first
357 {
358  BL_PROFILE("ERFPhysBCFunct_w::()");
359 
360  //
361  // We fill all of the interior and periodic ghost cells first, so we can fill
362  // those directly inside the lateral and vertical calls.
363  // If triply periodic this is all we do
364  //
365  if (do_fb) {
366  mf.FillBoundary(m_geom.periodicity());
367  }
368 
369  if (m_geom.isAllPeriodic()) return;
370 
371  int bccomp_u = BCVars::xvel_bc;
372  int bccomp_v = BCVars::yvel_bc;
373 
374  const auto& domain = m_geom.Domain();
375  const auto dxInv = m_geom.InvCellSizeArray();
376 
377  Box gdomainz = surroundingNodes(domain,2);
378  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
379  if (m_geom.isPeriodic(i)) {
380  gdomainz.grow(i, nghost[i]);
381  }
382  }
383  //
384  // We want to make sure we impose the z-vels at k=0 if the box includes k=0
385  //
386  if (gdomainz.smallEnd(2) == 0) gdomainz.setSmall(2,1);
387 
388 #ifdef AMREX_USE_OMP
389 #pragma omp parallel if (Gpu::notInLaunchRegion())
390 #endif
391  {
392  for (MFIter mfi(mf,false); mfi.isValid(); ++mfi)
393  {
394  //
395  // This is the box we pass to the different routines
396  // NOTE -- this is the full grid NOT the tile box
397  //
398  Box bx = mfi.validbox();
399 
400  //
401  // These are the boxes we use to test on relative to the domain
402  //
403  Box zbx = surroundingNodes(bx,2); zbx.grow(nghost);
404  if (zbx.smallEnd(2) < domain.smallEnd(2)) zbx.setSmall(2,domain.smallEnd(2));
405  if (zbx.bigEnd(2) > domain.bigEnd(2)) {
406  zbx.setBig(2,domain.bigEnd(2)+1);
407  } else if (zbx.bigEnd(2) > xvel[mfi].box().bigEnd(2)) {
408  // We do this so if a box at level > 0 doesn't reach the top boundary, we don't go out of bounds
409  // (Note xvel is chosen arbitrarily; we could have used yvel instead)
410  zbx.setBig(2,xvel[mfi].box().bigEnd(2));
411  }
412 
413  Array4<const Real> z_nd_arr;
414  const Array4<const Real>& mf_u = m_mapfac_u->const_array(mfi);
415  const Array4<const Real>& mf_v = m_mapfac_v->const_array(mfi);
416 
417  if (m_z_phys_nd) {
418  z_nd_arr = m_z_phys_nd->const_array(mfi);
419  }
420 
421  //
422  // Recall that gdomainz.smallEnd(2) = 1 not 0!
423  //
424  if (!gdomainz.contains(zbx)) {
425  Array4<const Real> const& velx_arr = xvel.const_array(mfi);
426  Array4<const Real> const& vely_arr = yvel.const_array(mfi);
427  Array4< Real> const& velz_arr = mf.array(mfi);
428 
429  if (!gdomainz.contains(zbx) && !m_use_real_bcs) {
430  impose_lateral_zvel_bcs(velz_arr,velx_arr,vely_arr,zbx,domain,
431  mf_u,mf_v,z_nd_arr,dxInv,m_terrain_type,bccomp_w,time);
432  }
433 
434  impose_vertical_zvel_bcs(velz_arr,velx_arr,vely_arr,zbx,domain,mf_u,mf_v,
435  z_nd_arr,dxInv,bccomp_u, bccomp_v, bccomp_w, m_terrain_type, time);
436  }
437 
438  //
439  // The faces beyond the bottom and top boundary faces are not set above, so
440  // give them the value on the boundary face. Nothing else fills them: on
441  // a level > 0 FillPatchTwoLevels does not fill outside the domain, and
442  // ERF::Advance has set them to bogus_large_value. The EB wall slopes
443  // read w at k = -1 where the EB meets the bottom boundary (issue #4876).
444  //
445  if (!m_geom.isPeriodic(2)) {
446  Array4<Real> const& velz_arr = mf.array(mfi);
447  Box gbx = mfi.fabbox() & surroundingNodes(bx,2).grow(nghost);
448  const int klo = domain.smallEnd(2);
449  const int khi = domain.bigEnd(2)+1;
450  if (gbx.smallEnd(2) < klo) {
451  Box bx_zlo(gbx); bx_zlo.setBig(2,klo-1);
452  ParallelFor(bx_zlo, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
453  velz_arr(i,j,k) = velz_arr(i,j,klo);
454  });
455  }
456  if (gbx.bigEnd(2) > khi) {
457  Box bx_zhi(gbx); bx_zhi.setSmall(2,khi+1);
458  ParallelFor(bx_zhi, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
459  velz_arr(i,j,k) = velz_arr(i,j,khi);
460  });
461  }
462  }
463  } // MFIter
464  } // OpenMP
465 } // operator()
const int khi
Definition: ERF_InitCustomPert_Bubble.H:25
const int klo
Definition: ERF_InitCustomPert_KE.H:9
@ yvel_bc
Definition: ERF_IndexDefines.H:127
@ xvel_bc
Definition: ERF_IndexDefines.H:126
@ xvel
Definition: ERF_IndexDefines.H:255
@ yvel
Definition: ERF_IndexDefines.H:256
Here is the call graph for this function:

Member Data Documentation

◆ m_bc_extdir_vals

amrex::Array<amrex::Array<amrex::Real, AMREX_SPACEDIM*2>,AMREX_SPACEDIM+NBCVAR_max> ERFPhysBCFunct_w::m_bc_extdir_vals
private

◆ m_bc_neumann_vals

amrex::Array<amrex::Array<amrex::Real, AMREX_SPACEDIM*2>,AMREX_SPACEDIM+NBCVAR_max> ERFPhysBCFunct_w::m_bc_neumann_vals
private

◆ m_domain_bcs_type

amrex::Vector<amrex::BCRec> ERFPhysBCFunct_w::m_domain_bcs_type
private

◆ m_domain_bcs_type_d

amrex::Gpu::DeviceVector<amrex::BCRec> ERFPhysBCFunct_w::m_domain_bcs_type_d
private

◆ m_geom

amrex::Geometry ERFPhysBCFunct_w::m_geom
private

◆ m_lev

int ERFPhysBCFunct_w::m_lev
private

◆ m_mapfac_u

amrex::MultiFab* ERFPhysBCFunct_w::m_mapfac_u
private

Referenced by ERFPhysBCFunct_w().

◆ m_mapfac_v

amrex::MultiFab* ERFPhysBCFunct_w::m_mapfac_v
private

Referenced by ERFPhysBCFunct_w().

◆ m_terrain_type

TerrainType ERFPhysBCFunct_w::m_terrain_type
private

◆ m_use_real_bcs

bool ERFPhysBCFunct_w::m_use_real_bcs
private

◆ m_w_bc_data

amrex::Real* ERFPhysBCFunct_w::m_w_bc_data
private

◆ m_z_phys_nd

amrex::MultiFab* ERFPhysBCFunct_w::m_z_phys_nd
private

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