@@ -1223,6 +1223,61 @@ FillPatchNLevels (MF& mf, int level, const IntVect& nghost, Real time,
1223
1223
{
1224
1224
BL_PROFILE (" FillPatchNLevels" );
1225
1225
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
+
1226
1281
#ifdef AMREX_USE_EB
1227
1282
EB2::IndexSpace const * index_space = EB2::TopIndexSpaceIfPresent ();
1228
1283
#else
@@ -1235,35 +1290,40 @@ FillPatchNLevels (MF& mf, int level, const IntVect& nghost, Real time,
1235
1290
if (level == 0 ) {
1236
1291
FillPatchSingleLevel (mf, nghost, time , smf[0 ], st[0 ], scomp, dcomp, ncomp, geom[0 ],
1237
1292
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;
1253
1297
#ifdef AMREX_USE_EB
1254
1298
if (index_space) {
1255
- auto factory = makeEBFabFactory (index_space, geom[level-1 ], cba ,
1299
+ auto factory = makeEBFabFactory (index_space, geom[level-1 ], ba1 ,
1256
1300
mf.DistributionMap (), {0 ,0 ,0 },
1257
1301
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
+ }
1259
1309
} else
1260
1310
#endif
1261
1311
{
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
+ }
1263
1316
}
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,
1265
1320
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],
1267
1327
domain_g, ratio[level-1 ], mapper, bcr, bcrcomp);
1268
1328
} else {
1269
1329
NullInterpHook<typename MF::FABType::value_type> hook{};
@@ -1278,30 +1338,34 @@ FillPatchNLevels (MF& mf, int level, const IntVect& nghost, Real time,
1278
1338
hook, hook, index_space, true );
1279
1339
if (error_code == 0 ) { return ; }
1280
1340
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;
1292
1343
#ifdef AMREX_USE_EB
1293
1344
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
+ }
1298
1356
} else
1299
1357
#endif
1300
1358
{
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
+ }
1302
1364
}
1365
+
1303
1366
FillPatchNLevels (cmf_tmp, level-1 , IntVect (0 ), time , smf, st, scomp, 0 , ncomp,
1304
1367
geom, bc, bccomp, ratio, mapper, bcr, bcrcomp);
1368
+
1305
1369
Vector<MF*> cmf{&cmf_tmp};
1306
1370
Vector<MF*> fmf = smf[level];
1307
1371
Vector<MF> fmf_raii;
@@ -1310,6 +1374,7 @@ FillPatchNLevels (MF& mf, int level, const IntVect& nghost, Real time,
1310
1374
fmf_raii.emplace_back (*p, amrex::make_alias, scomp, ncomp);
1311
1375
}
1312
1376
}
1377
+
1313
1378
detail::FillPatchTwoLevels_doit (mf, nghost, time ,
1314
1379
cmf, {time },
1315
1380
fmf, st[level],
0 commit comments