NeoFOAM
WIP Prototype of a modern OpenFOAM core
Loading...
Searching...
No Matches
operator.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// SPDX-FileCopyrightText: 2023-2024 NeoFOAM authors
3#pragma once
4
5#include <memory>
6#include <concepts>
7
11#include "NeoFOAM/dsl/coeff.hpp"
12
13namespace NeoFOAM::dsl
14{
15
16template<typename T>
17concept HasTemporalOperator = requires(T t) {
18 {
19 t.temporalOperation(std::declval<Field<scalar>&>(), std::declval<scalar>())
20 } -> std::same_as<void>; // Adjust return type and arguments as needed
21};
22
23template<typename T>
24concept HasExplicitOperator = requires(T t) {
25 {
26 t.explicitOperation(std::declval<Field<scalar>&>())
27 } -> std::same_as<void>; // Adjust return type and arguments as needed
28};
29
30/* @class Operator
31 * @brief A class to represent an operator in NeoFOAMs dsl
32 *
33 * The design here is based on the type erasure design pattern
34 * see https://www.youtube.com/watch?v=4eeESJQk-mw
35 *
36 * Motivation for using type erasure is that concrete implementation
37 * of Operators e.g Divergence, Laplacian, etc can be stored in a vector of
38 * Operators
39 *
40 * @ingroup dsl
41 */
43{
44public:
45
46 enum class Type
47 {
51 };
52
53 template<typename T>
54 Operator(T cls) : model_(std::make_unique<OperatorModel<T>>(std::move(cls)))
55 {}
56
57 Operator(const Operator& eqnOperator);
58
59 Operator(Operator&& eqnOperator);
60
62
64
65 /* returns the fundamental type of an operator, ie explicit, implicit, temporal */
67
69
71
72 /* @brief Given an input this function reads required coeffs */
73 void build(const Input& input);
74
75 /* @brief Get the executor */
76 const Executor& exec() const;
77
78
79private:
80
81 /* @brief Base class defining the concept of a term. This effectively
82 * defines what functions need to be implemented by a concrete Operator implementation
83 * */
84 struct OperatorConcept
85 {
86 virtual ~OperatorConcept() = default;
87
88 virtual void explicitOperation(Field<scalar>& source) = 0;
89
90 virtual void temporalOperation(Field<scalar>& field) = 0;
91
92 /* @brief Given an input this function reads required coeffs */
93 virtual void build(const Input& input) = 0;
94
95 /* returns the name of the operator */
96 virtual std::string getName() const = 0;
97
98 /* returns the fundamental type of an operator, ie explicit, implicit, temporal */
99 virtual Operator::Type getType() const = 0;
100
101 /* @brief get the associated coefficient for this term */
102 virtual Coeff& getCoefficient() = 0;
103
104 /* @brief get the associated coefficient for this term */
105 virtual Coeff getCoefficient() const = 0;
106
107 /* @brief Get the executor */
108 virtual const Executor& exec() const = 0;
109
110 // The Prototype Design Pattern
111 virtual std::unique_ptr<OperatorConcept> clone() const = 0;
112 };
113
114 // Templated derived class to implement the type-specific behavior
115 template<typename ConcreteOperatorType>
116 struct OperatorModel : OperatorConcept
117 {
118 /* @brief build with concrete operator */
119 OperatorModel(ConcreteOperatorType concreteOp) : concreteOp_(std::move(concreteOp)) {}
120
121 /* returns the name of the operator */
122 std::string getName() const override { return concreteOp_.getName(); }
123
124 virtual void explicitOperation(Field<scalar>& source) override
125 {
126 if constexpr (HasExplicitOperator<ConcreteOperatorType>)
127 {
128 concreteOp_.explicitOperation(source);
129 }
130 }
131
132 virtual void temporalOperation(Field<scalar>& field) override
133 {
134 if constexpr (HasTemporalOperator<ConcreteOperatorType>)
135 {
136 concreteOp_.temporalOperation(field);
137 }
138 }
139
140 /* @brief Given an input this function reads required coeffs */
141 virtual void build(const Input& input) override { concreteOp_.build(input); }
142
143 /* returns the fundamental type of an operator, ie explicit, implicit, temporal */
144 Operator::Type getType() const override { return concreteOp_.getType(); }
145
146 /* @brief Get the executor */
147 const Executor& exec() const override { return concreteOp_.exec(); }
148
149 /* @brief get the associated coefficient for this term */
150 virtual Coeff& getCoefficient() override { return concreteOp_.getCoefficient(); }
151
152 /* @brief get the associated coefficient for this term */
153 virtual Coeff getCoefficient() const override { return concreteOp_.getCoefficient(); }
154
155 // The Prototype Design Pattern
156 std::unique_ptr<OperatorConcept> clone() const override
157 {
158 return std::make_unique<OperatorModel>(*this);
159 }
160
161 ConcreteOperatorType concreteOp_;
162 };
163
164 std::unique_ptr<OperatorConcept> model_;
165};
166
167
169
170Operator operator*(const Field<scalar>& coeffField, Operator rhs);
171
172Operator operator*(const Coeff& coeff, Operator rhs);
173
174template<typename CoeffFunction>
175 requires std::invocable<CoeffFunction&, size_t>
176Operator operator*([[maybe_unused]] CoeffFunction coeffFunc, const Operator& lhs)
177{
178 // TODO implement
179 NF_ERROR_EXIT("Not implemented");
180 Operator result = lhs;
181 // if (!result.getCoefficient().useSpan)
182 // {
183 // result.setField(std::make_shared<Field<scalar>>(result.exec(), result.nCells(), 1.0));
184 // }
185 // map(result.exec(), result.getCoefficient().values, scaleFunc);
186 return result;
187}
188
189/* @class OperatorMixin
190 * @brief A mixin class to simplify implementations of concrete operators
191 * in NeoFOAMs dsl
192 *
193 * @ingroup dsl
194 */
195template<typename FieldType>
197{
198
199public:
200
201 OperatorMixin(const Executor exec, FieldType& field, Operator::Type type)
202 : exec_(exec), coeffs_(), field_(field), type_(type) {};
203
204 Operator::Type getType() const { return type_; }
205
206 virtual ~OperatorMixin() = default;
207
208 virtual const Executor& exec() const final { return exec_; }
209
211
212 const Coeff& getCoefficient() const { return coeffs_; }
213
214 FieldType& getField() { return field_; }
215
216 const FieldType& getField() const { return field_; }
217
218 /* @brief Given an input this function reads required coeffs */
219 void build([[maybe_unused]] const Input& input) {}
220
221protected:
222
224
226
227 FieldType& field_;
228
230};
231} // namespace NeoFOAM::dsl
A class to contain the data and executors for a field and define some basic operations.
Definition field.hpp:49
A class that represents a coefficient for the NeoFOAM dsl.
Definition coeff.hpp:22
const Coeff & getCoefficient() const
Definition operator.hpp:212
const FieldType & getField() const
Definition operator.hpp:216
virtual const Executor & exec() const final
Definition operator.hpp:208
OperatorMixin(const Executor exec, FieldType &field, Operator::Type type)
Definition operator.hpp:201
virtual ~OperatorMixin()=default
void build(const Input &input)
Definition operator.hpp:219
const Executor exec_
Executor associated with the field. (CPU, GPU, openMP, etc.)
Definition operator.hpp:223
Operator::Type getType() const
Definition operator.hpp:204
Operator(const Operator &eqnOperator)
void build(const Input &input)
Operator::Type getType() const
Operator(Operator &&eqnOperator)
Coeff getCoefficient() const
void temporalOperation(Field< scalar > &field)
const Executor & exec() const
void explicitOperation(Field< scalar > &source)
#define NF_ERROR_EXIT(message)
Macro for printing an error message and aborting the program.
Definition error.hpp:108
Coeff operator*(const Coeff &lhs, const Coeff &rhs)
Definition coeff.hpp:57
float scalar
Definition scalar.hpp:11
std::variant< Dictionary, TokenList > Input
Definition input.hpp:13
std::variant< SerialExecutor, CPUExecutor, GPUExecutor > Executor
Definition executor.hpp:16