Skip to content

Conversation

@rois1995
Copy link
Contributor

Proposed Changes

Hi everyone! I am starting to implement the Simplified version of the Langtry-Menter transition model following the work in https://doi.org/10.2514/6.2012-672. More updates will follow.

Related Work

This follows the implementation of the LM model as #1751.

  • 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 have added a test case that demonstrates my contribution, if necessary.
  • I have updated appropriate documentation (Tutorials, Docs Page, config_template.cpp), if necessary.

@rois1995
Copy link
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
Copy link
Member

@pcarruscag pcarruscag left a comment

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

- Added correlations for Simplified LM.
- There is a bug on the computation of grad(n*U)*n
@rois1995
Copy link
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:
CODER_SLM (40 lines)
.
*/

#pragma once
//#include <cmath>

Check notice

Code scanning / CodeQL

Commented-out code Note

This comment appears to contain commented-out code.

Copilot Autofix

AI about 1 month ago

The best fix is to remove the line //#include <cmath> from SU2_CFD/include/numerics/turbulent/transition/trans_correlations.hpp. This eliminates the commented-out code and improves the code’s readability and maintainability. There is no justification provided for retaining the commented-out include, and there is no indication within the provided code that <cmath> is needed. No further imports, methods, or code changes are necessary.

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,8 +25,8 @@
  */
 
 #pragma once
-//#include <cmath>
 
+
 /*!
  * \class TransLMCorrelations
  * \brief Class for LM model's correlation functions.
EOF
@@ -25,8 +25,8 @@
*/

#pragma once
//#include <cmath>


/*!
* \class TransLMCorrelations
* \brief Class for LM model's correlation functions.
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
Member

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

Copy link
Contributor

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

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
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
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.

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
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
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.


/*--- 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
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
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
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
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
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
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
Member

The solution I suggested didn’t work?

@rois1995
Copy link
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
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
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
Member

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

@rois1995
Copy link
Contributor Author

rois1995 commented Mar 10, 2025

Results for the Eppler E367

Aerodynamic coefficients

Coefficients

Here you can see a comparison on the aerodynamic coefficients between the SU2 implementation and the one coming from reference papers. Results are a little bit different. In particular, for the Menter implementation the mesh topology is different as they have simulated a wind-tunnel like domain whereas mine is in free air (O-grid). I will try to compare the SU2 implementation with their meshes in the next days.

$c_P$ and $c_F$ distributions

$\alpha = 5^\circ$

CPPlot_5

Here, the main comparison is between the Coder implementation and the reference paper. The laminar bubble is slightly smaller in the reference paper but the shape of the pressure coefficient curve is very similar.

$\alpha = 6^\circ$

CPPlot_6
CFPlot_6

Here, the main comparison is between the Menter implementation and the reference paper. As said before, the mesh topologies are completely different. However, the same differences in the skin friction coefficient between the SLM and the LM model can be seen in both the reference and the SU2 implementation. On the other hand, the $c_P$ distribution is very different, with the SLM reference implementation predicting a much smoother effect coming from the LSB. The same smoothing is visible in the SU2 implementation, although it is much weaker. The peak of the $c_P$ at the leading edge is not visible in the reference paper as the image is cropped.

UPDATE - Using Menter's meshes. $c_P$ and $c_F$ distributions at $\alpha = 6^\circ$

CPPlot_6_Menter
CFPlot_6_Menter

The pressure coefficient's distribution essentially remains unaltered. On the other hand, the skin friction is more in line with the reference paper. The oscillations are related to the mesh refinement, mostly due to a non-splined underlying database.

@rois1995
Copy link
Contributor Author

rois1995 commented Mar 10, 2025

Every testcase that is failing is due to a bug that I fixed in the CFlowIncOutput where the value of MAX_RMS_W was used for the RMS_W output. I should fix in the tutorials. Should I open another PR for that?

@bigfooted
Copy link
Contributor

Every testcase that is failing is due to a bug that I fixed in the CFlowIncOutput where the value of MAX_RMS_W was used for the RMS_W output. I should fix in the tutorials. Should I open another PR for that?

The overhead in this PR is not so large, so I'd say keep it in this PR.

@rois1995
Copy link
Contributor Author

Every testcase that is failing is due to a bug that I fixed in the CFlowIncOutput where the value of MAX_RMS_W was used for the RMS_W output. I should fix in the tutorials. Should I open another PR for that?

The overhead in this PR is not so large, so I'd say keep it in this PR.

Guess it's too late now! Sorry 😐

@pcarruscag
Copy link
Member

You did well to make a small PR for it.

@pcarruscag
Copy link
Member

If you are happy with the validation does that mean this PR is ready for review? Can you remove [WIP] if that is the case?

@rois1995
Copy link
Contributor Author

rois1995 commented Mar 11, 2025

I think that the Modified Eppler correlations can be removed as they do not perform very well. We can leave there just the Coder and the Menter correlations. Plus, there are a lot of debug quantities that will be removed before the merge. To me I think that the code can be reviewed. Should I clean everything before reviewing?

@rois1995 rois1995 changed the title [WIP] Implementation of Simplified LM Transition model Implementation of Simplified LM Transition model Mar 11, 2025
@rois1995
Copy link
Contributor Author

I guess I am still missing the cross-flow validation, I will do it in the next days.

@pcarruscag
Copy link
Member

What about this one @rois1995, is it ready?

@rois1995
Copy link
Contributor Author

rois1995 commented Jul 7, 2025

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
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
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).

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