alpaka
Abstraction Library for Parallel Kernel Acceleration
Loading...
Searching...
No Matches
BoundaryIter.hpp
Go to the documentation of this file.
1/* Copyright 2025 Anton Reinhard
2 * SPDX-License-Identifier: MPL-2.0
3 */
4
5#pragma once
6
7#include "alpaka/CVec.hpp"
8#include "alpaka/Vec.hpp"
9#include "alpaka/api/api.hpp"
11#include "alpaka/concepts.hpp"
13#include "alpaka/utility.hpp"
14
15#include <ostream>
16
17namespace alpaka
18{
19
20 /**
21 * @brief An enum representing the different types of boundary, with LOWER, MIDDLE, and UPPER being valid states,
22 * and OOB being invalid (out-of-bounds).
23 */
24 enum class BoundaryType : uint32_t
25 {
30 };
31
32 /**
33 * @brief An n-dimensional boundary direction. Encodes a single unique boundary of an nD volume, e.g., a specific
34 * corner of a 2D plane or a side of a 3D cube.
35 *
36 * See also: @ref BoundaryDirectionsContainer
37 *
38 * @tparam T_dim The dimensionality of the volume that this is a boundary direction for.
39 * @tparam T_LowHaloVec The vector type used for the lower halo sizes.
40 * @tparam T_UpHaloVec The vector type used for the upper halo sizes.
41 */
42 template<uint32_t T_dim, concepts::Vector T_LowHaloVec, concepts::Vector T_UpHaloVec>
44 {
46
48 T_LowHaloVec lowerHaloSize;
49 T_UpHaloVec upperHaloSize;
50
52 concepts::Vector auto const& boundaries,
53 T_LowHaloVec const& lower_halo_sizes,
54 T_UpHaloVec const& upper_halo_sizes)
55 : data(boundaries)
56 , lowerHaloSize(lower_halo_sizes)
57 , upperHaloSize(upper_halo_sizes)
58 {
59 }
60
61 /** @brief The dimensionality of the whole volume that this is a boundary direction for. Not to be confused
62 * with boundaryDimensionality().
63 */
64 [[nodiscard]] static constexpr uint32_t dim()
65 {
66 return T_dim;
67 }
68
69 /** @brief The dimensionality of the boundary direction. For example, a vertex (corner) of a 3D-volume (cube)
70 * is 0-dimensional. See also the functions isVertex(), isEdge(), etc.
71 */
72 [[nodiscard]] constexpr uint32_t boundaryDimensionality() const
73 {
74 uint32_t c = 0;
75 for(uint32_t i = 0; i < T_dim; ++i)
76 {
78 ++c;
79 }
80 return c;
81 }
82
83 /** @brief Return true if this boundary direction describes a vertex, for example the corner of a plane.
84 */
85 [[nodiscard]] constexpr bool isVertex() const
86 {
87 return boundaryDimensionality() == 0;
88 }
89
90 /** @brief Return true if this boundary direction describes an edge, for example any of the 12 edges of a cube.
91 */
92 [[nodiscard]] constexpr bool isEdge() const
93 {
94 return boundaryDimensionality() == 1;
95 }
96
97 /** @brief Return true if this boundary direction describes a face, for example any of the 6 sides of a cube.
98 */
99 [[nodiscard]] constexpr bool isFace() const
100 {
101 return boundaryDimensionality() == 2;
102 }
103
104 /** @brief Return true if this boundary direction describes a cell, for example the interior of a cube or one
105 * of the 8 cells in a tesseract.
106 */
107 [[nodiscard]] constexpr bool isCell() const
108 {
109 return boundaryDimensionality() == 3;
110 }
111
112 /** @brief Return true if this boundary direction describes the interior of a volume, like the 2D interior of a
113 * plane or the 3D interior of a cube.
114 */
115 [[nodiscard]] constexpr bool isInterior() const
116 {
117 return boundaryDimensionality() == dim();
118 }
119
120 [[nodiscard]] constexpr auto operator<=>(BoundaryDirection const&) const = default;
121 };
122
123 /**
124 * @brief The iterator type for @ref BoundaryDirectionsContainer.
125 *
126 * @tparam T_dim The dimensionality of the volume that this is a boundary direction iterator for.
127 * @tparam T_LowHaloVec The vector type used for the lower halo sizes.
128 * @tparam T_UpHaloVec The vector type used for the upper halo sizes.
129 */
130 template<uint32_t T_dim, concepts::Vector T_LowHaloVec, concepts::Vector T_UpHaloVec>
132 {
134
135 using difference_type = std::ptrdiff_t;
140 using const_pointer = value_type const*;
141
143 T_BoundaryVec const& boundaries,
144 T_LowHaloVec const& lower_halo_sizes,
145 T_UpHaloVec const& upper_halo_sizes)
146 : boundaries(boundaries, lower_halo_sizes, upper_halo_sizes)
147 , lowerHaloSizes(lower_halo_sizes)
148 , upperHaloSizes(upper_halo_sizes)
149 {
150 }
151
152 [[nodiscard]] constexpr const_reference& operator*() const
153 {
154 return boundaries;
155 }
156
157 [[nodiscard]] constexpr reference& operator*()
158 {
159 return boundaries;
160 }
161
162 constexpr auto& operator++()
163 {
164 uint32_t i = T_dim - 1;
165 bool oob = true;
166 while(i != static_cast<uint32_t>(-1))
167 {
168 switch(boundaries.data[i])
169 {
171 boundaries.data[i] = BoundaryType::MIDDLE;
172 i = static_cast<uint32_t>(-1);
173 oob = false;
174 break;
176 boundaries.data[i] = BoundaryType::UPPER;
177 i = static_cast<uint32_t>(-1);
178 oob = false;
179 break;
181 boundaries.data[i] = BoundaryType::LOWER;
182 --i;
183 break;
185 [[fallthrough]];
186 default:
187 constexpr bool onHost = std::is_same_v<api::Host, ALPAKA_TYPEOF(thisApi())>;
188 if constexpr(onHost)
189 assert(false);
190 else
191 ALPAKA_ASSERT_ACC(false);
192 }
193 }
194 if(oob)
195 {
196 boundaries
197 = {Vec<BoundaryType, T_dim>([](int) { return BoundaryType::OOB; }),
198 lowerHaloSizes,
199 upperHaloSizes};
200 }
201 return *this;
202 }
203
204 [[nodiscard]] static consteval auto dim()
205 {
206 return T_dim;
207 }
208
209 [[nodiscard]] constexpr auto operator<=>(BoundaryDirectionIter const&) const = default;
210
211 private:
213
214 T_LowHaloVec lowerHaloSizes;
215 T_UpHaloVec upperHaloSizes;
216 };
217
218 /**
219 * @brief A container for boundary directions of an n-dimensional volume.
220 *
221 * This class implements `begin()`, `end()`, and `length()`, and can be iterated over. This is useful for stencil
222 * codes, where boundary conditions exist, that need to only be applied to elements on the borders of memory. To
223 * create a BoundaryDirectionsContainer for a memory object, see @ref makeBoundaryDirIterator.
224 *
225 * A 0D boundary direction is a single value, a 1D boundary direction is a "line", for example edges of a cube, a
226 * 2D boundary direction is a "plane", for example the sides of a cube.
227 *
228 * For example, a 1-dimensional (1D) volume has two 0D ends and a 1D center. A 2D volume has 4 0D corners, 4 1D
229 * edges, and one 2D center. In general, there are 3^n boundaries for an nD volume.
230 *
231 * @tparam T_dim The dimensionality of the volume that this contains boundaries for.
232 * @tparam T_LowHaloVec The vector type used for the lower halo sizes.
233 * @tparam T_UpHaloVec The vector type used for the upper halo sizes.
234 */
235 template<uint32_t T_dim, concepts::Vector T_LowHaloVec, concepts::Vector T_UpHaloVec>
237 {
238 static_assert(T_dim > 0, "0 Dimension Boundary Direction Container is not defined");
239
240 constexpr BoundaryDirectionsContainer(T_LowHaloVec const& lowerHaloSizes, T_UpHaloVec const& upperHaloSizes)
241 : m_lowerHaloSizes(lowerHaloSizes)
242 , m_upperHaloSizes(upperHaloSizes)
243 {
244 }
245
247 {
250 m_lowerHaloSizes,
251 m_upperHaloSizes};
252 }
253
255 {
257 Vec<BoundaryType, T_dim>([](int) { return BoundaryType::OOB; }),
258 m_lowerHaloSizes,
259 m_upperHaloSizes};
260 }
261
262 [[nodiscard]] static consteval uint32_t length()
263 {
264 return ipow(3u, T_dim);
265 }
266
267 [[nodiscard]] static consteval auto dim()
268 {
269 return T_dim;
270 }
271
272 private:
273 T_LowHaloVec const m_lowerHaloSizes;
274 T_UpHaloVec const m_upperHaloSizes;
275 };
276
277 template<concepts::Vector LowHaloVecType, concepts::Vector UpHaloVecType>
278 BoundaryDirectionsContainer(LowHaloVecType const& lowerHalos, UpHaloVecType const& upperHalos)
279 -> BoundaryDirectionsContainer<LowHaloVecType::dim(), LowHaloVecType, UpHaloVecType>;
280
281 /** @brief Construct and return a single @ref BoundaryDirection specifying the middle of a volume.
282 */
283 template<uint32_t T_dim>
284 [[nodiscard]] constexpr auto makeCoreBoundaryDirection(
285 concepts::Vector auto const& lowerHalos,
286 concepts::Vector auto const& upperHalos)
287 {
288 return BoundaryDirection<T_dim, ALPAKA_TYPEOF(lowerHalos), ALPAKA_TYPEOF(upperHalos)>{
290 lowerHalos,
291 upperHalos};
292 }
293
294 /** @brief Construct and return a single @ref BoundaryDirection specifying the middle of a volume with symmetric
295 * halos.
296 */
297 template<uint32_t T_dim>
298 [[nodiscard]] constexpr auto makeCoreBoundaryDirection(concepts::Vector auto const& halos)
299 {
300 return BoundaryDirection<T_dim, ALPAKA_TYPEOF(halos), ALPAKA_TYPEOF(halos)>{
302 halos,
303 halos};
304 }
305
306 /**
307 * @brief Construct and return a single @ref BoundaryDirection specifying the middle of a volume with all halo
308 * sizes set to 1.
309 */
310 template<uint32_t T_dim>
315
316 /** @brief Construct and return a @ref BoundaryDirectionsContainer. This container can be iterated over.
317 *
318 * This constructor uses a default halo size of 1 everywhere.
319 *
320 * @tparam T_dim The dimensionality of the container.
321 */
322 template<uint32_t T_dim>
323 [[nodiscard]] constexpr auto makeBoundaryDirIterator()
324 {
327 return BoundaryDirectionsContainer{lowerHalos, upperHalos};
328 }
329
330 /** @brief Construct and return a boundary direction container with the given halo sizes.
331 * This container can be iterated over. See BoundaryDirectionsContainer.
332 * The dimensionality is inferred from the given haloSizes.
333 *
334 * @param haloSizes The halo sizes per dimension. The halos are used for both "ends" of each dimension
335 * symmetrically.
336 */
337 [[nodiscard]] constexpr auto makeBoundaryDirIterator(concepts::Vector auto const& haloSizes)
338 {
339 return BoundaryDirectionsContainer{haloSizes, haloSizes};
340 }
341
342 /** @brief Construct and return a @ref BoundaryDirectionsContainer with the given halo sizes.
343 * This container can be iterated over.
344 * The dimensionality is inferred from the given halo sizes, which are asserted to be identical.
345 *
346 * @param lowerHaloSizes The lower end halo sizes per dimension. These are the halos from 0 in each dimension.
347 * @param upperHaloSizes The upper end halo sizes per dimension. These are the halos to `size()` in each dimension.
348 */
349 [[nodiscard]] constexpr auto makeBoundaryDirIterator(
350 concepts::Vector auto const& lowerHaloSizes,
351 concepts::Vector auto const& upperHaloSizes)
352 {
353 static_assert(
354 ALPAKA_TYPEOF(lowerHaloSizes)::dim() == ALPAKA_TYPEOF(upperHaloSizes)::dim(),
355 "dimension mismatch");
356 return BoundaryDirectionsContainer{lowerHaloSizes, upperHaloSizes};
357 }
358
359 /** @brief Construct and return a @ref BoundaryDirectionsContainer for the given view with default (size 1) halo
360 * sizes. This container can be iterated over.
361 * For custom halo sizes, use one of the other overloads.
362 *
363 * @param view The given view; only the dimension of the view matters.
364 */
365 [[nodiscard]] constexpr auto makeBoundaryDirIterator(concepts::IView auto const& view)
366 {
368 }
369
370 namespace trait
371 {
372 template<typename T>
373 struct IsBoundaryDirection : std::false_type
374 {
375 };
376
377 template<uint32_t T_dim, concepts::Vector T_LowHaloVec, concepts::Vector T_UpHaloVec>
378 requires(T_dim == T_LowHaloVec::dim() && T_dim == T_UpHaloVec::dim())
382 } // namespace trait
383
384 template<typename T>
386
387 namespace concepts
388 {
389 /** @brief Concept checking whether T is a boundary direction.
390 */
391 template<typename T>
393 } // namespace concepts
394
395 std::ostream& operator<<(std::ostream& os, concepts::BoundaryDirection auto const& bd)
396 {
397 for(uint32_t i = 0; i < bd.dim(); ++i)
398 {
399 switch(bd.data[i])
400 {
402 os << 'v';
403 break;
405 os << '-';
406 break;
408 os << '^';
409 break;
411 [[fallthrough]];
412 default:
413 os << 'x';
414 break;
415 }
416 }
417
418 if(bd.isVertex())
419 os << " (vertex) ";
420 if(bd.isEdge())
421 os << " (edge) ";
422 if(bd.isFace())
423 os << " (face) ";
424 if(bd.isCell())
425 os << " (cell) ";
426 if(bd.boundaryDimensionality() >= 4)
427 os << " (" << bd.boundaryDimensionality() << "D volume)";
428
429 return os;
430 }
431} // namespace alpaka
#define ALPAKA_ASSERT_ACC(...)
ALPAKA_ASSERT_ACC is an assert-like macro.
Definition Assert.hpp:53
#define ALPAKA_TYPEOF(...)
Get the type of instance.
Definition common.hpp:154
Concept checking whether T is a boundary direction.
Interface concept for objects describing api-related multidimensional memory access.
Definition IView.hpp:56
Concept to check if a type is a vector.
Definition Vec.hpp:54
Functionality which is usable on the host CPU controller thread.
Definition api.hpp:40
main alpaka namespace.
Definition alpaka.hpp:76
std::ostream & operator<<(std::ostream &os, concepts::BoundaryDirection auto const &bd)
BoundaryDirectionsContainer(LowHaloVecType const &lowerHalos, UpHaloVecType const &upperHalos) -> BoundaryDirectionsContainer< LowHaloVecType::dim(), LowHaloVecType, UpHaloVecType >
constexpr auto ipow(std::integral auto const base, std::integral auto const exponent)
Helper function calculating the integer power for the given base and exponent.
Definition utility.hpp:124
constexpr bool isBoundaryDirection_v
consteval auto fillCVec()
Create and return a CVector of some length, filled with the given value.
Definition CVec.hpp:153
constexpr auto thisApi()
provides the API used during the execution of the current code path
Definition api.hpp:26
BoundaryType
An enum representing the different types of boundary, with LOWER, MIDDLE, and UPPER being valid state...
consteval auto makeCoreBoundaryDirection()
Construct and return a single BoundaryDirection specifying the middle of a volume with all halo sizes...
constexpr auto makeBoundaryDirIterator()
Construct and return a BoundaryDirectionsContainer.
STL namespace.
The iterator type for BoundaryDirectionsContainer.
Vec< BoundaryType, T_dim > T_BoundaryVec
value_type const * const_pointer
constexpr const_reference & operator*() const
BoundaryDirection< T_dim, T_LowHaloVec, T_UpHaloVec > value_type
constexpr auto operator<=>(BoundaryDirectionIter const &) const =default
value_type const & const_reference
constexpr reference & operator*()
constexpr BoundaryDirectionIter(T_BoundaryVec const &boundaries, T_LowHaloVec const &lower_halo_sizes, T_UpHaloVec const &upper_halo_sizes)
static consteval auto dim()
An n-dimensional boundary direction.
constexpr uint32_t boundaryDimensionality() const
The dimensionality of the boundary direction.
constexpr bool isEdge() const
Return true if this boundary direction describes an edge, for example any of the 12 edges of a cube.
constexpr bool isVertex() const
Return true if this boundary direction describes a vertex, for example the corner of a plane.
constexpr BoundaryDirection(concepts::Vector auto const &boundaries, T_LowHaloVec const &lower_halo_sizes, T_UpHaloVec const &upper_halo_sizes)
static constexpr uint32_t dim()
The dimensionality of the whole volume that this is a boundary direction for.
constexpr bool isFace() const
Return true if this boundary direction describes a face, for example any of the 6 sides of a cube.
Vec< BoundaryType, T_dim > T_BoundaryVec
constexpr bool isInterior() const
Return true if this boundary direction describes the interior of a volume, like the 2D interior of a ...
constexpr bool isCell() const
Return true if this boundary direction describes a cell, for example the interior of a cube or one of...
constexpr auto operator<=>(BoundaryDirection const &) const =default
A container for boundary directions of an n-dimensional volume.
constexpr BoundaryDirectionIter< T_dim, T_LowHaloVec, T_UpHaloVec > end() const
constexpr BoundaryDirectionsContainer(T_LowHaloVec const &lowerHaloSizes, T_UpHaloVec const &upperHaloSizes)
static consteval uint32_t length()
constexpr BoundaryDirectionIter< T_dim, T_LowHaloVec, T_UpHaloVec > begin() const