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

#include <ERF_PhysBCFunct.H>

Collaboration diagram for ERFPhysBCFunct_base:

Public Member Functions

 ERFPhysBCFunct_base (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, std::unique_ptr< amrex::MultiFab > &z_phys_nd, bool moving_terrain, bool use_terrain, amrex::Real rdOcp, amrex::Real gravity)
 
 ~ERFPhysBCFunct_base ()
 
void operator() (amrex::MultiFab &mf, int icomp, int ncomp, amrex::IntVect const &nghost)
 
void impose_lateral_basestate_bcs (const amrex::Array4< amrex::Real > &dest_arr, const amrex::Array4< amrex::Real const > &z_nd, const amrex::Box &bx, const amrex::Box &domain, int ncomp, const amrex::IntVect &nghost)
 
void impose_vertical_basestate_bcs (const amrex::Array4< amrex::Real > &dest_arr, const amrex::Array4< amrex::Real const > &z_nd, const amrex::Box &bx, const amrex::Box &domain, int ncomp, const amrex::IntVect &nghost)
 

Private Attributes

int m_lev
 
amrex::Geometry m_geom
 
bool m_moving_terrain
 
bool m_use_terrain
 
amrex::Real m_rdOcp
 
amrex::Real m_gravity
 
amrex::Vector< amrex::BCRec > m_domain_bcs_type
 
amrex::Gpu::DeviceVector< amrex::BCRec > m_domain_bcs_type_d
 
amrex::MultiFab * m_z_phys_nd
 

Constructor & Destructor Documentation

◆ ERFPhysBCFunct_base()

ERFPhysBCFunct_base::ERFPhysBCFunct_base ( 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,
std::unique_ptr< amrex::MultiFab > &  z_phys_nd,
bool  moving_terrain,
bool  use_terrain,
amrex::Real  rdOcp,
amrex::Real  gravity 
)
inline

Construct the base-state 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]z_phys_ndnodal physical height MultiFab
[in]moving_terrainwhether moving terrain is active
[in]use_terrainwhether the mesh is terrain-fitted, so that the cell-centered height of a lateral ghost cell differs from that of the cell it copies from
[in]rdOcpratio of R_d to c_p, used to close the EOS in the ghost cells
[in]gravitymagnitude of gravity, used to transfer the base state in height
493  : m_lev(lev), m_geom(geom),
494  m_moving_terrain(moving_terrain),
496  m_rdOcp(rdOcp),
497  m_gravity(gravity),
498  m_domain_bcs_type(domain_bcs_type),
499  m_domain_bcs_type_d(domain_bcs_type_d),
500  m_z_phys_nd(z_phys_nd.get())
501  {}
const bool use_terrain
Definition: ERF_InitCustomPertVels_Terrain3DHemisphere.H:26
const Real rdOcp
Definition: ERF_InitCustomPert_ABL.H:72
amrex::Gpu::DeviceVector< amrex::BCRec > m_domain_bcs_type_d
Definition: ERF_PhysBCFunct.H:556
amrex::Real m_rdOcp
Definition: ERF_PhysBCFunct.H:553
bool m_use_terrain
Definition: ERF_PhysBCFunct.H:552
int m_lev
Definition: ERF_PhysBCFunct.H:549
amrex::MultiFab * m_z_phys_nd
Definition: ERF_PhysBCFunct.H:557
amrex::Geometry m_geom
Definition: ERF_PhysBCFunct.H:550
bool m_moving_terrain
Definition: ERF_PhysBCFunct.H:551
amrex::Real m_gravity
Definition: ERF_PhysBCFunct.H:554
amrex::Vector< amrex::BCRec > m_domain_bcs_type
Definition: ERF_PhysBCFunct.H:555

◆ ~ERFPhysBCFunct_base()

ERFPhysBCFunct_base::~ERFPhysBCFunct_base ( )
inline

Destroy the base-state physical boundary-condition functor.

506 {}

Member Function Documentation

◆ impose_lateral_basestate_bcs()

