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

#include <ERF_FillPatcher.H>

Collaboration diagram for ERFFillPatcher:

Public Member Functions

 ERFFillPatcher (amrex::BoxArray const &fba, amrex::DistributionMapping const &fdm, amrex::Geometry const &fgeom, amrex::BoxArray const &cba, amrex::DistributionMapping const &cdm, amrex::Geometry const &cgeom, int nghost, int nghost_set, int ncomp, amrex::InterpBase *interp)
 
void Define (amrex::BoxArray const &fba, amrex::DistributionMapping const &fdm, amrex::Geometry const &fgeom, amrex::BoxArray const &cba, amrex::DistributionMapping const &cdm, amrex::Geometry const &cgeom, int nghost, int nghost_set, int ncomp, amrex::InterpBase *interp)
 
void BuildMask (amrex::BoxArray const &fba, int nghost, int nghost_set)
 
void RegisterCoarseData (amrex::Vector< amrex::MultiFab const * > const &crse_data, amrex::Vector< double > const &crse_time)
 
void InterpFace (amrex::MultiFab &fine, amrex::MultiFab const &crse, int mask_val)
 
void InterpCell (amrex::MultiFab &fine, amrex::MultiFab const &crse, amrex::Vector< amrex::BCRec > const &bcr, int mask_val)
 
int GetSetMaskVal ()
 
void SetLogLawFill (bool on, amrex::Real z0, amrex::MultiFab const *wall_tblank)
 
int GetRelaxMaskVal ()
 
amrex::iMultiFab * GetMask ()
 
template<typename BC >
void FillSet (amrex::MultiFab &mf, double time, BC &cbc, amrex::Vector< amrex::BCRec > const &bcs)
 
template<typename BC >
void FillRelax (amrex::MultiFab &mf, double time, BC &cbc, amrex::Vector< amrex::BCRec > const &bcs)
 
template<typename BC >
void Fill (amrex::MultiFab &mf, double time, BC &cbc, amrex::Vector< amrex::BCRec > const &bcs, int mask_val)
 
amrex::Vector< double > const & crse_times () const
 The times of the coarse data last registered (RegisterCoarseData) More...
 

Private Attributes

amrex::BoxArray m_fba
 
amrex::BoxArray m_cba
 
amrex::DistributionMapping m_fdm
 
amrex::DistributionMapping m_cdm
 
amrex::Geometry m_fgeom
 
amrex::Geometry m_cgeom
 
int m_nghost
 
int m_nghost_subset
 
int m_ncomp
 
amrex::InterpBase * m_interp
 
amrex::IntVect m_ratio
 
std::unique_ptr< amrex::MultiFab > m_cf_crse_data_old
 
std::unique_ptr< amrex::MultiFab > m_cf_crse_data_new
 
std::unique_ptr< amrex::iMultiFab > m_cf_mask
 
bool m_loglaw = false
 
amrex::Real m_loglaw_z0 = amrex::Real(0.1)
 
amrex::MultiFab const * m_loglaw_tblank = nullptr
 
amrex::Vector< double > m_crse_times
 
double m_dt_crse
 
int m_set_mask {2}
 
int m_relax_mask {1}
 

Constructor & Destructor Documentation

◆ ERFFillPatcher()

ERFFillPatcher::ERFFillPatcher ( amrex::BoxArray const &  fba,
amrex::DistributionMapping const &  fdm,
amrex::Geometry const &  fgeom,
amrex::BoxArray const &  cba,
amrex::DistributionMapping const &  cdm,
amrex::Geometry const &  cgeom,
int  nghost,
int  nghost_set,
int  ncomp,
amrex::InterpBase *  interp 
)

Construct a coarse-fine fill patcher.

Parameters
[in]fbafine-level BoxArray
[in]fdmfine-level DistributionMapping
[in]fgeomfine-level Geometry
[in]cbacoarse-level BoxArray
[in]cdmcoarse-level DistributionMapping
[in]cgeomcoarse-level Geometry
[in]nghostnumber of ghost cells in the fill region
[in]nghost_setnumber of ghost cells in the set region
[in]ncompnumber of components
[in]interpinterpolation operator

Fill valid and ghost data with the "state data" at the given time

Parameters
[in]fbaBoxArray of data to be filled at fine level
[in]fdmDistributionMapping of data to be filled at fine level
[in]fgeomcontainer of geometry information at fine level
[in]cbaBoxArray of data to be filled at coarse level
[in]cdmDistributionMapping of data to be filled at coarse level
[in]cgeomcontainer of geometry information at coarse level
[in]nghostnumber of ghost cells to be filled
[in]nghost_setnumber of ghost cells in the set region
[in]ncompnumber of components to be filled
[in]interpinterpolation operator to be used
77  : m_fba(fba),
78  m_cba(cba),
79  m_fdm(fdm),
80  m_cdm(cdm),
81  m_fgeom(fgeom),
82  m_cgeom(cgeom)
83 {
84  AMREX_ALWAYS_ASSERT(fba.ixType() == cba.ixType());
85 
86  // Vector to hold times for coarse data
87  m_crse_times.resize(2);
88 
89  // Define the coarse and fine MFs
90  Define(fba, fdm, fgeom, cba, cdm, cgeom,nghost, nghost_set, ncomp, interp);
91 }
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
amrex::Geometry m_fgeom
Definition: ERF_FillPatcher.H:175
amrex::BoxArray m_fba
Definition: ERF_FillPatcher.H:171
amrex::BoxArray m_cba
Definition: ERF_FillPatcher.H:172
void Define(amrex::BoxArray const &fba, amrex::DistributionMapping const &fdm, amrex::Geometry const &fgeom, amrex::BoxArray const &cba, amrex::DistributionMapping const &cdm, amrex::Geometry const &cgeom, int nghost, int nghost_set, int ncomp, amrex::InterpBase *interp)
Definition: ERF_FillPatcher.cpp:108
amrex::DistributionMapping m_cdm
Definition: ERF_FillPatcher.H:174
amrex::Geometry m_cgeom
Definition: ERF_FillPatcher.H:176
amrex::Vector< double > m_crse_times
Definition: ERF_FillPatcher.H:188
amrex::DistributionMapping m_fdm
Definition: ERF_FillPatcher.H:173
Here is the call graph for this function:

