NeoFOAM
WIP Prototype of a modern OpenFOAM core
Loading...
Searching...
No Matches
sundials.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// SPDX-FileCopyrightText: 2023 NeoFOAM authors
3
4#pragma once
5
6#include <concepts>
7#include <functional>
8#include <memory>
9
10#include <sundials/sundials_nvector.h>
11#include <sundials/sundials_core.hpp>
12#include <nvector/nvector_serial.h>
13#include <nvector/nvector_kokkos.hpp>
14#include <arkode/arkode_arkstep.h>
15#include <arkode/arkode_erkstep.h>
16
20
22{
23
29auto SUN_CONTEXT_DELETER = [](SUNContext* ctx)
30{
31 if (ctx != nullptr)
32 {
33 SUNContext_Free(ctx);
34 }
35};
36
42auto SUN_ARK_DELETER = [](char* ark)
43{
44 if (ark != nullptr)
45 {
46 void* arkodMem = reinterpret_cast<void*>(ark);
47 ARKodeFree(&arkodMem);
48 }
49};
50
57ARKODE_ERKTableID stringToERKTable(const std::string& key)
58{
59 if (key == "Forward-Euler") return ARKODE_FORWARD_EULER_1_1;
60 if (key == "Heun")
61 {
62 NF_ERROR_EXIT("Currently unsupported until field time step-stage indexing resolved.");
63 return ARKODE_HEUN_EULER_2_1_2;
64 }
65 if (key == "Midpoint")
66 {
67 NF_ERROR_EXIT("Currently unsupported until field time step-stage indexing resolved.");
68 return ARKODE_EXPLICIT_MIDPOINT_EULER_2_1_2;
69 }
71 "Unsupported Runge-Kutta time integration method selectied: " + key + ".\n"
72 + "Supported methods are: Forward-Euler, Heun, Midpoint."
73 );
74 return ARKODE_ERK_NONE; // avoids compiler warnings.
75}
76
85template<typename SKVectorType, typename ValueType>
86void fieldToSunNVectorImpl(const NeoFOAM::Field<ValueType>& field, N_Vector& vector)
87{
88 auto view = ::sundials::kokkos::GetVec<SKVectorType>(vector)->View();
90 field.exec(), field.range(), KOKKOS_LAMBDA(const size_t i) { view(i) = field[i]; }
91 );
92};
93
101template<typename ValueType>
102void fieldToSunNVector(const NeoFOAM::Field<ValueType>& field, N_Vector& vector)
103{
104 // CHECK FOR N_Vector on correct space in DEBUG
105 if (std::holds_alternative<NeoFOAM::GPUExecutor>(field.exec()))
106 {
107 fieldToSunNVectorImpl<::sundials::kokkos::Vector<Kokkos::DefaultExecutionSpace>>(
108 field, vector
109 );
110 return;
111 }
112 if (std::holds_alternative<NeoFOAM::CPUExecutor>(field.exec()))
113 {
114 fieldToSunNVectorImpl<::sundials::kokkos::Vector<Kokkos::DefaultHostExecutionSpace>>(
115 field, vector
116 );
117 return;
118 }
119 if (std::holds_alternative<NeoFOAM::SerialExecutor>(field.exec()))
120 {
121 fieldToSunNVectorImpl<::sundials::kokkos::Vector<Kokkos::Serial>>(field, vector);
122 return;
123 }
124 NF_ERROR_EXIT("Unsupported NeoFOAM executor for field.");
125};
126
135template<typename SKVectorType, typename ValueType>
136void sunNVectorToFieldImpl(const N_Vector& vector, NeoFOAM::Field<ValueType>& field)
137{
138 auto view = ::sundials::kokkos::GetVec<SKVectorType>(vector)->View();
139 ValueType* fieldData = field.data();
141 field.exec(), field.range(), KOKKOS_LAMBDA(const size_t i) { fieldData[i] = view(i); }
142 );
143};
144
151template<typename ValueType>
152void sunNVectorToField(const N_Vector& vector, NeoFOAM::Field<ValueType>& field)
153{
154 if (std::holds_alternative<NeoFOAM::GPUExecutor>(field.exec()))
155 {
156 sunNVectorToFieldImpl<::sundials::kokkos::Vector<Kokkos::DefaultExecutionSpace>>(
157 vector, field
158 );
159 return;
160 }
161 if (std::holds_alternative<NeoFOAM::CPUExecutor>(field.exec()))
162 {
163 sunNVectorToFieldImpl<::sundials::kokkos::Vector<Kokkos::DefaultHostExecutionSpace>>(
164 vector, field
165 );
166 return;
167 }
168 if (std::holds_alternative<NeoFOAM::SerialExecutor>(field.exec()))
169 {
170 sunNVectorToFieldImpl<::sundials::kokkos::Vector<Kokkos::Serial>>(vector, field);
171 return;
172 }
173 NF_ERROR_EXIT("Unsupported NeoFOAM executor for field.");
174};
175
190template<typename SolutionFieldType>
191int explicitRKSolve([[maybe_unused]] sunrealtype t, N_Vector y, N_Vector ydot, void* userData)
192{
193 // Pointer wrangling
194 NeoFOAM::dsl::Expression* pdeExpre = reinterpret_cast<NeoFOAM::dsl::Expression*>(userData);
195 sunrealtype* yDotArray = N_VGetArrayPointer(ydot);
196 sunrealtype* yArray = N_VGetArrayPointer(y);
197
198 NF_ASSERT(
199 yDotArray != nullptr && yArray != nullptr && pdeExpre != nullptr,
200 "Failed to dereference pointers in sundails."
201 );
202
203 size_t size = static_cast<size_t>(N_VGetLength(y));
204 // Copy initial value from y to source.
206 pdeExpre->explicitOperation(size) * -1.0; // compute spatial
207 if (std::holds_alternative<NeoFOAM::GPUExecutor>(pdeExpre->exec()))
208 {
209 Kokkos::fence();
210 }
211 NeoFOAM::sundials::fieldToSunNVector(source, ydot); // assign rhs to ydot.
212 return 0;
213}
214
215namespace detail
216{
217
225template<typename Vector>
226void initNVector(size_t size, std::shared_ptr<SUNContext> context, Vector& vec)
227{
228 vec.initNVector(size, context);
229}
230
237template<typename Vector>
238const N_Vector& sunNVector(const Vector& vec)
239{
240 return vec.sunNVector();
241}
242
249template<typename Vector>
250N_Vector& sunNVector(Vector& vec)
251{
252 return vec.sunNVector();
253}
254}
255
261template<typename ValueType>
263{
264public:
265
267 ~SKVectorSerial() = default;
269 : kvector_(other.kvector_), svector_(other.kvector_) {};
271 : kvector_(std::move(other.kvector_)), svector_(std::move(other.svector_)) {};
272 SKVectorSerial& operator=(const SKVectorSerial& other) = delete;
274
275
276 using KVector = ::sundials::kokkos::Vector<Kokkos::Serial>;
277 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
278 {
279 kvector_ = KVector(size, *context);
280 svector_ = kvector_;
281 };
282 const N_Vector& sunNVector() const { return svector_; };
283 N_Vector& sunNVector() { return svector_; };
284
285private:
286
287 KVector kvector_ {};
288 N_Vector svector_ {nullptr};
289};
290
296template<typename ValueType>
298{
299public:
300
301 using KVector = ::sundials::kokkos::Vector<Kokkos::DefaultHostExecutionSpace>;
302
306 : kvector_(other.kvector_), svector_(other.kvector_) {};
308 : kvector_(std::move(other.kvector_)), svector_(std::move(other.svector_)) {};
311
312 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
313 {
314 kvector_ = KVector(size, *context);
315 svector_ = kvector_;
316 };
317 const N_Vector& sunNVector() const { return svector_; };
318 N_Vector& sunNVector() { return svector_; };
319
320private:
321
322 KVector kvector_ {};
323 N_Vector svector_ {nullptr};
324};
325
331template<typename ValueType>
333{
334public:
335
336 using KVector = ::sundials::kokkos::Vector<Kokkos::DefaultExecutionSpace>;
337
338 SKVectorDefault() = default;
339 ~SKVectorDefault() = default;
341 : kvector_(other.kvector_), svector_(other.kvector_) {};
343 : kvector_(std::move(other.kvector_)), svector_(std::move(other.svector_)) {};
346
347 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
348 {
349 kvector_ = KVector(size, *context);
350 svector_ = kvector_;
351 };
352
353 const N_Vector& sunNVector() const { return svector_; };
354
355 N_Vector& sunNVector() { return svector_; };
356
357private:
358
359 KVector kvector_ {};
360 N_Vector svector_ {nullptr};
361};
362
369template<typename ValueType>
371{
372public:
373
377 using SKVectorVariant = std::variant<SKVectorSerialV, SKVectorHostDefaultV, SKDefaultVectorV>;
378
382 SKVector() { vector_.template emplace<SKVectorHostDefaultV>(); };
383
387 ~SKVector() = default;
388
393 SKVector(const SKVector&) = default;
394
398 SKVector& operator=(const SKVector&) = delete;
399
404 SKVector(SKVector&&) noexcept = default;
405
409 SKVector& operator=(SKVector&&) noexcept = delete;
410
415 void setExecutor(const NeoFOAM::Executor& exec)
416 {
417 if (std::holds_alternative<NeoFOAM::GPUExecutor>(exec))
418 {
419 vector_.template emplace<SKDefaultVectorV>();
420 return;
421 }
422 if (std::holds_alternative<NeoFOAM::CPUExecutor>(exec))
423 {
424 vector_.template emplace<SKVectorHostDefaultV>();
425 return;
426 }
427 if (std::holds_alternative<NeoFOAM::SerialExecutor>(exec))
428 {
429 vector_.template emplace<SKVectorSerialV>();
430 return;
431 }
432
434 "Unsupported NeoFOAM executor: "
435 << std::visit([](const auto& e) { return e.name(); }, exec) << "."
436 );
437 }
438
444 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
445 {
446 std::visit(
447 [size, &context](auto& vec) { detail::initNVector(size, context, vec); }, vector_
448 );
449 }
450
455 const N_Vector& sunNVector() const
456 {
457 return std::visit(
458 [](const auto& vec) -> const N_Vector& { return detail::sunNVector(vec); }, vector_
459 );
460 }
461
466 N_Vector& sunNVector()
467 {
468 return std::visit([](auto& vec) -> N_Vector& { return detail::sunNVector(vec); }, vector_);
469 }
470
475 const SKVectorVariant& variant() const { return vector_; }
476
481 SKVectorVariant& variant() { return vector_; }
482
483private:
484
485 SKVectorVariant vector_;
486};
487}
A class to contain the data and executors for a field and define some basic operations.
Definition field.hpp:49
std::pair< size_t, size_t > range() const
Gets the range of the field.
Definition field.hpp:412
const Executor & exec() const
Gets the executor associated with the field.
Definition field.hpp:349
ValueType * data()
Direct access to the underlying field data.
Definition field.hpp:337
A class for the representation of a 3D Vector.
Definition vector.hpp:21
Field< scalar > explicitOperation(size_t nCells)
const Executor & exec() const
Default executor SUNDIALS Kokkos vector wrapper.
Definition sundials.hpp:333
SKVectorDefault(SKVectorDefault &&other) noexcept
Definition sundials.hpp:342
SKVectorDefault & operator=(const SKVectorDefault &other)=delete
SKVectorDefault(const SKVectorDefault &other)
Definition sundials.hpp:340
void initNVector(size_t size, std::shared_ptr< SUNContext > context)
Definition sundials.hpp:347
SKVectorDefault & operator=(SKVectorDefault &&other)=delete
::sundials::kokkos::Vector< Kokkos::DefaultExecutionSpace > KVector
Definition sundials.hpp:336
const N_Vector & sunNVector() const
Definition sundials.hpp:353
Host default executor SUNDIALS Kokkos vector wrapper.
Definition sundials.hpp:298
const N_Vector & sunNVector() const
Definition sundials.hpp:317
void initNVector(size_t size, std::shared_ptr< SUNContext > context)
Definition sundials.hpp:312
SKVectorHostDefault(const SKVectorHostDefault &other)
Definition sundials.hpp:305
SKVectorHostDefault(SKVectorHostDefault &&other) noexcept
Definition sundials.hpp:307
::sundials::kokkos::Vector< Kokkos::DefaultHostExecutionSpace > KVector
Definition sundials.hpp:301
SKVectorHostDefault & operator=(SKVectorHostDefault &&other)=delete
SKVectorHostDefault & operator=(const SKVectorHostDefault &other)=delete
Serial executor SUNDIALS Kokkos vector wrapper.
Definition sundials.hpp:263
::sundials::kokkos::Vector< Kokkos::Serial > KVector
Definition sundials.hpp:276
const N_Vector & sunNVector() const
Definition sundials.hpp:282
SKVectorSerial(const SKVectorSerial &other)
Definition sundials.hpp:268
SKVectorSerial & operator=(SKVectorSerial &&other)=delete
void initNVector(size_t size, std::shared_ptr< SUNContext > context)
Definition sundials.hpp:277
SKVectorSerial(SKVectorSerial &&other) noexcept
Definition sundials.hpp:270
SKVectorSerial & operator=(const SKVectorSerial &other)=delete
Unified interface for SUNDIALS Kokkos vector management.
Definition sundials.hpp:371
~SKVector()=default
Default destructor.
const SKVectorVariant & variant() const
Gets const reference to variant storing implementation.
Definition sundials.hpp:475
SKVector(SKVector &&) noexcept=default
Move constructor.
void initNVector(size_t size, std::shared_ptr< SUNContext > context)
Initializes underlying vector with given size and context.
Definition sundials.hpp:444
SKVector(const SKVector &)=default
Copy constructor.
SKVectorVariant & variant()
Gets mutable reference to variant storing implementation.
Definition sundials.hpp:481
void setExecutor(const NeoFOAM::Executor &exec)
Sets appropriate vector implementation based on executor type.
Definition sundials.hpp:415
std::variant< SKVectorSerialV, SKVectorHostDefaultV, SKDefaultVectorV > SKVectorVariant
Definition sundials.hpp:377
N_Vector & sunNVector()
Gets mutable reference to underlying N_Vector.
Definition sundials.hpp:466
SKVector & operator=(const SKVector &)=delete
Copy assignment operator (deleted).
SKVector()
Default constructor. Initializes with host-default vector.
Definition sundials.hpp:382
const N_Vector & sunNVector() const
Gets const reference to underlying N_Vector.
Definition sundials.hpp:455
#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
void initNVector(size_t size, std::shared_ptr< SUNContext > context, Vector &vec)
Initializes a vector wrapper with specified size and context.
Definition sundials.hpp:226
const N_Vector & sunNVector(const Vector &vec)
Provides const access to underlying N_Vector.
Definition sundials.hpp:238
void sunNVectorToField(const N_Vector &vector, NeoFOAM::Field< ValueType > &field)
Dispatcher for N_Vector to field conversion based on executor type.
Definition sundials.hpp:152
void fieldToSunNVector(const NeoFOAM::Field< ValueType > &field, N_Vector &vector)
Dispatcher for field to N_Vector conversion based on executor type.
Definition sundials.hpp:102
auto SUN_ARK_DELETER
Custom deleter for explicit type RK solvers (ERK, ARK, etc) for the unique pointers.
Definition sundials.hpp:42
void sunNVectorToFieldImpl(const N_Vector &vector, NeoFOAM::Field< ValueType > &field)
Converts SUNDIALS N_Vector data back to NeoFOAM Field format.
Definition sundials.hpp:136
void fieldToSunNVectorImpl(const NeoFOAM::Field< ValueType > &field, N_Vector &vector)
Converts NeoFOAM Field data to SUNDIALS N_Vector format.
Definition sundials.hpp:86
auto SUN_CONTEXT_DELETER
Custom deleter for SUNContext shared pointers.
Definition sundials.hpp:29
int explicitRKSolve(sunrealtype t, N_Vector y, N_Vector ydot, void *userData)
Performs a single explicit Runge-Kutta stage evaluation.
Definition sundials.hpp:191
ARKODE_ERKTableID stringToERKTable(const std::string &key)
Maps dictionary keywords to SUNDIALS RKButcher tableau identifiers.
Definition sundials.hpp:57
std::variant< SerialExecutor, CPUExecutor, GPUExecutor > Executor
Definition executor.hpp:16
void parallelFor(const Executor &exec, std::pair< size_t, size_t > range, Kernel kernel, std::string name="parallelFor")