Skip to content

Commit ebd9a11

Browse files
authored
Fix FillPatchNLevels (#4117)
This fixes periodic boundary bugs in FillPatchNLevels. The issue is FillPatchNLevels calls FillPatchTwoLevels, which does not work if the destination MultiFab's valid region is outside periodic boundaries. So we need to make sure that that does not happen by shifting the boxes into valid domain.
1 parent 74127d6 commit ebd9a11

File tree

2 files changed

+102
-36
lines changed

2 files changed

+102
-36
lines changed

Src/AmrCore/AMReX_FillPatchUtil.H

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
#include <cmath>
2626
#include <limits>
27+
#include <map>
2728

2829
namespace amrex
2930
{

Src/AmrCore/AMReX_FillPatchUtil_I.H

Lines changed: 101 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,61 @@ FillPatchNLevels (MF& mf, int level, const IntVect& nghost, Real time,
12231223
{
12241224
BL_PROFILE("FillPatchNLevels");
12251225

1226+
// FillPatchTwolevels relies on that mf's valid region is inside the
1227+
// domain at periodic boundaries. But when we create coarsen boxarray
1228+
// using mapper->CoarseBox, the resulting boxarray might violate the
1229+
// requirement. If that happens, we need to create a second version of
1230+
// the boxarray that is safe for FillPatchTwolevels.
1231+
1232+
auto get_clayout = [&] () -> std::tuple<BoxArray,BoxArray,DistributionMapping>
1233+
{
1234+
if (level == 0) {
1235+
return std::make_tuple(BoxArray(),BoxArray(),DistributionMapping());
1236+
} else {
1237+
BoxArray const& ba = mf.boxArray();
1238+
auto const& typ = ba.ixType();
1239+
std::map<int,Vector<Box>> extra_boxes_map;
1240+
BoxList cbl(typ);
1241+
cbl.reserve(ba.size());
1242+
for (int i = 0, N = int(ba.size()); i < N; ++i) {
1243+
Box const& cbox = mapper->CoarseBox(amrex::grow(ba[i],nghost),ratio[level-1]);
1244+
cbl.push_back(cbox);
1245+
Box gdomain = geom[level-1].growNonPeriodicDomain(cbox.length());
1246+
gdomain.convert(typ);
1247+
if (!gdomain.contains(cbox)) {
1248+
auto& extra_boxes = extra_boxes_map[i];
1249+
auto const& pshift = geom[level-1].periodicity().shiftIntVect();
1250+
for (auto const& piv : pshift) {
1251+
auto const& ibox = amrex::shift(cbox,piv) & gdomain;
1252+
if (ibox.ok()) {
1253+
extra_boxes.push_back(ibox);
1254+
}
1255+
}
1256+
}
1257+
}
1258+
1259+
BoxArray cba2;
1260+
DistributionMapping dm2;
1261+
if (!extra_boxes_map.empty()) {
1262+
BoxList cbl2 = cbl;
1263+
auto& lbox = cbl2.data();
1264+
DistributionMapping const& dm = mf.DistributionMap();
1265+
Vector<int> procmap2 = dm.ProcessorMap();
1266+
for (auto const& [i, vb] : extra_boxes_map) {
1267+
lbox[i] = vb[0];
1268+
for (int j = 1, nj = int(vb.size()); j < nj; ++j) {
1269+
lbox.push_back(vb[j]);
1270+
procmap2.push_back(dm[i]);
1271+
}
1272+
}
1273+
cba2 = BoxArray(std::move(cbl2));
1274+
dm2 = DistributionMapping(std::move(procmap2));
1275+
}
1276+
1277+
return std::make_tuple(BoxArray(std::move(cbl)), cba2, dm2);
1278+
}
1279+
};
1280+
12261281
#ifdef AMREX_USE_EB
12271282
EB2::IndexSpace const* index_space = EB2::TopIndexSpaceIfPresent();
12281283
#else
@@ -1235,35 +1290,40 @@ FillPatchNLevels (MF& mf, int level, const IntVect& nghost, Real time,
12351290
if (level == 0) {
12361291
FillPatchSingleLevel(mf, nghost, time, smf[0], st[0], scomp, dcomp, ncomp, geom[0],
12371292
bc[0], bccomp);
1238-
} else if (level >= int(smf.size())) {
1239-
BoxArray const& ba = mf.boxArray();
1240-
auto const& typ = ba.ixType();
1241-
Box domain_g = geom[level].growPeriodicDomain(nghost);
1242-
domain_g.convert(typ);
1243-
BoxArray cba;
1244-
{
1245-
BoxList cbl(typ);
1246-
cbl.reserve(ba.size());
1247-
for (int i = 0, N = int(ba.size()); i < N; ++i) {
1248-
cbl.push_back(mapper->CoarseBox(amrex::grow(ba[i],nghost), ratio[level-1]));
1249-
}
1250-
cba = BoxArray(std::move(cbl));
1251-
}
1252-
MultiFab cmf_tmp;
1293+
} else if (level >= int(smf.size()))
1294+
{
1295+
auto const& [ba1, ba2, dm2] = get_clayout();
1296+
MF cmf1, cmf2;
12531297
#ifdef AMREX_USE_EB
12541298
if (index_space) {
1255-
auto factory = makeEBFabFactory(index_space, geom[level-1], cba,
1299+
auto factory = makeEBFabFactory(index_space, geom[level-1], ba1,
12561300
mf.DistributionMap(), {0,0,0},
12571301
EBSupport::basic);
1258-
cmf_tmp.define(cba, mf.DistributionMap(), ncomp, 0, MFInfo(), *factory);
1302+
cmf1.define(ba1, mf.DistributionMap(), ncomp, 0, MFInfo(), *factory);
1303+
if (!ba2.empty()) {
1304+
auto factory2 = makeEBFabFactory(index_space, geom[level-1], ba2,
1305+
dm2, {0,0,0},
1306+
EBSupport::basic);
1307+
cmf2.define(ba2, dm2, ncomp, 0, MFInfo(), *factory2);
1308+
}
12591309
} else
12601310
#endif
12611311
{
1262-
cmf_tmp.define(cba, mf.DistributionMap(), ncomp, 0);
1312+
cmf1.define(ba1, mf.DistributionMap(), ncomp, 0);
1313+
if (!ba2.empty()) {
1314+
cmf2.define(ba2, dm2, ncomp, 0);
1315+
}
12631316
}
1264-
FillPatchNLevels(cmf_tmp, level-1, IntVect(0), time, smf, st, scomp, 0, ncomp,
1317+
1318+
MF* p_mf_inside = (ba2.empty()) ? &cmf1 : &cmf2;
1319+
FillPatchNLevels(*p_mf_inside, level-1, IntVect(0), time, smf, st, scomp, 0, ncomp,
12651320
geom, bc, bccomp, ratio, mapper, bcr, bcrcomp);
1266-
FillPatchInterp(mf, dcomp, cmf_tmp, 0, ncomp, nghost, geom[level-1], geom[level],
1321+
if (&cmf1 != p_mf_inside) {
1322+
cmf1.ParallelCopy(*p_mf_inside, geom[level-1].periodicity());
1323+
}
1324+
Box domain_g = geom[level].growPeriodicDomain(nghost);
1325+
domain_g.convert(mf.ixType());
1326+
FillPatchInterp(mf, dcomp, cmf1, 0, ncomp, nghost, geom[level-1], geom[level],
12671327
domain_g, ratio[level-1], mapper, bcr, bcrcomp);
12681328
} else {
12691329
NullInterpHook<typename MF::FABType::value_type> hook{};
@@ -1278,30 +1338,34 @@ FillPatchNLevels (MF& mf, int level, const IntVect& nghost, Real time,
12781338
hook, hook, index_space, true);
12791339
if (error_code == 0) { return; }
12801340

1281-
BoxArray cba;
1282-
{
1283-
BoxArray const& ba = mf.boxArray();
1284-
BoxList cbl(mf.ixType());
1285-
cbl.reserve(ba.size());
1286-
for (int i = 0; i < int(ba.size()); ++i) {
1287-
cbl.push_back(mapper->CoarseBox(amrex::grow(ba[i], nghost), ratio[level-1]));
1288-
}
1289-
cba = BoxArray(std::move(cbl));
1290-
}
1291-
MultiFab cmf_tmp;
1341+
auto const& [ba1, ba2, dm2] = get_clayout();
1342+
MF cmf_tmp;
12921343
#ifdef AMREX_USE_EB
12931344
if (index_space) {
1294-
auto factory = makeEBFabFactory(index_space, geom[level-1], cba,
1295-
mf.DistributionMap(), {0,0,0},
1296-
EBSupport::basic);
1297-
cmf_tmp.define(cba, mf.DistributionMap(), ncomp, 0, MFInfo(), *factory);
1345+
if (ba2.empty()) {
1346+
auto factory = makeEBFabFactory(index_space, geom[level-1], ba1,
1347+
mf.DistributionMap(), {0,0,0},
1348+
EBSupport::basic);
1349+
cmf_tmp.define(ba1, mf.DistributionMap(), ncomp, 0, MFInfo(), *factory);
1350+
} else {
1351+
auto factory = makeEBFabFactory(index_space, geom[level-1], ba2,
1352+
dm2, {0,0,0},
1353+
EBSupport::basic);
1354+
cmf_tmp.define(ba2, dm2, ncomp, 0, MFInfo(), *factory);
1355+
}
12981356
} else
12991357
#endif
13001358
{
1301-
cmf_tmp.define(cba, mf.DistributionMap(), ncomp, 0);
1359+
if (ba2.empty()) {
1360+
cmf_tmp.define(ba1, mf.DistributionMap(), ncomp, 0);
1361+
} else {
1362+
cmf_tmp.define(ba2, dm2, ncomp, 0);
1363+
}
13021364
}
1365+
13031366
FillPatchNLevels(cmf_tmp, level-1, IntVect(0), time, smf, st, scomp, 0, ncomp,
13041367
geom, bc, bccomp, ratio, mapper, bcr, bcrcomp);
1368+
13051369
Vector<MF*> cmf{&cmf_tmp};
13061370
Vector<MF*> fmf = smf[level];
13071371
Vector<MF> fmf_raii;
@@ -1310,6 +1374,7 @@ FillPatchNLevels (MF& mf, int level, const IntVect& nghost, Real time,
13101374
fmf_raii.emplace_back(*p, amrex::make_alias, scomp, ncomp);
13111375
}
13121376
}
1377+
13131378
detail::FillPatchTwoLevels_doit(mf, nghost, time,
13141379
cmf, {time},
13151380
fmf, st[level],

0 commit comments

Comments
 (0)