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

#include <ERF_PhysBCFunct.H>

Collaboration diagram for ERFPhysBCFunct_u:

Public Member Functions

 ERFPhysBCFunct_u (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 *u_bc_data)
 
 ~ERFPhysBCFunct_u ()
 
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_xvel_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_xvel_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_u_bc_data
 
BelowGroundGhostSync m_below_ground_sync
 

Constructor & Destructor Documentation

◆ ERFPhysBCFunct_u()

ERFPhysBCFunct_u::ERFPhysBCFunct_u ( 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 *  u_bc_data 
)
inline

Construct the x-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]u_bc_dataoptional x-velocity boundary data
200  : m_lev(lev), m_geom(geom),
201  m_domain_bcs_type(domain_bcs_type),
202  m_domain_bcs_type_d(domain_bcs_type_d),
203  m_bc_extdir_vals(bc_extdir_vals),
204  m_bc_neumann_vals(bc_neumann_vals),
205  m_terrain_type(terrain_type),
206  m_z_phys_nd(z_phys_nd.get()),
207  m_use_real_bcs(use_real_bcs),
208  m_u_bc_data(u_bc_data)
209  { }
amrex::Geometry m_geom
Definition: ERF_PhysBCFunct.H:268
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_extdir_vals
Definition: ERF_PhysBCFunct.H:271
amrex::Gpu::DeviceVector< amrex::BCRec > m_domain_bcs_type_d
Definition: ERF_PhysBCFunct.H:270
bool m_use_real_bcs
Definition: ERF_PhysBCFunct.H:275
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_neumann_vals
Definition: ERF_PhysBCFunct.H:272
amrex::Real * m_u_bc_data
Definition: ERF_PhysBCFunct.H:276
int m_lev
Definition: ERF_PhysBCFunct.H:267
amrex::Vector< amrex::BCRec > m_domain_bcs_type
Definition: ERF_PhysBCFunct.H:269
amrex::MultiFab * m_z_phys_nd
Definition: ERF_PhysBCFunct.H:274
TerrainType m_terrain_type
Definition: ERF_PhysBCFunct.H:273

◆ ~ERFPhysBCFunct_u()

ERFPhysBCFunct_u::~ERFPhysBCFunct_u ( )
inline

Destroy the x-velocity physical boundary-condition functor.

214 {}

Member Function Documentation

◆ impose_lateral_xvel_bcs()

void ERFPhysBCFunct_u::impose_lateral_xvel_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 x velocity.

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

void ERFPhysBCFunct_u::impose_vertical_xvel_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 x velocity.

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

◆ operator()()

void ERFPhysBCFunct_u::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]mfx-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 x velocity.

Parameters
[in,out]mfx-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
180 {
181  BL_PROFILE("ERFPhysBCFunct_u::()");
182 
183  //
184  // We fill all of the interior and periodic ghost cells first, so we can fill
185  // those directly inside the lateral and vertical calls.
186  // If triply periodic this is all we do
187  //
188  if (do_fb) {
189  mf.FillBoundary(m_geom.periodicity());
190  }
191 
192  if (m_geom.isAllPeriodic()) return;
193 
194  const auto& domain = m_geom.Domain();
195  const auto dxInv = m_geom.InvCellSizeArray();
196 
197  Box gdomainx = surroundingNodes(domain,0);
198  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
199  if (m_geom.isPeriodic(i)) {
200  gdomainx.grow(i, nghost[i]);
201  }
202  }
203 
204 #ifdef AMREX_USE_OMP
205 #pragma omp parallel if (Gpu::notInLaunchRegion())
206 #endif
207  {
208  for (MFIter mfi(mf,false); mfi.isValid(); ++mfi)
209  {
210  //
211  // This is the box we pass to the different routines
212  // NOTE -- this is the full grid NOT the tile box
213  //
214  Box bx = mfi.validbox();
215 
216  //
217  // These are the boxes we use to test on relative to the domain
218  //
219  Box xbx1 = surroundingNodes(bx,0); xbx1.grow(nghost);
220  if(xbx1.smallEnd(2) < domain.smallEnd(2)) xbx1.setSmall(2,domain.smallEnd(2));
221  if(xbx1.bigEnd(2) > domain.bigEnd(2)) xbx1.setBig(2,domain.bigEnd(2));
222 
223  Box xbx2 = surroundingNodes(bx,0); xbx2.grow(nghost);
224 
225  Array4<const Real> z_nd_arr;
226 
227  if (m_z_phys_nd) {
228  z_nd_arr = m_z_phys_nd->const_array(mfi);
229  }
230 
231  if (!gdomainx.contains(xbx2)) {
232  Array4< Real> const& dest_arr = mf.array(mfi);
233  Array4<const Real> const& velx_arr = xvel.const_array(mfi);
234  Array4<const Real> const& vely_arr = yvel.const_array(mfi);
235 
236  if (!gdomainx.contains(xbx1) && !m_use_real_bcs) {
237  impose_lateral_xvel_bcs(dest_arr,velx_arr,vely_arr,xbx1,domain,bccomp,time);
238  }
239 
240  impose_vertical_xvel_bcs(dest_arr,xbx2,domain,z_nd_arr,dxInv,bccomp,time);
241  }
242  } // MFIter
243  } // OpenMP
244 
245  // The terrain correction below the ground is computed box by box; make the
246  // copies of each ghost cell agree. Only a terrain-fitted mesh has a
247  // non-zero correction -- z_phys_nd is allocated (and zeroed) for every
248  // terrain type, so testing it alone would pay for the sync on flat runs.
249  if (m_z_phys_nd && terrain_is_fitted(m_terrain_type)) {
250  m_below_ground_sync(mf, 0, 1, nghost, m_geom);
251  }
252 } // operator()
BelowGroundGhostSync m_below_ground_sync
Definition: ERF_PhysBCFunct.H:277
@ 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_u::m_bc_extdir_vals
private

◆ m_bc_neumann_vals

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

◆ m_below_ground_sync

BelowGroundGhostSync ERFPhysBCFunct_u::m_below_ground_sync
private

◆ m_domain_bcs_type

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

◆ m_domain_bcs_type_d

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

◆ m_geom

amrex::Geometry ERFPhysBCFunct_u::m_geom
private

◆ m_lev

int ERFPhysBCFunct_u::m_lev
private

◆ m_terrain_type

TerrainType ERFPhysBCFunct_u::m_terrain_type
private

◆ m_u_bc_data

amrex::Real* ERFPhysBCFunct_u::m_u_bc_data
private

◆ m_use_real_bcs

bool ERFPhysBCFunct_u::m_use_real_bcs
private

◆ m_z_phys_nd

amrex::MultiFab* ERFPhysBCFunct_u::m_z_phys_nd
private

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