void ERFPhysBCFunct_base::impose_lateral_basestate_bcs ( const amrex::Array4< amrex::Real > &  dest_arr,
const amrex::Array4< amrex::Real const > &  z_nd,
const amrex::Box &  bx,
const amrex::Box &  domain,
int  ncomp,
const amrex::IntVect &  nghost 
)

Impose lateral boundary conditions on base-state variables.

Parameters
[in,out]dest_arrbase-state data to be filled
[in]z_ndnodal physical height
[in]bxbox holding data to be filled
[in]domainsimulation domain
[in]ncompnumber of components
[in]nghostnumber of ghost cells to be filled

Impose lateral boundary conditions on the base state

Parameters
[in,out]dest_arrcell-centered data to be filled
[in]z_ndnodal physical height
[in]bxbox holding data to be filled
[in]domainsimulation domain
[in]ncompnumber of base-state components to fill
[in]nghostnumber of ghost cells in each coordinate direction
24 {
25  BL_PROFILE_VAR("impose_lateral_base_bcs()",impose_lateral_base_bcs);
26  //
27  // Note that the "bx" that comes in here has already been grown in the lateral directions
28  // but not in the vertical
29  //
30 
31  const int* bxlo = bx.loVect();
32  const int* bxhi = bx.hiVect();
33 
34  const int* dlo = domain.loVect();
35  const int* dhi = domain.hiVect();
36 
37  const auto& dom_lo = lbound(domain);
38  const auto& dom_hi = ubound(domain);
39 
40  // xlo: ori = 0
41  // ylo: ori = 1
42  // zlo: ori = 2
43  // xhi: ori = 3
44  // yhi: ori = 4
45  // zhi: ori = 5
46 
47  // Based on BCRec for the domain, we need to make BCRec for this Box
48  // 0 is used as starting index for bcrs
49  Vector<BCRec> bcrs(ncomp);
50 
51  int bc_comp = BaseBCVars::rho0_bc_comp;
52 
53  for (int nc = 0; nc < ncomp; nc++)
54  {
55  for (int dir = 0; dir < AMREX_SPACEDIM; dir++)
56  {
57  bcrs[nc].setLo(dir, ( bxlo[dir]<=dlo[dir]
58  ? m_domain_bcs_type[bc_comp].lo(dir) : BCType::int_dir ));
59  bcrs[nc].setHi(dir, ( bxhi[dir]>=dhi[dir]
60  ? m_domain_bcs_type[bc_comp].hi(dir) : BCType::int_dir ));
61  }
62  }
63 
64  Gpu::DeviceVector<BCRec> bcrs_d(ncomp);
65  Gpu::copyAsync(Gpu::hostToDevice, bcrs.begin(), bcrs.end(), bcrs_d.begin());
66  const BCRec* bc_ptr = bcrs_d.data();
67 
68  GeometryData const& geomdata = m_geom.data();
69  bool is_periodic_in_x = geomdata.isPeriodic(0);
70  bool is_periodic_in_y = geomdata.isPeriodic(1);
71 
72  // Do ghost cells in x-direction but not reaching out in y
73  // The corners we miss here will be covered in the y-loop below or by periodicity
74  if (!is_periodic_in_x)
75  {
76  // Populate ghost cells on lo-x and hi-x domain boundaries
77  Box bx_xlo(bx); bx_xlo.setBig (0,dom_lo.x-1);
78  Box bx_xhi(bx); bx_xhi.setSmall(0,dom_hi.x+1);
79 
81  bx_xlo, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n)
82  {
83  int dest_comp = n;
84  int l_bc_type = bc_ptr[n].lo(0);
85  int iflip = dom_lo.x - 1 - i;
86  if (l_bc_type == ERFBCType::foextrap) {
87  dest_arr(i,j,k,dest_comp) = dest_arr(dom_lo.x,j,k,dest_comp);
88  } else if (l_bc_type == ERFBCType::open) {
89  dest_arr(i,j,k,dest_comp) = dest_arr(dom_lo.x,j,k,dest_comp);
90  } else if (l_bc_type == ERFBCType::reflect_even) {
91  dest_arr(i,j,k,dest_comp) = dest_arr(iflip,j,k,dest_comp);
92  }
93  },
94  bx_xhi, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n)
95  {
96  int dest_comp = n;
97  int h_bc_type = bc_ptr[n].hi(0);
98  int iflip = 2*dom_hi.x + 1 - i;
99  if (h_bc_type == ERFBCType::foextrap) {
100  dest_arr(i,j,k,dest_comp) = dest_arr(dom_hi.x,j,k,dest_comp);
101  } else if (h_bc_type == ERFBCType::open) {
102  dest_arr(i,j,k,dest_comp) = dest_arr(dom_hi.x,j,k,dest_comp);
103  } else if (h_bc_type == ERFBCType::reflect_even) {
104  dest_arr(i,j,k,dest_comp) = dest_arr(iflip,j,k,dest_comp);
105  }
106  }
107  );
108  }
109 
110  if (!is_periodic_in_y)
111  {
112  // Populate ghost cells on lo-y and hi-y domain boundaries
113  Box bx_ylo(bx); bx_ylo.setBig (1,dom_lo.y-1);
114  Box bx_yhi(bx); bx_yhi.setSmall(1,dom_hi.y+1);
115  if (bx_ylo.smallEnd(2) != domain.smallEnd(2)) bx_ylo.growLo(2,nghost[2]);
116  if (bx_ylo.bigEnd(2) != domain.bigEnd(2)) bx_ylo.growHi(2,nghost[2]);
117  if (bx_yhi.smallEnd(2) != domain.smallEnd(2)) bx_yhi.growLo(2,nghost[2]);
118  if (bx_yhi.bigEnd(2) != domain.bigEnd(2)) bx_yhi.growHi(2,nghost[2]);
119  ParallelFor(
120  bx_ylo, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n)
121  {
122  int dest_comp = n;
123  int l_bc_type = bc_ptr[n].lo(1);
124  int jflip = dom_lo.y - 1 - j;
125  if (l_bc_type == ERFBCType::foextrap) {
126  dest_arr(i,j,k,dest_comp) = dest_arr(i,dom_lo.y,k,dest_comp);
127  } else if (l_bc_type == ERFBCType::open) {
128  dest_arr(i,j,k,dest_comp) = dest_arr(i,dom_lo.y,k,dest_comp);
129  } else if (l_bc_type == ERFBCType::reflect_even) {
130  dest_arr(i,j,k,dest_comp) = dest_arr(i,jflip,k,dest_comp);
131  }
132 
133  },
134  bx_yhi, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n)
135  {
136  int dest_comp = n;
137  int h_bc_type = bc_ptr[n].hi(1);
138  int jflip = 2*dom_hi.y + 1 - j;
139  if (h_bc_type == ERFBCType::foextrap) {
140  dest_arr(i,j,k,dest_comp) = dest_arr(i,dom_hi.y,k,dest_comp);
141  } else if (h_bc_type == ERFBCType::open) {
142  dest_arr(i,j,k,dest_comp) = dest_arr(i,dom_hi.y,k,dest_comp);
143  } else if (h_bc_type == ERFBCType::reflect_even) {
144  dest_arr(i,j,k,dest_comp) = dest_arr(i,jflip,k,dest_comp);
145  }
146  }
147  );
148  }
149 
150  // Next do ghost cells in x-direction but not reaching out in y
151  // The corners we miss here will be covered in the y-loop below or by periodicity
152  if (!is_periodic_in_x)
153  {
154  // Populate ghost cells on lo-x and hi-x domain boundaries
155  Box bx_xlo(bx); bx_xlo.setBig (0,dom_lo.x-1);
156  Box bx_xhi(bx); bx_xhi.setSmall(0,dom_hi.x+1);
157  if (bx_xlo.smallEnd(2) != domain.smallEnd(2)) bx_xlo.growLo(2,nghost[2]);
158  if (bx_xlo.bigEnd(2) != domain.bigEnd(2)) bx_xlo.growHi(2,nghost[2]);
159  if (bx_xhi.smallEnd(2) != domain.smallEnd(2)) bx_xhi.growLo(2,nghost[2]);
160  if (bx_xhi.bigEnd(2) != domain.bigEnd(2)) bx_xhi.growHi(2,nghost[2]);
161  ParallelFor(
162  bx_xlo, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n)
163  {
164  int dest_comp = n;
165  int l_bc_type = bc_ptr[n].lo(0);
166  int iflip = dom_lo.x - 1 - i;
167  if (l_bc_type == ERFBCType::foextrap) {
168  dest_arr(i,j,k,dest_comp) = dest_arr(dom_lo.x,j,k,dest_comp);
169  } else if (l_bc_type == ERFBCType::open) {
170  dest_arr(i,j,k,dest_comp) = dest_arr(dom_lo.x,j,k,dest_comp);
171  } else if (l_bc_type == ERFBCType::reflect_even) {
172  dest_arr(i,j,k,dest_comp) = dest_arr(iflip,j,k,dest_comp);
173  } else if (l_bc_type == ERFBCType::reflect_odd) {
174  dest_arr(i,j,k,dest_comp) = -dest_arr(iflip,j,k,dest_comp);
175  } else if (l_bc_type == ERFBCType::hoextrap) {
176  Real delta_i = static_cast<Real>(dom_lo.x - i);
177  dest_arr(i,j,k,dest_comp) = (one + delta_i)*dest_arr(dom_lo.x,j,k,dest_comp) - delta_i*dest_arr(dom_lo.x+1,j,k,dest_comp) ;
178  }
179  },
180  bx_xhi, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n)
181  {
182  int dest_comp = n;
183  int h_bc_type = bc_ptr[n].hi(0);
184  int iflip = 2*dom_hi.x + 1 - i;
185  if (h_bc_type == ERFBCType::foextrap) {
186  dest_arr(i,j,k,dest_comp) = dest_arr(dom_hi.x,j,k,dest_comp);
187  } else if (h_bc_type == ERFBCType::open) {
188  dest_arr(i,j,k,dest_comp) = dest_arr(dom_hi.x,j,k,dest_comp);
189  } else if (h_bc_type == ERFBCType::reflect_even) {
190  dest_arr(i,j,k,dest_comp) = dest_arr(iflip,j,k,dest_comp);
191  } else if (h_bc_type == ERFBCType::reflect_odd) {
192  dest_arr(i,j,k,dest_comp) = -dest_arr(iflip,j,k,dest_comp);
193  } else if (h_bc_type == ERFBCType::hoextrap) {
194  Real delta_i = static_cast<Real>(i - dom_hi.x);
195  dest_arr(i,j,k,dest_comp) = (one + delta_i)*dest_arr(dom_hi.x,j,k,dest_comp) - delta_i*dest_arr(dom_hi.x-1,j,k,dest_comp) ;
196  }
197  }
198  );
199  }
200 
201  if (!is_periodic_in_y)
202  {
203  // Populate ghost cells on lo-y and hi-y domain boundaries
204  Box bx_ylo(bx); bx_ylo.setBig (1,dom_lo.y-1);
205  Box bx_yhi(bx); bx_yhi.setSmall(1,dom_hi.y+1);
206  if (bx_ylo.smallEnd(2) != domain.smallEnd(2)) bx_ylo.growLo(2,nghost[2]);
207  if (bx_ylo.bigEnd(2) != domain.bigEnd(2)) bx_ylo.growHi(2,nghost[2]);
208  if (bx_yhi.smallEnd(2) != domain.smallEnd(2)) bx_yhi.growLo(2,nghost[2]);
209  if (bx_yhi.bigEnd(2) != domain.bigEnd(2)) bx_yhi.growHi(2,nghost[2]);
210  ParallelFor(
211  bx_ylo, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n)
212  {
213  int dest_comp = n;
214  int l_bc_type = bc_ptr[n].lo(1);
215  int jflip = dom_lo.y - 1 - j;
216  if (l_bc_type == ERFBCType::foextrap) {
217  dest_arr(i,j,k,dest_comp) = dest_arr(i,dom_lo.y,k,dest_comp);
218  } else if (l_bc_type == ERFBCType::open) {
219  dest_arr(i,j,k,dest_comp) = dest_arr(i,dom_lo.y,k,dest_comp);
220  } else if (l_bc_type == ERFBCType::reflect_even) {
221  dest_arr(i,j,k,dest_comp) = dest_arr(i,jflip,k,dest_comp);
222  } else if (l_bc_type == ERFBCType::reflect_odd) {
223  dest_arr(i,j,k,dest_comp) = -dest_arr(i,jflip,k,dest_comp);
224  } else if (l_bc_type == ERFBCType::hoextrap) {
225  Real delta_j = static_cast<Real>(dom_lo.y - j);
226  dest_arr(i,j,k,dest_comp) = (one + delta_j)*dest_arr(i,dom_lo.y,k,dest_comp) - delta_j*dest_arr(i,dom_lo.y+1,k,dest_comp) ;
227  }
228 
229  },
230  bx_yhi, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n)
231  {
232  int dest_comp = n;
233  int h_bc_type = bc_ptr[n].hi(1);
234  int jflip = 2*dom_hi.y + 1 - j;
235  if (h_bc_type == ERFBCType::foextrap) {
236  dest_arr(i,j,k,dest_comp) = dest_arr(i,dom_hi.y,k,dest_comp);
237  } else if (h_bc_type == ERFBCType::open) {
238  dest_arr(i,j,k,dest_comp) = dest_arr(i,dom_hi.y,k,dest_comp);
239  } else if (h_bc_type == ERFBCType::reflect_even) {
240  dest_arr(i,j,k,dest_comp) = dest_arr(i,jflip,k,dest_comp);
241  } else if (h_bc_type == ERFBCType::reflect_odd) {
242  dest_arr(i,j,k,dest_comp) = -dest_arr(i,jflip,k,dest_comp);
243  } else if (h_bc_type == ERFBCType::hoextrap) {
244  Real delta_j = static_cast<Real>(j - dom_hi.y);
245  dest_arr(i,j,k,dest_comp) = (one + delta_j)*dest_arr(i,dom_hi.y,k,dest_comp) - delta_j*dest_arr(i,dom_hi.y-1,k,dest_comp);
246  }
247  }
248  );
249  }
250 
251  //
252  // The copies above give a lateral ghost cell the base state of the cell it copies from,
253  // which on a terrain-fitted mesh sits at a different height: the nodal mesh is extrapolated
254  // past the domain, so z_cc of a ghost cell differs from z_cc of that cell whenever the
255  // terrain has a slope at the boundary. The base state left there is then neither the
256  // hydrostatic profile at the ghost cell's own height nor in hydrostatic balance along the
257  // ghost column, while detJ and the metric terms in that same column are height-consistent.
258  //
259  // Here we rebuild the base state of those cells at the height the mesh says the cell is at:
260  // p_0 is carried across the height offset by the hydrostatic relation, and rho_0 and pi_0
261  // follow from the equation of state so that it holds exactly in the ghost cell.
262  //
263  // This is done only where the boundary is foextrap or open: the reflecting and hoextrap
264  // conditions above are not copies of a single cell and are left alone. It reduces to the
265  // identity, bit for bit, wherever the two heights agree -- every constant-dz mesh, and any
266  // terrain that is flat at the boundary -- so it changes nothing there.
267  //
268  if (m_use_terrain && z_nd && ncomp == BaseState::num_comps)
269  {
270  auto is_ext_bc = [] (int bc_type) {
271  return (bc_type == ERFBCType::foextrap || bc_type == ERFBCType::open);
272  };
273 
274  const bool xlo_ext = !is_periodic_in_x && is_ext_bc(bcrs[0].lo(0));
275  const bool xhi_ext = !is_periodic_in_x && is_ext_bc(bcrs[0].hi(0));
276  const bool ylo_ext = !is_periodic_in_y && is_ext_bc(bcrs[0].lo(1));
277  const bool yhi_ext = !is_periodic_in_y && is_ext_bc(bcrs[0].hi(1));
278 
279  if (xlo_ext || xhi_ext || ylo_ext || yhi_ext)
280  {
281  //
282  // "bx" is grown laterally but not vertically, so we grow it in z the same way the
283  // loops above do, then trim it to the domain: the ghost cells above and below the
284  // domain are filled after us, by impose_vertical_basestate_bcs.
285  //
286  Box gbx(bx);
287  if (gbx.smallEnd(2) != domain.smallEnd(2)) gbx.growLo(2,nghost[2]);
288  if (gbx.bigEnd(2) != domain.bigEnd(2)) gbx.growHi(2,nghost[2]);
289  gbx.setSmall(2, amrex::max(gbx.smallEnd(2), dom_lo.z));
290  gbx.setBig (2, amrex::min(gbx.bigEnd(2) , dom_hi.z));
291 
292  const Real l_rdOcp = m_rdOcp;
293  const Real l_gravity = m_gravity;
294 
295  ParallelFor(gbx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
296  {
297  //
298  // The cell this one was copied from: the nearest cell that is inside the domain
299  // laterally, which is just what the x-pass followed by the y-pass above leaves
300  // here, corners included.
301  //
302  const bool out_xlo = (i < dom_lo.x);
303  const bool out_xhi = (i > dom_hi.x);
304  const bool out_ylo = (j < dom_lo.y);
305  const bool out_yhi = (j > dom_hi.y);
306 
307  if (!(out_xlo || out_xhi || out_ylo || out_yhi)) { return; }
308 
309  // Leave the cell alone unless every boundary it lies outside of is foextrap/open
310  if (out_xlo && !xlo_ext) { return; }
311  if (out_xhi && !xhi_ext) { return; }
312  if (out_ylo && !ylo_ext) { return; }
313  if (out_yhi && !yhi_ext) { return; }
314 
315  const int ir = amrex::min(amrex::max(i,dom_lo.x),dom_hi.x);
316  const int jr = amrex::min(amrex::max(j,dom_lo.y),dom_hi.y);
317 
318  auto zcc = [=] (int ii, int jj, int kk) {
319  return Real(0.125) * ( z_nd(ii,jj ,kk ) + z_nd(ii+1,jj ,kk )
320  + z_nd(ii,jj+1,kk ) + z_nd(ii+1,jj+1,kk )
321  + z_nd(ii,jj ,kk+1) + z_nd(ii+1,jj ,kk+1)
322  + z_nd(ii,jj+1,kk+1) + z_nd(ii+1,jj+1,kk+1) );
323  };
324 
325  const Real dz_offset = zcc(i,j,k) - zcc(ir,jr,k);
326 
327  // Same height as the cell we copied from: the copy is already right
328  if (dz_offset == Real(0.0)) { return; }
329 
330  const Real r0_ref = dest_arr(ir,jr,k,BaseState::r0_comp );
331  const Real p0_ref = dest_arr(ir,jr,k,BaseState::p0_comp );
332  const Real th0_ref = dest_arr(ir,jr,k,BaseState::th0_comp);
333  const Real qv0_ref = dest_arr(ir,jr,k,BaseState::qv0_comp);
334 
335  //
336  // A base state that has not been built yet -- this is called on a MultiFab that
337  // was only just allocated and zeroed -- has nothing to transfer, and the scale
338  // height below would divide by zero. Leave the copy alone.
339  //
340  if (!(p0_ref > Real(0.0)) || !(r0_ref > Real(0.0)) || !(th0_ref > Real(0.0))) { return; }
341 
342  //
343  // p_0 across the height offset, using the scale height of the cell we copied
344  // from: p_0 * exp(-g dz / (R_d T_v)) with R_d T_v = p_0 / rho_0.
345  //
346  const Real p0_new = p0_ref * std::exp(-l_gravity * dz_offset * r0_ref / p0_ref);
347 
348  //
349  // theta_0 and qv_0 carry over unchanged. Reconstructing them at the height of
350  // this cell would need the profile of the column above and below k, and the
351  // cells we could read there are the ones this box happens to hold, so the
352  // stencil -- and with it the answer -- would depend on where the grids are
353  // split in z. Holding them fixed leaves an error of dtheta_0/dz * dz, which
354  // for the offsets a terrain-fitted mesh produces is a few thousandths of a
355  // kelvin, against the several pascals in p_0 that the transfer above removes.
356  //
357  dest_arr(i,j,k,BaseState::p0_comp ) = p0_new;
358  dest_arr(i,j,k,BaseState::th0_comp) = th0_ref;
359  dest_arr(i,j,k,BaseState::qv0_comp) = qv0_ref;
360  dest_arr(i,j,k,BaseState::pi0_comp) = getExnergivenP(p0_new, l_rdOcp);
361  dest_arr(i,j,k,BaseState::r0_comp ) = getRhogivenThetaPress(th0_ref, p0_new,
362  l_rdOcp, qv0_ref);
363  });
364  }
365  }
366 
367  Gpu::streamSynchronize();
368 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getRhogivenThetaPress(const amrex::Real th, const amrex::Real p, const amrex::Real rdOcp, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:96
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getExnergivenP(const amrex::Real P, const amrex::Real rdOcp)
Definition: ERF_EOS.H:141
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 one
Definition: ERF_NumericalConstants.H:30
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ rho0_bc_comp
Definition: ERF_IndexDefines.H:116
@ num_comps
Definition: ERF_IndexDefines.H:81
@ qv0_comp
Definition: ERF_IndexDefines.H:80
@ pi0_comp
Definition: ERF_IndexDefines.H:78
@ p0_comp
Definition: ERF_IndexDefines.H:77
@ th0_comp
Definition: ERF_IndexDefines.H:79
@ r0_comp
Definition: ERF_IndexDefines.H:76
@ open
Definition: ERF_IndexDefines.H:304
@ reflect_odd
Definition: ERF_IndexDefines.H:293
@ hoextrap
Definition: ERF_IndexDefines.H:298
@ foextrap
Definition: ERF_IndexDefines.H:296
@ int_dir
Definition: ERF_IndexDefines.H:294
@ reflect_even
Definition: ERF_IndexDefines.H:295
@ nc
Definition: ERF_Morrison.H:46
Here is the call graph for this function:

◆ impose_vertical_basestate_bcs()

void ERFPhysBCFunct_base::impose_vertical_basestate_bcs ( const amrex::Array4< amrex::Real > &  dest_arr,
const amrex::Array4< amrex::Real const > &  z_nd,
const amrex::Box &  bx,
const amrex::Box &  domain,
int  ncomp,
const amrex::IntVect &  nghost 
)

Impose vertical boundary conditions on base-state variables.

Parameters
[in,out]dest_arrbase-state data to be filled
[in]z_ndnodal physical height
[in]bxbox holding data to be filled
[in]domainsimulation domain
[in]ncompnumber of components
[in]nghostnumber of ghost cells to be filled

Impose vertical boundary conditions on the base state

Parameters
[in,out]dest_arrcell-centered base-state data to be filled
[in]z_phys_ndheight coordinate at nodes, unused for base-state fills
[in]bxbox holding data to be filled
[in]domainsimulation domain
[in]ncompnumber of base-state components to fill
[in]nghostnumber of ghost cells, unused for base-state fills
386 {
387  BL_PROFILE_VAR("impose_vertical_base_bcs()",impose_vertical_base_bcs);
388 
389  const auto& dom_lo = lbound(domain);
390  const auto& dom_hi = ubound(domain);
391 
392  Box bx_zlo(bx); bx_zlo.setBig(2,dom_lo.z-1);
393  Box bx_zhi(bx); bx_zhi.setSmall(2,dom_hi.z+1);
394  ParallelFor(
395  bx_zlo, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n)
396  {
397  dest_arr(i,j,k,n) = dest_arr(i,j,dom_lo.z,n);
398  },
399  bx_zhi, ncomp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n)
400  {
401  dest_arr(i,j,k,n) = dest_arr(i,j,dom_hi.z,n);
402  }
403  );
404 }
Here is the call graph for this function:

