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 * @param[in] fba BoxArray of data to be filled at fine level
9 * @param[in] fdm DistributionMapping of data to be filled at fine level
10 * @param[in] fgeom container of geometry information at fine level
11 * @param[in] cba BoxArray of data to be filled at coarse level
12 * @param[in] cdm DistributionMapping of data to be filled at coarse level
13 * @param[in] cgeom container of geometry information at coarse level
14 * @param[in] nghost number of ghost cells to be filled
15 * @param[in] ncomp number of components to be filled
16 * @param[in] interp interpolation operator to be used
17 */
18
19REMORAFillPatcher::REMORAFillPatcher (BoxArray const& fba, DistributionMapping const& fdm,
20 Geometry const& fgeom,
21 BoxArray const& cba, DistributionMapping const& cdm,
22 Geometry const& cgeom,
23 int nghost, int nghost_set,
24 int ncomp, InterpBase* interp)
25 : m_fba(fba),
26 m_cba(cba),
27 m_fdm(fdm),
28 m_cdm(cdm),
29 m_fgeom(fgeom),
30 m_cgeom(cgeom)
31{
32 AMREX_ALWAYS_ASSERT(fba.ixType() == cba.ixType());
33
34 // Vector to hold times for coarse data
35 m_crse_times.resize(2);
36
37 // Define the coarse and fine MFs
38 Define(fba, fdm, fgeom, cba, cdm, cgeom,nghost, nghost_set, ncomp, interp);
39}
40
41
42/**
43 * @param[in] fba BoxArray of data to be filled at fine level
44 * @param[in] fdm DistributionMapping of data to be filled at fine level
45 * @param[in] fgeom container of geometry information at fine level
46 * @param[in] cba BoxArray of data to be filled at coarse level
47 * @param[in] cdm DistributionMapping of data to be filled at coarse level
48 * @param[in] cgeom container of geometry information at coarse level
49 * @param[in] nghost number of ghost cells to be filled
50 * @param[in] ncomp number of components to be filled
51 * @param[in] interp interpolation operator to be used
52 */
53void REMORAFillPatcher::Define (BoxArray const& fba, DistributionMapping const& fdm,
54 Geometry const& fgeom,
55 BoxArray const& cba, DistributionMapping const& cdm,
56 Geometry const& cgeom,
57 int nghost, int nghost_set,
58 int ncomp, InterpBase* interp)
59{
60 AMREX_ALWAYS_ASSERT(nghost <= 0);
61 AMREX_ALWAYS_ASSERT(nghost_set <= 0);
62 AMREX_ALWAYS_ASSERT(nghost <= nghost_set);
63
64 // Set data members
65 m_fba = fba; m_cba = cba;
66 m_fdm = fdm; m_cdm = cdm;
67 m_fgeom = fgeom; m_cgeom = cgeom;
68 m_nghost = nghost; m_nghost_subset = nghost_set;
69 m_ncomp = ncomp; m_interp = interp;
70
71 // Delete old MFs if they exist
74 if (m_cf_mask) m_cf_mask.reset();
75
76 // Index type for the BL/BA
77 IndexType m_ixt = fba.ixType();
78
79 // Refinement ratios
80 for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
81 m_ratio[idim] = m_fgeom.Domain().length(idim) / m_cgeom.Domain().length(idim);
82 }
83
84 // Coarse box list
85 // NOTE: if we use face_cons_linear_interp then CoarseBox returns the grown box
86 // so we don't need to manually grow it here
87 BoxList cbl;
88 cbl.set(m_ixt);
89 cbl.reserve(fba.size());
90 for (int i(0); i < fba.size(); ++i) {
91 Box coarse_box(interp->CoarseBox(fba[i], m_ratio));
92 cbl.push_back(coarse_box);
93 }
94
95 // Box arrays for the coarse data
96 BoxArray cf_cba(std::move(cbl));
97
98 // Two coarse patches to hold the data to be interpolated
99 m_cf_crse_data_old = std::make_unique<MultiFab> (cf_cba, fdm, m_ncomp, 0);
100 m_cf_crse_data_new = std::make_unique<MultiFab> (cf_cba, fdm, m_ncomp, 0);
101
102 // Integer masking array
103 m_cf_mask = std::make_unique<iMultiFab> (fba, fdm, 1, 0);
104
105 // Populate mask array
106 if (nghost_set <= 0) {
107 m_cf_mask->setVal(m_set_mask);
108 BuildMask(fba,nghost_set,m_set_mask-1);
109 } else {
110 m_cf_mask->setVal(m_relax_mask);
111 BuildMask(fba,nghost,m_relax_mask-1);
112 }
113}
114
115void REMORAFillPatcher::BuildMask (BoxArray const& fba,
116 int nghost,
117 int mask_val)
118{
119 // Minimal bounding box of fine BA plus a halo cell
120 Box fba_bnd = amrex::grow(fba.minimalBox(), IntVect(1,1,1));
121
122 // BoxList and BoxArray to store complement
123 BoxList com_bl; BoxArray com_ba;
124
125 // Compute the complement
126 fba.complementIn(com_bl,fba_bnd);
127
128 // com_bl cannot be null since we grew with halo cells
129 AMREX_ALWAYS_ASSERT(com_bl.size() > 0);
130
131 IntVect box_grow_vect(-nghost,-nghost,0);
132
133 // cf_set_width = cf_width = 0 is a special case
134 // In this case we set only the normal velocities
135 // (not any cell-centered quantities) and only
136 // on the coarse-fine boundary itself
137 if (nghost == 0) {
138 if (fba.ixType()[0] == IndexType::NODE) {
139 box_grow_vect = IntVect(1,0,0);
140 } else if (fba.ixType()[1] == IndexType::NODE) {
141 box_grow_vect = IntVect(0,1,0);
142 } else if (fba.ixType()[2] == IndexType::NODE) {
143 box_grow_vect = IntVect(0,0,1);
144 }
145 }
146
147 // Grow the complement boxes and trim with the bounding box
148 Vector<Box>& com_bl_v = com_bl.data();
149 for (int i(0); i<com_bl.size(); ++i) {
150 Box& bx = com_bl_v[i];
151 bx.grow(box_grow_vect);
152 bx &= fba_bnd;
153 }
154
155
156 // Do second complement with the grown boxes
157 com_ba.define(std::move(com_bl));
158 com_ba.complementIn(com_bl, fba_bnd);
159
160 // Fill mask based upon the com_bl BoxList
161 for (MFIter mfi(*m_cf_mask); mfi.isValid(); ++mfi) {
162 const Box& vbx = mfi.validbox();
163 const Array4<int>& mask_arr = m_cf_mask->array(mfi);
164
165 for (auto const& b : com_bl) {
166 Box com_bx = vbx & b;
167 ParallelFor(com_bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
168 {
169 mask_arr(i,j,k) = mask_val;
170 });
171 }
172 }
173}
174
175/*
176 * @param[in] crse_data data at old and new time at coarse level
177 * @param[in] crse_time times at which crse_data is defined
178 */
179
180void REMORAFillPatcher::RegisterCoarseData (Vector<MultiFab const*> const& crse_data,
181 Vector<Real> const& crse_time)
182{
183 AMREX_ALWAYS_ASSERT(crse_data.size() == 2); // old and new
184 AMREX_ALWAYS_ASSERT(crse_time[1] >= crse_time[0]);
185
186 // NOTE: CoarseBox with CellConsLinear interpolation grows the
187 // box by 1 in all directions. This pushes the domain for
188 // m_cf_crse_data into ghost cells in the z-dir. So we need
189 // to include ghost cells for crse_data when doing the copy
190 IntVect src_ng = crse_data[0]->nGrowVect();
191 IntVect dst_ng = m_cf_crse_data_old->nGrowVect();
192
193 m_cf_crse_data_old->ParallelCopy(*(crse_data[0]), 0, 0, m_ncomp,
194 src_ng, dst_ng, m_cgeom.periodicity()); // old data
195 m_cf_crse_data_new->ParallelCopy(*(crse_data[1]), 0, 0, m_ncomp,
196 src_ng, dst_ng, m_cgeom.periodicity()); // new data
197
198 m_crse_times[0] = crse_time[0]; // time of "old" coarse data
199 m_crse_times[1] = crse_time[1]; // time of "new" coarse data
200
201 m_dt_crse = crse_time[1] - crse_time[0];
202}
203
204/**
205 * @param[inout] fine fine level data
206 * @param[in ] crse coarse level data
207 * @param[in ] mask_val masked value
208 */
209void REMORAFillPatcher::InterpFace (MultiFab& fine,
210 MultiFab const& crse,
211 int mask_val)
212{
213 int ncomp = m_ncomp;
214 IntVect ratio = m_ratio;
215
216 FArrayBox slope;
217
218 //
219 // This box is only used to make sure we don't look outside
220 // the domain for computing the slopes in the interpolation
221 // We need it to be of the type of the faces being filled
222 //
223 // IndexType ixt = fine.boxArray().ixType();
224 // Box const& domface = amrex::convert(m_cgeom.Domain(), ixt);
225
226 // We don't need to worry about face-based domain because this is only used in the tangential interpolation
227 Box per_grown_domain = m_cgeom.Domain();
228 for (int dim = 0; dim < AMREX_SPACEDIM; dim++) {
229 if (m_cgeom.isPeriodic(dim)) {
230 per_grown_domain.grow(dim,1);
231 }
232 }
233
234 for (MFIter mfi(fine); mfi.isValid(); ++mfi)
235 {
236 Box const& fbx = mfi.validbox();
237
238 slope.resize(fbx,ncomp,The_Async_Arena());
239
240 Array4<Real> const& fine_arr = fine.array(mfi);
241 Array4<Real> const& slope_arr = slope.array();
242 Array4<Real const> const& crse_arr = crse.const_array(mfi);
243 Array4<int const> const& mask_arr = m_cf_mask->const_array(mfi);
244
245 if (fbx.type(0) == IndexType::NODE) // x-faces
246 {
247 // Here do interpolation in the tangential directions
248 AMREX_HOST_DEVICE_PARALLEL_FOR_3D_FLAG(RunOn::Gpu,fbx,i,j,k,
249 {
250 if (mask_arr(i,j,k) == mask_val) { // x-faces
251 const int ii = amrex::coarsen(i,ratio[0]);
252 if (i-ii*ratio[0] == 0) {
253 interp_face_reg(i,j,k,ratio,fine_arr,0,crse_arr,slope_arr,ncomp,per_grown_domain,0);
254 }
255 }
256 });
257
258 // Here do interpolation in the normal direction
259 // using the fine values that have already been filled
260 AMREX_HOST_DEVICE_PARALLEL_FOR_3D_FLAG(RunOn::Gpu,fbx,i,j,k,
261 {
262 if (mask_arr(i,j,k) == mask_val) {
263 const int ii = amrex::coarsen(i,ratio[0]);
264 if (i-ii*ratio[0] != 0) {
265 Real const w = static_cast<Real>(i-ii*ratio[0]) * (Real(1.)/Real(ratio[0]));
266 fine_arr(i,j,k,0) = (Real(1.)-w) * fine_arr(ii*ratio[0],j,k,0) + w * fine_arr((ii+1)*ratio[0],j,k,0);
267 }
268 }
269 });
270
271 }
272 else if (fbx.type(1) == IndexType::NODE) // y-faces
273 {
274 // Here do interpolation in the tangential directions
275 AMREX_HOST_DEVICE_PARALLEL_FOR_3D_FLAG(RunOn::Gpu,fbx,i,j,k,
276 {
277 if (mask_arr(i,j,k) == mask_val) {
278 const int jj = amrex::coarsen(j,ratio[1]);
279 if (j-jj*ratio[1] == 0) {
280 interp_face_reg(i,j,k,ratio,fine_arr,0,crse_arr,slope_arr,ncomp,per_grown_domain,1);
281 }
282 }
283 });
284
285 // Here do interpolation in the normal direction
286 // using the fine values that have already been filled
287 AMREX_HOST_DEVICE_PARALLEL_FOR_3D_FLAG(RunOn::Gpu,fbx,i,j,k,
288 {
289 if (mask_arr(i,j,k) == mask_val) {
290 const int jj = amrex::coarsen(j,ratio[1]);
291 if (j-jj*ratio[1] != 0) {
292 Real const w = static_cast<Real>(j-jj*ratio[1]) * (Real(1.)/Real(ratio[1]));
293 fine_arr(i,j,k,0) = (Real(1.)-w) * fine_arr(i,jj*ratio[1],k,0) + w * fine_arr(i,(jj+1)*ratio[1],k,0);
294 }
295 }
296 });
297 }
298 else // z-faces
299 {
300 // Here do interpolation in the tangential directions
301 AMREX_HOST_DEVICE_PARALLEL_FOR_3D_FLAG(RunOn::Gpu,fbx,i,j,k,
302 {
303 if (mask_arr(i,j,k) == mask_val) {
304 const int kk = amrex::coarsen(k,ratio[2]);
305 if (k-kk*ratio[2] == 0) {
306 interp_face_reg(i,j,k,ratio,fine_arr,0,crse_arr,slope_arr,1,per_grown_domain,2);
307 }
308 }
309 });
310
311 // Here do interpolation in the normal direction
312 // using the fine values that have already been filled
313 AMREX_HOST_DEVICE_PARALLEL_FOR_3D_FLAG(RunOn::Gpu,fbx,i,j,k,
314 {
315 if (mask_arr(i,j,k) == mask_val) {
316 const int kk = amrex::coarsen(k,ratio[2]);
317 if (k-kk*ratio[2] != 0) {
318 Real const w = static_cast<Real>(k-kk*ratio[2]) * (Real(1.)/Real(ratio[2]));
319 fine_arr(i,j,k,0) = (Real(1.)-w) * fine_arr(i,j,kk*ratio[2],0) + w * fine_arr(i,j,(kk+1)*ratio[2],0);
320 }
321 }
322 });
323 } // IndexType::NODE
324 } // MFiter
325}
326
327/**
328 * @param[inout] fine fine level data
329 * @param[in ] crse coarse level data
330 * @param[in ] bcr boundary condition type
331 * @param[in ] mask_val masked value
332 */
333void REMORAFillPatcher::InterpCell (MultiFab& fine,
334 MultiFab const& crse,
335 Vector<BCRec> const& bcr,
336 int mask_val)
337{
338 int ncomp = m_ncomp;
339 IntVect ratio = m_ratio;
340 IndexType m_ixt = fine.boxArray().ixType();
341 Box const& cdomain = amrex::convert(m_cgeom.Domain(), m_ixt);
342
343 for (MFIter mfi(fine); mfi.isValid(); ++mfi) {
344 Box const& fbx = mfi.validbox();
345
346 Array4<Real> const& fine_arr = fine.array(mfi);
347 Array4<Real const> const& crse_arr = crse.const_array(mfi);
348 Array4<int const> const& mask_arr = m_cf_mask->const_array(mfi);
349
350 bool run_on_gpu = Gpu::inLaunchRegion();
351 amrex::ignore_unused(run_on_gpu);
352
353 amrex::ignore_unused(m_fgeom);
354
355 const Box& crse_region = m_interp->CoarseBox(fbx,ratio);
356 Box cslope_bx(crse_region);
357 for (int dim = 0; dim < AMREX_SPACEDIM; dim++) {
358 if (ratio[dim] > 1) {
359 cslope_bx.grow(dim,-1);
360 }
361 }
362
363 FArrayBox ccfab(cslope_bx, ncomp*AMREX_SPACEDIM, The_Async_Arena());
364 Array4<Real> const& tmp = ccfab.array();
365 Array4<Real const> const& ctmp = ccfab.const_array();
366
367#ifdef AMREX_USE_GPU
368 AsyncArray<BCRec> async_bcr(bcr.data(), (run_on_gpu) ? ncomp : 0);
369 BCRec const* bcrp = (run_on_gpu) ? async_bcr.data() : bcr.data();
370#else
371 BCRec const* bcrp = bcr.data();
372#endif
373
374 AMREX_HOST_DEVICE_PARALLEL_FOR_4D_FLAG(RunOn::Gpu, cslope_bx, ncomp, i, j, k, n,
375 {
376 mf_cell_cons_lin_interp_mcslope(i,j,k,n, tmp, crse_arr, 0, ncomp,
377 cdomain, ratio, bcrp);
378 });
379
380 AMREX_HOST_DEVICE_PARALLEL_FOR_4D_FLAG(RunOn::Gpu, fbx, ncomp, i, j, k, n,
381 {
382 if (mask_arr(i,j,k) == mask_val) mf_cell_cons_lin_interp(i,j,k,n, fine_arr, 0, ctmp,
383 crse_arr, 0, ncomp, ratio);
384 });
385 } // MFIter
386}
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