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

#include <ERF_PhysBCFunct.H>

Collaboration diagram for ERFPhysBCFunct_v:

Public Member Functions

 ERFPhysBCFunct_v (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, std::unique_ptr< amrex::MultiFab > &z_phys_nd, const bool use_real_bcs, amrex::Real *v_bc_data)
 
 ~ERFPhysBCFunct_v ()
 
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_yvel_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, int bccomp, const double time)
 
void impose_vertical_yvel_bcs (const amrex::Array4< amrex::Real > &dest_arr, const amrex::Box &bx, const amrex::Box &domain, const amrex::Array4< amrex::Real const > &z_nd, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > dxInv, int bccomp, 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_z_phys_nd
 
bool m_use_real_bcs
 
amrex::Real * m_v_bc_data
 
BelowGroundGhostSync m_below_ground_sync
 

Constructor & Destructor Documentation

◆ ERFPhysBCFunct_v()

ERFPhysBCFunct_v::ERFPhysBCFunct_v ( 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,
std::unique_ptr< amrex::MultiFab > &  z_phys_nd,
const bool  use_real_bcs,
amrex::Real *  v_bc_data 
)
inline

Construct the y-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]z_phys_ndnodal physical height MultiFab
[in]use_real_bcswhether real-data boundary conditions are active
[in]v_bc_dataoptional y-velocity boundary data
306  : m_lev(lev),
307  m_geom(geom), m_domain_bcs_type(domain_bcs_type),
308  m_domain_bcs_type_d(domain_bcs_type_d),
309  m_bc_extdir_vals(bc_extdir_vals),
310  m_bc_neumann_vals(bc_neumann_vals),
311  m_terrain_type(terrain_type),
312  m_z_phys_nd(z_phys_nd.get()),
313  m_use_real_bcs(use_real_bcs),
314  m_v_bc_data(v_bc_data)
315  { }
amrex::Geometry m_geom
Definition: ERF_PhysBCFunct.H:374
amrex::Gpu::DeviceVector< amrex::BCRec > m_domain_bcs_type_d
Definition: ERF_PhysBCFunct.H:376
amrex::Real * m_v_bc_data
Definition: ERF_PhysBCFunct.H:382
int m_lev
Definition: ERF_PhysBCFunct.H:373
TerrainType m_terrain_type
Definition: ERF_PhysBCFunct.H:379
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_neumann_vals
Definition: ERF_PhysBCFunct.H:378
bool m_use_real_bcs
Definition: ERF_PhysBCFunct.H:381
amrex::Vector< amrex::BCRec > m_domain_bcs_type
Definition: ERF_PhysBCFunct.H:375
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_extdir_vals
Definition: ERF_PhysBCFunct.H:377
amrex::MultiFab * m_z_phys_nd
Definition: ERF_PhysBCFunct.H:380

◆ ~ERFPhysBCFunct_v()

ERFPhysBCFunct_v::~ERFPhysBCFunct_v ( )
inline

Destroy the y-velocity physical boundary-condition functor.

320 {}

Member Function Documentation

◆ impose_lateral_yvel_bcs()

void ERFPhysBCFunct_v::impose_lateral_yvel_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,
int  bccomp,
const double  time 
)

Impose lateral boundary conditions on y velocity.

Parameters
[in,out]dest_arry-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]bccompboundary-condition component
[in]timetime at which data should be filled

