LCOV - code coverage report
Current view: top level - ext/amrex/3d-coverage-g++-24.08/include - AMReX_FabArray.H (source / functions) Hit Total Coverage
Test: coverage_merged.info Lines: 199 259 76.8 %
Date: 2024-11-18 05:28:54 Functions: 177 828 21.4 %

          Line data    Source code
       1             : 
       2             : #ifndef BL_FABARRAY_H
       3             : #define BL_FABARRAY_H
       4             : #include <AMReX_Config.H>
       5             : 
       6             : #include <AMReX_BLassert.H>
       7             : #include <AMReX_Array.H>
       8             : #include <AMReX_Vector.H>
       9             : #include <AMReX_Box.H>
      10             : #include <AMReX.H>
      11             : #include <AMReX_BoxArray.H>
      12             : #include <AMReX_BoxDomain.H>
      13             : #include <AMReX_FabFactory.H>
      14             : #include <AMReX_DistributionMapping.H>
      15             : #include <AMReX_Geometry.H>
      16             : #include <AMReX_ParallelDescriptor.H>
      17             : #include <AMReX_Utility.H>
      18             : #include <AMReX_ccse-mpi.H>
      19             : #include <AMReX_BLProfiler.H>
      20             : #include <AMReX_Periodicity.H>
      21             : #include <AMReX_Print.H>
      22             : #include <AMReX_FabArrayBase.H>
      23             : #include <AMReX_MFIter.H>
      24             : #include <AMReX_MakeType.H>
      25             : #include <AMReX_TypeTraits.H>
      26             : #include <AMReX_LayoutData.H>
      27             : #include <AMReX_BaseFab.H>
      28             : #include <AMReX_BaseFabUtility.H>
      29             : #include <AMReX_MFParallelFor.H>
      30             : #include <AMReX_TagParallelFor.H>
      31             : #include <AMReX_ParReduce.H>
      32             : 
      33             : #include <AMReX_Gpu.H>
      34             : 
      35             : #ifdef AMREX_USE_EB
      36             : #include <AMReX_EBFabFactory.H>
      37             : #endif
      38             : 
      39             : #ifdef AMREX_USE_OMP
      40             : #include <omp.h>
      41             : #endif
      42             : 
      43             : #include <algorithm>
      44             : #include <cstring>
      45             : #include <limits>
      46             : #include <map>
      47             : #include <memory>
      48             : #include <utility>
      49             : #include <set>
      50             : #include <string>
      51             : #include <vector>
      52             : 
      53             : 
      54             : namespace amrex {
      55             : 
      56             : template <typename T, std::enable_if_t<!IsBaseFab<T>::value,int> = 0>
      57             : Long nBytesOwned (T const&) noexcept { return 0; }
      58             : 
      59             : template <typename T>
      60      811512 : Long nBytesOwned (BaseFab<T> const& fab) noexcept { return fab.nBytesOwned(); }
      61             : 
      62             : /**
      63             :  * \brief FabArray memory allocation information
      64             :  */
      65             : struct MFInfo {
      66             :     // alloc: allocate memory or not
      67             :     bool    alloc = true;
      68             :     bool    alloc_single_chunk = FabArrayBase::getAllocSingleChunk();
      69             :     Arena*  arena = nullptr;
      70             :     Vector<std::string> tags;
      71             : 
      72           0 :     MFInfo& SetAlloc (bool a) noexcept { alloc = a; return *this; }
      73             : 
      74             :     MFInfo& SetAllocSingleChunk (bool a) noexcept { alloc_single_chunk = a; return *this; }
      75             : 
      76             :     MFInfo& SetArena (Arena* ar) noexcept { arena = ar; return *this; }
      77             : 
      78             :     MFInfo& SetTag () noexcept { return *this; }
      79             : 
      80             :     MFInfo& SetTag (const char* t) noexcept {
      81             :         tags.emplace_back(t);
      82             :         return *this;
      83             :     }
      84             : 
      85             :     MFInfo& SetTag (const std::string& t) noexcept {
      86             :         tags.emplace_back(t);
      87             :         return *this;
      88             :     }
      89             : 
      90             :     template <typename T, typename... Ts>
      91             :     MFInfo& SetTag (T&& t, Ts&&... ts) noexcept {
      92             :         tags.emplace_back(std::forward<T>(t));
      93             :         return SetTag(std::forward<Ts>(ts)...);
      94             :     }
      95             : };
      96             : 
      97             : struct TheFaArenaDeleter {
      98             :     using pointer = char*;
      99             :     void operator()(pointer p) const noexcept {
     100             :         The_Comms_Arena()->free(p);
     101             :     }
     102             : };
     103             : using TheFaArenaPointer = std::unique_ptr<char, TheFaArenaDeleter>;
     104             : 
     105             : // Data used in non-blocking fill boundary.
     106             : template <class FAB>
     107             : struct FBData {
     108             : 
     109             :     const FabArrayBase::FB*  fb = nullptr;
     110             :     int                 scomp;
     111             :     int                 ncomp;
     112             : 
     113             :     //
     114             :     char*               the_recv_data = nullptr;
     115             :     char*               the_send_data = nullptr;
     116             :     Vector<int>         recv_from;
     117             :     Vector<char*>       recv_data;
     118             :     Vector<std::size_t> recv_size;
     119             :     Vector<MPI_Request> recv_reqs;
     120             :     Vector<MPI_Status>  recv_stat;
     121             :     //
     122             :     Vector<char*>       send_data;
     123             :     Vector<MPI_Request> send_reqs;
     124             :     int                 tag;
     125             : 
     126             : };
     127             : 
     128             : // Data used in non-blocking parallel copy.
     129             : template <class FAB>
     130             : struct PCData {
     131             : 
     132             :     const FabArrayBase::CPC*  cpc = nullptr;
     133             :     const FabArray<FAB>*      src = nullptr;
     134             :     FabArrayBase::CpOp  op;
     135             :     int                 tag = -1;
     136             :     int                 actual_n_rcvs = -1;
     137             :     int                 SC = -1, NC = -1, DC = -1;
     138             : 
     139             :     char*               the_recv_data = nullptr;
     140             :     char*               the_send_data = nullptr;
     141             :     Vector<int>         recv_from;
     142             :     Vector<char*>       recv_data;
     143             :     Vector<std::size_t> recv_size;
     144             :     Vector<MPI_Request> recv_reqs;
     145             :     Vector<MPI_Request> send_reqs;
     146             : 
     147             : };
     148             : 
     149             : template <typename T>
     150             : struct MultiArray4
     151             : {
     152             :     AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
     153             :     Array4<T> const& operator[] (int li) const noexcept {
     154             :         AMREX_IF_ON_DEVICE((return dp[li];))
     155             :         AMREX_IF_ON_HOST((return hp[li];))
     156             :     }
     157             : 
     158             :     AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
     159             :     explicit operator bool() const noexcept {
     160             :         AMREX_IF_ON_DEVICE((return dp != nullptr;))
     161             :         AMREX_IF_ON_HOST((return hp != nullptr;))
     162             :     }
     163             : 
     164             : #ifdef AMREX_USE_GPU
     165             :     Array4<T> const* AMREX_RESTRICT dp = nullptr;
     166             : #endif
     167             :     Array4<T> const* AMREX_RESTRICT hp = nullptr;
     168             : };
     169             : 
     170             : template <class FAB> class FabArray;
     171             : 
     172             : template <class DFAB, class SFAB,
     173             :           std::enable_if_t<std::conjunction_v<
     174             :               IsBaseFab<DFAB>, IsBaseFab<SFAB>,
     175             :               std::is_convertible<typename SFAB::value_type,
     176             :                                   typename DFAB::value_type>>, int> BAR = 0>
     177             : void
     178             : Copy (FabArray<DFAB>& dst, FabArray<SFAB> const& src, int srccomp, int dstcomp, int numcomp, int nghost)
     179             : {
     180             :     Copy(dst,src,srccomp,dstcomp,numcomp,IntVect(nghost));
     181             : }
     182             : 
     183             : template <class DFAB, class SFAB,
     184             :           std::enable_if_t<std::conjunction_v<
     185             :               IsBaseFab<DFAB>, IsBaseFab<SFAB>,
     186             :               std::is_convertible<typename SFAB::value_type,
     187             :                                   typename DFAB::value_type>>, int> BAR = 0>
     188             : void
     189      365725 : Copy (FabArray<DFAB>& dst, FabArray<SFAB> const& src, int srccomp, int dstcomp, int numcomp, const IntVect& nghost)
     190             : {
     191             :     BL_PROFILE("amrex::Copy()");
     192             : 
     193             :     using DT = typename DFAB::value_type;
     194             : 
     195      365725 :     if (dst.local_size() == 0) { return; }
     196             : 
     197             :     // avoid self copy
     198             :     if constexpr (std::is_same_v<typename SFAB::value_type, typename DFAB::value_type>) {
     199      365725 :         if (dst.atLocalIdx(0).dataPtr(dstcomp) == src.atLocalIdx(0).dataPtr(srccomp)) {
     200           0 :             return;
     201             :         }
     202             :     }
     203             : 
     204             : #ifdef AMREX_USE_GPU
     205             :     if (Gpu::inLaunchRegion() && dst.isFusingCandidate()) {
     206             :         auto const& srcarr = src.const_arrays();
     207             :         auto const& dstarr = dst.arrays();
     208             :         ParallelFor(dst, nghost, numcomp,
     209             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
     210             :         {
     211             :             dstarr[box_no](i,j,k,dstcomp+n) = DT(srcarr[box_no](i,j,k,srccomp+n));
     212             :         });
     213             :         Gpu::streamSynchronize();
     214             :     } else
     215             : #endif
     216             :     {
     217             : #ifdef AMREX_USE_OMP
     218             : #pragma omp parallel if (Gpu::notInLaunchRegion())
     219             : #endif
     220      732292 :         for (MFIter mfi(dst,TilingIfNotGPU()); mfi.isValid(); ++mfi)
     221             :         {
     222      366567 :             const Box& bx = mfi.growntilebox(nghost);
     223      366567 :             if (bx.ok())
     224             :             {
     225      366567 :                 auto const& srcFab = src.const_array(mfi);
     226      366567 :                 auto const& dstFab = dst.array(mfi);
     227   419563000 :                 AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, numcomp, i, j, k, n,
     228             :                 {
     229             :                     dstFab(i,j,k,dstcomp+n) = DT(srcFab(i,j,k,srccomp+n));
     230             :                 });
     231             :             }
     232             :         }
     233             :     }
     234             : }
     235             : 
     236             : template <class FAB,
     237             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     238             : void
     239             : Add (FabArray<FAB>& dst, FabArray<FAB> const& src, int srccomp, int dstcomp, int numcomp, int nghost)
     240             : {
     241             :     Add(dst,src,srccomp,dstcomp,numcomp,IntVect(nghost));
     242             : }
     243             : 
     244             : template <class FAB,
     245             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     246             : void
     247        9540 : Add (FabArray<FAB>& dst, FabArray<FAB> const& src, int srccomp, int dstcomp, int numcomp, const IntVect& nghost)
     248             : {
     249             :     BL_PROFILE("amrex::Add()");
     250             : 
     251             : #ifdef AMREX_USE_GPU
     252             :     if (Gpu::inLaunchRegion() && dst.isFusingCandidate()) {
     253             :         auto const& dstfa = dst.arrays();
     254             :         auto const& srcfa = src.const_arrays();
     255             :         ParallelFor(dst, nghost, numcomp,
     256             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
     257             :         {
     258             :             dstfa[box_no](i,j,k,n+dstcomp) += srcfa[box_no](i,j,k,n+srccomp);
     259             :         });
     260             :         if (!Gpu::inNoSyncRegion()) {
     261             :             Gpu::streamSynchronize();
     262             :         }
     263             :     } else
     264             : #endif
     265             :     {
     266             : #ifdef AMREX_USE_OMP
     267             : #pragma omp parallel if (Gpu::notInLaunchRegion())
     268             : #endif
     269       19080 :         for (MFIter mfi(dst,TilingIfNotGPU()); mfi.isValid(); ++mfi)
     270             :         {
     271        9540 :             const Box& bx = mfi.growntilebox(nghost);
     272        9540 :             if (bx.ok())
     273             :             {
     274        9540 :                 auto const srcFab = src.array(mfi);
     275        9540 :                 auto       dstFab = dst.array(mfi);
     276    44341900 :                 AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, numcomp, i, j, k, n,
     277             :                 {
     278             :                     dstFab(i,j,k,n+dstcomp) += srcFab(i,j,k,n+srccomp);
     279             :                 });
     280             :             }
     281             :         }
     282             :     }
     283        9540 : }
     284             : 
     285             : /**
     286             :  * \brief An Array of FortranArrayBox(FAB)-like Objects
     287             :  *
     288             :  * The FabArray<FAB> class implements a collection (stored as an array) of
     289             :  * Fortran array box-like ( \p FAB ) objects.  The parameterized type \p FAB is intended to be
     290             :  * any class derived from BaseFab<T>.  For example, \p FAB may be a BaseFab of
     291             :  * integers, so we could write:
     292             :  *
     293             :  *   FabArray<BaseFab<int> > int_fabs;
     294             :  *
     295             :  * Then int_fabs is a FabArray that can hold a collection of BaseFab<int>
     296             :  * objects.
     297             :  *
     298             :  * FabArray is not just a general container class for Fortran arrays.  It is
     299             :  * intended to hold "grid" data for use in finite difference calculations in
     300             :  * which the data is defined on a union of (usually disjoint) rectangular
     301             :  * regions embedded in a uniform index space.  This region, called the valid
     302             :  * region, is represented by a BoxArray.  For the purposes of this discussion,
     303             :  * the Kth Box in the BoxArray represents the interior region of the Kth grid.
     304             :  *
     305             :  * Since the intent is to be used with finite difference calculations a
     306             :  * FabArray also includes the notion of a boundary region for each grid.  The
     307             :  * boundary region is specified by the ngrow parameter which tells the FabArray
     308             :  * to allocate each \p FAB to be ngrow cells larger in all directions than the
     309             :  * underlying Box.  The larger region covered by the union of all the \p FABs is
     310             :  * called the region of definition.  The underlying notion is that the valid
     311             :  * region contains the grid interior data and the region of definition includes
     312             :  * the interior region plus the boundary areas.
     313             :  *
     314             :  * Operations are available to copy data from the valid regions into these
     315             :  * boundary areas where the two overlap.  The number of components, that is,
     316             :  * the number of values that can be stored in each cell of a \p FAB, is either
     317             :  * given as an argument to the constructor or is inherent in the definition of
     318             :  * the underlying \p FAB.  Each \p FAB in the FabArray will have the same number of
     319             :  * components.
     320             :  *
     321             :  * In summary, a FabArray is an array of \p FABs.  The Kth element contains a \p FAB
     322             :  * that holds the data for the Kth grid, a Box that defines the valid region
     323             :  * of the Kth grid.
     324             :  *
     325             :  * A typical use for a FabArray would be to hold the solution vector or
     326             :  * right-hand-side when solving a linear system of equations on a union of
     327             :  * rectangular grids.  The copy operations would be used to copy data from the
     328             :  * valid regions of neighboring grids into the boundary regions after each
     329             :  * relaxation step of the iterative method.  If a multigrid method is used, a
     330             :  * FabArray could be used to hold the data at each level in the multigrid
     331             :  * hierarchy.
     332             :  *
     333             :  * This class is a concrete class not a polymorphic one.
     334             :  *
     335             :  * This class does NOT provide a copy constructor or assignment operator.
     336             :  *
     337             :  * \tparam FAB FortranArrayBox-like object. Typically a derived class of BaseFab. Not to be confused with FabArrayBase.
     338             :  */
     339             : template <class FAB>
     340             : class FabArray
     341             :     :
     342             :     public FabArrayBase
     343             : {
     344             : public:
     345             : 
     346             :     struct FABType {
     347             :         using value_type = FAB;
     348             :     };
     349             : 
     350             :     /*
     351             :     * if FAB is a BaseFab or its child, value_type = FAB::value_type
     352             :     * else                              value_type = FAB;
     353             :     */
     354             :     using value_type = typename std::conditional_t<IsBaseFab<FAB>::value, FAB, FABType>::value_type;
     355             : 
     356             :     using fab_type = FAB;
     357             : 
     358             :     //
     359             :     //! Constructs an empty FabArray<FAB>.
     360             :     FabArray () noexcept;
     361             : 
     362             :     /**
     363             :      * \brief Construct an empty FabArray<FAB> that has a default Arena.
     364             :      *
     365             :      * If `define` is called later with a nullptr as MFInfo's arena, the
     366             :      * default Arena `a` will be used.  If the arena in MFInfo is not a
     367             :      * nullptr, the MFInfo's arena will be used.
     368             :      */
     369             :     explicit FabArray (Arena* a) noexcept;
     370             : 
     371             :     /**
     372             :     * \brief Construct a FabArray<FAB> with a valid region defined by bxs
     373             :     * and a region of definition defined by the grow factor ngrow
     374             :     * and the number of components nvar.
     375             :     */
     376             :     FabArray (const BoxArray&            bxs,
     377             :               const DistributionMapping& dm,
     378             :               int                        nvar,
     379             :               int                        ngrow,
     380             : #ifdef AMREX_STRICT_MODE
     381             :               const MFInfo&              info,
     382             :               const FabFactory<FAB>&     factory);
     383             : #else
     384             :               const MFInfo&              info = MFInfo(),
     385             :               const FabFactory<FAB>&     factory = DefaultFabFactory<FAB>());
     386             : #endif
     387             : 
     388             :     FabArray (const BoxArray&            bxs,
     389             :               const DistributionMapping& dm,
     390             :               int                        nvar,
     391             :               const IntVect&             ngrow,
     392             : #ifdef AMREX_STRICT_MODE
     393             :               const MFInfo&              info,
     394             :               const FabFactory<FAB>&     factory);
     395             : #else
     396             :               const MFInfo&              info = MFInfo(),
     397             :               const FabFactory<FAB>&     factory = DefaultFabFactory<FAB>());
     398             : #endif
     399             : 
     400             :     FabArray (const FabArray<FAB>& rhs, MakeType maketype, int scomp, int ncomp);
     401             : 
     402             :     //! The destructor -- deletes all FABs in the array.
     403             :     ~FabArray ();
     404             : 
     405             :     FabArray (FabArray<FAB>&& rhs) noexcept;
     406             :     FabArray<FAB>& operator= (FabArray<FAB>&& rhs) noexcept;
     407             : 
     408             :     FabArray (const FabArray<FAB>& rhs) = delete;
     409             :     FabArray<FAB>& operator= (const FabArray<FAB>& rhs) = delete;
     410             : 
     411             :     /**
     412             :     * \brief Define this FabArray identically to that performed by
     413             :     * the constructor having an analogous function signature.
     414             :     * This is only valid if this FabArray was defined using
     415             :     * the default constructor.
     416             :     */
     417             :     void define (const BoxArray& bxs,
     418             :                  const DistributionMapping& dm,
     419             :                  int                        nvar,
     420             :                  int                        ngrow,
     421             : #ifdef AMREX_STRICT_MODE
     422             :                  const MFInfo&              info,
     423             :                  const FabFactory<FAB>&     factory);
     424             : #else
     425             :                  const MFInfo&              info = MFInfo(),
     426             :                  const FabFactory<FAB>&     factory = DefaultFabFactory<FAB>());
     427             : #endif
     428             : 
     429             :     void define (const BoxArray& bxs,
     430             :                  const DistributionMapping& dm,
     431             :                  int                        nvar,
     432             :                  const IntVect&             ngrow,
     433             : #ifdef AMREX_STRICT_MODE
     434             :                  const MFInfo&              info,
     435             :                  const FabFactory<FAB>&     factory);
     436             : #else
     437             :                  const MFInfo&              info = MFInfo(),
     438             :                  const FabFactory<FAB>&     factory = DefaultFabFactory<FAB>());
     439             : #endif
     440             : 
     441           0 :     const FabFactory<FAB>& Factory () const noexcept { return *m_factory; }
     442             : 
     443             :     // Provides access to the Arena this FabArray was build with.
     444             :     Arena* arena () const noexcept { return m_dallocator.arena(); }
     445             : 
     446             :     const Vector<std::string>& tags () const noexcept { return m_tags; }
     447             : 
     448             :     bool hasEBFabFactory () const noexcept {
     449             : #ifdef AMREX_USE_EB
     450             :         const auto *const f = dynamic_cast<EBFArrayBoxFactory const*>(m_factory.get());
     451             :         return (f != nullptr);
     452             : #else
     453             :         return false;
     454             : #endif
     455             :     }
     456             : 
     457             :     //! Return the data pointer to the single chunk memory if this object
     458             :     //! uses a single contiguous chunk of memory, nullptr otherwise.
     459             :     [[nodiscard]] value_type* singleChunkPtr () noexcept {
     460             :         return m_single_chunk_arena ? (value_type*)m_single_chunk_arena->data() : nullptr;
     461             :     }
     462             : 
     463             :     //! Return the data pointer to the single chunk memory if this object
     464             :     //! uses a single contiguous chunk of memory, nullptr otherwise.
     465             :     [[nodiscard]] value_type const* singleChunkPtr () const noexcept {
     466             :         return m_single_chunk_arena ? (value_type const*)m_single_chunk_arena->data() : nullptr;
     467             :     }
     468             : 
     469             :     //! Return the size of the single chunk memory if this object uses a
     470             :     //! single contiguous chunk of memory, 0 otherwise.
     471             :     [[nodiscard]] std::size_t singleChunkSize () const noexcept { return m_single_chunk_size; }
     472             : 
     473             :     bool isAllRegular () const noexcept {
     474             : #ifdef AMREX_USE_EB
     475             :         const auto *const f = dynamic_cast<EBFArrayBoxFactory const*>(m_factory.get());
     476             :         if (f) {
     477             :             return f->isAllRegular();
     478             :         } else {
     479             :             return true;
     480             :         }
     481             : #else
     482             :         return true;
     483             : #endif
     484             :     }
     485             : 
     486             :     /**
     487             :     * \brief Return true if the FabArray is well-defined.  That is,
     488             :     * the FabArray has a BoxArray and DistributionMapping, the
     489             :     * FABs are allocated for each Box in the BoxArray and the
     490             :     * sizes of the FABs and the number of components are consistent
     491             :     * with the definition of the FabArray.
     492             :     */
     493             :     bool ok () const;
     494             : 
     495             :     /** Has define() been called on this rank?
     496             :      *
     497             :      * \return true if `define` has been called on this `FabArray`.  Note that all constructors except `FabArray ()`
     498             :      * and `FabArray(Arena*a)` call `define`, even if the `MFInfo` argument has `alloc=false`.  One could
     499             :      * also use `FabArrayBase::empty()` to find whether `define` is called or not, although they are not exactly
     500             :      * the same.
     501             :      */
     502             :     bool isDefined () const;
     503             : 
     504             :     //! Return a constant reference to the FAB associated with mfi.
     505       43162 :     const FAB& operator[] (const MFIter& mfi) const noexcept { return *(this->fabPtr(mfi)); }
     506             : 
     507             :     //! Return a constant reference to the FAB associated with mfi.
     508             :     const FAB& get (const MFIter& mfi) const noexcept { return *(this->fabPtr(mfi)); }
     509             : 
     510             :     //! Returns a reference to the FAB associated mfi.
     511      125824 :     FAB& operator[] (const MFIter& mfi) noexcept { return *(this->fabPtr(mfi)); }
     512             : 
     513             :     //! Returns a reference to the FAB associated mfi.
     514         216 :     FAB& get (const MFIter& mfi) noexcept { return *(this->fabPtr(mfi)); }
     515             : 
     516             :     //! Return a constant reference to the FAB associated with the Kth element.
     517        8850 :     const FAB& operator[] (int K) const noexcept { return *(this->fabPtr(K)); }
     518             : 
     519             :     //! Return a constant reference to the FAB associated with the Kth element.
     520             :     const FAB& get (int K) const noexcept { return *(this->fabPtr(K)); }
     521             : 
     522             :     //! Return a reference to the FAB associated with the Kth element.
     523           0 :     FAB& operator[] (int K) noexcept { return *(this->fabPtr(K)); }
     524             : 
     525             :     //! Return a reference to the FAB associated with the Kth element.
     526       18298 :     FAB& get (int K) noexcept { return *(this->fabPtr(K)); }
     527             : 
     528             :     //! Return a reference to the FAB associated with local index L
     529      365725 :     FAB& atLocalIdx (int L) noexcept { return *m_fabs_v[L]; }
     530      365725 :     const FAB& atLocalIdx (int L) const noexcept { return *m_fabs_v[L]; }
     531             : 
     532             :     //! Return pointer to FAB
     533             :     FAB      * fabPtr (const MFIter& mfi) noexcept;
     534             :     FAB const* fabPtr (const MFIter& mfi) const noexcept;
     535             :     FAB      * fabPtr (int K) noexcept;  // Here K is global index
     536             :     FAB const* fabPtr (int K) const noexcept;
     537             : 
     538             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     539             :     void prefetchToHost (const MFIter& mfi) const noexcept;
     540             : 
     541             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     542             :     void prefetchToDevice (const MFIter& mfi) const noexcept;
     543             : 
     544             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     545             :     Array4<typename FabArray<FAB>::value_type const> array (const MFIter& mfi) const noexcept;
     546             :     //
     547             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     548             :     Array4<typename FabArray<FAB>::value_type> array (const MFIter& mfi) noexcept;
     549             :     //
     550             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     551             :     Array4<typename FabArray<FAB>::value_type const> array (int K) const noexcept;
     552             :     //
     553             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     554             :     Array4<typename FabArray<FAB>::value_type> array (int K) noexcept;
     555             : 
     556             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     557             :     Array4<typename FabArray<FAB>::value_type const> const_array (const MFIter& mfi) const noexcept;
     558             :     //
     559             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     560             :     Array4<typename FabArray<FAB>::value_type const> const_array (int K) const noexcept;
     561             : 
     562             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     563             :     Array4<typename FabArray<FAB>::value_type const> array (const MFIter& mfi, int start_comp) const noexcept;
     564             :     //
     565             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     566             :     Array4<typename FabArray<FAB>::value_type> array (const MFIter& mfi, int start_comp) noexcept;
     567             :     //
     568             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     569             :     Array4<typename FabArray<FAB>::value_type const> array (int K, int start_comp) const noexcept;
     570             :     //
     571             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     572             :     Array4<typename FabArray<FAB>::value_type> array (int K, int start_comp) noexcept;
     573             : 
     574             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     575             :     Array4<typename FabArray<FAB>::value_type const> const_array (const MFIter& mfi, int start_comp) const noexcept;
     576             :     //
     577             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     578             :     Array4<typename FabArray<FAB>::value_type const> const_array (int K, int start_comp) const noexcept;
     579             : 
     580             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     581             :     MultiArray4<typename FabArray<FAB>::value_type> arrays () noexcept;
     582             : 
     583             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     584             :     MultiArray4<typename FabArray<FAB>::value_type const> arrays () const noexcept;
     585             : 
     586             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     587             :     MultiArray4<typename FabArray<FAB>::value_type const> const_arrays () const noexcept;
     588             : 
     589             :     //! Explicitly set the Kth FAB in the FabArray to point to elem.
     590             :     void setFab (int boxno, std::unique_ptr<FAB> elem);
     591             : 
     592             :     //! Explicitly set the Kth FAB in the FabArray to point to elem.
     593             :     template <class F=FAB, std::enable_if_t<std::is_move_constructible_v<F>,int> = 0>
     594             :     void setFab (int boxno, FAB&& elem);
     595             : 
     596             :     //! Explicitly set the FAB associated with mfi in the FabArray to point to elem.
     597             :     void setFab (const MFIter&mfi, std::unique_ptr<FAB> elem);
     598             : 
     599             :     //! Explicitly set the FAB associated with mfi in the FabArray to point to elem.
     600             :     template <class F=FAB, std::enable_if_t<std::is_move_constructible_v<F>,int> = 0>
     601             :     void setFab (const MFIter&mfi, FAB&& elem);
     602             : 
     603             :     //! Release ownership of the FAB. This function is not thread safe.
     604             :     AMREX_NODISCARD
     605             :     FAB* release (int K);
     606             : 
     607             :     //! Release ownership of the FAB. This function is not thread safe.
     608             :     AMREX_NODISCARD
     609             :     FAB* release (const MFIter& mfi);
     610             : 
     611             :     //! Releases FAB memory in the FabArray.
     612             :     void clear ();
     613             : 
     614             :     /**
     615             :      * \brief Perform local copy of FabArray data.
     616             :      *
     617             :      * The two FabArrays must have the same BoxArray and
     618             :      * DistributionMapping, although they could have different data types.
     619             :      * For example, this could be used to copy from FabArray<BaseFab<float>>
     620             :      * to FabArray<BaseFab<double>>.
     621             :      *
     622             :      * \param src    source FabArray
     623             :      * \param scomp  starting component of source
     624             :      * \param dcomp  starting component of this FabArray
     625             :      * \param ncomp  number of components
     626             :      * \param nghost number of ghost cells
     627             :      */
     628             :     template <typename SFAB, typename DFAB = FAB,
     629             :               std::enable_if_t<std::conjunction_v<
     630             :                   IsBaseFab<DFAB>, IsBaseFab<SFAB>,
     631             :                   std::is_convertible<typename SFAB::value_type,
     632             :                                       typename DFAB::value_type>>, int> = 0>
     633             :     void LocalCopy (FabArray<SFAB> const& src, int scomp, int dcomp, int ncomp,
     634             :                     IntVect const& nghost);
     635             : 
     636             :     /**
     637             :      * \brief Perform local addition of FabArray data.
     638             :      *
     639             :      * The two FabArrays must have the same BoxArray and
     640             :      * DistributionMapping.
     641             :      *
     642             :      * \param src    source FabArray
     643             :      * \param scomp  starting component of source
     644             :      * \param dcomp  starting component of this FabArray
     645             :      * \param ncomp  number of components
     646             :      * \param nghost number of ghost cells
     647             :      */
     648             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     649             :     void LocalAdd (FabArray<FAB> const& src, int scomp, int dcomp, int ncomp,
     650             :                    IntVect const& nghost);
     651             : 
     652             :     //! Set all components in the entire region of each FAB to val.
     653             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     654             :     void setVal (value_type val);
     655             : 
     656             :     //! Set all components in the entire region of each FAB to val.
     657             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     658             :     FabArray<FAB>& operator= (value_type val);
     659             : 
     660             :     /**
     661             :     * \brief Set the value of num_comp components in the valid region of
     662             :     * each FAB in the FabArray, starting at component comp to val.
     663             :     * Also set the value of nghost boundary cells.
     664             :     */
     665             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     666             :     void setVal (value_type val,
     667             :                  int        comp,
     668             :                  int        ncomp,
     669             :                  int        nghost = 0);
     670             : 
     671             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     672             :     void setVal (value_type val,
     673             :                  int        comp,
     674             :                  int        ncomp,
     675             :                  const IntVect& nghost);
     676             : 
     677             :     /**
     678             :     * \brief Set the value of num_comp components in the valid region of
     679             :     * each FAB in the FabArray, starting at component comp, as well
     680             :     * as nghost boundary cells, to val, provided they also intersect
     681             :     * with the Box region.
     682             :     */
     683             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     684             :     void setVal (value_type val,
     685             :                  const Box& region,
     686             :                  int        comp,
     687             :                  int        ncomp,
     688             :                  int        nghost = 0);
     689             : 
     690             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     691             :     void setVal (value_type val,
     692             :                  const Box& region,
     693             :                  int        comp,
     694             :                  int        ncomp,
     695             :                  const IntVect& nghost);
     696             :     /**
     697             :     * \brief Set all components in the valid region of each FAB in the
     698             :     * FabArray to val, including nghost boundary cells.
     699             :     */
     700             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     701             :     void setVal (value_type val, int nghost);
     702             : 
     703             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     704             :     void setVal (value_type val, const IntVect& nghost);
     705             : 
     706             :     /**
     707             :     * \brief Set all components in the valid region of each FAB in the
     708             :     * FabArray to val, including nghost boundary cells, that also
     709             :     * intersect the Box region.
     710             :     */
     711             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     712             :     void setVal (value_type val, const Box& region, int nghost);
     713             : 
     714             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     715             :     void setVal (value_type val, const Box& region, const IntVect& nghost);
     716             : 
     717             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     718             :     void abs (int comp, int ncomp, int nghost = 0);
     719             : 
     720             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     721             :     void abs (int comp, int ncomp, const IntVect& nghost);
     722             : 
     723             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     724             :     void plus (value_type val, int comp, int num_comp, int nghost = 0);
     725             : 
     726             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     727             :     void plus (value_type val, const Box& region, int comp, int num_comp, int nghost = 0);
     728             : 
     729             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     730             :     void mult (value_type val, int comp, int num_comp, int nghost = 0);
     731             : 
     732             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     733             :     void mult (value_type val, const Box& region, int comp, int num_comp, int nghost = 0);
     734             : 
     735             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     736             :     void invert (value_type numerator, int comp, int num_comp, int nghost = 0);
     737             : 
     738             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     739             :     void invert (value_type numerator, const Box& region, int comp, int num_comp, int nghost = 0);
     740             : 
     741             :     //! Set all values in the boundary region to val.
     742             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     743             :     void setBndry (value_type val);
     744             : 
     745             :     //! Set ncomp values in the boundary region, starting at start_comp to val.
     746             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     747             :     void setBndry (value_type val, int strt_comp, int ncomp);
     748             : 
     749             :    //! Set all values outside the Geometry domain to val.
     750             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     751             :     void setDomainBndry (value_type val, const Geometry& geom);
     752             : 
     753             :     //! Set ncomp values outside the Geometry domain to val, starting at start_comp.
     754             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     755             :     void setDomainBndry (value_type val, int strt_comp, int ncomp, const Geometry& geom);
     756             : 
     757             :     /**
     758             :     * \brief Returns the sum of component "comp"
     759             :     *
     760             :     * \param comp   component
     761             :     * \param nghost number of ghost cells
     762             :     * \param local  If true, MPI communication is skipped.
     763             :     */
     764             :     template <typename F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
     765             :     typename F::value_type
     766             :     sum (int comp, IntVect const& nghost, bool local = false) const;
     767             : 
     768             :     /**
     769             :     * \brief This function copies data from src to this FabArray.  Each FAB
     770             :     * in fa is intersected with all FABs in this FabArray and a copy
     771             :     * is performed on the region of intersection.  The intersection
     772             :     * is restricted to the valid regions.
     773             :     */
     774             :     void ParallelAdd (const FabArray<FAB>& src,
     775             :                       const Periodicity&   period = Periodicity::NonPeriodic())
     776             :        { ParallelCopy(src,period,FabArray::ADD); }
     777           0 :     void ParallelCopy (const FabArray<FAB>& src,
     778             :                        const Periodicity&   period = Periodicity::NonPeriodic(),
     779             :                        CpOp                 op = FabArrayBase::COPY)
     780           0 :        { ParallelCopy(src,0,0,nComp(),0,0,period,op); }
     781             : 
     782             :     [[deprecated("Use FabArray::ParallelCopy() instead.")]]
     783             :     void copy (const FabArray<FAB>& src,
     784             :                const Periodicity&   period = Periodicity::NonPeriodic(),
     785             :                CpOp                 op = FabArrayBase::COPY)
     786             :         { ParallelCopy(src,period,op); }
     787             : 
     788             :     void ParallelAdd_nowait (const FabArray<FAB>& src,
     789             :                              const Periodicity& period = Periodicity::NonPeriodic())
     790             :         { ParallelCopy_nowait(src,period,FabArray::ADD); }
     791             :     void ParallelCopy_nowait (const FabArray<FAB>& src,
     792             :                               const Periodicity&   period = Periodicity::NonPeriodic(),
     793             :                               CpOp                 op = FabArrayBase::COPY)
     794             :        { ParallelCopy_nowait(src,0,0,nComp(),0,0,period,op); }
     795             : 
     796             :     /**
     797             :     * \brief This function copies data from src to this FabArray.  Each FAB
     798             :     * in src is intersected with all FABs in this FabArray and a copy
     799             :     * is performed on the region of intersection.  The intersection
     800             :     * is restricted to the num_comp components starting at src_comp
     801             :     * in the FabArray src, with the destination components in this
     802             :     * FabArray starting at dest_comp.
     803             :     */
     804             :     void ParallelAdd (const FabArray<FAB>& src,
     805             :                       int                  src_comp,
     806             :                       int                  dest_comp,
     807             :                       int                  num_comp,
     808             :                       const Periodicity&   period = Periodicity::NonPeriodic())
     809             :        { ParallelCopy(src,src_comp,dest_comp,num_comp, period, FabArrayBase::ADD); }
     810          34 :     void ParallelCopy (const FabArray<FAB>& src,
     811             :                        int                  src_comp,
     812             :                        int                  dest_comp,
     813             :                        int                  num_comp,
     814             :                        const Periodicity&   period = Periodicity::NonPeriodic(),
     815             :                        CpOp                 op = FabArrayBase::COPY)
     816          34 :        { ParallelCopy(src,src_comp,dest_comp,num_comp,0,0,period,op); }
     817             : 
     818             :     [[deprecated("Use FabArray::ParallelCopy() instead.")]]
     819             :     void copy (const FabArray<FAB>& src,
     820             :                int                  src_comp,
     821             :                int                  dest_comp,
     822             :                int                  num_comp,
     823             :                const Periodicity&   period = Periodicity::NonPeriodic(),
     824             :                CpOp                 op = FabArrayBase::COPY)
     825             :         { ParallelCopy(src,src_comp,dest_comp,num_comp, period, op); }
     826             : 
     827             :     void ParallelAdd_nowait (const FabArray<FAB>& src,
     828             :                              int                  src_comp,
     829             :                              int                  dest_comp,
     830             :                              int                  num_comp,
     831             :                              const Periodicity&   period = Periodicity::NonPeriodic())
     832             :        { ParallelCopy_nowait(src,src_comp,dest_comp,num_comp, period, FabArrayBase::ADD); }
     833             :     void ParallelCopy_nowait (const FabArray<FAB>& src,
     834             :                               int                  src_comp,
     835             :                               int                  dest_comp,
     836             :                               int                  num_comp,
     837             :                               const Periodicity&   period = Periodicity::NonPeriodic(),
     838             :                               CpOp                 op = FabArrayBase::COPY)
     839             :        { ParallelCopy_nowait(src,src_comp,dest_comp,num_comp,0,0,period,op); }
     840             : 
     841             :     //! Similar to the above function, except that source and destination are grown by src_nghost and dst_nghost, respectively
     842             :     void ParallelAdd (const FabArray<FAB>& src,
     843             :                       int                  src_comp,
     844             :                       int                  dest_comp,
     845             :                       int                  num_comp,
     846             :                       int                  src_nghost,
     847             :                       int                  dst_nghost,
     848             :                       const Periodicity&   period = Periodicity::NonPeriodic())
     849             :        { ParallelCopy(src,src_comp,dest_comp,num_comp,IntVect(src_nghost),IntVect(dst_nghost),period,
     850             :                       FabArrayBase::ADD); }
     851             :     void ParallelAdd (const FabArray<FAB>& src,
     852             :                       int                  src_comp,
     853             :                       int                  dest_comp,
     854             :                       int                  num_comp,
     855             :                       const IntVect&       src_nghost,
     856             :                       const IntVect&       dst_nghost,
     857             :                       const Periodicity&   period = Periodicity::NonPeriodic())
     858             :        { ParallelCopy(src,src_comp,dest_comp,num_comp,src_nghost,dst_nghost,period,FabArrayBase::ADD); }
     859        6334 :     void ParallelCopy (const FabArray<FAB>& src,
     860             :                        int                  src_comp,
     861             :                        int                  dest_comp,
     862             :                        int                  num_comp,
     863             :                        int                  src_nghost,
     864             :                        int                  dst_nghost,
     865             :                        const Periodicity&   period = Periodicity::NonPeriodic(),
     866             :                        CpOp                 op = FabArrayBase::COPY)
     867        6334 :        { ParallelCopy(src,src_comp,dest_comp,num_comp,IntVect(src_nghost),IntVect(dst_nghost),period,op); }
     868             :     void ParallelCopy (const FabArray<FAB>& src,
     869             :                        int                  scomp,
     870             :                        int                  dcomp,
     871             :                        int                  ncomp,
     872             :                        const IntVect&       snghost,
     873             :                        const IntVect&       dnghost,
     874             :                        const Periodicity&   period = Periodicity::NonPeriodic(),
     875             :                        CpOp                 op = FabArrayBase::COPY,
     876             :                        const FabArrayBase::CPC* a_cpc = nullptr);
     877             : 
     878             :     void ParallelAdd_nowait (const FabArray<FAB>& src,
     879             :                              int                  src_comp,
     880             :                              int                  dest_comp,
     881             :                              int                  num_comp,
     882             :                              int                  src_nghost,
     883             :                              int                  dst_nghost,
     884             :                              const Periodicity&   period = Periodicity::NonPeriodic())
     885             :        { ParallelCopy_nowait(src,src_comp,dest_comp,num_comp,IntVect(src_nghost),
     886             :                                IntVect(dst_nghost),period,FabArrayBase::ADD); }
     887             : 
     888             :     void ParallelAdd_nowait (const FabArray<FAB>& src,
     889             :                              int                  src_comp,
     890             :                              int                  dest_comp,
     891             :                              int                  num_comp,
     892             :                              const IntVect&       src_nghost,
     893             :                              const IntVect&       dst_nghost,
     894             :                              const Periodicity&   period = Periodicity::NonPeriodic())
     895             :        { ParallelCopy_nowait(src,src_comp,dest_comp,num_comp,src_nghost,
     896             :                              dst_nghost,period,FabArrayBase::ADD); }
     897             : 
     898             :     void ParallelCopy_nowait (const FabArray<FAB>& src,
     899             :                               int                  src_comp,
     900             :                               int                  dest_comp,
     901             :                               int                  num_comp,
     902             :                               int                  src_nghost,
     903             :                               int                  dst_nghost,
     904             :                               const Periodicity&   period = Periodicity::NonPeriodic(),
     905             :                               CpOp                 op = FabArrayBase::COPY)
     906             :        { ParallelCopy_nowait(src,src_comp,dest_comp,num_comp,IntVect(src_nghost),
     907             :                              IntVect(dst_nghost),period,op); }
     908             : 
     909             :     void ParallelCopy_nowait (const FabArray<FAB>& src,
     910             :                               int                  scomp,
     911             :                               int                  dcomp,
     912             :                               int                  ncomp,
     913             :                               const IntVect&       snghost,
     914             :                               const IntVect&       dnghost,
     915             :                               const Periodicity&   period = Periodicity::NonPeriodic(),
     916             :                               CpOp                 op = FabArrayBase::COPY,
     917             :                               const FabArrayBase::CPC* a_cpc = nullptr,
     918             :                               bool                 to_ghost_cells_only = false);
     919             : 
     920             :     void ParallelCopy_finish ();
     921             : 
     922             :     void ParallelCopyToGhost (const FabArray<FAB>& src,
     923             :                               int                  scomp,
     924             :                               int                  dcomp,
     925             :                               int                  ncomp,
     926             :                               const IntVect&       snghost,
     927             :                               const IntVect&       dnghost,
     928             :                               const Periodicity&   period = Periodicity::NonPeriodic());
     929             : 
     930             :     void ParallelCopyToGhost_nowait (const FabArray<FAB>& src,
     931             :                                      int                  scomp,
     932             :                                      int                  dcomp,
     933             :                                      int                  ncomp,
     934             :                                      const IntVect&       snghost,
     935             :                                      const IntVect&       dnghost,
     936             :                                      const Periodicity&   period = Periodicity::NonPeriodic());
     937             : 
     938             :     void ParallelCopyToGhost_finish();
     939             : 
     940             :     [[deprecated("Use FabArray::ParallelCopy() instead.")]]
     941             :     void copy (const FabArray<FAB>& src,
     942             :                int                  src_comp,
     943             :                int                  dest_comp,
     944             :                int                  num_comp,
     945             :                int                  src_nghost,
     946             :                int                  dst_nghost,
     947             :                const Periodicity&   period = Periodicity::NonPeriodic(),
     948             :                CpOp                 op = FabArrayBase::COPY)
     949             :        { ParallelCopy(src,src_comp,dest_comp,num_comp,IntVect(src_nghost),IntVect(dst_nghost),period,op); }
     950             : 
     951             :     [[deprecated("Use FabArray::ParallelCopy() instead.")]]
     952             :     void copy (const FabArray<FAB>& src,
     953             :                int                  src_comp,
     954             :                int                  dest_comp,
     955             :                int                  num_comp,
     956             :                const IntVect&       src_nghost,
     957             :                const IntVect&       dst_nghost,
     958             :                const Periodicity&   period = Periodicity::NonPeriodic(),
     959             :                CpOp                 op = FabArrayBase::COPY)
     960             :         { ParallelCopy(src,src_comp,dest_comp,num_comp,src_nghost,dst_nghost,period,op); }
     961             : 
     962             :     //! Copy from src to this.  this and src have the same BoxArray, but different DistributionMapping
     963             :     void Redistribute (const FabArray<FAB>& src,
     964             :                        int                  scomp,
     965             :                        int                  dcomp,
     966             :                        int                  ncomp,
     967             :                        const IntVect&       nghost);
     968             : 
     969             :     /**
     970             :     * \brief Copy the values contained in the intersection of the
     971             :     * valid + nghost region of this FabArray with the FAB dest into dest.
     972             :     * Note that FAB dest is assumed to be identical on each process.
     973             :     */
     974             :     void copyTo (FAB& dest, int  nghost = 0) const;
     975             : 
     976             :     /**
     977             :     * \brief Copy the values contained in the intersection of the
     978             :     * num_comp component valid + nghost region of this FabArray, starting at
     979             :     * component src_comp, with the FAB dest into dest, starting at
     980             :     * component dest_comp in dest.
     981             :     * Note that FAB dest is assumed to be identical on each process.
     982             :     */
     983             :     void copyTo (FAB& dest, int  scomp, int  dcomp, int  ncomp, int  nghost = 0) const;
     984             : 
     985             :     //! Shift the boxarray by vector v
     986             :     void shift (const IntVect& v);
     987             : 
     988             :     bool defined (int K) const noexcept;
     989             :     bool defined (const MFIter& mfi) const noexcept;
     990             : 
     991             :     /**
     992             :     * \brief Copy on intersection within a FabArray.  Data is copied from
     993             :     * valid regions to intersecting regions of definition.  The
     994             :     * purpose is to fill in the boundary regions of each FAB in
     995             :     * the FabArray.  If cross=true, corner cells are not filled.
     996             :     * If the length of periodic is provided, periodic boundaries are
     997             :     * also filled.  Note that FabArray itself does not contains
     998             :     * any periodicity information.
     999             :     * FillBoundary expects that its cell-centered version of its BoxArray
    1000             :     * is non-overlapping.
    1001             :     */
    1002             :     template <typename BUF=value_type>
    1003             :     void FillBoundary (bool cross = false);
    1004             : 
    1005             :     template <typename BUF=value_type>
    1006             :     void FillBoundary (const Periodicity& period, bool cross = false);
    1007             : 
    1008             :     template <typename BUF=value_type>
    1009             :     void FillBoundary (const IntVect& nghost, const Periodicity& period, bool cross = false);
    1010             : 
    1011             :     //! Same as FillBoundary(), but only copies ncomp components starting at scomp.
    1012             :     template <typename BUF=value_type>
    1013             :     void FillBoundary (int scomp, int ncomp, bool cross = false);
    1014             : 
    1015             :     template <typename BUF=value_type>
    1016             :     void FillBoundary (int scomp, int ncomp, const Periodicity& period, bool cross = false);
    1017             : 
    1018             :     template <typename BUF=value_type>
    1019             :     void FillBoundary (int scomp, int ncomp, const IntVect& nghost, const Periodicity& period, bool cross = false);
    1020             : 
    1021             :     template <typename BUF=value_type>
    1022             :     void FillBoundary_nowait (bool cross = false);
    1023             : 
    1024             :     template <typename BUF=value_type>
    1025             :     void FillBoundary_nowait (const Periodicity& period, bool cross = false);
    1026             : 
    1027             :     template <typename BUF=value_type>
    1028             :     void FillBoundary_nowait (const IntVect& nghost, const Periodicity& period, bool cross = false);
    1029             : 
    1030             :     template <typename BUF=value_type>
    1031             :     void FillBoundary_nowait (int scomp, int ncomp, bool cross = false);
    1032             : 
    1033             :     template <typename BUF=value_type>
    1034             :     void FillBoundary_nowait (int scomp, int ncomp, const Periodicity& period, bool cross = false);
    1035             : 
    1036             :     template <typename BUF=value_type>
    1037             :     void FillBoundary_nowait (int scomp, int ncomp, const IntVect& nghost, const Periodicity& period, bool cross = false);
    1038             : 
    1039             :     template <typename BUF=value_type,
    1040             :               class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
    1041             :     void FillBoundary_finish ();
    1042             : 
    1043             :     void FillBoundary_test ();
    1044             : 
    1045             : 
    1046             :     /**
    1047             :      * \brief Fill ghost cells and synchronize nodal data. Ghost regions are
    1048             :      * filled with data from the intersecting valid regions. The
    1049             :      * synchronization will override valid regions by the intersecting valid
    1050             :      * regions with a higher precedence.  The smaller the global box index
    1051             :      * is, the higher precedence the box has.  With periodic boundaries, for
    1052             :      * cells in the same box, those near the lower corner have higher
    1053             :      * precedence than those near the upper corner.
    1054             :      *
    1055             :      * \param period periodic length if it's non-zero
    1056             :      */
    1057             :     void FillBoundaryAndSync (const Periodicity& period = Periodicity::NonPeriodic());
    1058             :     /**
    1059             :      * \brief Fill ghost cells and synchronize nodal data. Ghost regions are
    1060             :      * filled with data from the intersecting valid regions. The
    1061             :      * synchronization will override valid regions by the intersecting valid
    1062             :      * regions with a higher precedence.  The smaller the global box index
    1063             :      * is, the higher precedence the box has.  With periodic boundaries, for
    1064             :      * cells in the same box, those near the lower corner have higher
    1065             :      * precedence than those near the upper corner.
    1066             :      *
    1067             :      * \param scomp starting component
    1068             :      * \param ncomp number of components
    1069             :      * \param nghost number of ghost cells to fill
    1070             :      * \param period periodic length if it's non-zero
    1071             :      */
    1072             :     void FillBoundaryAndSync (int scomp, int ncomp, const IntVect& nghost,
    1073             :                               const Periodicity& period);
    1074             :     void FillBoundaryAndSync_nowait (const Periodicity& period = Periodicity::NonPeriodic());
    1075             :     void FillBoundaryAndSync_nowait (int scomp, int ncomp, const IntVect& nghost,
    1076             :                                      const Periodicity& period);
    1077             :     void FillBoundaryAndSync_finish ();
    1078             : 
    1079             :     /**
    1080             :      * \brief Synchronize nodal data.  The synchronization will override
    1081             :      * valid regions by the intersecting valid regions with a higher
    1082             :      * precedence.  The smaller the global box index is, the higher
    1083             :      * precedence the box has.  With periodic boundaries, for cells in the
    1084             :      * same box, those near the lower corner have higher precedence than
    1085             :      * those near the upper corner.
    1086             :      *
    1087             :      * \param period periodic length if it's non-zero
    1088             :      */
    1089             :     void OverrideSync (const Periodicity& period = Periodicity::NonPeriodic());
    1090             :     /**
    1091             :      * \brief Synchronize nodal data.  The synchronization will override
    1092             :      * valid regions by the intersecting valid regions with a higher
    1093             :      * precedence.  The smaller the global box index is, the higher
    1094             :      * precedence the box has.  With periodic boundaries, for cells in the
    1095             :      * same box, those near the lower corner have higher precedence than
    1096             :      * those near the upper corner.
    1097             :      *
    1098             :      * \param scomp starting component
    1099             :      * \param ncomp number of components
    1100             :      * \param period periodic length if it's non-zero
    1101             :      */
    1102             :     void OverrideSync (int scomp, int ncomp, const Periodicity& period);
    1103             :     void OverrideSync_nowait (const Periodicity& period = Periodicity::NonPeriodic());
    1104             :     void OverrideSync_nowait (int scomp, int ncomp, const Periodicity& period);
    1105             :     void OverrideSync_finish ();
    1106             : 
    1107             :     /**
    1108             :     * \brief Sum values in overlapped cells.  The destination is limited to valid cells.
    1109             :     */
    1110             :     void SumBoundary (const Periodicity& period = Periodicity::NonPeriodic());
    1111             :     void SumBoundary (int scomp, int ncomp, const Periodicity& period = Periodicity::NonPeriodic());
    1112             :     void SumBoundary_nowait (const Periodicity& period = Periodicity::NonPeriodic());
    1113             :     void SumBoundary_nowait (int scomp, int ncomp, const Periodicity& period = Periodicity::NonPeriodic());
    1114             : 
    1115             :     /**
    1116             :     * \brief Sum values in overlapped cells.  The destination is limited to valid + ngrow cells.
    1117             :     */
    1118             :     void SumBoundary (int scomp, int ncomp, IntVect const& nghost,
    1119             :                       const Periodicity& period = Periodicity::NonPeriodic());
    1120             :     void SumBoundary_nowait (int scomp, int ncomp, IntVect const& nghost,
    1121             :                              const Periodicity& period = Periodicity::NonPeriodic());
    1122             : 
    1123             :     /**
    1124             :     * \brief Sum values in overlapped cells.
    1125             :     *        For computing the overlap, the dst is grown by dst_ngrow, while the src uses src_ngrow.
    1126             :     */
    1127             :     void SumBoundary (int scomp, int ncomp, IntVect const& src_nghost, IntVect const& dst_nghost,
    1128             :                       const Periodicity& period = Periodicity::NonPeriodic());
    1129             :     void SumBoundary_nowait (int scomp, int ncomp, IntVect const& src_nghost, IntVect const& dst_nghost,
    1130             :                              const Periodicity& period = Periodicity::NonPeriodic());
    1131             :     void SumBoundary_finish ();
    1132             : 
    1133             :     /** \brief Fill ghost cells with values from their corresponding cells across periodic
    1134             :     * boundaries, regardless of whether the corresponding cells are valid. This differs from
    1135             :     * FillBoundary, which only fills from valid cells, and does not fill from ghost cells.
    1136             :     * The BoxArray is allowed to be overlapping.
    1137             :     */
    1138             :     void EnforcePeriodicity (const Periodicity& period);
    1139             :     void EnforcePeriodicity (int scomp, int ncomp, const Periodicity& period);
    1140             :     void EnforcePeriodicity (int scomp, int ncomp, const IntVect& nghost,
    1141             :                              const Periodicity& period);
    1142             : 
    1143             :     // covered   : ghost cells covered by valid cells of this FabArray
    1144             :     //             (including periodically shifted valid cells)
    1145             :     // notcovered: ghost cells not covered by valid cells
    1146             :     //             (including ghost cells outside periodic boundaries)
    1147             :     // physbnd   : boundary cells outside the domain (excluding periodic boundaries)
    1148             :     // interior  : interior cells (i.e., valid cells)
    1149             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
    1150             :     void BuildMask (const Box& phys_domain, const Periodicity& period,
    1151             :                     value_type covered, value_type notcovered,
    1152             :                     value_type physbnd, value_type interior);
    1153             : 
    1154             :     // The following are private functions.  But we have to make them public for cuda.
    1155             : 
    1156             :     template <typename BUF=value_type,
    1157             :               class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
    1158             :     void FBEP_nowait (int scomp, int ncomp, const IntVect& nghost,
    1159             :                       const Periodicity& period, bool cross,
    1160             :                       bool enforce_periodicity_only = false,
    1161             :                       bool override_sync = false);
    1162             : 
    1163             :     void FB_local_copy_cpu (const FB& TheFB, int scomp, int ncomp);
    1164             :     void PC_local_cpu (const CPC& thecpc, FabArray<FAB> const& src,
    1165             :                        int scomp, int dcomp, int ncomp, CpOp op);
    1166             : 
    1167             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
    1168             :     void setVal (value_type val, const CommMetaData& thecmd, int scomp, int ncomp);
    1169             : 
    1170             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
    1171             :     LayoutData<int> RecvLayoutMask (const CommMetaData& thecmd);
    1172             : 
    1173             : #ifdef AMREX_USE_GPU
    1174             : 
    1175             :     void FB_local_copy_gpu (const FB& TheFB, int scomp, int ncomp);
    1176             :     void PC_local_gpu (const CPC& thecpc, FabArray<FAB> const& src,
    1177             :                        int scomp, int dcomp, int ncomp, CpOp op);
    1178             : 
    1179             :     void CMD_local_setVal_gpu (value_type x, const CommMetaData& thecmd, int scomp, int ncomp);
    1180             :     void CMD_remote_setVal_gpu (value_type x, const CommMetaData& thecmd, int scomp, int ncomp);
    1181             : 
    1182             : #if defined(__CUDACC__)
    1183             : 
    1184             :     void FB_local_copy_cuda_graph_1 (const FB& TheFB, int scomp, int ncomp);
    1185             :     void FB_local_copy_cuda_graph_n (const FB& TheFB, int scomp, int ncomp);
    1186             : 
    1187             : #endif
    1188             : #endif
    1189             : 
    1190             : #ifdef AMREX_USE_MPI
    1191             : 
    1192             : #ifdef AMREX_USE_GPU
    1193             : #if defined(__CUDACC__)
    1194             : 
    1195             :     void FB_pack_send_buffer_cuda_graph (const FB& TheFB, int scomp, int ncomp,
    1196             :                                          Vector<char*>& send_data,
    1197             :                                          Vector<std::size_t> const& send_size,
    1198             :                                          Vector<const CopyComTagsContainer*> const& send_cctc);
    1199             : 
    1200             :     void FB_unpack_recv_buffer_cuda_graph (const FB& TheFB, int dcomp, int ncomp,
    1201             :                                            Vector<char*> const& recv_data,
    1202             :                                            Vector<std::size_t> const& recv_size,
    1203             :                                            Vector<const CopyComTagsContainer*> const& recv_cctc,
    1204             :                                            bool is_thread_safe);
    1205             : 
    1206             : #endif
    1207             : 
    1208             :     template <typename BUF = value_type>
    1209             :     static void pack_send_buffer_gpu (FabArray<FAB> const& src, int scomp, int ncomp,
    1210             :                                       Vector<char*> const& send_data,
    1211             :                                       Vector<std::size_t> const& send_size,
    1212             :                                       Vector<const CopyComTagsContainer*> const& send_cctc);
    1213             : 
    1214             :     template <typename BUF = value_type>
    1215             :     static void unpack_recv_buffer_gpu (FabArray<FAB>& dst, int dcomp, int ncomp,
    1216             :                                         Vector<char*> const& recv_data,
    1217             :                                         Vector<std::size_t> const& recv_size,
    1218             :                                         Vector<const CopyComTagsContainer*> const& recv_cctc,
    1219             :                                         CpOp op, bool is_thread_safe);
    1220             : 
    1221             : #endif
    1222             : 
    1223             :     template <typename BUF = value_type>
    1224             :     static void pack_send_buffer_cpu (FabArray<FAB> const& src, int scomp, int ncomp,
    1225             :                                       Vector<char*> const& send_data,
    1226             :                                       Vector<std::size_t> const& send_size,
    1227             :                                       Vector<const CopyComTagsContainer*> const& send_cctc);
    1228             : 
    1229             :     template <typename BUF = value_type>
    1230             :     static void unpack_recv_buffer_cpu (FabArray<FAB>& dst, int dcomp, int ncomp,
    1231             :                                         Vector<char*> const& recv_data,
    1232             :                                         Vector<std::size_t> const& recv_size,
    1233             :                                         Vector<const CopyComTagsContainer*> const& recv_cctc,
    1234             :                                         CpOp op, bool is_thread_safe);
    1235             : 
    1236             : #endif
    1237             : 
    1238             :     /**
    1239             :      * \brief Return infinity norm
    1240             :      *
    1241             :      * \param comp           starting component
    1242             :      * \param ncomp          number of components
    1243             :      * \param nghost         number of ghost cells
    1244             :      * \param local          If true, MPI communication is skipped.
    1245             :      * \param ignore_covered ignore covered cells. Only relevant for cell-centered EB data.
    1246             :      */
    1247             :     template <typename F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
    1248             :     typename F::value_type
    1249             :     norminf (int comp, int ncomp, IntVect const& nghost, bool local = false,
    1250             :              [[maybe_unused]] bool ignore_covered = false) const;
    1251             : 
    1252             :     /**
    1253             :      * \brief Return infinity norm in masked region
    1254             :      *
    1255             :      * \param mask   only mask=true region is included
    1256             :      * \param comp   starting component
    1257             :      * \param ncomp  number of components
    1258             :      * \param nghost number of ghost cells
    1259             :      * \param local  If true, MPI communication is skipped.
    1260             :      */
    1261             :     template <typename IFAB, typename F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
    1262             :     typename F::value_type
    1263             :     norminf (FabArray<IFAB> const& mask, int comp, int ncomp, IntVect const& nghost,
    1264             :              bool local = false) const;
    1265             : 
    1266             : protected:
    1267             : 
    1268             :     std::unique_ptr<FabFactory<FAB> > m_factory;
    1269             :     DataAllocator m_dallocator;
    1270             :     std::unique_ptr<detail::SingleChunkArena> m_single_chunk_arena;
    1271             :     Long m_single_chunk_size = 0;
    1272             : 
    1273             :     //! has define() been called?
    1274             :     bool define_function_called = false;
    1275             : 
    1276             :     //
    1277             :     //! The data.
    1278             :     std::vector<FAB*> m_fabs_v;
    1279             : 
    1280             : #ifdef AMREX_USE_GPU
    1281             :     mutable void* m_dp_arrays = nullptr;
    1282             : #endif
    1283             :     mutable void* m_hp_arrays = nullptr;
    1284             :     mutable MultiArray4<value_type> m_arrays;
    1285             :     mutable MultiArray4<value_type const> m_const_arrays;
    1286             : 
    1287             :     Vector<std::string> m_tags;
    1288             : 
    1289             :     //! for shared memory
    1290             :     struct ShMem {
    1291             : 
    1292      403505 :         ShMem () noexcept = default;
    1293             : 
    1294      452872 :         ~ShMem () { // NOLINT
    1295             : #if defined(BL_USE_MPI3)
    1296             :             if (win != MPI_WIN_NULL) { MPI_Win_free(&win); }
    1297             : #endif
    1298             : #ifdef BL_USE_TEAM
    1299             :             if (alloc) {
    1300             :                 amrex::update_fab_stats(-n_points, -n_values, sizeof(value_type));
    1301             :             }
    1302             : #endif
    1303      452872 :         }
    1304           0 :         ShMem (ShMem&& rhs) noexcept
    1305           0 :                  : alloc(rhs.alloc), n_values(rhs.n_values), n_points(rhs.n_points)
    1306             : #if defined(BL_USE_MPI3)
    1307             :                  , win(rhs.win)
    1308             : #endif
    1309             :         {
    1310           0 :             rhs.alloc = false;
    1311             : #if defined(BL_USE_MPI3)
    1312             :             rhs.win = MPI_WIN_NULL;
    1313             : #endif
    1314           0 :         }
    1315       11120 :         ShMem& operator= (ShMem&& rhs) noexcept {
    1316       11120 :             if (&rhs != this) {
    1317       11120 :                 alloc = rhs.alloc;
    1318       11120 :                 n_values = rhs.n_values;
    1319       11120 :                 n_points = rhs.n_points;
    1320       11120 :                 rhs.alloc = false;
    1321             : #if defined(BL_USE_MPI3)
    1322             :                 win = rhs.win;
    1323             :                 rhs.win = MPI_WIN_NULL;
    1324             : #endif
    1325             :             }
    1326       11120 :             return *this;
    1327             :         }
    1328             :         ShMem (const ShMem&) = delete;
    1329             :         ShMem& operator= (const ShMem&) = delete;
    1330             :         bool  alloc{false};
    1331             :         Long  n_values{0};
    1332             :         Long  n_points{0};
    1333             : #if defined(BL_USE_MPI3)
    1334             :         MPI_Win win = MPI_WIN_NULL;
    1335             : #endif
    1336             :     };
    1337             :     ShMem shmem;
    1338             : 
    1339             :     bool SharedMemory () const noexcept { return shmem.alloc; }
    1340             : 
    1341             : private:
    1342             :     using Iterator = typename std::vector<FAB*>::iterator;
    1343             : 
    1344             :     void AllocFabs (const FabFactory<FAB>& factory, Arena* ar,
    1345             :                     const Vector<std::string>& tags,
    1346             :                     bool alloc_single_chunk);
    1347             : 
    1348             :     void setFab_assert (int K, FAB const& fab) const;
    1349             : 
    1350             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
    1351             :     void build_arrays () const;
    1352             : 
    1353             :     void clear_arrays ();
    1354             : 
    1355             : public:
    1356             : 
    1357             : #ifdef BL_USE_MPI
    1358             : 
    1359             :     //! Prepost nonblocking receives
    1360             :     template <typename BUF=value_type>
    1361             :     static void PostRcvs (const MapOfCopyComTagContainers&       RcvTags,
    1362             :                    char*&                                 the_recv_data,
    1363             :                    Vector<char*>&                         recv_data,
    1364             :                    Vector<std::size_t>&                   recv_size,
    1365             :                    Vector<int>&                           recv_from,
    1366             :                    Vector<MPI_Request>&                   recv_reqs,
    1367             :                    int                                    ncomp,
    1368             :                    int                                    SeqNum);
    1369             : 
    1370             :     template <typename BUF=value_type>
    1371             :     AMREX_NODISCARD
    1372             :     static TheFaArenaPointer PostRcvs (const MapOfCopyComTagContainers&       RcvTags,
    1373             :                    Vector<char*>&                         recv_data,
    1374             :                    Vector<std::size_t>&                   recv_size,
    1375             :                    Vector<int>&                           recv_from,
    1376             :                    Vector<MPI_Request>&                   recv_reqs,
    1377             :                    int                                    ncomp,
    1378             :                    int                                    SeqNum);
    1379             : 
    1380             :     template <typename BUF=value_type>
    1381             :     static void PrepareSendBuffers (const MapOfCopyComTagContainers&     SndTags,
    1382             :                              char*&                               the_send_data,
    1383             :                              Vector<char*>&                       send_data,
    1384             :                              Vector<std::size_t>&                 send_size,
    1385             :                              Vector<int>&                         send_rank,
    1386             :                              Vector<MPI_Request>&                 send_reqs,
    1387             :                              Vector<const CopyComTagsContainer*>& send_cctc,
    1388             :                              int                                  ncomp);
    1389             : 
    1390             :     template <typename BUF=value_type>
    1391             :     AMREX_NODISCARD
    1392             :     static TheFaArenaPointer PrepareSendBuffers (const MapOfCopyComTagContainers&     SndTags,
    1393             :                              Vector<char*>&                       send_data,
    1394             :                              Vector<std::size_t>&                 send_size,
    1395             :                              Vector<int>&                         send_rank,
    1396             :                              Vector<MPI_Request>&                 send_reqs,
    1397             :                              Vector<const CopyComTagsContainer*>& send_cctc,
    1398             :                              int                                  ncomp);
    1399             : 
    1400             :     static void PostSnds (Vector<char*> const&       send_data,
    1401             :                           Vector<std::size_t> const& send_size,
    1402             :                           Vector<int> const&         send_rank,
    1403             :                           Vector<MPI_Request>&       send_reqs,
    1404             :                           int                        SeqNum);
    1405             : #endif
    1406             : 
    1407             :     std::unique_ptr<FBData<FAB>> fbd;
    1408             :     std::unique_ptr<PCData<FAB>> pcd;
    1409             : 
    1410             :     // Pointer to temporary fab used in non-blocking amrex::OverrideSync
    1411             :     std::unique_ptr< FabArray<FAB> > os_temp;
    1412             : 
    1413             : 
    1414             : 
    1415             :     /**
    1416             :      * \brief y += a*x
    1417             :      *
    1418             :      * \param y      FabArray y
    1419             :      * \param a      scalar a
    1420             :      * \param x      FabArray x
    1421             :      * \param xcomp  starting component of x
    1422             :      * \param ycomp  starting component of y
    1423             :      * \param ncomp  number of components
    1424             :      * \param nghost number of ghost cells
    1425             :      */
    1426             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
    1427             :     static void Saxpy (FabArray<FAB>& y, value_type a, FabArray<FAB> const& x,
    1428             :                        int xcomp, int ycomp, int ncomp, IntVect const& nghost);
    1429             : 
    1430             :     /**
    1431             :      * \brief y = x + a*y
    1432             :      *
    1433             :      * \param y      FabArray y
    1434             :      * \param a      scalar a
    1435             :      * \param x      FabArray x
    1436             :      * \param xcomp  starting component of x
    1437             :      * \param ycomp  starting component of y
    1438             :      * \param ncomp  number of components
    1439             :      * \param nghost number of ghost cells
    1440             :      */
    1441             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
    1442             :     static void Xpay (FabArray<FAB>& y, value_type a, FabArray<FAB> const& x,
    1443             :                       int xcomp, int ycomp, int ncomp, IntVect const& nghost);
    1444             : 
    1445             :     /**
    1446             :      * \brief dst = a*x + b*y
    1447             :      *
    1448             :      * \param dst     destination FabArray
    1449             :      * \param a       scalar a
    1450             :      * \param x       FabArray x
    1451             :      * \param xcomp   starting component of x
    1452             :      * \param b       scalar b
    1453             :      * \param y       FabArray y
    1454             :      * \param ycomp   starting component of y
    1455             :      * \param dstcomp starting component of destination
    1456             :      * \param numcomp number of components
    1457             :      * \param nghost  number of ghost cells
    1458             :      */
    1459             :     template <class F=FAB, std::enable_if_t<IsBaseFab<F>::value,int> = 0>
    1460             :     static void LinComb (FabArray<FAB>& dst,
    1461             :                          value_type a, const FabArray<FAB>& x, int xcomp,
    1462             :                          value_type b, const FabArray<FAB>& y, int ycomp,
    1463             :                          int dstcomp, int numcomp, const IntVect& nghost);
    1464             : };
    1465             : 
    1466             : 
    1467             : #include <AMReX_FabArrayCommI.H>
    1468             : 
    1469             : template <class FAB>
    1470             : bool
    1471             : FabArray<FAB>::defined (int K) const noexcept
    1472             : {
    1473             :     int li = localindex(K);
    1474             :     if (li >= 0 && li < static_cast<int>(m_fabs_v.size()) && m_fabs_v[li] != 0) {
    1475             :         return true;
    1476             :     }
    1477             :     else {
    1478             :         return false;
    1479             :     }
    1480             : }
    1481             : 
    1482             : template <class FAB>
    1483             : bool
    1484             : FabArray<FAB>::defined (const MFIter& mfi) const noexcept
    1485             : {
    1486             :     int li = mfi.LocalIndex();
    1487             :     if (li < static_cast<int>(m_fabs_v.size()) && m_fabs_v[li] != nullptr) {
    1488             :         return true;
    1489             :     }
    1490             :     else {
    1491             :         return false;
    1492             :     }
    1493             : }
    1494             : 
    1495             : template <class FAB>
    1496             : FAB*
    1497     2800506 : FabArray<FAB>::fabPtr (const MFIter& mfi) noexcept
    1498             : {
    1499             :     AMREX_ASSERT(mfi.LocalIndex() < indexArray.size());
    1500             :     AMREX_ASSERT(DistributionMap() == mfi.DistributionMap());
    1501     2800506 :     int li = mfi.LocalIndex();
    1502     2800506 :     return m_fabs_v[li];
    1503             : }
    1504             : 
    1505             : template <class FAB>
    1506             : FAB const*
    1507     1956420 : FabArray<FAB>::fabPtr (const MFIter& mfi) const noexcept
    1508             : {
    1509             :     AMREX_ASSERT(mfi.LocalIndex() < indexArray.size());
    1510             :     AMREX_ASSERT(DistributionMap() == mfi.DistributionMap());
    1511     1956420 :     int li = mfi.LocalIndex();
    1512     1956420 :     return m_fabs_v[li];
    1513             : }
    1514             : 
    1515             : template <class FAB>
    1516             : FAB*
    1517       18298 : FabArray<FAB>::fabPtr (int K) noexcept
    1518             : {
    1519       18298 :     int li = localindex(K);
    1520             :     AMREX_ASSERT(li >=0 && li < indexArray.size());
    1521       18298 :     return m_fabs_v[li];
    1522             : }
    1523             : 
    1524             : template <class FAB>
    1525             : FAB const*
    1526        8850 : FabArray<FAB>::fabPtr (int K) const noexcept
    1527             : {
    1528        8850 :     int li = localindex(K);
    1529             :     AMREX_ASSERT(li >=0 && li < indexArray.size());
    1530        8850 :     return m_fabs_v[li];
    1531             : }
    1532             : 
    1533             : template <class FAB>
    1534             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1535             : void
    1536             : FabArray<FAB>::prefetchToHost (const MFIter& mfi) const noexcept
    1537             : {
    1538             : #ifdef AMREX_USE_CUDA
    1539             :     this->fabPtr(mfi)->prefetchToHost();
    1540             : #else
    1541             :     amrex::ignore_unused(mfi);
    1542             : #endif
    1543             : }
    1544             : 
    1545             : template <class FAB>
    1546             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1547             : void
    1548             : FabArray<FAB>::prefetchToDevice (const MFIter& mfi) const noexcept
    1549             : {
    1550             : #ifdef AMREX_USE_CUDA
    1551             :     this->fabPtr(mfi)->prefetchToDevice();
    1552             : #else
    1553             :     amrex::ignore_unused(mfi);
    1554             : #endif
    1555             : }
    1556             : 
    1557             : template <class FAB>
    1558             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1559             : Array4<typename FabArray<FAB>::value_type const>
    1560     1155950 : FabArray<FAB>::array (const MFIter& mfi) const noexcept
    1561             : {
    1562     1155950 :     return fabPtr(mfi)->const_array();
    1563             : }
    1564             : 
    1565             : template <class FAB>
    1566             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1567             : Array4<typename FabArray<FAB>::value_type>
    1568     2674466 : FabArray<FAB>::array (const MFIter& mfi) noexcept
    1569             : {
    1570     2674466 :     return fabPtr(mfi)->array();
    1571             : }
    1572             : 
    1573             : template <class FAB>
    1574             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1575             : Array4<typename FabArray<FAB>::value_type const>
    1576           0 : FabArray<FAB>::array (int K) const noexcept
    1577             : {
    1578           0 :     return fabPtr(K)->const_array();
    1579             : }
    1580             : 
    1581             : template <class FAB>
    1582             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1583             : Array4<typename FabArray<FAB>::value_type>
    1584             : FabArray<FAB>::array (int K) noexcept
    1585             : {
    1586             :     return fabPtr(K)->array();
    1587             : }
    1588             : 
    1589             : template <class FAB>
    1590             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1591             : Array4<typename FabArray<FAB>::value_type const>
    1592      757312 : FabArray<FAB>::const_array (const MFIter& mfi) const noexcept
    1593             : {
    1594      757312 :     return fabPtr(mfi)->const_array();
    1595             : }
    1596             : 
    1597             : template <class FAB>
    1598             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1599             : Array4<typename FabArray<FAB>::value_type const>
    1600             : FabArray<FAB>::const_array (int K) const noexcept
    1601             : {
    1602             :     return fabPtr(K)->const_array();
    1603             : }
    1604             : 
    1605             : template <class FAB>
    1606             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1607             : Array4<typename FabArray<FAB>::value_type const>
    1608             : FabArray<FAB>::array (const MFIter& mfi, int start_comp) const noexcept
    1609             : {
    1610             :     return fabPtr(mfi)->const_array(start_comp);
    1611             : }
    1612             : 
    1613             : template <class FAB>
    1614             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1615             : Array4<typename FabArray<FAB>::value_type>
    1616             : FabArray<FAB>::array (const MFIter& mfi, int start_comp) noexcept
    1617             : {
    1618             :     return fabPtr(mfi)->array(start_comp);
    1619             : }
    1620             : 
    1621             : template <class FAB>
    1622             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1623             : Array4<typename FabArray<FAB>::value_type const>
    1624             : FabArray<FAB>::array (int K, int start_comp) const noexcept
    1625             : {
    1626             :     return fabPtr(K)->const_array(start_comp);
    1627             : }
    1628             : 
    1629             : template <class FAB>
    1630             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1631             : Array4<typename FabArray<FAB>::value_type>
    1632             : FabArray<FAB>::array (int K, int start_comp) noexcept
    1633             : {
    1634             :     return fabPtr(K)->array(start_comp);
    1635             : }
    1636             : 
    1637             : template <class FAB>
    1638             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1639             : Array4<typename FabArray<FAB>::value_type const>
    1640             : FabArray<FAB>::const_array (const MFIter& mfi, int start_comp) const noexcept
    1641             : {
    1642             :     return fabPtr(mfi)->const_array(start_comp);
    1643             : }
    1644             : 
    1645             : template <class FAB>
    1646             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1647             : Array4<typename FabArray<FAB>::value_type const>
    1648             : FabArray<FAB>::const_array (int K, int start_comp) const noexcept
    1649             : {
    1650             :     return fabPtr(K)->const_array(start_comp);
    1651             : }
    1652             : 
    1653             : template <class FAB>
    1654             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1655             : MultiArray4<typename FabArray<FAB>::value_type>
    1656             : FabArray<FAB>::arrays () noexcept
    1657             : {
    1658             :     build_arrays();
    1659             :     return m_arrays;
    1660             : }
    1661             : 
    1662             : template <class FAB>
    1663             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1664             : MultiArray4<typename FabArray<FAB>::value_type const>
    1665             : FabArray<FAB>::arrays () const noexcept
    1666             : {
    1667             :     build_arrays();
    1668             :     return m_const_arrays;
    1669             : }
    1670             : 
    1671             : template <class FAB>
    1672             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1673             : MultiArray4<typename FabArray<FAB>::value_type const>
    1674             : FabArray<FAB>::const_arrays () const noexcept
    1675             : {
    1676             :     build_arrays();
    1677             :     return m_const_arrays;
    1678             : }
    1679             : 
    1680             : template <class FAB>
    1681             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1682             : void
    1683             : FabArray<FAB>::build_arrays () const
    1684             : {
    1685             :     using A = Array4<value_type>;
    1686             :     using AC = Array4<value_type const>;
    1687             :     static_assert(sizeof(A) == sizeof(AC), "sizeof(Array4<T>) != sizeof(Array4<T const>)");
    1688             :     if (!m_hp_arrays && local_size() > 0) {
    1689             :         const int n = local_size();
    1690             : #ifdef AMREX_USE_GPU
    1691             :         m_hp_arrays = (void*)The_Pinned_Arena()->alloc(n*2*sizeof(A));
    1692             :         m_dp_arrays = (void*)The_Arena()->alloc(n*2*sizeof(A));
    1693             : #else
    1694             :         m_hp_arrays = (void*)std::malloc(n*2*sizeof(A));
    1695             : #endif
    1696             :         for (int li = 0; li < n; ++li) {
    1697             :             if (m_fabs_v[li]) {
    1698             :                 new ((A*)m_hp_arrays+li) A(m_fabs_v[li]->array());
    1699             :                 new ((AC*)m_hp_arrays+li+n) AC(m_fabs_v[li]->const_array());
    1700             :             } else {
    1701             :                 new ((A*)m_hp_arrays+li) A{};
    1702             :                 new ((AC*)m_hp_arrays+li+n) AC{};
    1703             :             }
    1704             :         }
    1705             :         m_arrays.hp = (A*)m_hp_arrays;
    1706             :         m_const_arrays.hp = (AC*)m_hp_arrays + n;
    1707             : #ifdef AMREX_USE_GPU
    1708             :         m_arrays.dp = (A*)m_dp_arrays;
    1709             :         m_const_arrays.dp = (AC*)m_dp_arrays + n;
    1710             :         Gpu::htod_memcpy(m_dp_arrays, m_hp_arrays, n*2*sizeof(A));
    1711             : #endif
    1712             :     }
    1713             : }
    1714             : 
    1715             : template <class FAB>
    1716             : void
    1717      884068 : FabArray<FAB>::clear_arrays ()
    1718             : {
    1719             : #ifdef AMREX_USE_GPU
    1720             :     The_Pinned_Arena()->free(m_hp_arrays);
    1721             :     The_Arena()->free(m_dp_arrays);
    1722             :     m_dp_arrays = nullptr;
    1723             : #else
    1724      884068 :     std::free(m_hp_arrays);
    1725             : #endif
    1726      884068 :     m_hp_arrays = nullptr;
    1727      884068 :     m_arrays.hp = nullptr;
    1728      884068 :     m_const_arrays.hp = nullptr;
    1729      884068 : }
    1730             : 
    1731             : template <class FAB>
    1732             : AMREX_NODISCARD
    1733             : FAB*
    1734             : FabArray<FAB>::release (int K)
    1735             : {
    1736             :     const int li = localindex(K);
    1737             :     if (li >= 0 && li < static_cast<int>(m_fabs_v.size()) && m_fabs_v[li] != nullptr) {
    1738             :         AMREX_ASSERT(m_single_chunk_arena == nullptr);
    1739             :         Long nbytes = amrex::nBytesOwned(*m_fabs_v[li]);
    1740             :         if (nbytes > 0) {
    1741             :             for (auto const& t : m_tags) {
    1742             :                 updateMemUsage(t, -nbytes, nullptr);
    1743             :             }
    1744             :         }
    1745             :         return std::exchange(m_fabs_v[li], nullptr);
    1746             :     } else {
    1747             :         return nullptr;
    1748             :     }
    1749             : }
    1750             : 
    1751             : template <class FAB>
    1752             : AMREX_NODISCARD
    1753             : FAB*
    1754             : FabArray<FAB>::release (const MFIter& mfi)
    1755             : {
    1756             :     const int li = mfi.LocalIndex();
    1757             :     if (li >= 0 && li < static_cast<int>(m_fabs_v.size()) && m_fabs_v[li] != nullptr) {
    1758             :         AMREX_ASSERT(m_single_chunk_arena == nullptr);
    1759             :         Long nbytes = amrex::nBytesOwned(*m_fabs_v[li]);
    1760             :         if (nbytes > 0) {
    1761             :             for (auto const& t : m_tags) {
    1762             :                 updateMemUsage(t, -nbytes, nullptr);
    1763             :             }
    1764             :         }
    1765             :         return std::exchange(m_fabs_v[li], nullptr);
    1766             :     } else {
    1767             :         return nullptr;
    1768             :     }
    1769             : }
    1770             : 
    1771             : template <class FAB>
    1772             : void
    1773      884068 : FabArray<FAB>::clear ()
    1774             : {
    1775      884068 :     if (define_function_called)
    1776             :     {
    1777      406261 :         define_function_called = false;
    1778      406261 :         clearThisBD();  //!< addThisBD is called in define
    1779             :     }
    1780             : 
    1781      884068 :     Long nbytes = 0L;
    1782     1290890 :     for (auto *x : m_fabs_v) {
    1783      406826 :         if (x) {
    1784      406826 :             nbytes += amrex::nBytesOwned(*x);
    1785      406826 :             m_factory->destroy(x);
    1786             :         }
    1787             :     }
    1788      884068 :     m_fabs_v.clear();
    1789      884068 :     clear_arrays();
    1790      884068 :     m_factory.reset();
    1791      884068 :     m_dallocator.m_arena = nullptr;
    1792             :     // no need to clear the non-blocking fillboundary stuff
    1793             : 
    1794      884068 :     if (nbytes > 0) {
    1795      810122 :         for (auto const& t : m_tags) {
    1796      405061 :             updateMemUsage(t, -nbytes, nullptr);
    1797             :         }
    1798             :     }
    1799             : 
    1800      884068 :     if (m_single_chunk_arena) {
    1801           0 :         m_single_chunk_arena.reset();
    1802             :     }
    1803      884068 :     m_single_chunk_size = 0;
    1804             : 
    1805      884068 :     m_tags.clear();
    1806             : 
    1807      884068 :     FabArrayBase::clear();
    1808      884068 : }
    1809             : 
    1810             : template <class FAB>
    1811             : template <typename SFAB, typename DFAB,
    1812             :           std::enable_if_t<std::conjunction_v<
    1813             :               IsBaseFab<DFAB>, IsBaseFab<SFAB>,
    1814             :               std::is_convertible<typename SFAB::value_type,
    1815             :                                   typename DFAB::value_type>>, int>>
    1816             : void
    1817             : FabArray<FAB>::LocalCopy (FabArray<SFAB> const& src, int scomp, int dcomp, int ncomp,
    1818             :                           IntVect const& nghost)
    1819             : {
    1820             :     amrex::Copy(*this, src, scomp, dcomp, ncomp, nghost);
    1821             : }
    1822             : 
    1823             : template <class FAB>
    1824             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1825             : void
    1826             : FabArray<FAB>::LocalAdd (FabArray<FAB> const& src, int scomp, int dcomp, int ncomp,
    1827             :                          IntVect const& nghost)
    1828             : {
    1829             :     amrex::Add(*this, src, scomp, dcomp, ncomp, nghost);
    1830             : }
    1831             : 
    1832             : template <class FAB>
    1833             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1834             : void
    1835             : FabArray<FAB>::setVal (value_type val, int nghost)
    1836             : {
    1837             :     setVal(val,0,n_comp,IntVect(nghost));
    1838             : }
    1839             : 
    1840             : template <class FAB>
    1841             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1842             : void
    1843             : FabArray<FAB>::setVal (value_type val, const IntVect& nghost)
    1844             : {
    1845             :     setVal(val,0,n_comp,nghost);
    1846             : }
    1847             : 
    1848             : template <class FAB>
    1849             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1850             : void
    1851             : FabArray<FAB>::setVal (value_type val, const Box& region, int nghost)
    1852             : {
    1853             :     setVal(val,region,0,n_comp,IntVect(nghost));
    1854             : }
    1855             : 
    1856             : template <class FAB>
    1857             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    1858             : void
    1859             : FabArray<FAB>::setVal (value_type val, const Box& region, const IntVect& nghost)
    1860             : {
    1861             :     setVal(val,region,0,n_comp,nghost);
    1862             : }
    1863             : 
    1864             : template <class FAB>
    1865         300 : FabArray<FAB>::FabArray () noexcept
    1866         300 :     : shmem()
    1867             : {
    1868         300 :     m_FA_stats.recordBuild();
    1869         300 : }
    1870             : 
    1871             : template <class FAB>
    1872             : FabArray<FAB>::FabArray (Arena* a) noexcept
    1873             :     : m_dallocator(a),
    1874             :       shmem()
    1875             : {
    1876             :     m_FA_stats.recordBuild();
    1877             : }
    1878             : 
    1879             : template <class FAB>
    1880        3049 : FabArray<FAB>::FabArray (const BoxArray&            bxs,
    1881             :                          const DistributionMapping& dm,
    1882             :                          int                        nvar,
    1883             :                          int                        ngrow,
    1884             :                          const MFInfo&              info,
    1885             :                          const FabFactory<FAB>&     factory)
    1886        3049 :     : FabArray<FAB>(bxs,dm,nvar,IntVect(ngrow),info,factory)
    1887        3049 : {}
    1888             : 
    1889             : template <class FAB>
    1890      403205 : FabArray<FAB>::FabArray (const BoxArray&            bxs,
    1891             :                          const DistributionMapping& dm,
    1892             :                          int                        nvar,
    1893             :                          const IntVect&             ngrow,
    1894             :                          const MFInfo&              info,
    1895             :                          const FabFactory<FAB>&     factory)
    1896             :     : m_factory(factory.clone()),
    1897      403205 :       shmem()
    1898             : {
    1899      403205 :     m_FA_stats.recordBuild();
    1900      403205 :     define(bxs,dm,nvar,ngrow,info,*m_factory);
    1901      403205 : }
    1902             : 
    1903             : template <class FAB>
    1904             : FabArray<FAB>::FabArray (const FabArray<FAB>& rhs, MakeType maketype, int scomp, int ncomp)
    1905             :     : m_factory(rhs.Factory().clone()),
    1906             :       shmem()
    1907             : {
    1908             :     m_FA_stats.recordBuild();
    1909             :     define(rhs.boxArray(), rhs.DistributionMap(), ncomp, rhs.nGrowVect(),
    1910             :            MFInfo().SetAlloc(false), *m_factory);
    1911             : 
    1912             :     if (maketype == amrex::make_alias)
    1913             :     {
    1914             :         for (int i = 0, n = indexArray.size(); i < n; ++i) {
    1915             :             auto const& rhsfab = *(rhs.m_fabs_v[i]);
    1916             :             m_fabs_v.push_back(m_factory->create_alias(rhsfab, scomp, ncomp));
    1917             :         }
    1918             :     }
    1919             :     else
    1920             :     {
    1921             :         amrex::Abort("FabArray: unknown MakeType");
    1922             :     }
    1923             : }
    1924             : 
    1925             : template <class FAB>
    1926           0 : FabArray<FAB>::FabArray (FabArray<FAB>&& rhs) noexcept
    1927             :     : FabArrayBase (static_cast<FabArrayBase&&>(rhs))
    1928           0 :     , m_factory    (std::move(rhs.m_factory))
    1929           0 :     , m_dallocator (std::move(rhs.m_dallocator))
    1930           0 :     , m_single_chunk_arena(std::move(rhs.m_single_chunk_arena))
    1931           0 :     , m_single_chunk_size(std::exchange(rhs.m_single_chunk_size,0))
    1932           0 :     , define_function_called(rhs.define_function_called)
    1933           0 :     , m_fabs_v     (std::move(rhs.m_fabs_v))
    1934             : #ifdef AMREX_USE_GPU
    1935             :     , m_dp_arrays  (std::exchange(rhs.m_dp_arrays, nullptr))
    1936             : #endif
    1937           0 :     , m_hp_arrays  (std::exchange(rhs.m_hp_arrays, nullptr))
    1938             :     , m_arrays     (rhs.m_arrays)
    1939             :     , m_const_arrays(rhs.m_const_arrays)
    1940           0 :     , m_tags       (std::move(rhs.m_tags))
    1941           0 :     , shmem        (std::move(rhs.shmem))
    1942             :     // no need to worry about the data used in non-blocking FillBoundary.
    1943             : {
    1944           0 :     m_FA_stats.recordBuild();
    1945           0 :     rhs.define_function_called = false; // the responsibility of clear BD has been transferred.
    1946           0 :     rhs.m_fabs_v.clear(); // clear the data pointers so that rhs.clear does delete them.
    1947           0 :     rhs.clear();
    1948           0 : }
    1949             : 
    1950             : template <class FAB>
    1951             : FabArray<FAB>&
    1952       11120 : FabArray<FAB>::operator= (FabArray<FAB>&& rhs) noexcept
    1953             : {
    1954       11120 :     if (&rhs != this)
    1955             :     {
    1956       11120 :         clear();
    1957             : 
    1958       11120 :         FabArrayBase::operator=(static_cast<FabArrayBase&&>(rhs));
    1959       11120 :         m_factory = std::move(rhs.m_factory);
    1960       11120 :         m_dallocator = std::move(rhs.m_dallocator);
    1961       11120 :         m_single_chunk_arena = std::move(rhs.m_single_chunk_arena);
    1962       11120 :         std::swap(m_single_chunk_size, rhs.m_single_chunk_size);
    1963       11120 :         define_function_called = rhs.define_function_called;
    1964       11120 :         std::swap(m_fabs_v, rhs.m_fabs_v);
    1965             : #ifdef AMREX_USE_GPU
    1966             :         std::swap(m_dp_arrays, rhs.m_dp_arrays);
    1967             : #endif
    1968       11120 :         std::swap(m_hp_arrays, rhs.m_hp_arrays);
    1969       11120 :         m_arrays = rhs.m_arrays;
    1970       11120 :         m_const_arrays = rhs.m_const_arrays;
    1971       11120 :         std::swap(m_tags, rhs.m_tags);
    1972       11120 :         shmem = std::move(rhs.shmem);
    1973             : 
    1974       11120 :         rhs.define_function_called = false;
    1975       11120 :         rhs.m_fabs_v.clear();
    1976       11120 :         rhs.m_tags.clear();
    1977       11120 :         rhs.clear();
    1978             :     }
    1979       11120 :     return *this;
    1980             : }
    1981             : 
    1982             : template <class FAB>
    1983      452872 : FabArray<FAB>::~FabArray ()
    1984             : {
    1985      452872 :     m_FA_stats.recordDelete();
    1986      452872 :     clear();
    1987      452872 : }
    1988             : 
    1989             : template <class FAB>
    1990             : bool
    1991             : FabArray<FAB>::ok () const
    1992             : {
    1993             :     if (!define_function_called) { return false; }
    1994             : 
    1995             :     int isok = 1;
    1996             : 
    1997             :     for (MFIter fai(*this); fai.isValid() && isok; ++fai)
    1998             :     {
    1999             :         if (defined(fai))
    2000             :         {
    2001             :             if (get(fai).box() != fabbox(fai.index()))
    2002             :             {
    2003             :                 isok = 0;
    2004             :             }
    2005             :         }
    2006             :         else
    2007             :         {
    2008             :             isok = 0;
    2009             :         }
    2010             :     }
    2011             : 
    2012             :     ParallelAllReduce::Min(isok, ParallelContext::CommunicatorSub());
    2013             : 
    2014             :     return isok == 1;
    2015             : }
    2016             : 
    2017             : template <class FAB>
    2018             : bool
    2019             : FabArray<FAB>::isDefined () const
    2020             : {
    2021             :     return define_function_called;
    2022             : }
    2023             : 
    2024             : template <class FAB>
    2025             : void
    2026         300 : FabArray<FAB>::define (const BoxArray&            bxs,
    2027             :                        const DistributionMapping& dm,
    2028             :                        int                        nvar,
    2029             :                        int                        ngrow,
    2030             :                        const MFInfo&              info,
    2031             :                        const FabFactory<FAB>&     a_factory)
    2032             : {
    2033         300 :     define(bxs,dm,nvar,IntVect(ngrow),info,a_factory);
    2034         300 : }
    2035             : 
    2036             : template <class FAB>
    2037             : void
    2038      403505 : FabArray<FAB>::define (const BoxArray&            bxs,
    2039             :                        const DistributionMapping& dm,
    2040             :                        int                        nvar,
    2041             :                        const IntVect&             ngrow,
    2042             :                        const MFInfo&              info,
    2043             :                        const FabFactory<FAB>&     a_factory)
    2044             : {
    2045      807010 :     std::unique_ptr<FabFactory<FAB> > factory(a_factory.clone());
    2046             : 
    2047      403505 :     auto *default_arena = m_dallocator.m_arena;
    2048      403505 :     clear();
    2049             : 
    2050      403505 :     m_factory = std::move(factory);
    2051      403505 :     m_dallocator.m_arena = info.arena ? info.arena : default_arena;
    2052             : 
    2053      403505 :     define_function_called = true;
    2054             : 
    2055             :     AMREX_ASSERT(ngrow.allGE(0));
    2056             :     AMREX_ASSERT(boxarray.empty());
    2057      403505 :     FabArrayBase::define(bxs, dm, nvar, ngrow);
    2058             : 
    2059      403505 :     addThisBD();
    2060             : 
    2061      403505 :     if(info.alloc) {
    2062      402905 :         AllocFabs(*m_factory, m_dallocator.m_arena, info.tags, info.alloc_single_chunk);
    2063             : #ifdef BL_USE_TEAM
    2064             :         ParallelDescriptor::MyTeam().MemoryBarrier();
    2065             : #endif
    2066             :     }
    2067      403505 : }
    2068             : 
    2069             : template <class FAB>
    2070             : void
    2071      403246 : FabArray<FAB>::AllocFabs (const FabFactory<FAB>& factory, Arena* ar,
    2072             :                           const Vector<std::string>& tags, bool alloc_single_chunk)
    2073             : {
    2074      403246 :     if (shmem.alloc) { alloc_single_chunk = false; }
    2075             :     if constexpr (!IsBaseFab_v<FAB>) { alloc_single_chunk = false; }
    2076             : 
    2077      403246 :     const int n = indexArray.size();
    2078      403246 :     const int nworkers = ParallelDescriptor::TeamSize();
    2079      403246 :     shmem.alloc = (nworkers > 1);
    2080             : 
    2081      403246 :     bool alloc = !shmem.alloc;
    2082             : 
    2083      403246 :     FabInfo fab_info;
    2084      403246 :     fab_info.SetAlloc(alloc).SetShared(shmem.alloc).SetArena(ar);
    2085             : 
    2086      403246 :     if (alloc_single_chunk) {
    2087           0 :         m_single_chunk_size = 0L;
    2088           0 :         for (int i = 0; i < n; ++i) {
    2089           0 :             int K = indexArray[i];
    2090           0 :             const Box& tmpbox = fabbox(K);
    2091           0 :             m_single_chunk_size += factory.nBytes(tmpbox, n_comp, K);
    2092             :         }
    2093             :         AMREX_ASSERT(m_single_chunk_size >= 0); // 0 is okay.
    2094           0 :         m_single_chunk_arena = std::make_unique<detail::SingleChunkArena>(ar, m_single_chunk_size);
    2095           0 :         fab_info.SetArena(m_single_chunk_arena.get());
    2096             :     }
    2097             : 
    2098      403246 :     m_fabs_v.reserve(n);
    2099             : 
    2100      403246 :     Long nbytes = 0L;
    2101      807932 :     for (int i = 0; i < n; ++i)
    2102             :     {
    2103      404686 :         int K = indexArray[i];
    2104      404686 :         const Box& tmpbox = fabbox(K);
    2105      404686 :         m_fabs_v.push_back(factory.create(tmpbox, n_comp, fab_info, K));
    2106      404686 :         nbytes += amrex::nBytesOwned(*m_fabs_v.back());
    2107             :     }
    2108             : 
    2109      403246 :     m_tags.clear();
    2110      403246 :     m_tags.emplace_back("All");
    2111      403246 :     for (auto const& t : m_region_tag) {
    2112           0 :         m_tags.push_back(t);
    2113             :     }
    2114      403246 :     for (auto const& t : tags) {
    2115           0 :         m_tags.push_back(t);
    2116             :     }
    2117      806492 :     for (auto const& t: m_tags) {
    2118      403246 :         updateMemUsage(t, nbytes, ar);
    2119             :     }
    2120             : 
    2121             : #ifdef BL_USE_TEAM
    2122             :     if (shmem.alloc)
    2123             :     {
    2124             :         const int teamlead = ParallelDescriptor::MyTeamLead();
    2125             : 
    2126             :         shmem.n_values = 0;
    2127             :         shmem.n_points = 0;
    2128             :         Vector<Long> offset(n,0);
    2129             :         Vector<Long> nextoffset(nworkers,-1);
    2130             :         for (int i = 0; i < n; ++i) {
    2131             :             int K = indexArray[i];
    2132             :             int owner = distributionMap[K] - teamlead;
    2133             :             Long s = m_fabs_v[i]->size();
    2134             :             if (ownership[i]) {
    2135             :                 shmem.n_values += s;
    2136             :                 shmem.n_points += m_fabs_v[i]->numPts();
    2137             :             }
    2138             :             if (nextoffset[owner] < 0) {
    2139             :                 offset[i] = 0;
    2140             :                 nextoffset[owner] = s;
    2141             :             } else {
    2142             :                 offset[i] = nextoffset[owner];
    2143             :                 nextoffset[owner] += s;
    2144             :             }
    2145             :         }
    2146             : 
    2147             :         size_t bytes = shmem.n_values*sizeof(value_type);
    2148             : 
    2149             :         value_type *mfp;
    2150             :         Vector<value_type*> dps;
    2151             : 
    2152             : #if defined (BL_USE_MPI3)
    2153             : 
    2154             :         static MPI_Info info = MPI_INFO_NULL;
    2155             :         if (info == MPI_INFO_NULL) {
    2156             :             MPI_Info_create(&info);
    2157             :             MPI_Info_set(info, "alloc_shared_noncontig", "true");
    2158             :         }
    2159             : 
    2160             :         const MPI_Comm& team_comm = ParallelDescriptor::MyTeam().get();
    2161             : 
    2162             :         BL_MPI_REQUIRE( MPI_Win_allocate_shared(bytes, sizeof(value_type),
    2163             :                                                 info, team_comm, &mfp, &shmem.win) );
    2164             : 
    2165             :         for (int w = 0; w < nworkers; ++w) {
    2166             :             MPI_Aint sz;
    2167             :             int disp;
    2168             :             value_type *dptr = 0;
    2169             :             BL_MPI_REQUIRE( MPI_Win_shared_query(shmem.win, w, &sz, &disp, &dptr) );
    2170             :             // AMREX_ASSERT(disp == sizeof(value_type));
    2171             :             dps.push_back(dptr);
    2172             :         }
    2173             : 
    2174             : #else
    2175             : 
    2176             :         amrex::Abort("BaseFab::define: to allocate shared memory, USE_MPI3 must be true");
    2177             : 
    2178             : #endif
    2179             : 
    2180             :         for (int i = 0; i < n; ++i) {
    2181             :             int K = indexArray[i];
    2182             :             int owner = distributionMap[K] - teamlead;
    2183             :             value_type *p = dps[owner] + offset[i];
    2184             :             m_fabs_v[i]->setPtr(p, m_fabs_v[i]->size());
    2185             :         }
    2186             : 
    2187             :         for (Long i = 0; i < shmem.n_values; i++, mfp++) {
    2188             :             new (mfp) value_type;
    2189             :         }
    2190             : 
    2191             :         amrex::update_fab_stats(shmem.n_points, shmem.n_values, sizeof(value_type));
    2192             :     }
    2193             : #endif
    2194      403246 : }
    2195             : 
    2196             : template <class FAB>
    2197             : void
    2198             : FabArray<FAB>::setFab_assert (int K, FAB const& fab) const
    2199             : {
    2200             :     amrex::ignore_unused(K,fab);
    2201             :     AMREX_ASSERT(n_comp == fab.nComp());
    2202             :     AMREX_ASSERT(!boxarray.empty());
    2203             :     AMREX_ASSERT(fab.box() == fabbox(K));
    2204             :     AMREX_ASSERT(distributionMap[K] == ParallelDescriptor::MyProc());
    2205             :     AMREX_ASSERT(m_single_chunk_arena == nullptr);
    2206             : }
    2207             : 
    2208             : template <class FAB>
    2209             : void
    2210             : FabArray<FAB>::setFab (int boxno, std::unique_ptr<FAB> elem)
    2211             : {
    2212             :     if (n_comp == 0) {
    2213             :         n_comp = elem->nComp();
    2214             :     }
    2215             : 
    2216             :     setFab_assert(boxno, *elem);
    2217             : 
    2218             :     if (m_fabs_v.empty()) {
    2219             :         m_fabs_v.resize(indexArray.size(),nullptr);
    2220             :     }
    2221             : 
    2222             :     const int li = localindex(boxno);
    2223             :     if (m_fabs_v[li]) {
    2224             :         m_factory->destroy(m_fabs_v[li]);
    2225             :     }
    2226             :     m_fabs_v[li] = elem.release();
    2227             : }
    2228             : 
    2229             : template <class FAB>
    2230             : template <class F, std::enable_if_t<std::is_move_constructible_v<F>,int> >
    2231             : void
    2232             : FabArray<FAB>::setFab (int boxno, FAB&& elem)
    2233             : {
    2234             :     if (n_comp == 0) {
    2235             :         n_comp = elem.nComp();
    2236             :     }
    2237             : 
    2238             :     setFab_assert(boxno, elem);
    2239             : 
    2240             :     if (m_fabs_v.empty()) {
    2241             :         m_fabs_v.resize(indexArray.size(),nullptr);
    2242             :     }
    2243             : 
    2244             :     const int li = localindex(boxno);
    2245             :     if (m_fabs_v[li]) {
    2246             :         m_factory->destroy(m_fabs_v[li]);
    2247             :     }
    2248             :     m_fabs_v[li] = new FAB(std::move(elem));
    2249             : }
    2250             : 
    2251             : template <class FAB>
    2252             : void
    2253             : FabArray<FAB>::setFab (const MFIter& mfi, std::unique_ptr<FAB> elem)
    2254             : {
    2255             :     if (n_comp == 0) {
    2256             :         n_comp = elem->nComp();
    2257             :     }
    2258             : 
    2259             :     setFab_assert(mfi.index(), *elem);
    2260             : 
    2261             :     if (m_fabs_v.empty()) {
    2262             :         m_fabs_v.resize(indexArray.size(),nullptr);
    2263             :     }
    2264             : 
    2265             :     const int li = mfi.LocalIndex();
    2266             :     if (m_fabs_v[li]) {
    2267             :         m_factory->destroy(m_fabs_v[li]);
    2268             :     }
    2269             :     m_fabs_v[li] = elem.release();
    2270             : }
    2271             : 
    2272             : template <class FAB>
    2273             : template <class F, std::enable_if_t<std::is_move_constructible_v<F>,int> >
    2274             : void
    2275             : FabArray<FAB>::setFab (const MFIter& mfi, FAB&& elem)
    2276             : {
    2277             :     if (n_comp == 0) {
    2278             :         n_comp = elem.nComp();
    2279             :     }
    2280             : 
    2281             :     setFab_assert(mfi.index(), elem);
    2282             : 
    2283             :     if (m_fabs_v.empty()) {
    2284             :         m_fabs_v.resize(indexArray.size(),nullptr);
    2285             :     }
    2286             : 
    2287             :     const int li = mfi.LocalIndex();
    2288             :     if (m_fabs_v[li]) {
    2289             :         m_factory->destroy(m_fabs_v[li]);
    2290             :     }
    2291             :     m_fabs_v[li] = new FAB(std::move(elem));
    2292             : }
    2293             : 
    2294             : template <class FAB>
    2295             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    2296             : void
    2297             : FabArray<FAB>::setBndry (value_type val)
    2298             : {
    2299             :     setBndry(val, 0, n_comp);
    2300             : }
    2301             : 
    2302             : template <class FAB>
    2303             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>Z>
    2304             : void
    2305           0 : FabArray<FAB>::setBndry (value_type val,
    2306             :                          int        strt_comp,
    2307             :                          int        ncomp)
    2308             : {
    2309           0 :     if (n_grow.max() > 0)
    2310             :     {
    2311             : #ifdef AMREX_USE_GPU
    2312             :         if (Gpu::inLaunchRegion()) {
    2313             :             bool use_mfparfor = true;
    2314             :             const int nboxes = local_size();
    2315             :             if (nboxes == 1) {
    2316             :                 if (boxarray[indexArray[0]].numPts() > Long(65*65*65)) {
    2317             :                     use_mfparfor = false;
    2318             :                 }
    2319             :             } else {
    2320             :                 for (int i = 0; i < nboxes; ++i) {
    2321             :                     const Long npts = boxarray[indexArray[i]].numPts();
    2322             :                     if (npts >= Long(64*64*64)) {
    2323             :                         use_mfparfor = false;
    2324             :                         break;
    2325             :                     } else if (npts <= Long(17*17*17)) {
    2326             :                         break;
    2327             :                     }
    2328             :                 }
    2329             :             }
    2330             :             const IntVect nghost = n_grow;
    2331             :             if (use_mfparfor) {
    2332             :                 auto const& ma = this->arrays();
    2333             :                 ParallelFor(*this, nghost,
    2334             :                 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept
    2335             :                 {
    2336             :                     auto const& a = ma[box_no];
    2337             :                     Box vbx(a);
    2338             :                     vbx.grow(-nghost);
    2339             :                     if (!vbx.contains(i,j,k)) {
    2340             :                         for (int n = 0; n < ncomp; ++n) {
    2341             :                             a(i,j,k,strt_comp+n) = val;
    2342             :                         }
    2343             :                     }
    2344             :                 });
    2345             :                 Gpu::streamSynchronize();
    2346             :             } else {
    2347             :                 using Tag = Array4BoxTag<value_type>;
    2348             :                 Vector<Tag> tags;
    2349             :                 for (MFIter mfi(*this); mfi.isValid(); ++mfi) {
    2350             :                     Box const& vbx = mfi.validbox();
    2351             :                     auto const& a = this->array(mfi);
    2352             : 
    2353             :                     Box b;
    2354             : #if (AMREX_SPACEDIM == 3)
    2355             :                     if (nghost[2] > 0) {
    2356             :                         b = vbx;
    2357             :                         b.setRange(2, vbx.smallEnd(2)-nghost[2], nghost[2]);
    2358             :                         b.grow(IntVect(nghost[0],nghost[1],0));
    2359             :                         tags.emplace_back(Tag{a, b});
    2360             :                         b.shift(2, vbx.length(2)+nghost[2]);
    2361             :                         tags.emplace_back(Tag{a, b});
    2362             :                     }
    2363             : #endif
    2364             : #if (AMREX_SPACEDIM >= 2)
    2365             :                     if (nghost[1] > 0) {
    2366             :                         b = vbx;
    2367             :                         b.setRange(1, vbx.smallEnd(1)-nghost[1], nghost[1]);
    2368             :                         b.grow(0, nghost[0]);
    2369             :                         tags.emplace_back(Tag{a, b});
    2370             :                         b.shift(1, vbx.length(1)+nghost[1]);
    2371             :                         tags.emplace_back(Tag{a, b});
    2372             :                     }
    2373             : #endif
    2374             :                     if (nghost[0] > 0) {
    2375             :                         b = vbx;
    2376             :                         b.setRange(0, vbx.smallEnd(0)-nghost[0], nghost[0]);
    2377             :                         tags.emplace_back(Tag{a, b});
    2378             :                         b.shift(0, vbx.length(0)+nghost[0]);
    2379             :                         tags.emplace_back(Tag{a, b});
    2380             :                     }
    2381             :                 }
    2382             : 
    2383             :                 ParallelFor(tags, ncomp,
    2384             :                 [=] AMREX_GPU_DEVICE (int i, int j, int k, int n, Tag const& tag) noexcept
    2385             :                 {
    2386             :                     tag.dfab(i,j,k,strt_comp+n) = val;
    2387             :                 });
    2388             :             }
    2389             :         } else
    2390             : #endif
    2391             :         {
    2392             : #ifdef AMREX_USE_OMP
    2393             : #pragma omp parallel
    2394             : #endif
    2395           0 :             for (MFIter fai(*this); fai.isValid(); ++fai)
    2396             :             {
    2397           0 :                 get(fai).template setComplement<RunOn::Host>(val, fai.validbox(), strt_comp, ncomp);
    2398             :             }
    2399             :         }
    2400             :     }
    2401           0 : }
    2402             : 
    2403             : template <class FAB>
    2404             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    2405             : void
    2406          66 : FabArray<FAB>::setDomainBndry (value_type val, const Geometry& geom)
    2407             : {
    2408          66 :     setDomainBndry(val, 0, n_comp, geom);
    2409          66 : }
    2410             : 
    2411             : template <class FAB>
    2412             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    2413             : void
    2414          66 : FabArray<FAB>::setDomainBndry (value_type val,
    2415             :                                int        strt_comp,
    2416             :                                int        ncomp,
    2417             :                                const Geometry& geom)
    2418             : {
    2419             :     BL_PROFILE("FabArray::setDomainBndry()");
    2420             : 
    2421          66 :     Box domain_box = amrex::convert(geom.Domain(), boxArray().ixType());
    2422         264 :     for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
    2423         198 :         if (geom.isPeriodic(idim)) {
    2424           0 :             int n = domain_box.length(idim);
    2425           0 :             domain_box.grow(idim, n);
    2426             :         }
    2427             :     }
    2428             : 
    2429             : #ifdef AMREX_USE_OMP
    2430             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    2431             : #endif
    2432         282 :     for (MFIter fai(*this); fai.isValid(); ++fai)
    2433             :     {
    2434         216 :         const Box& gbx = fai.fabbox();
    2435         216 :         if (! domain_box.contains(gbx))
    2436             :         {
    2437         216 :             get(fai).template setComplement<RunOn::Device>(val, domain_box, strt_comp, ncomp);
    2438             :         }
    2439             :     }
    2440          66 : }
    2441             : 
    2442             : template <class FAB>
    2443             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int> FOO>
    2444             : typename F::value_type
    2445             : FabArray<FAB>::sum (int comp, IntVect const& nghost, bool local) const
    2446             : {
    2447             :     BL_PROFILE("FabArray::sum()");
    2448             : 
    2449             :     using T = typename FAB::value_type;
    2450             :     auto sm = T(0.0);
    2451             : #ifdef AMREX_USE_GPU
    2452             :     if (Gpu::inLaunchRegion()) {
    2453             :         auto const& ma = this->const_arrays();
    2454             :         sm = ParReduce(TypeList<ReduceOpSum>{}, TypeList<T>{}, *this, nghost,
    2455             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept
    2456             :                        -> GpuTuple<T>
    2457             :         {
    2458             :             return ma[box_no](i,j,k,comp);
    2459             :         });
    2460             :     } else
    2461             : #endif
    2462             :     {
    2463             : #ifdef AMREX_USE_OMP
    2464             : #pragma omp parallel if (!system::regtest_reduction) reduction(+:sm)
    2465             : #endif
    2466             :         for (MFIter mfi(*this,true); mfi.isValid(); ++mfi)
    2467             :         {
    2468             :             Box const& bx = mfi.growntilebox(nghost);
    2469             :             auto const& a = this->const_array(mfi);
    2470             :             auto tmp = T(0.0);
    2471             :             AMREX_LOOP_3D(bx, i, j, k,
    2472             :             {
    2473             :                 tmp += a(i,j,k,comp);
    2474             :             });
    2475             :             sm += tmp; // Do it this way so that it does not break regression tests.
    2476             :         }
    2477             :     }
    2478             : 
    2479             :     if (!local) {
    2480             :         ParallelAllReduce::Sum(sm, ParallelContext::CommunicatorSub());
    2481             :     }
    2482             : 
    2483             :     return sm;
    2484             : }
    2485             : 
    2486             : template <class FAB>
    2487             : void
    2488             : FabArray<FAB>::copyTo (FAB& dest, int  nghost) const
    2489             : {
    2490             :     copyTo(dest, 0, 0, dest.nComp(), nghost);
    2491             : }
    2492             : 
    2493             : template <class FAB>
    2494             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    2495             : void
    2496       18319 : FabArray<FAB>::setVal (value_type val)
    2497             : {
    2498       18319 :     setVal(val,0,n_comp,n_grow);
    2499       18319 : }
    2500             : 
    2501             : template <class FAB>
    2502             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    2503             : FabArray<FAB>&
    2504             : FabArray<FAB>::operator= (value_type val)
    2505             : {
    2506             :     setVal(val);
    2507             :     return *this;
    2508             : }
    2509             : 
    2510             : template <class FAB>
    2511             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    2512             : void
    2513           0 : FabArray<FAB>::setVal (value_type val,
    2514             :                        int        comp,
    2515             :                        int        ncomp,
    2516             :                        int        nghost)
    2517             : {
    2518           0 :     setVal(val,comp,ncomp,IntVect(nghost));
    2519           0 : }
    2520             : 
    2521             : template <class FAB>
    2522             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>Z>
    2523             : void
    2524       18319 : FabArray<FAB>::setVal (value_type val,
    2525             :                        int        comp,
    2526             :                        int        ncomp,
    2527             :                        const IntVect& nghost)
    2528             : {
    2529             :     AMREX_ASSERT(nghost.allGE(0) && nghost.allLE(n_grow));
    2530       18319 :     AMREX_ALWAYS_ASSERT(comp+ncomp <= n_comp);
    2531             : 
    2532             :     BL_PROFILE("FabArray::setVal()");
    2533             : 
    2534             : #ifdef AMREX_USE_GPU
    2535             :     if (Gpu::inLaunchRegion() && this->isFusingCandidate()) {
    2536             :         auto const& fa = this->arrays();
    2537             :         ParallelFor(*this, nghost, ncomp,
    2538             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    2539             :         {
    2540             :             fa[box_no](i,j,k,n+comp) = val;
    2541             :         });
    2542             :         if (!Gpu::inNoSyncRegion()) {
    2543             :             Gpu::streamSynchronize();
    2544             :         }
    2545             :     } else
    2546             : #endif
    2547             :     {
    2548             : #ifdef AMREX_USE_OMP
    2549             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    2550             : #endif
    2551       39074 :         for (MFIter fai(*this,TilingIfNotGPU()); fai.isValid(); ++fai)
    2552             :         {
    2553       20755 :             const Box& bx = fai.growntilebox(nghost);
    2554       20755 :             auto fab = this->array(fai);
    2555    47841441 :             AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, ncomp, i, j, k, n,
    2556             :             {
    2557             :                 fab(i,j,k,n+comp) = val;
    2558             :             });
    2559             :         }
    2560             :     }
    2561       18319 : }
    2562             : 
    2563             : template <class FAB>
    2564             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    2565             : void
    2566             : FabArray<FAB>::setVal (value_type val,
    2567             :                        const Box& region,
    2568             :                        int        comp,
    2569             :                        int        ncomp,
    2570             :                        int        nghost)
    2571             : {
    2572             :     setVal(val,region,comp,ncomp,IntVect(nghost));
    2573             : }
    2574             : 
    2575             : template <class FAB>
    2576             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>Z>
    2577             : void
    2578             : FabArray<FAB>::setVal (value_type val,
    2579             :                        const Box& region,
    2580             :                        int        comp,
    2581             :                        int        ncomp,
    2582             :                        const IntVect& nghost)
    2583             : {
    2584             :     AMREX_ASSERT(nghost.allGE(0) && nghost.allLE(n_grow));
    2585             :     AMREX_ALWAYS_ASSERT(comp+ncomp <= n_comp);
    2586             : 
    2587             :     BL_PROFILE("FabArray::setVal(val,region,comp,ncomp,nghost)");
    2588             : 
    2589             : #ifdef AMREX_USE_GPU
    2590             :     if (Gpu::inLaunchRegion() && this->isFusingCandidate()) {
    2591             :         auto const& fa = this->arrays();
    2592             :         ParallelFor(*this, nghost, ncomp,
    2593             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    2594             :         {
    2595             :             if (region.contains(i,j,k)) {
    2596             :                 fa[box_no](i,j,k,n+comp) = val;
    2597             :             }
    2598             :         });
    2599             :         if (!Gpu::inNoSyncRegion()) {
    2600             :             Gpu::streamSynchronize();
    2601             :         }
    2602             :     } else
    2603             : #endif
    2604             :     {
    2605             : #ifdef AMREX_USE_OMP
    2606             :         AMREX_ALWAYS_ASSERT(!omp_in_parallel());
    2607             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    2608             : #endif
    2609             :         for (MFIter fai(*this,TilingIfNotGPU()); fai.isValid(); ++fai)
    2610             :         {
    2611             :             Box b = fai.growntilebox(nghost) & region;
    2612             : 
    2613             :             if (b.ok()) {
    2614             :                 auto fab = this->array(fai);
    2615             :                 AMREX_HOST_DEVICE_PARALLEL_FOR_4D( b, ncomp, i, j, k, n,
    2616             :                 {
    2617             :                     fab(i,j,k,n+comp) = val;
    2618             :                 });
    2619             :             }
    2620             :         }
    2621             :     }
    2622             : }
    2623             : 
    2624             : template <class FAB>
    2625             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    2626             : void
    2627             : FabArray<FAB>::abs (int comp, int ncomp, int nghost)
    2628             : {
    2629             :     abs(comp, ncomp, IntVect(nghost));
    2630             : }
    2631             : 
    2632             : template <class FAB>
    2633             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>Z>
    2634             : void
    2635             : FabArray<FAB>::abs (int comp, int ncomp, const IntVect& nghost)
    2636             : {
    2637             :     AMREX_ASSERT(nghost.allGE(0) && nghost.allLE(n_grow));
    2638             :     AMREX_ALWAYS_ASSERT(comp+ncomp <= n_comp);
    2639             :     BL_PROFILE("FabArray::abs()");
    2640             : 
    2641             : #ifdef AMREX_USE_GPU
    2642             :     if (Gpu::inLaunchRegion() && this->isFusingCandidate()) {
    2643             :         auto const& fa = this->arrays();
    2644             :         ParallelFor(*this, nghost, ncomp,
    2645             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    2646             :         {
    2647             :             fa[box_no](i,j,k,n+comp) = std::abs(fa[box_no](i,j,k,n+comp));
    2648             :         });
    2649             :         if (!Gpu::inNoSyncRegion()) {
    2650             :             Gpu::streamSynchronize();
    2651             :         }
    2652             :     } else
    2653             : #endif
    2654             :     {
    2655             : #ifdef AMREX_USE_OMP
    2656             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    2657             : #endif
    2658             :         for (MFIter mfi(*this,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    2659             :         {
    2660             :             const Box& bx = mfi.growntilebox(nghost);
    2661             :             auto fab = this->array(mfi);
    2662             :             AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, ncomp, i, j, k, n,
    2663             :             {
    2664             :                 fab(i,j,k,n+comp) = std::abs(fab(i,j,k,n+comp));
    2665             :             });
    2666             :         }
    2667             :     }
    2668             : }
    2669             : 
    2670             : template <class FAB>
    2671             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>Z>
    2672             : void
    2673             : FabArray<FAB>::plus (value_type val, int comp, int num_comp, int nghost)
    2674             : {
    2675             :     BL_PROFILE("FabArray::plus()");
    2676             : 
    2677             : #ifdef AMREX_USE_GPU
    2678             :     if (Gpu::inLaunchRegion() && this->isFusingCandidate()) {
    2679             :         auto const& fa = this->arrays();
    2680             :         ParallelFor(*this, IntVect(nghost), num_comp,
    2681             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    2682             :         {
    2683             :             fa[box_no](i,j,k,n+comp) += val;
    2684             :         });
    2685             :         if (!Gpu::inNoSyncRegion()) {
    2686             :             Gpu::streamSynchronize();
    2687             :         }
    2688             :     } else
    2689             : #endif
    2690             :     {
    2691             : #ifdef AMREX_USE_OMP
    2692             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    2693             : #endif
    2694             :         for (MFIter mfi(*this,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    2695             :         {
    2696             :             const Box& bx = mfi.growntilebox(nghost);
    2697             :             auto fab = this->array(mfi);
    2698             :             AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, num_comp, i, j, k, n,
    2699             :             {
    2700             :                 fab(i,j,k,n+comp) += val;
    2701             :             });
    2702             :         }
    2703             :     }
    2704             : }
    2705             : 
    2706             : template <class FAB>
    2707             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>Z>
    2708             : void
    2709             : FabArray<FAB>::plus (value_type val, const Box& region, int comp, int num_comp, int nghost)
    2710             : {
    2711             :     BL_PROFILE("FabArray::plus(val, region, comp, num_comp, nghost)");
    2712             : 
    2713             : #ifdef AMREX_USE_GPU
    2714             :     if (Gpu::inLaunchRegion() && this->isFusingCandidate()) {
    2715             :         auto const& fa = this->arrays();
    2716             :         ParallelFor(*this, IntVect(nghost), num_comp,
    2717             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    2718             :         {
    2719             :             if (region.contains(i,j,k)) {
    2720             :                 fa[box_no](i,j,k,n+comp) += val;
    2721             :             }
    2722             :         });
    2723             :         if (!Gpu::inNoSyncRegion()) {
    2724             :             Gpu::streamSynchronize();
    2725             :         }
    2726             :     } else
    2727             : #endif
    2728             :     {
    2729             : #ifdef AMREX_USE_OMP
    2730             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    2731             : #endif
    2732             :         for (MFIter mfi(*this,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    2733             :         {
    2734             :             const Box& bx = mfi.growntilebox(nghost) & region;
    2735             :             if (bx.ok()) {
    2736             :                 auto fab = this->array(mfi);
    2737             :                 AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, num_comp, i, j, k, n,
    2738             :                 {
    2739             :                     fab(i,j,k,n+comp) += val;
    2740             :                 });
    2741             :             }
    2742             :         }
    2743             :     }
    2744             : }
    2745             : 
    2746             : template <class FAB>
    2747             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>Z>
    2748             : void
    2749             : FabArray<FAB>::mult (value_type val, int comp, int num_comp, int nghost)
    2750             : {
    2751             :     BL_PROFILE("FabArray::mult()");
    2752             : 
    2753             : #ifdef AMREX_USE_GPU
    2754             :     if (Gpu::inLaunchRegion() && this->isFusingCandidate()) {
    2755             :         auto const& fa = this->arrays();
    2756             :         ParallelFor(*this, IntVect(nghost), num_comp,
    2757             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    2758             :         {
    2759             :             fa[box_no](i,j,k,n+comp) *= val;
    2760             :         });
    2761             :         if (!Gpu::inNoSyncRegion()) {
    2762             :             Gpu::streamSynchronize();
    2763             :         }
    2764             :     } else
    2765             : #endif
    2766             :     {
    2767             : #ifdef AMREX_USE_OMP
    2768             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    2769             : #endif
    2770             :         for (MFIter mfi(*this,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    2771             :         {
    2772             :             const Box& bx = mfi.growntilebox(nghost);
    2773             :             auto fab = this->array(mfi);
    2774             :             AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, num_comp, i, j, k, n,
    2775             :             {
    2776             :                 fab(i,j,k,n+comp) *= val;
    2777             :             });
    2778             :         }
    2779             :     }
    2780             : }
    2781             : 
    2782             : template <class FAB>
    2783             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>Z>
    2784             : void
    2785             : FabArray<FAB>::mult (value_type val, const Box& region, int comp, int num_comp, int nghost)
    2786             : {
    2787             :     BL_PROFILE("FabArray::mult(val, region, comp, num_comp, nghost)");
    2788             : 
    2789             : #ifdef AMREX_USE_GPU
    2790             :     if (Gpu::inLaunchRegion() && this->isFusingCandidate()) {
    2791             :         auto const& fa = this->arrays();
    2792             :         ParallelFor(*this, IntVect(nghost), num_comp,
    2793             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    2794             :         {
    2795             :             if (region.contains(i,j,k)) {
    2796             :                 fa[box_no](i,j,k,n+comp) *= val;
    2797             :             }
    2798             :         });
    2799             :         if (!Gpu::inNoSyncRegion()) {
    2800             :             Gpu::streamSynchronize();
    2801             :         }
    2802             :     } else
    2803             : #endif
    2804             :     {
    2805             : #ifdef AMREX_USE_OMP
    2806             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    2807             : #endif
    2808             :         for (MFIter mfi(*this,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    2809             :         {
    2810             :             const Box& bx = mfi.growntilebox(nghost) & region;
    2811             :             if (bx.ok()) {
    2812             :                 auto fab = this->array(mfi);
    2813             :                 AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, num_comp, i, j, k, n,
    2814             :                 {
    2815             :                     fab(i,j,k,n+comp) *= val;
    2816             :                 });
    2817             :             }
    2818             :         }
    2819             :     }
    2820             : }
    2821             : 
    2822             : template <class FAB>
    2823             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>Z>
    2824             : void
    2825             : FabArray<FAB>::invert (value_type numerator, int comp, int num_comp, int nghost)
    2826             : {
    2827             :     BL_PROFILE("FabArray::invert()");
    2828             : 
    2829             : #ifdef AMREX_USE_GPU
    2830             :     if (Gpu::inLaunchRegion() && this->isFusingCandidate()) {
    2831             :         auto const& fa = this->arrays();
    2832             :         ParallelFor(*this, IntVect(nghost), num_comp,
    2833             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    2834             :         {
    2835             :             fa[box_no](i,j,k,n+comp) = numerator / fa[box_no](i,j,k,n+comp);
    2836             :         });
    2837             :         if (!Gpu::inNoSyncRegion()) {
    2838             :             Gpu::streamSynchronize();
    2839             :         }
    2840             :     } else
    2841             : #endif
    2842             :     {
    2843             : #ifdef AMREX_USE_OMP
    2844             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    2845             : #endif
    2846             :         for (MFIter mfi(*this,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    2847             :         {
    2848             :             const Box& bx = mfi.growntilebox(nghost);
    2849             :             auto fab = this->array(mfi);
    2850             :             AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, num_comp, i, j, k, n,
    2851             :             {
    2852             :                 fab(i,j,k,n+comp) = numerator / fab(i,j,k,n+comp);
    2853             :             });
    2854             :         }
    2855             :     }
    2856             : }
    2857             : 
    2858             : template <class FAB>
    2859             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>Z>
    2860             : void
    2861             : FabArray<FAB>::invert (value_type numerator, const Box& region, int comp, int num_comp, int nghost)
    2862             : {
    2863             :     BL_PROFILE("FabArray::invert(numerator, region, comp, num_comp, nghost)");
    2864             : 
    2865             : #ifdef AMREX_USE_GPU
    2866             :     if (Gpu::inLaunchRegion() && this->isFusingCandidate()) {
    2867             :         auto const& fa = this->arrays();
    2868             :         ParallelFor(*this, IntVect(nghost), num_comp,
    2869             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    2870             :         {
    2871             :             if (region.contains(i,j,k)) {
    2872             :                 fa[box_no](i,j,k,n+comp) = numerator / fa[box_no](i,j,k,n+comp);
    2873             :             }
    2874             :         });
    2875             :         if (!Gpu::inNoSyncRegion()) {
    2876             :             Gpu::streamSynchronize();
    2877             :         }
    2878             :     } else
    2879             : #endif
    2880             :     {
    2881             : #ifdef AMREX_USE_OMP
    2882             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    2883             : #endif
    2884             :         for (MFIter mfi(*this,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    2885             :         {
    2886             :             const Box& bx = mfi.growntilebox(nghost) & region;
    2887             :             if (bx.ok()) {
    2888             :                 auto fab = this->array(mfi);
    2889             :                 AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, num_comp, i, j, k, n,
    2890             :                 {
    2891             :                     fab(i,j,k,n+comp) = numerator / fab(i,j,k,n+comp);
    2892             :                 });
    2893             :             }
    2894             :         }
    2895             :     }
    2896             : }
    2897             : 
    2898             : template <class FAB>
    2899             : void
    2900             : FabArray<FAB>::shift (const IntVect& v)
    2901             : {
    2902             :     clearThisBD();  // The new boxarray will have a different ID.
    2903             :     boxarray.shift(v);
    2904             :     addThisBD();
    2905             : #ifdef AMREX_USE_OMP
    2906             : #pragma omp parallel
    2907             : #endif
    2908             :     for (MFIter fai(*this); fai.isValid(); ++fai)
    2909             :     {
    2910             :         get(fai).shift(v);
    2911             :     }
    2912             :     clear_arrays();
    2913             : }
    2914             : 
    2915             : template <class FAB>
    2916             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int> FOO>
    2917             : void FabArray<FAB>::Saxpy (FabArray<FAB>& y, value_type a, FabArray<FAB> const& x,
    2918             :                            int xcomp, int ycomp, int ncomp, IntVect const& nghost)
    2919             : {
    2920             :     AMREX_ASSERT(y.boxArray() == x.boxArray());
    2921             :     AMREX_ASSERT(y.distributionMap == x.distributionMap);
    2922             :     AMREX_ASSERT(y.nGrowVect().allGE(nghost) && x.nGrowVect().allGE(nghost));
    2923             : 
    2924             :     BL_PROFILE("FabArray::Saxpy()");
    2925             : 
    2926             : #ifdef AMREX_USE_GPU
    2927             :     if (Gpu::inLaunchRegion() && y.isFusingCandidate()) {
    2928             :         auto const& yma = y.arrays();
    2929             :         auto const& xma = x.const_arrays();
    2930             :         ParallelFor(y, nghost, ncomp,
    2931             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    2932             :         {
    2933             :             yma[box_no](i,j,k,ycomp+n) += a * xma[box_no](i,j,k,xcomp+n);
    2934             :         });
    2935             :         if (!Gpu::inNoSyncRegion()) {
    2936             :             Gpu::streamSynchronize();
    2937             :         }
    2938             :     } else
    2939             : #endif
    2940             :     {
    2941             : #ifdef AMREX_USE_OMP
    2942             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    2943             : #endif
    2944             :         for (MFIter mfi(y,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    2945             :         {
    2946             :             const Box& bx = mfi.growntilebox(nghost);
    2947             : 
    2948             :             if (bx.ok()) {
    2949             :                 auto const& xfab = x.const_array(mfi);
    2950             :                 auto const& yfab = y.array(mfi);
    2951             :                 AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, ncomp, i, j, k, n,
    2952             :                 {
    2953             :                     yfab(i,j,k,ycomp+n) += a * xfab(i,j,k,xcomp+n);
    2954             :                 });
    2955             :             }
    2956             :         }
    2957             :     }
    2958             : }
    2959             : 
    2960             : template <class FAB>
    2961             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int> FOO>
    2962             : void
    2963             : FabArray<FAB>::Xpay (FabArray<FAB>& y, value_type a, FabArray<FAB> const& x,
    2964             :                      int xcomp, int ycomp, int ncomp, IntVect const& nghost)
    2965             : {
    2966             :     AMREX_ASSERT(y.boxArray() == x.boxArray());
    2967             :     AMREX_ASSERT(y.distributionMap == x.distributionMap);
    2968             :     AMREX_ASSERT(y.nGrowVect().allGE(nghost) && x.nGrowVect().allGE(nghost));
    2969             : 
    2970             :     BL_PROFILE("FabArray::Xpay()");
    2971             : 
    2972             : #ifdef AMREX_USE_GPU
    2973             :     if (Gpu::inLaunchRegion() && y.isFusingCandidate()) {
    2974             :         auto const& yfa = y.arrays();
    2975             :         auto const& xfa = x.const_arrays();
    2976             :         ParallelFor(y, nghost, ncomp,
    2977             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    2978             :         {
    2979             :             yfa[box_no](i,j,k,n+ycomp) = xfa[box_no](i,j,k,n+xcomp)
    2980             :                 +                    a * yfa[box_no](i,j,k,n+ycomp);
    2981             :         });
    2982             :         if (!Gpu::inNoSyncRegion()) {
    2983             :             Gpu::streamSynchronize();
    2984             :         }
    2985             :     } else
    2986             : #endif
    2987             :     {
    2988             : #ifdef AMREX_USE_OMP
    2989             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    2990             : #endif
    2991             :         for (MFIter mfi(y,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    2992             :         {
    2993             :             const Box& bx = mfi.growntilebox(nghost);
    2994             :             auto const& xFab = x.const_array(mfi);
    2995             :             auto const& yFab = y.array(mfi);
    2996             :             AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, ncomp, i, j, k, n,
    2997             :             {
    2998             :                 yFab(i,j,k,n+ycomp) = xFab(i,j,k,n+xcomp)
    2999             :                     +             a * yFab(i,j,k,n+ycomp);
    3000             :             });
    3001             :         }
    3002             :     }
    3003             : }
    3004             : 
    3005             : template <class FAB>
    3006             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int> FOO>
    3007             : void
    3008             : FabArray<FAB>::LinComb (FabArray<FAB>& dst,
    3009             :                         value_type a, const FabArray<FAB>& x, int xcomp,
    3010             :                         value_type b, const FabArray<FAB>& y, int ycomp,
    3011             :                         int dstcomp, int numcomp, const IntVect& nghost)
    3012             : {
    3013             :     AMREX_ASSERT(dst.boxArray() == x.boxArray());
    3014             :     AMREX_ASSERT(dst.distributionMap == x.distributionMap);
    3015             :     AMREX_ASSERT(dst.boxArray() == y.boxArray());
    3016             :     AMREX_ASSERT(dst.distributionMap == y.distributionMap);
    3017             :     AMREX_ASSERT(dst.nGrowVect().allGE(nghost) && x.nGrowVect().allGE(nghost) && y.nGrowVect().allGE(nghost));
    3018             : 
    3019             :     BL_PROFILE("FabArray::LinComb()");
    3020             : 
    3021             : #ifdef AMREX_USE_GPU
    3022             :     if (Gpu::inLaunchRegion() && dst.isFusingCandidate()) {
    3023             :         auto const& dstma = dst.arrays();
    3024             :         auto const& xma = x.const_arrays();
    3025             :         auto const& yma = y.const_arrays();
    3026             :         ParallelFor(dst, nghost, numcomp,
    3027             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    3028             :         {
    3029             :             dstma[box_no](i,j,k,dstcomp+n) = a*xma[box_no](i,j,k,xcomp+n)
    3030             :                 +                            b*yma[box_no](i,j,k,ycomp+n);
    3031             :         });
    3032             :         if (!Gpu::inNoSyncRegion()) {
    3033             :             Gpu::streamSynchronize();
    3034             :         }
    3035             :     } else
    3036             : #endif
    3037             :     {
    3038             : #ifdef AMREX_USE_OMP
    3039             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    3040             : #endif
    3041             :         for (MFIter mfi(dst,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    3042             :         {
    3043             :             const Box& bx = mfi.growntilebox(nghost);
    3044             :             auto const& xfab = x.const_array(mfi);
    3045             :             auto const& yfab = y.const_array(mfi);
    3046             :             auto const& dfab = dst.array(mfi);
    3047             :             AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, numcomp, i, j, k, n,
    3048             :             {
    3049             :                 dfab(i,j,k,dstcomp+n) = a*xfab(i,j,k,xcomp+n) + b*yfab(i,j,k,ycomp+n);
    3050             :             });
    3051             :         }
    3052             :     }
    3053             : }
    3054             : 
    3055             : template <class FAB>
    3056             : template <typename BUF>
    3057             : void
    3058      233100 : FabArray<FAB>::FillBoundary (bool cross)
    3059             : {
    3060             :     BL_PROFILE("FabArray::FillBoundary()");
    3061      466200 :     if ( n_grow.max() > 0 ) {
    3062      233100 :         FillBoundary_nowait<BUF>(0, nComp(), n_grow, Periodicity::NonPeriodic(), cross);
    3063      233100 :         FillBoundary_finish<BUF>();
    3064             :     }
    3065      233100 : }
    3066             : 
    3067             : template <class FAB>
    3068             : template <typename BUF>
    3069             : void
    3070        3448 : FabArray<FAB>::FillBoundary (const Periodicity& period, bool cross)
    3071             : {
    3072             :     BL_PROFILE("FabArray::FillBoundary()");
    3073        6896 :     if ( n_grow.max() > 0 ) {
    3074        3382 :         FillBoundary_nowait<BUF>(0, nComp(), n_grow, period, cross);
    3075        3382 :         FillBoundary_finish<BUF>();
    3076             :     }
    3077        3448 : }
    3078             : 
    3079             : template <class FAB>
    3080             : template <typename BUF>
    3081             : void
    3082             : FabArray<FAB>::FillBoundary (const IntVect& nghost, const Periodicity& period, bool cross)
    3083             : {
    3084             :     BL_PROFILE("FabArray::FillBoundary()");
    3085             :     AMREX_ALWAYS_ASSERT_WITH_MESSAGE(nghost.allLE(nGrowVect()),
    3086             :                                      "FillBoundary: asked to fill more ghost cells than we have");
    3087             :     if ( nghost.max() > 0 ) {
    3088             :         FillBoundary_nowait<BUF>(0, nComp(), nghost, period, cross);
    3089             :         FillBoundary_finish<BUF>();
    3090             :     }
    3091             : }
    3092             : 
    3093             : template <class FAB>
    3094             : template <typename BUF>
    3095             : void
    3096             : FabArray<FAB>::FillBoundary (int scomp, int ncomp, bool cross)
    3097             : {
    3098             :     BL_PROFILE("FabArray::FillBoundary()");
    3099             :     if ( n_grow.max() > 0 ) {
    3100             :         FillBoundary_nowait<BUF>(scomp, ncomp, n_grow, Periodicity::NonPeriodic(), cross);
    3101             :         FillBoundary_finish<BUF>();
    3102             :     }
    3103             : }
    3104             : 
    3105             : template <class FAB>
    3106             : template <typename BUF>
    3107             : void
    3108             : FabArray<FAB>::FillBoundary (int scomp, int ncomp, const Periodicity& period, bool cross)
    3109             : {
    3110             :     BL_PROFILE("FabArray::FillBoundary()");
    3111             :     if ( n_grow.max() > 0 ) {
    3112             :         FillBoundary_nowait<BUF>(scomp, ncomp, n_grow, period, cross);
    3113             :         FillBoundary_finish<BUF>();
    3114             :     }
    3115             : }
    3116             : 
    3117             : template <class FAB>
    3118             : template <typename BUF>
    3119             : void
    3120         360 : FabArray<FAB>::FillBoundary (int scomp, int ncomp, const IntVect& nghost,
    3121             :                              const Periodicity& period, bool cross)
    3122             : {
    3123             :     BL_PROFILE("FabArray::FillBoundary()");
    3124         720 :     AMREX_ALWAYS_ASSERT_WITH_MESSAGE(nghost.allLE(nGrowVect()),
    3125             :                                      "FillBoundary: asked to fill more ghost cells than we have");
    3126         360 :     if ( nghost.max() > 0 ) {
    3127         360 :         FillBoundary_nowait<BUF>(scomp, ncomp, nghost, period, cross);
    3128         360 :         FillBoundary_finish<BUF>();
    3129             :     }
    3130         360 : }
    3131             : 
    3132             : template <class FAB>
    3133             : template <typename BUF>
    3134             : void
    3135             : FabArray<FAB>::FillBoundary_nowait (bool cross)
    3136             : {
    3137             :     FillBoundary_nowait<BUF>(0, nComp(), nGrowVect(), Periodicity::NonPeriodic(), cross);
    3138             : }
    3139             : 
    3140             : template <class FAB>
    3141             : template <typename BUF>
    3142             : void
    3143             : FabArray<FAB>::FillBoundary_nowait (const Periodicity& period, bool cross)
    3144             : {
    3145             :     FillBoundary_nowait<BUF>(0, nComp(), nGrowVect(), period, cross);
    3146             : }
    3147             : 
    3148             : template <class FAB>
    3149             : template <typename BUF>
    3150             : void
    3151             : FabArray<FAB>::FillBoundary_nowait (const IntVect& nghost, const Periodicity& period, bool cross)
    3152             : {
    3153             :     FillBoundary_nowait<BUF>(0, nComp(), nghost, period, cross);
    3154             : }
    3155             : 
    3156             : template <class FAB>
    3157             : template <typename BUF>
    3158             : void
    3159             : FabArray<FAB>::FillBoundary_nowait (int scomp, int ncomp, bool cross)
    3160             : {
    3161             :     FillBoundary_nowait<BUF>(scomp, ncomp, nGrowVect(), Periodicity::NonPeriodic(), cross);
    3162             : }
    3163             : 
    3164             : template <class FAB>
    3165             : void
    3166             : FabArray<FAB>::FillBoundaryAndSync (const Periodicity& period)
    3167             : {
    3168             :     BL_PROFILE("FabArray::FillBoundaryAndSync()");
    3169             :     if (n_grow.max() > 0 || !is_cell_centered()) {
    3170             :         FillBoundaryAndSync_nowait(0, nComp(), n_grow, period);
    3171             :         FillBoundaryAndSync_finish();
    3172             :     }
    3173             : }
    3174             : 
    3175             : template <class FAB>
    3176             : void
    3177             : FabArray<FAB>::FillBoundaryAndSync (int scomp, int ncomp, const IntVect& nghost,
    3178             :                                     const Periodicity& period)
    3179             : {
    3180             :     BL_PROFILE("FabArray::FillBoundaryAndSync()");
    3181             :     if (nghost.max() > 0 || !is_cell_centered()) {
    3182             :         FillBoundaryAndSync_nowait(scomp, ncomp, nghost, period);
    3183             :         FillBoundaryAndSync_finish();
    3184             :     }
    3185             : }
    3186             : 
    3187             : template <class FAB>
    3188             : void
    3189             : FabArray<FAB>::FillBoundaryAndSync_nowait (const Periodicity& period)
    3190             : {
    3191             :     FillBoundaryAndSync_nowait(0, nComp(), nGrowVect(), period);
    3192             : }
    3193             : 
    3194             : template <class FAB>
    3195             : void
    3196             : FabArray<FAB>::FillBoundaryAndSync_nowait (int scomp, int ncomp, const IntVect& nghost,
    3197             :                                            const Periodicity& period)
    3198             : {
    3199             :     BL_PROFILE("FillBoundaryAndSync_nowait()");
    3200             :     FBEP_nowait(scomp, ncomp, nghost, period, false, false, true);
    3201             : }
    3202             : 
    3203             : template <class FAB>
    3204             : void
    3205             : FabArray<FAB>::FillBoundaryAndSync_finish ()
    3206             : {
    3207             :     BL_PROFILE("FillBoundaryAndSync_finish()");
    3208             :     FillBoundary_finish();
    3209             : }
    3210             : 
    3211             : template <class FAB>
    3212             : void
    3213             : FabArray<FAB>::OverrideSync (const Periodicity& period)
    3214             : {
    3215             :     BL_PROFILE("FAbArray::OverrideSync()");
    3216             :     if (!is_cell_centered()) {
    3217             :         OverrideSync_nowait(0, nComp(), period);
    3218             :         OverrideSync_finish();
    3219             :     }
    3220             : }
    3221             : 
    3222             : template <class FAB>
    3223             : void
    3224             : FabArray<FAB>::OverrideSync (int scomp, int ncomp, const Periodicity& period)
    3225             : {
    3226             :     BL_PROFILE("FAbArray::OverrideSync()");
    3227             :     if (!is_cell_centered()) {
    3228             :         OverrideSync_nowait(scomp, ncomp, period);
    3229             :         OverrideSync_finish();
    3230             :     }
    3231             : }
    3232             : 
    3233             : template <class FAB>
    3234             : void
    3235             : FabArray<FAB>::OverrideSync_nowait (const Periodicity& period)
    3236             : {
    3237             :     OverrideSync_nowait(0, nComp(), period);
    3238             : }
    3239             : 
    3240             : template <class FAB>
    3241             : void
    3242             : FabArray<FAB>::OverrideSync_nowait (int scomp, int ncomp, const Periodicity& period)
    3243             : {
    3244             :     BL_PROFILE("OverrideSync_nowait()");
    3245             :     FBEP_nowait(scomp, ncomp, IntVect(0), period, false, false, true);
    3246             : }
    3247             : 
    3248             : template <class FAB>
    3249             : void
    3250             : FabArray<FAB>::OverrideSync_finish ()
    3251             : {
    3252             :     BL_PROFILE("OverrideSync_finish()");
    3253             :     FillBoundary_finish();
    3254             : }
    3255             : 
    3256             : template <class FAB>
    3257             : void
    3258             : FabArray<FAB>::SumBoundary (const Periodicity& period)
    3259             : {
    3260             :     SumBoundary(0, n_comp, IntVect(0), period);
    3261             : }
    3262             : 
    3263             : template <class FAB>
    3264             : void
    3265             : FabArray<FAB>::SumBoundary (int scomp, int ncomp, const Periodicity& period)
    3266             : {
    3267             :     SumBoundary(scomp, ncomp, IntVect(0), period);
    3268             : }
    3269             : 
    3270             : template <class FAB>
    3271             : void
    3272             : FabArray<FAB>::SumBoundary (int scomp, int ncomp, IntVect const& nghost, const Periodicity& period)
    3273             : {
    3274             :     SumBoundary(scomp, ncomp, this->nGrowVect(), nghost, period);
    3275             : }
    3276             : 
    3277             : template <class FAB>
    3278             : void
    3279             : FabArray<FAB>::SumBoundary (int scomp, int ncomp, IntVect const& src_nghost, IntVect const& dst_nghost, const Periodicity& period)
    3280             : {
    3281             :     BL_PROFILE("FabArray<FAB>::SumBoundary()");
    3282             : 
    3283             :     SumBoundary_nowait(scomp, ncomp, src_nghost, dst_nghost, period);
    3284             :     SumBoundary_finish();
    3285             : }
    3286             : 
    3287             : template <class FAB>
    3288             : void
    3289             : FabArray<FAB>::SumBoundary_nowait (const Periodicity& period)
    3290             : {
    3291             :     SumBoundary_nowait(0, n_comp, IntVect(0), period);
    3292             : }
    3293             : 
    3294             : template <class FAB>
    3295             : void
    3296             : FabArray<FAB>::SumBoundary_nowait (int scomp, int ncomp, const Periodicity& period)
    3297             : {
    3298             :     SumBoundary_nowait(scomp, ncomp, IntVect(0), period);
    3299             : }
    3300             : 
    3301             : template <class FAB>
    3302             : void
    3303             : FabArray<FAB>::SumBoundary_nowait (int scomp, int ncomp, IntVect const& nghost, const Periodicity& period)
    3304             : {
    3305             :     SumBoundary_nowait(scomp, ncomp, this->nGrowVect(), nghost, period);
    3306             : }
    3307             : 
    3308             : template <class FAB>
    3309             : void
    3310             : FabArray<FAB>::SumBoundary_nowait (int scomp, int ncomp, IntVect const& src_nghost, IntVect const& dst_nghost, const Periodicity& period)
    3311             : {
    3312             :     BL_PROFILE("FabArray<FAB>::SumBoundary_nowait()");
    3313             : 
    3314             :     if ( n_grow == IntVect::TheZeroVector() && boxArray().ixType().cellCentered()) { return; }
    3315             : 
    3316             :     AMREX_ALWAYS_ASSERT(src_nghost.allLE(n_grow));
    3317             : 
    3318             :     auto* tmp = new FabArray<FAB>( boxArray(), DistributionMap(), ncomp, src_nghost, MFInfo(), Factory() );
    3319             :     amrex::Copy(*tmp, *this, scomp, 0, ncomp, src_nghost);
    3320             :     this->setVal(typename FAB::value_type(0), scomp, ncomp, dst_nghost);
    3321             :     this->ParallelCopy_nowait(*tmp,0,scomp,ncomp,src_nghost,dst_nghost,period,FabArrayBase::ADD);
    3322             : 
    3323             :     // All local. Operation complete.
    3324             :     if (!this->pcd) { delete tmp; }
    3325             : }
    3326             : 
    3327             : template <class FAB>
    3328             : void
    3329             : FabArray<FAB>::SumBoundary_finish ()
    3330             : {
    3331             :     BL_PROFILE("FabArray<FAB>::SumBoundary_finish()");
    3332             : 
    3333             :     // If pcd doesn't exist, ParallelCopy was all local and operation was fully completed in "SumBoundary_nowait".
    3334             :     if ( (n_grow == IntVect::TheZeroVector() && boxArray().ixType().cellCentered()) || !(this->pcd) ) { return; }
    3335             : 
    3336             :     auto* tmp = const_cast<FabArray<FAB>*> (this->pcd->src);
    3337             :     this->ParallelCopy_finish();
    3338             :     delete tmp;
    3339             : }
    3340             : 
    3341             : template <class FAB>
    3342             : void
    3343             : FabArray<FAB>::EnforcePeriodicity (const Periodicity& period)
    3344             : {
    3345             :     BL_PROFILE("FabArray::EnforcePeriodicity");
    3346             :     if (period.isAnyPeriodic()) {
    3347             :         FBEP_nowait(0, nComp(), nGrowVect(), period, false, true);
    3348             :         FillBoundary_finish(); // unsafe unless isAnyPeriodic()
    3349             :     }
    3350             : }
    3351             : 
    3352             : template <class FAB>
    3353             : void
    3354             : FabArray<FAB>::EnforcePeriodicity (int scomp, int ncomp, const Periodicity& period)
    3355             : {
    3356             :     BL_PROFILE("FabArray::EnforcePeriodicity");
    3357             :     if (period.isAnyPeriodic()) {
    3358             :         FBEP_nowait(scomp, ncomp, nGrowVect(), period, false, true);
    3359             :         FillBoundary_finish(); // unsafe unless isAnyPeriodic()
    3360             :     }
    3361             : }
    3362             : 
    3363             : template <class FAB>
    3364             : void
    3365             : FabArray<FAB>::EnforcePeriodicity (int scomp, int ncomp, const IntVect& nghost,
    3366             :                                    const Periodicity& period)
    3367             : {
    3368             :     BL_PROFILE("FabArray::EnforcePeriodicity");
    3369             :     if (period.isAnyPeriodic()) {
    3370             :         FBEP_nowait(scomp, ncomp, nghost, period, false, true);
    3371             :         FillBoundary_finish(); // unsafe unless isAnyPeriodic()
    3372             :     }
    3373             : }
    3374             : 
    3375             : template <class FAB>
    3376             : template <typename BUF>
    3377             : void
    3378             : FabArray<FAB>::FillBoundary_nowait (int scomp, int ncomp, const Periodicity& period, bool cross)
    3379             : {
    3380             :     FBEP_nowait<BUF>(scomp, ncomp, nGrowVect(), period, cross);
    3381             : }
    3382             : 
    3383             : template <class FAB>
    3384             : template <typename BUF>
    3385             : void
    3386      236842 : FabArray<FAB>::FillBoundary_nowait (int scomp, int ncomp, const IntVect& nghost,
    3387             :                                     const Periodicity& period, bool cross)
    3388             : {
    3389      236842 :     FBEP_nowait<BUF>(scomp, ncomp, nghost, period, cross);
    3390      236842 : }
    3391             : 
    3392             : template <class FAB>
    3393             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>Z>
    3394             : void
    3395             : FabArray<FAB>::BuildMask (const Box& phys_domain, const Periodicity& period,
    3396             :                           value_type covered, value_type notcovered,
    3397             :                           value_type physbnd, value_type interior)
    3398             : {
    3399             :     BL_PROFILE("FabArray::BuildMask()");
    3400             : 
    3401             :     int ncomp = this->nComp();
    3402             :     const IntVect& ngrow = this->nGrowVect();
    3403             : 
    3404             :     Box domain = amrex::convert(phys_domain, boxArray().ixType());
    3405             :     for (int i = 0; i < AMREX_SPACEDIM; ++i) {
    3406             :         if (period.isPeriodic(i)) {
    3407             :             domain.grow(i, ngrow[i]);
    3408             :         }
    3409             :     }
    3410             : 
    3411             : #ifdef AMREX_USE_GPU
    3412             :     if (Gpu::inLaunchRegion() && this->isFusingCandidate()) {
    3413             :         auto const& fa = this->arrays();
    3414             :         ParallelFor(*this, ngrow, ncomp,
    3415             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    3416             :         {
    3417             :             auto const& fab = fa[box_no];
    3418             :             Box vbx(fab);
    3419             :             vbx.grow(-ngrow);
    3420             :             if (vbx.contains(i,j,k)) {
    3421             :                 fab(i,j,k,n) = interior;
    3422             :             } else if (domain.contains(i,j,k)) {
    3423             :                 fab(i,j,k,n) = notcovered;
    3424             :             } else {
    3425             :                 fab(i,j,k,n) = physbnd;
    3426             :             }
    3427             :         });
    3428             :         if (!Gpu::inNoSyncRegion()) {
    3429             :             Gpu::streamSynchronize();
    3430             :         }
    3431             :     } else
    3432             : #endif
    3433             :     {
    3434             : #ifdef AMREX_USE_OMP
    3435             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    3436             : #endif
    3437             :         for (MFIter mfi(*this,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    3438             :         {
    3439             :             auto const& fab = this->array(mfi);
    3440             :             Box const& fbx = mfi.growntilebox();
    3441             :             Box const& gbx = fbx & domain;
    3442             :             Box const& vbx = mfi.validbox();
    3443             :             AMREX_HOST_DEVICE_FOR_4D(fbx, ncomp, i, j, k, n,
    3444             :             {
    3445             :                 if (vbx.contains(i,j,k)) {
    3446             :                     fab(i,j,k,n) = interior;
    3447             :                 } else if (gbx.contains(i,j,k)) {
    3448             :                     fab(i,j,k,n) = notcovered;
    3449             :                 } else {
    3450             :                     fab(i,j,k,n) = physbnd;
    3451             :                 }
    3452             :             });
    3453             :         }
    3454             :     }
    3455             : 
    3456             :     const FabArrayBase::FB& TheFB = this->getFB(ngrow,period);
    3457             :     setVal(covered, TheFB, 0, ncomp);
    3458             : }
    3459             : 
    3460             : template <class FAB>
    3461             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    3462             : void
    3463           0 : FabArray<FAB>::setVal (value_type val, const CommMetaData& thecmd, int scomp, int ncomp)
    3464             : {
    3465             :     BL_PROFILE("FabArray::setVal(val, thecmd, scomp, ncomp)");
    3466             : 
    3467             : #ifdef AMREX_USE_GPU
    3468             :     if (Gpu::inLaunchRegion())
    3469             :     {
    3470             :         CMD_local_setVal_gpu(val, thecmd, scomp, ncomp);
    3471             :         CMD_remote_setVal_gpu(val, thecmd, scomp, ncomp);
    3472             :     }
    3473             :     else
    3474             : #endif
    3475             :     {
    3476             :         AMREX_ASSERT(thecmd.m_LocTags && thecmd.m_RcvTags);
    3477           0 :         const CopyComTagsContainer&      LocTags = *(thecmd.m_LocTags);
    3478           0 :         const MapOfCopyComTagContainers& RcvTags = *(thecmd.m_RcvTags);
    3479           0 :         auto N_locs = static_cast<int>(LocTags.size());
    3480             : #ifdef AMREX_USE_OMP
    3481             : #pragma omp parallel for if (thecmd.m_threadsafe_loc)
    3482             : #endif
    3483           0 :         for (int i = 0; i < N_locs; ++i) {
    3484           0 :             const CopyComTag& tag = LocTags[i];
    3485           0 :             (*this)[tag.dstIndex].template setVal<RunOn::Host>(val, tag.dbox, scomp, ncomp);
    3486             :         }
    3487             : 
    3488           0 :         for (const auto & RcvTag : RcvTags) {
    3489           0 :             auto N = static_cast<int>(RcvTag.second.size());
    3490             : #ifdef AMREX_USE_OMP
    3491             : #pragma omp parallel for if (thecmd.m_threadsafe_rcv)
    3492             : #endif
    3493           0 :             for (int i = 0; i < N; ++i) {
    3494           0 :                 const CopyComTag& tag = RcvTag.second[i];
    3495           0 :                 (*this)[tag.dstIndex].template setVal<RunOn::Host>(val, tag.dbox, scomp, ncomp);
    3496             :             }
    3497             :         }
    3498             :     }
    3499           0 : }
    3500             : 
    3501             : template <class FAB>
    3502             : template <class F, std::enable_if_t<IsBaseFab<F>::value,int>>
    3503             : LayoutData<int>
    3504             : FabArray<FAB>::RecvLayoutMask (const CommMetaData& thecmd)
    3505             : {
    3506             :     BL_PROFILE("FabArray::RecvLayoutMask()");
    3507             : 
    3508             :     LayoutData<int> r(this->boxArray(), this->DistributionMap());
    3509             : #ifdef AMREX_USE_OMP
    3510             : #pragma omp parallel if (thecmd.m_threadsafe_rcv)
    3511             : #endif
    3512             :     for (MFIter mfi(r); mfi.isValid(); ++mfi) {
    3513             :         r[mfi] = 0;
    3514             :     }
    3515             : 
    3516             :     const CopyComTagsContainer&      LocTags = *(thecmd.m_LocTags);
    3517             :     const MapOfCopyComTagContainers& RcvTags = *(thecmd.m_RcvTags);
    3518             : 
    3519             :     auto N_locs = static_cast<int>(LocTags.size());
    3520             :     for (int i = 0; i < N_locs; ++i) {
    3521             :         const CopyComTag& tag = LocTags[i];
    3522             :         r[tag.dstIndex] = 1;
    3523             :     }
    3524             : 
    3525             :     for (const auto & RcvTag : RcvTags) {
    3526             :         auto N = static_cast<int>(RcvTag.second.size());
    3527             :         for (int i = 0; i < N; ++i) {
    3528             :             const CopyComTag& tag = RcvTag.second[i];
    3529             :             r[tag.dstIndex] = 1;
    3530             :         }
    3531             :     }
    3532             :     return r;
    3533             : }
    3534             : 
    3535             : template <class FAB>
    3536             : template <typename F, std::enable_if_t<IsBaseFab<F>::value,int> FOO>
    3537             : typename F::value_type
    3538             : FabArray<FAB>::norminf (int comp, int ncomp, IntVect const& nghost, bool local,
    3539             :                         [[maybe_unused]] bool ignore_covered) const
    3540             : {
    3541             :     BL_PROFILE("FabArray::norminf()");
    3542             : 
    3543             :     using RT = typename F::value_type;
    3544             : 
    3545             :     auto nm0 = RT(0.0);
    3546             : 
    3547             : #ifdef AMREX_USE_EB
    3548             :     if ( this->is_cell_centered() && this->hasEBFabFactory() && ignore_covered )
    3549             :     {
    3550             :         const auto& ebfactory = dynamic_cast<EBFArrayBoxFactory const&>(this->Factory());
    3551             :         auto const& flags = ebfactory.getMultiEBCellFlagFab();
    3552             : #ifdef AMREX_USE_GPU
    3553             :         if (Gpu::inLaunchRegion()) {
    3554             :             auto const& flagsma = flags.const_arrays();
    3555             :             auto const& ma = this->const_arrays();
    3556             :             nm0 = ParReduce(TypeList<ReduceOpMax>{}, TypeList<RT>{}, *this, nghost,
    3557             :             [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept -> GpuTuple<RT>
    3558             :             {
    3559             :                 if (flagsma[box_no](i,j,k).isCovered()) {
    3560             :                     return RT(0.0);
    3561             :                 } else {
    3562             :                     auto tmp = RT(0.0);
    3563             :                     auto const& a = ma[box_no];
    3564             :                     for (int n = 0; n < ncomp; ++n) {
    3565             :                         tmp = amrex::max(tmp, std::abs(a(i,j,k,comp+n)));
    3566             :                     }
    3567             :                     return tmp;
    3568             :                 }
    3569             :             });
    3570             :         } else
    3571             : #endif
    3572             :         {
    3573             : #ifdef AMREX_USE_OMP
    3574             : #pragma omp parallel reduction(max:nm0)
    3575             : #endif
    3576             :             for (MFIter mfi(*this,true); mfi.isValid(); ++mfi) {
    3577             :                 Box const& bx = mfi.growntilebox(nghost);
    3578             :                 if (flags[mfi].getType(bx) != FabType::covered) {
    3579             :                     auto const& flag = flags.const_array(mfi);
    3580             :                     auto const& a = this->const_array(mfi);
    3581             :                     AMREX_LOOP_4D(bx, ncomp, i, j, k, n,
    3582             :                     {
    3583             :                         if (!flag(i,j,k).isCovered()) {
    3584             :                             nm0 = std::max(nm0, std::abs(a(i,j,k,comp+n)));
    3585             :                         }
    3586             :                     });
    3587             :                 }
    3588             :             }
    3589             :         }
    3590             :     }
    3591             :     else
    3592             : #endif
    3593             :     {
    3594             : #ifdef AMREX_USE_GPU
    3595             :         if (Gpu::inLaunchRegion()) {
    3596             :             auto const& ma = this->const_arrays();
    3597             :             nm0 = ParReduce(TypeList<ReduceOpMax>{}, TypeList<RT>{}, *this, nghost, ncomp,
    3598             :             [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept -> GpuTuple<RT>
    3599             :             {
    3600             :                 return std::abs(ma[box_no](i,j,k,comp+n));
    3601             :             });
    3602             :         } else
    3603             : #endif
    3604             :         {
    3605             : #ifdef AMREX_USE_OMP
    3606             : #pragma omp parallel reduction(max:nm0)
    3607             : #endif
    3608             :             for (MFIter mfi(*this,true); mfi.isValid(); ++mfi) {
    3609             :                 Box const& bx = mfi.growntilebox(nghost);
    3610             :                 auto const& a = this->const_array(mfi);
    3611             :                 AMREX_LOOP_4D(bx, ncomp, i, j, k, n,
    3612             :                 {
    3613             :                     nm0 = std::max(nm0, std::abs(a(i,j,k,comp+n)));
    3614             :                 });
    3615             :             }
    3616             :         }
    3617             :     }
    3618             : 
    3619             :     if (!local) {
    3620             :         ParallelAllReduce::Max(nm0, ParallelContext::CommunicatorSub());
    3621             :     }
    3622             : 
    3623             :     return nm0;
    3624             : }
    3625             : 
    3626             : template <class FAB>
    3627             : template <typename IFAB, typename F, std::enable_if_t<IsBaseFab<F>::value,int> FOO>
    3628             : typename F::value_type
    3629             : FabArray<FAB>::norminf (FabArray<IFAB> const& mask, int comp, int ncomp,
    3630             :                         IntVect const& nghost, bool local) const
    3631             : {
    3632             :     BL_PROFILE("FabArray::norminf(mask)");
    3633             : 
    3634             :     using RT = typename F::value_type;
    3635             : 
    3636             :     auto nm0 = RT(0.0);
    3637             : 
    3638             : #ifdef AMREX_USE_GPU
    3639             :     if (Gpu::inLaunchRegion()) {
    3640             :         auto const& ma = this->const_arrays();
    3641             :         auto const& maskma = mask.const_arrays();
    3642             :         nm0 = ParReduce(TypeList<ReduceOpMax>{}, TypeList<RT>{}, *this, IntVect(nghost),
    3643             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept -> GpuTuple<RT>
    3644             :         {
    3645             :             if (maskma[box_no](i,j,k)) {
    3646             :                 auto tmp = RT(0.0);
    3647             :                 auto const& a = ma[box_no];
    3648             :                 for (int n = 0; n < ncomp; ++n) {
    3649             :                     tmp = amrex::max(tmp, std::abs(a(i,j,k,comp+n)));
    3650             :                 }
    3651             :                 return tmp;
    3652             :             } else {
    3653             :                 return RT(0.0);
    3654             :             }
    3655             :         });
    3656             :     } else
    3657             : #endif
    3658             :     {
    3659             : #ifdef AMREX_USE_OMP
    3660             : #pragma omp parallel reduction(max:nm0)
    3661             : #endif
    3662             :         for (MFIter mfi(*this,true); mfi.isValid(); ++mfi) {
    3663             :             Box const& bx = mfi.growntilebox(nghost);
    3664             :             auto const& a = this->const_array(mfi);
    3665             :             auto const& mskfab = mask.const_array(mfi);
    3666             :             AMREX_LOOP_4D(bx, ncomp, i, j, k, n,
    3667             :             {
    3668             :                 if (mskfab(i,j,k)) {
    3669             :                     nm0 = std::max(nm0, std::abs(a(i,j,k,comp+n)));
    3670             :                 }
    3671             :             });
    3672             :         }
    3673             :     }
    3674             : 
    3675             :     if (!local) {
    3676             :         ParallelAllReduce::Max(nm0, ParallelContext::CommunicatorSub());
    3677             :     }
    3678             : 
    3679             :     return nm0;
    3680             : }
    3681             : 
    3682             : }
    3683             : 
    3684             : #endif /*BL_FABARRAY_H*/

Generated by: LCOV version 1.14