Documentation 6b54b78464
Loading...
Searching...
No Matches
turb_sa_edge_flux.hpp
Go to the documentation of this file.
1/*!
2 * \file turb_sa_edge_flux.hpp
3 * \brief Spalart-Allmaras model as a third-layer scalar flux, see numerics/scalar/scalar_edge_flux.hpp.
4 * \author P. Gomes
5 * \version 8.5.0 "Harrier"
6 *
7 * SU2 Project Website: https://su2code.github.io
8 *
9 * The SU2 Project is maintained by the SU2 Foundation
10 * (http://su2foundation.org)
11 *
12 * Copyright 2012-2026, SU2 Contributors (cf. AUTHORS.md)
13 *
14 * SU2 is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * SU2 is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with SU2. If not, see <http://www.gnu.org/licenses/>.
26 */
27
28#pragma once
29
30#include "../scalar/scalar_edge_flux.hpp"
31
32/*!
33 * \class CScalarFlux_SA
34 * \ingroup ConvDiscr
35 * \ingroup ViscDiscr
36 * \brief Convection and diffusion of the Spalart-Allmaras model, non-conservative and with a
37 * diagonal (but asymmetric) diffusion coefficient.
38 * \note SA writes its own convective term rather than using the inherited CUpwScalarFlux one,
39 * because with stochastic backscatter active (nVar 4) the three Langevin equations are
40 * advected with a centered flux, unlike the plain upwind SA equation itself.
41 */
42template <class Double, class FlowIndices, int nDim, size_t nVar>
44 : public CUpwScalarBase<Double, CScalarFlux_SA<Double, FlowIndices, nDim, nVar>, FlowIndices, nDim, nVar> {
45 public:
46 static constexpr bool Conservative = false;
47 static constexpr bool DiagonalDiffusion = true;
48 static constexpr bool DiffusionReadsDensity = true; /*!< \brief The kinematic viscosities below. */
49
51 using Int = typename Base::Int;
52
53 explicit CScalarFlux_SA(const CConfig& config)
54 : Base(config),
55 negativeSA(config.GetSAParsedOptions().version == SA_OPTIONS::NEG),
56 accurateJacobians(config.GetUse_Accurate_Turb_Jacobians()) {}
57
58 private:
59 static constexpr passivedouble sigma = 2.0 / 3.0; /*!< \brief Constant of the diffusion term. */
60 static constexpr passivedouble cb2 = 0.622; /*!< \brief Constant of the diffusion term. */
61 static constexpr passivedouble cn1 = 16.0; /*!< \brief Constant of the SA-neg diffusion correction. */
62
63 /*!< \brief Whether nu_tilde may go negative (SA_OPTIONS= NEGATIVE), which needs the fn-corrected
64 * diffusion coefficient below to keep the diffusion term from turning anti-diffusive. */
65 const bool negativeSA;
66 const bool accurateJacobians;
67
68 public:
69 /*!
70 * \brief SA convection, plus the centered advection of the backscatter equations when nVar > 1.
71 */
72 template <class VariableType, size_t Size>
73 FORCEINLINE void finalizeFlux(const FlowIndices&, const ScalarFluxOptions& opt, Int, const EdgeSide<VariableType>&,
74 Int, const EdgeSide<VariableType>&, const Double& a0, const Double& a1,
76 EdgeResidual<Double, nVar>& res) const {
77 const Double flux = a0 * phi.i.all(0) + a1 * phi.j.all(0);
78
79 res.flux_i(0) += flux;
80 if (!opt.oneSided) res.flux_j(0) -= flux;
81
82 if (opt.implicit) {
83 res.jac_ii(0, 0) += a0;
84 if (!opt.oneSided) {
85 res.jac_ij(0, 0) += a1;
86 res.jac_ji(0, 0) -= a0;
87 res.jac_jj(0, 0) -= a1;
88 }
89 }
90
91 /*--- Stochastic backscatter: three Langevin equations, advected with the mean of the two
92 * upwinding weights and with no diffusion. ---*/
93 const Double avg = 0.5 * (a0 + a1);
94 for (size_t iVar = 1; iVar < res.nVar; ++iVar) {
95 const Double flux_bs = avg * (phi.i.all(iVar) + phi.j.all(iVar));
96
97 res.flux_i(iVar) += flux_bs;
98 if (!opt.oneSided) res.flux_j(iVar) -= flux_bs;
99
100 if (opt.implicit) {
101 res.jac_ii(iVar, iVar) += avg;
102 if (!opt.oneSided) {
103 res.jac_ij(iVar, iVar) += avg;
104 res.jac_ji(iVar, iVar) -= avg;
105 res.jac_jj(iVar, iVar) -= avg;
106 }
107 }
108 }
109 }
110
111 /*!
112 * \brief fn, the positivity-preserving correction to the SA-neg diffusion coefficient
113 * (Allmaras, Johnson & Spalart), 1 when nu_tilde is not negative enough to need it.
114 */
115 FORCEINLINE Double fn(const Double& zeta) const {
116 if (!negativeSA || zeta >= 0.0) return 1.0;
117 const Double zeta3 = zeta * zeta * zeta;
118 return (cn1 + zeta3) / (cn1 - zeta3);
119 }
120
121 /*!
122 * \brief Diffusion coefficients of both orientations of the edge.
123 * \note The coefficient is not symmetric: it uses the transported variable of the row it is
124 * going to be used for (the quadratic, non-conservative part of the diffusion term).
125 * Coefficients past index 0 are left at zero, the backscatter equations have no diffusion.
126 */
127 template <class VariableType>
129 const EdgeSide<VariableType>& side_i, Int jPoint,
130 const EdgeSide<VariableType>& side_j,
131 const CPair<Double>& rho) const {
132 const Double nu_i = gatherVariables(iPoint, side_i.flowNodes->GetPrimitive(), idx.LaminarViscosity()) / rho.i;
133 const Double nu_j = gatherVariables(jPoint, side_j.flowNodes->GetPrimitive(), idx.LaminarViscosity()) / rho.j;
134
135 const Double nuTilde_i = gatherVariables(iPoint, side_i.scalarNodes.GetSolution(), 0);
136 const Double nuTilde_j = gatherVariables(jPoint, side_j.scalarNodes.GetSolution(), 0);
137
138 const Double nu_ij = 0.5 * (nu_i + nu_j);
139 const Double nuTilde_ij = 0.5 * (nuTilde_i + nuTilde_j);
140
141 /*--- fn is only ever != 1 under SA_OPTIONS= NEGATIVE, and then only where the row's own
142 * nu_tilde pulls the coefficient negative; without it (nu + nu_tilde going anti-diffusive)
143 * the equation diverges, see Allmaras, Johnson & Spalart's negative SA modification. ---*/
144 const Double fn_i = fn(((1.0 + cb2) * nuTilde_ij - cb2 * nuTilde_i) / nu_ij);
145 const Double fn_j = fn(((1.0 + cb2) * nuTilde_ij - cb2 * nuTilde_j) / nu_ij);
146
147 Vector<Double, nVar> D_i, D_j;
148 D_i(0) = (nu_ij + (1.0 + cb2) * nuTilde_ij * fn_i - cb2 * nuTilde_i * fn_i) / sigma;
149 D_j(0) = (nu_ij + (1.0 + cb2) * nuTilde_ij * fn_j - cb2 * nuTilde_j * fn_j) / sigma;
150 for (size_t iVar = 1; iVar < nVar; ++iVar) {
151 D_i(iVar) = 0.0;
152 D_j(iVar) = 0.0;
153 }
154 return {D_i, D_j};
155 }
156
157 /*!
158 * \brief Extra Jacobian terms from the dependence of the diffusion coefficient on nu_tilde.
159 * \note Skipped for SA-neg, whose fn-corrected coefficient was found (upstream, pre-migration)
160 * to diverge with exact Jacobians; frozen (TSL-only) Jacobians are used there instead.
161 * Skipped for standard SA too unless USE_ACCURATE_TURB_JACOBIANS is set, matching the
162 * pre-migration default of using frozen Jacobians there as well.
163 */
164 template <class Coefficients, size_t Size>
165 FORCEINLINE void coefficientJacobians(const ScalarFluxOptions& opt, const Coefficients&,
166 const Vector<Double, Size>& projGrad, EdgeResidual<Double, nVar>& res) const {
167 if (negativeSA || !accurateJacobians) return;
168
169 /*--- d(diffusion coefficient of i)/d(nu_tilde_i), and its counterpart w.r.t. nu_tilde_j;
170 * the coefficient of j is the same expression with i and j swapped, so the same two
171 * derivatives apply to both orientations. Both are per-edge constants, so the coefficients
172 * themselves are not read here. ---*/
173 const Double dDC_dNuTilde_i = ((1.0 + cb2) * 0.5 - cb2) / sigma;
174 const Double dDC_dNuTilde_j = (1.0 + cb2) * 0.5 / sigma;
175
176 res.jac_ii(0, 0) -= dDC_dNuTilde_i * projGrad(0);
177 if (opt.oneSided) return;
178
179 res.jac_ij(0, 0) -= dDC_dNuTilde_j * projGrad(0);
180 res.jac_ji(0, 0) += dDC_dNuTilde_j * projGrad(0);
181 res.jac_jj(0, 0) += dDC_dNuTilde_i * projGrad(0);
182 }
183};
A templated matrix/vector-like object.
Definition C2DContainer.hpp:374
Main class for defining the problem; basically this class reads the configuration file,...
Definition CConfig.hpp:64
su2double GetPrimitive(unsigned long iPoint, unsigned long iVar) const final
Get a primitive variable.
Definition CFlowVariable.hpp:95
Convection and diffusion of the Spalart-Allmaras model, non-conservative and with a diagonal (but asy...
Definition turb_sa_edge_flux.hpp:44
CPair< Vector< Double, nVar > > coefficients(const FlowIndices &idx, Int iPoint, const EdgeSide< VariableType > &side_i, Int jPoint, const EdgeSide< VariableType > &side_j, const CPair< Double > &rho) const
Diffusion coefficients of both orientations of the edge.
Definition turb_sa_edge_flux.hpp:128
static constexpr bool Conservative
Definition turb_sa_edge_flux.hpp:46
static constexpr bool DiagonalDiffusion
Definition turb_sa_edge_flux.hpp:47
void finalizeFlux(const FlowIndices &, const ScalarFluxOptions &opt, Int, const EdgeSide< VariableType > &, Int, const EdgeSide< VariableType > &, const Double &a0, const Double &a1, const CPair< Double > &, const CPair< CScalarValues< Double, Size > > &phi, EdgeResidual< Double, nVar > &res) const
SA convection, plus the centered advection of the backscatter equations when nVar > 1.
Definition turb_sa_edge_flux.hpp:73
typename Base::Int Int
Definition turb_sa_edge_flux.hpp:51
Double fn(const Double &zeta) const
fn, the positivity-preserving correction to the SA-neg diffusion coefficient (Allmaras,...
Definition turb_sa_edge_flux.hpp:115
static constexpr bool DiffusionReadsDensity
The kinematic viscosities below.
Definition turb_sa_edge_flux.hpp:48
CScalarFlux_SA(const CConfig &config)
Definition turb_sa_edge_flux.hpp:53
void coefficientJacobians(const ScalarFluxOptions &opt, const Coefficients &, const Vector< Double, Size > &projGrad, EdgeResidual< Double, nVar > &res) const
Extra Jacobian terms from the dependence of the diffusion coefficient on nu_tilde.
Definition turb_sa_edge_flux.hpp:165
Upwind convection and diffusion of a transported scalar, accumulated into one residual,...
Definition scalar_edge_flux.hpp:316
typename CLaneTraits< Double_ >::Int Int
Definition scalar_edge_flux.hpp:319
double passivedouble
Definition code_config.hpp:129
#define FORCEINLINE
Definition code_config.hpp:44
Double gatherVariables(Int iPoint, const Container &vars, size_t iVar=0)
Gather a single variable, from column iVar (0 by default) of row iPoint of a 2D container,...
Definition util.hpp:277
SA_OPTIONS
SA Options.
Definition option_structure.hpp:1264
@ NEG
Negative SA.
Simple pair type for i/j variables.
Definition util.hpp:130
T i
Definition util.hpp:131
T j
Definition util.hpp:131
Thin wrapper giving a Vector the all(iVar) accessor the MUSCL reconstruction helpers expect (see CCom...
Definition scalar_edge_flux.hpp:133
Residual of one edge, accumulated by the convective and the diffusive terms.
Definition util.hpp:169
Vector< Double, Size > flux_j
Definition util.hpp:176
Matrix< Double, Size, Size > jac_jj
Definition util.hpp:177
Matrix< Double, Size, Size > jac_ji
Definition util.hpp:177
const size_t nVar
Definition util.hpp:178
Vector< Double, Size > flux_i
Definition util.hpp:176
Matrix< Double, Size, Size > jac_ii
Definition util.hpp:177
Matrix< Double, Size, Size > jac_ij
Definition util.hpp:177
Locates the data of one endpoint of an edge.
Definition scalar_edge_flux.hpp:42
const CFlowVariable * flowNodes
Flow variables, null for solid heat transfer.
Definition scalar_edge_flux.hpp:44
const VariableType & scalarNodes
Scalar solver variables.
Definition scalar_edge_flux.hpp:43
Loop invariant flags for a scalar edge flux, built once outside the edge loop so the compiler can uns...
Definition scalar_edge_flux.hpp:55
bool implicit
Whether the Jacobians are assembled, and so computed.
Definition scalar_edge_flux.hpp:60
bool oneSided
Whether only the row of i is assembled.
Definition scalar_edge_flux.hpp:63