NeoFOAM
WIP Prototype of a modern OpenFOAM core
Loading...
Searching...
No Matches
parallelAlgorithms.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// SPDX-FileCopyrightText: 2023 NeoFOAM authors
3#pragma once
4
5#include <Kokkos_Core.hpp>
6#include <type_traits>
7
9
10namespace NeoFOAM
11{
12
13
14template<typename ValueType>
15class Field;
16
17
18// Concept to check if a callable is compatible with void(const size_t)
19template<typename Kernel>
20concept parallelForKernel = requires(Kernel t, size_t i) {
21 {
22 t(i)
23 } -> std::same_as<void>;
24};
25
26template<typename Executor, parallelForKernel Kernel>
28 [[maybe_unused]] const Executor& exec,
29 std::pair<size_t, size_t> range,
30 Kernel kernel,
31 std::string name = "parallelFor"
32)
33{
34 auto [start, end] = range;
35 if constexpr (std::is_same<std::remove_reference_t<Executor>, SerialExecutor>::value)
36 {
37 for (size_t i = start; i < end; i++)
38 {
39 kernel(i);
40 }
41 }
42 else
43 {
44 using runOn = typename Executor::exec;
45 Kokkos::parallel_for(
46 name,
47 Kokkos::RangePolicy<runOn>(start, end),
48 KOKKOS_LAMBDA(const size_t i) { kernel(i); }
49 );
50 }
51}
52
53
54template<parallelForKernel Kernel>
56 const NeoFOAM::Executor& exec,
57 std::pair<size_t, size_t> range,
58 Kernel kernel,
59 std::string name = "parallelFor"
60)
61{
62 std::visit([&](const auto& e) { parallelFor(e, range, kernel, name); }, exec);
63}
64
65// Concept to check if a callable is compatible with ValueType(const size_t)
66template<typename Kernel, typename ValueType>
67concept parallelForFieldKernel = requires(Kernel t, ValueType val, size_t i) {
68 {
69 t(i)
70 } -> std::same_as<ValueType>;
71};
72
73template<typename Executor, typename ValueType, parallelForFieldKernel<ValueType> Kernel>
75 [[maybe_unused]] const Executor& exec,
76 Field<ValueType>& field,
77 Kernel kernel,
78 std::string name = "parallelFor"
79)
80{
81 auto span = field.span();
82 if constexpr (std::is_same<std::remove_reference_t<Executor>, SerialExecutor>::value)
83 {
84 size_t fieldSize = field.size();
85 for (size_t i = 0; i < fieldSize; i++)
86 {
87 span[i] = kernel(i);
88 }
89 }
90 else
91 {
92 using runOn = typename Executor::exec;
93 Kokkos::parallel_for(
94 name,
95 Kokkos::RangePolicy<runOn>(0, field.size()),
96 KOKKOS_LAMBDA(const size_t i) { span[i] = kernel(i); }
97 );
98 }
99}
100
101template<typename ValueType, parallelForFieldKernel<ValueType> Kernel>
102void parallelFor(Field<ValueType>& field, Kernel kernel, std::string name = "parallelFor")
103{
104 std::visit([&](const auto& e) { parallelFor(e, field, kernel, name); }, field.exec());
105}
106
107template<typename Executor, typename Kernel, typename T>
109 [[maybe_unused]] const Executor& exec, std::pair<size_t, size_t> range, Kernel kernel, T& value
110)
111{
112 auto [start, end] = range;
113 if constexpr (std::is_same<std::remove_reference_t<Executor>, SerialExecutor>::value)
114 {
115 for (size_t i = start; i < end; i++)
116 {
117 if constexpr (Kokkos::is_reducer<T>::value)
118 {
119 kernel(i, value.reference());
120 }
121 else
122 {
123 kernel(i, value);
124 }
125 }
126 }
127 else
128 {
129 using runOn = typename Executor::exec;
130 Kokkos::parallel_reduce(
131 "parallelReduce", Kokkos::RangePolicy<runOn>(start, end), kernel, value
132 );
133 }
134}
135
136template<typename Kernel, typename T>
138 const NeoFOAM::Executor& exec, std::pair<size_t, size_t> range, Kernel kernel, T& value
139)
140{
141 return std::visit([&](const auto& e) { return parallelReduce(e, range, kernel, value); }, exec);
142}
143
144
145template<typename Executor, typename ValueType, typename Kernel, typename T>
147 [[maybe_unused]] const Executor& exec, Field<ValueType>& field, Kernel kernel, T& value
148)
149{
150 if constexpr (std::is_same<std::remove_reference_t<Executor>, SerialExecutor>::value)
151 {
152 size_t fieldSize = field.size();
153 for (size_t i = 0; i < fieldSize; i++)
154 {
155 if constexpr (Kokkos::is_reducer<T>::value)
156 {
157 kernel(i, value.reference());
158 }
159 else
160 {
161 kernel(i, value);
162 }
163 }
164 }
165 else
166 {
167 using runOn = typename Executor::exec;
168 Kokkos::parallel_reduce(
169 "parallelReduce", Kokkos::RangePolicy<runOn>(0, field.size()), kernel, value
170 );
171 }
172}
173
174template<typename ValueType, typename Kernel, typename T>
175void parallelReduce(Field<ValueType>& field, Kernel kernel, T& value)
176{
177 return std::visit(
178 [&](const auto& e) { return parallelReduce(e, field, kernel, value); }, field.exec()
179 );
180}
181
182template<typename Executor, typename Kernel>
184 [[maybe_unused]] const Executor& exec, std::pair<size_t, size_t> range, Kernel kernel
185)
186{
187 auto [start, end] = range;
188 using runOn = typename Executor::exec;
189 Kokkos::parallel_scan("parallelScan", Kokkos::RangePolicy<runOn>(start, end), kernel);
190}
191
192template<typename Kernel>
193void parallelScan(const NeoFOAM::Executor& exec, std::pair<size_t, size_t> range, Kernel kernel)
194{
195 std::visit([&](const auto& e) { parallelScan(e, range, kernel); }, exec);
196}
197
198template<typename Executor, typename Kernel, typename ReturnType>
200 [[maybe_unused]] const Executor& exec,
201 std::pair<size_t, size_t> range,
202 Kernel kernel,
203 ReturnType& returnValue
204)
205{
206 auto [start, end] = range;
207 using runOn = typename Executor::exec;
208 Kokkos::parallel_scan(
209 "parallelScan", Kokkos::RangePolicy<runOn>(start, end), kernel, returnValue
210 );
211}
212
213template<typename Kernel, typename ReturnType>
215 const NeoFOAM::Executor& exec,
216 std::pair<size_t, size_t> range,
217 Kernel kernel,
218 ReturnType& returnValue
219)
220{
221 return std::visit(
222 [&](const auto& e) { return parallelScan(e, range, kernel, returnValue); }, exec
223 );
224}
225
226
227} // namespace NeoFOAM
A class to contain the data and executors for a field and define some basic operations.
Definition field.hpp:49
size_t size() const
Gets the size of the field.
Definition field.hpp:355
const Executor & exec() const
Gets the executor associated with the field.
Definition field.hpp:349
std::span< ValueType > span() &&=delete
Reference executor for serial CPU execution.
const std::string & name(const NeoFOAM::Document &doc)
Retrieves the name of a Document.
void parallelReduce(const Executor &exec, std::pair< size_t, size_t > range, Kernel kernel, T &value)
std::variant< SerialExecutor, CPUExecutor, GPUExecutor > Executor
Definition executor.hpp:16
void parallelScan(const Executor &exec, std::pair< size_t, size_t > range, Kernel kernel)
void parallelFor(const Executor &exec, std::pair< size_t, size_t > range, Kernel kernel, std::string name="parallelFor")