NeoN
A framework for CFD software
Loading...
Searching...
No Matches
inletOutlet.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
16
18{
19
20namespace detail
21{
22// Shared kernel behind inletOutlet. Per boundary face it switches between two mixed-BC states
23// according to the sign of the face flux phi:
24// inflow (phi < 0): Dirichlet -> valueFraction = 1, refValue = inletValue, refGrad = 0
25// outflow (phi >= 0): zeroGradient -> valueFraction = 0, refGrad = 0
26// The explicit face value is the evaluated mixed value used by convection/interpolation:
27// value = valueFraction*inletValue + (1 - valueFraction)*(phi_C + refGrad/delta)
28// with refGrad = 0 this is inletValue on inflow and the owner-cell value on outflow.
29//
30// When no flux is available (hasFlux == false, e.g. the plain correctBoundaryCondition path with
31// no BoundaryContext) every face is treated as outflow, degenerating to a pure zeroGradient BC.
32template<typename ValueType>
34 Field<ValueType>& domainVector,
35 const UnstructuredMesh& mesh,
36 std::pair<localIdx, localIdx> range,
37 ValueType inletValue,
38 View<const NeoN::scalar> boundaryFlux,
39 bool hasFlux
40)
41{
42 const auto internalV = domainVector.internalVector().view();
43
44 auto [refGradV, valueV, valueFractionV, refValueV, boundaryFaceOwnersV] = views(
45 domainVector.boundaryData().refGrad(),
46 domainVector.boundaryData().value(),
47 domainVector.boundaryData().valueFraction(),
48 domainVector.boundaryData().refValue(),
50 );
51
53 domainVector.exec(),
54 range,
55 NEON_LAMBDA(const localIdx i) {
56 const localIdx owner = boundaryFaceOwnersV[i];
57 const auto internal = internalV[owner];
58
59 // Inflow where the face flux is negative; otherwise outflow (zero-gradient).
60 const NeoN::scalar valueFraction = (hasFlux && boundaryFlux[i] < 0.0) ? 1.0 : 0.0;
61
62 valueFractionV[i] = valueFraction;
63 refValueV[i] = inletValue;
64 refGradV[i] = NeoN::zero<ValueType>();
65 valueV[i] = inletValue * valueFraction + internal * (1.0 - valueFraction);
66 },
67 "setInletOutletValue"
68 );
69}
70
71}
72
73// inletOutlet switches between a fixed inlet value (on inflow faces) and zero-gradient
74// extrapolation (on outflow faces), decided per face by the sign of the face flux phi. It is the
75// generic-transport outlet counterpart to fixedValue and mirrors OpenFOAM's inletOutlet
76// (a mixedFvPatchField with valueFraction = neg(phi), refGrad = 0).
77//
78// The flux is looked up by name (key "phi", default "phi") from the BoundaryContext passed to the
79// context-aware correctBoundaryCondition overload. The plain overload has no flux and degenerates
80// to zeroGradient, so a solver that wants the dynamic switch must call the field's
81// correctBoundaryConditions(ctx) with phi inserted into the context.
82template<typename ValueType>
84 public VolumeBoundaryFactory<ValueType>::template Register<InletOutlet<ValueType>>
85{
86 using Base =
88
89public:
90
91 using Base::correctBoundaryCondition;
92
94
95 // assignable = true: the boundary value is recomputed every correctBoundaryCondition call, so
96 // any downstream overwrite is reversible. fixesValue = false: the per-face
97 // refValue/valueFraction drive the operators via the mixed-BC kernels; a global Dirichlet flag
98 // would over-constrain mixed-flow patches.
99 InletOutlet(const UnstructuredMesh& mesh, const Dictionary& dict, localIdx patchID)
100 : Base(mesh, dict, patchID, {.assignable = true, .fixesValue = false}), mesh_(mesh),
101 inletValue_(dict.get<ValueType>("inletValue")),
102 phiName_(dict.contains("phi") ? dict.get<std::string>("phi") : std::string("phi"))
103 {}
104
105 // No context => no flux available: behave as zero-gradient (all faces treated as outflow).
106 virtual void correctBoundaryCondition(Field<ValueType>& domainVector) final
107 {
109 domainVector, mesh_, this->range(), inletValue_, View<const NeoN::scalar> {}, false
110 );
111 }
112
113 // Context-aware: read the face flux phi and switch inflow/outflow per face.
114 virtual void
116 {
117 if (ctx.hasSurfaceScalar(phiName_))
118 {
119 const auto& phi = ctx.surfaceScalarField(phiName_);
121 domainVector,
122 mesh_,
123 this->range(),
124 inletValue_,
125 phi.boundaryData().value().view(),
126 true
127 );
128 }
129 else
130 {
131 correctBoundaryCondition(domainVector);
132 }
133 }
134
135 static std::string name() { return "inletOutlet"; }
136
137 std::string getName() const override { return name(); }
138
139 static std::string doc()
140 {
141 return "Inlet/outlet: fixed inletValue on inflow faces, zero-gradient on outflow faces "
142 "(switched per face by the sign of the face flux phi).";
143 }
144
145 static std::string schema() { return "none"; }
146
147 virtual std::unique_ptr<VolumeBoundaryFactory<ValueType>> clone() const final
148 {
149 return std::make_unique<InletOutlet>(*this);
150 }
151
152private:
153
154 const UnstructuredMesh& mesh_;
155 ValueType inletValue_;
156 std::string phiName_;
157};
158
159} // namespace NeoN::finiteVolume::cellCentred::volumeBoundary
const labelVector & faceOwners() const
Get the list of labels of owner cells of boundary faces.
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
const Vector< ValueType > & internalVector() const
Definition field.hpp:90
Represents an unstructured mesh in NeoN.
const BoundaryMesh & boundaryMesh() const
Get the boundary mesh.
Carries named field references for context-aware boundary conditions.
virtual void correctBoundaryCondition(Field< ValueType > &domainVector) final
virtual void correctBoundaryCondition(Field< ValueType > &domainVector, const BoundaryContext &ctx) final
InletOutlet(const UnstructuredMesh &mesh, const Dictionary &dict, localIdx patchID)
virtual std::unique_ptr< VolumeBoundaryFactory< ValueType > > clone() const final
A template class for registering derived classes with a base class.
void setInletOutletValue(Field< ValueType > &domainVector, const UnstructuredMesh &mesh, std::pair< localIdx, localIdx > range, ValueType inletValue, View< const NeoN::scalar > boundaryFlux, bool hasFlux)
int32_t localIdx
Definition label.hpp:50
float scalar
Definition scalar.hpp:17
void parallelFor(const ExecutorType &, std::pair< localIdx, localIdx > range, const Kernel &kernel, std::string name)
auto views(Types &... args)
Unpacks all views of the passed classes.
Definition view.hpp:107
#define NEON_LAMBDA