NeoN
A framework for CFD software
Loading...
Searching...
No Matches
slipSymmetry.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
14
15// Shared implementation behind the `slip` and `symmetry` boundary conditions: they apply the same
16// operator and differ only in their registered name and in where they may be applied (slip on a
17// wall/regular patch, symmetry on a symmetry-plane patch). The operator is, per face:
18// scalar => zero-gradient
19// vector => tangential projection of the boundary value (the normal component is removed), plus a
20// normal-damping surface-normal gradient that drives the normal component of the cell
21// value towards zero.
22//
23// The normal damping can be realised two ways, selected by NormalDamping:
24// - Deferred: written into refGrad as -deltaCoeffs*(v·n)*n, so it enters the per-component RHS
25// through the existing fixed-gradient assembly. Keeps the shared scalar matrix + multi-RHS
26// solve, at the cost of lagging the normal coupling by one outer iteration.
27// - Implicit: refGrad is left zero here; the BoundaryAttributes::transformImplicit flag signals
28// the Laplacian assembly to add a per-component diagonal correction (γ|S|·deltaCoeffs·|n_c|)
29// instead, which the solver applies column-by-column. Fully implicit, single matrix, but the
30// solve runs segregated rather than multi-RHS.
31//
32// NOTE: a future Tensor specialization (e.g. for a transported Reynolds-stress field) must use the
33// full reflective transform (T + H·T·H)/2 with H = I - 2 n⊗n, NOT a per-component projection.
35{
36
37enum class NormalDamping
38{
39 Deferred,
41};
42
56inline bool readTransformImplicit(const Dictionary& dict)
57{
58 const std::string key = "implicit";
59 if (!dict.contains(key)) return true;
60 if (dict.isType<bool>(key)) return dict.get<bool>(key);
61 if (dict.isType<int>(key)) return dict.get<int>(key) != 0;
62 if (dict.isType<std::string>(key))
63 {
64 const std::string v = dict.get<std::string>(key);
65 return (v == "true" || v == "yes" || v == "on" || v == "1");
66 }
67 return false;
68}
69
71inline NormalDamping normalDampingMode(bool implicit)
72{
74}
75
76// Primary declaration
77template<typename ValueType>
79 Field<ValueType>& domainVector,
80 const UnstructuredMesh& mesh,
81 std::pair<localIdx, localIdx> range,
82 NormalDamping mode
83);
84
85// --- Scalar specialization: zero-gradient (mode is irrelevant; no normal component) ---
86template<>
88 Field<NeoN::scalar>& domainVector,
89 const UnstructuredMesh& mesh,
90 std::pair<localIdx, localIdx> range,
91 [[maybe_unused]] NormalDamping mode
92)
93{
94 const auto internalV = domainVector.internalVector().view();
95
96 auto [refGradV, valueV, valueFractionV, refValueV, boundaryFaceOwnersV] = views(
97 domainVector.boundaryData().refGrad(),
98 domainVector.boundaryData().value(),
99 domainVector.boundaryData().valueFraction(),
100 domainVector.boundaryData().refValue(),
101 mesh.boundaryMesh().faceOwners()
102 );
103
105 domainVector.exec(),
106 range,
107 NEON_LAMBDA(const localIdx i) {
108 const localIdx owner = boundaryFaceOwnersV[i];
109 const auto v = internalV[owner];
110
111 refValueV[i] = v;
112 valueV[i] = v;
113 valueFractionV[i] = 0.0;
114 refGradV[i] = 0.0;
115 },
116 "setSlipSymmetryValue(scalar)"
117 );
118}
119
120// --- Vec3 specialization: tangential projection + normal damping ---
121template<>
123 Field<NeoN::Vec3>& domainVector,
124 const UnstructuredMesh& mesh,
125 std::pair<localIdx, localIdx> range,
126 NormalDamping mode
127)
128{
129 const auto internalV = domainVector.internalVector().view();
130 const bool deferred = (mode == NormalDamping::Deferred);
131
132 auto
133 [refGradV,
134 valueV,
135 valueFractionV,
136 refValueV,
137 boundaryFaceOwnersV,
138 faceUnitNormalsV,
139 deltaCoeffsV] =
140 views(
141 domainVector.boundaryData().refGrad(),
142 domainVector.boundaryData().value(),
143 domainVector.boundaryData().valueFraction(),
144 domainVector.boundaryData().refValue(),
145 mesh.boundaryMesh().faceOwners(),
148 );
149
151 domainVector.exec(),
152 range,
153 NEON_LAMBDA(const localIdx i) {
154 const localIdx owner = boundaryFaceOwnersV[i];
155 const auto v = internalV[owner];
156 const auto n = faceUnitNormalsV[i];
157
158 const auto un = (v & n); // normal component (scalar)
159 const auto vtan = v - n * un; // tangential projection (remove normal component)
160
161 // Explicit boundary value: used by convection / face interpolation (no penetration).
162 refValueV[i] = vtan;
163 valueV[i] = vtan;
164
165 // Keep the diagonal contribution component-isotropic (zero here) so the shared scalar
166 // matrix and its multi-RHS solve are preserved.
167 valueFractionV[i] = 0.0;
168
169 // Deferred mode: normal damping as the surface-normal gradient -deltaCoeffs*(v·n)*n
170 // (purely normal, so the tangential components stay zero-gradient). Implicit mode:
171 // leave refGrad zero — the damping is applied as a per-component diagonal correction
172 // during assembly/solve.
173 refGradV[i] = deferred ? n * (-deltaCoeffsV[i] * un) : NeoN::zero<NeoN::Vec3>();
174 },
175 "setSlipSymmetryValue(Vec3)"
176 );
177}
178
179} // namespace NeoN::finiteVolume::cellCentred::volumeBoundary::detail
const vectorVector & faceUnitNormals() const
Get the field of face unit normal vectors.
const scalarVector & deltaCoeffs() const
Get the field of delta coefficients.
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.
T & get(const std::string &key)
Retrieves the value associated with the given key, casting it to the specified type.
bool isType(const std::string &key) const
Checks if the value associated with the given key is of given Type T.
bool contains(const std::string &key) const
Checks if the given key is present in the dictionary.
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.
NormalDamping normalDampingMode(bool implicit)
Map the implicit flag onto the NormalDamping mode.
void setSlipSymmetryValue(Field< ValueType > &domainVector, const UnstructuredMesh &mesh, std::pair< localIdx, localIdx > range, NormalDamping mode)
void setSlipSymmetryValue< NeoN::scalar >(Field< NeoN::scalar > &domainVector, const UnstructuredMesh &mesh, std::pair< localIdx, localIdx > range, NormalDamping mode)
void setSlipSymmetryValue< NeoN::Vec3 >(Field< NeoN::Vec3 > &domainVector, const UnstructuredMesh &mesh, std::pair< localIdx, localIdx > range, NormalDamping mode)
bool readTransformImplicit(const Dictionary &dict)
Read the "implicit" flag from a slip/symmetry patch dictionary.
@ Implicit
normal damping via per-component diagonal correction (segregated solve)
@ Deferred
normal damping via refGrad -> per-component RHS (multi-RHS friendly)
int32_t localIdx
Definition label.hpp:50
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