Impose lateral boundary conditions on y-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]bccompindex into m_domain_bcs_type
[in]timetime at which the data should be filled
22 {
23  BL_PROFILE_VAR("impose_lateral_yvel_bcs()",impose_lateral_yvel_bcs);
24  const auto& dom_lo = lbound(domain);
25  const auto& dom_hi = ubound(domain);
26 
27  //
28  // An ext_dir_upwind face decides inflow against the face velocity, but the box we
29  // loop over does not always have a face velocity at every one of its cells: the
30  // state carries one more lateral ghost than the velocities do (ngrow_state =
31  // ComputeGhostCells()+1 against ngrow_vels = ComputeGhostCells()), and a velocity
32  // box is nodal in its own direction where the array being read is cell centered.
33  // Either way the outermost ghost cells have no velocity of their own, so sample
34  // the nearest one that exists. Cells already inside the velocity array are
35  // unaffected; only that outermost layer changes, and it previously read out of
36  // bounds.
37  //
38  const auto& xvel_lo = lbound(xvel_arr);
39  const auto& xvel_hi = ubound(xvel_arr);
40  const auto& yvel_lo = lbound(yvel_arr);
41  const auto& yvel_hi = ubound(yvel_arr);
42 
43  // Based on BCRec for the domain, we need to make BCRec for this Box
44  // bccomp is used as starting index for m_domain_bcs_type
45  // 0 is used as starting index for bcrs
46  Vector<BCRec> bcrs(1);
47  setBC(enclosedCells(bx), domain, bccomp, 0, 1, m_domain_bcs_type, bcrs);
48 
49  // xlo: ori = 0
50  // ylo: ori = 1
51  // zlo: ori = 2
52  // xhi: ori = 3
53  // yhi: ori = 4
54  // zhi: ori = 5
55 
56  Gpu::DeviceVector<BCRec> bcrs_d(1);
57  Gpu::copyAsync(Gpu::hostToDevice, bcrs.begin(), bcrs.end(), bcrs_d.begin());
58  const BCRec* bc_ptr = bcrs_d.data();
59 
60  GpuArray<GpuArray<Real, AMREX_SPACEDIM*2>, 1> l_bc_extdir_vals_d;
61 
62  for (int ori = 0; ori < 2*AMREX_SPACEDIM; ori++) {
63  l_bc_extdir_vals_d[0][ori] = m_bc_extdir_vals[bccomp][ori];
64  }
65 
66  GeometryData const& geomdata = m_geom.data();
67  bool is_periodic_in_x = geomdata.isPeriodic(0);
68  bool is_periodic_in_y = geomdata.isPeriodic(1);
69 
70  // First do all ext_dir bcs
71  if (!is_periodic_in_x)
72  {
73  // Populate ghost cells on lo-x and hi-x domain boundaries
74  Real* yvel_bc_ptr = m_v_bc_data;
75  Box bx_xlo(bx); bx_xlo.setBig (0,dom_lo.x-1);
76  Box bx_xhi(bx); bx_xhi.setSmall(0,dom_hi.x+1);
77  ParallelFor(bx_xlo, bx_xhi,
78  [=] AMREX_GPU_DEVICE (int i, int j, int k) {
79  int iflip = dom_lo.x - 1- i;
80  if (bc_ptr[0].lo(0) == ERFBCType::ext_dir) {
81  dest_arr(i,j,k) = (yvel_bc_ptr) ? yvel_bc_ptr[k] : l_bc_extdir_vals_d[0][0];
82  } else if (bc_ptr[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) {
83  dest_arr(i,j,k) = (yvel_bc_ptr) ? yvel_bc_ptr[k] : l_bc_extdir_vals_d[0][0];
84  } else if (bc_ptr[0].lo(0) == ERFBCType::foextrap) {
85  dest_arr(i,j,k) = dest_arr(dom_lo.x,j,k);
86  } else if (bc_ptr[0].lo(0) == ERFBCType::open) {
87  dest_arr(i,j,k) = dest_arr(dom_lo.x,j,k);
88  } else if (bc_ptr[0].lo(0) == ERFBCType::reflect_even) {
89  dest_arr(i,j,k) = dest_arr(iflip,j,k);
90  } else if (bc_ptr[0].lo(0) == ERFBCType::reflect_odd) {
91  dest_arr(i,j,k) = -dest_arr(iflip,j,k);
92  } else if (bc_ptr[0].lo(0) == ERFBCType::hoextrap) {
93  Real delta_i = (dom_lo.x - i);
94  dest_arr(i,j,k) = (one + delta_i)*dest_arr(dom_lo.x,j,k) - delta_i*dest_arr(dom_lo.x+1,j,k);
95  }
96  },
97  [=] AMREX_GPU_DEVICE (int i, int j, int k) {
98  int iflip = 2*dom_hi.x + 1 - i;
99  if (bc_ptr[0].hi(0) == ERFBCType::ext_dir) {
100  dest_arr(i,j,k) = (yvel_bc_ptr) ? yvel_bc_ptr[k] : l_bc_extdir_vals_d[0][3];
101  } else if (bc_ptr[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) {
102  dest_arr(i,j,k) = (yvel_bc_ptr) ? yvel_bc_ptr[k] : l_bc_extdir_vals_d[0][3];
103  } else if (bc_ptr[0].hi(0) == ERFBCType::foextrap) {
104  dest_arr(i,j,k) = dest_arr(dom_hi.x,j,k);
105  } else if (bc_ptr[0].hi(0) == ERFBCType::open) {
106  dest_arr(i,j,k) = dest_arr(dom_hi.x,j,k);
107  } else if (bc_ptr[0].hi(0) == ERFBCType::reflect_even) {
108  dest_arr(i,j,k) = dest_arr(iflip,j,k);
109  } else if (bc_ptr[0].hi(0) == ERFBCType::reflect_odd) {
110  dest_arr(i,j,k) = -dest_arr(iflip,j,k);
111  } else if (bc_ptr[0].hi(0) == ERFBCType::hoextrap) {
112  Real delta_i = (i - dom_hi.x);
113  dest_arr(i,j,k) = (one + delta_i)*dest_arr(dom_hi.x,j,k) - delta_i*dest_arr(dom_hi.x-1,j,k);
114  }
115  }
116  );
117  }
118 
119  if (!is_periodic_in_y)
120  {
121  // Populate ghost cells on lo-y and hi-y domain boundaries
122  Real* yvel_bc_ptr = m_v_bc_data;
123  Box bx_ylo(bx); bx_ylo.setBig (1,dom_lo.y-1);
124  Box bx_yhi(bx); bx_yhi.setSmall(1,dom_hi.y+2);
125  Box bx_ylo_face(bx); bx_ylo_face.setSmall(1,dom_lo.y ); bx_ylo_face.setBig(1,dom_lo.y );
126  Box bx_yhi_face(bx); bx_yhi_face.setSmall(1,dom_hi.y+1); bx_yhi_face.setBig(1,dom_hi.y+1);
127  ParallelFor(bx_ylo, bx_ylo_face,
128  [=] AMREX_GPU_DEVICE (int i, int j, int k)
129  {
130  int jflip = dom_lo.y-j;
131  if (bc_ptr[0].lo(1) == ERFBCType::ext_dir) {
132  dest_arr(i,j,k) = (yvel_bc_ptr) ? yvel_bc_ptr[k] : l_bc_extdir_vals_d[0][1];
133  } else if (bc_ptr[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) {
134  dest_arr(i,j,k) = (yvel_bc_ptr) ? yvel_bc_ptr[k] : l_bc_extdir_vals_d[0][1];
135  } else if (bc_ptr[0].lo(1) == ERFBCType::foextrap) {
136  dest_arr(i,j,k) = dest_arr(i,dom_lo.y,k);
137  } else if (bc_ptr[0].lo(1) == ERFBCType::open) {
138  dest_arr(i,j,k) = dest_arr(i,dom_lo.y,k);
139  } else if (bc_ptr[0].lo(1) == ERFBCType::reflect_even) {
140  dest_arr(i,j,k) = dest_arr(i,jflip,k);
141  } else if (bc_ptr[0].lo(1) == ERFBCType::reflect_odd) {
142  dest_arr(i,j,k) = -dest_arr(i,jflip,k);
143  } else if (bc_ptr[0].lo(1) == ERFBCType::neumann_int) {
144  dest_arr(i,j,k) = (Real(4.0)*dest_arr(i,dom_lo.y+1,k) - dest_arr(i,dom_lo.y+2,k))/three;
145  } else if (bc_ptr[0].lo(1) == ERFBCType::hoextrap) {
146  Real delta_j = (dom_lo.y - j);
147  dest_arr(i,j,k) = (one + delta_j)*dest_arr(i,dom_lo.y,k) - delta_j*dest_arr(i,dom_lo.y+1,k);
148  }
149  },
150  // We only set the values on the domain faces themselves if EXT_DIR or neumann_int
151  [=] AMREX_GPU_DEVICE (int i, int j, int k)
152  {
153  if (bc_ptr[0].lo(1) == ERFBCType::ext_dir) {
154  dest_arr(i,j,k) = (yvel_bc_ptr) ? yvel_bc_ptr[k] : l_bc_extdir_vals_d[0][1];
155  } else if (bc_ptr[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) {
156  dest_arr(i,j,k) = (yvel_bc_ptr) ? yvel_bc_ptr[k] : l_bc_extdir_vals_d[0][1];
157  } else if (bc_ptr[0].lo(1) == ERFBCType::neumann_int) {
158  dest_arr(i,j,k) = (Real(4.0)*dest_arr(i,dom_lo.y+1,k) - dest_arr(i,dom_lo.y+2,k))/three;
159  }
160  }
161  );
162  ParallelFor(bx_yhi, bx_yhi_face,
163  [=] AMREX_GPU_DEVICE (int i, int j, int k)
164  {
165  int jflip = 2*(dom_hi.y + 1) - j;
166  if (bc_ptr[0].hi(1) == ERFBCType::ext_dir) {
167  dest_arr(i,j,k) = (yvel_bc_ptr) ? yvel_bc_ptr[k] : l_bc_extdir_vals_d[0][4];
168  } else if (bc_ptr[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) {
169  dest_arr(i,j,k) = (yvel_bc_ptr) ? yvel_bc_ptr[k] : l_bc_extdir_vals_d[0][4];
170  } else if (bc_ptr[0].hi(1) == ERFBCType::foextrap) {
171  dest_arr(i,j,k) = dest_arr(i,dom_hi.y+1,k);
172  } else if (bc_ptr[0].hi(1) == ERFBCType::open) {
173  dest_arr(i,j,k) = dest_arr(i,dom_hi.y+1,k);
174  } else if (bc_ptr[0].hi(1) == ERFBCType::reflect_even) {
175  dest_arr(i,j,k) = dest_arr(i,jflip,k);
176  } else if (bc_ptr[0].hi(1) == ERFBCType::reflect_odd) {
177  dest_arr(i,j,k) = -dest_arr(i,jflip,k);
178  } else if (bc_ptr[0].hi(1) == ERFBCType::neumann_int) {
179  dest_arr(i,j,k) = (Real(4.0)*dest_arr(i,dom_hi.y,k) - dest_arr(i,dom_hi.y-1,k))/three;
180  } else if (bc_ptr[0].hi(1) == ERFBCType::hoextrap) {
181  Real delta_j = (j - dom_hi.y - 1);
182  dest_arr(i,j,k) = (one + delta_j)*dest_arr(i,dom_hi.y+1,k) - delta_j*dest_arr(i,dom_hi.y,k);
183  }
184  },
185  // We only set the values on the domain faces themselves if EXT_DIR or neumann_int
186  [=] AMREX_GPU_DEVICE (int i, int j, int k)
187  {
188  if (bc_ptr[0].hi(1) == ERFBCType::ext_dir) {
189  dest_arr(i,j,k) = (yvel_bc_ptr) ? yvel_bc_ptr[k] : l_bc_extdir_vals_d[0][4];
190  } else if (bc_ptr[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) {
191  dest_arr(i,j,k) = (yvel_bc_ptr) ? yvel_bc_ptr[k] : l_bc_extdir_vals_d[0][4];
192  } else if (bc_ptr[0].hi(1) == ERFBCType::neumann_int) {
193  dest_arr(i,j,k) = (Real(4.0)*dest_arr(i,dom_hi.y,k) - dest_arr(i,dom_hi.y-1,k))/three;
194  }
195  }
196  );
197  }
198  Gpu::streamSynchronize();
199 }
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 three
Definition: ERF_NumericalConstants.H:39
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:37
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:36
amrex::Real Real
Definition: ERF_ShocInterface.H:19
void impose_lateral_yvel_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, int bccomp, const double time)
Definition: ERF_BoundaryConditionsYvel.cpp:17
@ open
Definition: ERF_IndexDefines.H:307
@ reflect_odd
Definition: ERF_IndexDefines.H:296
@ hoextrap
Definition: ERF_IndexDefines.H:301
@ foextrap
Definition: ERF_IndexDefines.H:299
@ ext_dir
Definition: ERF_IndexDefines.H:300
@ ext_dir_upwind
Definition: ERF_IndexDefines.H:308
@ neumann_int
Definition: ERF_IndexDefines.H:306
@ reflect_even
Definition: ERF_IndexDefines.H:298
Here is the call graph for this function:

◆ impose_vertical_yvel_bcs()

void ERFPhysBCFunct_v::impose_vertical_yvel_bcs ( const amrex::Array4< amrex::Real > &  dest_arr,
const amrex::Box &  bx,
const amrex::Box &  domain,
const amrex::Array4< amrex::Real const > &  z_nd,
const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM >  dxInv,
int  bccomp,
const double  time 
)

Impose vertical boundary conditions on y velocity.

Parameters
[in,out]dest_arry-velocity data to be filled
[in]bxbox holding data to be filled
[in]domainsimulation domain
[in]z_ndnodal physical height
[in]dxInvinverse cell size
[in]bccompboundary-condition component
[in]timetime at which data should be filled

Impose vertical boundary conditions on y-component of velocity

Parameters
[in,out]dest_arrthe Array4 of the quantity to be filled
[in]bxthe box associated with this data
[in]domainthe computational domain
[in]z_phys_ndheight coordinate at nodes
[in]dxInvinverse cell size array
[in]bccompindex into m_domain_bcs_type
[in]timetime at which the data should be filled
218 {
219  BL_PROFILE_VAR("impose_vertical_yvel_bcs()",impose_vertical_yvel_bcs);
220  const auto& dom_lo = lbound(domain);
221  const auto& dom_hi = ubound(domain);
222 
223  Box per_grown_domain(domain);
224  int growx = (m_geom.isPeriodic(0)) ? 1 : 0;
225  int growy = (m_geom.isPeriodic(1)) ? 1 : 0;
226  per_grown_domain.grow(IntVect(growx,growy,0));
227  const auto& perdom_lo = lbound(per_grown_domain);
228  const auto& perdom_hi = ubound(per_grown_domain);
229 
230  // Based on BCRec for the domain, we need to make BCRec for this Box
231  // bccomp is used as starting index for m_domain_bcs_type
232  // 0 is used as starting index for bcrs
233  Vector<BCRec> bcrs(1);
234  setBC(enclosedCells(bx), domain, bccomp, 0, 1, m_domain_bcs_type, bcrs);
235 
236  // xlo: ori = 0
237  // ylo: ori = 1
238  // zlo: ori = 2
239  // xhi: ori = 3
240  // yhi: ori = 4
241  // zhi: ori = 5
242 
243  Gpu::DeviceVector<BCRec> bcrs_d(1);
244  Gpu::copyAsync(Gpu::hostToDevice, bcrs.begin(), bcrs.end(), bcrs_d.begin());
245  const BCRec* bc_ptr = bcrs_d.data();
246 
247  GpuArray<GpuArray<Real, AMREX_SPACEDIM*2>, 1> l_bc_extdir_vals_d;
248 
249  for (int ori = 0; ori < 2*AMREX_SPACEDIM; ori++) {
250  l_bc_extdir_vals_d[0][ori] = m_bc_extdir_vals[bccomp][ori];
251  }
252 
253  GeometryData const& geomdata = m_geom.data();
254 
255  {
256  // Populate ghost cells on lo-z and hi-z domain boundaries
257  Box bx_zlo(bx); bx_zlo.setBig (2,dom_lo.z-1);
258  Box bx_zhi(bx); bx_zhi.setSmall(2,dom_hi.z+1);
259  ParallelFor(bx_zlo, bx_zhi,
260  [=] AMREX_GPU_DEVICE (int i, int j, int k) {
261  int kflip = dom_lo.z - 1 - k;
262  if (bc_ptr[0].lo(2) == ERFBCType::ext_dir) {
263  dest_arr(i,j,k) = l_bc_extdir_vals_d[0][2];
264  } else if (bc_ptr[0].lo(2) == ERFBCType::foextrap) {
265  dest_arr(i,j,k) = dest_arr(i,j,dom_lo.z);
266  } else if (bc_ptr[0].lo(2) == ERFBCType::open) {
267  dest_arr(i,j,k) = dest_arr(i,j,dom_lo.z);
268  } else if (bc_ptr[0].lo(2) == ERFBCType::reflect_even) {
269  dest_arr(i,j,k) = dest_arr(i,j,kflip);
270  } else if (bc_ptr[0].lo(2) == ERFBCType::reflect_odd) {
271  dest_arr(i,j,k) = -dest_arr(i,j,kflip);
272  } else if (bc_ptr[0].lo(2) == ERFBCType::hoextrap) {
273  Real delta_k = (dom_lo.z - k);
274  dest_arr(i,j,k) = (one + delta_k)*dest_arr(i,j,dom_lo.z) - delta_k*dest_arr(i,j,dom_lo.z+1);
275  }
276  },
277  [=] AMREX_GPU_DEVICE (int i, int j, int k) {
278  int kflip = 2*dom_hi.z + 1 - k;
279  if (bc_ptr[0].hi(2) == ERFBCType::ext_dir) {
280  dest_arr(i,j,k) = l_bc_extdir_vals_d[0][5];
281  } else if (bc_ptr[0].hi(2) == ERFBCType::foextrap) {
282  dest_arr(i,j,k) = dest_arr(i,j,dom_hi.z);
283  } else if (bc_ptr[0].hi(2) == ERFBCType::open) {
284  dest_arr(i,j,k) = dest_arr(i,j,dom_hi.z);
285  } else if (bc_ptr[0].hi(2) == ERFBCType::reflect_even) {
286  dest_arr(i,j,k) = dest_arr(i,j,kflip);
287  } else if (bc_ptr[0].hi(2) == ERFBCType::reflect_odd) {
288  dest_arr(i,j,k) = -dest_arr(i,j,kflip);
289  } else if (bc_ptr[0].hi(2) == ERFBCType::hoextrap){
290  Real delta_k = (k - dom_hi.z);
291  dest_arr(i,j,k) = (one + delta_k)*dest_arr(i,j,dom_hi.z) - delta_k*dest_arr(i,j,dom_hi.z-1);
292  }
293  }
294  );
295  }
296 
297  if (m_z_phys_nd) {
298 
299  const auto& bx_lo = lbound(bx);
300  const auto& bx_hi = ubound(bx);
301 
302  const auto& zphys_lo = lbound(Box(z_phys_nd));
303  const auto& zphys_hi = ubound(Box(z_phys_nd));
304 
305  // Neumann conditions (d<var>/dn = 0) must be aware of the surface normal with terrain.
306  // An additional source term arises from d<var>/dx & d<var>/dy & met_h_xi/eta/zeta.
307  //=====================================================================================
308  // Only modify scalars, U, or V
309  // Loop over each component
310  // Hit for Neumann condition at kmin
311  if(bcrs[0].lo(2) == ERFBCType::foextrap) {
312  // Loop over ghost cells in bottom XY-plane (valid box)
313  Box xybx = bx;
314  xybx.setBig(2,-1);
315  xybx.setSmall(2,bx.smallEnd()[2]);
316  int k0 = 0;
317 
318  // Get the dz cell size
319  Real dz = geomdata.CellSize(2);
320 
321  // Fill all the Neumann srcs with terrain
322  ParallelFor(xybx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
323  {
324  // Clip indices for ghost-cells
325  int ii = amrex::min(amrex::max(i,perdom_lo.x),perdom_hi.x);
326  ii = amrex::min(amrex::max(ii,zphys_lo.x),zphys_hi.x);
327  int jj = amrex::min(amrex::max(j,perdom_lo.y),perdom_hi.y);
328  jj = amrex::min(amrex::max(jj,zphys_lo.y),zphys_hi.y);
329 
330  // Get metrics
331  Real met_h_xi = Compute_h_xi_AtJface (ii, jj, k0, dxInv, z_phys_nd);
332  Real met_h_eta = Compute_h_eta_AtJface (ii, jj, k0, dxInv, z_phys_nd);
333  Real met_h_zeta = Compute_h_zeta_AtJface(ii, jj, k0, dxInv, z_phys_nd);
334 
335  // GradX at IJK location inside domain -- this relies on the assumption that we have
336  // used foextrap for cell-centered quantities outside the domain to define the gradient as zero
337  Real GradVarx, GradVary;
338  if ( i < dom_lo.x-1 || i > dom_hi.x+1 || (i+1 > bx_hi.x && i-1 < bx_lo.x) ) {
339  GradVarx = zero;
340  } else if (i+1 > bx_hi.x) {
341  GradVarx = dxInv[0] * (dest_arr(i ,j,k0) - dest_arr(i-1,j,k0));
342  } else if (i-1 < bx_lo.x) {
343  GradVarx = dxInv[0] * (dest_arr(i+1,j,k0) - dest_arr(i ,j,k0));
344  } else {
345  GradVarx = myhalf * dxInv[0] * (dest_arr(i+1,j,k0) - dest_arr(i-1,j,k0));
346  }
347 
348  // GradY at IJK location inside domain -- this relies on the assumption that we have
349  // used foextrap for cell-centered quantities outside the domain to define the gradient as zero
350  if ( j < dom_lo.y-1 || j > dom_hi.y+1 || (j+1 > bx_hi.y && j-1 < bx_lo.y) ) {
351  GradVary = zero;
352  } else if (j+1 > bx_hi.y) {
353  GradVary = dxInv[1] * (dest_arr(i,j ,k0) - dest_arr(i,j-1,k0));
354  } else if (j-1 < bx_lo.y) {
355  GradVary = dxInv[1] * (dest_arr(i,j+1,k0) - dest_arr(i,j ,k0));
356  } else {
357  GradVary = myhalf * dxInv[1] * (dest_arr(i,j+1,k0) - dest_arr(i,j-1,k0));
358  }
359 
360  // Prefactor
361  Real met_fac = met_h_zeta / ( met_h_xi*met_h_xi + met_h_eta*met_h_eta + one );
362 
363  // Accumulate in bottom ghost cell (EXTRAP already populated)
364  dest_arr(i,j,k) -= dz * met_fac * ( met_h_xi * GradVarx + met_h_eta * GradVary );
365  });
366  } // foextrap
367  } //m_z_phys_nd
368  Gpu::streamSynchronize();
369 }
amrex::GpuArray< Real, AMREX_SPACEDIM > dxInv
Definition: ERF_InitCustomPertVels_ParticleTests.H:17
constexpr amrex::Real myhalf
Definition: ERF_NumericalConstants.H:41
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_eta_AtJface(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:392
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_xi_AtJface(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:369
AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_h_zeta_AtJface(const int &i, const int &j, const int &k, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &z_nd)
Definition: ERF_TerrainMetrics.H:346
void impose_vertical_yvel_bcs(const amrex::Array4< amrex::Real > &dest_arr, const amrex::Box &bx, const amrex::Box &domain, const amrex::Array4< amrex::Real const > &z_nd, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > dxInv, int bccomp, const double time)
Definition: ERF_BoundaryConditionsYvel.cpp:213
@ dz
Definition: ERF_AdvanceWDM6.cpp:272
Here is the call graph for this function:

◆ operator()()

void ERFPhysBCFunct_v::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]mfy-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
[in]do_fbwhether to fill periodic/interior ghost cells first

Impose physical boundary conditions on y velocity.

Parameters
[in,out]mfy-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]bccompindex into m_domain_bcs_type
[in]do_fbwhether to fill periodic/interior ghost cells first
268 {
269  BL_PROFILE("ERFPhysBCFunct_v::()");
270 
271  //
272  // We fill all of the interior and periodic ghost cells first, so we can fill
273  // those directly inside the lateral and vertical calls.
274  // If triply periodic this is all we do
275  //
276  if (do_fb) {
277  mf.FillBoundary(m_geom.periodicity());
278  }
279 
280  if (m_geom.isAllPeriodic()) return;
281 
282  const auto& domain = m_geom.Domain();
283  const auto dxInv = m_geom.InvCellSizeArray();
284 
285  Box gdomainy = surroundingNodes(domain,1);
286  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
287  if (m_geom.isPeriodic(i)) {
288  gdomainy.grow(i, nghost[i]);
289  }
290  }
291 
292 #ifdef AMREX_USE_OMP
293 #pragma omp parallel if (Gpu::notInLaunchRegion())
294 #endif
295  {
296  for (MFIter mfi(mf,false); mfi.isValid(); ++mfi)
297  {
298  //
299  // This is the box we pass to the different routines
300  // NOTE -- this is the full grid NOT the tile box
301  //
302  Box bx = mfi.validbox();
303 
304  //
305  // These are the boxes we use to test on relative to the domain
306  //
307  Box ybx1 = surroundingNodes(bx,1); ybx1.grow(nghost);
308  if (ybx1.smallEnd(2) < domain.smallEnd(2)) ybx1.setSmall(2,domain.smallEnd(2));
309  if (ybx1.bigEnd(2) > domain.bigEnd(2)) ybx1.setBig(2,domain.bigEnd(2));
310 
311  Box ybx2 = surroundingNodes(bx,1); ybx2.grow(nghost);
312 
313  Array4<const Real> z_nd_arr;
314 
315  if (m_z_phys_nd) {
316  z_nd_arr = m_z_phys_nd->const_array(mfi);
317  }
318 
319  if (!gdomainy.contains(ybx2)) {
320  Array4< Real> const& dest_arr = mf.array(mfi);
321  Array4<const Real> const& velx_arr = xvel.const_array(mfi);
322  Array4<const Real> const& vely_arr = yvel.const_array(mfi);
323 
324  if (!m_use_real_bcs) {
325  impose_lateral_yvel_bcs(dest_arr,velx_arr,vely_arr,ybx1,domain,bccomp,time);
326  }
327 
328  impose_vertical_yvel_bcs(dest_arr,ybx2,domain,z_nd_arr,dxInv,bccomp,time);
329  }
330 
331  } // MFIter
332  } // OpenMP
333 
334  // The terrain correction below the ground is computed box by box; make the
335  // copies of each ghost cell agree. Only a terrain-fitted mesh has a
336  // non-zero correction -- z_phys_nd is allocated (and zeroed) for every
337  // terrain type, so testing it alone would pay for the sync on flat runs.
338  if (m_z_phys_nd && terrain_is_fitted(m_terrain_type)) {
339  m_below_ground_sync(mf, 0, 1, nghost, m_geom);
340  }
341 } // operator()
BelowGroundGhostSync m_below_ground_sync
Definition: ERF_PhysBCFunct.H:383
@ xvel
Definition: ERF_IndexDefines.H:218
@ yvel
Definition: ERF_IndexDefines.H:219

Member Data Documentation

◆ m_bc_extdir_vals

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

◆ m_bc_neumann_vals

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

◆ m_below_ground_sync

BelowGroundGhostSync ERFPhysBCFunct_v::m_below_ground_sync
private

◆ m_domain_bcs_type

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

◆ m_domain_bcs_type_d

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

◆ m_geom

amrex::Geometry ERFPhysBCFunct_v::m_geom
private

◆ m_lev

int ERFPhysBCFunct_v::m_lev
private

◆ m_terrain_type

TerrainType ERFPhysBCFunct_v::m_terrain_type
private

◆ m_use_real_bcs

bool ERFPhysBCFunct_v::m_use_real_bcs
private

◆ m_v_bc_data

amrex::Real* ERFPhysBCFunct_v::m_v_bc_data
private

◆ m_z_phys_nd

amrex::MultiFab* ERFPhysBCFunct_v::m_z_phys_nd
private

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