NeoN
A framework for CFD software
Loading...
Searching...
No Matches
parallelAlgorithms.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2023 - 2025 NeoN authors
2//
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include <Kokkos_Core.hpp>
8#include <type_traits>
9
10#include "NeoN/core/logging.hpp"
13
14namespace NeoN
15{
16
17
18template<typename ValueType>
19class Vector;
20
21
22// Concept to check if a callable is compatible with void(const size_t)
23template<typename Kernel>
24concept parallelForKernel = requires(Kernel t, size_t i) {
25 {
26 t(i)
27 } -> std::same_as<void>;
28};
29
30
31/* @brief calls fence if a logger is set */
32template<typename ExecutorType>
33void fenceIfLogger(const ExecutorType& exec)
34{
35 auto logger = getLogger(exec);
36 if (logger != nullptr)
37 {
38 fence(exec);
39 }
40}
41
42/* @brief execute parallelFor with concrete executor */
43template<typename ExecutorType, parallelForKernel Kernel>
45 const ExecutorType& exec, std::pair<localIdx, localIdx> range, Kernel kernel, std::string name
46)
47{
48 auto [start, end] = range;
49
50 if constexpr (std::is_same<std::remove_reference_t<ExecutorType>, SerialExecutor>::value)
51 {
52 for (localIdx i = start; i < end; i++)
53 {
54 kernel(i);
55 }
56 }
57 else
58 {
59 using runOn = typename ExecutorType::exec;
60 Kokkos::parallel_for(
61 name,
62 Kokkos::RangePolicy<runOn>(start, end),
63 KOKKOS_LAMBDA(const localIdx i) { kernel(i); }
64 );
65 }
66}
67
68
69/* @brief dispatch parallelFor based on executor variant type */
70template<parallelForKernel Kernel>
72 const NeoN::Executor& exec,
73 std::pair<localIdx, localIdx> range,
74 Kernel kernel,
75 std::string name = "parallelFor"
76)
77{
78 std::visit([&](const auto& e) { parallelFor(e, range, kernel, name); }, exec);
79}
80
81// Concept to check if a callable is compatible with ValueType(const size_t)
82template<typename Kernel, typename ValueType>
83concept parallelForContainerKernel = requires(Kernel t, ValueType val, size_t i) {
84 {
85 t(i)
86 } -> std::same_as<ValueType>;
87};
88
89template<
90 typename Executor,
91 template<typename>
92 class ContType,
93 typename ValueType,
96 const Executor& exec,
97 ContType<ValueType>& container,
98 Kernel kernel,
99 std::string name = "parallelFor"
100)
101{
102 auto view = container.view();
103 if constexpr (std::is_same<std::remove_reference_t<Executor>, SerialExecutor>::value)
104 {
105 for (localIdx i = 0; i < view.size(); i++)
106 {
107 view[i] = kernel(i);
108 }
109 }
110 else
111 {
112 using runOn = typename Executor::exec;
113 Kokkos::parallel_for(
114 name,
115 Kokkos::RangePolicy<runOn>(0, view.size()),
116 KOKKOS_LAMBDA(const localIdx i) { view[i] = kernel(i); }
117 );
118 }
119}
120
121template<
122 template<typename>
123 class ContType,
124 typename ValueType,
125 parallelForContainerKernel<ValueType> Kernel>
126void parallelFor(ContType<ValueType>& cont, Kernel kernel, std::string name = "parallelFor")
127{
128 std::visit([&](const auto& e) { parallelFor(e, cont, kernel, name); }, cont.exec());
129}
130
131template<typename Executor, typename Kernel, typename T>
133 [[maybe_unused]] const Executor& exec,
134 std::pair<localIdx, localIdx> range,
135 Kernel kernel,
136 T& value
137)
138{
139 auto [start, end] = range;
140 if constexpr (std::is_same<std::remove_reference_t<Executor>, SerialExecutor>::value)
141 {
142 for (localIdx i = start; i < end; i++)
143 {
144 if constexpr (Kokkos::is_reducer<T>::value)
145 {
146 kernel(i, value.reference());
147 }
148 else
149 {
150 kernel(i, value);
151 }
152 }
153 }
154 else
155 {
156 using runOn = typename Executor::exec;
157 Kokkos::parallel_reduce(
158 "parallelReduce", Kokkos::RangePolicy<runOn>(start, end), kernel, value
159 );
160 }
161}
162
163template<typename Kernel, typename T>
165 const NeoN::Executor& exec, std::pair<localIdx, localIdx> range, Kernel kernel, T& value
166)
167{
168 std::visit([&](const auto& e) { parallelReduce(e, range, kernel, value); }, exec);
169}
170
171
172template<typename Executor, typename ValueType, typename Kernel, typename T>
174 [[maybe_unused]] const Executor& exec, Vector<ValueType>& field, Kernel kernel, T& value
175)
176{
177 if constexpr (std::is_same<std::remove_reference_t<Executor>, SerialExecutor>::value)
178 {
179 localIdx fieldSize = field.size();
180 for (localIdx i = 0; i < fieldSize; i++)
181 {
182 if constexpr (Kokkos::is_reducer<T>::value)
183 {
184 kernel(i, value.reference());
185 }
186 else
187 {
188 kernel(i, value);
189 }
190 }
191 }
192 else
193 {
194 using runOn = typename Executor::exec;
195 Kokkos::parallel_reduce(
196 "parallelReduce", Kokkos::RangePolicy<runOn>(0, field.size()), kernel, value
197 );
198 }
199}
200
201template<typename ValueType, typename Kernel, typename T>
202void parallelReduce(Vector<ValueType>& field, Kernel kernel, T& value)
203{
204 std::visit([&](const auto& e) { parallelReduce(e, field, kernel, value); }, field.exec());
205}
206
207template<typename Executor, typename Kernel>
209 [[maybe_unused]] const Executor& exec, std::pair<localIdx, localIdx> range, Kernel kernel
210)
211{
212 auto [start, end] = range;
213 using runOn = typename Executor::exec;
214 Kokkos::parallel_scan("parallelScan", Kokkos::RangePolicy<runOn>(start, end), kernel);
215}
216
217template<typename Kernel>
218void parallelScan(const NeoN::Executor& exec, std::pair<localIdx, localIdx> range, Kernel kernel)
219{
220 std::visit([&](const auto& e) { parallelScan(e, range, kernel); }, exec);
221}
222
223template<typename Executor, typename Kernel, typename ReturnType>
225 [[maybe_unused]] const Executor& exec,
226 std::pair<localIdx, localIdx> range,
227 Kernel kernel,
228 ReturnType& returnValue
229)
230{
231 auto [start, end] = range;
232 using runOn = typename Executor::exec;
233 Kokkos::parallel_scan(
234 "parallelScan", Kokkos::RangePolicy<runOn>(start, end), kernel, returnValue
235 );
236}
237
238template<typename Kernel, typename ReturnType>
240 const NeoN::Executor& exec,
241 std::pair<localIdx, localIdx> range,
242 Kernel kernel,
243 ReturnType& returnValue
244)
245{
246 std::visit([&](const auto& e) { parallelScan(e, range, kernel, returnValue); }, exec);
247}
248
249} // namespace NeoN
Reference executor for serial CPU execution.
A class to contain the data and executors for a field and define some basic operations.
Definition vector.hpp:30
localIdx size() const
Gets the size of the field.
Definition vector.hpp:235
const Executor & exec() const
Gets the executor associated with the field.
Definition vector.hpp:229
Definition array.hpp:20
void fenceIfLogger(const ExecutorType &exec)
void fence(const Executor &exec)
Definition executor.hpp:22
std::shared_ptr< const Logging::BaseLogger > getLogger(const Executor &exec)
Definition executor.hpp:31
int32_t localIdx
Definition label.hpp:32
std::variant< SerialExecutor, CPUExecutor, GPUExecutor > Executor
Definition executor.hpp:19
void parallelReduce(const Executor &exec, std::pair< localIdx, localIdx > range, Kernel kernel, T &value)
const std::string & name(const NeoN::Document &doc)
Retrieves the name of a Document.
void parallelFor(const ExecutorType &exec, std::pair< localIdx, localIdx > range, Kernel kernel, std::string name)
void parallelScan(const Executor &exec, std::pair< localIdx, localIdx > range, Kernel kernel)