NeoN
A framework for CFD software
Loading...
Searching...
No Matches
totalPressure.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 <Kokkos_Core.hpp>
8
17
19{
20
21namespace detail
22{
23
24// Shared kernel behind totalPressure, for the incompressible form
25//
26// p = p0 - 0.5 * (1 - pos0(phi)) * magSqr(U)
27//
28// i.e. on outflow (phi >= 0) the static pressure is the specified total pressure, and on
29// inflow (phi < 0) the dynamic head 0.5*|U|^2 is subtracted so that the *total* pressure of
30// the entering stream is p0. The patch is Dirichlet either way: valueFraction = 1 with
31// refGrad = 0, only the value differs per face.
32//
33// Without a flux (hasFlux == false, the plain correctBoundaryCondition path with no
34// BoundaryContext) every face is treated as outflow, degenerating to a fixedValue at p0.
35// Without a velocity the dynamic head is zero, which is the same degeneration.
36template<typename ValueType>
38 Field<ValueType>& domainVector,
39 const UnstructuredMesh& mesh,
40 std::pair<localIdx, localIdx> range,
41 ValueType p0,
42 View<const NeoN::scalar> boundaryFlux,
43 bool hasFlux,
44 View<const Vec3> boundaryVelocity,
45 bool hasVelocity
46)
47{
48 auto [refGradV, valueV, valueFractionV, refValueV] = views(
49 domainVector.boundaryData().refGrad(),
50 domainVector.boundaryData().value(),
51 domainVector.boundaryData().valueFraction(),
52 domainVector.boundaryData().refValue()
53 );
54 (void)mesh;
55
57 domainVector.exec(),
58 range,
59 NEON_LAMBDA(const localIdx i) {
60 // nvcc forbids an extended __host__ __device__ lambda from FIRST capturing a
61 // variable inside an `if constexpr` body, and the velocity is only referenced
62 // there. Name both captures unconditionally first so the capture happens out
63 // here; the copies are a bool and a view handle, so this costs nothing.
64 [[maybe_unused]] const bool velocityKnown = hasVelocity;
65 [[maybe_unused]] const View<const Vec3> velocity = boundaryVelocity;
66
67 // pos0(phi): 1 on outflow (phi >= 0), 0 on inflow.
68 const bool inflow = hasFlux && boundaryFlux[i] < NeoN::scalar(0);
69
70 ValueType p = p0;
71 if constexpr (std::is_same<ValueType, NeoN::scalar>::value)
72 {
73 if (inflow && velocityKnown)
74 {
75 const Vec3 u = velocity[i];
76 const NeoN::scalar magSqrU = u[0] * u[0] + u[1] * u[1] + u[2] * u[2];
77 p = p0 - NeoN::scalar(0.5) * magSqrU;
78 }
79 }
80
81 valueFractionV[i] = NeoN::scalar(1);
82 refValueV[i] = p;
83 refGradV[i] = NeoN::zero<ValueType>();
84 valueV[i] = p;
85 },
86 "setTotalPressureValue"
87 );
88}
89
90} // namespace detail
91
92// totalPressure fixes the *total* pressure on a patch: the static pressure it imposes is the
93// specified p0 on outflow, and p0 minus the dynamic head on inflow, so a stream entering the
94// domain carries total pressure p0. It mirrors OpenFOAM's incompressible totalPressure
95// (a fixedValue whose value is p0 - 0.5*(1 - pos0(phi))*magSqr(U)).
96//
97// The flux and velocity are looked up by name from the BoundaryContext passed to the
98// context-aware correctBoundaryCondition overload (keys "phi" and "U", both overridable via
99// the dictionary). The plain overload has neither and degenerates to a fixedValue at p0, so a
100// solver that wants the dynamic head must call correctBoundaryConditions(ctx) with phi and U
101// inserted.
102//
103// Not modelled: the compressible forms (psi/rho variants) and a time-varying p0.
104template<typename ValueType>
106 public VolumeBoundaryFactory<ValueType>::template Register<TotalPressure<ValueType>>
107{
109
110public:
111
112 using Base::correctBoundaryCondition;
113
114 // assignable = true: the value is recomputed on every correctBoundaryCondition, so a
115 // downstream overwrite is reversible. fixesValue = true: the patch is Dirichlet on every
116 // face, which is what the pressure equation needs to pin its datum here.
118 : Base(mesh, dict, patchID, {.assignable = true, .fixesValue = true}), mesh_(mesh),
119 p0_(dict.get<ValueType>("p0")), // required: an omitted datum is a case-setup error
120 phiName_(dict.contains("phi") ? dict.get<std::string>("phi") : std::string("phi")),
121 uName_(dict.contains("U") ? dict.get<std::string>("U") : std::string("U"))
122 {}
123
124 // No context => no flux or velocity: a plain fixedValue at p0.
125 virtual void correctBoundaryCondition(Field<ValueType>& domainVector) final
126 {
128 domainVector,
129 mesh_,
130 this->range(),
131 p0_,
133 false,
135 false
136 );
137 }
138
139 // Context-aware: subtract the dynamic head on inflow faces.
140 virtual void
142 {
143 const bool hasFlux = ctx.hasSurfaceScalar(phiName_);
144 const bool hasVelocity = ctx.hasVector(uName_);
145
147 domainVector,
148 mesh_,
149 this->range(),
150 p0_,
151 hasFlux ? ctx.surfaceScalarField(phiName_).boundaryData().value().view()
153 hasFlux,
154 hasVelocity ? ctx.vectorFieldPtr(uName_).boundaryData().value().view()
155 : View<const Vec3> {},
156 hasVelocity
157 );
158 }
159
160 static std::string name() { return "totalPressure"; }
161
162 std::string getName() const override { return name(); }
163
164 static std::string doc()
165 {
166 return "Total-pressure patch: static pressure p0 on outflow, p0 minus the dynamic "
167 "head 0.5*magSqr(U) on inflow, so the entering stream carries total pressure "
168 "p0. Needs phi and U in the BoundaryContext; without them it is a fixedValue "
169 "at p0.";
170 }
171
172 static std::string schema() { return "none"; }
173
174 std::unique_ptr<VolumeBoundaryFactory<ValueType>> clone() const final
175 {
176 return std::make_unique<TotalPressure>(*this);
177 }
178
179private:
180
181 const UnstructuredMesh& mesh_;
182 ValueType p0_;
183 std::string phiName_;
184 std::string uName_;
185};
186
187} // namespace NeoN::finiteVolume::cellCentred::volumeBoundary
A class representing a dictionary that stores key-value pairs.
Represents the domain fields for a computational domain.
Definition field.hpp:34
const BoundaryData< ValueType > & boundaryData() const
Definition field.hpp:96
const Executor & exec() const
Definition field.hpp:101
Represents an unstructured mesh in NeoN.
A class for the representation of a 3D Vec3.
Definition vec3.hpp:24
Carries named field references for context-aware boundary conditions.
std::pair< localIdx, localIdx > range() const
VolumeBoundaryFactory(const UnstructuredMesh &mesh, const Dictionary &dict, localIdx patchID, BoundaryAttributes attributes)
virtual void correctBoundaryCondition(Field< ValueType > &domainVector) final
virtual void correctBoundaryCondition(Field< ValueType > &domainVector, const BoundaryContext &ctx) final
TotalPressure(const UnstructuredMesh &mesh, const Dictionary &dict, localIdx patchID)
std::unique_ptr< VolumeBoundaryFactory< ValueType > > clone() const final
A template class for registering derived classes with a base class.
void setTotalPressureValue(Field< ValueType > &domainVector, const UnstructuredMesh &mesh, std::pair< localIdx, localIdx > range, ValueType p0, View< const NeoN::scalar > boundaryFlux, bool hasFlux, View< const Vec3 > boundaryVelocity, bool hasVelocity)
KOKKOS_INLINE_FUNCTION T zero()
float scalar
Definition scalar.hpp:17
void parallelFor(const ExecutorType &, std::pair< localIdx, localIdx > range, const Kernel &kernel, std::string name)
int32_t localIdx
Definition label.hpp:50
auto views(Types &... args)
Unpacks all views of the passed classes.
Definition view.hpp:108
#define NEON_LAMBDA