NeoN
A framework for CFD software
Loading...
Searching...
No Matches
sundials.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#if NN_WITH_SUNDIALS
8
9#include <concepts>
10#include <functional>
11#include <memory>
12
13#include <sundials/sundials_nvector.h>
14#include <sundials/sundials_core.hpp>
15#include <nvector/nvector_serial.h>
16#include <nvector/nvector_kokkos.hpp>
17#include <arkode/arkode_arkstep.h>
18#include <arkode/arkode_erkstep.h>
19
20#include "NeoN/core/error.hpp"
22#include "NeoN/fields/field.hpp"
23
24namespace NeoN::sundials
25{
26
32inline auto SUN_CONTEXT_DELETER = [](SUNContext* ctx)
33{
34 if (ctx != nullptr)
35 {
36 SUNContext_Free(ctx);
37 }
38};
39
45inline auto SUN_ARK_DELETER = [](char* ark)
46{
47 if (ark != nullptr)
48 {
49 void* arkodMem = reinterpret_cast<void*>(ark);
50 ARKodeFree(&arkodMem);
51 }
52};
53
60inline ARKODE_ERKTableID stringToERKTable(const std::string& key)
61{
62 if (key == "Forward-Euler") return ARKODE_FORWARD_EULER_1_1;
63 if (key == "Heun")
64 {
65 NF_ERROR_EXIT("Currently unsupported until field time step-stage indexing resolved.");
66 return ARKODE_HEUN_EULER_2_1_2;
67 }
68 if (key == "Midpoint")
69 {
70 NF_ERROR_EXIT("Currently unsupported until field time step-stage indexing resolved.");
71 return ARKODE_EXPLICIT_MIDPOINT_EULER_2_1_2;
72 }
74 "Unsupported Runge-Kutta time integration method selectied: " + key + ".\n"
75 + "Supported methods are: Forward-Euler, Heun, Midpoint."
76 );
77 return ARKODE_ERK_NONE; // avoids compiler warnings.
78}
79
88template<typename SKVectorType, typename ValueType>
89void fieldToSunNVectorImpl(const NeoN::Vector<ValueType>& field, N_Vector& vector)
90{
91 auto view = ::sundials::kokkos::GetVec<SKVectorType>(vector)->View();
92 auto fieldView = field.view();
94 field.exec(),
95 field.range(),
96 KOKKOS_LAMBDA(const localIdx i) { view(i) = fieldView[i]; },
97 "fieldToSunNVector"
98 );
99};
100
108template<typename ValueType>
109void fieldToSunNVector(const NeoN::Vector<ValueType>& field, N_Vector& vector)
110{
111 // CHECK FOR N_Vector on correct space in DEBUG
112 if (std::holds_alternative<NeoN::GPUExecutor>(field.exec()))
113 {
114 fieldToSunNVectorImpl<::sundials::kokkos::Vector<Kokkos::DefaultExecutionSpace>>(
115 field, vector
116 );
117 return;
118 }
119 if (std::holds_alternative<NeoN::CPUExecutor>(field.exec()))
120 {
121 fieldToSunNVectorImpl<::sundials::kokkos::Vector<Kokkos::DefaultHostExecutionSpace>>(
122 field, vector
123 );
124 return;
125 }
126 if (std::holds_alternative<NeoN::SerialExecutor>(field.exec()))
127 {
128 fieldToSunNVectorImpl<::sundials::kokkos::Vector<Kokkos::Serial>>(field, vector);
129 return;
130 }
131 NF_ERROR_EXIT("Unsupported NeoN executor for field.");
132};
133
142template<typename SKVectorType, typename ValueType>
143void sunNVectorToVectorImpl(const N_Vector& vector, NeoN::Vector<ValueType>& field)
144{
145 auto view = ::sundials::kokkos::GetVec<SKVectorType>(vector)->View();
146 ValueType* fieldData = field.data();
148 field.exec(),
149 field.range(),
150 KOKKOS_LAMBDA(const localIdx i) { fieldData[i] = view(i); },
151 "sunNVectorToVectorImpl"
152 );
153};
154
161template<typename ValueType>
162void sunNVectorToVector(const N_Vector& vector, NeoN::Vector<ValueType>& field)
163{
164 if (std::holds_alternative<NeoN::GPUExecutor>(field.exec()))
165 {
166 sunNVectorToVectorImpl<::sundials::kokkos::Vector<Kokkos::DefaultExecutionSpace>>(
167 vector, field
168 );
169 return;
170 }
171 if (std::holds_alternative<NeoN::CPUExecutor>(field.exec()))
172 {
173 sunNVectorToVectorImpl<::sundials::kokkos::Vector<Kokkos::DefaultHostExecutionSpace>>(
174 vector, field
175 );
176 return;
177 }
178 if (std::holds_alternative<NeoN::SerialExecutor>(field.exec()))
179 {
180 sunNVectorToVectorImpl<::sundials::kokkos::Vector<Kokkos::Serial>>(vector, field);
181 return;
182 }
183 NF_ERROR_EXIT("Unsupported NeoN executor for field.");
184};
185
200template<typename SolutionVectorType>
201int explicitRKSolve([[maybe_unused]] sunrealtype t, N_Vector y, N_Vector ydot, void* userData)
202{
203 // Pointer wrangling
204 using ValueType = typename SolutionVectorType::VectorValueType;
206 reinterpret_cast<NeoN::dsl::Expression<ValueType>*>(userData);
207 sunrealtype* yDotArray = N_VGetArrayPointer(ydot);
208 sunrealtype* yArray = N_VGetArrayPointer(y);
209
210 NF_ASSERT(
211 yDotArray != nullptr && yArray != nullptr && pdeExpre != nullptr,
212 "Failed to dereference pointers in sundails."
213 );
214
215 auto size = static_cast<localIdx>(N_VGetLength(y));
216 // Copy initial value from y to source.
217 NeoN::Vector<NeoN::scalar> source = pdeExpre->explicitOperation(size) * -1.0; // compute spatial
218 fence(pdeExpre->exec());
219 NeoN::sundials::fieldToSunNVector(source, ydot); // assign rhs to ydot.
220 return 0;
221}
222
223namespace detail
224{
225
233template<typename Vector>
234void initNVector(size_t size, std::shared_ptr<SUNContext> context, Vector& vec)
235{
236 vec.initNVector(size, context);
237}
238
245template<typename Vector>
246const N_Vector& sunNVector(const Vector& vec)
247{
248 return vec.sunNVector();
249}
250
257template<typename Vector>
258N_Vector& sunNVector(Vector& vec)
259{
260 return vec.sunNVector();
261}
262}
263
269template<typename ValueType>
270class SKVectorSerial
271{
272public:
273
274 SKVectorSerial() {};
275 ~SKVectorSerial() = default;
276 SKVectorSerial(const SKVectorSerial& other)
277 : kvector_(other.kvector_), svector_(other.kvector_) {};
278 SKVectorSerial(SKVectorSerial&& other) noexcept
279 : kvector_(std::move(other.kvector_)), svector_(std::move(other.svector_)) {};
280 SKVectorSerial& operator=(const SKVectorSerial& other) = delete;
281 SKVectorSerial& operator=(SKVectorSerial&& other) = delete;
282
283
284 using KVector = ::sundials::kokkos::Vector<Kokkos::Serial>;
285 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
286 {
287 kvector_ = KVector(size, *context);
288 svector_ = kvector_;
289 };
290 const N_Vector& sunNVector() const { return svector_; };
291 N_Vector& sunNVector() { return svector_; };
292
293private:
294
295 KVector kvector_ {};
296 N_Vector svector_ {nullptr};
297};
298
304template<typename ValueType>
305class SKVectorHostDefault
306{
307public:
308
309 using KVector = ::sundials::kokkos::Vector<Kokkos::DefaultHostExecutionSpace>;
310
311 SKVectorHostDefault() = default;
312 ~SKVectorHostDefault() = default;
313 SKVectorHostDefault(const SKVectorHostDefault& other)
314 : kvector_(other.kvector_), svector_(other.kvector_) {};
315 SKVectorHostDefault(SKVectorHostDefault&& other) noexcept
316 : kvector_(std::move(other.kvector_)), svector_(std::move(other.svector_)) {};
317 SKVectorHostDefault& operator=(const SKVectorHostDefault& other) = delete;
318 SKVectorHostDefault& operator=(SKVectorHostDefault&& other) = delete;
319
320 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
321 {
322 kvector_ = KVector(size, *context);
323 svector_ = kvector_;
324 };
325 const N_Vector& sunNVector() const { return svector_; };
326 N_Vector& sunNVector() { return svector_; };
327
328private:
329
330 KVector kvector_ {};
331 N_Vector svector_ {nullptr};
332};
333
339template<typename ValueType>
340class SKVectorDefault
341{
342public:
343
344 using KVector = ::sundials::kokkos::Vector<Kokkos::DefaultExecutionSpace>;
345
346 SKVectorDefault() = default;
347 ~SKVectorDefault() = default;
348 SKVectorDefault(const SKVectorDefault& other)
349 : kvector_(other.kvector_), svector_(other.kvector_) {};
350 SKVectorDefault(SKVectorDefault&& other) noexcept
351 : kvector_(std::move(other.kvector_)), svector_(std::move(other.svector_)) {};
352 SKVectorDefault& operator=(const SKVectorDefault& other) = delete;
353 SKVectorDefault& operator=(SKVectorDefault&& other) = delete;
354
355 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
356 {
357 kvector_ = KVector(size, *context);
358 svector_ = kvector_;
359 };
360
361 const N_Vector& sunNVector() const { return svector_; };
362
363 N_Vector& sunNVector() { return svector_; };
364
365private:
366
367 KVector kvector_ {};
368 N_Vector svector_ {nullptr};
369};
370
377template<typename ValueType>
378class SKVector
379{
380public:
381
382 using SKVectorSerialV = SKVectorSerial<ValueType>;
383 using SKVectorHostDefaultV = SKVectorHostDefault<ValueType>;
384 using SKDefaultVectorV = SKVectorDefault<ValueType>;
385 using SKVectorVariant = std::variant<SKVectorSerialV, SKVectorHostDefaultV, SKDefaultVectorV>;
386
390 SKVector() { vector_.template emplace<SKVectorHostDefaultV>(); };
391
395 ~SKVector() = default;
396
401 SKVector(const SKVector&) = default;
402
406 SKVector& operator=(const SKVector&) = delete;
407
412 SKVector(SKVector&&) noexcept = default;
413
417 SKVector& operator=(SKVector&&) noexcept = delete;
418
423 void setExecutor(const NeoN::Executor& exec)
424 {
425 if (std::holds_alternative<NeoN::GPUExecutor>(exec))
426 {
427 vector_.template emplace<SKDefaultVectorV>();
428 return;
429 }
430 if (std::holds_alternative<NeoN::CPUExecutor>(exec))
431 {
432 vector_.template emplace<SKVectorHostDefaultV>();
433 return;
434 }
435 if (std::holds_alternative<NeoN::SerialExecutor>(exec))
436 {
437 vector_.template emplace<SKVectorSerialV>();
438 return;
439 }
440
442 "Unsupported NeoN executor: "
443 << std::visit([](const auto& e) { return e.name(); }, exec) << "."
444 );
445 }
446
452 void initNVector(size_t size, std::shared_ptr<SUNContext> context)
453 {
454 std::visit(
455 [size, &context](auto& vec) { detail::initNVector(size, context, vec); }, vector_
456 );
457 }
458
463 const N_Vector& sunNVector() const
464 {
465 return std::visit(
466 [](const auto& vec) -> const N_Vector& { return detail::sunNVector(vec); }, vector_
467 );
468 }
469
474 N_Vector& sunNVector()
475 {
476 return std::visit([](auto& vec) -> N_Vector& { return detail::sunNVector(vec); }, vector_);
477 }
478
483 const SKVectorVariant& variant() const { return vector_; }
484
489 SKVectorVariant& variant() { return vector_; }
490
491private:
492
493 SKVectorVariant vector_;
494};
495}
496
497#endif
A class to contain the data and executors for a field and define some basic operations.
Definition vector.hpp:30
ValueType * data()
Direct access to the underlying field data.
Definition vector.hpp:217
std::pair< localIdx, localIdx > range() const
Gets the range of the field.
Definition vector.hpp:305
const Executor & exec() const
Gets the executor associated with the field.
Definition vector.hpp:229
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:110
#define NF_ASSERT(condition, message)
Macro for asserting a condition and printing an error message if the condition is false.
Definition error.hpp:144
SpatialOperator< scalar > source(fvcc::VolumeField< scalar > &coeff, fvcc::VolumeField< scalar > &phi)
Definition array.hpp:20
void fence(const Executor &exec)
Definition executor.hpp:22
int32_t localIdx
Definition label.hpp:32
void parallelFor(const ExecutorType &exec, std::pair< localIdx, localIdx > range, Kernel kernel, std::string name)