8#include <ryujin/base/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>
49 template <
typename ScalarNumber,
typename Functor,
typename... Args>
50 inline void cpu_simd_loop(
const std::string ®ion_name [[maybe_unused]],
52 const unsigned int left,
53 const unsigned int internal,
54 const unsigned int right,
57 Assert(left <= internal && internal <= right,
58 dealii::ExcMessage(
"Invalid index range: it must hold left <= "
59 "internal, internal <= right"));
61 if (!region_name.empty()) {
65 using VA = dealii::VectorizedArray<ScalarNumber>;
67 constexpr unsigned int stride_size = VA::size();
68 const unsigned int regular =
69 left + (internal - left) / stride_size * stride_size;
71#if defined(WITH_OPENMP)
78 for (
unsigned int i = left; i < regular; i += stride_size)
79 body(VA(), std::forward<Args>(args)..., i);
83 for (
unsigned int i = regular; i < right; i += 1)
84 body(ScalarNumber(), std::forward<Args>(args)..., i);
87#elif defined(WITH_DEAL_II_THREADS)
94 Assert((regular - left) % stride_size == 0, dealii::ExcInternalError());
95 dealii::parallel::apply_to_subranges(
97 (regular - left) / stride_size,
98 [&](
const unsigned int begin,
const unsigned int end) {
100 for (
unsigned int i = begin; i < end; ++i)
101 body(VA(), std::forward<Args>(args)..., left + stride_size * i);
105 dealii::parallel::apply_to_subranges(
108 [&](
const unsigned int begin,
const unsigned int end) {
110 for (
unsigned int i = begin; i < end; ++i)
111 body(ScalarNumber(), std::forward<Args>(args)..., i);
120 for (
unsigned int i = left; i < regular; i += stride_size)
121 body(VA(), std::forward<Args>(args)..., i);
124 for (
unsigned int i = regular; i < right; i += 1)
125 body(ScalarNumber(), std::forward<Args>(args)..., i);
129 if (!region_name.empty()) {
161 template <
typename ScalarNumber,
typename Functor,
typename... Args>
162 inline void gpu_loop(
const std::string ®ion_name,
164 const unsigned int left,
165 const unsigned int internal [[maybe_unused]],
166 const unsigned int right,
171 Assert(left <= internal && internal <= right,
172 dealii::ExcMessage(
"Invalid index range: it must hold left <= "
173 "internal, internal <= right"));
175 using MemorySpace = dealii::MemorySpace::Default;
176 using ExecutionSpace =
typename MemorySpace::kokkos_space::execution_space;
178 Kokkos::RangePolicy<ExecutionSpace, Kokkos::IndexType<unsigned int>>;
180 const auto exec = ExecutionSpace{};
182 if (!region_name.empty()) {
186 Kokkos::parallel_for(
188 Policy(exec, left, right),
189 KOKKOS_LAMBDA(
const unsigned int i) {
190 body(ScalarNumber(), args..., i);
195 if (!region_name.empty()) {
214 template <
typename MemorySpace,
215 typename ScalarNumber,
218 inline void loop(
const std::string ®ion_name,
220 const unsigned int left,
221 const unsigned int internal,
222 const unsigned int right,
225 using HostSpace = dealii::MemorySpace::Host;
226 using DefaultSpace = dealii::MemorySpace::Default;
227 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
228 std::is_same_v<MemorySpace, DefaultSpace>,
229 "Unexpected memory space");
231 if constexpr (std::is_same_v<MemorySpace, HostSpace>) {
232 cpu_simd_loop<ScalarNumber>(region_name,
237 std::forward<Args>(args)...);
239 gpu_loop<ScalarNumber>(region_name,
244 std::forward<Args>(args)...);
266 template <
typename ElementReducer>
276 , element_reducer_(typename ElementReducer::result_view_type())
281 :
ArrayReducer(values.data(), static_cast<unsigned int>(values.size()))
285 KOKKOS_INLINE_FUNCTION
289 element_reducer_.init(values[k]);
292 KOKKOS_INLINE_FUNCTION
296 element_reducer_.join(destination[k], source[k]);
299 template <
typename Contribution>
300 requires std::invocable<const Contribution &, unsigned int>
302 const Contribution &contribution)
const
305 element_reducer_.join(destination[k], contribution(k));
320 const ElementReducer element_reducer_;
332 template <
typename Reducer>
334 static constexpr bool is_array =
335 std::is_array_v<typename Reducer::value_type>;
336 using scalar_type = std::remove_extent_t<typename Reducer::value_type>;
338 std::conditional_t<is_array, std::vector<scalar_type>, scalar_type>
342 LocalResult(
const Reducer &reducer)
344 if constexpr (is_array)
345 storage.resize(reducer.value_count);
350 std::conditional_t<is_array, scalar_type *, scalar_type &> get()
352 if constexpr (is_array)
353 return storage.data();
361 using Unmanaged = Kokkos::MemoryTraits<Kokkos::Unmanaged>;
362 if constexpr (is_array)
363 return Kokkos::View<scalar_type *, Kokkos::HostSpace, Unmanaged>(
364 storage.data(), storage.size());
366 return Kokkos::View<scalar_type, Kokkos::HostSpace, Unmanaged>(
377 template <
typename Reducer,
typename Body>
378 struct ReductionFunctor : Reducer {
381 ReductionFunctor(
const Reducer &reducer,
const Body &body)
387 KOKKOS_INLINE_FUNCTION
388 void operator()(
const unsigned int i,
auto &&local_result)
const
390 Reducer::join(local_result, body(i));
412 template <
typename Reducer,
typename Functor,
typename... Args>
416 const Reducer &reducer,
417 const unsigned int left,
418 const unsigned int right,
423 dealii::ExcMessage(
"Invalid index range: it must hold left <= right"));
425 if (!region_name.empty()) {
429 using scalar_type = std::remove_extent_t<typename Reducer::value_type>;
431#if defined(WITH_OPENMP)
436 internal::LocalResult<Reducer> local_result(reducer);
439 for (
unsigned int i = left; i < right; ++i)
440 reducer.join(local_result.get(),
441 body(scalar_type(), std::forward<Args>(args)..., i));
444 reducer.join(reducer.reference(), local_result.get());
447#elif defined(WITH_DEAL_II_THREADS)
452 dealii::parallel::apply_to_subranges(
455 [&](
const unsigned int begin,
const unsigned int end) {
457 internal::LocalResult<Reducer> local_result(reducer);
459 for (
unsigned int i = begin; i < end; ++i)
460 reducer.join(local_result.get(),
461 body(scalar_type(), std::forward<Args>(args)..., i));
463 std::lock_guard<std::mutex> lock(mutex);
464 reducer.join(reducer.reference(), local_result.get());
472 for (
unsigned int i = left; i < right; ++i)
473 reducer.join(reducer.reference(),
474 body(scalar_type(), std::forward<Args>(args)..., i));
478 if (!region_name.empty()) {
504 template <
typename Reducer,
typename Functor,
typename... Args>
507 const Reducer &reducer,
508 const unsigned int left,
509 const unsigned int right,
516 dealii::ExcMessage(
"Invalid index range: it must hold left <= right"));
518 using scalar_type = std::remove_extent_t<typename Reducer::value_type>;
520 using MemorySpace = dealii::MemorySpace::Default;
521 using ExecutionSpace =
typename MemorySpace::kokkos_space::execution_space;
523 Kokkos::RangePolicy<ExecutionSpace, Kokkos::IndexType<unsigned int>>;
525 const auto exec = ExecutionSpace{};
527 const auto kernel = KOKKOS_LAMBDA(
const unsigned int i)
529 return body(scalar_type(), args..., i);
533 internal::ReductionFunctor<Reducer, decltype(kernel)>(reducer, kernel);
535 internal::LocalResult<Reducer> result(reducer);
537 if (!region_name.empty()) {
541 Kokkos::parallel_reduce(
542 region_name, Policy(exec, left, right), functor, result.view());
546 if (!region_name.empty()) {
550 reducer.join(reducer.reference(), result.get());
596 template <
typename MemorySpace,
602 const Reducer &reducer,
603 const unsigned int left,
604 const unsigned int right,
607 using HostSpace = dealii::MemorySpace::Host;
608 using DefaultSpace = dealii::MemorySpace::Default;
609 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
610 std::is_same_v<MemorySpace, DefaultSpace>,
611 "Unexpected memory space");
613 if constexpr (std::is_same_v<MemorySpace, HostSpace>) {
615 region_name, body, reducer, left, right, std::forward<Args>(args)...);
618 region_name, body, reducer, left, right, std::forward<Args>(args)...);
#define LIKWID_MARKER_START(opt)
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)
#define LIKWID_MARKER_STOP(opt)
#define NVTX_MARKER_START(opt)
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)
#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 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_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