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