Line data Source code
1 : #ifndef AMREX_ARRAY_H_
2 : #define AMREX_ARRAY_H_
3 : #include <AMReX_Config.H>
4 :
5 : #include <AMReX.H>
6 : #include <AMReX_GpuQualifiers.H>
7 : #include <AMReX_GpuControl.H>
8 : #include <AMReX_BLassert.H>
9 : #include <AMReX_SPACE.H>
10 : #include <AMReX_REAL.H>
11 : #include <AMReX_Algorithm.H>
12 : #include <AMReX_Dim3.H>
13 :
14 : #include <array>
15 : #include <memory>
16 : #include <utility>
17 : #include <string>
18 : #include <type_traits>
19 :
20 : namespace amrex {
21 :
22 : template <class T, std::size_t N>
23 : using Array = std::array<T,N>;
24 :
25 : using RealArray = Array<Real, AMREX_SPACEDIM>;
26 : using IntArray = Array<int , AMREX_SPACEDIM>;
27 :
28 : }
29 :
30 : namespace amrex {
31 : template <class T, unsigned int N>
32 : struct GpuArray
33 : {
34 : using value_type = T;
35 : using reference_type = T&;
36 :
37 : /**
38 : * GpuArray elements are indexed using square brackets, as with any
39 : * other array.
40 : */
41 : AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
42 : const T& operator [] (int i) const noexcept { return arr[i]; }
43 :
44 : /**
45 : * GpuArray elements are indexed using square brackets, as with any
46 : * other array.
47 : */
48 : AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
49 : T& operator [] (int i) noexcept { return arr[i]; }
50 :
51 : /**
52 : * Returns a \c const pointer to the underlying data of a GpuArray object.
53 : */
54 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
55 : const T* data () const noexcept { return arr; }
56 :
57 : /**
58 : * Returns a pointer to the underlying data of a GpuArray object.
59 : */
60 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
61 0 : T* data () noexcept { return arr; }
62 :
63 : /**
64 : * Returns the number of elements in the GpuArray object as an
65 : * unsigned integer.
66 : */
67 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
68 : static constexpr unsigned int size () noexcept { return N; }
69 :
70 : /**
71 : * Returns a \c const pointer address to the first element of the
72 : * GpuArray object.
73 : */
74 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
75 : const T* begin () const noexcept { return arr; }
76 :
77 : /**
78 : * Returns a const pointer address right after the last element of the
79 : * GpuArray object.
80 : */
81 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
82 : const T* end () const noexcept { return arr + N; }
83 :
84 : /**
85 : * Returns a pointer address to the first element of the
86 : * GpuArray object.
87 : */
88 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
89 : T* begin () noexcept { return arr; }
90 :
91 : /**
92 : * Returns a pointer address right after the last element of the
93 : * GpuArray object.
94 : */
95 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
96 : T* end () noexcept { return arr + N; }
97 :
98 : /**
99 : * Fills in all of the elements in the GpuArray object to the same
100 : * value.
101 : *
102 : * \param value The fill value
103 : */
104 : AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
105 : void fill ( const T& value ) noexcept
106 : { for (unsigned int i = 0; i < N; ++i) { arr[i] = value; } }
107 :
108 : /**
109 : * Returns the sum of all elements in the GpuArray object.
110 : */
111 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
112 : constexpr T sum () const noexcept
113 : {
114 : T s = 0;
115 : for (unsigned int i = 0; i < N; ++i) { s += arr[i]; }
116 : return s;
117 : }
118 :
119 : /**
120 : * Returns the product of all elements in the GpuArray object.
121 : */
122 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
123 : T product () const noexcept
124 : {
125 : T p = 1;
126 : for (unsigned int i = 0; i < N; ++i) { p *= arr[i]; }
127 : return p;
128 : }
129 :
130 : AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
131 : GpuArray<T,N>& operator+= (GpuArray<T,N> const& a) noexcept
132 : {
133 : for (unsigned int i = 0; i < N; ++i) {
134 : arr[i] += a.arr[i];
135 : }
136 : return *this;
137 : }
138 :
139 : T arr[amrex::max(N,1U)];
140 : };
141 : }
142 :
143 : namespace amrex {
144 :
145 : /**
146 : * Array2D and Array3D objects can be indexed according to Fortran
147 : * column-major order (first index moving fastest) or C/C++ row-major
148 : * order (last index moving fastest). If not specified, Fortran order is
149 : * assumed.
150 : */
151 : namespace Order {
152 : struct C {};
153 : struct F {};
154 : }
155 :
156 : /**
157 : * A GPU-compatible one-dimensional array.
158 : *
159 : * \tparam XLO Index for lower bound. Can be other than 0.
160 : * \tparam XHI Index for upper bound.
161 : */
162 : template <class T, int XLO, int XHI>
163 : struct Array1D
164 : {
165 : /**
166 : * Returns the number of elements in the Array1D object as an unsigned
167 : * integer.
168 : */
169 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
170 : static constexpr unsigned int size () noexcept { return (XHI-XLO+1); }
171 :
172 : /**
173 : * Returns the index of the lower bound of the Array1D object.
174 : * Can be other than 0.
175 : */
176 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
177 : static constexpr int lo () noexcept { return XLO; }
178 :
179 : /**
180 : * Returns the index of the upper bound of the Array1D object.
181 : */
182 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
183 : static constexpr int hi () noexcept { return XHI; }
184 :
185 : /**
186 : * Returns the number of elements in the Array1D object as an unsigned
187 : * integer.
188 : */
189 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
190 : static constexpr unsigned int len () noexcept { return (XHI-XLO+1); }
191 :
192 : /**
193 : * Returns a \c const pointer address to the first element of the
194 : * Array1D object.
195 : */
196 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
197 : const T* begin () const noexcept { return arr; }
198 :
199 : /**
200 : * Returns a \c const pointer address right after the last element of the
201 : * Array1D object.
202 : */
203 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
204 : const T* end () const noexcept { return arr + XHI-XLO+1; }
205 :
206 : /**
207 : * Returns a pointer address to the first element of the
208 : * Array1D object.
209 : */
210 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
211 : T* begin () noexcept { return arr; }
212 :
213 : /**
214 : * Returns a pointer address right after the last element of the
215 : * Array1D object.
216 : */
217 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
218 : T* end () noexcept { return arr + XHI-XLO+1; }
219 :
220 : /**
221 : * The elements of an Array1D object are accessed using parentheses,
222 : * e.g. \c array(i), instead of using square brackets.
223 : */
224 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
225 : const T& operator() (int i) const noexcept {
226 : AMREX_ASSERT(i >= XLO && i <= XHI);
227 : return arr[i-XLO];
228 : }
229 :
230 : /**
231 : * The elements of an Array1D object are accessed using parentheses,
232 : * e.g. array(i), instead of using square brackets.
233 : */
234 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
235 : T& operator() (int i) noexcept {
236 : AMREX_ASSERT(i >= XLO && i <= XHI);
237 : return arr[i-XLO];
238 : }
239 :
240 : /**
241 : * Returns the sum of all elements in the Array1D object.
242 : */
243 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
244 : constexpr T sum () const noexcept
245 : {
246 : T s = 0;
247 : for (int i = XLO; i <= XHI; ++i) { s += arr[i-XLO]; }
248 : return s;
249 : }
250 :
251 : /**
252 : * Returns the product of all elements in the Array1D object.
253 : */
254 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
255 : constexpr T product() const noexcept
256 : {
257 : T p = 1;
258 : for (int i = 0; i < (XHI-XLO+1); ++i) {
259 : p *= arr[i];
260 : }
261 : return p;
262 : }
263 :
264 : /**
265 : * Array1D is implemented as a fixed-size array.
266 : * Hence, no constructor or destructor is given.
267 : */
268 : T arr[(XHI-XLO+1)];
269 : };
270 :
271 : /**
272 : * A GPU-compatible two-dimensional array.
273 : *
274 : * \tparam XLO Index for lower bound in \a x dimension. Can be other than 0.
275 : * \tparam XHI Index for upper bound in \a x dimension.
276 : * \tparam YLO Index for lower bound in \a y dimension. Can be other than 0.
277 : * \tparam YHI Index for upper bound in \a y dimension.
278 : * \tparam ORDER Either Order::C (C/C++ row-major order) or
279 : * Order::F (Fortran column-major order, which is the
280 : * default if not given)
281 : */
282 : template <class T, int XLO, int XHI, int YLO, int YHI,
283 : class ORDER=Order::F>
284 : struct Array2D
285 : {
286 : /**
287 : * Returns the total number of elements of the Array2D object as an
288 : * unsigned integer.
289 : */
290 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
291 : static constexpr unsigned int size() noexcept { return (XHI-XLO+1)*(YHI-YLO+1); }
292 :
293 : /**
294 : * Returns the index of the lower bound of the Array2D object in the
295 : * \a x direction.
296 : * Can be other than 0.
297 : */
298 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
299 : static constexpr int xlo () noexcept { return XLO; }
300 :
301 : /**
302 : * Returns the index of the upper bound of the Array2D object in the
303 : * \a x direction.
304 : */
305 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
306 : static constexpr int xhi () noexcept { return XHI; }
307 :
308 :
309 : /**
310 : * Returns the number of elements of the Array2D object in the
311 : * \a x direction as an unsigned integer.
312 : */
313 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
314 : static constexpr unsigned int xlen () noexcept { return (XHI-XLO+1); }
315 :
316 : /**
317 : * Returns the index of the lower bound of the Array2D object in the
318 : * \a y direction.
319 : * Can be other than 0.
320 : */
321 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
322 : static constexpr int ylo () noexcept { return YLO; }
323 :
324 : /**
325 : * Returns the index of the upper bound of the Array2D object in the
326 : * \a y direction.
327 : */
328 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
329 : static constexpr int yhi () noexcept { return YHI; }
330 :
331 :
332 : /**
333 : * Returns the number of elements of the Array2D object in the
334 : * \a y direction as an unsigned integer.
335 : */
336 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
337 : static constexpr unsigned int ylen () noexcept { return (YHI-YLO+1); }
338 :
339 : /**
340 : * Returns a \c const pointer address to the first element of the
341 : * Array2D object, as if the object is treated as one-dimensional.
342 : */
343 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
344 : const T* begin () const noexcept { return arr; }
345 :
346 : /**
347 : * Returns a \c const pointer address right after the last element of the
348 : * Array2D object, as if the object is treated as one-dimensional.
349 : */
350 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
351 : const T* end () const noexcept { return arr + (XHI-XLO+1)*(YHI-YLO+1); }
352 :
353 : /**
354 : * Returns a pointer address to the first element of the
355 : * Array2D object, as if the object is treated as one-dimensional.
356 : */
357 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
358 : T* begin () noexcept { return arr; }
359 :
360 : /**
361 : * Returns a pointer address right after the last element of the
362 : * Array2D object, as if the object is treated as one-dimensional.
363 : */
364 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
365 : T* end () noexcept { return arr + (XHI-XLO+1)*(YHI-YLO+1); }
366 :
367 : /**
368 : * The elements of an Array2D object are accessed using parentheses,
369 : * e.g. \c array(i,j), instead of using square brackets.
370 : * If the order is not specified, Fortran column-major order is assumed
371 : * (the index \c i moves the fastest)
372 : */
373 : template <typename O=ORDER,
374 : std::enable_if_t<std::is_same_v<O,Order::F>,int> = 0>
375 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
376 : const T& operator() (int i, int j) const noexcept {
377 : AMREX_ASSERT(i >= XLO && i <= XHI && j >= YLO && j <= YHI);
378 : return arr[i+j*(XHI-XLO+1)-(YLO*(XHI-XLO+1)+XLO)];
379 : }
380 :
381 : /**
382 : * The elements of an Array2D object are accessed using parentheses,
383 : * e.g. \c array(i,j), instead of using square brackets.
384 : * If the order is not specified, Fortran column-major order is assumed
385 : * (the index \c i moves the fastest)
386 : */
387 : template <typename O=ORDER,
388 : std::enable_if_t<std::is_same_v<O,Order::F>,int> = 0>
389 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
390 : T& operator() (int i, int j) noexcept {
391 : AMREX_ASSERT(i >= XLO && i <= XHI && j >= YLO && j <= YHI);
392 : return arr[i+j*(XHI-XLO+1)-(YLO*(XHI-XLO+1)+XLO)];
393 : }
394 :
395 : /**
396 : * The elements of an Array2D object are accessed using parentheses,
397 : * e.g. \c array(i,j), instead of using square brackets.
398 : * When the order is manually specified as Order::C, row-major order
399 : * is used (the index \c j moves the fastest).
400 : */
401 : template <typename O=ORDER,
402 : std::enable_if_t<std::is_same_v<O,Order::C>,int> = 0>
403 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
404 : const T& operator() (int i, int j) const noexcept {
405 : AMREX_ASSERT(i >= XLO && i <= XHI && j >= YLO && j <= YHI);
406 : return arr[j+i*(YHI-YLO+1)-(XLO*(YHI-YLO+1)+YLO)];
407 : }
408 :
409 : /**
410 : * The elements of an Array2D object are accessed using parentheses,
411 : * e.g. \c array(i,j), instead of using square brackets.
412 : * When the order is manually specified as Order::C, row-major order
413 : * is used (the index \c j moves the fastest).
414 : */
415 : template <typename O=ORDER,
416 : std::enable_if_t<std::is_same_v<O,Order::C>,int> = 0>
417 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
418 : T& operator() (int i, int j) noexcept {
419 : AMREX_ASSERT(i >= XLO && i <= XHI && j >= YLO && j <= YHI);
420 : return arr[j+i*(YHI-YLO+1)-(XLO*(YHI-YLO+1)+YLO)];
421 : }
422 :
423 : /**
424 : * When called without any arguments, returns the sum of all
425 : * elements in the Array2D object.
426 : */
427 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
428 : constexpr T sum () const noexcept
429 : {
430 : T s = 0;
431 : for (int i = 0; i < (XHI-XLO+1)*(YHI-YLO+1); ++i) {
432 : s += arr[i];
433 : }
434 : return s;
435 : }
436 :
437 : /**
438 : * When called with two arguments, performs a sum reduction over
439 : * the specified \c axis, for a particular location index \c loc.
440 : *
441 : * \param axis The dimension to reduce (0 for \a x dimension,
442 : * 1 for \a y dimension)
443 : * \param loc The appropriate location index
444 : *
445 : * This can be used, for instance, to calculate the sum over the \a y
446 : * dimension of an Array2D object that was instantiated as
447 : * \verbatim Array2D<amrex::Real, 1, M, 1, N> array; \endverbatim
448 : *
449 : * One could instantiate an Array1D object to hold the results,
450 : * \verbatim Array1D<amrex::Real, 1, M> vec; \endverbatim
451 : * and then perform the summation for each element of the resulting
452 : * vector.
453 : * \verbatim
454 : for (int i = 1; i <= M; ++i) {
455 : vec(i) = array.sum(1,i)
456 : }
457 : \endverbatim
458 : * In this example, the axis is 1 and the location index is \c i.
459 : *
460 : */
461 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
462 : constexpr T sum (int axis, int loc) const noexcept
463 : {
464 : T s = 0;
465 : if (axis == 0) {
466 : int j = loc;
467 : for (int i = XLO; i <= XHI; ++i) {
468 : s += this->operator()(i,j);
469 : }
470 : } else if (axis == 1) {
471 : int i = loc;
472 : for (int j = YLO; j <= YHI; ++j) {
473 : s += this->operator()(i,j);
474 : }
475 : }
476 : return s;
477 : }
478 :
479 : /**
480 : * When called without any arguments, returns the product of all
481 : * elements in the Array2D object.
482 : */
483 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
484 : constexpr T product () const noexcept
485 : {
486 : T p = 1;
487 : for (int i = 0; i < (XHI-XLO+1)*(YHI-YLO+1); ++i) {
488 : p *= arr[i];
489 : }
490 : return p;
491 : }
492 :
493 : /**
494 : * When called with two arguments, performs a product reduction over
495 : * the specified \c axis, for a particular location index \c loc.
496 : *
497 : * \param axis The dimension to reduce (0 for \a x dimension,
498 : * 1 for \a y dimension)
499 : * \param loc The appropriate location index
500 : *
501 : * This can be used, for instance, to calculate the product over the \a x
502 : * dimension of an Array2D object that was instantiated as
503 : * \verbatim Array2D<amrex::Real, 1, M, 1, N> array; \endverbatim
504 : *
505 : * One could instantiate an Array1D object to hold the results with,
506 : * \verbatim Array1D<amrex::Real, 1, N> vec; \endverbatim
507 : * and then perform the product for each element of the resulting
508 : * vector.
509 : *
510 : * \verbatim
511 : for (int j = 1; j <= N; ++j) {
512 : vec(j) = array.sum(0,j)
513 : }
514 : \endverbatim
515 : * In this example, the axis is 0 and the location index is \c j.
516 : *
517 : */
518 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
519 : constexpr T product (int axis, int loc) const noexcept
520 : {
521 : T p = 1;
522 : if (axis == 0) {
523 : int j = loc;
524 : for (int i = XLO; i <= XHI; ++i) {
525 : p *= this->operator()(i,j);
526 : }
527 : } else if (axis == 1) {
528 : int i = loc;
529 : for (int j = YLO; j <= YHI; ++j) {
530 : p *= this->operator()(i,j);
531 : }
532 : }
533 : return p;
534 : }
535 :
536 : T arr[(XHI-XLO+1)*(YHI-YLO+1)];
537 : };
538 :
539 :
540 : /**
541 : * A GPU-compatible three-dimensional array.
542 : *
543 : * \tparam XLO Index for lower bound in \a x dimension. Can be other than 0.
544 : * \tparam XHI Index for upper bound in \a x dimension.
545 : * \tparam YLO Index for lower bound in \a y dimension. Can be other than 0.
546 : * \tparam YHI Index for upper bound in \a y dimension.
547 : * \tparam ZLO Index for lower bound in \a z dimension. Can be other than 0.
548 : * \tparam ZHI Index for upper bound in \a z dimension.
549 : * \tparam ORDER Either Order::C (C/C++ row-major order) or
550 : * Order::F (Fortran column-major order, which is the
551 : * default if not given)
552 : */
553 : template <class T, int XLO, int XHI, int YLO, int YHI, int ZLO, int ZHI,
554 : class ORDER=Order::F>
555 : struct Array3D
556 : {
557 : /**
558 : * Returns the total number of elements in the Array3D object as an
559 : * unsigned integer.
560 : */
561 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
562 : static constexpr unsigned int size () noexcept { return (XHI-XLO+1)*(YHI-YLO+1)*(ZHI-ZLO+1); }
563 :
564 : /**
565 : * Returns the index of the lower bound of the Array3D object in the
566 : * \a x direction.
567 : * Can be other than 0.
568 : */
569 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
570 : static constexpr int xlo () noexcept { return XLO; }
571 :
572 : /**
573 : * Returns the index of the upper bound of the Array3D object in the
574 : * \a x direction.
575 : */
576 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
577 : static constexpr int xhi () noexcept { return XHI; }
578 :
579 : /**
580 : * Returns the number of elements of the Array3D object in the
581 : * \a x direction as an unsigned integer.
582 : */
583 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
584 : static constexpr unsigned int xlen () noexcept { return (XHI-XLO+1); }
585 :
586 : /**
587 : * Returns the index of the lower bound of the Array3D object in the
588 : * \a y direction.
589 : * Can be other than 0.
590 : */
591 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
592 : static constexpr int ylo () noexcept { return YLO; }
593 :
594 : /**
595 : * Returns the index of the upper bound of the Array3D object in the
596 : * \a y direction.
597 : */
598 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
599 : static constexpr int yhi () noexcept { return YHI; }
600 :
601 :
602 : /**
603 : * Returns the number of elements of the Array3D object in the
604 : * \a y direction as an unsigned integer.
605 : */
606 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
607 : static constexpr unsigned int ylen () noexcept { return (YHI-YLO+1); }
608 :
609 : /**
610 : * Returns the index of the lower bound of the Array3D object in the
611 : * \a z direction.
612 : * Can be other than 0.
613 : */
614 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
615 : static constexpr int zlo () noexcept { return ZLO; }
616 :
617 : /**
618 : * Returns the index of the upper bound of the Array3D object in the
619 : * \a z direction.
620 : */
621 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
622 : static constexpr int zhi () noexcept { return ZHI; }
623 :
624 : /**
625 : * Returns the number of elements of the Array3D object in the
626 : * \a z direction as an unsigned integer.
627 : */
628 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
629 : static constexpr unsigned int zlen () noexcept { return (ZHI-ZLO+1); }
630 :
631 : /**
632 : * Returns a \c const pointer address to the first element of the
633 : * Array3D object, as if the object is treated as one-dimensional.
634 : */
635 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
636 : const T* begin () const noexcept { return arr; }
637 :
638 : /**
639 : * Returns a \c const pointer address right after the last element of the
640 : * Array3D object, as if the object is treated as one-dimensional.
641 : */
642 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
643 : const T* end () const noexcept { return arr + (XHI-XLO+1)*(YHI-YLO+1)*(ZHI-ZLO+1); }
644 :
645 : /**
646 : * Returns a pointer address to the first element of the
647 : * Array3D object, as if the object is treated as one-dimensional.
648 : */
649 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
650 : T* begin () noexcept { return arr; }
651 :
652 : /**
653 : * Returns a pointer address right after the last element of the
654 : * Array3D object, as if the object is treated as one-dimensional.
655 : */
656 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
657 : T* end () noexcept { return arr + (XHI-XLO+1)*(YHI-YLO+1)*(ZHI-ZLO+1); }
658 :
659 : /**
660 : * The elements of an Array3D object are accessed using parentheses,
661 : * e.g. \c array(i,j,k), instead of using square brackets.
662 : * If the order is not specified, Fortran column-major order is assumed
663 : * (the index \c i moves the fastest)
664 : */
665 : template <typename O=ORDER,
666 : std::enable_if_t<std::is_same_v<O,Order::F>,int> = 0>
667 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
668 : const T& operator() (int i, int j, int k) const noexcept {
669 : return arr[i+j*(XHI-XLO+1)+k*((XHI-XLO+1)*(YHI-YLO+1))
670 : -(ZLO*((XHI-XLO+1)*(YHI-YLO+1))+YLO*(XHI-XLO+1)+XLO)];
671 : }
672 :
673 : /**
674 : * The elements of an Array3D object are accessed using parentheses,
675 : * e.g. \c array(i,j,k), instead of using square brackets.
676 : * If the order is not specified, Fortran column-major order is assumed
677 : * (the index \c i moves the fastest)
678 : */
679 : template <typename O=ORDER,
680 : std::enable_if_t<std::is_same_v<O,Order::F>,int> = 0>
681 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
682 : T& operator() (int i, int j, int k) noexcept {
683 : return arr[i+j*(XHI-XLO+1)+k*((XHI-XLO+1)*(YHI-YLO+1))
684 : -(ZLO*((XHI-XLO+1)*(YHI-YLO+1))+YLO*(XHI-XLO+1)+XLO)];
685 : }
686 :
687 : /**
688 : * The elements of an Array3D object are accessed using parentheses,
689 : * e.g. \c array(i,j,k), instead of using square brackets.
690 : * When the order is manually specified as Order::C, row-major order
691 : * is used (the index \c k moves the fastest).
692 : */
693 : template <typename O=ORDER,
694 : std::enable_if_t<std::is_same_v<O,Order::C>,int> = 0>
695 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
696 : const T& operator() (int i, int j, int k) const noexcept {
697 : return arr[k+j*(ZHI-ZLO+1)+i*((ZHI-ZLO+1)*(YHI-YLO+1))
698 : -(XLO*((ZHI-ZLO+1)*(YHI-YLO+1))+YLO*(ZHI-ZLO+1)+ZLO)];
699 : }
700 :
701 : /**
702 : * The elements of an Array3D object are accessed using parentheses,
703 : * e.g. \c array(i,j,k), instead of using square brackets.
704 : * When the order is manually specified as Order::C, row-major order
705 : * is used (the index \c k moves the fastest).
706 : */
707 : template <typename O=ORDER,
708 : std::enable_if_t<std::is_same_v<O,Order::C>,int> = 0>
709 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
710 : T& operator() (int i, int j, int k) noexcept {
711 : return arr[k+j*(ZHI-ZLO+1)+i*((ZHI-ZLO+1)*(YHI-YLO+1))
712 : -(XLO*((ZHI-ZLO+1)*(YHI-YLO+1))+YLO*(ZHI-ZLO+1)+ZLO)];
713 : }
714 :
715 : /**
716 : * When called without any arguments, returns the sum of all
717 : * elements in the Array3D object.
718 : */
719 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
720 : constexpr T sum () const noexcept
721 : {
722 : T s = 0;
723 : for (int i = 0; i < (XHI-XLO+1)*(YHI-YLO+1)*(ZHI-ZLO+1); ++i) {
724 : s += arr[i];
725 : }
726 : return s;
727 : }
728 :
729 : /**
730 : * When called with three arguments, performs a sum reduction over
731 : * the specified \c axis, for a particular set of location indices \c loc0
732 : * and \c loc1.
733 : *
734 : * \param axis The dimension to reduce (0 for \a x dimension,
735 : * 1 for \a y dimension, 2 for \a z dimension)
736 : * \param loc0 The appropriate location index (either \c i or \c j)
737 : * \param loc1 The appropriate location index (either \c j or \c k)
738 : *
739 : * This can be used, for instance, to calculate the sum over the \a x
740 : * dimension of an Array3D object that was instantiated as
741 : * \verbatim Array3D<amrex::Real, 1, M, 1, N, 1, K> array; \endverbatim
742 : *
743 : * One could instantiate an Array2D object to hold the results,
744 : * \verbatim Array2D<amrex::Real, 1, N, 1, K> mat; \endverbatim
745 : * and then perform the summation for each element of the resulting
746 : * matrix.
747 : * \verbatim
748 : for (int j = 1; j <= N; ++j) {
749 : for (int k = 1; k <= K; ++k) {
750 : mat(j,k) = array.sum(0,j,k)
751 : }
752 : }
753 : \endverbatim
754 : * In this example, the axis is 0 and the location indices are \c loc0 = \c j
755 : * and \c loc1 = \c k. For axis = 1, the location indices are treated as
756 : * \c loc0 = \c i and \c loc1 = \c k; for axis = 2, \c loc0 = \c j and \c loc1 = \c k.
757 : *
758 : */
759 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
760 : constexpr T sum (int axis, int loc0, int loc1) const noexcept
761 : {
762 : T s = 0;
763 : if (axis == 0) {
764 : int j = loc0;
765 : int k = loc1;
766 : for (int i = XLO; i <= XHI; ++i) {
767 : s += this->operator()(i,j,k);
768 : }
769 : } else if (axis == 1) {
770 : int i = loc0;
771 : int k = loc1;
772 : for (int j = YLO; j <= YHI; ++j) {
773 : s += this->operator()(i,j,k);
774 : }
775 : } else if (axis == 2) {
776 : int i = loc0;
777 : int j = loc1;
778 : for (int k = ZLO; k <= ZHI; ++k) {
779 : s += this->operator()(i,j,k);
780 : }
781 : }
782 : return s;
783 : }
784 :
785 : /**
786 : * When called without any arguments, returns the product of all
787 : * elements in the Array3D object.
788 : */
789 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
790 : constexpr T product () const noexcept
791 : {
792 : T p = 1;
793 : for (int i = 0; i < (XHI-XLO+1)*(YHI-YLO+1)*(ZHI-ZLO+1); ++i) {
794 : p *= arr[i];
795 : }
796 : return p;
797 : }
798 :
799 :
800 : /**
801 : * When called with three arguments, performs a product reduction over
802 : * the specified \c axis, for a particular set of location indices \c loc0
803 : * and \c loc1.
804 : *
805 : * \param axis The dimension to reduce (0 for \a x dimension,
806 : * 1 for \a y dimension, 2 for \a z dimension)
807 : * \param loc0 The appropriate location index (either \c i or \c j)
808 : * \param loc1 The appropriate location index (either \c j or \c k)
809 : *
810 : * This can be used, for instance, to calculate the sum over the \a z
811 : * dimension of an Array3D object that was instantiated as
812 : * \verbatim Array3D<amrex::Real, 1, M, 1, N, 1, K> array; \endverbatim
813 : *
814 : * One could instantiate an Array2D object to hold the results,
815 : * \verbatim Array2D<amrex::Real, 1, M, 1, N> mat; \endverbatim
816 : * and then perform the summation for each element of the resulting
817 : * matrix.
818 : * \verbatim
819 : for (int j = 1; j <= N; ++j) {
820 : for (int i = 1; i <= M; ++i) {
821 : mat(i,j) = array.sum(2,i,j)
822 : }
823 : }
824 : \endverbatim
825 : * In this example, the axis is 2 and the location indices are \c loc0 = \c i
826 : * and \c loc1 = \c j. For axis = 0, the location indices are treated as
827 : * \c loc0 = \c j and \c loc1 = \c k; for axis = 1, \c loc0 = \c i and \c loc1 = \c k.
828 : *
829 : */
830 : [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
831 : constexpr T product (const int axis, const int loc0, const int loc1) const noexcept
832 : {
833 : T p = 1;
834 : if (axis == 0) {
835 : int j = loc0;
836 : int k = loc1;
837 : for (int i = XLO; i <= XHI; ++i) {
838 : p *= this->operator()(i,j,k);
839 : }
840 : } else if (axis == 1) {
841 : int i = loc0;
842 : int k = loc1;
843 : for (int j = YLO; j <= YHI; ++j) {
844 : p *= this->operator()(i,j,k);
845 : }
846 : } else if (axis == 2) {
847 : int i = loc0;
848 : int j = loc1;
849 : for (int k = ZLO; k <= ZHI; ++k) {
850 : p *= this->operator()(i,j,k);
851 : }
852 : }
853 : return p;
854 : }
855 :
856 : T arr[(XHI-XLO+1)*(YHI-YLO+1)*(ZHI-ZLO+1)];
857 : };
858 : }
859 :
860 : namespace amrex
861 : {
862 : template <class T, typename = typename T::FABType>
863 : std::array<T*,AMREX_SPACEDIM> GetArrOfPtrs (std::array<T,AMREX_SPACEDIM>& a) noexcept
864 : {
865 : return {{AMREX_D_DECL(a.data(), a.data()+1, a.data()+2)}};
866 : }
867 :
868 : template <class T>
869 : std::array<T*,AMREX_SPACEDIM> GetArrOfPtrs (const std::array<std::unique_ptr<T>,AMREX_SPACEDIM>& a) noexcept
870 : {
871 : return {{AMREX_D_DECL(a[0].get(), a[1].get(), a[2].get())}};
872 : }
873 :
874 : template <class T>
875 : std::array<T const*,AMREX_SPACEDIM> GetArrOfConstPtrs (const std::array<T,AMREX_SPACEDIM>& a) noexcept
876 : {
877 : return {{AMREX_D_DECL(a.data(), a.data()+1, a.data()+2)}};
878 : }
879 :
880 : template <class T>
881 : std::array<T const*,AMREX_SPACEDIM> GetArrOfConstPtrs (const std::array<T*,AMREX_SPACEDIM>& a) noexcept
882 : {
883 : return {{AMREX_D_DECL(a[0], a[1], a[2])}};
884 : }
885 :
886 : template <class T>
887 : std::array<T const*,AMREX_SPACEDIM> GetArrOfConstPtrs (const std::array<std::unique_ptr<T>,AMREX_SPACEDIM>& a) noexcept
888 : {
889 : return {{AMREX_D_DECL(a[0].get(), a[1].get(), a[2].get())}};
890 : }
891 :
892 : }
893 :
894 : namespace amrex
895 : {
896 : inline XDim3 makeXDim3 (const Array<Real,AMREX_SPACEDIM>& a) noexcept
897 : {
898 : #if (AMREX_SPACEDIM == 1)
899 : return XDim3{a[0], 0., 0.};
900 : #elif (AMREX_SPACEDIM == 2)
901 : return XDim3{a[0], a[1], 0.};
902 : #else
903 : return XDim3{a[0], a[1], a[2]};
904 : #endif
905 : }
906 : }
907 :
908 : #endif
|