Member Function Documentation

◆ BuildMask()

void ERFFillPatcher::BuildMask ( amrex::BoxArray const &  fba,
int  nghost,
int  nghost_set 
)

Build the coarse-fine mask.

Parameters
[in]fbafine-level BoxArray
[in]nghostnumber of ghost cells in the fill region
[in]nghost_setnumber of ghost cells in the set region

Build the coarse-fine mask for set and relax regions.

Parameters
[in]fbaBoxArray of data to be filled at fine level
[in]nghostnumber of ghost cells defining the region width
[in]mask_valvalue assigned to selected mask cells
184 {
185  // Minimal bounding box of fine BA plus a halo cell
186  Box fba_bnd = grow(fba.minimalBox(), IntVect(1,1,1));
187 
188  BoxArray fba_per;
189  Box fdomain = m_fgeom.Domain();
190  // Here we add additional boxes that are periodic wraparounds of existing boxes
191  if (m_fgeom.isAnyPeriodic())
192  {
193  Box domain_cc(fdomain); domain_cc.enclosedCells();
194  BoxList bl_mf = fba.boxList();
195  BoxList bl_mf_new;
196  for (auto& b : bl_mf) {
197  Box bcc(b); bcc.enclosedCells();
198 
199  // Per direction, collect the periodic shifts that can bring this box back
200  // into the bounding box. A box only has an image across a face it actually
201  // touches, and a box that spans the domain in a direction touches both.
202  int shift[AMREX_SPACEDIM][3];
203  int nshift[AMREX_SPACEDIM];
204  for (int dim = 0; dim < AMREX_SPACEDIM; dim++) {
205  int ns = 0;
206  shift[dim][ns++] = 0; // the box where it already is
207  if (m_fgeom.isPeriodic(dim)) {
208  int n = domain_cc.length(dim);
209  if (bcc.smallEnd(dim) == domain_cc.smallEnd(dim)) { shift[dim][ns++] = n; }
210  if (bcc.bigEnd(dim) == domain_cc.bigEnd(dim) ) { shift[dim][ns++] = -n; }
211  }
212  nshift[dim] = ns;
213  }
214 
215  // Every *combination* of those shifts, not one direction at a time. In a
216  // multiply periodic domain a fine patch sitting in a periodic corner also
217  // has diagonal images, e.g. (+Lx,+Ly); shifting along single axes alone
218  // never generates those, and complementIn then reports the corner cells as
219  // uncovered coarse-fine boundary.
220  for (int kk(0); kk < nshift[2]; ++kk) {
221  for (int jj(0); jj < nshift[1]; ++jj) {
222  for (int ii(0); ii < nshift[0]; ++ii) {
223  if (ii == 0 && jj == 0 && kk == 0) { continue; } // already in bl_mf
224  Box bb(bcc);
225  bb.shift(IntVect(shift[0][ii],shift[1][jj],shift[2][kk]));
226  bb.setType(b.ixType());
227  bb &= fba_bnd;
228  if (bb.ok()) { bl_mf_new.push_back(bb); }
229  }}} // shift combinations
230  } // bl_mf
231 
232  for (auto& b : bl_mf_new) {
233  bl_mf.push_back(b);
234  } // bl_mf
235  fba_per.define(std::move(bl_mf));
236 
237  } else {
238  fba_per = fba;
239  }
240 
241  // BoxList and BoxArray to store complement
242  BoxList com_bl; BoxArray com_ba;
243 
244  // Compute the complement
245  fba_per.complementIn(com_bl,fba_bnd);
246 
247  // com_bl cannot be null since we grew with halo cells
248  AMREX_ALWAYS_ASSERT(com_bl.size() > 0);
249 
250  // A band of width -nghost fine cells inside every coarse/fine face, including the top and
251  // bottom faces of a level that does not reach the top or bottom of the domain (issue 4303)
252  IntVect box_grow_vect(-nghost,-nghost,-nghost);
253 
254  // In z, only those coarse/fine faces start a band: drop the part of the complement that lies
255  // above or below a non-periodic domain, so a level that does reach the top or bottom gets no
256  // band at the physical boundary (in x and y the complement is used as it is)
257  Box zdomain = convert(m_fgeom.Domain(), fba.ixType());
258  zdomain.setRange(0, fba_bnd.smallEnd(0), fba_bnd.length(0));
259  zdomain.setRange(1, fba_bnd.smallEnd(1), fba_bnd.length(1));
260  const bool clip_z = (nghost != 0) && !m_fgeom.isPeriodic(2);
261 
262  // cf_set_width = cf_width = 0 is a special case
263  // In this case we set only the normal velocities
264  // (not any cell-centered quantities) and only
265  // on the coarse-fine boundary itself
266  if (nghost == 0) {
267  if (fba.ixType()[0] == IndexType::NODE) {
268  box_grow_vect = IntVect(1,0,0);
269  } else if (fba.ixType()[1] == IndexType::NODE) {
270  box_grow_vect = IntVect(0,1,0);
271  } else if (fba.ixType()[2] == IndexType::NODE) {
272  box_grow_vect = IntVect(0,0,1);
273  }
274  }
275 
276  // Grow the complement boxes and trim with the bounding box
277  BoxList grown_bl(fba.ixType());
278  for (Box bx : com_bl) {
279  if (clip_z) {
280  bx &= zdomain;
281  if (!bx.ok()) { continue; }
282  }
283  bx.grow(box_grow_vect);
284  bx &= fba_bnd;
285  grown_bl.push_back(bx);
286  }
287  com_bl = std::move(grown_bl);
288 
289 
290  // Do second complement with the grown boxes
291  com_ba.define(std::move(com_bl));
292  com_ba.complementIn(com_bl, fba_bnd);
293 
294  // Fill mask based upon the com_bl BoxList
295  for (MFIter mfi(*m_cf_mask); mfi.isValid(); ++mfi) {
296  const Box& vbx = mfi.validbox();
297  const Array4<int>& mask_arr = m_cf_mask->array(mfi);
298 
299  for (auto const& b : com_bl) {
300  Box com_bx = vbx & b;
301  ParallelFor(com_bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
302  {
303  mask_arr(i,j,k) = mask_val;
304  });
305  }
306  }
307 }
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);})
std::unique_ptr< amrex::iMultiFab > m_cf_mask
Definition: ERF_FillPatcher.H:184
@ ns
Definition: ERF_Morrison.H:50

