NeoN
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 NeoN 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
17#include "NeoN/core/error.hpp"
19#include "NeoN/fields/field.hpp"
20
22{
23
29inline auto SUN_CONTEXT_DELETER = [](SUNContext* ctx)
30{
31 if (ctx != nullptr)
32 {
33 SUNContext_Free(ctx);
34 }
35};
36
42inline auto SUN_ARK_DELETER = [](char* ark)
43{
44 if (ark != nullptr)
45 {
46 void* arkodMem = reinterpret_cast<void*>(ark);
47 ARKodeFree(&arkodMem);
48 }
49};
50
57inline ARKODE_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 NeoN::Vector<ValueType>& field, N_Vector& vector)
87{
88 auto view = ::sundials::kokkos::GetVec<SKVectorType>(vector)->View();
89 auto fieldView = field.view();
91 field.exec(), field.range(), KOKKOS_LAMBDA(const localIdx i) { view(i) = fieldView[i]; }
92 );
93};
94
102template<typename ValueType>
103void fieldToSunNVector(const NeoN::Vector<ValueType>& field, N_Vector& vector)
104{
105 // CHECK FOR N_Vector on correct space in DEBUG
106 if (std::holds_alternative<NeoN::GPUExecutor>(field.exec()))
107 {
108 fieldToSunNVectorImpl<::sundials::kokkos::Vector<Kokkos::DefaultExecutionSpace>>(
109 field, vector
110 );
111 return;
112 }
113 if (std::holds_alternative<NeoN::CPUExecutor>(field.exec()))
114 {
115 fieldToSunNVectorImpl<::sundials::kokkos::Vector<Kokkos::DefaultHostExecutionSpace>>(
116 field, vector
117 );
118 return;
119 }
120 if (std::holds_alternative<NeoN::SerialExecutor>(field.exec()))
121 {
122 fieldToSunNVectorImpl<::sundials::kokkos::Vector<Kokkos::Serial>>(field, vector);
123 return;
124 }
125 NF_ERROR_EXIT("Unsupported NeoN executor for field.");
126};
127
136template<typename SKVectorType, typename ValueType>
137void sunNVectorToVectorImpl(const N_Vector& vector, NeoN::Vector<ValueType>& field)
138{
139 auto view = ::sundials::kokkos::GetVec<SKVectorType>(vector)->View();
140 ValueType* fieldData = field.data();
142 field.exec(), field.range(), KOKKOS_LAMBDA(const localIdx i) { fieldData[i] = view(i); }
143 );
144};
145
152template<typename ValueType>
153void sunNVectorToVector(const N_Vector& vector, NeoN::Vector<ValueType>& field)
154{
155 if (std::holds_alternative<NeoN::GPUExecutor>(field.exec()))
156 {
157 sunNVectorToVectorImpl<::sundials::kokkos::Vector<Kokkos::DefaultExecutionSpace>>(
158 vector, field
159 );
160 return;
161 }
162 if (std::holds_alternative<NeoN::CPUExecutor>(field.exec()))
163 {
164 sunNVectorToVectorImpl<::sundials::kokkos::Vector<Kokkos::DefaultHostExecutionSpace>>(
165 vector, field
166 );
167 return;
168 }
169 if (std::holds_alternative<NeoN::SerialExecutor>(field.exec()))
170 {
171 sunNVectorToVectorImpl<::sundials::kokkos::Vector<Kokkos::Serial>>(vector, field);
172 return;
173 }
174 NF_ERROR_EXIT("Unsupported NeoN executor for field.");
175};
176
191template<typename SolutionVectorType>
192int explicitRKSolve([[maybe_unused]] sunrealtype t, N_Vector y, N_Vector ydot, void* userData)
193{
194 // Pointer wrangling
195 using ValueType = typename SolutionVectorType::VectorValueType;
197 reinterpret_cast<NeoN::dsl::Expression<ValueType>*>(userData);
198 sunrealtype* yDotArray = N_VGetArrayPointer(ydot);
199 sunrealtype* yArray = N_VGetArrayPointer(y);
200
201 NF_ASSERT(
202 yDotArray != nullptr && yArray != nullptr && pdeExpre != nullptr,
203 "Failed to dereference pointers in sundails."
204 );
205
206 auto size = static_cast<localIdx>(N_VGetLength(y));
207 // Copy initial value from y to source.
208 NeoN::Vector<NeoN::scalar> source = pdeExpre->explicitOperation(size) * -1.0; // compute spatial
209 if (std::holds_alternative<NeoN::GPUExecutor>(pdeExpre->exec()))
210 {
211 Kokkos::fence();
212 }
213 NeoN::sundials::fieldToSunNVector(source, ydot); // assign rhs to ydot.
214 return 0;
215}
216
217namespace detail
218{
219
227template<typename Vector>
228void initNVector(size_t size, std::shared_ptr<SUNContext> context, Vector& vec)
229{
230 vec.initNVector(size, context);
231}
232
239template<typename Vector>
240const N_Vector& sunNVector(const Vector& vec)
241{
242 return vec.sunNVector();
243}
244
251template<typename Vector>
252N_Vector& sunNVector(Vector& vec)
253{
254 return vec.sunNVector();
255}
256}
257
263template<typename ValueType>
265{
266public:
267
269 ~SKVectorSerial() = default;
271 : kvector_(other.kvector_), svector_(other.kvector_) {};
273 : kvector_(std::move(other.kvector_)), svector_(std::move(other.svector_)) {};
274 SKVectorSerial& operator=(const SKVectorSerial& other) = delete;
276
277
278 using KVector = ::sundials::kokkos::Vector<Kokkos::Serial>;
279 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
280 {
281 kvector_ = KVector(size, *context);
282 svector_ = kvector_;
283 };
284 const N_Vector& sunNVector() const { return svector_; };
285 N_Vector& sunNVector() { return svector_; };
286
287private:
288
289 KVector kvector_ {};
290 N_Vector svector_ {nullptr};
291};
292
298template<typename ValueType>
300{
301public:
302
303 using KVector = ::sundials::kokkos::Vector<Kokkos::DefaultHostExecutionSpace>;
304
308 : kvector_(other.kvector_), svector_(other.kvector_) {};
310 : kvector_(std::move(other.kvector_)), svector_(std::move(other.svector_)) {};
313
314 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
315 {
316 kvector_ = KVector(size, *context);
317 svector_ = kvector_;
318 };
319 const N_Vector& sunNVector() const { return svector_; };
320 N_Vector& sunNVector() { return svector_; };
321
322private:
323
324 KVector kvector_ {};
325 N_Vector svector_ {nullptr};
326};
327
333template<typename ValueType>
335{
336public:
337
338 using KVector = ::sundials::kokkos::Vector<Kokkos::DefaultExecutionSpace>;
339
340 SKVectorDefault() = default;
341 ~SKVectorDefault() = default;
343 : kvector_(other.kvector_), svector_(other.kvector_) {};
345 : kvector_(std::move(other.kvector_)), svector_(std::move(other.svector_)) {};
348
349 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
350 {
351 kvector_ = KVector(size, *context);
352 svector_ = kvector_;
353 };
354
355 const N_Vector& sunNVector() const { return svector_; };
356
357 N_Vector& sunNVector() { return svector_; };
358
359private:
360
361 KVector kvector_ {};
362 N_Vector svector_ {nullptr};
363};
364
371template<typename ValueType>
373{
374public:
375
379 using SKVectorVariant = std::variant<SKVectorSerialV, SKVectorHostDefaultV, SKDefaultVectorV>;
380
384 SKVector() { vector_.template emplace<SKVectorHostDefaultV>(); };
385
389 ~SKVector() = default;
390
395 SKVector(const SKVector&) = default;
396
400 SKVector& operator=(const SKVector&) = delete;
401
406 SKVector(SKVector&&) noexcept = default;
407
411 SKVector& operator=(SKVector&&) noexcept = delete;
412
417 void setExecutor(const NeoN::Executor& exec)
418 {
419 if (std::holds_alternative<NeoN::GPUExecutor>(exec))
420 {
421 vector_.template emplace<SKDefaultVectorV>();
422 return;
423 }
424 if (std::holds_alternative<NeoN::CPUExecutor>(exec))
425 {
426 vector_.template emplace<SKVectorHostDefaultV>();
427 return;
428 }
429 if (std::holds_alternative<NeoN::SerialExecutor>(exec))
430 {
431 vector_.template emplace<SKVectorSerialV>();
432 return;
433 }
434
436 "Unsupported NeoN executor: "
437 << std::visit([](const auto& e) { return e.name(); }, exec) << "."
438 );
439 }
440
446 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
447 {
448 std::visit(
449 [size, &context](auto& vec) { detail::initNVector(size, context, vec); }, vector_
450 );
451 }
452
457 const N_Vector& sunNVector() const
458 {
459 return std::visit(
460 [](const auto& vec) -> const N_Vector& { return detail::sunNVector(vec); }, vector_
461 );
462 }
463
468 N_Vector& sunNVector()
469 {
470 return std::visit([](auto& vec) -> N_Vector& { return detail::sunNVector(vec); }, vector_);
471 }
472
477 const SKVectorVariant& variant() const { return vector_; }
478
483 SKVectorVariant& variant() { return vector_; }
484
485private:
486
487 SKVectorVariant vector_;
488};
489}
A class to contain the data and executors for a field and define some basic operations.
Definition vector.hpp:53
ValueType * data()
Direct access to the underlying field data.
Definition vector.hpp:346
std::pair< localIdx, localIdx > range() const
Gets the range of the field.
Definition vector.hpp:434
const Executor & exec() const
Gets the executor associated with the field.
Definition vector.hpp:358
View< ValueType > view() &&=delete
Vector< ValueType > explicitOperation(localIdx nCells) const
const Executor & exec() const
Default executor SUNDIALS Kokkos vector wrapper.
Definition sundials.hpp:335
::sundials::kokkos::Vector< Kokkos::DefaultExecutionSpace > KVector
Definition sundials.hpp:338
SKVectorDefault(SKVectorDefault &&other) noexcept
Definition sundials.hpp:344
void initNVector(size_t size, std::shared_ptr< SUNContext > context)
Definition sundials.hpp:349
SKVectorDefault & operator=(const SKVectorDefault &other)=delete
SKVectorDefault(const SKVectorDefault &other)
Definition sundials.hpp:342
const N_Vector & sunNVector() const
Definition sundials.hpp:355
SKVectorDefault & operator=(SKVectorDefault &&other)=delete
Host default executor SUNDIALS Kokkos vector wrapper.
Definition sundials.hpp:300
void initNVector(size_t size, std::shared_ptr< SUNContext > context)
Definition sundials.hpp:314
SKVectorHostDefault(SKVectorHostDefault &&other) noexcept
Definition sundials.hpp:309
SKVectorHostDefault(const SKVectorHostDefault &other)
Definition sundials.hpp:307
const N_Vector & sunNVector() const
Definition sundials.hpp:319
SKVectorHostDefault & operator=(SKVectorHostDefault &&other)=delete
::sundials::kokkos::Vector< Kokkos::DefaultHostExecutionSpace > KVector
Definition sundials.hpp:303
SKVectorHostDefault & operator=(const SKVectorHostDefault &other)=delete
Serial executor SUNDIALS Kokkos vector wrapper.
Definition sundials.hpp:265
SKVectorSerial & operator=(SKVectorSerial &&other)=delete
SKVectorSerial & operator=(const SKVectorSerial &other)=delete
::sundials::kokkos::Vector< Kokkos::Serial > KVector
Definition sundials.hpp:278
void initNVector(size_t size, std::shared_ptr< SUNContext > context)
Definition sundials.hpp:279
SKVectorSerial(const SKVectorSerial &other)
Definition sundials.hpp:270
const N_Vector & sunNVector() const
Definition sundials.hpp:284
SKVectorSerial(SKVectorSerial &&other) noexcept
Definition sundials.hpp:272
Unified interface for SUNDIALS Kokkos vector management.
Definition sundials.hpp:373
SKVectorVariant & variant()
Gets mutable reference to variant storing implementation.
Definition sundials.hpp:483
void initNVector(size_t size, std::shared_ptr< SUNContext > context)
Initializes underlying vector with given size and context.
Definition sundials.hpp:446
const N_Vector & sunNVector() const
Gets const reference to underlying N_Vector.
Definition sundials.hpp:457
N_Vector & sunNVector()
Gets mutable reference to underlying N_Vector.
Definition sundials.hpp:468
SKVector()
Default constructor. Initializes with host-default vector.
Definition sundials.hpp:384
const SKVectorVariant & variant() const
Gets const reference to variant storing implementation.
Definition sundials.hpp:477
SKVector & operator=(const SKVector &)=delete
Copy assignment operator (deleted).
void setExecutor(const NeoN::Executor &exec)
Sets appropriate vector implementation based on executor type.
Definition sundials.hpp:417
SKVector(SKVector &&) noexcept=default
Move constructor.
SKVector(const SKVector &)=default
Copy constructor.
~SKVector()=default
Default destructor.
std::variant< SKVectorSerialV, SKVectorHostDefaultV, SKDefaultVectorV > SKVectorVariant
Definition sundials.hpp:379
#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
const N_Vector & sunNVector(const Vector &vec)
Provides const access to underlying N_Vector.
Definition sundials.hpp:240
void initNVector(size_t size, std::shared_ptr< SUNContext > context, Vector &vec)
Initializes a vector wrapper with specified size and context.
Definition sundials.hpp:228
int explicitRKSolve(sunrealtype t, N_Vector y, N_Vector ydot, void *userData)
Performs a single explicit Runge-Kutta stage evaluation.
Definition sundials.hpp:192
auto SUN_CONTEXT_DELETER
Custom deleter for SUNContext shared pointers.
Definition sundials.hpp:29
ARKODE_ERKTableID stringToERKTable(const std::string &key)
Maps dictionary keywords to SUNDIALS RKButcher tableau identifiers.
Definition sundials.hpp:57
void sunNVectorToVectorImpl(const N_Vector &vector, NeoN::Vector< ValueType > &field)
Converts SUNDIALS N_Vector data back to NeoN Vector format.
Definition sundials.hpp:137
void sunNVectorToVector(const N_Vector &vector, NeoN::Vector< ValueType > &field)
Dispatcher for N_Vector to field conversion based on executor type.
Definition sundials.hpp:153
auto SUN_ARK_DELETER
Custom deleter for explicit type RK solvers (ERK, ARK, etc) for the unique pointers.
Definition sundials.hpp:42
void fieldToSunNVectorImpl(const NeoN::Vector< ValueType > &field, N_Vector &vector)
Converts NeoN Vector data to SUNDIALS N_Vector format.
Definition sundials.hpp:86
void fieldToSunNVector(const NeoN::Vector< ValueType > &field, N_Vector &vector)
Dispatcher for field to N_Vector conversion based on executor type.
Definition sundials.hpp:103
void parallelFor(const Executor &exec, std::pair< localIdx, localIdx > range, Kernel kernel, std::string name="parallelFor")
int32_t localIdx
Definition label.hpp:30
std::variant< SerialExecutor, CPUExecutor, GPUExecutor > Executor
Definition executor.hpp:16