NeoN
WIP Prototype of a modern OpenFOAM core
Loading...
Searching...
No Matches
expression.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// SPDX-FileCopyrightText: 2025 NeoN authors
3// TODO: move to cellCenred dsl?
4
5#pragma once
6
10#include "NeoN/dsl/solver.hpp"
13
14namespace dsl = NeoN::dsl;
15
17{
18
19/*@brief extends expression by giving access to assembled matrix
20 * @note used in neoIcoFOAM directly instead of dsl::expression
21 * TODO: implement flag if matrix is assembled or not -> if not assembled call assemble
22 * for dependent operations like discrete momentum fields
23 * needs storage for assembled matrix? and whether update is needed like for rAU and HbyA
24 */
25template<typename ValueType, typename IndexType = localIdx>
27{
28public:
29
33 [[maybe_unused]] const Dictionary& fvSchemes,
34 [[maybe_unused]] const Dictionary& fvSolution
35 )
36 : psi_(psi), expr_(expr), fvSchemes_(fvSchemes), fvSolution_(fvSolution),
37 sparsityPattern_(SparsityPattern::readOrCreate(psi.mesh())),
38 ls_(la::createEmptyLinearSystem<ValueType, localIdx, SparsityPattern>(
39 *sparsityPattern_.get()
40 ))
41 {
42 expr_.build(fvSchemes_);
43 // assemble();
44 };
45
47 : psi_(ls.psi_), expr_(ls.expr_), fvSchemes_(ls.fvSchemes_), fvSolution_(ls.fvSolution_),
48 ls_(ls.ls_), sparsityPattern_(ls.sparsityPattern_) {};
49
50 ~Expression() = default;
51
54 {
55 if (!sparsityPattern_)
56 {
57 NF_THROW(std::string("fvcc:LinearSystem:sparsityPattern: sparsityPattern is null"));
58 }
59 return *sparsityPattern_;
60 }
61
62 VolumeField<ValueType>& getVector() { return this->psi_; }
63
64 const VolumeField<ValueType>& getVector() const { return this->psi_; }
65
66 [[nodiscard]] const la::LinearSystem<ValueType, IndexType>& linearSystem() const { return ls_; }
67 [[nodiscard]] const SparsityPattern& sparsityPattern() const
68 {
69 if (!sparsityPattern_)
70 {
71 NF_THROW("fvcc:LinearSystem:sparsityPattern: sparsityPattern is null");
72 }
73 return *sparsityPattern_;
74 }
75
76 const Executor& exec() const { return ls_.exec(); }
77
78
80 {
81 auto vol = psi_.mesh().cellVolumes().view();
82 auto expSource = expr_.explicitOperation(psi_.mesh().nCells());
83 expr_.explicitOperation(expSource, t, dt);
84 auto expSourceView = expSource.view();
85 fill(ls_.rhs(), zero<ValueType>());
86 fill(ls_.matrix().values(), zero<ValueType>());
87 expr_.implicitOperation(ls_);
88 // TODO rename implicitOperation -> assembleLinearSystem
89 expr_.implicitOperation(ls_, t, dt);
90 auto rhs = ls_.rhs().view();
91 // we subtract the explicit source term from the rhs
93 exec(),
94 {0, rhs.size()},
95 KOKKOS_LAMBDA(const localIdx i) { rhs[i] -= expSourceView[i] * vol[i]; }
96 );
97 }
98
99 void assemble()
100 {
101 if (expr_.temporalOperators().size() == 0 && expr_.spatialOperators().size() == 0)
102 {
103 NF_ERROR_EXIT("No temporal or implicit terms to solve.");
104 }
105
106 if (expr_.temporalOperators().size() > 0)
107 {
108 // integrate equations in time
109 // NeoN::timeIntegration::TimeIntegration<VolumeField<ValueType>> timeIntegrator(
110 // fvSchemes_.subDict("ddtSchemes"), fvSolution_
111 // );
112 // timeIntegrator.solve(expr_, psi_, t, dt);
113 }
114 else
115 {
116 // solve sparse matrix system
117 auto vol = psi_.mesh().cellVolumes().view();
118 auto expSource = expr_.explicitOperation(psi_.mesh().nCells());
119 auto expSourceSpan = expSource.view();
120
121 ls_ = expr_.implicitOperation();
122 auto rhs = ls_.rhs().view();
123 // we subtract the explicit source term from the rhs
125 exec(),
126 {0, rhs.size()},
127 KOKKOS_LAMBDA(const localIdx i) { rhs[i] -= expSourceSpan[i] * vol[i]; }
128 );
129 }
130 }
131
132 // TODO unify with dsl/solver.hpp
134 {
135 // dsl::solve(expr_, psi_, t, dt, fvSchemes_, fvSolution_);
136 if (expr_.temporalOperators().size() == 0 && expr_.spatialOperators().size() == 0)
137 {
138 NF_ERROR_EXIT("No temporal or implicit terms to solve.");
139 }
140 if (expr_.temporalOperators().size() > 0)
141 {
142 NF_ERROR_EXIT("Not implemented");
143 // // integrate equations in time
144 // NeoN::timeIntegration::TimeIntegration<VolumeField<ValueType>> timeIntegrator(
145 // fvSchemes_.subDict("ddtSchemes"), fvSolution_
146 // );
147 // timeIntegrator.solve(expr_, psi_, t, dt);
148 }
149 else
150 {
151 auto exec = psi_.exec();
152 auto solver = NeoN::la::Solver(exec, fvSolution_);
153 solver.solve(ls_, psi_.internalVector());
154 // NF_ERROR_EXIT("No linear solver is available, build with -DNeoN_WITH_GINKGO=ON");
155 }
156 }
157
158 void setReference(const IndexType refCell, ValueType refValue)
159 {
160 // TODO currently assumes that matrix is already assembled
161 const auto diagOffset = sparsityPattern_->diagOffset().view();
162 const auto rowPtrs = ls_.matrix().rowPtrs().view();
163 auto rhs = ls_.rhs().view();
164 auto values = ls_.matrix().values().view();
166 ls_.exec(),
167 {refCell, refCell + 1},
168 KOKKOS_LAMBDA(const std::size_t refCelli) {
169 auto diagIdx = rowPtrs[refCelli] + diagOffset[refCelli];
170 auto diagValue = values[diagIdx];
171 rhs[refCelli] += diagValue * refValue;
172 values[diagIdx] += diagValue;
173 }
174 );
175 }
176
177private:
178
181 const Dictionary& fvSchemes_;
182 const Dictionary& fvSolution_;
183 std::shared_ptr<SparsityPattern> sparsityPattern_;
185};
186
187template<typename ValueType, typename IndexType = localIdx>
188VolumeField<ValueType>
190{
191 VolumeField<ValueType> resultVector(
192 psi.exec(),
193 "ls_" + psi.name,
194 psi.mesh(),
195 psi.internalVector(),
196 psi.boundaryData(),
198 );
199
200 auto [result, b, x] =
201 spans(resultVector.internalVector(), expr.linearSystem().rhs(), psi.internalVector());
202 const auto [values, colIdxs, rowPtrs] = expr.linearSystem().view();
203
205 resultVector.exec(),
206 {0, result.size()},
207 KOKKOS_LAMBDA(const std::size_t rowi) {
208 IndexType rowStart = rowPtrs[rowi];
209 IndexType rowEnd = rowPtrs[rowi + 1];
210 ValueType sum = 0.0;
211 for (IndexType coli = rowStart; coli < rowEnd; coli++)
212 {
213 sum += values[coli] * x[colIdxs[coli]];
214 }
215 result[rowi] = sum - b[rowi];
216 }
217 );
218
219 return resultVector;
220}
221
222}
A class representing a dictionary that stores key-value pairs.
const UnstructuredMesh & mesh() const
Returns a const reference to the unstructured mesh object.
Definition domain.hpp:121
const BoundaryData< ValueType > & boundaryData() const
Returns a const reference to the boundary field.
Definition domain.hpp:100
const Executor & exec() const
Returns a const reference to the executor object.
Definition domain.hpp:114
const Vector< ValueType > & internalVector() const
Returns a const reference to the internal field.
Definition domain.hpp:79
const SparsityPattern & sparsityPattern() const
const la::LinearSystem< ValueType, IndexType > & linearSystem() const
const VolumeField< ValueType > & getVector() const
la::LinearSystem< ValueType, IndexType > & linearSystem()
Expression(dsl::Expression< ValueType > expr, VolumeField< ValueType > &psi, const Dictionary &fvSchemes, const Dictionary &fvSolution)
VolumeField< ValueType > & getVector()
void setReference(const IndexType refCell, ValueType refValue)
Represents a volume field in a finite volume method.
std::vector< VolumeBoundary< ValueType > > boundaryConditions() const
A class representing a linear system of equations.
#define NF_THROW(message)
Macro for throwing a NeoNException with the specified error message.
Definition error.hpp:127
#define NF_ERROR_EXIT(message)
Macro for printing an error message and aborting the program.
Definition error.hpp:108
VolumeField< ValueType > operator&(const Expression< ValueType, IndexType > expr, const VolumeField< ValueType > &psi)
void parallelFor(const Executor &exec, std::pair< localIdx, localIdx > range, Kernel kernel, std::string name="parallelFor")
int32_t localIdx
Definition label.hpp:30
void fill(Vector< ValueType > &a, const std::type_identity_t< ValueType > value, std::pair< localIdx, localIdx > range={0, 0})
Fill the field with a scalar value using a specific executor.
std::variant< SerialExecutor, CPUExecutor, GPUExecutor > Executor
Definition executor.hpp:16
float scalar
Definition scalar.hpp:14
auto spans(Args &... fields)