Skip to content

Commit ffc0e1f

Browse files
authored
Merge pull request #2525 from su2code/feature_sa_diffusion
Improving the discretisation of the SA non-linear (cross) diffusion term $(\tilde{\nu})^2$
2 parents 814f21a + 4145705 commit ffc0e1f

File tree

18 files changed

+250
-124
lines changed

18 files changed

+250
-124
lines changed

Common/include/CConfig.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,7 @@ class CConfig {
591591
MUSCL_AdjTurb; /*!< \brief MUSCL scheme for the adj turbulence equations.*/
592592
bool MUSCL_Species; /*!< \brief MUSCL scheme for the species equations.*/
593593
bool Use_Accurate_Jacobians; /*!< \brief Use numerically computed Jacobians for AUSM+up(2) and SLAU(2). */
594+
bool Use_Accurate_Turb_Jacobians; /*!< \brief Use numerically computed Jacobians for standard SA turbulence model. */
594595
bool EulerPersson; /*!< \brief Boolean to determine whether this is an Euler simulation with Persson shock capturing. */
595596
bool FSI_Problem = false,/*!< \brief Boolean to determine whether the simulation is FSI or not. */
596597
Multizone_Problem; /*!< \brief Boolean to determine whether we are solving a multizone problem. */
@@ -4516,6 +4517,12 @@ class CConfig {
45164517
*/
45174518
bool GetUse_Accurate_Jacobians(void) const { return Use_Accurate_Jacobians; }
45184519

4520+
/*!
4521+
* \brief Get whether to "Use Accurate Jacobians" for Standard SA turbulence model.
4522+
* \return yes/no.
4523+
*/
4524+
bool GetUse_Accurate_Turb_Jacobians(void) const { return Use_Accurate_Turb_Jacobians; }
4525+
45194526
/*!
45204527
* \brief Get the kind of integration scheme (explicit or implicit)
45214528
* for the flow equations.

Common/include/linear_algebra/CSysMatrix.hpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,22 @@ class CSysMatrix {
553553
SetBlock<MatrixType, false>(block_i, block_j, val_block, alpha);
554554
}
555555

556+
/*!
557+
* \brief Returns the 4 blocks ii, ij, ji, jj used by "UpdateBlocks".
558+
* \note This method assumes an FVM-type sparse pattern.
559+
* \param[in] edge - Index of edge that connects iPoint and jPoint.
560+
* \param[in] iPoint - Row to which we add the blocks.
561+
* \param[in] jPoint - Row from which we subtract the blocks.
562+
* \param[out] bii, bij, bji, bjj - Blocks of the matrix.
563+
*/
564+
inline void GetBlocks(unsigned long iEdge, unsigned long iPoint, unsigned long jPoint, ScalarType*& bii,
565+
ScalarType*& bij, ScalarType*& bji, ScalarType*& bjj) {
566+
bii = &matrix[dia_ptr[iPoint] * nVar * nEqn];
567+
bjj = &matrix[dia_ptr[jPoint] * nVar * nEqn];
568+
bij = &matrix[edge_ptr(iEdge, 0) * nVar * nEqn];
569+
bji = &matrix[edge_ptr(iEdge, 1) * nVar * nEqn];
570+
}
571+
556572
/*!
557573
* \brief Update 4 blocks ii, ij, ji, jj (add to i* sub from j*).
558574
* \note This method assumes an FVM-type sparse pattern.
@@ -566,10 +582,8 @@ class CSysMatrix {
566582
template <class MatrixType, class OtherType = ScalarType>
567583
inline void UpdateBlocks(unsigned long iEdge, unsigned long iPoint, unsigned long jPoint, const MatrixType& block_i,
568584
const MatrixType& block_j, OtherType scale = 1) {
569-
ScalarType* bii = &matrix[dia_ptr[iPoint] * nVar * nEqn];
570-
ScalarType* bjj = &matrix[dia_ptr[jPoint] * nVar * nEqn];
571-
ScalarType* bij = &matrix[edge_ptr(iEdge, 0) * nVar * nEqn];
572-
ScalarType* bji = &matrix[edge_ptr(iEdge, 1) * nVar * nEqn];
585+
ScalarType *bii, *bij, *bji, *bjj;
586+
GetBlocks(iEdge, iPoint, jPoint, bii, bij, bji, bjj);
573587

574588
unsigned long iVar, jVar, offset = 0;
575589

Common/src/CConfig.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2006,6 +2006,8 @@ void CConfig::SetConfig_Options() {
20062006
/*!\brief CONV_NUM_METHOD_TURB
20072007
* \n DESCRIPTION: Convective numerical method \ingroup Config*/
20082008
addConvectOption("CONV_NUM_METHOD_TURB", Kind_ConvNumScheme_Turb, Kind_Centered_Turb, Kind_Upwind_Turb);
2009+
/*!\brief USE_ACCURATE_TURB_JACOBIANS \n DESCRIPTION: Use numerically computed Jacobians for Standard SA model \ingroup Config*/
2010+
addBoolOption("USE_ACCURATE_TURB_JACOBIANS", Use_Accurate_Turb_Jacobians, false);
20092011

20102012
/*!\brief MUSCL_ADJTURB \n DESCRIPTION: Check if the MUSCL scheme should be used \ingroup Config*/
20112013
addBoolOption("MUSCL_ADJTURB", MUSCL_AdjTurb, false);

SU2_CFD/include/numerics/turbulent/turb_diffusion.hpp

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ class CAvgGrad_TurbSA final : public CAvgGrad_Scalar<FlowIndices> {
5252
using Base::Jacobian_j;
5353

5454
const su2double sigma = 2.0/3.0;
55+
const su2double cb2 = 0.622;
56+
57+
const bool use_accurate_jacobians;
5558

5659
/*!
5760
* \brief Adds any extra variables to AD
@@ -67,17 +70,39 @@ class CAvgGrad_TurbSA final : public CAvgGrad_Scalar<FlowIndices> {
6770

6871
/*--- Compute mean effective viscosity ---*/
6972

73+
/*--- First Term. Normal diffusion, and conservative part of the quadratic diffusion.
74+
* ||grad nu_t||^2 = div(nu_t grad nu_t) - nu_t div grad nu_t ---*/
7075
const su2double nu_i = Laminar_Viscosity_i/Density_i;
7176
const su2double nu_j = Laminar_Viscosity_j/Density_j;
72-
const su2double nu_e = 0.5*(nu_i+nu_j+ScalarVar_i[0]+ScalarVar_j[0]);
77+
const su2double nu_e = 0.5 * (nu_i + nu_j + (1 + cb2) * (ScalarVar_i[0] + ScalarVar_j[0]));
78+
const su2double term_1 = nu_e;
7379

74-
Flux[0] = nu_e*Proj_Mean_GradScalarVar[0]/sigma;
80+
/* Second Term (quadratic diffusion, non conservative). */
81+
const su2double nu_tilde_i = ScalarVar_i[0];
82+
const su2double term_2 = cb2 * nu_tilde_i;
7583

76-
/*--- For Jacobians -> Use of TSL approx. to compute derivatives of the gradients ---*/
84+
const su2double diffusion_coefficient = term_1 - term_2;
85+
Flux[0] = diffusion_coefficient * Proj_Mean_GradScalarVar[0] / sigma;
7786

7887
if (implicit) {
79-
Jacobian_i[0][0] = (0.5*Proj_Mean_GradScalarVar[0]-nu_e*proj_vector_ij)/sigma;
80-
Jacobian_j[0][0] = (0.5*Proj_Mean_GradScalarVar[0]+nu_e*proj_vector_ij)/sigma;
88+
/*--- For Jacobians -> Use of TSL approx. to compute derivatives of the gradients ---*/
89+
Jacobian_i[0][0] = -diffusion_coefficient * proj_vector_ij / sigma;
90+
Jacobian_j[0][0] = diffusion_coefficient * proj_vector_ij / sigma;
91+
92+
if (use_accurate_jacobians) {
93+
/*--- The diffusion coefficient is also a function of nu_t. ---*/
94+
const su2double dTerm1_dnut_i = (1 + cb2) * 0.5;
95+
const su2double dTerm1_dnut_j = (1 + cb2) * 0.5;
96+
97+
const su2double dTerm2_dnut_i = cb2;
98+
const su2double dTerm2_dnut_j = 0.0;
99+
100+
const su2double dDC_dnut_i = dTerm1_dnut_i - dTerm2_dnut_i;
101+
const su2double dDC_dnut_j = dTerm1_dnut_j - dTerm2_dnut_j;
102+
103+
Jacobian_i[0][0] += dDC_dnut_i * Proj_Mean_GradScalarVar[0] / sigma;
104+
Jacobian_j[0][0] += dDC_dnut_j * Proj_Mean_GradScalarVar[0] / sigma;
105+
}
81106
}
82107
}
83108

@@ -91,7 +116,8 @@ class CAvgGrad_TurbSA final : public CAvgGrad_Scalar<FlowIndices> {
91116
*/
92117
CAvgGrad_TurbSA(unsigned short val_nDim, unsigned short val_nVar,
93118
bool correct_grad, const CConfig* config)
94-
: CAvgGrad_Scalar<FlowIndices>(val_nDim, val_nVar, correct_grad, config) {}
119+
: CAvgGrad_Scalar<FlowIndices>(val_nDim, val_nVar, correct_grad, config),
120+
use_accurate_jacobians(config->GetUse_Accurate_Turb_Jacobians()) {}
95121
};
96122

97123
/*!
@@ -118,6 +144,7 @@ class CAvgGrad_TurbSA_Neg final : public CAvgGrad_Scalar<FlowIndices> {
118144

119145
const su2double sigma = 2.0/3.0;
120146
const su2double cn1 = 16.0;
147+
const su2double cb2 = 0.622;
121148

122149
/*!
123150
* \brief Adds any extra variables to AD
@@ -136,27 +163,39 @@ class CAvgGrad_TurbSA_Neg final : public CAvgGrad_Scalar<FlowIndices> {
136163
const su2double nu_i = Laminar_Viscosity_i/Density_i;
137164
const su2double nu_j = Laminar_Viscosity_j/Density_j;
138165

139-
const su2double nu_ij = 0.5*(nu_i+nu_j);
140-
const su2double nu_tilde_ij = 0.5*(ScalarVar_i[0] + ScalarVar_j[0]);
141-
142-
su2double nu_e;
143-
144-
if (nu_tilde_ij > 0.0) {
145-
nu_e = nu_ij + nu_tilde_ij;
146-
}
147-
else {
148-
const su2double Xi = nu_tilde_ij/nu_ij;
149-
const su2double fn = (cn1 + Xi*Xi*Xi)/(cn1 - Xi*Xi*Xi);
150-
nu_e = nu_ij + fn*nu_tilde_ij;
166+
const su2double nu_ij = 0.5 * (nu_i + nu_j);
167+
const su2double nu_tilde_i = ScalarVar_i[0];
168+
const su2double nu_tilde_j = ScalarVar_j[0];
169+
const su2double nu_tilde_ij = 0.5 * (nu_tilde_i + nu_tilde_j);
170+
171+
/*--- Following Diskin's implementation from 10.2514/1.J064629, they propose a new fn function
172+
* to be evaluated at the cell to maintain positivity in the diffusion coefficient, which is
173+
* used in both terms. The new fn term averaged across the face reverts to the original fn
174+
* function. ---*/
175+
176+
/*--- Second Term (LHS) ---*/
177+
const su2double zeta_i = ((1 + cb2) * nu_tilde_ij - cb2 * nu_tilde_i) / nu_ij;
178+
su2double fn_i = 1.0;
179+
if (zeta_i < 0.0) {
180+
fn_i = (cn1 + pow(zeta_i,3)) / (cn1 - pow(zeta_i,3));
151181
}
152182

153-
Flux[0] = nu_e*Proj_Mean_GradScalarVar[0]/sigma;
183+
const su2double term_1 = (nu_ij + (1 + cb2) * nu_tilde_ij * fn_i);
184+
const su2double term_2 = cb2 * nu_tilde_i * fn_i;
185+
Flux[0] = (term_1 - term_2) * Proj_Mean_GradScalarVar[0] / sigma;
154186

155-
/*--- For Jacobians -> Use of TSL approx. to compute derivatives of the gradients ---*/
187+
/*--- For Jacobians -> Use of TSL approx. to compute derivatives of the gradients
188+
* Exact Jacobians were tested on multiple cases but resulted in divergence of all
189+
* simulations, hence only frozen diffusion coefficient (approximate) Jacobians are used. ---*/
156190

157191
if (implicit) {
158-
Jacobian_i[0][0] = (0.5*Proj_Mean_GradScalarVar[0]-nu_e*proj_vector_ij)/sigma;
159-
Jacobian_j[0][0] = (0.5*Proj_Mean_GradScalarVar[0]+nu_e*proj_vector_ij)/sigma;
192+
const su2double diffusion_coefficient = (term_1 - term_2);
193+
194+
const su2double dGrad_dnut_i = -proj_vector_ij;
195+
const su2double dGrad_dnut_j = proj_vector_ij;
196+
197+
Jacobian_i[0][0] = diffusion_coefficient * dGrad_dnut_i / sigma;
198+
Jacobian_j[0][0] = diffusion_coefficient * dGrad_dnut_j / sigma;
160199
}
161200
}
162201

SU2_CFD/include/numerics/turbulent/turb_sources.hpp

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class CSourceBase_TurbSA : public CNumerics {
8686
*/
8787
inline void ResidualAxisymmetricDiffusion(su2double sigma) {
8888
if (Coord_i[1] < EPS) return;
89-
89+
9090
const su2double yinv = 1.0 / Coord_i[1];
9191
const su2double& nue = ScalarVar_i[0];
9292

@@ -243,14 +243,14 @@ class CSourceBase_TurbSA : public CNumerics {
243243
var.interDestrFactor = 1.0;
244244
}
245245

246-
/*--- Compute production, destruction and cross production and jacobian ---*/
247-
su2double Production = 0.0, Destruction = 0.0, CrossProduction = 0.0;
248-
SourceTerms::get(ScalarVar_i[0], var, Production, Destruction, CrossProduction, Jacobian_i[0]);
246+
/*--- Compute production, destruction and jacobian ---*/
247+
su2double Production = 0.0, Destruction = 0.0;
248+
SourceTerms::get(ScalarVar_i[0], var, Production, Destruction, Jacobian_i[0]);
249249

250-
Residual = (Production - Destruction + CrossProduction) * Volume;
250+
Residual = (Production - Destruction) * Volume;
251251

252252
if (axisymmetric) ResidualAxisymmetricDiffusion(var.sigma);
253-
253+
254254
Jacobian_i[0] *= Volume;
255255
}
256256

@@ -423,24 +423,23 @@ struct Edw {
423423
};
424424

425425
/*!
426-
* \brief SA source terms classes: production, destruction and cross-productions term and their derivative.
426+
* \brief SA source terms classes: production and destruction term and their derivative.
427+
* \note Quadratic diffusion is included in the viscous fluxes.
427428
* \ingroup SourceDiscr
428429
* \param[in] nue: SA variable.
429430
* \param[in] var: Common SA variables struct.
430431
* \param[out] production: Production term.
431432
* \param[out] destruction: Destruction term.
432-
* \param[out] cross_production: CrossProduction term.
433433
* \param[out] jacobian: Derivative of the combined source term wrt nue.
434434
*/
435435
struct SourceTerms {
436436

437437
/*! \brief Baseline (Original SA model). */
438438
struct Bsl {
439439
static void get(const su2double& nue, const CSAVariables& var, su2double& production, su2double& destruction,
440-
su2double& cross_production, su2double& jacobian) {
440+
su2double& jacobian) {
441441
ComputeProduction(nue, var, production, jacobian);
442442
ComputeDestruction(nue, var, destruction, jacobian);
443-
ComputeCrossProduction(nue, var, cross_production, jacobian);
444443
}
445444

446445
static void ComputeProduction(const su2double& nue, const CSAVariables& var, su2double& production,
@@ -458,23 +457,17 @@ struct Bsl {
458457
jacobian -= var.interDestrFactor * ((var.cw1 * var.d_fw - cb1_k2 * var.d_ft2) * pow(nue, 2) + factor * 2 * nue) / var.dist_i_2;
459458
}
460459

461-
static void ComputeCrossProduction(const su2double& nue, const CSAVariables& var, su2double& cross_production,
462-
su2double&) {
463-
cross_production = var.cb2_sigma * var.norm2_Grad;
464-
/*--- No contribution to the jacobian. ---*/
465-
}
466460
};
467461

468462
/*! \brief Negative. */
469463
struct Neg {
470464
static void get(const su2double& nue, const CSAVariables& var, su2double& production, su2double& destruction,
471-
su2double& cross_production, su2double& jacobian) {
465+
su2double& jacobian) {
472466
if (nue > 0.0) {
473-
Bsl::get(nue, var, production, destruction, cross_production, jacobian);
467+
Bsl::get(nue, var, production, destruction, jacobian);
474468
} else {
475469
ComputeProduction(nue, var, production, jacobian);
476470
ComputeDestruction(nue, var, destruction, jacobian);
477-
ComputeCrossProduction(nue, var, cross_production, jacobian);
478471
}
479472
}
480473

@@ -493,10 +486,6 @@ struct Neg {
493486
jacobian -= 2 * dD_dnu * var.interDestrFactor;
494487
}
495488

496-
static void ComputeCrossProduction(const su2double& nue, const CSAVariables& var, su2double& cross_production,
497-
su2double& jacobian) {
498-
Bsl::ComputeCrossProduction(nue, var, cross_production, jacobian);
499-
}
500489
};
501490
};
502491

@@ -562,7 +551,7 @@ class CCompressibilityCorrection final : public ParentClass {
562551
const su2double v = V_i[idx.Velocity() + 1];
563552

564553
const su2double d_axiCorrection = 2.0 * c5 * nue * pow(v * yinv / sound_speed, 2) * Volume;
565-
const su2double axiCorrection = 0.5 * nue * d_axiCorrection;
554+
const su2double axiCorrection = 0.5 * nue * d_axiCorrection;
566555

567556
this->Residual -= axiCorrection;
568557
this->Jacobian_i[0] -= d_axiCorrection;

SU2_CFD/include/solvers/CScalarSolver.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class CScalarSolver : public CSolver {
7777

7878
/*--- Edge fluxes for reducer strategy (see the notes in CEulerSolver.hpp). ---*/
7979
CSysVector<su2double> EdgeFluxes; /*!< \brief Flux across each edge. */
80+
CSysVector<su2double> EdgeFluxesDiff; /*!< \brief Flux difference between ij and ji for non-conservative discretisation. */
8081

8182
/*!
8283
* \brief The highest level in the variable hierarchy this solver can safely use.

SU2_CFD/include/solvers/CScalarSolver.inl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -341,15 +341,21 @@ void CScalarSolver<VariableType>::Upwind_Residual(CGeometry* geometry, CSolver**
341341

342342
template <class VariableType>
343343
void CScalarSolver<VariableType>::SumEdgeFluxes(CGeometry* geometry) {
344+
const bool nonConservative = EdgeFluxesDiff.GetLocSize() > 0;
345+
344346
SU2_OMP_FOR_STAT(omp_chunk_size)
345347
for (unsigned long iPoint = 0; iPoint < nPoint; ++iPoint) {
346348
LinSysRes.SetBlock_Zero(iPoint);
347349

348350
for (auto iEdge : geometry->nodes->GetEdges(iPoint)) {
349-
if (iPoint == geometry->edges->GetNode(iEdge, 0))
351+
if (iPoint == geometry->edges->GetNode(iEdge, 0)) {
350352
LinSysRes.AddBlock(iPoint, EdgeFluxes.GetBlock(iEdge));
351-
else
353+
} else {
352354
LinSysRes.SubtractBlock(iPoint, EdgeFluxes.GetBlock(iEdge));
355+
if (nonConservative) {
356+
LinSysRes.SubtractBlock(iPoint, EdgeFluxesDiff.GetBlock(iEdge));
357+
}
358+
}
353359
}
354360
}
355361
END_SU2_OMP_FOR

SU2_CFD/include/solvers/CSolver.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,12 +191,12 @@ class CSolver {
191191
CSysVector<su2double> LinSysSol; /*!< \brief vector to store iterative solution of implicit linear system. */
192192
CSysVector<su2double> LinSysRes; /*!< \brief vector to store iterative residual of implicit linear system. */
193193
#ifndef CODI_FORWARD_TYPE
194-
CSysMatrix<su2mixedfloat> Jacobian; /*!< \brief Complete sparse Jacobian structure for implicit computations. */
195-
CSysSolve<su2mixedfloat> System; /*!< \brief Linear solver/smoother. */
194+
using JacobianScalarType = su2mixedfloat;
196195
#else
197-
CSysMatrix<su2double> Jacobian;
198-
CSysSolve<su2double> System;
196+
using JacobianScalarType = su2double;
199197
#endif
198+
CSysMatrix<JacobianScalarType> Jacobian; /*!< \brief Complete sparse Jacobian structure for implicit computations. */
199+
CSysSolve<JacobianScalarType> System; /*!< \brief Linear solver/smoother. */
200200

201201
CSysVector<su2double> OutputVariables; /*!< \brief vector to store the extra variables to be written. */
202202
string* OutputHeadingNames; /*!< \brief vector of strings to store the headings for the exra variables */

0 commit comments

Comments
 (0)