◆ operator()()

void ERFPhysBCFunct_base::operator() ( amrex::MultiFab &  mf,
int  icomp,
int  ncomp,
amrex::IntVect const &  nghost 
)

Impose physical boundary conditions at domain boundaries

Parameters
[in,out]mfbase-state MultiFab to be filled
[in]icompstarting component for base-state variables
[in]ncompnumber of components for base-state variables
[in]nghostnumber of ghost cells to be filled

Impose physical boundary conditions on the base state.

Parameters
[in,out]mfbase-state MultiFab to be filled
[in]icompstarting component, unused here
[in]ncompnumber of components
[in]nghostnumber of ghost cells to be filled
361 {
362  BL_PROFILE("ERFPhysBCFunct_base::()");
363 
364  if (m_geom.isAllPeriodic()) return;
365 
366  const auto& domain = m_geom.Domain();
367 
368  // Create a grown domain box containing valid + periodic cells
369  Box gdomain = domain;
370  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
371  if (m_geom.isPeriodic(i)) {
372  gdomain.grow(i, nghost[i]);
373  }
374  }
375 
376  //
377  // We fill all of the interior and periodic ghost cells first, so we can fill
378  // those directly inside the lateral and vertical calls.
379  //
380  mf.FillBoundary(m_geom.periodicity());
381 
382 #ifdef AMREX_USE_OMP
383 #pragma omp parallel if (Gpu::notInLaunchRegion())
384 #endif
385  {
386  for (MFIter mfi(mf,false); mfi.isValid(); ++mfi)
387  {
388  //
389  // This is the box we pass to the different routines
390  // NOTE -- this is the full grid box NOT the tile box
391  //
392  Box bx = mfi.validbox();
393 
394  //
395  // These are the boxes we use to test on relative to the domain
396  //
397  Box cbx1 = bx; cbx1.grow(IntVect(nghost[0],nghost[1],0));
398  Box cbx2 = bx; cbx2.grow(nghost);
399 
400  Array4<const Real> z_nd_arr;
401 
402  if (m_z_phys_nd) {
403  z_nd_arr = m_z_phys_nd->const_array(mfi);
404  }
405 
406  if (!gdomain.contains(cbx2)) {
407  const Array4<Real> base_arr = mf.array(mfi);
408 
409  impose_lateral_basestate_bcs(base_arr,z_nd_arr,cbx1,domain,ncomp,nghost);
410  if (!m_moving_terrain) { // TODO: I don't know why the CI test fails if this is called
411  impose_vertical_basestate_bcs(base_arr,z_nd_arr,cbx2,domain,ncomp,nghost);
412  }
413  }
414 
415  } // MFIter
416  } // OpenMP
417 } // operator()
void impose_vertical_basestate_bcs(const amrex::Array4< amrex::Real > &dest_arr, const amrex::Array4< amrex::Real const > &z_nd, const amrex::Box &bx, const amrex::Box &domain, int ncomp, const amrex::IntVect &nghost)
Definition: ERF_BoundaryConditionsBaseState.cpp:380
void impose_lateral_basestate_bcs(const amrex::Array4< amrex::Real > &dest_arr, const amrex::Array4< amrex::Real const > &z_nd, const amrex::Box &bx, const amrex::Box &domain, int ncomp, const amrex::IntVect &nghost)
Definition: ERF_BoundaryConditionsBaseState.cpp:20

Member Data Documentation

◆ m_domain_bcs_type

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

◆ m_domain_bcs_type_d

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

◆ m_geom

amrex::Geometry ERFPhysBCFunct_base::m_geom
private

◆ m_gravity

amrex::Real ERFPhysBCFunct_base::m_gravity
private

◆ m_lev

int ERFPhysBCFunct_base::m_lev
private

◆ m_moving_terrain

bool ERFPhysBCFunct_base::m_moving_terrain
private

◆ m_rdOcp

amrex::Real ERFPhysBCFunct_base::m_rdOcp
private

◆ m_use_terrain

bool ERFPhysBCFunct_base::m_use_terrain
private

◆ m_z_phys_nd

amrex::MultiFab* ERFPhysBCFunct_base::m_z_phys_nd
private

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