From 36b6f7a3ce7da466c2bcfad4d652c39be3cfa5f7 Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Mon, 15 Sep 2025 18:26:39 +0200 Subject: [PATCH 01/70] Preliminary implementation: uncorrelated stochastic variables The Reynolds stress tensor definition is modified to include a random contribution, which is expressed as the curl of a normally-distributed stochastic vector potential. --- Common/include/CConfig.hpp | 7 +++ Common/src/CConfig.cpp | 8 +++ SU2_CFD/include/numerics/CNumerics.hpp | 58 +++++++++++++++++++ .../include/numerics/flow/flow_diffusion.hpp | 4 +- SU2_CFD/src/numerics/flow/flow_diffusion.cpp | 39 +++++++++++-- TestCases/ddes/flatplate/ddes_flatplate.cfg | 10 ++-- config_template.cfg | 3 + 7 files changed, 120 insertions(+), 9 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 4439410efff..66c58eafdcf 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -1077,6 +1077,7 @@ class CConfig { su2double Const_DES; /*!< \brief Detached Eddy Simulation Constant. */ WINDOW_FUNCTION Kind_WindowFct; /*!< \brief Type of window (weight) function for objective functional. */ unsigned short Kind_HybridRANSLES; /*!< \brief Kind of Hybrid RANS/LES. */ + bool StochasticBackscatter; /*!< \brief Option to include Stochastic Backscatter Model. */ unsigned short Kind_RoeLowDiss; /*!< \brief Kind of Roe scheme with low dissipation for unsteady flows. */ unsigned short nSpanWiseSections; /*!< \brief number of span-wise sections */ @@ -9466,6 +9467,12 @@ class CConfig { */ unsigned short GetKind_HybridRANSLES(void) const { return Kind_HybridRANSLES; } + /*! + * \brief Get if the Stochastic Backscatter Model must be activated. + * \return TRUE if the Stochastic Backscatter Model is activated. + */ + bool GetStochastic_Backscatter(void) const { return StochasticBackscatter; } + /*! * \brief Get the Kind of Roe Low Dissipation Scheme for Unsteady flows. * \return Value of Low dissipation approach. diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 3cadb5be5ef..a5aa8e2bd08 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2911,6 +2911,9 @@ void CConfig::SetConfig_Options() { /* DESCRIPTION: Specify Hybrid RANS/LES model */ addEnumOption("HYBRID_RANSLES", Kind_HybridRANSLES, HybridRANSLES_Map, NO_HYBRIDRANSLES); + /* DESCRIPTION: Specify if the Stochastic Backscatter Model must be activated */ + addBoolOption("STOCHASTIC_BACKSCATTER", StochasticBackscatter, false); + /* DESCRIPTION: Roe with low dissipation for unsteady flows */ addEnumOption("ROE_LOW_DISSIPATION", Kind_RoeLowDiss, RoeLowDiss_Map, NO_ROELOWDISS); @@ -6448,6 +6451,11 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { case SA_ZDES: cout << "Delayed Detached Eddy Simulation (DDES) with Vorticity-based SGS" << endl; break; case SA_EDDES: cout << "Delayed Detached Eddy Simulation (DDES) with Shear-layer Adapted SGS" << endl; break; } + cout << "Stochastic Backscatter: "; + if (StochasticBackscatter) + cout << "ON" << endl; + else + cout << "OFF" << endl; break; case MAIN_SOLVER::NEMO_EULER: if (Kind_Regime == ENUM_REGIME::COMPRESSIBLE) cout << "Compressible two-temperature thermochemical non-equilibrium Euler equations." << endl; diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index 13111efbb49..5130b17ef0e 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "../../../Common/include/CConfig.hpp" #include "../../../Common/include/linear_algebra/blas_structure.hpp" @@ -180,6 +181,7 @@ class CNumerics { roughness_j = 0.0; /*!< \brief Roughness of the wall nearest to point j. */ su2double MeanPerturbedRSM[3][3]; /*!< \brief Perturbed Reynolds stress tensor */ + su2double stochReynStress[3][3]; /*!< \brief Stochastic contribution to Reynolds stress tensor for Backscatter Model. */ SST_ParsedOptions sstParsedOptions; /*!< \brief additional options for the SST turbulence model */ unsigned short Eig_Val_Comp; /*!< \brief Component towards which perturbation is perfromed */ su2double uq_delta_b; /*!< \brief Magnitude of perturbation */ @@ -635,6 +637,62 @@ class CNumerics { } } + /*! + * \brief Compute a random contribution to the Reynolds stress tensor (Stochastic Backscatter Model). + * \details See: Kok, Johan C. "A stochastic backscatter model for grey-area mitigation in detached + * eddy simulations." Flow, Turbulence and Combustion 99.1 (2017): 119-150. + * \param[in] nDim - Dimension of the flow problem, 2 or 3. + * \param[in] density - Density. + * \param[in] eddyVis - Eddy viscosity. + * \param[in] velGrad - Velocity gradient matrix. + * \param[out] stochReynStress - Stochastic tensor (to be added to the Reynolds stress tensor). + */ + template + NEVERINLINE static void ComputeStochReynStress(size_t nDim, Scalar density, Scalar eddyVis, + const Mat1& velGrad, Mat2& stochReynStress) { + + /* --- Initialize seed ---*/ + + static std::default_random_engine gen; + std::random_device rd; + gen.seed(rd()); + + /* --- Generate a vector of three independent normally-distributed samples ---*/ + + std::normal_distribution rnd(0.0,1.0); + Scalar rndVec [3] = {0.0}; + for (size_t iDim = 0; iDim < nDim; iDim++) + rndVec[iDim] = rnd(gen); + + /* --- Estimate turbulent kinetic energy --- */ + + Scalar turbKE = 0.0, strainMag = 0.0; + for (size_t iDim = 0; iDim < nDim; iDim++) { + for (size_t jDim = 0; jDim < nDim; jDim++) { + strainMag += pow(0.5 * (velGrad[iDim][jDim] + velGrad[jDim][iDim]), 2); + } + } + strainMag = sqrt(2.0 * strainMag); + turbKE = eddyVis * strainMag; + turbKE = max(turbKE, 1E-10); + + /* --- Calculate stochastic tensor --- */ + + stochReynStress[1][0] = - density * turbKE * rndVec[2]; + stochReynStress[2][0] = density * turbKE * rndVec[1]; + stochReynStress[2][1] = - density * turbKE * rndVec[0]; + for (size_t iDim = 0; iDim < nDim; iDim++) { + for (size_t jDim = 0; jDim <= iDim; jDim++) { + if (iDim==jDim) { + stochReynStress[iDim][jDim] = 0.0; + } else { + stochReynStress[jDim][iDim] = - stochReynStress[iDim][jDim]; + } + } + } + + } + /*! * \brief Project average gradient onto normal (with or w/o correction) for viscous fluxes of scalar quantities. * \param[in] nDim - Dimension of the flow problem, 2 or 3. diff --git a/SU2_CFD/include/numerics/flow/flow_diffusion.hpp b/SU2_CFD/include/numerics/flow/flow_diffusion.hpp index 6cbb450d4bf..9c5919578e6 100644 --- a/SU2_CFD/include/numerics/flow/flow_diffusion.hpp +++ b/SU2_CFD/include/numerics/flow/flow_diffusion.hpp @@ -198,12 +198,14 @@ class CAvgGrad_Base : public CNumerics { * \param[in] val_turb_ke - Turbulent kinetic energy * \param[in] val_laminar_viscosity - Laminar viscosity. * \param[in] val_eddy_viscosity - Eddy viscosity. + * \param[in] config - Definition of the particular problem. */ void SetStressTensor(const su2double *val_primvar, const su2double* const *val_gradprimvar, su2double val_turb_ke, su2double val_laminar_viscosity, - su2double val_eddy_viscosity); + su2double val_eddy_viscosity, + const CConfig* config); /*! * \brief Get a component of the viscous stress tensor. diff --git a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp index 97b27e261d0..4732a134b78 100644 --- a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp +++ b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp @@ -122,7 +122,8 @@ void CAvgGrad_Base::SetStressTensor(const su2double *val_primvar, const su2double* const *val_gradprimvar, const su2double val_turb_ke, const su2double val_laminar_viscosity, - const su2double val_eddy_viscosity) { + const su2double val_eddy_viscosity, + const CConfig* config) { const su2double Density = val_primvar[nDim+2]; @@ -142,6 +143,15 @@ void CAvgGrad_Base::SetStressTensor(const su2double *val_primvar, // turb_ke is not considered in the stress tensor, see #797 ComputeStressTensor(nDim, tau, val_gradprimvar+1, total_viscosity, Density, su2double(0.0)); } + + /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ + + if (config->GetStochastic_Backscatter()) { + for (unsigned short iDim = 0 ; iDim < nDim; iDim++) + for (unsigned short jDim = 0 ; jDim < nDim; jDim++) + tau[iDim][jDim] += stochReynStress[iDim][jDim]; + } + } void CAvgGrad_Base::AddTauWall(const su2double *UnitNormal, @@ -432,10 +442,17 @@ CNumerics::ResidualType<> CAvgGrad_Flow::ComputeResidual(const CConfig* config) Mean_turb_ke, MeanPerturbedRSM); } + /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ + + if (config->GetStochastic_Backscatter()) { + ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_GradPrimVar+1, + stochReynStress); + } + /*--- Get projected flux tensor (viscous residual) ---*/ SetStressTensor(Mean_PrimVar, Mean_GradPrimVar, Mean_turb_ke, - Mean_Laminar_Viscosity, Mean_Eddy_Viscosity); + Mean_Laminar_Viscosity, Mean_Eddy_Viscosity,config); if (config->GetSAParsedOptions().qcr2000) AddQCR(nDim, &Mean_GradPrimVar[1], tau); if (Mean_TauWall > 0) AddTauWall(UnitNormal, Mean_TauWall); @@ -617,9 +634,16 @@ CNumerics::ResidualType<> CAvgGradInc_Flow::ComputeResidual(const CConfig* confi Mean_turb_ke, MeanPerturbedRSM); } + /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ + + if (config->GetStochastic_Backscatter()) { + ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_GradPrimVar+1, + stochReynStress); + } + /*--- Get projected flux tensor (viscous residual) ---*/ SetStressTensor(Mean_PrimVar, Mean_GradPrimVar, Mean_turb_ke, - Mean_Laminar_Viscosity, Mean_Eddy_Viscosity); + Mean_Laminar_Viscosity, Mean_Eddy_Viscosity,config); if (config->GetSAParsedOptions().qcr2000) AddQCR(nDim, &Mean_GradPrimVar[1], tau); if (Mean_TauWall > 0) AddTauWall(UnitNormal, Mean_TauWall); @@ -947,10 +971,17 @@ CNumerics::ResidualType<> CGeneralAvgGrad_Flow::ComputeResidual(const CConfig* c Mean_turb_ke, MeanPerturbedRSM); } + /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ + + if (config->GetStochastic_Backscatter()) { + ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_GradPrimVar+1, + stochReynStress); + } + /*--- Get projected flux tensor (viscous residual) ---*/ SetStressTensor(Mean_PrimVar, Mean_GradPrimVar, Mean_turb_ke, - Mean_Laminar_Viscosity, Mean_Eddy_Viscosity); + Mean_Laminar_Viscosity, Mean_Eddy_Viscosity,config); if (config->GetSAParsedOptions().qcr2000) AddQCR(nDim, &Mean_GradPrimVar[1], tau); if (Mean_TauWall > 0) AddTauWall(UnitNormal, Mean_TauWall); diff --git a/TestCases/ddes/flatplate/ddes_flatplate.cfg b/TestCases/ddes/flatplate/ddes_flatplate.cfg index 5c1d0804b3b..03b780bcb06 100644 --- a/TestCases/ddes/flatplate/ddes_flatplate.cfg +++ b/TestCases/ddes/flatplate/ddes_flatplate.cfg @@ -13,9 +13,11 @@ % SOLVER= RANS KIND_TURB_MODEL= SA -HYBRID_RANSLES= SA_EDDES +HYBRID_RANSLES= SA_DES +STOCHASTIC_BACKSCATTER= YES MATH_PROBLEM= DIRECT RESTART_SOL= NO +RESTART_ITER= 100 % ----------- COMPRESSIBLE AND INCOMPRESSIBLE FREE-STREAM DEFINITION ----------% % @@ -41,7 +43,7 @@ TIME_MARCHING= DUAL_TIME_STEPPING-2ND_ORDER % % U_inf = 69.4448 - dt*=0.02 - dt=0.000288 TIME_STEP= 0.000288 -MAX_TIME= 20.0 +MAX_TIME= 5 UNST_CFL_NUMBER= 0.0 INNER_ITER= 20 @@ -61,7 +63,7 @@ CFL_NUMBER= 10.0 CFL_ADAPT= NO CFL_ADAPT_PARAM= ( 1.5, 0.5, 1.0, 100.0 ) RK_ALPHA_COEFF= ( 0.66667, 0.66667, 1.000000 ) -TIME_ITER= 10 +TIME_ITER= 500 % ----------------------- SLOPE LIMITER DEFINITION ----------------------------% % @@ -103,5 +105,5 @@ VOLUME_ADJ_FILENAME= adjoint GRAD_OBJFUNC_FILENAME= of_grad SURFACE_FILENAME= surface_flow SURFACE_ADJ_FILENAME= surface_adjoint -OUTPUT_WRT_FREQ= 1000 +OUTPUT_WRT_FREQ= 1000000 SCREEN_OUTPUT= (TIME_ITER, INNER_ITER, RMS_DENSITY, RMS_NU_TILDE, LIFT, DRAG, TOTAL_HEATFLUX) diff --git a/config_template.cfg b/config_template.cfg index bd7a8ff1700..fc154e57595 100644 --- a/config_template.cfg +++ b/config_template.cfg @@ -180,6 +180,9 @@ HYBRID_RANSLES= SA_DDES % % DES Constant (0.65) DES_CONST= 0.65 +% +% Stochastic Backscatter Model (NO, YES) +STOCHASTIC_BACKSCATTER= NO % -------------------- COMPRESSIBLE FREE-STREAM DEFINITION --------------------% % From cfa0cd80dfc2c09311c620aaceac216052bdab01 Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Tue, 23 Sep 2025 10:12:29 +0200 Subject: [PATCH 02/70] Add solution of Langevin equations Add Langevin equations to Spalart-Allmaras solver (uncorrelated random source term) + add stochastic contribution to Reynolds stress tensor (using conservative variables from Langevin equations). --- Common/include/toolboxes/random_toolbox.hpp | 85 +++++++++++++++++++ Common/src/CConfig.cpp | 2 + SU2_CFD/include/numerics/CNumerics.hpp | 69 +++++++++++---- .../include/numerics/flow/flow_diffusion.hpp | 1 + .../numerics/turbulent/turb_convection.hpp | 17 +++- .../numerics/turbulent/turb_sources.hpp | 74 +++++++++++++++- .../include/solvers/CFVMFlowSolverBase.inl | 14 ++- SU2_CFD/include/variables/CIncNSVariable.hpp | 16 +++- SU2_CFD/include/variables/CNEMONSVariable.hpp | 1 + SU2_CFD/include/variables/CNSVariable.hpp | 14 +++ SU2_CFD/include/variables/CTurbSAVariable.hpp | 12 +++ SU2_CFD/include/variables/CTurbVariable.hpp | 2 +- SU2_CFD/include/variables/CVariable.hpp | 12 +++ SU2_CFD/src/numerics/flow/flow_diffusion.cpp | 12 ++- SU2_CFD/src/output/CFlowOutput.cpp | 41 +++++++++ SU2_CFD/src/solvers/CIncNSSolver.cpp | 7 +- SU2_CFD/src/solvers/CNSSolver.cpp | 2 + SU2_CFD/src/solvers/CTurbSASolver.cpp | 37 +++++++- SU2_CFD/src/variables/CIncNSVariable.cpp | 1 + SU2_CFD/src/variables/CNEMONSVariable.cpp | 1 + SU2_CFD/src/variables/CNSVariable.cpp | 1 + SU2_CFD/src/variables/CTurbSAVariable.cpp | 17 +++- 22 files changed, 409 insertions(+), 29 deletions(-) create mode 100644 Common/include/toolboxes/random_toolbox.hpp diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp new file mode 100644 index 00000000000..d7300f2c950 --- /dev/null +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -0,0 +1,85 @@ +/*! + * \file random_toolbox.hpp + * \brief Collection of utility functions for random number generation. + * \version 8.3.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2025, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include +#include + +namespace RandomToolbox { +/// \addtogroup RandomToolbox +/// @{ + +/*! + * \brief Combine two 64-bit integers into a single hash value. + * \param[in] v1 Current hash value. + * \param[in] v2 Value to mix in. + * \return Combined hash value. + */ +inline uint64_t HashCombine(uint64_t v1, uint64_t v2) { + const uint64_t prime = 1099511628211ULL; + v1 ^= v2; + v1 *= prime; + return v1; +} + +/*! + * \brief Convert a double to a 64-bit integer suitable for hashing. + * \param[in] x Double to integer. + * \return Hash value of the double. + */ +inline uint64_t ToUInt64(double x) { + return std::hash{}(x); +} + +/*! + * \brief Build a deterministic seed from physical time. + * \param[in] time Physical time. + * \return 64-bit seed value. + */ +inline uint64_t GetSeed(double x) { + uint64_t h = 1469598103934665603ULL; // Offset + h = HashCombine(h, ToUInt64(x)); + return h; +} + +/*! + * \brief Generate a standard normally-distributed random number. + * \param[in] seed Seed for the random number generator. + * \param[in] mean Mean of the normal distribution (default 0). + * \param[in] stddev Standard deviation of the normal distribution (default 1). + * \return Normally-distributed random number. + */ +inline double GetRandomNormal(uint64_t seed, + double mean = 0.0, + double stddev = 1.0) { + std::mt19937 gen(static_cast(seed)); + std::normal_distribution rnd(mean, stddev); + return rnd(gen); +} + +/// @} +} // namespace RandomToolbox diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index a5aa8e2bd08..4e0ecf9cab1 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -6456,6 +6456,8 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { cout << "ON" << endl; else cout << "OFF" << endl; + if (StochasticBackscatter && Kind_HybridRANSLES == NO_HYBRIDRANSLES) + SU2_MPI::Error("Stochastic Backscatter can only be activated with Hybrid RANS/LES.", CURRENT_FUNCTION); break; case MAIN_SOLVER::NEMO_EULER: if (Kind_Regime == ENUM_REGIME::COMPRESSIBLE) cout << "Compressible two-temperature thermochemical non-equilibrium Euler equations." << endl; diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index 5130b17ef0e..a523d62d4ae 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -182,6 +182,14 @@ class CNumerics { su2double MeanPerturbedRSM[3][3]; /*!< \brief Perturbed Reynolds stress tensor */ su2double stochReynStress[3][3]; /*!< \brief Stochastic contribution to Reynolds stress tensor for Backscatter Model. */ + su2double + lesSensor_i, /*!< \brief LES sensor at point i. */ + lesSensor_j; /*!< \brief LES sensor at point j. */ + su2double lastTime; /*!< \brief Physical time of unsteady simulation. */ + su2double stochSource[3]; /*!< \brief Source term for Langevin equations in Stochastic Backscatter Model. */ + const su2double + *stochVar_i, /*!< \brief Stochastic variables at point i for Stochastic Backscatter Model. */ + *stochVar_j; /*!< \brief Stochastic variables at point j for Stochastic Backscatter Model. */ SST_ParsedOptions sstParsedOptions; /*!< \brief additional options for the SST turbulence model */ unsigned short Eig_Val_Comp; /*!< \brief Component towards which perturbation is perfromed */ su2double uq_delta_b; /*!< \brief Magnitude of perturbation */ @@ -636,7 +644,7 @@ class CNumerics { } } } - + /*! * \brief Compute a random contribution to the Reynolds stress tensor (Stochastic Backscatter Model). * \details See: Kok, Johan C. "A stochastic backscatter model for grey-area mitigation in detached @@ -649,20 +657,8 @@ class CNumerics { */ template NEVERINLINE static void ComputeStochReynStress(size_t nDim, Scalar density, Scalar eddyVis, - const Mat1& velGrad, Mat2& stochReynStress) { - - /* --- Initialize seed ---*/ - - static std::default_random_engine gen; - std::random_device rd; - gen.seed(rd()); - - /* --- Generate a vector of three independent normally-distributed samples ---*/ - - std::normal_distribution rnd(0.0,1.0); - Scalar rndVec [3] = {0.0}; - for (size_t iDim = 0; iDim < nDim; iDim++) - rndVec[iDim] = rnd(gen); + const Mat1& velGrad, const su2double *rndVec, + Mat2& stochReynStress) { /* --- Estimate turbulent kinetic energy --- */ @@ -876,6 +872,16 @@ class CNumerics { turb_ke_j = val_turb_ke_j; } + /*! + * \brief Set the stochastic variables from Langevin equations (Stochastic Backscatter Model). + * \param[in] val_stochvar_i - Value of the stochastic variable at point i. + * \param[in] val_stochvar_j - Value of the stochastic variable at point j. + */ + inline void SetStochVar(su2double *val_stochvar_i, su2double *val_stochvar_j) { + stochVar_i = val_stochvar_i; + stochVar_j = val_stochvar_j; + } + /*! * \brief Set the value of the distance from the nearest wall. * \param[in] val_dist_i - Value of of the distance from point i to the nearest wall. @@ -886,6 +892,39 @@ class CNumerics { dist_j = val_dist_j; } + /*! + * \brief Set the value of the LES sensor. + * \param[in] val_les_i - Value of the LES sensor at point point i. + * \param[in] val_les_j - Value of the LES sensor at point point j. + */ + void SetLESSensor(su2double val_les_i, su2double val_les_j) { + lesSensor_i = val_les_i; + lesSensor_j = val_les_j; + } + + /*! + * \brief Set the value of physical time. + * \param[in] val_last_time - Value of physical time. + */ + void SetLastTime(su2double val_last_time) { + lastTime = val_last_time; + } + + /*! + * \brief Get the value of physical time. + * \param[out] lastTime - Value of physical time. + */ + inline su2double GetLastTime() const { return lastTime; } + + /*! + * \brief Set the stochastic source term for the Langevin equations (Backscatter Model). + * \param[in] val_stoch_source - Value of stochastic source term. + * \param[in] iDim - Index of Langevin equation. + */ + void SetStochSource(su2double val_stoch_source, unsigned short iDim) { + stochSource[iDim] = val_stoch_source; + } + /*! * \brief Set the value of the roughness from the nearest wall. * \param[in] val_dist_i - Value of of the roughness of the nearest wall from point i diff --git a/SU2_CFD/include/numerics/flow/flow_diffusion.hpp b/SU2_CFD/include/numerics/flow/flow_diffusion.hpp index 9c5919578e6..a3afe1b3c45 100644 --- a/SU2_CFD/include/numerics/flow/flow_diffusion.hpp +++ b/SU2_CFD/include/numerics/flow/flow_diffusion.hpp @@ -59,6 +59,7 @@ class CAvgGrad_Base : public CNumerics { Mean_Eddy_Viscosity, /*!< \brief Mean value of the eddy viscosity. */ Mean_turb_ke, /*!< \brief Mean value of the turbulent kinetic energy. */ Mean_TauWall, /*!< \brief Mean wall shear stress (wall functions). */ + *Mean_StochVar, /*!< \brief Mean stochastic variables (Stochastic Backscatter Model). */ TauWall_i, TauWall_j, /*!< \brief Wall shear stress at point i and j (wall functions). */ dist_ij_2, /*!< \brief Length of the edge and face, squared */ Edge_Vector[MAXNDIM] = {0.0}, /*!< \brief Vector from point i to point j. */ diff --git a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp index 03c33d38138..2b5954ae22b 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp @@ -59,9 +59,20 @@ class CUpwSca_TurbSA final : public CUpwScalar { * \param[in] config - Definition of the particular problem. */ void FinishResidualCalc(const CConfig* config) override { - Flux[0] = a0*ScalarVar_i[0] + a1*ScalarVar_j[0]; - Jacobian_i[0][0] = a0; - Jacobian_j[0][0] = a1; + bool backscatter = config->GetStochastic_Backscatter(); + if (!backscatter) { + Flux[0] = a0*ScalarVar_i[0] + a1*ScalarVar_j[0]; + Jacobian_i[0][0] = a0; + Jacobian_j[0][0] = a1; + } else { + for (unsigned short iVar = 0; iVar < 4; iVar++) { + Flux[iVar] = a0*ScalarVar_i[iVar] + a1*ScalarVar_j[iVar]; + for (unsigned short jVar = 0; jVar < 4; jVar++) { + Jacobian_i[iVar][jVar] = (iVar == jVar) ? a0 : 0.0; + Jacobian_j[iVar][jVar] = (iVar == jVar) ? a1 : 0.0; + } + } + } } public: diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index 2195f94bd21..27dfabb07fe 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -74,6 +74,8 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Residual and Jacobian ---*/ su2double Residual, *Jacobian_i; su2double Jacobian_Buffer; /*!< \brief Static storage for the Jacobian (which needs to be pointer for return type). */ + su2double ResidSB[4] = {0.0}, *JacobianSB_i[4]; + su2double JacobianSB_Buffer[16]; const FlowIndices idx; /*!< \brief Object to manage the access to the flow primitives. */ const SA_ParsedOptions options; /*!< \brief Struct with SA options. */ @@ -112,6 +114,55 @@ class CSourceBase_TurbSA : public CNumerics { Residual += yinv * dv_axi * Volume; } + /*! + * \brief Include source-term residuals for Langevin equations (Stochastic Backscatter Model) + */ + inline void ResidualStochEquations(su2double timeStep, const su2double ct, + su2double lengthScale, su2double les_sensor, + const CSAVariables& var) { + + const su2double& nue = ScalarVar_i[0]; + + const auto& density = V_i[idx.Density()]; + + const su2double nut_small = 1.0e-10; + + su2double Ji_2 = pow(var.Ji,2); + su2double Ji_3 = Ji_2 * var.Ji; + + const su2double nut = nue * var.fv1; + + su2double tTurb = ct * pow(lengthScale, 2) / max(nut, nut_small); + su2double tRat = timeStep / tTurb; + su2double corrFac = sqrt(0.5*(1.0+tRat)*(4.0+tRat)/(2.0+tRat)); + + su2double scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * density * corrFac; + + ResidSB[0] = Residual; + for (unsigned short iDim = 1; iDim < 4; iDim++ ) { + ResidSB[iDim] = les_sensor * scaleFactor * stochSource[iDim-1] - + 1.0/tTurb * density * ScalarVar_i[iDim]; + ResidSB[iDim] *= Volume; + } + + for (unsigned short iDim = 0; iDim < 4; iDim++ ) + for (unsigned short jDim = 0; jDim < 4; jDim++ ) + JacobianSB_i[iDim][jDim] = 0.0; + JacobianSB_i[0][0] = Jacobian_i[0]; + JacobianSB_i[1][1] = JacobianSB_i[2][2] = JacobianSB_i[3][3] = - 1.0/tTurb * density * Volume; + + su2double dnut_dnue = var.fv1 + 3.0 * var.cv1_3 * Ji_3 / pow(Ji_3 + var.cv1_3, 2); + su2double dtTurb_dnut = - ct * pow(lengthScale,2) / (max(nut, nut_small)*max(nut, nut_small)); + + for (unsigned short iDim = 1; iDim < 4; iDim++ ) { + JacobianSB_i[iDim][0] = - 1.0/tTurb * les_sensor * scaleFactor * stochSource[iDim-1] + + 1.0/(tTurb*tTurb) * ScalarVar_i[iDim] + + density * les_sensor * corrFac * stochSource[iDim-1] / + (tTurb * sqrt(2.0*tTurb*timeStep)); + JacobianSB_i[iDim][0] *= dtTurb_dnut * dnut_dnue * Volume; + } + } + public: /*! * \brief Constructor of the class. @@ -127,6 +178,9 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Setup the Jacobian pointer, we need to return su2double** but we know * the Jacobian is 1x1 so we use this trick to avoid heap allocation. ---*/ Jacobian_i = &Jacobian_Buffer; + /*--- Setup the Jacobian pointer for Stochastic Backscatter Model. ---*/ + for (unsigned short iVar = 0; iVar < 4; iVar++) + JacobianSB_i[iVar] = JacobianSB_Buffer + 4*iVar; } @@ -145,6 +199,12 @@ class CSourceBase_TurbSA : public CNumerics { AD::SetPreaccIn(PrimVar_Grad_i + idx.Velocity(), nDim, nDim); AD::SetPreaccIn(ScalarVar_Grad_i[0], nDim); + bool backscatter = config->GetStochastic_Backscatter(); + if (backscatter) { + AD::SetPreaccIn(lesSensor_i); + AD::SetPreaccIn(stochSource, 3); + } + /*--- Common auxiliary variables and constants of the model. ---*/ CSAVariables var; @@ -252,12 +312,24 @@ class CSourceBase_TurbSA : public CNumerics { if (axisymmetric) ResidualAxisymmetricDiffusion(var.sigma); Jacobian_i[0] *= Volume; + + /*--- Compute residual for Langevin equations (Stochastic Backscatter Model). ---*/ + + if (backscatter) { + const su2double constDES = config->GetConst_DES(); + const su2double ctTurb = 0.05 / pow(constDES, 2); + ResidualStochEquations(config->GetDelta_UnstTime(), ctTurb, dist_i, lesSensor_i, var); + } } AD::SetPreaccOut(Residual); + if (backscatter) { AD::SetPreaccOut(ResidSB, 4); } AD::EndPreacc(); - return ResidualType<>(&Residual, &Jacobian_i, nullptr); + if (backscatter) + return ResidualType<>(ResidSB, JacobianSB_i, nullptr); + else + return ResidualType<>(&Residual, &Jacobian_i, nullptr); } }; diff --git a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl index 1d88295d7ed..459c915b107 100644 --- a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl +++ b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl @@ -433,9 +433,10 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome const bool implicit = (config->GetKind_TimeIntScheme() == EULER_IMPLICIT); const bool tkeNeeded = (config->GetKind_Turb_Model() == TURB_MODEL::SST); + const bool backscatter = config->GetStochastic_Backscatter(); CVariable* turbNodes = nullptr; - if (tkeNeeded) turbNodes = solver_container[TURB_SOL]->GetNodes(); + if (tkeNeeded || backscatter) turbNodes = solver_container[TURB_SOL]->GetNodes(); /*--- Points, coordinates and normal vector in edge ---*/ @@ -466,6 +467,17 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome numerics->SetTurbKineticEnergy(turbNodes->GetSolution(iPoint,0), turbNodes->GetSolution(jPoint,0)); + /*--- Stochastic variables from Langevin equations (Stochastic Backscatter Model). ---*/ + + if (backscatter) { + su2double stochVars_i [3], stochVars_j [3]; + for (unsigned short iVar = 1; iVar < 4; iVar++) { + stochVars_i[iVar-1] = turbNodes->GetSolution(iPoint, iVar); + stochVars_j[iVar-1] = turbNodes->GetSolution(jPoint, iVar); + } + numerics->SetStochVar(stochVars_i, stochVars_j); + } + /*--- Wall shear stress values (wall functions) ---*/ numerics->SetTau_Wall(nodes->GetTau_Wall(iPoint), diff --git a/SU2_CFD/include/variables/CIncNSVariable.hpp b/SU2_CFD/include/variables/CIncNSVariable.hpp index 5e254506b84..b9caeb7193f 100644 --- a/SU2_CFD/include/variables/CIncNSVariable.hpp +++ b/SU2_CFD/include/variables/CIncNSVariable.hpp @@ -39,7 +39,8 @@ class CIncNSVariable final : public CIncEulerVariable { private: VectorType Tau_Wall; /*!< \brief Magnitude of the wall shear stress from a wall function. */ - VectorType DES_LengthScale; + VectorType DES_LengthScale; /*!< \brief DES Length Scale. */ + VectorType LES_Mode; /*!< \brief Sensor for local simulation mode (0=RANS, 1=LES).*/ public: /*! @@ -132,4 +133,17 @@ class CIncNSVariable final : public CIncEulerVariable { */ inline su2double GetDES_LengthScale(unsigned long iPoint) const override { return DES_LengthScale(iPoint); } + /*! + * \brief Set the LES sensor. + */ + inline void SetLES_Mode(unsigned long iPoint, su2double val_les_mode) override { + LES_Mode(iPoint) = val_les_mode; + } + + /*! + * \brief Get the LES sensor. + * \return Value of the LES sensor. + */ + inline su2double GetLES_Mode(unsigned long iPoint) const override { return LES_Mode(iPoint); } + }; diff --git a/SU2_CFD/include/variables/CNEMONSVariable.hpp b/SU2_CFD/include/variables/CNEMONSVariable.hpp index 1d399a7325c..bdda130e14c 100644 --- a/SU2_CFD/include/variables/CNEMONSVariable.hpp +++ b/SU2_CFD/include/variables/CNEMONSVariable.hpp @@ -52,6 +52,7 @@ class CNEMONSVariable final : public CNEMOEulerVariable { VectorType Tau_Wall; /*!< \brief Magnitude of the wall shear stress from a wall function. */ VectorType DES_LengthScale; /*!< \brief DES Length Scale. */ + VectorType LES_Mode; /*!< \brief Sensor for local simulation mode (0=RANS, 1=LES). */ VectorType Roe_Dissipation; /*!< \brief Roe low dissipation coefficient. */ VectorType Vortex_Tilting; /*!< \brief Value of the vortex tilting variable for DES length scale computation. */ diff --git a/SU2_CFD/include/variables/CNSVariable.hpp b/SU2_CFD/include/variables/CNSVariable.hpp index 69855f3d8a6..44cc1c5c60f 100644 --- a/SU2_CFD/include/variables/CNSVariable.hpp +++ b/SU2_CFD/include/variables/CNSVariable.hpp @@ -41,6 +41,7 @@ class CNSVariable final : public CEulerVariable { VectorType Tau_Wall; /*!< \brief Magnitude of the wall shear stress from a wall function. */ VectorType DES_LengthScale; /*!< \brief DES Length Scale. */ + VectorType LES_Mode; /*!< \brief Sensor for local simulation mode (0=RANS, 1=LES).*/ VectorType Roe_Dissipation; /*!< \brief Roe low dissipation coefficient. */ VectorType Vortex_Tilting; /*!< \brief Value of the vortex tilting variable for DES length scale computation. */ @@ -185,6 +186,19 @@ class CNSVariable final : public CEulerVariable { DES_LengthScale(iPoint) = val_des_lengthscale; } +/*! + * \brief Set the LES sensor. + */ + inline void SetLES_Mode(unsigned long iPoint, su2double val_les_mode) override { + LES_Mode(iPoint) = val_les_mode; + } + + /*! + * \brief Get the LES sensor. + * \return Value of the LES sensor. + */ + inline su2double GetLES_Mode(unsigned long iPoint) const override { return LES_Mode(iPoint); } + /*! * \brief Set the new solution for Roe Dissipation. * \param[in] val_delta - A scalar measure of the grid size diff --git a/SU2_CFD/include/variables/CTurbSAVariable.hpp b/SU2_CFD/include/variables/CTurbSAVariable.hpp index adf3cb5cf17..9cab3dd177f 100644 --- a/SU2_CFD/include/variables/CTurbSAVariable.hpp +++ b/SU2_CFD/include/variables/CTurbSAVariable.hpp @@ -40,6 +40,7 @@ class CTurbSAVariable final : public CTurbVariable { private: VectorType DES_LengthScale; + VectorType LES_Mode; VectorType Vortex_Tilting; public: @@ -73,6 +74,17 @@ class CTurbSAVariable final : public CTurbVariable { */ inline void SetDES_LengthScale(unsigned long iPoint, su2double val_des_lengthscale) override { DES_LengthScale(iPoint) = val_des_lengthscale; } +/*! + * \brief Set the LES sensor. + */ + inline void SetLES_Mode(unsigned long iPoint, su2double val_les_mode) override { LES_Mode(iPoint) = val_les_mode; } + + /*! + * \brief Get the LES sensor. + * \return Value of the LES sensor. + */ + inline su2double GetLES_Mode(unsigned long iPoint) const override { return LES_Mode(iPoint); } + /*! * \brief Set the vortex tilting measure for computation of the EDDES length scale * \param[in] iPoint - Point index. diff --git a/SU2_CFD/include/variables/CTurbVariable.hpp b/SU2_CFD/include/variables/CTurbVariable.hpp index c0c33efd8c9..2fbec9abd24 100644 --- a/SU2_CFD/include/variables/CTurbVariable.hpp +++ b/SU2_CFD/include/variables/CTurbVariable.hpp @@ -40,7 +40,7 @@ class CTurbVariable : public CScalarVariable { VectorType muT; /*!< \brief Eddy viscosity. */ public: - static constexpr size_t MAXNVAR = 2; + static constexpr size_t MAXNVAR = 4; VectorType turb_index; VectorType intermittency; /*!< \brief Value of the intermittency for the trans. model. */ diff --git a/SU2_CFD/include/variables/CVariable.hpp b/SU2_CFD/include/variables/CVariable.hpp index dc905d79fcb..30753179836 100644 --- a/SU2_CFD/include/variables/CVariable.hpp +++ b/SU2_CFD/include/variables/CVariable.hpp @@ -397,6 +397,18 @@ class CVariable { */ inline virtual void SetDES_LengthScale(unsigned long iPoint, su2double val_des_lengthscale) {} + /*! + * \brief A virtual member. + * \param[in] iPoint - Point index. + */ + inline virtual su2double GetLES_Mode(unsigned long iPoint) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] iPoint - Point index. + */ + inline virtual void SetLES_Mode(unsigned long iPoint, su2double val_les_mode) {} + /*! * \brief A virtual member. * \param[in] iPoint - Point index. diff --git a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp index 4732a134b78..9e13ffa7dc5 100644 --- a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp +++ b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp @@ -445,8 +445,10 @@ CNumerics::ResidualType<> CAvgGrad_Flow::ComputeResidual(const CConfig* config) /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ if (config->GetStochastic_Backscatter()) { + for (iVar = 0; iVar < 3; iVar++) + Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_GradPrimVar+1, - stochReynStress); + Mean_StochVar, stochReynStress); } /*--- Get projected flux tensor (viscous residual) ---*/ @@ -637,8 +639,10 @@ CNumerics::ResidualType<> CAvgGradInc_Flow::ComputeResidual(const CConfig* confi /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ if (config->GetStochastic_Backscatter()) { + for (iVar = 0; iVar < 3; iVar++) + Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_GradPrimVar+1, - stochReynStress); + Mean_StochVar, stochReynStress); } /*--- Get projected flux tensor (viscous residual) ---*/ @@ -974,8 +978,10 @@ CNumerics::ResidualType<> CGeneralAvgGrad_Flow::ComputeResidual(const CConfig* c /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ if (config->GetStochastic_Backscatter()) { + for (iVar = 0; iVar < 3; iVar++) + Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_GradPrimVar+1, - stochReynStress); + Mean_StochVar, stochReynStress); } /*--- Get projected flux tensor (viscous residual) ---*/ diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index b355c0698af..d3f2bd02b9f 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -964,6 +964,14 @@ void CFlowOutput::AddHistoryOutputFields_ScalarRMS_RES(const CConfig* config) { case TURB_FAMILY::SA: /// DESCRIPTION: Root-mean square residual of nu tilde (SA model). AddHistoryOutput("RMS_NU_TILDE", "rms[nu]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of nu tilde (SA model).", HistoryFieldType::RESIDUAL); + if (config->GetStochastic_Backscatter()) { + /// DESCRIPTION: Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model). + AddHistoryOutput("RMS_STOCH_VAR_X", "rms[stoch_var_x]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + /// DESCRIPTION: Root-mean square residual of stochastic vector y-component (Stochastic Backscatter Model). + AddHistoryOutput("RMS_STOCH_VAR_Y", "rms[stoch_var_y]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + /// DESCRIPTION: Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model). + AddHistoryOutput("RMS_STOCH_VAR_Z", "rms[stoch_var_z]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + } break; case TURB_FAMILY::KW: @@ -1019,6 +1027,14 @@ void CFlowOutput::AddHistoryOutputFields_ScalarMAX_RES(const CConfig* config) { case TURB_FAMILY::SA: /// DESCRIPTION: Maximum residual of nu tilde (SA model). AddHistoryOutput("MAX_NU_TILDE", "max[nu]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of nu tilde (SA model).", HistoryFieldType::RESIDUAL); + if (config->GetStochastic_Backscatter()) { + /// DESCRIPTION: Maximum residual of stochastic vector x-component (Stochastic Backscatter Model). + AddHistoryOutput("MAX_STOCH_VAR_X", "max[stoch_var_x]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + /// DESCRIPTION: Maximum residual of stochastic vector y-component (Stochastic Backscatter Model). + AddHistoryOutput("MAX_STOCH_VAR_Y", "max[stoch_var_y]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + /// DESCRIPTION: Maximum residual of stochastic vector z-component (Stochastic Backscatter Model). + AddHistoryOutput("MAX_STOCH_VAR_Z", "max[stoch_var_z]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + } break; case TURB_FAMILY::KW: @@ -1160,8 +1176,21 @@ void CFlowOutput::LoadHistoryDataScalar(const CConfig* config, const CSolver* co case TURB_FAMILY::SA: SetHistoryOutputValue("RMS_NU_TILDE", log10(solver[TURB_SOL]->GetRes_RMS(0))); SetHistoryOutputValue("MAX_NU_TILDE", log10(solver[TURB_SOL]->GetRes_Max(0))); + if (config->GetStochastic_Backscatter()) { + SetHistoryOutputValue("RMS_STOCH_VAR_X", log10(solver[TURB_SOL]->GetRes_RMS(1))); + SetHistoryOutputValue("RMS_STOCH_VAR_Y", log10(solver[TURB_SOL]->GetRes_RMS(2))); + SetHistoryOutputValue("RMS_STOCH_VAR_Z", log10(solver[TURB_SOL]->GetRes_RMS(3))); + SetHistoryOutputValue("MAX_STOCH_VAR_X", log10(solver[TURB_SOL]->GetRes_Max(1))); + SetHistoryOutputValue("MAX_STOCH_VAR_Y", log10(solver[TURB_SOL]->GetRes_Max(2))); + SetHistoryOutputValue("MAX_STOCH_VAR_Z", log10(solver[TURB_SOL]->GetRes_Max(3))); + } if (multiZone) { SetHistoryOutputValue("BGS_NU_TILDE", log10(solver[TURB_SOL]->GetRes_BGS(0))); + if (config->GetStochastic_Backscatter()) { + SetHistoryOutputValue("BGS_STOCH_VAR_X", log10(solver[TURB_SOL]->GetRes_BGS(1))); + SetHistoryOutputValue("BGS_STOCH_VAR_Y", log10(solver[TURB_SOL]->GetRes_BGS(2))); + SetHistoryOutputValue("BGS_STOCH_VAR_Z", log10(solver[TURB_SOL]->GetRes_BGS(3))); + } } break; @@ -1483,6 +1512,12 @@ void CFlowOutput::SetVolumeOutputFieldsScalarMisc(const CConfig* config) { if (config->GetKind_HybridRANSLES() != NO_HYBRIDRANSLES) { AddVolumeOutput("DES_LENGTHSCALE", "DES_LengthScale", "DDES", "DES length scale value"); AddVolumeOutput("WALL_DISTANCE", "Wall_Distance", "DDES", "Wall distance value"); + AddVolumeOutput("LES_SENSOR","LES_Sensor","DDES","LES sensor value"); + if (config->GetStochastic_Backscatter()) { + AddVolumeOutput("STOCHASTIC_VAR_X", "Stochastic_Var_X", "BACKSCATTER", "x-component of the stochastic vector potential"); + AddVolumeOutput("STOCHASTIC_VAR_Y", "Stochastic_Var_Y", "BACKSCATTER", "y-component of the stochastic vector potential"); + AddVolumeOutput("STOCHASTIC_VAR_Z", "Stochastic_Var_Z", "BACKSCATTER", "z-component of the stochastic vector potential"); + } } if (config->GetViscous()) { @@ -1582,6 +1617,12 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con if (config->GetKind_HybridRANSLES() != NO_HYBRIDRANSLES) { SetVolumeOutputValue("DES_LENGTHSCALE", iPoint, Node_Flow->GetDES_LengthScale(iPoint)); SetVolumeOutputValue("WALL_DISTANCE", iPoint, Node_Geo->GetWall_Distance(iPoint)); + SetVolumeOutputValue("LES_SENSOR", iPoint, Node_Flow->GetLES_Mode(iPoint)); + if (config->GetStochastic_Backscatter()) { + SetVolumeOutputValue("STOCHASTIC_VAR_X", iPoint, Node_Turb->GetSolution(iPoint, 1)); + SetVolumeOutputValue("STOCHASTIC_VAR_Y", iPoint, Node_Turb->GetSolution(iPoint, 2)); + SetVolumeOutputValue("STOCHASTIC_VAR_Z", iPoint, Node_Turb->GetSolution(iPoint, 3)); + } } switch (config->GetKind_Species_Model()) { diff --git a/SU2_CFD/src/solvers/CIncNSSolver.cpp b/SU2_CFD/src/solvers/CIncNSSolver.cpp index 30f0efd46d9..7c4955bf93e 100644 --- a/SU2_CFD/src/solvers/CIncNSSolver.cpp +++ b/SU2_CFD/src/solvers/CIncNSSolver.cpp @@ -282,7 +282,7 @@ void CIncNSSolver::Viscous_Residual(unsigned long iEdge, CGeometry *geometry, CS unsigned long CIncNSSolver::SetPrimitive_Variables(CSolver **solver_container, const CConfig *config) { unsigned long iPoint, nonPhysicalPoints = 0; - su2double eddy_visc = 0.0, turb_ke = 0.0, DES_LengthScale = 0.0; + su2double eddy_visc = 0.0, turb_ke = 0.0, DES_LengthScale = 0.0, LES_Mode = 0.0; const su2double* scalar = nullptr; const TURB_MODEL turb_model = config->GetKind_Turb_Model(); const SPECIES_MODEL species_model = config->GetKind_Species_Model(); @@ -302,6 +302,7 @@ unsigned long CIncNSSolver::SetPrimitive_Variables(CSolver **solver_container, c if (config->GetKind_HybridRANSLES() != NO_HYBRIDRANSLES){ DES_LengthScale = solver_container[TURB_SOL]->GetNodes()->GetDES_LengthScale(iPoint); + LES_Mode = solver_container[TURB_SOL]->GetNodes()->GetLES_Mode(iPoint); } } @@ -322,6 +323,10 @@ unsigned long CIncNSSolver::SetPrimitive_Variables(CSolver **solver_container, c nodes->SetDES_LengthScale(iPoint,DES_LengthScale); + /*--- Set the LES sensor ---*/ + + nodes->SetLES_Mode(iPoint, LES_Mode); + } END_SU2_OMP_FOR diff --git a/SU2_CFD/src/solvers/CNSSolver.cpp b/SU2_CFD/src/solvers/CNSSolver.cpp index 2513cae7f34..97be3482491 100644 --- a/SU2_CFD/src/solvers/CNSSolver.cpp +++ b/SU2_CFD/src/solvers/CNSSolver.cpp @@ -151,6 +151,8 @@ unsigned long CNSSolver::SetPrimitive_Variables(CSolver **solver_container, cons if (config->GetKind_HybridRANSLES() != NO_HYBRIDRANSLES) { su2double DES_LengthScale = solver_container[TURB_SOL]->GetNodes()->GetDES_LengthScale(iPoint); nodes->SetDES_LengthScale(iPoint, DES_LengthScale); + su2double LES_Mode = solver_container[TURB_SOL]->GetNodes()->GetLES_Mode(iPoint); + nodes->SetLES_Mode(iPoint, LES_Mode); } } diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 7649165d0be..c76b819f790 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -30,6 +30,7 @@ #include "../../include/variables/CFlowVariable.hpp" #include "../../../Common/include/parallelization/omp_structure.hpp" #include "../../../Common/include/toolboxes/geometry_toolbox.hpp" +#include "../../../Common/include/toolboxes/random_toolbox.hpp" CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned short iMesh, CFluidModel* FluidModel) @@ -46,6 +47,11 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor nPoint = geometry->GetnPoint(); nPointDomain = geometry->GetnPointDomain(); + /*--- Add Langevin equations if the Stochastic Backscatter Model is used ---*/ + + bool backscatter = config->GetStochastic_Backscatter(); + if (backscatter) { nVar += 3; nPrimVar += 3; } + /*--- Initialize nVarGrad for deallocation ---*/ nVarGrad = nVar; @@ -377,6 +383,24 @@ void CTurbSASolver::Source_Residual(CGeometry *geometry, CSolver **solver_contai /*--- Set DES length scale ---*/ numerics->SetDistance(nodes->GetDES_LengthScale(iPoint), 0.0); + numerics->SetLESSensor(nodes->GetLES_Mode(iPoint), 0.0); + + /*--- Compute source terms in Langevin equations (Stochastic Basckscatter Model) ---*/ + + bool backscatter = config->GetStochastic_Backscatter(); + if (backscatter) { + su2double currentTime = config->GetPhysicalTime(); + su2double lastTime = numerics->GetLastTime(); + if (currentTime != lastTime) { + numerics->SetLastTime(currentTime); + su2double randomSource; + for (unsigned short iDim = 0; iDim < 3; iDim++) { + unsigned long seed = RandomToolbox::GetSeed(currentTime); + randomSource = RandomToolbox::GetRandomNormal(seed, 0.0, 1.0); + numerics->SetStochSource(randomSource, iDim); + } + } + } } @@ -402,6 +426,10 @@ void CTurbSASolver::Source_Residual(CGeometry *geometry, CSolver **solver_contai nodes->SetIntermittency(iPoint,numerics->GetIntermittencyEff()); } + /*--- Store stochastic variables (Stochastic Backscatter Model) ---*/ + + + /*--- Subtract residual and the Jacobian ---*/ LinSysRes.SubtractBlock(iPoint, residual); @@ -558,7 +586,7 @@ void CTurbSASolver::BC_Inlet(CGeometry *geometry, CSolver **solver_container, CN conv_numerics->SetPrimitive(V_domain, V_inlet); /*--- Non-dimensionalize Inlet_TurbVars if Inlet-Files are used. ---*/ - su2double Inlet_Vars[MAXNVAR]; + su2double Inlet_Vars[MAXNVAR] = {0.0}; Inlet_Vars[0] = Inlet_TurbVars[val_marker][iVertex][0]; if (config->GetInlet_Profile_From_File()) { Inlet_Vars[0] *= config->GetDensity_Ref() / config->GetViscosity_Ref(); @@ -1396,7 +1424,7 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC su2double psi_2 = (1.0 - (cb1/(cw1*k2*fw_star))*(ft2 + (1.0 - ft2)*fv2))/(fv1 * max(1.0e-10,1.0-ft2)); psi_2 = min(100.0,psi_2); - su2double lengthScale = 0.0; + su2double lengthScale = 0.0, lesSensor = 0.0; switch(kindHybridRANSLES){ case SA_DES: { @@ -1408,6 +1436,7 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC const su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); const su2double distDES = constDES * maxDelta; lengthScale = min(distDES,wallDistance); + lesSensor = (wallDistance<=distDES) ? 0.0 : 1.0; break; } @@ -1424,6 +1453,7 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC const su2double distDES = constDES * maxDelta; lengthScale = wallDistance-f_d*max(0.0,(wallDistance-distDES)); + lesSensor = (wallDistance<=distDES) ? 0.0 : f_d; break; } @@ -1464,6 +1494,7 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC const su2double distDES = constDES * maxDelta; lengthScale = wallDistance-f_d*max(0.0,(wallDistance-distDES)); + lesSensor = (wallDistance<=distDES) ? 0.0 : f_d; break; } @@ -1516,12 +1547,14 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC const su2double distDES = constDES * maxDelta; lengthScale = wallDistance-f_d*max(0.0,(wallDistance-distDES)); + lesSensor = (wallDistance<=distDES) ? 0.0 : f_d; break; } } nodes->SetDES_LengthScale(iPoint, lengthScale); + nodes->SetLES_Mode(iPoint, lesSensor); } END_SU2_OMP_FOR diff --git a/SU2_CFD/src/variables/CIncNSVariable.cpp b/SU2_CFD/src/variables/CIncNSVariable.cpp index 13585167504..ff2d8bea0d3 100644 --- a/SU2_CFD/src/variables/CIncNSVariable.cpp +++ b/SU2_CFD/src/variables/CIncNSVariable.cpp @@ -36,6 +36,7 @@ CIncNSVariable::CIncNSVariable(su2double pressure, const su2double *velocity, su StrainMag.resize(nPoint); Tau_Wall.resize(nPoint) = su2double(-1.0); DES_LengthScale.resize(nPoint) = su2double(0.0); + LES_Mode.resize(nPoint) = su2double(0.0); Max_Lambda_Visc.resize(nPoint); /*--- Allocate memory for the AuxVar and its gradient. See e.g. CIncEulerSolver::Source_Residual: * Axisymmetric: total-viscosity * y-vel / y-coord diff --git a/SU2_CFD/src/variables/CNEMONSVariable.cpp b/SU2_CFD/src/variables/CNEMONSVariable.cpp index e673ad5603b..b379ce2752d 100644 --- a/SU2_CFD/src/variables/CNEMONSVariable.cpp +++ b/SU2_CFD/src/variables/CNEMONSVariable.cpp @@ -70,6 +70,7 @@ CNEMONSVariable::CNEMONSVariable(su2double val_pressure, StrainMag.resize(nPoint) = su2double(0.0); Tau_Wall.resize(nPoint) = su2double(-1.0); DES_LengthScale.resize(nPoint) = su2double(0.0); + LES_Mode.resize(nPoint) = su2double(0.0); Roe_Dissipation.resize(nPoint) = su2double(0.0); Vortex_Tilting.resize(nPoint) = su2double(0.0); Max_Lambda_Visc.resize(nPoint) = su2double(0.0); diff --git a/SU2_CFD/src/variables/CNSVariable.cpp b/SU2_CFD/src/variables/CNSVariable.cpp index 6c360efc995..753f7b4feeb 100644 --- a/SU2_CFD/src/variables/CNSVariable.cpp +++ b/SU2_CFD/src/variables/CNSVariable.cpp @@ -39,6 +39,7 @@ CNSVariable::CNSVariable(su2double density, const su2double *velocity, su2double StrainMag.resize(nPoint) = su2double(0.0); Tau_Wall.resize(nPoint) = su2double(-1.0); DES_LengthScale.resize(nPoint) = su2double(0.0); + LES_Mode.resize(nPoint) = su2double(0.0); Roe_Dissipation.resize(nPoint) = su2double(0.0); Vortex_Tilting.resize(nPoint) = su2double(0.0); Max_Lambda_Visc.resize(nPoint) = su2double(0.0); diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index 75119c89ed5..6b42a4d9106 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -27,13 +27,27 @@ #include "../../include/variables/CTurbSAVariable.hpp" +#include "random" CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsigned long npoint, unsigned long ndim, unsigned long nvar, CConfig *config) : CTurbVariable(npoint, ndim, nvar, config) { - Solution_Old = Solution = val_nu_tilde; + /*--- Initialize solution (check if the Stochastic Backscatter Model is active) ---*/ + bool backscatter = config->GetStochastic_Backscatter(); + if (!backscatter) { + Solution_Old = Solution = val_nu_tilde; + } else { + std::default_random_engine gen(std::random_device{}()); + std::normal_distribution rnd(0.0,1.0); + for (unsigned long iPoint = 0; iPoint < npoint; iPoint++) { + Solution_Old(iPoint, 0) = Solution(iPoint, 0) = val_nu_tilde; + for (unsigned short iVar = 1; iVar < nvar; iVar++) { + Solution_Old(iPoint, iVar) = Solution(iPoint, iVar) = rnd(gen); + } + } + } muT.resize(nPoint) = val_muT; @@ -47,6 +61,7 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi } DES_LengthScale.resize(nPoint) = su2double(0.0); + LES_Mode.resize(nPoint) = su2double(0.0); Vortex_Tilting.resize(nPoint); } From 34f676f2b6c425a4bc25810e685942d10f480c3d Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Wed, 24 Sep 2025 11:05:02 +0200 Subject: [PATCH 03/70] Fix sanitizer warnings and regression failures Fix sanitizer warnings and regression test failures - Address issues reported by clang sanitizers. - Adjust implementation to ensure regression tests pass. --- Common/include/toolboxes/random_toolbox.hpp | 21 +++++--------- SU2_CFD/include/numerics/CNumerics.hpp | 15 +++++----- .../numerics/turbulent/turb_convection.hpp | 11 +++++-- .../include/solvers/CFVMFlowSolverBase.inl | 8 ++--- SU2_CFD/src/output/CFlowOutput.cpp | 12 ++++---- SU2_CFD/src/solvers/CTurbSASolver.cpp | 29 +++++++++++++++---- SU2_CFD/src/variables/CTurbSAVariable.cpp | 11 +++---- 7 files changed, 62 insertions(+), 45 deletions(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index d7300f2c950..7d9a3a85608 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -49,22 +49,17 @@ inline uint64_t HashCombine(uint64_t v1, uint64_t v2) { /*! * \brief Convert a double to a 64-bit integer suitable for hashing. * \param[in] x Double to integer. - * \return Hash value of the double. + * \return Hash value of the double (not portable). */ -inline uint64_t ToUInt64(double x) { - return std::hash{}(x); -} +inline uint64_t ToUInt64(double x) { return std::hash{}(x); } /*! * \brief Build a deterministic seed from physical time. - * \param[in] time Physical time. + * \param[in] x First integer value. + * \param[in] y Second integer value. * \return 64-bit seed value. */ -inline uint64_t GetSeed(double x) { - uint64_t h = 1469598103934665603ULL; // Offset - h = HashCombine(h, ToUInt64(x)); - return h; -} +inline uint64_t GetSeed(uint64_t x, uint64_t y) { return HashCombine(x, y); } /*! * \brief Generate a standard normally-distributed random number. @@ -73,10 +68,8 @@ inline uint64_t GetSeed(double x) { * \param[in] stddev Standard deviation of the normal distribution (default 1). * \return Normally-distributed random number. */ -inline double GetRandomNormal(uint64_t seed, - double mean = 0.0, - double stddev = 1.0) { - std::mt19937 gen(static_cast(seed)); +inline double GetRandomNormal(uint64_t seed, double mean = 0.0, double stddev = 1.0) { + std::mt19937_64 gen(seed); std::normal_distribution rnd(mean, stddev); return rnd(gen); } diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index fff3ed7b905..b35c49596e6 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -184,11 +184,11 @@ class CNumerics { su2double lesSensor_i, /*!< \brief LES sensor at point i. */ lesSensor_j; /*!< \brief LES sensor at point j. */ - su2double lastTime; /*!< \brief Physical time of unsteady simulation. */ + unsigned long lastTime; /*!< \brief Physical time iteration of unsteady simulation. */ su2double stochSource[3]; /*!< \brief Source term for Langevin equations in Stochastic Backscatter Model. */ - const su2double - *stochVar_i, /*!< \brief Stochastic variables at point i for Stochastic Backscatter Model. */ - *stochVar_j; /*!< \brief Stochastic variables at point j for Stochastic Backscatter Model. */ + su2double + stochVar_i[3], /*!< \brief Stochastic variables at point i for Stochastic Backscatter Model. */ + stochVar_j[3]; /*!< \brief Stochastic variables at point j for Stochastic Backscatter Model. */ SST_ParsedOptions sstParsedOptions; /*!< \brief additional options for the SST turbulence model */ unsigned short Eig_Val_Comp; /*!< \brief Component towards which perturbation is perfromed */ su2double uq_delta_b; /*!< \brief Magnitude of perturbation */ @@ -875,10 +875,11 @@ class CNumerics { * \brief Set the stochastic variables from Langevin equations (Stochastic Backscatter Model). * \param[in] val_stochvar_i - Value of the stochastic variable at point i. * \param[in] val_stochvar_j - Value of the stochastic variable at point j. + * \param[in] iDim - Index of Langevin equation. */ - inline void SetStochVar(su2double *val_stochvar_i, su2double *val_stochvar_j) { - stochVar_i = val_stochvar_i; - stochVar_j = val_stochvar_j; + inline void SetStochVar(su2double val_stochvar_i, su2double val_stochvar_j, unsigned short iDim) { + stochVar_i[iDim] = val_stochvar_i; + stochVar_j[iDim] = val_stochvar_j; } /*! diff --git a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp index 2b5954ae22b..fe829cc054b 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp @@ -48,6 +48,10 @@ class CUpwSca_TurbSA final : public CUpwScalar { using Base::ScalarVar_i; using Base::ScalarVar_j; using Base::bounded_scalar; + using Base::V_i; + using Base::V_j; + using Base::idx; + using Base::nVar; /*! * \brief Adds any extra variables to AD. @@ -65,9 +69,10 @@ class CUpwSca_TurbSA final : public CUpwScalar { Jacobian_i[0][0] = a0; Jacobian_j[0][0] = a1; } else { - for (unsigned short iVar = 0; iVar < 4; iVar++) { - Flux[iVar] = a0*ScalarVar_i[iVar] + a1*ScalarVar_j[iVar]; - for (unsigned short jVar = 0; jVar < 4; jVar++) { + Flux[0] = a0*ScalarVar_i[0] + a1*ScalarVar_j[0]; + for (unsigned short iVar = 1; iVar < nVar; iVar++) { + Flux[iVar] = a0*V_i[idx.Density()]*ScalarVar_i[iVar] + a1*V_j[idx.Density()]*ScalarVar_j[iVar]; + for (unsigned short jVar = 0; jVar < nVar; jVar++) { Jacobian_i[iVar][jVar] = (iVar == jVar) ? a0 : 0.0; Jacobian_j[iVar][jVar] = (iVar == jVar) ? a1 : 0.0; } diff --git a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl index 13236680ac2..51db989405e 100644 --- a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl +++ b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl @@ -470,12 +470,10 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome /*--- Stochastic variables from Langevin equations (Stochastic Backscatter Model). ---*/ if (backscatter) { - su2double stochVars_i [3], stochVars_j [3]; - for (unsigned short iVar = 1; iVar < 4; iVar++) { - stochVars_i[iVar-1] = turbNodes->GetSolution(iPoint, iVar); - stochVars_j[iVar-1] = turbNodes->GetSolution(jPoint, iVar); + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + numerics->SetStochVar(turbNodes->GetSolution(iPoint, 1 + iDim), + turbNodes->GetSolution(jPoint, 1 + iDim), iDim); } - numerics->SetStochVar(stochVars_i, stochVars_j); } /*--- Wall shear stress values (wall functions) ---*/ diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index d3f2bd02b9f..d1ea3269634 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -966,11 +966,11 @@ void CFlowOutput::AddHistoryOutputFields_ScalarRMS_RES(const CConfig* config) { AddHistoryOutput("RMS_NU_TILDE", "rms[nu]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of nu tilde (SA model).", HistoryFieldType::RESIDUAL); if (config->GetStochastic_Backscatter()) { /// DESCRIPTION: Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model). - AddHistoryOutput("RMS_STOCH_VAR_X", "rms[stoch_var_x]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + AddHistoryOutput("RMS_STOCH_VAR_X", "rms[stoch_x]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Root-mean square residual of stochastic vector y-component (Stochastic Backscatter Model). - AddHistoryOutput("RMS_STOCH_VAR_Y", "rms[stoch_var_y]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + AddHistoryOutput("RMS_STOCH_VAR_Y", "rms[stoch_y]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model). - AddHistoryOutput("RMS_STOCH_VAR_Z", "rms[stoch_var_z]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + AddHistoryOutput("RMS_STOCH_VAR_Z", "rms[stoch_z]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); } break; @@ -1029,11 +1029,11 @@ void CFlowOutput::AddHistoryOutputFields_ScalarMAX_RES(const CConfig* config) { AddHistoryOutput("MAX_NU_TILDE", "max[nu]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of nu tilde (SA model).", HistoryFieldType::RESIDUAL); if (config->GetStochastic_Backscatter()) { /// DESCRIPTION: Maximum residual of stochastic vector x-component (Stochastic Backscatter Model). - AddHistoryOutput("MAX_STOCH_VAR_X", "max[stoch_var_x]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + AddHistoryOutput("MAX_STOCH_VAR_X", "max[stoch_x]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Maximum residual of stochastic vector y-component (Stochastic Backscatter Model). - AddHistoryOutput("MAX_STOCH_VAR_Y", "max[stoch_var_y]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + AddHistoryOutput("MAX_STOCH_VAR_Y", "max[stoch_y]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Maximum residual of stochastic vector z-component (Stochastic Backscatter Model). - AddHistoryOutput("MAX_STOCH_VAR_Z", "max[stoch_var_z]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + AddHistoryOutput("MAX_STOCH_VAR_Z", "max[stoch_z]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); } break; diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index c76b819f790..1d6e6fc5e7d 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -60,6 +60,12 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor nDim = geometry->GetnDim(); + /*--- Check if Stochastic Backscatter Model can be used ---*/ + + if (backscatter && nDim != 3) { + SU2_MPI::Error("The Stochastic Backscatter Model can be used for three-dimensional problems only.", CURRENT_FUNCTION); + } + /*--- Single grid simulation ---*/ if (iMesh == MESH_0 || config->GetMGCycle() == FULLMG_CYCLE) { @@ -115,6 +121,11 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor } Solution_Inf[0] = nu_tilde_Inf; + if (backscatter) { + for (unsigned short iVar = 1; iVar < nVar; iVar++) { + Solution_Inf[iVar] = 0.0; // Backscatter variables initialized in CTurbSAVariable.hpp + } + } /*--- Factor_nu_Engine ---*/ Factor_nu_Engine = config->GetNuFactor_Engine(); @@ -161,8 +172,16 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor * due to arbitrary number of turbulence variables ---*/ Inlet_TurbVars.resize(nMarker); - for (unsigned long iMarker = 0; iMarker < nMarker; iMarker++) + for (unsigned long iMarker = 0; iMarker < nMarker; iMarker++) { Inlet_TurbVars[iMarker].resize(nVertex[iMarker],nVar) = nu_tilde_Inf; + if (backscatter) { + for (unsigned long iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + for (unsigned short iVar = 1; iVar < nVar; iVar++) { + Inlet_TurbVars[iMarker](iVertex,iVar) = 0.0; + } + } + } + } /*--- Store the initial CFL number for all grid points. ---*/ @@ -389,14 +408,14 @@ void CTurbSASolver::Source_Residual(CGeometry *geometry, CSolver **solver_contai bool backscatter = config->GetStochastic_Backscatter(); if (backscatter) { - su2double currentTime = config->GetPhysicalTime(); - su2double lastTime = numerics->GetLastTime(); + uint64_t currentTime = static_cast(config->GetTimeIter()); + uint64_t lastTime = static_cast(numerics->GetLastTime()); if (currentTime != lastTime) { numerics->SetLastTime(currentTime); su2double randomSource; for (unsigned short iDim = 0; iDim < 3; iDim++) { - unsigned long seed = RandomToolbox::GetSeed(currentTime); - randomSource = RandomToolbox::GetRandomNormal(seed, 0.0, 1.0); + uint64_t seed = RandomToolbox::GetSeed(currentTime, iDim+1); + randomSource = RandomToolbox::GetRandomNormal(seed); numerics->SetStochSource(randomSource, iDim); } } diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index 6b42a4d9106..5f4a58b84e0 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -27,7 +27,7 @@ #include "../../include/variables/CTurbSAVariable.hpp" -#include "random" +#include "../../../Common/include/toolboxes/random_toolbox.hpp" CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsigned long npoint, @@ -39,12 +39,13 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi if (!backscatter) { Solution_Old = Solution = val_nu_tilde; } else { - std::default_random_engine gen(std::random_device{}()); - std::normal_distribution rnd(0.0,1.0); for (unsigned long iPoint = 0; iPoint < npoint; iPoint++) { Solution_Old(iPoint, 0) = Solution(iPoint, 0) = val_nu_tilde; - for (unsigned short iVar = 1; iVar < nvar; iVar++) { - Solution_Old(iPoint, iVar) = Solution(iPoint, iVar) = rnd(gen); + for (unsigned long iVar = 1; iVar < nvar; iVar++) { + uint64_t seed = RandomToolbox::GetSeed( + static_cast(config->GetTimeIter()+1), + static_cast(iPoint*nvar + iVar)); + Solution_Old(iPoint, iVar) = Solution(iPoint, iVar) = RandomToolbox::GetRandomNormal(seed); } } } From 66293fdc667d2027bda91ccbf6fcec40bd062f01 Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Wed, 24 Sep 2025 12:51:28 +0200 Subject: [PATCH 04/70] Minor fixes - Enhance readability. - Ensure consistent declaration types. --- SU2_CFD/include/numerics/CNumerics.hpp | 2 +- .../include/numerics/turbulent/turb_convection.hpp | 12 ++++++------ SU2_CFD/src/solvers/CTurbSASolver.cpp | 4 ---- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index b35c49596e6..6e2c636dffd 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -906,7 +906,7 @@ class CNumerics { * \brief Set the value of physical time. * \param[in] val_last_time - Value of physical time. */ - void SetLastTime(su2double val_last_time) { + void SetLastTime(unsigned long val_last_time) { lastTime = val_last_time; } diff --git a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp index fe829cc054b..711934b518f 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp @@ -63,15 +63,15 @@ class CUpwSca_TurbSA final : public CUpwScalar { * \param[in] config - Definition of the particular problem. */ void FinishResidualCalc(const CConfig* config) override { + Flux[0] = a0*ScalarVar_i[0] + a1*ScalarVar_j[0]; + Jacobian_i[0][0] = a0; + Jacobian_j[0][0] = a1; bool backscatter = config->GetStochastic_Backscatter(); - if (!backscatter) { - Flux[0] = a0*ScalarVar_i[0] + a1*ScalarVar_j[0]; - Jacobian_i[0][0] = a0; - Jacobian_j[0][0] = a1; - } else { - Flux[0] = a0*ScalarVar_i[0] + a1*ScalarVar_j[0]; + if (backscatter) { for (unsigned short iVar = 1; iVar < nVar; iVar++) { Flux[iVar] = a0*V_i[idx.Density()]*ScalarVar_i[iVar] + a1*V_j[idx.Density()]*ScalarVar_j[iVar]; + } + for (unsigned short iVar = 0; iVar < nVar; iVar++) { for (unsigned short jVar = 0; jVar < nVar; jVar++) { Jacobian_i[iVar][jVar] = (iVar == jVar) ? a0 : 0.0; Jacobian_j[iVar][jVar] = (iVar == jVar) ? a1 : 0.0; diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 1d6e6fc5e7d..825e6faf747 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -444,10 +444,6 @@ void CTurbSASolver::Source_Residual(CGeometry *geometry, CSolver **solver_contai if (transition_BC || config->GetKind_Trans_Model() != TURB_TRANS_MODEL::NONE) { nodes->SetIntermittency(iPoint,numerics->GetIntermittencyEff()); } - - /*--- Store stochastic variables (Stochastic Backscatter Model) ---*/ - - /*--- Subtract residual and the Jacobian ---*/ From 3481df3267fff8908bbcbd43ecaf20a9ef6222ae Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Fri, 26 Sep 2025 09:33:06 +0200 Subject: [PATCH 05/70] Ensure consistency with DES - Extend implementation to 2D configurations. - Improve robustness. --- SU2_CFD/include/numerics/CNumerics.hpp | 2 +- .../include/numerics/flow/flow_diffusion.hpp | 2 +- .../numerics/turbulent/turb_sources.hpp | 67 ++++++++++++------- SU2_CFD/src/numerics/flow/flow_diffusion.cpp | 6 +- SU2_CFD/src/output/CFlowOutput.cpp | 16 ++--- SU2_CFD/src/solvers/CTurbSASolver.cpp | 12 +--- 6 files changed, 60 insertions(+), 45 deletions(-) diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index 6e2c636dffd..6d8551135d4 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -914,7 +914,7 @@ class CNumerics { * \brief Get the value of physical time. * \param[out] lastTime - Value of physical time. */ - inline su2double GetLastTime() const { return lastTime; } + inline unsigned long GetLastTime() const { return lastTime; } /*! * \brief Set the stochastic source term for the Langevin equations (Backscatter Model). diff --git a/SU2_CFD/include/numerics/flow/flow_diffusion.hpp b/SU2_CFD/include/numerics/flow/flow_diffusion.hpp index 55cf22d5e8f..b5bfc716afd 100644 --- a/SU2_CFD/include/numerics/flow/flow_diffusion.hpp +++ b/SU2_CFD/include/numerics/flow/flow_diffusion.hpp @@ -61,7 +61,7 @@ class CAvgGrad_Base : public CNumerics { Mean_Cp, /*!< \brief Mean value of the specific heat capacity at constant pressure. */ Mean_turb_ke, /*!< \brief Mean value of the turbulent kinetic energy. */ Mean_TauWall, /*!< \brief Mean wall shear stress (wall functions). */ - *Mean_StochVar, /*!< \brief Mean stochastic variables (Stochastic Backscatter Model). */ + Mean_StochVar[3], /*!< \brief Mean stochastic variables (Stochastic Backscatter Model). */ TauWall_i, TauWall_j, /*!< \brief Wall shear stress at point i and j (wall functions). */ dist_ij_2, /*!< \brief Length of the edge and face, squared */ Edge_Vector[MAXNDIM] = {0.0}, /*!< \brief Vector from point i to point j. */ diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index 27dfabb07fe..970c7b6d555 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -74,8 +74,8 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Residual and Jacobian ---*/ su2double Residual, *Jacobian_i; su2double Jacobian_Buffer; /*!< \brief Static storage for the Jacobian (which needs to be pointer for return type). */ - su2double ResidSB[4] = {0.0}, *JacobianSB_i[4]; - su2double JacobianSB_Buffer[16]; + su2double* ResidSB = nullptr; + su2double** JacobianSB_i = nullptr; const FlowIndices idx; /*!< \brief Object to manage the access to the flow primitives. */ const SA_ParsedOptions options; /*!< \brief Struct with SA options. */ @@ -139,29 +139,31 @@ class CSourceBase_TurbSA : public CNumerics { su2double scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * density * corrFac; ResidSB[0] = Residual; - for (unsigned short iDim = 1; iDim < 4; iDim++ ) { - ResidSB[iDim] = les_sensor * scaleFactor * stochSource[iDim-1] - - 1.0/tTurb * density * ScalarVar_i[iDim]; - ResidSB[iDim] *= Volume; + for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { + ResidSB[iVar] = std::nearbyint(les_sensor) * scaleFactor * stochSource[iVar-1] - + 1.0/tTurb * density * ScalarVar_i[iVar]; + ResidSB[iVar] *= Volume; } - for (unsigned short iDim = 0; iDim < 4; iDim++ ) - for (unsigned short jDim = 0; jDim < 4; jDim++ ) - JacobianSB_i[iDim][jDim] = 0.0; + for (unsigned short iVar = 0; iVar < nVar; iVar++ ) { + for (unsigned short jVar = 0; jVar < nVar; jVar++ ) { + JacobianSB_i[iVar][jVar] = 0.0; + if (iVar == jVar) JacobianSB_i[iVar][jVar] = -1.0/tTurb * density * Volume; + } + } JacobianSB_i[0][0] = Jacobian_i[0]; - JacobianSB_i[1][1] = JacobianSB_i[2][2] = JacobianSB_i[3][3] = - 1.0/tTurb * density * Volume; - su2double dnut_dnue = var.fv1 + 3.0 * var.cv1_3 * Ji_3 / pow(Ji_3 + var.cv1_3, 2); +/* su2double dnut_dnue = var.fv1 + 3.0 * var.cv1_3 * Ji_3 / pow(Ji_3 + var.cv1_3, 2); su2double dtTurb_dnut = - ct * pow(lengthScale,2) / (max(nut, nut_small)*max(nut, nut_small)); - for (unsigned short iDim = 1; iDim < 4; iDim++ ) { - JacobianSB_i[iDim][0] = - 1.0/tTurb * les_sensor * scaleFactor * stochSource[iDim-1] - + 1.0/(tTurb*tTurb) * ScalarVar_i[iDim] - + density * les_sensor * corrFac * stochSource[iDim-1] / + for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { + JacobianSB_i[iVar][0] = - 1.0/tTurb * les_sensor * scaleFactor * stochSource[iVar-1] + + 1.0/(tTurb*tTurb) * ScalarVar_i[iVar] + + density * les_sensor * corrFac * stochSource[iVar-1] / (tTurb * sqrt(2.0*tTurb*timeStep)); - JacobianSB_i[iDim][0] *= dtTurb_dnut * dnut_dnue * Volume; - } - } + JacobianSB_i[iVar][0] *= dtTurb_dnut * dnut_dnue * Volume; + } */ + } public: /*! @@ -170,7 +172,7 @@ class CSourceBase_TurbSA : public CNumerics { * \param[in] config - Definition of the particular problem. */ CSourceBase_TurbSA(unsigned short nDim, const CConfig* config) - : CNumerics(nDim, 1, config), + : CNumerics(nDim, config->GetStochastic_Backscatter() ? 1+nDim : 1, config), idx(nDim, config->GetnSpecies()), options(config->GetSAParsedOptions()), axisymmetric(config->GetAxisymmetric()), @@ -178,11 +180,30 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Setup the Jacobian pointer, we need to return su2double** but we know * the Jacobian is 1x1 so we use this trick to avoid heap allocation. ---*/ Jacobian_i = &Jacobian_Buffer; - /*--- Setup the Jacobian pointer for Stochastic Backscatter Model. ---*/ - for (unsigned short iVar = 0; iVar < 4; iVar++) - JacobianSB_i[iVar] = JacobianSB_Buffer + 4*iVar; + /*--- Setup the Jacobian for Stochastic Backscatter Model. ---*/ + if (config->GetStochastic_Backscatter()) { + ResidSB = new su2double [nVar] (); + JacobianSB_i = new su2double* [nVar]; + for (unsigned short iVar = 0; iVar < nVar; iVar++ ) { + JacobianSB_i[iVar] = new su2double [nVar] (); + } + } } + /*! + * \brief Destructor of the class. + */ + ~CSourceBase_TurbSA() { + if (JacobianSB_i) { + for (unsigned short iVar = 0; iVar < nVar; iVar++) { + delete [] JacobianSB_i[iVar]; + } + delete [] JacobianSB_i; + } + if (ResidSB) { + delete [] ResidSB; + } + } /*! * \brief Residual for source term integration. @@ -323,7 +344,7 @@ class CSourceBase_TurbSA : public CNumerics { } AD::SetPreaccOut(Residual); - if (backscatter) { AD::SetPreaccOut(ResidSB, 4); } + if (backscatter) { AD::SetPreaccOut(ResidSB, nVar); } AD::EndPreacc(); if (backscatter) diff --git a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp index c31d29106c5..dc5c51b41f3 100644 --- a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp +++ b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp @@ -460,7 +460,7 @@ CNumerics::ResidualType<> CAvgGrad_Flow::ComputeResidual(const CConfig* config) /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ if (config->GetStochastic_Backscatter()) { - for (iVar = 0; iVar < 3; iVar++) + for (iVar = 0; iVar < nDim; iVar++) Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_GradPrimVar+1, Mean_StochVar, stochReynStress); @@ -640,7 +640,7 @@ CNumerics::ResidualType<> CAvgGradInc_Flow::ComputeResidual(const CConfig* confi /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ if (config->GetStochastic_Backscatter()) { - for (iVar = 0; iVar < 3; iVar++) + for (iVar = 0; iVar < nDim; iVar++) Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_GradPrimVar+1, Mean_StochVar, stochReynStress); @@ -965,7 +965,7 @@ CNumerics::ResidualType<> CGeneralAvgGrad_Flow::ComputeResidual(const CConfig* c /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ if (config->GetStochastic_Backscatter()) { - for (iVar = 0; iVar < 3; iVar++) + for (iVar = 0; iVar < nDim; iVar++) Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_GradPrimVar+1, Mean_StochVar, stochReynStress); diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index d1ea3269634..aff75b2e3eb 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -969,8 +969,8 @@ void CFlowOutput::AddHistoryOutputFields_ScalarRMS_RES(const CConfig* config) { AddHistoryOutput("RMS_STOCH_VAR_X", "rms[stoch_x]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Root-mean square residual of stochastic vector y-component (Stochastic Backscatter Model). AddHistoryOutput("RMS_STOCH_VAR_Y", "rms[stoch_y]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); - /// DESCRIPTION: Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model). - AddHistoryOutput("RMS_STOCH_VAR_Z", "rms[stoch_z]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + /// DESCRIPTION: Root-mean square residual of stochastic vector z-component (Stochastic Backscatter Model). + if (nDim==3) AddHistoryOutput("RMS_STOCH_VAR_Z", "rms[stoch_z]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); } break; @@ -1033,7 +1033,7 @@ void CFlowOutput::AddHistoryOutputFields_ScalarMAX_RES(const CConfig* config) { /// DESCRIPTION: Maximum residual of stochastic vector y-component (Stochastic Backscatter Model). AddHistoryOutput("MAX_STOCH_VAR_Y", "max[stoch_y]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Maximum residual of stochastic vector z-component (Stochastic Backscatter Model). - AddHistoryOutput("MAX_STOCH_VAR_Z", "max[stoch_z]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + if (nDim==3) AddHistoryOutput("MAX_STOCH_VAR_Z", "max[stoch_z]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); } break; @@ -1179,17 +1179,17 @@ void CFlowOutput::LoadHistoryDataScalar(const CConfig* config, const CSolver* co if (config->GetStochastic_Backscatter()) { SetHistoryOutputValue("RMS_STOCH_VAR_X", log10(solver[TURB_SOL]->GetRes_RMS(1))); SetHistoryOutputValue("RMS_STOCH_VAR_Y", log10(solver[TURB_SOL]->GetRes_RMS(2))); - SetHistoryOutputValue("RMS_STOCH_VAR_Z", log10(solver[TURB_SOL]->GetRes_RMS(3))); + if (nDim==3) SetHistoryOutputValue("RMS_STOCH_VAR_Z", log10(solver[TURB_SOL]->GetRes_RMS(3))); SetHistoryOutputValue("MAX_STOCH_VAR_X", log10(solver[TURB_SOL]->GetRes_Max(1))); SetHistoryOutputValue("MAX_STOCH_VAR_Y", log10(solver[TURB_SOL]->GetRes_Max(2))); - SetHistoryOutputValue("MAX_STOCH_VAR_Z", log10(solver[TURB_SOL]->GetRes_Max(3))); + if (nDim==3) SetHistoryOutputValue("MAX_STOCH_VAR_Z", log10(solver[TURB_SOL]->GetRes_Max(3))); } if (multiZone) { SetHistoryOutputValue("BGS_NU_TILDE", log10(solver[TURB_SOL]->GetRes_BGS(0))); if (config->GetStochastic_Backscatter()) { SetHistoryOutputValue("BGS_STOCH_VAR_X", log10(solver[TURB_SOL]->GetRes_BGS(1))); SetHistoryOutputValue("BGS_STOCH_VAR_Y", log10(solver[TURB_SOL]->GetRes_BGS(2))); - SetHistoryOutputValue("BGS_STOCH_VAR_Z", log10(solver[TURB_SOL]->GetRes_BGS(3))); + if (nDim==3) SetHistoryOutputValue("BGS_STOCH_VAR_Z", log10(solver[TURB_SOL]->GetRes_BGS(3))); } } break; @@ -1516,7 +1516,7 @@ void CFlowOutput::SetVolumeOutputFieldsScalarMisc(const CConfig* config) { if (config->GetStochastic_Backscatter()) { AddVolumeOutput("STOCHASTIC_VAR_X", "Stochastic_Var_X", "BACKSCATTER", "x-component of the stochastic vector potential"); AddVolumeOutput("STOCHASTIC_VAR_Y", "Stochastic_Var_Y", "BACKSCATTER", "y-component of the stochastic vector potential"); - AddVolumeOutput("STOCHASTIC_VAR_Z", "Stochastic_Var_Z", "BACKSCATTER", "z-component of the stochastic vector potential"); + if (nDim==3) AddVolumeOutput("STOCHASTIC_VAR_Z", "Stochastic_Var_Z", "BACKSCATTER", "z-component of the stochastic vector potential"); } } @@ -1621,7 +1621,7 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con if (config->GetStochastic_Backscatter()) { SetVolumeOutputValue("STOCHASTIC_VAR_X", iPoint, Node_Turb->GetSolution(iPoint, 1)); SetVolumeOutputValue("STOCHASTIC_VAR_Y", iPoint, Node_Turb->GetSolution(iPoint, 2)); - SetVolumeOutputValue("STOCHASTIC_VAR_Z", iPoint, Node_Turb->GetSolution(iPoint, 3)); + if (nDim==3) SetVolumeOutputValue("STOCHASTIC_VAR_Z", iPoint, Node_Turb->GetSolution(iPoint, 3)); } } diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 825e6faf747..659d35693b8 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -47,11 +47,6 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor nPoint = geometry->GetnPoint(); nPointDomain = geometry->GetnPointDomain(); - /*--- Add Langevin equations if the Stochastic Backscatter Model is used ---*/ - - bool backscatter = config->GetStochastic_Backscatter(); - if (backscatter) { nVar += 3; nPrimVar += 3; } - /*--- Initialize nVarGrad for deallocation ---*/ nVarGrad = nVar; @@ -60,11 +55,10 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor nDim = geometry->GetnDim(); - /*--- Check if Stochastic Backscatter Model can be used ---*/ + /*--- Add Langevin equations if the Stochastic Backscatter Model is used ---*/ - if (backscatter && nDim != 3) { - SU2_MPI::Error("The Stochastic Backscatter Model can be used for three-dimensional problems only.", CURRENT_FUNCTION); - } + bool backscatter = config->GetStochastic_Backscatter(); + if (backscatter) { nVar += nDim; nVarGrad = nPrimVar = nVar; } /*--- Single grid simulation ---*/ From 85b8aaca32a453ec6b6734891253382bae37f2f3 Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Mon, 29 Sep 2025 18:09:40 +0200 Subject: [PATCH 06/70] Boundary conditions for Langevin equations Enforce boundary conditions in Langevin equations. --- SU2_CFD/include/numerics/CNumerics.hpp | 17 +--- .../numerics/scalar/scalar_diffusion.hpp | 2 +- .../numerics/turbulent/turb_sources.hpp | 50 ++++++---- SU2_CFD/include/solvers/CTurbSASolver.hpp | 29 +++++- SU2_CFD/include/solvers/CTurbSolver.hpp | 1 + SU2_CFD/include/variables/CTurbSAVariable.hpp | 17 ++++ SU2_CFD/include/variables/CVariable.hpp | 15 +++ SU2_CFD/src/solvers/CTurbSASolver.cpp | 99 ++++++++++++------- SU2_CFD/src/variables/CTurbSAVariable.cpp | 11 +-- 9 files changed, 163 insertions(+), 78 deletions(-) diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index 6d8551135d4..7327472d144 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -184,8 +184,7 @@ class CNumerics { su2double lesSensor_i, /*!< \brief LES sensor at point i. */ lesSensor_j; /*!< \brief LES sensor at point j. */ - unsigned long lastTime; /*!< \brief Physical time iteration of unsteady simulation. */ - su2double stochSource[3]; /*!< \brief Source term for Langevin equations in Stochastic Backscatter Model. */ + su2double stochSource[3] = {0.0}; /*!< \brief Source term for Langevin equations in Stochastic Backscatter Model. */ su2double stochVar_i[3], /*!< \brief Stochastic variables at point i for Stochastic Backscatter Model. */ stochVar_j[3]; /*!< \brief Stochastic variables at point j for Stochastic Backscatter Model. */ @@ -902,20 +901,6 @@ class CNumerics { lesSensor_j = val_les_j; } - /*! - * \brief Set the value of physical time. - * \param[in] val_last_time - Value of physical time. - */ - void SetLastTime(unsigned long val_last_time) { - lastTime = val_last_time; - } - - /*! - * \brief Get the value of physical time. - * \param[out] lastTime - Value of physical time. - */ - inline unsigned long GetLastTime() const { return lastTime; } - /*! * \brief Set the stochastic source term for the Langevin equations (Backscatter Model). * \param[in] val_stoch_source - Value of stochastic source term. diff --git a/SU2_CFD/include/numerics/scalar/scalar_diffusion.hpp b/SU2_CFD/include/numerics/scalar/scalar_diffusion.hpp index 13ee01f7eda..d92776f2f3b 100644 --- a/SU2_CFD/include/numerics/scalar/scalar_diffusion.hpp +++ b/SU2_CFD/include/numerics/scalar/scalar_diffusion.hpp @@ -64,7 +64,7 @@ class CAvgGrad_Scalar : public CNumerics { const FlowIndices idx; /*!< \brief Object to manage the access to the flow primitives. */ su2double Proj_Mean_GradScalarVar[MAXNVAR]; /*!< \brief Mean_gradScalarVar DOT normal, corrected if required. */ su2double proj_vector_ij = 0.0; /*!< \brief (Edge_Vector DOT normal)/|Edge_Vector|^2 */ - su2double Flux[MAXNVAR]; /*!< \brief Final result, diffusive flux/residual. */ + su2double Flux[MAXNVAR] = {0.0}; /*!< \brief Final result, diffusive flux/residual. */ su2double* Jacobian_i[MAXNVAR]; /*!< \brief Flux Jacobian w.r.t. node i. */ su2double* Jacobian_j[MAXNVAR]; /*!< \brief Flux Jacobian w.r.t. node j. */ su2double JacobianBuffer[2*MAXNVAR*MAXNVAR];/*!< \brief Static storage for the two Jacobians. */ diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index 970c7b6d555..29eb598652f 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -119,7 +119,7 @@ class CSourceBase_TurbSA : public CNumerics { */ inline void ResidualStochEquations(su2double timeStep, const su2double ct, su2double lengthScale, su2double les_sensor, - const CSAVariables& var) { + const CSAVariables& var, TIME_MARCHING time_marching) { const su2double& nue = ScalarVar_i[0]; @@ -132,9 +132,17 @@ class CSourceBase_TurbSA : public CNumerics { const su2double nut = nue * var.fv1; - su2double tTurb = ct * pow(lengthScale, 2) / max(nut, nut_small); + su2double tTurb = 0.01 * ct * pow(lengthScale, 2) / max(nut, nut_small); su2double tRat = timeStep / tTurb; - su2double corrFac = sqrt(0.5*(1.0+tRat)*(4.0+tRat)/(2.0+tRat)); + + su2double corrFac = 1.0; + if (time_marching == TIME_MARCHING::DT_STEPPING_2ND) { + corrFac = sqrt(0.5*(1.0+tRat)*(4.0+tRat)/(2.0+tRat)); + } else if (time_marching == TIME_MARCHING::DT_STEPPING_1ST) { + corrFac = sqrt(1.0+0.5*tRat); + } else { + SU2_MPI::Error("Stochastic Backscatter Model only implemented for dual time stepping.", CURRENT_FUNCTION); + } su2double scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * density * corrFac; @@ -153,16 +161,16 @@ class CSourceBase_TurbSA : public CNumerics { } JacobianSB_i[0][0] = Jacobian_i[0]; -/* su2double dnut_dnue = var.fv1 + 3.0 * var.cv1_3 * Ji_3 / pow(Ji_3 + var.cv1_3, 2); + su2double dnut_dnue = var.fv1 + 3.0 * var.cv1_3 * Ji_3 / pow(Ji_3 + var.cv1_3, 2); su2double dtTurb_dnut = - ct * pow(lengthScale,2) / (max(nut, nut_small)*max(nut, nut_small)); for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { - JacobianSB_i[iVar][0] = - 1.0/tTurb * les_sensor * scaleFactor * stochSource[iVar-1] + JacobianSB_i[iVar][0] = - 1.0/tTurb * std::nearbyint(les_sensor) * scaleFactor * stochSource[iVar-1] + 1.0/(tTurb*tTurb) * ScalarVar_i[iVar] - + density * les_sensor * corrFac * stochSource[iVar-1] / + + density * std::nearbyint(les_sensor) * corrFac * stochSource[iVar-1] / (tTurb * sqrt(2.0*tTurb*timeStep)); JacobianSB_i[iVar][0] *= dtTurb_dnut * dnut_dnue * Volume; - } */ + } } public: @@ -182,10 +190,10 @@ class CSourceBase_TurbSA : public CNumerics { Jacobian_i = &Jacobian_Buffer; /*--- Setup the Jacobian for Stochastic Backscatter Model. ---*/ if (config->GetStochastic_Backscatter()) { - ResidSB = new su2double [nVar] (); - JacobianSB_i = new su2double* [nVar]; - for (unsigned short iVar = 0; iVar < nVar; iVar++ ) { - JacobianSB_i[iVar] = new su2double [nVar] (); + ResidSB = new su2double [1+nDim] (); + JacobianSB_i = new su2double* [1+nDim]; + for (unsigned short iVar = 0; iVar < 1+nDim; iVar++ ) { + JacobianSB_i[iVar] = new su2double [1+nDim] (); } } } @@ -195,7 +203,7 @@ class CSourceBase_TurbSA : public CNumerics { */ ~CSourceBase_TurbSA() { if (JacobianSB_i) { - for (unsigned short iVar = 0; iVar < nVar; iVar++) { + for (unsigned short iVar = 0; iVar < 1+nDim; iVar++) { delete [] JacobianSB_i[iVar]; } delete [] JacobianSB_i; @@ -215,10 +223,11 @@ class CSourceBase_TurbSA : public CNumerics { const auto& laminar_viscosity = V_i[idx.LaminarViscosity()]; AD::StartPreacc(); - AD::SetPreaccIn(density, laminar_viscosity, StrainMag_i, ScalarVar_i[0], Volume, dist_i, roughness_i); + AD::SetPreaccIn(density, laminar_viscosity, StrainMag_i, Volume, dist_i, roughness_i); + AD::SetPreaccIn(ScalarVar_i, nVar); AD::SetPreaccIn(Vorticity_i, 3); AD::SetPreaccIn(PrimVar_Grad_i + idx.Velocity(), nDim, nDim); - AD::SetPreaccIn(ScalarVar_Grad_i[0], nDim); + AD::SetPreaccIn(ScalarVar_Grad_i, nVar, nDim); bool backscatter = config->GetStochastic_Backscatter(); if (backscatter) { @@ -337,14 +346,17 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Compute residual for Langevin equations (Stochastic Backscatter Model). ---*/ if (backscatter) { - const su2double constDES = config->GetConst_DES(); - const su2double ctTurb = 0.05 / pow(constDES, 2); - ResidualStochEquations(config->GetDelta_UnstTime(), ctTurb, dist_i, lesSensor_i, var); + const su2double ctTurb = 1.0; + ResidualStochEquations(config->GetDelta_UnstTime(), ctTurb, dist_i, lesSensor_i, var, + config->GetTime_Marching()); } } - AD::SetPreaccOut(Residual); - if (backscatter) { AD::SetPreaccOut(ResidSB, nVar); } + if (backscatter) { + AD::SetPreaccOut(ResidSB, nVar); + } else { + AD::SetPreaccOut(Residual); + } AD::EndPreacc(); if (backscatter) diff --git a/SU2_CFD/include/solvers/CTurbSASolver.hpp b/SU2_CFD/include/solvers/CTurbSASolver.hpp index 7220ffc3290..e2672b3ba8b 100644 --- a/SU2_CFD/include/solvers/CTurbSASolver.hpp +++ b/SU2_CFD/include/solvers/CTurbSASolver.hpp @@ -39,7 +39,13 @@ class CTurbSASolver final : public CTurbSolver { private: - su2double nu_tilde_Engine, nu_tilde_ActDisk; + su2double* nu_tilde_Engine = nullptr; + su2double* nu_tilde_ActDisk = nullptr; + su2double* ext_AverageNu = nullptr; + su2double* Res_Wall = nullptr; + su2double** Jacobian_i = nullptr; + su2double* nu_tilde_inturb = nullptr; + su2double* nu_tilde_WF = nullptr; /*! * \brief A virtual member. @@ -51,6 +57,11 @@ class CTurbSASolver final : public CTurbSolver { CGeometry *geometry, CConfig *config); + /*! + * \brief Update the source terms of the stochastic equations (Stochastic Backscatter Model). + */ + void SetLangevinSourceTerms(CConfig *config, CGeometry* geometry); + /*! * \brief Compute nu tilde from the wall functions. * \param[in] geometry - Geometrical definition of the problem. @@ -85,7 +96,21 @@ class CTurbSASolver final : public CTurbSolver { /*! * \brief Destructor of the class. */ - ~CTurbSASolver() = default; + ~CTurbSASolver() { + + for(unsigned short iVar = 0; iVar < nVar; ++iVar) { + delete [] Jacobian_i[iVar]; + } + delete [] Jacobian_i; + + delete [] Res_Wall; + delete [] nu_tilde_Engine; + delete [] nu_tilde_ActDisk; + delete [] ext_AverageNu; + delete [] nu_tilde_inturb; + delete [] nu_tilde_WF; + + } /*! * \brief Restart residual and compute gradients. diff --git a/SU2_CFD/include/solvers/CTurbSolver.hpp b/SU2_CFD/include/solvers/CTurbSolver.hpp index 8753093b346..db6415a0fda 100644 --- a/SU2_CFD/include/solvers/CTurbSolver.hpp +++ b/SU2_CFD/include/solvers/CTurbSolver.hpp @@ -152,6 +152,7 @@ class CTurbSolver : public CScalarSolver { * \brief Compute a suitable under-relaxation parameter to limit the change in the solution variables over * a nonlinear iteration for stability. * \param[in] allowableRatio - Maximum percentage update in variable per iteration. + * \param[in] backscatter - Flag for Stochastic Backscatter Model. */ void ComputeUnderRelaxationFactorHelper(su2double allowableRatio); }; diff --git a/SU2_CFD/include/variables/CTurbSAVariable.hpp b/SU2_CFD/include/variables/CTurbSAVariable.hpp index 9cab3dd177f..2a15145825e 100644 --- a/SU2_CFD/include/variables/CTurbSAVariable.hpp +++ b/SU2_CFD/include/variables/CTurbSAVariable.hpp @@ -41,6 +41,7 @@ class CTurbSAVariable final : public CTurbVariable { private: VectorType DES_LengthScale; VectorType LES_Mode; + MatrixType stochSource; VectorType Vortex_Tilting; public: @@ -74,6 +75,22 @@ class CTurbSAVariable final : public CTurbVariable { */ inline void SetDES_LengthScale(unsigned long iPoint, su2double val_des_lengthscale) override { DES_LengthScale(iPoint) = val_des_lengthscale; } +/*! + * \brief Get the source terms for the stochastic equations. + * \param[in] iPoint - Point index. + * \param[in] iDim - Dimension index. + * \return Value of the source term for the stochastic equations. + */ + inline su2double GetLangevinSourceTerms(unsigned long iPoint, unsigned short iDim) const override { return stochSource(iPoint, iDim); } + + /*! + * \brief Set the source terms for the stochastic equations. + * \param[in] iPoint - Point index. + * \param[in] iDim - Dimension index. + * \param[in] val_stochSource - Value of the source term for the stochastic equations. + */ + inline void SetLangevinSourceTerms(unsigned long iPoint, unsigned short iDim, su2double val_stochSource) override { stochSource(iPoint, iDim) = val_stochSource; } + /*! * \brief Set the LES sensor. */ diff --git a/SU2_CFD/include/variables/CVariable.hpp b/SU2_CFD/include/variables/CVariable.hpp index 30753179836..f07935f04bc 100644 --- a/SU2_CFD/include/variables/CVariable.hpp +++ b/SU2_CFD/include/variables/CVariable.hpp @@ -409,6 +409,21 @@ class CVariable { */ inline virtual void SetLES_Mode(unsigned long iPoint, su2double val_les_mode) {} + /*! + * \brief A virtual member. + * \param[in] iPoint - Point index. + * \param[in] iDim - Dimension index. + */ + inline virtual su2double GetLangevinSourceTerms(unsigned long iPoint, unsigned short iDim) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] iPoint - Point index. + * \param[in] iDim - Dimension index. + * \param[in] val_stochSource - Source term for Langevin equations. + */ + inline virtual void SetLangevinSourceTerms(unsigned long iPoint, unsigned short iDim, su2double val_stochSource) {} + /*! * \brief A virtual member. * \param[in] iPoint - Point index. diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 659d35693b8..dbbaafe1cf8 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -117,20 +117,22 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor Solution_Inf[0] = nu_tilde_Inf; if (backscatter) { for (unsigned short iVar = 1; iVar < nVar; iVar++) { - Solution_Inf[iVar] = 0.0; // Backscatter variables initialized in CTurbSAVariable.hpp + Solution_Inf[iVar] = 0.0; } } /*--- Factor_nu_Engine ---*/ - Factor_nu_Engine = config->GetNuFactor_Engine(); - nu_tilde_Engine = Factor_nu_Engine*Viscosity_Inf/Density_Inf; + Factor_nu_Engine = config->GetNuFactor_Engine(); + nu_tilde_Engine = new su2double [nVar] (); + nu_tilde_Engine[0] = Factor_nu_Engine*Viscosity_Inf/Density_Inf; if (config->GetSAParsedOptions().bc) { - nu_tilde_Engine = 0.005*Factor_nu_Engine*Viscosity_Inf/Density_Inf; + nu_tilde_Engine[0] = 0.005*Factor_nu_Engine*Viscosity_Inf/Density_Inf; } /*--- Factor_nu_ActDisk ---*/ - Factor_nu_ActDisk = config->GetNuFactor_Engine(); - nu_tilde_ActDisk = Factor_nu_ActDisk*Viscosity_Inf/Density_Inf; + Factor_nu_ActDisk = config->GetNuFactor_Engine(); + nu_tilde_ActDisk = new su2double [nVar] (); + nu_tilde_ActDisk[0] = Factor_nu_ActDisk*Viscosity_Inf/Density_Inf; /*--- Eddy viscosity at infinity ---*/ su2double Ji, Ji_3, fv1, cv1_3 = 7.1*7.1*7.1; @@ -140,6 +142,19 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor fv1 = Ji_3/(Ji_3+cv1_3); muT_Inf = Density_Inf*fv1*nu_tilde_Inf; + ext_AverageNu = new su2double [nVar] (); + + Res_Wall = new su2double [nVar] (); + + Jacobian_i = new su2double* [nVar]; + for (unsigned short iVar = 0; iVar < nVar; iVar++) { + Jacobian_i[iVar] = new su2double [nVar] (); + } + + nu_tilde_inturb = new su2double [nVar] (); + + nu_tilde_WF = new su2double [nVar] (); + /*--- Initialize the solution to the far-field state everywhere. ---*/ nodes = new CTurbSAVariable(nu_tilde_Inf, muT_Inf, nPoint, nDim, nVar, config); @@ -222,6 +237,10 @@ void CTurbSASolver::Preprocessing(CGeometry *geometry, CSolver **solver_containe SetDES_LengthScale(solver_container, geometry, config); + /*--- Compute source terms for Langevin equations ---*/ + + if (config->GetStochastic_Backscatter()) SetLangevinSourceTerms(config, geometry); + } } @@ -400,19 +419,9 @@ void CTurbSASolver::Source_Residual(CGeometry *geometry, CSolver **solver_contai /*--- Compute source terms in Langevin equations (Stochastic Basckscatter Model) ---*/ - bool backscatter = config->GetStochastic_Backscatter(); - if (backscatter) { - uint64_t currentTime = static_cast(config->GetTimeIter()); - uint64_t lastTime = static_cast(numerics->GetLastTime()); - if (currentTime != lastTime) { - numerics->SetLastTime(currentTime); - su2double randomSource; - for (unsigned short iDim = 0; iDim < 3; iDim++) { - uint64_t seed = RandomToolbox::GetSeed(currentTime, iDim+1); - randomSource = RandomToolbox::GetRandomNormal(seed); - numerics->SetStochSource(randomSource, iDim); - } - } + if (config->GetStochastic_Backscatter()) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + numerics->SetStochSource(nodes->GetLangevinSourceTerms(iPoint, iDim), iDim); } } @@ -540,19 +549,20 @@ void CTurbSASolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_conta su2double coeff = (nu_total/sigma); su2double RoughWallBC = nodes->GetSolution(iPoint,0)/(0.03*Roughness_Height); - su2double Res_Wall;// = new su2double [nVar]; - Res_Wall = coeff*RoughWallBC*Area; - LinSysRes.SubtractBlock(iPoint, &Res_Wall); + Res_Wall[0] = coeff*RoughWallBC*Area; + LinSysRes.SubtractBlock(iPoint, Res_Wall); - su2double Jacobian_i = (laminar_viscosity /density *Area)/(0.03*Roughness_Height*sigma); - Jacobian_i += 2.0*RoughWallBC*Area/sigma; - if (implicit) Jacobian.AddVal2Diag(iPoint, -Jacobian_i); + Jacobian_i[0][0] = (laminar_viscosity /density *Area)/(0.03*Roughness_Height*sigma); + Jacobian_i[0][0] += 2.0*RoughWallBC*Area/sigma; + if (implicit) Jacobian.AddVal2Diag(iPoint, 0, -Jacobian_i[0][0]); } } } END_SU2_OMP_FOR } + + void CTurbSASolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { @@ -900,7 +910,7 @@ void CTurbSASolver::BC_Engine_Exhaust(CGeometry *geometry, CSolver **solver_cont /*--- Set the turbulent variable states (prescribed for an inflow) ---*/ - conv_numerics->SetScalarVar(nodes->GetSolution(iPoint), &nu_tilde_Engine); + conv_numerics->SetScalarVar(nodes->GetSolution(iPoint), nu_tilde_Engine); /*--- Set various other quantities in the conv_numerics class ---*/ @@ -1053,7 +1063,7 @@ void CTurbSASolver::BC_ActDisk(CGeometry *geometry, CSolver **solver_container, } else { /*--- Outflow analysis ---*/ - conv_numerics->SetScalarVar(nodes->GetSolution(iPoint), &nu_tilde_ActDisk); + conv_numerics->SetScalarVar(nodes->GetSolution(iPoint), nu_tilde_ActDisk); } /*--- Grid Movement ---*/ @@ -1114,6 +1124,8 @@ void CTurbSASolver::BC_Inlet_MixingPlane(CGeometry *geometry, CSolver **solver_c su2double extAverageNu = solver_container[FLOW_SOL]->GetExtAverageNu(val_marker, iSpan); + ext_AverageNu[0] = extAverageNu; + /*--- Loop over all the vertices on this boundary marker ---*/ SU2_OMP_FOR_STAT(OMP_MIN_SIZE) @@ -1148,7 +1160,7 @@ void CTurbSASolver::BC_Inlet_MixingPlane(CGeometry *geometry, CSolver **solver_c /*--- Set the turbulent variable states (prescribed for an inflow) ---*/ - conv_numerics->SetScalarVar(nodes->GetSolution(iPoint), &extAverageNu); + conv_numerics->SetScalarVar(nodes->GetSolution(iPoint), ext_AverageNu); /*--- Set various other quantities in the conv_numerics class ---*/ @@ -1178,7 +1190,7 @@ void CTurbSASolver::BC_Inlet_MixingPlane(CGeometry *geometry, CSolver **solver_c /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ - visc_numerics->SetScalarVar(nodes->GetSolution(iPoint), &extAverageNu); + visc_numerics->SetScalarVar(nodes->GetSolution(iPoint), ext_AverageNu); visc_numerics->SetScalarVarGradient(nodes->GetGradient(iPoint), nodes->GetGradient(iPoint)); @@ -1253,7 +1265,9 @@ void CTurbSASolver::BC_Inlet_Turbo(CGeometry *geometry, CSolver **solver_contain /*--- Set the turbulent variable states (prescribed for an inflow) ---*/ - conv_numerics->SetScalarVar(nodes->GetSolution(iPoint), &nu_tilde); + nu_tilde_inturb[0] = nu_tilde; + + conv_numerics->SetScalarVar(nodes->GetSolution(iPoint), nu_tilde_inturb); if (dynamic_grid) conv_numerics->SetGridVel(geometry->nodes->GetGridVel(iPoint), @@ -1283,7 +1297,7 @@ void CTurbSASolver::BC_Inlet_Turbo(CGeometry *geometry, CSolver **solver_contain /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ - visc_numerics->SetScalarVar(nodes->GetSolution(iPoint), &nu_tilde); + visc_numerics->SetScalarVar(nodes->GetSolution(iPoint), nu_tilde_inturb); visc_numerics->SetScalarVarGradient(nodes->GetGradient(iPoint), nodes->GetGradient(iPoint)); @@ -1374,7 +1388,9 @@ void CTurbSASolver::SetTurbVars_WF(CGeometry *geometry, CSolver **solver_contain if (counter > max_iter) break; } - nodes->SetSolution_Old(iPoint_Neighbor, &nu_til); + nu_tilde_WF[0] = nu_til; + + nodes->SetSolution_Old(iPoint_Neighbor, nu_tilde_WF); LinSysRes.SetBlock_Zero(iPoint_Neighbor); /*--- includes 1 in the diagonal ---*/ @@ -1569,6 +1585,22 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC END_SU2_OMP_FOR } +void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) { + + uint64_t currentTime = static_cast(config->GetTimeIter()); + + SU2_OMP_FOR_DYN(omp_chunk_size) + for (auto iPoint = 0ul; iPoint < nPointDomain; iPoint++){ + const auto iGlobalPoint = geometry->nodes->GetGlobalIndex(iPoint); + for (auto iDim = 0u; iDim < nDim; iDim++){ + uint64_t seed = RandomToolbox::GetSeed(currentTime+1, iGlobalPoint+iDim+1); + nodes->SetLangevinSourceTerms(iPoint, iDim, RandomToolbox::GetRandomNormal(seed)); + } + } + END_SU2_OMP_FOR + +} + void CTurbSASolver::SetInletAtVertex(const su2double *val_inlet, unsigned short iMarker, unsigned long iVertex) { @@ -1603,7 +1635,8 @@ void CTurbSASolver::ComputeUnderRelaxationFactor(const CConfig *config) { SA_NEG model is more robust due to allowing for negative nu_tilde, so the under-relaxation is not applied to that variant. */ - if (config->GetSAParsedOptions().version == SA_OPTIONS::NEG) return; + if (config->GetSAParsedOptions().version == SA_OPTIONS::NEG || + config->GetStochastic_Backscatter()) return; /* Loop over the solution update given by relaxing the linear system for this nonlinear iteration. */ diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index 5f4a58b84e0..3450ebfbcd4 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -27,7 +27,6 @@ #include "../../include/variables/CTurbSAVariable.hpp" -#include "../../../Common/include/toolboxes/random_toolbox.hpp" CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsigned long npoint, @@ -39,13 +38,10 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi if (!backscatter) { Solution_Old = Solution = val_nu_tilde; } else { - for (unsigned long iPoint = 0; iPoint < npoint; iPoint++) { + for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { Solution_Old(iPoint, 0) = Solution(iPoint, 0) = val_nu_tilde; - for (unsigned long iVar = 1; iVar < nvar; iVar++) { - uint64_t seed = RandomToolbox::GetSeed( - static_cast(config->GetTimeIter()+1), - static_cast(iPoint*nvar + iVar)); - Solution_Old(iPoint, iVar) = Solution(iPoint, iVar) = RandomToolbox::GetRandomNormal(seed); + for (unsigned long iVar = 1; iVar < nVar; iVar++) { + Solution_Old(iPoint, iVar) = Solution(iPoint, iVar) = 0.0; } } } @@ -64,6 +60,7 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi DES_LengthScale.resize(nPoint) = su2double(0.0); LES_Mode.resize(nPoint) = su2double(0.0); Vortex_Tilting.resize(nPoint); + stochSource.resize(nPoint, nDim) = su2double(0.0); } void CTurbSAVariable::SetVortex_Tilting(unsigned long iPoint, CMatrixView PrimGrad_Flow, From 62930428a1a0e146753527b04cab6b0c0b985b4a Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Tue, 30 Sep 2025 15:39:10 +0200 Subject: [PATCH 07/70] Use symmetry-preserving scheme for Langevin equations - Implement a skew-symmetric scheme for the discretization of the convective terms in the Langevin equations. - Fix the seed for the generation of the random source terms at the beginning of the simulation. --- Common/include/CConfig.hpp | 7 ++++ Common/include/toolboxes/random_toolbox.hpp | 12 +++---- Common/src/CConfig.cpp | 9 +++-- SU2_CFD/include/numerics/CNumerics.hpp | 13 ------- .../numerics/scalar/scalar_convection.hpp | 8 +++++ .../numerics/turbulent/turb_convection.hpp | 13 +++---- .../numerics/turbulent/turb_sources.hpp | 32 ++++++++--------- SU2_CFD/include/solvers/CTurbSASolver.hpp | 9 +++++ SU2_CFD/include/variables/CTurbSAVariable.hpp | 19 +++++++++- SU2_CFD/include/variables/CVariable.hpp | 19 +++++++++- SU2_CFD/src/output/CFlowOutput.cpp | 6 ++++ SU2_CFD/src/solvers/CTurbSASolver.cpp | 35 ++++++++++++++----- SU2_CFD/src/variables/CTurbSAVariable.cpp | 2 ++ config_template.cfg | 3 ++ 14 files changed, 133 insertions(+), 54 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index bc753e18b93..85328ee4d43 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -1082,6 +1082,7 @@ class CConfig { WINDOW_FUNCTION Kind_WindowFct; /*!< \brief Type of window (weight) function for objective functional. */ unsigned short Kind_HybridRANSLES; /*!< \brief Kind of Hybrid RANS/LES. */ bool StochasticBackscatter; /*!< \brief Option to include Stochastic Backscatter Model. */ + su2double SBS_Ctau; /*!< \brief Stochastic Backscatter Model timescale coefficient. */ unsigned short Kind_RoeLowDiss; /*!< \brief Kind of Roe scheme with low dissipation for unsteady flows. */ unsigned short nSpanWiseSections; /*!< \brief number of span-wise sections */ @@ -9543,6 +9544,12 @@ class CConfig { */ su2double GetConst_DES(void) const { return Const_DES; } + /*! + * \brief Get the DES Constant. + * \return Value of DES constant. + */ + su2double GetSBS_Ctau(void) const { return SBS_Ctau; } + /*! * \brief Get the type of tape that will be checked in a tape debug run. */ diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index 7d9a3a85608..811691ac772 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -39,8 +39,8 @@ namespace RandomToolbox { * \param[in] v2 Value to mix in. * \return Combined hash value. */ -inline uint64_t HashCombine(uint64_t v1, uint64_t v2) { - const uint64_t prime = 1099511628211ULL; +inline unsigned long HashCombine(unsigned long v1, unsigned long v2) { + const unsigned long prime = 1099511628211ULL; v1 ^= v2; v1 *= prime; return v1; @@ -51,7 +51,7 @@ inline uint64_t HashCombine(uint64_t v1, uint64_t v2) { * \param[in] x Double to integer. * \return Hash value of the double (not portable). */ -inline uint64_t ToUInt64(double x) { return std::hash{}(x); } +inline unsigned long ToUInt64(double x) { return std::hash{}(x); } /*! * \brief Build a deterministic seed from physical time. @@ -59,7 +59,7 @@ inline uint64_t ToUInt64(double x) { return std::hash{}(x); } * \param[in] y Second integer value. * \return 64-bit seed value. */ -inline uint64_t GetSeed(uint64_t x, uint64_t y) { return HashCombine(x, y); } +inline unsigned long GetSeed(unsigned long x, unsigned long y) { return HashCombine(x, y); } /*! * \brief Generate a standard normally-distributed random number. @@ -68,8 +68,8 @@ inline uint64_t GetSeed(uint64_t x, uint64_t y) { return HashCombine(x, y); } * \param[in] stddev Standard deviation of the normal distribution (default 1). * \return Normally-distributed random number. */ -inline double GetRandomNormal(uint64_t seed, double mean = 0.0, double stddev = 1.0) { - std::mt19937_64 gen(seed); +inline double GetRandomNormal(unsigned long seed, double mean = 0.0, double stddev = 1.0) { + std::mt19937 gen(seed); std::normal_distribution rnd(mean, stddev); return rnd(gen); } diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 898a0333c1e..81695d75dbe 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2911,6 +2911,9 @@ void CConfig::SetConfig_Options() { /* DESCRIPTION: DES Constant */ addDoubleOption("DES_CONST", Const_DES, 0.65); + /* DESCRIPTION: SBS timescale constant */ + addDoubleOption("SBS_CTAU", SBS_Ctau, 0.05); + /* DESCRIPTION: Specify Hybrid RANS/LES model */ addEnumOption("HYBRID_RANSLES", Kind_HybridRANSLES, HybridRANSLES_Map, NO_HYBRIDRANSLES); @@ -6451,10 +6454,12 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { case SA_EDDES: cout << "Delayed Detached Eddy Simulation (DDES) with Shear-layer Adapted SGS" << endl; break; } cout << "Stochastic Backscatter: "; - if (StochasticBackscatter) + if (StochasticBackscatter) { cout << "ON" << endl; - else + cout << "Backscatter timescale coefficient: " << SBS_Ctau << endl; + } else { cout << "OFF" << endl; + } if (StochasticBackscatter && Kind_HybridRANSLES == NO_HYBRIDRANSLES) SU2_MPI::Error("Stochastic Backscatter can only be activated with Hybrid RANS/LES.", CURRENT_FUNCTION); break; diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index 7327472d144..8899491e17e 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -181,9 +181,6 @@ class CNumerics { su2double MeanPerturbedRSM[3][3]; /*!< \brief Perturbed Reynolds stress tensor */ su2double stochReynStress[3][3]; /*!< \brief Stochastic contribution to Reynolds stress tensor for Backscatter Model. */ - su2double - lesSensor_i, /*!< \brief LES sensor at point i. */ - lesSensor_j; /*!< \brief LES sensor at point j. */ su2double stochSource[3] = {0.0}; /*!< \brief Source term for Langevin equations in Stochastic Backscatter Model. */ su2double stochVar_i[3], /*!< \brief Stochastic variables at point i for Stochastic Backscatter Model. */ @@ -891,16 +888,6 @@ class CNumerics { dist_j = val_dist_j; } - /*! - * \brief Set the value of the LES sensor. - * \param[in] val_les_i - Value of the LES sensor at point point i. - * \param[in] val_les_j - Value of the LES sensor at point point j. - */ - void SetLESSensor(su2double val_les_i, su2double val_les_j) { - lesSensor_i = val_les_i; - lesSensor_j = val_les_j; - } - /*! * \brief Set the stochastic source term for the Langevin equations (Backscatter Model). * \param[in] val_stoch_source - Value of stochastic source term. diff --git a/SU2_CFD/include/numerics/scalar/scalar_convection.hpp b/SU2_CFD/include/numerics/scalar/scalar_convection.hpp index 91b8429e0aa..4395a4a2092 100644 --- a/SU2_CFD/include/numerics/scalar/scalar_convection.hpp +++ b/SU2_CFD/include/numerics/scalar/scalar_convection.hpp @@ -52,6 +52,7 @@ class CUpwScalar : public CNumerics { const FlowIndices idx; /*!< \brief Object to manage the access to the flow primitives. */ su2double a0 = 0.0; /*!< \brief The maximum of the face-normal velocity and 0. */ su2double a1 = 0.0; /*!< \brief The minimum of the face-normal velocity and 0. */ + su2double qij = 0.0; /*!< \brief The face-normal velocity (Langevin equations). */ su2double Flux[MAXNVAR]; /*!< \brief Final result, diffusive flux/residual. */ su2double* Jacobian_i[MAXNVAR]; /*!< \brief Flux Jacobian w.r.t. node i. */ su2double* Jacobian_j[MAXNVAR]; /*!< \brief Flux Jacobian w.r.t. node j. */ @@ -140,6 +141,13 @@ class CUpwScalar : public CNumerics { a1 = fmin(0.0, q_ij); } + if (config->GetStochastic_Backscatter()) { + qij = 0.0; + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + qij += 0.5 * (V_i[idx.Density()]*V_i[iDim + idx.Velocity()] + V_j[idx.Density()]*V_j[iDim + idx.Velocity()]) * Normal[iDim]; + } + } + FinishResidualCalc(config); AD::SetPreaccOut(Flux, nVar); diff --git a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp index 711934b518f..15635dc9fcc 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp @@ -52,6 +52,7 @@ class CUpwSca_TurbSA final : public CUpwScalar { using Base::V_j; using Base::idx; using Base::nVar; + using Base::qij; /*! * \brief Adds any extra variables to AD. @@ -63,21 +64,21 @@ class CUpwSca_TurbSA final : public CUpwScalar { * \param[in] config - Definition of the particular problem. */ void FinishResidualCalc(const CConfig* config) override { - Flux[0] = a0*ScalarVar_i[0] + a1*ScalarVar_j[0]; - Jacobian_i[0][0] = a0; - Jacobian_j[0][0] = a1; bool backscatter = config->GetStochastic_Backscatter(); if (backscatter) { for (unsigned short iVar = 1; iVar < nVar; iVar++) { - Flux[iVar] = a0*V_i[idx.Density()]*ScalarVar_i[iVar] + a1*V_j[idx.Density()]*ScalarVar_j[iVar]; + Flux[iVar] = qij * 0.5 * (ScalarVar_i[iVar] + ScalarVar_j[iVar]); } for (unsigned short iVar = 0; iVar < nVar; iVar++) { for (unsigned short jVar = 0; jVar < nVar; jVar++) { - Jacobian_i[iVar][jVar] = (iVar == jVar) ? a0 : 0.0; - Jacobian_j[iVar][jVar] = (iVar == jVar) ? a1 : 0.0; + Jacobian_i[iVar][jVar] = (iVar == jVar) ? 0.5*qij : 0.0; + Jacobian_j[iVar][jVar] = (iVar == jVar) ? 0.5*qij : 0.0; } } } + Flux[0] = a0*ScalarVar_i[0] + a1*ScalarVar_j[0]; + Jacobian_i[0][0] = a0; + Jacobian_j[0][0] = a1; } public: diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index 29eb598652f..cb74c1523ac 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -118,7 +118,7 @@ class CSourceBase_TurbSA : public CNumerics { * \brief Include source-term residuals for Langevin equations (Stochastic Backscatter Model) */ inline void ResidualStochEquations(su2double timeStep, const su2double ct, - su2double lengthScale, su2double les_sensor, + su2double lengthScale, const CSAVariables& var, TIME_MARCHING time_marching) { const su2double& nue = ScalarVar_i[0]; @@ -132,7 +132,7 @@ class CSourceBase_TurbSA : public CNumerics { const su2double nut = nue * var.fv1; - su2double tTurb = 0.01 * ct * pow(lengthScale, 2) / max(nut, nut_small); + su2double tTurb = ct * pow(lengthScale, 2) / max(nut, nut_small); su2double tRat = timeStep / tTurb; su2double corrFac = 1.0; @@ -148,8 +148,7 @@ class CSourceBase_TurbSA : public CNumerics { ResidSB[0] = Residual; for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { - ResidSB[iVar] = std::nearbyint(les_sensor) * scaleFactor * stochSource[iVar-1] - - 1.0/tTurb * density * ScalarVar_i[iVar]; + ResidSB[iVar] = scaleFactor * stochSource[iVar-1] - 1.0/tTurb * density * ScalarVar_i[iVar]; ResidSB[iVar] *= Volume; } @@ -161,16 +160,16 @@ class CSourceBase_TurbSA : public CNumerics { } JacobianSB_i[0][0] = Jacobian_i[0]; - su2double dnut_dnue = var.fv1 + 3.0 * var.cv1_3 * Ji_3 / pow(Ji_3 + var.cv1_3, 2); - su2double dtTurb_dnut = - ct * pow(lengthScale,2) / (max(nut, nut_small)*max(nut, nut_small)); +// su2double dnut_dnue = var.fv1 + 3.0 * var.cv1_3 * Ji_3 / pow(Ji_3 + var.cv1_3, 2); +// su2double dtTurb_dnut = - ct * pow(lengthScale,2) / (max(nut, nut_small)*max(nut, nut_small)); - for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { - JacobianSB_i[iVar][0] = - 1.0/tTurb * std::nearbyint(les_sensor) * scaleFactor * stochSource[iVar-1] - + 1.0/(tTurb*tTurb) * ScalarVar_i[iVar] - + density * std::nearbyint(les_sensor) * corrFac * stochSource[iVar-1] / - (tTurb * sqrt(2.0*tTurb*timeStep)); - JacobianSB_i[iVar][0] *= dtTurb_dnut * dnut_dnue * Volume; - } +// for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { +// JacobianSB_i[iVar][0] = - 1.0/tTurb * scaleFactor * stochSource[iVar-1] +// + 1.0/(tTurb*tTurb) * ScalarVar_i[iVar] +// + density * corrFac * stochSource[iVar-1] / +// (tTurb * sqrt(2.0*tTurb*timeStep)); +// JacobianSB_i[iVar][0] *= dtTurb_dnut * dnut_dnue * Volume; +// } } public: @@ -231,7 +230,6 @@ class CSourceBase_TurbSA : public CNumerics { bool backscatter = config->GetStochastic_Backscatter(); if (backscatter) { - AD::SetPreaccIn(lesSensor_i); AD::SetPreaccIn(stochSource, 3); } @@ -346,8 +344,10 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Compute residual for Langevin equations (Stochastic Backscatter Model). ---*/ if (backscatter) { - const su2double ctTurb = 1.0; - ResidualStochEquations(config->GetDelta_UnstTime(), ctTurb, dist_i, lesSensor_i, var, + const su2double DES_const = config->GetConst_DES(); + const su2double ctau = config->GetSBS_Ctau(); + const su2double ctTurb = ctau / pow(DES_const, 2); + ResidualStochEquations(config->GetDelta_UnstTime(), ctTurb, dist_i, var, config->GetTime_Marching()); } } diff --git a/SU2_CFD/include/solvers/CTurbSASolver.hpp b/SU2_CFD/include/solvers/CTurbSASolver.hpp index e2672b3ba8b..2a6a489f304 100644 --- a/SU2_CFD/include/solvers/CTurbSASolver.hpp +++ b/SU2_CFD/include/solvers/CTurbSASolver.hpp @@ -59,9 +59,18 @@ class CTurbSASolver final : public CTurbSolver { /*! * \brief Update the source terms of the stochastic equations (Stochastic Backscatter Model). + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition. */ void SetLangevinSourceTerms(CConfig *config, CGeometry* geometry); + /*! + * \brief Set seed for Langevin equations (Stochastic Backscatter Model). + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition. + */ + void SetLangevinSeed(CGeometry* geometry); + /*! * \brief Compute nu tilde from the wall functions. * \param[in] geometry - Geometrical definition of the problem. diff --git a/SU2_CFD/include/variables/CTurbSAVariable.hpp b/SU2_CFD/include/variables/CTurbSAVariable.hpp index 2a15145825e..b47585dab6f 100644 --- a/SU2_CFD/include/variables/CTurbSAVariable.hpp +++ b/SU2_CFD/include/variables/CTurbSAVariable.hpp @@ -43,6 +43,7 @@ class CTurbSAVariable final : public CTurbVariable { VectorType LES_Mode; MatrixType stochSource; VectorType Vortex_Tilting; + MatrixTypeInt stochSeed; public: /*! @@ -75,7 +76,7 @@ class CTurbSAVariable final : public CTurbVariable { */ inline void SetDES_LengthScale(unsigned long iPoint, su2double val_des_lengthscale) override { DES_LengthScale(iPoint) = val_des_lengthscale; } -/*! + /*! * \brief Get the source terms for the stochastic equations. * \param[in] iPoint - Point index. * \param[in] iDim - Dimension index. @@ -116,4 +117,20 @@ class CTurbSAVariable final : public CTurbVariable { */ inline su2double GetVortex_Tilting(unsigned long iPoint) const override { return Vortex_Tilting(iPoint); } + /*! + * \brief Get the seed for the stochastic equations. + * \param[in] iPoint - Point index. + * \param[in] iDim - Dimension index. + * \return Value of the seed for the stochastic equations. + */ + inline su2double GetLangevinSeed(unsigned long iPoint, unsigned short iDim) const override { return stochSeed(iPoint, iDim); } + + /*! + * \brief Set the seed for the stochastic equations. + * \param[in] iPoint - Point index. + * \param[in] iDim - Dimension index. + * \param[in] val_stochSeed - Value of the seed for the stochastic equations. + */ + inline void SetLangevinSeed(unsigned long iPoint, unsigned short iDim, unsigned long val_stochSeed) override { stochSeed(iPoint, iDim) = val_stochSeed; } + }; diff --git a/SU2_CFD/include/variables/CVariable.hpp b/SU2_CFD/include/variables/CVariable.hpp index f07935f04bc..6b1159d3888 100644 --- a/SU2_CFD/include/variables/CVariable.hpp +++ b/SU2_CFD/include/variables/CVariable.hpp @@ -51,6 +51,7 @@ class CVariable { protected: using VectorType = C2DContainer; using MatrixType = C2DContainer; + using MatrixTypeInt = C2DContainer; MatrixType Solution; /*!< \brief Solution of the problem. */ MatrixType Solution_Old; /*!< \brief Old solution of the problem R-K. */ @@ -420,10 +421,26 @@ class CVariable { * \brief A virtual member. * \param[in] iPoint - Point index. * \param[in] iDim - Dimension index. - * \param[in] val_stochSource - Source term for Langevin equations. + * \param[in] val_stochSource - Seed for Langevin equations. */ inline virtual void SetLangevinSourceTerms(unsigned long iPoint, unsigned short iDim, su2double val_stochSource) {} + /*! + * \brief A virtual member. + * \param[in] iPoint - Point index. + * \param[in] iDim - Dimension index. + * \param[in] val_stochSeed - Seed for Langevin equations. + */ + inline virtual su2double GetLangevinSeed(unsigned long iPoint, unsigned short iDim) const {return 0.0;} + + /*! + * \brief A virtual member. + * \param[in] iPoint - Point index. + * \param[in] iDim - Dimension index. + * \param[in] val_stochSource - Source term for Langevin equations. + */ + inline virtual void SetLangevinSeed(unsigned long iPoint, unsigned short iDim, unsigned long val_stochSeed) {} + /*! * \brief A virtual member. * \param[in] iPoint - Point index. diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index aff75b2e3eb..106aed24352 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -1517,6 +1517,9 @@ void CFlowOutput::SetVolumeOutputFieldsScalarMisc(const CConfig* config) { AddVolumeOutput("STOCHASTIC_VAR_X", "Stochastic_Var_X", "BACKSCATTER", "x-component of the stochastic vector potential"); AddVolumeOutput("STOCHASTIC_VAR_Y", "Stochastic_Var_Y", "BACKSCATTER", "y-component of the stochastic vector potential"); if (nDim==3) AddVolumeOutput("STOCHASTIC_VAR_Z", "Stochastic_Var_Z", "BACKSCATTER", "z-component of the stochastic vector potential"); + AddVolumeOutput("STOCHASTIC_SOURCE_X", "Stochastic_Source_X", "BACKSCATTER", "x-component of the stochastic source vector"); + AddVolumeOutput("STOCHASTIC_SOURCE_Y", "Stochastic_Source_Y", "BACKSCATTER", "y-component of the stochastic source vector"); + if (nDim==3) AddVolumeOutput("STOCHASTIC_SOURCE_Z", "Stochastic_Source_Z", "BACKSCATTER", "z-component of the stochastic source vector"); } } @@ -1622,6 +1625,9 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con SetVolumeOutputValue("STOCHASTIC_VAR_X", iPoint, Node_Turb->GetSolution(iPoint, 1)); SetVolumeOutputValue("STOCHASTIC_VAR_Y", iPoint, Node_Turb->GetSolution(iPoint, 2)); if (nDim==3) SetVolumeOutputValue("STOCHASTIC_VAR_Z", iPoint, Node_Turb->GetSolution(iPoint, 3)); + SetVolumeOutputValue("STOCHASTIC_SOURCE_X", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 0)); + SetVolumeOutputValue("STOCHASTIC_SOURCE_Y", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 1)); + if (nDim==3) SetVolumeOutputValue("STOCHASTIC_SOURCE_Z", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 2)); } } diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index dbbaafe1cf8..6750be81dd1 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -142,17 +142,14 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor fv1 = Ji_3/(Ji_3+cv1_3); muT_Inf = Density_Inf*fv1*nu_tilde_Inf; + /*--- Allocate memory for boundary conditions ---*/ ext_AverageNu = new su2double [nVar] (); - Res_Wall = new su2double [nVar] (); - Jacobian_i = new su2double* [nVar]; for (unsigned short iVar = 0; iVar < nVar; iVar++) { Jacobian_i[iVar] = new su2double [nVar] (); } - nu_tilde_inturb = new su2double [nVar] (); - nu_tilde_WF = new su2double [nVar] (); /*--- Initialize the solution to the far-field state everywhere. ---*/ @@ -160,6 +157,10 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor nodes = new CTurbSAVariable(nu_tilde_Inf, muT_Inf, nPoint, nDim, nVar, config); SetBaseClassPointerToNodes(); + /*--- Set seed for Langevin equations (Stochastic Backscatter Model) ---*/ + + if (backscatter) { SetLangevinSeed(geometry); } + /*--- MPI solution ---*/ InitiateComms(geometry, config, MPI_QUANTITIES::SOLUTION_EDDY); @@ -239,7 +240,10 @@ void CTurbSASolver::Preprocessing(CGeometry *geometry, CSolver **solver_containe /*--- Compute source terms for Langevin equations ---*/ - if (config->GetStochastic_Backscatter()) SetLangevinSourceTerms(config, geometry); + bool backscatter = config->GetStochastic_Backscatter(); + unsigned long innerIter = config->GetInnerIter(); + + if (backscatter && innerIter==0) SetLangevinSourceTerms(config, geometry); } @@ -415,7 +419,6 @@ void CTurbSASolver::Source_Residual(CGeometry *geometry, CSolver **solver_contai /*--- Set DES length scale ---*/ numerics->SetDistance(nodes->GetDES_LengthScale(iPoint), 0.0); - numerics->SetLESSensor(nodes->GetLES_Mode(iPoint), 0.0); /*--- Compute source terms in Langevin equations (Stochastic Basckscatter Model) ---*/ @@ -1587,14 +1590,28 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) { - uint64_t currentTime = static_cast(config->GetTimeIter()); + SU2_OMP_FOR_DYN(omp_chunk_size) + for (auto iPoint = 0ul; iPoint < nPointDomain; iPoint++){ + for (auto iDim = 0u; iDim < nDim; iDim++){ + unsigned long seed = nodes->GetLangevinSeed(iPoint, iDim); + su2double lesSensor = nodes->GetLES_Mode(iPoint); + su2double rnd = RandomToolbox::GetRandomNormal(seed); + rnd *= std::nearbyint(lesSensor); + nodes->SetLangevinSourceTerms(iPoint, iDim, rnd); + } + } + END_SU2_OMP_FOR + +} + +void CTurbSASolver::SetLangevinSeed(CGeometry* geometry) { SU2_OMP_FOR_DYN(omp_chunk_size) for (auto iPoint = 0ul; iPoint < nPointDomain; iPoint++){ const auto iGlobalPoint = geometry->nodes->GetGlobalIndex(iPoint); for (auto iDim = 0u; iDim < nDim; iDim++){ - uint64_t seed = RandomToolbox::GetSeed(currentTime+1, iGlobalPoint+iDim+1); - nodes->SetLangevinSourceTerms(iPoint, iDim, RandomToolbox::GetRandomNormal(seed)); + unsigned long seed = RandomToolbox::GetSeed(iGlobalPoint+1,iDim+1); + nodes->SetLangevinSeed(iPoint, iDim, seed); } } END_SU2_OMP_FOR diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index 3450ebfbcd4..12b1e415c18 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -61,6 +61,8 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi LES_Mode.resize(nPoint) = su2double(0.0); Vortex_Tilting.resize(nPoint); stochSource.resize(nPoint, nDim) = su2double(0.0); + stochSeed.resize(nPoint, nDim) = 0ul; + } void CTurbSAVariable::SetVortex_Tilting(unsigned long iPoint, CMatrixView PrimGrad_Flow, diff --git a/config_template.cfg b/config_template.cfg index 2422dcf60b2..f11335c5230 100644 --- a/config_template.cfg +++ b/config_template.cfg @@ -183,6 +183,9 @@ DES_CONST= 0.65 % % Stochastic Backscatter Model (NO, YES) STOCHASTIC_BACKSCATTER= NO +% +% Backscatter timescale coefficient (0.001) +SBS_CTAU= 0.001 % -------------------- COMPRESSIBLE FREE-STREAM DEFINITION --------------------% % From 1e8e4e1e39b7bbef50f1e958c8505e4684b558e1 Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Mon, 13 Oct 2025 10:23:40 +0200 Subject: [PATCH 08/70] Add option for simulating DIHT - Add the flag for the simulation of the Decaying Isotropic Homogeneous Turbulence. - Generate the initial velocity field matching the experimental data by Comte-Bellot & Corrsin. - Include a preliminary test case. --- Common/include/CConfig.hpp | 31 ++++ Common/include/toolboxes/random_toolbox.hpp | 17 ++- Common/src/CConfig.cpp | 21 +++ SU2_CFD/include/solvers/CTurbSASolver.hpp | 2 +- SU2_CFD/include/variables/CEulerVariable.hpp | 12 ++ SU2_CFD/include/variables/CTurbSAVariable.hpp | 9 +- SU2_CFD/include/variables/CVariable.hpp | 8 +- SU2_CFD/src/solvers/CEulerSolver.cpp | 4 + SU2_CFD/src/solvers/CTurbSASolver.cpp | 40 +++-- SU2_CFD/src/variables/CEulerVariable.cpp | 142 ++++++++++++++++++ SU2_CFD/src/variables/CTurbSAVariable.cpp | 2 +- .../backscatter/DIHT/backscatter_DIHT.cfg | 107 +++++++++++++ config_template.cfg | 12 ++ 13 files changed, 385 insertions(+), 22 deletions(-) create mode 100644 TestCases/backscatter/DIHT/backscatter_DIHT.cfg diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 5a89fa1e979..0e0905073df 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -1084,6 +1084,10 @@ class CConfig { unsigned short Kind_HybridRANSLES; /*!< \brief Kind of Hybrid RANS/LES. */ bool StochasticBackscatter; /*!< \brief Option to include Stochastic Backscatter Model. */ su2double SBS_Ctau; /*!< \brief Stochastic Backscatter Model timescale coefficient. */ + bool DIHT; /*!< \brief Option to simulate Decaying Isotropic Homogeneous Turbulence (DIHT). */ + su2double DIHT_DomainLength[3]; /*!< \brief Domain length in each direction (DIHT). */ + su2double DIHT_nPoint[3]; /*!< \brief Number of points in each direction (DIHT). */ + unsigned long DIHT_nModes; /*!< \brief Number of Fourier modes (DIHT). */ unsigned short Kind_RoeLowDiss; /*!< \brief Kind of Roe scheme with low dissipation for unsteady flows. */ unsigned short nSpanWiseSections; /*!< \brief number of span-wise sections */ @@ -9543,6 +9547,33 @@ class CConfig { */ bool GetStochastic_Backscatter(void) const { return StochasticBackscatter; } + /*! + * \brief Get if the Decaying Isotropic Homogeneous Turbulence (DIHT) must be simulated. + * \return TRUE if DIHT is simulated. + */ + bool GetDIHT(void) const { return DIHT; } + + /*! + * \brief Get the computational domain length (DIHT). + * \param[in] iDim - spatial component + * \return Domain length. + */ + su2double GetDIHT_DomainLength(unsigned short iDim) const { return DIHT_DomainLength[iDim]*Length_Ref;} + + /*! + * \brief Get the number of grid points in each direction (DIHT). + * \param[in] iDim - spatial component + * \return Number of grid points. + */ + su2double GetDIHT_nPoint(unsigned short iDim) const { return DIHT_nPoint[iDim];} + + /*! + * \brief Get the number of Fourier modes (DIHT). + * \param[in] iDim - spatial component + * \return Number of Fourier modes. + */ + unsigned long GetDIHT_nModes() const { return DIHT_nModes;} + /*! * \brief Get the Kind of Roe Low Dissipation Scheme for Unsteady flows. * \return Value of Low dissipation approach. diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index 811691ac772..fe8bc8ca9eb 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -63,16 +63,27 @@ inline unsigned long GetSeed(unsigned long x, unsigned long y) { return HashComb /*! * \brief Generate a standard normally-distributed random number. - * \param[in] seed Seed for the random number generator. + * \param[in] gen Pseudo-random number generator. * \param[in] mean Mean of the normal distribution (default 0). * \param[in] stddev Standard deviation of the normal distribution (default 1). * \return Normally-distributed random number. */ -inline double GetRandomNormal(unsigned long seed, double mean = 0.0, double stddev = 1.0) { - std::mt19937 gen(seed); +inline double GetRandomNormal(std::mt19937 gen, double mean = 0.0, double stddev = 1.0) { std::normal_distribution rnd(mean, stddev); return rnd(gen); } +/*! + * \brief Generate a uniformly-distributed random number. + * \param[in] gen Pseudo-random number generator. + * \param[in] xmin Lower boundary of the interval (default 0). + * \param[in] xmax Upper bounary of the interval (default 1). + * \return Uniformly-distributed random number. + */ +inline double GetRandomUniform(std::mt19937 gen, double xmin = 0.0, double xmax = 1.0) { + std::uniform_real_distribution rnd(xmin, xmax); + return rnd(gen); +} + /// @} } // namespace RandomToolbox diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 0e9320a7c17..8c963b3bea0 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2920,6 +2920,18 @@ void CConfig::SetConfig_Options() { /* DESCRIPTION: Specify if the Stochastic Backscatter Model must be activated */ addBoolOption("STOCHASTIC_BACKSCATTER", StochasticBackscatter, false); + /* DESCRIPTION: Specify if the Decay of Isotropic Homogeneous Turbulence (DIHT) must be simulated */ + addBoolOption("DIHT", DIHT, false); + + /* DESCRIPTION: Domain length in x, y and z directions (DIHT) */ + addDoubleArrayOption("DIHT_DOMAIN_LENGTH", 3, DIHT_DomainLength); + + /* DESCRIPTION: Spacing of the grid points in x, y and z directions (DIHT) */ + addDoubleArrayOption("DIHT_NPOINT", 3, DIHT_nPoint); + + /* DESCRIPTION: Number of Fourier modes (DIHT) */ + addUnsignedLongOption("DIHT_NUM_MODES", DIHT_nModes, 1000); + /* DESCRIPTION: Roe with low dissipation for unsteady flows */ addEnumOption("ROE_LOW_DISSIPATION", Kind_RoeLowDiss, RoeLowDiss_Map, NO_ROELOWDISS); @@ -6462,6 +6474,15 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { } if (StochasticBackscatter && Kind_HybridRANSLES == NO_HYBRIDRANSLES) SU2_MPI::Error("Stochastic Backscatter can only be activated with Hybrid RANS/LES.", CURRENT_FUNCTION); + if (DIHT) { + cout << "Decaying Isotropic Homogeneous Turbulence (DIHT): spectrum by Comte-Bellot & Corrsin (1971)." << endl; + cout << "WARNING: DIHT algorithm is only compatible with structured grids." << endl; + cout << "Computational domain size: " << DIHT_DomainLength[0] << ", " << DIHT_DomainLength[1] << ", " << DIHT_DomainLength[2] << " (L_REF)" << endl; + cout << "Number of grid points in x, y and z directions: " << static_cast(DIHT_nPoint[0]) << ", " << static_cast(DIHT_nPoint[1]) << ", " << static_cast(DIHT_nPoint[2]) << endl; + cout << "Number of Fourier modes: " << DIHT_nModes << endl; + if (Kind_HybridRANSLES == NO_HYBRIDRANSLES) + SU2_MPI::Error("DIHT mode can only be activated with Hybrid RANS/LES.", CURRENT_FUNCTION); + } break; case MAIN_SOLVER::NEMO_EULER: if (Kind_Regime == ENUM_REGIME::COMPRESSIBLE) cout << "Compressible two-temperature thermochemical non-equilibrium Euler equations." << endl; diff --git a/SU2_CFD/include/solvers/CTurbSASolver.hpp b/SU2_CFD/include/solvers/CTurbSASolver.hpp index 2a6a489f304..1f08fe9566b 100644 --- a/SU2_CFD/include/solvers/CTurbSASolver.hpp +++ b/SU2_CFD/include/solvers/CTurbSASolver.hpp @@ -69,7 +69,7 @@ class CTurbSASolver final : public CTurbSolver { * \param[in] config - Definition of the particular problem. * \param[in] geometry - Geometrical definition. */ - void SetLangevinSeed(CGeometry* geometry); + void SetLangevinGen(CConfig* config, CGeometry* geometry); /*! * \brief Compute nu tilde from the wall functions. diff --git a/SU2_CFD/include/variables/CEulerVariable.hpp b/SU2_CFD/include/variables/CEulerVariable.hpp index 4d49f382572..82102a7cf44 100644 --- a/SU2_CFD/include/variables/CEulerVariable.hpp +++ b/SU2_CFD/include/variables/CEulerVariable.hpp @@ -29,6 +29,7 @@ #include #include "CFlowVariable.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" /*! * \brief Returns the number of primitive variables for which to compute gradients. @@ -345,4 +346,15 @@ class CEulerVariable : public CFlowVariable { */ inline unsigned long GetNewtonSolverIterations(unsigned long iPoint) const final { return NIterNewtonsolver[iPoint]; } + /*! + * \brief Generate initial random velocity field (Decaying Isotropic Homogeneous Turbulence). + * \param[in] npoint - Number of points/nodes/vertices in the domain. + * \param[in] ndim - Number of dimensions of the problem. + * \param[in] nvar - Number of variables of the problem. + * \param[in] config - Definition of the particular problem. + */ + virtual void SetVelDIHT(unsigned long npoint, unsigned long ndim, unsigned long nvar, const CConfig *config, + const CGeometry *geometry); + + }; diff --git a/SU2_CFD/include/variables/CTurbSAVariable.hpp b/SU2_CFD/include/variables/CTurbSAVariable.hpp index b47585dab6f..000f05d13d9 100644 --- a/SU2_CFD/include/variables/CTurbSAVariable.hpp +++ b/SU2_CFD/include/variables/CTurbSAVariable.hpp @@ -28,6 +28,7 @@ #pragma once #include "CTurbVariable.hpp" +#include /*! * \class CTurbSAVariable @@ -43,7 +44,7 @@ class CTurbSAVariable final : public CTurbVariable { VectorType LES_Mode; MatrixType stochSource; VectorType Vortex_Tilting; - MatrixTypeInt stochSeed; + MatrixTypeGen stochGen; public: /*! @@ -123,14 +124,14 @@ class CTurbSAVariable final : public CTurbVariable { * \param[in] iDim - Dimension index. * \return Value of the seed for the stochastic equations. */ - inline su2double GetLangevinSeed(unsigned long iPoint, unsigned short iDim) const override { return stochSeed(iPoint, iDim); } + inline std::mt19937 GetLangevinGen(unsigned long iPoint, unsigned short iDim) const override { return stochGen(iPoint, iDim); } /*! * \brief Set the seed for the stochastic equations. * \param[in] iPoint - Point index. * \param[in] iDim - Dimension index. - * \param[in] val_stochSeed - Value of the seed for the stochastic equations. + * \param[in] val_stochGen - Value of the seed for the stochastic equations. */ - inline void SetLangevinSeed(unsigned long iPoint, unsigned short iDim, unsigned long val_stochSeed) override { stochSeed(iPoint, iDim) = val_stochSeed; } + inline void SetLangevinGen(unsigned long iPoint, unsigned short iDim, std::mt19937 val_stochGen) override { stochGen(iPoint, iDim) = val_stochGen; } }; diff --git a/SU2_CFD/include/variables/CVariable.hpp b/SU2_CFD/include/variables/CVariable.hpp index 6b1159d3888..b01b01bc9db 100644 --- a/SU2_CFD/include/variables/CVariable.hpp +++ b/SU2_CFD/include/variables/CVariable.hpp @@ -34,6 +34,7 @@ #include #include #include +#include #include "../../../Common/include/CConfig.hpp" #include "../../../Common/include/containers/container_decorators.hpp" @@ -51,7 +52,7 @@ class CVariable { protected: using VectorType = C2DContainer; using MatrixType = C2DContainer; - using MatrixTypeInt = C2DContainer; + using MatrixTypeGen = C2DContainer; MatrixType Solution; /*!< \brief Solution of the problem. */ MatrixType Solution_Old; /*!< \brief Old solution of the problem R-K. */ @@ -429,9 +430,8 @@ class CVariable { * \brief A virtual member. * \param[in] iPoint - Point index. * \param[in] iDim - Dimension index. - * \param[in] val_stochSeed - Seed for Langevin equations. */ - inline virtual su2double GetLangevinSeed(unsigned long iPoint, unsigned short iDim) const {return 0.0;} + inline virtual std::mt19937 GetLangevinGen(unsigned long iPoint, unsigned short iDim) const {std::mt19937 gen(123); return gen; } /*! * \brief A virtual member. @@ -439,7 +439,7 @@ class CVariable { * \param[in] iDim - Dimension index. * \param[in] val_stochSource - Source term for Langevin equations. */ - inline virtual void SetLangevinSeed(unsigned long iPoint, unsigned short iDim, unsigned long val_stochSeed) {} + inline virtual void SetLangevinGen(unsigned long iPoint, unsigned short iDim, std::mt19937 val_stochGen) {} /*! * \brief A virtual member. diff --git a/SU2_CFD/src/solvers/CEulerSolver.cpp b/SU2_CFD/src/solvers/CEulerSolver.cpp index 5b85687071f..ecb0e8ce0cc 100644 --- a/SU2_CFD/src/solvers/CEulerSolver.cpp +++ b/SU2_CFD/src/solvers/CEulerSolver.cpp @@ -298,6 +298,10 @@ CEulerSolver::CEulerSolver(CGeometry *geometry, CConfig *config, } SetBaseClassPointerToNodes(); + /*--- Generate initial random velocity field (Decaying Isotropic Homogeneous Turbulence). ---*/ + + if (config->GetDIHT()) nodes->SetVelDIHT(nPoint, nDim, nVar, config, geometry); + if (iMesh == MESH_0) { nodes->NonPhysicalEdgeCounter.resize(geometry->GetnEdge()) = 0; } diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 6750be81dd1..7a47b77fa91 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -157,10 +157,6 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor nodes = new CTurbSAVariable(nu_tilde_Inf, muT_Inf, nPoint, nDim, nVar, config); SetBaseClassPointerToNodes(); - /*--- Set seed for Langevin equations (Stochastic Backscatter Model) ---*/ - - if (backscatter) { SetLangevinSeed(geometry); } - /*--- MPI solution ---*/ InitiateComms(geometry, config, MPI_QUANTITIES::SOLUTION_EDDY); @@ -243,7 +239,10 @@ void CTurbSASolver::Preprocessing(CGeometry *geometry, CSolver **solver_containe bool backscatter = config->GetStochastic_Backscatter(); unsigned long innerIter = config->GetInnerIter(); - if (backscatter && innerIter==0) SetLangevinSourceTerms(config, geometry); + if (backscatter && innerIter==0) { + SetLangevinGen(config, geometry); + SetLangevinSourceTerms(config, geometry); + } } @@ -1466,6 +1465,11 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC lengthScale = min(distDES,wallDistance); lesSensor = (wallDistance<=distDES) ? 0.0 : 1.0; + if (config->GetDIHT()) { + lengthScale = distDES; + lesSensor = 1.0; + } + break; } case SA_DDES: { @@ -1483,6 +1487,11 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC lengthScale = wallDistance-f_d*max(0.0,(wallDistance-distDES)); lesSensor = (wallDistance<=distDES) ? 0.0 : f_d; + if (config->GetDIHT()) { + lengthScale = distDES; + lesSensor = 1.0; + } + break; } case SA_ZDES: { @@ -1524,6 +1533,11 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC lengthScale = wallDistance-f_d*max(0.0,(wallDistance-distDES)); lesSensor = (wallDistance<=distDES) ? 0.0 : f_d; + if (config->GetDIHT()) { + lengthScale = distDES; + lesSensor = 1.0; + } + break; } case SA_EDDES: { @@ -1577,6 +1591,11 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC lengthScale = wallDistance-f_d*max(0.0,(wallDistance-distDES)); lesSensor = (wallDistance<=distDES) ? 0.0 : f_d; + if (config->GetDIHT()) { + lengthScale = distDES; + lesSensor = 1.0; + } + break; } } @@ -1593,9 +1612,9 @@ void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) SU2_OMP_FOR_DYN(omp_chunk_size) for (auto iPoint = 0ul; iPoint < nPointDomain; iPoint++){ for (auto iDim = 0u; iDim < nDim; iDim++){ - unsigned long seed = nodes->GetLangevinSeed(iPoint, iDim); + auto gen = nodes->GetLangevinGen(iPoint, iDim); su2double lesSensor = nodes->GetLES_Mode(iPoint); - su2double rnd = RandomToolbox::GetRandomNormal(seed); + su2double rnd = RandomToolbox::GetRandomNormal(gen); rnd *= std::nearbyint(lesSensor); nodes->SetLangevinSourceTerms(iPoint, iDim, rnd); } @@ -1604,14 +1623,17 @@ void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) } -void CTurbSASolver::SetLangevinSeed(CGeometry* geometry) { +void CTurbSASolver::SetLangevinGen(CConfig* config, CGeometry* geometry) { + + unsigned long timeStep = config->GetTimeIter(); SU2_OMP_FOR_DYN(omp_chunk_size) for (auto iPoint = 0ul; iPoint < nPointDomain; iPoint++){ const auto iGlobalPoint = geometry->nodes->GetGlobalIndex(iPoint); for (auto iDim = 0u; iDim < nDim; iDim++){ unsigned long seed = RandomToolbox::GetSeed(iGlobalPoint+1,iDim+1); - nodes->SetLangevinSeed(iPoint, iDim, seed); + std::mt19937 gen(seed + timeStep); + nodes->SetLangevinGen(iPoint, iDim, gen); } } END_SU2_OMP_FOR diff --git a/SU2_CFD/src/variables/CEulerVariable.cpp b/SU2_CFD/src/variables/CEulerVariable.cpp index 263530705c8..cabdfcfeff6 100644 --- a/SU2_CFD/src/variables/CEulerVariable.cpp +++ b/SU2_CFD/src/variables/CEulerVariable.cpp @@ -27,6 +27,7 @@ #include "../../include/variables/CEulerVariable.hpp" #include "../../include/fluid/CFluidModel.hpp" +#include "../../../Common/include/toolboxes/random_toolbox.hpp" unsigned long EulerNPrimVarGrad(const CConfig *config, unsigned long ndim) { if (config->GetContinuous_Adjoint()) return ndim + 4; @@ -161,3 +162,144 @@ void CEulerVariable::SetSecondaryVar(unsigned long iPoint, CFluidModel *FluidMod SetdPde_rho(iPoint, FluidModel->GetdPde_rho()); } + +void CEulerVariable::SetVelDIHT(unsigned long npoint, unsigned long ndim, unsigned long nvar, const CConfig *config, + const CGeometry *geometry) { + + const unsigned short MAXnModes = 5000; + const unsigned short nModes = config->GetDIHT_nModes(); + if (nModes > MAXnModes) SU2_MPI::Error("The maximum number of Fourier modes for DIHT is 5000.", CURRENT_FUNCTION); + if (nModes <= 0) SU2_MPI::Error("Assign a valid value for the number of Fourier modes. (DIHT)", CURRENT_FUNCTION); + + const su2double Lx = config->GetDIHT_DomainLength(0); + const su2double Ly = config->GetDIHT_DomainLength(1); + const su2double Lz = config->GetDIHT_DomainLength(2); + if (Lx <= 0.0 || Ly <= 0.0 || Lz <= 0.0) SU2_MPI::Error("Assign a valid value for the computational domain size. (DIHT)", CURRENT_FUNCTION); + + const unsigned long nx = static_cast(config->GetDIHT_nPoint(0)); + const unsigned long ny = static_cast(config->GetDIHT_nPoint(1)); + const unsigned long nz = static_cast(config->GetDIHT_nPoint(2)); + if (nx <= 0 || ny <= 0 || nz <= 0) SU2_MPI::Error("Assign a valid value for the number of nodes. (DIHT)", CURRENT_FUNCTION); + + const su2double pi = 4.0 * atan(1.0); + const su2double vref = config->GetVelocity_Ref(); + su2double Density_Inf = config->GetDensity_FreeStreamND(); + su2double ModVel_Freestream = config->GetModVel_FreeStream(); + + su2double k_cbc[39] = {0.11, 0.15, 0.20, 0.25, 0.30, 0.40, 0.50, 0.70, 1.00, + 1.50, 2.00, 2.50, 3.00, 4.00, 6.00, 8.00, 10.0, 12.5, + 15.0, 17.5, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, + 90.0, 100., 110., 120., 130., 140., 150., 160., 170., + 180., 190., 200.}; + + su2double espec_cbc[39] = {30.0, 60.0, 129., 230., 322., 435., 457., 380., + 270., 168., 120., 89.0, 70.3, 47.0, 24.7, 12.6, + 7.42, 3.96, 2.33, 1.34, 0.80, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; + + for (unsigned short ind = 0; ind < 39; ind++) { + k_cbc[ind] *= 100.0; + espec_cbc[ind] *= 1.0e-6; + } + + su2double dx = Lx/nx; + su2double dy = Ly/ny; + su2double dz = Lz/nz; + + if (ndim < 3) { + SU2_MPI::Error("DIHT: Decay of turbulence must be three-dimensional.", CURRENT_FUNCTION); + } + + su2double wmin = min(2.0*pi/Lx, min(2.0*pi/Ly, 2.0*pi/Lz)); + su2double wmax = max(pi/dx, max(pi/dy, pi/dz)); + su2double dk = (wmax-wmin)/nModes; + + auto espec_interpol = [&] (su2double k_) { + + if (k_k_cbc[38]) return espec_cbc[38]; + + unsigned short ind = 1; + while (ind < 39 && k_cbc[ind] < k_) ind++; + + su2double km = k_cbc[ind-1]; + su2double kp = k_cbc[ind]; + su2double em = espec_cbc[ind-1]; + su2double ep = espec_cbc[ind]; + + su2double de_dk = (ep-em)/(kp-km); + su2double e_interp = em + de_dk * (k_-km); + + return e_interp; + + }; + + unsigned long seed = RandomToolbox::GetSeed(npoint, ndim + nvar); + + su2double phi[MAXnModes], theta[MAXnModes], psi[MAXnModes], phi1[MAXnModes], theta1[MAXnModes]; + + for (unsigned long iMode = 0; iMode < nModes; iMode++) { + std::mt19937 gen(seed + iMode*nModes); + phi[iMode] = RandomToolbox::GetRandomUniform(gen, 0.0, 2.0*pi); + theta[iMode] = acos(RandomToolbox::GetRandomUniform(gen, -1.0, 1.0)); + psi[iMode] = RandomToolbox::GetRandomUniform(gen, -0.5*pi, 0.5*pi); + phi1[iMode] = RandomToolbox::GetRandomUniform(gen, 0.0, 2.0*pi); + theta1[iMode] = acos(RandomToolbox::GetRandomUniform(gen, -1.0, 1.0)); + } + + for (unsigned long iPoint = 0; iPoint < npoint; iPoint++) { + su2double u = 0.0, v = 0.0, w = 0.0; + su2double xp = geometry->nodes->GetCoord(iPoint,0); + su2double yp = geometry->nodes->GetCoord(iPoint,1); + su2double zp = geometry->nodes->GetCoord(iPoint,2); + for (unsigned long iMode = 0; iMode < nModes; iMode++) { + su2double wn = wmin + 0.5*dk + iMode*dk; + su2double kx = sin(theta[iMode]) * cos(phi[iMode]) * wn; + su2double ky = sin(theta[iMode]) * sin(phi[iMode]) * wn; + su2double kz = cos(theta[iMode]) * wn; + su2double ktx = sin(kx * dx * 0.5) / dx; + su2double kty = sin(ky * dy * 0.5) / dy; + su2double ktz = sin(kz * dz * 0.5) / dz; + su2double zetax = sin(theta1[iMode]) * cos(phi1[iMode]); + su2double zetay = sin(theta1[iMode]) * sin(phi1[iMode]); + su2double zetaz = cos(theta1[iMode]); + su2double sxm = zetay*ktz - zetaz*kty; + su2double sym = zetaz*ktx - zetax*ktz; + su2double szm = zetax*kty - zetay*ktx; + su2double smag = sqrt(sxm*sxm + sym*sym + szm*szm + 1.0e-16); + sxm /= smag; sym /= smag; szm /= smag; + su2double espec = espec_interpol(wn); + su2double qm = sqrt(espec*dk); + su2double arg = kx * xp + ky * yp + kz * zp - psi[iMode]; + su2double facx = 2.0 * qm * cos(arg - kx*dx*0.5); + su2double facy = 2.0 * qm * cos(arg - ky*dy*0.5); + su2double facz = 2.0 * qm * cos(arg - kz*dz*0.5); + u += facx * sxm; + v += facy * sym; + w += facz * szm; + } + Solution(iPoint, 1) = Density_Inf * u/vref; + Solution(iPoint, 2) = Density_Inf * v/vref; + Solution(iPoint, 3) = Density_Inf * w/vref; + su2double q2 = Solution(iPoint, 1)*Solution(iPoint, 1) + + Solution(iPoint, 2)*Solution(iPoint, 2) + + Solution(iPoint, 3)*Solution(iPoint, 3); + Solution(iPoint, 4) += 0.5 * (q2/Density_Inf - Density_Inf*ModVel_Freestream*ModVel_Freestream); + } + + const bool dual_time = (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) || + (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND); + + const bool classical_rk4 = (config->GetKind_TimeIntScheme_Flow() == CLASSICAL_RK4_EXPLICIT); + + Solution_Old = Solution; + + if (classical_rk4) Solution_New = Solution; + + if (dual_time) { + Solution_time_n = Solution; + Solution_time_n1 = Solution; + } + +} \ No newline at end of file diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index 12b1e415c18..e463909ecf0 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -61,7 +61,7 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi LES_Mode.resize(nPoint) = su2double(0.0); Vortex_Tilting.resize(nPoint); stochSource.resize(nPoint, nDim) = su2double(0.0); - stochSeed.resize(nPoint, nDim) = 0ul; + stochGen.resize(nPoint, nDim); } diff --git a/TestCases/backscatter/DIHT/backscatter_DIHT.cfg b/TestCases/backscatter/DIHT/backscatter_DIHT.cfg new file mode 100644 index 00000000000..6fd2aa72485 --- /dev/null +++ b/TestCases/backscatter/DIHT/backscatter_DIHT.cfg @@ -0,0 +1,107 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% SU2 configuration file % +% Case description: Decaying Isotropic Homogeneous Turbulence (DIHT) % +% Author: Angelo Passariello % +% Institution: University of Naples Federico II % +% Date: 2025.10.01 % +% File Version 8.3.0 "Harrier" % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% ------------- DIRECT, ADJOINT, AND LINEARIZED PROBLEM DEFINITION ------------% + +SOLVER= RANS +KIND_TURB_MODEL= SA +HYBRID_RANSLES= SA_DES +MATH_PROBLEM= DIRECT +RESTART_SOL= NO + +% ------------- STOCHASTIC BACKSCATTER MODEL PARAMETERS -----------------------% + +STOCHASTIC_BACKSCATTER= YES +SBS_CTAU= 0.001 + +% ------------- DECAYING ISOTROPIC HOMOGENEOUS TURBULENCE ---------------------% + +DIHT= YES +DIHT_DOMAIN_LENGTH= (0.5588, 0.5588, 0.5588) +DIHT_NPOINT= (64, 64, 64) +DIHT_NUM_MODES= 800 + +% ----------- COMPRESSIBLE AND INCOMPRESSIBLE FREE-STREAM DEFINITION ----------% + +MACH_NUMBER= 0.001 +FREESTREAM_TEMPERATURE= 300.0 +REYNOLDS_NUMBER= 10129 +REYNOLDS_LENGTH= 0.5588 +FREESTREAM_NU_FACTOR= 1.0 + +% ---------------------- REFERENCE VALUE DEFINITION ---------------------------% + +REF_LENGTH= 1.0 +REF_AREA= 1.0 + +% ------------------------- UNSTEADY SIMULATION -------------------------------% + +TIME_DOMAIN= NO +%TIME_MARCHING= DUAL_TIME_STEPPING-2ND_ORDER +%TIME_STEP= 0.001 +%MAX_TIME= 20 +%UNST_CFL_NUMBER= 0.0 +INNER_ITER= 0 + +% -------------------- BOUNDARY CONDITION DEFINITION --------------------------% + +MARKER_PERIODIC= (xmin, xmax, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5588, 0.0, 0.0, ymin, ymax, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5588, 0.0, zmin, zmax, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5588) + +% ------------- COMMON PARAMETERS DEFINING THE NUMERICAL METHOD ---------------% + +NUM_METHOD_GRAD= GREEN_GAUSS +CFL_NUMBER= 10.0 +CFL_ADAPT= NO +CFL_ADAPT_PARAM= ( 1.5, 0.5, 1.0, 100.0 ) +RK_ALPHA_COEFF= ( 0.66667, 0.66667, 1.000000 ) +TIME_ITER= 1 +LINEAR_SOLVER_PREC= ILU +LOW_MACH_PREC= YES +%LOW_MACH_CORR= YES + +% ----------------------- SLOPE LIMITER DEFINITION ----------------------------% + +MUSCL_FLOW= YES +SLOPE_LIMITER_FLOW= NONE +MUSCL_TURB= NO +VENKAT_LIMITER_COEFF= 0.05 + +% -------------------- FLOW NUMERICAL METHOD DEFINITION -----------------------% +% +CONV_NUM_METHOD_FLOW= SLAU2 +TIME_DISCRE_FLOW= EULER_IMPLICIT + +% -------------------- TURBULENT NUMERICAL METHOD DEFINITION ------------------% +% +CONV_NUM_METHOD_TURB= SCALAR_UPWIND +TIME_DISCRE_TURB= EULER_IMPLICIT + +% --------------------------- CONVERGENCE PARAMETERS --------------------------% +% +CONV_RESIDUAL_MINVAL= -15 +CONV_STARTITER= 0 +CONV_CAUCHY_ELEMS= 100 +CONV_CAUCHY_EPS= 1E-6 + +% ------------------------- INPUT/OUTPUT INFORMATION --------------------------% +% +MESH_FILENAME= cube_64.su2 +MESH_FORMAT= SU2 +TABULAR_FORMAT= CSV +CONV_FILENAME= history +RESTART_FILENAME= restart_flow +VOLUME_FILENAME= flow +VOLUME_OUTPUT= DDES, BACKSCATTER +SCREEN_OUTPUT= (TIME_ITER, INNER_ITER, RMS_DENSITY, RMS_MOMENTUM-X, RMS_MOMENTUM-Y, RMS_MOMENTUM-Z, RMS_NU_TILDE, RMS_STOCH_VAR_X, RMS_STOCH_VAR_Y, RMS_STOCH_VAR_Z) +HISTORY_OUTPUT= (TIME_ITER, RMS_DENSITY, RMS_MOMENTUM-X, RMS_MOMENTUM-Y, RMS_MOMENTUM-Z, RMS_NU_TILDE) +HISTORY_WRT_FREQ_INNER= 1000000 +OUTPUT_WRT_FREQ= 1000000 +OUTPUT_FILES= (RESTART, PARAVIEW) diff --git a/config_template.cfg b/config_template.cfg index 87c89f60cb6..5b9edee47f3 100644 --- a/config_template.cfg +++ b/config_template.cfg @@ -186,6 +186,18 @@ STOCHASTIC_BACKSCATTER= NO % % Backscatter timescale coefficient (0.001) SBS_CTAU= 0.001 +% +% Decaying Isotropic Homogeneous Turbulence (DIHT) simulation (NO, YES) +DIHT= NO +% +% Domain length in x, y and z directions for DIHT (non-dimensional, based on the reference length) +DIHT_DOMAIN_LENGTH= (1.0, 1.0, 1.0) +% +% Number of points in x, y and z directions for DIHT (non-dimensional) +DIHT_NPOINT= (1, 1, 1) +% +% Number of Fourier modes for DIHT +DIHT_NUM_MODES= 1000 % -------------------- COMPRESSIBLE FREE-STREAM DEFINITION --------------------% % From 67c133cccd6f8087c270531fdadffc8f44b4d828 Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Thu, 16 Oct 2025 09:19:20 +0200 Subject: [PATCH 09/70] Fix options for DIHT - Implement flag to enforce LES in the whole domain. - Add option to set the LES filter width to a user-specified value. - Add velocity divergence to volume outputs. - Remove internal generation of initial velocity field for simulating the Decaying Isotropic Homogeneous Turbulence (DIHT). --- Common/include/CConfig.hpp | 33 +--- Common/src/CConfig.cpp | 40 +++-- .../numerics/turbulent/turb_sources.hpp | 2 - SU2_CFD/include/variables/CEulerVariable.hpp | 12 -- SU2_CFD/src/output/CFlowCompOutput.cpp | 9 ++ SU2_CFD/src/output/CFlowIncOutput.cpp | 9 ++ SU2_CFD/src/solvers/CEulerSolver.cpp | 4 - SU2_CFD/src/solvers/CTurbSASolver.cpp | 26 +++- SU2_CFD/src/variables/CEulerVariable.cpp | 142 ------------------ config_template.cfg | 16 +- 10 files changed, 68 insertions(+), 225 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 0e0905073df..078357f14fc 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -1084,10 +1084,8 @@ class CConfig { unsigned short Kind_HybridRANSLES; /*!< \brief Kind of Hybrid RANS/LES. */ bool StochasticBackscatter; /*!< \brief Option to include Stochastic Backscatter Model. */ su2double SBS_Ctau; /*!< \brief Stochastic Backscatter Model timescale coefficient. */ - bool DIHT; /*!< \brief Option to simulate Decaying Isotropic Homogeneous Turbulence (DIHT). */ - su2double DIHT_DomainLength[3]; /*!< \brief Domain length in each direction (DIHT). */ - su2double DIHT_nPoint[3]; /*!< \brief Number of points in each direction (DIHT). */ - unsigned long DIHT_nModes; /*!< \brief Number of Fourier modes (DIHT). */ + bool enforceLES; /*!< \brief Option to enforce LES mode in hybrid RANS-LES simulations. */ + su2double LES_FilterWidth; /*!< \brief LES filter width for hybrid RANS-LES simulations. */ unsigned short Kind_RoeLowDiss; /*!< \brief Kind of Roe scheme with low dissipation for unsteady flows. */ unsigned short nSpanWiseSections; /*!< \brief number of span-wise sections */ @@ -9548,31 +9546,16 @@ class CConfig { bool GetStochastic_Backscatter(void) const { return StochasticBackscatter; } /*! - * \brief Get if the Decaying Isotropic Homogeneous Turbulence (DIHT) must be simulated. - * \return TRUE if DIHT is simulated. + * \brief Get if the LES mode must be enforced. + * \return TRUE if LES is enforced. */ - bool GetDIHT(void) const { return DIHT; } + bool GetEnforceLES(void) const { return enforceLES; } /*! - * \brief Get the computational domain length (DIHT). - * \param[in] iDim - spatial component - * \return Domain length. - */ - su2double GetDIHT_DomainLength(unsigned short iDim) const { return DIHT_DomainLength[iDim]*Length_Ref;} - - /*! - * \brief Get the number of grid points in each direction (DIHT). - * \param[in] iDim - spatial component - * \return Number of grid points. - */ - su2double GetDIHT_nPoint(unsigned short iDim) const { return DIHT_nPoint[iDim];} - - /*! - * \brief Get the number of Fourier modes (DIHT). - * \param[in] iDim - spatial component - * \return Number of Fourier modes. + * \brief Get the LES Filter Width. + * \return Value of LES Filter Width. */ - unsigned long GetDIHT_nModes() const { return DIHT_nModes;} + su2double GetLES_FilterWidth(void) const { return LES_FilterWidth; } /*! * \brief Get the Kind of Roe Low Dissipation Scheme for Unsteady flows. diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 8c963b3bea0..21a683fcc9c 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2920,17 +2920,11 @@ void CConfig::SetConfig_Options() { /* DESCRIPTION: Specify if the Stochastic Backscatter Model must be activated */ addBoolOption("STOCHASTIC_BACKSCATTER", StochasticBackscatter, false); - /* DESCRIPTION: Specify if the Decay of Isotropic Homogeneous Turbulence (DIHT) must be simulated */ - addBoolOption("DIHT", DIHT, false); + /* DESCRIPTION: Specify if the LES mode must be enforced */ + addBoolOption("ENFORCE_LES", enforceLES, false); - /* DESCRIPTION: Domain length in x, y and z directions (DIHT) */ - addDoubleArrayOption("DIHT_DOMAIN_LENGTH", 3, DIHT_DomainLength); - - /* DESCRIPTION: Spacing of the grid points in x, y and z directions (DIHT) */ - addDoubleArrayOption("DIHT_NPOINT", 3, DIHT_nPoint); - - /* DESCRIPTION: Number of Fourier modes (DIHT) */ - addUnsignedLongOption("DIHT_NUM_MODES", DIHT_nModes, 1000); + /* DESCRIPTION: Filter width for LES (if negative, it is computed based on the local cell size) */ + addDoubleOption("LES_FILTER_WIDTH", LES_FilterWidth, -1.0); /* DESCRIPTION: Roe with low dissipation for unsteady flows */ addEnumOption("ROE_LOW_DISSIPATION", Kind_RoeLowDiss, RoeLowDiss_Map, NO_ROELOWDISS); @@ -6465,23 +6459,23 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { case SA_ZDES: cout << "Delayed Detached Eddy Simulation (DDES) with Vorticity-based SGS" << endl; break; case SA_EDDES: cout << "Delayed Detached Eddy Simulation (DDES) with Shear-layer Adapted SGS" << endl; break; } - cout << "Stochastic Backscatter: "; - if (StochasticBackscatter) { - cout << "ON" << endl; - cout << "Backscatter timescale coefficient: " << SBS_Ctau << endl; - } else { - cout << "OFF" << endl; + if (Kind_HybridRANSLES != NO_HYBRIDRANSLES) { + if (LES_FilterWidth > 0.0) cout << "User-specified LES filter width: " << LES_FilterWidth << endl; + cout << "Stochastic Backscatter: "; + if (StochasticBackscatter) { + cout << "ON" << endl; + cout << "Backscatter timescale coefficient: " << SBS_Ctau << endl; + } else { + cout << "OFF" << endl; + } } if (StochasticBackscatter && Kind_HybridRANSLES == NO_HYBRIDRANSLES) SU2_MPI::Error("Stochastic Backscatter can only be activated with Hybrid RANS/LES.", CURRENT_FUNCTION); - if (DIHT) { - cout << "Decaying Isotropic Homogeneous Turbulence (DIHT): spectrum by Comte-Bellot & Corrsin (1971)." << endl; - cout << "WARNING: DIHT algorithm is only compatible with structured grids." << endl; - cout << "Computational domain size: " << DIHT_DomainLength[0] << ", " << DIHT_DomainLength[1] << ", " << DIHT_DomainLength[2] << " (L_REF)" << endl; - cout << "Number of grid points in x, y and z directions: " << static_cast(DIHT_nPoint[0]) << ", " << static_cast(DIHT_nPoint[1]) << ", " << static_cast(DIHT_nPoint[2]) << endl; - cout << "Number of Fourier modes: " << DIHT_nModes << endl; + if (enforceLES) { if (Kind_HybridRANSLES == NO_HYBRIDRANSLES) - SU2_MPI::Error("DIHT mode can only be activated with Hybrid RANS/LES.", CURRENT_FUNCTION); + SU2_MPI::Error("ENFORCE_LES can only be activated with Hybrid RANS/LES.", CURRENT_FUNCTION); + else + cout << "LES enforced in the whole computational domain." << endl; } break; case MAIN_SOLVER::NEMO_EULER: diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index cb74c1523ac..a6e8598c54e 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -140,8 +140,6 @@ class CSourceBase_TurbSA : public CNumerics { corrFac = sqrt(0.5*(1.0+tRat)*(4.0+tRat)/(2.0+tRat)); } else if (time_marching == TIME_MARCHING::DT_STEPPING_1ST) { corrFac = sqrt(1.0+0.5*tRat); - } else { - SU2_MPI::Error("Stochastic Backscatter Model only implemented for dual time stepping.", CURRENT_FUNCTION); } su2double scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * density * corrFac; diff --git a/SU2_CFD/include/variables/CEulerVariable.hpp b/SU2_CFD/include/variables/CEulerVariable.hpp index 82102a7cf44..4d49f382572 100644 --- a/SU2_CFD/include/variables/CEulerVariable.hpp +++ b/SU2_CFD/include/variables/CEulerVariable.hpp @@ -29,7 +29,6 @@ #include #include "CFlowVariable.hpp" -#include "../../../Common/include/geometry/CGeometry.hpp" /*! * \brief Returns the number of primitive variables for which to compute gradients. @@ -346,15 +345,4 @@ class CEulerVariable : public CFlowVariable { */ inline unsigned long GetNewtonSolverIterations(unsigned long iPoint) const final { return NIterNewtonsolver[iPoint]; } - /*! - * \brief Generate initial random velocity field (Decaying Isotropic Homogeneous Turbulence). - * \param[in] npoint - Number of points/nodes/vertices in the domain. - * \param[in] ndim - Number of dimensions of the problem. - * \param[in] nvar - Number of variables of the problem. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetVelDIHT(unsigned long npoint, unsigned long ndim, unsigned long nvar, const CConfig *config, - const CGeometry *geometry); - - }; diff --git a/SU2_CFD/src/output/CFlowCompOutput.cpp b/SU2_CFD/src/output/CFlowCompOutput.cpp index 2476498e84d..b96cdc6fbf3 100644 --- a/SU2_CFD/src/output/CFlowCompOutput.cpp +++ b/SU2_CFD/src/output/CFlowCompOutput.cpp @@ -234,6 +234,8 @@ void CFlowCompOutput::SetVolumeOutputFields(CConfig *config){ AddVolumeOutput("GRID_VELOCITY-Z", "Grid_Velocity_z", "GRID_VELOCITY", "z-component of the grid velocity vector"); } + AddVolumeOutput("VELOCITY_DIVERGENCE", "Velocity_Divergence", "DERIVED", "Divergence of the velocity field"); + // Primitive variables AddVolumeOutput("PRESSURE", "Pressure", "PRIMITIVE", "Pressure"); AddVolumeOutput("TEMPERATURE", "Temperature", "PRIMITIVE", "Temperature"); @@ -325,6 +327,13 @@ void CFlowCompOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolv SetVolumeOutputValue("ENERGY", iPoint, Node_Flow->GetSolution(iPoint, 3)); } + const auto VelocityGradient = Node_Flow->GetVelocityGradient(iPoint); + su2double divVel = 0.0; + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + divVel += VelocityGradient[iDim][iDim]; + } + SetVolumeOutputValue("VELOCITY_DIVERGENCE", iPoint, divVel); + if (gridMovement){ SetVolumeOutputValue("GRID_VELOCITY-X", iPoint, Node_Geo->GetGridVel(iPoint)[0]); SetVolumeOutputValue("GRID_VELOCITY-Y", iPoint, Node_Geo->GetGridVel(iPoint)[1]); diff --git a/SU2_CFD/src/output/CFlowIncOutput.cpp b/SU2_CFD/src/output/CFlowIncOutput.cpp index 761f4ab9a13..6c4c3ce2965 100644 --- a/SU2_CFD/src/output/CFlowIncOutput.cpp +++ b/SU2_CFD/src/output/CFlowIncOutput.cpp @@ -312,6 +312,8 @@ void CFlowIncOutput::SetVolumeOutputFields(CConfig *config){ AddVolumeOutput("GRID_VELOCITY-Z", "Grid_Velocity_z", "GRID_VELOCITY", "z-component of the grid velocity vector"); } + AddVolumeOutput("VELOCITY_DIVERGENCE", "Velocity_Divergence", "DERIVED", "Divergence of the velocity field"); + // Primitive variables AddVolumeOutput("PRESSURE_COEFF", "Pressure_Coefficient", "PRIMITIVE", "Pressure coefficient"); AddVolumeOutput("DENSITY", "Density", "PRIMITIVE", "Density"); @@ -415,6 +417,13 @@ void CFlowIncOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolve SetVolumeOutputValue("GRID_VELOCITY-Z", iPoint, Node_Geo->GetGridVel(iPoint)[2]); } + const auto VelocityGradient = Node_Flow->GetVelocityGradient(iPoint); + su2double divVel = 0.0; + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + divVel += VelocityGradient[iDim][iDim]; + } + SetVolumeOutputValue("VELOCITY_DIVERGENCE", iPoint, divVel); + const su2double factor = solver[FLOW_SOL]->GetReferenceDynamicPressure(); SetVolumeOutputValue("PRESSURE_COEFF", iPoint, (Node_Flow->GetPressure(iPoint) - solver[FLOW_SOL]->GetPressure_Inf())/factor); SetVolumeOutputValue("DENSITY", iPoint, Node_Flow->GetDensity(iPoint)); diff --git a/SU2_CFD/src/solvers/CEulerSolver.cpp b/SU2_CFD/src/solvers/CEulerSolver.cpp index ecb0e8ce0cc..5b85687071f 100644 --- a/SU2_CFD/src/solvers/CEulerSolver.cpp +++ b/SU2_CFD/src/solvers/CEulerSolver.cpp @@ -298,10 +298,6 @@ CEulerSolver::CEulerSolver(CGeometry *geometry, CConfig *config, } SetBaseClassPointerToNodes(); - /*--- Generate initial random velocity field (Decaying Isotropic Homogeneous Turbulence). ---*/ - - if (config->GetDIHT()) nodes->SetVelDIHT(nPoint, nDim, nVar, config, geometry); - if (iMesh == MESH_0) { nodes->NonPhysicalEdgeCounter.resize(geometry->GetnEdge()) = 0; } diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 7a47b77fa91..72c1096e67f 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1453,6 +1453,8 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC su2double lengthScale = 0.0, lesSensor = 0.0; + const su2double LES_FilterWidth = config->GetLES_FilterWidth(); + switch(kindHybridRANSLES){ case SA_DES: { /*--- Original Detached Eddy Simulation (DES97) @@ -1460,12 +1462,15 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC 1997 ---*/ - const su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); + su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); + if (LES_FilterWidth > 0.0){ + maxDelta = LES_FilterWidth; + } const su2double distDES = constDES * maxDelta; lengthScale = min(distDES,wallDistance); lesSensor = (wallDistance<=distDES) ? 0.0 : 1.0; - if (config->GetDIHT()) { + if (config->GetEnforceLES()) { lengthScale = distDES; lesSensor = 1.0; } @@ -1478,7 +1483,10 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC Theoretical and Computational Fluid Dynamics - 2006 ---*/ - const su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); + su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); + if (LES_FilterWidth > 0.0){ + maxDelta = LES_FilterWidth; + } const su2double r_d = (kinematicViscosityTurb+kinematicViscosity)/(uijuij*k2*pow(wallDistance, 2.0)); const su2double f_d = 1.0-tanh(pow(8.0*r_d,3.0)); @@ -1487,7 +1495,7 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC lengthScale = wallDistance-f_d*max(0.0,(wallDistance-distDES)); lesSensor = (wallDistance<=distDES) ? 0.0 : f_d; - if (config->GetDIHT()) { + if (config->GetEnforceLES()) { lengthScale = distDES; lesSensor = 1.0; } @@ -1529,11 +1537,14 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC maxDelta = deltaDDES; } + if (LES_FilterWidth > 0.0){ + maxDelta = LES_FilterWidth; + } const su2double distDES = constDES * maxDelta; lengthScale = wallDistance-f_d*max(0.0,(wallDistance-distDES)); lesSensor = (wallDistance<=distDES) ? 0.0 : f_d; - if (config->GetDIHT()) { + if (config->GetEnforceLES()) { lengthScale = distDES; lesSensor = 1.0; } @@ -1587,11 +1598,14 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC maxDelta = deltaDDES; } + if (LES_FilterWidth > 0.0){ + maxDelta = LES_FilterWidth; + } const su2double distDES = constDES * maxDelta; lengthScale = wallDistance-f_d*max(0.0,(wallDistance-distDES)); lesSensor = (wallDistance<=distDES) ? 0.0 : f_d; - if (config->GetDIHT()) { + if (config->GetEnforceLES()) { lengthScale = distDES; lesSensor = 1.0; } diff --git a/SU2_CFD/src/variables/CEulerVariable.cpp b/SU2_CFD/src/variables/CEulerVariable.cpp index cabdfcfeff6..263530705c8 100644 --- a/SU2_CFD/src/variables/CEulerVariable.cpp +++ b/SU2_CFD/src/variables/CEulerVariable.cpp @@ -27,7 +27,6 @@ #include "../../include/variables/CEulerVariable.hpp" #include "../../include/fluid/CFluidModel.hpp" -#include "../../../Common/include/toolboxes/random_toolbox.hpp" unsigned long EulerNPrimVarGrad(const CConfig *config, unsigned long ndim) { if (config->GetContinuous_Adjoint()) return ndim + 4; @@ -162,144 +161,3 @@ void CEulerVariable::SetSecondaryVar(unsigned long iPoint, CFluidModel *FluidMod SetdPde_rho(iPoint, FluidModel->GetdPde_rho()); } - -void CEulerVariable::SetVelDIHT(unsigned long npoint, unsigned long ndim, unsigned long nvar, const CConfig *config, - const CGeometry *geometry) { - - const unsigned short MAXnModes = 5000; - const unsigned short nModes = config->GetDIHT_nModes(); - if (nModes > MAXnModes) SU2_MPI::Error("The maximum number of Fourier modes for DIHT is 5000.", CURRENT_FUNCTION); - if (nModes <= 0) SU2_MPI::Error("Assign a valid value for the number of Fourier modes. (DIHT)", CURRENT_FUNCTION); - - const su2double Lx = config->GetDIHT_DomainLength(0); - const su2double Ly = config->GetDIHT_DomainLength(1); - const su2double Lz = config->GetDIHT_DomainLength(2); - if (Lx <= 0.0 || Ly <= 0.0 || Lz <= 0.0) SU2_MPI::Error("Assign a valid value for the computational domain size. (DIHT)", CURRENT_FUNCTION); - - const unsigned long nx = static_cast(config->GetDIHT_nPoint(0)); - const unsigned long ny = static_cast(config->GetDIHT_nPoint(1)); - const unsigned long nz = static_cast(config->GetDIHT_nPoint(2)); - if (nx <= 0 || ny <= 0 || nz <= 0) SU2_MPI::Error("Assign a valid value for the number of nodes. (DIHT)", CURRENT_FUNCTION); - - const su2double pi = 4.0 * atan(1.0); - const su2double vref = config->GetVelocity_Ref(); - su2double Density_Inf = config->GetDensity_FreeStreamND(); - su2double ModVel_Freestream = config->GetModVel_FreeStream(); - - su2double k_cbc[39] = {0.11, 0.15, 0.20, 0.25, 0.30, 0.40, 0.50, 0.70, 1.00, - 1.50, 2.00, 2.50, 3.00, 4.00, 6.00, 8.00, 10.0, 12.5, - 15.0, 17.5, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, - 90.0, 100., 110., 120., 130., 140., 150., 160., 170., - 180., 190., 200.}; - - su2double espec_cbc[39] = {30.0, 60.0, 129., 230., 322., 435., 457., 380., - 270., 168., 120., 89.0, 70.3, 47.0, 24.7, 12.6, - 7.42, 3.96, 2.33, 1.34, 0.80, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; - - for (unsigned short ind = 0; ind < 39; ind++) { - k_cbc[ind] *= 100.0; - espec_cbc[ind] *= 1.0e-6; - } - - su2double dx = Lx/nx; - su2double dy = Ly/ny; - su2double dz = Lz/nz; - - if (ndim < 3) { - SU2_MPI::Error("DIHT: Decay of turbulence must be three-dimensional.", CURRENT_FUNCTION); - } - - su2double wmin = min(2.0*pi/Lx, min(2.0*pi/Ly, 2.0*pi/Lz)); - su2double wmax = max(pi/dx, max(pi/dy, pi/dz)); - su2double dk = (wmax-wmin)/nModes; - - auto espec_interpol = [&] (su2double k_) { - - if (k_k_cbc[38]) return espec_cbc[38]; - - unsigned short ind = 1; - while (ind < 39 && k_cbc[ind] < k_) ind++; - - su2double km = k_cbc[ind-1]; - su2double kp = k_cbc[ind]; - su2double em = espec_cbc[ind-1]; - su2double ep = espec_cbc[ind]; - - su2double de_dk = (ep-em)/(kp-km); - su2double e_interp = em + de_dk * (k_-km); - - return e_interp; - - }; - - unsigned long seed = RandomToolbox::GetSeed(npoint, ndim + nvar); - - su2double phi[MAXnModes], theta[MAXnModes], psi[MAXnModes], phi1[MAXnModes], theta1[MAXnModes]; - - for (unsigned long iMode = 0; iMode < nModes; iMode++) { - std::mt19937 gen(seed + iMode*nModes); - phi[iMode] = RandomToolbox::GetRandomUniform(gen, 0.0, 2.0*pi); - theta[iMode] = acos(RandomToolbox::GetRandomUniform(gen, -1.0, 1.0)); - psi[iMode] = RandomToolbox::GetRandomUniform(gen, -0.5*pi, 0.5*pi); - phi1[iMode] = RandomToolbox::GetRandomUniform(gen, 0.0, 2.0*pi); - theta1[iMode] = acos(RandomToolbox::GetRandomUniform(gen, -1.0, 1.0)); - } - - for (unsigned long iPoint = 0; iPoint < npoint; iPoint++) { - su2double u = 0.0, v = 0.0, w = 0.0; - su2double xp = geometry->nodes->GetCoord(iPoint,0); - su2double yp = geometry->nodes->GetCoord(iPoint,1); - su2double zp = geometry->nodes->GetCoord(iPoint,2); - for (unsigned long iMode = 0; iMode < nModes; iMode++) { - su2double wn = wmin + 0.5*dk + iMode*dk; - su2double kx = sin(theta[iMode]) * cos(phi[iMode]) * wn; - su2double ky = sin(theta[iMode]) * sin(phi[iMode]) * wn; - su2double kz = cos(theta[iMode]) * wn; - su2double ktx = sin(kx * dx * 0.5) / dx; - su2double kty = sin(ky * dy * 0.5) / dy; - su2double ktz = sin(kz * dz * 0.5) / dz; - su2double zetax = sin(theta1[iMode]) * cos(phi1[iMode]); - su2double zetay = sin(theta1[iMode]) * sin(phi1[iMode]); - su2double zetaz = cos(theta1[iMode]); - su2double sxm = zetay*ktz - zetaz*kty; - su2double sym = zetaz*ktx - zetax*ktz; - su2double szm = zetax*kty - zetay*ktx; - su2double smag = sqrt(sxm*sxm + sym*sym + szm*szm + 1.0e-16); - sxm /= smag; sym /= smag; szm /= smag; - su2double espec = espec_interpol(wn); - su2double qm = sqrt(espec*dk); - su2double arg = kx * xp + ky * yp + kz * zp - psi[iMode]; - su2double facx = 2.0 * qm * cos(arg - kx*dx*0.5); - su2double facy = 2.0 * qm * cos(arg - ky*dy*0.5); - su2double facz = 2.0 * qm * cos(arg - kz*dz*0.5); - u += facx * sxm; - v += facy * sym; - w += facz * szm; - } - Solution(iPoint, 1) = Density_Inf * u/vref; - Solution(iPoint, 2) = Density_Inf * v/vref; - Solution(iPoint, 3) = Density_Inf * w/vref; - su2double q2 = Solution(iPoint, 1)*Solution(iPoint, 1) + - Solution(iPoint, 2)*Solution(iPoint, 2) + - Solution(iPoint, 3)*Solution(iPoint, 3); - Solution(iPoint, 4) += 0.5 * (q2/Density_Inf - Density_Inf*ModVel_Freestream*ModVel_Freestream); - } - - const bool dual_time = (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) || - (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND); - - const bool classical_rk4 = (config->GetKind_TimeIntScheme_Flow() == CLASSICAL_RK4_EXPLICIT); - - Solution_Old = Solution; - - if (classical_rk4) Solution_New = Solution; - - if (dual_time) { - Solution_time_n = Solution; - Solution_time_n1 = Solution; - } - -} \ No newline at end of file diff --git a/config_template.cfg b/config_template.cfg index 5b9edee47f3..4ecf85b5a2b 100644 --- a/config_template.cfg +++ b/config_template.cfg @@ -181,23 +181,17 @@ HYBRID_RANSLES= SA_DDES % DES Constant (0.65) DES_CONST= 0.65 % +% User-specified LES filter width (if negative, it is computed based on the local cell size, default -1.0) +LES_FILTER_WIDTH= -1.0 +% % Stochastic Backscatter Model (NO, YES) STOCHASTIC_BACKSCATTER= NO % % Backscatter timescale coefficient (0.001) SBS_CTAU= 0.001 % -% Decaying Isotropic Homogeneous Turbulence (DIHT) simulation (NO, YES) -DIHT= NO -% -% Domain length in x, y and z directions for DIHT (non-dimensional, based on the reference length) -DIHT_DOMAIN_LENGTH= (1.0, 1.0, 1.0) -% -% Number of points in x, y and z directions for DIHT (non-dimensional) -DIHT_NPOINT= (1, 1, 1) -% -% Number of Fourier modes for DIHT -DIHT_NUM_MODES= 1000 +% Enforce LES mode in Hybrid RANS-LES Simulations (NO, YES) +ENFORCE_LES= NO % -------------------- COMPRESSIBLE FREE-STREAM DEFINITION --------------------% % From 9657bfb7e31c7f027bff33f6fb73e11204335d19 Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Fri, 24 Oct 2025 12:25:10 +0200 Subject: [PATCH 10/70] Consistent estimation of turb. kinetic energy (for SA) - Add consistent evaluation of the turbulent kinetic energy in the random source term appearing in the momentum equations. - Add backscatter intensity coefficient in the configuration file. - Add random initialization of the Langevin variables. --- Common/include/CConfig.hpp | 11 +++++++-- Common/src/CConfig.cpp | 12 ++++++++-- SU2_CFD/include/numerics/CNumerics.hpp | 24 +++++-------------- .../include/solvers/CFVMFlowSolverBase.inl | 13 ++++++++++ SU2_CFD/src/numerics/flow/flow_diffusion.cpp | 16 ++++++++----- SU2_CFD/src/variables/CTurbSAVariable.cpp | 7 ++++-- config_template.cfg | 7 ++++-- 7 files changed, 58 insertions(+), 32 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 580f107c383..3a1448137cd 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -1090,6 +1090,7 @@ class CConfig { unsigned short Kind_HybridRANSLES; /*!< \brief Kind of Hybrid RANS/LES. */ bool StochasticBackscatter; /*!< \brief Option to include Stochastic Backscatter Model. */ su2double SBS_Ctau; /*!< \brief Stochastic Backscatter Model timescale coefficient. */ + su2double SBS_Cmag; /*!< \brief Stochastic Backscatter Model intensity coefficient. */ bool enforceLES; /*!< \brief Option to enforce LES mode in hybrid RANS-LES simulations. */ su2double LES_FilterWidth; /*!< \brief LES filter width for hybrid RANS-LES simulations. */ unsigned short Kind_RoeLowDiss; /*!< \brief Kind of Roe scheme with low dissipation for unsteady flows. */ @@ -9553,11 +9554,17 @@ class CConfig { su2double GetConst_DES(void) const { return Const_DES; } /*! - * \brief Get the DES Constant. - * \return Value of DES constant. + * \brief Get the SBS timescale coefficient. + * \return Value of SBS timescale coefficient. */ su2double GetSBS_Ctau(void) const { return SBS_Ctau; } + /*! + * \brief Get the SBS intensity coefficient. + * \return Value of SBS intensity coefficient. + */ + su2double GetSBS_Cmag(void) const { return SBS_Cmag; } + /*! * \brief Get the type of tape that will be checked in a tape debug run. */ diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 73124858c20..6318fecfb8c 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2921,8 +2921,11 @@ void CConfig::SetConfig_Options() { /* DESCRIPTION: DES Constant */ addDoubleOption("DES_CONST", Const_DES, 0.65); - /* DESCRIPTION: SBS timescale constant */ - addDoubleOption("SBS_CTAU", SBS_Ctau, 0.05); + /* DESCRIPTION: SBS timescale coefficient */ + addDoubleOption("SBS_TIMESCALE_COEFF", SBS_Ctau, 0.05); + + /* DESCRIPTION: SBS intensity coefficient */ + addDoubleOption("SBS_INTENSITY_COEFF", SBS_Cmag, 1.0); /* DESCRIPTION: Specify Hybrid RANS/LES model */ addEnumOption("HYBRID_RANSLES", Kind_HybridRANSLES, HybridRANSLES_Map, NO_HYBRIDRANSLES); @@ -6491,7 +6494,12 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { cout << "Stochastic Backscatter: "; if (StochasticBackscatter) { cout << "ON" << endl; + cout << "Backscatter intensity coefficient: " << SBS_Cmag << endl; + if (SBS_Cmag < 0.0) + SU2_MPI::Error("Backscatter intensity coefficient must be non-negative.", CURRENT_FUNCTION); cout << "Backscatter timescale coefficient: " << SBS_Ctau << endl; + if (SBS_Ctau < 0.0) + SU2_MPI::Error("Backscatter timescale coefficient must be non-negative.", CURRENT_FUNCTION); } else { cout << "OFF" << endl; } diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index 8899491e17e..db326a23cc5 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -650,28 +650,16 @@ class CNumerics { * \param[in] velGrad - Velocity gradient matrix. * \param[out] stochReynStress - Stochastic tensor (to be added to the Reynolds stress tensor). */ - template + template NEVERINLINE static void ComputeStochReynStress(size_t nDim, Scalar density, Scalar eddyVis, - const Mat1& velGrad, const su2double *rndVec, - Mat2& stochReynStress) { - - /* --- Estimate turbulent kinetic energy --- */ - - Scalar turbKE = 0.0, strainMag = 0.0; - for (size_t iDim = 0; iDim < nDim; iDim++) { - for (size_t jDim = 0; jDim < nDim; jDim++) { - strainMag += pow(0.5 * (velGrad[iDim][jDim] + velGrad[jDim][iDim]), 2); - } - } - strainMag = sqrt(2.0 * strainMag); - turbKE = eddyVis * strainMag; - turbKE = max(turbKE, 1E-10); + Scalar turbKE, Vector rndVec, + Mat& stochReynStress, Scalar Cmag) { /* --- Calculate stochastic tensor --- */ - stochReynStress[1][0] = - density * turbKE * rndVec[2]; - stochReynStress[2][0] = density * turbKE * rndVec[1]; - stochReynStress[2][1] = - density * turbKE * rndVec[0]; + stochReynStress[1][0] = - Cmag * density * turbKE * rndVec[2]; + stochReynStress[2][0] = Cmag * density * turbKE * rndVec[1]; + stochReynStress[2][1] = - Cmag * density * turbKE * rndVec[0]; for (size_t iDim = 0; iDim < nDim; iDim++) { for (size_t jDim = 0; jDim <= iDim; jDim++) { if (iDim==jDim) { diff --git a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl index 13ee5a116a0..747e006a099 100644 --- a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl +++ b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl @@ -475,6 +475,19 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome numerics->SetStochVar(turbNodes->GetSolution(iPoint, 1 + iDim), turbNodes->GetSolution(jPoint, 1 + iDim), iDim); } + su2double eddy_visc_i, eddy_visc_j, DES_length_i, DES_length_j, tke_i, tke_j; + eddy_visc_i = turbNodes->GetmuT(iPoint); + eddy_visc_j = turbNodes->GetmuT(jPoint); + DES_length_i = turbNodes->GetDES_LengthScale(iPoint); + DES_length_j = turbNodes->GetDES_LengthScale(jPoint); + const su2double tol = 1e-12; + if (DES_length_i < tol || DES_length_j < tol) { + tke_i = tke_j = 0.0; + } else { + tke_i = pow(eddy_visc_i/DES_length_i, 2); + tke_j = pow(eddy_visc_j/DES_length_j, 2); + } + numerics->SetTurbKineticEnergy(tke_i, tke_j); } /*--- Wall shear stress values (wall functions) ---*/ diff --git a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp index 50a8fe915f4..7f19ec3db64 100644 --- a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp +++ b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp @@ -460,8 +460,9 @@ CNumerics::ResidualType<> CAvgGrad_Flow::ComputeResidual(const CConfig* config) if (config->GetStochastic_Backscatter()) { for (iVar = 0; iVar < nDim; iVar++) Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); - ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_GradPrimVar+1, - Mean_StochVar, stochReynStress); + su2double SBS_Cmag = config->GetSBS_Cmag(); + ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_turb_ke, + Mean_StochVar, stochReynStress, SBS_Cmag); } /*--- Get projected flux tensor (viscous residual) ---*/ @@ -640,11 +641,13 @@ CNumerics::ResidualType<> CAvgGradInc_Flow::ComputeResidual(const CConfig* confi if (config->GetStochastic_Backscatter()) { for (iVar = 0; iVar < nDim; iVar++) Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); - ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_GradPrimVar+1, - Mean_StochVar, stochReynStress); + su2double SBS_Cmag = config->GetSBS_Cmag(); + ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_turb_ke, + Mean_StochVar, stochReynStress, SBS_Cmag); } /*--- Get projected flux tensor (viscous residual) ---*/ + SetStressTensor(Mean_PrimVar, Mean_GradPrimVar, Mean_turb_ke, Mean_Laminar_Viscosity, Mean_Eddy_Viscosity,config); if (config->GetSAParsedOptions().qcr2000) AddQCR(nDim, &Mean_GradPrimVar[1], tau); @@ -965,8 +968,9 @@ CNumerics::ResidualType<> CGeneralAvgGrad_Flow::ComputeResidual(const CConfig* c if (config->GetStochastic_Backscatter()) { for (iVar = 0; iVar < nDim; iVar++) Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); - ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_GradPrimVar+1, - Mean_StochVar, stochReynStress); + su2double SBS_Cmag = config->GetSBS_Cmag(); + ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_turb_ke, + Mean_StochVar, stochReynStress, SBS_Cmag); } /*--- Get projected flux tensor (viscous residual) ---*/ diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index e463909ecf0..82a636b06e6 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -27,7 +27,7 @@ #include "../../include/variables/CTurbSAVariable.hpp" - +#include "../../../Common/include/toolboxes/random_toolbox.hpp" CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsigned long npoint, unsigned long ndim, unsigned long nvar, CConfig *config) : @@ -41,7 +41,10 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { Solution_Old(iPoint, 0) = Solution(iPoint, 0) = val_nu_tilde; for (unsigned long iVar = 1; iVar < nVar; iVar++) { - Solution_Old(iPoint, iVar) = Solution(iPoint, iVar) = 0.0; + unsigned long seed = RandomToolbox::GetSeed(val_nu_tilde, iVar); + std::mt19937 gen(seed); + su2double val_stoch_var = RandomToolbox::GetRandomNormal(gen); + Solution_Old(iPoint, iVar) = Solution(iPoint, iVar) = val_stoch_var; } } } diff --git a/config_template.cfg b/config_template.cfg index 4ed29b3b1f1..fb93c0bfc8f 100644 --- a/config_template.cfg +++ b/config_template.cfg @@ -187,8 +187,11 @@ LES_FILTER_WIDTH= -1.0 % Stochastic Backscatter Model (NO, YES) STOCHASTIC_BACKSCATTER= NO % -% Backscatter timescale coefficient (0.001) -SBS_CTAU= 0.001 +% Backscatter timescale coefficient (0.05) +SBS_TIMESCALE_COEFF= 0.05 +% +% Backscatter intensity coefficient (1.0) +SBS_INTENSITY_COEFF= 1.0 % % Enforce LES mode in Hybrid RANS-LES Simulations (NO, YES) ENFORCE_LES= NO From 968d8f96fa9bad1e0a66cf2138112cb04450ac04 Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Thu, 30 Oct 2025 08:38:46 +0100 Subject: [PATCH 11/70] Add Laplacian smoothing (Langevin equations) - Add Laplacian smoothing of source terms in Langevin equations. Remark: pseudo-time integration is employed (residuals are printed on screen with fixed frequency, the maximum number of time iterations can be defined by the user). --- Common/include/CConfig.hpp | 14 ++ Common/include/option_structure.hpp | 1 + Common/src/CConfig.cpp | 9 + SU2_CFD/include/solvers/CTurbSASolver.hpp | 7 + SU2_CFD/include/variables/CTurbSAVariable.hpp | 17 ++ SU2_CFD/include/variables/CVariable.hpp | 20 ++- SU2_CFD/src/solvers/CSolver.cpp | 12 ++ SU2_CFD/src/solvers/CTurbSASolver.cpp | 154 ++++++++++++++++++ SU2_CFD/src/variables/CTurbSAVariable.cpp | 1 + config_template.cfg | 6 + 10 files changed, 239 insertions(+), 2 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 3a1448137cd..c74f5699818 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -1089,6 +1089,8 @@ class CConfig { WINDOW_FUNCTION Kind_WindowFct; /*!< \brief Type of window (weight) function for objective functional. */ unsigned short Kind_HybridRANSLES; /*!< \brief Kind of Hybrid RANS/LES. */ bool StochasticBackscatter; /*!< \brief Option to include Stochastic Backscatter Model. */ + su2double SBS_Cdelta; /*!< \brief Stochastic Backscatter Model lengthscale coefficient. */ + unsigned short SBS_maxIterSmooth; /*!< \brief Maximum number of smoothing iterations for the SBS model. */ su2double SBS_Ctau; /*!< \brief Stochastic Backscatter Model timescale coefficient. */ su2double SBS_Cmag; /*!< \brief Stochastic Backscatter Model intensity coefficient. */ bool enforceLES; /*!< \brief Option to enforce LES mode in hybrid RANS-LES simulations. */ @@ -9553,6 +9555,18 @@ class CConfig { */ su2double GetConst_DES(void) const { return Const_DES; } + /*! + * \brief Get the SBS lengthscale coefficient. + * \return Value of SBS lengthscale coefficient. + */ + su2double GetSBS_Cdelta(void) const { return SBS_Cdelta; } + + /*! + * \brief Get the SBS timescale coefficient. + * \return Value of SBS timescale coefficient. + */ + su2double GetSBS_maxIterSmooth(void) const { return SBS_maxIterSmooth; } + /*! * \brief Get the SBS timescale coefficient. * \return Value of SBS timescale coefficient. diff --git a/Common/include/option_structure.hpp b/Common/include/option_structure.hpp index bf99257b138..3a72f5e6ba5 100644 --- a/Common/include/option_structure.hpp +++ b/Common/include/option_structure.hpp @@ -2645,6 +2645,7 @@ enum class MPI_QUANTITIES { MAX_LENGTH , /*!< \brief Maximum length communication. */ GRID_VELOCITY , /*!< \brief Grid velocity communication. */ SOLUTION_EDDY , /*!< \brief Turbulent solution plus eddy viscosity communication. */ + STOCH_SOURCE_LANG , /*!< \brief Stochastic source term for Langevin equations communication. */ SOLUTION_MATRIX , /*!< \brief Matrix solution communication. */ SOLUTION_MATRIXTRANS , /*!< \brief Matrix transposed solution communication. */ NEIGHBORS , /*!< \brief Neighbor point count communication (for JST). */ diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 6318fecfb8c..7fc6c833770 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2921,6 +2921,12 @@ void CConfig::SetConfig_Options() { /* DESCRIPTION: DES Constant */ addDoubleOption("DES_CONST", Const_DES, 0.65); + /* DESCRIPTION: SBS lengthscale coefficient */ + addDoubleOption("SBS_LENGTHSCALE_COEFF", SBS_Cdelta, 0.1); + + /* DESCRIPTION: Maximum number of smoothing iterations for SBS model. */ + addUnsignedShortOption("SBS_MAX_ITER_SMOOTH", SBS_maxIterSmooth, 100); + /* DESCRIPTION: SBS timescale coefficient */ addDoubleOption("SBS_TIMESCALE_COEFF", SBS_Ctau, 0.05); @@ -6497,6 +6503,9 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { cout << "Backscatter intensity coefficient: " << SBS_Cmag << endl; if (SBS_Cmag < 0.0) SU2_MPI::Error("Backscatter intensity coefficient must be non-negative.", CURRENT_FUNCTION); + cout << "Backscatter lengthscale coefficient: " << SBS_Cdelta << endl; + if (SBS_Cdelta < 0.0) + SU2_MPI::Error("Backscatter lengthscale coefficient must be non-negative.", CURRENT_FUNCTION); cout << "Backscatter timescale coefficient: " << SBS_Ctau << endl; if (SBS_Ctau < 0.0) SU2_MPI::Error("Backscatter timescale coefficient must be non-negative.", CURRENT_FUNCTION); diff --git a/SU2_CFD/include/solvers/CTurbSASolver.hpp b/SU2_CFD/include/solvers/CTurbSASolver.hpp index 1f08fe9566b..0aaf5022546 100644 --- a/SU2_CFD/include/solvers/CTurbSASolver.hpp +++ b/SU2_CFD/include/solvers/CTurbSASolver.hpp @@ -71,6 +71,13 @@ class CTurbSASolver final : public CTurbSolver { */ void SetLangevinGen(CConfig* config, CGeometry* geometry); + /*! + * \brief Apply Laplacian smoothing to the source terms in Langevin equations (Stochastic Backscatter Model). + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition. + */ + void SmoothLangevinSourceTerms(CConfig* config, CGeometry* geometry); + /*! * \brief Compute nu tilde from the wall functions. * \param[in] geometry - Geometrical definition of the problem. diff --git a/SU2_CFD/include/variables/CTurbSAVariable.hpp b/SU2_CFD/include/variables/CTurbSAVariable.hpp index 000f05d13d9..f07c2b8b8b6 100644 --- a/SU2_CFD/include/variables/CTurbSAVariable.hpp +++ b/SU2_CFD/include/variables/CTurbSAVariable.hpp @@ -43,6 +43,7 @@ class CTurbSAVariable final : public CTurbVariable { VectorType DES_LengthScale; VectorType LES_Mode; MatrixType stochSource; + MatrixType stochSource_old; VectorType Vortex_Tilting; MatrixTypeGen stochGen; @@ -93,6 +94,22 @@ class CTurbSAVariable final : public CTurbVariable { */ inline void SetLangevinSourceTerms(unsigned long iPoint, unsigned short iDim, su2double val_stochSource) override { stochSource(iPoint, iDim) = val_stochSource; } + /*! + * \brief Get the old value of the source terms for the stochastic equations. + * \param[in] iPoint - Point index. + * \param[in] iDim - Dimension index. + * \return Old value of the source terms for the stochastic equations. + */ + inline virtual su2double GetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim) const override { return stochSource_old(iPoint, iDim); } + + /*! + * \brief Set the old value of source terms for the stochastic equations. + * \param[in] iPoint - Point index. + * \param[in] iDim - Dimension index. + * \param[in] val_stochSource_old - Old value of the source term for the stochastic equations. + */ + inline void SetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim, su2double val_stochSource_old) override { stochSource_old(iPoint, iDim) = val_stochSource_old; } + /*! * \brief Set the LES sensor. */ diff --git a/SU2_CFD/include/variables/CVariable.hpp b/SU2_CFD/include/variables/CVariable.hpp index b01b01bc9db..4eb19e9dd0b 100644 --- a/SU2_CFD/include/variables/CVariable.hpp +++ b/SU2_CFD/include/variables/CVariable.hpp @@ -408,6 +408,7 @@ class CVariable { /*! * \brief A virtual member. * \param[in] iPoint - Point index. + * \param[in] val_les_mode - Value of the LES sensor. */ inline virtual void SetLES_Mode(unsigned long iPoint, su2double val_les_mode) {} @@ -422,10 +423,25 @@ class CVariable { * \brief A virtual member. * \param[in] iPoint - Point index. * \param[in] iDim - Dimension index. - * \param[in] val_stochSource - Seed for Langevin equations. + * \param[in] val_stochSource - Source term in Langevin equations. */ inline virtual void SetLangevinSourceTerms(unsigned long iPoint, unsigned short iDim, su2double val_stochSource) {} + /*! + * \brief A virtual member. + * \param[in] iPoint - Point index. + * \param[in] iDim - Dimension index. + */ + inline virtual su2double GetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] iPoint - Point index. + * \param[in] iDim - Dimension index. + * \param[in] val_stochSource_old - Old value of source term in Langevin equations. + */ + inline virtual void SetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim, su2double val_stochSource_old) {} + /*! * \brief A virtual member. * \param[in] iPoint - Point index. @@ -437,7 +453,7 @@ class CVariable { * \brief A virtual member. * \param[in] iPoint - Point index. * \param[in] iDim - Dimension index. - * \param[in] val_stochSource - Source term for Langevin equations. + * \param[in] val_stochGen - Pseudo-random number generator for Langevin equations. */ inline virtual void SetLangevinGen(unsigned long iPoint, unsigned short iDim, std::mt19937 val_stochGen) {} diff --git a/SU2_CFD/src/solvers/CSolver.cpp b/SU2_CFD/src/solvers/CSolver.cpp index a9c3875406b..502a459ec55 100644 --- a/SU2_CFD/src/solvers/CSolver.cpp +++ b/SU2_CFD/src/solvers/CSolver.cpp @@ -1356,6 +1356,10 @@ void CSolver::GetCommCountAndType(const CConfig* config, COUNT_PER_POINT = nVar+1; MPI_TYPE = COMM_TYPE_DOUBLE; break; + case MPI_QUANTITIES::STOCH_SOURCE_LANG: + COUNT_PER_POINT = nDim; + MPI_TYPE = COMM_TYPE_DOUBLE; + break; case MPI_QUANTITIES::SOLUTION_FEA: if (config->GetTime_Domain()) COUNT_PER_POINT = nVar*3; @@ -1483,6 +1487,10 @@ void CSolver::InitiateComms(CGeometry *geometry, bufDSend[buf_offset+iVar] = base_nodes->GetSolution(iPoint, iVar); bufDSend[buf_offset+nVar] = base_nodes->GetmuT(iPoint); break; + case MPI_QUANTITIES::STOCH_SOURCE_LANG: + for (iDim = 0; iDim < nDim; iDim++) + bufDSend[buf_offset+iDim] = base_nodes->GetLangevinSourceTerms(iPoint, iDim); + break; case MPI_QUANTITIES::UNDIVIDED_LAPLACIAN: for (iVar = 0; iVar < nVar; iVar++) bufDSend[buf_offset+iVar] = base_nodes->GetUndivided_Laplacian(iPoint, iVar); @@ -1631,6 +1639,10 @@ void CSolver::CompleteComms(CGeometry *geometry, base_nodes->SetSolution(iPoint, iVar, bufDRecv[buf_offset+iVar]); base_nodes->SetmuT(iPoint,bufDRecv[buf_offset+nVar]); break; + case MPI_QUANTITIES::STOCH_SOURCE_LANG: + for (iDim = 0; iDim < nDim; iDim++) + base_nodes->SetLangevinSourceTerms(iPoint, iDim, bufDRecv[buf_offset+iDim]); + break; case MPI_QUANTITIES::UNDIVIDED_LAPLACIAN: for (iVar = 0; iVar < nVar; iVar++) base_nodes->SetUnd_Lapl(iPoint, iVar, bufDRecv[buf_offset+iVar]); diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 72c1096e67f..6e99fd4559c 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -242,6 +242,7 @@ void CTurbSASolver::Preprocessing(CGeometry *geometry, CSolver **solver_containe if (backscatter && innerIter==0) { SetLangevinGen(config, geometry); SetLangevinSourceTerms(config, geometry); + SmoothLangevinSourceTerms(config, geometry); } } @@ -1630,6 +1631,7 @@ void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) su2double lesSensor = nodes->GetLES_Mode(iPoint); su2double rnd = RandomToolbox::GetRandomNormal(gen); rnd *= std::nearbyint(lesSensor); + nodes->SetLangevinSourceTermsOld(iPoint, iDim, rnd); nodes->SetLangevinSourceTerms(iPoint, iDim, rnd); } } @@ -1654,6 +1656,158 @@ void CTurbSASolver::SetLangevinGen(CConfig* config, CGeometry* geometry) { } +void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geometry) { + + const su2double LES_FilterWidth = config->GetLES_FilterWidth(); + const su2double pi = 4.0*atan(1.0); + const su2double cDelta = config->GetSBS_Cdelta(); + const unsigned short maxIter = config->GetSBS_maxIterSmooth(); + const unsigned long global_nPointDomain = geometry->GetGlobal_nPointDomain(); + const su2double tol = 1.0e-6; + + /*--- Compute the time step ensuring stability of the pseudo-time integration. ---*/ + + su2double localMinDx = -1.0; + for (unsigned long iPoint = 0; iPoint < nPointDomain; ++iPoint) { + auto coord_i = geometry->nodes->GetCoord(iPoint); + for (unsigned short iNode = 0; iNode < geometry->nodes->GetnPoint(iPoint); ++iNode) { + unsigned long jPoint = geometry->nodes->GetPoint(iPoint, iNode); + auto coord_j = geometry->nodes->GetCoord(jPoint); + su2double dx_ij = GeometryToolbox::Distance(nDim, coord_i, coord_j); + su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); + if (LES_FilterWidth > 0.0) maxDelta = LES_FilterWidth; + su2double b = sqrt(cDelta) * maxDelta; + dx_ij /= b; + if (dx_ij < localMinDx || localMinDx < 0.0) localMinDx = dx_ij; + } + } + su2double globalMinDx = 0.0; + SU2_MPI::Allreduce(&localMinDx, &globalMinDx, 1, MPI_DOUBLE, MPI_MIN, SU2_MPI::GetComm()); + su2double CFL = 0.8; + su2double dt = CFL * globalMinDx * globalMinDx; + + /*--- Start the pseudo-time integration for the Laplacian smoothing. ---*/ + + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + + for (unsigned short iter = 0; iter < maxIter; iter++) { + + /*--- Set the stochastic source terms to zero at solid walls. ---*/ + + for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetSolid_Wall(iMarker)) { + for (unsigned long iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++ ) { + unsigned long iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + nodes->SetLangevinSourceTerms(iPoint, iDim, 0.0); + nodes->SetLangevinSourceTermsOld(iPoint, iDim, 0.0); + } + } + } + + /*--- MPI communication. ---*/ + + InitiateComms(geometry, config, MPI_QUANTITIES::STOCH_SOURCE_LANG); + CompleteComms(geometry, config, MPI_QUANTITIES::STOCH_SOURCE_LANG); + + /*--- Update the solution in pseudo-time. ---*/ + + su2double localResNorm = 0.0; + + SU2_OMP_FOR_DYN(omp_chunk_size) + for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { + + unsigned short lesSensor = std::nearbyint(nodes->GetLES_Mode(iPoint)); + if (lesSensor == 0) continue; + + su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); + if (LES_FilterWidth > 0.0) maxDelta = LES_FilterWidth; + su2double b = sqrt(cDelta) * maxDelta; + su2double b2 = b * b; + su2double volume_iPoint = geometry->nodes->GetVolume(iPoint); + su2double source_i = nodes->GetLangevinSourceTerms(iPoint, iDim); + auto coord_i = geometry->nodes->GetCoord(iPoint); + + /*--- Discretize the Laplace operator. ---*/ + + su2double lap = 0.0; + for (unsigned short iNode = 0; iNode < geometry->nodes->GetnPoint(iPoint); iNode++) { + auto jPoint = geometry->nodes->GetPoint(iPoint, iNode); + auto coord_j = geometry->nodes->GetCoord(jPoint); + auto iEdge = geometry->nodes->GetEdge(iPoint, iNode); + auto* normal = geometry->edges->GetNormal(iEdge); + su2double area = GeometryToolbox::Norm(nDim, normal); + su2double dx_ij = GeometryToolbox::Distance(nDim, coord_i, coord_j); + su2double source_j = nodes->GetLangevinSourceTerms(jPoint, iDim); + lap += area/volume_iPoint * (source_j - source_i)/dx_ij; + } + lap *= b2; + + /*--- Update the solution and sum the residual. ---*/ + + su2double source_i_old = nodes->GetLangevinSourceTermsOld(iPoint, iDim); + su2double rhs = (source_i_old - source_i + lap) * dt; + localResNorm += rhs * rhs; + source_i += rhs; + nodes->SetLangevinSourceTerms(iPoint, iDim, source_i); + + } + END_SU2_OMP_FOR + + /*--- Stop integration if residual drops below tolerance. ---*/ + + su2double globalResNorm = 0.0; + SU2_MPI::Allreduce(&localResNorm, &globalResNorm, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + globalResNorm = sqrt(globalResNorm / global_nPointDomain); + + if (rank == MASTER_NODE) { + if (iter == 0) { + cout << endl + << "Residual of Laplacian smoothing along dimension " << iDim+1 << "." << endl + << "---------------------------------" << endl + << " Iter RMS Residual" << endl + << "---------------------------------" << endl; + } + if (iter%10 == 0) { + cout << " " + << std::setw(5) << iter + << " " + << std::setw(12) << std::fixed << std::scientific << std::setprecision(6) << globalResNorm + << endl; + } + } + + if (globalResNorm < tol || iter == maxIter-1) { + + if (rank == MASTER_NODE) { + cout << " " + << std::setw(5) << iter + << " " + << std::setw(12) << std::fixed << std::scientific << ::setprecision(6) << globalResNorm + << endl; + cout << "---------------------------------" << endl; + } + + /*--- Scale source terms for variance preservation. ---*/ + + for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { + su2double source = nodes->GetLangevinSourceTerms(iPoint, iDim); + su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); + if (LES_FilterWidth > 0.0) maxDelta = LES_FilterWidth; + su2double b = sqrt(cDelta) * maxDelta; + su2double b3 = b * b * b; + su2double volume = geometry->nodes->GetVolume(iPoint); + source *= sqrt(8.0*pi*b3/volume); + nodes->SetLangevinSourceTerms(iPoint, iDim, source); + } + + break; + + } + } + } + +} + void CTurbSASolver::SetInletAtVertex(const su2double *val_inlet, unsigned short iMarker, unsigned long iVertex) { diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index 82a636b06e6..c0ad7d6e6ab 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -64,6 +64,7 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi LES_Mode.resize(nPoint) = su2double(0.0); Vortex_Tilting.resize(nPoint); stochSource.resize(nPoint, nDim) = su2double(0.0); + stochSource_old.resize(nPoint, nDim) = su2double(0.0); stochGen.resize(nPoint, nDim); } diff --git a/config_template.cfg b/config_template.cfg index fb93c0bfc8f..ca8aba44d7a 100644 --- a/config_template.cfg +++ b/config_template.cfg @@ -187,6 +187,12 @@ LES_FILTER_WIDTH= -1.0 % Stochastic Backscatter Model (NO, YES) STOCHASTIC_BACKSCATTER= NO % +% Backscatter lengthscale coefficient (0.1) +SBS_LENGTHSCALE_COEFF= 0.1 +% +% Maximum number of smoothing iterations for SBS model (100) +SBS_MAX_ITER_SMOOTH= 100 +% % Backscatter timescale coefficient (0.05) SBS_TIMESCALE_COEFF= 0.05 % From 2f8245e84d49610370aa4297b5b0bd80b7ba3d1d Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Thu, 30 Oct 2025 08:42:24 +0100 Subject: [PATCH 12/70] Fix redundancy in CTurbSAVariable.hpp - Fix redundancy in virtual member definition. --- SU2_CFD/include/variables/CTurbSAVariable.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SU2_CFD/include/variables/CTurbSAVariable.hpp b/SU2_CFD/include/variables/CTurbSAVariable.hpp index f07c2b8b8b6..0944b580340 100644 --- a/SU2_CFD/include/variables/CTurbSAVariable.hpp +++ b/SU2_CFD/include/variables/CTurbSAVariable.hpp @@ -100,7 +100,7 @@ class CTurbSAVariable final : public CTurbVariable { * \param[in] iDim - Dimension index. * \return Old value of the source terms for the stochastic equations. */ - inline virtual su2double GetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim) const override { return stochSource_old(iPoint, iDim); } + inline su2double GetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim) const override { return stochSource_old(iPoint, iDim); } /*! * \brief Set the old value of source terms for the stochastic equations. From bdbfa059c5fc68e823000cc9d1f4c605ab091113 Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Thu, 30 Oct 2025 15:20:41 +0100 Subject: [PATCH 13/70] Add stochastic source to turbulence model equation - Add stochastic source term to Spalart-Allmaras turbulence model equation (to ensure exchange of modeled and resolved kinetic energy). --- SU2_CFD/include/numerics/CNumerics.hpp | 13 +++++ .../numerics/turbulent/turb_sources.hpp | 57 +++++++++++++++---- SU2_CFD/src/solvers/CTurbSASolver.cpp | 7 ++- 3 files changed, 63 insertions(+), 14 deletions(-) diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index db326a23cc5..6df63a83fa1 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -185,6 +185,9 @@ class CNumerics { su2double stochVar_i[3], /*!< \brief Stochastic variables at point i for Stochastic Backscatter Model. */ stochVar_j[3]; /*!< \brief Stochastic variables at point j for Stochastic Backscatter Model. */ + su2double + lesMode_i, /*!< \brief LES sensor at point i for hybrid RANS-LES methods. */ + lesMode_j; /*!< \brief LES sensor at point j for hybrid RANS-LES methods. */ SST_ParsedOptions sstParsedOptions; /*!< \brief additional options for the SST turbulence model */ unsigned short Eig_Val_Comp; /*!< \brief Component towards which perturbation is perfromed */ su2double uq_delta_b; /*!< \brief Magnitude of perturbation */ @@ -866,6 +869,16 @@ class CNumerics { stochVar_j[iDim] = val_stochvar_j; } + /*! + * \brief Set the LES sensor for hybrid RANS-LES methods. + * \param[in] val_lesMode_i - Value of the LES sensor at point i. + * \param[in] val_lesMode_j - Value of the LES sensor at point j. + */ + inline void SetLES_Mode(su2double val_lesMode_i, su2double val_lesMode_j) { + lesMode_i = val_lesMode_i; + lesMode_j = val_lesMode_j; + } + /*! * \brief Set the value of the distance from the nearest wall. * \param[in] val_dist_i - Value of of the distance from point i to the nearest wall. diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index a6e8598c54e..61d041bb7fc 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -158,17 +158,50 @@ class CSourceBase_TurbSA : public CNumerics { } JacobianSB_i[0][0] = Jacobian_i[0]; -// su2double dnut_dnue = var.fv1 + 3.0 * var.cv1_3 * Ji_3 / pow(Ji_3 + var.cv1_3, 2); -// su2double dtTurb_dnut = - ct * pow(lengthScale,2) / (max(nut, nut_small)*max(nut, nut_small)); - -// for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { -// JacobianSB_i[iVar][0] = - 1.0/tTurb * scaleFactor * stochSource[iVar-1] -// + 1.0/(tTurb*tTurb) * ScalarVar_i[iVar] -// + density * corrFac * stochSource[iVar-1] / -// (tTurb * sqrt(2.0*tTurb*timeStep)); -// JacobianSB_i[iVar][0] *= dtTurb_dnut * dnut_dnue * Volume; -// } - } + su2double dnut_dnue = var.fv1 + 3.0 * var.cv1_3 * Ji_3 / pow(Ji_3 + var.cv1_3, 2); + su2double dtTurb_dnut = - ct * pow(lengthScale,2) / (max(nut, nut_small)*max(nut, nut_small)); + + for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { + JacobianSB_i[iVar][0] = - 1.0/tTurb * scaleFactor * stochSource[iVar-1] + + 1.0/(tTurb*tTurb) * ScalarVar_i[iVar] + + density * corrFac * stochSource[iVar-1] / + (tTurb * sqrt(2.0*tTurb*timeStep)); + JacobianSB_i[iVar][0] *= dtTurb_dnut * dnut_dnue * Volume; + } + + } + + /*! + * \brief Include stochastic source term in the Spalart-Allmaras turbulence model equation (Stochastic Backscatter Model). + */ + template + inline void AddStochSource(const CSAVariables& var, const MatrixType& velGrad, const su2double Cmag) { + + su2double dist2 = dist_i * dist_i; + const su2double eps = 1.0e-10; + su2double xi3 = pow(var.Ji, 3); + + su2double factor = dist2 / (2.0 * var.fv1 * ScalarVar_i[0] + eps); + factor /= (3.0 * xi3 * var.cv1_3 / pow(xi3 + var.cv1_3, 2) + var.fv1 + eps); + + const auto& density = V_i[idx.Density()]; + + su2double tke = pow(var.fv1*ScalarVar_i[0]/dist_i, 2); + + su2double R12 = Cmag * density * tke * ScalarVar_i[2]; + su2double R13 = - Cmag * density * tke * ScalarVar_i[1]; + su2double R23 = Cmag * density * tke * ScalarVar_i[0]; + + su2double RGradU = R12 * (velGrad[0][1] - velGrad[1][0]) + + R13 * (velGrad[0][2] - velGrad[2][0]) + + R23 * (velGrad[1][2] - velGrad[2][1]); + + su2double source_k = - RGradU; + su2double source_nu = factor * source_k; + + Residual += source_nu * Volume; + + } public: /*! @@ -342,6 +375,8 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Compute residual for Langevin equations (Stochastic Backscatter Model). ---*/ if (backscatter) { + if (lesMode_i > 0.999) + AddStochSource(var, PrimVar_Grad_i + idx.Velocity(), config->GetSBS_Cmag()); const su2double DES_const = config->GetConst_DES(); const su2double ctau = config->GetSBS_Ctau(); const su2double ctTurb = ctau / pow(DES_const, 2); diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 6e99fd4559c..1c426e5dcb7 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -425,6 +425,7 @@ void CTurbSASolver::Source_Residual(CGeometry *geometry, CSolver **solver_contai if (config->GetStochastic_Backscatter()) { for (unsigned short iDim = 0; iDim < nDim; iDim++) numerics->SetStochSource(nodes->GetLangevinSourceTerms(iPoint, iDim), iDim); + numerics->SetLES_Mode(nodes->GetLES_Mode(iPoint), 0.0); } } @@ -1764,14 +1765,14 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet cout << endl << "Residual of Laplacian smoothing along dimension " << iDim+1 << "." << endl << "---------------------------------" << endl - << " Iter RMS Residual" << endl + << " Iter RMS Residual" << endl << "---------------------------------" << endl; } if (iter%10 == 0) { cout << " " << std::setw(5) << iter << " " - << std::setw(12) << std::fixed << std::scientific << std::setprecision(6) << globalResNorm + << std::setw(12) << std::fixed << std::setprecision(6) << log10(globalResNorm) << endl; } } @@ -1782,7 +1783,7 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet cout << " " << std::setw(5) << iter << " " - << std::setw(12) << std::fixed << std::scientific << ::setprecision(6) << globalResNorm + << std::setw(12) << std::fixed << ::setprecision(6) << log10(globalResNorm) << endl; cout << "---------------------------------" << endl; } From 3272a1b00c4f45247bc83c7a9fc4e6ddbdf9edf0 Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Tue, 11 Nov 2025 09:44:58 +0100 Subject: [PATCH 14/70] SOR algorithm for Laplacian smoothing - Replace dual-time integration with Successive Over-Relaxation for Laplacian smoothing. - Initialize stochastic vector potential as equal to the stochastic source terms in Langevin equations. - Add random source term to main balance equations in LES zones exclusively. - Blend RANS and LES turbulence timescales using the LES sensor. --- Common/src/CConfig.cpp | 4 + SU2_CFD/include/numerics/CNumerics.hpp | 26 +++-- .../numerics/turbulent/turb_sources.hpp | 15 ++- .../include/solvers/CFVMFlowSolverBase.inl | 6 +- SU2_CFD/src/numerics/flow/flow_diffusion.cpp | 9 +- SU2_CFD/src/solvers/CTurbSASolver.cpp | 104 +++++++++--------- SU2_CFD/src/variables/CTurbSAVariable.cpp | 8 +- 7 files changed, 95 insertions(+), 77 deletions(-) diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 7fc6c833770..6bcc39d1039 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -6509,6 +6509,10 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { cout << "Backscatter timescale coefficient: " << SBS_Ctau << endl; if (SBS_Ctau < 0.0) SU2_MPI::Error("Backscatter timescale coefficient must be non-negative.", CURRENT_FUNCTION); + if (SBS_maxIterSmooth > 0) + cout << "Maximum number of iterations for implicit smoothing: " << SBS_maxIterSmooth << endl; + else + cout << "No smoothing applied to source terms in Langevin equations." << endl; } else { cout << "OFF" << endl; } diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index 6df63a83fa1..5cd17e770fe 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -655,20 +655,28 @@ class CNumerics { */ template NEVERINLINE static void ComputeStochReynStress(size_t nDim, Scalar density, Scalar eddyVis, - Scalar turbKE, Vector rndVec, + Scalar turbKE, Vector rndVec, Scalar lesSensor, Mat& stochReynStress, Scalar Cmag) { /* --- Calculate stochastic tensor --- */ - stochReynStress[1][0] = - Cmag * density * turbKE * rndVec[2]; - stochReynStress[2][0] = Cmag * density * turbKE * rndVec[1]; - stochReynStress[2][1] = - Cmag * density * turbKE * rndVec[0]; - for (size_t iDim = 0; iDim < nDim; iDim++) { - for (size_t jDim = 0; jDim <= iDim; jDim++) { - if (iDim==jDim) { + if (lesSensor > 0.999) { + stochReynStress[1][0] = - Cmag * density * turbKE * rndVec[2]; + stochReynStress[2][0] = Cmag * density * turbKE * rndVec[1]; + stochReynStress[2][1] = - Cmag * density * turbKE * rndVec[0]; + for (size_t iDim = 0; iDim < nDim; iDim++) { + for (size_t jDim = 0; jDim <= iDim; jDim++) { + if (iDim==jDim) { + stochReynStress[iDim][jDim] = 0.0; + } else { + stochReynStress[jDim][iDim] = - stochReynStress[iDim][jDim]; + } + } + } + } else { + for (size_t iDim = 0; iDim < nDim; iDim++) { + for (size_t jDim = 0; jDim < nDim; jDim++) { stochReynStress[iDim][jDim] = 0.0; - } else { - stochReynStress[jDim][iDim] = - stochReynStress[iDim][jDim]; } } } diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index 61d041bb7fc..224f0441a37 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -118,7 +118,7 @@ class CSourceBase_TurbSA : public CNumerics { * \brief Include source-term residuals for Langevin equations (Stochastic Backscatter Model) */ inline void ResidualStochEquations(su2double timeStep, const su2double ct, - su2double lengthScale, + su2double lengthScale, su2double DES_const, const CSAVariables& var, TIME_MARCHING time_marching) { const su2double& nue = ScalarVar_i[0]; @@ -132,7 +132,10 @@ class CSourceBase_TurbSA : public CNumerics { const su2double nut = nue * var.fv1; - su2double tTurb = ct * pow(lengthScale, 2) / max(nut, nut_small); + su2double tLES = ct * pow(lengthScale/DES_const, 2) / max(nut, nut_small); + su2double tRANS = pow(lengthScale, 2) / max(nut, nut_small); + su2double tLR = tLES / tRANS; + su2double tTurb = tLES / (lesMode_i + (1.0-lesMode_i)*tLR); su2double tRat = timeStep / tTurb; su2double corrFac = 1.0; @@ -142,7 +145,8 @@ class CSourceBase_TurbSA : public CNumerics { corrFac = sqrt(1.0+0.5*tRat); } - su2double scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * density * corrFac; + su2double scaleFactor = 0.0; + if (lesMode_i > 0.999) scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * density * corrFac; ResidSB[0] = Residual; for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { @@ -379,9 +383,8 @@ class CSourceBase_TurbSA : public CNumerics { AddStochSource(var, PrimVar_Grad_i + idx.Velocity(), config->GetSBS_Cmag()); const su2double DES_const = config->GetConst_DES(); const su2double ctau = config->GetSBS_Ctau(); - const su2double ctTurb = ctau / pow(DES_const, 2); - ResidualStochEquations(config->GetDelta_UnstTime(), ctTurb, dist_i, var, - config->GetTime_Marching()); + ResidualStochEquations(config->GetDelta_UnstTime(), ctau, dist_i, DES_const, + var, config->GetTime_Marching()); } } diff --git a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl index 747e006a099..b2a42e4c166 100644 --- a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl +++ b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl @@ -475,11 +475,14 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome numerics->SetStochVar(turbNodes->GetSolution(iPoint, 1 + iDim), turbNodes->GetSolution(jPoint, 1 + iDim), iDim); } - su2double eddy_visc_i, eddy_visc_j, DES_length_i, DES_length_j, tke_i, tke_j; + su2double eddy_visc_i, eddy_visc_j, DES_length_i, + DES_length_j, tke_i, tke_j, lesMode_i, lesMode_j; eddy_visc_i = turbNodes->GetmuT(iPoint); eddy_visc_j = turbNodes->GetmuT(jPoint); DES_length_i = turbNodes->GetDES_LengthScale(iPoint); DES_length_j = turbNodes->GetDES_LengthScale(jPoint); + lesMode_i = turbNodes->GetLES_Mode(iPoint); + lesMode_j = turbNodes->GetLES_Mode(jPoint); const su2double tol = 1e-12; if (DES_length_i < tol || DES_length_j < tol) { tke_i = tke_j = 0.0; @@ -488,6 +491,7 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome tke_j = pow(eddy_visc_j/DES_length_j, 2); } numerics->SetTurbKineticEnergy(tke_i, tke_j); + numerics->SetLES_Mode(lesMode_i, lesMode_j); } /*--- Wall shear stress values (wall functions) ---*/ diff --git a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp index 7f19ec3db64..e357dbdeab5 100644 --- a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp +++ b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp @@ -461,8 +461,9 @@ CNumerics::ResidualType<> CAvgGrad_Flow::ComputeResidual(const CConfig* config) for (iVar = 0; iVar < nDim; iVar++) Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); su2double SBS_Cmag = config->GetSBS_Cmag(); + su2double lesSensor = max(lesMode_i, lesMode_j); ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_turb_ke, - Mean_StochVar, stochReynStress, SBS_Cmag); + Mean_StochVar, lesSensor, stochReynStress, SBS_Cmag); } /*--- Get projected flux tensor (viscous residual) ---*/ @@ -642,8 +643,9 @@ CNumerics::ResidualType<> CAvgGradInc_Flow::ComputeResidual(const CConfig* confi for (iVar = 0; iVar < nDim; iVar++) Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); su2double SBS_Cmag = config->GetSBS_Cmag(); + su2double lesSensor = max(lesMode_i, lesMode_j); ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_turb_ke, - Mean_StochVar, stochReynStress, SBS_Cmag); + Mean_StochVar, lesSensor, stochReynStress, SBS_Cmag); } /*--- Get projected flux tensor (viscous residual) ---*/ @@ -969,8 +971,9 @@ CNumerics::ResidualType<> CGeneralAvgGrad_Flow::ComputeResidual(const CConfig* c for (iVar = 0; iVar < nDim; iVar++) Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); su2double SBS_Cmag = config->GetSBS_Cmag(); + su2double lesSensor = max(lesMode_i, lesMode_j); ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_turb_ke, - Mean_StochVar, stochReynStress, SBS_Cmag); + Mean_StochVar, lesSensor, stochReynStress, SBS_Cmag); } /*--- Get projected flux tensor (viscous residual) ---*/ diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 1c426e5dcb7..da36de5760b 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -238,11 +238,29 @@ void CTurbSASolver::Preprocessing(CGeometry *geometry, CSolver **solver_containe bool backscatter = config->GetStochastic_Backscatter(); unsigned long innerIter = config->GetInnerIter(); + unsigned long timeIter = config->GetTimeIter(); + unsigned long restartIter = config->GetRestart_Iter(); if (backscatter && innerIter==0) { SetLangevinGen(config, geometry); SetLangevinSourceTerms(config, geometry); - SmoothLangevinSourceTerms(config, geometry); + const unsigned short maxIter = config->GetSBS_maxIterSmooth(); + bool dual_time = ((config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) || + (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND)); + if (maxIter>0) SmoothLangevinSourceTerms(config, geometry); + if (timeIter == restartIter) { + for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { + for (unsigned short iVar = 1; iVar < nVar; iVar++) { + const su2double randomSource = nodes->GetLangevinSourceTerms(iPoint, iVar-1); + nodes->SetSolution(iPoint, iVar, randomSource); + nodes->SetSolution_Old(iPoint, iVar, randomSource); + if (dual_time) { + nodes->Set_Solution_time_n(iPoint, iVar, randomSource); + nodes->Set_Solution_time_n1(iPoint, iVar, randomSource); + } + } + } + } } } @@ -1630,8 +1648,8 @@ void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) for (auto iDim = 0u; iDim < nDim; iDim++){ auto gen = nodes->GetLangevinGen(iPoint, iDim); su2double lesSensor = nodes->GetLES_Mode(iPoint); - su2double rnd = RandomToolbox::GetRandomNormal(gen); - rnd *= std::nearbyint(lesSensor); + su2double rnd = 0.0; + if (lesSensor > 0.999) rnd = RandomToolbox::GetRandomNormal(gen); nodes->SetLangevinSourceTermsOld(iPoint, iDim, rnd); nodes->SetLangevinSourceTerms(iPoint, iDim, rnd); } @@ -1664,73 +1682,53 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet const su2double cDelta = config->GetSBS_Cdelta(); const unsigned short maxIter = config->GetSBS_maxIterSmooth(); const unsigned long global_nPointDomain = geometry->GetGlobal_nPointDomain(); - const su2double tol = 1.0e-6; - - /*--- Compute the time step ensuring stability of the pseudo-time integration. ---*/ - - su2double localMinDx = -1.0; - for (unsigned long iPoint = 0; iPoint < nPointDomain; ++iPoint) { - auto coord_i = geometry->nodes->GetCoord(iPoint); - for (unsigned short iNode = 0; iNode < geometry->nodes->GetnPoint(iPoint); ++iNode) { - unsigned long jPoint = geometry->nodes->GetPoint(iPoint, iNode); - auto coord_j = geometry->nodes->GetCoord(jPoint); - su2double dx_ij = GeometryToolbox::Distance(nDim, coord_i, coord_j); - su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); - if (LES_FilterWidth > 0.0) maxDelta = LES_FilterWidth; - su2double b = sqrt(cDelta) * maxDelta; - dx_ij /= b; - if (dx_ij < localMinDx || localMinDx < 0.0) localMinDx = dx_ij; + const su2double tol = -5.0; + const su2double sourceLim = 5.0; + const su2double omega = 0.8; + + /*--- Set the stochastic source terms to zero at boundaries. ---*/ + + for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + for (unsigned long iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++ ) { + unsigned long iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (geometry->nodes->GetDomain(iPoint)) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + nodes->SetLangevinSourceTerms(iPoint, iDim, 0.0); + nodes->SetLangevinSourceTermsOld(iPoint, iDim, 0.0); + } + } } } - su2double globalMinDx = 0.0; - SU2_MPI::Allreduce(&localMinDx, &globalMinDx, 1, MPI_DOUBLE, MPI_MIN, SU2_MPI::GetComm()); - su2double CFL = 0.8; - su2double dt = CFL * globalMinDx * globalMinDx; - /*--- Start the pseudo-time integration for the Laplacian smoothing. ---*/ + /*--- Start SOR algorithm for the Laplacian smoothing. ---*/ for (unsigned short iDim = 0; iDim < nDim; iDim++) { for (unsigned short iter = 0; iter < maxIter; iter++) { - /*--- Set the stochastic source terms to zero at solid walls. ---*/ - - for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetSolid_Wall(iMarker)) { - for (unsigned long iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++ ) { - unsigned long iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - nodes->SetLangevinSourceTerms(iPoint, iDim, 0.0); - nodes->SetLangevinSourceTermsOld(iPoint, iDim, 0.0); - } - } - } - /*--- MPI communication. ---*/ InitiateComms(geometry, config, MPI_QUANTITIES::STOCH_SOURCE_LANG); CompleteComms(geometry, config, MPI_QUANTITIES::STOCH_SOURCE_LANG); - /*--- Update the solution in pseudo-time. ---*/ - su2double localResNorm = 0.0; SU2_OMP_FOR_DYN(omp_chunk_size) for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { - unsigned short lesSensor = std::nearbyint(nodes->GetLES_Mode(iPoint)); - if (lesSensor == 0) continue; - su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); if (LES_FilterWidth > 0.0) maxDelta = LES_FilterWidth; su2double b = sqrt(cDelta) * maxDelta; su2double b2 = b * b; su2double volume_iPoint = geometry->nodes->GetVolume(iPoint); su2double source_i = nodes->GetLangevinSourceTerms(iPoint, iDim); + su2double source_i_old = nodes->GetLangevinSourceTermsOld(iPoint, iDim); auto coord_i = geometry->nodes->GetCoord(iPoint); - /*--- Discretize the Laplace operator. ---*/ + /*--- Assemble system matrix. ---*/ - su2double lap = 0.0; + su2double diag = 1.0; + su2double sum = 0.0; for (unsigned short iNode = 0; iNode < geometry->nodes->GetnPoint(iPoint); iNode++) { auto jPoint = geometry->nodes->GetPoint(iPoint, iNode); auto coord_j = geometry->nodes->GetCoord(jPoint); @@ -1739,16 +1737,16 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet su2double area = GeometryToolbox::Norm(nDim, normal); su2double dx_ij = GeometryToolbox::Distance(nDim, coord_i, coord_j); su2double source_j = nodes->GetLangevinSourceTerms(jPoint, iDim); - lap += area/volume_iPoint * (source_j - source_i)/dx_ij; + su2double a_ij = area/volume_iPoint * b2/dx_ij; + diag += a_ij; + sum += a_ij * source_j; } - lap *= b2; - /*--- Update the solution and sum the residual. ---*/ + /*--- Update the solution. ---*/ - su2double source_i_old = nodes->GetLangevinSourceTermsOld(iPoint, iDim); - su2double rhs = (source_i_old - source_i + lap) * dt; - localResNorm += rhs * rhs; - source_i += rhs; + su2double source_tmp = (source_i_old + sum) / diag; + localResNorm += pow(omega * (source_tmp - source_i), 2); + source_i = (1.0-omega)*source_i + omega*source_tmp; nodes->SetLangevinSourceTerms(iPoint, iDim, source_i); } @@ -1777,7 +1775,7 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet } } - if (globalResNorm < tol || iter == maxIter-1) { + if (log10(globalResNorm) < tol || iter == maxIter-1) { if (rank == MASTER_NODE) { cout << " " @@ -1797,7 +1795,9 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet su2double b = sqrt(cDelta) * maxDelta; su2double b3 = b * b * b; su2double volume = geometry->nodes->GetVolume(iPoint); - source *= sqrt(8.0*pi*b3/volume); + su2double scaleFactor = sqrt(8.0 * pi * b3 / volume); + source *= scaleFactor; + source = min(max(source, -sourceLim), sourceLim); nodes->SetLangevinSourceTerms(iPoint, iDim, source); } diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index c0ad7d6e6ab..0f9b3ec9821 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -27,7 +27,6 @@ #include "../../include/variables/CTurbSAVariable.hpp" -#include "../../../Common/include/toolboxes/random_toolbox.hpp" CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsigned long npoint, unsigned long ndim, unsigned long nvar, CConfig *config) : @@ -40,11 +39,8 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi } else { for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { Solution_Old(iPoint, 0) = Solution(iPoint, 0) = val_nu_tilde; - for (unsigned long iVar = 1; iVar < nVar; iVar++) { - unsigned long seed = RandomToolbox::GetSeed(val_nu_tilde, iVar); - std::mt19937 gen(seed); - su2double val_stoch_var = RandomToolbox::GetRandomNormal(gen); - Solution_Old(iPoint, iVar) = Solution(iPoint, iVar) = val_stoch_var; + for (unsigned short iVar = 1; iVar < nVar; iVar++) { + Solution_Old(iPoint, iVar) = Solution(iPoint, iVar) = 0.0; } } } From 15dbff392df54585180e6860ac0204b66f326bdc Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Thu, 20 Nov 2025 17:53:52 +0100 Subject: [PATCH 15/70] Correct scaling of stochastic source terms in Langevin eqs. - Scale source terms in Langevin equations using Bessel functions to preserve the variance. - Compute Bessel integral at the beginning of the simulation for optimization. - Add variance monitoring to screen output. --- Common/include/toolboxes/random_toolbox.hpp | 60 +++++++++++++++ SU2_CFD/include/variables/CTurbSAVariable.hpp | 16 +++- SU2_CFD/include/variables/CVariable.hpp | 12 +++ SU2_CFD/src/solvers/CTurbSASolver.cpp | 77 ++++++++++++++++++- SU2_CFD/src/variables/CTurbSAVariable.cpp | 1 + 5 files changed, 161 insertions(+), 5 deletions(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index fe8bc8ca9eb..96dbed7314c 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -85,5 +85,65 @@ inline double GetRandomUniform(std::mt19937 gen, double xmin = 0.0, double xmax return rnd(gen); } +/*! + * \brief Compute modified bessel function of first kind (order 0). + * \param[in] x Argument of Bessel funtion. + * \return Value of Bessel function. + */ +inline double GetBesselZero(double x) { + double abx = fabs(x); + if (abx < 3.75) { + double t = x / 3.75; + t = t * t; + return 1.0 + t*(3.5156229 + + t*(3.0899424 + + t*(1.2067492 + + t*(0.2659732 + + t*(0.0360768 + + t*0.0045813))))); + } else { + double t = 3.75/abx; + double ans = (exp(abx)/sqrt(abx)) * + (0.39894228 + + t*(0.01328592 + + t*(0.00225319 + + t*(-0.00157565 + + t*(0.00916281 + + t*(-0.02057706 + + t*(0.02635537 + + t*(-0.01647633 + + t*0.00392377)))))))); + return ans; + } +} + +/*! + * \brief Compute integral involving product of three modified Bessel functions. + * \param[in] beta_x Argument in x-direction. + * \param[in] beta_y Argument in y-direction. + * \param[in] beta_z Argument in z-direction. + * \return Value of the integral. + */ +inline double GetBesselIntegral(double beta_x, double beta_y, double beta_z) { + const double A = 1.0 + 2.0*(beta_x + beta_y + beta_z); + const double Bx = 2.0*beta_x; + const double By = 2.0*beta_y; + const double Bz = 2.0*beta_z; + const int N = 4000; + const double t_max = 40.0; + const double delta_t = t_max / N; + double sum = 0.0; + for (int i = 0; i < N; i++) { + double t = i * delta_t; + double I0x = GetBesselZero(Bx * t); + double I0y = GetBesselZero(By * t); + double I0z = GetBesselZero(Bz * t); + double integrand = t * exp(-A * t) + * (I0x * I0y * I0z); + sum += integrand; + } + return sum * delta_t; +} + /// @} } // namespace RandomToolbox diff --git a/SU2_CFD/include/variables/CTurbSAVariable.hpp b/SU2_CFD/include/variables/CTurbSAVariable.hpp index 0944b580340..4b625b90101 100644 --- a/SU2_CFD/include/variables/CTurbSAVariable.hpp +++ b/SU2_CFD/include/variables/CTurbSAVariable.hpp @@ -46,6 +46,7 @@ class CTurbSAVariable final : public CTurbVariable { MatrixType stochSource_old; VectorType Vortex_Tilting; MatrixTypeGen stochGen; + VectorType besselIntegral; public: /*! @@ -110,7 +111,7 @@ class CTurbSAVariable final : public CTurbVariable { */ inline void SetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim, su2double val_stochSource_old) override { stochSource_old(iPoint, iDim) = val_stochSource_old; } -/*! + /*! * \brief Set the LES sensor. */ inline void SetLES_Mode(unsigned long iPoint, su2double val_les_mode) override { LES_Mode(iPoint) = val_les_mode; } @@ -151,4 +152,17 @@ class CTurbSAVariable final : public CTurbVariable { */ inline void SetLangevinGen(unsigned long iPoint, unsigned short iDim, std::mt19937 val_stochGen) override { stochGen(iPoint, iDim) = val_stochGen; } + /*! + * \brief Set the integral of the product of three Bessel functions appearing in Laplacian smoothing. + * \param[in] iPoint - Point index. + * \param[in] val_integral - Value of the integral. + */ + inline void SetBesselIntegral(unsigned long iPoint, su2double val_integral) override { besselIntegral(iPoint) = val_integral; } + + /*! + * \brief Get the the integral of the product of three Bessel functions appearing in Laplacian smoothing. + * \return Value of the integral. + */ + inline su2double GetBesselIntegral(unsigned long iPoint) const override { return besselIntegral(iPoint); } + }; diff --git a/SU2_CFD/include/variables/CVariable.hpp b/SU2_CFD/include/variables/CVariable.hpp index 4eb19e9dd0b..5a432dedcbb 100644 --- a/SU2_CFD/include/variables/CVariable.hpp +++ b/SU2_CFD/include/variables/CVariable.hpp @@ -449,6 +449,18 @@ class CVariable { */ inline virtual std::mt19937 GetLangevinGen(unsigned long iPoint, unsigned short iDim) const {std::mt19937 gen(123); return gen; } + /*! + * \brief A virtual member. + * \param[in] iPoint - Point index. + * \param[in] val_integral - Value of the integral. + */ + inline virtual void SetBesselIntegral(unsigned long iPoint, su2double val_integral) {} + + /*! + * \brief A virtual member. + */ + inline virtual su2double GetBesselIntegral(unsigned long iPoint) const { return 0.0; } + /*! * \brief A virtual member. * \param[in] iPoint - Point index. diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index da36de5760b..4f80b2a6992 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1678,13 +1678,14 @@ void CTurbSASolver::SetLangevinGen(CConfig* config, CGeometry* geometry) { void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geometry) { const su2double LES_FilterWidth = config->GetLES_FilterWidth(); - const su2double pi = 4.0*atan(1.0); const su2double cDelta = config->GetSBS_Cdelta(); const unsigned short maxIter = config->GetSBS_maxIterSmooth(); const unsigned long global_nPointDomain = geometry->GetGlobal_nPointDomain(); const su2double tol = -5.0; const su2double sourceLim = 5.0; const su2double omega = 0.8; + unsigned long timeIter = config->GetTimeIter(); + unsigned long restartIter = config->GetRestart_Iter(); /*--- Set the stochastic source terms to zero at boundaries. ---*/ @@ -1788,18 +1789,86 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet /*--- Scale source terms for variance preservation. ---*/ + su2double var_check_old = 0.0; + su2double mean_check_old = 0.0; + su2double var_check_new = 0.0; + su2double mean_check_new = 0.0; + su2double var_check_notSmoothed = 0.0; + su2double mean_check_notSmoothed = 0.0; for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { su2double source = nodes->GetLangevinSourceTerms(iPoint, iDim); + su2double source_notSmoothed = nodes->GetLangevinSourceTermsOld(iPoint, iDim); + mean_check_old += source; + var_check_old += source * source; + mean_check_notSmoothed += source_notSmoothed; + var_check_notSmoothed += source_notSmoothed * source_notSmoothed; su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); if (LES_FilterWidth > 0.0) maxDelta = LES_FilterWidth; su2double b = sqrt(cDelta) * maxDelta; - su2double b3 = b * b * b; - su2double volume = geometry->nodes->GetVolume(iPoint); - su2double scaleFactor = sqrt(8.0 * pi * b3 / volume); + su2double b2 = b * b; + auto coord_i = geometry->nodes->GetCoord(iPoint); + su2double max_dx = 0.0; + su2double max_dy = 0.0; + su2double max_dz = 0.0; + unsigned short nNeigh = geometry->nodes->GetnPoint(iPoint); + for (unsigned short iNode = 0; iNode < nNeigh; iNode++) { + auto jPoint = geometry->nodes->GetPoint(iPoint, iNode); + auto coord_j = geometry->nodes->GetCoord(jPoint); + su2double dx = fabs(coord_i[0]-coord_j[0]); + su2double dy = fabs(coord_i[1]-coord_j[1]); + su2double dz = 0.0; + if (nDim == 3) dz = fabs(coord_i[2]-coord_j[2]); + if (dx > max_dx) max_dx = dx; + if (dy > max_dy) max_dy = dy; + if (dz > max_dz) max_dz = dz; + } + su2double dx2 = max_dx * max_dx; + su2double dy2 = max_dy * max_dy; + su2double dz2 = max_dz * max_dz; + su2double bx = b2 / dx2; + su2double by = b2 / dy2; + su2double bz = 0.0; + if (nDim == 3) bz = b2 / dz2; + su2double integral = 0.0; + if (timeIter==restartIter) { + integral = RandomToolbox::GetBesselIntegral(bx, by, bz); + nodes->SetBesselIntegral(iPoint, integral); + } else { + integral = nodes->GetBesselIntegral(iPoint); + } + su2double scaleFactor = 1.0 / sqrt(max(integral, 1e-10)); source *= scaleFactor; + mean_check_new += source; + var_check_new += source * source; source = min(max(source, -sourceLim), sourceLim); nodes->SetLangevinSourceTerms(iPoint, iDim, source); } + su2double mean_check_old_G = 0.0; + su2double mean_check_new_G = 0.0; + su2double mean_check_notSmoothed_G = 0.0; + su2double var_check_old_G = 0.0; + su2double var_check_new_G = 0.0; + su2double var_check_notSmoothed_G = 0.0; + SU2_MPI::Allreduce(&mean_check_old, &mean_check_old_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&mean_check_new, &mean_check_new_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&mean_check_notSmoothed, &mean_check_notSmoothed_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&var_check_old, &var_check_old_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&var_check_new, &var_check_new_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&var_check_notSmoothed, &var_check_notSmoothed_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + mean_check_old_G /= global_nPointDomain; + var_check_old_G /= global_nPointDomain; + var_check_old_G -= mean_check_old_G * mean_check_old_G; + mean_check_new_G /= global_nPointDomain; + var_check_new_G /= global_nPointDomain; + var_check_new_G -= mean_check_new_G * mean_check_new_G; + mean_check_notSmoothed_G /= global_nPointDomain; + var_check_notSmoothed_G /= global_nPointDomain; + var_check_notSmoothed_G -= mean_check_notSmoothed_G * mean_check_notSmoothed_G; + if (rank == MASTER_NODE) { + cout << "Mean of stochastic source term before scaling: " << mean_check_old_G <<". After: " << mean_check_new_G << "." << endl; + cout << "Variance of stochastic source term before scaling: " << var_check_old_G/var_check_notSmoothed_G <<". After: " << var_check_new_G/var_check_notSmoothed_G << "." << endl; + cout << endl; + } break; diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index 0f9b3ec9821..384cc70e51c 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -62,6 +62,7 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi stochSource.resize(nPoint, nDim) = su2double(0.0); stochSource_old.resize(nPoint, nDim) = su2double(0.0); stochGen.resize(nPoint, nDim); + besselIntegral.resize(nPoint); } From 420e44aadbb02f29a8395421e4de5053a0eb39f8 Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Wed, 26 Nov 2025 14:56:50 +0100 Subject: [PATCH 16/70] Add LD2 scheme for the incompressible solver - Add LD2 discretization for the inviscid terms in the main balance equations. Remarks: -- Valid only for the incompressible flow solver, with constant density fluid model. -- JST scheme must be selected in the config file. The novel option LD2_SCHEME must be set to YES. --- Common/include/CConfig.hpp | 7 +++++ Common/src/CConfig.cpp | 15 ++++++++++- .../src/numerics/flow/convection/centered.cpp | 27 +++++++++++++++++++ SU2_CFD/src/solvers/CIncEulerSolver.cpp | 6 +++++ SU2_CFD/src/solvers/CTurbSASolver.cpp | 4 +-- config_template.cfg | 3 +++ 6 files changed, 59 insertions(+), 3 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index c74f5699818..52245b1ffbe 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -1095,6 +1095,7 @@ class CConfig { su2double SBS_Cmag; /*!< \brief Stochastic Backscatter Model intensity coefficient. */ bool enforceLES; /*!< \brief Option to enforce LES mode in hybrid RANS-LES simulations. */ su2double LES_FilterWidth; /*!< \brief LES filter width for hybrid RANS-LES simulations. */ + bool LD2_Scheme; /*!< \brief Use the LD2 scheme (incompressible flows, combined with JST discretization). */ unsigned short Kind_RoeLowDiss; /*!< \brief Kind of Roe scheme with low dissipation for unsteady flows. */ unsigned short nSpanWiseSections; /*!< \brief number of span-wise sections */ @@ -9543,6 +9544,12 @@ class CConfig { */ su2double GetLES_FilterWidth(void) const { return LES_FilterWidth; } + /*! + * \brief Get if the LD2 scheme must be employed (incompressible flows, combined with JST discretization). + * \return TRUE if LD2 scheme is enabled. + */ + bool GetLD2_Scheme(void) const { return LD2_Scheme; } + /*! * \brief Get the Kind of Roe Low Dissipation Scheme for Unsteady flows. * \return Value of Low dissipation approach. diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 6bcc39d1039..c7e9ed11df9 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2945,6 +2945,9 @@ void CConfig::SetConfig_Options() { /* DESCRIPTION: Filter width for LES (if negative, it is computed based on the local cell size) */ addDoubleOption("LES_FILTER_WIDTH", LES_FilterWidth, -1.0); + /* DESCRIPTION: Specify if the LD2 scheme must be employed (incompressible flows, combined with JST discretization). */ + addBoolOption("LD2_OPTION", LD2_Scheme, false); + /* DESCRIPTION: Roe with low dissipation for unsteady flows */ addEnumOption("ROE_LOW_DISSIPATION", Kind_RoeLowDiss, RoeLowDiss_Map, NO_ROELOWDISS); @@ -7079,7 +7082,17 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { cout << "First order integration." << endl; } else { - cout << "Jameson-Schmidt-Turkel scheme (2nd order in space) for the flow inviscid terms.\n"; + if (LD2_Scheme) { + cout << "Low-Dissipation Low-Dispersion (LD2) scheme for the flow inviscid terms." << endl; + if (!(Kind_Solver==MAIN_SOLVER::INC_EULER || Kind_Solver==MAIN_SOLVER::INC_NAVIER_STOKES || Kind_Solver==MAIN_SOLVER::INC_RANS)) + SU2_MPI::Error("LD2 option available for incompressible flow simulations only.", CURRENT_FUNCTION); + if (Kind_FluidModel != CONSTANT_DENSITY) + SU2_MPI::Error("LD2 option available for constant density flow simulations only.", CURRENT_FUNCTION); + if (Energy_Equation) + cout << "WARNING: LD2 option not compatible with the energy equation. JST discretization in energy equation employed." << endl; + } else { + cout << "Jameson-Schmidt-Turkel scheme (2nd order in space) for the flow inviscid terms.\n"; + } cout << "JST viscous coefficients (2nd & 4th): " << Kappa_2nd_Flow << ", " << Kappa_4th_Flow << ".\n"; cout << "The method includes a grid stretching correction (p = 0.3)."<< endl; } diff --git a/SU2_CFD/src/numerics/flow/convection/centered.cpp b/SU2_CFD/src/numerics/flow/convection/centered.cpp index ba66bd66c18..2beb4cadc54 100644 --- a/SU2_CFD/src/numerics/flow/convection/centered.cpp +++ b/SU2_CFD/src/numerics/flow/convection/centered.cpp @@ -312,6 +312,8 @@ CNumerics::ResidualType<> CCentJSTInc_Flow::ComputeResidual(const CConfig* confi su2double U_i[5] = {0.0}, U_j[5] = {0.0}; su2double ProjGridVel = 0.0; + bool LD2_Scheme = config->GetLD2_Scheme(); + const su2double alpha_LD2 = 0.36; /*--- Primitive variables at point i and j ---*/ @@ -327,6 +329,31 @@ CNumerics::ResidualType<> CCentJSTInc_Flow::ComputeResidual(const CConfig* confi for (iDim = 0; iDim < nDim; iDim++) { Velocity_i[iDim] = V_i[iDim+1]; Velocity_j[iDim] = V_j[iDim+1]; + } + + if (LD2_Scheme) { + su2double d_ij[3] = {0.0}; + for (iDim = 0; iDim < nDim; iDim++) + d_ij[iDim] = Coord_j[iDim]-Coord_i[iDim]; + su2double velGrad_i[3][3] = {{0.0}}; + su2double velGrad_j[3][3] = {{0.0}}; + for (unsigned short jDim = 0; jDim < nDim; jDim++) { + for (iDim = 0; iDim < nDim; iDim++) { + velGrad_i[iDim][jDim] = PrimVar_Grad_i[iDim+1][jDim]; + velGrad_j[iDim][jDim] = PrimVar_Grad_j[iDim+1][jDim]; + } + } + for (iDim = 0; iDim < nDim; iDim++) { + Velocity_i[iDim] += alpha_LD2 * (velGrad_i[iDim][0] * d_ij[0] + + velGrad_i[iDim][1] * d_ij[1] + + velGrad_i[iDim][2] * d_ij[2]); + Velocity_j[iDim] -= alpha_LD2 * (velGrad_j[iDim][0] * d_ij[0] + + velGrad_j[iDim][1] * d_ij[1] + + velGrad_j[iDim][2] * d_ij[2]); + } + } + + for (iDim = 0; iDim < nDim; iDim++) { MeanVelocity[iDim] = 0.5*(Velocity_i[iDim]+Velocity_j[iDim]); sq_vel_i += 0.5*Velocity_i[iDim]*Velocity_i[iDim]; sq_vel_j += 0.5*Velocity_j[iDim]*Velocity_j[iDim]; diff --git a/SU2_CFD/src/solvers/CIncEulerSolver.cpp b/SU2_CFD/src/solvers/CIncEulerSolver.cpp index 3df1ffbe3dd..f964b22f74c 100644 --- a/SU2_CFD/src/solvers/CIncEulerSolver.cpp +++ b/SU2_CFD/src/solvers/CIncEulerSolver.cpp @@ -1125,6 +1125,7 @@ void CIncEulerSolver::Centered_Residual(CGeometry *geometry, CSolver **solver_co const bool implicit = (config->GetKind_TimeIntScheme() == EULER_IMPLICIT); const bool jst_scheme = ((config->GetKind_Centered_Flow() == CENTERED::JST) && (iMesh == MESH_0)); const bool bounded_scalar = config->GetBounded_Scalar(); + const bool LD2_Scheme = config->GetLD2_Scheme(); /*--- For hybrid parallel AD, pause preaccumulation if there is shared reading of * variables, otherwise switch to the faster adjoint evaluation mode. ---*/ @@ -1162,6 +1163,11 @@ void CIncEulerSolver::Centered_Residual(CGeometry *geometry, CSolver **solver_co numerics->SetSensor(nodes->GetSensor(iPoint), nodes->GetSensor(jPoint)); } + if (LD2_Scheme) { + numerics->SetPrimVarGradient(nodes->GetGradient_Primitive(iPoint), nodes->GetGradient_Primitive(jPoint)); + numerics->SetCoord(geometry->nodes->GetCoord(iPoint), geometry->nodes->GetCoord(jPoint)); + } + /*--- Grid movement ---*/ if (dynamic_grid) { diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 4f80b2a6992..41b4146d78f 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1865,8 +1865,8 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet var_check_notSmoothed_G /= global_nPointDomain; var_check_notSmoothed_G -= mean_check_notSmoothed_G * mean_check_notSmoothed_G; if (rank == MASTER_NODE) { - cout << "Mean of stochastic source term before scaling: " << mean_check_old_G <<". After: " << mean_check_new_G << "." << endl; - cout << "Variance of stochastic source term before scaling: " << var_check_old_G/var_check_notSmoothed_G <<". After: " << var_check_new_G/var_check_notSmoothed_G << "." << endl; + cout << "Mean of stochastic source term before scaling: " << mean_check_old_G <<". After scaling: " << mean_check_new_G << "." << endl; + cout << "Variance of stochastic source term before scaling: " << var_check_old_G/var_check_notSmoothed_G <<". After scaling: " << var_check_new_G/var_check_notSmoothed_G << "." << endl; cout << endl; } diff --git a/config_template.cfg b/config_template.cfg index ca8aba44d7a..b224656e4de 100644 --- a/config_template.cfg +++ b/config_template.cfg @@ -1636,6 +1636,9 @@ SMOOTH_GEOMETRY= 0 % SW, MSW, FDS, SLAU, SLAU2, L2ROE, LMROE) CONV_NUM_METHOD_FLOW= ROE % +% Option to employ the Low-Dissipation Low-Dispersion (LD2) scheme for incompressible flows (NO, YES) +LD2_SCHEME= NO +% % Roe Low Dissipation function for Hybrid RANS/LES simulations (FD, NTS, NTS_DUCROS) ROE_LOW_DISSIPATION= FD % From 5c3e35ce22e98b159c319f9cdf8c1b774fc69a88 Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Fri, 28 Nov 2025 18:28:41 +0100 Subject: [PATCH 17/70] Fix LD2 for periodic boundaries - Retrieve classic second-order central scheme at periodic boundaries. --- Common/src/CConfig.cpp | 4 ++++ SU2_CFD/src/solvers/CIncEulerSolver.cpp | 7 ++++++- config_template.cfg | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 3fa9e1e0027..f4a0bef3159 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -7098,6 +7098,10 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { } } + if (Kind_ConvNumScheme_Flow != SPACE_CENTERED || (Kind_ConvNumScheme_Flow == SPACE_CENTERED && Kind_Centered_Flow == CENTERED::LAX)) { + SU2_MPI::Error("LD2 option available for JST scheme only.", CURRENT_FUNCTION); + } + if (Kind_ConvNumScheme_Flow == SPACE_UPWIND) { if (Kind_Upwind_Flow == UPWIND::ROE) cout << "Roe (with entropy fix = "<< EntropyFix_Coeff <<") solver for the flow inviscid terms."<< endl; if (Kind_Upwind_Flow == UPWIND::TURKEL) cout << "Roe-Turkel solver for the flow inviscid terms."<< endl; diff --git a/SU2_CFD/src/solvers/CIncEulerSolver.cpp b/SU2_CFD/src/solvers/CIncEulerSolver.cpp index f964b22f74c..8e249147d7d 100644 --- a/SU2_CFD/src/solvers/CIncEulerSolver.cpp +++ b/SU2_CFD/src/solvers/CIncEulerSolver.cpp @@ -1165,7 +1165,12 @@ void CIncEulerSolver::Centered_Residual(CGeometry *geometry, CSolver **solver_co if (LD2_Scheme) { numerics->SetPrimVarGradient(nodes->GetGradient_Primitive(iPoint), nodes->GetGradient_Primitive(jPoint)); - numerics->SetCoord(geometry->nodes->GetCoord(iPoint), geometry->nodes->GetCoord(jPoint)); + if (!geometry->nodes->GetPeriodicBoundary(iPoint) || (geometry->nodes->GetPeriodicBoundary(iPoint) + && !geometry->nodes->GetPeriodicBoundary(jPoint))) { + numerics->SetCoord(geometry->nodes->GetCoord(iPoint), geometry->nodes->GetCoord(jPoint)); + } else { + numerics->SetCoord(geometry->nodes->GetCoord(iPoint), geometry->nodes->GetCoord(iPoint)); + } } /*--- Grid movement ---*/ diff --git a/config_template.cfg b/config_template.cfg index b224656e4de..60138cc27ed 100644 --- a/config_template.cfg +++ b/config_template.cfg @@ -1637,7 +1637,7 @@ SMOOTH_GEOMETRY= 0 CONV_NUM_METHOD_FLOW= ROE % % Option to employ the Low-Dissipation Low-Dispersion (LD2) scheme for incompressible flows (NO, YES) -LD2_SCHEME= NO +LD2_OPTION= NO % % Roe Low Dissipation function for Hybrid RANS/LES simulations (FD, NTS, NTS_DUCROS) ROE_LOW_DISSIPATION= FD From 63890230d77d3b26e599bc713f6cc8ed8335cc4d Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Wed, 3 Dec 2025 14:53:54 +0100 Subject: [PATCH 18/70] Include stochastic source term in turb. equation Add option to include stochastic contribution to turbulence model equation. --- Common/include/CConfig.hpp | 7 +++++++ Common/src/CConfig.cpp | 5 +++++ SU2_CFD/include/numerics/turbulent/turb_sources.hpp | 2 +- config_template.cfg | 5 ++++- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 52245b1ffbe..bdd0741aab5 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -1093,6 +1093,7 @@ class CConfig { unsigned short SBS_maxIterSmooth; /*!< \brief Maximum number of smoothing iterations for the SBS model. */ su2double SBS_Ctau; /*!< \brief Stochastic Backscatter Model timescale coefficient. */ su2double SBS_Cmag; /*!< \brief Stochastic Backscatter Model intensity coefficient. */ + bool stochSourceNu; /*!< \brief Option for including stochastic source term in turbulence model equation (Stochastic Backscatter Model). */ bool enforceLES; /*!< \brief Option to enforce LES mode in hybrid RANS-LES simulations. */ su2double LES_FilterWidth; /*!< \brief LES filter width for hybrid RANS-LES simulations. */ bool LD2_Scheme; /*!< \brief Use the LD2 scheme (incompressible flows, combined with JST discretization). */ @@ -9538,6 +9539,12 @@ class CConfig { */ bool GetEnforceLES(void) const { return enforceLES; } + /*! + * \brief Get if the stochastic source term must be included in the turbulence model equation. + * \return TRUE if the stochastic source term is included in the turbulence model equation. + */ + bool GetStochSourceNu(void) const { return stochSourceNu; } + /*! * \brief Get the LES Filter Width. * \return Value of LES Filter Width. diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index f4a0bef3159..ed8ab9bce5b 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2942,6 +2942,9 @@ void CConfig::SetConfig_Options() { /* DESCRIPTION: Specify if the LES mode must be enforced */ addBoolOption("ENFORCE_LES", enforceLES, false); + /* DESCRIPTION: Specify if the stochastic source term must be included in the turbulence model equation */ + addBoolOption("STOCH_SOURCE_NU", stochSourceNu, false) + /* DESCRIPTION: Filter width for LES (if negative, it is computed based on the local cell size) */ addDoubleOption("LES_FILTER_WIDTH", LES_FilterWidth, -1.0); @@ -6516,6 +6519,8 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { cout << "Maximum number of iterations for implicit smoothing: " << SBS_maxIterSmooth << endl; else cout << "No smoothing applied to source terms in Langevin equations." << endl; + if (stochSourceNu) + cout << "Stochastic source term included in turbulence model equation" << endl; } else { cout << "OFF" << endl; } diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index 224f0441a37..4992ebe60d2 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -379,7 +379,7 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Compute residual for Langevin equations (Stochastic Backscatter Model). ---*/ if (backscatter) { - if (lesMode_i > 0.999) + if (lesMode_i > 0.999 && config->GetStochSourceNu()) AddStochSource(var, PrimVar_Grad_i + idx.Velocity(), config->GetSBS_Cmag()); const su2double DES_const = config->GetConst_DES(); const su2double ctau = config->GetSBS_Ctau(); diff --git a/config_template.cfg b/config_template.cfg index 60138cc27ed..2abd0d07624 100644 --- a/config_template.cfg +++ b/config_template.cfg @@ -199,9 +199,12 @@ SBS_TIMESCALE_COEFF= 0.05 % Backscatter intensity coefficient (1.0) SBS_INTENSITY_COEFF= 1.0 % +% Include stochastic source in turbulence model equation (NO, YES) +STOCH_SOURCE_NU= NO +% % Enforce LES mode in Hybrid RANS-LES Simulations (NO, YES) ENFORCE_LES= NO - +% % -------------------- COMPRESSIBLE FREE-STREAM DEFINITION --------------------% % % Mach number (non-dimensional, based on the free-stream values) From d382a2d11dad8ee154915d2e3b1cbe6ab4bf4e06 Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Wed, 3 Dec 2025 15:05:50 +0100 Subject: [PATCH 19/70] Minor fixes - Use logarithmic approximation for Bessel function. - Compute relative variance of the stochastic field for verification. --- Common/include/toolboxes/random_toolbox.hpp | 72 ++++++++++++--------- Common/src/CConfig.cpp | 2 +- SU2_CFD/src/solvers/CTurbSASolver.cpp | 6 +- 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index 96dbed7314c..28eb0267636 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -92,28 +92,30 @@ inline double GetRandomUniform(std::mt19937 gen, double xmin = 0.0, double xmax */ inline double GetBesselZero(double x) { double abx = fabs(x); + if (abx < 3.75) { double t = x / 3.75; - t = t * t; - return 1.0 + t*(3.5156229 + - t*(3.0899424 + - t*(1.2067492 + - t*(0.2659732 + - t*(0.0360768 + - t*0.0045813))))); + double p = 1.0 + + t*t*(3.5156229 + + t*t*(3.0899424 + + t*t*(1.2067492 + + t*t*(0.2659732 + + t*t*(0.0360768 + + t*t*0.0045813))))); + return log(p); } else { - double t = 3.75/abx; - double ans = (exp(abx)/sqrt(abx)) * - (0.39894228 + - t*(0.01328592 + - t*(0.00225319 + - t*(-0.00157565 + - t*(0.00916281 + - t*(-0.02057706 + - t*(0.02635537 + - t*(-0.01647633 + - t*0.00392377)))))))); - return ans; + double t = 3.75 / abx; + double poly = + 0.39894228 + + t*(0.01328592 + + t*(0.00225319 + + t*(-0.00157565 + + t*(0.00916281 + + t*(-0.02057706 + + t*(0.02635537 + + t*(-0.01647633 + + t*0.00392377))))))); + return abx - 0.5*log(abx) + log(poly); } } @@ -125,24 +127,34 @@ inline double GetBesselZero(double x) { * \return Value of the integral. */ inline double GetBesselIntegral(double beta_x, double beta_y, double beta_z) { + const double A = 1.0 + 2.0*(beta_x + beta_y + beta_z); const double Bx = 2.0*beta_x; const double By = 2.0*beta_y; const double Bz = 2.0*beta_z; - const int N = 4000; - const double t_max = 40.0; - const double delta_t = t_max / N; + + const int N = 4000; + const double t_max = 40.0; + const double dt = t_max / N; + double sum = 0.0; - for (int i = 0; i < N; i++) { - double t = i * delta_t; - double I0x = GetBesselZero(Bx * t); - double I0y = GetBesselZero(By * t); - double I0z = GetBesselZero(Bz * t); - double integrand = t * exp(-A * t) - * (I0x * I0y * I0z); + + for (int i = 1; i < N; i++) { + double t = i * dt; + + double e = exp(-A*t); + + double lx = GetBesselZero(Bx*t); + double ly = GetBesselZero(By*t); + double lz = GetBesselZero(Bz*t); + + double lin = log(t) - A*t + lx + ly + lz; + + double integrand = exp(lin); sum += integrand; } - return sum * delta_t; + + return sum * dt; } /// @} diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index ed8ab9bce5b..8e8d09bedfc 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2943,7 +2943,7 @@ void CConfig::SetConfig_Options() { addBoolOption("ENFORCE_LES", enforceLES, false); /* DESCRIPTION: Specify if the stochastic source term must be included in the turbulence model equation */ - addBoolOption("STOCH_SOURCE_NU", stochSourceNu, false) + addBoolOption("STOCH_SOURCE_NU", stochSourceNu, false); /* DESCRIPTION: Filter width for LES (if negative, it is computed based on the local cell size) */ addDoubleOption("LES_FILTER_WIDTH", LES_FilterWidth, -1.0); diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 41b4146d78f..02132c345aa 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1682,7 +1682,7 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet const unsigned short maxIter = config->GetSBS_maxIterSmooth(); const unsigned long global_nPointDomain = geometry->GetGlobal_nPointDomain(); const su2double tol = -5.0; - const su2double sourceLim = 5.0; + const su2double sourceLim = 3.0; const su2double omega = 0.8; unsigned long timeIter = config->GetTimeIter(); unsigned long restartIter = config->GetRestart_Iter(); @@ -1838,9 +1838,9 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet } su2double scaleFactor = 1.0 / sqrt(max(integral, 1e-10)); source *= scaleFactor; + source = min(max(source, -sourceLim), sourceLim); mean_check_new += source; var_check_new += source * source; - source = min(max(source, -sourceLim), sourceLim); nodes->SetLangevinSourceTerms(iPoint, iDim, source); } su2double mean_check_old_G = 0.0; @@ -1865,7 +1865,7 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet var_check_notSmoothed_G /= global_nPointDomain; var_check_notSmoothed_G -= mean_check_notSmoothed_G * mean_check_notSmoothed_G; if (rank == MASTER_NODE) { - cout << "Mean of stochastic source term before scaling: " << mean_check_old_G <<". After scaling: " << mean_check_new_G << "." << endl; + cout << "Mean of stochastic source term before scaling: " << mean_check_old_G-mean_check_notSmoothed_G <<". After scaling: " << mean_check_new_G-mean_check_notSmoothed_G << "." << endl; cout << "Variance of stochastic source term before scaling: " << var_check_old_G/var_check_notSmoothed_G <<". After scaling: " << var_check_new_G/var_check_notSmoothed_G << "." << endl; cout << endl; } From d1a1ae8f21022bd6e3f50307613bfe8b8f693fc1 Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Tue, 9 Dec 2025 11:43:13 +0100 Subject: [PATCH 20/70] Add time-averaged skin friction coefficient - Add option to print time-averaged skin friction coefficient in volume output. --- Common/src/CConfig.cpp | 4 +++- SU2_CFD/src/output/CFlowOutput.cpp | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 8e8d09bedfc..60bb5c5e1c8 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -6520,7 +6520,9 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { else cout << "No smoothing applied to source terms in Langevin equations." << endl; if (stochSourceNu) - cout << "Stochastic source term included in turbulence model equation" << endl; + cout << "Stochastic source term included in turbulence model equation." << endl; + else + cout << "Stochastic source term NOT included in turbulence model equation." << endl; } else { cout << "OFF" << endl; } diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index 106aed24352..58a53d6b599 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -4015,6 +4015,11 @@ void CFlowOutput::SetTimeAveragedFields() { AddVolumeOutput("MEAN_VELOCITY-Z", "MeanVelocity_z", "TIME_AVERAGE", "Mean velocity z-component"); AddVolumeOutput("MEAN_PRESSURE", "MeanPressure", "TIME_AVERAGE", "Mean pressure"); + AddVolumeOutput("MEAN_SKIN_FRICTION-X", "MeanSkinFriction_x", "TIME_AVERAGE", "Mean skin friction x-component"); + AddVolumeOutput("MEAN_SKIN_FRICTION-Y", "MeanSkinFriction_y", "TIME_AVERAGE", "Mean skin friction y-component"); + if (nDim==3) + AddVolumeOutput("MEAN_SKIN_FRICTION-Z", "MeanSkinFriction_z", "TIME_AVERAGE", "Mean skin friction z-component"); + AddVolumeOutput("RMS_U", "RMS[u]", "TIME_AVERAGE", "RMS u"); AddVolumeOutput("RMS_V", "RMS[v]", "TIME_AVERAGE", "RMS v"); AddVolumeOutput("RMS_UV", "RMS[uv]", "TIME_AVERAGE", "RMS uv"); @@ -4041,6 +4046,9 @@ void CFlowOutput::LoadTimeAveragedData(unsigned long iPoint, const CVariable *No SetAvgVolumeOutputValue("MEAN_VELOCITY-Z", iPoint, Node_Flow->GetVelocity(iPoint,2)); SetAvgVolumeOutputValue("MEAN_PRESSURE", iPoint, Node_Flow->GetPressure(iPoint)); + SetAvgVolumeOutputValue("MEAN_SKIN_FRICTION-X", iPoint, GetVolumeOutputValue("SKIN_FRICTION-X", iPoint)); + SetAvgVolumeOutputValue("MEAN_SKIN_FRICTION-Y", iPoint, GetVolumeOutputValue("SKIN_FRICTION-Y", iPoint)); + if (nDim == 3) SetAvgVolumeOutputValue("MEAN_SKIN_FRICTION-Z", iPoint, GetVolumeOutputValue("SKIN_FRICTION-Z", iPoint)); SetAvgVolumeOutputValue("RMS_U", iPoint, pow(Node_Flow->GetVelocity(iPoint,0),2)); SetAvgVolumeOutputValue("RMS_V", iPoint, pow(Node_Flow->GetVelocity(iPoint,1),2)); From babfb586e343cea1f9da1fc5fa085f553c8a71d4 Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:52:51 +0100 Subject: [PATCH 21/70] Minor fix - Minor syntax fix in CConfig.cpp --- Common/src/CConfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 60bb5c5e1c8..68483cef039 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -6521,7 +6521,7 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { cout << "No smoothing applied to source terms in Langevin equations." << endl; if (stochSourceNu) cout << "Stochastic source term included in turbulence model equation." << endl; - else + else cout << "Stochastic source term NOT included in turbulence model equation." << endl; } else { cout << "OFF" << endl; From 562f311cbe57a742aedda65655756b79f6bad34e Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:55:35 +0100 Subject: [PATCH 22/70] Minor fix - Minor syntax fix in CConfig.cpp --- Common/src/CConfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 68483cef039..511472ff7a6 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -6521,7 +6521,7 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { cout << "No smoothing applied to source terms in Langevin equations." << endl; if (stochSourceNu) cout << "Stochastic source term included in turbulence model equation." << endl; - else + else cout << "Stochastic source term NOT included in turbulence model equation." << endl; } else { cout << "OFF" << endl; From 90ede00b4fb8dbe09792b5b6682ed92a8d07e9be Mon Sep 17 00:00:00 2001 From: Angelo Passariello Date: Mon, 15 Dec 2025 12:01:06 +0100 Subject: [PATCH 23/70] Add fields to VOLUME_OUTPUT - Include time-averaged skin friction coefficient and instantaneous energy backscatter ratio into volume output fields. - Fix boundary conditions for the implicit smoothing of the stochastic source term in Langevin equations. - Fix computation of the source term in turbulence model equation. - Fix computation of the subgrid kinetic energy (divide eddy viscosity by flow density). - Diagonalize Jacobian in turbulence equations for numerical robustness. --- Common/include/toolboxes/random_toolbox.hpp | 85 ++++++------ Common/src/CConfig.cpp | 2 +- SU2_CFD/include/numerics/CNumerics.hpp | 24 ++-- .../numerics/turbulent/turb_sources.hpp | 45 +++--- .../include/solvers/CFVMFlowSolverBase.inl | 7 +- SU2_CFD/src/output/CFlowOutput.cpp | 129 +++++++++++++----- SU2_CFD/src/solvers/CTurbSASolver.cpp | 45 +++--- config_template.cfg | 2 +- 8 files changed, 186 insertions(+), 153 deletions(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index 28eb0267636..aa50baf1e7f 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -91,32 +91,26 @@ inline double GetRandomUniform(std::mt19937 gen, double xmin = 0.0, double xmax * \return Value of Bessel function. */ inline double GetBesselZero(double x) { - double abx = fabs(x); - - if (abx < 3.75) { - double t = x / 3.75; - double p = 1.0 + - t*t*(3.5156229 + - t*t*(3.0899424 + - t*t*(1.2067492 + - t*t*(0.2659732 + - t*t*(0.0360768 + - t*t*0.0045813))))); - return log(p); - } else { - double t = 3.75 / abx; - double poly = - 0.39894228 + - t*(0.01328592 + - t*(0.00225319 + - t*(-0.00157565 + - t*(0.00916281 + - t*(-0.02057706 + - t*(0.02635537 + - t*(-0.01647633 + - t*0.00392377))))))); - return abx - 0.5*log(abx) + log(poly); - } + double abx = fabs(x); + + if (abx < 3.75) { + double t = x / 3.75; + double p = + 1.0 + + t * t * + (3.5156229 + + t * t * (3.0899424 + t * t * (1.2067492 + t * t * (0.2659732 + t * t * (0.0360768 + t * t * 0.0045813))))); + return log(p); + } else { + double t = 3.75 / abx; + double poly = + 0.39894228 + + t * (0.01328592 + + t * (0.00225319 + + t * (-0.00157565 + + t * (0.00916281 + t * (-0.02057706 + t * (0.02635537 + t * (-0.01647633 + t * 0.00392377))))))); + return abx - 0.5 * log(abx) + log(poly); + } } /*! @@ -127,34 +121,33 @@ inline double GetBesselZero(double x) { * \return Value of the integral. */ inline double GetBesselIntegral(double beta_x, double beta_y, double beta_z) { + const double A = 1.0 + 2.0 * (beta_x + beta_y + beta_z); + const double Bx = 2.0 * beta_x; + const double By = 2.0 * beta_y; + const double Bz = 2.0 * beta_z; - const double A = 1.0 + 2.0*(beta_x + beta_y + beta_z); - const double Bx = 2.0*beta_x; - const double By = 2.0*beta_y; - const double Bz = 2.0*beta_z; + const int N = 4000; + const double t_max = 40.0; + const double dt = t_max / N; - const int N = 4000; - const double t_max = 40.0; - const double dt = t_max / N; + double sum = 0.0; - double sum = 0.0; + for (int i = 1; i < N; i++) { + double t = i * dt; - for (int i = 1; i < N; i++) { - double t = i * dt; + double e = exp(-A * t); - double e = exp(-A*t); + double lx = GetBesselZero(Bx * t); + double ly = GetBesselZero(By * t); + double lz = GetBesselZero(Bz * t); - double lx = GetBesselZero(Bx*t); - double ly = GetBesselZero(By*t); - double lz = GetBesselZero(Bz*t); + double lin = log(t) - A * t + lx + ly + lz; - double lin = log(t) - A*t + lx + ly + lz; + double integrand = exp(lin); + sum += integrand; + } - double integrand = exp(lin); - sum += integrand; - } - - return sum * dt; + return sum * dt; } /// @} diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index f6ec93572de..d34ef9790da 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2946,7 +2946,7 @@ void CConfig::SetConfig_Options() { addBoolOption("ENFORCE_LES", enforceLES, false); /* DESCRIPTION: Specify if the stochastic source term must be included in the turbulence model equation */ - addBoolOption("STOCH_SOURCE_NU", stochSourceNu, false); + addBoolOption("STOCH_SOURCE_NU", stochSourceNu, true); /* DESCRIPTION: Filter width for LES (if negative, it is computed based on the local cell size) */ addDoubleOption("LES_FILTER_WIDTH", LES_FilterWidth, -1.0); diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index 1510f299603..ba1c7d6dd5e 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -666,23 +666,15 @@ class CNumerics { /* --- Calculate stochastic tensor --- */ - if (lesSensor > 0.999) { - stochReynStress[1][0] = - Cmag * density * turbKE * rndVec[2]; - stochReynStress[2][0] = Cmag * density * turbKE * rndVec[1]; - stochReynStress[2][1] = - Cmag * density * turbKE * rndVec[0]; - for (size_t iDim = 0; iDim < nDim; iDim++) { - for (size_t jDim = 0; jDim <= iDim; jDim++) { - if (iDim==jDim) { - stochReynStress[iDim][jDim] = 0.0; - } else { - stochReynStress[jDim][iDim] = - stochReynStress[iDim][jDim]; - } - } - } - } else { - for (size_t iDim = 0; iDim < nDim; iDim++) { - for (size_t jDim = 0; jDim < nDim; jDim++) { + stochReynStress[1][0] = - std::nearbyint(lesSensor) * Cmag * density * turbKE * rndVec[2]; + stochReynStress[2][0] = std::nearbyint(lesSensor) * Cmag * density * turbKE * rndVec[1]; + stochReynStress[2][1] = - std::nearbyint(lesSensor) * Cmag * density * turbKE * rndVec[0]; + for (size_t iDim = 0; iDim < nDim; iDim++) { + for (size_t jDim = 0; jDim <= iDim; jDim++) { + if (iDim==jDim) { stochReynStress[iDim][jDim] = 0.0; + } else { + stochReynStress[jDim][iDim] = - stochReynStress[iDim][jDim]; } } } diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index 4992ebe60d2..a377531b72f 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -122,18 +122,14 @@ class CSourceBase_TurbSA : public CNumerics { const CSAVariables& var, TIME_MARCHING time_marching) { const su2double& nue = ScalarVar_i[0]; - const auto& density = V_i[idx.Density()]; - const su2double nut_small = 1.0e-10; - - su2double Ji_2 = pow(var.Ji,2); - su2double Ji_3 = Ji_2 * var.Ji; + const su2double nut_small = 1.0e-12; - const su2double nut = nue * var.fv1; + const su2double nut = max(nue * var.fv1, nut_small); - su2double tLES = ct * pow(lengthScale/DES_const, 2) / max(nut, nut_small); - su2double tRANS = pow(lengthScale, 2) / max(nut, nut_small); + su2double tLES = ct * pow(lengthScale/DES_const, 2) / nut; + su2double tRANS = pow(lengthScale, 2) / nut; su2double tLR = tLES / tRANS; su2double tTurb = tLES / (lesMode_i + (1.0-lesMode_i)*tLR); su2double tRat = timeStep / tTurb; @@ -146,7 +142,7 @@ class CSourceBase_TurbSA : public CNumerics { } su2double scaleFactor = 0.0; - if (lesMode_i > 0.999) scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * density * corrFac; + if (std::nearbyint(lesMode_i) == 1) scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * density * corrFac; ResidSB[0] = Residual; for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { @@ -157,22 +153,15 @@ class CSourceBase_TurbSA : public CNumerics { for (unsigned short iVar = 0; iVar < nVar; iVar++ ) { for (unsigned short jVar = 0; jVar < nVar; jVar++ ) { JacobianSB_i[iVar][jVar] = 0.0; - if (iVar == jVar) JacobianSB_i[iVar][jVar] = -1.0/tTurb * density * Volume; } } - JacobianSB_i[0][0] = Jacobian_i[0]; - - su2double dnut_dnue = var.fv1 + 3.0 * var.cv1_3 * Ji_3 / pow(Ji_3 + var.cv1_3, 2); - su2double dtTurb_dnut = - ct * pow(lengthScale,2) / (max(nut, nut_small)*max(nut, nut_small)); for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { - JacobianSB_i[iVar][0] = - 1.0/tTurb * scaleFactor * stochSource[iVar-1] - + 1.0/(tTurb*tTurb) * ScalarVar_i[iVar] - + density * corrFac * stochSource[iVar-1] / - (tTurb * sqrt(2.0*tTurb*timeStep)); - JacobianSB_i[iVar][0] *= dtTurb_dnut * dnut_dnue * Volume; + JacobianSB_i[iVar][iVar] = -1.0/tTurb * density * Volume; } + JacobianSB_i[0][0] = Jacobian_i[0]; + } /*! @@ -182,23 +171,21 @@ class CSourceBase_TurbSA : public CNumerics { inline void AddStochSource(const CSAVariables& var, const MatrixType& velGrad, const su2double Cmag) { su2double dist2 = dist_i * dist_i; - const su2double eps = 1.0e-10; + const su2double eps = 1.0e-12; su2double xi3 = pow(var.Ji, 3); su2double factor = dist2 / (2.0 * var.fv1 * ScalarVar_i[0] + eps); factor /= (3.0 * xi3 * var.cv1_3 / pow(xi3 + var.cv1_3, 2) + var.fv1 + eps); - const auto& density = V_i[idx.Density()]; - su2double tke = pow(var.fv1*ScalarVar_i[0]/dist_i, 2); - su2double R12 = Cmag * density * tke * ScalarVar_i[2]; - su2double R13 = - Cmag * density * tke * ScalarVar_i[1]; - su2double R23 = Cmag * density * tke * ScalarVar_i[0]; + su2double R12 = (nDim==3 ? Cmag * tke * ScalarVar_i[3] : 0.0); + su2double R13 = - Cmag * tke * ScalarVar_i[2]; + su2double R23 = Cmag * tke * ScalarVar_i[1]; - su2double RGradU = R12 * (velGrad[0][1] - velGrad[1][0]) + - R13 * (velGrad[0][2] - velGrad[2][0]) + - R23 * (velGrad[1][2] - velGrad[2][1]); + su2double RGradU = R12 * (velGrad[0][1] - velGrad[1][0]) + + (nDim==3 ? R13 * (velGrad[0][2] - velGrad[2][0]) + + R23 * (velGrad[1][2] - velGrad[2][1]) : 0.0); su2double source_k = - RGradU; su2double source_nu = factor * source_k; @@ -379,7 +366,7 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Compute residual for Langevin equations (Stochastic Backscatter Model). ---*/ if (backscatter) { - if (lesMode_i > 0.999 && config->GetStochSourceNu()) + if (std::nearbyint(lesMode_i) == 1 && config->GetStochSourceNu()) AddStochSource(var, PrimVar_Grad_i + idx.Velocity(), config->GetSBS_Cmag()); const su2double DES_const = config->GetConst_DES(); const su2double ctau = config->GetSBS_Ctau(); diff --git a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl index b2a42e4c166..1d7322f0e11 100644 --- a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl +++ b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl @@ -475,10 +475,11 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome numerics->SetStochVar(turbNodes->GetSolution(iPoint, 1 + iDim), turbNodes->GetSolution(jPoint, 1 + iDim), iDim); } - su2double eddy_visc_i, eddy_visc_j, DES_length_i, + su2double rho, eddy_visc_i, eddy_visc_j, DES_length_i, DES_length_j, tke_i, tke_j, lesMode_i, lesMode_j; - eddy_visc_i = turbNodes->GetmuT(iPoint); - eddy_visc_j = turbNodes->GetmuT(jPoint); + rho = nodes->GetDensity(iPoint); + eddy_visc_i = turbNodes->GetmuT(iPoint) / rho; + eddy_visc_j = turbNodes->GetmuT(jPoint) / rho; DES_length_i = turbNodes->GetDES_LengthScale(iPoint); DES_length_j = turbNodes->GetDES_LengthScale(jPoint); lesMode_i = turbNodes->GetLES_Mode(iPoint); diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index 7428dbfaaad..e53cf67c549 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -966,11 +966,11 @@ void CFlowOutput::AddHistoryOutputFields_ScalarRMS_RES(const CConfig* config) { AddHistoryOutput("RMS_NU_TILDE", "rms[nu]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of nu tilde (SA model).", HistoryFieldType::RESIDUAL); if (config->GetStochastic_Backscatter()) { /// DESCRIPTION: Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model). - AddHistoryOutput("RMS_STOCH_VAR_X", "rms[stoch_x]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + AddHistoryOutput("RMS_STOCH_VAR-X", "rms[stoch_x]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Root-mean square residual of stochastic vector y-component (Stochastic Backscatter Model). - AddHistoryOutput("RMS_STOCH_VAR_Y", "rms[stoch_y]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + AddHistoryOutput("RMS_STOCH_VAR-Y", "rms[stoch_y]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Root-mean square residual of stochastic vector z-component (Stochastic Backscatter Model). - if (nDim==3) AddHistoryOutput("RMS_STOCH_VAR_Z", "rms[stoch_z]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + if (nDim==3) AddHistoryOutput("RMS_STOCH_VAR-Z", "rms[stoch_z]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); } break; @@ -1029,11 +1029,11 @@ void CFlowOutput::AddHistoryOutputFields_ScalarMAX_RES(const CConfig* config) { AddHistoryOutput("MAX_NU_TILDE", "max[nu]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of nu tilde (SA model).", HistoryFieldType::RESIDUAL); if (config->GetStochastic_Backscatter()) { /// DESCRIPTION: Maximum residual of stochastic vector x-component (Stochastic Backscatter Model). - AddHistoryOutput("MAX_STOCH_VAR_X", "max[stoch_x]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + AddHistoryOutput("MAX_STOCH_VAR-X", "max[stoch_x]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Maximum residual of stochastic vector y-component (Stochastic Backscatter Model). - AddHistoryOutput("MAX_STOCH_VAR_Y", "max[stoch_y]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + AddHistoryOutput("MAX_STOCH_VAR-Y", "max[stoch_y]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Maximum residual of stochastic vector z-component (Stochastic Backscatter Model). - if (nDim==3) AddHistoryOutput("MAX_STOCH_VAR_Z", "max[stoch_z]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + if (nDim==3) AddHistoryOutput("MAX_STOCH_VAR-Z", "max[stoch_z]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); } break; @@ -1177,19 +1177,19 @@ void CFlowOutput::LoadHistoryDataScalar(const CConfig* config, const CSolver* co SetHistoryOutputValue("RMS_NU_TILDE", log10(solver[TURB_SOL]->GetRes_RMS(0))); SetHistoryOutputValue("MAX_NU_TILDE", log10(solver[TURB_SOL]->GetRes_Max(0))); if (config->GetStochastic_Backscatter()) { - SetHistoryOutputValue("RMS_STOCH_VAR_X", log10(solver[TURB_SOL]->GetRes_RMS(1))); - SetHistoryOutputValue("RMS_STOCH_VAR_Y", log10(solver[TURB_SOL]->GetRes_RMS(2))); - if (nDim==3) SetHistoryOutputValue("RMS_STOCH_VAR_Z", log10(solver[TURB_SOL]->GetRes_RMS(3))); - SetHistoryOutputValue("MAX_STOCH_VAR_X", log10(solver[TURB_SOL]->GetRes_Max(1))); - SetHistoryOutputValue("MAX_STOCH_VAR_Y", log10(solver[TURB_SOL]->GetRes_Max(2))); - if (nDim==3) SetHistoryOutputValue("MAX_STOCH_VAR_Z", log10(solver[TURB_SOL]->GetRes_Max(3))); + SetHistoryOutputValue("RMS_STOCH_VAR-X", log10(solver[TURB_SOL]->GetRes_RMS(1))); + SetHistoryOutputValue("RMS_STOCH_VAR-Y", log10(solver[TURB_SOL]->GetRes_RMS(2))); + if (nDim==3) SetHistoryOutputValue("RMS_STOCH_VAR-Z", log10(solver[TURB_SOL]->GetRes_RMS(3))); + SetHistoryOutputValue("MAX_STOCH_VAR-X", log10(solver[TURB_SOL]->GetRes_Max(1))); + SetHistoryOutputValue("MAX_STOCH_VAR-Y", log10(solver[TURB_SOL]->GetRes_Max(2))); + if (nDim==3) SetHistoryOutputValue("MAX_STOCH_VAR-Z", log10(solver[TURB_SOL]->GetRes_Max(3))); } if (multiZone) { SetHistoryOutputValue("BGS_NU_TILDE", log10(solver[TURB_SOL]->GetRes_BGS(0))); if (config->GetStochastic_Backscatter()) { - SetHistoryOutputValue("BGS_STOCH_VAR_X", log10(solver[TURB_SOL]->GetRes_BGS(1))); - SetHistoryOutputValue("BGS_STOCH_VAR_Y", log10(solver[TURB_SOL]->GetRes_BGS(2))); - if (nDim==3) SetHistoryOutputValue("BGS_STOCH_VAR_Z", log10(solver[TURB_SOL]->GetRes_BGS(3))); + SetHistoryOutputValue("BGS_STOCH_VAR-X", log10(solver[TURB_SOL]->GetRes_BGS(1))); + SetHistoryOutputValue("BGS_STOCH_VAR-Y", log10(solver[TURB_SOL]->GetRes_BGS(2))); + if (nDim==3) SetHistoryOutputValue("BGS_STOCH_VAR-Z", log10(solver[TURB_SOL]->GetRes_BGS(3))); } } break; @@ -1514,12 +1514,13 @@ void CFlowOutput::SetVolumeOutputFieldsScalarMisc(const CConfig* config) { AddVolumeOutput("WALL_DISTANCE", "Wall_Distance", "DDES", "Wall distance value"); AddVolumeOutput("LES_SENSOR","LES_Sensor","DDES","LES sensor value"); if (config->GetStochastic_Backscatter()) { - AddVolumeOutput("STOCHASTIC_VAR_X", "Stochastic_Var_X", "BACKSCATTER", "x-component of the stochastic vector potential"); - AddVolumeOutput("STOCHASTIC_VAR_Y", "Stochastic_Var_Y", "BACKSCATTER", "y-component of the stochastic vector potential"); - if (nDim==3) AddVolumeOutput("STOCHASTIC_VAR_Z", "Stochastic_Var_Z", "BACKSCATTER", "z-component of the stochastic vector potential"); - AddVolumeOutput("STOCHASTIC_SOURCE_X", "Stochastic_Source_X", "BACKSCATTER", "x-component of the stochastic source vector"); - AddVolumeOutput("STOCHASTIC_SOURCE_Y", "Stochastic_Source_Y", "BACKSCATTER", "y-component of the stochastic source vector"); - if (nDim==3) AddVolumeOutput("STOCHASTIC_SOURCE_Z", "Stochastic_Source_Z", "BACKSCATTER", "z-component of the stochastic source vector"); + AddVolumeOutput("STOCHVAR_X", "StochVar_x", "BACKSCATTER", "x-component of the stochastic vector potential"); + AddVolumeOutput("STOCHVAR_Y", "StochVar_y", "BACKSCATTER", "y-component of the stochastic vector potential"); + if (nDim==3) AddVolumeOutput("STOCHVAR_Z", "StochVar_z", "BACKSCATTER", "z-component of the stochastic vector potential"); + AddVolumeOutput("STOCHSOURCE_X", "StochSource_x", "BACKSCATTER", "x-component of the stochastic source vector"); + AddVolumeOutput("STOCHSOURCE_Y", "StochSource_y", "BACKSCATTER", "y-component of the stochastic source vector"); + if (nDim==3) AddVolumeOutput("STOCHSOURCE_Z", "StochSource_z", "BACKSCATTER", "z-component of the stochastic source vector"); + AddVolumeOutput("ENERGY_BACKSCATTER_RATIO", "Energy_Backscatter_Ratio", "BACKSCATTER", "Energy backscatter from unresolved to resolved scales (divided by the turbulent dissipation of resolved kinetic energy)"); } } @@ -1622,12 +1623,66 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con SetVolumeOutputValue("WALL_DISTANCE", iPoint, Node_Geo->GetWall_Distance(iPoint)); SetVolumeOutputValue("LES_SENSOR", iPoint, Node_Flow->GetLES_Mode(iPoint)); if (config->GetStochastic_Backscatter()) { - SetVolumeOutputValue("STOCHASTIC_VAR_X", iPoint, Node_Turb->GetSolution(iPoint, 1)); - SetVolumeOutputValue("STOCHASTIC_VAR_Y", iPoint, Node_Turb->GetSolution(iPoint, 2)); - if (nDim==3) SetVolumeOutputValue("STOCHASTIC_VAR_Z", iPoint, Node_Turb->GetSolution(iPoint, 3)); - SetVolumeOutputValue("STOCHASTIC_SOURCE_X", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 0)); - SetVolumeOutputValue("STOCHASTIC_SOURCE_Y", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 1)); - if (nDim==3) SetVolumeOutputValue("STOCHASTIC_SOURCE_Z", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 2)); + SetVolumeOutputValue("STOCHVAR_X", iPoint, Node_Turb->GetSolution(iPoint, 1)); + SetVolumeOutputValue("STOCHVAR_Y", iPoint, Node_Turb->GetSolution(iPoint, 2)); + if (nDim==3) SetVolumeOutputValue("STOCHVAR_Z", iPoint, Node_Turb->GetSolution(iPoint, 3)); + SetVolumeOutputValue("STOCHSOURCE_X", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 0)); + SetVolumeOutputValue("STOCHSOURCE_Y", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 1)); + if (nDim==3) SetVolumeOutputValue("STOCHSOURCE_Z", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 2)); + const su2double rho = Node_Flow->GetDensity(iPoint); + const su2double mu_t = Node_Flow->GetEddyViscosity(iPoint) / rho; + const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1.0E-10); + const su2double lesSensor = Node_Flow->GetLES_Mode(iPoint); + const su2double mag = config->GetSBS_Cmag(); + const su2double tke_estim = pow(mu_t/DES_lengthscale, 2.0); + const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); + const su2double csi_y = Node_Turb->GetSolution(iPoint, 2); + const su2double csi_z = (nDim==3) ? Node_Turb->GetSolution(iPoint, 3) : 0.0; + const su2double R_xy = mag * tke_estim * csi_z * std::nearbyint(lesSensor); + const su2double R_xz = - mag * tke_estim * csi_y * std::nearbyint(lesSensor); + const su2double R_yz = mag * tke_estim * csi_x * std::nearbyint(lesSensor); + const auto vel_grad = Node_Flow->GetVelocityGradient(iPoint); + const su2double vel_div = vel_grad(0,0) + vel_grad(1,1) + (nDim ==3 ? vel_grad(2,2) : 0.0); + const su2double tau_xx = mu_t/rho * (2*vel_grad(0,0) - (2.0/3.0)*vel_div); + const su2double tau_yy = mu_t/rho * (2*vel_grad(1,1) - (2.0/3.0)*vel_div); + const su2double tau_xy = mu_t/rho * (vel_grad(0,1) + vel_grad(1,0)); + su2double tau_zz=0.0, tau_xz=0.0, tau_yz=0.0; + if (nDim == 3){ + tau_zz = mu_t/rho * (2*vel_grad(2,2) - (2.0/3.0)*vel_div); + tau_xz = mu_t/rho * (vel_grad(0,2) + vel_grad(2,0)); + tau_yz = mu_t/rho * (vel_grad(1,2) + vel_grad(2,1)); + } + const su2double energy_res_to_mod = tau_xx * vel_grad(0,0) + tau_yy * vel_grad(1,1) + + (nDim==3 ? tau_zz * vel_grad(2,2) : 0.0) + + tau_xy * (vel_grad(0,1) + vel_grad(1,0)) + + (nDim==3 ? tau_xz * (vel_grad(0,2) + vel_grad(2,0)) + + tau_yz * (vel_grad(1,2) + vel_grad(2,1)) : 0.0); + const su2double energy_backscatter = R_xy * (vel_grad(0,1) - vel_grad(1,0)) + + (nDim==3 ? R_xz * (vel_grad(0,2) - vel_grad(2,0)) + + R_yz * (vel_grad(1,2) - vel_grad(2,1)) : 0.0); + const su2double energy_backscatter_ratio = energy_backscatter / (energy_res_to_mod + 1e-12); + SetVolumeOutputValue("ENERGY_BACKSCATTER_RATIO", iPoint, energy_backscatter_ratio); + } + } + + if (config->GetTime_Domain()) { + const su2double mu_t = Node_Flow->GetEddyViscosity(iPoint); + const su2double rho = Node_Flow->GetDensity(iPoint); + const auto vel_grad = Node_Flow->GetVelocityGradient(iPoint); + const su2double vel_div = vel_grad(0,0) + vel_grad(1,1) + (nDim ==3 ? vel_grad(2,2) : 0.0); + const su2double tau_xx = mu_t/rho * (2*vel_grad(0,0) - (2.0/3.0)*vel_div); + const su2double tau_yy = mu_t/rho * (2*vel_grad(1,1) - (2.0/3.0)*vel_div); + const su2double tau_xy = mu_t/rho * (vel_grad(0,1) + vel_grad(1,0)); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_11", iPoint, -tau_xx); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_22", iPoint, -tau_yy); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_12", iPoint, -tau_xy); + if (nDim == 3){ + const su2double tau_zz = mu_t/rho * (2*vel_grad(2,2) - (2.0/3.0)*vel_div); + const su2double tau_xz = mu_t/rho * (vel_grad(0,2) + vel_grad(2,0)); + const su2double tau_yz = mu_t/rho * (vel_grad(1,2) + vel_grad(2,1)); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_33", iPoint, -tau_zz); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_13", iPoint, -tau_xz); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_23", iPoint, -tau_yz); } } @@ -1708,6 +1763,13 @@ void CFlowOutput::LoadSurfaceData(CConfig *config, CGeometry *geometry, CSolver SetVolumeOutputValue("SKIN_FRICTION-Z", iPoint, solver[FLOW_SOL]->GetCSkinFriction(iMarker, iVertex, 2)); SetVolumeOutputValue("HEAT_FLUX", iPoint, solver[heat_sol]->GetHeatFlux(iMarker, iVertex)); SetVolumeOutputValue("Y_PLUS", iPoint, solver[FLOW_SOL]->GetYPlus(iMarker, iVertex)); + + if (config->GetTime_Domain()) { + SetAvgVolumeOutputValue("MEAN_SKIN_FRICTION-X", iPoint, solver[FLOW_SOL]->GetCSkinFriction(iMarker, iVertex, 0)); + SetAvgVolumeOutputValue("MEAN_SKIN_FRICTION-Y", iPoint, solver[FLOW_SOL]->GetCSkinFriction(iMarker, iVertex, 1)); + if (nDim == 3) + SetAvgVolumeOutputValue("MEAN_SKIN_FRICTION-Z", iPoint, solver[FLOW_SOL]->GetCSkinFriction(iMarker, iVertex, 2)); + } } void CFlowOutput::AddAerodynamicCoefficients(const CConfig* config) { @@ -4036,6 +4098,15 @@ void CFlowOutput::SetTimeAveragedFields() { AddVolumeOutput("UWPRIME", "w'u'", "TIME_AVERAGE", "Mean Reynolds-stress component w'u'"); AddVolumeOutput("VWPRIME", "w'v'", "TIME_AVERAGE", "Mean Reynolds-stress component w'v'"); } + + AddVolumeOutput("MODELED_REYNOLDS_STRESS_11", "ModeledReynoldsStress_11", "TIME_AVERAGE", "Modeled Reynolds stress xx-component"); + AddVolumeOutput("MODELED_REYNOLDS_STRESS_22", "ModeledReynoldsStress_22", "TIME_AVERAGE", "Modeled Reynolds stress yy-component"); + AddVolumeOutput("MODELED_REYNOLDS_STRESS_12", "ModeledReynoldsStress_12", "TIME_AVERAGE", "Modeled Reynolds stress xy-component"); + if (nDim == 3){ + AddVolumeOutput("MODELED_REYNOLDS_STRESS_33", "ModeledReynoldsStress_33", "TIME_AVERAGE", "Modeled Reynolds stress zz-component"); + AddVolumeOutput("MODELED_REYNOLDS_STRESS_13", "ModeledReynoldsStress_13", "TIME_AVERAGE", "Modeled Reynolds stress xz-component"); + AddVolumeOutput("MODELED_REYNOLDS_STRESS_23", "ModeledReynoldsStress_23", "TIME_AVERAGE", "Modeled Reynolds stress yz-component"); + } } void CFlowOutput::LoadTimeAveragedData(unsigned long iPoint, const CVariable *Node_Flow){ @@ -4046,10 +4117,6 @@ void CFlowOutput::LoadTimeAveragedData(unsigned long iPoint, const CVariable *No SetAvgVolumeOutputValue("MEAN_VELOCITY-Z", iPoint, Node_Flow->GetVelocity(iPoint,2)); SetAvgVolumeOutputValue("MEAN_PRESSURE", iPoint, Node_Flow->GetPressure(iPoint)); - SetAvgVolumeOutputValue("MEAN_SKIN_FRICTION-X", iPoint, GetVolumeOutputValue("SKIN_FRICTION-X", iPoint)); - SetAvgVolumeOutputValue("MEAN_SKIN_FRICTION-Y", iPoint, GetVolumeOutputValue("SKIN_FRICTION-Y", iPoint)); - if (nDim == 3) SetAvgVolumeOutputValue("MEAN_SKIN_FRICTION-Z", iPoint, GetVolumeOutputValue("SKIN_FRICTION-Z", iPoint)); - SetAvgVolumeOutputValue("RMS_U", iPoint, pow(Node_Flow->GetVelocity(iPoint,0),2)); SetAvgVolumeOutputValue("RMS_V", iPoint, pow(Node_Flow->GetVelocity(iPoint,1),2)); SetAvgVolumeOutputValue("RMS_UV", iPoint, Node_Flow->GetVelocity(iPoint,0) * Node_Flow->GetVelocity(iPoint,1)); diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 02132c345aa..07585c5b222 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1648,8 +1648,7 @@ void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) for (auto iDim = 0u; iDim < nDim; iDim++){ auto gen = nodes->GetLangevinGen(iPoint, iDim); su2double lesSensor = nodes->GetLES_Mode(iPoint); - su2double rnd = 0.0; - if (lesSensor > 0.999) rnd = RandomToolbox::GetRandomNormal(gen); + su2double rnd = RandomToolbox::GetRandomNormal(gen) * std::nearbyint(lesSensor); nodes->SetLangevinSourceTermsOld(iPoint, iDim, rnd); nodes->SetLangevinSourceTerms(iPoint, iDim, rnd); } @@ -1678,29 +1677,15 @@ void CTurbSASolver::SetLangevinGen(CConfig* config, CGeometry* geometry) { void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geometry) { const su2double LES_FilterWidth = config->GetLES_FilterWidth(); + const su2double constDES = config->GetConst_DES(); const su2double cDelta = config->GetSBS_Cdelta(); const unsigned short maxIter = config->GetSBS_maxIterSmooth(); - const unsigned long global_nPointDomain = geometry->GetGlobal_nPointDomain(); const su2double tol = -5.0; const su2double sourceLim = 3.0; const su2double omega = 0.8; unsigned long timeIter = config->GetTimeIter(); unsigned long restartIter = config->GetRestart_Iter(); - /*--- Set the stochastic source terms to zero at boundaries. ---*/ - - for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - for (unsigned long iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++ ) { - unsigned long iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (geometry->nodes->GetDomain(iPoint)) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - nodes->SetLangevinSourceTerms(iPoint, iDim, 0.0); - nodes->SetLangevinSourceTermsOld(iPoint, iDim, 0.0); - } - } - } - } - /*--- Start SOR algorithm for the Laplacian smoothing. ---*/ for (unsigned short iDim = 0; iDim < nDim; iDim++) { @@ -1713,11 +1698,15 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet CompleteComms(geometry, config, MPI_QUANTITIES::STOCH_SOURCE_LANG); su2double localResNorm = 0.0; + unsigned long local_nPointLES = 0; SU2_OMP_FOR_DYN(omp_chunk_size) for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { - - su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); + const su2double lesSensor = nodes->GetLES_Mode(iPoint); + if (std::nearbyint(lesSensor) == 0.0) continue; + local_nPointLES += 1; + const su2double DES_LengthScale = nodes->GetDES_LengthScale(iPoint); + su2double maxDelta = DES_LengthScale / constDES; if (LES_FilterWidth > 0.0) maxDelta = LES_FilterWidth; su2double b = sqrt(cDelta) * maxDelta; su2double b2 = b * b; @@ -1756,8 +1745,10 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet /*--- Stop integration if residual drops below tolerance. ---*/ su2double globalResNorm = 0.0; + unsigned long global_nPointLES = 0; + SU2_MPI::Allreduce(&local_nPointLES, &global_nPointLES, 1, MPI_INT, MPI_SUM, SU2_MPI::GetComm()); SU2_MPI::Allreduce(&localResNorm, &globalResNorm, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - globalResNorm = sqrt(globalResNorm / global_nPointDomain); + globalResNorm = sqrt(globalResNorm / global_nPointLES); if (rank == MASTER_NODE) { if (iter == 0) { @@ -1796,6 +1787,8 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet su2double var_check_notSmoothed = 0.0; su2double mean_check_notSmoothed = 0.0; for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { + const su2double lesSensor = nodes->GetLES_Mode(iPoint); + if (std::nearbyint(lesSensor) == 0.0) continue; su2double source = nodes->GetLangevinSourceTerms(iPoint, iDim); su2double source_notSmoothed = nodes->GetLangevinSourceTermsOld(iPoint, iDim); mean_check_old += source; @@ -1855,14 +1848,14 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet SU2_MPI::Allreduce(&var_check_old, &var_check_old_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); SU2_MPI::Allreduce(&var_check_new, &var_check_new_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); SU2_MPI::Allreduce(&var_check_notSmoothed, &var_check_notSmoothed_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - mean_check_old_G /= global_nPointDomain; - var_check_old_G /= global_nPointDomain; + mean_check_old_G /= global_nPointLES; + var_check_old_G /= global_nPointLES; var_check_old_G -= mean_check_old_G * mean_check_old_G; - mean_check_new_G /= global_nPointDomain; - var_check_new_G /= global_nPointDomain; + mean_check_new_G /= global_nPointLES; + var_check_new_G /= global_nPointLES; var_check_new_G -= mean_check_new_G * mean_check_new_G; - mean_check_notSmoothed_G /= global_nPointDomain; - var_check_notSmoothed_G /= global_nPointDomain; + mean_check_notSmoothed_G /= global_nPointLES; + var_check_notSmoothed_G /= global_nPointLES; var_check_notSmoothed_G -= mean_check_notSmoothed_G * mean_check_notSmoothed_G; if (rank == MASTER_NODE) { cout << "Mean of stochastic source term before scaling: " << mean_check_old_G-mean_check_notSmoothed_G <<". After scaling: " << mean_check_new_G-mean_check_notSmoothed_G << "." << endl; diff --git a/config_template.cfg b/config_template.cfg index 2abd0d07624..f70c736d897 100644 --- a/config_template.cfg +++ b/config_template.cfg @@ -200,7 +200,7 @@ SBS_TIMESCALE_COEFF= 0.05 SBS_INTENSITY_COEFF= 1.0 % % Include stochastic source in turbulence model equation (NO, YES) -STOCH_SOURCE_NU= NO +STOCH_SOURCE_NU= YES % % Enforce LES mode in Hybrid RANS-LES Simulations (NO, YES) ENFORCE_LES= NO From a5b3aa0cfd16b188230650084004a794bb2ed402 Mon Sep 17 00:00:00 2001 From: paan882 Date: Tue, 16 Dec 2025 11:56:48 +0100 Subject: [PATCH 24/70] Fix LD2 option in config file - Allow LD2 option only for JST scheme. --- Common/src/CConfig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index d34ef9790da..eaf8e93f109 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -7108,7 +7108,7 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { } } - if (Kind_ConvNumScheme_Flow != SPACE_CENTERED || (Kind_ConvNumScheme_Flow == SPACE_CENTERED && Kind_Centered_Flow == CENTERED::LAX)) { + if ((Kind_ConvNumScheme_Flow != SPACE_CENTERED || (Kind_ConvNumScheme_Flow == SPACE_CENTERED && Kind_Centered_Flow == CENTERED::LAX)) && LD2_Scheme) { { SU2_MPI::Error("LD2 option available for JST scheme only.", CURRENT_FUNCTION); } From 0df34ac5e4197ffe5ca341555f1728076fb30e2a Mon Sep 17 00:00:00 2001 From: paan882 Date: Fri, 2 Jan 2026 12:30:32 +0100 Subject: [PATCH 25/70] Enhance numerical robustness - Add option to include diagnostics of the stochastic source term smoothing. - Add relaxation factor for the random forcing term in the main balanca equations. - Add modeled and stochastic Reynolds stresses to volume output files. --- Common/include/CConfig.hpp | 14 +++ Common/src/CConfig.cpp | 12 +- .../numerics/turbulent/turb_sources.hpp | 19 ++- SU2_CFD/src/numerics/flow/flow_diffusion.cpp | 42 ++++++- SU2_CFD/src/output/CFlowOutput.cpp | 49 +++++--- SU2_CFD/src/solvers/CTurbSASolver.cpp | 108 +++++++++--------- config_template.cfg | 6 + 7 files changed, 176 insertions(+), 74 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 6609268343c..abb11731a7f 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -1103,6 +1103,8 @@ class CConfig { su2double SBS_Ctau; /*!< \brief Stochastic Backscatter Model timescale coefficient. */ su2double SBS_Cmag; /*!< \brief Stochastic Backscatter Model intensity coefficient. */ bool stochSourceNu; /*!< \brief Option for including stochastic source term in turbulence model equation (Stochastic Backscatter Model). */ + bool stochSourceDiagnostics; /*!< \brief Option for writing diagnostics related to stochastic source terms in Langevin equations (Stochastic Backscatter Model). */ + su2double stochSourceRelax; /*!< \brief Relaxation factor for stochastic source term generation (Stochastic Backscatter Model). */ bool enforceLES; /*!< \brief Option to enforce LES mode in hybrid RANS-LES simulations. */ su2double LES_FilterWidth; /*!< \brief LES filter width for hybrid RANS-LES simulations. */ bool LD2_Scheme; /*!< \brief Use the LD2 scheme (incompressible flows, combined with JST discretization). */ @@ -9590,6 +9592,18 @@ class CConfig { */ bool GetStochSourceNu(void) const { return stochSourceNu; } + /*! + * \brief Get if the diagnostics of the stochastic source terms in Langevin equations must be computed. + * \return TRUE if the diagnostics of the stochastic source terms in Langevin equations are computed. + */ + bool GetStochSourceDiagnostics(void) const { return stochSourceDiagnostics; } + + /*! + * \brief Get the relaxation factor for stochastic source term generation. + * \return Relaxation factor for stochastic source term generation. + */ + su2double GetStochSourceRelax(void) const { return stochSourceRelax; } + /*! * \brief Get the LES Filter Width. * \return Value of LES Filter Width. diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 615b906f03f..c6a48109831 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2968,6 +2968,12 @@ void CConfig::SetConfig_Options() { /* DESCRIPTION: Specify if the stochastic source term must be included in the turbulence model equation */ addBoolOption("STOCH_SOURCE_NU", stochSourceNu, true); + /* DESCRIPTION: Enable diagnostics of the stochastic source term in Langevin equations. */ + addBoolOption("STOCH_SOURCE_DIAGNOSTICS", stochSourceDiagnostics, false); + + /* DESCRIPTION: Relaxation factor for the stochastic source term (Stochastic Backscatter Model). */ + addDoubleOption("SBS_RELAXATION_FACTOR", stochSourceRelax, 0.0); + /* DESCRIPTION: Filter width for LES (if negative, it is computed based on the local cell size) */ addDoubleOption("LES_FILTER_WIDTH", LES_FilterWidth, -1.0); @@ -6548,6 +6554,10 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { cout << "Stochastic source term included in turbulence model equation." << endl; else cout << "Stochastic source term NOT included in turbulence model equation." << endl; + if (stochSourceRelax > 0.0) + cout << "Relaxation factor for stochastic source term: " << stochSourceRelax << endl; + else + cout << "No relaxation factor for stochastic source term." << endl; } else { cout << "OFF" << endl; } @@ -7130,7 +7140,7 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { } } - if ((Kind_ConvNumScheme_Flow != SPACE_CENTERED || (Kind_ConvNumScheme_Flow == SPACE_CENTERED && Kind_Centered_Flow == CENTERED::LAX)) && LD2_Scheme) { { + if ((Kind_ConvNumScheme_Flow != SPACE_CENTERED || (Kind_ConvNumScheme_Flow == SPACE_CENTERED && Kind_Centered_Flow == CENTERED::LAX)) && LD2_Scheme) { SU2_MPI::Error("LD2 option available for JST scheme only.", CURRENT_FUNCTION); } diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index a377531b72f..f9cc15a146c 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -366,8 +366,23 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Compute residual for Langevin equations (Stochastic Backscatter Model). ---*/ if (backscatter) { - if (std::nearbyint(lesMode_i) == 1 && config->GetStochSourceNu()) - AddStochSource(var, PrimVar_Grad_i + idx.Velocity(), config->GetSBS_Cmag()); + if (std::nearbyint(lesMode_i) == 1 && config->GetStochSourceNu()) { + su2double SBS_Cmag = config->GetSBS_Cmag(); + su2double lesSensor = max(lesMode_i, lesMode_j); + su2double SBS_RelaxFactor = config->GetStochSourceRelax(); + su2double intensityCoeff = SBS_Cmag; + if (SBS_RelaxFactor > 0.0) { + su2double FS_Vel = config->GetModVel_FreeStream(); + su2double ReynoldsLength = config->GetLength_Reynolds(); + su2double timeScale = ReynoldsLength / FS_Vel; + unsigned long timeIter = config->GetTimeIter(); + unsigned long restartIter = config->GetRestart_Iter(); + su2double timeStep = config->GetTime_Step(); + su2double currentTime = (timeIter - restartIter) * timeStep; + intensityCoeff = SBS_Cmag * (1.0 - exp(-SBS_RelaxFactor * currentTime / timeScale)); + } + AddStochSource(var, PrimVar_Grad_i + idx.Velocity(), intensityCoeff); + } const su2double DES_const = config->GetConst_DES(); const su2double ctau = config->GetSBS_Ctau(); ResidualStochEquations(config->GetDelta_UnstTime(), ctau, dist_i, DES_const, diff --git a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp index d5b224801c7..902b8a6f0f0 100644 --- a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp +++ b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp @@ -462,8 +462,20 @@ CNumerics::ResidualType<> CAvgGrad_Flow::ComputeResidual(const CConfig* config) Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); su2double SBS_Cmag = config->GetSBS_Cmag(); su2double lesSensor = max(lesMode_i, lesMode_j); + su2double SBS_RelaxFactor = config->GetStochSourceRelax(); + su2double intensityCoeff = SBS_Cmag; + if (SBS_RelaxFactor > 0.0) { + su2double FS_Vel = config->GetModVel_FreeStream(); + su2double ReynoldsLength = config->GetLength_Reynolds(); + su2double timeScale = ReynoldsLength / FS_Vel; + unsigned long timeIter = config->GetTimeIter(); + unsigned long restartIter = config->GetRestart_Iter(); + su2double timeStep = config->GetTime_Step(); + su2double currentTime = (timeIter - restartIter) * timeStep; + intensityCoeff = SBS_Cmag * (1.0 - exp(-SBS_RelaxFactor * currentTime / timeScale)); + } ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_turb_ke, - Mean_StochVar, lesSensor, stochReynStress, SBS_Cmag); + Mean_StochVar, lesSensor, stochReynStress, intensityCoeff); } /*--- Get projected flux tensor (viscous residual) ---*/ @@ -647,8 +659,20 @@ CNumerics::ResidualType<> CAvgGradInc_Flow::ComputeResidual(const CConfig* confi Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); su2double SBS_Cmag = config->GetSBS_Cmag(); su2double lesSensor = max(lesMode_i, lesMode_j); + su2double SBS_RelaxFactor = config->GetStochSourceRelax(); + su2double intensityCoeff = SBS_Cmag; + if (SBS_RelaxFactor > 0.0) { + su2double FS_Vel = config->GetModVel_FreeStream(); + su2double ReynoldsLength = config->GetLength_Reynolds(); + su2double timeScale = ReynoldsLength / FS_Vel; + unsigned long timeIter = config->GetTimeIter(); + unsigned long restartIter = config->GetRestart_Iter(); + su2double timeStep = config->GetTime_Step(); + su2double currentTime = (timeIter - restartIter) * timeStep; + intensityCoeff = SBS_Cmag * (1.0 - exp(-SBS_RelaxFactor * currentTime / timeScale)); + } ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_turb_ke, - Mean_StochVar, lesSensor, stochReynStress, SBS_Cmag); + Mean_StochVar, lesSensor, stochReynStress, intensityCoeff); } /*--- Get projected flux tensor (viscous residual) ---*/ @@ -984,8 +1008,20 @@ CNumerics::ResidualType<> CGeneralAvgGrad_Flow::ComputeResidual(const CConfig* c Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); su2double SBS_Cmag = config->GetSBS_Cmag(); su2double lesSensor = max(lesMode_i, lesMode_j); + su2double SBS_RelaxFactor = config->GetStochSourceRelax(); + su2double intensityCoeff = SBS_Cmag; + if (SBS_RelaxFactor > 0.0) { + su2double FS_Vel = config->GetModVel_FreeStream(); + su2double ReynoldsLength = config->GetLength_Reynolds(); + su2double timeScale = ReynoldsLength / FS_Vel; + unsigned long timeIter = config->GetTimeIter(); + unsigned long restartIter = config->GetRestart_Iter(); + su2double timeStep = config->GetTime_Step(); + su2double currentTime = (timeIter - restartIter) * timeStep; + intensityCoeff = SBS_Cmag * (1.0 - exp(-SBS_RelaxFactor * currentTime / timeScale)); + } ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_turb_ke, - Mean_StochVar, lesSensor, stochReynStress, SBS_Cmag); + Mean_StochVar, lesSensor, stochReynStress, intensityCoeff); } /*--- Get projected flux tensor (viscous residual) ---*/ diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index e53cf67c549..44338b645a5 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -1630,11 +1630,11 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con SetVolumeOutputValue("STOCHSOURCE_Y", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 1)); if (nDim==3) SetVolumeOutputValue("STOCHSOURCE_Z", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 2)); const su2double rho = Node_Flow->GetDensity(iPoint); - const su2double mu_t = Node_Flow->GetEddyViscosity(iPoint) / rho; + const su2double nu_t = Node_Flow->GetEddyViscosity(iPoint) / rho; const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1.0E-10); const su2double lesSensor = Node_Flow->GetLES_Mode(iPoint); const su2double mag = config->GetSBS_Cmag(); - const su2double tke_estim = pow(mu_t/DES_lengthscale, 2.0); + const su2double tke_estim = pow(nu_t/DES_lengthscale, 2.0); const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); const su2double csi_y = Node_Turb->GetSolution(iPoint, 2); const su2double csi_z = (nDim==3) ? Node_Turb->GetSolution(iPoint, 3) : 0.0; @@ -1643,14 +1643,14 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con const su2double R_yz = mag * tke_estim * csi_x * std::nearbyint(lesSensor); const auto vel_grad = Node_Flow->GetVelocityGradient(iPoint); const su2double vel_div = vel_grad(0,0) + vel_grad(1,1) + (nDim ==3 ? vel_grad(2,2) : 0.0); - const su2double tau_xx = mu_t/rho * (2*vel_grad(0,0) - (2.0/3.0)*vel_div); - const su2double tau_yy = mu_t/rho * (2*vel_grad(1,1) - (2.0/3.0)*vel_div); - const su2double tau_xy = mu_t/rho * (vel_grad(0,1) + vel_grad(1,0)); + const su2double tau_xx = nu_t * (2*vel_grad(0,0) - (2.0/3.0)*vel_div); + const su2double tau_yy = nu_t * (2*vel_grad(1,1) - (2.0/3.0)*vel_div); + const su2double tau_xy = nu_t * (vel_grad(0,1) + vel_grad(1,0)); su2double tau_zz=0.0, tau_xz=0.0, tau_yz=0.0; if (nDim == 3){ - tau_zz = mu_t/rho * (2*vel_grad(2,2) - (2.0/3.0)*vel_div); - tau_xz = mu_t/rho * (vel_grad(0,2) + vel_grad(2,0)); - tau_yz = mu_t/rho * (vel_grad(1,2) + vel_grad(2,1)); + tau_zz = nu_t * (2*vel_grad(2,2) - (2.0/3.0)*vel_div); + tau_xz = nu_t * (vel_grad(0,2) + vel_grad(2,0)); + tau_yz = nu_t * (vel_grad(1,2) + vel_grad(2,1)); } const su2double energy_res_to_mod = tau_xx * vel_grad(0,0) + tau_yy * vel_grad(1,1) + (nDim==3 ? tau_zz * vel_grad(2,2) : 0.0) @@ -1666,24 +1666,39 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con } if (config->GetTime_Domain()) { - const su2double mu_t = Node_Flow->GetEddyViscosity(iPoint); const su2double rho = Node_Flow->GetDensity(iPoint); + const su2double nu_t = Node_Flow->GetEddyViscosity(iPoint) / rho; const auto vel_grad = Node_Flow->GetVelocityGradient(iPoint); const su2double vel_div = vel_grad(0,0) + vel_grad(1,1) + (nDim ==3 ? vel_grad(2,2) : 0.0); - const su2double tau_xx = mu_t/rho * (2*vel_grad(0,0) - (2.0/3.0)*vel_div); - const su2double tau_yy = mu_t/rho * (2*vel_grad(1,1) - (2.0/3.0)*vel_div); - const su2double tau_xy = mu_t/rho * (vel_grad(0,1) + vel_grad(1,0)); + const su2double tau_xx = nu_t * (2*vel_grad(0,0) - (2.0/3.0)*vel_div); + const su2double tau_yy = nu_t * (2*vel_grad(1,1) - (2.0/3.0)*vel_div); + const su2double tau_xy = nu_t * (vel_grad(0,1) + vel_grad(1,0)); SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_11", iPoint, -tau_xx); SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_22", iPoint, -tau_yy); SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_12", iPoint, -tau_xy); if (nDim == 3){ - const su2double tau_zz = mu_t/rho * (2*vel_grad(2,2) - (2.0/3.0)*vel_div); - const su2double tau_xz = mu_t/rho * (vel_grad(0,2) + vel_grad(2,0)); - const su2double tau_yz = mu_t/rho * (vel_grad(1,2) + vel_grad(2,1)); + const su2double tau_zz = nu_t * (2*vel_grad(2,2) - (2.0/3.0)*vel_div); + const su2double tau_xz = nu_t * (vel_grad(0,2) + vel_grad(2,0)); + const su2double tau_yz = nu_t * (vel_grad(1,2) + vel_grad(2,1)); SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_33", iPoint, -tau_zz); SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_13", iPoint, -tau_xz); SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_23", iPoint, -tau_yz); } + if (config->GetKind_HybridRANSLES()!=NO_HYBRIDRANSLES && config->GetStochastic_Backscatter()) { + const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1.0E-10); + const su2double lesSensor = Node_Flow->GetLES_Mode(iPoint); + const su2double mag = config->GetSBS_Cmag(); + const su2double tke_estim = pow(nu_t/DES_lengthscale, 2.0); + const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); + const su2double csi_y = Node_Turb->GetSolution(iPoint, 2); + const su2double csi_z = (nDim==3) ? Node_Turb->GetSolution(iPoint, 3) : 0.0; + const su2double R_xy = mag * tke_estim * csi_z * std::nearbyint(lesSensor); + const su2double R_xz = - mag * tke_estim * csi_y * std::nearbyint(lesSensor); + const su2double R_yz = mag * tke_estim * csi_x * std::nearbyint(lesSensor); + SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_12", iPoint, -R_xy); + SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_13", iPoint, -R_xz); + SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_23", iPoint, -R_yz); + } } switch (config->GetKind_Species_Model()) { @@ -4107,6 +4122,10 @@ void CFlowOutput::SetTimeAveragedFields() { AddVolumeOutput("MODELED_REYNOLDS_STRESS_13", "ModeledReynoldsStress_13", "TIME_AVERAGE", "Modeled Reynolds stress xz-component"); AddVolumeOutput("MODELED_REYNOLDS_STRESS_23", "ModeledReynoldsStress_23", "TIME_AVERAGE", "Modeled Reynolds stress yz-component"); } + + AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_12", "StochasticReynoldsStress_12", "TIME_AVERAGE", "Stochastic Reynolds stress xy-component"); + AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_13", "StochasticReynoldsStress_13", "TIME_AVERAGE", "Stochastic Reynolds stress xz-component"); + AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_23", "StochasticReynoldsStress_23", "TIME_AVERAGE", "Stochastic Reynolds stress yz-component"); } void CFlowOutput::LoadTimeAveragedData(unsigned long iPoint, const CVariable *Node_Flow){ diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 07585c5b222..6b050fb3841 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1795,35 +1795,36 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet var_check_old += source * source; mean_check_notSmoothed += source_notSmoothed; var_check_notSmoothed += source_notSmoothed * source_notSmoothed; - su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); - if (LES_FilterWidth > 0.0) maxDelta = LES_FilterWidth; - su2double b = sqrt(cDelta) * maxDelta; - su2double b2 = b * b; - auto coord_i = geometry->nodes->GetCoord(iPoint); - su2double max_dx = 0.0; - su2double max_dy = 0.0; - su2double max_dz = 0.0; - unsigned short nNeigh = geometry->nodes->GetnPoint(iPoint); - for (unsigned short iNode = 0; iNode < nNeigh; iNode++) { - auto jPoint = geometry->nodes->GetPoint(iPoint, iNode); - auto coord_j = geometry->nodes->GetCoord(jPoint); - su2double dx = fabs(coord_i[0]-coord_j[0]); - su2double dy = fabs(coord_i[1]-coord_j[1]); - su2double dz = 0.0; - if (nDim == 3) dz = fabs(coord_i[2]-coord_j[2]); - if (dx > max_dx) max_dx = dx; - if (dy > max_dy) max_dy = dy; - if (dz > max_dz) max_dz = dz; - } - su2double dx2 = max_dx * max_dx; - su2double dy2 = max_dy * max_dy; - su2double dz2 = max_dz * max_dz; - su2double bx = b2 / dx2; - su2double by = b2 / dy2; - su2double bz = 0.0; - if (nDim == 3) bz = b2 / dz2; su2double integral = 0.0; if (timeIter==restartIter) { + const su2double DES_LengthScale = nodes->GetDES_LengthScale(iPoint); + su2double maxDelta = DES_LengthScale / constDES; + if (LES_FilterWidth > 0.0) maxDelta = LES_FilterWidth; + su2double b = sqrt(cDelta) * maxDelta; + su2double b2 = b * b; + auto coord_i = geometry->nodes->GetCoord(iPoint); + su2double max_dx = 0.0; + su2double max_dy = 0.0; + su2double max_dz = 0.0; + unsigned short nNeigh = geometry->nodes->GetnPoint(iPoint); + for (unsigned short iNode = 0; iNode < nNeigh; iNode++) { + auto jPoint = geometry->nodes->GetPoint(iPoint, iNode); + auto coord_j = geometry->nodes->GetCoord(jPoint); + su2double dx = fabs(coord_i[0]-coord_j[0]); + su2double dy = fabs(coord_i[1]-coord_j[1]); + su2double dz = 0.0; + if (nDim == 3) dz = fabs(coord_i[2]-coord_j[2]); + if (dx > max_dx) max_dx = dx; + if (dy > max_dy) max_dy = dy; + if (dz > max_dz) max_dz = dz; + } + su2double dx2 = max_dx * max_dx; + su2double dy2 = max_dy * max_dy; + su2double dz2 = max_dz * max_dz; + su2double bx = b2 / dx2; + su2double by = b2 / dy2; + su2double bz = 0.0; + if (nDim == 3) bz = b2 / dz2; integral = RandomToolbox::GetBesselIntegral(bx, by, bz); nodes->SetBesselIntegral(iPoint, integral); } else { @@ -1836,33 +1837,34 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet var_check_new += source * source; nodes->SetLangevinSourceTerms(iPoint, iDim, source); } - su2double mean_check_old_G = 0.0; - su2double mean_check_new_G = 0.0; - su2double mean_check_notSmoothed_G = 0.0; - su2double var_check_old_G = 0.0; - su2double var_check_new_G = 0.0; - su2double var_check_notSmoothed_G = 0.0; - SU2_MPI::Allreduce(&mean_check_old, &mean_check_old_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - SU2_MPI::Allreduce(&mean_check_new, &mean_check_new_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - SU2_MPI::Allreduce(&mean_check_notSmoothed, &mean_check_notSmoothed_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - SU2_MPI::Allreduce(&var_check_old, &var_check_old_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - SU2_MPI::Allreduce(&var_check_new, &var_check_new_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - SU2_MPI::Allreduce(&var_check_notSmoothed, &var_check_notSmoothed_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - mean_check_old_G /= global_nPointLES; - var_check_old_G /= global_nPointLES; - var_check_old_G -= mean_check_old_G * mean_check_old_G; - mean_check_new_G /= global_nPointLES; - var_check_new_G /= global_nPointLES; - var_check_new_G -= mean_check_new_G * mean_check_new_G; - mean_check_notSmoothed_G /= global_nPointLES; - var_check_notSmoothed_G /= global_nPointLES; - var_check_notSmoothed_G -= mean_check_notSmoothed_G * mean_check_notSmoothed_G; - if (rank == MASTER_NODE) { - cout << "Mean of stochastic source term before scaling: " << mean_check_old_G-mean_check_notSmoothed_G <<". After scaling: " << mean_check_new_G-mean_check_notSmoothed_G << "." << endl; - cout << "Variance of stochastic source term before scaling: " << var_check_old_G/var_check_notSmoothed_G <<". After scaling: " << var_check_new_G/var_check_notSmoothed_G << "." << endl; - cout << endl; + if (config->GetStochSourceDiagnostics()) { + su2double mean_check_old_G = 0.0; + su2double mean_check_new_G = 0.0; + su2double mean_check_notSmoothed_G = 0.0; + su2double var_check_old_G = 0.0; + su2double var_check_new_G = 0.0; + su2double var_check_notSmoothed_G = 0.0; + SU2_MPI::Allreduce(&mean_check_old, &mean_check_old_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&mean_check_new, &mean_check_new_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&mean_check_notSmoothed, &mean_check_notSmoothed_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&var_check_old, &var_check_old_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&var_check_new, &var_check_new_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&var_check_notSmoothed, &var_check_notSmoothed_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + mean_check_old_G /= global_nPointLES; + var_check_old_G /= global_nPointLES; + var_check_old_G -= mean_check_old_G * mean_check_old_G; + mean_check_new_G /= global_nPointLES; + var_check_new_G /= global_nPointLES; + var_check_new_G -= mean_check_new_G * mean_check_new_G; + mean_check_notSmoothed_G /= global_nPointLES; + var_check_notSmoothed_G /= global_nPointLES; + var_check_notSmoothed_G -= mean_check_notSmoothed_G * mean_check_notSmoothed_G; + if (rank == MASTER_NODE) { + cout << "Mean of stochastic source term before scaling: " << mean_check_old_G-mean_check_notSmoothed_G <<". After scaling: " << mean_check_new_G-mean_check_notSmoothed_G << "." << endl; + cout << "Variance of stochastic source term before scaling: " << var_check_old_G/var_check_notSmoothed_G <<". After scaling: " << var_check_new_G/var_check_notSmoothed_G << "." << endl; + cout << endl; + } } - break; } diff --git a/config_template.cfg b/config_template.cfg index afca061f033..4d206f2e9b9 100644 --- a/config_template.cfg +++ b/config_template.cfg @@ -199,9 +199,15 @@ SBS_TIMESCALE_COEFF= 0.05 % Backscatter intensity coefficient (1.0) SBS_INTENSITY_COEFF= 1.0 % +% Relaxation factor for the stochastic source term in the main balance equations (0.0) +SBS_RELAXATION_FACTOR= 0.0 +% % Include stochastic source in turbulence model equation (NO, YES) STOCH_SOURCE_NU= YES % +% Include diagnostics of the stochastic source term in Langevin equations (NO, YES) +STOCH_SOURCE_DIAGNOSTICS= NO +% % Enforce LES mode in Hybrid RANS-LES Simulations (NO, YES) ENFORCE_LES= NO % From 443838f8022765a59972181d5328533d39689ff2 Mon Sep 17 00:00:00 2001 From: paan882 Date: Tue, 6 Jan 2026 16:13:17 +0100 Subject: [PATCH 26/70] Enhance numerical efficiency - Random generators removed from static variables. - Random generators re-initialized at every time step using deterministic seeds. --- Common/include/toolboxes/random_toolbox.hpp | 11 ++++---- .../numerics/turbulent/turb_sources.hpp | 6 +++-- .../include/solvers/CFVMFlowSolverBase.inl | 2 +- SU2_CFD/include/variables/CTurbSAVariable.hpp | 17 ------------ SU2_CFD/include/variables/CVariable.hpp | 16 ------------ SU2_CFD/src/solvers/CTurbSASolver.cpp | 26 +++++-------------- SU2_CFD/src/variables/CTurbSAVariable.cpp | 1 - 7 files changed, 17 insertions(+), 62 deletions(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index aa50baf1e7f..cf268b63bcb 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -57,9 +57,12 @@ inline unsigned long ToUInt64(double x) { return std::hash{}(x); } * \brief Build a deterministic seed from physical time. * \param[in] x First integer value. * \param[in] y Second integer value. + * \param[in] z Third integer value. * \return 64-bit seed value. */ -inline unsigned long GetSeed(unsigned long x, unsigned long y) { return HashCombine(x, y); } +inline unsigned long GetSeed(unsigned long x, unsigned long y, unsigned long z) { + return HashCombine(HashCombine(x, y), z); +} /*! * \brief Generate a standard normally-distributed random number. @@ -68,7 +71,7 @@ inline unsigned long GetSeed(unsigned long x, unsigned long y) { return HashComb * \param[in] stddev Standard deviation of the normal distribution (default 1). * \return Normally-distributed random number. */ -inline double GetRandomNormal(std::mt19937 gen, double mean = 0.0, double stddev = 1.0) { +inline double GetRandomNormal(std::mt19937& gen, double mean = 0.0, double stddev = 1.0) { std::normal_distribution rnd(mean, stddev); return rnd(gen); } @@ -80,7 +83,7 @@ inline double GetRandomNormal(std::mt19937 gen, double mean = 0.0, double stddev * \param[in] xmax Upper bounary of the interval (default 1). * \return Uniformly-distributed random number. */ -inline double GetRandomUniform(std::mt19937 gen, double xmin = 0.0, double xmax = 1.0) { +inline double GetRandomUniform(std::mt19937& gen, double xmin = 0.0, double xmax = 1.0) { std::uniform_real_distribution rnd(xmin, xmax); return rnd(gen); } @@ -135,8 +138,6 @@ inline double GetBesselIntegral(double beta_x, double beta_y, double beta_z) { for (int i = 1; i < N; i++) { double t = i * dt; - double e = exp(-A * t); - double lx = GetBesselZero(Bx * t); double ly = GetBesselZero(By * t); double lz = GetBesselZero(Bz * t); diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index f9cc15a146c..084a4fc087e 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -171,13 +171,15 @@ class CSourceBase_TurbSA : public CNumerics { inline void AddStochSource(const CSAVariables& var, const MatrixType& velGrad, const su2double Cmag) { su2double dist2 = dist_i * dist_i; - const su2double eps = 1.0e-12; + const su2double eps = 1e-10; su2double xi3 = pow(var.Ji, 3); su2double factor = dist2 / (2.0 * var.fv1 * ScalarVar_i[0] + eps); factor /= (3.0 * xi3 * var.cv1_3 / pow(xi3 + var.cv1_3, 2) + var.fv1 + eps); - su2double tke = pow(var.fv1*ScalarVar_i[0]/dist_i, 2); + su2double tke = 0.0; + if (dist_i >= eps) + tke = pow(var.fv1*ScalarVar_i[0]/dist_i, 2); su2double R12 = (nDim==3 ? Cmag * tke * ScalarVar_i[3] : 0.0); su2double R13 = - Cmag * tke * ScalarVar_i[2]; diff --git a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl index 1d7322f0e11..0293b3bf6d4 100644 --- a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl +++ b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl @@ -484,7 +484,7 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome DES_length_j = turbNodes->GetDES_LengthScale(jPoint); lesMode_i = turbNodes->GetLES_Mode(iPoint); lesMode_j = turbNodes->GetLES_Mode(jPoint); - const su2double tol = 1e-12; + const su2double tol = 1e-10; if (DES_length_i < tol || DES_length_j < tol) { tke_i = tke_j = 0.0; } else { diff --git a/SU2_CFD/include/variables/CTurbSAVariable.hpp b/SU2_CFD/include/variables/CTurbSAVariable.hpp index 4b625b90101..0d345b0611e 100644 --- a/SU2_CFD/include/variables/CTurbSAVariable.hpp +++ b/SU2_CFD/include/variables/CTurbSAVariable.hpp @@ -45,7 +45,6 @@ class CTurbSAVariable final : public CTurbVariable { MatrixType stochSource; MatrixType stochSource_old; VectorType Vortex_Tilting; - MatrixTypeGen stochGen; VectorType besselIntegral; public: @@ -136,22 +135,6 @@ class CTurbSAVariable final : public CTurbVariable { */ inline su2double GetVortex_Tilting(unsigned long iPoint) const override { return Vortex_Tilting(iPoint); } - /*! - * \brief Get the seed for the stochastic equations. - * \param[in] iPoint - Point index. - * \param[in] iDim - Dimension index. - * \return Value of the seed for the stochastic equations. - */ - inline std::mt19937 GetLangevinGen(unsigned long iPoint, unsigned short iDim) const override { return stochGen(iPoint, iDim); } - - /*! - * \brief Set the seed for the stochastic equations. - * \param[in] iPoint - Point index. - * \param[in] iDim - Dimension index. - * \param[in] val_stochGen - Value of the seed for the stochastic equations. - */ - inline void SetLangevinGen(unsigned long iPoint, unsigned short iDim, std::mt19937 val_stochGen) override { stochGen(iPoint, iDim) = val_stochGen; } - /*! * \brief Set the integral of the product of three Bessel functions appearing in Laplacian smoothing. * \param[in] iPoint - Point index. diff --git a/SU2_CFD/include/variables/CVariable.hpp b/SU2_CFD/include/variables/CVariable.hpp index 5a432dedcbb..68bf526ad8e 100644 --- a/SU2_CFD/include/variables/CVariable.hpp +++ b/SU2_CFD/include/variables/CVariable.hpp @@ -52,7 +52,6 @@ class CVariable { protected: using VectorType = C2DContainer; using MatrixType = C2DContainer; - using MatrixTypeGen = C2DContainer; MatrixType Solution; /*!< \brief Solution of the problem. */ MatrixType Solution_Old; /*!< \brief Old solution of the problem R-K. */ @@ -442,13 +441,6 @@ class CVariable { */ inline virtual void SetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim, su2double val_stochSource_old) {} - /*! - * \brief A virtual member. - * \param[in] iPoint - Point index. - * \param[in] iDim - Dimension index. - */ - inline virtual std::mt19937 GetLangevinGen(unsigned long iPoint, unsigned short iDim) const {std::mt19937 gen(123); return gen; } - /*! * \brief A virtual member. * \param[in] iPoint - Point index. @@ -461,14 +453,6 @@ class CVariable { */ inline virtual su2double GetBesselIntegral(unsigned long iPoint) const { return 0.0; } - /*! - * \brief A virtual member. - * \param[in] iPoint - Point index. - * \param[in] iDim - Dimension index. - * \param[in] val_stochGen - Pseudo-random number generator for Langevin equations. - */ - inline virtual void SetLangevinGen(unsigned long iPoint, unsigned short iDim, std::mt19937 val_stochGen) {} - /*! * \brief A virtual member. * \param[in] iPoint - Point index. diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 6b050fb3841..f04c95fb75b 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -242,7 +242,6 @@ void CTurbSASolver::Preprocessing(CGeometry *geometry, CSolver **solver_containe unsigned long restartIter = config->GetRestart_Iter(); if (backscatter && innerIter==0) { - SetLangevinGen(config, geometry); SetLangevinSourceTerms(config, geometry); const unsigned short maxIter = config->GetSBS_maxIterSmooth(); bool dual_time = ((config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) || @@ -443,7 +442,7 @@ void CTurbSASolver::Source_Residual(CGeometry *geometry, CSolver **solver_contai if (config->GetStochastic_Backscatter()) { for (unsigned short iDim = 0; iDim < nDim; iDim++) numerics->SetStochSource(nodes->GetLangevinSourceTerms(iPoint, iDim), iDim); - numerics->SetLES_Mode(nodes->GetLES_Mode(iPoint), 0.0); + numerics->SetLES_Mode(nodes->GetLES_Mode(iPoint), 0.0); } } @@ -1643,10 +1642,14 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) { + unsigned long timeIter = config->GetTimeIter(); + SU2_OMP_FOR_DYN(omp_chunk_size) for (auto iPoint = 0ul; iPoint < nPointDomain; iPoint++){ + const auto iGlobalPoint = geometry->nodes->GetGlobalIndex(iPoint); for (auto iDim = 0u; iDim < nDim; iDim++){ - auto gen = nodes->GetLangevinGen(iPoint, iDim); + unsigned long seed = RandomToolbox::GetSeed(iGlobalPoint+1, iDim+1, timeIter+1); + std::mt19937 gen(seed); su2double lesSensor = nodes->GetLES_Mode(iPoint); su2double rnd = RandomToolbox::GetRandomNormal(gen) * std::nearbyint(lesSensor); nodes->SetLangevinSourceTermsOld(iPoint, iDim, rnd); @@ -1657,23 +1660,6 @@ void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) } -void CTurbSASolver::SetLangevinGen(CConfig* config, CGeometry* geometry) { - - unsigned long timeStep = config->GetTimeIter(); - - SU2_OMP_FOR_DYN(omp_chunk_size) - for (auto iPoint = 0ul; iPoint < nPointDomain; iPoint++){ - const auto iGlobalPoint = geometry->nodes->GetGlobalIndex(iPoint); - for (auto iDim = 0u; iDim < nDim; iDim++){ - unsigned long seed = RandomToolbox::GetSeed(iGlobalPoint+1,iDim+1); - std::mt19937 gen(seed + timeStep); - nodes->SetLangevinGen(iPoint, iDim, gen); - } - } - END_SU2_OMP_FOR - -} - void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geometry) { const su2double LES_FilterWidth = config->GetLES_FilterWidth(); diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index 384cc70e51c..26f150cc711 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -61,7 +61,6 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi Vortex_Tilting.resize(nPoint); stochSource.resize(nPoint, nDim) = su2double(0.0); stochSource_old.resize(nPoint, nDim) = su2double(0.0); - stochGen.resize(nPoint, nDim); besselIntegral.resize(nPoint); } From fb3f8ec6d979b9ed36e0ffb1867e3286f7f03b71 Mon Sep 17 00:00:00 2001 From: paan882 Date: Thu, 8 Jan 2026 18:15:01 +0100 Subject: [PATCH 27/70] Fix bug in viscous flux computation - Account for zero DES length scale in ghost cells. - Fix threshold (=0.9) for the activation of the backscatter model. --- SU2_CFD/include/numerics/CNumerics.hpp | 26 +++---- .../numerics/turbulent/turb_sources.hpp | 72 +++++++++---------- .../include/solvers/CFVMFlowSolverBase.inl | 27 ++++--- SU2_CFD/include/solvers/CTurbSASolver.hpp | 7 -- SU2_CFD/src/numerics/flow/flow_diffusion.cpp | 24 +++---- SU2_CFD/src/output/CFlowOutput.cpp | 24 ++++--- SU2_CFD/src/solvers/CTurbSASolver.cpp | 15 ++-- 7 files changed, 94 insertions(+), 101 deletions(-) diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index cacc6b35658..8f9d121095f 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -660,24 +660,20 @@ class CNumerics { * \param[out] stochReynStress - Stochastic tensor (to be added to the Reynolds stress tensor). */ template - NEVERINLINE static void ComputeStochReynStress(size_t nDim, Scalar density, Scalar eddyVis, - Scalar turbKE, Vector rndVec, Scalar lesSensor, - Mat& stochReynStress, Scalar Cmag) { + NEVERINLINE static void ComputeStochReynStress(size_t nDim, Scalar density, Scalar tke, + Vector rndVec, Mat& stochReynStress, Scalar Cmag) { /* --- Calculate stochastic tensor --- */ - stochReynStress[1][0] = - std::nearbyint(lesSensor) * Cmag * density * turbKE * rndVec[2]; - stochReynStress[2][0] = std::nearbyint(lesSensor) * Cmag * density * turbKE * rndVec[1]; - stochReynStress[2][1] = - std::nearbyint(lesSensor) * Cmag * density * turbKE * rndVec[0]; - for (size_t iDim = 0; iDim < nDim; iDim++) { - for (size_t jDim = 0; jDim <= iDim; jDim++) { - if (iDim==jDim) { - stochReynStress[iDim][jDim] = 0.0; - } else { - stochReynStress[jDim][iDim] = - stochReynStress[iDim][jDim]; - } - } - } + stochReynStress[0][0] = 0.0; + stochReynStress[1][1] = 0.0; + stochReynStress[2][2] = 0.0; + stochReynStress[0][1] = Cmag * density * tke * rndVec[2]; + stochReynStress[0][2] = - Cmag * density * tke * rndVec[1]; + stochReynStress[1][2] = Cmag * density * tke * rndVec[0]; + stochReynStress[1][0] = - stochReynStress[1][0]; + stochReynStress[2][0] = - stochReynStress[2][0]; + stochReynStress[2][1] = - stochReynStress[2][1]; } diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index 084a4fc087e..ae05251f458 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -123,44 +123,47 @@ class CSourceBase_TurbSA : public CNumerics { const su2double& nue = ScalarVar_i[0]; const auto& density = V_i[idx.Density()]; + const su2double threshold = 0.9; + const su2double nut = max(nue*var.fv1, 1e-10); + const su2double delta = lengthScale/DES_const; - const su2double nut_small = 1.0e-12; - - const su2double nut = max(nue * var.fv1, nut_small); - - su2double tLES = ct * pow(lengthScale/DES_const, 2) / nut; - su2double tRANS = pow(lengthScale, 2) / nut; - su2double tLR = tLES / tRANS; - su2double tTurb = tLES / (lesMode_i + (1.0-lesMode_i)*tLR); - su2double tRat = timeStep / tTurb; - - su2double corrFac = 1.0; - if (time_marching == TIME_MARCHING::DT_STEPPING_2ND) { - corrFac = sqrt(0.5*(1.0+tRat)*(4.0+tRat)/(2.0+tRat)); - } else if (time_marching == TIME_MARCHING::DT_STEPPING_1ST) { - corrFac = sqrt(1.0+0.5*tRat); + for (unsigned short iVar = 0; iVar < nVar; iVar++ ) { + ResidSB[iVar] = 0.0; } - - su2double scaleFactor = 0.0; - if (std::nearbyint(lesMode_i) == 1) scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * density * corrFac; - ResidSB[0] = Residual; - for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { - ResidSB[iVar] = scaleFactor * stochSource[iVar-1] - 1.0/tTurb * density * ScalarVar_i[iVar]; - ResidSB[iVar] *= Volume; - } for (unsigned short iVar = 0; iVar < nVar; iVar++ ) { for (unsigned short jVar = 0; jVar < nVar; jVar++ ) { JacobianSB_i[iVar][jVar] = 0.0; } } + JacobianSB_i[0][0] = Jacobian_i[0]; - for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { - JacobianSB_i[iVar][iVar] = -1.0/tTurb * density * Volume; - } + if (delta > 1e-10) { - JacobianSB_i[0][0] = Jacobian_i[0]; + su2double tTurb = ct*pow(delta, 2)/nut; + su2double tRat = timeStep / tTurb; + + su2double corrFac = 1.0; + if (time_marching == TIME_MARCHING::DT_STEPPING_2ND) { + corrFac = sqrt(0.5*(1.0+tRat)*(4.0+tRat)/(2.0+tRat)); + } else if (time_marching == TIME_MARCHING::DT_STEPPING_1ST) { + corrFac = sqrt(1.0+0.5*tRat); + } + + su2double scaleFactor = 0.0; + if (lesMode_i > threshold) scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * density * corrFac; + + for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { + ResidSB[iVar] = scaleFactor * stochSource[iVar-1] - 1.0/tTurb * density * ScalarVar_i[iVar]; + ResidSB[iVar] *= Volume; + } + + for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { + JacobianSB_i[iVar][iVar] = -1.0/tTurb * density * Volume; + } + + } } @@ -171,15 +174,13 @@ class CSourceBase_TurbSA : public CNumerics { inline void AddStochSource(const CSAVariables& var, const MatrixType& velGrad, const su2double Cmag) { su2double dist2 = dist_i * dist_i; - const su2double eps = 1e-10; su2double xi3 = pow(var.Ji, 3); - - su2double factor = dist2 / (2.0 * var.fv1 * ScalarVar_i[0] + eps); - factor /= (3.0 * xi3 * var.cv1_3 / pow(xi3 + var.cv1_3, 2) + var.fv1 + eps); + su2double factor = dist2 / (2.0 * var.fv1 * ScalarVar_i[0]); + factor /= (3.0 * xi3 * var.cv1_3 / pow(xi3 + var.cv1_3, 2) + var.fv1); su2double tke = 0.0; - if (dist_i >= eps) - tke = pow(var.fv1*ScalarVar_i[0]/dist_i, 2); + const su2double threshold = 0.9; + if (lesMode_i > threshold) tke = pow(var.fv1*ScalarVar_i[0]/dist_i, 2); su2double R12 = (nDim==3 ? Cmag * tke * ScalarVar_i[3] : 0.0); su2double R13 = - Cmag * tke * ScalarVar_i[2]; @@ -368,9 +369,8 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Compute residual for Langevin equations (Stochastic Backscatter Model). ---*/ if (backscatter) { - if (std::nearbyint(lesMode_i) == 1 && config->GetStochSourceNu()) { + if (config->GetStochSourceNu()) { su2double SBS_Cmag = config->GetSBS_Cmag(); - su2double lesSensor = max(lesMode_i, lesMode_j); su2double SBS_RelaxFactor = config->GetStochSourceRelax(); su2double intensityCoeff = SBS_Cmag; if (SBS_RelaxFactor > 0.0) { @@ -381,7 +381,7 @@ class CSourceBase_TurbSA : public CNumerics { unsigned long restartIter = config->GetRestart_Iter(); su2double timeStep = config->GetTime_Step(); su2double currentTime = (timeIter - restartIter) * timeStep; - intensityCoeff = SBS_Cmag * (1.0 - exp(-SBS_RelaxFactor * currentTime / timeScale)); + intensityCoeff = SBS_Cmag * (1.0 - exp(- currentTime / (timeScale*SBS_RelaxFactor))); } AddStochSource(var, PrimVar_Grad_i + idx.Velocity(), intensityCoeff); } diff --git a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl index 0293b3bf6d4..673c037aef0 100644 --- a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl +++ b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl @@ -475,24 +475,21 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome numerics->SetStochVar(turbNodes->GetSolution(iPoint, 1 + iDim), turbNodes->GetSolution(jPoint, 1 + iDim), iDim); } - su2double rho, eddy_visc_i, eddy_visc_j, DES_length_i, - DES_length_j, tke_i, tke_j, lesMode_i, lesMode_j; - rho = nodes->GetDensity(iPoint); - eddy_visc_i = turbNodes->GetmuT(iPoint) / rho; - eddy_visc_j = turbNodes->GetmuT(jPoint) / rho; - DES_length_i = turbNodes->GetDES_LengthScale(iPoint); - DES_length_j = turbNodes->GetDES_LengthScale(jPoint); - lesMode_i = turbNodes->GetLES_Mode(iPoint); - lesMode_j = turbNodes->GetLES_Mode(jPoint); - const su2double tol = 1e-10; - if (DES_length_i < tol || DES_length_j < tol) { - tke_i = tke_j = 0.0; - } else { + su2double rho = nodes->GetDensity(iPoint); + su2double eddy_visc_i = turbNodes->GetmuT(iPoint) / rho; + su2double eddy_visc_j = turbNodes->GetmuT(jPoint) / rho; + su2double DES_length_i = turbNodes->GetDES_LengthScale(iPoint); + su2double DES_length_j = turbNodes->GetDES_LengthScale(jPoint); + su2double lesMode_i = (DES_length_i > 1e-10) ? turbNodes->GetLES_Mode(iPoint) : 0.0; + su2double lesMode_j = (DES_length_j > 1e-10) ? turbNodes->GetLES_Mode(jPoint) : 0.0; + const su2double threshold = 0.9; + su2double tke_i = 0.0, tke_j = 0.0; + if (max(lesMode_i, lesMode_j) > threshold) { tke_i = pow(eddy_visc_i/DES_length_i, 2); - tke_j = pow(eddy_visc_j/DES_length_j, 2); + tke_j = tke_i; + if (geometry->nodes->GetDomain(jPoint)) tke_j = pow(eddy_visc_j/DES_length_j, 2); } numerics->SetTurbKineticEnergy(tke_i, tke_j); - numerics->SetLES_Mode(lesMode_i, lesMode_j); } /*--- Wall shear stress values (wall functions) ---*/ diff --git a/SU2_CFD/include/solvers/CTurbSASolver.hpp b/SU2_CFD/include/solvers/CTurbSASolver.hpp index 0aaf5022546..71004ee5504 100644 --- a/SU2_CFD/include/solvers/CTurbSASolver.hpp +++ b/SU2_CFD/include/solvers/CTurbSASolver.hpp @@ -64,13 +64,6 @@ class CTurbSASolver final : public CTurbSolver { */ void SetLangevinSourceTerms(CConfig *config, CGeometry* geometry); - /*! - * \brief Set seed for Langevin equations (Stochastic Backscatter Model). - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition. - */ - void SetLangevinGen(CConfig* config, CGeometry* geometry); - /*! * \brief Apply Laplacian smoothing to the source terms in Langevin equations (Stochastic Backscatter Model). * \param[in] config - Definition of the particular problem. diff --git a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp index 902b8a6f0f0..be11dabccdc 100644 --- a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp +++ b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp @@ -146,8 +146,9 @@ void CAvgGrad_Base::SetStressTensor(const su2double *val_primvar, if (config->GetStochastic_Backscatter()) { for (unsigned short iDim = 0 ; iDim < nDim; iDim++) - for (unsigned short jDim = 0 ; jDim < nDim; jDim++) + for (unsigned short jDim = 0 ; jDim < nDim; jDim++) { tau[iDim][jDim] += stochReynStress[iDim][jDim]; + } } } @@ -461,7 +462,6 @@ CNumerics::ResidualType<> CAvgGrad_Flow::ComputeResidual(const CConfig* config) for (iVar = 0; iVar < nDim; iVar++) Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); su2double SBS_Cmag = config->GetSBS_Cmag(); - su2double lesSensor = max(lesMode_i, lesMode_j); su2double SBS_RelaxFactor = config->GetStochSourceRelax(); su2double intensityCoeff = SBS_Cmag; if (SBS_RelaxFactor > 0.0) { @@ -472,10 +472,10 @@ CNumerics::ResidualType<> CAvgGrad_Flow::ComputeResidual(const CConfig* config) unsigned long restartIter = config->GetRestart_Iter(); su2double timeStep = config->GetTime_Step(); su2double currentTime = (timeIter - restartIter) * timeStep; - intensityCoeff = SBS_Cmag * (1.0 - exp(-SBS_RelaxFactor * currentTime / timeScale)); + intensityCoeff = SBS_Cmag * (1.0 - exp(- currentTime / (timeScale*SBS_RelaxFactor))); } - ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_turb_ke, - Mean_StochVar, lesSensor, stochReynStress, intensityCoeff); + ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_turb_ke, + Mean_StochVar, stochReynStress, intensityCoeff); } /*--- Get projected flux tensor (viscous residual) ---*/ @@ -658,7 +658,6 @@ CNumerics::ResidualType<> CAvgGradInc_Flow::ComputeResidual(const CConfig* confi for (iVar = 0; iVar < nDim; iVar++) Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); su2double SBS_Cmag = config->GetSBS_Cmag(); - su2double lesSensor = max(lesMode_i, lesMode_j); su2double SBS_RelaxFactor = config->GetStochSourceRelax(); su2double intensityCoeff = SBS_Cmag; if (SBS_RelaxFactor > 0.0) { @@ -669,10 +668,10 @@ CNumerics::ResidualType<> CAvgGradInc_Flow::ComputeResidual(const CConfig* confi unsigned long restartIter = config->GetRestart_Iter(); su2double timeStep = config->GetTime_Step(); su2double currentTime = (timeIter - restartIter) * timeStep; - intensityCoeff = SBS_Cmag * (1.0 - exp(-SBS_RelaxFactor * currentTime / timeScale)); + intensityCoeff = SBS_Cmag * (1.0 - exp(- currentTime / (timeScale*SBS_RelaxFactor))); } - ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_turb_ke, - Mean_StochVar, lesSensor, stochReynStress, intensityCoeff); + ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_turb_ke, + Mean_StochVar, stochReynStress, intensityCoeff); } /*--- Get projected flux tensor (viscous residual) ---*/ @@ -1007,7 +1006,6 @@ CNumerics::ResidualType<> CGeneralAvgGrad_Flow::ComputeResidual(const CConfig* c for (iVar = 0; iVar < nDim; iVar++) Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); su2double SBS_Cmag = config->GetSBS_Cmag(); - su2double lesSensor = max(lesMode_i, lesMode_j); su2double SBS_RelaxFactor = config->GetStochSourceRelax(); su2double intensityCoeff = SBS_Cmag; if (SBS_RelaxFactor > 0.0) { @@ -1018,10 +1016,10 @@ CNumerics::ResidualType<> CGeneralAvgGrad_Flow::ComputeResidual(const CConfig* c unsigned long restartIter = config->GetRestart_Iter(); su2double timeStep = config->GetTime_Step(); su2double currentTime = (timeIter - restartIter) * timeStep; - intensityCoeff = SBS_Cmag * (1.0 - exp(-SBS_RelaxFactor * currentTime / timeScale)); + intensityCoeff = SBS_Cmag * (1.0 - exp(- currentTime / (timeScale*SBS_RelaxFactor))); } - ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, Mean_turb_ke, - Mean_StochVar, lesSensor, stochReynStress, intensityCoeff); + ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_turb_ke, + Mean_StochVar, stochReynStress, intensityCoeff); } /*--- Get projected flux tensor (viscous residual) ---*/ diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index 44338b645a5..1331363a90f 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -1631,16 +1631,18 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con if (nDim==3) SetVolumeOutputValue("STOCHSOURCE_Z", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 2)); const su2double rho = Node_Flow->GetDensity(iPoint); const su2double nu_t = Node_Flow->GetEddyViscosity(iPoint) / rho; - const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1.0E-10); + const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1e-10); const su2double lesSensor = Node_Flow->GetLES_Mode(iPoint); const su2double mag = config->GetSBS_Cmag(); - const su2double tke_estim = pow(nu_t/DES_lengthscale, 2.0); + const su2double threshold = 0.9; + su2double tke_estim = 0.0; + if (lesSensor > threshold) tke_estim = pow(nu_t/DES_lengthscale, 2.0); const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); const su2double csi_y = Node_Turb->GetSolution(iPoint, 2); const su2double csi_z = (nDim==3) ? Node_Turb->GetSolution(iPoint, 3) : 0.0; - const su2double R_xy = mag * tke_estim * csi_z * std::nearbyint(lesSensor); - const su2double R_xz = - mag * tke_estim * csi_y * std::nearbyint(lesSensor); - const su2double R_yz = mag * tke_estim * csi_x * std::nearbyint(lesSensor); + const su2double R_xy = mag * tke_estim * csi_z; + const su2double R_xz = - mag * tke_estim * csi_y; + const su2double R_yz = mag * tke_estim * csi_x; const auto vel_grad = Node_Flow->GetVelocityGradient(iPoint); const su2double vel_div = vel_grad(0,0) + vel_grad(1,1) + (nDim ==3 ? vel_grad(2,2) : 0.0); const su2double tau_xx = nu_t * (2*vel_grad(0,0) - (2.0/3.0)*vel_div); @@ -1685,16 +1687,18 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_23", iPoint, -tau_yz); } if (config->GetKind_HybridRANSLES()!=NO_HYBRIDRANSLES && config->GetStochastic_Backscatter()) { - const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1.0E-10); + const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1e-10); const su2double lesSensor = Node_Flow->GetLES_Mode(iPoint); const su2double mag = config->GetSBS_Cmag(); - const su2double tke_estim = pow(nu_t/DES_lengthscale, 2.0); + const su2double threshold = 0.9; + su2double tke_estim = 0.0; + if (lesSensor > threshold) tke_estim = pow(nu_t/DES_lengthscale, 2.0); const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); const su2double csi_y = Node_Turb->GetSolution(iPoint, 2); const su2double csi_z = (nDim==3) ? Node_Turb->GetSolution(iPoint, 3) : 0.0; - const su2double R_xy = mag * tke_estim * csi_z * std::nearbyint(lesSensor); - const su2double R_xz = - mag * tke_estim * csi_y * std::nearbyint(lesSensor); - const su2double R_yz = mag * tke_estim * csi_x * std::nearbyint(lesSensor); + const su2double R_xy = mag * tke_estim * csi_z; + const su2double R_xz = - mag * tke_estim * csi_y; + const su2double R_yz = mag * tke_estim * csi_x; SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_12", iPoint, -R_xy); SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_13", iPoint, -R_xz); SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_23", iPoint, -R_yz); diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index f04c95fb75b..ff3115ab8c8 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1643,15 +1643,19 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) { unsigned long timeIter = config->GetTimeIter(); + const su2double threshold = 0.9; SU2_OMP_FOR_DYN(omp_chunk_size) for (auto iPoint = 0ul; iPoint < nPointDomain; iPoint++){ - const auto iGlobalPoint = geometry->nodes->GetGlobalIndex(iPoint); + const auto coord = geometry->nodes->GetCoord(iPoint); + su2double coordSum = (coord[0] + coord[1] + ((nDim == 3) ? coord[2] : 0.0)) * 1e6; + unsigned long coordHash = std::nearbyint(coordSum); for (auto iDim = 0u; iDim < nDim; iDim++){ - unsigned long seed = RandomToolbox::GetSeed(iGlobalPoint+1, iDim+1, timeIter+1); + unsigned long seed = RandomToolbox::GetSeed(coordHash, iDim+1, timeIter+1); std::mt19937 gen(seed); su2double lesSensor = nodes->GetLES_Mode(iPoint); - su2double rnd = RandomToolbox::GetRandomNormal(gen) * std::nearbyint(lesSensor); + su2double rnd = 0.0; + if (lesSensor > threshold) rnd = RandomToolbox::GetRandomNormal(gen); nodes->SetLangevinSourceTermsOld(iPoint, iDim, rnd); nodes->SetLangevinSourceTerms(iPoint, iDim, rnd); } @@ -1671,6 +1675,7 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet const su2double omega = 0.8; unsigned long timeIter = config->GetTimeIter(); unsigned long restartIter = config->GetRestart_Iter(); + const su2double threshold = 0.9; /*--- Start SOR algorithm for the Laplacian smoothing. ---*/ @@ -1689,7 +1694,7 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet SU2_OMP_FOR_DYN(omp_chunk_size) for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { const su2double lesSensor = nodes->GetLES_Mode(iPoint); - if (std::nearbyint(lesSensor) == 0.0) continue; + if (lesSensor < threshold) continue; local_nPointLES += 1; const su2double DES_LengthScale = nodes->GetDES_LengthScale(iPoint); su2double maxDelta = DES_LengthScale / constDES; @@ -1774,7 +1779,7 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet su2double mean_check_notSmoothed = 0.0; for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { const su2double lesSensor = nodes->GetLES_Mode(iPoint); - if (std::nearbyint(lesSensor) == 0.0) continue; + if (lesSensor < threshold) continue; su2double source = nodes->GetLangevinSourceTerms(iPoint, iDim); su2double source_notSmoothed = nodes->GetLangevinSourceTermsOld(iPoint, iDim); mean_check_old += source; From 77de85b1fbb64d648858ad12685cd79d7a198f90 Mon Sep 17 00:00:00 2001 From: paan882 Date: Tue, 27 Jan 2026 12:30:11 +0100 Subject: [PATCH 28/70] First major revision - Add LD2 scheme to CONV_NUM_METHOD enum. - Change scaling of the backscatter term. - Increase the size of residual and Jacobian in turb_sources.hpp. - Remove dynamic allocation in CTurbSASolver.cpp. - Add helper function to compute relaxed backscatter intensity coefficient. - Include pressure extrapolation in LD2 scheme formulation. - Make code style homogeneous. --- Common/include/CConfig.hpp | 9 +- Common/include/option_structure.hpp | 4 +- Common/include/toolboxes/random_toolbox.hpp | 124 +++++++------- Common/src/CConfig.cpp | 30 ++-- SU2_CFD/include/numerics/CNumerics.hpp | 45 ++++- .../numerics/scalar/scalar_convection.hpp | 6 +- .../numerics/turbulent/turb_convection.hpp | 11 +- .../numerics/turbulent/turb_sources.hpp | 154 ++++++------------ .../include/numerics_simd/CNumericsSIMD.cpp | 1 + .../include/solvers/CFVMFlowSolverBase.inl | 19 +-- SU2_CFD/include/solvers/CTurbSASolver.hpp | 26 +-- SU2_CFD/include/solvers/CTurbSolver.hpp | 1 - SU2_CFD/include/variables/CIncNSVariable.hpp | 6 +- SU2_CFD/include/variables/CNEMONSVariable.hpp | 2 +- SU2_CFD/include/variables/CNSVariable.hpp | 6 +- SU2_CFD/include/variables/CTurbSAVariable.hpp | 12 +- SU2_CFD/include/variables/CTurbVariable.hpp | 15 ++ SU2_CFD/include/variables/CVariable.hpp | 15 -- SU2_CFD/src/drivers/CDriver.cpp | 1 + .../src/numerics/flow/convection/centered.cpp | 8 +- SU2_CFD/src/numerics/flow/flow_diffusion.cpp | 68 +++----- SU2_CFD/src/output/CFlowCompOutput.cpp | 9 - SU2_CFD/src/output/CFlowIncOutput.cpp | 9 - SU2_CFD/src/output/CFlowOutput.cpp | 53 +++--- SU2_CFD/src/solvers/CIncEulerSolver.cpp | 6 +- SU2_CFD/src/solvers/CTurbSASolver.cpp | 109 +++++++------ SU2_CFD/src/variables/CIncNSVariable.cpp | 2 +- SU2_CFD/src/variables/CNEMONSVariable.cpp | 2 +- SU2_CFD/src/variables/CNSVariable.cpp | 2 +- SU2_CFD/src/variables/CTurbSAVariable.cpp | 6 +- config_template.cfg | 5 +- 31 files changed, 339 insertions(+), 427 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index a18d6584246..46a557e17c2 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -1107,7 +1107,6 @@ class CConfig { su2double stochSourceRelax; /*!< \brief Relaxation factor for stochastic source term generation (Stochastic Backscatter Model). */ bool enforceLES; /*!< \brief Option to enforce LES mode in hybrid RANS-LES simulations. */ su2double LES_FilterWidth; /*!< \brief LES filter width for hybrid RANS-LES simulations. */ - bool LD2_Scheme; /*!< \brief Use the LD2 scheme (incompressible flows, combined with JST discretization). */ unsigned short Kind_RoeLowDiss; /*!< \brief Kind of Roe scheme with low dissipation for unsteady flows. */ unsigned short nSpanWiseSections; /*!< \brief number of span-wise sections */ @@ -9642,12 +9641,6 @@ class CConfig { */ su2double GetLES_FilterWidth(void) const { return LES_FilterWidth; } - /*! - * \brief Get if the LD2 scheme must be employed (incompressible flows, combined with JST discretization). - * \return TRUE if LD2 scheme is enabled. - */ - bool GetLD2_Scheme(void) const { return LD2_Scheme; } - /*! * \brief Get the Kind of Roe Low Dissipation Scheme for Unsteady flows. * \return Value of Low dissipation approach. @@ -9670,7 +9663,7 @@ class CConfig { * \brief Get the SBS timescale coefficient. * \return Value of SBS timescale coefficient. */ - su2double GetSBS_maxIterSmooth(void) const { return SBS_maxIterSmooth; } + unsigned short GetSBS_maxIterSmooth(void) const { return SBS_maxIterSmooth; } /*! * \brief Get the SBS timescale coefficient. diff --git a/Common/include/option_structure.hpp b/Common/include/option_structure.hpp index 9f9f851c714..548871ba9d1 100644 --- a/Common/include/option_structure.hpp +++ b/Common/include/option_structure.hpp @@ -820,7 +820,8 @@ enum class CENTERED { JST, /*!< \brief Jameson-Smith-Turkel centered numerical method. */ LAX, /*!< \brief Lax-Friedrich centered numerical method. */ JST_MAT, /*!< \brief JST with matrix dissipation. */ - JST_KE /*!< \brief Kinetic Energy preserving Jameson-Smith-Turkel centered numerical method. */ + JST_KE, /*!< \brief Kinetic Energy preserving Jameson-Smith-Turkel centered numerical method. */ + LD2 /*!< \brief Low-Dissipation Low-Dispersion (LD2) centered scheme. */ }; static const MapType Centered_Map = { MakePair("NONE", CENTERED::NONE) @@ -828,6 +829,7 @@ static const MapType Centered_Map = { MakePair("JST_KE", CENTERED::JST_KE) MakePair("JST_MAT", CENTERED::JST_MAT) MakePair("LAX-FRIEDRICH", CENTERED::LAX) + MakePair("LD2", CENTERED::LD2) }; diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index cf268b63bcb..0249e1c5076 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -25,67 +25,80 @@ */ #pragma once - -#include -#include +#include namespace RandomToolbox { /// \addtogroup RandomToolbox /// @{ /*! - * \brief Combine two 64-bit integers into a single hash value. - * \param[in] v1 Current hash value. - * \param[in] v2 Value to mix in. - * \return Combined hash value. + * \brief SplitMix64 hash function for 64-bit integers. + * \param[in] x Input value to hash. + * \return Hashed 64-bit output. */ -inline unsigned long HashCombine(unsigned long v1, unsigned long v2) { - const unsigned long prime = 1099511628211ULL; - v1 ^= v2; - v1 *= prime; - return v1; +static inline uint64_t splitmix64(uint64_t x) { + x += 0x9e3779b97f4a7c15ULL; // golden ratio offset + x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL; // first mixing step + x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL; // second mixing step + return x ^ (x >> 31); // final avalanche } /*! - * \brief Convert a double to a 64-bit integer suitable for hashing. - * \param[in] x Double to integer. - * \return Hash value of the double (not portable). + * \brief Generate a deterministic 64-bit hash from three integers. + * \param[in] nodeIndex Global node index. + * \param[in] iDim Dimension index. + * \param[in] timeIter Current time iteration of the simulation. + * \return 64-bit hash value. */ -inline unsigned long ToUInt64(double x) { return std::hash{}(x); } +inline uint64_t GetHash(unsigned long nodeIndex, unsigned short iDim, unsigned long timeIter) { + uint64_t x = nodeIndex; + x ^= splitmix64(iDim); + x ^= splitmix64(timeIter); + return splitmix64(x); +} /*! - * \brief Build a deterministic seed from physical time. - * \param[in] x First integer value. - * \param[in] y Second integer value. - * \param[in] z Third integer value. - * \return 64-bit seed value. + * \brief Convert a 64-bit hash into a uniform double in (0,1]. + * Uses the top 53 bits of the hash to fill the mantissa of a double. + * Ensures the result is never zero, suitable for Box-Muller transform. + * \param[in] x 64-bit hash. + * \return Uniform double in the interval (0,1]. */ -inline unsigned long GetSeed(unsigned long x, unsigned long y, unsigned long z) { - return HashCombine(HashCombine(x, y), z); +inline double HashToUniform(uint64_t x) { + constexpr double inv53 = 1.0 / 9007199254740992.0; // 1/2^53 + uint64_t uInt = x >> 11; // top 53 bits + return (uInt + 1) * inv53; // map to (0,1] } /*! - * \brief Generate a standard normally-distributed random number. - * \param[in] gen Pseudo-random number generator. - * \param[in] mean Mean of the normal distribution (default 0). - * \param[in] stddev Standard deviation of the normal distribution (default 1). - * \return Normally-distributed random number. + * \brief Generate a standard normal random number from a 64-bit hash. + * Uses two deterministic uniforms derived from the hash and its bitwise NOT + * as inputs to the Box-Muller transform. + * \param[in] x 64-bit hash. + * \return Standard normal random number (mean=0, stddev=1). */ -inline double GetRandomNormal(std::mt19937& gen, double mean = 0.0, double stddev = 1.0) { - std::normal_distribution rnd(mean, stddev); - return rnd(gen); +inline double HashToNormal(uint64_t x) { + constexpr double pi = 3.14159265358979323846; + double u = HashToUniform(x); // first uniform + double v = HashToUniform(~x); // second uniform (bitwise NOT) + double r = sqrt(-2.0 * log(u)); + double theta = 2.0 * pi * v; + return r * cos(theta); // one normal sample } /*! - * \brief Generate a uniformly-distributed random number. - * \param[in] gen Pseudo-random number generator. - * \param[in] xmin Lower boundary of the interval (default 0). - * \param[in] xmax Upper bounary of the interval (default 1). - * \return Uniformly-distributed random number. + * \brief Generate a deterministic standard normal number for a cell, dimension, and timestep. + * + * Combines hashing and Box-Muller in one function. + * + * \param[in] nodeIndex Global node index. + * \param[in] dim Dimension index. + * \param[in] timeIter Simulation timestep (1-based). + * \return Standard normal random number. */ -inline double GetRandomUniform(std::mt19937& gen, double xmin = 0.0, double xmax = 1.0) { - std::uniform_real_distribution rnd(xmin, xmax); - return rnd(gen); +inline double GetNormal(unsigned long nodeIndex, unsigned long dim, unsigned long timeIter) { + uint64_t hash = GetHash(nodeIndex, dim, timeIter); + return HashToNormal(hash); } /*! @@ -95,29 +108,20 @@ inline double GetRandomUniform(std::mt19937& gen, double xmin = 0.0, double xmax */ inline double GetBesselZero(double x) { double abx = fabs(x); - if (abx < 3.75) { - double t = x / 3.75; - double p = - 1.0 + - t * t * - (3.5156229 + - t * t * (3.0899424 + t * t * (1.2067492 + t * t * (0.2659732 + t * t * (0.0360768 + t * t * 0.0045813))))); + double t = abx / 3.75; + double p = 1.0 + t * t * (3.5156229 + t * t * (3.0899424 + t * t * (1.2067492 + t * t * (0.2659732 + t * t * (0.0360768 + t * t * 0.0045813))))); return log(p); } else { double t = 3.75 / abx; - double poly = - 0.39894228 + - t * (0.01328592 + - t * (0.00225319 + - t * (-0.00157565 + - t * (0.00916281 + t * (-0.02057706 + t * (0.02635537 + t * (-0.01647633 + t * 0.00392377))))))); + double poly = 0.39894228 + t * (0.01328592 + t * (0.00225319 + t * (-0.00157565 + t * (0.00916281 + t * (-0.02057706 + t * (0.02635537 + t * (-0.01647633 + t * 0.00392377))))))); return abx - 0.5 * log(abx) + log(poly); } } /*! - * \brief Compute integral involving product of three modified Bessel functions. + * \brief Compute integral involving the product of three modified Bessel functions. + * Useful for scaling the smoothed stochastic source terms in Langevin equations. * \param[in] beta_x Argument in x-direction. * \param[in] beta_y Argument in y-direction. * \param[in] beta_z Argument in z-direction. @@ -128,28 +132,22 @@ inline double GetBesselIntegral(double beta_x, double beta_y, double beta_z) { const double Bx = 2.0 * beta_x; const double By = 2.0 * beta_y; const double Bz = 2.0 * beta_z; - const int N = 4000; - const double t_max = 40.0; + const double t_max = 20.0; const double dt = t_max / N; - double sum = 0.0; - - for (int i = 1; i < N; i++) { + for (int i = 1; i <= N; i++) { double t = i * dt; - double lx = GetBesselZero(Bx * t); double ly = GetBesselZero(By * t); double lz = GetBesselZero(Bz * t); - double lin = log(t) - A * t + lx + ly + lz; - double integrand = exp(lin); + if (i==N) integrand *= 0.5; sum += integrand; } - return sum * dt; } /// @} -} // namespace RandomToolbox +} // namespace RandomToolbox \ No newline at end of file diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 3c737ec34b1..f9673d4ae15 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2993,9 +2993,6 @@ void CConfig::SetConfig_Options() { /* DESCRIPTION: Filter width for LES (if negative, it is computed based on the local cell size) */ addDoubleOption("LES_FILTER_WIDTH", LES_FilterWidth, -1.0); - /* DESCRIPTION: Specify if the LD2 scheme must be employed (incompressible flows, combined with JST discretization). */ - addBoolOption("LD2_OPTION", LD2_Scheme, false); - /* DESCRIPTION: Roe with low dissipation for unsteady flows */ addEnumOption("ROE_LOW_DISSIPATION", Kind_RoeLowDiss, RoeLowDiss_Map, NO_ROELOWDISS); @@ -7161,25 +7158,20 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { cout << "Lax viscous coefficients (1st): " << Kappa_1st_Flow << ".\n"; cout << "First order integration." << endl; } + else if (Kind_Centered_Flow == CENTERED::LD2) { + cout << "Low-Dissipation Low-Dispersion (LD2) scheme for the flow inviscid terms." << endl; + if (!(Kind_Solver==MAIN_SOLVER::INC_EULER || Kind_Solver==MAIN_SOLVER::INC_NAVIER_STOKES || Kind_Solver==MAIN_SOLVER::INC_RANS)) + SU2_MPI::Error("LD2 scheme not yet implemented for the compressible flow solver.", CURRENT_FUNCTION); + if (Kind_FluidModel != CONSTANT_DENSITY) + SU2_MPI::Error("LD2 scheme available for constant density flows only.", CURRENT_FUNCTION); + if (Energy_Equation) + cout << "WARNING: Current implementation of the LD2 scheme not compatible with the energy equation. JST employed in energy equation instead." << endl; + } else { - if (LD2_Scheme) { - cout << "Low-Dissipation Low-Dispersion (LD2) scheme for the flow inviscid terms." << endl; - if (!(Kind_Solver==MAIN_SOLVER::INC_EULER || Kind_Solver==MAIN_SOLVER::INC_NAVIER_STOKES || Kind_Solver==MAIN_SOLVER::INC_RANS)) - SU2_MPI::Error("LD2 option available for incompressible flow simulations only.", CURRENT_FUNCTION); - if (Kind_FluidModel != CONSTANT_DENSITY) - SU2_MPI::Error("LD2 option available for constant density flow simulations only.", CURRENT_FUNCTION); - if (Energy_Equation) - cout << "WARNING: LD2 option not compatible with the energy equation. JST discretization in energy equation employed." << endl; - } else { cout << "Jameson-Schmidt-Turkel scheme (2nd order in space) for the flow inviscid terms.\n"; - } - cout << "JST viscous coefficients (2nd & 4th): " << Kappa_2nd_Flow << ", " << Kappa_4th_Flow << ".\n"; - cout << "The method includes a grid stretching correction (p = 0.3)."<< endl; } - } - - if ((Kind_ConvNumScheme_Flow != SPACE_CENTERED || (Kind_ConvNumScheme_Flow == SPACE_CENTERED && Kind_Centered_Flow == CENTERED::LAX)) && LD2_Scheme) { - SU2_MPI::Error("LD2 option available for JST scheme only.", CURRENT_FUNCTION); + cout << "JST viscous coefficients (2nd & 4th): " << Kappa_2nd_Flow << ", " << Kappa_4th_Flow << ".\n"; + cout << "The method includes a grid stretching correction (p = 0.3)."<< endl; } if (Kind_ConvNumScheme_Flow == SPACE_UPWIND) { diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index 1888d035db8..0ec06ced366 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -185,14 +185,14 @@ class CNumerics { roughness_j = 0.0; /*!< \brief Roughness of the wall nearest to point j. */ su2double MeanPerturbedRSM[3][3]; /*!< \brief Perturbed Reynolds stress tensor */ - su2double stochReynStress[3][3]; /*!< \brief Stochastic contribution to Reynolds stress tensor for Backscatter Model. */ + su2double stochReynStress[3][3] = {{0.0}}; /*!< \brief Stochastic contribution to Reynolds stress tensor for Backscatter Model. */ su2double stochSource[3] = {0.0}; /*!< \brief Source term for Langevin equations in Stochastic Backscatter Model. */ su2double - stochVar_i[3], /*!< \brief Stochastic variables at point i for Stochastic Backscatter Model. */ - stochVar_j[3]; /*!< \brief Stochastic variables at point j for Stochastic Backscatter Model. */ + stochVar_i[3] = {0.0}, /*!< \brief Stochastic variables at point i for Stochastic Backscatter Model. */ + stochVar_j[3] = {0.0}; /*!< \brief Stochastic variables at point j for Stochastic Backscatter Model. */ su2double - lesMode_i, /*!< \brief LES sensor at point i for hybrid RANS-LES methods. */ - lesMode_j; /*!< \brief LES sensor at point j for hybrid RANS-LES methods. */ + lesMode_i = 0.0, /*!< \brief LES sensor at point i for hybrid RANS-LES methods. */ + lesMode_j = 0.0; /*!< \brief LES sensor at point j for hybrid RANS-LES methods. */ SST_ParsedOptions sstParsedOptions; /*!< \brief additional options for the SST turbulence model */ unsigned short Eig_Val_Comp; /*!< \brief Component towards which perturbation is perfromed */ su2double uq_delta_b; /*!< \brief Magnitude of perturbation */ @@ -656,13 +656,14 @@ class CNumerics { * eddy simulations." Flow, Turbulence and Combustion 99.1 (2017): 119-150. * \param[in] nDim - Dimension of the flow problem, 2 or 3. * \param[in] density - Density. - * \param[in] eddyVis - Eddy viscosity. - * \param[in] velGrad - Velocity gradient matrix. + * \param[in] tke - Turbulent kinetic energy. + * \param[in] rndVec - Vector of stochastic variables from Langevin equations. + * \param[in] Cmag - Stochastic backscatter intensity coefficient. * \param[out] stochReynStress - Stochastic tensor (to be added to the Reynolds stress tensor). */ template NEVERINLINE static void ComputeStochReynStress(size_t nDim, Scalar density, Scalar tke, - Vector rndVec, Mat& stochReynStress, Scalar Cmag) { + Vector rndVec, Scalar Cmag, Mat& stochReynStress) { /* --- Calculate stochastic tensor --- */ @@ -676,6 +677,32 @@ class CNumerics { stochReynStress[2][0] = - stochReynStress[2][0]; stochReynStress[2][1] = - stochReynStress[2][1]; + } + + /*! + * \brief Compute relaxation factor for stochastic source term in momentum equations (Stochastic Backscatter Model). + * \param[in] config - Definition of the particular problem. + * \param[out] intensityCoeff - Relaxation factor for backscatter intensity. + */ + NEVERINLINE static su2double ComputeStochRelaxFactor(const CConfig* config) { + + unsigned long timeIter = config->GetTimeIter(); + unsigned long restartIter = config->GetRestart_Iter(); + su2double SBS_Cmag = config->GetSBS_Cmag(); + su2double SBS_RelaxFactor = config->GetStochSourceRelax(); + su2double intensityCoeff = SBS_Cmag; + if (SBS_RelaxFactor > 0.0) { + su2double FS_Vel = config->GetModVel_FreeStream(); + su2double ReynoldsLength = config->GetLength_Reynolds(); + su2double timeScale = ReynoldsLength / FS_Vel; + unsigned long timeIter = config->GetTimeIter(); + unsigned long restartIter = config->GetRestart_Iter(); + su2double timeStep = config->GetTime_Step(); + su2double currentTime = (timeIter - restartIter) * timeStep; + intensityCoeff = SBS_Cmag * (1.0 - exp(- currentTime / (timeScale*SBS_RelaxFactor))); + } + return intensityCoeff; + } /*! @@ -881,7 +908,7 @@ class CNumerics { * \param[in] val_stochvar_j - Value of the stochastic variable at point j. * \param[in] iDim - Index of Langevin equation. */ - inline void SetStochVar(su2double val_stochvar_i, su2double val_stochvar_j, unsigned short iDim) { + inline void SetStochVar(unsigned short iDim, su2double val_stochvar_i, su2double val_stochvar_j) { stochVar_i[iDim] = val_stochvar_i; stochVar_j[iDim] = val_stochvar_j; } diff --git a/SU2_CFD/include/numerics/scalar/scalar_convection.hpp b/SU2_CFD/include/numerics/scalar/scalar_convection.hpp index e6a38b9a210..41d0ca2c5ac 100644 --- a/SU2_CFD/include/numerics/scalar/scalar_convection.hpp +++ b/SU2_CFD/include/numerics/scalar/scalar_convection.hpp @@ -52,7 +52,7 @@ class CUpwScalar : public CNumerics { const FlowIndices idx; /*!< \brief Object to manage the access to the flow primitives. */ su2double a0 = 0.0; /*!< \brief The maximum of the face-normal velocity and 0. */ su2double a1 = 0.0; /*!< \brief The minimum of the face-normal velocity and 0. */ - su2double qij = 0.0; /*!< \brief The face-normal velocity (Langevin equations). */ + su2double m_ij = 0.0; /*!< \brief Face-normal momentum (Langevin equations). */ su2double Flux[MAXNVAR]; /*!< \brief Final result, diffusive flux/residual. */ su2double* Jacobian_i[MAXNVAR]; /*!< \brief Flux Jacobian w.r.t. node i. */ su2double* Jacobian_j[MAXNVAR]; /*!< \brief Flux Jacobian w.r.t. node j. */ @@ -142,9 +142,9 @@ class CUpwScalar : public CNumerics { } if (config->GetStochastic_Backscatter()) { - qij = 0.0; + m_ij = 0.0; for (unsigned short iDim = 0; iDim < nDim; iDim++) { - qij += 0.5 * (V_i[idx.Density()]*V_i[iDim + idx.Velocity()] + V_j[idx.Density()]*V_j[iDim + idx.Velocity()]) * Normal[iDim]; + m_ij += 0.5 * (V_i[idx.Density()]*V_i[iDim + idx.Velocity()] + V_j[idx.Density()]*V_j[iDim + idx.Velocity()]) * Normal[iDim]; } } diff --git a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp index 7a2d86fca67..2df13c7bd55 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp @@ -52,7 +52,7 @@ class CUpwSca_TurbSA final : public CUpwScalar { using Base::V_j; using Base::idx; using Base::nVar; - using Base::qij; + using Base::m_ij; /*! * \brief Adds any extra variables to AD. @@ -64,15 +64,14 @@ class CUpwSca_TurbSA final : public CUpwScalar { * \param[in] config - Definition of the particular problem. */ void FinishResidualCalc(const CConfig* config) override { - bool backscatter = config->GetStochastic_Backscatter(); - if (backscatter) { + if (config->GetStochastic_Backscatter()) { for (unsigned short iVar = 1; iVar < nVar; iVar++) { - Flux[iVar] = qij * 0.5 * (ScalarVar_i[iVar] + ScalarVar_j[iVar]); + Flux[iVar] = m_ij * 0.5 * (ScalarVar_i[iVar] + ScalarVar_j[iVar]); } for (unsigned short iVar = 0; iVar < nVar; iVar++) { for (unsigned short jVar = 0; jVar < nVar; jVar++) { - Jacobian_i[iVar][jVar] = (iVar == jVar) ? 0.5*qij : 0.0; - Jacobian_j[iVar][jVar] = (iVar == jVar) ? 0.5*qij : 0.0; + Jacobian_i[iVar][jVar] = (iVar == jVar) ? 0.5*m_ij : 0.0; + Jacobian_j[iVar][jVar] = (iVar == jVar) ? 0.5*m_ij : 0.0; } } } diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index efaaf5609d5..a662a315856 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -72,10 +72,8 @@ class CSourceBase_TurbSA : public CNumerics { protected: /*--- Residual and Jacobian ---*/ - su2double Residual, *Jacobian_i; - su2double Jacobian_Buffer; /*!< \brief Static storage for the Jacobian (which needs to be pointer for return type). */ - su2double* ResidSB = nullptr; - su2double** JacobianSB_i = nullptr; + su2double Residual[4], *Jacobian_i[4]; /*!< \brief Increase the size of residual and Jacobian for Langevin equations (Stochastic Backscatter Model).*/ + su2double Jacobian_Buffer[16]; /*!< \brief Static storage for the Jacobian (which needs to be pointer for return type). */ const FlowIndices idx; /*!< \brief Object to manage the access to the flow primitives. */ const SA_ParsedOptions options; /*!< \brief Struct with SA options. */ @@ -111,7 +109,7 @@ class CSourceBase_TurbSA : public CNumerics { /* Diffusion source term */ const su2double dv_axi = (1.0/sigma)*nu_e*ScalarVar_Grad_i[0][1]; - Residual += yinv * dv_axi * Volume; + Residual[0] += yinv * dv_axi * Volume; } /*! @@ -127,18 +125,6 @@ class CSourceBase_TurbSA : public CNumerics { const su2double nut = max(nue*var.fv1, 1e-10); const su2double delta = lengthScale/DES_const; - for (unsigned short iVar = 0; iVar < nVar; iVar++ ) { - ResidSB[iVar] = 0.0; - } - ResidSB[0] = Residual; - - for (unsigned short iVar = 0; iVar < nVar; iVar++ ) { - for (unsigned short jVar = 0; jVar < nVar; jVar++ ) { - JacobianSB_i[iVar][jVar] = 0.0; - } - } - JacobianSB_i[0][0] = Jacobian_i[0]; - if (delta > 1e-10) { su2double tTurb = ct*pow(delta, 2)/nut; @@ -154,14 +140,13 @@ class CSourceBase_TurbSA : public CNumerics { su2double scaleFactor = 0.0; if (lesMode_i > threshold) scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * density * corrFac; - for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { - ResidSB[iVar] = scaleFactor * stochSource[iVar-1] - 1.0/tTurb * density * ScalarVar_i[iVar]; - ResidSB[iVar] *= Volume; + for (unsigned short iVar = 1; iVar < nVar; iVar++) { + Residual[iVar] = scaleFactor * stochSource[iVar-1] - 1.0/tTurb * density * ScalarVar_i[iVar]; + Residual[iVar] *= Volume; } - for (unsigned short iVar = 1; iVar < nVar; iVar++ ) { - JacobianSB_i[iVar][iVar] = -1.0/tTurb * density * Volume; - } + for (unsigned short iVar = 1; iVar < nVar; iVar++ ) + Jacobian_i[iVar][iVar] = -1.0/tTurb * density * Volume; } @@ -170,30 +155,25 @@ class CSourceBase_TurbSA : public CNumerics { /*! * \brief Include stochastic source term in the Spalart-Allmaras turbulence model equation (Stochastic Backscatter Model). */ - template - inline void AddStochSource(const CSAVariables& var, const MatrixType& velGrad, const su2double Cmag) { - - su2double dist2 = dist_i * dist_i; - su2double xi3 = pow(var.Ji, 3); - su2double factor = dist2 / (2.0 * var.fv1 * ScalarVar_i[0]); - factor /= (3.0 * xi3 * var.cv1_3 / pow(xi3 + var.cv1_3, 2) + var.fv1); + inline void AddStochSource(CSAVariables& var, const su2double Cmag, su2double& prod) { + su2double nut = ScalarVar_i[0] * var.fv1; su2double tke = 0.0; const su2double threshold = 0.9; - if (lesMode_i > threshold) tke = pow(var.fv1*ScalarVar_i[0]/dist_i, 2); + const su2double limiter = 10.0; + if (lesMode_i > threshold) tke = nut * StrainMag_i; - su2double R12 = (nDim==3 ? Cmag * tke * ScalarVar_i[3] : 0.0); - su2double R13 = - Cmag * tke * ScalarVar_i[2]; - su2double R23 = Cmag * tke * ScalarVar_i[1]; + su2double R12 = Cmag * tke * ScalarVar_i[3]; + su2double R13 = - Cmag * tke * ScalarVar_i[2]; + su2double R23 = Cmag * tke * ScalarVar_i[1]; - su2double RGradU = R12 * (velGrad[0][1] - velGrad[1][0]) + - (nDim==3 ? R13 * (velGrad[0][2] - velGrad[2][0]) + - R23 * (velGrad[1][2] - velGrad[2][1]) : 0.0); + su2double RGradU = R12*Vorticity_i[2] - R13*Vorticity_i[1] + R23*Vorticity_i[0]; - su2double source_k = - RGradU; - su2double source_nu = factor * source_k; + su2double stoch_prod_k = - RGradU; + su2double prod_k = nut * StrainMag_i * StrainMag_i; + su2double stoch_prod_nut = min(limiter, max(-limiter, stoch_prod_k/max(prod_k,1e-10))); - Residual += source_nu * Volume; + prod *= (1.0 + stoch_prod_nut); } @@ -204,37 +184,17 @@ class CSourceBase_TurbSA : public CNumerics { * \param[in] config - Definition of the particular problem. */ CSourceBase_TurbSA(unsigned short nDim, const CConfig* config) - : CNumerics(nDim, config->GetStochastic_Backscatter() ? 1+nDim : 1, config), + : CNumerics(nDim, config->GetStochastic_Backscatter() ? 4 : 1, config), idx(nDim, config->GetnSpecies()), options(config->GetSAParsedOptions()), axisymmetric(config->GetAxisymmetric()), transition_LM(config->GetKind_Trans_Model() == TURB_TRANS_MODEL::LM) { /*--- Setup the Jacobian pointer, we need to return su2double** but we know * the Jacobian is 1x1 so we use this trick to avoid heap allocation. ---*/ - Jacobian_i = &Jacobian_Buffer; - /*--- Setup the Jacobian for Stochastic Backscatter Model. ---*/ - if (config->GetStochastic_Backscatter()) { - ResidSB = new su2double [1+nDim] (); - JacobianSB_i = new su2double* [1+nDim]; - for (unsigned short iVar = 0; iVar < 1+nDim; iVar++ ) { - JacobianSB_i[iVar] = new su2double [1+nDim] (); - } - } - } - - /*! - * \brief Destructor of the class. - */ - ~CSourceBase_TurbSA() { - if (JacobianSB_i) { - for (unsigned short iVar = 0; iVar < 1+nDim; iVar++) { - delete [] JacobianSB_i[iVar]; - } - delete [] JacobianSB_i; - } - if (ResidSB) { - delete [] ResidSB; - } + //Jacobian_i = &Jacobian_Buffer; + /*--- Setup the Jacobian pointer (size increased for Stochastic Backscatter Model). ---*/ + for (unsigned short iVar = 0; iVar < 4; iVar++) + Jacobian_i[iVar] = Jacobian_Buffer + 4*iVar; } /*! @@ -252,17 +212,17 @@ class CSourceBase_TurbSA : public CNumerics { AD::SetPreaccIn(Vorticity_i, 3); AD::SetPreaccIn(PrimVar_Grad_i + idx.Velocity(), nDim, nDim); AD::SetPreaccIn(ScalarVar_Grad_i, nVar, nDim); - - bool backscatter = config->GetStochastic_Backscatter(); - if (backscatter) { - AD::SetPreaccIn(stochSource, 3); - } + AD::SetPreaccIn(stochSource, 3); /*--- Common auxiliary variables and constants of the model. ---*/ CSAVariables var; - Residual = 0.0; - Jacobian_i[0] = 0.0; + for (unsigned short iVar = 0; iVar < 4; iVar++) { + Residual[iVar] = 0.0; + for (unsigned short jVar = 0; jVar < 4; jVar++) { + Jacobian_i[iVar][jVar] = 0.0; + } + } if (dist_i > 1e-10) { @@ -358,33 +318,22 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Compute production, destruction and jacobian ---*/ su2double Production = 0.0, Destruction = 0.0; - SourceTerms::get(ScalarVar_i[0], var, Production, Destruction, Jacobian_i[0]); + SourceTerms::get(ScalarVar_i[0], var, Production, Destruction, Jacobian_i[0][0]); - Residual = (Production - Destruction) * Volume; + if (config->GetStochastic_Backscatter() && config->GetStochSourceNu()) { + su2double intensityCoeff = ComputeStochRelaxFactor(config); + AddStochSource(var, intensityCoeff, Production); + } + + Residual[0] = (Production - Destruction) * Volume; if (axisymmetric) ResidualAxisymmetricDiffusion(var.sigma); - Jacobian_i[0] *= Volume; + Jacobian_i[0][0] *= Volume; /*--- Compute residual for Langevin equations (Stochastic Backscatter Model). ---*/ - if (backscatter) { - if (config->GetStochSourceNu()) { - su2double SBS_Cmag = config->GetSBS_Cmag(); - su2double SBS_RelaxFactor = config->GetStochSourceRelax(); - su2double intensityCoeff = SBS_Cmag; - if (SBS_RelaxFactor > 0.0) { - su2double FS_Vel = config->GetModVel_FreeStream(); - su2double ReynoldsLength = config->GetLength_Reynolds(); - su2double timeScale = ReynoldsLength / FS_Vel; - unsigned long timeIter = config->GetTimeIter(); - unsigned long restartIter = config->GetRestart_Iter(); - su2double timeStep = config->GetTime_Step(); - su2double currentTime = (timeIter - restartIter) * timeStep; - intensityCoeff = SBS_Cmag * (1.0 - exp(- currentTime / (timeScale*SBS_RelaxFactor))); - } - AddStochSource(var, PrimVar_Grad_i + idx.Velocity(), intensityCoeff); - } + if (config->GetStochastic_Backscatter()) { const su2double DES_const = config->GetConst_DES(); const su2double ctau = config->GetSBS_Ctau(); ResidualStochEquations(config->GetDelta_UnstTime(), ctau, dist_i, DES_const, @@ -392,17 +341,10 @@ class CSourceBase_TurbSA : public CNumerics { } } - if (backscatter) { - AD::SetPreaccOut(ResidSB, nVar); - } else { - AD::SetPreaccOut(Residual); - } + AD::SetPreaccOut(Residual, 4); AD::EndPreacc(); - if (backscatter) - return ResidualType<>(ResidSB, JacobianSB_i, nullptr); - else - return ResidualType<>(&Residual, &Jacobian_i, nullptr); + return ResidualType<>(Residual, Jacobian_i, nullptr); } }; @@ -698,14 +640,14 @@ class CCompressibilityCorrection final : public ParentClass { const su2double d_axiCorrection = 2.0 * c5 * nue * pow(v * yinv / sound_speed, 2) * Volume; const su2double axiCorrection = 0.5 * nue * d_axiCorrection; - this->Residual -= axiCorrection; - this->Jacobian_i[0] -= d_axiCorrection; + this->Residual[0] -= axiCorrection; + this->Jacobian_i[0][0] -= d_axiCorrection; } - this->Residual -= CompCorrection; - this->Jacobian_i[0] -= d_CompCorrection; + this->Residual[0] -= CompCorrection; + this->Jacobian_i[0][0] -= d_CompCorrection; - return ResidualType(&this->Residual, &this->Jacobian_i, nullptr); + return ResidualType(this->Residual, this->Jacobian_i, nullptr); } }; diff --git a/SU2_CFD/include/numerics_simd/CNumericsSIMD.cpp b/SU2_CFD/include/numerics_simd/CNumericsSIMD.cpp index 09e71002f8a..69101654c99 100644 --- a/SU2_CFD/include/numerics_simd/CNumericsSIMD.cpp +++ b/SU2_CFD/include/numerics_simd/CNumericsSIMD.cpp @@ -71,6 +71,7 @@ CNumericsSIMD* createCenteredNumerics(const CConfig& config, int iMesh, const CV obj = new CLaxScheme(config, iMesh, turbVars); break; case CENTERED::JST: + case CENTERED::LD2: // Just to silence compiler warnings (LD2 implemented in the incompressible solver only). obj = new CJSTScheme(config, iMesh, turbVars); break; case CENTERED::JST_KE: diff --git a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl index a3b5f5a31ec..92f35c463f6 100644 --- a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl +++ b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl @@ -471,13 +471,9 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome /*--- Stochastic variables from Langevin equations (Stochastic Backscatter Model). ---*/ if (backscatter) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - numerics->SetStochVar(turbNodes->GetSolution(iPoint, 1 + iDim), - turbNodes->GetSolution(jPoint, 1 + iDim), iDim); - } - su2double rho = nodes->GetDensity(iPoint); - su2double eddy_visc_i = turbNodes->GetmuT(iPoint) / rho; - su2double eddy_visc_j = turbNodes->GetmuT(jPoint) / rho; + for (unsigned short iDim = 0; iDim < nDim; iDim++) + numerics->SetStochVar(iDim, turbNodes->GetSolution(iPoint, iDim+1), + turbNodes->GetSolution(jPoint, iDim+1)); su2double DES_length_i = turbNodes->GetDES_LengthScale(iPoint); su2double DES_length_j = turbNodes->GetDES_LengthScale(jPoint); su2double lesMode_i = (DES_length_i > 1e-10) ? turbNodes->GetLES_Mode(iPoint) : 0.0; @@ -485,9 +481,12 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome const su2double threshold = 0.9; su2double tke_i = 0.0, tke_j = 0.0; if (max(lesMode_i, lesMode_j) > threshold) { - tke_i = pow(eddy_visc_i/DES_length_i, 2); - tke_j = tke_i; - if (geometry->nodes->GetDomain(jPoint)) tke_j = pow(eddy_visc_j/DES_length_j, 2); + su2double eddyVisc_i = turbNodes->GetmuT(iPoint) / nodes->GetDensity(iPoint); + su2double eddyVisc_j = turbNodes->GetmuT(jPoint) / nodes->GetDensity(jPoint); + su2double strainMag_i = nodes->GetStrainMag(iPoint); + su2double strainMag_j = nodes->GetStrainMag(jPoint); + tke_i = strainMag_i * eddyVisc_i; + tke_j = strainMag_j * eddyVisc_j; } numerics->SetTurbKineticEnergy(tke_i, tke_j); } diff --git a/SU2_CFD/include/solvers/CTurbSASolver.hpp b/SU2_CFD/include/solvers/CTurbSASolver.hpp index 70ad3f60bc1..a19ffb3dd9e 100644 --- a/SU2_CFD/include/solvers/CTurbSASolver.hpp +++ b/SU2_CFD/include/solvers/CTurbSASolver.hpp @@ -39,13 +39,9 @@ class CTurbSASolver final : public CTurbSolver { private: - su2double* nu_tilde_Engine = nullptr; - su2double* nu_tilde_ActDisk = nullptr; - su2double* ext_AverageNu = nullptr; - su2double* Res_Wall = nullptr; - su2double** Jacobian_i = nullptr; - su2double* nu_tilde_inturb = nullptr; - su2double* nu_tilde_WF = nullptr; + + su2double nu_tilde_Engine[4] = {0.0}; + su2double nu_tilde_ActDisk[4] = {0.0}; /*! * \brief A virtual member. @@ -105,21 +101,7 @@ class CTurbSASolver final : public CTurbSolver { /*! * \brief Destructor of the class. */ - ~CTurbSASolver() { - - for(unsigned short iVar = 0; iVar < nVar; ++iVar) { - delete [] Jacobian_i[iVar]; - } - delete [] Jacobian_i; - - delete [] Res_Wall; - delete [] nu_tilde_Engine; - delete [] nu_tilde_ActDisk; - delete [] ext_AverageNu; - delete [] nu_tilde_inturb; - delete [] nu_tilde_WF; - - } + ~CTurbSASolver() = default; /*! * \brief Restart residual and compute gradients. diff --git a/SU2_CFD/include/solvers/CTurbSolver.hpp b/SU2_CFD/include/solvers/CTurbSolver.hpp index dc4676186eb..56b7b96b3b2 100644 --- a/SU2_CFD/include/solvers/CTurbSolver.hpp +++ b/SU2_CFD/include/solvers/CTurbSolver.hpp @@ -152,7 +152,6 @@ class CTurbSolver : public CScalarSolver { * \brief Compute a suitable under-relaxation parameter to limit the change in the solution variables over * a nonlinear iteration for stability. * \param[in] allowableRatio - Maximum percentage update in variable per iteration. - * \param[in] backscatter - Flag for Stochastic Backscatter Model. */ void ComputeUnderRelaxationFactorHelper(su2double allowableRatio); }; diff --git a/SU2_CFD/include/variables/CIncNSVariable.hpp b/SU2_CFD/include/variables/CIncNSVariable.hpp index feffcc34928..5aa1ebaa75e 100644 --- a/SU2_CFD/include/variables/CIncNSVariable.hpp +++ b/SU2_CFD/include/variables/CIncNSVariable.hpp @@ -40,7 +40,7 @@ class CIncNSVariable final : public CIncEulerVariable { private: VectorType Tau_Wall; /*!< \brief Magnitude of the wall shear stress from a wall function. */ VectorType DES_LengthScale; /*!< \brief DES Length Scale. */ - VectorType LES_Mode; /*!< \brief Sensor for local simulation mode (0=RANS, 1=LES).*/ + VectorType lesMode; /*!< \brief Sensor for local simulation mode (0=RANS, 1=LES).*/ const bool Energy; /*!< \brief Flag for Energy equation in incompressible flows. */ public: @@ -138,13 +138,13 @@ class CIncNSVariable final : public CIncEulerVariable { * \brief Set the LES sensor. */ inline void SetLES_Mode(unsigned long iPoint, su2double val_les_mode) override { - LES_Mode(iPoint) = val_les_mode; + lesMode(iPoint) = val_les_mode; } /*! * \brief Get the LES sensor. * \return Value of the LES sensor. */ - inline su2double GetLES_Mode(unsigned long iPoint) const override { return LES_Mode(iPoint); } + inline su2double GetLES_Mode(unsigned long iPoint) const override { return lesMode(iPoint); } }; diff --git a/SU2_CFD/include/variables/CNEMONSVariable.hpp b/SU2_CFD/include/variables/CNEMONSVariable.hpp index fdf3e9229e5..4585c1c6b9b 100644 --- a/SU2_CFD/include/variables/CNEMONSVariable.hpp +++ b/SU2_CFD/include/variables/CNEMONSVariable.hpp @@ -52,7 +52,7 @@ class CNEMONSVariable final : public CNEMOEulerVariable { VectorType Tau_Wall; /*!< \brief Magnitude of the wall shear stress from a wall function. */ VectorType DES_LengthScale; /*!< \brief DES Length Scale. */ - VectorType LES_Mode; /*!< \brief Sensor for local simulation mode (0=RANS, 1=LES). */ + VectorType lesMode; /*!< \brief Sensor for local simulation mode (0=RANS, 1=LES). */ VectorType Roe_Dissipation; /*!< \brief Roe low dissipation coefficient. */ VectorType Vortex_Tilting; /*!< \brief Value of the vortex tilting variable for DES length scale computation. */ diff --git a/SU2_CFD/include/variables/CNSVariable.hpp b/SU2_CFD/include/variables/CNSVariable.hpp index 19f2d8924e9..9c3ab8dabf5 100644 --- a/SU2_CFD/include/variables/CNSVariable.hpp +++ b/SU2_CFD/include/variables/CNSVariable.hpp @@ -41,7 +41,7 @@ class CNSVariable final : public CEulerVariable { VectorType Tau_Wall; /*!< \brief Magnitude of the wall shear stress from a wall function. */ VectorType DES_LengthScale; /*!< \brief DES Length Scale. */ - VectorType LES_Mode; /*!< \brief Sensor for local simulation mode (0=RANS, 1=LES).*/ + VectorType lesMode; /*!< \brief Sensor for local simulation mode (0=RANS, 1=LES).*/ VectorType Roe_Dissipation; /*!< \brief Roe low dissipation coefficient. */ VectorType Vortex_Tilting; /*!< \brief Value of the vortex tilting variable for DES length scale computation. */ @@ -190,14 +190,14 @@ class CNSVariable final : public CEulerVariable { * \brief Set the LES sensor. */ inline void SetLES_Mode(unsigned long iPoint, su2double val_les_mode) override { - LES_Mode(iPoint) = val_les_mode; + lesMode(iPoint) = val_les_mode; } /*! * \brief Get the LES sensor. * \return Value of the LES sensor. */ - inline su2double GetLES_Mode(unsigned long iPoint) const override { return LES_Mode(iPoint); } + inline su2double GetLES_Mode(unsigned long iPoint) const override { return lesMode(iPoint); } /*! * \brief Set the new solution for Roe Dissipation. diff --git a/SU2_CFD/include/variables/CTurbSAVariable.hpp b/SU2_CFD/include/variables/CTurbSAVariable.hpp index 90be6f1e047..7e4d88df4d2 100644 --- a/SU2_CFD/include/variables/CTurbSAVariable.hpp +++ b/SU2_CFD/include/variables/CTurbSAVariable.hpp @@ -41,9 +41,9 @@ class CTurbSAVariable final : public CTurbVariable { private: VectorType DES_LengthScale; - VectorType LES_Mode; + VectorType lesMode; MatrixType stochSource; - MatrixType stochSource_old; + MatrixType stochSourceOld; VectorType Vortex_Tilting; VectorType besselIntegral; @@ -100,7 +100,7 @@ class CTurbSAVariable final : public CTurbVariable { * \param[in] iDim - Dimension index. * \return Old value of the source terms for the stochastic equations. */ - inline su2double GetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim) const override { return stochSource_old(iPoint, iDim); } + inline su2double GetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim) const override { return stochSourceOld(iPoint, iDim); } /*! * \brief Set the old value of source terms for the stochastic equations. @@ -108,18 +108,18 @@ class CTurbSAVariable final : public CTurbVariable { * \param[in] iDim - Dimension index. * \param[in] val_stochSource_old - Old value of the source term for the stochastic equations. */ - inline void SetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim, su2double val_stochSource_old) override { stochSource_old(iPoint, iDim) = val_stochSource_old; } + inline void SetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim, su2double val_stochSource_old) override { stochSourceOld(iPoint, iDim) = val_stochSource_old; } /*! * \brief Set the LES sensor. */ - inline void SetLES_Mode(unsigned long iPoint, su2double val_les_mode) override { LES_Mode(iPoint) = val_les_mode; } + inline void SetLES_Mode(unsigned long iPoint, su2double val_les_mode) override { lesMode(iPoint) = val_les_mode; } /*! * \brief Get the LES sensor. * \return Value of the LES sensor. */ - inline su2double GetLES_Mode(unsigned long iPoint) const override { return LES_Mode(iPoint); } + inline su2double GetLES_Mode(unsigned long iPoint) const override { return lesMode(iPoint); } /*! * \brief Set the vortex tilting measure for computation of the EDDES length scale diff --git a/SU2_CFD/include/variables/CTurbVariable.hpp b/SU2_CFD/include/variables/CTurbVariable.hpp index 9db56e77127..34bf86e04e7 100644 --- a/SU2_CFD/include/variables/CTurbVariable.hpp +++ b/SU2_CFD/include/variables/CTurbVariable.hpp @@ -111,4 +111,19 @@ class CTurbVariable : public CScalarVariable { * \param[in] input - Boolean whether In- or Output should be registered. */ void RegisterEddyViscosity(bool input); + + /*! + * \brief A virtual member. + * \param[in] iPoint - Point index. + * \param[in] iDim - Dimension index. + */ + inline virtual su2double GetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] iPoint - Point index. + * \param[in] iDim - Dimension index. + * \param[in] val_stochSource_old - Old value of source term in Langevin equations. + */ + inline virtual void SetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim, su2double val_stochSource_old) {} }; diff --git a/SU2_CFD/include/variables/CVariable.hpp b/SU2_CFD/include/variables/CVariable.hpp index cc46938b43e..a520ed27f46 100644 --- a/SU2_CFD/include/variables/CVariable.hpp +++ b/SU2_CFD/include/variables/CVariable.hpp @@ -426,21 +426,6 @@ class CVariable { */ inline virtual void SetLangevinSourceTerms(unsigned long iPoint, unsigned short iDim, su2double val_stochSource) {} - /*! - * \brief A virtual member. - * \param[in] iPoint - Point index. - * \param[in] iDim - Dimension index. - */ - inline virtual su2double GetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim) const { return 0.0; } - - /*! - * \brief A virtual member. - * \param[in] iPoint - Point index. - * \param[in] iDim - Dimension index. - * \param[in] val_stochSource_old - Old value of source term in Langevin equations. - */ - inline virtual void SetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim, su2double val_stochSource_old) {} - /*! * \brief A virtual member. * \param[in] iPoint - Point index. diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index 961ce04832f..f2e1e5b953e 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -1658,6 +1658,7 @@ void CDriver::InitializeNumerics(CConfig *config, CGeometry **geometry, CSolver /*--- Incompressible flow, use preconditioning method ---*/ switch (config->GetKind_Centered_Flow()) { case CENTERED::LAX : numerics[MESH_0][FLOW_SOL][conv_term] = new CCentLaxInc_Flow(nDim, nVar_Flow, config); break; + case CENTERED::LD2 : case CENTERED::JST : numerics[MESH_0][FLOW_SOL][conv_term] = new CCentJSTInc_Flow(nDim, nVar_Flow, config); break; default: SU2_MPI::Error("Invalid centered scheme or not implemented.\n Currently, only JST and LAX-FRIEDRICH are available for incompressible flows.", CURRENT_FUNCTION); diff --git a/SU2_CFD/src/numerics/flow/convection/centered.cpp b/SU2_CFD/src/numerics/flow/convection/centered.cpp index 4ad35559df9..fb3c8ac7b4c 100644 --- a/SU2_CFD/src/numerics/flow/convection/centered.cpp +++ b/SU2_CFD/src/numerics/flow/convection/centered.cpp @@ -311,7 +311,7 @@ CNumerics::ResidualType<> CCentJSTInc_Flow::ComputeResidual(const CConfig* confi su2double U_i[5] = {0.0}, U_j[5] = {0.0}; su2double ProjGridVel = 0.0; - bool LD2_Scheme = config->GetLD2_Scheme(); + bool LD2_Scheme = (config->GetKind_Centered_Flow() == CENTERED::LD2); const su2double alpha_LD2 = 0.36; /*--- Primitive variables at point i and j ---*/ @@ -336,13 +336,19 @@ CNumerics::ResidualType<> CCentJSTInc_Flow::ComputeResidual(const CConfig* confi d_ij[iDim] = Coord_j[iDim]-Coord_i[iDim]; su2double velGrad_i[3][3] = {{0.0}}; su2double velGrad_j[3][3] = {{0.0}}; + su2double pressGrad_i[3] = {0.0}; + su2double pressGrad_j[3] = {0.0}; for (unsigned short jDim = 0; jDim < nDim; jDim++) { + pressGrad_i[jDim] = PrimVar_Grad_i[0][jDim]; + pressGrad_j[jDim] = PrimVar_Grad_j[0][jDim]; for (iDim = 0; iDim < nDim; iDim++) { velGrad_i[iDim][jDim] = PrimVar_Grad_i[iDim+1][jDim]; velGrad_j[iDim][jDim] = PrimVar_Grad_j[iDim+1][jDim]; } } for (iDim = 0; iDim < nDim; iDim++) { + Pressure_i += alpha_LD2 * pressGrad_i[iDim] * d_ij[iDim]; + Pressure_j += alpha_LD2 * pressGrad_j[iDim] * d_ij[iDim]; Velocity_i[iDim] += alpha_LD2 * (velGrad_i[iDim][0] * d_ij[0] + velGrad_i[iDim][1] * d_ij[1] + velGrad_i[iDim][2] * d_ij[2]); diff --git a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp index ecd88810ecc..15ba9809b37 100644 --- a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp +++ b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp @@ -458,24 +458,15 @@ CNumerics::ResidualType<> CAvgGrad_Flow::ComputeResidual(const CConfig* config) /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ + + unsigned long timeIter = config->GetTimeIter(); + unsigned long restartIter = config->GetRestart_Iter(); if (config->GetStochastic_Backscatter()) { - for (iVar = 0; iVar < nDim; iVar++) - Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); - su2double SBS_Cmag = config->GetSBS_Cmag(); - su2double SBS_RelaxFactor = config->GetStochSourceRelax(); - su2double intensityCoeff = SBS_Cmag; - if (SBS_RelaxFactor > 0.0) { - su2double FS_Vel = config->GetModVel_FreeStream(); - su2double ReynoldsLength = config->GetLength_Reynolds(); - su2double timeScale = ReynoldsLength / FS_Vel; - unsigned long timeIter = config->GetTimeIter(); - unsigned long restartIter = config->GetRestart_Iter(); - su2double timeStep = config->GetTime_Step(); - su2double currentTime = (timeIter - restartIter) * timeStep; - intensityCoeff = SBS_Cmag * (1.0 - exp(- currentTime / (timeScale*SBS_RelaxFactor))); - } + for (iDim = 0; iDim < nDim; iDim++) + Mean_StochVar[iDim] = 0.5*(stochVar_i[iDim] + stochVar_j[iDim]); + su2double intensityCoeff = ComputeStochRelaxFactor(config); ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_turb_ke, - Mean_StochVar, stochReynStress, intensityCoeff); + Mean_StochVar, intensityCoeff, stochReynStress); } /*--- Get projected flux tensor (viscous residual) ---*/ @@ -654,24 +645,15 @@ CNumerics::ResidualType<> CAvgGradInc_Flow::ComputeResidual(const CConfig* confi /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ + + unsigned long timeIter = config->GetTimeIter(); + unsigned long restartIter = config->GetRestart_Iter(); if (config->GetStochastic_Backscatter()) { - for (iVar = 0; iVar < nDim; iVar++) - Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); - su2double SBS_Cmag = config->GetSBS_Cmag(); - su2double SBS_RelaxFactor = config->GetStochSourceRelax(); - su2double intensityCoeff = SBS_Cmag; - if (SBS_RelaxFactor > 0.0) { - su2double FS_Vel = config->GetModVel_FreeStream(); - su2double ReynoldsLength = config->GetLength_Reynolds(); - su2double timeScale = ReynoldsLength / FS_Vel; - unsigned long timeIter = config->GetTimeIter(); - unsigned long restartIter = config->GetRestart_Iter(); - su2double timeStep = config->GetTime_Step(); - su2double currentTime = (timeIter - restartIter) * timeStep; - intensityCoeff = SBS_Cmag * (1.0 - exp(- currentTime / (timeScale*SBS_RelaxFactor))); - } + for (iDim = 0; iDim < nDim; iDim++) + Mean_StochVar[iDim] = 0.5*(stochVar_i[iDim] + stochVar_j[iDim]); + su2double intensityCoeff = ComputeStochRelaxFactor(config); ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_turb_ke, - Mean_StochVar, stochReynStress, intensityCoeff); + Mean_StochVar, intensityCoeff, stochReynStress); } /*--- Get projected flux tensor (viscous residual) ---*/ @@ -1002,24 +984,14 @@ CNumerics::ResidualType<> CGeneralAvgGrad_Flow::ComputeResidual(const CConfig* c /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ + unsigned long timeIter = config->GetTimeIter(); + unsigned long restartIter = config->GetRestart_Iter(); if (config->GetStochastic_Backscatter()) { - for (iVar = 0; iVar < nDim; iVar++) - Mean_StochVar[iVar] = 0.5*(stochVar_i[iVar] + stochVar_j[iVar]); - su2double SBS_Cmag = config->GetSBS_Cmag(); - su2double SBS_RelaxFactor = config->GetStochSourceRelax(); - su2double intensityCoeff = SBS_Cmag; - if (SBS_RelaxFactor > 0.0) { - su2double FS_Vel = config->GetModVel_FreeStream(); - su2double ReynoldsLength = config->GetLength_Reynolds(); - su2double timeScale = ReynoldsLength / FS_Vel; - unsigned long timeIter = config->GetTimeIter(); - unsigned long restartIter = config->GetRestart_Iter(); - su2double timeStep = config->GetTime_Step(); - su2double currentTime = (timeIter - restartIter) * timeStep; - intensityCoeff = SBS_Cmag * (1.0 - exp(- currentTime / (timeScale*SBS_RelaxFactor))); - } + for (iDim = 0; iDim < nDim; iDim++) + Mean_StochVar[iDim] = 0.5*(stochVar_i[iDim] + stochVar_j[iDim]); + su2double intensityCoeff = ComputeStochRelaxFactor(config); ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_turb_ke, - Mean_StochVar, stochReynStress, intensityCoeff); + Mean_StochVar, intensityCoeff, stochReynStress); } /*--- Get projected flux tensor (viscous residual) ---*/ diff --git a/SU2_CFD/src/output/CFlowCompOutput.cpp b/SU2_CFD/src/output/CFlowCompOutput.cpp index 0f31e5c5dc3..4429cdfd7a0 100644 --- a/SU2_CFD/src/output/CFlowCompOutput.cpp +++ b/SU2_CFD/src/output/CFlowCompOutput.cpp @@ -234,8 +234,6 @@ void CFlowCompOutput::SetVolumeOutputFields(CConfig *config){ AddVolumeOutput("GRID_VELOCITY-Z", "Grid_Velocity_z", "GRID_VELOCITY", "z-component of the grid velocity vector"); } - AddVolumeOutput("VELOCITY_DIVERGENCE", "Velocity_Divergence", "DERIVED", "Divergence of the velocity field"); - // Primitive variables AddVolumeOutput("PRESSURE", "Pressure", "PRIMITIVE", "Pressure"); AddVolumeOutput("TEMPERATURE", "Temperature", "PRIMITIVE", "Temperature"); @@ -327,13 +325,6 @@ void CFlowCompOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolv SetVolumeOutputValue("ENERGY", iPoint, Node_Flow->GetSolution(iPoint, 3)); } - const auto VelocityGradient = Node_Flow->GetVelocityGradient(iPoint); - su2double divVel = 0.0; - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - divVel += VelocityGradient[iDim][iDim]; - } - SetVolumeOutputValue("VELOCITY_DIVERGENCE", iPoint, divVel); - if (gridMovement){ SetVolumeOutputValue("GRID_VELOCITY-X", iPoint, Node_Geo->GetGridVel(iPoint)[0]); SetVolumeOutputValue("GRID_VELOCITY-Y", iPoint, Node_Geo->GetGridVel(iPoint)[1]); diff --git a/SU2_CFD/src/output/CFlowIncOutput.cpp b/SU2_CFD/src/output/CFlowIncOutput.cpp index de2bde987bc..b13edb7732f 100644 --- a/SU2_CFD/src/output/CFlowIncOutput.cpp +++ b/SU2_CFD/src/output/CFlowIncOutput.cpp @@ -322,8 +322,6 @@ void CFlowIncOutput::SetVolumeOutputFields(CConfig *config){ AddVolumeOutput("GRID_VELOCITY-Z", "Grid_Velocity_z", "GRID_VELOCITY", "z-component of the grid velocity vector"); } - AddVolumeOutput("VELOCITY_DIVERGENCE", "Velocity_Divergence", "DERIVED", "Divergence of the velocity field"); - // Primitive variables AddVolumeOutput("PRESSURE_COEFF", "Pressure_Coefficient", "PRIMITIVE", "Pressure coefficient"); AddVolumeOutput("DENSITY", "Density", "PRIMITIVE", "Density"); @@ -435,13 +433,6 @@ void CFlowIncOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolve SetVolumeOutputValue("GRID_VELOCITY-Z", iPoint, Node_Geo->GetGridVel(iPoint)[2]); } - const auto VelocityGradient = Node_Flow->GetVelocityGradient(iPoint); - su2double divVel = 0.0; - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - divVel += VelocityGradient[iDim][iDim]; - } - SetVolumeOutputValue("VELOCITY_DIVERGENCE", iPoint, divVel); - const su2double factor = solver[FLOW_SOL]->GetReferenceDynamicPressure(); SetVolumeOutputValue("PRESSURE_COEFF", iPoint, (Node_Flow->GetPressure(iPoint) - solver[FLOW_SOL]->GetPressure_Inf())/factor); SetVolumeOutputValue("DENSITY", iPoint, Node_Flow->GetDensity(iPoint)); diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index fe625fbf343..e8b7abd04f3 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -1703,34 +1703,29 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con const su2double lesSensor = Node_Flow->GetLES_Mode(iPoint); const su2double mag = config->GetSBS_Cmag(); const su2double threshold = 0.9; + const auto VelocityGradient = Node_Flow->GetVelocityGradient(iPoint); + su2double strainMag2 = 0.0; + for (unsigned long iDim = 0; iDim < nDim; iDim++) { + strainMag2 += pow(VelocityGradient(iDim, iDim), 2); + } + strainMag2 += 2.0*pow(0.5*(VelocityGradient(0,1) + VelocityGradient(1,0)), 2); + if (nDim == 3) { + strainMag2 += 2.0*pow(0.5*(VelocityGradient(0,2) + VelocityGradient(2,0)), 2); + strainMag2 += 2.0*pow(0.5*(VelocityGradient(1,2) + VelocityGradient(2,1)), 2); + } + strainMag2 *= 2.0; su2double tke_estim = 0.0; - if (lesSensor > threshold) tke_estim = pow(nu_t/DES_lengthscale, 2.0); + if (lesSensor > threshold) tke_estim = sqrt(strainMag2) * nu_t; const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); const su2double csi_y = Node_Turb->GetSolution(iPoint, 2); - const su2double csi_z = (nDim==3) ? Node_Turb->GetSolution(iPoint, 3) : 0.0; + const su2double csi_z = Node_Turb->GetSolution(iPoint, 3); const su2double R_xy = mag * tke_estim * csi_z; const su2double R_xz = - mag * tke_estim * csi_y; const su2double R_yz = mag * tke_estim * csi_x; - const auto vel_grad = Node_Flow->GetVelocityGradient(iPoint); - const su2double vel_div = vel_grad(0,0) + vel_grad(1,1) + (nDim ==3 ? vel_grad(2,2) : 0.0); - const su2double tau_xx = nu_t * (2*vel_grad(0,0) - (2.0/3.0)*vel_div); - const su2double tau_yy = nu_t * (2*vel_grad(1,1) - (2.0/3.0)*vel_div); - const su2double tau_xy = nu_t * (vel_grad(0,1) + vel_grad(1,0)); - su2double tau_zz=0.0, tau_xz=0.0, tau_yz=0.0; - if (nDim == 3){ - tau_zz = nu_t * (2*vel_grad(2,2) - (2.0/3.0)*vel_div); - tau_xz = nu_t * (vel_grad(0,2) + vel_grad(2,0)); - tau_yz = nu_t * (vel_grad(1,2) + vel_grad(2,1)); - } - const su2double energy_res_to_mod = tau_xx * vel_grad(0,0) + tau_yy * vel_grad(1,1) - + (nDim==3 ? tau_zz * vel_grad(2,2) : 0.0) - + tau_xy * (vel_grad(0,1) + vel_grad(1,0)) - + (nDim==3 ? tau_xz * (vel_grad(0,2) + vel_grad(2,0)) - + tau_yz * (vel_grad(1,2) + vel_grad(2,1)) : 0.0); - const su2double energy_backscatter = R_xy * (vel_grad(0,1) - vel_grad(1,0)) - + (nDim==3 ? R_xz * (vel_grad(0,2) - vel_grad(2,0)) + - R_yz * (vel_grad(1,2) - vel_grad(2,1)) : 0.0); - const su2double energy_backscatter_ratio = energy_backscatter / (energy_res_to_mod + 1e-12); + const su2double energy_res_to_mod = nu_t * strainMag2; + const auto vorticity = Node_Flow->GetVorticity(iPoint); + const su2double energy_backscatter = R_xy*vorticity[2] - R_xz*vorticity[1] + R_yz*vorticity[0]; + const su2double energy_backscatter_ratio = energy_backscatter / (energy_res_to_mod + 1e-10); SetVolumeOutputValue("ENERGY_BACKSCATTER_RATIO", iPoint, energy_backscatter_ratio); } } @@ -1760,10 +1755,20 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con const su2double mag = config->GetSBS_Cmag(); const su2double threshold = 0.9; su2double tke_estim = 0.0; - if (lesSensor > threshold) tke_estim = pow(nu_t/DES_lengthscale, 2.0); + su2double strainMag2 = 0.0; + for (unsigned long iDim = 0; iDim < nDim; iDim++) { + strainMag2 += pow(vel_grad(iDim, iDim), 2); + } + strainMag2 += 2.0*pow(0.5*(vel_grad(0,1) + vel_grad(1,0)), 2); + if (nDim == 3) { + strainMag2 += 2.0*pow(0.5*(vel_grad(0,2) + vel_grad(2,0)), 2); + strainMag2 += 2.0*pow(0.5*(vel_grad(1,2) + vel_grad(2,1)), 2); + } + strainMag2 *= 2.0; + if (lesSensor > threshold) tke_estim = sqrt(strainMag2) * nu_t; const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); const su2double csi_y = Node_Turb->GetSolution(iPoint, 2); - const su2double csi_z = (nDim==3) ? Node_Turb->GetSolution(iPoint, 3) : 0.0; + const su2double csi_z = Node_Turb->GetSolution(iPoint, 3); const su2double R_xy = mag * tke_estim * csi_z; const su2double R_xz = - mag * tke_estim * csi_y; const su2double R_yz = mag * tke_estim * csi_x; diff --git a/SU2_CFD/src/solvers/CIncEulerSolver.cpp b/SU2_CFD/src/solvers/CIncEulerSolver.cpp index 5b25796947c..f771594113d 100644 --- a/SU2_CFD/src/solvers/CIncEulerSolver.cpp +++ b/SU2_CFD/src/solvers/CIncEulerSolver.cpp @@ -959,7 +959,7 @@ void CIncEulerSolver::CommonPreprocessing(CGeometry *geometry, CSolver **solver_ const bool implicit = (config->GetKind_TimeIntScheme() == EULER_IMPLICIT); const bool center = (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED); - const bool center_jst = (config->GetKind_Centered_Flow() == CENTERED::JST) && (iMesh == MESH_0); + const bool center_jst = (config->GetKind_Centered_Flow() == CENTERED::JST || config->GetKind_Centered_Flow() == CENTERED::LD2) && (iMesh == MESH_0); const bool outlet = (config->GetnMarker_Outlet() != 0); /*--- Set the primitive variables ---*/ @@ -1132,9 +1132,9 @@ void CIncEulerSolver::Centered_Residual(CGeometry *geometry, CSolver **solver_co unsigned long iPoint, jPoint; const bool implicit = (config->GetKind_TimeIntScheme() == EULER_IMPLICIT); - const bool jst_scheme = ((config->GetKind_Centered_Flow() == CENTERED::JST) && (iMesh == MESH_0)); + const bool jst_scheme = ((config->GetKind_Centered_Flow() == CENTERED::JST || config->GetKind_Centered_Flow() == CENTERED::LD2) && (iMesh == MESH_0)); const bool bounded_scalar = config->GetBounded_Scalar(); - const bool LD2_Scheme = config->GetLD2_Scheme(); + const bool LD2_Scheme = (config->GetKind_Centered_Flow() == CENTERED::LD2); /*--- For hybrid parallel AD, pause preaccumulation if there is shared reading of * variables, otherwise switch to the faster adjoint evaluation mode. ---*/ diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index b798d98c3c6..6bb898f89e5 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -57,8 +57,13 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor /*--- Add Langevin equations if the Stochastic Backscatter Model is used ---*/ - bool backscatter = config->GetStochastic_Backscatter(); - if (backscatter) { nVar += nDim; nVarGrad = nPrimVar = nVar; } + if (config->GetStochastic_Backscatter()) { + if (nDim == 3) { + nVar += nDim; nVarGrad = nPrimVar = nVar; + } else { + SU2_MPI::Error("Stochastic Backscatter Model available for 3D flows only.", CURRENT_FUNCTION);; + } + } /*--- Single grid simulation ---*/ @@ -115,7 +120,7 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor } Solution_Inf[0] = nu_tilde_Inf; - if (backscatter) { + if (config->GetStochastic_Backscatter()) { for (unsigned short iVar = 1; iVar < nVar; iVar++) { Solution_Inf[iVar] = 0.0; } @@ -123,7 +128,6 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor /*--- Factor_nu_Engine ---*/ Factor_nu_Engine = config->GetNuFactor_Engine(); - nu_tilde_Engine = new su2double [nVar] (); nu_tilde_Engine[0] = Factor_nu_Engine*Viscosity_Inf/Density_Inf; if (config->GetSAParsedOptions().bc) { nu_tilde_Engine[0] = 0.005*Factor_nu_Engine*Viscosity_Inf/Density_Inf; @@ -131,7 +135,6 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor /*--- Factor_nu_ActDisk ---*/ Factor_nu_ActDisk = config->GetNuFactor_Engine(); - nu_tilde_ActDisk = new su2double [nVar] (); nu_tilde_ActDisk[0] = Factor_nu_ActDisk*Viscosity_Inf/Density_Inf; /*--- Eddy viscosity at infinity ---*/ @@ -142,16 +145,6 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor fv1 = Ji_3/(Ji_3+cv1_3); muT_Inf = Density_Inf*fv1*nu_tilde_Inf; - /*--- Allocate memory for boundary conditions ---*/ - ext_AverageNu = new su2double [nVar] (); - Res_Wall = new su2double [nVar] (); - Jacobian_i = new su2double* [nVar]; - for (unsigned short iVar = 0; iVar < nVar; iVar++) { - Jacobian_i[iVar] = new su2double [nVar] (); - } - nu_tilde_inturb = new su2double [nVar] (); - nu_tilde_WF = new su2double [nVar] (); - /*--- Initialize the solution to the far-field state everywhere. ---*/ nodes = new CTurbSAVariable(nu_tilde_Inf, muT_Inf, nPoint, nDim, nVar, config); @@ -180,7 +173,7 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor Inlet_TurbVars.resize(nMarker); for (unsigned long iMarker = 0; iMarker < nMarker; iMarker++) { Inlet_TurbVars[iMarker].resize(nVertex[iMarker],nVar) = nu_tilde_Inf; - if (backscatter) { + if (config->GetStochastic_Backscatter()) { for (unsigned long iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { for (unsigned short iVar = 1; iVar < nVar; iVar++) { Inlet_TurbVars[iMarker](iVertex,iVar) = 0.0; @@ -570,6 +563,7 @@ void CTurbSASolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_conta su2double coeff = (nu_total/sigma); su2double RoughWallBC = nodes->GetSolution(iPoint,0)/(0.03*Roughness_Height); + su2double Res_Wall[MAXNVAR] = {0.0}; Res_Wall[0] = coeff*RoughWallBC*Area; LinSysRes.SubtractBlock(iPoint, Res_Wall); @@ -1143,9 +1137,8 @@ void CTurbSASolver::BC_Inlet_MixingPlane(CGeometry *geometry, CSolver **solver_c /*--- Loop over all the vertices on this boundary marker ---*/ for (auto iSpan = 0u; iSpan < nSpanWiseSections ; iSpan++){ - su2double extAverageNu = solver_container[FLOW_SOL]->GetExtAverageNu(val_marker, iSpan); - - ext_AverageNu[0] = extAverageNu; + su2double extAverageNu[MAXNVAR] = {0.0}; + extAverageNu[0] = solver_container[FLOW_SOL]->GetExtAverageNu(val_marker, iSpan); /*--- Loop over all the vertices on this boundary marker ---*/ @@ -1181,7 +1174,7 @@ void CTurbSASolver::BC_Inlet_MixingPlane(CGeometry *geometry, CSolver **solver_c /*--- Set the turbulent variable states (prescribed for an inflow) ---*/ - conv_numerics->SetScalarVar(nodes->GetSolution(iPoint), ext_AverageNu); + conv_numerics->SetScalarVar(nodes->GetSolution(iPoint), extAverageNu); /*--- Set various other quantities in the conv_numerics class ---*/ @@ -1211,7 +1204,7 @@ void CTurbSASolver::BC_Inlet_MixingPlane(CGeometry *geometry, CSolver **solver_c /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ - visc_numerics->SetScalarVar(nodes->GetSolution(iPoint), ext_AverageNu); + visc_numerics->SetScalarVar(nodes->GetSolution(iPoint), extAverageNu); visc_numerics->SetScalarVarGradient(nodes->GetGradient(iPoint), nodes->GetGradient(iPoint)); @@ -1250,7 +1243,8 @@ void CTurbSASolver::BC_Inlet_Turbo(CGeometry *geometry, CSolver **solver_contain FluidModel->SetTDState_Prho(pressure, rho); su2double muLam = FluidModel->GetLaminarViscosity(); - su2double nu_tilde = Factor_nu_Inf*muLam/rho; + su2double nu_tilde[MAXNVAR] = {0.0}; + nu_tilde[0] = Factor_nu_Inf*muLam/rho; /*--- Loop over all the vertices on this boundary marker ---*/ @@ -1286,9 +1280,7 @@ void CTurbSASolver::BC_Inlet_Turbo(CGeometry *geometry, CSolver **solver_contain /*--- Set the turbulent variable states (prescribed for an inflow) ---*/ - nu_tilde_inturb[0] = nu_tilde; - - conv_numerics->SetScalarVar(nodes->GetSolution(iPoint), nu_tilde_inturb); + conv_numerics->SetScalarVar(nodes->GetSolution(iPoint), nu_tilde); if (dynamic_grid) conv_numerics->SetGridVel(geometry->nodes->GetGridVel(iPoint), @@ -1318,7 +1310,7 @@ void CTurbSASolver::BC_Inlet_Turbo(CGeometry *geometry, CSolver **solver_contain /*--- Turbulent variables w/o reconstruction, and its gradients ---*/ - visc_numerics->SetScalarVar(nodes->GetSolution(iPoint), nu_tilde_inturb); + visc_numerics->SetScalarVar(nodes->GetSolution(iPoint), nu_tilde); visc_numerics->SetScalarVarGradient(nodes->GetGradient(iPoint), nodes->GetGradient(iPoint)); @@ -1409,9 +1401,9 @@ void CTurbSASolver::SetTurbVars_WF(CGeometry *geometry, CSolver **solver_contain if (counter > max_iter) break; } - nu_tilde_WF[0] = nu_til; - - nodes->SetSolution_Old(iPoint_Neighbor, nu_tilde_WF); + su2double nuTil[MAXNVAR] = {0.0}; + nuTil[0] = nu_til; + nodes->SetSolution_Old(iPoint_Neighbor, nuTil); LinSysRes.SetBlock_Zero(iPoint_Neighbor); /*--- includes 1 in the diagonal ---*/ @@ -1646,22 +1638,31 @@ void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) const su2double threshold = 0.9; SU2_OMP_FOR_DYN(omp_chunk_size) - for (auto iPoint = 0ul; iPoint < nPointDomain; iPoint++){ - const auto coord = geometry->nodes->GetCoord(iPoint); - su2double coordSum = (coord[0] + coord[1] + ((nDim == 3) ? coord[2] : 0.0)) * 1e6; - unsigned long coordHash = std::nearbyint(coordSum); - for (auto iDim = 0u; iDim < nDim; iDim++){ - unsigned long seed = RandomToolbox::GetSeed(coordHash, iDim+1, timeIter+1); - std::mt19937 gen(seed); + for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++){ + unsigned long iPointGlobal = geometry->nodes->GetGlobalIndex(iPoint); + for (unsigned short iDim = 0; iDim < nDim; iDim++){ su2double lesSensor = nodes->GetLES_Mode(iPoint); - su2double rnd = 0.0; - if (lesSensor > threshold) rnd = RandomToolbox::GetRandomNormal(gen); + su2double rnd = (lesSensor>threshold) ? RandomToolbox::GetNormal(iPointGlobal, iDim, timeIter) : 0.0; nodes->SetLangevinSourceTermsOld(iPoint, iDim, rnd); nodes->SetLangevinSourceTerms(iPoint, iDim, rnd); } } END_SU2_OMP_FOR + SU2_OMP_FOR_DYN(omp_chunk_size) + for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + for (unsigned long iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + unsigned long iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + nodes->SetLangevinSourceTermsOld(iPoint, iDim, 1e3); + nodes->SetLangevinSourceTerms(iPoint, iDim, 0.0); + } + } + } + } + END_SU2_OMP_FOR + } void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geometry) { @@ -1682,7 +1683,7 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet for (unsigned short iDim = 0; iDim < nDim; iDim++) { for (unsigned short iter = 0; iter < maxIter; iter++) { - + /*--- MPI communication. ---*/ InitiateComms(geometry, config, MPI_QUANTITIES::STOCH_SOURCE_LANG); @@ -1694,7 +1695,8 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet SU2_OMP_FOR_DYN(omp_chunk_size) for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { const su2double lesSensor = nodes->GetLES_Mode(iPoint); - if (lesSensor < threshold) continue; + su2double source_i_old = nodes->GetLangevinSourceTermsOld(iPoint, iDim); + if (lesSensor < threshold || source_i_old > 3.0*sourceLim ) continue; local_nPointLES += 1; const su2double DES_LengthScale = nodes->GetDES_LengthScale(iPoint); su2double maxDelta = DES_LengthScale / constDES; @@ -1703,7 +1705,6 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet su2double b2 = b * b; su2double volume_iPoint = geometry->nodes->GetVolume(iPoint); su2double source_i = nodes->GetLangevinSourceTerms(iPoint, iDim); - su2double source_i_old = nodes->GetLangevinSourceTermsOld(iPoint, iDim); auto coord_i = geometry->nodes->GetCoord(iPoint); /*--- Assemble system matrix. ---*/ @@ -1737,9 +1738,9 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet su2double globalResNorm = 0.0; unsigned long global_nPointLES = 0; - SU2_MPI::Allreduce(&local_nPointLES, &global_nPointLES, 1, MPI_INT, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&local_nPointLES, &global_nPointLES, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); SU2_MPI::Allreduce(&localResNorm, &globalResNorm, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - globalResNorm = sqrt(globalResNorm / global_nPointLES); + globalResNorm = (global_nPointLES==0) ? 0.0 : sqrt(globalResNorm / global_nPointLES); if (rank == MASTER_NODE) { if (iter == 0) { @@ -1779,9 +1780,9 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet su2double mean_check_notSmoothed = 0.0; for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { const su2double lesSensor = nodes->GetLES_Mode(iPoint); - if (lesSensor < threshold) continue; - su2double source = nodes->GetLangevinSourceTerms(iPoint, iDim); su2double source_notSmoothed = nodes->GetLangevinSourceTermsOld(iPoint, iDim); + if (lesSensor < threshold || source_notSmoothed > 3.0*sourceLim) continue; + su2double source = nodes->GetLangevinSourceTerms(iPoint, iDim); mean_check_old += source; var_check_old += source * source; mean_check_notSmoothed += source_notSmoothed; @@ -1851,10 +1852,24 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet var_check_notSmoothed_G /= global_nPointLES; var_check_notSmoothed_G -= mean_check_notSmoothed_G * mean_check_notSmoothed_G; if (rank == MASTER_NODE) { - cout << "Mean of stochastic source term before scaling: " << mean_check_old_G-mean_check_notSmoothed_G <<". After scaling: " << mean_check_new_G-mean_check_notSmoothed_G << "." << endl; - cout << "Variance of stochastic source term before scaling: " << var_check_old_G/var_check_notSmoothed_G <<". After scaling: " << var_check_new_G/var_check_notSmoothed_G << "." << endl; + cout << "Mean of stochastic source term in Langevin equations: " << endl; + cout << " Uncorrelated --> " << mean_check_notSmoothed_G << "." << endl; + cout << " Smoothed before scaling --> " << mean_check_old_G << "." << endl; + cout << " Smoothed after scaling --> " << mean_check_new_G << "." << endl; + cout << "Variance of stochastic source term in Langevin equations: " << endl; + cout << " Uncorrelated --> " << var_check_notSmoothed_G << "." << endl; + cout << " Smoothed before scaling --> " << var_check_old_G << "." << endl; + cout << " Smoothed after scaling --> " << var_check_new_G << "." << endl; cout << endl; } + for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { + const su2double lesSensor = nodes->GetLES_Mode(iPoint); + su2double source_notSmoothed = nodes->GetLangevinSourceTermsOld(iPoint, iDim); + su2double source = nodes->GetLangevinSourceTerms(iPoint, iDim); + if (lesSensor < threshold || source_notSmoothed > 3.0*sourceLim) continue; + source -= mean_check_new_G; + nodes->SetLangevinSourceTerms(iPoint, iDim, source); + } } break; diff --git a/SU2_CFD/src/variables/CIncNSVariable.cpp b/SU2_CFD/src/variables/CIncNSVariable.cpp index c2b019aa47f..fd2cb97c60b 100644 --- a/SU2_CFD/src/variables/CIncNSVariable.cpp +++ b/SU2_CFD/src/variables/CIncNSVariable.cpp @@ -37,7 +37,7 @@ CIncNSVariable::CIncNSVariable(su2double pressure, const su2double *velocity, su StrainMag.resize(nPoint); Tau_Wall.resize(nPoint) = su2double(-1.0); DES_LengthScale.resize(nPoint) = su2double(0.0); - LES_Mode.resize(nPoint) = su2double(0.0); + lesMode.resize(nPoint) = su2double(0.0); Max_Lambda_Visc.resize(nPoint); /*--- Allocate memory for the AuxVar and its gradient. See e.g. CIncEulerSolver::Source_Residual: * Axisymmetric: total-viscosity * y-vel / y-coord diff --git a/SU2_CFD/src/variables/CNEMONSVariable.cpp b/SU2_CFD/src/variables/CNEMONSVariable.cpp index 31d40c355f2..3ae287e9d4f 100644 --- a/SU2_CFD/src/variables/CNEMONSVariable.cpp +++ b/SU2_CFD/src/variables/CNEMONSVariable.cpp @@ -70,7 +70,7 @@ CNEMONSVariable::CNEMONSVariable(su2double val_pressure, StrainMag.resize(nPoint) = su2double(0.0); Tau_Wall.resize(nPoint) = su2double(-1.0); DES_LengthScale.resize(nPoint) = su2double(0.0); - LES_Mode.resize(nPoint) = su2double(0.0); + lesMode.resize(nPoint) = su2double(0.0); Roe_Dissipation.resize(nPoint) = su2double(0.0); Vortex_Tilting.resize(nPoint) = su2double(0.0); Max_Lambda_Visc.resize(nPoint) = su2double(0.0); diff --git a/SU2_CFD/src/variables/CNSVariable.cpp b/SU2_CFD/src/variables/CNSVariable.cpp index 81aab2e70e9..951c1c0cff8 100644 --- a/SU2_CFD/src/variables/CNSVariable.cpp +++ b/SU2_CFD/src/variables/CNSVariable.cpp @@ -39,7 +39,7 @@ CNSVariable::CNSVariable(su2double density, const su2double *velocity, su2double StrainMag.resize(nPoint) = su2double(0.0); Tau_Wall.resize(nPoint) = su2double(-1.0); DES_LengthScale.resize(nPoint) = su2double(0.0); - LES_Mode.resize(nPoint) = su2double(0.0); + lesMode.resize(nPoint) = su2double(0.0); Roe_Dissipation.resize(nPoint) = su2double(0.0); Vortex_Tilting.resize(nPoint) = su2double(0.0); Max_Lambda_Visc.resize(nPoint) = su2double(0.0); diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index 70651696ed3..8f107936725 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -39,7 +39,7 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi } else { for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { Solution_Old(iPoint, 0) = Solution(iPoint, 0) = val_nu_tilde; - for (unsigned short iVar = 1; iVar < nVar; iVar++) { + for (unsigned long iVar = 1; iVar < nVar; iVar++) { Solution_Old(iPoint, iVar) = Solution(iPoint, iVar) = 0.0; } } @@ -57,10 +57,10 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi } DES_LengthScale.resize(nPoint) = su2double(0.0); - LES_Mode.resize(nPoint) = su2double(0.0); + lesMode.resize(nPoint) = su2double(0.0); Vortex_Tilting.resize(nPoint); stochSource.resize(nPoint, nDim) = su2double(0.0); - stochSource_old.resize(nPoint, nDim) = su2double(0.0); + stochSourceOld.resize(nPoint, nDim) = su2double(0.0); besselIntegral.resize(nPoint); } diff --git a/config_template.cfg b/config_template.cfg index 52948756313..c04f48910b7 100644 --- a/config_template.cfg +++ b/config_template.cfg @@ -1670,12 +1670,9 @@ SMOOTH_GEOMETRY= 0 % % Convective numerical method (JST, JST_KE, JST_MAT, LAX-FRIEDRICH, ROE, AUSM, % AUSMPLUSUP, AUSMPLUSUP2, AUSMPLUSM, HLLC, TURKEL_PREC, -% SW, MSW, FDS, SLAU, SLAU2, L2ROE, LMROE) +% SW, MSW, FDS, SLAU, SLAU2, L2ROE, LMROE, LD2) CONV_NUM_METHOD_FLOW= ROE % -% Option to employ the Low-Dissipation Low-Dispersion (LD2) scheme for incompressible flows (NO, YES) -LD2_OPTION= NO -% % Roe Low Dissipation function for Hybrid RANS/LES simulations (FD, NTS, NTS_DUCROS) ROE_LOW_DISSIPATION= FD % From 84c42d25e95c6dd0b25a849388da0d8e34945fc4 Mon Sep 17 00:00:00 2001 From: paan882 Date: Fri, 30 Jan 2026 14:42:45 +0100 Subject: [PATCH 29/70] Minor fixes - Redefine default values for backscatter parameters. - Introduce RANS-LES blending factor for source terms in Langevin equations. - Fix bug in MPI communication of slope limiters between periodic faces. --- Common/src/CConfig.cpp | 4 +-- .../numerics/turbulent/turb_sources.hpp | 5 +++ SU2_CFD/src/solvers/CSolver.cpp | 4 +-- SU2_CFD/src/solvers/CTurbSASolver.cpp | 36 +++++++++---------- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index f9673d4ae15..0148eb90dbd 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2961,7 +2961,7 @@ void CConfig::SetConfig_Options() { addDoubleOption("DES_CONST", Const_DES, 0.65); /* DESCRIPTION: SBS lengthscale coefficient */ - addDoubleOption("SBS_LENGTHSCALE_COEFF", SBS_Cdelta, 0.1); + addDoubleOption("SBS_LENGTHSCALE_COEFF", SBS_Cdelta, 0.02); /* DESCRIPTION: Maximum number of smoothing iterations for SBS model. */ addUnsignedShortOption("SBS_MAX_ITER_SMOOTH", SBS_maxIterSmooth, 100); @@ -2982,7 +2982,7 @@ void CConfig::SetConfig_Options() { addBoolOption("ENFORCE_LES", enforceLES, false); /* DESCRIPTION: Specify if the stochastic source term must be included in the turbulence model equation */ - addBoolOption("STOCH_SOURCE_NU", stochSourceNu, true); + addBoolOption("STOCH_SOURCE_NU", stochSourceNu, false); /* DESCRIPTION: Enable diagnostics of the stochastic source term in Langevin equations. */ addBoolOption("STOCH_SOURCE_DIAGNOSTICS", stochSourceDiagnostics, false); diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index a662a315856..28961c0d270 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -122,12 +122,17 @@ class CSourceBase_TurbSA : public CNumerics { const su2double& nue = ScalarVar_i[0]; const auto& density = V_i[idx.Density()]; const su2double threshold = 0.9; + const su2double limiterRANS = 0.1; + const su2double timeStepFrac = 0.2; const su2double nut = max(nue*var.fv1, 1e-10); const su2double delta = lengthScale/DES_const; if (delta > 1e-10) { su2double tTurb = ct*pow(delta, 2)/nut; + su2double blendingFactor = DES_const*DES_const/ct*(1.0-lesMode_i) + lesMode_i; + tTurb *= blendingFactor; + tTurb = max(timeStep*timeStepFrac, min(tTurb, timeStep/timeStepFrac)); su2double tRat = timeStep / tTurb; su2double corrFac = 1.0; diff --git a/SU2_CFD/src/solvers/CSolver.cpp b/SU2_CFD/src/solvers/CSolver.cpp index f40b9453d41..d4a23d6de3f 100644 --- a/SU2_CFD/src/solvers/CSolver.cpp +++ b/SU2_CFD/src/solvers/CSolver.cpp @@ -363,8 +363,8 @@ void CSolver::InitiatePeriodicComms(CGeometry *geometry, auto *Diff = new su2double[nVar]; auto *Und_Lapl = new su2double[nVar]; - auto *Sol_Min = new su2double[nPrimVarGrad]; - auto *Sol_Max = new su2double[nPrimVarGrad]; + auto *Sol_Min = new su2double[nVar]; + auto *Sol_Max = new su2double[nVar]; auto *rotPrim_i = new su2double[nPrimVar]; auto *rotPrim_j = new su2double[nPrimVar]; diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 6bb898f89e5..57a39f00e7b 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -61,7 +61,7 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor if (nDim == 3) { nVar += nDim; nVarGrad = nPrimVar = nVar; } else { - SU2_MPI::Error("Stochastic Backscatter Model available for 3D flows only.", CURRENT_FUNCTION);; + SU2_MPI::Error("Stochastic Backscatter Model available for 3D flows only.", CURRENT_FUNCTION); } } @@ -1829,15 +1829,24 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet var_check_new += source * source; nodes->SetLangevinSourceTerms(iPoint, iDim, source); } + su2double mean_check_new_G = 0.0; + SU2_MPI::Allreduce(&mean_check_new, &mean_check_new_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + mean_check_new_G /= global_nPointLES; + for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { + const su2double lesSensor = nodes->GetLES_Mode(iPoint); + su2double source_notSmoothed = nodes->GetLangevinSourceTermsOld(iPoint, iDim); + su2double source = nodes->GetLangevinSourceTerms(iPoint, iDim); + if (lesSensor < threshold || source_notSmoothed > 3.0*sourceLim) continue; + source -= mean_check_new_G; + nodes->SetLangevinSourceTerms(iPoint, iDim, source); + } if (config->GetStochSourceDiagnostics()) { su2double mean_check_old_G = 0.0; - su2double mean_check_new_G = 0.0; su2double mean_check_notSmoothed_G = 0.0; su2double var_check_old_G = 0.0; su2double var_check_new_G = 0.0; su2double var_check_notSmoothed_G = 0.0; SU2_MPI::Allreduce(&mean_check_old, &mean_check_old_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - SU2_MPI::Allreduce(&mean_check_new, &mean_check_new_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); SU2_MPI::Allreduce(&mean_check_notSmoothed, &mean_check_notSmoothed_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); SU2_MPI::Allreduce(&var_check_old, &var_check_old_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); SU2_MPI::Allreduce(&var_check_new, &var_check_new_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); @@ -1845,7 +1854,6 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet mean_check_old_G /= global_nPointLES; var_check_old_G /= global_nPointLES; var_check_old_G -= mean_check_old_G * mean_check_old_G; - mean_check_new_G /= global_nPointLES; var_check_new_G /= global_nPointLES; var_check_new_G -= mean_check_new_G * mean_check_new_G; mean_check_notSmoothed_G /= global_nPointLES; @@ -1853,23 +1861,15 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet var_check_notSmoothed_G -= mean_check_notSmoothed_G * mean_check_notSmoothed_G; if (rank == MASTER_NODE) { cout << "Mean of stochastic source term in Langevin equations: " << endl; - cout << " Uncorrelated --> " << mean_check_notSmoothed_G << "." << endl; - cout << " Smoothed before scaling --> " << mean_check_old_G << "." << endl; - cout << " Smoothed after scaling --> " << mean_check_new_G << "." << endl; + cout << " Uncorrelated --> " << mean_check_notSmoothed_G << endl; + cout << " Smoothed before scaling --> " << mean_check_old_G << endl; + cout << " Smoothed after scaling --> " << mean_check_new_G << " (subtracted from stochastic field to guarantee zero mean)" << endl; cout << "Variance of stochastic source term in Langevin equations: " << endl; - cout << " Uncorrelated --> " << var_check_notSmoothed_G << "." << endl; - cout << " Smoothed before scaling --> " << var_check_old_G << "." << endl; - cout << " Smoothed after scaling --> " << var_check_new_G << "." << endl; + cout << " Uncorrelated --> " << var_check_notSmoothed_G << endl; + cout << " Smoothed before scaling --> " << var_check_old_G << endl; + cout << " Smoothed after scaling --> " << var_check_new_G << endl; cout << endl; } - for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { - const su2double lesSensor = nodes->GetLES_Mode(iPoint); - su2double source_notSmoothed = nodes->GetLangevinSourceTermsOld(iPoint, iDim); - su2double source = nodes->GetLangevinSourceTerms(iPoint, iDim); - if (lesSensor < threshold || source_notSmoothed > 3.0*sourceLim) continue; - source -= mean_check_new_G; - nodes->SetLangevinSourceTerms(iPoint, iDim, source); - } } break; From dc5189daedd562b1a6b77c2622dd8fbb9ec10100 Mon Sep 17 00:00:00 2001 From: paan882 Date: Fri, 13 Feb 2026 17:25:20 +0100 Subject: [PATCH 30/70] Add new features - Add the option to apply the backscatter model only in a bounded box. - Add the option to enforce backscatter where shielding function exceeds user-defined value. - Correct bug in LD2 implementation. - Make style consistent and update configuration template. --- Common/include/CConfig.hpp | 21 ++++++++ Common/src/CConfig.cpp | 31 +++++++++-- SU2_CFD/include/numerics/CNumerics.hpp | 8 +-- .../numerics/turbulent/turb_sources.hpp | 24 +++++---- .../include/solvers/CFVMFlowSolverBase.inl | 3 +- .../src/numerics/flow/convection/centered.cpp | 52 +++++++++---------- SU2_CFD/src/output/CFlowOutput.cpp | 4 +- SU2_CFD/src/solvers/CTurbSASolver.cpp | 36 ++++++++----- config_template.cfg | 10 +++- 9 files changed, 126 insertions(+), 63 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 46a557e17c2..d2435111601 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -1104,6 +1104,9 @@ class CConfig { su2double SBS_Cmag; /*!< \brief Stochastic Backscatter Model intensity coefficient. */ bool stochSourceNu; /*!< \brief Option for including stochastic source term in turbulence model equation (Stochastic Backscatter Model). */ bool stochSourceDiagnostics; /*!< \brief Option for writing diagnostics related to stochastic source terms in Langevin equations (Stochastic Backscatter Model). */ + bool StochBackscatterInBox; /*!< \brief Option for activating the Stochastic Backscatter Model only in a bounded box. */ + su2double StochBackscatterBoxBounds[6]; /*!< \brief Bounds of the box where the Stochastic Backscatter Model is active. */ + su2double stochFdThreshold; /*!< \brief Shielding function lower threshold for application of Stochastic Backscatter Model. */ su2double stochSourceRelax; /*!< \brief Relaxation factor for stochastic source term generation (Stochastic Backscatter Model). */ bool enforceLES; /*!< \brief Option to enforce LES mode in hybrid RANS-LES simulations. */ su2double LES_FilterWidth; /*!< \brief LES filter width for hybrid RANS-LES simulations. */ @@ -9677,6 +9680,24 @@ class CConfig { */ su2double GetSBS_Cmag(void) const { return SBS_Cmag; } + /*! + * \brief Get if the Stochastic Backscatter Model must be applied only in a bounded box. + * \return True if the model is applied in a bounded box. + */ + bool GetStochBackscatterInBox(void) const { return StochBackscatterInBox; } + + /*! + * \brief Get the bounds of the box where the Stochastic Backscatter Model is active. + * \return Bounds of the box where the model is active. + */ + const su2double* GetStochBackscatterBoxBounds(void) const { return StochBackscatterBoxBounds; } + + /*! + * \brief Get shielding function lower threshold for application of Stochastic Backscatter Model. + * \return Shielding function threshold for application of the model. + */ + su2double GetStochFdThreshold(void) const { return stochFdThreshold; } + /*! * \brief Get the type of tape that will be checked in a tape debug run. */ diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 0148eb90dbd..3b1304c73e6 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2982,14 +2982,23 @@ void CConfig::SetConfig_Options() { addBoolOption("ENFORCE_LES", enforceLES, false); /* DESCRIPTION: Specify if the stochastic source term must be included in the turbulence model equation */ - addBoolOption("STOCH_SOURCE_NU", stochSourceNu, false); + addBoolOption("SBS_SOURCE_NU_EQUATION", stochSourceNu, false); - /* DESCRIPTION: Enable diagnostics of the stochastic source term in Langevin equations. */ - addBoolOption("STOCH_SOURCE_DIAGNOSTICS", stochSourceDiagnostics, false); + /* DESCRIPTION: Enable diagnostics of the stochastic source term in Langevin equation. */ + addBoolOption("SBS_SOURCE_DIAGNOSTICS", stochSourceDiagnostics, false); - /* DESCRIPTION: Relaxation factor for the stochastic source term (Stochastic Backscatter Model). */ + /* DESCRIPTION: Relaxation factor for the stochastic source term (Stochastic Backscatter Model) */ addDoubleOption("SBS_RELAXATION_FACTOR", stochSourceRelax, 0.0); + /* DESCRIPTION: Apply Stochastic Backscatter Model only in a bounded box */ + addBoolOption("SBS_IN_BOX", StochBackscatterInBox, false); + + /* DESCRIPTION: Specify extents of box where Stochastic Backscatter Model is active */ + addDoubleArrayOption("SBS_BOX_BOUNDS", 6, false, StochBackscatterBoxBounds); + + /* DESCRIPTION: Shielding function lower threshold for application of Stochastic Backscatter Model */ + addDoubleOption("SBS_FD_LOWER_THRESHOLD", stochFdThreshold, 0.9); + /* DESCRIPTION: Filter width for LES (if negative, it is computed based on the local cell size) */ addDoubleOption("LES_FILTER_WIDTH", LES_FilterWidth, -1.0); @@ -6578,6 +6587,20 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { cout << "Relaxation factor for stochastic source term: " << stochSourceRelax << endl; else cout << "No relaxation factor for stochastic source term." << endl; + if (StochBackscatterInBox) { + cout << "Stochastic Backscatter Model activated only in a bounded box." << endl; + cout << "Box bounds: " << endl; + cout << " X: " << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[0] << " , " + << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[1] << endl; + cout << " Y: " << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[2] << " , " + << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[3] << endl; + cout << " Z: " << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[4] << " , " + << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[5] << endl; + } else { + cout << "Stochastic Backscatter Model activated in the whole computational domain." << endl; + } + if (Kind_HybridRANSLES != SA_DES) + cout << "Stochastic source terms suppressed where the shielding function is lower than: " << setw(5) << setprecision(3) << stochFdThreshold << endl; } else { cout << "OFF" << endl; } diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index 0ec06ced366..d5c11569698 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -667,12 +667,14 @@ class CNumerics { /* --- Calculate stochastic tensor --- */ + su2double stochLim = 3.0; + stochReynStress[0][0] = 0.0; stochReynStress[1][1] = 0.0; stochReynStress[2][2] = 0.0; - stochReynStress[0][1] = Cmag * density * tke * rndVec[2]; - stochReynStress[0][2] = - Cmag * density * tke * rndVec[1]; - stochReynStress[1][2] = Cmag * density * tke * rndVec[0]; + stochReynStress[0][1] = Cmag * density * tke * max(-stochLim, min(stochLim, rndVec[2])); + stochReynStress[0][2] = - Cmag * density * tke * max(-stochLim, min(stochLim, rndVec[1])); + stochReynStress[1][2] = Cmag * density * tke * max(-stochLim, min(stochLim, rndVec[0])); stochReynStress[1][0] = - stochReynStress[1][0]; stochReynStress[2][0] = - stochReynStress[2][0]; stochReynStress[2][1] = - stochReynStress[2][1]; diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index 28961c0d270..e9462a57274 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -117,11 +117,11 @@ class CSourceBase_TurbSA : public CNumerics { */ inline void ResidualStochEquations(su2double timeStep, const su2double ct, su2double lengthScale, su2double DES_const, - const CSAVariables& var, TIME_MARCHING time_marching) { + const CSAVariables& var, TIME_MARCHING time_marching, + su2double threshold) { const su2double& nue = ScalarVar_i[0]; const auto& density = V_i[idx.Density()]; - const su2double threshold = 0.9; const su2double limiterRANS = 0.1; const su2double timeStepFrac = 0.2; const su2double nut = max(nue*var.fv1, 1e-10); @@ -160,12 +160,11 @@ class CSourceBase_TurbSA : public CNumerics { /*! * \brief Include stochastic source term in the Spalart-Allmaras turbulence model equation (Stochastic Backscatter Model). */ - inline void AddStochSource(CSAVariables& var, const su2double Cmag, su2double& prod) { + inline void AddStochSource(CSAVariables& var, const su2double Cmag, su2double threshold, su2double& prod) { su2double nut = ScalarVar_i[0] * var.fv1; su2double tke = 0.0; - const su2double threshold = 0.9; - const su2double limiter = 10.0; + const su2double limiter = 5.0; if (lesMode_i > threshold) tke = nut * StrainMag_i; su2double R12 = Cmag * tke * ScalarVar_i[3]; @@ -174,11 +173,14 @@ class CSourceBase_TurbSA : public CNumerics { su2double RGradU = R12*Vorticity_i[2] - R13*Vorticity_i[1] + R23*Vorticity_i[0]; - su2double stoch_prod_k = - RGradU; - su2double prod_k = nut * StrainMag_i * StrainMag_i; - su2double stoch_prod_nut = min(limiter, max(-limiter, stoch_prod_k/max(prod_k,1e-10))); + su2double stochProdK = - RGradU; + su2double Ji_3 = pow(var.Ji, 3); + su2double Dfv1Dnut = 3.0 * var.fv1 * var.cv1_3 / (var.cv1_3 + Ji_3); + su2double fac = 1.0 / (var.fv1 + ScalarVar_i[0]*Dfv1Dnut); + su2double stochProdNut = stochProdK * dist_i*dist_i/(2.0*ScalarVar_i[0]) * fac; + stochProdNut = max(-limiter*prod, min(limiter*prod, stochProdNut)); - prod *= (1.0 + stoch_prod_nut); + prod += stochProdNut; } @@ -327,7 +329,7 @@ class CSourceBase_TurbSA : public CNumerics { if (config->GetStochastic_Backscatter() && config->GetStochSourceNu()) { su2double intensityCoeff = ComputeStochRelaxFactor(config); - AddStochSource(var, intensityCoeff, Production); + AddStochSource(var, intensityCoeff, config->GetStochFdThreshold(), Production); } Residual[0] = (Production - Destruction) * Volume; @@ -342,7 +344,7 @@ class CSourceBase_TurbSA : public CNumerics { const su2double DES_const = config->GetConst_DES(); const su2double ctau = config->GetSBS_Ctau(); ResidualStochEquations(config->GetDelta_UnstTime(), ctau, dist_i, DES_const, - var, config->GetTime_Marching()); + var, config->GetTime_Marching(), config->GetStochFdThreshold()); } } diff --git a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl index 92f35c463f6..5129e9b8b8e 100644 --- a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl +++ b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl @@ -478,9 +478,8 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome su2double DES_length_j = turbNodes->GetDES_LengthScale(jPoint); su2double lesMode_i = (DES_length_i > 1e-10) ? turbNodes->GetLES_Mode(iPoint) : 0.0; su2double lesMode_j = (DES_length_j > 1e-10) ? turbNodes->GetLES_Mode(jPoint) : 0.0; - const su2double threshold = 0.9; su2double tke_i = 0.0, tke_j = 0.0; - if (max(lesMode_i, lesMode_j) > threshold) { + if (max(lesMode_i, lesMode_j) > config->GetStochFdThreshold()) { su2double eddyVisc_i = turbNodes->GetmuT(iPoint) / nodes->GetDensity(iPoint); su2double eddyVisc_j = turbNodes->GetmuT(jPoint) / nodes->GetDensity(jPoint); su2double strainMag_i = nodes->GetStrainMag(iPoint); diff --git a/SU2_CFD/src/numerics/flow/convection/centered.cpp b/SU2_CFD/src/numerics/flow/convection/centered.cpp index fb3c8ac7b4c..59d904c5605 100644 --- a/SU2_CFD/src/numerics/flow/convection/centered.cpp +++ b/SU2_CFD/src/numerics/flow/convection/centered.cpp @@ -328,7 +328,26 @@ CNumerics::ResidualType<> CCentJSTInc_Flow::ComputeResidual(const CConfig* confi for (iDim = 0; iDim < nDim; iDim++) { Velocity_i[iDim] = V_i[iDim+1]; Velocity_j[iDim] = V_j[iDim+1]; + } + + for (iDim = 0; iDim < nDim; iDim++) { + MeanVelocity[iDim] = 0.5*(Velocity_i[iDim]+Velocity_j[iDim]); + sq_vel_i += 0.5*Velocity_i[iDim]*Velocity_i[iDim]; + sq_vel_j += 0.5*Velocity_j[iDim]*Velocity_j[iDim]; + ProjVelocity_i += Velocity_i[iDim]*Normal[iDim]; + ProjVelocity_j += Velocity_j[iDim]*Normal[iDim]; + Area += Normal[iDim]*Normal[iDim]; } + Area = sqrt(Area); + + /*--- Compute mean values of the variables ---*/ + + MeanDensity = 0.5*(DensityInc_i + DensityInc_j); + MeanPressure = 0.5*(Pressure_i + Pressure_j); + MeanBetaInc2 = 0.5*(BetaInc2_i + BetaInc2_j); + MeanEnthalpy = 0.5*(Enthalpy_i + Enthalpy_j); + MeanCp = 0.5*(Cp_i + Cp_j); + MeanTemperature = 0.5*(Temperature_i + Temperature_j); if (LD2_Scheme) { su2double d_ij[3] = {0.0}; @@ -347,36 +366,15 @@ CNumerics::ResidualType<> CCentJSTInc_Flow::ComputeResidual(const CConfig* confi } } for (iDim = 0; iDim < nDim; iDim++) { - Pressure_i += alpha_LD2 * pressGrad_i[iDim] * d_ij[iDim]; - Pressure_j += alpha_LD2 * pressGrad_j[iDim] * d_ij[iDim]; - Velocity_i[iDim] += alpha_LD2 * (velGrad_i[iDim][0] * d_ij[0] + - velGrad_i[iDim][1] * d_ij[1] + - velGrad_i[iDim][2] * d_ij[2]); - Velocity_j[iDim] -= alpha_LD2 * (velGrad_j[iDim][0] * d_ij[0] + - velGrad_j[iDim][1] * d_ij[1] + - velGrad_j[iDim][2] * d_ij[2]); + MeanVelocity[iDim] += 0.5 * alpha_LD2 * ((velGrad_i[iDim][0] - velGrad_j[iDim][0]) * d_ij[0] + + (velGrad_i[iDim][1] - velGrad_j[iDim][1]) * d_ij[1] + + (velGrad_i[iDim][2] - velGrad_j[iDim][2]) * d_ij[2]); } + MeanPressure += 0.5 * alpha_LD2 * ((pressGrad_i[0] - pressGrad_j[0]) * d_ij[0] + + (pressGrad_i[1] - pressGrad_j[1]) * d_ij[1] + + (pressGrad_i[2] - pressGrad_j[2]) * d_ij[2]); } - for (iDim = 0; iDim < nDim; iDim++) { - MeanVelocity[iDim] = 0.5*(Velocity_i[iDim]+Velocity_j[iDim]); - sq_vel_i += 0.5*Velocity_i[iDim]*Velocity_i[iDim]; - sq_vel_j += 0.5*Velocity_j[iDim]*Velocity_j[iDim]; - ProjVelocity_i += Velocity_i[iDim]*Normal[iDim]; - ProjVelocity_j += Velocity_j[iDim]*Normal[iDim]; - Area += Normal[iDim]*Normal[iDim]; - } - Area = sqrt(Area); - - /*--- Compute mean values of the variables ---*/ - - MeanDensity = 0.5*(DensityInc_i + DensityInc_j); - MeanPressure = 0.5*(Pressure_i + Pressure_j); - MeanBetaInc2 = 0.5*(BetaInc2_i + BetaInc2_j); - MeanEnthalpy = 0.5*(Enthalpy_i + Enthalpy_j); - MeanCp = 0.5*(Cp_i + Cp_j); - MeanTemperature = 0.5*(Temperature_i + Temperature_j); - /*--- We need the derivative of the equation of state to build the preconditioning matrix. For now, the only option is the ideal gas law, but in the future, dRhodT should be in the fluid model. ---*/ diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index e8b7abd04f3..81573093d74 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -1702,7 +1702,7 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1e-10); const su2double lesSensor = Node_Flow->GetLES_Mode(iPoint); const su2double mag = config->GetSBS_Cmag(); - const su2double threshold = 0.9; + const su2double threshold = config->GetStochFdThreshold(); const auto VelocityGradient = Node_Flow->GetVelocityGradient(iPoint); su2double strainMag2 = 0.0; for (unsigned long iDim = 0; iDim < nDim; iDim++) { @@ -1753,7 +1753,7 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1e-10); const su2double lesSensor = Node_Flow->GetLES_Mode(iPoint); const su2double mag = config->GetSBS_Cmag(); - const su2double threshold = 0.9; + const su2double threshold = config->GetStochFdThreshold(); su2double tke_estim = 0.0; su2double strainMag2 = 0.0; for (unsigned long iDim = 0; iDim < nDim; iDim++) { diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 57a39f00e7b..b197f8f8a0e 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1635,16 +1635,32 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) { unsigned long timeIter = config->GetTimeIter(); - const su2double threshold = 0.9; + const su2double threshold = config->GetStochFdThreshold(); + const su2double dummySource = 1e3; + bool stochBackscatterInBox = config->GetStochBackscatterInBox(); + bool insideBox = true; SU2_OMP_FOR_DYN(omp_chunk_size) for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++){ unsigned long iPointGlobal = geometry->nodes->GetGlobalIndex(iPoint); for (unsigned short iDim = 0; iDim < nDim; iDim++){ su2double lesSensor = nodes->GetLES_Mode(iPoint); - su2double rnd = (lesSensor>threshold) ? RandomToolbox::GetNormal(iPointGlobal, iDim, timeIter) : 0.0; - nodes->SetLangevinSourceTermsOld(iPoint, iDim, rnd); - nodes->SetLangevinSourceTerms(iPoint, iDim, rnd); + const auto coord = geometry->nodes->GetCoord(iPoint); + if (stochBackscatterInBox) { + auto sbsBoxBounds = config->GetStochBackscatterBoxBounds(); + bool insideBoxX = (coord[0]>=sbsBoxBounds[0] && coord[0]<=sbsBoxBounds[1]); + bool insideBoxY = (coord[1]>=sbsBoxBounds[2] && coord[1]<=sbsBoxBounds[3]); + bool insideBoxZ = (coord[2]>=sbsBoxBounds[4] && coord[2]<=sbsBoxBounds[5]); + insideBox = (insideBoxX && insideBoxY && insideBoxZ); + } + if (lesSensor>threshold && insideBox) { + su2double rnd = RandomToolbox::GetNormal(iPointGlobal, iDim, timeIter); + nodes->SetLangevinSourceTermsOld(iPoint, iDim, rnd); + nodes->SetLangevinSourceTerms(iPoint, iDim, rnd); + } else { + nodes->SetLangevinSourceTermsOld(iPoint, iDim, dummySource); + nodes->SetLangevinSourceTerms(iPoint, iDim, 0.0); + } } } END_SU2_OMP_FOR @@ -1655,7 +1671,7 @@ void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) unsigned long iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { for (unsigned short iDim = 0; iDim < nDim; iDim++) { - nodes->SetLangevinSourceTermsOld(iPoint, iDim, 1e3); + nodes->SetLangevinSourceTermsOld(iPoint, iDim, dummySource); nodes->SetLangevinSourceTerms(iPoint, iDim, 0.0); } } @@ -1676,7 +1692,6 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet const su2double omega = 0.8; unsigned long timeIter = config->GetTimeIter(); unsigned long restartIter = config->GetRestart_Iter(); - const su2double threshold = 0.9; /*--- Start SOR algorithm for the Laplacian smoothing. ---*/ @@ -1694,9 +1709,8 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet SU2_OMP_FOR_DYN(omp_chunk_size) for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { - const su2double lesSensor = nodes->GetLES_Mode(iPoint); su2double source_i_old = nodes->GetLangevinSourceTermsOld(iPoint, iDim); - if (lesSensor < threshold || source_i_old > 3.0*sourceLim ) continue; + if (source_i_old > 3.0*sourceLim) continue; local_nPointLES += 1; const su2double DES_LengthScale = nodes->GetDES_LengthScale(iPoint); su2double maxDelta = DES_LengthScale / constDES; @@ -1779,9 +1793,8 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet su2double var_check_notSmoothed = 0.0; su2double mean_check_notSmoothed = 0.0; for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { - const su2double lesSensor = nodes->GetLES_Mode(iPoint); su2double source_notSmoothed = nodes->GetLangevinSourceTermsOld(iPoint, iDim); - if (lesSensor < threshold || source_notSmoothed > 3.0*sourceLim) continue; + if (source_notSmoothed > 3.0*sourceLim) continue; su2double source = nodes->GetLangevinSourceTerms(iPoint, iDim); mean_check_old += source; var_check_old += source * source; @@ -1833,10 +1846,9 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet SU2_MPI::Allreduce(&mean_check_new, &mean_check_new_G, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); mean_check_new_G /= global_nPointLES; for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { - const su2double lesSensor = nodes->GetLES_Mode(iPoint); su2double source_notSmoothed = nodes->GetLangevinSourceTermsOld(iPoint, iDim); su2double source = nodes->GetLangevinSourceTerms(iPoint, iDim); - if (lesSensor < threshold || source_notSmoothed > 3.0*sourceLim) continue; + if (source_notSmoothed > 3.0*sourceLim) continue; source -= mean_check_new_G; nodes->SetLangevinSourceTerms(iPoint, iDim, source); } diff --git a/config_template.cfg b/config_template.cfg index c04f48910b7..468ccadcc12 100644 --- a/config_template.cfg +++ b/config_template.cfg @@ -203,10 +203,16 @@ SBS_INTENSITY_COEFF= 1.0 SBS_RELAXATION_FACTOR= 0.0 % % Include stochastic source in turbulence model equation (NO, YES) -STOCH_SOURCE_NU= YES +SBS_SOURCE_NU_EQUATION= YES % % Include diagnostics of the stochastic source term in Langevin equations (NO, YES) -STOCH_SOURCE_DIAGNOSTICS= NO +SBS_SOURCE_DIAGNOSTICS= NO +% +% Apply Stochastic Backscatter Model only in a bounded box (NO, YES) +SBS_IN_BOX= NO +% +% Bounds of the box where the Stochastic Backscatter Model is activated (x_min, x_max, y_min, y_max, z_min, z_max) +SBS_BOX_BOUNDS= (0.0, 0.0, 0.0, 0.0, 0.0, 0.0) % % Enforce LES mode in Hybrid RANS-LES Simulations (NO, YES) ENFORCE_LES= NO From cb91b8e54b8e41116ba7cf545256a30581eca41a Mon Sep 17 00:00:00 2001 From: paan882 Date: Mon, 2 Mar 2026 11:53:40 +0100 Subject: [PATCH 31/70] Redefine scaling of stochastic source term - Modify the scaling of the stochastic forcing to include the modeled viscosity. - Fix the computation of the stochastic tensor. - Add the MPI communication of the DES lengthscale. --- Common/include/option_structure.hpp | 1 + Common/src/CConfig.cpp | 22 ++++---- SU2_CFD/include/numerics/CNumerics.hpp | 23 ++++----- .../include/numerics/flow/flow_diffusion.hpp | 2 +- .../numerics/scalar/scalar_convection.hpp | 8 --- .../numerics/turbulent/turb_convection.hpp | 9 ++-- .../numerics/turbulent/turb_sources.hpp | 33 ++++++------ .../include/solvers/CFVMFlowSolverBase.inl | 30 ++++++----- SU2_CFD/src/numerics/flow/flow_diffusion.cpp | 32 ++++++++---- SU2_CFD/src/output/CFlowOutput.cpp | 50 ++++++++----------- SU2_CFD/src/solvers/CSolver.cpp | 10 ++++ SU2_CFD/src/solvers/CTurbSASolver.cpp | 16 ++++-- SU2_CFD/src/variables/CTurbSAVariable.cpp | 4 +- 13 files changed, 123 insertions(+), 117 deletions(-) diff --git a/Common/include/option_structure.hpp b/Common/include/option_structure.hpp index c4a4f6ab604..30d08e35c99 100644 --- a/Common/include/option_structure.hpp +++ b/Common/include/option_structure.hpp @@ -2698,6 +2698,7 @@ enum class MPI_QUANTITIES { GRID_VELOCITY , /*!< \brief Grid velocity communication. */ SOLUTION_EDDY , /*!< \brief Turbulent solution plus eddy viscosity communication. */ STOCH_SOURCE_LANG , /*!< \brief Stochastic source term for Langevin equations communication. */ + DES_LENGTHSCALE , /*!< \brief DES length scale communication. */ SOLUTION_MATRIX , /*!< \brief Matrix solution communication. */ SOLUTION_MATRIXTRANS , /*!< \brief Matrix transposed solution communication. */ NEIGHBORS , /*!< \brief Neighbor point count communication (for JST). */ diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 569a7b40f51..e75251d6fe6 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -6565,16 +6565,18 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { cout << "Backscatter intensity coefficient: " << SBS_Cmag << endl; if (SBS_Cmag < 0.0) SU2_MPI::Error("Backscatter intensity coefficient must be non-negative.", CURRENT_FUNCTION); - cout << "Backscatter lengthscale coefficient: " << SBS_Cdelta << endl; - if (SBS_Cdelta < 0.0) - SU2_MPI::Error("Backscatter lengthscale coefficient must be non-negative.", CURRENT_FUNCTION); - cout << "Backscatter timescale coefficient: " << SBS_Ctau << endl; - if (SBS_Ctau < 0.0) - SU2_MPI::Error("Backscatter timescale coefficient must be non-negative.", CURRENT_FUNCTION); - if (SBS_maxIterSmooth > 0) - cout << "Maximum number of iterations for implicit smoothing: " << SBS_maxIterSmooth << endl; + if (SBS_Ctau > 0.0) + cout << "Backscatter timescale coefficient: " << SBS_Ctau << endl; else - cout << "No smoothing applied to source terms in Langevin equations." << endl; + cout << "Langevin equations not integrated (temporally uncorrelated stochastic field)." << endl; + if (SBS_maxIterSmooth > 0) { + cout << "Maximum number of iterations for implicit smoothing: " << SBS_maxIterSmooth << endl; + cout << "Backscatter lengthscale coefficient: " << SBS_Cdelta << endl; + if (SBS_Cdelta < 0.0) + SU2_MPI::Error("Backscatter lengthscale coefficient must be non-negative.", CURRENT_FUNCTION); + } else { + cout << "No smoothing applied to stochastic source terms in Langevin equations." << endl; + } if (stochSourceNu) cout << "Stochastic source term included in turbulence model equation." << endl; else @@ -6592,8 +6594,6 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[3] << endl; cout << " Z: " << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[4] << " , " << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[5] << endl; - } else { - cout << "Stochastic Backscatter Model activated in the whole computational domain." << endl; } if (Kind_HybridRANSLES != SA_DES) cout << "Stochastic source terms suppressed where the shielding function is lower than: " << setw(5) << setprecision(3) << stochFdThreshold << endl; diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index d5c11569698..824a44eba3c 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -661,23 +661,22 @@ class CNumerics { * \param[in] Cmag - Stochastic backscatter intensity coefficient. * \param[out] stochReynStress - Stochastic tensor (to be added to the Reynolds stress tensor). */ - template - NEVERINLINE static void ComputeStochReynStress(size_t nDim, Scalar density, Scalar tke, - Vector rndVec, Scalar Cmag, Mat& stochReynStress) { + NEVERINLINE static void ComputeStochReynStress(su2double density, su2double tke, su2double rndVec[3], + su2double Cmag, su2double stochReynStress[3][3]) { /* --- Calculate stochastic tensor --- */ su2double stochLim = 3.0; - stochReynStress[0][0] = 0.0; - stochReynStress[1][1] = 0.0; - stochReynStress[2][2] = 0.0; - stochReynStress[0][1] = Cmag * density * tke * max(-stochLim, min(stochLim, rndVec[2])); - stochReynStress[0][2] = - Cmag * density * tke * max(-stochLim, min(stochLim, rndVec[1])); - stochReynStress[1][2] = Cmag * density * tke * max(-stochLim, min(stochLim, rndVec[0])); - stochReynStress[1][0] = - stochReynStress[1][0]; - stochReynStress[2][0] = - stochReynStress[2][0]; - stochReynStress[2][1] = - stochReynStress[2][1]; + stochReynStress[0][0] = 0.0; + stochReynStress[1][1] = 0.0; + stochReynStress[2][2] = 0.0; + stochReynStress[0][1] = - Cmag * density * tke * max(-stochLim, min(stochLim, rndVec[2])); + stochReynStress[0][2] = + Cmag * density * tke * max(-stochLim, min(stochLim, rndVec[1])); + stochReynStress[1][2] = - Cmag * density * tke * max(-stochLim, min(stochLim, rndVec[0])); + stochReynStress[1][0] = - stochReynStress[0][1]; + stochReynStress[2][0] = - stochReynStress[0][2]; + stochReynStress[2][1] = - stochReynStress[1][2]; } diff --git a/SU2_CFD/include/numerics/flow/flow_diffusion.hpp b/SU2_CFD/include/numerics/flow/flow_diffusion.hpp index 57dfea12ff2..870511e70e0 100644 --- a/SU2_CFD/include/numerics/flow/flow_diffusion.hpp +++ b/SU2_CFD/include/numerics/flow/flow_diffusion.hpp @@ -61,7 +61,7 @@ class CAvgGrad_Base : public CNumerics { Mean_Cp, /*!< \brief Mean value of the specific heat capacity at constant pressure. */ Mean_turb_ke, /*!< \brief Mean value of the turbulent kinetic energy. */ Mean_TauWall, /*!< \brief Mean wall shear stress (wall functions). */ - Mean_StochVar[3], /*!< \brief Mean stochastic variables (Stochastic Backscatter Model). */ + Mean_StochVar[3] = {0.0}, /*!< \brief Mean stochastic variables (Stochastic Backscatter Model). */ TauWall_i, TauWall_j, /*!< \brief Wall shear stress at point i and j (wall functions). */ dist_ij_2, /*!< \brief Length of the edge and face, squared */ Edge_Vector[MAXNDIM] = {0.0}; /*!< \brief Vector from point i to point j. */ diff --git a/SU2_CFD/include/numerics/scalar/scalar_convection.hpp b/SU2_CFD/include/numerics/scalar/scalar_convection.hpp index 41d0ca2c5ac..b8d8a640393 100644 --- a/SU2_CFD/include/numerics/scalar/scalar_convection.hpp +++ b/SU2_CFD/include/numerics/scalar/scalar_convection.hpp @@ -52,7 +52,6 @@ class CUpwScalar : public CNumerics { const FlowIndices idx; /*!< \brief Object to manage the access to the flow primitives. */ su2double a0 = 0.0; /*!< \brief The maximum of the face-normal velocity and 0. */ su2double a1 = 0.0; /*!< \brief The minimum of the face-normal velocity and 0. */ - su2double m_ij = 0.0; /*!< \brief Face-normal momentum (Langevin equations). */ su2double Flux[MAXNVAR]; /*!< \brief Final result, diffusive flux/residual. */ su2double* Jacobian_i[MAXNVAR]; /*!< \brief Flux Jacobian w.r.t. node i. */ su2double* Jacobian_j[MAXNVAR]; /*!< \brief Flux Jacobian w.r.t. node j. */ @@ -141,13 +140,6 @@ class CUpwScalar : public CNumerics { a1 = fmin(0.0, q_ij); } - if (config->GetStochastic_Backscatter()) { - m_ij = 0.0; - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - m_ij += 0.5 * (V_i[idx.Density()]*V_i[iDim + idx.Velocity()] + V_j[idx.Density()]*V_j[iDim + idx.Velocity()]) * Normal[iDim]; - } - } - FinishResidualCalc(config); AD::SetPreaccOut(Flux, nVar); diff --git a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp index 2df13c7bd55..d4b5c5d951e 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp @@ -52,7 +52,6 @@ class CUpwSca_TurbSA final : public CUpwScalar { using Base::V_j; using Base::idx; using Base::nVar; - using Base::m_ij; /*! * \brief Adds any extra variables to AD. @@ -64,14 +63,14 @@ class CUpwSca_TurbSA final : public CUpwScalar { * \param[in] config - Definition of the particular problem. */ void FinishResidualCalc(const CConfig* config) override { - if (config->GetStochastic_Backscatter()) { + if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { for (unsigned short iVar = 1; iVar < nVar; iVar++) { - Flux[iVar] = m_ij * 0.5 * (ScalarVar_i[iVar] + ScalarVar_j[iVar]); + Flux[iVar] = (a0 + a1) * 0.5 * (ScalarVar_i[iVar] + ScalarVar_j[iVar]); } for (unsigned short iVar = 0; iVar < nVar; iVar++) { for (unsigned short jVar = 0; jVar < nVar; jVar++) { - Jacobian_i[iVar][jVar] = (iVar == jVar) ? 0.5*m_ij : 0.0; - Jacobian_j[iVar][jVar] = (iVar == jVar) ? 0.5*m_ij : 0.0; + Jacobian_i[iVar][jVar] = (iVar == jVar) ? 0.5*(a0+a1) : 0.0; + Jacobian_j[iVar][jVar] = (iVar == jVar) ? 0.5*(a0+a1) : 0.0; } } } diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index e9462a57274..d344087aeda 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -121,18 +121,12 @@ class CSourceBase_TurbSA : public CNumerics { su2double threshold) { const su2double& nue = ScalarVar_i[0]; - const auto& density = V_i[idx.Density()]; - const su2double limiterRANS = 0.1; - const su2double timeStepFrac = 0.2; const su2double nut = max(nue*var.fv1, 1e-10); const su2double delta = lengthScale/DES_const; if (delta > 1e-10) { su2double tTurb = ct*pow(delta, 2)/nut; - su2double blendingFactor = DES_const*DES_const/ct*(1.0-lesMode_i) + lesMode_i; - tTurb *= blendingFactor; - tTurb = max(timeStep*timeStepFrac, min(tTurb, timeStep/timeStepFrac)); su2double tRat = timeStep / tTurb; su2double corrFac = 1.0; @@ -143,15 +137,15 @@ class CSourceBase_TurbSA : public CNumerics { } su2double scaleFactor = 0.0; - if (lesMode_i > threshold) scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * density * corrFac; + if (lesMode_i > threshold) scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * corrFac; for (unsigned short iVar = 1; iVar < nVar; iVar++) { - Residual[iVar] = scaleFactor * stochSource[iVar-1] - 1.0/tTurb * density * ScalarVar_i[iVar]; + Residual[iVar] = scaleFactor * stochSource[iVar-1] - 1.0/tTurb * ScalarVar_i[iVar]; Residual[iVar] *= Volume; } for (unsigned short iVar = 1; iVar < nVar; iVar++ ) - Jacobian_i[iVar][iVar] = -1.0/tTurb * density * Volume; + Jacobian_i[iVar][iVar] = -1.0/tTurb * Volume; } @@ -165,19 +159,18 @@ class CSourceBase_TurbSA : public CNumerics { su2double nut = ScalarVar_i[0] * var.fv1; su2double tke = 0.0; const su2double limiter = 5.0; - if (lesMode_i > threshold) tke = nut * StrainMag_i; + if (lesMode_i > threshold) tke = pow(nut/dist_i, 2); - su2double R12 = Cmag * tke * ScalarVar_i[3]; - su2double R13 = - Cmag * tke * ScalarVar_i[2]; - su2double R23 = Cmag * tke * ScalarVar_i[1]; + su2double R12 = - Cmag * tke * ScalarVar_i[3]; + su2double R13 = + Cmag * tke * ScalarVar_i[2]; + su2double R23 = - Cmag * tke * ScalarVar_i[1]; su2double RGradU = R12*Vorticity_i[2] - R13*Vorticity_i[1] + R23*Vorticity_i[0]; - su2double stochProdK = - RGradU; su2double Ji_3 = pow(var.Ji, 3); su2double Dfv1Dnut = 3.0 * var.fv1 * var.cv1_3 / (var.cv1_3 + Ji_3); su2double fac = 1.0 / (var.fv1 + ScalarVar_i[0]*Dfv1Dnut); - su2double stochProdNut = stochProdK * dist_i*dist_i/(2.0*ScalarVar_i[0]) * fac; + su2double stochProdNut = RGradU * dist_i*dist_i/(2.0*ScalarVar_i[0]) * fac; stochProdNut = max(-limiter*prod, min(limiter*prod, stochProdNut)); prod += stochProdNut; @@ -191,7 +184,7 @@ class CSourceBase_TurbSA : public CNumerics { * \param[in] config - Definition of the particular problem. */ CSourceBase_TurbSA(unsigned short nDim, const CConfig* config) - : CNumerics(nDim, config->GetStochastic_Backscatter() ? 4 : 1, config), + : CNumerics(nDim, (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) ? 4 : 1, config), idx(nDim, config->GetnSpecies()), options(config->GetSAParsedOptions()), axisymmetric(config->GetAxisymmetric()), @@ -248,11 +241,13 @@ class CSourceBase_TurbSA : public CNumerics { const su2double Ji_3 = Ji_2 * var.Ji; var.fv1 = Ji_3 / (Ji_3 + var.cv1_3); + if (config->GetStochastic_Backscatter() && lesMode_i > 0.0) var.fv1 = 1.0; var.d_fv1 = 3 * Ji_2 * var.cv1_3 / (nu * pow(Ji_3 + var.cv1_3, 2)); /*--- Using a modified relation so as to not change the Shat that depends on fv2. * From NASA turb modeling resource and 2003 paper. ---*/ var.fv2 = 1 - ScalarVar_i[0] / (nu + ScalarVar_i[0] * var.fv1); + if (config->GetStochastic_Backscatter() && lesMode_i > 0.0) var.fv2 = 0.0; var.d_fv2 = -(1 / nu - Ji_2 * var.d_fv1) / pow(1 + var.Ji * var.fv1, 2); /*--- Evaluate Omega with a rotational correction term. ---*/ @@ -281,6 +276,7 @@ class CSourceBase_TurbSA : public CNumerics { var.g_6 = pow(var.g, 6); var.glim = pow((1 + var.cw3_6) / (var.g_6 + var.cw3_6), 1.0 / 6.0); var.fw = var.g * var.glim; + if (config->GetStochastic_Backscatter() && lesMode_i > 0.0) var.fw = 1.0; var.d_g = var.d_r * (1 + var.cw2 * (6 * pow(var.r, 5) - 1)); var.d_fw = var.d_g * var.glim * (1 - var.g_6 / (var.g_6 + var.cw3_6)); @@ -340,10 +336,9 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Compute residual for Langevin equations (Stochastic Backscatter Model). ---*/ - if (config->GetStochastic_Backscatter()) { + if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { const su2double DES_const = config->GetConst_DES(); - const su2double ctau = config->GetSBS_Ctau(); - ResidualStochEquations(config->GetDelta_UnstTime(), ctau, dist_i, DES_const, + ResidualStochEquations(config->GetDelta_UnstTime(), config->GetSBS_Ctau(), dist_i, DES_const, var, config->GetTime_Marching(), config->GetStochFdThreshold()); } } diff --git a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl index f43bce2f793..7fcb8c7c3bd 100644 --- a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl +++ b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl @@ -472,23 +472,21 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome /*--- Stochastic variables from Langevin equations (Stochastic Backscatter Model). ---*/ if (backscatter) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) - numerics->SetStochVar(iDim, turbNodes->GetSolution(iPoint, iDim+1), - turbNodes->GetSolution(jPoint, iDim+1)); - su2double DES_length_i = turbNodes->GetDES_LengthScale(iPoint); - su2double DES_length_j = turbNodes->GetDES_LengthScale(jPoint); - su2double lesMode_i = (DES_length_i > 1e-10) ? turbNodes->GetLES_Mode(iPoint) : 0.0; - su2double lesMode_j = (DES_length_j > 1e-10) ? turbNodes->GetLES_Mode(jPoint) : 0.0; - su2double tke_i = 0.0, tke_j = 0.0; - if (max(lesMode_i, lesMode_j) > config->GetStochFdThreshold()) { - su2double eddyVisc_i = turbNodes->GetmuT(iPoint) / nodes->GetDensity(iPoint); - su2double eddyVisc_j = turbNodes->GetmuT(jPoint) / nodes->GetDensity(jPoint); - su2double strainMag_i = nodes->GetStrainMag(iPoint); - su2double strainMag_j = nodes->GetStrainMag(jPoint); - tke_i = strainMag_i * eddyVisc_i; - tke_j = strainMag_j * eddyVisc_j; + if (config->GetSBS_Ctau() > 0.0) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + numerics->SetStochVar(iDim, turbNodes->GetSolution(iPoint, iDim+1), + turbNodes->GetSolution(jPoint, iDim+1)); + } else { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + numerics->SetStochVar(iDim, turbNodes->GetLangevinSourceTerms(iPoint, iDim), + turbNodes->GetLangevinSourceTerms(jPoint, iDim)); } - numerics->SetTurbKineticEnergy(tke_i, tke_j); + su2double DES_length_i = max(turbNodes->GetDES_LengthScale(iPoint), 1e-10); + su2double DES_length_j = max(turbNodes->GetDES_LengthScale(jPoint), 1e-10); + su2double lesMode_i = turbNodes->GetLES_Mode(iPoint); + su2double lesMode_j = turbNodes->GetLES_Mode(jPoint); + numerics->SetDistance(DES_length_i, DES_length_j); + numerics->SetLES_Mode(lesMode_i, lesMode_j); } /*--- Wall shear stress values (wall functions) ---*/ diff --git a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp index 15ba9809b37..251d92d2e4f 100644 --- a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp +++ b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp @@ -458,14 +458,17 @@ CNumerics::ResidualType<> CAvgGrad_Flow::ComputeResidual(const CConfig* config) /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ - - unsigned long timeIter = config->GetTimeIter(); - unsigned long restartIter = config->GetRestart_Iter(); if (config->GetStochastic_Backscatter()) { for (iDim = 0; iDim < nDim; iDim++) Mean_StochVar[iDim] = 0.5*(stochVar_i[iDim] + stochVar_j[iDim]); + su2double tkeEstim_i = 0.0, tkeEstim_j = 0.0; + if (max(lesMode_i, lesMode_j) > config->GetStochFdThreshold()) { + tkeEstim_i = pow(Eddy_Viscosity_i/dist_i, 2); + tkeEstim_j = pow(Eddy_Viscosity_j/dist_j, 2); + } + su2double Mean_turb_ke_estim = 0.5*(tkeEstim_i + tkeEstim_j); su2double intensityCoeff = ComputeStochRelaxFactor(config); - ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_turb_ke, + ComputeStochReynStress(Mean_PrimVar[nDim+2], Mean_turb_ke_estim, Mean_StochVar, intensityCoeff, stochReynStress); } @@ -645,14 +648,17 @@ CNumerics::ResidualType<> CAvgGradInc_Flow::ComputeResidual(const CConfig* confi /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ - - unsigned long timeIter = config->GetTimeIter(); - unsigned long restartIter = config->GetRestart_Iter(); if (config->GetStochastic_Backscatter()) { for (iDim = 0; iDim < nDim; iDim++) Mean_StochVar[iDim] = 0.5*(stochVar_i[iDim] + stochVar_j[iDim]); + su2double tkeEstim_i = 0.0, tkeEstim_j = 0.0; + if (max(lesMode_i, lesMode_j) > config->GetStochFdThreshold()) { + tkeEstim_i = pow(Eddy_Viscosity_i/dist_i, 2); + tkeEstim_j = pow(Eddy_Viscosity_j/dist_j, 2); + } + su2double Mean_turb_ke_estim = 0.5*(tkeEstim_i + tkeEstim_j); su2double intensityCoeff = ComputeStochRelaxFactor(config); - ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_turb_ke, + ComputeStochReynStress(Mean_PrimVar[nDim+2], Mean_turb_ke_estim, Mean_StochVar, intensityCoeff, stochReynStress); } @@ -984,13 +990,17 @@ CNumerics::ResidualType<> CGeneralAvgGrad_Flow::ComputeResidual(const CConfig* c /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ - unsigned long timeIter = config->GetTimeIter(); - unsigned long restartIter = config->GetRestart_Iter(); if (config->GetStochastic_Backscatter()) { for (iDim = 0; iDim < nDim; iDim++) Mean_StochVar[iDim] = 0.5*(stochVar_i[iDim] + stochVar_j[iDim]); + su2double tkeEstim_i = 0.0, tkeEstim_j = 0.0; + if (max(lesMode_i, lesMode_j) > config->GetStochFdThreshold()) { + tkeEstim_i = pow(Eddy_Viscosity_i/dist_i, 2); + tkeEstim_j = pow(Eddy_Viscosity_j/dist_j, 2); + } + su2double Mean_turb_ke_estim = 0.5*(tkeEstim_i + tkeEstim_j); su2double intensityCoeff = ComputeStochRelaxFactor(config); - ComputeStochReynStress(nDim, Mean_PrimVar[nDim+2], Mean_turb_ke, + ComputeStochReynStress(Mean_PrimVar[nDim+2], Mean_turb_ke_estim, Mean_StochVar, intensityCoeff, stochReynStress); } diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index 81573093d74..3b54c779641 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -1032,7 +1032,7 @@ void CFlowOutput::AddHistoryOutputFields_ScalarRMS_RES(const CConfig* config) { case TURB_FAMILY::SA: /// DESCRIPTION: Root-mean square residual of nu tilde (SA model). AddHistoryOutput("RMS_NU_TILDE", "rms[nu]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of nu tilde (SA model).", HistoryFieldType::RESIDUAL); - if (config->GetStochastic_Backscatter()) { + if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { /// DESCRIPTION: Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model). AddHistoryOutput("RMS_STOCH_VAR-X", "rms[stoch_x]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Root-mean square residual of stochastic vector y-component (Stochastic Backscatter Model). @@ -1095,7 +1095,7 @@ void CFlowOutput::AddHistoryOutputFields_ScalarMAX_RES(const CConfig* config) { case TURB_FAMILY::SA: /// DESCRIPTION: Maximum residual of nu tilde (SA model). AddHistoryOutput("MAX_NU_TILDE", "max[nu]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of nu tilde (SA model).", HistoryFieldType::RESIDUAL); - if (config->GetStochastic_Backscatter()) { + if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { /// DESCRIPTION: Maximum residual of stochastic vector x-component (Stochastic Backscatter Model). AddHistoryOutput("MAX_STOCH_VAR-X", "max[stoch_x]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Maximum residual of stochastic vector y-component (Stochastic Backscatter Model). @@ -1244,7 +1244,7 @@ void CFlowOutput::LoadHistoryDataScalar(const CConfig* config, const CSolver* co case TURB_FAMILY::SA: SetHistoryOutputValue("RMS_NU_TILDE", log10(solver[TURB_SOL]->GetRes_RMS(0))); SetHistoryOutputValue("MAX_NU_TILDE", log10(solver[TURB_SOL]->GetRes_Max(0))); - if (config->GetStochastic_Backscatter()) { + if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { SetHistoryOutputValue("RMS_STOCH_VAR-X", log10(solver[TURB_SOL]->GetRes_RMS(1))); SetHistoryOutputValue("RMS_STOCH_VAR-Y", log10(solver[TURB_SOL]->GetRes_RMS(2))); if (nDim==3) SetHistoryOutputValue("RMS_STOCH_VAR-Z", log10(solver[TURB_SOL]->GetRes_RMS(3))); @@ -1254,7 +1254,7 @@ void CFlowOutput::LoadHistoryDataScalar(const CConfig* config, const CSolver* co } if (multiZone) { SetHistoryOutputValue("BGS_NU_TILDE", log10(solver[TURB_SOL]->GetRes_BGS(0))); - if (config->GetStochastic_Backscatter()) { + if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { SetHistoryOutputValue("BGS_STOCH_VAR-X", log10(solver[TURB_SOL]->GetRes_BGS(1))); SetHistoryOutputValue("BGS_STOCH_VAR-Y", log10(solver[TURB_SOL]->GetRes_BGS(2))); if (nDim==3) SetHistoryOutputValue("BGS_STOCH_VAR-Z", log10(solver[TURB_SOL]->GetRes_BGS(3))); @@ -1582,9 +1582,11 @@ void CFlowOutput::SetVolumeOutputFieldsScalarMisc(const CConfig* config) { AddVolumeOutput("WALL_DISTANCE", "Wall_Distance", "DDES", "Wall distance value"); AddVolumeOutput("LES_SENSOR","LES_Sensor","DDES","LES sensor value"); if (config->GetStochastic_Backscatter()) { - AddVolumeOutput("STOCHVAR_X", "StochVar_x", "BACKSCATTER", "x-component of the stochastic vector potential"); - AddVolumeOutput("STOCHVAR_Y", "StochVar_y", "BACKSCATTER", "y-component of the stochastic vector potential"); - if (nDim==3) AddVolumeOutput("STOCHVAR_Z", "StochVar_z", "BACKSCATTER", "z-component of the stochastic vector potential"); + if (config->GetSBS_Ctau() > 0.0) { + AddVolumeOutput("STOCHVAR_X", "StochVar_x", "BACKSCATTER", "x-component of the stochastic vector potential"); + AddVolumeOutput("STOCHVAR_Y", "StochVar_y", "BACKSCATTER", "y-component of the stochastic vector potential"); + if (nDim==3) AddVolumeOutput("STOCHVAR_Z", "StochVar_z", "BACKSCATTER", "z-component of the stochastic vector potential"); + } AddVolumeOutput("STOCHSOURCE_X", "StochSource_x", "BACKSCATTER", "x-component of the stochastic source vector"); AddVolumeOutput("STOCHSOURCE_Y", "StochSource_y", "BACKSCATTER", "y-component of the stochastic source vector"); if (nDim==3) AddVolumeOutput("STOCHSOURCE_Z", "StochSource_z", "BACKSCATTER", "z-component of the stochastic source vector"); @@ -1691,9 +1693,11 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con SetVolumeOutputValue("WALL_DISTANCE", iPoint, Node_Geo->GetWall_Distance(iPoint)); SetVolumeOutputValue("LES_SENSOR", iPoint, Node_Flow->GetLES_Mode(iPoint)); if (config->GetStochastic_Backscatter()) { - SetVolumeOutputValue("STOCHVAR_X", iPoint, Node_Turb->GetSolution(iPoint, 1)); - SetVolumeOutputValue("STOCHVAR_Y", iPoint, Node_Turb->GetSolution(iPoint, 2)); - if (nDim==3) SetVolumeOutputValue("STOCHVAR_Z", iPoint, Node_Turb->GetSolution(iPoint, 3)); + if (config->GetSBS_Ctau() > 0.0) { + SetVolumeOutputValue("STOCHVAR_X", iPoint, Node_Turb->GetSolution(iPoint, 1)); + SetVolumeOutputValue("STOCHVAR_Y", iPoint, Node_Turb->GetSolution(iPoint, 2)); + if (nDim==3) SetVolumeOutputValue("STOCHVAR_Z", iPoint, Node_Turb->GetSolution(iPoint, 3)); + } SetVolumeOutputValue("STOCHSOURCE_X", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 0)); SetVolumeOutputValue("STOCHSOURCE_Y", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 1)); if (nDim==3) SetVolumeOutputValue("STOCHSOURCE_Z", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 2)); @@ -1715,13 +1719,13 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con } strainMag2 *= 2.0; su2double tke_estim = 0.0; - if (lesSensor > threshold) tke_estim = sqrt(strainMag2) * nu_t; + if (lesSensor > threshold) tke_estim = pow(nu_t/DES_lengthscale, 2); const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); const su2double csi_y = Node_Turb->GetSolution(iPoint, 2); const su2double csi_z = Node_Turb->GetSolution(iPoint, 3); - const su2double R_xy = mag * tke_estim * csi_z; - const su2double R_xz = - mag * tke_estim * csi_y; - const su2double R_yz = mag * tke_estim * csi_x; + const su2double R_xy = - mag * tke_estim * csi_z; + const su2double R_xz = + mag * tke_estim * csi_y; + const su2double R_yz = - mag * tke_estim * csi_x; const su2double energy_res_to_mod = nu_t * strainMag2; const auto vorticity = Node_Flow->GetVorticity(iPoint); const su2double energy_backscatter = R_xy*vorticity[2] - R_xz*vorticity[1] + R_yz*vorticity[0]; @@ -1755,23 +1759,13 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con const su2double mag = config->GetSBS_Cmag(); const su2double threshold = config->GetStochFdThreshold(); su2double tke_estim = 0.0; - su2double strainMag2 = 0.0; - for (unsigned long iDim = 0; iDim < nDim; iDim++) { - strainMag2 += pow(vel_grad(iDim, iDim), 2); - } - strainMag2 += 2.0*pow(0.5*(vel_grad(0,1) + vel_grad(1,0)), 2); - if (nDim == 3) { - strainMag2 += 2.0*pow(0.5*(vel_grad(0,2) + vel_grad(2,0)), 2); - strainMag2 += 2.0*pow(0.5*(vel_grad(1,2) + vel_grad(2,1)), 2); - } - strainMag2 *= 2.0; - if (lesSensor > threshold) tke_estim = sqrt(strainMag2) * nu_t; + if (lesSensor > threshold) tke_estim = pow(nu_t/DES_lengthscale, 2); const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); const su2double csi_y = Node_Turb->GetSolution(iPoint, 2); const su2double csi_z = Node_Turb->GetSolution(iPoint, 3); - const su2double R_xy = mag * tke_estim * csi_z; - const su2double R_xz = - mag * tke_estim * csi_y; - const su2double R_yz = mag * tke_estim * csi_x; + const su2double R_xy = - mag * tke_estim * csi_z; + const su2double R_xz = + mag * tke_estim * csi_y; + const su2double R_yz = - mag * tke_estim * csi_x; SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_12", iPoint, -R_xy); SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_13", iPoint, -R_xz); SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_23", iPoint, -R_yz); diff --git a/SU2_CFD/src/solvers/CSolver.cpp b/SU2_CFD/src/solvers/CSolver.cpp index e8340a7fe0d..0b01435f960 100644 --- a/SU2_CFD/src/solvers/CSolver.cpp +++ b/SU2_CFD/src/solvers/CSolver.cpp @@ -1367,6 +1367,10 @@ void CSolver::GetCommCountAndType(const CConfig* config, COUNT_PER_POINT = nDim; MPI_TYPE = COMM_TYPE_DOUBLE; break; + case MPI_QUANTITIES::DES_LENGTHSCALE: + COUNT_PER_POINT = 1; + MPI_TYPE = COMM_TYPE_DOUBLE; + break; case MPI_QUANTITIES::SOLUTION_FEA: if (config->GetTime_Domain()) COUNT_PER_POINT = nVar*3; @@ -1498,6 +1502,9 @@ void CSolver::InitiateComms(CGeometry *geometry, for (iDim = 0; iDim < nDim; iDim++) bufDSend[buf_offset+iDim] = base_nodes->GetLangevinSourceTerms(iPoint, iDim); break; + case MPI_QUANTITIES::DES_LENGTHSCALE: + bufDSend[buf_offset] = base_nodes->GetDES_LengthScale(iPoint); + break; case MPI_QUANTITIES::UNDIVIDED_LAPLACIAN: for (iVar = 0; iVar < nVar; iVar++) bufDSend[buf_offset+iVar] = base_nodes->GetUndivided_Laplacian(iPoint, iVar); @@ -1650,6 +1657,9 @@ void CSolver::CompleteComms(CGeometry *geometry, for (iDim = 0; iDim < nDim; iDim++) base_nodes->SetLangevinSourceTerms(iPoint, iDim, bufDRecv[buf_offset+iDim]); break; + case MPI_QUANTITIES::DES_LENGTHSCALE: + base_nodes->SetDES_LengthScale(iPoint, bufDRecv[buf_offset]); + break; case MPI_QUANTITIES::UNDIVIDED_LAPLACIAN: for (iVar = 0; iVar < nVar; iVar++) base_nodes->SetUnd_Lapl(iPoint, iVar, bufDRecv[buf_offset+iVar]); diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 35fff934fe0..81a42667c15 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -59,7 +59,9 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor if (config->GetStochastic_Backscatter()) { if (nDim == 3) { - nVar += nDim; nVarGrad = nPrimVar = nVar; + if (config->GetSBS_Ctau() > 0.0) { + nVar += 3; nVarGrad = nPrimVar = nVar; + } } else { SU2_MPI::Error("Stochastic Backscatter Model available for 3D flows only.", CURRENT_FUNCTION); } @@ -120,7 +122,7 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor } Solution_Inf[0] = nu_tilde_Inf; - if (config->GetStochastic_Backscatter()) { + if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { for (unsigned short iVar = 1; iVar < nVar; iVar++) { Solution_Inf[iVar] = 0.0; } @@ -173,7 +175,7 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor Inlet_TurbVars.resize(nMarker); for (unsigned long iMarker = 0; iMarker < nMarker; iMarker++) { Inlet_TurbVars[iMarker].resize(nVertex[iMarker],nVar) = nu_tilde_Inf; - if (config->GetStochastic_Backscatter()) { + if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { for (unsigned long iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { for (unsigned short iVar = 1; iVar < nVar; iVar++) { Inlet_TurbVars[iMarker](iVertex,iVar) = 0.0; @@ -227,6 +229,9 @@ void CTurbSASolver::Preprocessing(CGeometry *geometry, CSolver **solver_containe SetDES_LengthScale(solver_container, geometry, config); + InitiateComms(geometry, config, MPI_QUANTITIES::DES_LENGTHSCALE); + CompleteComms(geometry, config, MPI_QUANTITIES::DES_LENGTHSCALE); + /*--- Compute source terms for Langevin equations ---*/ bool backscatter = config->GetStochastic_Backscatter(); @@ -240,7 +245,7 @@ void CTurbSASolver::Preprocessing(CGeometry *geometry, CSolver **solver_containe bool dual_time = ((config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) || (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND)); if (maxIter>0) SmoothLangevinSourceTerms(config, geometry); - if (timeIter == restartIter) { + if (timeIter == restartIter && config->GetSBS_Ctau() > 0.0) { for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { for (unsigned short iVar = 1; iVar < nVar; iVar++) { const su2double randomSource = nodes->GetLangevinSourceTerms(iPoint, iVar-1); @@ -1679,6 +1684,9 @@ void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) } END_SU2_OMP_FOR + InitiateComms(geometry, config, MPI_QUANTITIES::STOCH_SOURCE_LANG); + CompleteComms(geometry, config, MPI_QUANTITIES::STOCH_SOURCE_LANG); + } void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geometry) { diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index 8f107936725..9b2e941656a 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -34,7 +34,7 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi /*--- Initialize solution (check if the Stochastic Backscatter Model is active) ---*/ bool backscatter = config->GetStochastic_Backscatter(); - if (!backscatter) { + if (!(backscatter && config->GetSBS_Ctau() > 0.0)) { Solution_Old = Solution = val_nu_tilde; } else { for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { @@ -61,7 +61,7 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi Vortex_Tilting.resize(nPoint); stochSource.resize(nPoint, nDim) = su2double(0.0); stochSourceOld.resize(nPoint, nDim) = su2double(0.0); - besselIntegral.resize(nPoint); + besselIntegral.resize(nPoint) = su2double(0.0); } From 190a1cc86ac0e43820c9a9c1e098ba1319731052 Mon Sep 17 00:00:00 2001 From: paan882 Date: Mon, 2 Mar 2026 12:01:41 +0100 Subject: [PATCH 32/70] Update config template --- Common/src/CConfig.cpp | 2 +- config_template.cfg | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index e75251d6fe6..10e46a03cae 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2981,7 +2981,7 @@ void CConfig::SetConfig_Options() { addBoolOption("ENFORCE_LES", enforceLES, false); /* DESCRIPTION: Specify if the stochastic source term must be included in the turbulence model equation */ - addBoolOption("SBS_SOURCE_NU_EQUATION", stochSourceNu, false); + addBoolOption("SBS_SOURCE_NU_EQUATION", stochSourceNu, true); /* DESCRIPTION: Enable diagnostics of the stochastic source term in Langevin equation. */ addBoolOption("SBS_SOURCE_DIAGNOSTICS", stochSourceDiagnostics, false); diff --git a/config_template.cfg b/config_template.cfg index cef2b2532d7..ad7d1a71276 100644 --- a/config_template.cfg +++ b/config_template.cfg @@ -188,7 +188,7 @@ LES_FILTER_WIDTH= -1.0 STOCHASTIC_BACKSCATTER= NO % % Backscatter lengthscale coefficient (0.1) -SBS_LENGTHSCALE_COEFF= 0.1 +SBS_LENGTHSCALE_COEFF= 0.02 % % Maximum number of smoothing iterations for SBS model (100) SBS_MAX_ITER_SMOOTH= 100 @@ -199,6 +199,9 @@ SBS_TIMESCALE_COEFF= 0.05 % Backscatter intensity coefficient (1.0) SBS_INTENSITY_COEFF= 1.0 % +% Shielding function lower threshold for application of Stochastic Backscatter Model (0.9) +SBS_FD_LOWER_THRESHOLD= 0.9 +% % Relaxation factor for the stochastic source term in the main balance equations (0.0) SBS_RELAXATION_FACTOR= 0.0 % From e6b99375a19f43bc8c85dea32f581a75810b934c Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Wed, 4 Mar 2026 15:21:37 +0100 Subject: [PATCH 33/70] Delete TestCases/backscatter/DIHT directory Remove outdated configuration file. --- .../backscatter/DIHT/backscatter_DIHT.cfg | 107 ------------------ 1 file changed, 107 deletions(-) delete mode 100644 TestCases/backscatter/DIHT/backscatter_DIHT.cfg diff --git a/TestCases/backscatter/DIHT/backscatter_DIHT.cfg b/TestCases/backscatter/DIHT/backscatter_DIHT.cfg deleted file mode 100644 index 6fd2aa72485..00000000000 --- a/TestCases/backscatter/DIHT/backscatter_DIHT.cfg +++ /dev/null @@ -1,107 +0,0 @@ -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% SU2 configuration file % -% Case description: Decaying Isotropic Homogeneous Turbulence (DIHT) % -% Author: Angelo Passariello % -% Institution: University of Naples Federico II % -% Date: 2025.10.01 % -% File Version 8.3.0 "Harrier" % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% ------------- DIRECT, ADJOINT, AND LINEARIZED PROBLEM DEFINITION ------------% - -SOLVER= RANS -KIND_TURB_MODEL= SA -HYBRID_RANSLES= SA_DES -MATH_PROBLEM= DIRECT -RESTART_SOL= NO - -% ------------- STOCHASTIC BACKSCATTER MODEL PARAMETERS -----------------------% - -STOCHASTIC_BACKSCATTER= YES -SBS_CTAU= 0.001 - -% ------------- DECAYING ISOTROPIC HOMOGENEOUS TURBULENCE ---------------------% - -DIHT= YES -DIHT_DOMAIN_LENGTH= (0.5588, 0.5588, 0.5588) -DIHT_NPOINT= (64, 64, 64) -DIHT_NUM_MODES= 800 - -% ----------- COMPRESSIBLE AND INCOMPRESSIBLE FREE-STREAM DEFINITION ----------% - -MACH_NUMBER= 0.001 -FREESTREAM_TEMPERATURE= 300.0 -REYNOLDS_NUMBER= 10129 -REYNOLDS_LENGTH= 0.5588 -FREESTREAM_NU_FACTOR= 1.0 - -% ---------------------- REFERENCE VALUE DEFINITION ---------------------------% - -REF_LENGTH= 1.0 -REF_AREA= 1.0 - -% ------------------------- UNSTEADY SIMULATION -------------------------------% - -TIME_DOMAIN= NO -%TIME_MARCHING= DUAL_TIME_STEPPING-2ND_ORDER -%TIME_STEP= 0.001 -%MAX_TIME= 20 -%UNST_CFL_NUMBER= 0.0 -INNER_ITER= 0 - -% -------------------- BOUNDARY CONDITION DEFINITION --------------------------% - -MARKER_PERIODIC= (xmin, xmax, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5588, 0.0, 0.0, ymin, ymax, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5588, 0.0, zmin, zmax, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5588) - -% ------------- COMMON PARAMETERS DEFINING THE NUMERICAL METHOD ---------------% - -NUM_METHOD_GRAD= GREEN_GAUSS -CFL_NUMBER= 10.0 -CFL_ADAPT= NO -CFL_ADAPT_PARAM= ( 1.5, 0.5, 1.0, 100.0 ) -RK_ALPHA_COEFF= ( 0.66667, 0.66667, 1.000000 ) -TIME_ITER= 1 -LINEAR_SOLVER_PREC= ILU -LOW_MACH_PREC= YES -%LOW_MACH_CORR= YES - -% ----------------------- SLOPE LIMITER DEFINITION ----------------------------% - -MUSCL_FLOW= YES -SLOPE_LIMITER_FLOW= NONE -MUSCL_TURB= NO -VENKAT_LIMITER_COEFF= 0.05 - -% -------------------- FLOW NUMERICAL METHOD DEFINITION -----------------------% -% -CONV_NUM_METHOD_FLOW= SLAU2 -TIME_DISCRE_FLOW= EULER_IMPLICIT - -% -------------------- TURBULENT NUMERICAL METHOD DEFINITION ------------------% -% -CONV_NUM_METHOD_TURB= SCALAR_UPWIND -TIME_DISCRE_TURB= EULER_IMPLICIT - -% --------------------------- CONVERGENCE PARAMETERS --------------------------% -% -CONV_RESIDUAL_MINVAL= -15 -CONV_STARTITER= 0 -CONV_CAUCHY_ELEMS= 100 -CONV_CAUCHY_EPS= 1E-6 - -% ------------------------- INPUT/OUTPUT INFORMATION --------------------------% -% -MESH_FILENAME= cube_64.su2 -MESH_FORMAT= SU2 -TABULAR_FORMAT= CSV -CONV_FILENAME= history -RESTART_FILENAME= restart_flow -VOLUME_FILENAME= flow -VOLUME_OUTPUT= DDES, BACKSCATTER -SCREEN_OUTPUT= (TIME_ITER, INNER_ITER, RMS_DENSITY, RMS_MOMENTUM-X, RMS_MOMENTUM-Y, RMS_MOMENTUM-Z, RMS_NU_TILDE, RMS_STOCH_VAR_X, RMS_STOCH_VAR_Y, RMS_STOCH_VAR_Z) -HISTORY_OUTPUT= (TIME_ITER, RMS_DENSITY, RMS_MOMENTUM-X, RMS_MOMENTUM-Y, RMS_MOMENTUM-Z, RMS_NU_TILDE) -HISTORY_WRT_FREQ_INNER= 1000000 -OUTPUT_WRT_FREQ= 1000000 -OUTPUT_FILES= (RESTART, PARAVIEW) From daac35fe488610d91955ef8b2a74cceaa8be3891 Mon Sep 17 00:00:00 2001 From: paan882 Date: Tue, 10 Mar 2026 10:36:56 +0100 Subject: [PATCH 34/70] Include stochastic variables in restart file - Add the stochastic variables (from Langevin equations) to the restart file. - Optimize the definition of the points lying inside the box where the backscatter model is active. - Limit the turbulence time scale in RANS regions (Langevin equations). - Add test case: spatially-developing mixing layer. --- SU2_CFD/include/numerics/CNumerics.hpp | 13 ++ .../numerics/turbulent/turb_sources.hpp | 17 ++- SU2_CFD/include/variables/CTurbSAVariable.hpp | 15 +++ SU2_CFD/include/variables/CTurbVariable.hpp | 13 ++ SU2_CFD/src/output/CFlowOutput.cpp | 6 +- SU2_CFD/src/solvers/CTurbSASolver.cpp | 40 +++--- SU2_CFD/src/variables/CTurbSAVariable.cpp | 1 + TestCases/backscatter/mixLayer.cfg | 120 ++++++++++++++++++ 8 files changed, 194 insertions(+), 31 deletions(-) create mode 100644 TestCases/backscatter/mixLayer.cfg diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index 824a44eba3c..f26fd39db78 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -193,6 +193,9 @@ class CNumerics { su2double lesMode_i = 0.0, /*!< \brief LES sensor at point i for hybrid RANS-LES methods. */ lesMode_j = 0.0; /*!< \brief LES sensor at point j for hybrid RANS-LES methods. */ + unsigned short + sbsInBox_i = 0, /*!< \brief Sensor to assess if point i lies inside the box where the Stochastic Backscatter Model is active. */ + sbsInBox_j = 0; /*!< \brief Sensor to assess if point j lies inside the box where the Stochastic Backscatter Model is active. */ SST_ParsedOptions sstParsedOptions; /*!< \brief additional options for the SST turbulence model */ unsigned short Eig_Val_Comp; /*!< \brief Component towards which perturbation is perfromed */ su2double uq_delta_b; /*!< \brief Magnitude of perturbation */ @@ -914,6 +917,16 @@ class CNumerics { stochVar_j[iDim] = val_stochvar_j; } + /*! + * \brief Set the sensor to locate the box where the Stochastic Backscatter Model is active. + * \param[in] val_sbsInBox_i - 1 if point i lies inside the box where the model is active. + * \param[in] val_sbsInBox_j - 1 if point j lies inside the box where the model is active. + */ + inline void SetSbsInBoxSensor(su2double val_sbsInBox_i, su2double val_sbsInBox_j) { + sbsInBox_i = val_sbsInBox_i; + sbsInBox_j = val_sbsInBox_j; + } + /*! * \brief Set the LES sensor for hybrid RANS-LES methods. * \param[in] val_lesMode_i - Value of the LES sensor at point i. diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index d344087aeda..f9d978d4124 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -137,7 +137,10 @@ class CSourceBase_TurbSA : public CNumerics { } su2double scaleFactor = 0.0; - if (lesMode_i > threshold) scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * corrFac; + if (lesMode_i > threshold) + scaleFactor = 1.0/tTurb * sqrt(2.0/tRat) * corrFac; + else + tTurb = min(tTurb, 10.0*timeStep); for (unsigned short iVar = 1; iVar < nVar; iVar++) { Residual[iVar] = scaleFactor * stochSource[iVar-1] - 1.0/tTurb * ScalarVar_i[iVar]; @@ -154,7 +157,10 @@ class CSourceBase_TurbSA : public CNumerics { /*! * \brief Include stochastic source term in the Spalart-Allmaras turbulence model equation (Stochastic Backscatter Model). */ - inline void AddStochSource(CSAVariables& var, const su2double Cmag, su2double threshold, su2double& prod) { + inline void AddStochSource(const CConfig* config, CSAVariables& var, su2double& prod) { + + su2double Cmag = ComputeStochRelaxFactor(config); + su2double threshold = config->GetStochFdThreshold(); su2double nut = ScalarVar_i[0] * var.fv1; su2double tke = 0.0; @@ -171,6 +177,7 @@ class CSourceBase_TurbSA : public CNumerics { su2double Dfv1Dnut = 3.0 * var.fv1 * var.cv1_3 / (var.cv1_3 + Ji_3); su2double fac = 1.0 / (var.fv1 + ScalarVar_i[0]*Dfv1Dnut); su2double stochProdNut = RGradU * dist_i*dist_i/(2.0*ScalarVar_i[0]) * fac; + stochProdNut *= sbsInBox_i; stochProdNut = max(-limiter*prod, min(limiter*prod, stochProdNut)); prod += stochProdNut; @@ -323,10 +330,8 @@ class CSourceBase_TurbSA : public CNumerics { su2double Production = 0.0, Destruction = 0.0; SourceTerms::get(ScalarVar_i[0], var, Production, Destruction, Jacobian_i[0][0]); - if (config->GetStochastic_Backscatter() && config->GetStochSourceNu()) { - su2double intensityCoeff = ComputeStochRelaxFactor(config); - AddStochSource(var, intensityCoeff, config->GetStochFdThreshold(), Production); - } + if (config->GetStochastic_Backscatter() && config->GetStochSourceNu()) + AddStochSource(config, var, Production); Residual[0] = (Production - Destruction) * Volume; diff --git a/SU2_CFD/include/variables/CTurbSAVariable.hpp b/SU2_CFD/include/variables/CTurbSAVariable.hpp index 7e4d88df4d2..756df06f7c5 100644 --- a/SU2_CFD/include/variables/CTurbSAVariable.hpp +++ b/SU2_CFD/include/variables/CTurbSAVariable.hpp @@ -42,6 +42,7 @@ class CTurbSAVariable final : public CTurbVariable { private: VectorType DES_LengthScale; VectorType lesMode; + VectorType sbsInBox; MatrixType stochSource; MatrixType stochSourceOld; VectorType Vortex_Tilting; @@ -110,6 +111,20 @@ class CTurbSAVariable final : public CTurbVariable { */ inline void SetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim, su2double val_stochSource_old) override { stochSourceOld(iPoint, iDim) = val_stochSource_old; } + /*! + * \brief Get if the Stochastic Backscatter Model must be applied only in a confined box. + * \param[in] iPoint - Point index. + * \return 1.0 if the Stochastic Backscatter Model must be applied only in a confined box. + */ + inline su2double GetSbsInBox(unsigned long iPoint) const override { return sbsInBox(iPoint); } + + /*! + * \brief Set if the Stochastic Backscatter Model must be applied only in a confined box. + * \param[in] iPoint - Point index. + * \param[in] val_sbsInBox - 1.0 if the Stochastic Backscatter Model must be applied only in a confined box. + */ + inline void SetSbsInBox(unsigned long iPoint, su2double val_sbsInBox) override { sbsInBox(iPoint) = val_sbsInBox; } + /*! * \brief Set the LES sensor. */ diff --git a/SU2_CFD/include/variables/CTurbVariable.hpp b/SU2_CFD/include/variables/CTurbVariable.hpp index 34bf86e04e7..3aa9ef71089 100644 --- a/SU2_CFD/include/variables/CTurbVariable.hpp +++ b/SU2_CFD/include/variables/CTurbVariable.hpp @@ -126,4 +126,17 @@ class CTurbVariable : public CScalarVariable { * \param[in] val_stochSource_old - Old value of source term in Langevin equations. */ inline virtual void SetLangevinSourceTermsOld(unsigned long iPoint, unsigned short iDim, su2double val_stochSource_old) {} + + /*! + * \brief A virtual member. + * \param[in] iPoint - Point index. + */ + inline virtual su2double GetSbsInBox(unsigned long iPoint) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] iPoint - Point index. + * \param[in] val_sbsInBox - 1.0 if the Stochastic Backscatter Model must be applied only in a confined box. + */ + inline virtual void SetSbsInBox(unsigned long iPoint, su2double val_sbsInBox) {} }; diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index 3b54c779641..6480ac15d16 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -1583,9 +1583,9 @@ void CFlowOutput::SetVolumeOutputFieldsScalarMisc(const CConfig* config) { AddVolumeOutput("LES_SENSOR","LES_Sensor","DDES","LES sensor value"); if (config->GetStochastic_Backscatter()) { if (config->GetSBS_Ctau() > 0.0) { - AddVolumeOutput("STOCHVAR_X", "StochVar_x", "BACKSCATTER", "x-component of the stochastic vector potential"); - AddVolumeOutput("STOCHVAR_Y", "StochVar_y", "BACKSCATTER", "y-component of the stochastic vector potential"); - if (nDim==3) AddVolumeOutput("STOCHVAR_Z", "StochVar_z", "BACKSCATTER", "z-component of the stochastic vector potential"); + AddVolumeOutput("STOCHVAR_X", "StochVar_x", "SOLUTION", "x-component of the stochastic vector potential"); + AddVolumeOutput("STOCHVAR_Y", "StochVar_y", "SOLUTION", "y-component of the stochastic vector potential"); + if (nDim==3) AddVolumeOutput("STOCHVAR_Z", "StochVar_z", "SOLUTION", "z-component of the stochastic vector potential"); } AddVolumeOutput("STOCHSOURCE_X", "StochSource_x", "BACKSCATTER", "x-component of the stochastic source vector"); AddVolumeOutput("STOCHSOURCE_Y", "StochSource_y", "BACKSCATTER", "y-component of the stochastic source vector"); diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 81a42667c15..75b85363ace 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -245,19 +245,6 @@ void CTurbSASolver::Preprocessing(CGeometry *geometry, CSolver **solver_containe bool dual_time = ((config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) || (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND)); if (maxIter>0) SmoothLangevinSourceTerms(config, geometry); - if (timeIter == restartIter && config->GetSBS_Ctau() > 0.0) { - for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { - for (unsigned short iVar = 1; iVar < nVar; iVar++) { - const su2double randomSource = nodes->GetLangevinSourceTerms(iPoint, iVar-1); - nodes->SetSolution(iPoint, iVar, randomSource); - nodes->SetSolution_Old(iPoint, iVar, randomSource); - if (dual_time) { - nodes->Set_Solution_time_n(iPoint, iVar, randomSource); - nodes->Set_Solution_time_n1(iPoint, iVar, randomSource); - } - } - } - } } } @@ -441,6 +428,7 @@ void CTurbSASolver::Source_Residual(CGeometry *geometry, CSolver **solver_contai for (unsigned short iDim = 0; iDim < nDim; iDim++) numerics->SetStochSource(nodes->GetLangevinSourceTerms(iPoint, iDim), iDim); numerics->SetLES_Mode(nodes->GetLES_Mode(iPoint), 0.0); + numerics->SetSbsInBoxSensor(std::nearbyint(nodes->GetSbsInBox(iPoint)), 0); } } @@ -1640,24 +1628,32 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) { unsigned long timeIter = config->GetTimeIter(); + unsigned long restartIter = config->GetRestart_Iter(); const su2double threshold = config->GetStochFdThreshold(); const su2double dummySource = 1e3; bool stochBackscatterInBox = config->GetStochBackscatterInBox(); - bool insideBox = true; + + SU2_OMP_FOR_DYN(omp_chunk_size) + if (stochBackscatterInBox && timeIter==restartIter) { + for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { + const auto coord = geometry->nodes->GetCoord(iPoint); + auto sbsBoxBounds = config->GetStochBackscatterBoxBounds(); + bool insideBoxX = (coord[0]>=sbsBoxBounds[0] && coord[0]<=sbsBoxBounds[1]); + bool insideBoxY = (coord[1]>=sbsBoxBounds[2] && coord[1]<=sbsBoxBounds[3]); + bool insideBoxZ = (coord[2]>=sbsBoxBounds[4] && coord[2]<=sbsBoxBounds[5]); + bool insideBox = (insideBoxX && insideBoxY && insideBoxZ); + if (insideBox) nodes->SetSbsInBox(iPoint, 1.0); + } + } + END_SU2_OMP_FOR SU2_OMP_FOR_DYN(omp_chunk_size) for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++){ unsigned long iPointGlobal = geometry->nodes->GetGlobalIndex(iPoint); for (unsigned short iDim = 0; iDim < nDim; iDim++){ su2double lesSensor = nodes->GetLES_Mode(iPoint); - const auto coord = geometry->nodes->GetCoord(iPoint); - if (stochBackscatterInBox) { - auto sbsBoxBounds = config->GetStochBackscatterBoxBounds(); - bool insideBoxX = (coord[0]>=sbsBoxBounds[0] && coord[0]<=sbsBoxBounds[1]); - bool insideBoxY = (coord[1]>=sbsBoxBounds[2] && coord[1]<=sbsBoxBounds[3]); - bool insideBoxZ = (coord[2]>=sbsBoxBounds[4] && coord[2]<=sbsBoxBounds[5]); - insideBox = (insideBoxX && insideBoxY && insideBoxZ); - } + su2double inBoxSensor = nodes->GetSbsInBox(iPoint); + bool insideBox = (std::nearbyint(inBoxSensor) == 1); if (lesSensor>threshold && insideBox) { su2double rnd = RandomToolbox::GetNormal(iPointGlobal, iDim, timeIter); nodes->SetLangevinSourceTermsOld(iPoint, iDim, rnd); diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index 9b2e941656a..2ee073c2fe8 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -58,6 +58,7 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi DES_LengthScale.resize(nPoint) = su2double(0.0); lesMode.resize(nPoint) = su2double(0.0); + sbsInBox.resize(nPoint) = su2double(0.0); Vortex_Tilting.resize(nPoint); stochSource.resize(nPoint, nDim) = su2double(0.0); stochSourceOld.resize(nPoint, nDim) = su2double(0.0); diff --git a/TestCases/backscatter/mixLayer.cfg b/TestCases/backscatter/mixLayer.cfg new file mode 100644 index 00000000000..4a22876ed7e --- /dev/null +++ b/TestCases/backscatter/mixLayer.cfg @@ -0,0 +1,120 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% SU2 configuration file % +% Case description: Spatial Mixing layer % +% Author: Angelo Passariello % +% Institution: Italian Aerospace Research Centre (CIRA) % +% University of Naples Federico II (Italy) % +% Date: 2026.03.04 % +% File Version 8.3.0 "Harrier" % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% ------------- DIRECT, ADJOINT, AND LINEARIZED PROBLEM DEFINITION ------------% + +SOLVER= INC_RANS +KIND_TURB_MODEL= SA +MATH_PROBLEM= DIRECT + +% ------------ HYBRID RANS-LES SIMULATION DEFINITION --------------------------% + +HYBRID_RANSLES= SA_DDES +DES_CONST= 0.65 + +% ------------ STOCHASTIC BACKSCATTER MODEL DEFINITION ------------------------% + +STOCHASTIC_BACKSCATTER= YES +SBS_LENGTHSCALE_COEFF= 0.02 +SBS_MAX_ITER_SMOOTH= 100 +SBS_TIMESCALE_COEFF= 0.05 +SBS_INTENSITY_COEFF= 1.0 +SBS_FD_LOWER_THRESHOLD= 0.5 +SBS_RELAXATION_FACTOR= 0.0 +SBS_SOURCE_NU_EQUATION= YES +SBS_SOURCE_DIAGNOSTICS= YES +SBS_IN_BOX= YES +SBS_BOX_BOUNDS= ( -0.050, 1.0, -5000.0, 5000.0, -0.15, 0.15 ) + +% ----------- INCOMPRESSIBLE FREE-STREAM DEFINITION ---------------------------% + +INC_DENSITY_INIT= 1.2049 +INC_VELOCITY_INIT= ( 41.54, 0.0, 0.0 ) +INC_TEMPERATURE_INIT= 293 +INC_ENERGY_EQUATION= NO +INC_NONDIM= DIMENSIONAL +REYNOLDS_LENGTH= 0.001 +VISCOSITY_MODEL= CONSTANT_VISCOSITY +MU_CONSTANT= 1.8361815E-5 +FREESTREAM_NU_FACTOR= 0.1 + +% ---------------------- REFERENCE VALUE DEFINITION ---------------------------% + +REF_LENGTH= 1.0 +REF_AREA= 1.0 + +% ------------------------- UNSTEADY SIMULATION -------------------------------% + +TIME_DOMAIN= YES +TIME_MARCHING= DUAL_TIME_STEPPING-2ND_ORDER +TIME_STEP= 3.75E-6 +INNER_ITER= 10 +TIME_ITER= 15000 +UNST_CFL_NUMBER= 0.0 + +% -------------------- BOUNDARY CONDITION DEFINITION --------------------------% + +MARKER_HEATFLUX= ( WALL, 0.0 ) +MARKER_SYM= ( SYMMETRY_TOP, SYMMETRY_BOTTOM ) +INC_OUTLET_TYPE= PRESSURE_OUTLET +MARKER_OUTLET= ( OUTLET, 0.0 ) +MARKER_PLOTTING= ( WALL ) +INC_INLET_TYPE= VELOCITY_INLET VELOCITY_INLET +MARKER_INLET= ( INLET_TOP, 293, 41.54, 1.0, 0.0, 0.0, INLET_BOTTOM, 293, 22.40, 1.0, 0.0, 0.0 ) +MARKER_PERIODIC= ( PERIODIC1, PERIODIC2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.15, 0.0) + +% ------------- COMMON PARAMETERS DEFINING THE NUMERICAL METHOD ---------------% + +NUM_METHOD_GRAD= GREEN_GAUSS +CFL_NUMBER= 1.5 +CFL_ADAPT= NO +RK_ALPHA_COEFF= ( 0.66667, 0.66667, 1.000000 ) + +% ----------------------- SLOPE LIMITER DEFINITION ----------------------------% + +MUSCL_FLOW= NO +MUSCL_TURB= NO + +% -------------------- FLOW NUMERICAL METHOD DEFINITION -----------------------% +% +% +CONV_NUM_METHOD_FLOW= LD2 +JST_SENSOR_COEFF= ( 0.0, 0.002 ) +TIME_DISCRE_FLOW= EULER_IMPLICIT + +% -------------------- TURBULENT NUMERICAL METHOD DEFINITION ------------------% +% +CONV_NUM_METHOD_TURB= SCALAR_UPWIND +TIME_DISCRE_TURB= EULER_IMPLICIT + +% --------------------------- CONVERGENCE PARAMETERS --------------------------% +% +CONV_RESIDUAL_MINVAL= -15 +CONV_STARTITER= 0 +CONV_CAUCHY_ELEMS= 100 +CONV_CAUCHY_EPS= 1E-6 + +% ------------------------- INPUT/OUTPUT INFORMATION --------------------------% +% +MESH_FILENAME= mixLayer.cgns +MESH_FORMAT= CGNS +TABULAR_FORMAT= CSV +CONV_FILENAME= history +RESTART_FILENAME= restart_flow +VOLUME_FILENAME= flow +VOLUME_OUTPUT= ( COORDINATES, SOLUTION, PRIMITIVE, LES_SENSOR, VORTEX_IDENTIFICATION, TIME_AVERAGE, BACKSCATTER ) +HISTORY_OUTPUT= (ITER, RMS_PRESSURE, RMS_VELOCITY-X, RMS_VELOCITY-Y, RMS_VELOCITY-Z, RMS_ENERGY, RMS_NU_TILDE, RMS_STOCH_VAR-X, RMS_STOCH_VAR-Y, RMS_STOCH_VAR-Z) +SCREEN_OUTPUT= (ITER, RMS_PRESSURE, RMS_VELOCITY-X, RMS_VELOCITY-Y, RMS_VELOCITY-Z, RMS_ENERGY, RMS_NU_TILDE, RMS_STOCH_VAR-X, RMS_STOCH_VAR-Y, RMS_STOCH_VAR-Z) +HISTORY_WRT_FREQ_INNER= 10 +SCREEN_WRT_FREQ_INNER= 5 +OUTPUT_WRT_FREQ= 1000 +OUTPUT_FILES= (RESTART, PARAVIEW, SURFACE_PARAVIEW) From 3e49b9b3b76921023c3736dc1442307ee4f486a6 Mon Sep 17 00:00:00 2001 From: paan882 Date: Mon, 16 Mar 2026 16:00:38 +0100 Subject: [PATCH 35/70] Change proposed test case --- .../backwardStep.cfg} | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) rename TestCases/backscatter/{mixLayer.cfg => backward_step/backwardStep.cfg} (70%) diff --git a/TestCases/backscatter/mixLayer.cfg b/TestCases/backscatter/backward_step/backwardStep.cfg similarity index 70% rename from TestCases/backscatter/mixLayer.cfg rename to TestCases/backscatter/backward_step/backwardStep.cfg index 4a22876ed7e..f823996a5ec 100644 --- a/TestCases/backscatter/mixLayer.cfg +++ b/TestCases/backscatter/backward_step/backwardStep.cfg @@ -1,11 +1,11 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % % SU2 configuration file % -% Case description: Spatial Mixing layer % +% Case description: Backward-Facing Step % % Author: Angelo Passariello % % Institution: Italian Aerospace Research Centre (CIRA) % -% University of Naples Federico II (Italy) % -% Date: 2026.03.04 % +% University of Naples Federico II % +% Date: 2026.03.16 % % File Version 8.3.0 "Harrier" % % % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -15,8 +15,9 @@ SOLVER= INC_RANS KIND_TURB_MODEL= SA MATH_PROBLEM= DIRECT +RESTART_SOL= NO -% ------------ HYBRID RANS-LES SIMULATION DEFINITION --------------------------% +% ----------- HYBRID RANS-LES SIMULATION --------------------------------------% HYBRID_RANSLES= SA_DDES DES_CONST= 0.65 @@ -28,24 +29,24 @@ SBS_LENGTHSCALE_COEFF= 0.02 SBS_MAX_ITER_SMOOTH= 100 SBS_TIMESCALE_COEFF= 0.05 SBS_INTENSITY_COEFF= 1.0 -SBS_FD_LOWER_THRESHOLD= 0.5 +SBS_FD_LOWER_THRESHOLD= 0.9 SBS_RELAXATION_FACTOR= 0.0 SBS_SOURCE_NU_EQUATION= YES SBS_SOURCE_DIAGNOSTICS= YES SBS_IN_BOX= YES -SBS_BOX_BOUNDS= ( -0.050, 1.0, -5000.0, 5000.0, -0.15, 0.15 ) +SBS_BOX_BOUNDS= ( -0.001, 0.025, -5000.0, 5000.0, -5000.0, 0.0375 ) + % ----------- INCOMPRESSIBLE FREE-STREAM DEFINITION ---------------------------% -INC_DENSITY_INIT= 1.2049 -INC_VELOCITY_INIT= ( 41.54, 0.0, 0.0 ) -INC_TEMPERATURE_INIT= 293 +INC_DENSITY_INIT= 1.183 +INC_VELOCITY_INIT= ( 44.316, 0.0, 0.0 ) +INC_TEMPERATURE_INIT= 298.333 INC_ENERGY_EQUATION= NO -INC_NONDIM= DIMENSIONAL -REYNOLDS_LENGTH= 0.001 +INC_NONDIM= DIMENSIONAL +REYNOLDS_LENGTH= 0.0125 VISCOSITY_MODEL= CONSTANT_VISCOSITY -MU_CONSTANT= 1.8361815E-5 -FREESTREAM_NU_FACTOR= 0.1 +MU_CONSTANT= 1.820E-5 % ---------------------- REFERENCE VALUE DEFINITION ---------------------------% @@ -54,35 +55,35 @@ REF_AREA= 1.0 % ------------------------- UNSTEADY SIMULATION -------------------------------% -TIME_DOMAIN= YES +TIME_DOMAIN= YES TIME_MARCHING= DUAL_TIME_STEPPING-2ND_ORDER -TIME_STEP= 3.75E-6 -INNER_ITER= 10 -TIME_ITER= 15000 +TIME_STEP= 2.82E-6 +INNER_ITER= 20 +TIME_ITER= 50000 UNST_CFL_NUMBER= 0.0 % -------------------- BOUNDARY CONDITION DEFINITION --------------------------% -MARKER_HEATFLUX= ( WALL, 0.0 ) -MARKER_SYM= ( SYMMETRY_TOP, SYMMETRY_BOTTOM ) +MARKER_HEATFLUX= ( WALL_TOP, 0.0, WALL_BOTTOM, 0.0 ) +INC_INLET_TYPE= VELOCITY_INLET +MARKER_INLET= ( INLET, 298.333, 44.316, 1.0, 0.0, 0.0 ) INC_OUTLET_TYPE= PRESSURE_OUTLET -MARKER_OUTLET= ( OUTLET, 0.0 ) -MARKER_PLOTTING= ( WALL ) -INC_INLET_TYPE= VELOCITY_INLET VELOCITY_INLET -MARKER_INLET= ( INLET_TOP, 293, 41.54, 1.0, 0.0, 0.0, INLET_BOTTOM, 293, 22.40, 1.0, 0.0, 0.0 ) -MARKER_PERIODIC= ( PERIODIC1, PERIODIC2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.15, 0.0) +MARKER_OUTLET= ( OUTLET, 500.0 ) +MARKER_SYM= ( SYMMETRY_TOP, SYMMETRY_BOTTOM ) +MARKER_PERIODIC= ( Y-2, Y2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.05, 0.0) +MARKER_PLOTTING= ( WALL_BOTTOM ) % ------------- COMMON PARAMETERS DEFINING THE NUMERICAL METHOD ---------------% NUM_METHOD_GRAD= GREEN_GAUSS -CFL_NUMBER= 1.5 +CFL_NUMBER= 2.0 CFL_ADAPT= NO RK_ALPHA_COEFF= ( 0.66667, 0.66667, 1.000000 ) % ----------------------- SLOPE LIMITER DEFINITION ----------------------------% MUSCL_FLOW= NO -MUSCL_TURB= NO +MUSCL_TURB= NO % -------------------- FLOW NUMERICAL METHOD DEFINITION -----------------------% % @@ -105,16 +106,15 @@ CONV_CAUCHY_EPS= 1E-6 % ------------------------- INPUT/OUTPUT INFORMATION --------------------------% % -MESH_FILENAME= mixLayer.cgns -MESH_FORMAT= CGNS +MESH_FILENAME= backward_step TABULAR_FORMAT= CSV CONV_FILENAME= history RESTART_FILENAME= restart_flow VOLUME_FILENAME= flow -VOLUME_OUTPUT= ( COORDINATES, SOLUTION, PRIMITIVE, LES_SENSOR, VORTEX_IDENTIFICATION, TIME_AVERAGE, BACKSCATTER ) -HISTORY_OUTPUT= (ITER, RMS_PRESSURE, RMS_VELOCITY-X, RMS_VELOCITY-Y, RMS_VELOCITY-Z, RMS_ENERGY, RMS_NU_TILDE, RMS_STOCH_VAR-X, RMS_STOCH_VAR-Y, RMS_STOCH_VAR-Z) -SCREEN_OUTPUT= (ITER, RMS_PRESSURE, RMS_VELOCITY-X, RMS_VELOCITY-Y, RMS_VELOCITY-Z, RMS_ENERGY, RMS_NU_TILDE, RMS_STOCH_VAR-X, RMS_STOCH_VAR-Y, RMS_STOCH_VAR-Z) +VOLUME_OUTPUT= ( COORDINATES, SOLUTION, PRIMITIVE, LES_SENSOR, VORTEX_IDENTIFICATION, TIME_AVERAGE, BACKSCATTER, DES_LENGTHSCALE) +HISTORY_OUTPUT= (ITER, RMS_PRESSURE, RMS_VELOCITY-X, RMS_VELOCITY-Y, RMS_VELOCITY-Z, RMS_NU_TILDE, RMS_STOCH_VAR-X, RMS_STOCH_VAR-Y, RMS_STOCH_VAR-Z) +SCREEN_OUTPUT= (ITER, RMS_PRESSURE, RMS_VELOCITY-X, RMS_VELOCITY-Y, RMS_VELOCITY-Z, RMS_NU_TILDE, RMS_STOCH_VAR-X, RMS_STOCH_VAR-Y, RMS_STOCH_VAR-Z) HISTORY_WRT_FREQ_INNER= 10 -SCREEN_WRT_FREQ_INNER= 5 +SCREEN_WRT_FREQ_INNER= 10 OUTPUT_WRT_FREQ= 1000 OUTPUT_FILES= (RESTART, PARAVIEW, SURFACE_PARAVIEW) From fcbca3472bf97115866625177e6a52c2df5887b8 Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Fri, 27 Mar 2026 17:45:50 +0100 Subject: [PATCH 36/70] Update Common/include/toolboxes/random_toolbox.hpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- Common/include/toolboxes/random_toolbox.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index 0249e1c5076..5fbf66764fa 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -115,7 +115,7 @@ inline double GetBesselZero(double x) { } else { double t = 3.75 / abx; double poly = 0.39894228 + t * (0.01328592 + t * (0.00225319 + t * (-0.00157565 + t * (0.00916281 + t * (-0.02057706 + t * (0.02635537 + t * (-0.01647633 + t * 0.00392377))))))); - return abx - 0.5 * log(abx) + log(poly); + return abx - log(sqrt(abx) * poly); } } From d3e8e319c645eb3ed874cf4f077b8d91b821f11c Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Fri, 27 Mar 2026 17:53:44 +0100 Subject: [PATCH 37/70] Update Common/include/toolboxes/random_toolbox.hpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- Common/include/toolboxes/random_toolbox.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index 5fbf66764fa..4054044f340 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -106,7 +106,7 @@ inline double GetNormal(unsigned long nodeIndex, unsigned long dim, unsigned lon * \param[in] x Argument of Bessel funtion. * \return Value of Bessel function. */ -inline double GetBesselZero(double x) { +inline su2double GetBesselZero(su2double x) { double abx = fabs(x); if (abx < 3.75) { double t = abx / 3.75; From 6500ddd297a9ac66e4890edff610c43fce3b42a7 Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Fri, 27 Mar 2026 17:55:27 +0100 Subject: [PATCH 38/70] Update SU2_CFD/src/solvers/CTurbSASolver.cpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/src/solvers/CTurbSASolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 75b85363ace..96a6923e7f6 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1647,7 +1647,7 @@ void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) } END_SU2_OMP_FOR - SU2_OMP_FOR_DYN(omp_chunk_size) + SU2_OMP_FOR_STAT(omp_chunk_size) for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++){ unsigned long iPointGlobal = geometry->nodes->GetGlobalIndex(iPoint); for (unsigned short iDim = 0; iDim < nDim; iDim++){ From 5459137403316724c5cdb02a561ad400c1c0a7cf Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Fri, 27 Mar 2026 17:55:41 +0100 Subject: [PATCH 39/70] Update SU2_CFD/src/solvers/CTurbSASolver.cpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/src/solvers/CTurbSASolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 96a6923e7f6..afd1f6ff73b 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1633,7 +1633,7 @@ void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) const su2double dummySource = 1e3; bool stochBackscatterInBox = config->GetStochBackscatterInBox(); - SU2_OMP_FOR_DYN(omp_chunk_size) + SU2_OMP_FOR_STAT(omp_chunk_size) if (stochBackscatterInBox && timeIter==restartIter) { for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { const auto coord = geometry->nodes->GetCoord(iPoint); From f633f7bcbe21c408392d4797145770ef27352861 Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Fri, 27 Mar 2026 17:57:18 +0100 Subject: [PATCH 40/70] Update SU2_CFD/include/numerics/turbulent/turb_sources.hpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/include/numerics/turbulent/turb_sources.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index f9d978d4124..933eabef333 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -198,7 +198,6 @@ class CSourceBase_TurbSA : public CNumerics { transition_LM(config->GetKind_Trans_Model() == TURB_TRANS_MODEL::LM) { /*--- Setup the Jacobian pointer, we need to return su2double** but we know * the Jacobian is 1x1 so we use this trick to avoid heap allocation. ---*/ - //Jacobian_i = &Jacobian_Buffer; /*--- Setup the Jacobian pointer (size increased for Stochastic Backscatter Model). ---*/ for (unsigned short iVar = 0; iVar < 4; iVar++) Jacobian_i[iVar] = Jacobian_Buffer + 4*iVar; From 5203d3f5ce8e129f23619c9f37bb4b98b937ec14 Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Fri, 27 Mar 2026 17:58:11 +0100 Subject: [PATCH 41/70] Update SU2_CFD/src/numerics/flow/convection/centered.cpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/src/numerics/flow/convection/centered.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/SU2_CFD/src/numerics/flow/convection/centered.cpp b/SU2_CFD/src/numerics/flow/convection/centered.cpp index 59d904c5605..cfe7b23bdca 100644 --- a/SU2_CFD/src/numerics/flow/convection/centered.cpp +++ b/SU2_CFD/src/numerics/flow/convection/centered.cpp @@ -328,9 +328,6 @@ CNumerics::ResidualType<> CCentJSTInc_Flow::ComputeResidual(const CConfig* confi for (iDim = 0; iDim < nDim; iDim++) { Velocity_i[iDim] = V_i[iDim+1]; Velocity_j[iDim] = V_j[iDim+1]; - } - - for (iDim = 0; iDim < nDim; iDim++) { MeanVelocity[iDim] = 0.5*(Velocity_i[iDim]+Velocity_j[iDim]); sq_vel_i += 0.5*Velocity_i[iDim]*Velocity_i[iDim]; sq_vel_j += 0.5*Velocity_j[iDim]*Velocity_j[iDim]; From f4b2fa1a06542799a3fc5eaef173147df7561cab Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Fri, 27 Mar 2026 17:58:38 +0100 Subject: [PATCH 42/70] Update SU2_CFD/src/solvers/CTurbSASolver.cpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/src/solvers/CTurbSASolver.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index afd1f6ff73b..2352a272dc8 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -569,8 +569,6 @@ void CTurbSASolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_conta END_SU2_OMP_FOR } - - void CTurbSASolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { From 617453d8ce0f1a3391596c47cdc1de123f5f5da0 Mon Sep 17 00:00:00 2001 From: paan882 Date: Sun, 29 Mar 2026 20:05:33 +0200 Subject: [PATCH 43/70] Second major revision --- Common/include/CConfig.hpp | 100 +++---------- Common/include/toolboxes/random_toolbox.hpp | 5 +- Common/src/CConfig.cpp | 68 ++++----- SU2_CFD/include/numerics/CNumerics.hpp | 12 +- .../include/numerics/flow/flow_diffusion.hpp | 6 + .../numerics/turbulent/turb_convection.hpp | 9 +- .../numerics/turbulent/turb_sources.hpp | 51 ++++--- SU2_CFD/include/output/CFlowOutput.hpp | 31 ++++ .../include/solvers/CFVMFlowSolverBase.inl | 4 +- SU2_CFD/include/solvers/CTurbSASolver.hpp | 7 + SU2_CFD/include/variables/CFlowVariable.hpp | 2 +- SU2_CFD/include/variables/CVariable.hpp | 7 + .../src/numerics/flow/convection/centered.cpp | 29 ++-- SU2_CFD/src/numerics/flow/flow_diffusion.cpp | 58 +++----- SU2_CFD/src/output/CFlowOutput.cpp | 53 ++----- SU2_CFD/src/solvers/CTurbSASolver.cpp | 138 +++++++++--------- SU2_CFD/src/solvers/CTurbSolver.cpp | 8 +- SU2_CFD/src/variables/CTurbSAVariable.cpp | 6 +- TestCases/TestCase.py | 9 ++ TestCases/parallel_regression.py | 11 ++ .../Common/toolboxes/random_toolbox_tests.cpp | 62 ++++++++ UnitTests/meson.build | 3 +- 22 files changed, 355 insertions(+), 324 deletions(-) create mode 100644 UnitTests/Common/toolboxes/random_toolbox_tests.cpp diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index ff206a7b322..ce1fd1cf2f0 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -1100,20 +1100,22 @@ class CConfig { su2double Const_DES; /*!< \brief Detached Eddy Simulation Constant. */ WINDOW_FUNCTION Kind_WindowFct; /*!< \brief Type of window (weight) function for objective functional. */ unsigned short Kind_HybridRANSLES; /*!< \brief Kind of Hybrid RANS/LES. */ - bool StochasticBackscatter; /*!< \brief Option to include Stochastic Backscatter Model. */ - su2double SBS_Cdelta; /*!< \brief Stochastic Backscatter Model lengthscale coefficient. */ - unsigned short SBS_maxIterSmooth; /*!< \brief Maximum number of smoothing iterations for the SBS model. */ - su2double SBS_Ctau; /*!< \brief Stochastic Backscatter Model timescale coefficient. */ - su2double SBS_Cmag; /*!< \brief Stochastic Backscatter Model intensity coefficient. */ - bool stochSourceNu; /*!< \brief Option for including stochastic source term in turbulence model equation (Stochastic Backscatter Model). */ - bool stochSourceDiagnostics; /*!< \brief Option for writing diagnostics related to stochastic source terms in Langevin equations (Stochastic Backscatter Model). */ - bool StochBackscatterInBox; /*!< \brief Option for activating the Stochastic Backscatter Model only in a bounded box. */ - su2double StochBackscatterBoxBounds[6]; /*!< \brief Bounds of the box where the Stochastic Backscatter Model is active. */ - su2double stochFdThreshold; /*!< \brief Shielding function lower threshold for application of Stochastic Backscatter Model. */ - su2double stochSourceRelax; /*!< \brief Relaxation factor for stochastic source term generation (Stochastic Backscatter Model). */ - bool enforceLES; /*!< \brief Option to enforce LES mode in hybrid RANS-LES simulations. */ - su2double LES_FilterWidth; /*!< \brief LES filter width for hybrid RANS-LES simulations. */ unsigned short Kind_RoeLowDiss; /*!< \brief Kind of Roe scheme with low dissipation for unsteady flows. */ + struct CStochBackScatParam { + bool StochasticBackscatter; /*!< \brief Option to include Stochastic Backscatter Model. */ + su2double SBS_Cdelta; /*!< \brief Stochastic Backscatter Model lengthscale coefficient. */ + unsigned short SBS_maxIterSmooth; /*!< \brief Maximum number of smoothing iterations for the SBS model. */ + su2double SBS_Ctau; /*!< \brief Stochastic Backscatter Model timescale coefficient. */ + su2double SBS_Cmag; /*!< \brief Stochastic Backscatter Model intensity coefficient. */ + bool stochSourceNu; /*!< \brief Option for including stochastic source term in turbulence model equation (Stochastic Backscatter Model). */ + bool stochSourceDiagnostics; /*!< \brief Option for writing diagnostics related to stochastic source terms in Langevin equations (Stochastic Backscatter Model). */ + bool StochBackscatterInBox; /*!< \brief Option for activating the Stochastic Backscatter Model only in a bounded box. */ + su2double StochBackscatterBoxBounds[6]; /*!< \brief Bounds of the box where the Stochastic Backscatter Model is active. */ + su2double stochFdThreshold; /*!< \brief Shielding function lower threshold for application of Stochastic Backscatter Model. */ + su2double stochSourceRelax; /*!< \brief Relaxation factor for stochastic source term generation (Stochastic Backscatter Model). */ + } SBSParam; + bool enforceLES; /*!< \brief Option to enforce LES mode in hybrid RANS-LES simulations. */ + su2double LES_FilterWidth; /*!< \brief LES filter width for hybrid RANS-LES simulations. */ unsigned short nSpanWiseSections; /*!< \brief number of span-wise sections */ unsigned short nSpanMaxAllZones; /*!< \brief number of maximum span-wise sections for all zones */ @@ -9644,36 +9646,12 @@ class CConfig { */ unsigned short GetKind_HybridRANSLES(void) const { return Kind_HybridRANSLES; } - /*! - * \brief Get if the Stochastic Backscatter Model must be activated. - * \return TRUE if the Stochastic Backscatter Model is activated. - */ - bool GetStochastic_Backscatter(void) const { return StochasticBackscatter; } - /*! * \brief Get if the LES mode must be enforced. * \return TRUE if LES is enforced. */ bool GetEnforceLES(void) const { return enforceLES; } - /*! - * \brief Get if the stochastic source term must be included in the turbulence model equation. - * \return TRUE if the stochastic source term is included in the turbulence model equation. - */ - bool GetStochSourceNu(void) const { return stochSourceNu; } - - /*! - * \brief Get if the diagnostics of the stochastic source terms in Langevin equations must be computed. - * \return TRUE if the diagnostics of the stochastic source terms in Langevin equations are computed. - */ - bool GetStochSourceDiagnostics(void) const { return stochSourceDiagnostics; } - - /*! - * \brief Get the relaxation factor for stochastic source term generation. - * \return Relaxation factor for stochastic source term generation. - */ - su2double GetStochSourceRelax(void) const { return stochSourceRelax; } - /*! * \brief Get the LES Filter Width. * \return Value of LES Filter Width. @@ -9687,52 +9665,16 @@ class CConfig { unsigned short GetKind_RoeLowDiss(void) const { return Kind_RoeLowDiss; } /*! - * \brief Get the DES Constant. - * \return Value of DES constant. - */ - su2double GetConst_DES(void) const { return Const_DES; } - - /*! - * \brief Get the SBS lengthscale coefficient. - * \return Value of SBS lengthscale coefficient. + * \brief Get the Stochastic BackScatter (SBS) model parameters. + * \return SBS model parameters. */ - su2double GetSBS_Cdelta(void) const { return SBS_Cdelta; } + const CStochBackScatParam& GetSBSParam(void) const { return SBSParam; } /*! - * \brief Get the SBS timescale coefficient. - * \return Value of SBS timescale coefficient. - */ - unsigned short GetSBS_maxIterSmooth(void) const { return SBS_maxIterSmooth; } - - /*! - * \brief Get the SBS timescale coefficient. - * \return Value of SBS timescale coefficient. - */ - su2double GetSBS_Ctau(void) const { return SBS_Ctau; } - - /*! - * \brief Get the SBS intensity coefficient. - * \return Value of SBS intensity coefficient. - */ - su2double GetSBS_Cmag(void) const { return SBS_Cmag; } - - /*! - * \brief Get if the Stochastic Backscatter Model must be applied only in a bounded box. - * \return True if the model is applied in a bounded box. - */ - bool GetStochBackscatterInBox(void) const { return StochBackscatterInBox; } - - /*! - * \brief Get the bounds of the box where the Stochastic Backscatter Model is active. - * \return Bounds of the box where the model is active. - */ - const su2double* GetStochBackscatterBoxBounds(void) const { return StochBackscatterBoxBounds; } - - /*! - * \brief Get shielding function lower threshold for application of Stochastic Backscatter Model. - * \return Shielding function threshold for application of the model. + * \brief Get the DES Constant. + * \return Value of DES constant. */ - su2double GetStochFdThreshold(void) const { return stochFdThreshold; } + su2double GetConst_DES(void) const { return Const_DES; } /*! * \brief Get the type of tape that will be checked in a tape debug run. diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index 4054044f340..a34ff80dcf5 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -78,11 +78,10 @@ inline double HashToUniform(uint64_t x) { * \return Standard normal random number (mean=0, stddev=1). */ inline double HashToNormal(uint64_t x) { - constexpr double pi = 3.14159265358979323846; double u = HashToUniform(x); // first uniform double v = HashToUniform(~x); // second uniform (bitwise NOT) double r = sqrt(-2.0 * log(u)); - double theta = 2.0 * pi * v; + double theta = 2.0 * PI_NUMBER * v; return r * cos(theta); // one normal sample } @@ -127,7 +126,7 @@ inline su2double GetBesselZero(su2double x) { * \param[in] beta_z Argument in z-direction. * \return Value of the integral. */ -inline double GetBesselIntegral(double beta_x, double beta_y, double beta_z) { +inline su2double GetBesselIntegral(su2double beta_x, su2double beta_y, su2double beta_z) { const double A = 1.0 + 2.0 * (beta_x + beta_y + beta_z); const double Bx = 2.0 * beta_x; const double By = 2.0 * beta_y; diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 3b0af723fbc..f68530f03e4 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2962,43 +2962,43 @@ void CConfig::SetConfig_Options() { addDoubleOption("DES_CONST", Const_DES, 0.65); /* DESCRIPTION: SBS lengthscale coefficient */ - addDoubleOption("SBS_LENGTHSCALE_COEFF", SBS_Cdelta, 0.02); + addDoubleOption("SBS_LENGTHSCALE_COEFF", SBSParam.SBS_Cdelta, 0.02); /* DESCRIPTION: Maximum number of smoothing iterations for SBS model. */ - addUnsignedShortOption("SBS_MAX_ITER_SMOOTH", SBS_maxIterSmooth, 100); + addUnsignedShortOption("SBS_MAX_ITER_SMOOTH", SBSParam.SBS_maxIterSmooth, 100); /* DESCRIPTION: SBS timescale coefficient */ - addDoubleOption("SBS_TIMESCALE_COEFF", SBS_Ctau, 0.05); + addDoubleOption("SBS_TIMESCALE_COEFF", SBSParam.SBS_Ctau, 0.05); /* DESCRIPTION: SBS intensity coefficient */ - addDoubleOption("SBS_INTENSITY_COEFF", SBS_Cmag, 1.0); + addDoubleOption("SBS_INTENSITY_COEFF", SBSParam.SBS_Cmag, 1.0); /* DESCRIPTION: Specify Hybrid RANS/LES model */ addEnumOption("HYBRID_RANSLES", Kind_HybridRANSLES, HybridRANSLES_Map, NO_HYBRIDRANSLES); /* DESCRIPTION: Specify if the Stochastic Backscatter Model must be activated */ - addBoolOption("STOCHASTIC_BACKSCATTER", StochasticBackscatter, false); + addBoolOption("STOCHASTIC_BACKSCATTER", SBSParam.StochasticBackscatter, false); /* DESCRIPTION: Specify if the LES mode must be enforced */ addBoolOption("ENFORCE_LES", enforceLES, false); /* DESCRIPTION: Specify if the stochastic source term must be included in the turbulence model equation */ - addBoolOption("SBS_SOURCE_NU_EQUATION", stochSourceNu, true); + addBoolOption("SBS_SOURCE_NU_EQUATION", SBSParam.stochSourceNu, true); /* DESCRIPTION: Enable diagnostics of the stochastic source term in Langevin equation. */ - addBoolOption("SBS_SOURCE_DIAGNOSTICS", stochSourceDiagnostics, false); + addBoolOption("SBS_SOURCE_DIAGNOSTICS", SBSParam.stochSourceDiagnostics, false); /* DESCRIPTION: Relaxation factor for the stochastic source term (Stochastic Backscatter Model) */ - addDoubleOption("SBS_RELAXATION_FACTOR", stochSourceRelax, 0.0); + addDoubleOption("SBS_RELAXATION_FACTOR", SBSParam.stochSourceRelax, 0.0); /* DESCRIPTION: Apply Stochastic Backscatter Model only in a bounded box */ - addBoolOption("SBS_IN_BOX", StochBackscatterInBox, false); + addBoolOption("SBS_IN_BOX", SBSParam.StochBackscatterInBox, false); /* DESCRIPTION: Specify extents of box where Stochastic Backscatter Model is active */ - addDoubleArrayOption("SBS_BOX_BOUNDS", 6, false, StochBackscatterBoxBounds); + addDoubleArrayOption("SBS_BOX_BOUNDS", 6, false, SBSParam.StochBackscatterBoxBounds); /* DESCRIPTION: Shielding function lower threshold for application of Stochastic Backscatter Model */ - addDoubleOption("SBS_FD_LOWER_THRESHOLD", stochFdThreshold, 0.9); + addDoubleOption("SBS_FD_LOWER_THRESHOLD", SBSParam.stochFdThreshold, 0.9); /* DESCRIPTION: Filter width for LES (if negative, it is computed based on the local cell size) */ addDoubleOption("LES_FILTER_WIDTH", LES_FilterWidth, -1.0); @@ -6562,49 +6562,51 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { if (Kind_HybridRANSLES != NO_HYBRIDRANSLES) { if (LES_FilterWidth > 0.0) cout << "User-specified LES filter width: " << LES_FilterWidth << endl; cout << "Stochastic Backscatter: "; - if (StochasticBackscatter) { + if (SBSParam.StochasticBackscatter) { cout << "ON" << endl; - cout << "Backscatter intensity coefficient: " << SBS_Cmag << endl; - if (SBS_Cmag < 0.0) + if (Kind_HybridRANSLES == NO_HYBRIDRANSLES) + SU2_MPI::Error("Stochastic Backscatter can only be activated with Hybrid RANS/LES.", CURRENT_FUNCTION); + if (GetnDim(GetMesh_FileName(), Mesh_FileFormat) < 3) + SU2_MPI::Error("Stochastic Backscatter Model available for 3D flow simulations only.", CURRENT_FUNCTION); + cout << "Backscatter intensity coefficient: " << SBSParam.SBS_Cmag << endl; + if (SBSParam.SBS_Cmag < 0.0) SU2_MPI::Error("Backscatter intensity coefficient must be non-negative.", CURRENT_FUNCTION); - if (SBS_Ctau > 0.0) - cout << "Backscatter timescale coefficient: " << SBS_Ctau << endl; + if (SBSParam.SBS_Ctau > 0.0) + cout << "Backscatter timescale coefficient: " << SBSParam.SBS_Ctau << endl; else cout << "Langevin equations not integrated (temporally uncorrelated stochastic field)." << endl; - if (SBS_maxIterSmooth > 0) { - cout << "Maximum number of iterations for implicit smoothing: " << SBS_maxIterSmooth << endl; - cout << "Backscatter lengthscale coefficient: " << SBS_Cdelta << endl; - if (SBS_Cdelta < 0.0) + if (SBSParam.SBS_maxIterSmooth > 0) { + cout << "Maximum number of iterations for implicit smoothing: " << SBSParam.SBS_maxIterSmooth << endl; + cout << "Backscatter lengthscale coefficient: " << SBSParam.SBS_Cdelta << endl; + if (SBSParam.SBS_Cdelta < 0.0) SU2_MPI::Error("Backscatter lengthscale coefficient must be non-negative.", CURRENT_FUNCTION); } else { cout << "No smoothing applied to stochastic source terms in Langevin equations." << endl; } - if (stochSourceNu) + if (SBSParam.stochSourceNu) cout << "Stochastic source term included in turbulence model equation." << endl; else cout << "Stochastic source term NOT included in turbulence model equation." << endl; - if (stochSourceRelax > 0.0) - cout << "Relaxation factor for stochastic source term: " << stochSourceRelax << endl; + if (SBSParam.stochSourceRelax > 0.0) + cout << "Relaxation factor for stochastic source term: " << SBSParam.stochSourceRelax << endl; else cout << "No relaxation factor for stochastic source term." << endl; - if (StochBackscatterInBox) { + if (SBSParam.StochBackscatterInBox) { cout << "Stochastic Backscatter Model activated only in a bounded box." << endl; cout << "Box bounds: " << endl; - cout << " X: " << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[0] << " , " - << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[1] << endl; - cout << " Y: " << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[2] << " , " - << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[3] << endl; - cout << " Z: " << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[4] << " , " - << setw(10) << fixed << setprecision(4) << StochBackscatterBoxBounds[5] << endl; + cout << " X: " << setw(10) << fixed << setprecision(4) << SBSParam.StochBackscatterBoxBounds[0] << " , " + << setw(10) << fixed << setprecision(4) << SBSParam.StochBackscatterBoxBounds[1] << endl; + cout << " Y: " << setw(10) << fixed << setprecision(4) << SBSParam.StochBackscatterBoxBounds[2] << " , " + << setw(10) << fixed << setprecision(4) << SBSParam.StochBackscatterBoxBounds[3] << endl; + cout << " Z: " << setw(10) << fixed << setprecision(4) << SBSParam.StochBackscatterBoxBounds[4] << " , " + << setw(10) << fixed << setprecision(4) << SBSParam.StochBackscatterBoxBounds[5] << endl; } if (Kind_HybridRANSLES != SA_DES) - cout << "Stochastic source terms suppressed where the shielding function is lower than: " << setw(5) << setprecision(3) << stochFdThreshold << endl; + cout << "Stochastic source terms suppressed where the shielding function is lower than: " << setw(5) << setprecision(3) << SBSParam.stochFdThreshold << endl; } else { cout << "OFF" << endl; } } - if (StochasticBackscatter && Kind_HybridRANSLES == NO_HYBRIDRANSLES) - SU2_MPI::Error("Stochastic Backscatter can only be activated with Hybrid RANS/LES.", CURRENT_FUNCTION); if (enforceLES) { if (Kind_HybridRANSLES == NO_HYBRIDRANSLES) SU2_MPI::Error("ENFORCE_LES can only be activated with Hybrid RANS/LES.", CURRENT_FUNCTION); diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index f26fd39db78..da2f3042532 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -664,7 +664,7 @@ class CNumerics { * \param[in] Cmag - Stochastic backscatter intensity coefficient. * \param[out] stochReynStress - Stochastic tensor (to be added to the Reynolds stress tensor). */ - NEVERINLINE static void ComputeStochReynStress(su2double density, su2double tke, su2double rndVec[3], + inline void ComputeStochReynStress(su2double density, su2double tke, su2double rndVec[3], su2double Cmag, su2double stochReynStress[3][3]) { /* --- Calculate stochastic tensor --- */ @@ -683,18 +683,16 @@ class CNumerics { } - /*! + /*! * \brief Compute relaxation factor for stochastic source term in momentum equations (Stochastic Backscatter Model). * \param[in] config - Definition of the particular problem. * \param[out] intensityCoeff - Relaxation factor for backscatter intensity. */ - NEVERINLINE static su2double ComputeStochRelaxFactor(const CConfig* config) { + inline su2double ComputeStochRelaxFactor(const CConfig* config) { - unsigned long timeIter = config->GetTimeIter(); - unsigned long restartIter = config->GetRestart_Iter(); - su2double SBS_Cmag = config->GetSBS_Cmag(); - su2double SBS_RelaxFactor = config->GetStochSourceRelax(); + su2double SBS_Cmag = config->GetSBSParam().SBS_Cmag; su2double intensityCoeff = SBS_Cmag; + su2double SBS_RelaxFactor = config->GetSBSParam().stochSourceRelax; if (SBS_RelaxFactor > 0.0) { su2double FS_Vel = config->GetModVel_FreeStream(); su2double ReynoldsLength = config->GetLength_Reynolds(); diff --git a/SU2_CFD/include/numerics/flow/flow_diffusion.hpp b/SU2_CFD/include/numerics/flow/flow_diffusion.hpp index 870511e70e0..8dee5dc46e6 100644 --- a/SU2_CFD/include/numerics/flow/flow_diffusion.hpp +++ b/SU2_CFD/include/numerics/flow/flow_diffusion.hpp @@ -209,6 +209,12 @@ class CAvgGrad_Base : public CNumerics { su2double val_eddy_viscosity, const CConfig* config); + /*! + * \brief Calculate the stochastic contribution to the subgrid stress tensor (Stochastic Backscatter Model) + * \param[in] config - Definition of the particular problem. + */ + void SetStochReynStress(const CConfig* config); + /*! * \brief Get a component of the viscous stress tensor. * diff --git a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp index d4b5c5d951e..701b27b1614 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp @@ -63,15 +63,10 @@ class CUpwSca_TurbSA final : public CUpwScalar { * \param[in] config - Definition of the particular problem. */ void FinishResidualCalc(const CConfig* config) override { - if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { + if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) { for (unsigned short iVar = 1; iVar < nVar; iVar++) { Flux[iVar] = (a0 + a1) * 0.5 * (ScalarVar_i[iVar] + ScalarVar_j[iVar]); - } - for (unsigned short iVar = 0; iVar < nVar; iVar++) { - for (unsigned short jVar = 0; jVar < nVar; jVar++) { - Jacobian_i[iVar][jVar] = (iVar == jVar) ? 0.5*(a0+a1) : 0.0; - Jacobian_j[iVar][jVar] = (iVar == jVar) ? 0.5*(a0+a1) : 0.0; - } + Jacobian_i[iVar][iVar] = 0.5 * (a0+a1); } } Flux[0] = a0*ScalarVar_i[0] + a1*ScalarVar_j[0]; diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index 933eabef333..33f7e046afc 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -160,7 +160,7 @@ class CSourceBase_TurbSA : public CNumerics { inline void AddStochSource(const CConfig* config, CSAVariables& var, su2double& prod) { su2double Cmag = ComputeStochRelaxFactor(config); - su2double threshold = config->GetStochFdThreshold(); + su2double threshold = config->GetSBSParam().stochFdThreshold; su2double nut = ScalarVar_i[0] * var.fv1; su2double tke = 0.0; @@ -191,7 +191,7 @@ class CSourceBase_TurbSA : public CNumerics { * \param[in] config - Definition of the particular problem. */ CSourceBase_TurbSA(unsigned short nDim, const CConfig* config) - : CNumerics(nDim, (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) ? 4 : 1, config), + : CNumerics(nDim, (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) ? 4 : 1, config), idx(nDim, config->GetnSpecies()), options(config->GetSAParsedOptions()), axisymmetric(config->GetAxisymmetric()), @@ -246,15 +246,23 @@ class CSourceBase_TurbSA : public CNumerics { const su2double Ji_2 = pow(var.Ji, 2); const su2double Ji_3 = Ji_2 * var.Ji; - var.fv1 = Ji_3 / (Ji_3 + var.cv1_3); - if (config->GetStochastic_Backscatter() && lesMode_i > 0.0) var.fv1 = 1.0; - var.d_fv1 = 3 * Ji_2 * var.cv1_3 / (nu * pow(Ji_3 + var.cv1_3, 2)); + if (config->GetSBSParam().StochasticBackscatter && lesMode_i > config->GetSBSParam().stochFdThreshold) { + var.fv1 = 1.0; + var.d_fv1 = 0.0; + } else { + var.fv1 = Ji_3 / (Ji_3 + var.cv1_3); + var.d_fv1 = 3 * Ji_2 * var.cv1_3 / (nu * pow(Ji_3 + var.cv1_3, 2)); + } /*--- Using a modified relation so as to not change the Shat that depends on fv2. * From NASA turb modeling resource and 2003 paper. ---*/ - var.fv2 = 1 - ScalarVar_i[0] / (nu + ScalarVar_i[0] * var.fv1); - if (config->GetStochastic_Backscatter() && lesMode_i > 0.0) var.fv2 = 0.0; - var.d_fv2 = -(1 / nu - Ji_2 * var.d_fv1) / pow(1 + var.Ji * var.fv1, 2); + if (config->GetSBSParam().StochasticBackscatter && lesMode_i > config->GetSBSParam().stochFdThreshold) { + var.fv2 = 0.0; + var.d_fv2 = 0.0; + } else { + var.fv2 = 1 - ScalarVar_i[0] / (nu + ScalarVar_i[0] * var.fv1); + var.d_fv2 = -(1 / nu - Ji_2 * var.d_fv1) / pow(1 + var.Ji * var.fv1, 2); + } /*--- Evaluate Omega with a rotational correction term. ---*/ @@ -278,14 +286,17 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Compute auxiliary function r ---*/ rFunc::get(ScalarVar_i[0], var); - var.g = var.r + var.cw2 * (pow(var.r, 6) - var.r); - var.g_6 = pow(var.g, 6); - var.glim = pow((1 + var.cw3_6) / (var.g_6 + var.cw3_6), 1.0 / 6.0); - var.fw = var.g * var.glim; - if (config->GetStochastic_Backscatter() && lesMode_i > 0.0) var.fw = 1.0; - - var.d_g = var.d_r * (1 + var.cw2 * (6 * pow(var.r, 5) - 1)); - var.d_fw = var.d_g * var.glim * (1 - var.g_6 / (var.g_6 + var.cw3_6)); + if (config->GetSBSParam().StochasticBackscatter && lesMode_i > config->GetSBSParam().stochFdThreshold) { + var.fw = 0.0; + var.d_fw = 0.0; + } else { + var.g = var.r + var.cw2 * (pow(var.r, 6) - var.r); + var.g_6 = pow(var.g, 6); + var.glim = pow((1 + var.cw3_6) / (var.g_6 + var.cw3_6), 1.0 / 6.0); + var.fw = var.g * var.glim; + var.d_g = var.d_r * (1 + var.cw2 * (6 * pow(var.r, 5) - 1)); + var.d_fw = var.d_g * var.glim * (1 - var.g_6 / (var.g_6 + var.cw3_6)); + } var.norm2_Grad = GeometryToolbox::SquaredNorm(nDim, ScalarVar_Grad_i[0]); @@ -329,7 +340,7 @@ class CSourceBase_TurbSA : public CNumerics { su2double Production = 0.0, Destruction = 0.0; SourceTerms::get(ScalarVar_i[0], var, Production, Destruction, Jacobian_i[0][0]); - if (config->GetStochastic_Backscatter() && config->GetStochSourceNu()) + if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().stochSourceNu) AddStochSource(config, var, Production); Residual[0] = (Production - Destruction) * Volume; @@ -340,10 +351,10 @@ class CSourceBase_TurbSA : public CNumerics { /*--- Compute residual for Langevin equations (Stochastic Backscatter Model). ---*/ - if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { + if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) { const su2double DES_const = config->GetConst_DES(); - ResidualStochEquations(config->GetDelta_UnstTime(), config->GetSBS_Ctau(), dist_i, DES_const, - var, config->GetTime_Marching(), config->GetStochFdThreshold()); + ResidualStochEquations(config->GetDelta_UnstTime(), config->GetSBSParam().SBS_Ctau, dist_i, DES_const, + var, config->GetTime_Marching(), config->GetSBSParam().stochFdThreshold); } } diff --git a/SU2_CFD/include/output/CFlowOutput.hpp b/SU2_CFD/include/output/CFlowOutput.hpp index 6a9984a6f0a..25cd710c1d8 100644 --- a/SU2_CFD/include/output/CFlowOutput.hpp +++ b/SU2_CFD/include/output/CFlowOutput.hpp @@ -352,4 +352,35 @@ class CFlowOutput : public CFVMOutput{ * \param[in] config - Definition of the particular problem per zone. */ void SetFixedCLScreenOutput(const CConfig *config); + + /*! + * \brief Compute the ratio of the stochastic energy backscatter to the turbulent energy dissipation. + * \param iPoint - Index of the point. + * \param config - Definition of the particular problem. + * \param node_flow - Flow solver solution. + * \param node_turb - Turbulence-model solver solution. + * \return Stochastic energy backscatter ratio. + */ + inline su2double GetEnergyBackscatterRatio(unsigned long iPoint, const CConfig *config, const CVariable *node_flow, const CVariable *node_turb) { + const su2double rho = node_flow->GetDensity(iPoint); + const su2double nu_t = node_flow->GetEddyViscosity(iPoint) / rho; + const su2double DES_lengthscale = max(node_flow->GetDES_LengthScale(iPoint), 1e-10); + const su2double lesSensor = node_flow->GetLES_Mode(iPoint); + const su2double mag = config->GetSBSParam().SBS_Cmag; + const su2double threshold = config->GetSBSParam().stochFdThreshold; + su2double strainMag = node_flow->GetStrainMag(iPoint); + su2double tke_estim = 0.0; + if (lesSensor > threshold) tke_estim = pow(nu_t/DES_lengthscale, 2); + const su2double csi_x = node_turb->GetSolution(iPoint, 1); + const su2double csi_y = node_turb->GetSolution(iPoint, 2); + const su2double csi_z = node_turb->GetSolution(iPoint, 3); + const su2double R_xy = - mag * tke_estim * csi_z; + const su2double R_xz = + mag * tke_estim * csi_y; + const su2double R_yz = - mag * tke_estim * csi_x; + const su2double energy_res_to_mod = nu_t * strainMag * strainMag; + const auto vorticity = node_flow->GetVorticity(iPoint); + const su2double energy_backscatter = R_xy*vorticity[2] - R_xz*vorticity[1] + R_yz*vorticity[0]; + const su2double energy_backscatter_ratio = energy_backscatter / (energy_res_to_mod + 1e-10); + return energy_backscatter_ratio; + } }; diff --git a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl index 0e2f38281b6..35cc4e6312a 100644 --- a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl +++ b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl @@ -435,7 +435,7 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome const bool implicit = (config->GetKind_TimeIntScheme() == EULER_IMPLICIT); const bool tkeNeeded = (config->GetKind_Turb_Model() == TURB_MODEL::SST); - const bool backscatter = config->GetStochastic_Backscatter(); + const bool backscatter = config->GetSBSParam().StochasticBackscatter; CVariable* turbNodes = nullptr; if (tkeNeeded || backscatter) turbNodes = solver_container[TURB_SOL]->GetNodes(); @@ -472,7 +472,7 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome /*--- Stochastic variables from Langevin equations (Stochastic Backscatter Model). ---*/ if (backscatter) { - if (config->GetSBS_Ctau() > 0.0) { + if (config->GetSBSParam().SBS_Ctau > 0.0) { for (unsigned short iDim = 0; iDim < nDim; iDim++) numerics->SetStochVar(iDim, turbNodes->GetSolution(iPoint, iDim+1), turbNodes->GetSolution(jPoint, iDim+1)); diff --git a/SU2_CFD/include/solvers/CTurbSASolver.hpp b/SU2_CFD/include/solvers/CTurbSASolver.hpp index fde19343f34..b95b9f16a72 100644 --- a/SU2_CFD/include/solvers/CTurbSASolver.hpp +++ b/SU2_CFD/include/solvers/CTurbSASolver.hpp @@ -53,6 +53,13 @@ class CTurbSASolver final : public CTurbSolver { CGeometry *geometry, CConfig *config); + /*! + * \brief Mark the points that are located inside the box where the Stochastic Backscatter Model is active. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition. + */ + void SetBackscatterInBox(CConfig *config, CGeometry* geometry); + /*! * \brief Update the source terms of the stochastic equations (Stochastic Backscatter Model). * \param[in] config - Definition of the particular problem. diff --git a/SU2_CFD/include/variables/CFlowVariable.hpp b/SU2_CFD/include/variables/CFlowVariable.hpp index 323bb57f2fa..ab2a8499492 100644 --- a/SU2_CFD/include/variables/CFlowVariable.hpp +++ b/SU2_CFD/include/variables/CFlowVariable.hpp @@ -263,7 +263,7 @@ class CFlowVariable : public CVariable { * \param[in] iPoint - Point index. * \return Value of magnitude. */ - inline su2double GetStrainMag(unsigned long iPoint) const { return StrainMag(iPoint); } + inline su2double GetStrainMag(unsigned long iPoint) const final { return StrainMag(iPoint); } /*! * \brief Get the entire vector of the rate of strain magnitude. diff --git a/SU2_CFD/include/variables/CVariable.hpp b/SU2_CFD/include/variables/CVariable.hpp index a520ed27f46..4e633cc8cf2 100644 --- a/SU2_CFD/include/variables/CVariable.hpp +++ b/SU2_CFD/include/variables/CVariable.hpp @@ -1211,6 +1211,13 @@ class CVariable { inline virtual su2double *GetVorticity(unsigned long iPoint) { return nullptr; } inline virtual const su2double *GetVorticity(unsigned long iPoint) const { return nullptr; } + /*! + * \brief A virtual member. + * \param[in] iPoint - Point index. + * \return Value of strain rate magnitude. + */ + inline virtual su2double GetStrainMag(unsigned long iPoint) const { return 0.0; } + /*! * \brief A virtual member. * \param[in] iPoint - Point index. diff --git a/SU2_CFD/src/numerics/flow/convection/centered.cpp b/SU2_CFD/src/numerics/flow/convection/centered.cpp index cfe7b23bdca..68f49114581 100644 --- a/SU2_CFD/src/numerics/flow/convection/centered.cpp +++ b/SU2_CFD/src/numerics/flow/convection/centered.cpp @@ -348,28 +348,17 @@ CNumerics::ResidualType<> CCentJSTInc_Flow::ComputeResidual(const CConfig* confi if (LD2_Scheme) { su2double d_ij[3] = {0.0}; - for (iDim = 0; iDim < nDim; iDim++) - d_ij[iDim] = Coord_j[iDim]-Coord_i[iDim]; - su2double velGrad_i[3][3] = {{0.0}}; - su2double velGrad_j[3][3] = {{0.0}}; - su2double pressGrad_i[3] = {0.0}; - su2double pressGrad_j[3] = {0.0}; - for (unsigned short jDim = 0; jDim < nDim; jDim++) { - pressGrad_i[jDim] = PrimVar_Grad_i[0][jDim]; - pressGrad_j[jDim] = PrimVar_Grad_j[0][jDim]; - for (iDim = 0; iDim < nDim; iDim++) { - velGrad_i[iDim][jDim] = PrimVar_Grad_i[iDim+1][jDim]; - velGrad_j[iDim][jDim] = PrimVar_Grad_j[iDim+1][jDim]; - } - } + GeometryToolbox::Distance(nDim, Coord_j, Coord_i, d_ij); + su2double diffPresGrad[3] = {0.0}; for (iDim = 0; iDim < nDim; iDim++) { - MeanVelocity[iDim] += 0.5 * alpha_LD2 * ((velGrad_i[iDim][0] - velGrad_j[iDim][0]) * d_ij[0] + - (velGrad_i[iDim][1] - velGrad_j[iDim][1]) * d_ij[1] + - (velGrad_i[iDim][2] - velGrad_j[iDim][2]) * d_ij[2]); + diffPresGrad[iDim] = PrimVar_Grad_i[0][iDim] - PrimVar_Grad_j[0][iDim]; + su2double diffVelGrad[3]; + for (unsigned short jDim = 0; jDim < nDim; jDim++) { + diffVelGrad[jDim] = PrimVar_Grad_i[iDim+1][jDim] - PrimVar_Grad_j[iDim+1][jDim]; + } + MeanVelocity[iDim] += 0.5 * alpha_LD2 * GeometryToolbox::DotProduct(nDim, diffVelGrad, d_ij); } - MeanPressure += 0.5 * alpha_LD2 * ((pressGrad_i[0] - pressGrad_j[0]) * d_ij[0] + - (pressGrad_i[1] - pressGrad_j[1]) * d_ij[1] + - (pressGrad_i[2] - pressGrad_j[2]) * d_ij[2]); + MeanPressure += 0.5 * alpha_LD2 * GeometryToolbox::DotProduct(nDim, diffPresGrad, d_ij); } /*--- We need the derivative of the equation of state to build the diff --git a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp index 251d92d2e4f..9d687b4acb0 100644 --- a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp +++ b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp @@ -144,7 +144,7 @@ void CAvgGrad_Base::SetStressTensor(const su2double *val_primvar, /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ - if (config->GetStochastic_Backscatter()) { + if (config->GetSBSParam().StochasticBackscatter) { for (unsigned short iDim = 0 ; iDim < nDim; iDim++) for (unsigned short jDim = 0 ; jDim < nDim; jDim++) { tau[iDim][jDim] += stochReynStress[iDim][jDim]; @@ -153,6 +153,20 @@ void CAvgGrad_Base::SetStressTensor(const su2double *val_primvar, } +void CAvgGrad_Base::SetStochReynStress(const CConfig* config) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) + Mean_StochVar[iDim] = 0.5*(stochVar_i[iDim] + stochVar_j[iDim]); + su2double tkeEstim_i = 0.0, tkeEstim_j = 0.0; + if (max(lesMode_i, lesMode_j) > config->GetSBSParam().stochFdThreshold) { + tkeEstim_i = pow(Eddy_Viscosity_i/dist_i, 2); + tkeEstim_j = pow(Eddy_Viscosity_j/dist_j, 2); + } + su2double Mean_turb_ke_estim = 0.5*(tkeEstim_i + tkeEstim_j); + su2double intensityCoeff = ComputeStochRelaxFactor(config); + ComputeStochReynStress(Mean_PrimVar[nDim+2], Mean_turb_ke_estim, + Mean_StochVar, intensityCoeff, stochReynStress); +} + void CAvgGrad_Base::SetHeatFluxVector(const su2double* const* val_gradprimvar, const su2double val_eddy_viscosity, const su2double val_thermal_conductivity, const su2double val_heat_capacity_cp) { const su2double heat_flux_factor = @@ -458,19 +472,7 @@ CNumerics::ResidualType<> CAvgGrad_Flow::ComputeResidual(const CConfig* config) /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ - if (config->GetStochastic_Backscatter()) { - for (iDim = 0; iDim < nDim; iDim++) - Mean_StochVar[iDim] = 0.5*(stochVar_i[iDim] + stochVar_j[iDim]); - su2double tkeEstim_i = 0.0, tkeEstim_j = 0.0; - if (max(lesMode_i, lesMode_j) > config->GetStochFdThreshold()) { - tkeEstim_i = pow(Eddy_Viscosity_i/dist_i, 2); - tkeEstim_j = pow(Eddy_Viscosity_j/dist_j, 2); - } - su2double Mean_turb_ke_estim = 0.5*(tkeEstim_i + tkeEstim_j); - su2double intensityCoeff = ComputeStochRelaxFactor(config); - ComputeStochReynStress(Mean_PrimVar[nDim+2], Mean_turb_ke_estim, - Mean_StochVar, intensityCoeff, stochReynStress); - } + if (config->GetSBSParam().StochasticBackscatter) SetStochReynStress(config); /*--- Get projected flux tensor (viscous residual) ---*/ @@ -648,19 +650,7 @@ CNumerics::ResidualType<> CAvgGradInc_Flow::ComputeResidual(const CConfig* confi /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ - if (config->GetStochastic_Backscatter()) { - for (iDim = 0; iDim < nDim; iDim++) - Mean_StochVar[iDim] = 0.5*(stochVar_i[iDim] + stochVar_j[iDim]); - su2double tkeEstim_i = 0.0, tkeEstim_j = 0.0; - if (max(lesMode_i, lesMode_j) > config->GetStochFdThreshold()) { - tkeEstim_i = pow(Eddy_Viscosity_i/dist_i, 2); - tkeEstim_j = pow(Eddy_Viscosity_j/dist_j, 2); - } - su2double Mean_turb_ke_estim = 0.5*(tkeEstim_i + tkeEstim_j); - su2double intensityCoeff = ComputeStochRelaxFactor(config); - ComputeStochReynStress(Mean_PrimVar[nDim+2], Mean_turb_ke_estim, - Mean_StochVar, intensityCoeff, stochReynStress); - } + if (config->GetSBSParam().StochasticBackscatter) SetStochReynStress(config); /*--- Get projected flux tensor (viscous residual) ---*/ @@ -990,19 +980,7 @@ CNumerics::ResidualType<> CGeneralAvgGrad_Flow::ComputeResidual(const CConfig* c /* --- If the Stochastic Backscatter Model is active, add random contribution to stress tensor ---*/ - if (config->GetStochastic_Backscatter()) { - for (iDim = 0; iDim < nDim; iDim++) - Mean_StochVar[iDim] = 0.5*(stochVar_i[iDim] + stochVar_j[iDim]); - su2double tkeEstim_i = 0.0, tkeEstim_j = 0.0; - if (max(lesMode_i, lesMode_j) > config->GetStochFdThreshold()) { - tkeEstim_i = pow(Eddy_Viscosity_i/dist_i, 2); - tkeEstim_j = pow(Eddy_Viscosity_j/dist_j, 2); - } - su2double Mean_turb_ke_estim = 0.5*(tkeEstim_i + tkeEstim_j); - su2double intensityCoeff = ComputeStochRelaxFactor(config); - ComputeStochReynStress(Mean_PrimVar[nDim+2], Mean_turb_ke_estim, - Mean_StochVar, intensityCoeff, stochReynStress); - } + if (config->GetSBSParam().StochasticBackscatter) SetStochReynStress(config); /*--- Get projected flux tensor (viscous residual) ---*/ diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index b59a81a776e..d600255319c 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -1032,7 +1032,7 @@ void CFlowOutput::AddHistoryOutputFields_ScalarRMS_RES(const CConfig* config) { case TURB_FAMILY::SA: /// DESCRIPTION: Root-mean square residual of nu tilde (SA model). AddHistoryOutput("RMS_NU_TILDE", "rms[nu]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of nu tilde (SA model).", HistoryFieldType::RESIDUAL); - if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { + if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) { /// DESCRIPTION: Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model). AddHistoryOutput("RMS_STOCH_VAR-X", "rms[stoch_x]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Root-mean square residual of stochastic vector y-component (Stochastic Backscatter Model). @@ -1095,7 +1095,7 @@ void CFlowOutput::AddHistoryOutputFields_ScalarMAX_RES(const CConfig* config) { case TURB_FAMILY::SA: /// DESCRIPTION: Maximum residual of nu tilde (SA model). AddHistoryOutput("MAX_NU_TILDE", "max[nu]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of nu tilde (SA model).", HistoryFieldType::RESIDUAL); - if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { + if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) { /// DESCRIPTION: Maximum residual of stochastic vector x-component (Stochastic Backscatter Model). AddHistoryOutput("MAX_STOCH_VAR-X", "max[stoch_x]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Maximum residual of stochastic vector y-component (Stochastic Backscatter Model). @@ -1244,7 +1244,7 @@ void CFlowOutput::LoadHistoryDataScalar(const CConfig* config, const CSolver* co case TURB_FAMILY::SA: SetHistoryOutputValue("RMS_NU_TILDE", log10(solver[TURB_SOL]->GetRes_RMS(0))); SetHistoryOutputValue("MAX_NU_TILDE", log10(solver[TURB_SOL]->GetRes_Max(0))); - if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { + if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) { SetHistoryOutputValue("RMS_STOCH_VAR-X", log10(solver[TURB_SOL]->GetRes_RMS(1))); SetHistoryOutputValue("RMS_STOCH_VAR-Y", log10(solver[TURB_SOL]->GetRes_RMS(2))); if (nDim==3) SetHistoryOutputValue("RMS_STOCH_VAR-Z", log10(solver[TURB_SOL]->GetRes_RMS(3))); @@ -1254,7 +1254,7 @@ void CFlowOutput::LoadHistoryDataScalar(const CConfig* config, const CSolver* co } if (multiZone) { SetHistoryOutputValue("BGS_NU_TILDE", log10(solver[TURB_SOL]->GetRes_BGS(0))); - if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { + if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) { SetHistoryOutputValue("BGS_STOCH_VAR-X", log10(solver[TURB_SOL]->GetRes_BGS(1))); SetHistoryOutputValue("BGS_STOCH_VAR-Y", log10(solver[TURB_SOL]->GetRes_BGS(2))); if (nDim==3) SetHistoryOutputValue("BGS_STOCH_VAR-Z", log10(solver[TURB_SOL]->GetRes_BGS(3))); @@ -1581,8 +1581,8 @@ void CFlowOutput::SetVolumeOutputFieldsScalarMisc(const CConfig* config) { AddVolumeOutput("DES_LENGTHSCALE", "DES_LengthScale", "DDES", "DES length scale value"); AddVolumeOutput("WALL_DISTANCE", "Wall_Distance", "DDES", "Wall distance value"); AddVolumeOutput("LES_SENSOR","LES_Sensor","DDES","LES sensor value"); - if (config->GetStochastic_Backscatter()) { - if (config->GetSBS_Ctau() > 0.0) { + if (config->GetSBSParam().StochasticBackscatter) { + if (config->GetSBSParam().SBS_Ctau > 0.0) { AddVolumeOutput("STOCHVAR_X", "StochVar_x", "SOLUTION", "x-component of the stochastic vector potential"); AddVolumeOutput("STOCHVAR_Y", "StochVar_y", "SOLUTION", "y-component of the stochastic vector potential"); if (nDim==3) AddVolumeOutput("STOCHVAR_Z", "StochVar_z", "SOLUTION", "z-component of the stochastic vector potential"); @@ -1692,8 +1692,8 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con SetVolumeOutputValue("DES_LENGTHSCALE", iPoint, Node_Flow->GetDES_LengthScale(iPoint)); SetVolumeOutputValue("WALL_DISTANCE", iPoint, Node_Geo->GetWall_Distance(iPoint)); SetVolumeOutputValue("LES_SENSOR", iPoint, Node_Flow->GetLES_Mode(iPoint)); - if (config->GetStochastic_Backscatter()) { - if (config->GetSBS_Ctau() > 0.0) { + if (config->GetSBSParam().StochasticBackscatter) { + if (config->GetSBSParam().SBS_Ctau > 0.0) { SetVolumeOutputValue("STOCHVAR_X", iPoint, Node_Turb->GetSolution(iPoint, 1)); SetVolumeOutputValue("STOCHVAR_Y", iPoint, Node_Turb->GetSolution(iPoint, 2)); if (nDim==3) SetVolumeOutputValue("STOCHVAR_Z", iPoint, Node_Turb->GetSolution(iPoint, 3)); @@ -1701,36 +1701,7 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con SetVolumeOutputValue("STOCHSOURCE_X", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 0)); SetVolumeOutputValue("STOCHSOURCE_Y", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 1)); if (nDim==3) SetVolumeOutputValue("STOCHSOURCE_Z", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 2)); - const su2double rho = Node_Flow->GetDensity(iPoint); - const su2double nu_t = Node_Flow->GetEddyViscosity(iPoint) / rho; - const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1e-10); - const su2double lesSensor = Node_Flow->GetLES_Mode(iPoint); - const su2double mag = config->GetSBS_Cmag(); - const su2double threshold = config->GetStochFdThreshold(); - const auto VelocityGradient = Node_Flow->GetVelocityGradient(iPoint); - su2double strainMag2 = 0.0; - for (unsigned long iDim = 0; iDim < nDim; iDim++) { - strainMag2 += pow(VelocityGradient(iDim, iDim), 2); - } - strainMag2 += 2.0*pow(0.5*(VelocityGradient(0,1) + VelocityGradient(1,0)), 2); - if (nDim == 3) { - strainMag2 += 2.0*pow(0.5*(VelocityGradient(0,2) + VelocityGradient(2,0)), 2); - strainMag2 += 2.0*pow(0.5*(VelocityGradient(1,2) + VelocityGradient(2,1)), 2); - } - strainMag2 *= 2.0; - su2double tke_estim = 0.0; - if (lesSensor > threshold) tke_estim = pow(nu_t/DES_lengthscale, 2); - const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); - const su2double csi_y = Node_Turb->GetSolution(iPoint, 2); - const su2double csi_z = Node_Turb->GetSolution(iPoint, 3); - const su2double R_xy = - mag * tke_estim * csi_z; - const su2double R_xz = + mag * tke_estim * csi_y; - const su2double R_yz = - mag * tke_estim * csi_x; - const su2double energy_res_to_mod = nu_t * strainMag2; - const auto vorticity = Node_Flow->GetVorticity(iPoint); - const su2double energy_backscatter = R_xy*vorticity[2] - R_xz*vorticity[1] + R_yz*vorticity[0]; - const su2double energy_backscatter_ratio = energy_backscatter / (energy_res_to_mod + 1e-10); - SetVolumeOutputValue("ENERGY_BACKSCATTER_RATIO", iPoint, energy_backscatter_ratio); + SetVolumeOutputValue("ENERGY_BACKSCATTER_RATIO", iPoint, GetEnergyBackscatterRatio(iPoint, config, Node_Flow, Node_Turb)); } } @@ -1753,11 +1724,11 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_13", iPoint, -tau_xz); SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_23", iPoint, -tau_yz); } - if (config->GetKind_HybridRANSLES()!=NO_HYBRIDRANSLES && config->GetStochastic_Backscatter()) { + if (config->GetKind_HybridRANSLES()!=NO_HYBRIDRANSLES && config->GetSBSParam().StochasticBackscatter) { const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1e-10); const su2double lesSensor = Node_Flow->GetLES_Mode(iPoint); - const su2double mag = config->GetSBS_Cmag(); - const su2double threshold = config->GetStochFdThreshold(); + const su2double mag = config->GetSBSParam().SBS_Cmag; + const su2double threshold = config->GetSBSParam().stochFdThreshold; su2double tke_estim = 0.0; if (lesSensor > threshold) tke_estim = pow(nu_t/DES_lengthscale, 2); const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 2352a272dc8..1bbb8cec09d 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -57,14 +57,9 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor /*--- Add Langevin equations if the Stochastic Backscatter Model is used ---*/ - if (config->GetStochastic_Backscatter()) { - if (nDim == 3) { - if (config->GetSBS_Ctau() > 0.0) { - nVar += 3; nVarGrad = nPrimVar = nVar; - } - } else { - SU2_MPI::Error("Stochastic Backscatter Model available for 3D flows only.", CURRENT_FUNCTION); - } + if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) { + nVar += 3; + nVarGrad = nPrimVar = nVar; } /*--- Single grid simulation ---*/ @@ -122,7 +117,7 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor } Solution_Inf[0] = nu_tilde_Inf; - if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { + if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) { for (unsigned short iVar = 1; iVar < nVar; iVar++) { Solution_Inf[iVar] = 0.0; } @@ -175,7 +170,7 @@ CTurbSASolver::CTurbSASolver(CGeometry *geometry, CConfig *config, unsigned shor Inlet_TurbVars.resize(nMarker); for (unsigned long iMarker = 0; iMarker < nMarker; iMarker++) { Inlet_TurbVars[iMarker].resize(nVertex[iMarker],nVar) = nu_tilde_Inf; - if (config->GetStochastic_Backscatter() && config->GetSBS_Ctau() > 0.0) { + if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) { for (unsigned long iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { for (unsigned short iVar = 1; iVar < nVar; iVar++) { Inlet_TurbVars[iMarker](iVertex,iVar) = 0.0; @@ -234,17 +229,16 @@ void CTurbSASolver::Preprocessing(CGeometry *geometry, CSolver **solver_containe /*--- Compute source terms for Langevin equations ---*/ - bool backscatter = config->GetStochastic_Backscatter(); + bool backscatter = config->GetSBSParam().StochasticBackscatter; unsigned long innerIter = config->GetInnerIter(); - unsigned long timeIter = config->GetTimeIter(); - unsigned long restartIter = config->GetRestart_Iter(); - if (backscatter && innerIter==0) { + bool backscatterInBox = config->GetSBSParam().StochBackscatterInBox; + unsigned long timeIter = config->GetTimeIter(); + unsigned long restartIter = config->GetRestart_Iter(); + if (backscatterInBox && timeIter==restartIter) SetBackscatterInBox(config, geometry); SetLangevinSourceTerms(config, geometry); - const unsigned short maxIter = config->GetSBS_maxIterSmooth(); - bool dual_time = ((config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) || - (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND)); - if (maxIter>0) SmoothLangevinSourceTerms(config, geometry); + const unsigned short maxIter = config->GetSBSParam().SBS_maxIterSmooth; + if (maxIter > 0) SmoothLangevinSourceTerms(config, geometry); } } @@ -424,7 +418,7 @@ void CTurbSASolver::Source_Residual(CGeometry *geometry, CSolver **solver_contai /*--- Compute source terms in Langevin equations (Stochastic Basckscatter Model) ---*/ - if (config->GetStochastic_Backscatter()) { + if (config->GetSBSParam().StochasticBackscatter) { for (unsigned short iDim = 0; iDim < nDim; iDim++) numerics->SetStochSource(nodes->GetLangevinSourceTerms(iPoint, iDim), iDim); numerics->SetLES_Mode(nodes->GetLES_Mode(iPoint), 0.0); @@ -556,9 +550,9 @@ void CTurbSASolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_conta su2double coeff = (nu_total/sigma); su2double RoughWallBC = nodes->GetSolution(iPoint,0)/(0.03*Roughness_Height); - su2double Res_Wall[MAXNVAR] = {0.0}; - Res_Wall[0] = coeff*RoughWallBC*Area; - LinSysRes.SubtractBlock(iPoint, Res_Wall); + su2double Res_Wall;// = new su2double [nVar]; + Res_Wall = coeff*RoughWallBC*Area; + LinSysRes(iPoint, 0) -= Res_Wall; Jacobian_i[0][0] = (laminar_viscosity /density *Area)/(0.03*Roughness_Height*sigma); Jacobian_i[0][0] += 2.0*RoughWallBC*Area/sigma; @@ -1623,28 +1617,29 @@ void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CC END_SU2_OMP_FOR } -void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) { - - unsigned long timeIter = config->GetTimeIter(); - unsigned long restartIter = config->GetRestart_Iter(); - const su2double threshold = config->GetStochFdThreshold(); - const su2double dummySource = 1e3; - bool stochBackscatterInBox = config->GetStochBackscatterInBox(); +void CTurbSASolver::SetBackscatterInBox(CConfig *config, CGeometry *geometry) { + auto sbsBoxBounds = config->GetSBSParam().StochBackscatterBoxBounds; + SU2_OMP_FOR_STAT(omp_chunk_size) - if (stochBackscatterInBox && timeIter==restartIter) { - for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { - const auto coord = geometry->nodes->GetCoord(iPoint); - auto sbsBoxBounds = config->GetStochBackscatterBoxBounds(); - bool insideBoxX = (coord[0]>=sbsBoxBounds[0] && coord[0]<=sbsBoxBounds[1]); - bool insideBoxY = (coord[1]>=sbsBoxBounds[2] && coord[1]<=sbsBoxBounds[3]); - bool insideBoxZ = (coord[2]>=sbsBoxBounds[4] && coord[2]<=sbsBoxBounds[5]); - bool insideBox = (insideBoxX && insideBoxY && insideBoxZ); - if (insideBox) nodes->SetSbsInBox(iPoint, 1.0); - } + for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { + const auto coord = geometry->nodes->GetCoord(iPoint); + bool outOfBoxX = (coord[0]sbsBoxBounds[1]); + bool outOfBoxY = (coord[1]sbsBoxBounds[3]); + bool outOfBoxZ = (coord[2]sbsBoxBounds[5]); + bool outOfBox = (outOfBoxX || outOfBoxY || outOfBoxZ); + if (outOfBox) nodes->SetSbsInBox(iPoint, 0.0); } END_SU2_OMP_FOR +} + +void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) { + + const su2double threshold = config->GetSBSParam().stochFdThreshold; + const su2double dummySource = 1e3; + unsigned long timeIter = config->GetTimeIter(); + SU2_OMP_FOR_STAT(omp_chunk_size) for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++){ unsigned long iPointGlobal = geometry->nodes->GetGlobalIndex(iPoint); @@ -1687,8 +1682,8 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet const su2double LES_FilterWidth = config->GetLES_FilterWidth(); const su2double constDES = config->GetConst_DES(); - const su2double cDelta = config->GetSBS_Cdelta(); - const unsigned short maxIter = config->GetSBS_maxIterSmooth(); + const su2double cDelta = config->GetSBSParam().SBS_Cdelta; + const unsigned short maxIter = config->GetSBSParam().SBS_maxIterSmooth; const su2double tol = -5.0; const su2double sourceLim = 3.0; const su2double omega = 0.8; @@ -1714,8 +1709,7 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet su2double source_i_old = nodes->GetLangevinSourceTermsOld(iPoint, iDim); if (source_i_old > 3.0*sourceLim) continue; local_nPointLES += 1; - const su2double DES_LengthScale = nodes->GetDES_LengthScale(iPoint); - su2double maxDelta = DES_LengthScale / constDES; + su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); if (LES_FilterWidth > 0.0) maxDelta = LES_FilterWidth; su2double b = sqrt(cDelta) * maxDelta; su2double b2 = b * b; @@ -1804,42 +1798,54 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet var_check_notSmoothed += source_notSmoothed * source_notSmoothed; su2double integral = 0.0; if (timeIter==restartIter) { - const su2double DES_LengthScale = nodes->GetDES_LengthScale(iPoint); - su2double maxDelta = DES_LengthScale / constDES; + su2double maxDelta = geometry->nodes->GetMaxLength(iPoint); if (LES_FilterWidth > 0.0) maxDelta = LES_FilterWidth; su2double b = sqrt(cDelta) * maxDelta; su2double b2 = b * b; auto coord_i = geometry->nodes->GetCoord(iPoint); - su2double max_dx = 0.0; - su2double max_dy = 0.0; - su2double max_dz = 0.0; + su2double maxDelta_vec[3] = {0.0}; + su2double maxDelta_tmp = 0.0; unsigned short nNeigh = geometry->nodes->GetnPoint(iPoint); for (unsigned short iNode = 0; iNode < nNeigh; iNode++) { auto jPoint = geometry->nodes->GetPoint(iPoint, iNode); auto coord_j = geometry->nodes->GetCoord(jPoint); - su2double dx = fabs(coord_i[0]-coord_j[0]); - su2double dy = fabs(coord_i[1]-coord_j[1]); - su2double dz = 0.0; - if (nDim == 3) dz = fabs(coord_i[2]-coord_j[2]); - if (dx > max_dx) max_dx = dx; - if (dy > max_dy) max_dy = dy; - if (dz > max_dz) max_dz = dz; + su2double dist_ij = GeometryToolbox::Distance(nDim, coord_j, coord_i); + if (dist_ij > maxDelta_tmp) { + maxDelta_tmp = dist_ij; + GeometryToolbox::Distance(nDim, coord_j, coord_i, maxDelta_vec); + } + } + su2double max_dist_ij_normal = 0.0; + for (unsigned short iNode = 0; iNode < nNeigh; iNode++) { + auto jPoint = geometry->nodes->GetPoint(iPoint, iNode); + auto coord_j = geometry->nodes->GetCoord(jPoint); + su2double dist_ij2 = GeometryToolbox::SquaredDistance(nDim, coord_j, coord_i); + su2double dist_ij_vec[3] = {0.0}; + GeometryToolbox::Distance(nDim, coord_j, coord_i, dist_ij_vec); + su2double dist_ij_parallel = GeometryToolbox::DotProduct(nDim, dist_ij_vec, maxDelta_vec); + dist_ij_parallel /= maxDelta; + su2double dist_ij_normal = sqrt(max(dist_ij2 - dist_ij_parallel*dist_ij_parallel, 0.0)); + if (dist_ij_normal > max_dist_ij_normal) { + max_dist_ij_normal = dist_ij_normal; + } } - su2double dx2 = max_dx * max_dx; - su2double dy2 = max_dy * max_dy; - su2double dz2 = max_dz * max_dz; - su2double bx = b2 / dx2; - su2double by = b2 / dy2; - su2double bz = 0.0; - if (nDim == 3) bz = b2 / dz2; - integral = RandomToolbox::GetBesselIntegral(bx, by, bz); + su2double dI = maxDelta; + su2double dJ = max_dist_ij_normal; + su2double dK = geometry->nodes->GetVolume(iPoint) / (dI*dJ); + su2double dI2 = dI * dI; + su2double dJ2 = dJ * dJ; + su2double dK2 = dK * dK; + su2double bI = b2 / dI2; + su2double bJ = b2 / dJ2; + su2double bK = b2 / dK2; + integral = RandomToolbox::GetBesselIntegral(bI, bJ, bK); nodes->SetBesselIntegral(iPoint, integral); } else { integral = nodes->GetBesselIntegral(iPoint); } su2double scaleFactor = 1.0 / sqrt(max(integral, 1e-10)); source *= scaleFactor; - source = min(max(source, -sourceLim), sourceLim); + if (source < -sourceLim || source > sourceLim) source = 0.0; mean_check_new += source; var_check_new += source * source; nodes->SetLangevinSourceTerms(iPoint, iDim, source); @@ -1854,7 +1860,7 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet source -= mean_check_new_G; nodes->SetLangevinSourceTerms(iPoint, iDim, source); } - if (config->GetStochSourceDiagnostics()) { + if (config->GetSBSParam().stochSourceDiagnostics) { su2double mean_check_old_G = 0.0; su2double mean_check_notSmoothed_G = 0.0; su2double var_check_old_G = 0.0; @@ -1928,7 +1934,7 @@ void CTurbSASolver::ComputeUnderRelaxationFactor(CSolver** solver_container, con so the under-relaxation is not applied to that variant. */ if (config->GetSAParsedOptions().version == SA_OPTIONS::NEG || - config->GetStochastic_Backscatter()) return; + config->GetSBSParam().StochasticBackscatter) return; /* Loop over the solution update given by relaxing the linear system for this nonlinear iteration. */ diff --git a/SU2_CFD/src/solvers/CTurbSolver.cpp b/SU2_CFD/src/solvers/CTurbSolver.cpp index f74f2fdefad..49ab8b41930 100644 --- a/SU2_CFD/src/solvers/CTurbSolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSolver.cpp @@ -134,6 +134,11 @@ void CTurbSolver::LoadRestart(CGeometry** geometry, CSolver*** solver, CConfig* if (incompressible && ((!energy) && (!weakly_coupled_heat))) skipVars--; + /*--- Compute how many turbulence variables are present in the restart file. ---*/ + + unsigned short nVarInRestart = Restart_Vars[1] - skipVars; + if (nVarInRestart > nVar) nVarInRestart = nVar; + /*--- Load data from the restart into correct containers. ---*/ unsigned long counter = 0; @@ -148,7 +153,8 @@ void CTurbSolver::LoadRestart(CGeometry** geometry, CSolver*** solver, CConfig* offset in the buffer of data from the restart file and load it. ---*/ const auto index = counter * Restart_Vars[1] + skipVars; - for (auto iVar = 0u; iVar < nVar; iVar++) nodes->SetSolution(iPoint_Local, iVar, Restart_Data[index + iVar]); + for (auto iVar = 0u; iVar < nVarInRestart; iVar++) nodes->SetSolution(iPoint_Local, iVar, Restart_Data[index + iVar]); + for (auto iVar = nVarInRestart; iVar < nVar; iVar++) nodes->SetSolution(iPoint_Local, iVar, 0.0); /*--- Increment the overall counter for how many points have been loaded. ---*/ counter++; diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index 2ee073c2fe8..62120f2624a 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -33,8 +33,8 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi CTurbVariable(npoint, ndim, nvar, config) { /*--- Initialize solution (check if the Stochastic Backscatter Model is active) ---*/ - bool backscatter = config->GetStochastic_Backscatter(); - if (!(backscatter && config->GetSBS_Ctau() > 0.0)) { + bool backscatter = config->GetSBSParam().StochasticBackscatter; + if (!(backscatter && config->GetSBSParam().SBS_Ctau > 0.0)) { Solution_Old = Solution = val_nu_tilde; } else { for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { @@ -58,7 +58,7 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi DES_LengthScale.resize(nPoint) = su2double(0.0); lesMode.resize(nPoint) = su2double(0.0); - sbsInBox.resize(nPoint) = su2double(0.0); + sbsInBox.resize(nPoint) = su2double(1.0); Vortex_Tilting.resize(nPoint); stochSource.resize(nPoint, nDim) = su2double(0.0); stochSourceOld.resize(nPoint, nDim) = su2double(0.0); diff --git a/TestCases/TestCase.py b/TestCases/TestCase.py index 006271bea71..11b48f66930 100644 --- a/TestCases/TestCase.py +++ b/TestCases/TestCase.py @@ -177,6 +177,15 @@ def run_test(self, with_tsan=False, with_asan=False, with_tapetests=False): workdir = os.getcwd() os.chdir(self.cfg_dir) print(os.getcwd()) + + if hasattr(self, "decompress") and self.decompress: + print("--- Decompressing grid file: " + self.grid_file + ".gz") + import gzip, shutil + with gzip.open(self.grid_file + ".gz", "rb") as f_in: + with open(self.grid_file, "wb") as f_out: + shutil.copyfileobj(f_in, f_out) + print("--- Decompression completed!") + start = datetime.datetime.now() process = subprocess.Popen(shell_command, shell=True) # This line launches SU2 diff --git a/TestCases/parallel_regression.py b/TestCases/parallel_regression.py index 5dbfde3f381..df1cd488673 100755 --- a/TestCases/parallel_regression.py +++ b/TestCases/parallel_regression.py @@ -1058,6 +1058,17 @@ def main(): ddes_flatplate.unsteady = True test_list.append(ddes_flatplate) + # Stochastic BackScatter (SBS) model + sbs_backward_step = TestCase('sbs_backward_step') + sbs_backward_step.cfg_dir = "backscatter/backward_step" + sbs_backward_step.cfg_file = "backwardStep.cfg" + sbs_backward_step.test_iter = 10 + sbs_backward_step.test_vals = [-6.656162, -4.527123, -5.971187, -5.333804, -9.765638, -8.499022, -8.462351, -8.482077] + sbs_backward_step.unsteady = True + sbs_backward_step.decompress = True + sbs_backward_step.grid_file = "backward_step.su2" + test_list.append(sbs_backward_step) + # unsteady pitching NACA0015, SA unst_inc_turb_naca0015_sa = TestCase('unst_inc_turb_naca0015_sa') unst_inc_turb_naca0015_sa.cfg_dir = "unsteady/pitching_naca0015_rans_inc" diff --git a/UnitTests/Common/toolboxes/random_toolbox_tests.cpp b/UnitTests/Common/toolboxes/random_toolbox_tests.cpp new file mode 100644 index 00000000000..eee2992d464 --- /dev/null +++ b/UnitTests/Common/toolboxes/random_toolbox_tests.cpp @@ -0,0 +1,62 @@ +/*! + * \file random_toolbox_tests.cpp + * \brief Unit tests for the random toolbox. + * \author A. Passariello + * \version 8.4.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2026, SU2 Contributors + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#include "catch.hpp" +#include + +/*--- Function to test (included in random_toolbox.hpp) ---*/ +inline double HashToUniform(uint64_t x) { + constexpr double inv53 = 1.0 / 9007199254740992.0; // 1/2^53 + uint64_t uInt = x >> 11; // top 53 bits + return (uInt + 1) * inv53; // map to (0,1] +} + +TEST_CASE("HashToUniform", "[Toolboxes]") { + + /*--- Basic checks: no zero, no >1 ---*/ + uint64_t simple_values[] = {0ULL, 1ULL, 123ULL, UINT64_MAX}; + for (auto v : simple_values) { + auto u = HashToUniform(v); + CHECK(u > 0.0); + CHECK(u <= 1.0); + } + + /*--- Worst-case mantissa: top 53 bits set to 1 ---*/ + uint64_t x = (uint64_t(-1) >> 11) << 11; // force top 53 bits = all ones + x |= 0x7FF; // set lower bits to avoid masking issues + + double u = HashToUniform(x); + + CHECK(u > 0.0); + CHECK(u <= 1.0); + + /*--- Check exact theoretical min and max ---*/ + constexpr double inv53 = 1.0 / 9007199254740992.0; + + CHECK(HashToUniform(0ULL) == Approx(inv53)); + CHECK(HashToUniform(UINT64_MAX) == Approx(1.0)); +} \ No newline at end of file diff --git a/UnitTests/meson.build b/UnitTests/meson.build index 40b54cf6971..76eecd1dc57 100644 --- a/UnitTests/meson.build +++ b/UnitTests/meson.build @@ -16,7 +16,8 @@ su2_cfd_tests = files(['Common/geometry/primal_grid/CPrimalGrid_tests.cpp', 'SU2_CFD/numerics/CNumerics_tests.cpp', 'SU2_CFD/fluid/CFluidModel_tests.cpp', 'SU2_CFD/gradients.cpp', - 'SU2_CFD/windowing.cpp']) + 'SU2_CFD/windowing.cpp', + 'Common/toolboxes/random_toolbox_tests.cpp']) # Reverse-mode (algorithmic differentiation) tests: su2_cfd_tests_ad = files(['Common/simple_ad_test.cpp', From ca6cfb6e11bb7dbafa2c878b1220891d3cb272ca Mon Sep 17 00:00:00 2001 From: paan882 Date: Sun, 29 Mar 2026 20:10:35 +0200 Subject: [PATCH 44/70] Minor fixes --- Common/include/toolboxes/random_toolbox.hpp | 59 +++++++++++-------- .../Common/toolboxes/random_toolbox_tests.cpp | 9 ++- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index a34ff80dcf5..1db4c56ceed 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -37,10 +37,10 @@ namespace RandomToolbox { * \return Hashed 64-bit output. */ static inline uint64_t splitmix64(uint64_t x) { - x += 0x9e3779b97f4a7c15ULL; // golden ratio offset - x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL; // first mixing step - x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL; // second mixing step - return x ^ (x >> 31); // final avalanche + x += 0x9e3779b97f4a7c15ULL; // golden ratio offset + x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL; // first mixing step + x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL; // second mixing step + return x ^ (x >> 31); // final avalanche } /*! @@ -51,10 +51,10 @@ static inline uint64_t splitmix64(uint64_t x) { * \return 64-bit hash value. */ inline uint64_t GetHash(unsigned long nodeIndex, unsigned short iDim, unsigned long timeIter) { - uint64_t x = nodeIndex; - x ^= splitmix64(iDim); - x ^= splitmix64(timeIter); - return splitmix64(x); + uint64_t x = nodeIndex; + x ^= splitmix64(iDim); + x ^= splitmix64(timeIter); + return splitmix64(x); } /*! @@ -65,9 +65,9 @@ inline uint64_t GetHash(unsigned long nodeIndex, unsigned short iDim, unsigned l * \return Uniform double in the interval (0,1]. */ inline double HashToUniform(uint64_t x) { - constexpr double inv53 = 1.0 / 9007199254740992.0; // 1/2^53 - uint64_t uInt = x >> 11; // top 53 bits - return (uInt + 1) * inv53; // map to (0,1] + constexpr double inv53 = 1.0 / 9007199254740992.0; // 1/2^53 + uint64_t uInt = x >> 11; // top 53 bits + return (uInt + 1) * inv53; // map to (0,1] } /*! @@ -78,26 +78,26 @@ inline double HashToUniform(uint64_t x) { * \return Standard normal random number (mean=0, stddev=1). */ inline double HashToNormal(uint64_t x) { - double u = HashToUniform(x); // first uniform - double v = HashToUniform(~x); // second uniform (bitwise NOT) - double r = sqrt(-2.0 * log(u)); - double theta = 2.0 * PI_NUMBER * v; - return r * cos(theta); // one normal sample + double u = HashToUniform(x); // first uniform + double v = HashToUniform(~x); // second uniform (bitwise NOT) + double r = sqrt(-2.0 * log(u)); + double theta = 2.0 * PI_NUMBER * v; + return r * cos(theta); // one normal sample } /*! * \brief Generate a deterministic standard normal number for a cell, dimension, and timestep. - * + * * Combines hashing and Box-Muller in one function. - * + * * \param[in] nodeIndex Global node index. * \param[in] dim Dimension index. * \param[in] timeIter Simulation timestep (1-based). * \return Standard normal random number. */ inline double GetNormal(unsigned long nodeIndex, unsigned long dim, unsigned long timeIter) { - uint64_t hash = GetHash(nodeIndex, dim, timeIter); - return HashToNormal(hash); + uint64_t hash = GetHash(nodeIndex, dim, timeIter); + return HashToNormal(hash); } /*! @@ -109,17 +109,26 @@ inline su2double GetBesselZero(su2double x) { double abx = fabs(x); if (abx < 3.75) { double t = abx / 3.75; - double p = 1.0 + t * t * (3.5156229 + t * t * (3.0899424 + t * t * (1.2067492 + t * t * (0.2659732 + t * t * (0.0360768 + t * t * 0.0045813))))); + double p = + 1.0 + + t * t * + (3.5156229 + + t * t * (3.0899424 + t * t * (1.2067492 + t * t * (0.2659732 + t * t * (0.0360768 + t * t * 0.0045813))))); return log(p); } else { double t = 3.75 / abx; - double poly = 0.39894228 + t * (0.01328592 + t * (0.00225319 + t * (-0.00157565 + t * (0.00916281 + t * (-0.02057706 + t * (0.02635537 + t * (-0.01647633 + t * 0.00392377))))))); + double poly = + 0.39894228 + + t * (0.01328592 + + t * (0.00225319 + + t * (-0.00157565 + + t * (0.00916281 + t * (-0.02057706 + t * (0.02635537 + t * (-0.01647633 + t * 0.00392377))))))); return abx - log(sqrt(abx) * poly); } } /*! - * \brief Compute integral involving the product of three modified Bessel functions. + * \brief Compute integral involving the product of three modified Bessel functions. * Useful for scaling the smoothed stochastic source terms in Langevin equations. * \param[in] beta_x Argument in x-direction. * \param[in] beta_y Argument in y-direction. @@ -142,11 +151,11 @@ inline su2double GetBesselIntegral(su2double beta_x, su2double beta_y, su2double double lz = GetBesselZero(Bz * t); double lin = log(t) - A * t + lx + ly + lz; double integrand = exp(lin); - if (i==N) integrand *= 0.5; + if (i == N) integrand *= 0.5; sum += integrand; } return sum * dt; } /// @} -} // namespace RandomToolbox \ No newline at end of file +} // namespace RandomToolbox diff --git a/UnitTests/Common/toolboxes/random_toolbox_tests.cpp b/UnitTests/Common/toolboxes/random_toolbox_tests.cpp index eee2992d464..56105b8d574 100644 --- a/UnitTests/Common/toolboxes/random_toolbox_tests.cpp +++ b/UnitTests/Common/toolboxes/random_toolbox_tests.cpp @@ -30,13 +30,12 @@ /*--- Function to test (included in random_toolbox.hpp) ---*/ inline double HashToUniform(uint64_t x) { - constexpr double inv53 = 1.0 / 9007199254740992.0; // 1/2^53 - uint64_t uInt = x >> 11; // top 53 bits - return (uInt + 1) * inv53; // map to (0,1] + constexpr double inv53 = 1.0 / 9007199254740992.0; // 1/2^53 + uint64_t uInt = x >> 11; // top 53 bits + return (uInt + 1) * inv53; // map to (0,1] } TEST_CASE("HashToUniform", "[Toolboxes]") { - /*--- Basic checks: no zero, no >1 ---*/ uint64_t simple_values[] = {0ULL, 1ULL, 123ULL, UINT64_MAX}; for (auto v : simple_values) { @@ -59,4 +58,4 @@ TEST_CASE("HashToUniform", "[Toolboxes]") { CHECK(HashToUniform(0ULL) == Approx(inv53)); CHECK(HashToUniform(UINT64_MAX) == Approx(1.0)); -} \ No newline at end of file +} From 5bc9b354216011c53668f6e8425690360ab21675 Mon Sep 17 00:00:00 2001 From: paan882 Date: Mon, 30 Mar 2026 15:27:07 +0200 Subject: [PATCH 45/70] Minor fixes --- Common/include/toolboxes/random_toolbox.hpp | 43 ++++++++++--------- SU2_CFD/include/numerics/CNumerics.hpp | 5 ++- .../Common/toolboxes/random_toolbox_tests.cpp | 16 +++---- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index 1db4c56ceed..b5c1a74a3df 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -26,6 +26,7 @@ #pragma once #include +#include "../option_structure.hpp" namespace RandomToolbox { /// \addtogroup RandomToolbox @@ -105,19 +106,20 @@ inline double GetNormal(unsigned long nodeIndex, unsigned long dim, unsigned lon * \param[in] x Argument of Bessel funtion. * \return Value of Bessel function. */ -inline su2double GetBesselZero(su2double x) { - double abx = fabs(x); +template +inline T GetBesselZero(T x) { + T abx = fabs(x); if (abx < 3.75) { - double t = abx / 3.75; - double p = + T t = abx / 3.75; + T p = 1.0 + t * t * (3.5156229 + t * t * (3.0899424 + t * t * (1.2067492 + t * t * (0.2659732 + t * t * (0.0360768 + t * t * 0.0045813))))); return log(p); } else { - double t = 3.75 / abx; - double poly = + T t = 3.75 / abx; + T poly = 0.39894228 + t * (0.01328592 + t * (0.00225319 + @@ -135,22 +137,23 @@ inline su2double GetBesselZero(su2double x) { * \param[in] beta_z Argument in z-direction. * \return Value of the integral. */ -inline su2double GetBesselIntegral(su2double beta_x, su2double beta_y, su2double beta_z) { - const double A = 1.0 + 2.0 * (beta_x + beta_y + beta_z); - const double Bx = 2.0 * beta_x; - const double By = 2.0 * beta_y; - const double Bz = 2.0 * beta_z; +template +inline T GetBesselIntegral(T beta_x, T beta_y, T beta_z) { + const T A = 1.0 + 2.0 * (beta_x + beta_y + beta_z); + const T Bx = 2.0 * beta_x; + const T By = 2.0 * beta_y; + const T Bz = 2.0 * beta_z; const int N = 4000; - const double t_max = 20.0; - const double dt = t_max / N; - double sum = 0.0; + const T t_max = 20.0; + const T dt = t_max / N; + T sum = 0.0; for (int i = 1; i <= N; i++) { - double t = i * dt; - double lx = GetBesselZero(Bx * t); - double ly = GetBesselZero(By * t); - double lz = GetBesselZero(Bz * t); - double lin = log(t) - A * t + lx + ly + lz; - double integrand = exp(lin); + T t = i * dt; + T lx = GetBesselZero(Bx * t); + T ly = GetBesselZero(By * t); + T lz = GetBesselZero(Bz * t); + T lin = log(t) - A * t + lx + ly + lz; + T integrand = exp(lin); if (i == N) integrand *= 0.5; sum += integrand; } diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index da2f3042532..d32daf705d3 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -664,8 +664,9 @@ class CNumerics { * \param[in] Cmag - Stochastic backscatter intensity coefficient. * \param[out] stochReynStress - Stochastic tensor (to be added to the Reynolds stress tensor). */ - inline void ComputeStochReynStress(su2double density, su2double tke, su2double rndVec[3], - su2double Cmag, su2double stochReynStress[3][3]) { + template + inline void ComputeStochReynStress(su2double density, su2double tke, const Vec& rndVec, + su2double Cmag, Mat& stochReynStress) { /* --- Calculate stochastic tensor --- */ diff --git a/UnitTests/Common/toolboxes/random_toolbox_tests.cpp b/UnitTests/Common/toolboxes/random_toolbox_tests.cpp index 56105b8d574..137ab61a059 100644 --- a/UnitTests/Common/toolboxes/random_toolbox_tests.cpp +++ b/UnitTests/Common/toolboxes/random_toolbox_tests.cpp @@ -27,19 +27,13 @@ #include "catch.hpp" #include - -/*--- Function to test (included in random_toolbox.hpp) ---*/ -inline double HashToUniform(uint64_t x) { - constexpr double inv53 = 1.0 / 9007199254740992.0; // 1/2^53 - uint64_t uInt = x >> 11; // top 53 bits - return (uInt + 1) * inv53; // map to (0,1] -} +#include "../../Common/include/toolboxes/random_toolbox.hpp" TEST_CASE("HashToUniform", "[Toolboxes]") { /*--- Basic checks: no zero, no >1 ---*/ uint64_t simple_values[] = {0ULL, 1ULL, 123ULL, UINT64_MAX}; for (auto v : simple_values) { - auto u = HashToUniform(v); + auto u = RandomToolbox::HashToUniform(v); CHECK(u > 0.0); CHECK(u <= 1.0); } @@ -48,7 +42,7 @@ TEST_CASE("HashToUniform", "[Toolboxes]") { uint64_t x = (uint64_t(-1) >> 11) << 11; // force top 53 bits = all ones x |= 0x7FF; // set lower bits to avoid masking issues - double u = HashToUniform(x); + double u = RandomToolbox::HashToUniform(x); CHECK(u > 0.0); CHECK(u <= 1.0); @@ -56,6 +50,6 @@ TEST_CASE("HashToUniform", "[Toolboxes]") { /*--- Check exact theoretical min and max ---*/ constexpr double inv53 = 1.0 / 9007199254740992.0; - CHECK(HashToUniform(0ULL) == Approx(inv53)); - CHECK(HashToUniform(UINT64_MAX) == Approx(1.0)); + CHECK(RandomToolbox::HashToUniform(0ULL) == Approx(inv53)); + CHECK(RandomToolbox::HashToUniform(UINT64_MAX) == Approx(1.0)); } From c702cc9c7dfaa5ea09a72a1f1c35dba56c755dea Mon Sep 17 00:00:00 2001 From: paan882 Date: Tue, 7 Apr 2026 11:27:41 +0200 Subject: [PATCH 46/70] Third major revision --- Common/src/CConfig.cpp | 4 +- .../numerics/turbulent/turb_convection.hpp | 1 + SU2_CFD/include/output/CFlowOutput.hpp | 7 +- SU2_CFD/src/output/CFlowCompOutput.cpp | 5 +- SU2_CFD/src/output/CFlowIncOutput.cpp | 5 +- SU2_CFD/src/output/CFlowOutput.cpp | 113 +++++++++--------- SU2_CFD/src/output/CNEMOCompOutput.cpp | 5 +- 7 files changed, 74 insertions(+), 66 deletions(-) diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index f68530f03e4..027027e175a 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -6564,8 +6564,6 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { cout << "Stochastic Backscatter: "; if (SBSParam.StochasticBackscatter) { cout << "ON" << endl; - if (Kind_HybridRANSLES == NO_HYBRIDRANSLES) - SU2_MPI::Error("Stochastic Backscatter can only be activated with Hybrid RANS/LES.", CURRENT_FUNCTION); if (GetnDim(GetMesh_FileName(), Mesh_FileFormat) < 3) SU2_MPI::Error("Stochastic Backscatter Model available for 3D flow simulations only.", CURRENT_FUNCTION); cout << "Backscatter intensity coefficient: " << SBSParam.SBS_Cmag << endl; @@ -6607,6 +6605,8 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { cout << "OFF" << endl; } } + if (Kind_HybridRANSLES == NO_HYBRIDRANSLES && SBSParam.StochasticBackscatter) + SU2_MPI::Error("Stochastic Backscatter can only be activated with Hybrid RANS/LES.", CURRENT_FUNCTION); if (enforceLES) { if (Kind_HybridRANSLES == NO_HYBRIDRANSLES) SU2_MPI::Error("ENFORCE_LES can only be activated with Hybrid RANS/LES.", CURRENT_FUNCTION); diff --git a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp index 701b27b1614..a384b652a8f 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_convection.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_convection.hpp @@ -67,6 +67,7 @@ class CUpwSca_TurbSA final : public CUpwScalar { for (unsigned short iVar = 1; iVar < nVar; iVar++) { Flux[iVar] = (a0 + a1) * 0.5 * (ScalarVar_i[iVar] + ScalarVar_j[iVar]); Jacobian_i[iVar][iVar] = 0.5 * (a0+a1); + Jacobian_j[iVar][iVar] = 0.5 * (a0+a1); } } Flux[0] = a0*ScalarVar_i[0] + a1*ScalarVar_j[0]; diff --git a/SU2_CFD/include/output/CFlowOutput.hpp b/SU2_CFD/include/output/CFlowOutput.hpp index 25cd710c1d8..eec5fb36518 100644 --- a/SU2_CFD/include/output/CFlowOutput.hpp +++ b/SU2_CFD/include/output/CFlowOutput.hpp @@ -337,15 +337,18 @@ class CFlowOutput : public CFVMOutput{ /*! * \brief Set the time averaged output fields. + * \param[in] config - Definition of the particular problem per zone. */ - void SetTimeAveragedFields(); + void SetTimeAveragedFields(const CConfig *config); /*! * \brief Load the time averaged output fields. * \param iPoint * \param node_flow + * \param node_turb + * \param config - Definition of the particular problem per zone. */ - void LoadTimeAveragedData(unsigned long iPoint, const CVariable *node_flow); + void LoadTimeAveragedData(unsigned long iPoint, const CVariable *node_flow, const CVariable *node_turb, const CConfig *config); /*! * \brief Write additional output for fixed CL mode. diff --git a/SU2_CFD/src/output/CFlowCompOutput.cpp b/SU2_CFD/src/output/CFlowCompOutput.cpp index 54a30d1b3a2..2d189b7b55d 100644 --- a/SU2_CFD/src/output/CFlowCompOutput.cpp +++ b/SU2_CFD/src/output/CFlowCompOutput.cpp @@ -308,13 +308,14 @@ void CFlowCompOutput::SetVolumeOutputFields(CConfig *config){ AddCommonFVMOutputs(config); if (config->GetTime_Domain()) { - SetTimeAveragedFields(); + SetTimeAveragedFields(config); } } void CFlowCompOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolver **solver, unsigned long iPoint){ const auto* Node_Flow = solver[FLOW_SOL]->GetNodes(); + const auto* Node_Turb = solver[TURB_SOL]->GetNodes(); auto* Node_Geo = geometry->nodes; LoadCoordinates(Node_Geo->GetCoord(iPoint), iPoint); @@ -395,7 +396,7 @@ void CFlowCompOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolv LoadCommonFVMOutputs(config, geometry, iPoint); if (config->GetTime_Domain()) { - LoadTimeAveragedData(iPoint, Node_Flow); + LoadTimeAveragedData(iPoint, Node_Flow, Node_Turb, config); } } diff --git a/SU2_CFD/src/output/CFlowIncOutput.cpp b/SU2_CFD/src/output/CFlowIncOutput.cpp index b13edb7732f..c91de17f481 100644 --- a/SU2_CFD/src/output/CFlowIncOutput.cpp +++ b/SU2_CFD/src/output/CFlowIncOutput.cpp @@ -392,13 +392,14 @@ void CFlowIncOutput::SetVolumeOutputFields(CConfig *config){ AddCommonFVMOutputs(config); if (config->GetTime_Domain()) { - SetTimeAveragedFields(); + SetTimeAveragedFields(config); } } void CFlowIncOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolver **solver, unsigned long iPoint){ const auto* Node_Flow = solver[FLOW_SOL]->GetNodes(); + const auto* Node_Turb = solver[TURB_SOL]->GetNodes(); const CVariable* Node_Heat = nullptr; const CVariable* Node_Rad = nullptr; auto* Node_Geo = geometry->nodes; @@ -481,7 +482,7 @@ void CFlowIncOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolve LoadCommonFVMOutputs(config, geometry, iPoint); if (config->GetTime_Domain()) { - LoadTimeAveragedData(iPoint, Node_Flow); + LoadTimeAveragedData(iPoint, Node_Flow, Node_Turb, config); } } diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index 0b7c160bb70..2c715f9cece 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -1034,7 +1034,7 @@ void CFlowOutput::AddHistoryOutputFields_ScalarRMS_RES(const CConfig* config) { /// DESCRIPTION: Root-mean square residual of stochastic vector y-component (Stochastic Backscatter Model). AddHistoryOutput("RMS_STOCH_VAR-Y", "rms[stoch_y]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Root-mean square residual of stochastic vector z-component (Stochastic Backscatter Model). - if (nDim==3) AddHistoryOutput("RMS_STOCH_VAR-Z", "rms[stoch_z]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + AddHistoryOutput("RMS_STOCH_VAR-Z", "rms[stoch_z]", ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean square residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); } break; @@ -1097,7 +1097,7 @@ void CFlowOutput::AddHistoryOutputFields_ScalarMAX_RES(const CConfig* config) { /// DESCRIPTION: Maximum residual of stochastic vector y-component (Stochastic Backscatter Model). AddHistoryOutput("MAX_STOCH_VAR-Y", "max[stoch_y]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); /// DESCRIPTION: Maximum residual of stochastic vector z-component (Stochastic Backscatter Model). - if (nDim==3) AddHistoryOutput("MAX_STOCH_VAR-Z", "max[stoch_z]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + AddHistoryOutput("MAX_STOCH_VAR-Z", "max[stoch_z]", ScreenOutputFormat::FIXED, "MAX_RES", "Maximum residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); } break; @@ -1243,17 +1243,17 @@ void CFlowOutput::LoadHistoryDataScalar(const CConfig* config, const CSolver* co if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) { SetHistoryOutputValue("RMS_STOCH_VAR-X", log10(solver[TURB_SOL]->GetRes_RMS(1))); SetHistoryOutputValue("RMS_STOCH_VAR-Y", log10(solver[TURB_SOL]->GetRes_RMS(2))); - if (nDim==3) SetHistoryOutputValue("RMS_STOCH_VAR-Z", log10(solver[TURB_SOL]->GetRes_RMS(3))); + SetHistoryOutputValue("RMS_STOCH_VAR-Z", log10(solver[TURB_SOL]->GetRes_RMS(3))); SetHistoryOutputValue("MAX_STOCH_VAR-X", log10(solver[TURB_SOL]->GetRes_Max(1))); SetHistoryOutputValue("MAX_STOCH_VAR-Y", log10(solver[TURB_SOL]->GetRes_Max(2))); - if (nDim==3) SetHistoryOutputValue("MAX_STOCH_VAR-Z", log10(solver[TURB_SOL]->GetRes_Max(3))); + SetHistoryOutputValue("MAX_STOCH_VAR-Z", log10(solver[TURB_SOL]->GetRes_Max(3))); } if (multiZone) { SetHistoryOutputValue("BGS_NU_TILDE", log10(solver[TURB_SOL]->GetRes_BGS(0))); if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) { SetHistoryOutputValue("BGS_STOCH_VAR-X", log10(solver[TURB_SOL]->GetRes_BGS(1))); SetHistoryOutputValue("BGS_STOCH_VAR-Y", log10(solver[TURB_SOL]->GetRes_BGS(2))); - if (nDim==3) SetHistoryOutputValue("BGS_STOCH_VAR-Z", log10(solver[TURB_SOL]->GetRes_BGS(3))); + SetHistoryOutputValue("BGS_STOCH_VAR-Z", log10(solver[TURB_SOL]->GetRes_BGS(3))); } } break; @@ -1344,6 +1344,11 @@ void CFlowOutput::SetVolumeOutputFieldsScalarSolution(const CConfig* config){ switch (TurbModelFamily(config->GetKind_Turb_Model())) { case TURB_FAMILY::SA: AddVolumeOutput("NU_TILDE", "Nu_Tilde", "SOLUTION", "Spalart-Allmaras variable"); + if (config->GetSBSParam().SBS_Ctau > 0.0) { + AddVolumeOutput("STOCHVAR_X", "StochVar_x", "SOLUTION", "x-component of the stochastic vector potential"); + AddVolumeOutput("STOCHVAR_Y", "StochVar_y", "SOLUTION", "y-component of the stochastic vector potential"); + AddVolumeOutput("STOCHVAR_Z", "StochVar_z", "SOLUTION", "z-component of the stochastic vector potential"); + } break; case TURB_FAMILY::KW: @@ -1578,14 +1583,9 @@ void CFlowOutput::SetVolumeOutputFieldsScalarMisc(const CConfig* config) { AddVolumeOutput("WALL_DISTANCE", "Wall_Distance", "DDES", "Wall distance value"); AddVolumeOutput("LES_SENSOR","LES_Sensor","DDES","LES sensor value"); if (config->GetSBSParam().StochasticBackscatter) { - if (config->GetSBSParam().SBS_Ctau > 0.0) { - AddVolumeOutput("STOCHVAR_X", "StochVar_x", "SOLUTION", "x-component of the stochastic vector potential"); - AddVolumeOutput("STOCHVAR_Y", "StochVar_y", "SOLUTION", "y-component of the stochastic vector potential"); - if (nDim==3) AddVolumeOutput("STOCHVAR_Z", "StochVar_z", "SOLUTION", "z-component of the stochastic vector potential"); - } AddVolumeOutput("STOCHSOURCE_X", "StochSource_x", "BACKSCATTER", "x-component of the stochastic source vector"); AddVolumeOutput("STOCHSOURCE_Y", "StochSource_y", "BACKSCATTER", "y-component of the stochastic source vector"); - if (nDim==3) AddVolumeOutput("STOCHSOURCE_Z", "StochSource_z", "BACKSCATTER", "z-component of the stochastic source vector"); + AddVolumeOutput("STOCHSOURCE_Z", "StochSource_z", "BACKSCATTER", "z-component of the stochastic source vector"); AddVolumeOutput("ENERGY_BACKSCATTER_RATIO", "Energy_Backscatter_Ratio", "BACKSCATTER", "Energy backscatter from unresolved to resolved scales (divided by the turbulent dissipation of resolved kinetic energy)"); } } @@ -1692,53 +1692,15 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con if (config->GetSBSParam().SBS_Ctau > 0.0) { SetVolumeOutputValue("STOCHVAR_X", iPoint, Node_Turb->GetSolution(iPoint, 1)); SetVolumeOutputValue("STOCHVAR_Y", iPoint, Node_Turb->GetSolution(iPoint, 2)); - if (nDim==3) SetVolumeOutputValue("STOCHVAR_Z", iPoint, Node_Turb->GetSolution(iPoint, 3)); + SetVolumeOutputValue("STOCHVAR_Z", iPoint, Node_Turb->GetSolution(iPoint, 3)); } SetVolumeOutputValue("STOCHSOURCE_X", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 0)); SetVolumeOutputValue("STOCHSOURCE_Y", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 1)); - if (nDim==3) SetVolumeOutputValue("STOCHSOURCE_Z", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 2)); + SetVolumeOutputValue("STOCHSOURCE_Z", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 2)); SetVolumeOutputValue("ENERGY_BACKSCATTER_RATIO", iPoint, GetEnergyBackscatterRatio(iPoint, config, Node_Flow, Node_Turb)); } } - if (config->GetTime_Domain()) { - const su2double rho = Node_Flow->GetDensity(iPoint); - const su2double nu_t = Node_Flow->GetEddyViscosity(iPoint) / rho; - const auto vel_grad = Node_Flow->GetVelocityGradient(iPoint); - const su2double vel_div = vel_grad(0,0) + vel_grad(1,1) + (nDim ==3 ? vel_grad(2,2) : 0.0); - const su2double tau_xx = nu_t * (2*vel_grad(0,0) - (2.0/3.0)*vel_div); - const su2double tau_yy = nu_t * (2*vel_grad(1,1) - (2.0/3.0)*vel_div); - const su2double tau_xy = nu_t * (vel_grad(0,1) + vel_grad(1,0)); - SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_11", iPoint, -tau_xx); - SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_22", iPoint, -tau_yy); - SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_12", iPoint, -tau_xy); - if (nDim == 3){ - const su2double tau_zz = nu_t * (2*vel_grad(2,2) - (2.0/3.0)*vel_div); - const su2double tau_xz = nu_t * (vel_grad(0,2) + vel_grad(2,0)); - const su2double tau_yz = nu_t * (vel_grad(1,2) + vel_grad(2,1)); - SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_33", iPoint, -tau_zz); - SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_13", iPoint, -tau_xz); - SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_23", iPoint, -tau_yz); - } - if (config->GetKind_HybridRANSLES()!=NO_HYBRIDRANSLES && config->GetSBSParam().StochasticBackscatter) { - const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1e-10); - const su2double lesSensor = Node_Flow->GetLES_Mode(iPoint); - const su2double mag = config->GetSBSParam().SBS_Cmag; - const su2double threshold = config->GetSBSParam().stochFdThreshold; - su2double tke_estim = 0.0; - if (lesSensor > threshold) tke_estim = pow(nu_t/DES_lengthscale, 2); - const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); - const su2double csi_y = Node_Turb->GetSolution(iPoint, 2); - const su2double csi_z = Node_Turb->GetSolution(iPoint, 3); - const su2double R_xy = - mag * tke_estim * csi_z; - const su2double R_xz = + mag * tke_estim * csi_y; - const su2double R_yz = - mag * tke_estim * csi_x; - SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_12", iPoint, -R_xy); - SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_13", iPoint, -R_xz); - SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_23", iPoint, -R_yz); - } - } - switch (config->GetKind_Species_Model()) { case SPECIES_MODEL::SPECIES_TRANSPORT: { @@ -4125,7 +4087,7 @@ bool CFlowOutput::WriteVolumeOutput(CConfig *config, unsigned long Iter, bool fo return force_writing; } -void CFlowOutput::SetTimeAveragedFields() { +void CFlowOutput::SetTimeAveragedFields(const CConfig *config) { AddVolumeOutput("MEAN_DENSITY", "MeanDensity", "TIME_AVERAGE", "Mean density"); AddVolumeOutput("MEAN_VELOCITY-X", "MeanVelocity_x", "TIME_AVERAGE", "Mean velocity x-component"); AddVolumeOutput("MEAN_VELOCITY-Y", "MeanVelocity_y", "TIME_AVERAGE", "Mean velocity y-component"); @@ -4164,12 +4126,14 @@ void CFlowOutput::SetTimeAveragedFields() { AddVolumeOutput("MODELED_REYNOLDS_STRESS_23", "ModeledReynoldsStress_23", "TIME_AVERAGE", "Modeled Reynolds stress yz-component"); } - AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_12", "StochasticReynoldsStress_12", "TIME_AVERAGE", "Stochastic Reynolds stress xy-component"); - AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_13", "StochasticReynoldsStress_13", "TIME_AVERAGE", "Stochastic Reynolds stress xz-component"); - AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_23", "StochasticReynoldsStress_23", "TIME_AVERAGE", "Stochastic Reynolds stress yz-component"); + if (config->GetSBSParam().StochasticBackscatter) { + AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_12", "StochasticReynoldsStress_12", "TIME_AVERAGE", "Stochastic Reynolds stress xy-component"); + AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_13", "StochasticReynoldsStress_13", "TIME_AVERAGE", "Stochastic Reynolds stress xz-component"); + AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_23", "StochasticReynoldsStress_23", "TIME_AVERAGE", "Stochastic Reynolds stress yz-component"); + } } -void CFlowOutput::LoadTimeAveragedData(unsigned long iPoint, const CVariable *Node_Flow){ +void CFlowOutput::LoadTimeAveragedData(unsigned long iPoint, const CVariable *Node_Flow, const CVariable *Node_Turb, const CConfig *config){ SetAvgVolumeOutputValue("MEAN_DENSITY", iPoint, Node_Flow->GetDensity(iPoint)); SetAvgVolumeOutputValue("MEAN_VELOCITY-X", iPoint, Node_Flow->GetVelocity(iPoint,0)); SetAvgVolumeOutputValue("MEAN_VELOCITY-Y", iPoint, Node_Flow->GetVelocity(iPoint,1)); @@ -4208,6 +4172,43 @@ void CFlowOutput::LoadTimeAveragedData(unsigned long iPoint, const CVariable *No SetVolumeOutputValue("UWPRIME", iPoint, -(umean*wmean - uwmean)); SetVolumeOutputValue("VWPRIME", iPoint, -(vmean*wmean - vwmean)); } + + const su2double rho = Node_Flow->GetDensity(iPoint); + const su2double nu_t = Node_Flow->GetEddyViscosity(iPoint) / rho; + const auto vel_grad = Node_Flow->GetVelocityGradient(iPoint); + const su2double vel_div = vel_grad(0,0) + vel_grad(1,1) + (nDim ==3 ? vel_grad(2,2) : 0.0); + const su2double tau_xx = nu_t * (2*vel_grad(0,0) - (2.0/3.0)*vel_div); + const su2double tau_yy = nu_t * (2*vel_grad(1,1) - (2.0/3.0)*vel_div); + const su2double tau_xy = nu_t * (vel_grad(0,1) + vel_grad(1,0)); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_11", iPoint, -tau_xx); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_22", iPoint, -tau_yy); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_12", iPoint, -tau_xy); + if (nDim == 3){ + const su2double tau_zz = nu_t * (2*vel_grad(2,2) - (2.0/3.0)*vel_div); + const su2double tau_xz = nu_t * (vel_grad(0,2) + vel_grad(2,0)); + const su2double tau_yz = nu_t * (vel_grad(1,2) + vel_grad(2,1)); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_33", iPoint, -tau_zz); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_13", iPoint, -tau_xz); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_23", iPoint, -tau_yz); + } + + if (config->GetSBSParam().StochasticBackscatter) { + const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1e-10); + const su2double lesSensor = Node_Flow->GetLES_Mode(iPoint); + const su2double mag = config->GetSBSParam().SBS_Cmag; + const su2double threshold = config->GetSBSParam().stochFdThreshold; + su2double tke_estim = 0.0; + if (lesSensor > threshold) tke_estim = pow(nu_t/DES_lengthscale, 2); + const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); + const su2double csi_y = Node_Turb->GetSolution(iPoint, 2); + const su2double csi_z = Node_Turb->GetSolution(iPoint, 3); + const su2double R_xy = - mag * tke_estim * csi_z; + const su2double R_xz = + mag * tke_estim * csi_y; + const su2double R_yz = - mag * tke_estim * csi_x; + SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_12", iPoint, -R_xy); + SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_13", iPoint, -R_xz); + SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_23", iPoint, -R_yz); + } } void CFlowOutput::SetFixedCLScreenOutput(const CConfig *config){ diff --git a/SU2_CFD/src/output/CNEMOCompOutput.cpp b/SU2_CFD/src/output/CNEMOCompOutput.cpp index fb6b8f90662..7ed4cfe0a97 100644 --- a/SU2_CFD/src/output/CNEMOCompOutput.cpp +++ b/SU2_CFD/src/output/CNEMOCompOutput.cpp @@ -299,13 +299,14 @@ void CNEMOCompOutput::SetVolumeOutputFields(CConfig *config){ AddCommonFVMOutputs(config); if (config->GetTime_Domain()) { - SetTimeAveragedFields(); + SetTimeAveragedFields(config); } } void CNEMOCompOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolver **solver, unsigned long iPoint){ const auto* Node_Flow = solver[FLOW_SOL]->GetNodes(); + const auto* Node_Turb = solver[TURB_SOL]->GetNodes(); auto* Node_Geo = geometry->nodes; const auto nSpecies = config->GetnSpecies(); @@ -385,7 +386,7 @@ void CNEMOCompOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolv LoadCommonFVMOutputs(config, geometry, iPoint); if (config->GetTime_Domain()) { - LoadTimeAveragedData(iPoint, Node_Flow); + LoadTimeAveragedData(iPoint, Node_Flow, Node_Turb, config); } } From 6dc1738df10c04a6ea34ae007a240a8ce1e1f84b Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Tue, 7 Apr 2026 11:29:02 +0200 Subject: [PATCH 47/70] Update SU2_CFD/include/variables/CTurbSAVariable.hpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/include/variables/CTurbSAVariable.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/SU2_CFD/include/variables/CTurbSAVariable.hpp b/SU2_CFD/include/variables/CTurbSAVariable.hpp index 756df06f7c5..a180fd3e8cf 100644 --- a/SU2_CFD/include/variables/CTurbSAVariable.hpp +++ b/SU2_CFD/include/variables/CTurbSAVariable.hpp @@ -28,7 +28,6 @@ #pragma once #include "CTurbVariable.hpp" -#include /*! * \class CTurbSAVariable From 592bdf46f83cb0ad7bd8bd790366e33705a55f73 Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Tue, 7 Apr 2026 11:29:25 +0200 Subject: [PATCH 48/70] Update SU2_CFD/include/numerics/CNumerics.hpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/include/numerics/CNumerics.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index 3641e9bc463..cc514609d04 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -32,7 +32,6 @@ #include #include #include -#include #include "../../../Common/include/CConfig.hpp" #include "../../../Common/include/linear_algebra/blas_structure.hpp" From fdbec427c9df26b7144662f15c215bf88f307d8d Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Tue, 7 Apr 2026 11:29:53 +0200 Subject: [PATCH 49/70] Update SU2_CFD/src/solvers/CTurbSASolver.cpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/src/solvers/CTurbSASolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 0e901477267..7623d61708d 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1622,7 +1622,7 @@ void CTurbSASolver::SetBackscatterInBox(CConfig *config, CGeometry *geometry) { auto sbsBoxBounds = config->GetSBSParam().StochBackscatterBoxBounds; SU2_OMP_FOR_STAT(omp_chunk_size) - for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { + for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { const auto coord = geometry->nodes->GetCoord(iPoint); bool outOfBoxX = (coord[0]sbsBoxBounds[1]); bool outOfBoxY = (coord[1]sbsBoxBounds[3]); From 3c2e445b49281ae71d96276d05e5a13af85d71c2 Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Tue, 7 Apr 2026 11:30:23 +0200 Subject: [PATCH 50/70] Update SU2_CFD/src/solvers/CTurbSASolver.cpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/src/solvers/CTurbSASolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 7623d61708d..d93e5dc5147 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1628,7 +1628,7 @@ void CTurbSASolver::SetBackscatterInBox(CConfig *config, CGeometry *geometry) { bool outOfBoxY = (coord[1]sbsBoxBounds[3]); bool outOfBoxZ = (coord[2]sbsBoxBounds[5]); bool outOfBox = (outOfBoxX || outOfBoxY || outOfBoxZ); - if (outOfBox) nodes->SetSbsInBox(iPoint, 0.0); + nodes->SetSbsInBox(iPoint, outOfBox ? 0 : 1); } END_SU2_OMP_FOR From 17bfb650a7262416e676d08302c1e881b69b0c11 Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Tue, 7 Apr 2026 11:30:38 +0200 Subject: [PATCH 51/70] Update SU2_CFD/src/solvers/CTurbSASolver.cpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/src/solvers/CTurbSASolver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index d93e5dc5147..0fbac6a64a4 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1891,6 +1891,7 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet cout << endl; } } + /*--- Converged or maximum number of iterations reached. ---*/ break; } From a27c3ffe136122c259a7cc9ba6a79cbccb025d8b Mon Sep 17 00:00:00 2001 From: paan882 Date: Tue, 7 Apr 2026 12:40:02 +0200 Subject: [PATCH 52/70] Add residuals of stoch. variables to vol. outputs --- SU2_CFD/src/output/CFlowOutput.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index 2c715f9cece..3afd0b8f8ea 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -1158,6 +1158,14 @@ void CFlowOutput::AddHistoryOutputFields_ScalarBGS_RES(const CConfig* config) { case TURB_FAMILY::SA: /// DESCRIPTION: Maximum residual of nu tilde (SA model). AddHistoryOutput("BGS_NU_TILDE", "bgs[nu]", ScreenOutputFormat::FIXED, "BGS_RES", "BGS residual of nu tilde (SA model).", HistoryFieldType::RESIDUAL); + if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) { + /// DESCRIPTION: Maximum residual of stochastic vector x-component (Stochastic Backscatter Model). + AddHistoryOutput("BGS_STOCH_VAR-X", "bgs[stoch_x]", ScreenOutputFormat::FIXED, "BGS_RES", "BGS residual of stochastic vector x-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + /// DESCRIPTION: Maximum residual of stochastic vector y-component (Stochastic Backscatter Model). + AddHistoryOutput("BGS_STOCH_VAR-Y", "bgs[stoch_y]", ScreenOutputFormat::FIXED, "BGS_RES", "BGS residual of stochastic vector y-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + /// DESCRIPTION: Maximum residual of stochastic vector z-component (Stochastic Backscatter Model). + AddHistoryOutput("BGS_STOCH_VAR-Z", "bgs[stoch_z]", ScreenOutputFormat::FIXED, "BGS_RES", "BGS residual of stochastic vector z-component (Stochastic Backscatter Model).", HistoryFieldType::RESIDUAL); + } break; case TURB_FAMILY::KW: @@ -1344,7 +1352,7 @@ void CFlowOutput::SetVolumeOutputFieldsScalarSolution(const CConfig* config){ switch (TurbModelFamily(config->GetKind_Turb_Model())) { case TURB_FAMILY::SA: AddVolumeOutput("NU_TILDE", "Nu_Tilde", "SOLUTION", "Spalart-Allmaras variable"); - if (config->GetSBSParam().SBS_Ctau > 0.0) { + if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) { AddVolumeOutput("STOCHVAR_X", "StochVar_x", "SOLUTION", "x-component of the stochastic vector potential"); AddVolumeOutput("STOCHVAR_Y", "StochVar_y", "SOLUTION", "y-component of the stochastic vector potential"); AddVolumeOutput("STOCHVAR_Z", "StochVar_z", "SOLUTION", "z-component of the stochastic vector potential"); @@ -1401,6 +1409,11 @@ void CFlowOutput::SetVolumeOutputFieldsScalarResidual(const CConfig* config) { switch (TurbModelFamily(config->GetKind_Turb_Model())){ case TURB_FAMILY::SA: AddVolumeOutput("RES_NU_TILDE", "Residual_Nu_Tilde", "RESIDUAL", "Residual of the Spalart-Allmaras variable"); + if (config->GetSBSParam().StochasticBackscatter && config->GetSBSParam().SBS_Ctau > 0.0) { + AddVolumeOutput("RES_STOCHVAR_X", "Residual_StochVar_X", "RESIDUAL", "Residual of the x-component of the stochastic vector potential"); + AddVolumeOutput("RES_STOCHVAR_Y", "Residual_StochVar_Y", "RESIDUAL", "Residual of the y-component of the stochastic vector potential"); + AddVolumeOutput("RES_STOCHVAR_Z", "Residual_StochVar_Z", "RESIDUAL", "Residual of the z-component of the stochastic vector potential"); + } break; case TURB_FAMILY::KW: @@ -1693,6 +1706,9 @@ void CFlowOutput::LoadVolumeDataScalar(const CConfig* config, const CSolver* con SetVolumeOutputValue("STOCHVAR_X", iPoint, Node_Turb->GetSolution(iPoint, 1)); SetVolumeOutputValue("STOCHVAR_Y", iPoint, Node_Turb->GetSolution(iPoint, 2)); SetVolumeOutputValue("STOCHVAR_Z", iPoint, Node_Turb->GetSolution(iPoint, 3)); + SetVolumeOutputValue("RES_STOCHVAR_X", iPoint, turb_solver->LinSysRes(iPoint, 1)); + SetVolumeOutputValue("RES_STOCHVAR_Y", iPoint, turb_solver->LinSysRes(iPoint, 2)); + SetVolumeOutputValue("RES_STOCHVAR_Z", iPoint, turb_solver->LinSysRes(iPoint, 3)); } SetVolumeOutputValue("STOCHSOURCE_X", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 0)); SetVolumeOutputValue("STOCHSOURCE_Y", iPoint, Node_Turb->GetLangevinSourceTerms(iPoint, 1)); From f7bd1c7b597fa5b07dd88e58abe93a98d8950a1c Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:24:52 +0200 Subject: [PATCH 53/70] Update Common/include/toolboxes/random_toolbox.hpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- Common/include/toolboxes/random_toolbox.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index b5c1a74a3df..e251f573ebf 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -1,7 +1,7 @@ /*! * \file random_toolbox.hpp * \brief Collection of utility functions for random number generation. - * \version 8.3.0 "Harrier" + * \version 8.4.0 "Harrier" * * SU2 Project Website: https://su2code.github.io * From ebcc1b87f097605df8058c453586a04ed69db344 Mon Sep 17 00:00:00 2001 From: paan882 Date: Thu, 9 Apr 2026 14:37:13 +0200 Subject: [PATCH 54/70] Fix compilation errors --- SU2_CFD/include/numerics/CNumerics.hpp | 2 +- SU2_CFD/src/solvers/CTurbSASolver.cpp | 1 - SU2_CFD/src/variables/CTurbSAVariable.cpp | 15 ++++++++++----- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index cc514609d04..e910c6c5a48 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -920,7 +920,7 @@ class CNumerics { * \param[in] val_sbsInBox_i - 1 if point i lies inside the box where the model is active. * \param[in] val_sbsInBox_j - 1 if point j lies inside the box where the model is active. */ - inline void SetSbsInBoxSensor(su2double val_sbsInBox_i, su2double val_sbsInBox_j) { + inline void SetSbsInBoxSensor(unsigned short val_sbsInBox_i, unsigned short val_sbsInBox_j) { sbsInBox_i = val_sbsInBox_i; sbsInBox_j = val_sbsInBox_j; } diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index d6eeadfdd6c..78b38a3fb00 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1680,7 +1680,6 @@ void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geometry) { const su2double LES_FilterWidth = config->GetLES_FilterWidth(); - const su2double constDES = config->GetConst_DES(); const su2double cDelta = config->GetSBSParam().SBS_Cdelta; const unsigned short maxIter = config->GetSBSParam().SBS_maxIterSmooth; const su2double tol = -5.0; diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index 62120f2624a..c745dbd52bc 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -57,12 +57,17 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi } DES_LengthScale.resize(nPoint) = su2double(0.0); - lesMode.resize(nPoint) = su2double(0.0); - sbsInBox.resize(nPoint) = su2double(1.0); Vortex_Tilting.resize(nPoint); - stochSource.resize(nPoint, nDim) = su2double(0.0); - stochSourceOld.resize(nPoint, nDim) = su2double(0.0); - besselIntegral.resize(nPoint) = su2double(0.0); + + if (config->GetKind_HybridRANSLES() != NO_HYBRIDRANSLES) { + lesMode.resize(nPoint) = su2double(0.0); + if (backscatter) { + sbsInBox.resize(nPoint) = su2double(1.0); + stochSource.resize(nPoint, nDim) = su2double(0.0); + stochSourceOld.resize(nPoint, nDim) = su2double(0.0); + besselIntegral.resize(nPoint) = su2double(0.0); + } + } } From 4d6ee964c74b31647ec17d05d817be5c5fdcbe5f Mon Sep 17 00:00:00 2001 From: paan882 Date: Thu, 9 Apr 2026 17:00:35 +0200 Subject: [PATCH 55/70] Fix compilation errors - bis --- Common/include/toolboxes/random_toolbox.hpp | 40 ++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index e251f573ebf..46037e91ed0 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -107,19 +107,19 @@ inline double GetNormal(unsigned long nodeIndex, unsigned long dim, unsigned lon * \return Value of Bessel function. */ template -inline T GetBesselZero(T x) { - T abx = fabs(x); +inline auto GetBesselZero(const T& x) { + auto abx = fabs(x); if (abx < 3.75) { - T t = abx / 3.75; - T p = + auto t = abx / 3.75; + auto p = 1.0 + t * t * (3.5156229 + t * t * (3.0899424 + t * t * (1.2067492 + t * t * (0.2659732 + t * t * (0.0360768 + t * t * 0.0045813))))); return log(p); } else { - T t = 3.75 / abx; - T poly = + auto t = 3.75 / abx; + auto poly = 0.39894228 + t * (0.01328592 + t * (0.00225319 + @@ -138,22 +138,22 @@ inline T GetBesselZero(T x) { * \return Value of the integral. */ template -inline T GetBesselIntegral(T beta_x, T beta_y, T beta_z) { - const T A = 1.0 + 2.0 * (beta_x + beta_y + beta_z); - const T Bx = 2.0 * beta_x; - const T By = 2.0 * beta_y; - const T Bz = 2.0 * beta_z; +inline auto GetBesselIntegral(const T& beta_x, const T& beta_y, const T& beta_z) { + const auto A = 1.0 + 2.0 * (beta_x + beta_y + beta_z); + const auto Bx = 2.0 * beta_x; + const auto By = 2.0 * beta_y; + const auto Bz = 2.0 * beta_z; const int N = 4000; - const T t_max = 20.0; - const T dt = t_max / N; - T sum = 0.0; + const auto t_max = T(20.0); + const auto dt = t_max / N; + auto sum = T(0.0); for (int i = 1; i <= N; i++) { - T t = i * dt; - T lx = GetBesselZero(Bx * t); - T ly = GetBesselZero(By * t); - T lz = GetBesselZero(Bz * t); - T lin = log(t) - A * t + lx + ly + lz; - T integrand = exp(lin); + auto t = i * dt; + auto lx = GetBesselZero(Bx * t); + auto ly = GetBesselZero(By * t); + auto lz = GetBesselZero(Bz * t); + auto lin = log(t) - A * t + lx + ly + lz; + auto integrand = exp(lin); if (i == N) integrand *= 0.5; sum += integrand; } From f6c1f0824259371c0224bb05189aa30457a16a70 Mon Sep 17 00:00:00 2001 From: paan882 Date: Thu, 9 Apr 2026 17:41:41 +0200 Subject: [PATCH 56/70] Fix compilation errors - tris --- Common/include/toolboxes/random_toolbox.hpp | 59 +++++++++++++-------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index 46037e91ed0..bece09a05e2 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -109,23 +109,32 @@ inline double GetNormal(unsigned long nodeIndex, unsigned long dim, unsigned lon template inline auto GetBesselZero(const T& x) { auto abx = fabs(x); - if (abx < 3.75) { - auto t = abx / 3.75; + + if (abx < T(3.75)) { + auto t = abx / T(3.75); auto p = - 1.0 + + T(1.0) + t * t * - (3.5156229 + - t * t * (3.0899424 + t * t * (1.2067492 + t * t * (0.2659732 + t * t * (0.0360768 + t * t * 0.0045813))))); + (T(3.5156229) + + t * t * + (T(3.0899424) + + t * t * (T(1.2067492) + t * t * (T(0.2659732) + t * t * (T(0.0360768) + t * t * T(0.0045813)))))); return log(p); } else { - auto t = 3.75 / abx; + auto t = T(3.75) / abx; + auto poly = - 0.39894228 + - t * (0.01328592 + - t * (0.00225319 + - t * (-0.00157565 + - t * (0.00916281 + t * (-0.02057706 + t * (0.02635537 + t * (-0.01647633 + t * 0.00392377))))))); - return abx - log(sqrt(abx) * poly); + T(0.39894228) + + t * (T(0.01328592) + + t * (T(0.00225319) + + t * (T(-0.00157565) + + t * (T(0.00916281) + + t * (T(-0.02057706) + t * (T(0.02635537) + t * (T(-0.01647633) + t * T(0.00392377)))))))); + + auto arg = sqrt(abx) * poly; + auto log_term = log(arg); + + return abx - log_term; } } @@ -139,24 +148,28 @@ inline auto GetBesselZero(const T& x) { */ template inline auto GetBesselIntegral(const T& beta_x, const T& beta_y, const T& beta_z) { - const auto A = 1.0 + 2.0 * (beta_x + beta_y + beta_z); - const auto Bx = 2.0 * beta_x; - const auto By = 2.0 * beta_y; - const auto Bz = 2.0 * beta_z; + const auto A = T(1.0) + T(2.0) * (beta_x + beta_y + beta_z); + const auto Bx = T(2.0) * beta_x; + const auto By = T(2.0) * beta_y; + const auto Bz = T(2.0) * beta_z; + const int N = 4000; const auto t_max = T(20.0); const auto dt = t_max / N; - auto sum = T(0.0); + + T sum = T(0.0); + for (int i = 1; i <= N; i++) { auto t = i * dt; - auto lx = GetBesselZero(Bx * t); - auto ly = GetBesselZero(By * t); - auto lz = GetBesselZero(Bz * t); - auto lin = log(t) - A * t + lx + ly + lz; + + auto lin = log(t) - A * t + GetBesselZero(Bx * t) + GetBesselZero(By * t) + GetBesselZero(Bz * t); + auto integrand = exp(lin); - if (i == N) integrand *= 0.5; - sum += integrand; + + auto weight = (i == N) ? T(0.5) : T(1.0); + sum += integrand * weight; } + return sum * dt; } From 86a1d425379790b585edf9b42d6090fbac7a67fa Mon Sep 17 00:00:00 2001 From: paan882 Date: Thu, 9 Apr 2026 17:58:50 +0200 Subject: [PATCH 57/70] Fix compilation errors - tetra --- Common/include/toolboxes/random_toolbox.hpp | 37 +++++++++++---------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index bece09a05e2..2b55fc6ab0c 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -110,31 +110,34 @@ template inline auto GetBesselZero(const T& x) { auto abx = fabs(x); - if (abx < T(3.75)) { - auto t = abx / T(3.75); + if (abx < 3.75) { + auto t = abx / 3.75; auto p = - T(1.0) + + 1.0 + t * t * - (T(3.5156229) + - t * t * - (T(3.0899424) + - t * t * (T(1.2067492) + t * t * (T(0.2659732) + t * t * (T(0.0360768) + t * t * T(0.0045813)))))); + (3.5156229 + + t * t * (3.0899424 + + t * t * (1.2067492 + + t * t * (0.2659732 + + t * t * (0.0360768 + + t * t * 0.0045813))))); return log(p); } else { - auto t = T(3.75) / abx; + auto t = 3.75 / abx; auto poly = - T(0.39894228) + - t * (T(0.01328592) + - t * (T(0.00225319) + - t * (T(-0.00157565) + - t * (T(0.00916281) + - t * (T(-0.02057706) + t * (T(0.02635537) + t * (T(-0.01647633) + t * T(0.00392377)))))))); + 0.39894228 + + t * (0.01328592 + + t * (0.00225319 + + t * (-0.00157565 + + t * (0.00916281 + + t * (-0.02057706 + + t * (0.02635537 + + t * (-0.01647633 + + t * 0.00392377))))))); auto arg = sqrt(abx) * poly; - auto log_term = log(arg); - - return abx - log_term; + return abx - log(arg); } } From 9a3a043e8a8dff93d0767f9701c90e196acdee3f Mon Sep 17 00:00:00 2001 From: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> Date: Fri, 10 Apr 2026 04:34:41 +0100 Subject: [PATCH 58/70] Apply suggestions from code review Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- Common/include/toolboxes/random_toolbox.hpp | 36 ++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index 2b55fc6ab0c..a1aca395a24 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -107,12 +107,12 @@ inline double GetNormal(unsigned long nodeIndex, unsigned long dim, unsigned lon * \return Value of Bessel function. */ template -inline auto GetBesselZero(const T& x) { - auto abx = fabs(x); +inline T GetBesselZero(const T& x) { + T abx = fabs(x); if (abx < 3.75) { - auto t = abx / 3.75; - auto p = + T t = abx / 3.75; + T p = 1.0 + t * t * (3.5156229 + @@ -123,9 +123,9 @@ inline auto GetBesselZero(const T& x) { t * t * 0.0045813))))); return log(p); } else { - auto t = 3.75 / abx; + T t = 3.75 / abx; - auto poly = + T poly = 0.39894228 + t * (0.01328592 + t * (0.00225319 + @@ -136,7 +136,7 @@ inline auto GetBesselZero(const T& x) { t * (-0.01647633 + t * 0.00392377))))))); - auto arg = sqrt(abx) * poly; + T arg = sqrt(abx) * poly; return abx - log(arg); } } @@ -150,26 +150,26 @@ inline auto GetBesselZero(const T& x) { * \return Value of the integral. */ template -inline auto GetBesselIntegral(const T& beta_x, const T& beta_y, const T& beta_z) { - const auto A = T(1.0) + T(2.0) * (beta_x + beta_y + beta_z); - const auto Bx = T(2.0) * beta_x; - const auto By = T(2.0) * beta_y; - const auto Bz = T(2.0) * beta_z; +inline T GetBesselIntegral(const T& beta_x, const T& beta_y, const T& beta_z) { + const T A = 1 + 2 * (beta_x + beta_y + beta_z); + const T Bx = 2 * beta_x; + const T By = 2 * beta_y; + const T Bz = 2 * beta_z; const int N = 4000; - const auto t_max = T(20.0); - const auto dt = t_max / N; + const T t_max = 20.0; + const T dt = t_max / N; T sum = T(0.0); for (int i = 1; i <= N; i++) { - auto t = i * dt; + T t = i * dt; - auto lin = log(t) - A * t + GetBesselZero(Bx * t) + GetBesselZero(By * t) + GetBesselZero(Bz * t); + T lin = log(t) - A * t + GetBesselZero(T(Bx * t)) + GetBesselZero(T(By * t)) + GetBesselZero(T(Bz * t)); - auto integrand = exp(lin); + T integrand = exp(lin); - auto weight = (i == N) ? T(0.5) : T(1.0); + T weight = (i == N) ? 0.5 : 1.0; sum += integrand * weight; } From 44fd5689eb374712e0153395a608f6cffad6c95c Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:09:48 +0200 Subject: [PATCH 59/70] Update SU2_CFD/include/variables/CTurbSAVariable.hpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/include/variables/CTurbSAVariable.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SU2_CFD/include/variables/CTurbSAVariable.hpp b/SU2_CFD/include/variables/CTurbSAVariable.hpp index a180fd3e8cf..bd810bb73d2 100644 --- a/SU2_CFD/include/variables/CTurbSAVariable.hpp +++ b/SU2_CFD/include/variables/CTurbSAVariable.hpp @@ -41,7 +41,7 @@ class CTurbSAVariable final : public CTurbVariable { private: VectorType DES_LengthScale; VectorType lesMode; - VectorType sbsInBox; + su2vector sbsInBox; MatrixType stochSource; MatrixType stochSourceOld; VectorType Vortex_Tilting; From 52f3ec15181e95f03d41720625bddb53f31b1aed Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:10:02 +0200 Subject: [PATCH 60/70] Update SU2_CFD/include/variables/CTurbSAVariable.hpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/include/variables/CTurbSAVariable.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SU2_CFD/include/variables/CTurbSAVariable.hpp b/SU2_CFD/include/variables/CTurbSAVariable.hpp index bd810bb73d2..28f55046d0b 100644 --- a/SU2_CFD/include/variables/CTurbSAVariable.hpp +++ b/SU2_CFD/include/variables/CTurbSAVariable.hpp @@ -122,7 +122,7 @@ class CTurbSAVariable final : public CTurbVariable { * \param[in] iPoint - Point index. * \param[in] val_sbsInBox - 1.0 if the Stochastic Backscatter Model must be applied only in a confined box. */ - inline void SetSbsInBox(unsigned long iPoint, su2double val_sbsInBox) override { sbsInBox(iPoint) = val_sbsInBox; } + inline void SetSbsInBox(unsigned long iPoint, int8_t val_sbsInBox) override { sbsInBox(iPoint) = val_sbsInBox; } /*! * \brief Set the LES sensor. From 052d6138fcf80707a308cbee5920165803228cd8 Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:10:33 +0200 Subject: [PATCH 61/70] Update SU2_CFD/include/variables/CTurbSAVariable.hpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/include/variables/CTurbSAVariable.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SU2_CFD/include/variables/CTurbSAVariable.hpp b/SU2_CFD/include/variables/CTurbSAVariable.hpp index 28f55046d0b..20c073d41d8 100644 --- a/SU2_CFD/include/variables/CTurbSAVariable.hpp +++ b/SU2_CFD/include/variables/CTurbSAVariable.hpp @@ -115,7 +115,7 @@ class CTurbSAVariable final : public CTurbVariable { * \param[in] iPoint - Point index. * \return 1.0 if the Stochastic Backscatter Model must be applied only in a confined box. */ - inline su2double GetSbsInBox(unsigned long iPoint) const override { return sbsInBox(iPoint); } + inline int8_t GetSbsInBox(unsigned long iPoint) const override { return sbsInBox(iPoint); } /*! * \brief Set if the Stochastic Backscatter Model must be applied only in a confined box. From 29004cb83a3a8f93ecbdf86bc701e07d5699699b Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:10:48 +0200 Subject: [PATCH 62/70] Update SU2_CFD/include/variables/CTurbVariable.hpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/include/variables/CTurbVariable.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SU2_CFD/include/variables/CTurbVariable.hpp b/SU2_CFD/include/variables/CTurbVariable.hpp index 3aa9ef71089..47424ffab8c 100644 --- a/SU2_CFD/include/variables/CTurbVariable.hpp +++ b/SU2_CFD/include/variables/CTurbVariable.hpp @@ -131,12 +131,12 @@ class CTurbVariable : public CScalarVariable { * \brief A virtual member. * \param[in] iPoint - Point index. */ - inline virtual su2double GetSbsInBox(unsigned long iPoint) const { return 0.0; } + inline virtual int8_t GetSbsInBox(unsigned long iPoint) const { return 0; } /*! * \brief A virtual member. * \param[in] iPoint - Point index. * \param[in] val_sbsInBox - 1.0 if the Stochastic Backscatter Model must be applied only in a confined box. */ - inline virtual void SetSbsInBox(unsigned long iPoint, su2double val_sbsInBox) {} + inline virtual void SetSbsInBox(unsigned long iPoint, int8_t val_sbsInBox) {} }; From 92f905676bd6aa011a24705e37c6d37b09d76071 Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:11:06 +0200 Subject: [PATCH 63/70] Update SU2_CFD/src/variables/CTurbSAVariable.cpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/src/variables/CTurbSAVariable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SU2_CFD/src/variables/CTurbSAVariable.cpp b/SU2_CFD/src/variables/CTurbSAVariable.cpp index c745dbd52bc..4166e285b10 100644 --- a/SU2_CFD/src/variables/CTurbSAVariable.cpp +++ b/SU2_CFD/src/variables/CTurbSAVariable.cpp @@ -62,7 +62,7 @@ CTurbSAVariable::CTurbSAVariable(su2double val_nu_tilde, su2double val_muT, unsi if (config->GetKind_HybridRANSLES() != NO_HYBRIDRANSLES) { lesMode.resize(nPoint) = su2double(0.0); if (backscatter) { - sbsInBox.resize(nPoint) = su2double(1.0); + sbsInBox.resize(nPoint) = 1; stochSource.resize(nPoint, nDim) = su2double(0.0); stochSourceOld.resize(nPoint, nDim) = su2double(0.0); besselIntegral.resize(nPoint) = su2double(0.0); From 36f154b195d6fa8746ba27efe974e2fc08a5b2c4 Mon Sep 17 00:00:00 2001 From: Angelo Passariello <91474456+AngPass@users.noreply.github.com> Date: Fri, 10 Apr 2026 09:11:23 +0200 Subject: [PATCH 64/70] Update SU2_CFD/src/solvers/CTurbSASolver.cpp Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_CFD/src/solvers/CTurbSASolver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 78b38a3fb00..b701d7e9f7f 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -422,7 +422,7 @@ void CTurbSASolver::Source_Residual(CGeometry *geometry, CSolver **solver_contai for (unsigned short iDim = 0; iDim < nDim; iDim++) numerics->SetStochSource(nodes->GetLangevinSourceTerms(iPoint, iDim), iDim); numerics->SetLES_Mode(nodes->GetLES_Mode(iPoint), 0.0); - numerics->SetSbsInBoxSensor(std::nearbyint(nodes->GetSbsInBox(iPoint)), 0); + numerics->SetSbsInBoxSensor(nodes->GetSbsInBox(iPoint), 0); } } From ffdeca1ed324b8aa6257374ba4760a77708229d0 Mon Sep 17 00:00:00 2001 From: paan882 Date: Fri, 10 Apr 2026 09:18:25 +0200 Subject: [PATCH 65/70] Fix code formatting --- Common/include/toolboxes/random_toolbox.hpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/Common/include/toolboxes/random_toolbox.hpp b/Common/include/toolboxes/random_toolbox.hpp index a1aca395a24..0f053497ae4 100644 --- a/Common/include/toolboxes/random_toolbox.hpp +++ b/Common/include/toolboxes/random_toolbox.hpp @@ -116,11 +116,7 @@ inline T GetBesselZero(const T& x) { 1.0 + t * t * (3.5156229 + - t * t * (3.0899424 + - t * t * (1.2067492 + - t * t * (0.2659732 + - t * t * (0.0360768 + - t * t * 0.0045813))))); + t * t * (3.0899424 + t * t * (1.2067492 + t * t * (0.2659732 + t * t * (0.0360768 + t * t * 0.0045813))))); return log(p); } else { T t = 3.75 / abx; @@ -130,11 +126,7 @@ inline T GetBesselZero(const T& x) { t * (0.01328592 + t * (0.00225319 + t * (-0.00157565 + - t * (0.00916281 + - t * (-0.02057706 + - t * (0.02635537 + - t * (-0.01647633 + - t * 0.00392377))))))); + t * (0.00916281 + t * (-0.02057706 + t * (0.02635537 + t * (-0.01647633 + t * 0.00392377))))))); T arg = sqrt(abx) * poly; return abx - log(arg); From ca99d8d5d3fcc9aad014e00b291ec3f91e057df5 Mon Sep 17 00:00:00 2001 From: paan882 Date: Fri, 10 Apr 2026 11:14:36 +0200 Subject: [PATCH 66/70] Fix compilation errors - V --- SU2_CFD/src/solvers/CTurbSASolver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index b701d7e9f7f..749a1ee9caf 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -1645,7 +1645,7 @@ void CTurbSASolver::SetLangevinSourceTerms(CConfig *config, CGeometry* geometry) for (unsigned short iDim = 0; iDim < nDim; iDim++){ su2double lesSensor = nodes->GetLES_Mode(iPoint); su2double inBoxSensor = nodes->GetSbsInBox(iPoint); - bool insideBox = (std::nearbyint(inBoxSensor) == 1); + bool insideBox = (inBoxSensor == 1); if (lesSensor>threshold && insideBox) { su2double rnd = RandomToolbox::GetNormal(iPointGlobal, iDim, timeIter); nodes->SetLangevinSourceTermsOld(iPoint, iDim, rnd); @@ -1748,7 +1748,7 @@ void CTurbSASolver::SmoothLangevinSourceTerms(CConfig* config, CGeometry* geomet unsigned long global_nPointLES = 0; SU2_MPI::Allreduce(&local_nPointLES, &global_nPointLES, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); SU2_MPI::Allreduce(&localResNorm, &globalResNorm, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - globalResNorm = (global_nPointLES==0) ? 0.0 : sqrt(globalResNorm / global_nPointLES); + globalResNorm = (global_nPointLES==0) ? su2double(0.0) : sqrt(globalResNorm / global_nPointLES); if (rank == MASTER_NODE) { if (iter == 0) { From 6a2f9503c6061812dc94ebe386a3abb5cbab9deb Mon Sep 17 00:00:00 2001 From: paan882 Date: Fri, 10 Apr 2026 12:21:07 +0200 Subject: [PATCH 67/70] Fix errors in regression tests (hopefully) --- SU2_CFD/src/output/CFlowCompOutput.cpp | 3 +- SU2_CFD/src/output/CFlowIncOutput.cpp | 3 +- SU2_CFD/src/output/CFlowOutput.cpp | 96 ++++++++++++++------------ SU2_CFD/src/output/CNEMOCompOutput.cpp | 3 +- 4 files changed, 56 insertions(+), 49 deletions(-) diff --git a/SU2_CFD/src/output/CFlowCompOutput.cpp b/SU2_CFD/src/output/CFlowCompOutput.cpp index 2d189b7b55d..55ee7c8bfed 100644 --- a/SU2_CFD/src/output/CFlowCompOutput.cpp +++ b/SU2_CFD/src/output/CFlowCompOutput.cpp @@ -315,7 +315,8 @@ void CFlowCompOutput::SetVolumeOutputFields(CConfig *config){ void CFlowCompOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolver **solver, unsigned long iPoint){ const auto* Node_Flow = solver[FLOW_SOL]->GetNodes(); - const auto* Node_Turb = solver[TURB_SOL]->GetNodes(); + const CVariable* Node_Turb = nullptr; + if (config->GetKind_Turb_Model() != TURB_MODEL::NONE) Node_Turb = solver[TURB_SOL]->GetNodes(); auto* Node_Geo = geometry->nodes; LoadCoordinates(Node_Geo->GetCoord(iPoint), iPoint); diff --git a/SU2_CFD/src/output/CFlowIncOutput.cpp b/SU2_CFD/src/output/CFlowIncOutput.cpp index c91de17f481..e91e038447e 100644 --- a/SU2_CFD/src/output/CFlowIncOutput.cpp +++ b/SU2_CFD/src/output/CFlowIncOutput.cpp @@ -399,7 +399,8 @@ void CFlowIncOutput::SetVolumeOutputFields(CConfig *config){ void CFlowIncOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolver **solver, unsigned long iPoint){ const auto* Node_Flow = solver[FLOW_SOL]->GetNodes(); - const auto* Node_Turb = solver[TURB_SOL]->GetNodes(); + const CVariable* Node_Turb = nullptr; + if (config->GetKind_Turb_Model() != TURB_MODEL::NONE) Node_Turb = solver[TURB_SOL]->GetNodes(); const CVariable* Node_Heat = nullptr; const CVariable* Node_Rad = nullptr; auto* Node_Geo = geometry->nodes; diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index 3afd0b8f8ea..86ce4213848 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -4133,19 +4133,21 @@ void CFlowOutput::SetTimeAveragedFields(const CConfig *config) { AddVolumeOutput("VWPRIME", "w'v'", "TIME_AVERAGE", "Mean Reynolds-stress component w'v'"); } - AddVolumeOutput("MODELED_REYNOLDS_STRESS_11", "ModeledReynoldsStress_11", "TIME_AVERAGE", "Modeled Reynolds stress xx-component"); - AddVolumeOutput("MODELED_REYNOLDS_STRESS_22", "ModeledReynoldsStress_22", "TIME_AVERAGE", "Modeled Reynolds stress yy-component"); - AddVolumeOutput("MODELED_REYNOLDS_STRESS_12", "ModeledReynoldsStress_12", "TIME_AVERAGE", "Modeled Reynolds stress xy-component"); - if (nDim == 3){ - AddVolumeOutput("MODELED_REYNOLDS_STRESS_33", "ModeledReynoldsStress_33", "TIME_AVERAGE", "Modeled Reynolds stress zz-component"); - AddVolumeOutput("MODELED_REYNOLDS_STRESS_13", "ModeledReynoldsStress_13", "TIME_AVERAGE", "Modeled Reynolds stress xz-component"); - AddVolumeOutput("MODELED_REYNOLDS_STRESS_23", "ModeledReynoldsStress_23", "TIME_AVERAGE", "Modeled Reynolds stress yz-component"); - } + if (config->GetKind_Turb_Model() != TURB_MODEL::NONE) { + AddVolumeOutput("MODELED_REYNOLDS_STRESS_11", "ModeledReynoldsStress_11", "TIME_AVERAGE", "Modeled Reynolds stress xx-component"); + AddVolumeOutput("MODELED_REYNOLDS_STRESS_22", "ModeledReynoldsStress_22", "TIME_AVERAGE", "Modeled Reynolds stress yy-component"); + AddVolumeOutput("MODELED_REYNOLDS_STRESS_12", "ModeledReynoldsStress_12", "TIME_AVERAGE", "Modeled Reynolds stress xy-component"); + if (nDim == 3){ + AddVolumeOutput("MODELED_REYNOLDS_STRESS_33", "ModeledReynoldsStress_33", "TIME_AVERAGE", "Modeled Reynolds stress zz-component"); + AddVolumeOutput("MODELED_REYNOLDS_STRESS_13", "ModeledReynoldsStress_13", "TIME_AVERAGE", "Modeled Reynolds stress xz-component"); + AddVolumeOutput("MODELED_REYNOLDS_STRESS_23", "ModeledReynoldsStress_23", "TIME_AVERAGE", "Modeled Reynolds stress yz-component"); + } - if (config->GetSBSParam().StochasticBackscatter) { - AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_12", "StochasticReynoldsStress_12", "TIME_AVERAGE", "Stochastic Reynolds stress xy-component"); - AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_13", "StochasticReynoldsStress_13", "TIME_AVERAGE", "Stochastic Reynolds stress xz-component"); - AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_23", "StochasticReynoldsStress_23", "TIME_AVERAGE", "Stochastic Reynolds stress yz-component"); + if (config->GetSBSParam().StochasticBackscatter) { + AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_12", "StochasticReynoldsStress_12", "TIME_AVERAGE", "Stochastic Reynolds stress xy-component"); + AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_13", "StochasticReynoldsStress_13", "TIME_AVERAGE", "Stochastic Reynolds stress xz-component"); + AddVolumeOutput("STOCHASTIC_REYNOLDS_STRESS_23", "StochasticReynoldsStress_23", "TIME_AVERAGE", "Stochastic Reynolds stress yz-component"); + } } } @@ -4189,41 +4191,43 @@ void CFlowOutput::LoadTimeAveragedData(unsigned long iPoint, const CVariable *No SetVolumeOutputValue("VWPRIME", iPoint, -(vmean*wmean - vwmean)); } - const su2double rho = Node_Flow->GetDensity(iPoint); - const su2double nu_t = Node_Flow->GetEddyViscosity(iPoint) / rho; - const auto vel_grad = Node_Flow->GetVelocityGradient(iPoint); - const su2double vel_div = vel_grad(0,0) + vel_grad(1,1) + (nDim ==3 ? vel_grad(2,2) : 0.0); - const su2double tau_xx = nu_t * (2*vel_grad(0,0) - (2.0/3.0)*vel_div); - const su2double tau_yy = nu_t * (2*vel_grad(1,1) - (2.0/3.0)*vel_div); - const su2double tau_xy = nu_t * (vel_grad(0,1) + vel_grad(1,0)); - SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_11", iPoint, -tau_xx); - SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_22", iPoint, -tau_yy); - SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_12", iPoint, -tau_xy); - if (nDim == 3){ - const su2double tau_zz = nu_t * (2*vel_grad(2,2) - (2.0/3.0)*vel_div); - const su2double tau_xz = nu_t * (vel_grad(0,2) + vel_grad(2,0)); - const su2double tau_yz = nu_t * (vel_grad(1,2) + vel_grad(2,1)); - SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_33", iPoint, -tau_zz); - SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_13", iPoint, -tau_xz); - SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_23", iPoint, -tau_yz); - } + if (config->GetKind_Turb_Model() != TURB_MODEL::NONE) { + const su2double rho = Node_Flow->GetDensity(iPoint); + const su2double nu_t = Node_Flow->GetEddyViscosity(iPoint) / rho; + const auto vel_grad = Node_Flow->GetVelocityGradient(iPoint); + const su2double vel_div = vel_grad(0,0) + vel_grad(1,1) + (nDim ==3 ? vel_grad(2,2) : 0.0); + const su2double tau_xx = nu_t * (2*vel_grad(0,0) - (2.0/3.0)*vel_div); + const su2double tau_yy = nu_t * (2*vel_grad(1,1) - (2.0/3.0)*vel_div); + const su2double tau_xy = nu_t * (vel_grad(0,1) + vel_grad(1,0)); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_11", iPoint, -tau_xx); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_22", iPoint, -tau_yy); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_12", iPoint, -tau_xy); + if (nDim == 3){ + const su2double tau_zz = nu_t * (2*vel_grad(2,2) - (2.0/3.0)*vel_div); + const su2double tau_xz = nu_t * (vel_grad(0,2) + vel_grad(2,0)); + const su2double tau_yz = nu_t * (vel_grad(1,2) + vel_grad(2,1)); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_33", iPoint, -tau_zz); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_13", iPoint, -tau_xz); + SetAvgVolumeOutputValue("MODELED_REYNOLDS_STRESS_23", iPoint, -tau_yz); + } - if (config->GetSBSParam().StochasticBackscatter) { - const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1e-10); - const su2double lesSensor = Node_Flow->GetLES_Mode(iPoint); - const su2double mag = config->GetSBSParam().SBS_Cmag; - const su2double threshold = config->GetSBSParam().stochFdThreshold; - su2double tke_estim = 0.0; - if (lesSensor > threshold) tke_estim = pow(nu_t/DES_lengthscale, 2); - const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); - const su2double csi_y = Node_Turb->GetSolution(iPoint, 2); - const su2double csi_z = Node_Turb->GetSolution(iPoint, 3); - const su2double R_xy = - mag * tke_estim * csi_z; - const su2double R_xz = + mag * tke_estim * csi_y; - const su2double R_yz = - mag * tke_estim * csi_x; - SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_12", iPoint, -R_xy); - SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_13", iPoint, -R_xz); - SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_23", iPoint, -R_yz); + if (config->GetSBSParam().StochasticBackscatter) { + const su2double DES_lengthscale = max(Node_Flow->GetDES_LengthScale(iPoint), 1e-10); + const su2double lesSensor = Node_Flow->GetLES_Mode(iPoint); + const su2double mag = config->GetSBSParam().SBS_Cmag; + const su2double threshold = config->GetSBSParam().stochFdThreshold; + su2double tke_estim = 0.0; + if (lesSensor > threshold) tke_estim = pow(nu_t/DES_lengthscale, 2); + const su2double csi_x = Node_Turb->GetSolution(iPoint, 1); + const su2double csi_y = Node_Turb->GetSolution(iPoint, 2); + const su2double csi_z = Node_Turb->GetSolution(iPoint, 3); + const su2double R_xy = - mag * tke_estim * csi_z; + const su2double R_xz = + mag * tke_estim * csi_y; + const su2double R_yz = - mag * tke_estim * csi_x; + SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_12", iPoint, -R_xy); + SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_13", iPoint, -R_xz); + SetAvgVolumeOutputValue("STOCHASTIC_REYNOLDS_STRESS_23", iPoint, -R_yz); + } } } diff --git a/SU2_CFD/src/output/CNEMOCompOutput.cpp b/SU2_CFD/src/output/CNEMOCompOutput.cpp index 7ed4cfe0a97..3f1de662c1c 100644 --- a/SU2_CFD/src/output/CNEMOCompOutput.cpp +++ b/SU2_CFD/src/output/CNEMOCompOutput.cpp @@ -306,7 +306,8 @@ void CNEMOCompOutput::SetVolumeOutputFields(CConfig *config){ void CNEMOCompOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolver **solver, unsigned long iPoint){ const auto* Node_Flow = solver[FLOW_SOL]->GetNodes(); - const auto* Node_Turb = solver[TURB_SOL]->GetNodes(); + const CVariable* Node_Turb = nullptr; + if (config->GetKind_Turb_Model() != TURB_MODEL::NONE) Node_Turb = solver[TURB_SOL]->GetNodes(); auto* Node_Geo = geometry->nodes; const auto nSpecies = config->GetnSpecies(); From 254115114e90447286db8c8680846c1b6f165c0e Mon Sep 17 00:00:00 2001 From: paan882 Date: Fri, 10 Apr 2026 15:46:16 +0200 Subject: [PATCH 68/70] Restore nPrimVarGrad in InitiatePeriodicComms --- SU2_CFD/src/solvers/CSolver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SU2_CFD/src/solvers/CSolver.cpp b/SU2_CFD/src/solvers/CSolver.cpp index 0565f58b0b2..40f316113d8 100644 --- a/SU2_CFD/src/solvers/CSolver.cpp +++ b/SU2_CFD/src/solvers/CSolver.cpp @@ -363,8 +363,8 @@ void CSolver::InitiatePeriodicComms(CGeometry *geometry, auto *Diff = new su2double[nVar]; auto *Und_Lapl = new su2double[nVar]; - auto *Sol_Min = new su2double[nVar]; - auto *Sol_Max = new su2double[nVar]; + auto *Sol_Min = new su2double[nPrimVarGrad]; + auto *Sol_Max = new su2double[nPrimVarGrad]; auto *rotPrim_i = new su2double[nPrimVar]; auto *rotPrim_j = new su2double[nPrimVar]; From 9c4b84aae6c4d3208e803a059a3d25606ecf8a4c Mon Sep 17 00:00:00 2001 From: paan882 Date: Fri, 10 Apr 2026 16:52:55 +0200 Subject: [PATCH 69/70] Restore DDES test case (committed by mistake) --- TestCases/ddes/flatplate/ddes_flatplate.cfg | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/TestCases/ddes/flatplate/ddes_flatplate.cfg b/TestCases/ddes/flatplate/ddes_flatplate.cfg index 723c11fcb57..b851ea55052 100644 --- a/TestCases/ddes/flatplate/ddes_flatplate.cfg +++ b/TestCases/ddes/flatplate/ddes_flatplate.cfg @@ -13,11 +13,9 @@ % SOLVER= RANS KIND_TURB_MODEL= SA -HYBRID_RANSLES= SA_DES -STOCHASTIC_BACKSCATTER= YES +HYBRID_RANSLES= SA_EDDES MATH_PROBLEM= DIRECT RESTART_SOL= NO -RESTART_ITER= 100 % ----------- COMPRESSIBLE AND INCOMPRESSIBLE FREE-STREAM DEFINITION ----------% % @@ -43,7 +41,7 @@ TIME_MARCHING= DUAL_TIME_STEPPING-2ND_ORDER % % U_inf = 69.4448 - dt*=0.02 - dt=0.000288 TIME_STEP= 0.000288 -MAX_TIME= 5 +MAX_TIME= 10 UNST_CFL_NUMBER= 0.0 INNER_ITER= 20 @@ -105,5 +103,5 @@ VOLUME_ADJ_FILENAME= adjoint GRAD_OBJFUNC_FILENAME= of_grad SURFACE_FILENAME= surface_flow SURFACE_ADJ_FILENAME= surface_adjoint -OUTPUT_WRT_FREQ= 1000000 +OUTPUT_WRT_FREQ= 1000 SCREEN_OUTPUT= (TIME_ITER, INNER_ITER, RMS_DENSITY, RMS_NU_TILDE, LIFT, DRAG, TOTAL_HEATFLUX) From 8b7841077049f95ab86c12d2b5f9d669b4fb7d09 Mon Sep 17 00:00:00 2001 From: paan882 Date: Sat, 11 Apr 2026 19:01:09 +0200 Subject: [PATCH 70/70] Simplify backscatter test --- TestCases/backscatter/backward_step/backwardStep.cfg | 2 +- TestCases/parallel_regression.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/TestCases/backscatter/backward_step/backwardStep.cfg b/TestCases/backscatter/backward_step/backwardStep.cfg index f823996a5ec..72a4304a467 100644 --- a/TestCases/backscatter/backward_step/backwardStep.cfg +++ b/TestCases/backscatter/backward_step/backwardStep.cfg @@ -32,7 +32,7 @@ SBS_INTENSITY_COEFF= 1.0 SBS_FD_LOWER_THRESHOLD= 0.9 SBS_RELAXATION_FACTOR= 0.0 SBS_SOURCE_NU_EQUATION= YES -SBS_SOURCE_DIAGNOSTICS= YES +SBS_SOURCE_DIAGNOSTICS= NO SBS_IN_BOX= YES SBS_BOX_BOUNDS= ( -0.001, 0.025, -5000.0, 5000.0, -5000.0, 0.0375 ) diff --git a/TestCases/parallel_regression.py b/TestCases/parallel_regression.py index 65a725c288c..464fa5f752b 100755 --- a/TestCases/parallel_regression.py +++ b/TestCases/parallel_regression.py @@ -1063,8 +1063,8 @@ def main(): sbs_backward_step = TestCase('sbs_backward_step') sbs_backward_step.cfg_dir = "backscatter/backward_step" sbs_backward_step.cfg_file = "backwardStep.cfg" - sbs_backward_step.test_iter = 10 - sbs_backward_step.test_vals = [-6.656162, -4.527123, -5.971187, -5.333804, -9.765638, -8.499022, -8.462351, -8.482077] + sbs_backward_step.test_iter = 3 + sbs_backward_step.test_vals = [-6.419128, -4.371595, -5.836729, -5.281628, -10.570440, -8.842410, -8.871305, -8.916457] sbs_backward_step.unsteady = True sbs_backward_step.decompress = True sbs_backward_step.grid_file = "backward_step.su2"