Referenced by Define().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ crse_times()

amrex::Vector<double> const& ERFFillPatcher::crse_times ( ) const
inline

The times of the coarse data last registered (RegisterCoarseData)

167 { return m_crse_times; }

Referenced by ERF::cf_anelastic_stage_registration().

Here is the caller graph for this function:

◆ Define()

void ERFFillPatcher::Define ( amrex::BoxArray const &  fba,
amrex::DistributionMapping const &  fdm,
amrex::Geometry const &  fgeom,
amrex::BoxArray const &  cba,
amrex::DistributionMapping const &  cdm,
amrex::Geometry const &  cgeom,
int  nghost,
int  nghost_set,
int  ncomp,
amrex::InterpBase *  interp 
)

Define the coarse-fine fill patcher.

Parameters
[in]fbafine-level BoxArray
[in]fdmfine-level DistributionMapping
[in]fgeomfine-level Geometry
[in]cbacoarse-level BoxArray
[in]cdmcoarse-level DistributionMapping
[in]cgeomcoarse-level Geometry
[in]nghostnumber of ghost cells in the fill region
[in]nghost_setnumber of ghost cells in the set region
[in]ncompnumber of components
[in]interpinterpolation operator

Redefine the coarse and fine patch MultiFabs.

Parameters
[in]fbaBoxArray of data to be filled at fine level
[in]fdmDistributionMapping of data to be filled at fine level
[in]fgeomcontainer of geometry information at fine level
[in]cbaBoxArray of data to be filled at coarse level
[in]cdmDistributionMapping of data to be filled at coarse level
[in]cgeomcontainer of geometry information at coarse level
[in]nghostnumber of ghost cells to be filled
[in]nghost_setnumber of ghost cells in the set region
[in]ncompnumber of components to be filled
[in]interpinterpolation operator to be used
114 {
115  AMREX_ALWAYS_ASSERT(nghost <= 0);
116  AMREX_ALWAYS_ASSERT(nghost_set <= 0);
117  AMREX_ALWAYS_ASSERT(nghost <= nghost_set);
118 
119  // Set data members
120  m_fba = fba; m_cba = cba;
121  m_fdm = fdm; m_cdm = cdm;
122  m_fgeom = fgeom; m_cgeom = cgeom;
123  m_nghost = nghost; m_nghost_subset = nghost_set;
124  m_ncomp = ncomp; m_interp = interp;
125 
126  // Delete old MFs if they exist
129  if (m_cf_mask) m_cf_mask.reset();
130 
131  // Index type for the BL/BA
132  IndexType m_ixt = fba.ixType();
133 
134  // Refinement ratios
135  for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
136  m_ratio[idim] = m_fgeom.Domain().length(idim) / m_cgeom.Domain().length(idim);
137  }
138 
139  // Coarse box list
140  // NOTE: if we use face_cons_linear_interp then CoarseBox returns the grown box
141  // so we don't need to manually grow it here
142  BoxList cbl;
143  cbl.set(m_ixt);
144  cbl.reserve(fba.size());
145  for (int i(0); i < fba.size(); ++i) {
146  Box coarse_box(interp->CoarseBox(fba[i], m_ratio));
147  cbl.push_back(coarse_box);
148  }
149 
150  // Box arrays for the coarse data
151  BoxArray cf_cba(std::move(cbl));
152 
153  // Two coarse patches to hold the data to be interpolated
154  m_cf_crse_data_old = std::make_unique<MultiFab> (cf_cba, fdm, m_ncomp, 0);
155  m_cf_crse_data_new = std::make_unique<MultiFab> (cf_cba, fdm, m_ncomp, 0);
156 
157  // Integer masking array
158  m_cf_mask = std::make_unique<iMultiFab> (fba, fdm, 1, 0);
159 
160  // Populate mask array. BuildMask(fba, n, val) sets val in every cell farther than
161  // -n cells (n <= 0) from the coarse-fine boundary, so after these three steps the band
162  // of width -nghost_set holds m_set_mask, the band out to -nghost holds m_relax_mask,
163  // and the rest of the fine level holds 0
164  //
165  // NOTE: the relax band is not currently used. Nothing calls FillRelax, and
166  // ERF::ReadParameters requires cf_width = 0 with two-way coupling, so the band is
167  // empty there; with one-way coupling a cf_width > 0 builds it but nothing reads it.
168  // It is kept so that relaxation can be re-enabled.
169  m_cf_mask->setVal(m_set_mask);
170  BuildMask(fba,nghost_set,m_relax_mask);
171  BuildMask(fba,nghost,0);
172 }
amrex::InterpBase * m_interp
Definition: ERF_FillPatcher.H:180
int m_ncomp
Definition: ERF_FillPatcher.H:179
int m_nghost_subset
Definition: ERF_FillPatcher.H:178
std::unique_ptr< amrex::MultiFab > m_cf_crse_data_new
Definition: ERF_FillPatcher.H:183
int m_set_mask
Definition: ERF_FillPatcher.H:190
amrex::IntVect m_ratio
Definition: ERF_FillPatcher.H:181
int m_relax_mask
Definition: ERF_FillPatcher.H:191
void BuildMask(amrex::BoxArray const &fba, int nghost, int nghost_set)
Definition: ERF_FillPatcher.cpp:181
std::unique_ptr< amrex::MultiFab > m_cf_crse_data_old
Definition: ERF_FillPatcher.H:182
int m_nghost
Definition: ERF_FillPatcher.H:177

