NeoN
A framework for CFD software
Loading...
Searching...
No Matches
sundials.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// SPDX-FileCopyrightText: 2023 NeoN authors
3
4#pragma once
5
6#if NN_WITH_SUNDIALS
7
8#include <concepts>
9#include <functional>
10#include <memory>
11
12#include <sundials/sundials_nvector.h>
13#include <sundials/sundials_core.hpp>
14#include <nvector/nvector_serial.h>
15#include <nvector/nvector_kokkos.hpp>
16#include <arkode/arkode_arkstep.h>
17#include <arkode/arkode_erkstep.h>
18
19#include "NeoN/core/error.hpp"
21#include "NeoN/fields/field.hpp"
22
23namespace NeoN::sundials
24{
25
31inline auto SUN_CONTEXT_DELETER = [](SUNContext* ctx)
32{
33 if (ctx != nullptr)
34 {
35 SUNContext_Free(ctx);
36 }
37};
38
44inline auto SUN_ARK_DELETER = [](char* ark)
45{
46 if (ark != nullptr)
47 {
48 void* arkodMem = reinterpret_cast<void*>(ark);
49 ARKodeFree(&arkodMem);
50 }
51};
52
59inline ARKODE_ERKTableID stringToERKTable(const std::string& key)
60{
61 if (key == "Forward-Euler") return ARKODE_FORWARD_EULER_1_1;
62 if (key == "Heun")
63 {
64 NF_ERROR_EXIT("Currently unsupported until field time step-stage indexing resolved.");
65 return ARKODE_HEUN_EULER_2_1_2;
66 }
67 if (key == "Midpoint")
68 {
69 NF_ERROR_EXIT("Currently unsupported until field time step-stage indexing resolved.");
70 return ARKODE_EXPLICIT_MIDPOINT_EULER_2_1_2;
71 }
73 "Unsupported Runge-Kutta time integration method selectied: " + key + ".\n"
74 + "Supported methods are: Forward-Euler, Heun, Midpoint."
75 );
76 return ARKODE_ERK_NONE; // avoids compiler warnings.
77}
78
87template<typename SKVectorType, typename ValueType>
88void fieldToSunNVectorImpl(const NeoN::Vector<ValueType>& field, N_Vector& vector)
89{
90 auto view = ::sundials::kokkos::GetVec<SKVectorType>(vector)->View();
91 auto fieldView = field.view();
93 field.exec(), field.range(), KOKKOS_LAMBDA(const localIdx i) { view(i) = fieldView[i]; }
94 );
95};
96
104template<typename ValueType>
105void fieldToSunNVector(const NeoN::Vector<ValueType>& field, N_Vector& vector)
106{
107 // CHECK FOR N_Vector on correct space in DEBUG
108 if (std::holds_alternative<NeoN::GPUExecutor>(field.exec()))
109 {
110 fieldToSunNVectorImpl<::sundials::kokkos::Vector<Kokkos::DefaultExecutionSpace>>(
111 field, vector
112 );
113 return;
114 }
115 if (std::holds_alternative<NeoN::CPUExecutor>(field.exec()))
116 {
117 fieldToSunNVectorImpl<::sundials::kokkos::Vector<Kokkos::DefaultHostExecutionSpace>>(
118 field, vector
119 );
120 return;
121 }
122 if (std::holds_alternative<NeoN::SerialExecutor>(field.exec()))
123 {
124 fieldToSunNVectorImpl<::sundials::kokkos::Vector<Kokkos::Serial>>(field, vector);
125 return;
126 }
127 NF_ERROR_EXIT("Unsupported NeoN executor for field.");
128};
129
138template<typename SKVectorType, typename ValueType>
139void sunNVectorToVectorImpl(const N_Vector& vector, NeoN::Vector<ValueType>& field)
140{
141 auto view = ::sundials::kokkos::GetVec<SKVectorType>(vector)->View();
142 ValueType* fieldData = field.data();
144 field.exec(), field.range(), KOKKOS_LAMBDA(const localIdx i) { fieldData[i] = view(i); }
145 );
146};
147
154template<typename ValueType>
155void sunNVectorToVector(const N_Vector& vector, NeoN::Vector<ValueType>& field)
156{
157 if (std::holds_alternative<NeoN::GPUExecutor>(field.exec()))
158 {
159 sunNVectorToVectorImpl<::sundials::kokkos::Vector<Kokkos::DefaultExecutionSpace>>(
160 vector, field
161 );
162 return;
163 }
164 if (std::holds_alternative<NeoN::CPUExecutor>(field.exec()))
165 {
166 sunNVectorToVectorImpl<::sundials::kokkos::Vector<Kokkos::DefaultHostExecutionSpace>>(
167 vector, field
168 );
169 return;
170 }
171 if (std::holds_alternative<NeoN::SerialExecutor>(field.exec()))
172 {
173 sunNVectorToVectorImpl<::sundials::kokkos::Vector<Kokkos::Serial>>(vector, field);
174 return;
175 }
176 NF_ERROR_EXIT("Unsupported NeoN executor for field.");
177};
178
193template<typename SolutionVectorType>
194int explicitRKSolve([[maybe_unused]] sunrealtype t, N_Vector y, N_Vector ydot, void* userData)
195{
196 // Pointer wrangling
197 using ValueType = typename SolutionVectorType::VectorValueType;
199 reinterpret_cast<NeoN::dsl::Expression<ValueType>*>(userData);
200 sunrealtype* yDotArray = N_VGetArrayPointer(ydot);
201 sunrealtype* yArray = N_VGetArrayPointer(y);
202
203 NF_ASSERT(
204 yDotArray != nullptr && yArray != nullptr && pdeExpre != nullptr,
205 "Failed to dereference pointers in sundails."
206 );
207
208 auto size = static_cast<localIdx>(N_VGetLength(y));
209 // Copy initial value from y to source.
210 NeoN::Vector<NeoN::scalar> source = pdeExpre->explicitOperation(size) * -1.0; // compute spatial
211 if (std::holds_alternative<NeoN::GPUExecutor>(pdeExpre->exec()))
212 {
213 Kokkos::fence();
214 }
215 NeoN::sundials::fieldToSunNVector(source, ydot); // assign rhs to ydot.
216 return 0;
217}
218
219namespace detail
220{
221
229template<typename Vector>
230void initNVector(size_t size, std::shared_ptr<SUNContext> context, Vector& vec)
231{
232 vec.initNVector(size, context);
233}
234
241template<typename Vector>
242const N_Vector& sunNVector(const Vector& vec)
243{
244 return vec.sunNVector();
245}
246
253template<typename Vector>
254N_Vector& sunNVector(Vector& vec)
255{
256 return vec.sunNVector();
257}
258}
259
265template<typename ValueType>
266class SKVectorSerial
267{
268public:
269
270 SKVectorSerial() {};
271 ~SKVectorSerial() = default;
272 SKVectorSerial(const SKVectorSerial& other)
273 : kvector_(other.kvector_), svector_(other.kvector_) {};
274 SKVectorSerial(SKVectorSerial&& other) noexcept
275 : kvector_(std::move(other.kvector_)), svector_(std::move(other.svector_)) {};
276 SKVectorSerial& operator=(const SKVectorSerial& other) = delete;
277 SKVectorSerial& operator=(SKVectorSerial&& other) = delete;
278
279
280 using KVector = ::sundials::kokkos::Vector<Kokkos::Serial>;
281 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
282 {
283 kvector_ = KVector(size, *context);
284 svector_ = kvector_;
285 };
286 const N_Vector& sunNVector() const { return svector_; };
287 N_Vector& sunNVector() { return svector_; };
288
289private:
290
291 KVector kvector_ {};
292 N_Vector svector_ {nullptr};
293};
294
300template<typename ValueType>
301class SKVectorHostDefault
302{
303public:
304
305 using KVector = ::sundials::kokkos::Vector<Kokkos::DefaultHostExecutionSpace>;
306
307 SKVectorHostDefault() = default;
308 ~SKVectorHostDefault() = default;
309 SKVectorHostDefault(const SKVectorHostDefault& other)
310 : kvector_(other.kvector_), svector_(other.kvector_) {};
311 SKVectorHostDefault(SKVectorHostDefault&& other) noexcept
312 : kvector_(std::move(other.kvector_)), svector_(std::move(other.svector_)) {};
313 SKVectorHostDefault& operator=(const SKVectorHostDefault& other) = delete;
314 SKVectorHostDefault& operator=(SKVectorHostDefault&& other) = delete;
315
316 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
317 {
318 kvector_ = KVector(size, *context);
319 svector_ = kvector_;
320 };
321 const N_Vector& sunNVector() const { return svector_; };
322 N_Vector& sunNVector() { return svector_; };
323
324private:
325
326 KVector kvector_ {};
327 N_Vector svector_ {nullptr};
328};
329
335template<typename ValueType>
336class SKVectorDefault
337{
338public:
339
340 using KVector = ::sundials::kokkos::Vector<Kokkos::DefaultExecutionSpace>;
341
342 SKVectorDefault() = default;
343 ~SKVectorDefault() = default;
344 SKVectorDefault(const SKVectorDefault& other)
345 : kvector_(other.kvector_), svector_(other.kvector_) {};
346 SKVectorDefault(SKVectorDefault&& other) noexcept
347 : kvector_(std::move(other.kvector_)), svector_(std::move(other.svector_)) {};
348 SKVectorDefault& operator=(const SKVectorDefault& other) = delete;
349 SKVectorDefault& operator=(SKVectorDefault&& other) = delete;
350
351 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
352 {
353 kvector_ = KVector(size, *context);
354 svector_ = kvector_;
355 };
356
357 const N_Vector& sunNVector() const { return svector_; };
358
359 N_Vector& sunNVector() { return svector_; };
360
361private:
362
363 KVector kvector_ {};
364 N_Vector svector_ {nullptr};
365};
366
373template<typename ValueType>
374class SKVector
375{
376public:
377
378 using SKVectorSerialV = SKVectorSerial<ValueType>;
379 using SKVectorHostDefaultV = SKVectorHostDefault<ValueType>;
380 using SKDefaultVectorV = SKVectorDefault<ValueType>;
381 using SKVectorVariant = std::variant<SKVectorSerialV, SKVectorHostDefaultV, SKDefaultVectorV>;
382
386 SKVector() { vector_.template emplace<SKVectorHostDefaultV>(); };
387
391 ~SKVector() = default;
392
397 SKVector(const SKVector&) = default;
398
402 SKVector& operator=(const SKVector&) = delete;
403
408 SKVector(SKVector&&) noexcept = default;
409
413 SKVector& operator=(SKVector&&) noexcept = delete;
414
419 void setExecutor(const NeoN::Executor& exec)
420 {
421 if (std::holds_alternative<NeoN::GPUExecutor>(exec))
422 {
423 vector_.template emplace<SKDefaultVectorV>();
424 return;
425 }
426 if (std::holds_alternative<NeoN::CPUExecutor>(exec))
427 {
428 vector_.template emplace<SKVectorHostDefaultV>();
429 return;
430 }
431 if (std::holds_alternative<NeoN::SerialExecutor>(exec))
432 {
433 vector_.template emplace<SKVectorSerialV>();
434 return;
435 }
436
438 "Unsupported NeoN executor: "
439 << std::visit([](const auto& e) { return e.name(); }, exec) << "."
440 );
441 }
442
448 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
449 {
450 std::visit(
451 [size, &context](auto& vec) { detail::initNVector(size, context, vec); }, vector_
452 );
453 }
454
459 const N_Vector& sunNVector() const
460 {
461 return std::visit(
462 [](const auto& vec) -> const N_Vector& { return detail::sunNVector(vec); }, vector_
463 );
464 }
465
470 N_Vector& sunNVector()
471 {
472 return std::visit([](auto& vec) -> N_Vector& { return detail::sunNVector(vec); }, vector_);
473 }
474
479 const SKVectorVariant& variant() const { return vector_; }
480
485 SKVectorVariant& variant() { return vector_; }
486
487private:
488
489 SKVectorVariant vector_;
490};
491}
492
493#endif
A class to contain the data and executors for a field and define some basic operations.
Definition vector.hpp:28
ValueType * data()
Direct access to the underlying field data.
Definition vector.hpp:215
std::pair< localIdx, localIdx > range() const
Gets the range of the field.
Definition vector.hpp:303
const Executor & exec() const
Gets the executor associated with the field.
Definition vector.hpp:227
View< ValueType > view() &&=delete
Vector< ValueType > explicitOperation(localIdx nCells) const
const Executor & exec() const
#define NF_ERROR_EXIT(message)
Macro for printing an error message and aborting the program.
Definition error.hpp:108
#define NF_ASSERT(condition, message)
Macro for asserting a condition and printing an error message if the condition is false.
Definition error.hpp:142
SpatialOperator< scalar > source(fvcc::VolumeField< scalar > &coeff, fvcc::VolumeField< scalar > &phi)
Definition array.hpp:19
void parallelFor(const Executor &exec, std::pair< localIdx, localIdx > range, Kernel kernel, std::string name="parallelFor")
int32_t localIdx
Definition label.hpp:30