Skip to content

One-equation (simplified) LM transition model for SST and SA - #1901

Open
rois1995 wants to merge 72 commits into
developfrom
feature_Trans_SLM
Open

rois1995 wants to merge 72 commits into
developfrom
feature_Trans_SLM

Conversation

@rois1995

@rois1995 rois1995 commented Jan 27, 2023 •

Copy link
Copy Markdown
Contributor

Proposed Changes

One-equation (simplified) version of the LM transition model: only the intermittency γ is transported, and the transition onset is computed from local correlations instead of the Re_θt equation. It is enabled with KIND_TRANS_MODEL= LM and LM_OPTIONS= (SLM, MENTER_SLM), optionally with CROSSFLOW.

Supported combinations. Only the combinations published in the literature are allowed; any other one stops with a config error.

Turbulence model Cross-flow Reference
SST off Menter, Smirnov, Liu, Avancha, A One-Equation Local Correlation-Based Transition Model, Flow Turbul. Combust. 95, 2015 (DOI)
SST on Vallinayagam Pillai & Lardeau, Accounting crossflow effects in one-equation local correlation-based transition model, AIAA 2017-3159
SA off / on Lee & Baeder, Prediction and validation of laminar-turbulent transition using SA-γ transition model, AIAA 2021-1532 (including their Langtry and Menter-Smirnov C1 cross-flow models)

The equations are implemented as in these papers, with equation numbers in the code comments. Notes:

  • SST: Menter et al. (2015) use the Kato-Launder production in the k equation without the production limiter. SU2 prints a warning if KATO-LAUNDER is not in SST_OPTIONS (the SST production limiter stays active in any case).
  • SA: the intermittency is rescaled (γ_s, Lee & Baeder eq. 18) so that it goes to zero in the laminar boundary layer, and it multiplies the SA production and destruction (eq. 17). The constants of Re_θc are blended with the turbulence intensity (eq. 13).
  • CODER_SLM and MOD_EPPLER_SLM are rejected: Coder & Maughmer (AIAA 2012-672) use these correlations with the two-equation Langtry-Menter model, not with the one-equation model.
  • Roughness (cross-flow): the roughness height is limited to at least 1e-8 (it enters log(h/θ_t) and h/h0; the papers give no calibration limit), and the value used is printed at startup. h0 = 0.25 µm assumes a mesh in meters.

Fixes to the existing LM model (found while bringing this branch up to date):

  • Restart: INTERMITTENCY_SEP and INTERMITTENCY_EFF were read as solution variables, but they are not in compact restart files. Restarts are now consistent (tested round trips for the two-equation and one-equation models, compact and full).
  • Free-stream Re_θt: the low-Tu branch used 0.27 instead of 0.027, and the Tu ≥ 0.027 % limit was applied to only one term of the correlation.
  • AD: γ and γ_eff were not registered as preaccumulation inputs of the SA source.
  • Discrete adjoint: the adjoint solvers create no transition solver, so KIND_TRANS_MODEL= LM with a discrete adjoint crashed (null pointer). It now stops with a config error. Adjoint support for transition models would be a separate PR.