Referenced by ERFFillPatcher().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Fill()

template<typename BC >
void ERFFillPatcher::Fill ( amrex::MultiFab &  mf,
double  time_d,
BC &  cbc,
amrex::Vector< amrex::BCRec > const &  bcs,
int  mask_val 
)

Fill fine data in the selected mask region.

Parameters
[in,out]mfMultiFab to be filled
[in]timetime at which to fill data
[in]cbccoarse boundary condition
[in]bcsvector of boundary conditions
[in]mask_valmask value selecting cells to fill

Fill fine data in the relax region

Parameters
[in,out]mfMultiFab to be filled
[in]time_dTime at which to fill data
[in]cbcCoarse boundary condition
[in]bcsVector of boundary conditions
[in]mask_valMask value selecting cells to fill
239 {
240  constexpr double eps = std::numeric_limits<float>::epsilon();
241 
242  AMREX_ALWAYS_ASSERT((time_d >= m_crse_times[0]-eps) && (time_d <= m_crse_times[1]+eps));
243 
244  amrex::Real time = static_cast<amrex::Real>(time_d);
245 
246  // Time interpolation factors
247  amrex::Real fac_new = amrex::Real(0);
248  amrex::Real fac_old = amrex::Real(1);
249  if (amrex::Math::abs(m_dt_crse) > eps) {
250  fac_new = static_cast<amrex::Real>((time_d - m_crse_times[0]) / m_dt_crse);
251  fac_old = amrex::Real(1) - fac_new;
252  }
253 
254  // Coarse MF to hold time interpolated data
255  amrex::MultiFab crse_data_time_interp(m_cf_crse_data_old->boxArray(),
256  m_cf_crse_data_old->DistributionMap(),
257  m_ncomp, amrex::IntVect{0});
258 
259  // Time interpolate the coarse data
260  amrex::MultiFab::LinComb(crse_data_time_interp,
261  fac_old, *(m_cf_crse_data_old), 0,
262  fac_new, *(m_cf_crse_data_new), 0,
263  0, m_ncomp, amrex::IntVect{0});
264 
265  // Boundary condition operator, at the time it is asked for, on the data at that time.
266  // Applied to the old coarse data before the interpolation it would be weighted by
267  // fac_old -- and vanish at the new coarse time -- and would overwrite the registered
268  // old data the next fill interpolates from.
269  cbc(crse_data_time_interp, 0, m_ncomp, amrex::IntVect(0), time, 0);
270 
271  // Call correct spatial interpolation type
272  amrex::IndexType m_ixt = mf.boxArray().ixType();
273  int ixt_sum = m_ixt[0]+m_ixt[1]+m_ixt[2];
274  if (ixt_sum == 0) {
275  InterpCell(mf,crse_data_time_interp,bcs,mask_val);
276  } else if (ixt_sum == 1) {
277  InterpFace(mf,crse_data_time_interp,mask_val);
278  } else {
279  amrex::Abort("ERF_FillPatcher only supports face linear and cell cons linear interp!");
280  }
281 }
amrex::Real Real
Definition: ERF_ShocInterface.H:19
void InterpFace(amrex::MultiFab &fine, amrex::MultiFab const &crse, int mask_val)
Definition: ERF_FillPatcher.cpp:348
void InterpCell(amrex::MultiFab &fine, amrex::MultiFab const &crse, amrex::Vector< amrex::BCRec > const &bcr, int mask_val)
Definition: ERF_FillPatcher.cpp:544
double m_dt_crse
Definition: ERF_FillPatcher.H:189
real(c_double), parameter epsilon
Definition: ERF_module_model_constants.F90:12

Referenced by FillRelax(), and FillSet().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ FillRelax()

template<typename BC >
void ERFFillPatcher::FillRelax ( amrex::MultiFab &  mf,
double  time,
BC &  cbc,
amrex::Vector< amrex::BCRec > const &  bcs 
)

Fill fine data in the relax region.

Not currently used: nothing calls it, and two-way coupling requires cf_width = 0, which leaves the relax region empty. Kept so that relaxation can be re-enabled.

Parameters
[in,out]mfMultiFab to be filled
[in]timetime at which to fill data
[in]cbccoarse boundary condition
[in]bcsvector of boundary conditions

Fill fine data in the relax region

