NeoN
A framework for CFD software
Loading...
Searching...
No Matches
temporalOperator.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2023 - 2026 NeoN authors
2//
3// SPDX-License-Identifier: MIT
4
5#pragma once
6
7#include <memory>
8#include <concepts>
9
10#include "NeoN/core/error.hpp"
13#include "NeoN/core/input.hpp"
16#include "NeoN/dsl/coeff.hpp"
17#include "NeoN/dsl/operator.hpp"
19
20namespace NeoN::dsl
21{
22
23template<typename T>
24concept HasTemporalExplicitOperator = requires(T t) {
25 {
26 t.explicitOperation(
27 std::declval<Vector<typename T::VectorValueType>&>(),
28 std::declval<NeoN::scalar>(),
29 std::declval<NeoN::scalar>()
30 )
31 } -> std::same_as<void>; // Adjust return type and arguments as needed
32};
33
34template<typename T>
35concept HasTemporalImplicitOperator = requires(T t) {
36 {
37 t.implicitOperation(
39 std::declval<NeoN::scalar>(),
40 std::declval<NeoN::scalar>()
41 )
42 } -> std::same_as<void>; // Adjust return type and arguments as needed
43};
44
45/* @brief Concept satisfied when T can assemble its temporal contribution into a
46 * LinearSystem whose matrix coefficients are scalar while the RHS holds T's
47 * field value type (segregated vector-solve form).
48 */
49template<typename T>
50concept HasTemporalImplicitOperatorScalarMtx = requires(T t) {
51 {
52 t.implicitOperation(
54 std::declval<NeoN::scalar>(),
55 std::declval<NeoN::scalar>()
56 )
57 } -> std::same_as<void>;
58};
59
60template<typename T>
63
64/* @class TemporalOperator
65 * @brief A class to represent a TemporalOperator in NeoNs DSL
66 *
67 * The design here is based on the type erasure design pattern
68 * see https://www.youtube.com/watch?v=4eeESJQk-mw
69 *
70 * Motivation for using type erasure is that concrete implementation
71 * of TemporalOperator e.g ddt, d2dt2, etc can be stored in a vector of
72 * TemporalOperator
73 *
74 * @ingroup dsl
75 */
76template<typename ValueType>
78{
79public:
80
81 using VectorValueType = ValueType;
82
83 template<HasTemporalOperator T>
84 TemporalOperator(T cls) : model_(std::make_unique<TemporalOperatorModel<T>>(std::move(cls)))
85 {}
86
87 TemporalOperator(const TemporalOperator& eqnOperator) : model_ {eqnOperator.model_->clone()} {}
88
89 TemporalOperator(TemporalOperator&& eqnOperator) : model_ {std::move(eqnOperator.model_)} {}
90
92 {
93 model_ = eqnOperator.model_->clone();
94 return *this;
95 }
96
98 {
99 model_->explicitOperation(source, t, dt);
100 }
101
103 {
104 model_->implicitOperation(ls, t, dt);
105 }
106
107 /* @brief Implicit temporal assembly into a scalar-matrix / ValueType-rhs linear system
108 * (segregated vector-solve form). Disabled when ValueType == scalar to avoid
109 * colliding with the same-type overload above.
110 */
111 template<typename U = ValueType>
112 requires(!std::is_same_v<U, scalar>)
114 {
115 model_->implicitOperationScalarMtx(ls, t, dt);
116 }
117
118 /* returns the fundamental type of an operator, ie explicit, implicit */
119 Operator::Type getType() const { return model_->getType(); }
120
121 std::string getName() const { return model_->getName(); }
122
123 Coeff& getCoefficient() { return model_->getCoefficient(); }
124
125 Coeff getCoefficient() const { return model_->getCoefficient(); }
126
127 /* @brief Given an input this function reads required properties */
128 void read(const Input& input) { model_->read(input); }
129
130 /* @brief Get the executor */
131 const Executor& exec() const { return model_->exec(); }
132
133 /* @brief Get the ddtScheme */
134 NeoN::finiteVolume::cellCentred::DdtScheme ddtScheme() const { return model_->ddtScheme(); }
135
136private:
137
138 /* @brief Base class defining the concept of a term. This effectively
139 * defines what functions need to be implemented by a concrete Operator implementation
140 * */
141 struct TemporalOperatorConcept
142 {
143 virtual ~TemporalOperatorConcept() = default;
144
145 virtual void explicitOperation(Vector<ValueType>& source, scalar t, scalar dt) = 0;
146
147 virtual void implicitOperation(la::LinearSystem<ValueType>& ls, scalar t, scalar dt) = 0;
148
149 /* @brief Temporal assembly into LinearSystem<scalar, ValueType> for the
150 * scalar-matrix / ValueType-rhs (segregated vector-solve) form.
151 * Concrete operators that don't support this form leave it as a no-op.
152 */
153 virtual void implicitOperationScalarMtx(
155 ) = 0;
156
157 /* @brief Given an input this function reads required properties */
158 virtual void read(const Input& input) = 0;
159
160 /* returns the name of the operator */
161 virtual std::string getName() const = 0;
162
163 /* returns the fundamental type of an operator, ie explicit, implicit, temporal */
164 virtual Operator::Type getType() const = 0;
165
166 /* @brief get the associated coefficient for this term */
167 virtual Coeff& getCoefficient() = 0;
168
169 /* @brief get the associated coefficient for this term */
170 virtual Coeff getCoefficient() const = 0;
171
172 /* @brief Get the executor */
173 virtual const Executor& exec() const = 0;
174
175 /* @brief Get the ddtScheme */
176 virtual NeoN::finiteVolume::cellCentred::DdtScheme ddtScheme() const
177 {
179 }
180
181 // The Prototype Design Pattern
182 virtual std::unique_ptr<TemporalOperatorConcept> clone() const = 0;
183 };
184
185 // Templated derived class to implement the type-specific behavior
186 template<typename ConcreteTemporalOperatorType>
187 struct TemporalOperatorModel : TemporalOperatorConcept
188 {
189 /* @brief build with concrete TemporalOperator */
190 TemporalOperatorModel(ConcreteTemporalOperatorType concreteOp)
191 : concreteOp_(std::move(concreteOp))
192 {}
193
194 /* returns the name of the operator */
195 std::string getName() const override { return concreteOp_.getName(); }
196
197 virtual void explicitOperation(Vector<ValueType>& source, scalar t, scalar dt) override
198 {
199 if constexpr (HasTemporalExplicitOperator<ConcreteTemporalOperatorType>)
200 {
201 concreteOp_.explicitOperation(source, t, dt);
202 }
203 }
204
205 virtual void
206 implicitOperation(la::LinearSystem<ValueType>& ls, scalar t, scalar dt) override
207 {
208 if constexpr (HasTemporalImplicitOperator<ConcreteTemporalOperatorType>)
209 {
210 concreteOp_.implicitOperation(ls, t, dt);
211 }
212 }
213
214 virtual void implicitOperationScalarMtx(
216 ) override
217 {
218 if constexpr (HasTemporalImplicitOperatorScalarMtx<ConcreteTemporalOperatorType>)
219 {
220 concreteOp_.implicitOperation(ls, t, dt);
221 }
222 else
223 {
224 // Reached only for an implicit temporal operator that lacks the scalar-matrix
225 // (segregated vector-solve) overload. Silently skipping it would drop its
226 // contribution (e.g. an implicit ddt term) and yield a wrong system, so fail
227 // fast instead.
229 "Temporal operator '" << getName()
230 << "' does not support scalar-matrix (segregated) "
231 "assembly."
232 );
233 }
234 }
235
236 /* @brief Given an input this function reads required coeffs */
237 virtual void read(const Input& input) override { concreteOp_.read(input); }
238
239 /* returns the fundamental type of an operator, ie explicit, implicit, temporal */
240 Operator::Type getType() const override { return concreteOp_.getType(); }
241
242 /* @brief Get the executor */
243 const Executor& exec() const override { return concreteOp_.exec(); }
244
245 /* @brief get the associated coefficient for this term */
246 virtual Coeff& getCoefficient() override { return concreteOp_.getCoefficient(); }
247
248 /* @brief get the associated coefficient for this term */
249 virtual Coeff getCoefficient() const override { return concreteOp_.getCoefficient(); }
250
251 /* @brief return the ddtScheme read by the ddtOperator */
252 NeoN::finiteVolume::cellCentred::DdtScheme ddtScheme() const override
253 {
254 if constexpr (requires { concreteOp_.scheme(); })
255 {
256 return concreteOp_.scheme();
257 }
258 else
259 {
261 }
262 }
263 // The Prototype Design Pattern
264 std::unique_ptr<TemporalOperatorConcept> clone() const override
265 {
266 return std::make_unique<TemporalOperatorModel>(*this);
267 }
268
269 ConcreteTemporalOperatorType concreteOp_;
270 };
271
272 std::unique_ptr<TemporalOperatorConcept> model_;
273};
274
275
276template<typename ValueType>
278{
279 TemporalOperator<ValueType> result = rhs;
280 result.getCoefficient() *= scalarCoeff;
281 return result;
282}
283
284template<typename ValueType>
285TemporalOperator<ValueType>
287{
288 TemporalOperator<ValueType> result = rhs;
289 result.getCoefficient() *= Coeff {coeffVector};
290 return result;
291}
292
293template<typename ValueType>
295{
296 TemporalOperator<ValueType> result = rhs;
297 result.getCoefficient() *= coeff;
298 return result;
299}
300
301
302} // namespace NeoN::dsl
A class to contain the data and executors for a field and define some basic operations.
Definition vector.hpp:27
A class that represents a coefficient for the NeoN dsl.
Definition coeff.hpp:24
TemporalOperator(const TemporalOperator &eqnOperator)
NeoN::finiteVolume::cellCentred::DdtScheme ddtScheme() const
Operator::Type getType() const
const Executor & exec() const
void read(const Input &input)
TemporalOperator(TemporalOperator &&eqnOperator)
void implicitOperation(la::LinearSystem< ValueType > &ls, scalar t, scalar dt) const
void implicitOperation(la::LinearSystem< scalar, ValueType > &ls, scalar t, scalar dt) const
TemporalOperator & operator=(const TemporalOperator &eqnOperator)
void explicitOperation(Vector< ValueType > &source, scalar t, scalar dt) const
A class representing a linear system of equations.
#define NF_ERROR_EXIT(message)
Macro for printing an error message and aborting the program.
Definition error.hpp:90
Coeff operator*(const Coeff &lhs, const Coeff &rhs)
Definition coeff.hpp:61
std::variant< Dictionary, TokenList > Input
Definition input.hpp:15
std::variant< SerialExecutor, CPUExecutor, GPUExecutor > Executor
Definition executor.hpp:20
float scalar
Definition scalar.hpp:17
DataClass read(Input input)
Definition input.hpp:18