Block-Structured AMR Software Framework
Loading...
Searching...
No Matches
AMReX_Array4.H
Go to the documentation of this file.
1#ifndef AMREX_ARRAY4_H_
2#define AMREX_ARRAY4_H_
3
4#include <AMReX_Config.H>
5
11#include <AMReX.H>
12#include <AMReX_IntVect.H>
13#include <AMReX_GpuPrint.H>
14#include <AMReX_ConstexprFor.H>
15
16#include <iostream>
17#include <sstream>
18
20#define AMREX_ARRAY4_INDEX_ASSERT(i,j,k,n) \
21 if ((i)<begin.vect[0] || (i)>=end.vect[0] || \
22 (j)<begin.vect[1] || (j)>=end.vect[1] || \
23 (k)<begin.vect[2] || (k)>=end.vect[2] || \
24 (n)<0 || (n)>=end.vect[3]) \
25 { \
26 index_assert_print_error_message(i,j,k,n); \
27 }
29
30namespace amrex {
31
32 template<int dim>
33 class BoxND;
34
45 template <typename T>
46 struct CellData
47 {
49 T* AMREX_RESTRICT p = nullptr;
50 Long stride = 0;
51 int ncomp = 0;
53
64 constexpr CellData (T* a_p, Long a_stride, int a_ncomp)
65 : p(a_p), stride(a_stride), ncomp(a_ncomp)
66 {}
67
76 template <class U=T>
77 requires (std::is_const_v<U>)
79 constexpr CellData (CellData<std::remove_const_t<T>> const& rhs) noexcept
80 : p(rhs.p), stride(rhs.stride), ncomp(rhs.ncomp)
81 {}
82
89 explicit operator bool() const noexcept { return p != nullptr; }
90
92 [[nodiscard]] AMREX_GPU_HOST_DEVICE
93 int nComp() const noexcept { return ncomp; }
94
106 T& operator[] (int n) const
107 requires (!std::is_void_v<T>)
108
109 {
110#if defined(AMREX_DEBUG) || defined(AMREX_BOUND_CHECK)
111 if (n < 0 || n >= ncomp) {
113 AMREX_DEVICE_PRINTF(" %d is out of bound (0:%d)", n, ncomp-1);
114 ))
116 std::stringstream ss;
117 ss << " " << n << " is out of bound: (0:" << ncomp-1 << ")";
118 amrex::Abort(ss.str());
119 ))
120 }
121#endif
122 return p[n*stride];
123 }
124 };
125
127 namespace detail {
128
129 template <int N> struct Stride { Long a[N] = {}; };
130 template <> struct Stride<0> {};
131
137 template <typename T>
138 struct IsValidIndexType {
139 static constexpr bool value = std::is_integral_v<T> && IsNonNarrowingConversion_v<T, int>;
140 };
141
148 template <int N, bool last_dim_component, typename... idx>
149 struct ArrayNDIndexCheck_impl {
150 private:
151 static constexpr int num_indices = sizeof...(idx);
152
153 template <typename... Ts>
154 struct AllExceptLastEnum;
155
156 template <typename first, typename... Ts>
157 struct AllExceptLastEnum<first, Ts...> {
158 static constexpr bool value =
159 IsValidIndexType<std::decay_t<first>>::value
160 && AllExceptLastEnum<Ts...>::value;
161 };
162
163 // Check if the last index type is an enum or valid index type.
164 // An enum is only allowed if last_dim_component is true.
165 template <typename last>
166 struct AllExceptLastEnum<last> {
167 static constexpr bool value = IsValidIndexType<std::decay_t<last>>::value
168 || (std::is_enum_v<std::decay_t<last>>);
169 };
170
171 static constexpr bool index_with_maybe_enum = AllExceptLastEnum<idx...>::value;
172
173 static constexpr bool index_all_values = Conjunction<
174 IsValidIndexType<std::decay_t<idx>>...>::value;
175
176 public:
177 static constexpr bool value = ((num_indices == N) && index_all_values) // N indices are integer types
178 || ((num_indices == N - 1) && index_all_values && last_dim_component) // N-1 indices are integer types, last is component
179 || ((num_indices == N) && index_with_maybe_enum && last_dim_component); // N indices, last dim is component and can be enum
180 };
181
182 template <int N, bool last_dim_component, class... idx>
183 inline constexpr bool ArrayNDIndexCheck_impl_v = ArrayNDIndexCheck_impl<N, last_dim_component, idx...>::value;
184
185 template<std::size_t... idx>
186 constexpr auto make_oob_message_impl (std::index_sequence<idx...>) {
187 constexpr std::size_t N = sizeof...(idx);
188 constexpr char prefix[] = " (";
189 constexpr char middle[] = ") is out of bound (";
190 constexpr char suffix[] = ")\n";
191
192 constexpr std::size_t size =
193 sizeof(prefix) - 1 +
194 (2*N + (N-1)) +
195 sizeof(middle) - 1 +
196 (5*N + (N-1)) +
197 sizeof(suffix); // include null terminator
198
199 std::array<char, size> buf{};
200
201 std::size_t pos = 0;
202
203 // prefix
204 for (char c : prefix) {
205 if (c != '\0') {
206 buf[pos++] = c;
207 }
208 }
209 // %d,%d,...
210 ((buf[pos++] = '%', buf[pos++] = 'd', idx + 1 < N ? buf[pos++] = ',' : 0), ...);
211
212 // ") is out of bound ("
213 for (char c : middle) {
214 if (c != '\0') {
215 buf[pos++] = c;
216 }
217 }
218
219 // %d:%d,%d:%d,...
220 ((buf[pos++] = '%', buf[pos++] = 'd', buf[pos++] = ':', buf[pos++] = '%', buf[pos++] = 'd',
221 idx + 1 < N ? buf[pos++] = ',' : 0), ...);
222
223 // suffix
224 for (char c : suffix) {
225 buf[pos++] = c;
226 }
227 return buf;
228 }
229
230 template <std::size_t... idx, std::size_t... idx2x>
232 void device_print_impl2 (std::index_sequence<idx...>,
233 std::index_sequence<idx2x...>,
234 IntVectND<sizeof...(idx)> const& iv,
235 IntVectND<sizeof...(idx)> const& begin,
236 IntVectND<sizeof...(idx)> const& end)
237 {
238 constexpr auto msg = make_oob_message_impl(std::index_sequence<idx...>{});
239
240 AMREX_DEVICE_PRINTF(msg.data(),
241 iv.vect[idx]...,
242 ((idx2x % 2 == 0) ? begin.vect[idx2x / 2] : end.vect[idx2x / 2])...
243 );
244 }
245
246 template <int N>
247 requires (N >= 1)
249 void device_printf_impl (const IntVectND<N>& iv,
250 const IntVectND<N>& begin,
251 const IntVectND<N>& end)
252 {
253 device_print_impl2(
254 std::make_index_sequence<N>{},
255 std::make_index_sequence<N*2>{},
256 iv, begin, end
257 );
258 }
259 }
261
286 template<typename T, int N, bool last_dim_component = false>
287 struct ArrayND
288 {
289 static_assert(N >= 1, "ArrayND must have at least one dimension");
290 static_assert(N > 1 || !last_dim_component, "ArrayND with N=1 cannot have last_dim_component=true");
291
293 static constexpr bool IsLastDimComponent_v = last_dim_component;
295 static constexpr bool IsArray4_v = (N==4 && last_dim_component);
296
297 T* AMREX_RESTRICT p = nullptr;
299 AMREX_NO_UNIQUE_ADDRESS detail::Stride<N-1> stride{};
303
310 constexpr ArrayND () noexcept : p(nullptr) {}
311
320 template <class U=T>
321 requires (std::is_const_v<U>)
323 constexpr ArrayND (ArrayND<std::remove_const_t<T>, N, last_dim_component> const& rhs) noexcept
324 : p(rhs.p), stride(rhs.stride), begin(rhs.begin), end(rhs.end) {}
325
331 // TODO: Make BoxND functions constexpr to allow this constructor to be constexpr.
333 ArrayND (T* a_p, BoxND<N> const& box) noexcept
334 requires (!last_dim_component)
335 : ArrayND(a_p, box.smallEnd(), box.bigEnd() + 1)
336 {}
337
344 template <int M>
345 requires (((M+1==N) || (N == 4 && M == AMREX_SPACEDIM))
346 && last_dim_component)
347 // TODO: Make BoxND functions constexpr to allow this constructor to be constexpr.
349 ArrayND (T* a_p, BoxND<M> const& box, int ncomp) noexcept
350 : ArrayND(a_p, box.smallEnd(), box.bigEnd() + 1, ncomp)
351 {}
352
363 constexpr ArrayND (T* a_p, IntVectND<N> const& a_begin, IntVectND<N> const& a_end) noexcept
364 requires (!last_dim_component)
365 : p(a_p), begin(a_begin), end(a_end)
366 {
367 set_stride();
368 }
369
381 constexpr ArrayND (T* a_p, Dim3 const& a_begin, Dim3 const& a_end, int a_ncomp) noexcept
382 requires (IsArray4_v)
383 : p(a_p), begin(a_begin.x, a_begin.y, a_begin.z, 0), end(a_end.x, a_end.y, a_end.z, a_ncomp)
384 {
385 set_stride();
386 }
387
398 template <int M>
399 requires (((M+1 == N) || (N == 4 && M == AMREX_SPACEDIM)) && last_dim_component)
401 constexpr ArrayND (T* a_p, IntVectND<M> const& a_begin, IntVectND<M> const& a_end, int ncomp) noexcept
402 : p(a_p)
403 {
404 constexpr_for<0, M>([&](int d) {
405 begin.vect[d] = a_begin.vect[d];
406 end.vect[d] = a_end.vect[d];
407 });
408 constexpr_for<M, N>([&](int d) {
409 begin.vect[d] = 0;
410 end.vect[d] = 1;
411 });
412 end.vect[N-1] = ncomp;
413
414 set_stride();
415 }
416
425 template <class U>
426 requires (std::is_same_v<std::remove_const_t<T>, std::remove_const_t<U>>
427 && (N >= 2) && last_dim_component)
429 constexpr ArrayND (ArrayND<U, N, last_dim_component> const& rhs, int start_comp) noexcept
430 : p((T*)(rhs.p + start_comp*rhs.stride.a[N-2])),
431 stride(rhs.stride),
432 begin(rhs.begin),
433 end(rhs.end)
434 {
435 begin.vect[N-1] = 0;
436 end.vect[N-1] = rhs.end.vect[N-1] - start_comp;
437 }
438
448 template <class U>
449 requires (std::is_same_v<std::remove_const_t<T>, std::remove_const_t<U>>
450 && (N >= 2) && last_dim_component)
452 constexpr ArrayND (ArrayND<U, N, last_dim_component> const& rhs, int start_comp, int num_comp) noexcept
453 : p((T*)(rhs.p + start_comp*rhs.stride.a[N-2])),
454 stride(rhs.stride),
455 begin(rhs.begin),
456 end(rhs.end)
457 {
458 begin.vect[N-1] = 0;
459 end.vect[N-1] = num_comp;
460 }
461
467 constexpr explicit operator bool() const noexcept { return p != nullptr; }
468
474 [[nodiscard]] AMREX_GPU_HOST_DEVICE
475 constexpr bool ok () const noexcept { return p != nullptr && end.allGT(begin); }
476
493 template <typename... idx>
494 requires (!std::is_void_v<T> && !IsArray4_v
495 && detail::ArrayNDIndexCheck_impl_v<N, last_dim_component, idx...>)
497 T& operator() (idx... i) const noexcept {
498 constexpr auto nidx = sizeof...(i);
499#if defined(AMREX_DEBUG) || defined(AMREX_BOUND_CHECK)
500 index_assert(IntVectND<nidx>{i...});
501#endif
502 return p[get_offset(IntVectND<nidx>{i...})];
503 }
504
517 template <int M>
518 requires (!std::is_void_v<T> &&
519 ((M == N) || (!IsArray4_v && last_dim_component && (M + 1 == N))))
521 T& operator() (IntVectND<M> const& iv) const noexcept {
522#if defined(AMREX_DEBUG) || defined(AMREX_BOUND_CHECK)
523 index_assert(iv);
524#endif
525 return p[get_offset(iv)];
526 }
527
539 template <int M>
540 requires (!std::is_void_v<T> && last_dim_component && !IsArray4_v
541 && (M + 1 == N))
543 T& operator() (IntVectND<M> const& iv, int n) const noexcept {
544#if defined(AMREX_DEBUG) || defined(AMREX_BOUND_CHECK)
545 index_assert(iv, n);
546#endif
547 return p[get_offset(iv, n)];
548 }
549
556 template <typename... idx>
557 requires (!std::is_void_v<T> && !IsArray4_v
558 && detail::ArrayNDIndexCheck_impl_v<N, last_dim_component, idx...>)
560 T* ptr (idx... i) const noexcept {
561 constexpr auto nidx = sizeof...(i);
562#if defined(AMREX_DEBUG) || defined(AMREX_BOUND_CHECK)
563 index_assert(IntVectND<nidx>{i...});
564#endif
565 return p + get_offset(IntVectND<nidx>{i...});
566 }
567
580 template <int M>
581 requires ((M == N) || (!IsArray4_v && last_dim_component && (M + 1 == N)))
583 T* ptr (IntVectND<M> const& iv) const noexcept {
584#if defined(AMREX_DEBUG) || defined(AMREX_BOUND_CHECK)
585 index_assert(iv);
586#endif
587 return p + get_offset(iv);
588 }
589
601 template <int M>
602 requires (last_dim_component && !IsArray4_v && (M + 1 == N))
604 T* ptr (IntVectND<M> const& iv, int n) const noexcept {
605#if defined(AMREX_DEBUG) || defined(AMREX_BOUND_CHECK)
606 index_assert(iv, n);
607#endif
608 return p + get_offset(iv, n);
609 }
610
616 constexpr T* dataPtr () const noexcept {
617 return this->p;
618 }
619
625 constexpr int nComp () const noexcept {
626 if constexpr (last_dim_component) {
627 return end.vect[N-1];
628 } else {
629 return 1;
630 }
631 }
632
642 constexpr std::size_t size () const noexcept {
643 if (ok()) {
644 std::size_t s = 1;
645 constexpr_for<0, N>([&](int d) {
646 s *= (end.vect[d] - begin.vect[d]);
647 });
648 return s;
649 } else {
650 return 0;
651 }
652 }
653
664 template <int d>
665 requires ((d < N) && (d >= 0))
667 constexpr Long get_stride () const noexcept {
668 if constexpr (N > 1 && d > 0) {
669 return stride.a[d-1];
670 } else {
671 return 1;
672 }
673 }
674
686 template <typename... idx>
687 requires (!IsArray4_v &&
688 detail::ArrayNDIndexCheck_impl_v<N, last_dim_component, idx...>)
690 constexpr bool contains (idx... i) const noexcept {
691 constexpr auto nidx = sizeof...(i);
692 return this->contains(IntVectND<nidx>{i...});
693 }
694
711 template <int M>
712 requires ((M == N) || (!IsArray4_v && last_dim_component && (M + 1 == N)))
714 constexpr bool contains (IntVectND<M> const& iv) const noexcept {
715 bool inside = true;
716 constexpr_for<0, M>([&](int d) {
717 inside = inside && (iv.vect[d] >= begin.vect[d]) && (iv.vect[d] < end.vect[d]);
718 });
719 return inside;
720 }
721
738 template <int M>
739 requires (last_dim_component && !IsArray4_v && (M + 1 == N))
741 constexpr bool contains (IntVectND<M> const& iv, int n) const noexcept {
742 bool inside = true;
743 constexpr_for<0, M>([&](int d) {
744 inside = inside && (iv.vect[d] >= begin.vect[d]) && (iv.vect[d] < end.vect[d]);
745 });
746 inside = inside && (n >= 0) && (n < end.vect[N-1]);
747 return inside;
748 }
749
767 CellData<T> cellData (int i, int j, int k) const noexcept
768 requires (IsArray4_v)
769
770 {
771 int ncomp = end.vect[N-1];
772 return CellData<T>(this->ptr(i,j,k), stride.a[N-2], ncomp);
773 }
774
782 template <int M>
783 requires ((M == N) || (last_dim_component && (M + 1 == N || M == AMREX_SPACEDIM)))
785 constexpr Long get_offset (IntVectND<M> const& iv) const noexcept
786 {
787 Long offset = iv.vect[0] - begin.vect[0];
788 // If M == N and we have a component at the end, we only loop up to N-1 for spatial.
789 // Otherwise, we loop up to M.
790 constexpr int idx = (last_dim_component && M == N) ? N - 1 : M;
791 if constexpr (N > 1) {
792 constexpr_for<1, idx>([&](int d) {
793 offset += (iv.vect[d] - begin.vect[d]) * stride.a[d-1];
794 });
795 }
796
797 // Handle the component offset if the input is the full N dimensions
798 // and the last dimension is a component.
799 if constexpr (last_dim_component && M == N) {
800 offset += iv.vect[N-1] * stride.a[N-2];
801 }
802 return offset;
803 }
804
814 template <int M>
815 requires (last_dim_component
816 && ((M + 1 == N) || (N == 4 && M == AMREX_SPACEDIM)))
818 constexpr Long get_offset (IntVectND<M> const& iv, int n) const noexcept
819 {
820 Long offset = iv.vect[0] - begin.vect[0];
821 constexpr_for<1, M>([&](int d) {
822 offset += (iv.vect[d] - begin.vect[d]) * stride.a[d-1];
823 });
824 offset += n * stride.a[N-2];
825 return offset;
826 }
827
828#if defined(AMREX_DEBUG) || defined(AMREX_BOUND_CHECK)
829#if defined(AMREX_USE_HIP)
831#else
833#endif
834 void index_assert (IntVectND<N> const& iv) const
835 {
836 bool out_of_bounds = false;
837 for (int d = 0; d < N; ++d) {
838 if (iv.vect[d] < begin.vect[d] || iv.vect[d] >= end.vect[d]) {
839 out_of_bounds = true;
840 }
841 }
842 if (out_of_bounds) {
844 detail::device_printf_impl(iv, begin, end);
845 amrex::Abort();
846 ))
848 std::stringstream ss;
849 ss << " (";
850 for (int d = 0; d < N; ++d) {
851 ss << iv.vect[d];
852 if (d + 1 < N) ss << ",";
853 }
854 ss << ") is out of bound (";
855 for (int d = 0; d < N; ++d) {
856 ss << begin.vect[d] << ":" << end.vect[d]-1;
857 if (d + 1 < N) ss << ",";
858 };
859 ss << ")";
860 amrex::Abort(ss.str());
861 ))
862 }
863 }
864
865 // index_assert overload for M == N-1 last index assumed 0
866 // Only valid when last_dim_component == true
867 template <int M>
868 requires (((M+1 == N) || (M == AMREX_SPACEDIM)) && last_dim_component)
869#if defined(AMREX_USE_HIP)
871#else
873#endif
874 void index_assert (IntVectND<M> const& iv) const
875 {
876 IntVectND<N> iv_full = iv.template expand<N>(0);
877 for (int d = M; d < N; ++d) {
878 iv_full.vect[d] = begin.vect[d];
879 }
880 index_assert(iv_full);
881 }
882
883 // index_assert overload for M == N-1 and last index n
884 // Only valid when last_dim_component == true
885 template <int M>
886 requires (((M+1 == N) || (M == AMREX_SPACEDIM)) && last_dim_component)
887#if defined(AMREX_USE_HIP)
889#else
891#endif
892 void index_assert (IntVectND<M> const& iv, int n) const
893 {
894 IntVectND<N> iv_full = iv.template expand<N>(0);
895 for (int d = M; d < N-1; ++d) {
896 iv_full.vect[d] = begin.vect[d];
897 }
898 iv_full.vect[N-1] = n;
899 index_assert(iv_full);
900 }
901#endif
902
903 //
904 // Specialization for Array4
905 //
906
925 T& operator() (int i, int j, int k) const noexcept
926 requires (!std::is_void_v<T> && IsArray4_v)
927
928 {
929#if defined(AMREX_DEBUG) || defined(AMREX_BOUND_CHECK)
930 AMREX_ARRAY4_INDEX_ASSERT(i,j,k,0);
931#endif
932#if defined(AMREX_USE_GPU) || defined(AMREX_DEBUG)
933 return p[(i-begin.vect[0]) +
934 (j-begin.vect[1]) * stride.a[0] +
935 (k-begin.vect[2]) * stride.a[1]];
936#else
937 Long idx1 = i + j*stride.a[0] + k*stride.a[1];
938 Long idx0 = begin.vect[0]
939 + begin.vect[1] * stride.a[0]
940 + begin.vect[2] * stride.a[1];
941 return p[idx1-idx0];
942#endif
943 }
944
961 T& operator() (int i, int j, int k, int n) const noexcept
962 requires (!std::is_void_v<T> && IsArray4_v)
963
964 {
965#if defined(AMREX_DEBUG) || defined(AMREX_BOUND_CHECK)
966 AMREX_ARRAY4_INDEX_ASSERT(i,j,k,n);
967#endif
968#if defined(AMREX_USE_GPU) || defined(AMREX_DEBUG)
969 return p[(i-begin.vect[0]) +
970 (j-begin.vect[1]) * stride.a[0] +
971 (k-begin.vect[2]) * stride.a[1] +
972 n * stride.a[2]];
973#else
974 Long idx1 = i + j*stride.a[0] + k*stride.a[1] + n*stride.a[2];
975 Long idx0 = begin.vect[0]
976 + begin.vect[1] * stride.a[0]
977 + begin.vect[2] * stride.a[1];
978 return p[idx1-idx0];
979#endif
980 }
981
991 template <int M>
992 requires (!std::is_void_v<T> && IsArray4_v && (M == 3 || M == AMREX_SPACEDIM))
994 T& operator() (IntVectND<M> const& iv) const noexcept {
995#if (AMREX_SPACEDIM == 1)
996 if constexpr (M == 1) {
997 return this->operator()(iv.vect[0],0,0);
998 } else
999#elif (AMREX_SPACEDIM == 2)
1000 if constexpr (M == 2) {
1001 return this->operator()(iv.vect[0],iv.vect[1],0);
1002 } else
1003#endif
1004 {
1005 return this->operator()(iv.vect[0],iv.vect[1],iv.vect[2]);
1006 }
1007 }
1008
1019 template <int M>
1020 requires (!std::is_void_v<T> && IsArray4_v && (M == 3 || M == AMREX_SPACEDIM))
1022 T& operator() (IntVectND<M> const& iv, int n) const noexcept {
1023#if (AMREX_SPACEDIM == 1)
1024 if constexpr (M == 1) {
1025 return this->operator()(iv.vect[0],0,0,n);
1026 } else
1027#elif (AMREX_SPACEDIM == 2)
1028 if constexpr (M == 2) {
1029 return this->operator()(iv.vect[0],iv.vect[1],0,n);
1030 } else
1031#endif
1032 {
1033 return this->operator()(iv.vect[0],iv.vect[1],iv.vect[2],n);
1034 }
1035 }
1036
1045 T& operator() (Dim3 const& cell) const noexcept
1046 requires (!std::is_void_v<T> && IsArray4_v)
1047
1048 {
1049 return this->operator()(cell.x,cell.y,cell.z);
1050 }
1051
1060 T& operator() (Dim3 const& cell, int n) const noexcept
1061 requires (!std::is_void_v<T> && IsArray4_v)
1062
1063 {
1064 return this->operator()(cell.x,cell.y,cell.z,n);
1065 }
1066
1076 T* ptr (int i, int j, int k) const noexcept
1077 requires (!std::is_void_v<T> && IsArray4_v)
1078
1079 {
1080#if defined(AMREX_DEBUG) || defined(AMREX_BOUND_CHECK)
1081 AMREX_ARRAY4_INDEX_ASSERT(i,j,k,0);
1082#endif
1083#if defined(AMREX_USE_GPU) || defined(AMREX_DEBUG)
1084 return p + ((i-begin.vect[0]) +
1085 (j-begin.vect[1]) * stride.a[0] +
1086 (k-begin.vect[2]) * stride.a[1]);
1087#else
1088 Long idx1 = i + j*stride.a[0] + k*stride.a[1];
1089 Long idx0 = begin.vect[0]
1090 + begin.vect[1] * stride.a[0]
1091 + begin.vect[2] * stride.a[1];
1092 return p + (idx1-idx0);
1093#endif
1094 }
1095
1106 T* ptr (int i, int j, int k, int n) const noexcept
1107 requires (!std::is_void_v<T> && IsArray4_v)
1108
1109 {
1110#if defined(AMREX_DEBUG) || defined(AMREX_BOUND_CHECK)
1111 AMREX_ARRAY4_INDEX_ASSERT(i,j,k,n);
1112#endif
1113#if defined(AMREX_USE_GPU) || defined(AMREX_DEBUG)
1114 return p + ((i-begin.vect[0]) +
1115 (j-begin.vect[1]) * stride.a[0] +
1116 (k-begin.vect[2]) * stride.a[1] +
1117 n * stride.a[2]);
1118#else
1119 Long idx1 = i + j*stride.a[0] + k*stride.a[1] + n*stride.a[2];
1120 Long idx0 = begin.vect[0]
1121 + begin.vect[1] * stride.a[0]
1122 + begin.vect[2] * stride.a[1];
1123 return p + (idx1-idx0);
1124#endif
1125 }
1126
1133 template <int M>
1134 requires (!std::is_void_v<T> && IsArray4_v && (M == 3 || M == AMREX_SPACEDIM))
1136 T* ptr (IntVectND<M> const& iv) const noexcept {
1137#if (AMREX_SPACEDIM == 1)
1138 if constexpr (M == 1) {
1139 return this->ptr(iv.vect[0],0,0);
1140 } else
1141#elif (AMREX_SPACEDIM == 2)
1142 if constexpr (M == 2) {
1143 return this->ptr(iv.vect[0],iv.vect[1],0);
1144 } else
1145#endif
1146 {
1147 return this->ptr(iv.vect[0],iv.vect[1],iv.vect[2]);
1148 }
1149 }
1150
1158 template <int M>
1159 requires (!std::is_void_v<T> && IsArray4_v && (M == 3 || M == AMREX_SPACEDIM))
1161 T* ptr (IntVectND<M> const& iv, int n) const noexcept {
1162#if (AMREX_SPACEDIM == 1)
1163 if constexpr (M == 1) {
1164 return this->ptr(iv.vect[0],0,0,n);
1165 } else
1166#elif (AMREX_SPACEDIM == 2)
1167 if constexpr (M == 2) {
1168 return this->ptr(iv.vect[0],iv.vect[1],0,n);
1169 } else
1170#endif
1171 {
1172 return this->ptr(iv.vect[0],iv.vect[1],iv.vect[2],n);
1173 }
1174 }
1175
1183 T* ptr (Dim3 const& cell) const noexcept
1184 requires (!std::is_void_v<T> && IsArray4_v)
1185
1186 {
1187 return this->ptr(cell.x,cell.y,cell.z);
1188 }
1189
1198 T* ptr (Dim3 const& cell, int n) const noexcept
1199 requires (!std::is_void_v<T> && IsArray4_v)
1200
1201 {
1202 return this->ptr(cell.x,cell.y,cell.z,n);
1203 }
1204
1214 bool contains (int i, int j, int k) const noexcept
1215 requires (IsArray4_v)
1216
1217 {
1218 return (i>=begin.vect[0] && i<end.vect[0] &&
1219 j>=begin.vect[1] && j<end.vect[1] &&
1220 k>=begin.vect[2] && k<end.vect[2]);
1221 }
1222
1229 template <int M>
1230 requires (IsArray4_v && (M == 3 || M == AMREX_SPACEDIM))
1232 bool contains (IntVectND<M> const& iv) const noexcept {
1233#if (AMREX_SPACEDIM < 3)
1234 if constexpr (M == AMREX_SPACEDIM) {
1235 return AMREX_D_TERM((iv.vect[0]>=begin.vect[0]) && (iv.vect[0]<end.vect[0]),
1236 && (iv.vect[1]>=begin.vect[1]) && (iv.vect[1]<end.vect[1]),
1237 && (iv.vect[2]>=begin.vect[2]) && (iv.vect[2]<end.vect[2]));
1238 } else
1239#endif
1240 {
1241 return (iv.vect[0]>=begin.vect[0]) && (iv.vect[0]<end.vect[0])
1242 && (iv.vect[1]>=begin.vect[1]) && (iv.vect[1]<end.vect[1])
1243 && (iv.vect[2]>=begin.vect[2]) && (iv.vect[2]<end.vect[2]);
1244 }
1245 }
1246
1254 bool contains (Dim3 const& cell) const noexcept
1255 requires (IsArray4_v)
1256
1257 {
1258 return (cell.x>=begin.vect[0] && cell.x<end.vect[0] &&
1259 cell.y>=begin.vect[1] && cell.y<end.vect[1] &&
1260 cell.z>=begin.vect[2] && cell.z<end.vect[2]);
1261 }
1262
1263#if defined(AMREX_DEBUG) || defined(AMREX_BOUND_CHECK)
1264#if defined(AMREX_USE_HIP)
1266#else
1268#endif
1269 void index_assert_print_error_message (int i, int j, int k, int n) const
1270 requires (IsArray4_v)
1271
1272 {
1274 AMREX_DEVICE_PRINTF(" (%d,%d,%d,%d) is out of bound (%d:%d,%d:%d,%d:%d,0:%d)\n",
1275 i, j, k, n,
1276 begin.vect[0], end.vect[0]-1,
1277 begin.vect[1], end.vect[1]-1,
1278 begin.vect[2], end.vect[2]-1,
1279 end.vect[3]-1);
1280 amrex::Abort();
1281 ))
1283 std::stringstream ss;
1284 ss << " (" << i << "," << j << "," << k << "," << n
1285 << ") is out of bound ("
1286 << begin.vect[0] << ":" << end.vect[0]-1 << ","
1287 << begin.vect[1] << ":" << end.vect[1]-1 << ","
1288 << begin.vect[2] << ":" << end.vect[2]-1 << ","
1289 << "0:" << end.vect[3]-1 << ")";
1290 amrex::Abort(ss.str());
1291 ))
1292 }
1293#endif
1294
1295 private:
1297 constexpr void set_stride () noexcept {
1298 if constexpr (N > 1) {
1299 Long current_stride = 1;
1300 constexpr_for<0, N-1>([&](int d) {
1301 Long len = end.vect[d] - begin.vect[d];
1302 current_stride *= len;
1303 stride.a[d] = current_stride;
1304 });
1305 }
1306 }
1307 };
1308
1310 // Deduction guides for ArrayND
1311 // 1: Matches ArrayND (T*, BoxND<N>) -> ArrayND<T,N, last_dim_component=false>
1312 template <typename T, int N>
1313 ArrayND (T*, BoxND<N> const&) -> ArrayND<T, N, false>;
1314
1315 // 2: Matches ArrayND (T*, BoxND<N>, ncomp) -> ArrayND<T,N+1, last_dim_component=true>
1316 // This supports the "N+1" logic (Spatial + Component)
1317 template <typename T, int N>
1318 ArrayND (T*, BoxND<N> const&, int) -> ArrayND<T, N+1, true>;
1319
1320 // 3: Matches ArrayND (T*, IntVectND<N>, IntVectND<N>) -> ArrayND<T,N, last_dim_component=false>
1321 template <typename T, int N>
1322 ArrayND (T*, IntVectND<N> const&, IntVectND<N> const&) -> ArrayND<T, N, false>;
1323
1324 // 4: Matches ArrayND (T*, IntVectND<N>, IntVectND<N>, int) -> ArrayND<T,N+1, last_dim_component=true>
1325 template <typename T, int N>
1326 ArrayND (T*, IntVectND<N> const&, IntVectND<N> const&, int) -> ArrayND<T, N+1, true>;
1327
1328 // 5: Matches ArrayND (T*, Dim3, Dim3) -> ArrayND<T,4, last_dim_component=true>
1329 template <typename T>
1330 ArrayND (T*, Dim3 const&, Dim3 const&, int) -> ArrayND<T, 4, true>;
1332
1338 template<typename T>
1340
1348 template <class T>
1350 Dim3 lbound (Array4<T> const& a) noexcept
1351 {
1352 return Dim3{.x = a.begin.vect[0], .y = a.begin.vect[1], .z = a.begin.vect[2]};
1353 }
1354
1362 template <class T>
1364 Dim3 ubound (Array4<T> const& a) noexcept
1365 {
1366 return Dim3{.x = a.end.vect[0]-1, .y = a.end.vect[1]-1, .z = a.end.vect[2]-1};
1367 }
1368
1376 template <class T>
1378 Dim3 length (Array4<T> const& a) noexcept
1379 {
1380 return Dim3{.x = a.end.vect[0]-a.begin.vect[0],
1381 .y = a.end.vect[1]-a.begin.vect[1],
1382 .z = a.end.vect[2]-a.begin.vect[2]};
1383 }
1384
1396 template <typename T, int N, bool C>
1397 std::ostream& operator<< (std::ostream& os, const ArrayND<T,N,C>& a) {
1398 os << "(" << a.begin << ',' << a.end-1 << ")";
1399 return os;
1400 }
1401
1403 //
1404 // Type traits for detecting if a class has a size() constexpr function.
1405 //
1406 template <class A> struct HasMultiComp : std::false_type {};
1407 //
1408 template <class B>
1409 requires (B().size() >= 1)
1410 struct HasMultiComp<B> : std::true_type {};
1412
1425 template <typename T>
1427 : public Array4<T>
1428 {
1431 : Array4<T>{a} {}
1432
1434 T& operator() (int i, int j, int k) const noexcept {
1435 return this->Array4<T>::operator()(i,j,k);
1436 }
1437
1439 typename T::reference_type
1440 operator() (int i, int j, int k, int n) const noexcept
1441 requires (amrex::HasMultiComp<T>::value)
1442
1443 {
1444 return this->Array4<T>::operator()(i,j,k,0)[n];
1445 }
1446
1448 T& operator() (int i, int j, int k, int n) const noexcept
1449 requires (!amrex::HasMultiComp<T>::value)
1450
1451 {
1452 return this->Array4<T>::operator()(i,j,k,n);
1453 }
1454 };
1455
1458 template <typename T>
1459 [[nodiscard]] PolymorphicArray4<T>
1461 {
1462 return PolymorphicArray4<T>(a);
1463 }
1464}
1465
1466#endif
Runtime initialization/finalization helpers and global diagnostics.
Compile-time unrolled loop utility.
#define AMREX_NO_UNIQUE_ADDRESS
Definition AMReX_Extension.H:269
#define AMREX_NO_INLINE
Definition AMReX_Extension.H:141
#define AMREX_FORCE_INLINE
Definition AMReX_Extension.H:124
#define AMREX_RESTRICT
Definition AMReX_Extension.H:37
#define AMREX_DEVICE_PRINTF(...)
Definition AMReX_GpuPrint.H:21
#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_HOST_DEVICE
Definition AMReX_GpuQualifiers.H:20
Array4< int const > offset
Definition AMReX_HypreMLABecLap.cpp:1129
#define AMREX_D_TERM(a, b, c)
Definition AMReX_SPACE.H:172
A Rectangular Domain on an Integer Lattice.
Definition AMReX_Box.H:54
An Integer Vector in dim-Dimensional Space.
Definition AMReX_IntVect.H:149
__host__ __device__ constexpr bool allGT(const IntVectND< dim > &rhs) const noexcept
Returns true if this is greater than argument for all components. NOTE: This is NOT a strict weak ord...
Definition AMReX_IntVect.H:517
int vect[dim]
Definition AMReX_IntVect.H:885
amrex_long Long
Definition AMReX_INT.H:30
__host__ __device__ Dim3 ubound(Array4< T > const &a) noexcept
Return the inclusive upper bounds of an Array4 in Dim3 form.
Definition AMReX_Array4.H:1364
__host__ __device__ Dim3 length(Array4< T > const &a) noexcept
Return the spatial extents of an Array4 in Dim3 form.
Definition AMReX_Array4.H:1378
PolymorphicArray4< T > makePolymorphic(Array4< T > const &a)
Definition AMReX_Array4.H:1460
__host__ __device__ Dim3 lbound(Array4< T > const &a) noexcept
Return the inclusive lower bounds of an Array4 in Dim3 form.
Definition AMReX_Array4.H:1350
__host__ __device__ constexpr void constexpr_for(F const &f)
Compile-time unrolled loop from I (inclusive) to N (exclusive).
Definition AMReX_ConstexprFor.H:38
Definition AMReX_Amr.cpp:50
std::ostream & operator<<(std::ostream &os, AmrMesh const &amr_mesh)
Stream helper; forwards to the friend declared inside AmrMesh.
Definition AMReX_AmrMesh.cpp:1306
__host__ __device__ Dim3 begin(BoxND< dim > const &box) noexcept
Return the iterator begin coordinate of box as Dim3.
Definition AMReX_Box.H:2239
void Abort(const std::string &msg)
Print a fatal-error message to stderr and abort execution.
Definition AMReX.cpp:241
__host__ __device__ Dim3 end(BoxND< dim > const &box) noexcept
Return the iterator end coordinate of box as Dim3.
Definition AMReX_Box.H:2257
A multidimensional array accessor.
Definition AMReX_Array4.H:288
__host__ __device__ T * ptr(int i, int j, int k) const noexcept
Return the pointer to an element.
Definition AMReX_Array4.H:1076
__host__ __device__ constexpr bool contains(IntVectND< M > const &iv, int n) const noexcept
Test whether a spatial index and component lie inside the bounds.
Definition AMReX_Array4.H:741
static constexpr bool IsArray4_v
True if this is an Array4 (N==4 and last dim is component).
Definition AMReX_Array4.H:295
__host__ __device__ ArrayND(T *a_p, BoxND< M > const &box, int ncomp) noexcept
Constructor using a BoxND and the number of components.
Definition AMReX_Array4.H:349
__host__ __device__ constexpr bool ok() const noexcept
Check if the ArrayND pointer is valid and bounds are valid.
Definition AMReX_Array4.H:475
__host__ __device__ T & operator()(idx... i) const noexcept
Multi-index operator() for accessing elements.
Definition AMReX_Array4.H:497
__host__ __device__ ArrayND(T *a_p, BoxND< N > const &box) noexcept
Constructor using a BoxND.
Definition AMReX_Array4.H:333
__host__ __device__ constexpr std::size_t size() const noexcept
Total number of elements in the ArrayND's index region.
Definition AMReX_Array4.H:642
__host__ __device__ constexpr bool contains(IntVectND< M > const &iv) const noexcept
Test whether an IntVectND lies inside the ArrayND bounds.
Definition AMReX_Array4.H:714
__host__ __device__ bool contains(IntVectND< M > const &iv) const noexcept
Test whether the spatial indices are inside the Array4 bounds.
Definition AMReX_Array4.H:1232
__host__ __device__ T * ptr(IntVectND< M > const &iv) const noexcept
Access pointer by IntVectND.
Definition AMReX_Array4.H:583
T *__restrict__ p
Definition AMReX_Array4.H:297
__host__ __device__ constexpr ArrayND(T *a_p, IntVectND< N > const &a_begin, IntVectND< N > const &a_end) noexcept
IntVectND<N> constructor.
Definition AMReX_Array4.H:363
__host__ __device__ constexpr bool contains(idx... i) const noexcept
Test whether an index tuple lies inside the ArrayND bounds.
Definition AMReX_Array4.H:690
__host__ __device__ T * ptr(Dim3 const &cell, int n) const noexcept
Return the pointer to an element.
Definition AMReX_Array4.H:1198
static constexpr bool IsLastDimComponent_v
True if the last dimension is treated as components.
Definition AMReX_Array4.H:293
__host__ __device__ constexpr int nComp() const noexcept
Get number of components.
Definition AMReX_Array4.H:625
__host__ __device__ constexpr T * dataPtr() const noexcept
Get raw data pointer.
Definition AMReX_Array4.H:616
__host__ __device__ T * ptr(idx... i) const noexcept
Multi-index ptr() for accessing pointer to element.
Definition AMReX_Array4.H:560
__host__ __device__ T * ptr(int i, int j, int k, int n) const noexcept
Return the pointer to an element.
Definition AMReX_Array4.H:1106
IntVectND< N > end
Exclusive upper bounds.
Definition AMReX_Array4.H:302
__host__ __device__ constexpr Long get_offset(IntVectND< M > const &iv, int n) const noexcept
Compute the linear offset (in elements) for an IntVectND and component index.
Definition AMReX_Array4.H:818
IntVectND< N > begin
Inclusive lower bounds.
Definition AMReX_Array4.H:301
__host__ __device__ CellData< T > cellData(int i, int j, int k) const noexcept
Create a single-cell component accessor.
Definition AMReX_Array4.H:767
__host__ __device__ T * ptr(IntVectND< M > const &iv, int n) const noexcept
Access pointer by spatial IntVectND and component index.
Definition AMReX_Array4.H:604
__host__ __device__ T * ptr(IntVectND< M > const &iv) const noexcept
Return the pointer to an element.
Definition AMReX_Array4.H:1136
__host__ __device__ constexpr ArrayND(ArrayND< U, N, last_dim_component > const &rhs, int start_comp, int num_comp) noexcept
Slicing constructor (Component subset with count).
Definition AMReX_Array4.H:452
__host__ __device__ constexpr Long get_offset(IntVectND< M > const &iv) const noexcept
Compute the linear offset (in elements) for an IntVectND.
Definition AMReX_Array4.H:785
__host__ __device__ T * ptr(Dim3 const &cell) const noexcept
Return the pointer to an element.
Definition AMReX_Array4.H:1183
__host__ __device__ constexpr Long get_stride() const noexcept
Return the stride (in elements) for dimension d.
Definition AMReX_Array4.H:667
__host__ __device__ constexpr ArrayND() noexcept
Default-construct an empty accessor.
Definition AMReX_Array4.H:310
__host__ __device__ constexpr ArrayND(ArrayND< U, N, last_dim_component > const &rhs, int start_comp) noexcept
Slicing constructor (Component subset).
Definition AMReX_Array4.H:429
__host__ __device__ constexpr ArrayND(T *a_p, Dim3 const &a_begin, Dim3 const &a_end, int a_ncomp) noexcept
Constructor for N=4 using Dim3.
Definition AMReX_Array4.H:381
__host__ __device__ T * ptr(IntVectND< M > const &iv, int n) const noexcept
Return the pointer to an element.
Definition AMReX_Array4.H:1161
__host__ __device__ bool contains(Dim3 const &cell) const noexcept
Test whether the spatial indices are inside the Array4 bounds.
Definition AMReX_Array4.H:1254
__host__ __device__ bool contains(int i, int j, int k) const noexcept
Test whether the spatial indices are inside the Array4 bounds.
Definition AMReX_Array4.H:1214
__host__ __device__ constexpr ArrayND(T *a_p, IntVectND< M > const &a_begin, IntVectND< M > const &a_end, int ncomp) noexcept
Reduced dimension constructor with component count.
Definition AMReX_Array4.H:401
Lightweight accessor for data associated with a single cell.
Definition AMReX_Array4.H:47
__host__ __device__ constexpr CellData(T *a_p, Long a_stride, int a_ncomp)
Construct a CellData.
Definition AMReX_Array4.H:64
__host__ __device__ T & operator[](int n) const
Access the n-th component of the cell.
Definition AMReX_Array4.H:106
__host__ __device__ int nComp() const noexcept
Return the number of components referenced by this accessor.
Definition AMReX_Array4.H:93
A simple struct holding 3 int values for a 3D index.
Definition AMReX_Dim3.H:24
int x
Definition AMReX_Dim3.H:24
Array4 subclass that provides uniform (i,j,k,n) access for both AoS and SoA data.
Definition AMReX_Array4.H:1428
__host__ __device__ PolymorphicArray4(Array4< T > const &a)
Definition AMReX_Array4.H:1430