8#include <compile_time_options.h>
14#include <deal.II/base/config.h>
15#include <deal.II/base/memory_space.h>
16#include <deal.II/base/parallel.h>
47 template <
typename ScalarNumber,
typename Functor,
typename... Args>
48 inline void cpu_simd_loop(
const std::string ®ion_name [[maybe_unused]],
50 const unsigned int left,
51 const unsigned int internal,
52 const unsigned int right,
55 Assert(left <= internal && internal <= right,
56 dealii::ExcMessage(
"Invalid index range: it must hold left <= "
57 "internal, internal <= right"));
59 if (!region_name.empty()) {
63 using VA = dealii::VectorizedArray<ScalarNumber>;
65 constexpr unsigned int stride_size = get_stride_size<VA>;
66 const unsigned int regular =
67 left + (internal - left) / stride_size * stride_size;
69#if defined(WITH_OPENMP)
76 for (
unsigned int i = left; i < regular; i += stride_size)
77 body(VA(), std::forward<Args>(args)..., i);
81 for (
unsigned int i = regular; i < right; i += 1)
82 body(ScalarNumber(), std::forward<Args>(args)..., i);
85#elif defined(WITH_DEAL_II_THREADS)
92 Assert((regular - left) % stride_size == 0, dealii::ExcInternalError());
93 dealii::parallel::apply_to_subranges(
95 (regular - left) / stride_size,
96 [&](
const unsigned int begin,
const unsigned int end) {
98 for (
unsigned int i = begin; i < end; ++i)
99 body(VA(), std::forward<Args>(args)..., left + stride_size * i);
103 dealii::parallel::apply_to_subranges(
106 [&](
const unsigned int begin,
const unsigned int end) {
108 for (
unsigned int i = begin; i < end; ++i)
109 body(ScalarNumber(), std::forward<Args>(args)..., i);
118 for (
unsigned int i = left; i < regular; i += stride_size)
119 body(VA(), std::forward<Args>(args)..., i);
122 for (
unsigned int i = regular; i < right; i += 1)
123 body(ScalarNumber(), std::forward<Args>(args)..., i);
127 if (!region_name.empty()) {
157 template <
typename ScalarNumber,
typename Functor,
typename... Args>
158 inline void gpu_loop(
const std::string ®ion_name,
160 const unsigned int left,
161 const unsigned int internal [[maybe_unused]],
162 const unsigned int right,
167 Assert(left <= internal && internal <= right,
168 dealii::ExcMessage(
"Invalid index range: it must hold left <= "
169 "internal, internal <= right"));
171 using MemorySpace = dealii::MemorySpace::Default;
172 using ExecutionSpace =
typename MemorySpace::kokkos_space::execution_space;
174 Kokkos::RangePolicy<ExecutionSpace, Kokkos::IndexType<unsigned int>>;
176 const auto exec = ExecutionSpace{};
178 if (!region_name.empty()) {
182 Kokkos::parallel_for(
184 Policy(exec, left, right),
185 KOKKOS_LAMBDA(
const unsigned int i) {
186 body(ScalarNumber(), args..., i);
191 if (!region_name.empty()) {
208 template <
typename MemorySpace,
209 typename ScalarNumber,
212 inline void loop(
const std::string ®ion_name,
214 const unsigned int left,
215 const unsigned int internal,
216 const unsigned int right,
219 using HostSpace = dealii::MemorySpace::Host;
220 using DefaultSpace = dealii::MemorySpace::Default;
221 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
222 std::is_same_v<MemorySpace, DefaultSpace>,
223 "Unexpected memory space");
225 if constexpr (std::is_same_v<MemorySpace, HostSpace>) {
226 cpu_simd_loop<ScalarNumber>(region_name,
231 std::forward<Args>(args)...);
233 gpu_loop<ScalarNumber>(region_name,
238 std::forward<Args>(args)...);
258 template <
typename ElementReducer>
268 , element_reducer_(typename ElementReducer::result_view_type())
273 :
ArrayReducer(values.data(), static_cast<unsigned int>(values.size()))
277 KOKKOS_INLINE_FUNCTION
281 element_reducer_.init(values[k]);
284 KOKKOS_INLINE_FUNCTION
288 element_reducer_.join(destination[k], source[k]);
291 template <
typename Contribution>
292 requires std::invocable<const Contribution &, unsigned int>
294 const Contribution &contribution)
const
297 element_reducer_.join(destination[k], contribution(k));
312 const ElementReducer element_reducer_;
324 template <
typename Reducer>
326 static constexpr bool is_array =
327 std::is_array_v<typename Reducer::value_type>;
328 using scalar_type = std::remove_extent_t<typename Reducer::value_type>;
330 std::conditional_t<is_array, std::vector<scalar_type>, scalar_type>
334 LocalResult(
const Reducer &reducer)
336 if constexpr (is_array)
337 storage.resize(reducer.value_count);
342 std::conditional_t<is_array, scalar_type *, scalar_type &> get()
344 if constexpr (is_array)
345 return storage.data();
353 using Unmanaged = Kokkos::MemoryTraits<Kokkos::Unmanaged>;
354 if constexpr (is_array)
355 return Kokkos::View<scalar_type *, Kokkos::HostSpace, Unmanaged>(
356 storage.data(), storage.size());
358 return Kokkos::View<scalar_type, Kokkos::HostSpace, Unmanaged>(
369 template <
typename Reducer,
typename Body>
370 struct ReductionFunctor : Reducer {
373 ReductionFunctor(
const Reducer &reducer,
const Body &body)
379 KOKKOS_INLINE_FUNCTION
380 void operator()(
const unsigned int i,
auto &&local_result)
const
382 Reducer::join(local_result, body(i));
404 template <
typename Reducer,
typename Functor,
typename... Args>
408 const Reducer &reducer,
409 const unsigned int left,
410 const unsigned int right,
415 dealii::ExcMessage(
"Invalid index range: it must hold left <= right"));
417 if (!region_name.empty()) {
421 using scalar_type = std::remove_extent_t<typename Reducer::value_type>;
423#if defined(WITH_OPENMP)
428 internal::LocalResult<Reducer> local_result(reducer);
431 for (
unsigned int i = left; i < right; ++i)
432 reducer.join(local_result.get(),
433 body(scalar_type(), std::forward<Args>(args)..., i));
436 reducer.join(reducer.reference(), local_result.get());
439#elif defined(WITH_DEAL_II_THREADS)
444 dealii::parallel::apply_to_subranges(
447 [&](
const unsigned int begin,
const unsigned int end) {
449 internal::LocalResult<Reducer> local_result(reducer);
451 for (
unsigned int i = begin; i < end; ++i)
452 reducer.join(local_result.get(),
453 body(scalar_type(), std::forward<Args>(args)..., i));
455 std::lock_guard<std::mutex> lock(mutex);
456 reducer.join(reducer.reference(), local_result.get());
464 for (
unsigned int i = left; i < right; ++i)
465 reducer.join(reducer.reference(),
466 body(scalar_type(), std::forward<Args>(args)..., i));
470 if (!region_name.empty()) {
496 template <
typename Reducer,
typename Functor,
typename... Args>
499 const Reducer &reducer,
500 const unsigned int left,
501 const unsigned int right,
508 dealii::ExcMessage(
"Invalid index range: it must hold left <= right"));
510 using scalar_type = std::remove_extent_t<typename Reducer::value_type>;
512 using MemorySpace = dealii::MemorySpace::Default;
513 using ExecutionSpace =
typename MemorySpace::kokkos_space::execution_space;
515 Kokkos::RangePolicy<ExecutionSpace, Kokkos::IndexType<unsigned int>>;
517 const auto exec = ExecutionSpace{};
519 const auto kernel = KOKKOS_LAMBDA(
const unsigned int i)
521 return body(scalar_type(), args..., i);
525 internal::ReductionFunctor<Reducer, decltype(kernel)>(reducer, kernel);
527 internal::LocalResult<Reducer> result(reducer);
529 if (!region_name.empty()) {
533 Kokkos::parallel_reduce(
534 region_name, Policy(exec, left, right), functor, result.view());
538 if (!region_name.empty()) {
542 reducer.join(reducer.reference(), result.get());
588 template <
typename MemorySpace,
594 const Reducer &reducer,
595 const unsigned int left,
596 const unsigned int right,
599 using HostSpace = dealii::MemorySpace::Host;
600 using DefaultSpace = dealii::MemorySpace::Default;
601 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
602 std::is_same_v<MemorySpace, DefaultSpace>,
603 "Unexpected memory space");
605 if constexpr (std::is_same_v<MemorySpace, HostSpace>) {
607 region_name, body, reducer, left, right, std::forward<Args>(args)...);
610 region_name, body, reducer, left, right, std::forward<Args>(args)...);
#define LIKWID_MARKER_START(opt)
#define LIKWID_MARKER_STOP(opt)
#define NVTX_MARKER_START(opt)
#define NVTX_MARKER_STOP(opt)
void gpu_reduction_loop(const std::string ®ion_name, const Functor &body, const Reducer &reducer, const unsigned int left, const unsigned int right, Args &&...args)
void gpu_loop(const std::string ®ion_name, const Functor &body, const unsigned int left, const unsigned int internal, const unsigned int right, Args &&...args)
void loop(const std::string ®ion_name, const Functor &body, const unsigned int left, const unsigned int internal, const unsigned int right, Args &&...args)
void reduction_loop(const std::string ®ion_name, const Functor &body, const Reducer &reducer, const unsigned int left, const unsigned int right, Args &&...args)
void cpu_simd_loop(const std::string ®ion_name, const Functor &body, const unsigned int left, const unsigned int internal, const unsigned int right, Args &&...args)
void cpu_reduction_loop(const std::string ®ion_name, const Functor &body, const Reducer &reducer, const unsigned int left, const unsigned int right, Args &&...args)
typename ElementReducer::value_type scalar_type
ArrayReducer(scalar_type *data, const unsigned int n)
scalar_type * reference() const
KOKKOS_INLINE_FUNCTION void init(scalar_type *values) const
ArrayReducer(std::vector< scalar_type > &values)
const unsigned int value_count
KOKKOS_INLINE_FUNCTION void join(scalar_type *destination, const scalar_type *source) const
KOKKOS_INLINE_FUNCTION void join(scalar_type *destination, const Contribution &contribution) const