-
Notifications
You must be signed in to change notification settings - Fork 974
Improved combustion solver robustness for coarse grids #2733
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 19 commits
11a88fb
6ba1ffb
5dca658
2df59a8
3af0712
b575044
e361ca7
0de7e0d
08573ce
ffe779b
ff6faea
5a9d2a0
d9e5b59
dde7b7b
6963939
e8b31f9
5dee848
1010429
92eec69
98de6ac
4ff73c6
746a543
7cdd149
7015adc
671c8c3
566618e
8f1f2a1
d6ddccb
a27d833
e9d88dc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1069,6 +1069,8 @@ void CFlowOutput::AddHistoryOutputFields_ScalarRMS_RES(const CConfig* config) { | |
| const auto& CV_name = flamelet_config_options.controlling_variable_names[iCV]; | ||
| AddHistoryOutput("RMS_"+CV_name, "rms["+CV_name+"]",ScreenOutputFormat::FIXED, "RMS_RES", "Root-mean squared residual of " + CV_name + " controlling variable equation.", HistoryFieldType::RESIDUAL); | ||
| } | ||
| if (flamelet_config_options.thickenedflame_correction) | ||
| AddHistoryOutput("THICKNESS","flamethickness",ScreenOutputFormat::FIXED, "RMS_RES", "Flame thickness used for thickened flame correction model.", HistoryFieldType::RESIDUAL); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not a residual
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have placed the flame thickness under its own category as a user-defined coefficient. |
||
|
|
||
| /*--- auxiliary species transport ---*/ | ||
| for (auto i_scalar = 0u; i_scalar < flamelet_config_options.n_user_scalars; i_scalar++){ | ||
|
|
@@ -1304,6 +1306,9 @@ void CFlowOutput::LoadHistoryDataScalar(const CConfig* config, const CSolver* co | |
| } | ||
| } | ||
|
|
||
| if (flamelet_config_options.thickenedflame_correction) | ||
| SetHistoryOutputValue("THICKNESS", solver[SPECIES_SOL]->GetFlameThickness()); | ||
|
|
||
| SetHistoryOutputValue("LINSOL_ITER_FLAMELET", solver[SPECIES_SOL]->GetIterLinSolver()); | ||
| SetHistoryOutputValue("LINSOL_RESIDUAL_FLAMELET", log10(solver[SPECIES_SOL]->GetResLinSolver())); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,6 +39,8 @@ | |
|
|
||
| /*--- Retrieve options from config. ---*/ | ||
| flamelet_config_options = config->GetFlameletParsedOptions(); | ||
| global_flame_thickness = default_flame_thickness; | ||
| calc_flame_thickness = flamelet_config_options.thickenedflame_correction; | ||
|
|
||
| /*--- Dimension of the problem. ---*/ | ||
| nVar = flamelet_config_options.n_scalars; | ||
|
|
@@ -65,45 +67,79 @@ | |
|
|
||
| /*--- Add the solver name. ---*/ | ||
| SolverName = "FLAMELET"; | ||
|
|
||
| if (calc_flame_thickness && rank==MASTER_NODE) { | ||
| cout << "Applying thickened flame source and diffusion correction." << endl; | ||
| } | ||
| } | ||
|
|
||
| void CSpeciesFlameletSolver::Preprocessing(CGeometry* geometry, CSolver** solver_container, CConfig* config, | ||
| unsigned short iMesh, unsigned short iRKStep, | ||
| unsigned short RunTime_EqSystem, bool Output) { | ||
| unsigned long n_not_in_domain_local = 0, n_not_in_domain_global = 0; | ||
| vector<su2double> scalars_vector(nVar); | ||
|
|
||
| unsigned long spark_iter_start, spark_duration; | ||
| bool ignition = false; | ||
| auto* flowNodes = su2staticcast_p<CFlowVariable*>(solver_container[FLOW_SOL]->GetNodes()); | ||
|
|
||
| /*--- Retrieve spark ignition parameters for spark-type ignition. ---*/ | ||
| unsigned long iter; | ||
| if (config->GetMultizone_Problem()) { | ||
| iter = config->GetOuterIter(); | ||
| } else if (config->GetTime_Domain()) { | ||
| iter = config->GetTimeIter(); | ||
| } else { | ||
| iter = config->GetInnerIter(); | ||
| } | ||
| if ((flamelet_config_options.ignition_method == FLAMELET_INIT_TYPE::SPARK)) { | ||
| auto spark_init = flamelet_config_options.spark_init; | ||
| spark_iter_start = ceil(spark_init[4]); | ||
| spark_duration = ceil(spark_init[5]); | ||
| unsigned long iter = config->GetMultizone_Problem() ? config->GetOuterIter() : config->GetInnerIter(); | ||
|
|
||
| ignition = ((iter >= spark_iter_start) && (iter <= (spark_iter_start + spark_duration))); | ||
| } | ||
|
|
||
| SU2_OMP_SAFE_GLOBAL_ACCESS(config->SetGlobalParam(config->GetKind_Solver(), RunTime_EqSystem);) | ||
|
|
||
| /* Update global flame thickness value. */ | ||
| if (calc_flame_thickness) { | ||
| su2double test_thickness = GetOverallFlameThickness(geometry, solver_container); | ||
| if (test_thickness < global_flame_thickness) { | ||
| global_flame_thickness = test_thickness; | ||
| } else { | ||
| global_flame_thickness = 0.95*global_flame_thickness + 0.05*test_thickness; | ||
| } | ||
| } | ||
|
|
||
| /* Flame thickness correction factors */ | ||
| su2double F{1.0}, F_source{1.0}; | ||
|
|
||
| SU2_OMP_FOR_STAT(omp_chunk_size) | ||
| for (auto i_point = 0u; i_point < nPoint; i_point++) { | ||
| CFluidModel* fluid_model_local = solver_container[FLOW_SOL]->GetFluidModel(); | ||
| su2double* scalars = nodes->GetSolution(i_point); | ||
|
|
||
| /*--- Calculate correction factor for flame propagation on coarse grids. ---*/ | ||
| if (calc_flame_thickness) { | ||
| F = ThickenedFlameCorrection(geometry, i_point); | ||
| F_source = 1.0 / F; | ||
| } | ||
|
|
||
| for (auto iVar = 0u; iVar < nVar; iVar++) scalars_vector[iVar] = scalars[iVar]; | ||
|
|
||
| /*--- Compute total source terms from the production and consumption. ---*/ | ||
| unsigned long misses = SetScalarSources(config, fluid_model_local, i_point, scalars_vector); | ||
| /*--- Only apply thickened flame correction factor to sources for steady problems. ---*/ | ||
| unsigned long misses = SetScalarSources(config, fluid_model_local, i_point, scalars_vector, F_source); | ||
|
|
||
| if (ignition) { | ||
| /*--- Apply source terms within spark radius. ---*/ | ||
| su2double dist_from_center = 0, | ||
| spark_radius = flamelet_config_options.spark_init[3]; | ||
| dist_from_center = GeometryToolbox::SquaredDistance(nDim, geometry->nodes->GetCoord(i_point), flamelet_config_options.spark_init.data()); | ||
| if (dist_from_center < pow(spark_radius,2)) { | ||
| for (auto iVar = 0u; iVar < nVar; iVar++) | ||
| nodes->SetScalarSource(i_point, iVar, nodes->GetScalarSources(i_point)[iVar] + flamelet_config_options.spark_reaction_rates[iVar]); | ||
| for (auto iVar = 0u; iVar < nVar; iVar++) { | ||
| su2double source_total = nodes->GetScalarSources(i_point)[iVar] + F_source * flamelet_config_options.spark_reaction_rates[iVar]; | ||
| nodes->SetScalarSource(i_point, iVar, source_total); | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -115,9 +151,9 @@ | |
| /*--- Set mass diffusivity based on thermodynamic state. ---*/ | ||
| auto T = flowNodes->GetTemperature(i_point); | ||
| fluid_model_local->SetTDState_T(T, scalars); | ||
| /*--- set the diffusivity in the fluid model to the diffusivity obtained from the lookup table ---*/ | ||
| /*--- set the diffusivity in the fluid model to the diffusivity obtained from the lookup table, multiplied by flame thickness correction factor ---*/ | ||
| for (auto i_scalar = 0u; i_scalar < nVar; ++i_scalar) { | ||
| nodes->SetDiffusivity(i_point, fluid_model_local->GetMassDiffusivity(i_scalar), i_scalar); | ||
| nodes->SetDiffusivity(i_point, F * (fluid_model_local->GetMassDiffusivity(i_scalar)), i_scalar); | ||
| } | ||
|
|
||
| /*--- Obtain preferential diffusion scalar values. ---*/ | ||
|
|
@@ -213,8 +249,6 @@ | |
|
|
||
| for (unsigned long i_mesh = 0; i_mesh <= config->GetnMGLevels(); i_mesh++) { | ||
| fluid_model_local = solver_container[i_mesh][FLOW_SOL]->GetFluidModel(); | ||
| if (flame_front_ignition) prog_burnt = GetBurntProgressVariable(fluid_model_local, scalar_init); | ||
|
|
||
| for (auto iVar = 0u; iVar < nVar; iVar++) scalar_init[iVar] = config->GetSpecies_Init()[iVar]; | ||
|
|
||
| /*--- Set enthalpy based on initial temperature and scalars. ---*/ | ||
|
|
@@ -228,6 +262,7 @@ | |
|
|
||
| if (flame_front_ignition) { | ||
|
|
||
| prog_burnt = GetBurntProgressVariable(fluid_model_local, scalar_init); | ||
| /*--- Determine if point is above or below the plane, assuming the normal | ||
| is pointing towards the burned region. ---*/ | ||
| point_loc = 0.0; | ||
|
|
@@ -383,7 +418,7 @@ | |
|
|
||
| void CSpeciesFlameletSolver::Source_Residual(CGeometry* geometry, CSolver** solver_container, | ||
| CNumerics** numerics_container, CConfig* config, unsigned short iMesh) { | ||
|
|
||
|
EvertBunschoten marked this conversation as resolved.
Outdated
|
||
| SU2_OMP_FOR_STAT(omp_chunk_size) | ||
| for (auto i_point = 0u; i_point < nPointDomain; i_point++) { | ||
| /*--- Add source terms from the lookup table directly to the residual. ---*/ | ||
|
|
@@ -516,7 +551,7 @@ | |
| } | ||
|
|
||
| unsigned long CSpeciesFlameletSolver::SetScalarSources(const CConfig* config, CFluidModel* fluid_model_local, | ||
| unsigned long iPoint, const vector<su2double>& scalars) { | ||
| unsigned long iPoint, const vector<su2double>& scalars, const su2double F) { | ||
| /*--- Compute total source terms from the production and consumption. ---*/ | ||
|
|
||
| vector<su2double> table_sources(flamelet_config_options.n_control_vars + 2 * flamelet_config_options.n_user_scalars); | ||
|
|
@@ -538,8 +573,9 @@ | |
| su2double source_cons = table_sources[flamelet_config_options.n_control_vars + 2 * i_aux + 1]; | ||
| source_scalar[flamelet_config_options.n_control_vars + i_aux] = source_prod + source_cons * y_aux; | ||
| } | ||
| /*--- Source term is divided by flame thickness correction factor to improve stability on coarse grids. ---*/ | ||
| for (auto i_scalar = 0u; i_scalar < nVar; i_scalar++) | ||
| nodes->SetScalarSource(iPoint, i_scalar, source_scalar[i_scalar]); | ||
| nodes->SetScalarSource(iPoint, i_scalar, F*source_scalar[i_scalar]); | ||
| return misses; | ||
| } | ||
|
|
||
|
|
@@ -804,3 +840,61 @@ | |
| su2double pv_burnt = scalars[I_PROGVAR] - delta; | ||
| return pv_burnt; | ||
| } | ||
|
|
||
|
|
||
| su2double CSpeciesFlameletSolver::ThickenedFlameCorrection(CGeometry const * geometry, const unsigned long iPoint) const { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You need to open PRs more often so you don't forge what style we follow in the code 😉
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. More PRs coming in! You refer to the const and pointer placement? |
||
| su2double F{1.0}; | ||
| if (global_flame_thickness != default_flame_thickness) { | ||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| su2double max_flame_vol = pow(global_flame_thickness, nDim); | ||
| F = max(1.0, geometry->nodes->GetVolume(iPoint) / max_flame_vol); | ||
| } | ||
| return F; | ||
| } | ||
|
|
||
| su2double CSpeciesFlameletSolver::GetOverallFlameThickness(CGeometry * geometry, CSolver **solver_container) const { | ||
| CFlowVariable const * flowNodes = su2staticcast_p<CFlowVariable*>(solver_container[FLOW_SOL]->GetNodes()); | ||
|
EvertBunschoten marked this conversation as resolved.
Outdated
|
||
| su2double pvmax_local{-1e3}, pvmin_local{1e3}, pvmax_global{0.0},pvmin_global{0.0}, gradpv_local{0.0}, gradpv_global{0.0}, Tmax_local{-1e6},Tmax_global{0.0}; | ||
|
|
||
| SU2_OMP_FOR_STAT(omp_chunk_size) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does not work with OpenMP because the local variables are also thread-local, you can take a look at how we compute time steps for the pattern you need to use. |
||
| for (auto iPoint = 0u; iPoint < nPoint; iPoint++) { | ||
|
EvertBunschoten marked this conversation as resolved.
Outdated
|
||
| su2double pv_local = nodes->GetSolution(iPoint, I_PROGVAR); | ||
| su2double T_local = solver_container[FLOW_SOL]->GetNodes()->GetTemperature(iPoint); | ||
|
|
||
| /* Parallel projection of progress variable gradient against velocity */ | ||
| su2double proj_grad_pv_u[MAXNDIM]; | ||
| for (auto iDim=0u; iDim < nDim; iDim++) { | ||
| su2double gradpv = nodes->GetGradient(iPoint, I_PROGVAR, iDim); | ||
| su2double val_u = flowNodes->GetVelocity(iPoint, iDim); | ||
| proj_grad_pv_u[iDim] = gradpv * val_u * val_u / (flowNodes->GetVelocity2(iPoint) + 1e-5); | ||
| } | ||
|
|
||
| /* Parallel projection of temperature gradient against projected progress variable gradient */ | ||
| su2double proj_grad_T_u = 0, gradT2{0}, mag_gradT{0}; | ||
| for (auto iDim=0u; iDim < nDim; iDim++) { | ||
| su2double gradT = flowNodes->GetGradient_Primitive(iPoint, prim_idx.Temperature(), iDim); | ||
| proj_grad_T_u += gradT * proj_grad_pv_u[iDim]; | ||
| gradT2 += gradT*gradT; | ||
| } | ||
|
EvertBunschoten marked this conversation as resolved.
Outdated
|
||
| mag_gradT = sqrt(gradT2); | ||
| proj_grad_T_u /= (gradT2 + 1e-5); | ||
| proj_grad_T_u *= mag_gradT; | ||
|
|
||
| /* Update minimum and maximum values. */ | ||
| gradpv_local = max(gradpv_local, proj_grad_T_u); | ||
| pvmax_local = max(pvmax_local, pv_local); | ||
| pvmin_local = min(pvmin_local, pv_local); | ||
| Tmax_local = max(Tmax_local, T_local); | ||
| } | ||
| END_SU2_OMP_FOR | ||
| SU2_MPI::Barrier(SU2_MPI::GetComm()); | ||
|
EvertBunschoten marked this conversation as resolved.
Outdated
|
||
| SU2_MPI::Allreduce(&gradpv_local, &gradpv_global, 1, MPI_DOUBLE, MPI_MAX, SU2_MPI::GetComm()); | ||
| SU2_MPI::Allreduce(&pvmin_local, &pvmin_global, 1, MPI_DOUBLE, MPI_MIN, SU2_MPI::GetComm()); | ||
| SU2_MPI::Allreduce(&pvmax_local, &pvmax_global, 1, MPI_DOUBLE, MPI_MAX, SU2_MPI::GetComm()); | ||
| SU2_MPI::Allreduce(&Tmax_local, &Tmax_global, 1, MPI_DOUBLE, MPI_MAX, SU2_MPI::GetComm()); | ||
|
EvertBunschoten marked this conversation as resolved.
Outdated
|
||
|
|
||
| /* Update flame thickness value. */ | ||
| su2double flame_thickness{default_flame_thickness}; | ||
| if (Tmax_global > 800.0) flame_thickness = (pvmax_global - pvmin_global) / (gradpv_global+1e-5); | ||
|
EvertBunschoten marked this conversation as resolved.
Outdated
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this temperature a tunable parameter?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now it is |
||
|
|
||
| return flame_thickness; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.