NeoN
A framework for CFD software
Loading...
Searching...
No Matches
spatialOperator.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"
15#include "NeoN/core/input.hpp"
16#include "NeoN/dsl/coeff.hpp"
17#include "NeoN/dsl/operator.hpp"
18
19namespace la = NeoN::la;
20
21namespace NeoN::dsl
22{
23
24template<typename T>
25concept HasExplicitOperator = requires(T const t) {
26 {
27 t.explicitOperation(std::declval<Vector<typename T::VectorValueType>&>())
28 } -> std::same_as<void>;
29};
30
31template<typename T>
32concept HasImplicitOperator = requires(T const t) {
33 {
34 t.implicitOperation(std::declval<la::LinearSystem<typename T::VectorValueType>&>())
35 } -> std::same_as<void>; // Adjust return type and arguments as needed
36};
37
38/* @brief Concept satisfied when T can assemble into a LinearSystem whose matrix
39 * coefficients are scalar while the RHS holds T's field value type
40 * (segregated vector-solve form). Only meaningful when VectorValueType != scalar.
41 */
42template<typename T>
43concept HasImplicitOperatorScalarMtx = requires(T const t) {
44 {
45 t.implicitOperation(std::declval<la::LinearSystem<scalar, typename T::VectorValueType>&>())
46 } -> std::same_as<void>;
47};
48
49template<typename T>
52
53/* @class SpatialOperator
54 * @brief A class to represent an operator in NeoNs dsl
55 *
56 * The design here is based on the type erasure design pattern
57 * see https://www.youtube.com/watch?v=4eeESJQk-mw
58 *
59 * Motivation for using type erasure is that concrete implementation
60 * of Operators e.g Divergence, Laplacian, etc can be stored in a vector of
61 * Operators
62 *
63 * @ingroup dsl
64 */
65template<typename ValueType>
67{
68public:
69
70 using VectorValueType = ValueType;
71
72 template<IsSpatialOperator T>
73 SpatialOperator(T cls) : model_(std::make_unique<OperatorModel<T>>(std::move(cls)))
74 {}
75
76 SpatialOperator(const SpatialOperator& eqnOperator) : model_(eqnOperator.model_->clone()) {}
77
78 SpatialOperator(SpatialOperator&& eqnOperator) : model_(std::move(eqnOperator.model_)) {}
79
81 {
82 model_ = eqnOperator.model_->clone();
83 return *this;
84 }
85
86 void explicitOperation(Vector<ValueType>& source) const { model_->explicitOperation(source); }
87
88 void implicitOperation(la::LinearSystem<ValueType>& ls) const { model_->implicitOperation(ls); }
89
90 /* @brief Implicit assembly into a scalar-matrix / ValueType-rhs linear system
91 * (segregated vector-solve form). Disabled when ValueType == scalar to
92 * avoid colliding with the same-type overload above.
93 */
94 template<typename U = ValueType>
95 requires(!std::is_same_v<U, scalar>)
97 {
98 model_->implicitOperationScalarMtx(ls);
99 }
100
101 /* returns the fundamental type of an operator, ie explicit, implicit */
102 Operator::Type getType() const { return model_->getType(); }
103
104 std::string getName() const { return model_->getName(); }
105
106 Coeff& getCoefficient() { return model_->getCoefficient(); }
107
108 Coeff getCoefficient() const { return model_->getCoefficient(); }
109
110 Dictionary getConfig() const { return model_->getConfig(); }
111
112 /* @brief Given an input this function reads required properties */
113 void read(const Input& input) { model_->read(input); }
114
115 /* @brief Get the executor */
116 const Executor& exec() const { return model_->exec(); }
117
118
119private:
120
121 /* @brief Base class defining the concept of a term. This effectively
122 * defines what functions need to be implemented by a concrete Operator implementation
123 * */
124 struct OperatorConcept
125 {
126 virtual ~OperatorConcept() = default;
127
128 virtual void explicitOperation(Vector<ValueType>& source) const = 0;
129
130 virtual void implicitOperation(la::LinearSystem<ValueType>& ls) const = 0;
131
132 /* @brief Implicit assembly into LinearSystem<scalar, ValueType> for the
133 * scalar-matrix / ValueType-rhs (segregated vector-solve) form.
134 * Concrete operators that don't support this form leave it as a no-op.
135 */
136 virtual void implicitOperationScalarMtx(la::LinearSystem<scalar, ValueType>& ls) const = 0;
137
138 /* @brief Given an input this function reads required coeffs */
139 virtual void read(const Input& input) = 0;
140
141 /* returns the name of the operator */
142 virtual std::string getName() const = 0;
143
144 /* returns the fundamental type of an operator, ie explicit, implicit */
145 virtual Operator::Type getType() const = 0;
146
147 /* @brief get the associated coefficient for this term */
148 virtual Coeff& getCoefficient() = 0;
149
150 /* @brief get the associated coefficient for this term */
151 virtual Coeff getCoefficient() const = 0;
152
153 /* @brief Get the config of operator*/
154 virtual Dictionary getConfig() const = 0;
155
156 /* @brief Get the executor */
157 virtual const Executor& exec() const = 0;
158
159 // The Prototype Design Pattern
160 virtual std::unique_ptr<OperatorConcept> clone() const = 0;
161 };
162
163 // Templated derived class to implement the type-specific behavior
164 template<typename ConcreteOperatorType>
165 struct OperatorModel : OperatorConcept
166 {
167 /* @brief build with concrete operator */
168 OperatorModel(ConcreteOperatorType concreteOp) : concreteOp_(std::move(concreteOp)) {}
169
170 /* returns the name of the operator */
171 std::string getName() const override { return concreteOp_.getName(); }
172
173 virtual void explicitOperation(Vector<ValueType>& source) const override
174 {
175 if constexpr (HasExplicitOperator<ConcreteOperatorType>)
176 {
177 concreteOp_.explicitOperation(source);
178 }
179 }
180
181 virtual void implicitOperation(la::LinearSystem<ValueType>& ls) const override
182 {
183 if constexpr (HasImplicitOperator<ConcreteOperatorType>)
184 {
185 concreteOp_.implicitOperation(ls);
186 }
187 }
188
189 virtual void implicitOperationScalarMtx(la::LinearSystem<scalar, ValueType>& ls
190 ) const override
191 {
192 if constexpr (HasImplicitOperatorScalarMtx<ConcreteOperatorType>)
193 {
194 concreteOp_.implicitOperation(ls);
195 }
196 else
197 {
198 // Reached only for an implicit operator that lacks the scalar-matrix
199 // (segregated vector-solve) overload. Silently skipping it would drop its
200 // contribution and yield a wrong system, so fail fast instead.
202 "Operator '" << getName()
203 << "' does not support scalar-matrix (segregated) assembly."
204 );
205 }
206 }
207
208 /* @brief Given an input this function reads required coeffs */
209 virtual void read(const Input& input) override { concreteOp_.read(input); }
210
211 /* returns the fundamental type of an operator, ie explicit, implicit, temporal */
212 Operator::Type getType() const override { return concreteOp_.getType(); }
213
214 /* @brief Get the executor */
215 const Executor& exec() const override { return concreteOp_.exec(); }
216
217 /* @brief get the associated coefficient for this term */
218 virtual Coeff& getCoefficient() override { return concreteOp_.getCoefficient(); }
219
220 /* @brief get the associated coefficient for this term */
221 virtual Coeff getCoefficient() const override { return concreteOp_.getCoefficient(); }
222
223 virtual Dictionary getConfig() const override { return concreteOp_.getConfig(); }
224
225 // The Prototype Design Pattern
226 std::unique_ptr<OperatorConcept> clone() const override
227 {
228 return std::make_unique<OperatorModel>(*this);
229 }
230
231 ConcreteOperatorType concreteOp_;
232 };
233
234 std::unique_ptr<OperatorConcept> model_;
235};
236
237
238template<typename ValueType>
240{
241 SpatialOperator<ValueType> result = rhs;
242 result.getCoefficient() *= scalarCoeff;
243 return result;
244}
245
246template<typename ValueType>
247SpatialOperator<ValueType>
249{
250 SpatialOperator<ValueType> result = rhs;
251 result.getCoefficient() *= Coeff {coeffVector};
252 return result;
253}
254
255template<typename ValueType>
257{
258 SpatialOperator<ValueType> result = rhs;
259 result.getCoefficient() *= coeff;
260 return result;
261}
262
263// template<typename CoeffFunction>
264// requires std::invocable<CoeffFunction&, size_t>
265// SpatialOperator operator*([[maybe_unused]] CoeffFunction coeffFunc, const SpatialOperator& lhs)
266// {
267// // TODO implement
268// NF_ERROR_EXIT("Not implemented");
269// SpatialOperator result = lhs;
270// // if (!result.getCoefficient().useView)
271// // {
272// // result.setVector(std::make_shared<Vector<scalar>>(result.exec(),
273// result.nCells(), 1.0));
274// // }
275// // map(result.exec(), result.getCoefficient().values, scaleFunc);
276// return result;
277// }
278
279} // namespace dsl
A class representing a dictionary that stores key-value pairs.
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
SpatialOperator & operator=(const SpatialOperator &eqnOperator)
SpatialOperator(SpatialOperator &&eqnOperator)
void explicitOperation(Vector< ValueType > &source) const
const Executor & exec() const
Operator::Type getType() const
void implicitOperation(la::LinearSystem< ValueType > &ls) const
SpatialOperator(const SpatialOperator &eqnOperator)
void implicitOperation(la::LinearSystem< scalar, ValueType > &ls) const
void read(const Input &input)
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