LCOV - code coverage report
Current view: top level - ext/amrex/2d-coverage-g++-24.08/include - AMReX_FabArrayUtility.H (source / functions) Hit Total Coverage
Test: coverage_merged.info Lines: 6 9 66.7 %
Date: 2024-11-18 05:28:54 Functions: 2 3 66.7 %

          Line data    Source code
       1             : #ifndef AMREX_FABARRAY_UTILITY_H_
       2             : #define AMREX_FABARRAY_UTILITY_H_
       3             : #include <AMReX_Config.H>
       4             : 
       5             : #include <AMReX_FabArray.H>
       6             : #include <AMReX_LayoutData.H>
       7             : #include <AMReX_Print.H>
       8             : #include <AMReX_ParReduce.H>
       9             : #include <limits>
      10             : 
      11             : namespace amrex {
      12             : 
      13             : template <class FAB, class F,
      14             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
      15             : typename FAB::value_type
      16             : ReduceSum (FabArray<FAB> const& fa, int nghost, F&& f) {
      17             :     return ReduceSum(fa, IntVect(nghost), std::forward<F>(f));
      18             : }
      19             : 
      20             : namespace fudetail {
      21             : template <class FAB, class F,
      22             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
      23             : typename FAB::value_type
      24             : ReduceSum_host (FabArray<FAB> const& fa, IntVect const& nghost, F const& f)
      25             : {
      26             :     using value_type = typename FAB::value_type;
      27             :     value_type sm = 0;
      28             : 
      29             : #ifdef AMREX_USE_OMP
      30             : #pragma omp parallel if (!system::regtest_reduction) reduction(+:sm)
      31             : #endif
      32             :     for (MFIter mfi(fa,true); mfi.isValid(); ++mfi)
      33             :     {
      34             :         const Box& bx = mfi.growntilebox(nghost);
      35             :         auto const& arr = fa.const_array(mfi);
      36             :         sm += f(bx, arr);
      37             :     }
      38             : 
      39             :     return sm;
      40             : }
      41             : }
      42             : 
      43             : #ifdef AMREX_USE_GPU
      44             : namespace fudetail {
      45             : template <class OP, class FAB, class F>
      46             : std::enable_if_t<IsBaseFab<FAB>::value,
      47             :                  std::conditional_t<std::is_same<OP,ReduceOpLogicalAnd>::value ||
      48             :                                     std::is_same<OP,ReduceOpLogicalOr>::value,
      49             :                                     int, typename FAB::value_type> >
      50             : ReduceMF (FabArray<FAB> const& fa, IntVect const& nghost, F const& f)
      51             : {
      52             :     using T = std::conditional_t<std::is_same<OP,ReduceOpLogicalAnd>::value ||
      53             :                                  std::is_same<OP,ReduceOpLogicalOr>::value,
      54             :                                  int, typename FAB::value_type>;
      55             :     auto typ = fa.ixType();
      56             :     auto const& ma = fa.const_arrays();
      57             :     return ParReduce(TypeList<OP>{}, TypeList<T>{}, fa, nghost,
      58             :            [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept -> GpuTuple<T>
      59             :            {
      60             :                return { static_cast<T>(f(amrex::makeSingleCellBox(i,j,k,typ), ma[box_no])) };
      61             :            });
      62             : }
      63             : 
      64             : template <class OP, class FAB1, class FAB2, class F>
      65             : std::enable_if_t<IsBaseFab<FAB1>::value && IsBaseFab<FAB2>::value,
      66             :                  std::conditional_t<std::is_same<OP,ReduceOpLogicalAnd>::value ||
      67             :                                     std::is_same<OP,ReduceOpLogicalOr>::value,
      68             :                                     int, typename FAB1::value_type> >
      69             : ReduceMF (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2, IntVect const& nghost, F const& f)
      70             : {
      71             :     using T = std::conditional_t<std::is_same<OP,ReduceOpLogicalAnd>::value ||
      72             :                                  std::is_same<OP,ReduceOpLogicalOr>::value,
      73             :                                  int, typename FAB1::value_type>;
      74             :     auto typ = fa1.ixType();
      75             :     auto const& ma1 = fa1.const_arrays();
      76             :     auto const& ma2 = fa2.const_arrays();
      77             :     return ParReduce(TypeList<OP>{}, TypeList<T>{}, fa1, nghost,
      78             :            [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept -> GpuTuple<T>
      79             :            {
      80             :                return { static_cast<T>(f(amrex::makeSingleCellBox(i,j,k,typ),
      81             :                                          ma1[box_no], ma2[box_no])) };
      82             :            });
      83             : }
      84             : 
      85             : template <class OP, class FAB1, class FAB2, class FAB3, class F>
      86             : std::enable_if_t<IsBaseFab<FAB1>::value && IsBaseFab<FAB2>::value && IsBaseFab<FAB3>::value,
      87             :                  std::conditional_t<std::is_same<OP,ReduceOpLogicalAnd>::value ||
      88             :                                     std::is_same<OP,ReduceOpLogicalOr>::value,
      89             :                                     int, typename FAB1::value_type> >
      90             : ReduceMF (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
      91             :           FabArray<FAB3> const& fa3, IntVect const& nghost, F const& f)
      92             : {
      93             :     using T = std::conditional_t<std::is_same<OP,ReduceOpLogicalAnd>::value ||
      94             :                                  std::is_same<OP,ReduceOpLogicalOr>::value,
      95             :                                  int, typename FAB1::value_type>;
      96             :     auto typ = fa1.ixType();
      97             :     auto const& ma1 = fa1.const_arrays();
      98             :     auto const& ma2 = fa2.const_arrays();
      99             :     auto const& ma3 = fa3.const_arrays();
     100             :     return ParReduce(TypeList<OP>{}, TypeList<T>{}, fa1, nghost,
     101             :            [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept -> GpuTuple<T>
     102             :            {
     103             :                return { static_cast<T>(f(amrex::makeSingleCellBox(i,j,k,typ),
     104             :                                          ma1[box_no], ma2[box_no], ma3[box_no])) };
     105             :            });
     106             : }
     107             : 
     108             : template <class FAB, class F>
     109             : std::enable_if_t<!amrex::DefinitelyNotHostRunnable<F>::value, typename FAB::value_type>
     110             : ReduceSum_host_wrapper (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     111             : {
     112             :     return ReduceSum_host(fa,nghost,std::forward<F>(f));
     113             : }
     114             : 
     115             : template <class FAB, class F>
     116             : std::enable_if_t<amrex::DefinitelyNotHostRunnable<F>::value, typename FAB::value_type>
     117             : ReduceSum_host_wrapper (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     118             : {
     119             :     amrex::ignore_unused(fa,nghost,f);
     120             :     amrex::Abort("ReduceSum: Launch Region is off. Device lambda cannot be called by host.");
     121             :     return 0;
     122             : }
     123             : }
     124             : 
     125             : template <class FAB, class F,
     126             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     127             : typename FAB::value_type
     128             : ReduceSum (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     129             : {
     130             :     if (Gpu::inLaunchRegion()) {
     131             :         return fudetail::ReduceMF<ReduceOpSum>(fa, nghost, std::forward<F>(f));
     132             :     } else {
     133             :         return fudetail::ReduceSum_host_wrapper(fa, nghost, std::forward<F>(f));
     134             :     }
     135             : }
     136             : #else
     137             : template <class FAB, class F,
     138             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     139             : typename FAB::value_type
     140             : ReduceSum (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     141             : {
     142             :     return fudetail::ReduceSum_host(fa, nghost, std::forward<F>(f));
     143             : }
     144             : #endif
     145             : 
     146             : template <class FAB1, class FAB2, class F,
     147             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     148             : typename FAB1::value_type
     149             : ReduceSum (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     150             :            int nghost, F&& f) {
     151             :     return ReduceSum(fa1, fa2, IntVect(nghost), std::forward<F>(f));
     152             : }
     153             : 
     154             : namespace fudetail {
     155             : template <class FAB1, class FAB2, class F,
     156             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     157             : typename FAB1::value_type
     158             : ReduceSum_host (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     159             :                 IntVect const& nghost, F const& f)
     160             : {
     161             :     using value_type = typename FAB1::value_type;
     162             :     value_type sm = 0;
     163             : 
     164             : #ifdef AMREX_USE_OMP
     165             : #pragma omp parallel if (!system::regtest_reduction) reduction(+:sm)
     166             : #endif
     167             :     for (MFIter mfi(fa1,true); mfi.isValid(); ++mfi)
     168             :     {
     169             :         const Box& bx = mfi.growntilebox(nghost);
     170             :         const auto& arr1 = fa1.const_array(mfi);
     171             :         const auto& arr2 = fa2.const_array(mfi);
     172             :         sm += f(bx, arr1, arr2);
     173             :     }
     174             : 
     175             :     return sm;
     176             : }
     177             : }
     178             : 
     179             : #ifdef AMREX_USE_GPU
     180             : namespace fudetail {
     181             : template <class FAB1, class FAB2, class F>
     182             : std::enable_if_t<!amrex::DefinitelyNotHostRunnable<F>::value, typename FAB1::value_type>
     183             : ReduceSum_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     184             :                         IntVect const& nghost, F&& f)
     185             : {
     186             :     return ReduceSum_host(fa1,fa2,nghost,std::forward<F>(f));
     187             : }
     188             : 
     189             : template <class FAB1, class FAB2, class F>
     190             : std::enable_if_t<amrex::DefinitelyNotHostRunnable<F>::value, typename FAB1::value_type>
     191             : ReduceSum_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     192             :                         IntVect const& nghost, F&& f)
     193             : {
     194             :     amrex::ignore_unused(fa1,fa2,nghost,f);
     195             :     amrex::Abort("ReduceSum: Launch Region is off. Device lambda cannot be called by host.");
     196             :     return 0;
     197             : }
     198             : }
     199             : 
     200             : template <class FAB1, class FAB2, class F,
     201             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     202             : typename FAB1::value_type
     203             : ReduceSum (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     204             :            IntVect const& nghost, F&& f)
     205             : {
     206             :     if (Gpu::inLaunchRegion()) {
     207             :         return fudetail::ReduceMF<ReduceOpSum>(fa1,fa2,nghost,std::forward<F>(f));
     208             :     } else {
     209             :         return fudetail::ReduceSum_host_wrapper(fa1,fa2,nghost,std::forward<F>(f));
     210             :     }
     211             : }
     212             : #else
     213             : template <class FAB1, class FAB2, class F,
     214             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     215             : typename FAB1::value_type
     216             : ReduceSum (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     217             :            IntVect const& nghost, F&& f)
     218             : {
     219             :     return fudetail::ReduceSum_host(fa1,fa2,nghost,std::forward<F>(f));
     220             : }
     221             : #endif
     222             : 
     223             : template <class FAB1, class FAB2, class FAB3, class F,
     224             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     225             : typename FAB1::value_type
     226             : ReduceSum (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2, FabArray<FAB3> const& fa3,
     227             :            int nghost, F&& f)
     228             : {
     229             :   return ReduceSum(fa1, fa2, fa3, IntVect(nghost), std::forward<F>(f));
     230             : }
     231             : 
     232             : namespace fudetail {
     233             : template <class FAB1, class FAB2, class FAB3, class F,
     234             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     235             : typename FAB1::value_type
     236             : ReduceSum_host (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     237             :                 FabArray<FAB3> const& fa3, IntVect const& nghost, F const& f)
     238             : {
     239             :     using value_type = typename FAB1::value_type;
     240             :     value_type sm = 0;
     241             : 
     242             : #ifdef AMREX_USE_OMP
     243             : #pragma omp parallel if (!system::regtest_reduction) reduction(+:sm)
     244             : #endif
     245             :     for (MFIter mfi(fa1,true); mfi.isValid(); ++mfi)
     246             :     {
     247             :         const Box& bx = mfi.growntilebox(nghost);
     248             :         const auto& arr1 = fa1.const_array(mfi);
     249             :         const auto& arr2 = fa2.const_array(mfi);
     250             :         const auto& arr3 = fa3.const_array(mfi);
     251             :         sm += f(bx, arr1, arr2, arr3);
     252             :     }
     253             : 
     254             :     return sm;
     255             : }
     256             : }
     257             : 
     258             : #ifdef AMREX_USE_GPU
     259             : namespace fudetail {
     260             : template <class FAB1, class FAB2, class FAB3, class F>
     261             : std::enable_if_t<!amrex::DefinitelyNotHostRunnable<F>::value, typename FAB1::value_type>
     262             : ReduceSum_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     263             :                         FabArray<FAB3> const& fa3, IntVect const& nghost, F&& f)
     264             : {
     265             :     return fudetail::ReduceSum_host(fa1,fa2,fa3,nghost,std::forward<F>(f));
     266             : }
     267             : 
     268             : template <class FAB1, class FAB2, class FAB3, class F>
     269             : std::enable_if_t<amrex::DefinitelyNotHostRunnable<F>::value, typename FAB1::value_type>
     270             : ReduceSum_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     271             :                         FabArray<FAB3> const& fa3, IntVect const& nghost, F&& f)
     272             : {
     273             :     amrex::ignore_unused(fa1,fa2,fa3,nghost,f);
     274             :     amrex::Abort("ReduceSum: Launch Region is off. Device lambda cannot be called by host.");
     275             :     return 0;
     276             : }
     277             : }
     278             : 
     279             : template <class FAB1, class FAB2, class FAB3, class F,
     280             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     281             : typename FAB1::value_type
     282             : ReduceSum (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     283             :            FabArray<FAB3> const& fa3, IntVect const& nghost, F&& f)
     284             : {
     285             :     if (Gpu::inLaunchRegion()) {
     286             :         return fudetail::ReduceMF<ReduceOpSum>(fa1,fa2,fa3,nghost,std::forward<F>(f));
     287             :     } else {
     288             :         return fudetail::ReduceSum_host_wrapper(fa1,fa2,fa3,nghost,std::forward<F>(f));
     289             :     }
     290             : }
     291             : #else
     292             : template <class FAB1, class FAB2, class FAB3, class F,
     293             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     294             : typename FAB1::value_type
     295             : ReduceSum (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     296             :            FabArray<FAB3> const& fa3, IntVect const& nghost, F&& f)
     297             : {
     298             :     return fudetail::ReduceSum_host(fa1,fa2,fa3,nghost,std::forward<F>(f));
     299             : }
     300             : #endif
     301             : 
     302             : template <class FAB, class F,
     303             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     304             : typename FAB::value_type
     305             : ReduceMin (FabArray<FAB> const& fa, int nghost, F&& f)
     306             : {
     307             :     return ReduceMin(fa, IntVect(nghost), std::forward<F>(f));
     308             : }
     309             : 
     310             : namespace fudetail {
     311             : template <class FAB, class F,
     312             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     313             : typename FAB::value_type
     314             : ReduceMin_host (FabArray<FAB> const& fa, IntVect const& nghost, F const& f)
     315             : {
     316             :     using value_type = typename FAB::value_type;
     317             :     value_type r = std::numeric_limits<value_type>::max();
     318             : 
     319             : #ifdef AMREX_USE_OMP
     320             : #pragma omp parallel reduction(min:r)
     321             : #endif
     322             :     for (MFIter mfi(fa,true); mfi.isValid(); ++mfi)
     323             :     {
     324             :         const Box& bx = mfi.growntilebox(nghost);
     325             :         const auto& arr = fa.const_array(mfi);
     326             :         r = std::min(r, f(bx, arr));
     327             :     }
     328             :     return r;
     329             : }
     330             : }
     331             : 
     332             : #ifdef AMREX_USE_GPU
     333             : namespace fudetail {
     334             : template <class FAB, class F>
     335             : std::enable_if_t<!amrex::DefinitelyNotHostRunnable<F>::value, typename FAB::value_type>
     336             : ReduceMin_host_wrapper (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     337             : {
     338             :     return ReduceMin_host(fa,nghost,std::forward<F>(f));
     339             : }
     340             : 
     341             : template <class FAB, class F>
     342             : std::enable_if_t<amrex::DefinitelyNotHostRunnable<F>::value, typename FAB::value_type>
     343             : ReduceMin_host_wrapper (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     344             : {
     345             :     amrex::ignore_unused(fa,nghost,f);
     346             :     amrex::Abort("ReduceMin: Launch Region is off. Device lambda cannot be called by host.");
     347             :     return 0;
     348             : }
     349             : }
     350             : 
     351             : template <class FAB, class F,
     352             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     353             : typename FAB::value_type
     354             : ReduceMin (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     355             : {
     356             :     if (Gpu::inLaunchRegion()) {
     357             :         return fudetail::ReduceMF<ReduceOpMin>(fa, nghost, std::forward<F>(f));
     358             :     } else {
     359             :         return fudetail::ReduceMin_host_wrapper(fa, nghost, std::forward<F>(f));
     360             :     }
     361             : }
     362             : #else
     363             : template <class FAB, class F,
     364             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     365             : typename FAB::value_type
     366             : ReduceMin (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     367             : {
     368             :     return fudetail::ReduceMin_host(fa, nghost, std::forward<F>(f));
     369             : }
     370             : #endif
     371             : 
     372             : template <class FAB1, class FAB2, class F,
     373             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     374             : typename FAB1::value_type
     375             : ReduceMin (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2, int nghost, F&& f)
     376             : {
     377             :     return ReduceMin(fa1, fa2, IntVect(nghost), std::forward<F>(f));
     378             : }
     379             : 
     380             : namespace fudetail {
     381             : template <class FAB1, class FAB2, class F,
     382             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     383             : typename FAB1::value_type
     384             : ReduceMin_host (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     385             :                 IntVect const& nghost, F const& f)
     386             : {
     387             :     using value_type = typename FAB1::value_type;
     388             :     value_type r = std::numeric_limits<value_type>::max();
     389             : 
     390             : #ifdef AMREX_USE_OMP
     391             : #pragma omp parallel reduction(min:r)
     392             : #endif
     393             :     for (MFIter mfi(fa1,true); mfi.isValid(); ++mfi)
     394             :     {
     395             :         const Box& bx = mfi.growntilebox(nghost);
     396             :         const auto& arr1 = fa1.const_array(mfi);
     397             :         const auto& arr2 = fa2.const_array(mfi);
     398             :         r = std::min(r, f(bx, arr1, arr2));
     399             :     }
     400             : 
     401             :     return r;
     402             : }
     403             : }
     404             : 
     405             : #ifdef AMREX_USE_GPU
     406             : namespace fudetail {
     407             : template <class FAB1, class FAB2, class F>
     408             : std::enable_if_t<!amrex::DefinitelyNotHostRunnable<F>::value, typename FAB1::value_type>
     409             : ReduceMin_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     410             :                         IntVect const& nghost, F&& f)
     411             : {
     412             :     return fudetail::ReduceMin_host(fa1,fa2,nghost,std::forward<F>(f));
     413             : }
     414             : 
     415             : template <class FAB1, class FAB2, class F>
     416             : std::enable_if_t<amrex::DefinitelyNotHostRunnable<F>::value, typename FAB1::value_type>
     417             : ReduceMin_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     418             :                         IntVect const& nghost, F&& f)
     419             : {
     420             :     amrex::ignore_unused(fa1,fa2,nghost,f);
     421             :     amrex::Abort("ReduceMin: Launch Region is off. Device lambda cannot be called by host.");
     422             :     return 0;
     423             : }
     424             : }
     425             : 
     426             : template <class FAB1, class FAB2, class F,
     427             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     428             : typename FAB1::value_type
     429             : ReduceMin (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     430             :            IntVect const& nghost, F&& f)
     431             : {
     432             :     if (Gpu::inLaunchRegion()) {
     433             :         return fudetail::ReduceMF<ReduceOpMin>(fa1,fa2,nghost,std::forward<F>(f));
     434             :     } else {
     435             :         return fudetail::ReduceMin_host_wrapper(fa1,fa2,nghost,std::forward<F>(f));
     436             :     }
     437             : }
     438             : #else
     439             : template <class FAB1, class FAB2, class F,
     440             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     441             : typename FAB1::value_type
     442             : ReduceMin (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     443             :            IntVect const& nghost, F&& f)
     444             : {
     445             :     return fudetail::ReduceMin_host(fa1,fa2,nghost,std::forward<F>(f));
     446             : }
     447             : #endif
     448             : 
     449             : template <class FAB1, class FAB2, class FAB3, class F,
     450             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     451             : typename FAB1::value_type
     452             : ReduceMin (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2, FabArray<FAB3> const& fa3,
     453             :            int nghost, F&& f)
     454             : {
     455             :     return ReduceMin(fa1, fa2, fa3, IntVect(nghost), std::forward<F>(f));
     456             : }
     457             : 
     458             : namespace fudetail {
     459             : template <class FAB1, class FAB2, class FAB3, class F,
     460             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     461             : typename FAB1::value_type
     462             : ReduceMin_host (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     463             :                 FabArray<FAB3> const& fa3, IntVect const& nghost, F const& f)
     464             : {
     465             :     using value_type = typename FAB1::value_type;
     466             :     value_type r = std::numeric_limits<value_type>::max();
     467             : 
     468             : #ifdef AMREX_USE_OMP
     469             : #pragma omp parallel reduction(min:r)
     470             : #endif
     471             :     for (MFIter mfi(fa1,true); mfi.isValid(); ++mfi)
     472             :     {
     473             :         const Box& bx = mfi.growntilebox(nghost);
     474             :         const auto& arr1 = fa1.const_array(mfi);
     475             :         const auto& arr2 = fa2.const_array(mfi);
     476             :         const auto& arr3 = fa3.const_array(mfi);
     477             :         r = std::min(r, f(bx, arr1, arr2, arr3));
     478             :     }
     479             : 
     480             :     return r;
     481             : }
     482             : }
     483             : 
     484             : #ifdef AMREX_USE_GPU
     485             : namespace fudetail {
     486             : template <class FAB1, class FAB2, class FAB3, class F>
     487             : std::enable_if_t<!amrex::DefinitelyNotHostRunnable<F>::value, typename FAB1::value_type>
     488             : ReduceMin_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     489             :                         FabArray<FAB3> const& fa3, IntVect const& nghost, F&& f)
     490             : {
     491             :     return fudetail::ReduceMin_host(fa1,fa2,fa3,nghost,std::forward<F>(f));
     492             : }
     493             : 
     494             : template <class FAB1, class FAB2, class FAB3, class F>
     495             : std::enable_if_t<amrex::DefinitelyNotHostRunnable<F>::value, typename FAB1::value_type>
     496             : ReduceMin_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     497             :                         FabArray<FAB3> const& fa3, IntVect const& nghost, F&& f)
     498             : {
     499             :     amrex::ignore_unused(fa1,fa2,fa3,nghost,f);
     500             :     amrex::Abort("ReduceMin: Launch Region is off. Device lambda lambda cannot be called by host.");
     501             :     return 0;
     502             : }
     503             : }
     504             : 
     505             : template <class FAB1, class FAB2, class FAB3, class F,
     506             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     507             : typename FAB1::value_type
     508             : ReduceMin (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     509             :            FabArray<FAB3> const& fa3, IntVect const& nghost, F&& f)
     510             : {
     511             :     if (Gpu::inLaunchRegion()) {
     512             :         return fudetail::ReduceMF<ReduceOpMin>(fa1,fa2,fa3,nghost,std::forward<F>(f));
     513             :     } else {
     514             :         return fudetail::ReduceMin_host_wrapper(fa1,fa2,fa3,nghost,std::forward<F>(f));
     515             :     }
     516             : }
     517             : #else
     518             : template <class FAB1, class FAB2, class FAB3, class F,
     519             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     520             : typename FAB1::value_type
     521             : ReduceMin (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     522             :            FabArray<FAB3> const& fa3, IntVect const& nghost, F&& f)
     523             : {
     524             :     return fudetail::ReduceMin_host(fa1,fa2,fa3,nghost,std::forward<F>(f));
     525             : }
     526             : #endif
     527             : 
     528             : template <class FAB, class F,
     529             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     530             : typename FAB::value_type
     531             : ReduceMax (FabArray<FAB> const& fa, int nghost, F&& f)
     532             : {
     533             :     return ReduceMax(fa, IntVect(nghost), std::forward<F>(f));
     534             : }
     535             : 
     536             : namespace fudetail {
     537             : template <class FAB, class F,
     538             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     539             : typename FAB::value_type
     540             : ReduceMax_host (FabArray<FAB> const& fa, IntVect const& nghost, F const& f)
     541             : {
     542             :     using value_type = typename FAB::value_type;
     543             :     value_type r = std::numeric_limits<value_type>::lowest();
     544             : 
     545             : #ifdef AMREX_USE_OMP
     546             : #pragma omp parallel reduction(max:r)
     547             : #endif
     548             :     for (MFIter mfi(fa,true); mfi.isValid(); ++mfi)
     549             :     {
     550             :         const Box& bx = mfi.growntilebox(nghost);
     551             :         const auto& arr = fa.const_array(mfi);
     552             :         r = std::max(r, f(bx, arr));
     553             :     }
     554             : 
     555             :     return r;
     556             : }
     557             : }
     558             : 
     559             : #ifdef AMREX_USE_GPU
     560             : namespace fudetail {
     561             : template <class FAB, class F>
     562             : std::enable_if_t<!amrex::DefinitelyNotHostRunnable<F>::value, typename FAB::value_type>
     563             : ReduceMax_host_wrapper (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     564             : {
     565             :     return ReduceMax_host(fa,nghost,std::forward<F>(f));
     566             : }
     567             : 
     568             : template <class FAB, class F>
     569             : std::enable_if_t<amrex::DefinitelyNotHostRunnable<F>::value, typename FAB::value_type>
     570             : ReduceMax_host_wrapper (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     571             : {
     572             :     amrex::ignore_unused(fa,nghost,f);
     573             :     amrex::Abort("ReduceMax: Launch Region is off. Device lambda cannot be called by host.");
     574             :     return 0;
     575             : }
     576             : }
     577             : 
     578             : template <class FAB, class F,
     579             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     580             : typename FAB::value_type
     581             : ReduceMax (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     582             : {
     583             :     if (Gpu::inLaunchRegion()) {
     584             :         return fudetail::ReduceMF<ReduceOpMax>(fa,nghost,std::forward<F>(f));
     585             :     } else {
     586             :         return fudetail::ReduceMax_host_wrapper(fa,nghost,std::forward<F>(f));
     587             :     }
     588             : }
     589             : #else
     590             : template <class FAB, class F,
     591             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     592             : typename FAB::value_type
     593             : ReduceMax (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     594             : {
     595             :     return fudetail::ReduceMax_host(fa,nghost,std::forward<F>(f));
     596             : }
     597             : #endif
     598             : 
     599             : template <class FAB1, class FAB2, class F,
     600             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     601             : typename FAB1::value_type
     602             : ReduceMax (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2, int nghost, F&& f)
     603             : {
     604             :     return ReduceMax(fa1, fa2, IntVect(nghost), std::forward<F>(f));
     605             : }
     606             : 
     607             : namespace fudetail {
     608             : template <class FAB1, class FAB2, class F,
     609             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     610             : typename FAB1::value_type
     611             : ReduceMax_host (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     612             :                 IntVect const& nghost, F const& f)
     613             : {
     614             :     using value_type = typename FAB1::value_type;
     615             :     value_type r = std::numeric_limits<value_type>::lowest();
     616             : 
     617             : #ifdef AMREX_USE_OMP
     618             : #pragma omp parallel reduction(max:r)
     619             : #endif
     620             :     for (MFIter mfi(fa1,true); mfi.isValid(); ++mfi)
     621             :     {
     622             :         const Box& bx = mfi.growntilebox(nghost);
     623             :         const auto& arr1 = fa1.const_array(mfi);
     624             :         const auto& arr2 = fa2.const_array(mfi);
     625             :         r = std::max(r, f(bx, arr1, arr2));
     626             :     }
     627             : 
     628             :     return r;
     629             : }
     630             : }
     631             : 
     632             : #ifdef AMREX_USE_GPU
     633             : namespace fudetail {
     634             : template <class FAB1, class FAB2, class F>
     635             : std::enable_if_t<!amrex::DefinitelyNotHostRunnable<F>::value, typename FAB1::value_type>
     636             : ReduceMax_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     637             :                         IntVect const& nghost, F&& f)
     638             : {
     639             :     return ReduceMax_host(fa1,fa2,nghost,std::forward<F>(f));
     640             : }
     641             : 
     642             : template <class FAB1, class FAB2, class F>
     643             : std::enable_if_t<amrex::DefinitelyNotHostRunnable<F>::value, typename FAB1::value_type>
     644             : ReduceMax_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     645             :                         IntVect const& nghost, F&& f)
     646             : {
     647             :     amrex::ignore_unused(fa1,fa2,nghost,f);
     648             :     amrex::Abort("ReduceMax: Launch Region is off. Device lambda cannot be called by host.");
     649             :     return 0;
     650             : }
     651             : }
     652             : 
     653             : template <class FAB1, class FAB2, class F,
     654             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     655             : typename FAB1::value_type
     656             : ReduceMax (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     657             :            IntVect const& nghost, F&& f)
     658             : {
     659             :     if (Gpu::inLaunchRegion()) {
     660             :         return fudetail::ReduceMF<ReduceOpMax>(fa1,fa2,nghost,std::forward<F>(f));
     661             :     } else {
     662             :         return fudetail::ReduceMax_host_wrapper(fa1,fa2,nghost,std::forward<F>(f));
     663             :     }
     664             : }
     665             : #else
     666             : template <class FAB1, class FAB2, class F,
     667             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     668             : typename FAB1::value_type
     669             : ReduceMax (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     670             :            IntVect const& nghost, F&& f)
     671             : {
     672             :     return fudetail::ReduceMax_host(fa1,fa2,nghost,std::forward<F>(f));
     673             : }
     674             : #endif
     675             : 
     676             : template <class FAB1, class FAB2, class FAB3, class F,
     677             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     678             : typename FAB1::value_type
     679             : ReduceMax (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2, FabArray<FAB3> const& fa3,
     680             :            int nghost, F&& f)
     681             : {
     682             :     return ReduceMax(fa1, fa2, fa3, IntVect(nghost), std::forward<F>(f));
     683             : }
     684             : 
     685             : namespace fudetail {
     686             : template <class FAB1, class FAB2, class FAB3, class F,
     687             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     688             : typename FAB1::value_type
     689             : ReduceMax_host (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     690             :                 FabArray<FAB3> const& fa3, IntVect const& nghost, F const& f)
     691             : {
     692             :     using value_type = typename FAB1::value_type;
     693             :     value_type r = std::numeric_limits<value_type>::lowest();
     694             : 
     695             : #ifdef AMREX_USE_OMP
     696             : #pragma omp parallel reduction(max:r)
     697             : #endif
     698             :     for (MFIter mfi(fa1,true); mfi.isValid(); ++mfi)
     699             :     {
     700             :         const Box& bx = mfi.growntilebox(nghost);
     701             :         const auto& arr1 = fa1.const_array(mfi);
     702             :         const auto& arr2 = fa2.const_array(mfi);
     703             :         const auto& arr3 = fa3.const_array(mfi);
     704             :         r = std::max(r, f(bx, arr1, arr2, arr3));
     705             :     }
     706             : 
     707             :     return r;
     708             : }
     709             : }
     710             : 
     711             : #ifdef AMREX_USE_GPU
     712             : namespace fudetail {
     713             : template <class FAB1, class FAB2, class FAB3, class F>
     714             : std::enable_if_t<!amrex::DefinitelyNotHostRunnable<F>::value, typename FAB1::value_type>
     715             : ReduceMax_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     716             :                         FabArray<FAB3> const& fa3, IntVect const& nghost, F&& f)
     717             : {
     718             :     return fudetail::ReduceMax_host(fa1,fa2,fa3,nghost,std::forward<F>(f));
     719             : }
     720             : 
     721             : template <class FAB1, class FAB2, class FAB3, class F>
     722             : std::enable_if_t<amrex::DefinitelyNotHostRunnable<F>::value, typename FAB1::value_type>
     723             : ReduceMax_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     724             :                         FabArray<FAB3> const& fa3, IntVect const& nghost, F&& f)
     725             : {
     726             :     amrex::ignore_unused(fa1,fa2,fa3,nghost,f);
     727             :     amrex::Abort("ReduceMax: Launch Region is off. Device lambda lambda cannot be called by host.");
     728             :     return 0;
     729             : }
     730             : }
     731             : 
     732             : template <class FAB1, class FAB2, class FAB3, class F,
     733             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     734             : typename FAB1::value_type
     735             : ReduceMax (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     736             :            FabArray<FAB3> const& fa3, IntVect const& nghost, F&& f)
     737             : {
     738             :     if (Gpu::inLaunchRegion()) {
     739             :         return fudetail::ReduceMF<ReduceOpMax>(fa1,fa2,fa3,nghost,std::forward<F>(f));
     740             :     } else {
     741             :         return fudetail::ReduceMax_host_wrapper(fa1,fa2,fa3,nghost,std::forward<F>(f));
     742             :     }
     743             : }
     744             : #else
     745             : template <class FAB1, class FAB2, class FAB3, class F,
     746             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     747             : typename FAB1::value_type
     748             : ReduceMax (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     749             :            FabArray<FAB3> const& fa3, IntVect const& nghost, F&& f)
     750             : {
     751             :     return fudetail::ReduceMax_host(fa1,fa2,fa3,nghost,std::forward<F>(f));
     752             : }
     753             : #endif
     754             : 
     755             : template <class FAB, class F,
     756             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     757             : bool
     758             : ReduceLogicalAnd (FabArray<FAB> const& fa, int nghost, F&& f)
     759             : {
     760             :     return ReduceLogicalAnd(fa, IntVect(nghost), std::forward<F>(f));
     761             : }
     762             : 
     763             : namespace fudetail {
     764             : template <class FAB, class F,
     765             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     766             : bool
     767             : ReduceLogicalAnd_host (FabArray<FAB> const& fa, IntVect const& nghost, F const& f)
     768             : {
     769             :     int r = true;
     770             : 
     771             : #ifdef AMREX_USE_OMP
     772             : #pragma omp parallel reduction(&&:r)
     773             : #endif
     774             :     for (MFIter mfi(fa,true); mfi.isValid(); ++mfi)
     775             :     {
     776             :         const Box& bx = mfi.growntilebox(nghost);
     777             :         const auto& arr = fa.const_array(mfi);
     778             :         r = r && f(bx, arr);
     779             :     }
     780             : 
     781             :     return r;
     782             : }
     783             : }
     784             : 
     785             : #ifdef AMREX_USE_GPU
     786             : namespace fudetail {
     787             : template <class FAB, class F>
     788             : std::enable_if_t<!amrex::DefinitelyNotHostRunnable<F>::value, bool>
     789             : ReduceLogicalAnd_host_wrapper (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     790             : {
     791             :     return ReduceLogicalAnd_host(fa,nghost,std::forward<F>(f));
     792             : }
     793             : 
     794             : template <class FAB, class F>
     795             : std::enable_if_t<amrex::DefinitelyNotHostRunnable<F>::value, bool>
     796             : ReduceLogicalAnd_host_wrapper (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     797             : {
     798             :     amrex::ignore_unused(fa,nghost,f);
     799             :     amrex::Abort("ReduceLogicalAnd: Launch Region is off. Device lambda cannot be called by host.");
     800             :     return false;
     801             : }
     802             : }
     803             : 
     804             : template <class FAB, class F,
     805             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     806             : bool
     807             : ReduceLogicalAnd (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     808             : {
     809             :     if (Gpu::inLaunchRegion()) {
     810             :         return fudetail::ReduceMF<ReduceOpLogicalAnd>(fa,nghost,std::forward<F>(f));
     811             :     } else {
     812             :         return fudetail::ReduceLogicalAnd_host_wrapper(fa,nghost,std::forward<F>(f));
     813             :     }
     814             : }
     815             : #else
     816             : template <class FAB, class F,
     817             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     818             : bool
     819             : ReduceLogicalAnd (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     820             : {
     821             :     return fudetail::ReduceLogicalAnd_host(fa,nghost,std::forward<F>(f));
     822             : }
     823             : #endif
     824             : 
     825             : template <class FAB1, class FAB2, class F,
     826             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     827             : bool
     828             : ReduceLogicalAnd (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     829             :                   int nghost, F&& f)
     830             : {
     831             :     return ReduceLogicalAnd(fa1, fa2, IntVect(nghost), std::forward<F>(f));
     832             : }
     833             : 
     834             : namespace fudetail {
     835             : template <class FAB1, class FAB2, class F,
     836             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     837             : bool
     838             : ReduceLogicalAnd_host (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     839             :                        IntVect const& nghost, F const& f)
     840             : {
     841             :     int r = true;
     842             : 
     843             : #ifdef AMREX_USE_OMP
     844             : #pragma omp parallel reduction(&&:r)
     845             : #endif
     846             :     for (MFIter mfi(fa1,true); mfi.isValid(); ++mfi)
     847             :     {
     848             :         const Box& bx = mfi.growntilebox(nghost);
     849             :         const auto& arr1 = fa1.const_array(mfi);
     850             :         const auto& arr2 = fa2.const_array(mfi);
     851             :         r = r && f(bx, arr1, arr2);
     852             :     }
     853             : 
     854             :     return r;
     855             : }
     856             : }
     857             : 
     858             : #ifdef AMREX_USE_GPU
     859             : namespace fudetail {
     860             : template <class FAB1, class FAB2, class F>
     861             : std::enable_if_t<!amrex::DefinitelyNotHostRunnable<F>::value, bool>
     862             : ReduceLogicalAnd_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     863             :                   IntVect const& nghost, F&& f)
     864             : {
     865             :     return ReduceLogicalAnd_host(fa1,fa2,nghost,std::forward<F>(f));
     866             : }
     867             : 
     868             : template <class FAB1, class FAB2, class F>
     869             : std::enable_if_t<amrex::DefinitelyNotHostRunnable<F>::value, bool>
     870             : ReduceLogicalAnd_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     871             :                                IntVect const& nghost, F&& f)
     872             : {
     873             :     amrex::ignore_unused(fa1,fa2,nghost,f);
     874             :     amrex::Abort("ReduceLogicalAnd: Luanch Region is off. Device lambda cannot be called by host.");
     875             :     return false;
     876             : }
     877             : }
     878             : 
     879             : template <class FAB1, class FAB2, class F,
     880             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     881             : bool
     882             : ReduceLogicalAnd (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     883             :                   IntVect const& nghost, F&& f)
     884             : {
     885             :     if (Gpu::inLaunchRegion()) {
     886             :         return fudetail::ReduceMF<ReduceOpLogicalAnd>(fa1,fa2,nghost,std::forward<F>(f));
     887             :     } else {
     888             :         return fudetail::ReduceLogicalAnd_host_wrapper(fa1,fa2,nghost,std::forward<F>(f));
     889             :     }
     890             : }
     891             : #else
     892             : template <class FAB1, class FAB2, class F,
     893             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     894             : bool
     895             : ReduceLogicalAnd (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     896             :                   IntVect const& nghost, F&& f)
     897             : {
     898             :     return fudetail::ReduceLogicalAnd_host(fa1,fa2,nghost,std::forward<F>(f));
     899             : }
     900             : #endif
     901             : 
     902             : template <class FAB, class F,
     903             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     904             : bool
     905             : ReduceLogicalOr (FabArray<FAB> const& fa, int nghost, F&& f)
     906             : {
     907             :     return ReduceLogicalOr(fa, IntVect(nghost), std::forward<F>(f));
     908             : }
     909             : 
     910             : namespace fudetail {
     911             : template <class FAB, class F,
     912             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     913             : bool
     914             : ReduceLogicalOr_host (FabArray<FAB> const& fa, IntVect const& nghost, F const& f)
     915             : {
     916             :     int r = false;
     917             : 
     918             : #ifdef AMREX_USE_OMP
     919             : #pragma omp parallel reduction(||:r)
     920             : #endif
     921             :     for (MFIter mfi(fa,true); mfi.isValid(); ++mfi)
     922             :     {
     923             :         const Box& bx = mfi.growntilebox(nghost);
     924             :         const auto& arr = fa.const_array(mfi);
     925             :         r = r || f(bx, arr);
     926             :     }
     927             : 
     928             :     return r;
     929             : }
     930             : }
     931             : 
     932             : #ifdef AMREX_USE_GPU
     933             : namespace fudetail {
     934             : template <class FAB, class F>
     935             : std::enable_if_t<!amrex::DefinitelyNotHostRunnable<F>::value, bool>
     936             : ReduceLogicalOr_host_wrapper (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     937             : {
     938             :     return ReduceLogicalOr_host(fa,nghost,std::forward<F>(f));
     939             : }
     940             : 
     941             : template <class FAB, class F>
     942             : std::enable_if_t<amrex::DefinitelyNotHostRunnable<F>::value, bool>
     943             : ReduceLogicalOr_host (FabArray<FAB> const& fa, IntVect const& nghost, F&& /*f*/)
     944             : {
     945             :     amrex::ignore_unused(fa,nghost);
     946             :     amrex::Abort("ReduceLogicalOr: Launch Region is off. Device lambda cannot be called by host.");
     947             :     return 0;
     948             : }
     949             : }
     950             : 
     951             : template <class FAB, class F,
     952             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     953             : bool
     954             : ReduceLogicalOr (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     955             : {
     956             :     if (Gpu::inLaunchRegion()) {
     957             :         return fudetail::ReduceMF<ReduceOpLogicalOr>(fa,nghost,std::forward<F>(f));
     958             :     } else {
     959             :         return fudetail::ReduceLogicalOr_host_wrapper(fa,nghost,std::forward<F>(f));
     960             :     }
     961             : }
     962             : #else
     963             : template <class FAB, class F,
     964             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
     965             : bool
     966             : ReduceLogicalOr (FabArray<FAB> const& fa, IntVect const& nghost, F&& f)
     967             : {
     968             :     return fudetail::ReduceLogicalOr_host(fa,nghost,std::forward<F>(f));
     969             : }
     970             : #endif
     971             : 
     972             : template <class FAB1, class FAB2, class F,
     973             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     974             : bool
     975             : ReduceLogicalOr (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     976             :                  int nghost, F&& f)
     977             : {
     978             :     return ReduceLogicalOr(fa1, fa2, IntVect(nghost), std::forward<F>(f));
     979             : }
     980             : 
     981             : namespace fudetail {
     982             : template <class FAB1, class FAB2, class F,
     983             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
     984             : bool
     985             : ReduceLogicalOr_host (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
     986             :                       IntVect const& nghost, F const& f)
     987             : {
     988             :     int r = false;
     989             : 
     990             : #ifdef AMREX_USE_OMP
     991             : #pragma omp parallel reduction(||:r)
     992             : #endif
     993             :     for (MFIter mfi(fa1,true); mfi.isValid(); ++mfi)
     994             :     {
     995             :         const Box& bx = mfi.growntilebox(nghost);
     996             :         const auto& arr1 = fa1.const_array(mfi);
     997             :         const auto& arr2 = fa2.const_array(mfi);
     998             :         r = r || f(bx, arr1, arr2);
     999             :     }
    1000             : 
    1001             :     return r;
    1002             : }
    1003             : }
    1004             : 
    1005             : #ifdef AMREX_USE_GPU
    1006             : namespace fudetail {
    1007             : template <class FAB1, class FAB2, class F>
    1008             : std::enable_if_t<!amrex::DefinitelyNotHostRunnable<F>::value, bool>
    1009             : ReduceLogicalOr_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
    1010             :                  IntVect const& nghost, F&& f)
    1011             : {
    1012             :     return fudetail::ReduceLogicalOr_host(fa1,fa2,nghost,std::forward<F>(f));
    1013             : }
    1014             : 
    1015             : template <class FAB1, class FAB2, class F>
    1016             : std::enable_if_t<amrex::DefinitelyNotHostRunnable<F>::value, bool>
    1017             : ReduceLogicalOr_host_wrapper (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
    1018             :                               IntVect const& nghost, F&& f)
    1019             : {
    1020             :     amrex::ignore_unused(fa1,fa2,nghost,f);
    1021             :     amrex::Abort("ReeuceLogicalOr: Launch Region is off. Device lambda cannot be called by host.");
    1022             :     return false;
    1023             : }
    1024             : }
    1025             : 
    1026             : template <class FAB1, class FAB2, class F,
    1027             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
    1028             : bool
    1029             : ReduceLogicalOr (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
    1030             :                  IntVect const& nghost, F&& f)
    1031             : {
    1032             :     if (Gpu::inLaunchRegion()) {
    1033             :         return fudetail::ReduceMF<ReduceOpLogicalOr>(fa1,fa2,nghost,std::forward<F>(f));
    1034             :     } else {
    1035             :         return fudetail::ReduceLogicalOr_host_wrapper(fa1,fa2,nghost,std::forward<F>(f));
    1036             :     }
    1037             : }
    1038             : #else
    1039             : template <class FAB1, class FAB2, class F,
    1040             :           class bar = std::enable_if_t<IsBaseFab<FAB1>::value> >
    1041             : bool
    1042             : ReduceLogicalOr (FabArray<FAB1> const& fa1, FabArray<FAB2> const& fa2,
    1043             :                  IntVect const& nghost, F&& f)
    1044             : {
    1045             :     return fudetail::ReduceLogicalOr_host(fa1,fa2,nghost,std::forward<F>(f));
    1046             : }
    1047             : #endif
    1048             : 
    1049             : template <class FAB, class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
    1050             : void
    1051             : printCell (FabArray<FAB> const& mf, const IntVect& cell, int comp = -1,
    1052             :            const IntVect& ng = IntVect::TheZeroVector())
    1053             : {
    1054             :     for (MFIter mfi(mf); mfi.isValid(); ++mfi)
    1055             :     {
    1056             :         const Box& bx = amrex::grow(mfi.validbox(), ng);
    1057             :         if (bx.contains(cell)) {
    1058             :             int n = (comp >= 0) ? 1 : mf.nComp();
    1059             :             auto const& fab = mf.const_array(mfi);
    1060             :             Gpu::PinnedVector<typename FAB::value_type> pv(n);
    1061             :             auto* dp = pv.data();
    1062             :             auto f = [=] AMREX_GPU_HOST_DEVICE ()
    1063             :                 {
    1064             :                     if (comp >= 0) {
    1065             :                         *dp = fab(cell, comp);
    1066             :                     } else {
    1067             :                         for (int i = 0; i < n; ++i) {
    1068             :                             dp[i] = fab(cell,i);
    1069             :                         }
    1070             :                     }
    1071             :                 };
    1072             : 
    1073             : #ifdef AMREX_USE_GPU
    1074             :             if (mf.arena()->isManaged() || mf.arena()->isDevice()) {
    1075             :                 amrex::single_task(f);
    1076             :                 Gpu::streamSynchronize();
    1077             :             } else
    1078             : #endif
    1079             :             {
    1080             :                 f();
    1081             :             }
    1082             : 
    1083             :             if (comp >= 0) {
    1084             :                 amrex::AllPrint().SetPrecision(17) << " At cell " << cell << " in Box " << bx
    1085             :                                                    << ": " << *dp << '\n';
    1086             :             } else {
    1087             :                 std::ostringstream ss;
    1088             :                 ss.precision(17);
    1089             :                 for (int i = 0; i < n-1; ++i)
    1090             :                 {
    1091             :                     ss << dp[i] << ", ";
    1092             :                 }
    1093             :                 ss << dp[n-1];
    1094             :                 amrex::AllPrint() << " At cell " << cell << " in Box " << bx
    1095             :                                   << ": " << ss.str() << '\n';
    1096             :             }
    1097             :         }
    1098             :     }
    1099             : }
    1100             : 
    1101             : template <class FAB,
    1102             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
    1103             : void
    1104             : Subtract (FabArray<FAB>& dst, FabArray<FAB> const& src, int srccomp, int dstcomp, int numcomp, int nghost)
    1105             : {
    1106             :     Subtract(dst,src,srccomp,dstcomp,numcomp,IntVect(nghost));
    1107             : }
    1108             : 
    1109             : template <class FAB,
    1110             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
    1111             : void
    1112             : Subtract (FabArray<FAB>& dst, FabArray<FAB> const& src, int srccomp, int dstcomp, int numcomp, const IntVect& nghost)
    1113             : {
    1114             : #ifdef AMREX_USE_GPU
    1115             :     if (Gpu::inLaunchRegion() && dst.isFusingCandidate()) {
    1116             :         auto const& dstfa = dst.arrays();
    1117             :         auto const& srcfa = src.const_arrays();
    1118             :         ParallelFor(dst, nghost, numcomp,
    1119             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    1120             :         {
    1121             :             dstfa[box_no](i,j,k,n+dstcomp) -= srcfa[box_no](i,j,k,n+srccomp);
    1122             :         });
    1123             :         if (!Gpu::inNoSyncRegion()) {
    1124             :             Gpu::streamSynchronize();
    1125             :         }
    1126             :     } else
    1127             : #endif
    1128             :     {
    1129             : #ifdef AMREX_USE_OMP
    1130             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    1131             : #endif
    1132             :         for (MFIter mfi(dst,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    1133             :         {
    1134             :             const Box& bx = mfi.growntilebox(nghost);
    1135             :             if (bx.ok())
    1136             :             {
    1137             :                 auto const srcFab = src.array(mfi);
    1138             :                 auto       dstFab = dst.array(mfi);
    1139             :                 AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, numcomp, i, j, k, n,
    1140             :                 {
    1141             :                     dstFab(i,j,k,n+dstcomp) -= srcFab(i,j,k,n+srccomp);
    1142             :                 });
    1143             :             }
    1144             :         }
    1145             :     }
    1146             : }
    1147             : 
    1148             : 
    1149             : template <class FAB,
    1150             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
    1151             : void
    1152             : Multiply (FabArray<FAB>& dst, FabArray<FAB> const& src, int srccomp, int dstcomp, int numcomp, int nghost)
    1153             : {
    1154             :     Multiply(dst,src,srccomp,dstcomp,numcomp,IntVect(nghost));
    1155             : }
    1156             : 
    1157             : template <class FAB,
    1158             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
    1159             : void
    1160             : Multiply (FabArray<FAB>& dst, FabArray<FAB> const& src, int srccomp, int dstcomp, int numcomp, const IntVect& nghost)
    1161             : {
    1162             : #ifdef AMREX_USE_GPU
    1163             :     if (Gpu::inLaunchRegion() && dst.isFusingCandidate()) {
    1164             :         auto const& dstfa = dst.arrays();
    1165             :         auto const& srcfa = src.const_arrays();
    1166             :         ParallelFor(dst, nghost, numcomp,
    1167             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    1168             :         {
    1169             :             dstfa[box_no](i,j,k,n+dstcomp) *= srcfa[box_no](i,j,k,n+srccomp);
    1170             :         });
    1171             :         if (!Gpu::inNoSyncRegion()) {
    1172             :             Gpu::streamSynchronize();
    1173             :         }
    1174             :     } else
    1175             : #endif
    1176             :     {
    1177             : #ifdef AMREX_USE_OMP
    1178             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    1179             : #endif
    1180             :         for (MFIter mfi(dst,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    1181             :         {
    1182             :             const Box& bx = mfi.growntilebox(nghost);
    1183             :             if (bx.ok())
    1184             :             {
    1185             :                 auto const srcFab = src.array(mfi);
    1186             :                 auto       dstFab = dst.array(mfi);
    1187             :                 AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, numcomp, i, j, k, n,
    1188             :                 {
    1189             :                     dstFab(i,j,k,n+dstcomp) *= srcFab(i,j,k,n+srccomp);
    1190             :                 });
    1191             :             }
    1192             :         }
    1193             :     }
    1194             : }
    1195             : 
    1196             : 
    1197             : template <class FAB,
    1198             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
    1199             : void
    1200             : Divide (FabArray<FAB>& dst, FabArray<FAB> const& src, int srccomp, int dstcomp, int numcomp, int nghost)
    1201             : {
    1202             :     Divide(dst,src,srccomp,dstcomp,numcomp,IntVect(nghost));
    1203             : }
    1204             : 
    1205             : template <class FAB,
    1206             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
    1207             : void
    1208             : Divide (FabArray<FAB>& dst, FabArray<FAB> const& src, int srccomp, int dstcomp, int numcomp, const IntVect& nghost)
    1209             : {
    1210             : #ifdef AMREX_USE_GPU
    1211             :     if (Gpu::inLaunchRegion() && dst.isFusingCandidate()) {
    1212             :         auto const& dstfa = dst.arrays();
    1213             :         auto const& srcfa = src.const_arrays();
    1214             :         ParallelFor(dst, nghost, numcomp,
    1215             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    1216             :         {
    1217             :             dstfa[box_no](i,j,k,n+dstcomp) /= srcfa[box_no](i,j,k,n+srccomp);
    1218             :         });
    1219             :         if (!Gpu::inNoSyncRegion()) {
    1220             :             Gpu::streamSynchronize();
    1221             :         }
    1222             :     } else
    1223             : #endif
    1224             :     {
    1225             : #ifdef AMREX_USE_OMP
    1226             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    1227             : #endif
    1228             :         for (MFIter mfi(dst,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    1229             :         {
    1230             :             const Box& bx = mfi.growntilebox(nghost);
    1231             :             if (bx.ok())
    1232             :             {
    1233             :                 auto const srcFab = src.array(mfi);
    1234             :                 auto       dstFab = dst.array(mfi);
    1235             :                 AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, numcomp, i, j, k, n,
    1236             :                 {
    1237             :                     dstFab(i,j,k,n+dstcomp) /= srcFab(i,j,k,n+srccomp);
    1238             :                 });
    1239             :             }
    1240             :         }
    1241             :     }
    1242             : }
    1243             : 
    1244             : template <class FAB,
    1245             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
    1246             : void
    1247             : Abs (FabArray<FAB>& fa, int icomp, int numcomp, int nghost)
    1248             : {
    1249             :     Abs(fa,icomp,numcomp,IntVect(nghost));
    1250             : }
    1251             : 
    1252             : template <class FAB,
    1253             :           class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
    1254             : void
    1255             : Abs (FabArray<FAB>& fa, int icomp, int numcomp, const IntVect& nghost)
    1256             : {
    1257             : #ifdef AMREX_USE_GPU
    1258             :     if (Gpu::inLaunchRegion() && fa.isFusingCandidate()) {
    1259             :         auto const& fabarr = fa.arrays();
    1260             :         ParallelFor(fa, nghost, numcomp,
    1261             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    1262             :         {
    1263             :             fabarr[box_no](i,j,k,n+icomp) = std::abs(fabarr[box_no](i,j,k,n+icomp));
    1264             :         });
    1265             :         if (!Gpu::inNoSyncRegion()) {
    1266             :             Gpu::streamSynchronize();
    1267             :         }
    1268             :     } else
    1269             : #endif
    1270             :     {
    1271             : #ifdef AMREX_USE_OMP
    1272             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    1273             : #endif
    1274             :         for (MFIter mfi(fa,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    1275             :         {
    1276             :             const Box& bx = mfi.growntilebox(nghost);
    1277             :             if (bx.ok())
    1278             :             {
    1279             :                 auto const& fab = fa.array(mfi);
    1280             :                 AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, numcomp, i, j, k, n,
    1281             :                 {
    1282             :                     fab(i,j,k,n+icomp) = std::abs(fab(i,j,k,n+icomp));
    1283             :                 });
    1284             :             }
    1285             :         }
    1286             :     }
    1287             : }
    1288             : 
    1289             : template <class FAB, class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
    1290             : void
    1291             : prefetchToHost (FabArray<FAB> const& fa, const bool synchronous = true)
    1292             : {
    1293             : #ifdef AMREX_USE_GPU
    1294             :     if (fa.arena()->isManaged()) {
    1295             :         for (MFIter mfi(fa, MFItInfo().SetDeviceSync(synchronous)); mfi.isValid(); ++mfi) {
    1296             :             fa.prefetchToHost(mfi);
    1297             :         }
    1298             :     }
    1299             : #else
    1300             :     amrex::ignore_unused(fa,synchronous);
    1301             : #endif
    1302             : }
    1303             : 
    1304             : template <class FAB, class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
    1305             : void
    1306             : prefetchToDevice (FabArray<FAB> const& fa, const bool synchronous = true)
    1307             : {
    1308             : #ifdef AMREX_USE_GPU
    1309             :     if (fa.arena()->isManaged()) {
    1310             :         for (MFIter mfi(fa, MFItInfo().SetDeviceSync(synchronous)); mfi.isValid(); ++mfi) {
    1311             :             fa.prefetchToDevice(mfi);
    1312             :         }
    1313             :     }
    1314             : #else
    1315             :     amrex::ignore_unused(fa,synchronous);
    1316             : #endif
    1317             : }
    1318             : 
    1319             : 
    1320             : template <class FAB, class IFAB, class bar = std::enable_if_t<IsBaseFab<FAB>::value
    1321             :                                                                && IsBaseFab<IFAB>::value> >
    1322             : void
    1323             : OverrideSync (FabArray<FAB> & fa, FabArray<IFAB> const& msk, const Periodicity& period)
    1324             : {
    1325             :     BL_PROFILE("OverrideSync()");
    1326             : 
    1327             :     OverrideSync_nowait(fa, msk, period);
    1328             :     OverrideSync_finish(fa);
    1329             : }
    1330             : 
    1331             : 
    1332             : template <class FAB, class IFAB, class bar = std::enable_if_t<IsBaseFab<FAB>::value
    1333             :                                                                && IsBaseFab<IFAB>::value> >
    1334             : void
    1335             : OverrideSync_nowait (FabArray<FAB> & fa, FabArray<IFAB> const& msk, const Periodicity& period)
    1336             : {
    1337             :     BL_PROFILE("OverrideSync_nowait()");
    1338             :     AMREX_ASSERT_WITH_MESSAGE(!fa.os_temp, "OverrideSync_nowait() called when already in progress.");
    1339             : 
    1340             :     if (fa.ixType().cellCentered()) { return; }
    1341             : 
    1342             :     const int ncomp = fa.nComp();
    1343             : 
    1344             : #ifdef AMREX_USE_GPU
    1345             :     if (Gpu::inLaunchRegion() && fa.isFusingCandidate()) {
    1346             :         auto const&  fabarr = fa.arrays();
    1347             :         auto const& ifabarr = msk.const_arrays();
    1348             :         ParallelFor(fa, IntVect(0), ncomp,
    1349             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
    1350             :         {
    1351             :             if (!ifabarr[box_no](i,j,k)) { fabarr[box_no](i,j,k,n) = 0; }
    1352             :         });
    1353             :         if (!Gpu::inNoSyncRegion()) {
    1354             :             Gpu::streamSynchronize();
    1355             :         }
    1356             :     } else
    1357             : #endif
    1358             :     {
    1359             : #ifdef AMREX_USE_OMP
    1360             : #pragma omp parallel if (Gpu::notInLaunchRegion())
    1361             : #endif
    1362             :         for (MFIter mfi(fa,TilingIfNotGPU()); mfi.isValid(); ++mfi)
    1363             :         {
    1364             :             const Box& bx = mfi.tilebox();
    1365             :             auto fab = fa.array(mfi);
    1366             :             auto const ifab = msk.array(mfi);
    1367             :             AMREX_HOST_DEVICE_PARALLEL_FOR_4D( bx, ncomp, i, j, k, n,
    1368             :             {
    1369             :                 if (!ifab(i,j,k)) { fab(i,j,k,n) = 0; }
    1370             :             });
    1371             :         }
    1372             :     }
    1373             : 
    1374             :     fa.os_temp = std::make_unique< FabArray<FAB> > ( fa.boxArray(), fa.DistributionMap(),
    1375             :                                                      ncomp, 0, MFInfo(), fa.Factory() );
    1376             :     fa.os_temp->setVal(0);
    1377             :     fa.os_temp->ParallelCopy_nowait(fa, period, FabArrayBase::ADD);
    1378             : }
    1379             : 
    1380             : template <class FAB, class bar = std::enable_if_t<IsBaseFab<FAB>::value> >
    1381             : void
    1382             : OverrideSync_finish (FabArray<FAB> & fa)
    1383             : {
    1384             :     BL_PROFILE("OverrideSync_finish()");
    1385             : 
    1386             :     if (fa.ixType().cellCentered()) { return; }
    1387             : 
    1388             :     fa.os_temp->ParallelCopy_finish();
    1389             :     amrex::Copy(fa, *(fa.os_temp), 0, 0, fa.nComp(), 0);
    1390             : 
    1391             :     fa.os_temp.reset();
    1392             : }
    1393             : 
    1394             : template <class FAB, class foo = std::enable_if_t<IsBaseFab<FAB>::value> >
    1395             : void
    1396             : dtoh_memcpy (FabArray<FAB>& dst, FabArray<FAB> const& src,
    1397             :              int scomp, int dcomp, int ncomp)
    1398             : {
    1399             :     AMREX_ASSERT(isMFIterSafe(dst, src));
    1400             :     AMREX_ASSERT(dst.nGrowVect() == src.nGrowVect());
    1401             : #ifdef AMREX_USE_GPU
    1402             :     for (MFIter mfi(dst); mfi.isValid(); ++mfi) {
    1403             :         void* pdst = dst[mfi].dataPtr(dcomp);
    1404             :         void const* psrc = src[mfi].dataPtr(scomp);
    1405             :         Gpu::dtoh_memcpy_async(pdst, psrc, dst[mfi].nBytes(mfi.fabbox(), ncomp));
    1406             :     }
    1407             : #else
    1408             :     Copy(dst, src, scomp, dcomp, ncomp, dst.nGrowVect());
    1409             : #endif
    1410             : }
    1411             : 
    1412             : template <class FAB, class foo = std::enable_if_t<IsBaseFab<FAB>::value> >
    1413             : void
    1414             : dtoh_memcpy (FabArray<FAB>& dst, FabArray<FAB> const& src)
    1415             : {
    1416             :     dtoh_memcpy(dst, src, 0, 0, dst.nComp());
    1417             : }
    1418             : 
    1419             : template <class FAB, class foo = std::enable_if_t<IsBaseFab<FAB>::value> >
    1420             : void
    1421             : htod_memcpy (FabArray<FAB>& dst, FabArray<FAB> const& src,
    1422             :              int scomp, int dcomp, int ncomp)
    1423             : {
    1424             :     AMREX_ASSERT(isMFIterSafe(dst, src));
    1425             :     AMREX_ASSERT(dst.nGrowVect() == src.nGrowVect());
    1426             : #ifdef AMREX_USE_GPU
    1427             :     for (MFIter mfi(dst); mfi.isValid(); ++mfi) {
    1428             :         void* pdst = dst[mfi].dataPtr(dcomp);
    1429             :         void const* psrc = src[mfi].dataPtr(scomp);
    1430             :         Gpu::htod_memcpy_async(pdst, psrc, dst[mfi].nBytes(mfi.fabbox(), ncomp));
    1431             :     }
    1432             : #else
    1433             :     Copy(dst, src, scomp, dcomp, ncomp, dst.nGrowVect());
    1434             : #endif
    1435             : }
    1436             : 
    1437             : template <class FAB, class foo = std::enable_if_t<IsBaseFab<FAB>::value> >
    1438             : void
    1439             : htod_memcpy (FabArray<FAB>& dst, FabArray<FAB> const& src)
    1440             : {
    1441             :     htod_memcpy(dst, src, 0, 0, dst.nComp());
    1442             : }
    1443             : 
    1444             : template <class FAB, class foo = std::enable_if_t<IsBaseFab<FAB>::value> >
    1445             : IntVect
    1446             : indexFromValue (FabArray<FAB> const& mf, int comp, IntVect const& nghost,
    1447             :                 typename FAB::value_type value)
    1448             : {
    1449             :     IntVect loc;
    1450             : 
    1451             : #ifdef AMREX_USE_GPU
    1452             :     if (Gpu::inLaunchRegion())
    1453             :     {
    1454             :         amrex::Gpu::Buffer<int> aa({0,AMREX_D_DECL(0,0,0)});
    1455             :         int* p = aa.data();
    1456             :         // This is a device ptr to 1+AMREX_SPACEDIM int zeros.
    1457             :         // The first is used as an atomic bool and the others for intvect.
    1458             :         if (mf.isFusingCandidate()) {
    1459             :             auto const& ma = mf.const_arrays();
    1460             :             ParallelFor(mf, nghost, [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept
    1461             :             {
    1462             :                 int* flag = p;
    1463             :                 if (*flag == 0) {
    1464             :                     if (ma[box_no](i,j,k,comp) == value) {
    1465             :                         if (Gpu::Atomic::Exch(flag,1) == 0) {
    1466             :                             AMREX_D_TERM(p[1] = i;,
    1467             :                                          p[2] = j;,
    1468             :                                          p[3] = k;);
    1469             :                         }
    1470             :                     }
    1471             :                 }
    1472             :             });
    1473             :         } else {
    1474             :             for (MFIter mfi(mf,MFItInfo().SetDeviceSync(false)); mfi.isValid(); ++mfi) {
    1475             :                 const Box& bx = amrex::grow(mfi.validbox(), nghost);
    1476             :                 auto const& arr = mf.const_array(mfi);
    1477             :                 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
    1478             :                 {
    1479             :                     int* flag = p;
    1480             :                     if (*flag == 0) {
    1481             :                         if (arr(i,j,k,comp) == value) {
    1482             :                             if (Gpu::Atomic::Exch(flag,1) == 0) {
    1483             :                                 AMREX_D_TERM(p[1] = i;,
    1484             :                                              p[2] = j;,
    1485             :                                              p[3] = k;);
    1486             :                             }
    1487             :                         }
    1488             :                     }
    1489             :                 });
    1490             :             }
    1491             :         }
    1492             :         int const* tmp = aa.copyToHost();
    1493             :         AMREX_D_TERM(loc[0] = tmp[1];,
    1494             :                      loc[1] = tmp[2];,
    1495             :                      loc[2] = tmp[3];);
    1496             :     }
    1497             :     else
    1498             : #endif
    1499             :     {
    1500             :         bool f = false;
    1501             : #ifdef AMREX_USE_OMP
    1502             : #pragma omp parallel
    1503             : #endif
    1504             :         {
    1505             :             IntVect priv_loc = IntVect::TheMinVector();
    1506             :             for (MFIter mfi(mf,true); mfi.isValid(); ++mfi)
    1507             :             {
    1508             :                 const Box& bx = mfi.growntilebox(nghost);
    1509             :                 auto const& fab = mf.const_array(mfi);
    1510             :                 AMREX_LOOP_3D(bx, i, j, k,
    1511             :                 {
    1512             :                     if (fab(i,j,k,comp) == value) {
    1513             :                         priv_loc = IntVect(AMREX_D_DECL(i,j,k));
    1514             :                     }
    1515             :                 });
    1516             :             }
    1517             : 
    1518             :             if (priv_loc.allGT(IntVect::TheMinVector())) {
    1519             :                 bool old;
    1520             : // we should be able to test on _OPENMP < 201107 for capture (version 3.1)
    1521             : // but we must work around a bug in gcc < 4.9
    1522             : // And, with NVHPC 21.9 to <23.1, we saw an ICE with the atomic capture (NV bug: #3390723)
    1523             : #if defined(AMREX_USE_OMP) && defined(_OPENMP) && (_OPENMP < 201307 || (defined(__NVCOMPILER) && __NVCOMPILER_MAJOR__ < 23)) // OpenMP 4.0
    1524             : #pragma omp critical (amrex_indexfromvalue)
    1525             : #elif defined(AMREX_USE_OMP)
    1526             : #pragma omp atomic capture
    1527             : #endif
    1528             :                 {
    1529             :                     old = f;
    1530             :                     f = true;
    1531             :                 }
    1532             : 
    1533             :                 if (old == false) { loc = priv_loc; }
    1534             :             }
    1535             :         }
    1536             :     }
    1537             : 
    1538             :     return loc;
    1539             : }
    1540             : 
    1541             : /**
    1542             :  * \brief Compute dot products of two FabArrays
    1543             :  *
    1544             :  * \param x      first FabArray
    1545             :  * \param xcomp  starting component of x
    1546             :  * \param y      second FabArray
    1547             :  * \param ycomp  starting component of y
    1548             :  * \param ncomp  number of components
    1549             :  * \param nghost number of ghost cells
    1550             :  * \param local  If true, MPI communication is skipped.
    1551             :  */
    1552             : template <typename FAB, std::enable_if_t<IsBaseFab<FAB>::value,int> FOO = 0>
    1553             : typename FAB::value_type
    1554             : Dot (FabArray<FAB> const& x, int xcomp, FabArray<FAB> const& y, int ycomp, int ncomp,
    1555             :      IntVect const& nghost, bool local = false)
    1556             : {
    1557             :     BL_ASSERT(x.boxArray() == y.boxArray());
    1558             :     BL_ASSERT(x.DistributionMap() == y.DistributionMap());
    1559             :     BL_ASSERT(x.nGrowVect().allGE(nghost) && y.nGrowVect().allGE(nghost));
    1560             : 
    1561             :     BL_PROFILE("amrex::Dot()");
    1562             : 
    1563             :     using T = typename FAB::value_type;
    1564             :     auto sm = T(0.0);
    1565             : #ifdef AMREX_USE_GPU
    1566             :     if (Gpu::inLaunchRegion()) {
    1567             :         auto const& xma = x.const_arrays();
    1568             :         auto const& yma = y.const_arrays();
    1569             :         sm = ParReduce(TypeList<ReduceOpSum>{}, TypeList<T>{}, x, nghost,
    1570             :         [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept -> GpuTuple<T>
    1571             :         {
    1572             :             auto t = T(0.0);
    1573             :             auto const& xfab = xma[box_no];
    1574             :             auto const& yfab = yma[box_no];
    1575             :             for (int n = 0; n < ncomp; ++n) {
    1576             :                 t += xfab(i,j,k,xcomp+n) * yfab(i,j,k,ycomp+n);
    1577             :             }
    1578             :             return t;
    1579             :         });
    1580             :     } else
    1581             : #endif
    1582             :     {
    1583             : #ifdef AMREX_USE_OMP
    1584             : #pragma omp parallel if (!system::regtest_reduction) reduction(+:sm)
    1585             : #endif
    1586             :         for (MFIter mfi(x,true); mfi.isValid(); ++mfi)
    1587             :         {
    1588             :             Box const& bx = mfi.growntilebox(nghost);
    1589             :             auto const& xfab = x.const_array(mfi);
    1590             :             auto const& yfab = y.const_array(mfi);
    1591             :             AMREX_LOOP_4D(bx, ncomp, i, j, k, n,
    1592             :             {
    1593             :                 sm += xfab(i,j,k,xcomp+n) * yfab(i,j,k,ycomp+n);
    1594             :             });
    1595             :         }
    1596             :     }
    1597             : 
    1598             :     if (!local) {
    1599             :         ParallelAllReduce::Sum(sm, ParallelContext::CommunicatorSub());
    1600             :     }
    1601             : 
    1602             :     return sm;
    1603             : }
    1604             : 
    1605             : //! dst = val
    1606             : template <class MF, std::enable_if_t<IsMultiFabLike_v<MF>,int> = 0>
    1607        7607 : void setVal (MF& dst, typename MF::value_type val)
    1608             : {
    1609        7607 :     dst.setVal(val);
    1610        7607 : }
    1611             : 
    1612             : //! dst = val in ghost cells.
    1613             : template <class MF, std::enable_if_t<IsMultiFabLike_v<MF>,int> = 0>
    1614           0 : void setBndry (MF& dst, typename MF::value_type val, int scomp, int ncomp)
    1615             : {
    1616           0 :     dst.setBndry(val, scomp, ncomp);
    1617           0 : }
    1618             : 
    1619             : //! dst *= val
    1620             : template <class MF, std::enable_if_t<IsMultiFabLike_v<MF>,int> = 0>
    1621             : void Scale (MF& dst, typename MF::value_type val, int scomp, int ncomp, int nghost)
    1622             : {
    1623             :     dst.mult(val, scomp, ncomp, nghost);
    1624             : }
    1625             : 
    1626             : //! dst = src
    1627             : template <class DMF, class SMF,
    1628             :           std::enable_if_t<IsMultiFabLike_v<DMF> &&
    1629             :                            IsMultiFabLike_v<SMF>, int> = 0>
    1630        1072 : void LocalCopy (DMF& dst, SMF const& src, int scomp, int dcomp,
    1631             :                 int ncomp, IntVect const& nghost)
    1632             : {
    1633        1072 :     amrex::Copy(dst, src, scomp, dcomp, ncomp, nghost);
    1634        1072 : }
    1635             : 
    1636             : //! dst += src
    1637             : template <class MF, std::enable_if_t<IsMultiFabLike_v<MF>,int> = 0>
    1638             : void LocalAdd (MF& dst, MF const& src, int scomp, int dcomp,
    1639             :                 int ncomp, IntVect const& nghost)
    1640             : {
    1641             :     amrex::Add(dst, src, scomp, dcomp, ncomp, nghost);
    1642             : }
    1643             : 
    1644             : //! dst += a * src
    1645             : template <class MF, std::enable_if_t<IsMultiFabLike_v<MF>,int> = 0>
    1646             : void Saxpy (MF& dst, typename MF::value_type a, MF const& src, int scomp, int dcomp,
    1647             :             int ncomp, IntVect const& nghost)
    1648             : {
    1649             :     MF::Saxpy(dst, a, src, scomp, dcomp, ncomp, nghost);
    1650             : }
    1651             : 
    1652             : //! dst = src + a * dst
    1653             : template <class MF, std::enable_if_t<IsMultiFabLike_v<MF>,int> = 0>
    1654             : void Xpay (MF& dst, typename MF::value_type a, MF const& src, int scomp, int dcomp,
    1655             :            int ncomp, IntVect const& nghost)
    1656             : {
    1657             :     MF::Xpay(dst, a, src, scomp, dcomp, ncomp, nghost);
    1658             : }
    1659             : 
    1660             : //! dst = a*src_a + b*src_b
    1661             : template <class MF, std::enable_if_t<IsMultiFabLike_v<MF>,int> = 0>
    1662             : void LinComb (MF& dst,
    1663             :               typename MF::value_type a, MF const& src_a, int acomp,
    1664             :               typename MF::value_type b, MF const& src_b, int bcomp,
    1665             :               int dcomp, int ncomp, IntVect const& nghost)
    1666             : {
    1667             :     MF::LinComb(dst, a, src_a, acomp, b, src_b, bcomp, dcomp, ncomp, nghost);
    1668             : }
    1669             : 
    1670             : //! dst = src w/ MPI communication
    1671             : template <class MF, std::enable_if_t<IsMultiFabLike_v<MF>, int> = 0>
    1672             : void ParallelCopy (MF& dst, MF const& src, int scomp, int dcomp, int ncomp,
    1673             :                    IntVect const& ng_src = IntVect(0),
    1674             :                    IntVect const& ng_dst = IntVect(0),
    1675             :                    Periodicity const& period = Periodicity::NonPeriodic())
    1676             : {
    1677             :     dst.ParallelCopy(src, scomp, dcomp, ncomp, ng_src, ng_dst, period);
    1678             : }
    1679             : 
    1680             : template <class MF, std::enable_if_t<IsMultiFabLike_v<MF>, int> = 0>
    1681             : [[nodiscard]] typename MF::value_type
    1682             : norminf (MF const& mf, int scomp, int ncomp, IntVect const& nghost,
    1683             :          bool local = false)
    1684             : {
    1685             :     return mf.norminf(scomp, ncomp, nghost, local);
    1686             : }
    1687             : 
    1688             : //! dst = val
    1689             : template <class MF, std::size_t N, std::enable_if_t<IsMultiFabLike_v<MF>,int> = 0>
    1690             : void setVal (Array<MF,N>& dst, typename MF::value_type val)
    1691             : {
    1692             :     for (auto& mf: dst) {
    1693             :         mf.setVal(val);
    1694             :     }
    1695             : }
    1696             : 
    1697             : //! dst = val in ghost cells.
    1698             : template <class MF, std::size_t N, std::enable_if_t<IsMultiFabLike_v<MF>,int> = 0>
    1699             : void setBndry (Array<MF,N>& dst, typename MF::value_type val, int scomp, int ncomp)
    1700             : {
    1701             :     for (auto& mf : dst) {
    1702             :         mf.setBndry(val, scomp, ncomp);
    1703             :     }
    1704             : }
    1705             : 
    1706             : //! dst *= val
    1707             : template <class MF, std::size_t N, std::enable_if_t<IsMultiFabLike_v<MF>,int> = 0>
    1708             : void Scale (Array<MF,N>& dst, typename MF::value_type val, int scomp, int ncomp,
    1709             :             int nghost)
    1710             : {
    1711             :     for (auto& mf : dst) {
    1712             :         mf.mult(val, scomp, ncomp, nghost);
    1713             :     }
    1714             : }
    1715             : 
    1716             : //! dst = src
    1717             : template <class DMF, class SMF, std::size_t N,
    1718             :           std::enable_if_t<IsMultiFabLike_v<DMF> &&
    1719             :                            IsMultiFabLike_v<SMF>, int> = 0>
    1720             : void LocalCopy (Array<DMF,N>& dst, Array<SMF,N> const& src, int scomp, int dcomp,
    1721             :                 int ncomp, IntVect const& nghost)
    1722             : {
    1723             :     for (std::size_t i = 0; i < N; ++i) {
    1724             :         amrex::Copy(dst[i], src[i], scomp, dcomp, ncomp, nghost);
    1725             :     }
    1726             : }
    1727             : 
    1728             : //! dst += src
    1729             : template <class MF, std::size_t N, std::enable_if_t<IsMultiFabLike_v<MF>,int> = 0>
    1730             : void LocalAdd (Array<MF,N>& dst, Array<MF,N> const& src, int scomp, int dcomp,
    1731             :                int ncomp, IntVect const& nghost)
    1732             : {
    1733             :     for (std::size_t i = 0; i < N; ++i) {
    1734             :         amrex::Add(dst[i], src[i], scomp, dcomp, ncomp, nghost);
    1735             :     }
    1736             : }
    1737             : 
    1738             : //! dst += a * src
    1739             : template <class MF, std::size_t N, std::enable_if_t<IsMultiFabLike_v<MF>,int> = 0>
    1740             : void Saxpy (Array<MF,N>& dst, typename MF::value_type a,
    1741             :             Array<MF,N> const& src, int scomp, int dcomp, int ncomp,
    1742             :             IntVect const& nghost)
    1743             : {
    1744             :     for (std::size_t i = 0; i < N; ++i) {
    1745             :         MF::Saxpy(dst[i], a, src[i], scomp, dcomp, ncomp, nghost);
    1746             :     }
    1747             : }
    1748             : 
    1749             : //! dst = src + a * dst
    1750             : template <class MF, std::size_t N, std::enable_if_t<IsMultiFabLike_v<MF>,int> = 0>
    1751             : void Xpay (Array<MF,N>& dst, typename MF::value_type a,
    1752             :            Array<MF,N> const& src, int scomp, int dcomp, int ncomp,
    1753             :            IntVect const& nghost)
    1754             : {
    1755             :     for (std::size_t i = 0; i < N; ++i) {
    1756             :         MF::Xpay(dst[i], a, src[i], scomp, dcomp, ncomp, nghost);
    1757             :     }
    1758             : }
    1759             : 
    1760             : //! dst = a*src_a + b*src_b
    1761             : template <class MF, std::size_t N, std::enable_if_t<IsMultiFabLike_v<MF>,int> = 0>
    1762             : void LinComb (Array<MF,N>& dst,
    1763             :               typename MF::value_type a, Array<MF,N> const& src_a, int acomp,
    1764             :               typename MF::value_type b, Array<MF,N> const& src_b, int bcomp,
    1765             :               int dcomp, int ncomp, IntVect const& nghost)
    1766             : {
    1767             :     for (std::size_t i = 0; i < N; ++i) {
    1768             :         MF::LinComb(dst[i], a, src_a[i], acomp, b, src_b[i], bcomp, dcomp, ncomp, nghost);
    1769             :     }
    1770             : }
    1771             : 
    1772             : //! dst = src w/ MPI communication
    1773             : template <class MF, std::size_t N, std::enable_if_t<IsMultiFabLike_v<MF>, int> = 0>
    1774             : void ParallelCopy (Array<MF,N>& dst, Array<MF,N> const& src,
    1775             :                    int scomp, int dcomp, int ncomp,
    1776             :                    IntVect const& ng_src = IntVect(0),
    1777             :                    IntVect const& ng_dst = IntVect(0),
    1778             :                    Periodicity const& period = Periodicity::NonPeriodic())
    1779             : {
    1780             :     for (std::size_t i = 0; i < N; ++i) {
    1781             :         dst[i].ParallelCopy(src[i], scomp, dcomp, ncomp, ng_src, ng_dst, period);
    1782             :     }
    1783             : }
    1784             : 
    1785             : template <class MF, std::size_t N, std::enable_if_t<IsMultiFabLike_v<MF>, int> = 0>
    1786             : [[nodiscard]] typename MF::value_type
    1787             : norminf (Array<MF,N> const& mf, int scomp, int ncomp, IntVect const& nghost,
    1788             :          bool local = false)
    1789             : {
    1790             :     auto r = typename MF::value_type(0);
    1791             :     for (std::size_t i = 0; i < N; ++i) {
    1792             :         auto tmp = mf[i].norminf(scomp, ncomp, nghost, true);
    1793             :         r = std::max(r,tmp);
    1794             :     }
    1795             :     if (!local) {
    1796             :         ParallelAllReduce::Max(r, ParallelContext::CommunicatorSub());
    1797             :     }
    1798             :     return r;
    1799             : }
    1800             : 
    1801             : template <class MF, std::size_t N, std::enable_if_t<IsMultiFabLike_v<MF> && (N > 0),
    1802             :                                                     int> = 0>
    1803             : [[nodiscard]] int nComp (Array<MF,N> const& mf)
    1804             : {
    1805             :     return mf[0].nComp();
    1806             : }
    1807             : 
    1808             : template <class MF, std::size_t N, std::enable_if_t<IsMultiFabLike_v<MF> && (N > 0),
    1809             :                                                     int> = 0>
    1810             : [[nodiscard]] IntVect nGrowVect (Array<MF,N> const& mf)
    1811             : {
    1812             :     return mf[0].nGrowVect();
    1813             : }
    1814             : 
    1815             : template <class MF, std::size_t N, std::enable_if_t<IsMultiFabLike_v<MF> && (N > 0),
    1816             :                                                     int> = 0>
    1817             : [[nodiscard]] BoxArray const&
    1818             : boxArray (Array<MF,N> const& mf)
    1819             : {
    1820             :     return mf[0].boxArray();
    1821             : }
    1822             : 
    1823             : template <class MF, std::size_t N, std::enable_if_t<IsMultiFabLike_v<MF> && (N > 0),
    1824             :                                                     int> = 0>
    1825             : [[nodiscard]] DistributionMapping const&
    1826             : DistributionMap (Array<MF,N> const& mf)
    1827             : {
    1828             :     return mf[0].DistributionMap();
    1829             : }
    1830             : 
    1831             : }
    1832             : 
    1833             : #endif

Generated by: LCOV version 1.14