Parameters
[in,out]mfMultiFab to be filled
[in]timeTime at which to fill data
[in]cbcCoarse boundary condition
[in]bcsVector of boundary conditions
222 {
223  Fill(mf,time,cbc,bcs,m_relax_mask);
224 }
void Fill(amrex::MultiFab &mf, double time, BC &cbc, amrex::Vector< amrex::BCRec > const &bcs, int mask_val)
Definition: ERF_FillPatcher.H:237

Referenced by fine_compute_interior_ghost_rhs().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ FillSet()

template<typename BC >
void ERFFillPatcher::FillSet ( amrex::MultiFab &  mf,
double  time,
BC &  cbc,
amrex::Vector< amrex::BCRec > const &  bcs 
)

Fill fine data in the set region.

Parameters
[in,out]mfMultiFab to be filled
[in]timetime at which to fill data
[in]cbccoarse boundary condition
[in]bcsvector of boundary conditions

Fill fine data in the set region

Parameters
[in,out]mfMultiFab to be filled
[in]timeTime at which to fill data
[in]cbcCoarse boundary condition
[in]bcsVector of boundary conditions
206 {
207  Fill(mf,time,cbc,bcs,m_set_mask);
208 }

Referenced by fill_cf_momentum().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetMask()

amrex::iMultiFab* ERFFillPatcher::GetMask ( )
inline

Return the coarse-fine mask.

124 { return m_cf_mask.get(); }

Referenced by fine_compute_interior_ghost_rhs().

Here is the caller graph for this function:

◆ GetRelaxMaskVal()

int ERFFillPatcher::GetRelaxMaskVal ( )
inline

Return the mask value for the relax region.

119 { return m_relax_mask; }

Referenced by fine_compute_interior_ghost_rhs().

Here is the caller graph for this function:

◆ GetSetMaskVal()

int ERFFillPatcher::GetSetMaskVal ( )
inline

Return the mask value for the set region.

98 { return m_set_mask; }

Referenced by fine_compute_interior_ghost_rhs().

Here is the caller graph for this function:

◆ InterpCell()

void ERFFillPatcher::InterpCell ( amrex::MultiFab &  fine,
amrex::MultiFab const &  crse,
amrex::Vector< amrex::BCRec > const &  bcr,
int  mask_val 
)

Interpolate coarse data to fine cell-centered data.

Parameters
[in,out]finefine-level data to fill
[in]crsecoarse-level source data
[in]bcrboundary-condition records
[in]mask_valmask value selecting cells to fill

Interpolate coarse data to fine cell-centered data selected by the mask.

Parameters
[in,out]finefine-level data to fill
[in]crsecoarse-level data to interpolate from
[in]bcrboundary-condition records used by the interpolater
[in]mask_valmask value selecting cells to fill
548 {
549  int ncomp = m_ncomp;
550  IntVect ratio = m_ratio;
551  IndexType m_ixt = fine.boxArray().ixType();
552  Box const& cdomain = convert(m_cgeom.Domain(), m_ixt);
553 
554  for (MFIter mfi(fine); mfi.isValid(); ++mfi) {
555  Box const& fbx = mfi.validbox();
556 
557  Array4<Real> const& fine_arr = fine.array(mfi);
558  Array4<Real const> const& crse_arr = crse.const_array(mfi);
559  Array4<int const> const& mask_arr = m_cf_mask->const_array(mfi);
560 
561  bool run_on_gpu = Gpu::inLaunchRegion();
562  amrex::ignore_unused(run_on_gpu);
563 
564  amrex::ignore_unused(m_fgeom);
565 
566  const Box& crse_region = m_interp->CoarseBox(fbx,ratio);
567  Box cslope_bx(crse_region);
568  for (int dim = 0; dim < AMREX_SPACEDIM; dim++) {
569  if (ratio[dim] > 1) {
570  cslope_bx.grow(dim,-1);
571  }
572  }
573 
574  FArrayBox ccfab(cslope_bx, ncomp*AMREX_SPACEDIM, The_Async_Arena());
575  Array4<Real> const& tmp = ccfab.array();
576  Array4<Real const> const& ctmp = ccfab.const_array();
577 
578 #ifdef AMREX_USE_GPU
579  AsyncArray<BCRec> async_bcr(bcr.data(), (run_on_gpu) ? ncomp : 0);
580  BCRec const* bcrp = (run_on_gpu) ? async_bcr.data() : bcr.data();
581 #else
582  BCRec const* bcrp = bcr.data();
583 #endif
584 
585  AMREX_HOST_DEVICE_PARALLEL_FOR_4D_FLAG(RunOn::Gpu, cslope_bx, ncomp, i, j, k, n,
586  {
587  mf_cell_cons_lin_interp_mcslope(i,j,k,n, tmp, crse_arr, 0, ncomp,
588  cdomain, ratio, bcrp);
589  });
590 
591  AMREX_HOST_DEVICE_PARALLEL_FOR_4D_FLAG(RunOn::Gpu, fbx, ncomp, i, j, k, n,
592  {
593  if (mask_arr(i,j,k) == mask_val) mf_cell_cons_lin_interp(i,j,k,n, fine_arr, 0, ctmp,
594  crse_arr, 0, ncomp, ratio);
595  });
596  } // MFIter
597 }
@ tmp
Definition: ERF_AdvanceWSM6.cpp:116

Referenced by Fill().

Here is the caller graph for this function:

◆ InterpFace()

void ERFFillPatcher::InterpFace ( amrex::MultiFab &  fine,
amrex::MultiFab const &  crse,
int  mask_val 
)

Interpolate coarse data to fine face data.

Parameters
[in,out]finefine-level data to fill
[in]crsecoarse-level source data
[in]mask_valmask value selecting cells to fill

