REMORA
Regional Modeling of Oceans Refined Adaptively
Loading...
Searching...
No Matches
REMORA_FillPatcher.cpp
Go to the documentation of this file.
2#include <AMReX_Arena.H>
3#include <AMReX_InterpFaceReg_3D_C.H>
4
5using namespace amrex;
6
7
8/**
9 * @param[in] fba BoxArray of data to be filled at fine level
10 * @param[in] fdm DistributionMapping of data to be filled at fine level
11 * @param[in] fgeom container of geometry information at fine level
12 * @param[in] cba BoxArray of data to be filled at coarse level
13 * @param[in] cdm DistributionMapping of data to be filled at coarse level
14 * @param[in] cgeom container of geometry information at coarse level
15 * @param[in] nghost number of ghost cells to be filled
16 * @param[in] ncomp number of components to be filled
17 * @param[in] interp interpolation operator to be used
18 */
19
20REMORAFillPatcher::REMORAFillPatcher (BoxArray const& fba, DistributionMapping const& fdm,
21 Geometry const& fgeom,
22 BoxArray const& cba, DistributionMapping const& cdm,
23 Geometry const& cgeom,
24 int nghost, int nghost_set,
26 : m_fba(fba),
27 m_cba(cba),
28 m_fdm(fdm),
29 m_cdm(cdm),
30 m_fgeom(fgeom),
31 m_cgeom(cgeom)
32{
33 AMREX_ALWAYS_ASSERT(fba.ixType() == cba.ixType());
34
35 // Vector to hold times for coarse data
36 m_crse_times.resize(2);
37
38 // Define the coarse and fine MFs
40}
41
42
43/**
44 * @param[in] fba BoxArray of data to be filled at fine level
45 * @param[in] fdm DistributionMapping of data to be filled at fine level
46 * @param[in] fgeom container of geometry information at fine level
47 * @param[in] cba BoxArray of data to be filled at coarse level
48 * @param[in] cdm DistributionMapping of data to be filled at coarse level
49 * @param[in] cgeom container of geometry information at coarse level
50 * @param[in] nghost number of ghost cells to be filled
51 * @param[in] ncomp number of components to be filled
52 * @param[in] interp interpolation operator to be used
53 */
54void REMORAFillPatcher::Define (BoxArray const& fba, DistributionMapping const& fdm,
55 Geometry const& fgeom,
56 BoxArray const& cba, DistributionMapping const& cdm,
57 Geometry const& cgeom,
58 int nghost, int nghost_set,
60{
64
65 // Set data members
66 m_fba = fba; m_cba = cba;
67 m_fdm = fdm; m_cdm = cdm;
71
72 // Delete old MFs if they exist
75 if (m_cf_mask) m_cf_mask.reset();
76
77 // Index type for the BL/BA
78 IndexType m_ixt = fba.ixType();
79
80 // Refinement ratios
81 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
82 m_ratio[idim] = m_fgeom.Domain().length(idim) / m_cgeom.Domain().length(idim);
83 }
84
85 // Coarse box list
86 // NOTE: if we use face_cons_linear_interp then CoarseBox returns the grown box
87 // so we don't need to manually grow it here
89 cbl.set(m_ixt);
90 cbl.reserve(fba.size());
91 for (int i(0); i < fba.size(); ++i) {
92 Box coarse_box(interp->CoarseBox(fba[i], m_ratio));
93 cbl.push_back(coarse_box);
94 }
95
96 // Box arrays for the coarse data
97 BoxArray cf_cba(std::move(cbl));
98
99 // Two coarse patches to hold the data to be interpolated
100 m_cf_crse_data_old = std::make_unique<MultiFab> (cf_cba, fdm, m_ncomp, 0);
101 m_cf_crse_data_new = std::make_unique<MultiFab> (cf_cba, fdm, m_ncomp, 0);
102
103 // Integer masking array
104 m_cf_mask = std::make_unique<iMultiFab> (fba, fdm, 1, 0);
105
106 // Populate mask array
107 if (nghost_set <= 0) {
108 m_cf_mask->setVal(m_set_mask);
110 } else {
111 m_cf_mask->setVal(m_relax_mask);
113 }
114}
115
116void REMORAFillPatcher::BuildMask (BoxArray const& fba,
117 int nghost,
118 int mask_val)
119{
120 // The complement below defines the coarse-fine interface, so it must be taken against a
121 // fine level that knows about periodicity: whether the far side of a seam is fine or
122 // coarse depends on whether the patch wraps onto itself there. Adding the periodic images
123 // first answers that geometrically. Without them complementIn reports the seam as
124 // uncovered either way, and misreports the corners where a seam meets an interface.
125 BoxList fimg_bl(fba.ixType());
126 for (int ibox = 0; ibox < fba.size(); ++ibox) { fimg_bl.push_back(fba[ibox]); }
127
128 for (int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
129 if (!m_fgeom.isPeriodic(dir)) { continue; }
130 const int len = m_fgeom.Domain().length(dir);
131 BoxList images(fba.ixType());
132 for (auto const& b : fimg_bl) {
133 Box bp(b); bp.shift(dir, len); images.push_back(bp);
134 Box bm(b); bm.shift(dir, -len); images.push_back(bm);
135 }
136 fimg_bl.join(images);
137 }
138 BoxArray fba_img(std::move(fimg_bl));
139
140 // Minimal bounding box of fine BA plus a halo cell
141 Box fba_bnd = amrex::grow(fba_img.minimalBox(), IntVect(1,1,1));
142
143 // BoxList and BoxArray to store complement
144 BoxList com_bl; BoxArray com_ba;
145
146 // Compute the complement
147 fba_img.complementIn(com_bl,fba_bnd);
148
149 // com_bl cannot be null since we grew with halo cells
150 AMREX_ALWAYS_ASSERT(com_bl.size() > 0);
151
152 IntVect box_grow_vect(-nghost,-nghost,0);
153
154 // cf_set_width = cf_width = 0 is a special case
155 // In this case we set only the normal velocities
156 // (not any cell-centered quantities) and only
157 // on the coarse-fine boundary itself
158 if (nghost == 0) {
159 if (fba.ixType()[0] == IndexType::NODE) {
160 box_grow_vect = IntVect(1,0,0);
161 } else if (fba.ixType()[1] == IndexType::NODE) {
162 box_grow_vect = IntVect(0,1,0);
163 } else if (fba.ixType()[2] == IndexType::NODE) {
164 box_grow_vect = IntVect(0,0,1);
165 }
166 }
167
168 // Grow the complement boxes and trim with the bounding box
169 Vector<Box>& com_bl_v = com_bl.data();
170 for (int i(0); i<com_bl.size(); ++i) {
171 Box& bx = com_bl_v[i];
172 bx.grow(box_grow_vect);
173 bx &= fba_bnd;
174 }
175
176
177 // Do second complement with the grown boxes
178 com_ba.define(std::move(com_bl));
179 com_ba.complementIn(com_bl, fba_bnd);
180
181 // Fill mask based upon the com_bl BoxList
182 for (MFIter mfi(*m_cf_mask); mfi.isValid(); ++mfi) {
183 const Box& vbx = mfi.validbox();
184 const Array4<int>& mask_arr = m_cf_mask->array(mfi);
185
186 for (auto const& b : com_bl) {
187 Box com_bx = vbx & b;
188 ParallelFor(com_bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
189 {
190 mask_arr(i,j,k) = mask_val;
191 });
192 }
193 }
194
195 // A face on a PHYSICAL domain boundary is never a coarse-fine interface: the boundary
196 // condition owns it, and left marked it would be overwritten from the parent every time
197 // the interface is set. Not applicable to a periodic direction, where a domain-edge face
198 // IS a real interface whenever the patch covers only part of the width -- the far side of
199 // the seam is coarse then. It is interior only when the patch wraps onto itself, which the
200 // periodic images above already keep out of the complement.
201 const Box mask_domain = amrex::convert(m_fgeom.Domain(), fba.ixType());
202 for (int dir = 0; dir < AMREX_SPACEDIM; ++dir) {
203 if (fba.ixType()[dir] != IndexType::NODE) { continue; }
204 if (m_fgeom.isPeriodic(dir)) { continue; }
205
206 const int edge_lo = mask_domain.smallEnd(dir);
207 const int edge_hi = mask_domain.bigEnd(dir);
208 const int idir = dir;
209
210 for (MFIter mfi(*m_cf_mask); mfi.isValid(); ++mfi) {
211 const Box& vbx = mfi.validbox();
212 const Array4<int>& mask_arr = m_cf_mask->array(mfi);
213 ParallelFor(vbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
214 {
215 const int idx = (idir == 0) ? i : ((idir == 1) ? j : k);
216 if (idx == edge_lo || idx == edge_hi) { mask_arr(i,j,k) = mask_val; }
217 });
218 }
219 }
220}
221
222/*
223 * @param[in] crse_data data at old and new time at coarse level
224 * @param[in] crse_time times at which crse_data is defined
225 */
226
228 Vector<Real> const& crse_time)
229{
230 AMREX_ALWAYS_ASSERT(crse_data.size() == 2); // old and new
232
233 // NOTE: CoarseBox with CellConsLinear interpolation grows the
234 // box by 1 in all directions. This pushes the domain for
235 // m_cf_crse_data into ghost cells in the z-dir. So we need
236 // to include ghost cells for crse_data when doing the copy
237 IntVect src_ng = crse_data[0]->nGrowVect();
238 IntVect dst_ng = m_cf_crse_data_old->nGrowVect();
239
240 m_cf_crse_data_old->ParallelCopy(*(crse_data[0]), 0, 0, m_ncomp,
241 src_ng, dst_ng, m_cgeom.periodicity()); // old data
242 m_cf_crse_data_new->ParallelCopy(*(crse_data[1]), 0, 0, m_ncomp,
243 src_ng, dst_ng, m_cgeom.periodicity()); // new data
244
245 m_crse_times[0] = crse_time[0]; // time of "old" coarse data
246 m_crse_times[1] = crse_time[1]; // time of "new" coarse data
247
248 m_dt_crse = crse_time[1] - crse_time[0];
249}
250
251/**
252 * @param[inout] fine fine level data
253 * @param[in ] crse coarse level data
254 * @param[in ] mask_val masked value
255 */
257 MultiFab const& crse,
258 int mask_val)
259{
260 int ncomp = m_ncomp;
261 IntVect ratio = m_ratio;
262
263 FArrayBox slope;
264
265 //
266 // This box is only used to make sure we don't look outside
267 // the domain for computing the slopes in the interpolation
268 // We need it to be of the type of the faces being filled
269 //
270 // IndexType ixt = fine.boxArray().ixType();
271 // Box const& domface = amrex::convert(m_cgeom.Domain(), ixt);
272
273 // We don't need to worry about face-based domain because this is only used in the tangential interpolation
274 Box per_grown_domain = m_cgeom.Domain();
275 for (int dim = 0; dim < AMREX_SPACEDIM; dim++) {
276 if (m_cgeom.isPeriodic(dim)) {
277 per_grown_domain.grow(dim,1);
278 }
279 }
280
281 for (MFIter mfi(fine); mfi.isValid(); ++mfi)
282 {
283 Box const& fbx = mfi.validbox();
284
285 slope.resize(fbx,ncomp,The_Async_Arena());
286
287 Array4<Real> const& fine_arr = fine.array(mfi);
288 Array4<Real> const& slope_arr = slope.array();
289 Array4<Real const> const& crse_arr = crse.const_array(mfi);
290 Array4<int const> const& mask_arr = m_cf_mask->const_array(mfi);
291
292 if (fbx.type(0) == IndexType::NODE) // x-faces
293 {
294 // Here do interpolation in the tangential directions
296 {
297 if (mask_arr(i,j,k) == mask_val) { // x-faces
298 const int ii = amrex::coarsen(i,ratio[0]);
299 if (i-ii*ratio[0] == 0) {
301 }
302 }
303 });
304
305 // Here do interpolation in the normal direction
306 // using the fine values that have already been filled
308 {
309 if (mask_arr(i,j,k) == mask_val) {
310 const int ii = amrex::coarsen(i,ratio[0]);
311 if (i-ii*ratio[0] != 0) {
312 Real const w = static_cast<Real>(i-ii*ratio[0]) * (one/Real(ratio[0]));
313 fine_arr(i,j,k,0) = (one-w) * fine_arr(ii*ratio[0],j,k,0) + w * fine_arr((ii+1)*ratio[0],j,k,0);
314 }
315 }
316 });
317
318 }
319 else if (fbx.type(1) == IndexType::NODE) // y-faces
320 {
321 // Here do interpolation in the tangential directions
323 {
324 if (mask_arr(i,j,k) == mask_val) {
325 const int jj = amrex::coarsen(j,ratio[1]);
326 if (j-jj*ratio[1] == 0) {
328 }
329 }
330 });
331
332 // Here do interpolation in the normal direction
333 // using the fine values that have already been filled
335 {
336 if (mask_arr(i,j,k) == mask_val) {
337 const int jj = amrex::coarsen(j,ratio[1]);
338 if (j-jj*ratio[1] != 0) {
339 Real const w = static_cast<Real>(j-jj*ratio[1]) * (one/Real(ratio[1]));
340 fine_arr(i,j,k,0) = (one-w) * fine_arr(i,jj*ratio[1],k,0) + w * fine_arr(i,(jj+1)*ratio[1],k,0);
341 }
342 }
343 });
344 }
345 else // z-faces
346 {
347 // Here do interpolation in the tangential directions
349 {
350 if (mask_arr(i,j,k) == mask_val) {
351 const int kk = amrex::coarsen(k,ratio[2]);
352 if (k-kk*ratio[2] == 0) {
354 }
355 }
356 });
357
358 // Here do interpolation in the normal direction
359 // using the fine values that have already been filled
361 {
362 if (mask_arr(i,j,k) == mask_val) {
363 const int kk = amrex::coarsen(k,ratio[2]);
364 if (k-kk*ratio[2] != 0) {
365 Real const w = static_cast<Real>(k-kk*ratio[2]) * (one/Real(ratio[2]));
366 fine_arr(i,j,k,0) = (one-w) * fine_arr(i,j,kk*ratio[2],0) + w * fine_arr(i,j,(kk+1)*ratio[2],0);
367 }
368 }
369 });
370 } // IndexType::NODE
371 } // MFiter
372}
373
374/**
375 * @param[inout] fine fine level data
376 * @param[in ] crse coarse level data
377 * @param[in ] bcr boundary condition type
378 * @param[in ] mask_val masked value
379 */
381 MultiFab const& crse,
382 Vector<BCRec> const& bcr,
383 int mask_val)
384{
385 int ncomp = m_ncomp;
386 IntVect ratio = m_ratio;
387 IndexType m_ixt = fine.boxArray().ixType();
388 Box const& cdomain = amrex::convert(m_cgeom.Domain(), m_ixt);
389
390 for (MFIter mfi(fine); mfi.isValid(); ++mfi) {
391 Box const& fbx = mfi.validbox();
392
393 Array4<Real> const& fine_arr = fine.array(mfi);
394 Array4<Real const> const& crse_arr = crse.const_array(mfi);
395 Array4<int const> const& mask_arr = m_cf_mask->const_array(mfi);
396
397 bool run_on_gpu = Gpu::inLaunchRegion();
398 amrex::ignore_unused(run_on_gpu);
399
400 amrex::ignore_unused(m_fgeom);
401
402 const Box& crse_region = m_interp->CoarseBox(fbx,ratio);
404 for (int dim = 0; dim < AMREX_SPACEDIM; dim++) {
405 if (ratio[dim] > 1) {
406 cslope_bx.grow(dim,-1);
407 }
408 }
409
411 Array4<Real> const& tmp = ccfab.array();
412 Array4<Real const> const& ctmp = ccfab.const_array();
413
414#ifdef AMREX_USE_GPU
416 BCRec const* bcrp = (run_on_gpu) ? async_bcr.data() : bcr.data();
417#else
418 BCRec const* bcrp = bcr.data();
419#endif
420
422 {
424 cdomain, ratio, bcrp);
425 });
426
428 {
430 crse_arr, 0, ncomp, ratio);
431 });
432 } // MFIter
433}
constexpr amrex::Real one
mf_h setVal(geomdata.ProbHi(2))
AMREX_ALWAYS_ASSERT(!NSPeriodic||!EWPeriodic)
amrex::InterpBase * m_interp
amrex::DistributionMapping m_fdm
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)
Redefine the coarse and fine patch MultiFabs.
void RegisterCoarseData(amrex::Vector< amrex::MultiFab const * > const &crse_data, amrex::Vector< amrex::Real > const &crse_time)
Register the coarse data to be used by the REMORAFillPatcher.
amrex::IntVect m_ratio
void InterpCell(amrex::MultiFab &fine, amrex::MultiFab const &crse, amrex::Vector< amrex::BCRec > const &bcr, int mask_val)
Interpolate to cell centers.
amrex::Geometry m_fgeom
REMORAFillPatcher(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)
Fill valid and ghost data with the "state data" at the given time.
amrex::BoxArray m_cba
amrex::BoxArray m_fba
amrex::Vector< amrex::Real > m_crse_times
void InterpFace(amrex::MultiFab &fine, amrex::MultiFab const &crse, int mask_val)
Interpolate to cell faces.
std::unique_ptr< amrex::MultiFab > m_cf_crse_data_new
void BuildMask(amrex::BoxArray const &fba, int nghost, int nghost_set)
Generate masking array.
amrex::DistributionMapping m_cdm
amrex::Geometry m_cgeom
std::unique_ptr< amrex::iMultiFab > m_cf_mask
std::unique_ptr< amrex::MultiFab > m_cf_crse_data_old