LCOV - code coverage report
Current view: top level - ext/amrex/2d-coverage-g++-24.08/include - AMReX_FillPatchUtil_I.H (source / functions) Hit Total Coverage
Test: coverage_merged.info Lines: 101 201 50.2 %
Date: 2024-11-18 05:28:54 Functions: 52 303 17.2 %

          Line data    Source code
       1             : #ifndef AMREX_FillPatchUtil_I_H_
       2             : #define AMREX_FillPatchUtil_I_H_
       3             : #include <AMReX_Config.H>
       4             : 
       5             : namespace amrex {
       6             : 
       7             : namespace detail {
       8             : 
       9             : template <typename F, typename MF>
      10      426450 : auto call_interp_hook (F const& f, MF& mf, int icomp, int ncomp)
      11             :     -> decltype(f(mf[0],Box(),icomp,ncomp))
      12             : {
      13             : #ifdef AMREX_USE_OMP
      14             : #pragma omp parallel if (Gpu::notInLaunchRegion())
      15             : #endif
      16     2752973 :     for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
      17     2326526 :         auto& dfab = mf[mfi];
      18     2326526 :         const Box& dbx = dfab.box();
      19     2326526 :         f(dfab, dbx, icomp, ncomp);
      20             :     }
      21      426450 : }
      22             : 
      23             : template <typename F, typename MF>
      24             : auto call_interp_hook (F const& f, MF& mf, int icomp, int ncomp)
      25             :     -> decltype(f(mf,icomp,ncomp))
      26             : {
      27             :     f(mf, icomp, ncomp);
      28             : }
      29             : 
      30             : }
      31             : 
      32             : template <typename Interp>
      33             : bool ProperlyNested (const IntVect& ratio, const IntVect& blocking_factor, int ngrow,
      34             :                      const IndexType& boxType, Interp* mapper)
      35             : {
      36             :     int ratio_max = ratio[0];
      37             : #if (AMREX_SPACEDIM > 1)
      38             :     ratio_max = std::max(ratio_max, ratio[1]);
      39             : #endif
      40             : #if (AMREX_SPACEDIM == 3)
      41             :     ratio_max = std::max(ratio_max, ratio[2]);
      42             : #endif
      43             :     // There are at least this many coarse cells outside fine grids
      44             :     // (except at physical boundaries).
      45             :     const IntVect& nbuf = blocking_factor / ratio_max;
      46             : 
      47             :     Box crse_box(IntVect(AMREX_D_DECL(0 ,0 ,0 )), IntVect(AMREX_D_DECL(4*nbuf[0]-1,
      48             :                                                                        4*nbuf[1]-1,
      49             :                                                                        4*nbuf[2]-1)));
      50             :     crse_box.convert(boxType);
      51             :     Box fine_box(nbuf, IntVect(AMREX_D_DECL(3*nbuf[0]-1,3*nbuf[1]-1,3*nbuf[2]-1)));
      52             :     fine_box.convert(boxType);
      53             :     fine_box.refine(ratio_max);
      54             :     fine_box.grow(ngrow);
      55             :     const Box& fine_box_coarsened = mapper->CoarseBox(fine_box, ratio_max);
      56             :     return crse_box.contains(fine_box_coarsened);
      57             : }
      58             : 
      59             : template <typename MF, typename BC>
      60             : std::enable_if_t<IsFabArray<MF>::value>
      61      217374 : FillPatchSingleLevel (MF& mf, Real time,
      62             :                       const Vector<MF*>& smf, const Vector<Real>& stime,
      63             :                       int scomp, int dcomp, int ncomp,
      64             :                       const Geometry& geom,
      65             :                       BC& physbcf, int bcfcomp)
      66             : {
      67      217374 :     FillPatchSingleLevel(mf, mf.nGrowVect(), time, smf, stime, scomp, dcomp, ncomp,
      68             :                          geom, physbcf, bcfcomp);
      69      217374 : }
      70             : 
      71             : template <typename MF, typename BC>
      72             : std::enable_if_t<IsFabArray<MF>::value>
      73      430982 : FillPatchSingleLevel (MF& mf, IntVect const& nghost, Real time,
      74             :                       const Vector<MF*>& smf, const Vector<Real>& stime,
      75             :                       int scomp, int dcomp, int ncomp,
      76             :                       const Geometry& geom,
      77             :                       BC& physbcf, int bcfcomp)
      78             : {
      79             :     BL_PROFILE("FillPatchSingleLevel");
      80             : 
      81             :     AMREX_ASSERT(scomp+ncomp <= smf[0]->nComp());
      82             :     AMREX_ASSERT(dcomp+ncomp <= mf.nComp());
      83             :     AMREX_ASSERT(smf.size() == stime.size());
      84             :     AMREX_ASSERT(!smf.empty());
      85             :     AMREX_ASSERT(nghost.allLE(mf.nGrowVect()));
      86             : 
      87      430982 :     if (smf.size() == 1)
      88             :     {
      89      430982 :         if (&mf == smf[0] && scomp == dcomp) {
      90      216914 :             mf.FillBoundary(dcomp, ncomp, nghost, geom.periodicity());
      91             :         } else {
      92      214068 :             mf.ParallelCopy(*smf[0], scomp, dcomp, ncomp, IntVect{0}, nghost, geom.periodicity());
      93             :         }
      94             :     }
      95           0 :     else if (smf.size() == 2)
      96             :     {
      97             :         BL_ASSERT(smf[0]->boxArray() == smf[1]->boxArray());
      98           0 :         MF raii;
      99             :         MF * dmf;
     100             :         int destcomp;
     101             :         bool sameba;
     102           0 :         if (mf.boxArray() == smf[0]->boxArray() &&
     103           0 :             mf.DistributionMap() == smf[0]->DistributionMap())
     104             :         {
     105           0 :             dmf = &mf;
     106           0 :             destcomp = dcomp;
     107           0 :             sameba = true;
     108             :         } else {
     109           0 :             raii.define(smf[0]->boxArray(), smf[0]->DistributionMap(), ncomp, 0,
     110           0 :                         MFInfo(), smf[0]->Factory());
     111             : 
     112           0 :             dmf = &raii;
     113           0 :             destcomp = 0;
     114           0 :             sameba = false;
     115             :         }
     116             : 
     117           0 :         if ((dmf != smf[0] && dmf != smf[1]) || scomp != dcomp)
     118             :         {
     119             : #ifdef AMREX_USE_OMP
     120             : #pragma omp parallel if (Gpu::notInLaunchRegion())
     121             : #endif
     122           0 :             for (MFIter mfi(*dmf,TilingIfNotGPU()); mfi.isValid(); ++mfi)
     123             :             {
     124           0 :                 const Box& bx = mfi.tilebox();
     125           0 :                 const Real t0 = stime[0];
     126           0 :                 const Real t1 = stime[1];
     127           0 :                 auto const sfab0 = smf[0]->array(mfi);
     128           0 :                 auto const sfab1 = smf[1]->array(mfi);
     129           0 :                 auto       dfab  = dmf->array(mfi);
     130             : 
     131           0 :                 if (time == t0)
     132             :                 {
     133           0 :                     AMREX_HOST_DEVICE_PARALLEL_FOR_4D ( bx, ncomp, i, j, k, n,
     134             :                     {
     135             :                         dfab(i,j,k,n+destcomp) = sfab0(i,j,k,n+scomp);
     136             :                     });
     137             :                 }
     138           0 :                 else if (time == t1)
     139             :                 {
     140           0 :                     AMREX_HOST_DEVICE_PARALLEL_FOR_4D ( bx, ncomp, i, j, k, n,
     141             :                     {
     142             :                         dfab(i,j,k,n+destcomp) = sfab1(i,j,k,n+scomp);
     143             :                     });
     144             :                 }
     145           0 :                 else if (! amrex::almostEqual(t0,t1))
     146             :                 {
     147           0 :                     Real alpha = (t1-time)/(t1-t0);
     148           0 :                     Real beta = (time-t0)/(t1-t0);
     149           0 :                     AMREX_HOST_DEVICE_PARALLEL_FOR_4D ( bx, ncomp, i, j, k, n,
     150             :                     {
     151             :                         dfab(i,j,k,n+destcomp) = alpha*sfab0(i,j,k,n+scomp)
     152             :                             +                     beta*sfab1(i,j,k,n+scomp);
     153             :                     });
     154             :                 }
     155             :                 else
     156             :                 {
     157           0 :                     AMREX_HOST_DEVICE_PARALLEL_FOR_4D ( bx, ncomp, i, j, k, n,
     158             :                     {
     159             :                         dfab(i,j,k,n+destcomp) = sfab0(i,j,k,n+scomp);
     160             :                     });
     161             :                 }
     162             :             }
     163             :         }
     164             : 
     165           0 :         if (sameba)
     166             :         {
     167             :             // Note that when sameba is true mf's BoxArray is nonoverlapping.
     168             :             // So FillBoundary is safe.
     169           0 :             mf.FillBoundary(dcomp, ncomp, nghost, geom.periodicity());
     170             :         }
     171             :         else
     172             :         {
     173           0 :             IntVect src_ngrow = IntVect::TheZeroVector();
     174           0 :             IntVect dst_ngrow = nghost;
     175             : 
     176           0 :             mf.ParallelCopy(*dmf, 0, dcomp, ncomp, src_ngrow, dst_ngrow, geom.periodicity());
     177             :         }
     178             :     }
     179             :     else {
     180             :         amrex::Abort("FillPatchSingleLevel: high-order interpolation in time not implemented yet");
     181             :     }
     182             : 
     183      430982 :     physbcf(mf, dcomp, ncomp, nghost, time, bcfcomp);
     184      430982 : }
     185             : 
     186             : void FillPatchInterp (MultiFab& mf_fine_patch, int fcomp, MultiFab const& mf_crse_patch, int ccomp,
     187             :                       int ncomp, IntVect const& ng, const Geometry& cgeom, const Geometry& fgeom,
     188             :                       Box const& dest_domain, const IntVect& ratio,
     189             :                       MFInterpolater* mapper, const Vector<BCRec>& bcs, int bcscomp);
     190             : 
     191             : template <typename MF, typename Interp>
     192             : std::enable_if_t<IsFabArray<MF>::value && !std::is_same_v<Interp,MFInterpolater>>
     193      213242 : FillPatchInterp (MF& mf_fine_patch, int fcomp, MF const& mf_crse_patch, int ccomp,
     194             :                  int ncomp, IntVect const& ng, const Geometry& cgeom, const Geometry& fgeom,
     195             :                  Box const& dest_domain, const IntVect& ratio,
     196             :                  Interp* mapper, const Vector<BCRec>& bcs, int bcscomp)
     197             : {
     198             :     BL_PROFILE("FillPatchInterp(Fab)");
     199             : 
     200      213242 :     Box const& cdomain = amrex::convert(cgeom.Domain(), mf_fine_patch.ixType());
     201      213242 :     int idummy=0;
     202             : #ifdef AMREX_USE_OMP
     203             : #pragma omp parallel if (Gpu::notInLaunchRegion())
     204             : #endif
     205             :     {
     206      426484 :         Vector<BCRec> bcr(ncomp);
     207     1376663 :         for (MFIter mfi(mf_fine_patch); mfi.isValid(); ++mfi)
     208             :         {
     209     1163421 :             auto& sfab = mf_crse_patch[mfi];
     210     1163421 :             const Box& sbx = sfab.box();
     211             : 
     212     1163421 :             auto& dfab = mf_fine_patch[mfi];
     213     2326842 :             Box const& dbx = amrex::grow(mfi.validbox(),ng) & dest_domain;
     214             : 
     215     1163421 :             amrex::setBC(sbx,cdomain,bcscomp,0,ncomp,bcs,bcr);
     216     1163421 :             mapper->interp(sfab, ccomp, dfab, fcomp, ncomp, dbx, ratio,
     217             :                            cgeom, fgeom, bcr, idummy, idummy, RunOn::Gpu);
     218             :         }
     219             :     }
     220      213242 : }
     221             : 
     222             : template <typename MF>
     223             : std::enable_if_t<IsFabArray<MF>::value>
     224             : FillPatchInterp (MF& mf_fine_patch, int fcomp, MF const& mf_crse_patch, int ccomp,
     225             :                  int ncomp, IntVect const& ng, const Geometry& cgeom, const Geometry& fgeom,
     226             :                  Box const& dest_domain, const IntVect& ratio,
     227             :                  InterpBase* mapper, const Vector<BCRec>& bcs, int bcscomp)
     228             : {
     229             :     if (dynamic_cast<MFInterpolater*>(mapper)) {
     230             :         FillPatchInterp(mf_fine_patch, fcomp, mf_crse_patch, ccomp,
     231             :                         ncomp, ng, cgeom, fgeom, dest_domain, ratio,
     232             :                         static_cast<MFInterpolater*>(mapper), bcs, bcscomp);
     233             :     } else if (dynamic_cast<Interpolater*>(mapper)) {
     234             :         FillPatchInterp(mf_fine_patch, fcomp, mf_crse_patch, ccomp,
     235             :                         ncomp, ng, cgeom, fgeom, dest_domain, ratio,
     236             :                         static_cast<Interpolater*>(mapper), bcs, bcscomp);
     237             :     } else {
     238             :         amrex::Abort("FillPatchInterp: unknown InterpBase");
     239             :     }
     240             : }
     241             : 
     242             : template <typename MF, typename iMF, typename Interp>
     243             : std::enable_if_t<IsFabArray<MF>::value  && !std::is_same_v<Interp,MFInterpolater>>
     244           0 : InterpFace (Interp *interp,
     245             :             MF const& mf_crse_patch,    int crse_comp,
     246             :             MF&       mf_refined_patch, int fine_comp,
     247             :             int ncomp, const IntVect&   ratio,
     248             :             const iMF& solve_mask, const Geometry&  crse_geom, const Geometry&  fine_geom,
     249             :             int bcscomp, RunOn gpu_or_cpu,
     250             :             const Vector<BCRec>& bcs)
     251             : {
     252           0 :     Vector<BCRec> bcr(ncomp);
     253           0 :     Box const& cdomain = amrex::convert(crse_geom.Domain(), mf_crse_patch.ixType());
     254           0 :     for (MFIter mfi(mf_refined_patch);mfi.isValid(); ++mfi)
     255             :     {
     256           0 :         auto& sfab = mf_crse_patch[mfi];
     257           0 :         const Box& sbx = sfab.box();
     258           0 :         auto& dfab = mf_refined_patch[mfi];
     259           0 :         Box const& dbx = dfab.box();
     260           0 :         auto& ifab = solve_mask[mfi];
     261           0 :         amrex::setBC(sbx,cdomain,bcscomp,0,ncomp,bcs,bcr);
     262           0 :         interp->interp_face(sfab,crse_comp,dfab,fine_comp,ncomp,
     263             :                             dbx, ratio, ifab, crse_geom, fine_geom,
     264             :                             bcr, bcscomp, gpu_or_cpu);
     265             :     }
     266           0 : }
     267             : 
     268             : template <typename MF, typename iMF>
     269             : std::enable_if_t<IsFabArray<MF>::value>
     270             : InterpFace (InterpBase *interp,
     271             :             MF const& mf_crse_patch,    int crse_comp,
     272             :             MF&       mf_refined_patch, int fine_comp,
     273             :             int ncomp, const IntVect&   ratio,
     274             :             const iMF& solve_mask, const Geometry&  crse_geom, const Geometry&  fine_geom,
     275             :             int bccomp, RunOn gpu_or_cpu,
     276             :             const Vector<BCRec>& bcs)
     277             : {
     278             :     if (dynamic_cast<MFInterpolater*>(interp)){
     279             :         InterpFace(static_cast<MFInterpolater*>(interp),
     280             :                     mf_crse_patch, crse_comp,mf_refined_patch, fine_comp,
     281             :                     ncomp, ratio, solve_mask, crse_geom, fine_geom, bccomp,
     282             :                     gpu_or_cpu, bcs);
     283             :     }
     284             :     else if (dynamic_cast<Interpolater*>(interp)){
     285             :         InterpFace(static_cast<Interpolater*>(interp),
     286             :                     mf_crse_patch, crse_comp,mf_refined_patch, fine_comp,
     287             :                     ncomp, ratio, solve_mask, crse_geom, fine_geom, bccomp,
     288             :                     gpu_or_cpu, bcs);
     289             :     }
     290             :     else {
     291             :         amrex::Abort("InterpFace: unknown InterpBase");
     292             :     }
     293             : }
     294             : 
     295             : 
     296             : namespace detail {
     297             : 
     298             : // ======== FArrayBox
     299             : 
     300             :     template <typename MF,
     301             :               std::enable_if_t<std::is_same_v<typename MF::FABType::value_type,
     302             :                                                    FArrayBox>,
     303             :                                       int> = 0>
     304      213203 :     MF make_mf_crse_patch (FabArrayBase::FPinfo const& fpc, int ncomp)
     305             :     {
     306      213203 :         MF mf_crse_patch(fpc.ba_crse_patch, fpc.dm_patch, ncomp, 0, MFInfo(),
     307      213203 :                          *fpc.fact_crse_patch);
     308      213203 :         return mf_crse_patch;
     309             :     }
     310             : 
     311             :     template <typename MF,
     312             :               std::enable_if_t<std::is_same_v<typename MF::FABType::value_type,
     313             :                                                    FArrayBox>,
     314             :                                       int> = 0>
     315           0 :     MF make_mf_crse_patch (FabArrayBase::FPinfo const& fpc, int ncomp, IndexType idx_type)
     316             :     {
     317           0 :         MF mf_crse_patch(amrex::convert(fpc.ba_crse_patch, idx_type), fpc.dm_patch,
     318           0 :                          ncomp, 0, MFInfo(), *fpc.fact_crse_patch);
     319           0 :         return mf_crse_patch;
     320             :     }
     321             : 
     322             :     template <typename MF,
     323             :               std::enable_if_t<std::is_same_v<typename MF::FABType::value_type,
     324             :                                                    FArrayBox>,
     325             :                                       int> = 0>
     326      213203 :     MF make_mf_fine_patch (FabArrayBase::FPinfo const& fpc, int ncomp)
     327             :     {
     328      213203 :         MF mf_fine_patch(fpc.ba_fine_patch, fpc.dm_patch, ncomp, 0, MFInfo(),
     329      213203 :                          *fpc.fact_fine_patch);
     330      213203 :         return mf_fine_patch;
     331             :     }
     332             : 
     333             :     template <typename MF,
     334             :               std::enable_if_t<std::is_same_v<typename MF::FABType::value_type,
     335             :                                                    FArrayBox>,
     336             :                                       int> = 0>
     337             :     MF make_mf_fine_patch (FabArrayBase::FPinfo const& fpc, int ncomp, IndexType idx_type)
     338             :     {
     339             :         MF mf_fine_patch(amrex::convert(fpc.ba_fine_patch, idx_type), fpc.dm_patch,
     340             :                          ncomp, 0, MFInfo(), *fpc.fact_fine_patch);
     341             :         return mf_fine_patch;
     342             :     }
     343             : 
     344             :     template <typename MF,
     345             :               std::enable_if_t<std::is_same_v<typename MF::FABType::value_type,
     346             :                                                    FArrayBox>,
     347             :                                       int> = 0>
     348           0 :     MF make_mf_refined_patch (FabArrayBase::FPinfo const& fpc, int ncomp, IndexType idx_type, IntVect ratio)
     349             :     {
     350           0 :         MF mf_refined_patch(amrex::convert( amrex::refine( amrex::coarsen(fpc.ba_fine_patch, ratio), ratio), idx_type),
     351           0 :                             fpc.dm_patch, ncomp, 0, MFInfo(), *fpc.fact_fine_patch);
     352           0 :         return mf_refined_patch;
     353             :     }
     354             : 
     355             :     template <typename MF,
     356             :               std::enable_if_t<std::is_same_v<typename MF::FABType::value_type,
     357             :                                                    FArrayBox>,
     358             :                                       int> = 0>
     359             :     MF make_mf_crse_mask (FabArrayBase::FPinfo const& fpc, int ncomp, IndexType idx_type, IntVect ratio)
     360             :     {
     361             :         MF mf_crse_mask(amrex::convert(amrex::coarsen(fpc.ba_fine_patch, ratio), idx_type),
     362             :                         fpc.dm_patch, ncomp, 0, MFInfo(), *fpc.fact_fine_patch);
     363             :         return mf_crse_mask;
     364             :     }
     365             : 
     366             :     template <typename MF,
     367             :               std::enable_if_t<std::is_same_v<typename MF::FABType::value_type,
     368             :                                                    FArrayBox>,
     369             :                                       int> = 0>
     370      213210 :     void mf_set_domain_bndry (MF &mf, Geometry const & geom)
     371             :     {
     372      213210 :         mf.setDomainBndry(std::numeric_limits<Real>::quiet_NaN(), geom);
     373      213210 :     }
     374             : 
     375             : 
     376             : // ======== Not FArrayBox
     377             : 
     378             :     template <typename MF,
     379             :               std::enable_if_t<!std::is_same_v<typename MF::FABType::value_type,
     380             :                                                     FArrayBox>,
     381             :                                       int> = 0>
     382           5 :     MF make_mf_crse_patch (FabArrayBase::FPinfo const& fpc, int ncomp)
     383             :     {
     384           5 :         return MF(fpc.ba_crse_patch, fpc.dm_patch, ncomp, 0);
     385             :     }
     386             : 
     387             :     template <typename MF,
     388             :               std::enable_if_t<!std::is_same_v<typename MF::FABType::value_type,
     389             :                                                     FArrayBox>,
     390             :                                       int> = 0>
     391           0 :     MF make_mf_crse_patch (FabArrayBase::FPinfo const& fpc, int ncomp, IndexType idx_type)
     392             :     {
     393           0 :         return MF(amrex::convert(fpc.ba_crse_patch, idx_type), fpc.dm_patch, ncomp, 0);
     394             :     }
     395             : 
     396             :     template <typename MF,
     397             :               std::enable_if_t<!std::is_same_v<typename MF::FABType::value_type,
     398             :                                                     FArrayBox>,
     399             :                                       int> = 0>
     400           5 :     MF make_mf_fine_patch (FabArrayBase::FPinfo const& fpc, int ncomp)
     401             :     {
     402           5 :         return MF(fpc.ba_fine_patch, fpc.dm_patch, ncomp, 0);
     403             :     }
     404             : 
     405             :     template <typename MF,
     406             :               std::enable_if_t<!std::is_same_v<typename MF::FABType::value_type,
     407             :                                                     FArrayBox>,
     408             :                                       int> = 0>
     409             :     MF make_mf_fine_patch (FabArrayBase::FPinfo const& fpc, int ncomp, IndexType idx_type)
     410             :     {
     411             :         return MF(amrex::convert(fpc.ba_fine_patch, idx_type), fpc.dm_patch, ncomp, 0);
     412             :     }
     413             : 
     414             :     template <typename MF,
     415             :               std::enable_if_t<!std::is_same_v<typename MF::FABType::value_type,
     416             :                                                    FArrayBox>,
     417             :                                       int> = 0>
     418           0 :     MF make_mf_refined_patch (FabArrayBase::FPinfo const& fpc, int ncomp, IndexType idx_type, IntVect ratio)
     419             :     {
     420           0 :         return MF(amrex::convert( amrex::refine( amrex::coarsen(fpc.ba_fine_patch, ratio), ratio), idx_type), fpc.dm_patch, ncomp, 0);
     421             :     }
     422             : 
     423             :     template <typename MF,
     424             :               std::enable_if_t<!std::is_same_v<typename MF::FABType::value_type,
     425             :                                                    FArrayBox>,
     426             :                                       int> = 0>
     427           0 :     MF make_mf_crse_mask (FabArrayBase::FPinfo const& fpc, int ncomp, IndexType idx_type, IntVect ratio)
     428             :     {
     429           0 :         return MF(amrex::convert(amrex::coarsen(fpc.ba_fine_patch, ratio), idx_type), fpc.dm_patch, ncomp, 0);
     430             :     }
     431             : 
     432             :     template <typename MF,
     433             :               std::enable_if_t<!std::is_same_v<typename MF::FABType::value_type,
     434             :                                                     FArrayBox>,
     435             :                                       int> = 0>
     436          32 :     void mf_set_domain_bndry (MF &/*mf*/, Geometry const & /*geom*/)
     437             :     {
     438             :         // nothing
     439          32 :     }
     440             : 
     441             :     template <typename MF, typename BC, typename Interp, typename PreInterpHook, typename PostInterpHook>
     442             :     std::enable_if_t<IsFabArray<MF>::value,int>
     443      213608 :     FillPatchTwoLevels_doit (MF& mf, IntVect const& nghost, Real time,
     444             :                              const Vector<MF*>& cmf, const Vector<Real>& ct,
     445             :                              const Vector<MF*>& fmf, const Vector<Real>& ft,
     446             :                              int scomp, int dcomp, int ncomp,
     447             :                              const Geometry& cgeom, const Geometry& fgeom,
     448             :                              BC& cbc, int cbccomp,
     449             :                              BC& fbc, int fbccomp,
     450             :                              const IntVect& ratio,
     451             :                              Interp* mapper,
     452             :                              const Vector<BCRec>& bcs, int bcscomp,
     453             :                              const PreInterpHook& pre_interp,
     454             :                              const PostInterpHook& post_interp,
     455             :                              EB2::IndexSpace const* index_space,
     456             :                              bool return_error_code = false)
     457             :     {
     458             :         BL_PROFILE("FillPatchTwoLevels");
     459             : 
     460      213608 :         int success_code = return_error_code ? 0 : -1;
     461      213608 :         int failure_code = 1;
     462             : 
     463      213608 :         if (nghost.max() > 0 || mf.getBDKey() != fmf[0]->getBDKey())
     464             :         {
     465      213608 :             const InterpolaterBoxCoarsener& coarsener = mapper->BoxCoarsener(ratio);
     466             : 
     467             :             // Test for Face-centered data
     468      427216 :             if ( AMREX_D_TERM(  mf.ixType().nodeCentered(0),
     469             :                               + mf.ixType().nodeCentered(1),
     470      213608 :                               + mf.ixType().nodeCentered(2) ) == 1 )
     471             :             {
     472           0 :                 if ( !dynamic_cast<Interpolater*>(mapper) ){
     473             :                     amrex::Abort("This interpolater has not yet implemented a version for face-based data");
     474             :                 }
     475             : 
     476             :                 // Convert to cell-centered MF meta-data for FPInfo.
     477           0 :                 MF mf_cc_dummy( amrex::convert(mf.boxArray(), IntVect::TheZeroVector()),
     478           0 :                                 mf.DistributionMap(), ncomp, nghost, MFInfo().SetAlloc(false) );
     479           0 :                 MF fmf_cc_dummy( amrex::convert(fmf[0]->boxArray(), IntVect::TheZeroVector()),
     480           0 :                                  fmf[0]->DistributionMap(), ncomp, nghost, MFInfo().SetAlloc(false) );
     481             : 
     482           0 :                 const FabArrayBase::FPinfo& fpc = FabArrayBase::TheFPinfo(fmf_cc_dummy, mf_cc_dummy,
     483             :                                                                           nghost,
     484             :                                                                           coarsener,
     485             :                                                                           fgeom,
     486             :                                                                           cgeom,
     487             :                                                                           index_space);
     488             : 
     489           0 :                 if ( ! fpc.ba_crse_patch.empty())
     490             :                 {
     491           0 :                     if (return_error_code) {
     492           0 :                         BoxArray const& cba = amrex::convert(cmf[0]->boxArray(), IntVect(0));
     493           0 :                         if (!cba.contains(fpc.ba_crse_patch,cgeom.periodicity())) {
     494           0 :                             return failure_code;
     495             :                         }
     496             :                     }
     497             : 
     498           0 :                     MF mf_crse_patch     = make_mf_crse_patch<MF>      (fpc, ncomp, mf.boxArray().ixType());
     499             :                     // Must make sure fine exists under needed coarse faces.
     500             :                     // It stores values for the final (interior) interpolation,
     501             :                     // which is done from this fine MF that's been partially filled
     502             :                     // (with only faces overlying coarse having valid data).
     503           0 :                     MF mf_refined_patch  = make_mf_refined_patch<MF>   (fpc, ncomp, mf.boxArray().ixType(), ratio);
     504           0 :                     auto solve_mask = make_mf_crse_mask<iMultiFab>(fpc, ncomp, mf.boxArray().ixType(), ratio);
     505             : 
     506           0 :                     mf_set_domain_bndry(mf_crse_patch, cgeom);
     507           0 :                     FillPatchSingleLevel(mf_crse_patch, time, cmf, ct, scomp, 0, ncomp,
     508             :                                          cgeom, cbc, cbccomp);
     509             : 
     510           0 :                     mf_set_domain_bndry(mf_refined_patch, fgeom);
     511           0 :                     FillPatchSingleLevel(mf_refined_patch, time, fmf, ft, scomp, 0, ncomp,
     512             :                                          fgeom, fbc, fbccomp);
     513             : 
     514             :                     // Aliased MFs, used to allow CPC caching.
     515           0 :                     MF mf_known( amrex::coarsen(fmf[0]->boxArray(), ratio), fmf[0]->DistributionMap(),
     516           0 :                                  ncomp, nghost, MFInfo().SetAlloc(false) );
     517           0 :                     MF mf_solution( amrex::coarsen(mf_refined_patch.boxArray(), ratio), mf_refined_patch.DistributionMap(),
     518           0 :                                     ncomp, 0, MFInfo().SetAlloc(false) );
     519             : 
     520           0 :                     const FabArrayBase::CPC mask_cpc( mf_solution, IntVect::TheZeroVector(),
     521           0 :                                                       mf_known, IntVect::TheZeroVector(),
     522           0 :                                                       cgeom.periodicity());
     523             : 
     524           0 :                     solve_mask.setVal(1);                   // Values to solve.
     525           0 :                     solve_mask.setVal(0, mask_cpc, 0, 1);   // Known values.
     526             : 
     527           0 :                     detail::call_interp_hook(pre_interp, mf_crse_patch, 0, ncomp);
     528             : 
     529           0 :                     InterpFace(mapper, mf_crse_patch, 0, mf_refined_patch, 0, ncomp,
     530             :                                ratio, solve_mask, cgeom, fgeom, bcscomp, RunOn::Gpu, bcs);
     531             : 
     532           0 :                     detail::call_interp_hook(post_interp, mf_refined_patch, 0, ncomp);
     533             : 
     534           0 :                     bool aliasing = false;
     535           0 :                     for (auto const& fmf_a : fmf) {
     536           0 :                         aliasing = aliasing || (&mf == fmf_a);
     537             :                     }
     538           0 :                     if (aliasing) {
     539           0 :                         mf.ParallelCopyToGhost(mf_refined_patch, 0, dcomp, ncomp,
     540             :                                                IntVect{0}, nghost);
     541             :                     } else {
     542           0 :                         mf.ParallelCopy(mf_refined_patch, 0, dcomp, ncomp,
     543             :                                         IntVect{0}, nghost);
     544             :                     }
     545             :                 }
     546             :             }
     547             :             else
     548             :             {
     549      213608 :                 const FabArrayBase::FPinfo& fpc = FabArrayBase::TheFPinfo(*fmf[0], mf,
     550             :                                                                           nghost,
     551             :                                                                           coarsener,
     552             :                                                                           fgeom,
     553             :                                                                           cgeom,
     554             :                                                                           index_space);
     555             : 
     556      213608 :                 if ( ! fpc.ba_crse_patch.empty())
     557             :                 {
     558      213208 :                     if (return_error_code) {
     559           0 :                         BoxArray const& cba = cmf[0]->boxArray();
     560           0 :                         if (!cba.contains(fpc.ba_crse_patch,cgeom.periodicity())) {
     561           0 :                             return failure_code;
     562             :                         }
     563             :                     }
     564             : 
     565      426416 :                     MF mf_crse_patch = make_mf_crse_patch<MF>(fpc, ncomp);
     566      213208 :                     mf_set_domain_bndry (mf_crse_patch, cgeom);
     567             : 
     568      213208 :                     FillPatchSingleLevel(mf_crse_patch, time, cmf, ct, scomp, 0, ncomp, cgeom, cbc, cbccomp);
     569             : 
     570      213208 :                     MF mf_fine_patch = make_mf_fine_patch<MF>(fpc, ncomp);
     571             : 
     572      213208 :                     detail::call_interp_hook(pre_interp, mf_crse_patch, 0, ncomp);
     573             : 
     574      213208 :                     FillPatchInterp(mf_fine_patch, 0, mf_crse_patch, 0,
     575             :                                     ncomp, IntVect(0), cgeom, fgeom,
     576      213208 :                                     amrex::grow(amrex::convert(fgeom.Domain(),mf.ixType()),nghost),
     577             :                                     ratio, mapper, bcs, bcscomp);
     578             : 
     579      213208 :                     detail::call_interp_hook(post_interp, mf_fine_patch, 0, ncomp);
     580             : 
     581      213208 :                     mf.ParallelCopy(mf_fine_patch, 0, dcomp, ncomp, IntVect{0}, nghost);
     582             :                 }
     583             :             }
     584             :         }
     585             : 
     586      213608 :         FillPatchSingleLevel(mf, nghost, time, fmf, ft, scomp, dcomp, ncomp,
     587             :                              fgeom, fbc, fbccomp);
     588             : 
     589      213608 :         return success_code;
     590             :     }
     591             : 
     592             :     template <typename MF, typename BC, typename Interp, typename PreInterpHook, typename PostInterpHook>
     593             :     std::enable_if_t<IsFabArray<MF>::value>
     594             :     FillPatchTwoLevels_doit (Array<MF*, AMREX_SPACEDIM> const& mf, IntVect const& nghost, Real time,
     595             :                              const Vector<Array<MF*, AMREX_SPACEDIM> >& cmf, const Vector<Real>& ct,
     596             :                              const Vector<Array<MF*, AMREX_SPACEDIM> >& fmf, const Vector<Real>& ft,
     597             :                              int scomp, int dcomp, int ncomp,
     598             :                              const Geometry& cgeom, const Geometry& fgeom,
     599             :                              Array<BC, AMREX_SPACEDIM>& cbc, const Array<int, AMREX_SPACEDIM>& cbccomp,
     600             :                              Array<BC, AMREX_SPACEDIM>& fbc, const Array<int, AMREX_SPACEDIM>& fbccomp,
     601             :                              const IntVect& ratio,
     602             :                              Interp* mapper,
     603             :                              const Array<Vector<BCRec>, AMREX_SPACEDIM>& bcs, const Array<int, AMREX_SPACEDIM>& bcscomp,
     604             :                              const PreInterpHook& pre_interp,
     605             :                              const PostInterpHook& post_interp,
     606             :                              EB2::IndexSpace const* index_space)
     607             :     {
     608             :         BL_PROFILE("FillPatchTwoLevels (Array<MF*>)");
     609             : 
     610             :         using FAB = typename MF::FABType::value_type;
     611             :         using iFAB = typename iMultiFab::FABType::value_type;
     612             : 
     613             :         AMREX_ASSERT(AMREX_D_TERM(mf[0]->ixType().nodeCentered(0),
     614             :                                && mf[1]->ixType().nodeCentered(1),
     615             :                                && mf[2]->ixType().nodeCentered(2)));
     616             : 
     617             :         // These need to be true: (ba[0] == ba[1] == ba[2]) & (dm[0] == dm[1] == dm[2]).
     618             :         // Debatable whether these are required, or will be enforced elsewhere prior to this func.
     619             :         AMREX_ASSERT(AMREX_D_TERM(true,
     620             :                                && BoxArray::SameRefs(mf[0]->boxArray(), mf[1]->boxArray()),
     621             :                                && BoxArray::SameRefs(mf[0]->boxArray(), mf[2]->boxArray())));
     622             : /*
     623             :         AMREX_ASSERT(AMREX_D_TERM(true,
     624             :                                && DistributionMapping::SameRefs(mf[0]->DistributionMap(), mf[1]->DistributionMap()),
     625             :                                && DistributionMapping::SameRefs(mf[0]->DistributionMap(), mf[2]->DistributionMap())));
     626             : */
     627             : 
     628             : 
     629             :         // Test all of them?
     630             :         if (nghost.max() > 0 || mf[0]->getBDKey() != fmf[0][0]->getBDKey())
     631             :         {
     632             :             const InterpolaterBoxCoarsener& coarsener = mapper->BoxCoarsener(ratio);
     633             : 
     634             :             // Convert to cell-centered MF meta-data for FPInfo.
     635             :             MF mf_cc_dummy( amrex::convert(mf[0]->boxArray(), IntVect::TheZeroVector()),
     636             :                             mf[0]->DistributionMap(), ncomp, nghost, MFInfo().SetAlloc(false) );
     637             :             MF fmf_cc_dummy( amrex::convert(fmf[0][0]->boxArray(), IntVect::TheZeroVector()),
     638             :                              fmf[0][0]->DistributionMap(), ncomp, nghost, MFInfo().SetAlloc(false) );
     639             : 
     640             :             const FabArrayBase::FPinfo& fpc = FabArrayBase::TheFPinfo(fmf_cc_dummy, mf_cc_dummy,
     641             :                                                                       nghost,
     642             :                                                                       coarsener,
     643             :                                                                       fgeom,
     644             :                                                                       cgeom,
     645             :                                                                       index_space);
     646             : 
     647             :             if ( !fpc.ba_crse_patch.empty() )
     648             :             {
     649             :                 Array<MF, AMREX_SPACEDIM> mf_crse_patch;
     650             :                 Array<MF, AMREX_SPACEDIM> mf_refined_patch;
     651             :                 Array<iMultiFab, AMREX_SPACEDIM> solve_mask;
     652             : 
     653             :                 for (int d=0; d<AMREX_SPACEDIM; ++d)
     654             :                 {
     655             :                     mf_crse_patch[d]    = make_mf_crse_patch<MF>      (fpc, ncomp, mf[d]->boxArray().ixType());
     656             :                     mf_refined_patch[d] = make_mf_refined_patch<MF>   (fpc, ncomp, mf[d]->boxArray().ixType(), ratio);
     657             :                     solve_mask[d]       = make_mf_crse_mask<iMultiFab>(fpc, ncomp, mf[d]->boxArray().ixType(), ratio);
     658             : 
     659             :                     mf_set_domain_bndry(mf_crse_patch[d], cgeom);
     660             :                     Vector<MF*> cmf_time;
     661             :                     for (const auto & mfab : cmf)
     662             :                         { cmf_time.push_back(mfab[d]); }
     663             : 
     664             :                     FillPatchSingleLevel(mf_crse_patch[d], time, cmf_time, ct, scomp, 0, ncomp,
     665             :                                          cgeom, cbc[d], cbccomp[d]);
     666             : 
     667             :                     mf_set_domain_bndry(mf_refined_patch[d], fgeom);
     668             :                     Vector<MF*> fmf_time;
     669             :                     for (const auto & mfab : fmf)
     670             :                         { fmf_time.push_back(mfab[d]); }
     671             : 
     672             :                     FillPatchSingleLevel(mf_refined_patch[d], time, fmf_time, ft, scomp, 0, ncomp,
     673             :                                          fgeom, fbc[d], fbccomp[d]);
     674             : 
     675             : 
     676             :                     // Aliased MFs, used to allow CPC caching.
     677             :                     MF mf_known( amrex::coarsen(fmf[0][d]->boxArray(), ratio), fmf[0][d]->DistributionMap(),
     678             :                                     ncomp, nghost, MFInfo().SetAlloc(false) );
     679             :                     MF mf_solution( amrex::coarsen(mf_refined_patch[d].boxArray(), ratio), mf_refined_patch[d].DistributionMap(),
     680             :                                     ncomp, 0, MFInfo().SetAlloc(false) );
     681             : 
     682             :                     const FabArrayBase::CPC mask_cpc( mf_solution, IntVect::TheZeroVector(),
     683             :                                                       mf_known, IntVect::TheZeroVector(),
     684             :                                                       cgeom.periodicity() );
     685             : 
     686             :                     solve_mask[d].setVal(1);                   // Values to solve.
     687             :                     solve_mask[d].setVal(0, mask_cpc, 0, 1);   // Known values.
     688             :                 }
     689             : 
     690             :                 int idummy=0;
     691             : #ifdef AMREX_USE_OMP
     692             : //              bool cc = fpc.ba_crse_patch.ixType().cellCentered();
     693             :                 bool cc = false;        // can anything be done to allow threading, or can the OpenMP just be removed?
     694             : #pragma omp parallel if (cc && Gpu::notInLaunchRegion() )
     695             : #endif
     696             :                 {
     697             :                     Vector<Array<BCRec, AMREX_SPACEDIM> > bcr(ncomp);
     698             :                     for (MFIter mfi(mf_refined_patch[0]); mfi.isValid(); ++mfi)
     699             :                     {
     700             :                         Array<FAB*, AMREX_SPACEDIM> sfab{ AMREX_D_DECL( &(mf_crse_patch[0][mfi]),
     701             :                                                                         &(mf_crse_patch[1][mfi]),
     702             :                                                                         &(mf_crse_patch[2][mfi])  )};
     703             :                         Array<FAB*, AMREX_SPACEDIM> dfab{ AMREX_D_DECL( &(mf_refined_patch[0][mfi]),
     704             :                                                                         &(mf_refined_patch[1][mfi]),
     705             :                                                                         &(mf_refined_patch[2][mfi])  )};
     706             :                         Array<iFAB*, AMREX_SPACEDIM> mfab{ AMREX_D_DECL( &(solve_mask[0][mfi]),
     707             :                                                                          &(solve_mask[1][mfi]),
     708             :                                                                          &(solve_mask[2][mfi])  )};
     709             : 
     710             :                         const Box& sbx_cc = amrex::convert(sfab[0]->box(), IntVect::TheZeroVector());
     711             :                         const Box& dbx_cc = amrex::convert(dfab[0]->box(), IntVect::TheZeroVector());
     712             : 
     713             :                         for (int d=0; d<AMREX_SPACEDIM; ++d)
     714             :                         {
     715             :                             Vector<BCRec> bcr_d(ncomp);
     716             : 
     717             :                             amrex::setBC(sfab[d]->box(), amrex::convert(cgeom.Domain(), mf[d]->ixType()),
     718             :                                          bcscomp[d],0,ncomp,bcs[d],bcr_d);
     719             : 
     720             :                             for (int n=0; n<ncomp; ++n)
     721             :                                 { bcr[n][d] = bcr_d[n]; }
     722             :                         }
     723             : 
     724             :                         pre_interp(sfab, sbx_cc, 0, ncomp);
     725             : 
     726             :                         mapper->interp_arr(sfab, 0, dfab, 0, ncomp, dbx_cc, ratio, mfab,
     727             :                                            cgeom, fgeom, bcr, idummy, idummy, RunOn::Gpu);
     728             : 
     729             :                         post_interp(dfab, dbx_cc, 0, ncomp);
     730             :                     }
     731             :                 }
     732             : 
     733             :                 for (int d=0; d<AMREX_SPACEDIM; ++d)
     734             :                 {
     735             :                     bool aliasing = false;
     736             :                     for (auto const& fmf_a : fmf) {
     737             :                         aliasing = aliasing || (mf[d] == fmf_a[d]);
     738             :                     }
     739             :                     if (aliasing) {
     740             :                         mf[d]->ParallelCopyToGhost(mf_refined_patch[d], 0, dcomp, ncomp,
     741             :                                                    IntVect{0}, nghost);
     742             :                     } else {
     743             :                         mf[d]->ParallelCopy(mf_refined_patch[d], 0, dcomp, ncomp,
     744             :                                             IntVect{0}, nghost);
     745             :                     }
     746             :                 }
     747             :             }
     748             :         }
     749             : 
     750             :         for (int d=0; d<AMREX_SPACEDIM; ++d)
     751             :         {
     752             :             Vector<MF*> fmf_time;
     753             :             for (auto const& ffab : fmf)
     754             :                  { fmf_time.push_back(ffab[d]); }
     755             : 
     756             :             FillPatchSingleLevel(*mf[d], nghost, time, fmf_time, ft, scomp, dcomp, ncomp,
     757             :                                  fgeom, fbc[d], fbccomp[d]);
     758             :         }
     759             :     }
     760             : 
     761             : } // namespace detail
     762             : 
     763             : template <typename MF, typename BC, typename Interp, typename PreInterpHook, typename PostInterpHook>
     764             : std::enable_if_t<IsFabArray<MF>::value>
     765             : FillPatchTwoLevels (MF& mf, IntVect const& nghost, Real time,
     766             :                     const Vector<MF*>& cmf, const Vector<Real>& ct,
     767             :                     const Vector<MF*>& fmf, const Vector<Real>& ft,
     768             :                     int scomp, int dcomp, int ncomp,
     769             :                     const Geometry& cgeom, const Geometry& fgeom,
     770             :                     BC& cbc, int cbccomp,
     771             :                     BC& fbc, int fbccomp,
     772             :                     const IntVect& ratio,
     773             :                     Interp* mapper,
     774             :                     const Vector<BCRec>& bcs, int bcscomp,
     775             :                     const PreInterpHook& pre_interp,
     776             :                     const PostInterpHook& post_interp)
     777             : {
     778             : #ifdef AMREX_USE_EB
     779             :     EB2::IndexSpace const* index_space = EB2::TopIndexSpaceIfPresent();
     780             : #else
     781             :     EB2::IndexSpace const* index_space = nullptr;
     782             : #endif
     783             :     detail::FillPatchTwoLevels_doit(mf,nghost,time,cmf,ct,fmf,ft,
     784             :                             scomp,dcomp,ncomp,cgeom,fgeom,
     785             :                             cbc,cbccomp,fbc,fbccomp,ratio,mapper,bcs,bcscomp,
     786             :                             pre_interp,post_interp,index_space);
     787             : }
     788             : 
     789             : template <typename MF, typename BC, typename Interp, typename PreInterpHook, typename PostInterpHook>
     790             : std::enable_if_t<IsFabArray<MF>::value>
     791      213608 : FillPatchTwoLevels (MF& mf, Real time,
     792             :                     const Vector<MF*>& cmf, const Vector<Real>& ct,
     793             :                     const Vector<MF*>& fmf, const Vector<Real>& ft,
     794             :                     int scomp, int dcomp, int ncomp,
     795             :                     const Geometry& cgeom, const Geometry& fgeom,
     796             :                     BC& cbc, int cbccomp,
     797             :                     BC& fbc, int fbccomp,
     798             :                     const IntVect& ratio,
     799             :                     Interp* mapper,
     800             :                     const Vector<BCRec>& bcs, int bcscomp,
     801             :                     const PreInterpHook& pre_interp,
     802             :                     const PostInterpHook& post_interp)
     803             : {
     804             : #ifdef AMREX_USE_EB
     805             :     EB2::IndexSpace const* index_space = EB2::TopIndexSpaceIfPresent();
     806             : #else
     807      213608 :     EB2::IndexSpace const* index_space = nullptr;
     808             : #endif
     809             : 
     810      213608 :     detail::FillPatchTwoLevels_doit(mf,mf.nGrowVect(),time,cmf,ct,fmf,ft,
     811             :                             scomp,dcomp,ncomp,cgeom,fgeom,
     812             :                             cbc,cbccomp,fbc,fbccomp,ratio,mapper,bcs,bcscomp,
     813             :                             pre_interp,post_interp,index_space);
     814      213608 : }
     815             : 
     816             : template <typename MF, typename BC, typename Interp, typename PreInterpHook, typename PostInterpHook>
     817             : std::enable_if_t<IsFabArray<MF>::value>
     818             : FillPatchTwoLevels (Array<MF*, AMREX_SPACEDIM> const& mf, IntVect const& nghost, Real time,
     819             :                     const Vector<Array<MF*, AMREX_SPACEDIM> >& cmf, const Vector<Real>& ct,
     820             :                     const Vector<Array<MF*, AMREX_SPACEDIM> >& fmf, const Vector<Real>& ft,
     821             :                     int scomp, int dcomp, int ncomp,
     822             :                     const Geometry& cgeom, const Geometry& fgeom,
     823             :                     Array<BC, AMREX_SPACEDIM>& cbc, const Array<int, AMREX_SPACEDIM>& cbccomp,
     824             :                     Array<BC, AMREX_SPACEDIM>& fbc, const Array<int, AMREX_SPACEDIM>& fbccomp,
     825             :                     const IntVect& ratio,
     826             :                     Interp* mapper,
     827             :                     const Array<Vector<BCRec>, AMREX_SPACEDIM>& bcs, const Array<int, AMREX_SPACEDIM>& bcscomp,
     828             :                     const PreInterpHook& pre_interp,
     829             :                     const PostInterpHook& post_interp)
     830             : {
     831             : #ifdef AMREX_USE_EB
     832             :     EB2::IndexSpace const* index_space = EB2::TopIndexSpaceIfPresent();
     833             : #else
     834             :     EB2::IndexSpace const* index_space = nullptr;
     835             : #endif
     836             : 
     837             :     detail::FillPatchTwoLevels_doit(mf,nghost,time,cmf,ct,fmf,ft,
     838             :                             scomp,dcomp,ncomp,cgeom,fgeom,
     839             :                             cbc,cbccomp,fbc,fbccomp,ratio,mapper,bcs,bcscomp,
     840             :                             pre_interp,post_interp,index_space);
     841             : }
     842             : 
     843             : template <typename MF, typename BC, typename Interp, typename PreInterpHook, typename PostInterpHook>
     844             : std::enable_if_t<IsFabArray<MF>::value>
     845             : FillPatchTwoLevels (Array<MF*, AMREX_SPACEDIM> const& mf, IntVect const& nghost, Real time,
     846             :                     const Vector<Array<MF*, AMREX_SPACEDIM> >& cmf, const Vector<Real>& ct,
     847             :                     const Vector<Array<MF*, AMREX_SPACEDIM> >& fmf, const Vector<Real>& ft,
     848             :                     int scomp, int dcomp, int ncomp,
     849             :                     const Geometry& cgeom, const Geometry& fgeom,
     850             :                     Array<BC, AMREX_SPACEDIM>& cbc, int cbccomp,
     851             :                     Array<BC, AMREX_SPACEDIM>& fbc, int fbccomp,
     852             :                     const IntVect& ratio,
     853             :                     Interp* mapper,
     854             :                     const Array<Vector<BCRec>, AMREX_SPACEDIM>& bcs, int bcscomp,
     855             :                     const PreInterpHook& pre_interp,
     856             :                     const PostInterpHook& post_interp)
     857             : {
     858             : #ifdef AMREX_USE_EB
     859             :     EB2::IndexSpace const* index_space = EB2::TopIndexSpaceIfPresent();
     860             : #else
     861             :     EB2::IndexSpace const* index_space = nullptr;
     862             : #endif
     863             : 
     864             :     Array<int, AMREX_SPACEDIM> cbccomp_arr = {AMREX_D_DECL(cbccomp,cbccomp,cbccomp)};
     865             :     Array<int, AMREX_SPACEDIM> fbccomp_arr = {AMREX_D_DECL(fbccomp,fbccomp,fbccomp)};
     866             :     Array<int, AMREX_SPACEDIM> bcscomp_arr = {AMREX_D_DECL(bcscomp,bcscomp,bcscomp)};
     867             : 
     868             :     detail::FillPatchTwoLevels_doit(mf,nghost,time,cmf,ct,fmf,ft,
     869             :                             scomp,dcomp,ncomp,cgeom,fgeom,
     870             :                             cbc,cbccomp_arr,fbc,fbccomp_arr,ratio,mapper,bcs,bcscomp_arr,
     871             :                             pre_interp,post_interp,index_space);
     872             : }
     873             : 
     874             : template <typename MF, typename BC, typename Interp, typename PreInterpHook, typename PostInterpHook>
     875             : std::enable_if_t<IsFabArray<MF>::value>
     876             : FillPatchTwoLevels (Array<MF*, AMREX_SPACEDIM> const& mf, Real time,
     877             :                     const Vector<Array<MF*, AMREX_SPACEDIM> >& cmf, const Vector<Real>& ct,
     878             :                     const Vector<Array<MF*, AMREX_SPACEDIM> >& fmf, const Vector<Real>& ft,
     879             :                     int scomp, int dcomp, int ncomp,
     880             :                     const Geometry& cgeom, const Geometry& fgeom,
     881             :                     Array<BC, AMREX_SPACEDIM>& cbc, int cbccomp,
     882             :                     Array<BC, AMREX_SPACEDIM>& fbc, int fbccomp,
     883             :                     const IntVect& ratio,
     884             :                     Interp* mapper,
     885             :                     const Array<Vector<BCRec>, AMREX_SPACEDIM>& bcs, int bcscomp,
     886             :                     const PreInterpHook& pre_interp,
     887             :                     const PostInterpHook& post_interp)
     888             : {
     889             : #ifdef AMREX_USE_EB
     890             :     EB2::IndexSpace const* index_space = EB2::TopIndexSpaceIfPresent();
     891             : #else
     892             :     EB2::IndexSpace const* index_space = nullptr;
     893             : #endif
     894             : 
     895             :     Array<int, AMREX_SPACEDIM> cbccomp_arr = {AMREX_D_DECL(cbccomp,cbccomp,cbccomp)};
     896             :     Array<int, AMREX_SPACEDIM> fbccomp_arr = {AMREX_D_DECL(fbccomp,fbccomp,fbccomp)};
     897             :     Array<int, AMREX_SPACEDIM> bcscomp_arr = {AMREX_D_DECL(bcscomp,bcscomp,bcscomp)};
     898             : 
     899             :     detail::FillPatchTwoLevels_doit(mf,mf[0]->nGrowVect(),time,cmf,ct,fmf,ft,
     900             :                             scomp,dcomp,ncomp,cgeom,fgeom,
     901             :                             cbc,cbccomp_arr,fbc,fbccomp_arr,ratio,mapper,bcs,bcscomp_arr,
     902             :                             pre_interp,post_interp,index_space);
     903             : }
     904             : 
     905             : #ifdef AMREX_USE_EB
     906             : template <typename MF, typename BC, typename Interp, typename PreInterpHook, typename PostInterpHook>
     907             : std::enable_if_t<IsFabArray<MF>::value>
     908             : FillPatchTwoLevels (MF& mf, IntVect const& nghost, Real time,
     909             :                     const EB2::IndexSpace& index_space,
     910             :                     const Vector<MF*>& cmf, const Vector<Real>& ct,
     911             :                     const Vector<MF*>& fmf, const Vector<Real>& ft,
     912             :                     int scomp, int dcomp, int ncomp,
     913             :                     const Geometry& cgeom, const Geometry& fgeom,
     914             :                     BC& cbc, int cbccomp,
     915             :                     BC& fbc, int fbccomp,
     916             :                     const IntVect& ratio,
     917             :                     Interp* mapper,
     918             :                     const Vector<BCRec>& bcs, int bcscomp,
     919             :                     const PreInterpHook& pre_interp,
     920             :                     const PostInterpHook& post_interp)
     921             : {
     922             :     detail::FillPatchTwoLevels_doit(mf,nghost,time,cmf,ct,fmf,ft,
     923             :                             scomp,dcomp,ncomp,cgeom,fgeom,
     924             :                             cbc,cbccomp,fbc,fbccomp,ratio,mapper,bcs,bcscomp,
     925             :                             pre_interp,post_interp,&index_space);
     926             : }
     927             : 
     928             : template <typename MF, typename BC, typename Interp, typename PreInterpHook, typename PostInterpHook>
     929             : std::enable_if_t<IsFabArray<MF>::value>
     930             : FillPatchTwoLevels (MF& mf, Real time,
     931             :                     const EB2::IndexSpace& index_space,
     932             :                     const Vector<MF*>& cmf, const Vector<Real>& ct,
     933             :                     const Vector<MF*>& fmf, const Vector<Real>& ft,
     934             :                     int scomp, int dcomp, int ncomp,
     935             :                     const Geometry& cgeom, const Geometry& fgeom,
     936             :                     BC& cbc, int cbccomp,
     937             :                     BC& fbc, int fbccomp,
     938             :                     const IntVect& ratio,
     939             :                     Interp* mapper,
     940             :                     const Vector<BCRec>& bcs, int bcscomp,
     941             :                     const PreInterpHook& pre_interp,
     942             :                     const PostInterpHook& post_interp)
     943             : {
     944             :     detail::FillPatchTwoLevels_doit(mf,mf.nGrowVect(),time,cmf,ct,fmf,ft,
     945             :                             scomp,dcomp,ncomp,cgeom,fgeom,
     946             :                             cbc,cbccomp,fbc,fbccomp,ratio,mapper,bcs,bcscomp,
     947             :                             pre_interp,post_interp,&index_space);
     948             : }
     949             : #endif
     950             : 
     951             : template <typename MF, typename BC, typename Interp, typename PreInterpHook, typename PostInterpHook>
     952             : std::enable_if_t<IsFabArray<MF>::value>
     953          34 : InterpFromCoarseLevel (MF& mf, Real time,
     954             :                        const MF& cmf, int scomp, int dcomp, int ncomp,
     955             :                        const Geometry& cgeom, const Geometry& fgeom,
     956             :                        BC& cbc, int cbccomp,
     957             :                        BC& fbc, int fbccomp,
     958             :                        const IntVect& ratio,
     959             :                        Interp* mapper,
     960             :                        const Vector<BCRec>& bcs, int bcscomp,
     961             :                        const PreInterpHook& pre_interp,
     962             :                        const PostInterpHook& post_interp)
     963             : {
     964          34 :     InterpFromCoarseLevel(mf,mf.nGrowVect(),time,cmf,scomp,dcomp,ncomp,cgeom,fgeom,
     965             :                           cbc,cbccomp,fbc,fbccomp,ratio,mapper,bcs,bcscomp,
     966             :                           pre_interp,post_interp);
     967          34 : }
     968             : 
     969             : template <typename MF, typename BC, typename Interp, typename PreInterpHook, typename PostInterpHook>
     970             : std::enable_if_t<IsFabArray<MF>::value>
     971             : InterpFromCoarseLevel (Array<MF*, AMREX_SPACEDIM> const& mf, Real time,
     972             :                        const Array<MF*, AMREX_SPACEDIM>& cmf, int scomp, int dcomp, int ncomp,
     973             :                        const Geometry& cgeom, const Geometry& fgeom,
     974             :                        Array<BC, AMREX_SPACEDIM>& cbc, int cbccomp,
     975             :                        Array<BC, AMREX_SPACEDIM>& fbc, int fbccomp,
     976             :                        const IntVect& ratio,
     977             :                        Interp* mapper,
     978             :                        const Array<Vector<BCRec>, AMREX_SPACEDIM>& bcs, int bcscomp,
     979             :                        const PreInterpHook& pre_interp,
     980             :                        const PostInterpHook& post_interp)
     981             : {
     982             :     InterpFromCoarseLevel(mf,mf[0]->nGrowVect(),time,cmf,scomp,dcomp,ncomp,cgeom,fgeom,
     983             :                           cbc,cbccomp,fbc,fbccomp,ratio,mapper,bcs,bcscomp,
     984             :                           pre_interp,post_interp);
     985             : }
     986             : 
     987             : template <typename MF, typename BC, typename Interp, typename PreInterpHook, typename PostInterpHook>
     988             : std::enable_if_t<IsFabArray<MF>::value>
     989          34 : InterpFromCoarseLevel (MF& mf, IntVect const& nghost, Real time,
     990             :                        const MF& cmf, int scomp, int dcomp, int ncomp,
     991             :                        const Geometry& cgeom, const Geometry& fgeom,
     992             :                        BC& cbc, int cbccomp,
     993             :                        BC& fbc, int fbccomp,
     994             :                        const IntVect& ratio,
     995             :                        Interp* mapper,
     996             :                        const Vector<BCRec>& bcs, int bcscomp,
     997             :                        const PreInterpHook& pre_interp,
     998             :                        const PostInterpHook& post_interp)
     999             : {
    1000             :     using FAB = typename MF::FABType::value_type;
    1001             : 
    1002          68 :     const InterpolaterBoxCoarsener& coarsener = mapper->BoxCoarsener(ratio);
    1003             : 
    1004          34 :     const BoxArray& ba = mf.boxArray();
    1005          34 :     const DistributionMapping& dm = mf.DistributionMap();
    1006             : 
    1007          34 :     const IndexType& typ = ba.ixType();
    1008             : 
    1009             :     BL_ASSERT(typ == cmf.boxArray().ixType());
    1010             : 
    1011          34 :     Box fdomain_g( amrex::convert(fgeom.Domain(),mf.ixType()) );
    1012         102 :     for (int i = 0; i < AMREX_SPACEDIM; ++i) {
    1013          68 :         if (fgeom.isPeriodic(i)) {
    1014           0 :             fdomain_g.grow(i,nghost[i]);
    1015             :         }
    1016             :     }
    1017             : 
    1018          68 :     BoxArray ba_crse_patch(ba.size());
    1019             :     {  // TODO: later we might want to cache this
    1020         350 :         for (int i = 0, N = ba.size(); i < N; ++i)
    1021             :         {
    1022         316 :             Box bx = amrex::convert(amrex::grow(ba[i],nghost), typ);
    1023         316 :             bx &= fdomain_g;
    1024         316 :             ba_crse_patch.set(i, coarsener.doit(bx));
    1025             :         }
    1026             :     }
    1027             : 
    1028          68 :     MF mf_crse_patch;
    1029             : #ifdef AMREX_USE_EB
    1030             :     if (EB2::TopIndexSpaceIfPresent()) {
    1031             :         auto factory = makeEBFabFactory(cgeom, ba_crse_patch, dm, {0,0,0}, EBSupport::basic);
    1032             :         mf_crse_patch.define(ba_crse_patch, dm, ncomp, 0, MFInfo(), *factory);
    1033             :     } else
    1034             : #endif
    1035             :     {
    1036          34 :         mf_crse_patch.define(ba_crse_patch, dm, ncomp, 0);
    1037             :     }
    1038          34 :     detail::mf_set_domain_bndry (mf_crse_patch, cgeom);
    1039             : 
    1040          34 :     mf_crse_patch.ParallelCopy(cmf, scomp, 0, ncomp, cgeom.periodicity());
    1041             : 
    1042          34 :     cbc(mf_crse_patch, 0, ncomp, mf_crse_patch.nGrowVect(), time, cbccomp);
    1043             : 
    1044          34 :     detail::call_interp_hook(pre_interp, mf_crse_patch, 0, ncomp);
    1045             : 
    1046          34 :     FillPatchInterp(mf, dcomp, mf_crse_patch, 0, ncomp, nghost, cgeom, fgeom, fdomain_g,
    1047             :                     ratio, mapper, bcs, bcscomp);
    1048             : 
    1049             : #ifdef AMREX_USE_OMP
    1050             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    1051             : #endif
    1052         350 :     for (MFIter mfi(mf); mfi.isValid(); ++mfi)
    1053             :     {
    1054         316 :         FAB& dfab   = mf[mfi];
    1055         316 :         Box dfab_bx = dfab.box();
    1056         632 :         dfab_bx.grow(nghost-mf.nGrowVect());
    1057         316 :         const Box& dbx = dfab_bx & fdomain_g;
    1058             : 
    1059         316 :         post_interp(dfab, dbx, dcomp, ncomp);
    1060             :     }
    1061             : 
    1062          34 :     fbc(mf, dcomp, ncomp, nghost, time, fbccomp);
    1063          34 : }
    1064             : 
    1065             : template <typename MF, typename BC, typename Interp, typename PreInterpHook, typename PostInterpHook>
    1066             : std::enable_if_t<IsFabArray<MF>::value>
    1067             : InterpFromCoarseLevel (Array<MF*, AMREX_SPACEDIM> const& mf, IntVect const& nghost, Real time,
    1068             :                        const Array<MF*, AMREX_SPACEDIM>& cmf, int scomp, int dcomp, int ncomp,
    1069             :                        const Geometry& cgeom, const Geometry& fgeom,
    1070             :                        Array<BC, AMREX_SPACEDIM>& cbc, int cbccomp,
    1071             :                        Array<BC, AMREX_SPACEDIM>& fbc, int fbccomp,
    1072             :                        const IntVect& ratio,
    1073             :                        Interp* mapper,
    1074             :                        const Array<Vector<BCRec>, AMREX_SPACEDIM>& bcs, int bcscomp,
    1075             :                        const PreInterpHook& pre_interp,
    1076             :                        const PostInterpHook& post_interp)
    1077             : {
    1078             :     using FAB = typename MF::FABType::value_type;
    1079             :     using iFAB = typename iMultiFab::FABType::value_type;
    1080             : 
    1081             :     const InterpolaterBoxCoarsener& coarsener = mapper->BoxCoarsener(ratio);
    1082             :     const BoxArray& ba = mf[0]->boxArray();
    1083             :     const DistributionMapping& dm = mf[0]->DistributionMap();
    1084             : 
    1085             :     AMREX_ASSERT(AMREX_D_TERM(mf[0]->ixType().nodeCentered(0),
    1086             :                            && mf[1]->ixType().nodeCentered(1),
    1087             :                            && mf[2]->ixType().nodeCentered(2)));
    1088             : 
    1089             :     // These need to be true: (ba[0] == ba[1] == ba[2]) & (dm[0] == dm[1] == dm[2]).
    1090             :     // Debatable whether these are required, or will be enforced elsewhere prior to this func.
    1091             :     AMREX_ASSERT(AMREX_D_TERM(true,
    1092             :                            && BoxArray::SameRefs(mf[0]->boxArray(), mf[1]->boxArray()),
    1093             :                            && BoxArray::SameRefs(mf[0]->boxArray(), mf[2]->boxArray())));
    1094             : /*
    1095             :     AMREX_ASSERT(AMREX_D_TERM(true,
    1096             :                            && DistributionMapping::SameRefs(mf[0]->DistributionMap(), mf[1]->DistributionMap()),
    1097             :                            && DistributionMapping::SameRefs(mf[0]->DistributionMap(), mf[2]->DistributionMap())));
    1098             : */
    1099             : 
    1100             :     // If needed, adjust to fully overlap the coarse cells.
    1101             :     IntVect nghost_adj = nghost;
    1102             :     for (int d=0; d<AMREX_SPACEDIM; ++d) {
    1103             :         if (nghost[d] % ratio[d] != 0) {
    1104             :             nghost_adj[d] += ratio[d] - (nghost[d] % ratio[d]);
    1105             :         }
    1106             :     }
    1107             : 
    1108             :     Array<MF*, AMREX_SPACEDIM> mf_local = mf;
    1109             :     int dcomp_adj = dcomp;
    1110             :     Array<std::unique_ptr<MF>, AMREX_SPACEDIM> mf_temp;
    1111             :     if (! nghost.allGE(nghost_adj)) {
    1112             :         for (int d=0; d<AMREX_SPACEDIM; ++d) {
    1113             :             mf_temp[d] = std::make_unique<MF>(mf[d]->boxArray(),
    1114             :                                               mf[d]->DistributionMap(), ncomp, nghost_adj);
    1115             :             mf_local[d] = mf_temp[d].get();
    1116             :         }
    1117             :         dcomp_adj = 0;
    1118             :     }
    1119             : 
    1120             :     // Create a cell-centered boxArray of the region to interp.
    1121             :     // Convert this boxArray and domain as needed.
    1122             :     Box fdomain = amrex::convert(fgeom.Domain(), IntVect::TheZeroVector());
    1123             :     Box fdomain_g(fdomain);
    1124             :     for (int d = 0; d < AMREX_SPACEDIM; ++d) {
    1125             :         if (fgeom.isPeriodic(d)) {
    1126             :             fdomain_g.grow(d,nghost_adj[d]);
    1127             :         }
    1128             :     }
    1129             : 
    1130             :     // Build patches, using domain to account for periodic bcs.
    1131             :     BoxArray ba_crse_patch(ba.size());
    1132             :     {  // TODO: later we might want to cache this
    1133             :         for (int i = 0, N = ba.size(); i < N; ++i)
    1134             :         {
    1135             :             Box bx = amrex::convert(amrex::grow(ba[i], nghost_adj), IntVect::TheZeroVector());
    1136             :             bx &= fdomain_g;
    1137             :             ba_crse_patch.set(i, coarsener.doit(bx));
    1138             :         }
    1139             :     }
    1140             : 
    1141             :     Array<MF, AMREX_SPACEDIM> mf_crse_patch;
    1142             :     for (int d = 0; d<AMREX_SPACEDIM; ++d)
    1143             :     {
    1144             :         IndexType typ = mf[d]->boxArray().ixType();
    1145             :         BoxArray ba_crse_idxed = amrex::convert(ba_crse_patch, typ);
    1146             : 
    1147             : #ifdef AMREX_USE_EB
    1148             :         auto crse_factory = makeEBFabFactory(cgeom, ba_crse_idxed, dm, {0,0,0}, EBSupport::basic);
    1149             :         mf_crse_patch[d].define(ba_crse_idxed, dm, ncomp, 0, MFInfo(), *crse_factory);
    1150             : #else
    1151             :         mf_crse_patch[d].define(ba_crse_idxed, dm, ncomp, 0);
    1152             : #endif
    1153             :         detail::mf_set_domain_bndry(mf_crse_patch[d], cgeom);
    1154             : 
    1155             :         mf_crse_patch[d].ParallelCopy(*(cmf[d]), scomp, 0, ncomp, cgeom.periodicity());
    1156             :         cbc[d](mf_crse_patch[d], 0, ncomp, mf_crse_patch[d].nGrowVect(), time, cbccomp);
    1157             :     }
    1158             : 
    1159             :     int idummy1=0, idummy2=0;
    1160             : #ifdef AMREX_USE_OMP
    1161             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    1162             : #endif
    1163             :     {
    1164             :         Vector<Array<BCRec, AMREX_SPACEDIM> > bcr(ncomp);
    1165             : 
    1166             :         // Empty containers describing that all points must be solved (no mask).
    1167             :         Array<iFAB*, AMREX_SPACEDIM> mfab{ AMREX_D_DECL( nullptr, nullptr, nullptr ) };
    1168             : 
    1169             :         for (MFIter mfi(mf_crse_patch[0]); mfi.isValid(); ++mfi)
    1170             :         {
    1171             :             Array<FAB*, AMREX_SPACEDIM>  sfab{ AMREX_D_DECL( &(mf_crse_patch[0][mfi]),
    1172             :                                                              &(mf_crse_patch[1][mfi]),
    1173             :                                                              &(mf_crse_patch[2][mfi]) )};
    1174             :             Array<FAB*, AMREX_SPACEDIM>  dfab{ AMREX_D_DECL( &(*mf_local[0])[mfi],
    1175             :                                                              &(*mf_local[1])[mfi],
    1176             :                                                              &(*mf_local[2])[mfi] )};
    1177             : 
    1178             :             const Box& sbx_cc = amrex::convert(sfab[0]->box(), IntVect::TheZeroVector());
    1179             :             Box dfab_cc = amrex::convert(dfab[0]->box(), IntVect::TheZeroVector());
    1180             :             const Box& dbx_cc = dfab_cc & fdomain_g;
    1181             : 
    1182             :             for (int d=0; d<AMREX_SPACEDIM; ++d)
    1183             :             {
    1184             :                 Vector<BCRec> bcr_d(ncomp);
    1185             : 
    1186             :                 amrex::setBC(sfab[d]->box(),
    1187             :                              amrex::convert(cgeom.Domain(), sfab[d]->box().ixType()),
    1188             :                              bcscomp,0,ncomp,bcs[d],bcr_d);
    1189             : 
    1190             :                 for (int n=0; n<ncomp; ++n)
    1191             :                     { bcr[n][d] = bcr_d[n]; }
    1192             :             }
    1193             : 
    1194             :             pre_interp(sfab, sbx_cc, 0, ncomp);
    1195             : 
    1196             :             mapper->interp_arr(sfab, 0, dfab, 0, ncomp, dbx_cc, ratio, mfab,
    1197             :                                cgeom, fgeom, bcr, idummy1, idummy2, RunOn::Gpu);
    1198             : 
    1199             :             post_interp(dfab, dbx_cc, 0, ncomp);
    1200             :         }
    1201             :     }
    1202             : 
    1203             :     for (int d=0; d<AMREX_SPACEDIM; ++d)
    1204             :     {
    1205             :         if (mf[d] != mf_local[d]) {
    1206             :             amrex::Copy(*mf[d], *mf_local[d], 0, dcomp_adj, ncomp, nghost);
    1207             :         }
    1208             : 
    1209             :         fbc[d](*mf[d], dcomp, ncomp, nghost, time, fbccomp);
    1210             :     }
    1211             : }
    1212             : 
    1213             : template <typename MF, typename BC, typename Interp>
    1214             : std::enable_if_t<IsFabArray<MF>::value>
    1215             : FillPatchNLevels (MF& mf, int level, const IntVect& nghost, Real time,
    1216             :                   const Vector<Vector<MF*>>& smf, const Vector<Vector<Real>>& st,
    1217             :                   int scomp, int dcomp, int ncomp,
    1218             :                   const Vector<Geometry>& geom,
    1219             :                   Vector<BC>& bc, int bccomp,
    1220             :                   const Vector<IntVect>& ratio,
    1221             :                   Interp* mapper,
    1222             :                   const Vector<BCRec>& bcr, int bcrcomp)
    1223             : {
    1224             :     BL_PROFILE("FillPatchNLevels");
    1225             : 
    1226             : #ifdef AMREX_USE_EB
    1227             :     EB2::IndexSpace const* index_space = EB2::TopIndexSpaceIfPresent();
    1228             : #else
    1229             :     EB2::IndexSpace const* index_space = nullptr;
    1230             : #endif
    1231             : 
    1232             :     AMREX_ALWAYS_ASSERT(level < int(geom.size()) &&
    1233             :                         level < int(bc.size()) &&
    1234             :                         level < int(ratio.size()+1));
    1235             :     if (level == 0) {
    1236             :         FillPatchSingleLevel(mf, nghost, time, smf[0], st[0], scomp, dcomp, ncomp, geom[0],
    1237             :                              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;
    1253             : #ifdef AMREX_USE_EB
    1254             :         if (index_space) {
    1255             :             auto factory = makeEBFabFactory(index_space, geom[level-1], cba,
    1256             :                                             mf.DistributionMap(), {0,0,0},
    1257             :                                             EBSupport::basic);
    1258             :             cmf_tmp.define(cba, mf.DistributionMap(), ncomp, 0, MFInfo(), *factory);
    1259             :         } else
    1260             : #endif
    1261             :         {
    1262             :             cmf_tmp.define(cba, mf.DistributionMap(), ncomp, 0);
    1263             :         }
    1264             :         FillPatchNLevels(cmf_tmp, level-1, IntVect(0), time, smf, st, scomp, 0, ncomp,
    1265             :                          geom, bc, bccomp, ratio, mapper, bcr, bcrcomp);
    1266             :         FillPatchInterp(mf, dcomp, cmf_tmp, 0, ncomp, nghost, geom[level-1], geom[level],
    1267             :                         domain_g, ratio[level-1], mapper, bcr, bcrcomp);
    1268             :     } else {
    1269             :         NullInterpHook<typename MF::FABType::value_type> hook{};
    1270             :         int error_code = detail::FillPatchTwoLevels_doit(mf, nghost, time,
    1271             :                                                          smf[level-1], st[level-1],
    1272             :                                                          smf[level  ], st[level  ],
    1273             :                                                          scomp, dcomp, ncomp,
    1274             :                                                          geom[level-1], geom[level],
    1275             :                                                          bc[level-1], bccomp,
    1276             :                                                          bc[level  ], bccomp,
    1277             :                                                          ratio[level-1], mapper, bcr, bcrcomp,
    1278             :                                                          hook, hook, index_space, true);
    1279             :         if (error_code == 0) { return; }
    1280             : 
    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;
    1292             : #ifdef AMREX_USE_EB
    1293             :         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);
    1298             :         } else
    1299             : #endif
    1300             :         {
    1301             :             cmf_tmp.define(cba, mf.DistributionMap(), ncomp, 0);
    1302             :         }
    1303             :         FillPatchNLevels(cmf_tmp, level-1, IntVect(0), time, smf, st, scomp, 0, ncomp,
    1304             :                          geom, bc, bccomp, ratio, mapper, bcr, bcrcomp);
    1305             :         Vector<MF*> cmf{&cmf_tmp};
    1306             :         Vector<MF*> fmf = smf[level];
    1307             :         Vector<MF> fmf_raii;
    1308             :         if (scomp != 0) {
    1309             :             for (auto const* p : fmf) {
    1310             :                 fmf_raii.emplace_back(*p,  amrex::make_alias, scomp, ncomp);
    1311             :             }
    1312             :         }
    1313             :         detail::FillPatchTwoLevels_doit(mf, nghost, time,
    1314             :                                         cmf, {time},
    1315             :                                         fmf, st[level],
    1316             :                                         0, dcomp, ncomp,
    1317             :                                         geom[level-1], geom[level],
    1318             :                                         bc[level-1], bccomp,
    1319             :                                         bc[level  ], bccomp,
    1320             :                                         ratio[level-1], mapper, bcr, bccomp,
    1321             :                                         hook, hook, index_space);
    1322             :     }
    1323             : }
    1324             : 
    1325             : }
    1326             : 
    1327             : #endif

Generated by: LCOV version 1.14