Interpolate coarse data to fine face-centered data selected by the mask.

Parameters
[in,out]finefine-level data to fill
[in]crsecoarse-level data to interpolate from
[in]mask_valmask value selecting cells to fill
351 {
352  int ncomp = 1;
353  IntVect ratio = m_ratio;
354 
355  FArrayBox slope;
356 
357  //
358  // This box is only used to make sure we don't look outside
359  // the domain for computing the slopes in the interpolation
360  // We need it to be of the type of the faces being filled
361  //
362  // IndexType ixt = fine.boxArray().ixType();
363  // Box const& domface = convert(m_cgeom.Domain(), ixt);
364 
365  // We don't need to worry about face-based domain because this is only used in the tangential interpolation
366  Box per_grown_domain = m_cgeom.Domain();
367  for (int dim = 0; dim < AMREX_SPACEDIM; dim++) {
368  if (m_cgeom.isPeriodic(dim)) {
369  per_grown_domain.grow(dim,1);
370  }
371  }
372 
373  for (MFIter mfi(fine); mfi.isValid(); ++mfi)
374  {
375  Box const& fbx = mfi.validbox();
376 
377  slope.resize(fbx,ncomp,The_Async_Arena());
378 
379  Array4<Real> const& fine_arr = fine.array(mfi);
380  Array4<Real> const& slope_arr = slope.array();
381  Array4<Real const> const& crse_arr = crse.const_array(mfi);
382  Array4<int const> const& mask_arr = m_cf_mask->const_array(mfi);
383 
384  if (fbx.type(0) == IndexType::NODE) // x-faces
385  {
386  // Here do interpolation in the tangential directions
387  AMREX_HOST_DEVICE_PARALLEL_FOR_3D_FLAG(RunOn::Gpu,fbx,i,j,k,
388  {
389  if (mask_arr(i,j,k) == mask_val) { // x-faces
390  const int ii = coarsen(i,ratio[0]);
391  if (i-ii*ratio[0] == 0) {
392  interp_face_reg(i,j,k,ratio,fine_arr,0,crse_arr,slope_arr,ncomp,per_grown_domain,0);
393  }
394  }
395  });
396 
397  // Here do interpolation in the normal direction
398  // using the fine values that have already been filled
399  AMREX_HOST_DEVICE_PARALLEL_FOR_3D_FLAG(RunOn::Gpu,fbx,i,j,k,
400  {
401  if (mask_arr(i,j,k) == mask_val) {
402  const int ii = coarsen(i,ratio[0]);
403  if (i-ii*ratio[0] != 0) {
404  Real const w = static_cast<Real>(i-ii*ratio[0]) * (Real(1.0)/Real(ratio[0]));
405  fine_arr(i,j,k,0) = (Real(1.0)-w) * fine_arr(ii*ratio[0],j,k,0) + w * fine_arr((ii+1)*ratio[0],j,k,0);
406  }
407  }
408  });
409 
410  }
411  else if (fbx.type(1) == IndexType::NODE) // y-faces
412  {
413  // Here do interpolation in the tangential directions
414  AMREX_HOST_DEVICE_PARALLEL_FOR_3D_FLAG(RunOn::Gpu,fbx,i,j,k,
415  {
416  if (mask_arr(i,j,k) == mask_val) {
417  const int jj = coarsen(j,ratio[1]);
418  if (j-jj*ratio[1] == 0) {
419  interp_face_reg(i,j,k,ratio,fine_arr,0,crse_arr,slope_arr,ncomp,per_grown_domain,1);
420  }
421  }
422  });
423 
424  // Here do interpolation in the normal direction
425  // using the fine values that have already been filled
426  AMREX_HOST_DEVICE_PARALLEL_FOR_3D_FLAG(RunOn::Gpu,fbx,i,j,k,
427  {
428  if (mask_arr(i,j,k) == mask_val) {
429  const int jj = coarsen(j,ratio[1]);
430  if (j-jj*ratio[1] != 0) {
431  Real const w = static_cast<Real>(j-jj*ratio[1]) * (Real(1.0)/Real(ratio[1]));
432  fine_arr(i,j,k,0) = (Real(1.0)-w) * fine_arr(i,jj*ratio[1],k,0) + w * fine_arr(i,(jj+1)*ratio[1],k,0);
433  }
434  }
435  });
436  }
437  else // z-faces
438  {
439  // Here do interpolation in the tangential directions
440  AMREX_HOST_DEVICE_PARALLEL_FOR_3D_FLAG(RunOn::Gpu,fbx,i,j,k,
441  {
442  if (mask_arr(i,j,k) == mask_val) {
443  const int kk = coarsen(k,ratio[2]);
444  if (k-kk*ratio[2] == 0) {
445  interp_face_reg(i,j,k,ratio,fine_arr,0,crse_arr,slope_arr,1,per_grown_domain,2);
446  }
447  }
448  });
449 
450  // Here do interpolation in the normal direction
451  // using the fine values that have already been filled
452  AMREX_HOST_DEVICE_PARALLEL_FOR_3D_FLAG(RunOn::Gpu,fbx,i,j,k,
453  {
454  if (mask_arr(i,j,k) == mask_val) {
455  const int kk = coarsen(k,ratio[2]);
456  if (k-kk*ratio[2] != 0) {
457  Real const w = static_cast<Real>(k-kk*ratio[2]) * (Real(1.0)/Real(ratio[2]));
458  fine_arr(i,j,k,0) = (Real(1.0)-w) * fine_arr(i,j,kk*ratio[2],0) + w * fine_arr(i,j,(kk+1)*ratio[2],0);
459  }
460  }
461  });
462  } // IndexType::NODE
463 
464  // Log-law fill (erf.cf_loglaw_fill), lateral faces of a box that reaches the ground only.
465  // The coarse face value next to a wall is a mean of a log profile, but the linear fill
466  // above spreads it over the fine sub-faces with a slope that does not know the wall: the
467  // fine sub-face at the wall gets too much flow and, at a surface-layer bottom (where the
468  // slope is limited to about zero), the one above it too little. Share the flux F of the
469  // first coarse face above the wall among its fine sub-faces in proportion to the integral
470  // of ln(1 + z/z0) over the fluid part of each (cf_loglaw_weight), so a half-solid sub-face
471  // carries its fluid share too. F is the sum of the sub-face values the linear fill put
472  // there, the solid ones included, and the share returns F exactly, so the average down
473  // of the c/f faces gives back the coarse values (moving flux between coarse faces would
474  // drive a circulation in the coarse cells next to the fine box). The wall is the top of
475  // the solid stack at the bottom of the column (the solid fraction, averaged over the two
476  // cells of the face), or the bottom of the domain. A wall coarse face with no fluid
477  // sub-face (the two columns' walls differ by a coarse cell or more) keeps the linear fill.
478  // The option is set only around the set fills (ERF::set_cf_fill_options), so the relax
479  // band keeps the linear fill.
480  const int ldir = (fbx.type(0) == IndexType::NODE) ? 0 : ((fbx.type(1) == IndexType::NODE) ? 1 : 2);
481  if (m_loglaw && ldir < 2 && fbx.smallEnd(2) == m_fgeom.Domain().smallEnd(2))
482  {
483  const int di = (ldir == 0), dj = (ldir == 1);
484  const int rz = ratio[2];
485  const Real dzf = m_fgeom.CellSize(2);
486  const Real zlo = m_fgeom.ProbLo(2);
487  const Real z0 = m_loglaw_z0;
488  const int klo = fbx.smallEnd(2), khi = fbx.bigEnd(2);
489  const bool have_tb = (m_loglaw_tblank != nullptr);
490  if (have_tb) {
491  // the solid fraction is read with the face array's MFIter: same boxes and ranks
492  AMREX_ALWAYS_ASSERT(m_loglaw_tblank->DistributionMap() == fine.DistributionMap() &&
493  m_loglaw_tblank->boxArray().size() == fine.boxArray().size());
494  }
495  Array4<Real const> const tb = have_tb ? m_loglaw_tblank->const_array(mfi) : Array4<Real const>{};
496  Box colbx = fbx; colbx.setRange(2, klo);
497  ParallelFor(colbx, [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept
498  {
499  // the surface height of the face (the mean of its two columns; the neighbour
500  // column across the coarse/fine boundary is a ghost cell of the fine blanking,
501  // which holds the geometry there), and the wall cell: the first cell up the
502  // column whose face is not next to a fully solid cell, found in integer
503  // arithmetic so that a wall on a cell face does not round to the cell below
504  const Real zs = have_tb ? Real(0.5) * (cf_wall_height(tb,i,j,klo,khi,zlo,dzf) +
505  cf_wall_height(tb,i-di,j-dj,klo,khi,zlo,dzf))
506  : zlo + dzf * static_cast<Real>(klo);
507  int kf = klo;
508  if (have_tb) {
509  while (kf <= khi && cf_face_solid(tb,i,j,kf,di,dj,0)) { ++kf; }
510  }
511  const int kc0 = coarsen(kf, rz) * rz;
512  if (kc0 < klo || kc0 + rz - 1 > khi) { return; }
513  for (int kk = kc0; kk < kc0+rz; ++kk) {
514  if (mask_arr(i,j,kk) != mask_val) { return; }
515  }
516  Real F = Real(0.0), W = Real(0.0);
517  for (int kk = kc0; kk < kc0+rz; ++kk) {
518  F += fine_arr(i,j,kk,0);
519  if (have_tb && cf_face_solid(tb,i,j,kk,di,dj,0)) { continue; }
520  const Real zb = zlo + dzf * static_cast<Real>(kk);
521  W += cf_loglaw_weight(zs, zb, dzf, z0);
522  }
523  if (W <= Real(0.0)) { return; }
524  // the solid sub-faces of the wall face carry nothing; the fluid ones share the
525  // whole flux of the coarse face
526  for (int kk = kc0; kk < kc0+rz; ++kk) {
527  if (have_tb && cf_face_solid(tb,i,j,kk,di,dj,0)) { fine_arr(i,j,kk,0) = Real(0.0); continue; }
528  const Real zb = zlo + dzf * static_cast<Real>(kk);
529  fine_arr(i,j,kk,0) = F * cf_loglaw_weight(zs, zb, dzf, z0) / W;
530  }
531  });
532  }
533  } // MFiter
534 }
Real z0
Definition: ERF_InitCustomPertVels_ScalarAdvDiff.H:12
const int khi
Definition: ERF_InitCustomPert_Bubble.H:25
const int klo
Definition: ERF_InitCustomPert_KE.H:9
Real w
Definition: ERF_Plotfile2DInterpolator.cpp:23
bool m_loglaw
Definition: ERF_FillPatcher.H:185
amrex::MultiFab const * m_loglaw_tblank
Definition: ERF_FillPatcher.H:187
amrex::Real m_loglaw_z0
Definition: ERF_FillPatcher.H:186
real(c_double), private di
Definition: ERF_module_mp_morr_two_moment.F90:203
@ W
Definition: ERF_ObsNudgingSeries.H:36

Referenced by Fill().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ RegisterCoarseData()

void ERFFillPatcher::RegisterCoarseData ( amrex::Vector< amrex::MultiFab const * > const &  crse_data,
amrex::Vector< double > const &  crse_time 
)

Register coarse data bracketing the fill time.

Parameters
[in]crse_datacoarse MultiFabs
[in]crse_timetimes associated with crse_data

Register the coarse data to be used by the ERFFillPatcher

Parameters
[in]crse_datadata at old and new time at coarse level
[in]crse_timetimes at which crse_data is defined
318 {
319  AMREX_ALWAYS_ASSERT(crse_data.size() == 2); // old and new
320  AMREX_ALWAYS_ASSERT(crse_time[1] >= crse_time[0]);
321 
322  // NOTE: CoarseBox grows the coarsened fine box by one cell in each direction whose
323  // refinement ratio is > 1 (and, for face_cons_linear_interp, that is cell-centered).
324  // Where the fine level touches the domain boundary, the grown box reaches past the
325  // coarse domain (e.g. in z when the vertical ratio is > 1), so include the ghost
326  // cells of crse_data in the copy
327  IntVect src_ng = crse_data[0]->nGrowVect();
328  IntVect dst_ng = m_cf_crse_data_old->nGrowVect();
329 
330  m_cf_crse_data_old->ParallelCopy(*(crse_data[0]), 0, 0, m_ncomp,
331  src_ng, dst_ng, m_cgeom.periodicity()); // old data
332  m_cf_crse_data_new->ParallelCopy(*(crse_data[1]), 0, 0, m_ncomp,
333  src_ng, dst_ng, m_cgeom.periodicity()); // new data
334 
335  m_crse_times[0] = crse_time[0]; // time of "old" coarse data
336  m_crse_times[1] = crse_time[1]; // time of "new" coarse data
337 
338  m_dt_crse = crse_time[1] - crse_time[0];
339 }

Referenced by ERF::cf_anelastic_stage_registration().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ SetLogLawFill()

void ERFFillPatcher::SetLogLawFill ( bool  on,
amrex::Real  z0,
amrex::MultiFab const *  wall_tblank 
)
inline

Log-law fill of the lateral coarse/fine faces next to a wall (erf.cf_loglaw_fill): the flux of the first coarse face above the wall is shared among its fine sub-faces in proportion to the integral of ln(1 + z/z0) over the fluid part of each, so the flux of every coarse face is kept. Acts on the set fills of fine boxes that reach the bottom of the domain.

Parameters
[in]onenable the log-law fill (constant dz only)
[in]z0roughness length [m]
[in]wall_tblankfine solid fraction giving the wall height (immersed forcing), or nullptr for a wall at the bottom of the domain
112  {
113  m_loglaw = on; m_loglaw_z0 = z0; m_loglaw_tblank = wall_tblank;
114  }

Member Data Documentation

◆ m_cba

amrex::BoxArray ERFFillPatcher::m_cba
private

Referenced by Define().

◆ m_cdm

amrex::DistributionMapping ERFFillPatcher::m_cdm
private

Referenced by Define().

◆ m_cf_crse_data_new

std::unique_ptr<amrex::MultiFab> ERFFillPatcher::m_cf_crse_data_new
private

Referenced by Define(), Fill(), and RegisterCoarseData().

◆ m_cf_crse_data_old

std::unique_ptr<amrex::MultiFab> ERFFillPatcher::m_cf_crse_data_old
private

Referenced by Define(), Fill(), and RegisterCoarseData().

◆ m_cf_mask

std::unique_ptr<amrex::iMultiFab> ERFFillPatcher::m_cf_mask
private

◆ m_cgeom

amrex::Geometry ERFFillPatcher::m_cgeom
private

◆ m_crse_times

amrex::Vector<double> ERFFillPatcher::m_crse_times
private

◆ m_dt_crse

double ERFFillPatcher::m_dt_crse
private

Referenced by Fill(), and RegisterCoarseData().

◆ m_fba

amrex::BoxArray ERFFillPatcher::m_fba
private

Referenced by Define().

◆ m_fdm

amrex::DistributionMapping ERFFillPatcher::m_fdm
private

Referenced by Define().

◆ m_fgeom

amrex::Geometry ERFFillPatcher::m_fgeom
private

◆ m_interp

amrex::InterpBase* ERFFillPatcher::m_interp
private

Referenced by Define(), and InterpCell().

◆ m_loglaw

bool ERFFillPatcher::m_loglaw = false
private

Referenced by InterpFace(), and SetLogLawFill().

◆ m_loglaw_tblank

amrex::MultiFab const* ERFFillPatcher::m_loglaw_tblank = nullptr
private

Referenced by InterpFace(), and SetLogLawFill().

◆ m_loglaw_z0

amrex::Real ERFFillPatcher::m_loglaw_z0 = amrex::Real(0.1)
private

Referenced by InterpFace(), and SetLogLawFill().

◆ m_ncomp

int ERFFillPatcher::m_ncomp
private

◆ m_nghost

int ERFFillPatcher::m_nghost
private

Referenced by Define().

◆ m_nghost_subset

int ERFFillPatcher::m_nghost_subset
private

Referenced by Define().

◆ m_ratio

amrex::IntVect ERFFillPatcher::m_ratio
private

Referenced by Define(), InterpCell(), and InterpFace().

◆ m_relax_mask

int ERFFillPatcher::m_relax_mask {1}
private

Referenced by Define(), FillRelax(), and GetRelaxMaskVal().

◆ m_set_mask

int ERFFillPatcher::m_set_mask {2}
private

Referenced by Define(), FillSet(), and GetSetMaskVal().


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