Tests: new regression tests slm_spheroid_* (serial, parallel, hybrid) for SST and SA, with and without cross-flow, on a coarse grid of the 6:1 prolate spheroid at 15°. They restart from converged transitional solutions (su2code/TestCases#207), so the transition terms are active. Temporary: .github/workflows/regression.yml uses the feature_Trans_SLM branch of TestCases until that PR is merged.

Validation (prolate spheroid, airfoils) is in progress.

Related Work

PR Checklist

  • I am submitting my contribution to the develop branch.
  • My contribution generates no new compiler warnings (try with --warnlevel=3 when using meson).
  • My contribution is commented and consistent with SU2 style (https://su2code.github.io/docs_v7/Style-Guide/).
  • I used the pre-commit hook to prevent dirty commits and used pre-commit run --all to format old commits.
  • I have added a test case that demonstrates my contribution, if necessary.
  • I have updated appropriate documentation (Tutorials, Docs Page, config_template.cpp), if necessary.

🤖 Generated with Claude Code

@rois1995

Copy link
Copy Markdown
Contributor Author

Technically, this model has only one equation, the one for intermittency. Most of the functions are the same as the original LM model. Should I consider the Simplified model (SLM) as an option for the LM model to avoid duplicates? This is how I started, but I am open to discussions and suggestions.

@pcarruscag pcarruscag changed the title Implementation of Simplified LM Transition model [WIP] [WIP] Implementation of Simplified LM Transition model Jan 27, 2023

@pcarruscag pcarruscag left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the changes to the solver don't become too intrusive this approach sounds good to me

Comment thread SU2_CFD/src/solvers/CTransLMSolver.cpp Fixed
- Added correlations for Simplified LM.
- There is a bug on the computation of grad(n*U)*n
@rois1995

Copy link
Copy Markdown
Contributor Author

I have a question: for each point in the mesh I am trying to compute the dot product between the velocity vector and the normal to the wall of the nearest point on the wall. How do I access such information? I've found that in the CPoint class I have the ClosestWall_Elem variable which stores the index of the closest element on a wall. However, when I try to assess the information with a number of cores greater than 2, it crashes. Moreover, to recover the normal of the element I perform a mean of the normals on the nodes of that element. Is there a structure that has the normals saved for each element of the primal grid? The part that I am referring to is from line 208 in CTransLMSolver.cpp .

Comment on lines +204 to +290
switch (options.Correlation_SLM) {
case TURB_TRANS_CORRELATION_SLM::MENTER_SLM: {

/*-- Thwaites parameter ---*/
su2double lambda_theta_local = 7.57e-3 * du_ds * wall_dist * wall_dist * Density / Laminar_Viscosity + 0.0128;
lambda_theta_local = min(max(lambda_theta_local, -1.0), 1.0);

/*-- Function to sensitize the transition onset to the streamwise pressure gradient ---*/
su2double FPG = 0.0;
const su2double C_PG1 = 14.68;
const su2double C_PG1_lim = 1.5;
const su2double C_PG2 = -7.34;
const su2double C_PG2_lim = 3.0;
const su2double C_PG3 = 0.0;
if (lambda_theta_local >= 0.0) {
FPG = min(1+ C_PG1 * lambda_theta_local, C_PG1_lim);
} else {
const su2double FirstTerm = C_PG2 * lambda_theta_local;
const su2double SecondTerm = C_PG3 * min(lambda_theta_local + 0.0681, 0.0);
FPG = min(1 + FirstTerm + SecondTerm, C_PG2_lim);
}

FPG = max(FPG, 0.0);

const su2double C_TU1 = 100.0;
const su2double C_TU2 = 1000.0;
const su2double C_TU3 = 1.0;
rethetac = C_TU1 + C_TU2 * exp(-C_TU3 * Tu_L * FPG);

break;
} case TURB_TRANS_CORRELATION_SLM::CODER_SLM: {

/*-- Local pressure gradient parameter ---*/
const su2double H_c = max(min(wall_dist * VorticityMag / VelocityMag, 1.1542), 0.3823);

/*-- Thwaites parameter ---*/
su2double lambda_theta_local = 0.0;
const su2double H_c_delta = 0.587743 - H_c;
if ( H_c >= 0.587743 ) {
const su2double FirstTerm = 0.1919 * pow(H_c_delta, 3.0);
const su2double SecondTerm = 0.4182 * pow(H_c_delta, 2.0);
const su2double ThirdTerm = 0.2959 * H_c_delta;
lambda_theta_local = FirstTerm + SecondTerm + ThirdTerm;
} else {
const su2double FirstTerm = 4.7596 * pow(H_c_delta, 3.0);
const su2double SecondTerm = -0.3837 * pow(H_c_delta, 2.0);
const su2double ThirdTerm = 0.3575 * H_c_delta;
lambda_theta_local = FirstTerm + SecondTerm + ThirdTerm;
}

/*-- Function to sensitize the transition onset to the streamwise pressure gradient ---*/
su2double FPG = 0.0;
if (lambda_theta_local <= 0.0) {
const su2double FirstTerm = -12.986 * lambda_theta_local;
const su2double SecondTerm = -123.66 * pow(lambda_theta_local, 2.0);
const su2double ThirdTerm = -405.689 * pow(lambda_theta_local, 3.0);
FPG = 1 - (FirstTerm + SecondTerm + ThirdTerm) * exp(-pow(Tu_L/1.5,1.5));
} else {
FPG = 1 + 0.275 * (1 - exp(-35.0 * lambda_theta_local)) * exp(-Tu_L/0.5);
}

// This is not reported in the paper
//FPG = max(FPG, 0.0);

const su2double C_TU1 = 100.0;
const su2double C_TU2 = 1000.0;
const su2double C_TU3 = 1.0;
rethetac = C_TU1 + C_TU2 * exp(-C_TU3 * Tu_L * FPG);

break;
} case TURB_TRANS_CORRELATION_SLM::MOD_EPPLER_SLM: {

/*-- Local pressure gradient parameter ---*/
const su2double H_c = max(min(wall_dist * VorticityMag / VelocityMag, 1.1542), 0.3823);

/*-- H_32 Shape factor --*/
const su2double H_32 = 1.515095 + 0.2041 * pow((1.1542 - H_c), 2.0956);

rethetac = exp(127.94 * pow((H_32-1.515095), 2.0) + 6.774224);

break;
}
case TURB_TRANS_CORRELATION_SLM::DEFAULT:
SU2_MPI::Error("Transition correlation for Simplified LM model is set to DEFAULT but no default value has ben set in the code.",
CURRENT_FUNCTION);
break;
}

Check notice

Code scanning / CodeQL

Long switch case Note

Switch has at least one case that is too long:
MENTER_SLM (36 lines)
.
Switch has at least one case that is too long:
CODER_SLM (40 lines)
.
Comment thread SU2_CFD/include/numerics/turbulent/transition/trans_sources.hpp Fixed
Comment thread SU2_CFD/src/solvers/CTransLMSolver.cpp Fixed
*/

#pragma once
//#include <cmath>

Check notice

Code scanning / CodeQL

Commented-out code Note

This comment appears to contain commented-out code.

Copilot Autofix

AI 3 days ago

To fix this, remove the commented-out include line in SU2_CFD/include/numerics/turbulent/transition/trans_correlations.hpp at the top of the file (line 28 in the snippet). This resolves the CodeQL “Commented-out code” finding without changing behavior.

Best single fix without changing functionality:

  • Delete //#include <cmath> entirely.
  • Do not add new imports or logic unless a real compile error demonstrates <cmath> is required.
  • Keep all surrounding formatting unchanged.
Suggested changeset 1
SU2_CFD/include/numerics/turbulent/transition/trans_correlations.hpp

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/SU2_CFD/include/numerics/turbulent/transition/trans_correlations.hpp b/SU2_CFD/include/numerics/turbulent/transition/trans_correlations.hpp
--- a/SU2_CFD/include/numerics/turbulent/transition/trans_correlations.hpp
+++ b/SU2_CFD/include/numerics/turbulent/transition/trans_correlations.hpp
@@ -25,7 +25,6 @@
  */
 
 #pragma once
-//#include <cmath>
 
 /*!
  * \class TransLMCorrelations
EOF
@@ -25,7 +25,6 @@
*/

#pragma once
//#include <cmath>

/*!
* \class TransLMCorrelations
Copilot is powered by AI and may make mistakes. Always verify output.
- Modified LM_OPTIONS to include cross-flow effects: from LM2015 to CROSSFLOW
@pcarruscag

Copy link
Copy Markdown
Member

See what is done at the bottom of CGeometry.cpp in CGeometry::ComputeWallDistance.
You need to communicate the normals you need first.

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeQL found more than 10 potential problems in the proposed changes. Check the Files changed tab for more details.

* \brief Get the index of the closest wall element.
* \param[in] iPoint - Index of the point.
*/
inline unsigned long GetClosestWall_Elem(unsigned long iPoint) {return ClosestWall_Elem(iPoint);}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add the param[out] for these please

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I'll do it now.

Comment thread Common/include/option_structure.hpp Outdated
SU2_MPI::Error("Two correlations selected for LM_OPTIONS. Please choose only one.", CURRENT_FUNCTION);
}
if (NFoundCorrelations_SLM > 1) {
SU2_MPI::Error("Two correlations selected for Simplified model into LM_OPTIONS. Please choose only one.", CURRENT_FUNCTION);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
SU2_MPI::Error("Two correlations selected for Simplified model into LM_OPTIONS. Please choose only one.", CURRENT_FUNCTION);
SU2_MPI::Error("Two correlations selected for simplified LM_OPTIONS. Please choose only one.", CURRENT_FUNCTION);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd stick with my change since the options are for the simplified model. They are not simplified options.

Comment thread Common/src/CConfig.cpp

/*--- Check if problem is 2D and LM2015 has been selected ---*/
if (lmParsedOptions.LM2015 && val_nDim == 2) {
SU2_MPI::Error("LM2015 is available only for 3D problems", CURRENT_FUNCTION);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is LM2015 gone? or is crossflow the same?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed the option to CROSSFLOW, since I will use it also for the Simplified model.

Comment on lines +266 to +268
// This is not reported in the paper
//FPG = max(FPG, 0.0);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// This is not reported in the paper
//FPG = max(FPG, 0.0);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have left it there since I do not know if I have to keep it or not.

@bigfooted

Copy link
Copy Markdown
Contributor

I have a question: for each point in the mesh I am trying to compute the dot product between the velocity vector and the normal to the wall of the nearest point on the wall. How do I access such information? I've found that in the CPoint class I have the ClosestWall_Elem variable which stores the index of the closest element on a wall. However, when I try to assess the information with a number of cores greater than 2, it crashes. Moreover, to recover the normal of the element I perform a mean of the normals on the nodes of that element. Is there a structure that has the normals saved for each element of the primal grid? The part that I am referring to is from line 208 in CTransLMSolver.cpp .

There is the geometry toolbox for dot product and normal:
https://github.com/su2code/SU2/blob/master/Common/include/toolboxes/geometry_toolbox.hpp
just look in the code for examples, in vscode you can search for GeometryToolbox::DotProduct or GeometryToolbox::Norm

@rois1995

Copy link
Copy Markdown
Contributor Author

I have a question: for each point in the mesh I am trying to compute the dot product between the velocity vector and the normal to the wall of the nearest point on the wall. How do I access such information? I've found that in the CPoint class I have the ClosestWall_Elem variable which stores the index of the closest element on a wall. However, when I try to assess the information with a number of cores greater than 2, it crashes. Moreover, to recover the normal of the element I perform a mean of the normals on the nodes of that element. Is there a structure that has the normals saved for each element of the primal grid? The part that I am referring to is from line 208 in CTransLMSolver.cpp .

There is the geometry toolbox for dot product and normal: https://github.com/su2code/SU2/blob/master/Common/include/toolboxes/geometry_toolbox.hpp just look in the code for examples, in vscode you can search for GeometryToolbox::DotProduct or GeometryToolbox::Norm

The problem is more related to the finding of the wall-normal for a point within the volume mesh, not to the computations that it will be involved in.

@pcarruscag

Copy link
Copy Markdown
Member

The solution I suggested didn’t work?

@rois1995

Copy link
Copy Markdown
Contributor Author

The solution I suggested didn’t work?

I still have to check if the implementation is correct but with more than two cores the code breaks. However, I found out that the wall-normal of a volume point can be computed as the normalized gradient of the wall-distance. Does this sound correct to you?

However, there is a problem: I am using the aux variables to compute these gradients, but to compute dot(n, U) I first need n, thus I cannot compute them simultaneously. Since these computations are performed in the Preprocessing of the solvers, I was thinking to compute the normal within the FLOW_SOL preprocessing and the dot(n, U) in the TRANS_SOL preprocessing since the flow solver comes before the trans solver. Is this right?

@pcarruscag

Copy link
Copy Markdown
Member

It's not correct. You need to follow the pattern from CGeometry::ComputeWallDistance
First you collect all the normals that are local to the rank
Then you collect the normals across all ranks (using the NDFlatner), then you access this information by (ClosestRank, ClosestMarker, ClosestVertex)
You cannot access the local information directly because ClosestMarker and ClosestVertex may refer to a different rank.

- Added variables only for debug
@rois1995

Copy link
Copy Markdown
Contributor Author

I managed to implement the computation of grad(n*U)*n, but at the moment it is located into CTransLMSolver::PreProcessing. It seems to work with a structured mesh on a flat plate. Currently, I am testing with a 2D profile too. However, being into the PreProcessing of the transition solver, the normals are computed at each iteration, thus it is not computationally efficient if non-deforming meshes are used. I am looking into where to put it such that it is computed just if the mesh is updated (and at the first iteration of course).

Plus, I have added a whole lot of variables to the output, but they will be removed in the final version. They are just used as debug.

@pcarruscag

Copy link
Copy Markdown
Member

Do what we do with wall roughness and do it in the same place (computewalldistance and store in CPoint)

@rois1995

rois1995 commented Jul 7, 2025

Copy link
Copy Markdown
Contributor Author

Hi @pcarruscag, yes, it is ready. I actually performed the 3D simulations on the prolate ellipsoid case but I did not share those here.

Mesh_Fine_AoA_5
Mesh_Fine_AoA_10
Mesh_Fine_AoA_15

Comparing simulations with the reference paper (https://doi.org/10.2514/6.2017-3159) shows really poor results. In the paper, only the Menter correlations have been investigated. The cross-flow effects work in promoting transition to turbulence only for the Modified Eppler correlations, whereas the Coder one shows no influence (the onset function related to the cross-flow transition is always smaller than the standard one).

@pcarruscag

Copy link
Copy Markdown
Member

I think everyone agrees to disagree when it comes to transition 🤣
Have you encountered a lot of sensitivity to initial conditions?

@rois1995

Copy link
Copy Markdown
Contributor Author

That is so true! There is some variability, especially with the turbulence intensity at freestream and the turbulent-to-laminar viscosity ratio at freestream (although it is lower for the latter).

@bigfooted

Copy link
Copy Markdown
Contributor

@rois1995 put a student on this one to validate further? Else this work might disappear into obscurity again.

rois1995 and others added 17 commits September 23, 2026 17:00
The transition numerics of develop are a single edge flux kernel,
CScalarFlux_TransLM: it now also handles the simplified model (one
equation, intermittency only) and the solver dispatches it for 2 or 1
equations. The SLM convection and diffusion classes and their setup in the
driver are removed with the old numerics.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
…ource

AuxVar (wall-normal derivative of the wall-normal velocity) is only set
for the Menter correlation; with the Coder and modified Eppler
correlations lambda_theta, which the cross-flow term and the output use,
was computed from an uninitialized value. Initialize it to zero.

The preaccumulation registered only nVar = 1 turbulence variables, so
omega was missing for SST, and AuxVar was not registered at all.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
In 2D the vertex normals have two components, reading three went past
the end of the array.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
…production

Menter et al. (2015, Eq. 24) compute the k production of SST with the
Kato-Launder form mu_t*S*Omega and without the production limiter. Print a
warning when MENTER_SLM is used with SST, suggesting KATO-LAUNDER when it is
not selected, and noting that the SST production limiter stays active.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
LoadRestart read the separation and effective intermittencies at
index + 2 and + 3, but they are PRIMITIVE outputs: in compact restarts
these are the values of the next point, in full restarts other fields.
They are not solution variables and are recomputed by Postprocessing at
the end of LoadRestart, so they are no longer read.

With the simplified model (one solution variable) RE_THETA_T and TU were
in the SOLUTION group and therefore in the restart files; they are now
PRIMITIVE outputs. The duplicated definitions of INTERMITTENCY_SEP and
INTERMITTENCY_EFF in the solution fields are removed, they are defined
with the primitive fields and written for all LM variants.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
…ta_t correlation

The limit Tu >= 0.027 % was applied only to the 1/Tu^2 term, the linear
term still used the unlimited value.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
The one-equation model is available with MENTER_SLM and SST (Menter et
al. 2015, cross-flow of Vallinayagam Pillai and Lardeau, AIAA 2017-3159)
or SA (Lee and Baeder, AIAA 2021-1532). The CODER_SLM and MOD_EPPLER_SLM
correlations of Coder and Maughmer (AIAA 2012-672) belong to the
Langtry-Menter intermittency equation, not to the one-equation model
implemented here, so they now stop with an error.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
…1-1532)

- Onset functions, F_turb and R_T = mu_t/mu as in Eqs. 4-7 (the same
  F_onset2 and F_onset3 as with SST).
- Re_theta_c with C_TU1 and C_TU2 blended with the freestream Tu between
  the constants of Colonia et al. and the original ones (Eqs. 10-13).
- SA equation: production times gamma_s, destruction times
  max(gamma_s, 0.1), with the scaled intermittency of Eq. 18 (Eq. 17).
  The two-equation LM coupling is unchanged.
- Positivity of the implicit operator of the intermittency source (Eq. 24).
- Cross-flow: the Langtry et al. stationary cross-flow criterion
  (Eqs. 36-43) and the Menter-Smirnov C1 criterion (Eqs. 25-35), with the
  cross-flow strength from the gradient of the vorticity direction.

The CODER_SLM and MOD_EPPLER_SLM branch of the source, rejected at
configuration, is removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
The SA source uses the intermittency of the LM models but did not declare
it as a preaccumulation input, so its derivative was lost in AD.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
The stationary cross-flow Reynolds number of Langtry et al. contains
log(h / theta_t), which diverges for HROUGHNESS= 0. Limit h from below to
0.25 micrometers, the smallest roughness for which the correlation was
validated by Lee and Baeder (AIAA 2021-1532) and the reference height h0
of Vallinayagam Pillai and Lardeau (AIAA 2017-3159). Applied to the SA
cross-flow of the simplified model and to the LM2015 option of the
two-equation model. The roughness factor C_r of the SST cross-flow model
is finite for h = 0 and is unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
…ST cross-flow model

The implementation matches Eqs. 2-10 and 17-18 of AIAA 2017-3159. The
sign of Eq. 2 differs from the printed one, which gives a negative
critical Reynolds number; the comment now explains it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
The papers give no calibration limit for small roughness heights, so the
limit of the previous commit (0.25 micrometers, the smallest validated
height) is replaced by h >= 1e-8, in the units of HROUGHNESS. It applies
to log(h/theta_t) of the Langtry et al. correlation (SA cross-flow of the
simplified model, and the cross-flow option of the two-equation model) and
to h/h0 of the SST cross-flow model of Vallinayagam Pillai and Lardeau.
The limit and whether HROUGHNESS is below it are printed at startup.

h and theta_t are both in mesh length units (reference length 1), so
log(h/theta_t) does not depend on REF_DIMENSIONALIZATION. Also add the
missing end of line after the name of the simplified model without
cross-flow.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
The two branches of the conditional had an AD expression and a double.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
The discrete adjoint solvers do not create the transition solver, but
the SA and SST sources read its solution when KIND_TRANS_MODEL is set:
with MATH_PROBLEM= DISCRETE_ADJOINT and LM (two-equation or simplified)
SU2_CFD_AD crashed with a segmentation fault (null pointer) on the E387
case. Stop with a clear error instead. This also applies to the
two-equation LM model of develop.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
Four tests on the 6:1 prolate spheroid at 15 degrees (INC_RANS, coarse
unstructured grid of 100958 points): SST and SA with MENTER_SLM, with and
without cross-flow. Each runs 5 iterations from a converged SST or SA
transitional solution; the cross-flow tests restart from the solution of
their base model. The grid and the solutions are in su2code/TestCases,
branch feature_Trans_SLM.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
Temporary, for the prolate spheroid data of su2code/TestCases#207. To be
reverted to develop before merging.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LEL91DW5WPbPwgFtCvHga6
@rois1995 rois1995 changed the title Implementation of Simplified LM Transition model One-equation (simplified) LM transition model for SST and SA Sep 24, 2026
@rois1995

Copy link
Copy Markdown
Contributor Author

Sorry for the long pause on this PR. I have now brought it up to date and reviewed it against the literature:

  • Merged develop. The one-equation model now uses the new edge-flux numerics of develop (CScalarFlux_TransLM with one variable), which also makes the convective flux of γ conservative (it was missing the density).
  • Checked the implementation against Menter et al. (2015), Vallinayagam Pillai & Lardeau (2017) and, for SA, Lee & Baeder (2021). The SA coupling previously reused the constants of the two-equation SA-LM coupling (Medida & Baeder); it now follows Lee & Baeder, who coupled exactly this one-equation model to SA.
  • Combinations not found in the literature (e.g. CODER_SLM, MOD_EPPLER_SLM with the one-equation model) now stop with a config error.
  • Fixed some bugs, also in the existing LM model: restart consistency, the free-stream Re_θt limit, missing AD inputs, and a crash with the discrete adjoint (now a clear error).
  • Added regression tests on the 6:1 prolate spheroid (TestCases#207).

I updated the description with the details. Validation runs are next.

Comment thread Common/src/CConfig.cpp
Comment on lines -6726 to +6763
cout << "Transition model: Langtry and Menter's 4 equation model";
if (lmParsedOptions.LM2015) {
cout << " w/ cross-flow corrections (2015)" << endl;
int NTurbEqs = 0;
switch (Kind_Turb_Model) {
case TURB_MODEL::SA: NTurbEqs = 1; break;
case TURB_MODEL::SST: NTurbEqs = 2; break;
case TURB_MODEL::NONE: SU2_MPI::Error("No turbulence model has been selected but LM transition model is active.", CURRENT_FUNCTION); break;
}
if (!lmParsedOptions.SLM) {
int NEquations = 2;
cout << "Transition model: Langtry and Menter's "<< NEquations+NTurbEqs <<" equation model";
} else {
cout << " (2009)" << endl;
int NEquations = 1;
cout << "Transition model: Simplified Langtry and Menter's "<< NEquations+NTurbEqs <<" equation model";
}
if (lmParsedOptions.CrossFlow) {
cout << " w/ cross-flow corrections";
if (!lmParsedOptions.SLM) {
cout << " (2015)";
}
cout << endl;
cout << "Roughness height of the cross-flow model (HROUGHNESS, in mesh length units): limited to at least "
<< LM_CROSSFLOW_MIN_ROUGHNESS << " to keep log(h/theta_t) and h/h0 finite (the papers give no\n"
<< "calibration limit for small heights); ";
if (hRoughness < LM_CROSSFLOW_MIN_ROUGHNESS)
cout << "the given value " << hRoughness << " is below it, " << LM_CROSSFLOW_MIN_ROUGHNESS << " is used." << endl;
else
cout << "the given value " << hRoughness << " is used." << endl;
} else {
if (!lmParsedOptions.SLM) {
cout << " (2009)";
}
cout << endl;
}
break;
}
}
if (Kind_Trans_Model == TURB_TRANS_MODEL::LM) {

cout << "Correlation Functions: ";
switch (lmParsedOptions.Correlation) {
case TURB_TRANS_CORRELATION::MALAN: cout << "Malan et al. (2009)" << endl; break;
case TURB_TRANS_CORRELATION::SULUKSNA: cout << "Suluksna et al. (2009)" << endl; break;
case TURB_TRANS_CORRELATION::KRAUSE: cout << "Krause et al. (2008)" << endl; break;
case TURB_TRANS_CORRELATION::KRAUSE_HYPER: cout << "Krause et al. (2008, paper)" << endl; break;
case TURB_TRANS_CORRELATION::MEDIDA_BAEDER: cout << "Medida and Baeder (2011)" << endl; break;
case TURB_TRANS_CORRELATION::MEDIDA: cout << "Medida PhD (2014)" << endl; break;
case TURB_TRANS_CORRELATION::MENTER_LANGTRY: cout << "Menter and Langtry (2009)" << endl; break;
case TURB_TRANS_CORRELATION::DEFAULT:
switch (Kind_Turb_Model) {
case TURB_MODEL::SA: cout << "Malan et al. (2009)" << endl; break;
case TURB_MODEL::SST: cout << "Menter and Langtry (2009)" << endl; break;
case TURB_MODEL::NONE: SU2_MPI::Error("No turbulence model has been selected but LM transition model is active.", CURRENT_FUNCTION); break;
}
break;
if (Kind_Trans_Model == TURB_TRANS_MODEL::LM) {
if (!lmParsedOptions.SLM){

Check notice

Code scanning / CodeQL

Long switch case Note

Switch has at least one case that is too long:
LM (34 lines)
.
@bigfooted

Copy link
Copy Markdown
Contributor

Great, thanks! I made some changes to multigrid, so cases that use it will converge differently, hopefully in a positive way.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants