NeoN
A framework for CFD software
Loading...
Searching...
No Matches
linearUpwind.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
14
15#include <Kokkos_Core.hpp>
16
17#include <functional>
18#include <string>
19
21{
22
23namespace detail
24{
25
26/* @brief maps a face-interpolated field type to the type of its cell gradient:
27** a scalar field has a Vec3 gradient, a Vec3 field has a Tensor gradient.
28*/
29template<typename ValueType>
31
32template<>
34{
35 using type = Vec3;
36};
37
38template<>
40{
41 using type = Tensor;
42};
43
44} // namespace detail
45
46/* @brief computational kernel to perform a linearUpwind interpolation
47** from a source volume field to a surface field. The face value is the upwind
48** cell value plus a gradient-based correction:
49**
50** phi_f = phi_U + (Cf - C_U) & grad(phi)_U
51**
52** where U is the upwind cell (owner if faceFlux >= 0, neighbour otherwise),
53** Cf is the face centre and C_U the upwind cell centre. The gradient is computed
54** internally with a Gauss-Green scheme. This reduces to plain upwind where the
55** field is locally constant and is second-order accurate for smooth fields.
56**
57** @pre src.correctBoundaryConditions() must have been called by the caller so that
58** processor-boundary ghost values are up to date before the gradient is computed.
59** @param src the input field
60** @param flux the face flux determining the upwind direction
61** @param faceDeltaOwner Cf - C_owner per internal face (from the geometry scheme)
62** @param faceDeltaNeighbour Cf - C_neighbour per internal face (from the geometry scheme)
63** @param dst the target surface field
64*/
65template<typename ValueType>
67 const VolumeField<ValueType>& src,
68 const SurfaceField<scalar>& flux,
69 const SurfaceField<Vec3>& faceDeltaOwner,
70 const SurfaceField<Vec3>& faceDeltaNeighbour,
72 const bool cellLimitedGradient = false
73);
74
75/* @brief computes only the gradient correction part of the linearUpwind face value,
76** `(Cf - C_U) & grad(phi)_U`, into dst (without the upwind cell value). Boundary faces are set to
77** zero, matching OpenFOAM which corrects only coupled patches. Used for the implicit deferred
78** correction (the explicit RHS source added by the divergence operator).
79**
80** @pre src.correctBoundaryConditions() must have been called by the caller so that
81** processor-boundary ghost values are up to date before the gradient is computed.
82*/
83template<typename ValueType>
85 const VolumeField<ValueType>& src,
86 const SurfaceField<scalar>& flux,
87 const SurfaceField<Vec3>& faceDeltaOwner,
88 const SurfaceField<Vec3>& faceDeltaNeighbour,
90 const bool cellLimitedGradient = false
91);
92
93// @tparam CellLimited when true the gradient correction is built from the cell-limited (minmod,
94// k=1) gradient rather than the unlimited Gauss-Green gradient — this is the "linearUpwindV"
95// scheme, a directionally-bounded vector reconstruction. Only meaningful for Vec3 fields; the
96// scalar path ignores it.
97template<typename ValueType, bool CellLimited = false>
99 public SurfaceInterpolationFactory<ValueType>::template Register<
100 LinearUpwind<ValueType, CellLimited>>
101{
104
105public:
106
107 LinearUpwind(const Executor& exec, const UnstructuredMesh& mesh, Input input)
108 : Base(exec, mesh), geometryScheme_(GeometryScheme::readOrCreate(mesh)),
109 gradSchemeName_(readGradSchemeName(input))
110 {
111 // Opt in to the geometry scheme's per-internal-face cell-to-face offset vectors. These are
112 // computed lazily and only for schemes that need them, so non-linearUpwind runs never
113 // allocate them. Done in the constructor — while the mesh centres are still alive — because
114 // the geometry scheme frees those centres on the first read of any cached geometry field.
115 geometryScheme_->ensureFaceDeltas();
116 };
117
118 static std::string name() { return CellLimited ? "linearUpwindV" : "linearUpwind"; }
119
120 static std::string doc()
121 {
122 return CellLimited ? "linearUpwindV interpolation (cell-limited gradient correction)"
123 : "linearUpwind interpolation";
124 }
125
126 static std::string schema() { return "none"; }
127
129 [[maybe_unused]] const VolumeField<ValueType>& src,
130 [[maybe_unused]] SurfaceField<ValueType>& dst
131 ) const override
132 {
133 NF_ERROR_EXIT("linearUpwind interpolation scheme requires a faceFlux");
134 }
135
137 const SurfaceField<scalar>& flux,
138 const VolumeField<ValueType>& src,
140 ) const override
141 {
143 src,
144 flux,
145 geometryScheme_->faceDeltaOwner(),
146 geometryScheme_->faceDeltaNeighbour(),
147 dst,
148 CellLimited
149 );
150 }
151
152 // linearUpwind shares upwind's implicit weights; the gradient correction is an explicit
153 // (deferred) term applied through interpolate() above, mirroring OpenFOAM's corrected scheme.
155 {
156 NF_ERROR_EXIT("linearUpwind interpolation scheme requires a faceFlux");
157 }
158
159 void weight(
160 const SurfaceField<scalar>& faceFlux,
161 const VolumeField<ValueType>& src,
162 SurfaceField<scalar>& weights
163 ) const override
164 {
165 computeUpwindInterpolationWeights(faceFlux, src, weights);
166 }
167
168 // linearUpwind carries an explicit gradient correction beyond the upwind weights.
169 bool corrected() const override { return true; }
170
172 const SurfaceField<scalar>& faceFlux,
173 const VolumeField<ValueType>& src,
175 ) const override
176 {
178 src,
179 faceFlux,
180 geometryScheme_->faceDeltaOwner(),
181 geometryScheme_->faceDeltaNeighbour(),
182 corr,
183 CellLimited
184 );
185 }
186
187 std::unique_ptr<SurfaceInterpolationFactory<ValueType>> clone() const override
188 {
189 return std::make_unique<LinearUpwind>(*this);
190 }
191
192private:
193
194 // The OpenFOAM scheme spec is "linearUpwind <gradScheme>"; NeoN currently has a single
195 // (Gauss-Green) gradient scheme, so the name is read for spec-compatibility but not used to
196 // select a scheme. Returns a default when absent.
197 static std::string readGradSchemeName(Input& input)
198 {
199 if (std::holds_alternative<NeoN::TokenList>(input))
200 {
201 auto& tokens = std::get<NeoN::TokenList>(input);
202 if (tokens.peekIs<std::string>())
203 {
204 return tokens.next<std::string>();
205 }
206 }
207 return "Gauss";
208 }
209
210 const std::shared_ptr<GeometryScheme> geometryScheme_;
211 std::string gradSchemeName_;
212};
213
214} // namespace NeoN::finiteVolume::cellCentred
215
216namespace NeoN
217{
218
219namespace fvcc = finiteVolume::cellCentred;
220
221template class fvcc::LinearUpwind<scalar>;
222template class fvcc::LinearUpwind<Vec3>;
223// linearUpwindV: cell-limited gradient reconstruction, vector fields only.
224template class fvcc::LinearUpwind<Vec3, true>;
225
226}
A class for the representation of a 3x3 tensor.
Definition tensor.hpp:26
Represents an unstructured mesh in NeoN.
A class for the representation of a 3D Vec3.
Definition vec3.hpp:24
LinearUpwind(const Executor &exec, const UnstructuredMesh &mesh, Input input)
void correction(const SurfaceField< scalar > &faceFlux, const VolumeField< ValueType > &src, SurfaceField< ValueType > &corr) const override
void interpolate(const VolumeField< ValueType > &src, SurfaceField< ValueType > &dst) const override
void interpolate(const SurfaceField< scalar > &flux, const VolumeField< ValueType > &src, SurfaceField< ValueType > &dst) const override
void weight(const VolumeField< ValueType > &, SurfaceField< scalar > &) const override
std::unique_ptr< SurfaceInterpolationFactory< ValueType > > clone() const override
void weight(const SurfaceField< scalar > &faceFlux, const VolumeField< ValueType > &src, SurfaceField< scalar > &weights) const override
Represents a surface field in a finite volume method.
Represents a volume field in a finite volume method.
A template class for registering derived classes with a base class.
#define NF_ERROR_EXIT(message)
Macro for printing an error message and aborting the program.
Definition error.hpp:90
void computeUpwindInterpolationWeights(const SurfaceField< scalar > &flux, const VolumeField< ValueType > &src, SurfaceField< scalar > &weights)
void computeLinearUpwindInterpolation(const VolumeField< ValueType > &src, const SurfaceField< scalar > &flux, const SurfaceField< Vec3 > &faceDeltaOwner, const SurfaceField< Vec3 > &faceDeltaNeighbour, SurfaceField< ValueType > &dst, const bool cellLimitedGradient=false)
void computeLinearUpwindCorrection(const VolumeField< ValueType > &src, const SurfaceField< scalar > &flux, const SurfaceField< Vec3 > &faceDeltaOwner, const SurfaceField< Vec3 > &faceDeltaNeighbour, SurfaceField< ValueType > &dst, const bool cellLimitedGradient=false)
Integer types used throughout NeoN.
Definition array.hpp:18
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