Skip to content

Commit d355978

Browse files
committed
add convergence check and early exit for pre,post and correction smoothing
1 parent c38a633 commit d355978

File tree

9 files changed

+186
-39
lines changed

9 files changed

+186
-39
lines changed

Common/include/CConfig.hpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,10 @@ class CConfig {
496496
unsigned short *MG_PreSmooth, /*!< \brief Multigrid Pre smoothing. */
497497
*MG_PostSmooth, /*!< \brief Multigrid Post smoothing. */
498498
*MG_CorrecSmooth; /*!< \brief Multigrid Jacobi implicit smoothing of the correction. */
499+
bool MG_Smooth_EarlyExit; /*!< \brief Enable early exit for MG smoothing. */
500+
su2double MG_Smooth_Res_Threshold; /*!< \brief Residual reduction threshold for early exit. */
501+
bool MG_Smooth_Output; /*!< \brief Output per-iteration multigrid smoothing info. */
502+
su2double MG_Smooth_Coeff; /*!< \brief Smoothing coefficient for multigrid correction smoothing. */
499503
su2double *LocationStations; /*!< \brief Airfoil sections in wing slicing subroutine. */
500504

501505
ENUM_MULTIZONE Kind_MZSolver; /*!< \brief Kind of multizone solver. */
@@ -3837,6 +3841,30 @@ class CConfig {
38373841
return MG_CorrecSmooth[val_mesh];
38383842
}
38393843

3844+
/*!
3845+
* \brief Get whether early exit is enabled for MG smoothing.
3846+
* \return True if early exit is enabled.
3847+
*/
3848+
bool GetMG_Smooth_EarlyExit() const { return MG_Smooth_EarlyExit; }
3849+
3850+
/*!
3851+
* \brief Get the residual threshold for early exit in MG smoothing.
3852+
* \return Residual threshold.
3853+
*/
3854+
su2double GetMG_Smooth_Res_Threshold() const { return MG_Smooth_Res_Threshold; }
3855+
3856+
/*!
3857+
* \brief Get whether per-iteration output is enabled for MG smoothing.
3858+
* \return True if output is enabled.
3859+
*/
3860+
bool GetMG_Smooth_Output() const { return MG_Smooth_Output; }
3861+
3862+
/*!
3863+
* \brief Get the smoothing coefficient for MG correction smoothing.
3864+
* \return Smoothing coefficient.
3865+
*/
3866+
su2double GetMG_Smooth_Coeff() const { return MG_Smooth_Coeff; }
3867+
38403868
/*!
38413869
* \brief plane of the FFD (I axis) that should be fixed.
38423870
* \param[in] val_index - Index of the arrray with all the planes in the I direction that should be fixed.

Common/src/CConfig.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,6 +1955,17 @@ void CConfig::SetConfig_Options() {
19551955
/*!\brief MG_DAMP_PROLONGATION\n DESCRIPTION: Damping factor for the correction prolongation. DEFAULT 0.75 \ingroup Config*/
19561956
addDoubleOption("MG_DAMP_PROLONGATION", Damp_Correc_Prolong, 0.75);
19571957

1958+
/*!\brief MG_SMOOTH_EARLY_EXIT\n DESCRIPTION: Enable early exit for MG smoothing iterations based on RMS residual. DEFAULT: NO \ingroup Config*/
1959+
addBoolOption("MG_SMOOTH_EARLY_EXIT", MG_Smooth_EarlyExit, false);
1960+
/*!\brief MG_SMOOTH_RES_THRESHOLD\n DESCRIPTION: RMS residual threshold for early exit in MG smoothing. DEFAULT: 1e-2 \ingroup Config*/
1961+
addDoubleOption("MG_SMOOTH_RES_THRESHOLD", MG_Smooth_Res_Threshold, 1e-2);
1962+
1963+
/*!\brief MG_SMOOTH_OUTPUT\n DESCRIPTION: Output per-iteration RMS for MG smoothing. DEFAULT: NO \ingroup Config*/
1964+
addBoolOption("MG_SMOOTH_OUTPUT", MG_Smooth_Output, false);
1965+
1966+
/*!\brief MG_SMOOTH_COEFF\n DESCRIPTION: Smoothing coefficient for MG correction smoothing. DEFAULT: 1.25 \ingroup Config*/
1967+
addDoubleOption("MG_SMOOTH_COEFF", MG_Smooth_Coeff, 1.25);
1968+
19581969
/*!\par CONFIG_CATEGORY: Spatial Discretization \ingroup Config*/
19591970
/*--- Options related to the spatial discretization ---*/
19601971

Common/src/geometry/CMultiGridGeometry.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -610,9 +610,9 @@ CMultiGridGeometry::CMultiGridGeometry(CGeometry* fine_grid, CConfig* config, un
610610

611611
if (iMesh != MESH_0) {
612612
//const su2double factor = 1.5; //nijso: too high
613-
const su2double factor = 2.0;
613+
const su2double factor = 1.1;
614614
const su2double Coeff = pow(su2double(Global_nPointFine) / Global_nPointCoarse, 1.0 / nDim);
615-
const su2double CFL = factor * config->GetCFL(iMesh - 1) / Coeff;
615+
const su2double CFL = factor * config->GetCFL(iMesh - 1);// / Coeff;
616616
config->SetCFL(iMesh, CFL);
617617
}
618618

QuickStart/inv_NACA0012.cfg

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ CFL_ADAPT= NO
105105
CFL_ADAPT_PARAM= ( 0.1, 2.0, 10.0, 1e10 )
106106
%
107107
% Number of total iterations
108-
ITER= 250
108+
ITER= 5
109109

110110
% ------------------------ LINEAR SOLVER DEFINITION ---------------------------%
111111
%
@@ -136,13 +136,22 @@ MG_PRE_SMOOTH= ( 1, 2, 3, 3 )
136136
MG_POST_SMOOTH= ( 0, 0, 0, 0 )
137137
%
138138
% Jacobi implicit smoothing of the correction
139-
MG_CORRECTION_SMOOTH= ( 0, 0, 0, 0 )
139+
MG_CORRECTION_SMOOTH= ( 0, 3, 3, 3 )
140140
%
141141
% Damping factor for the residual restriction
142142
MG_DAMP_RESTRICTION= 1.0
143143
%
144144
% Damping factor for the correction prolongation
145145
MG_DAMP_PROLONGATION= 1.0
146+
%
147+
% Enable early exit for multigrid smoothing iterations
148+
MG_SMOOTH_EARLY_EXIT= YES
149+
%
150+
% RMS residual threshold for early exit (fraction of initial RMS)
151+
MG_SMOOTH_RES_THRESHOLD= 0.99
152+
%
153+
% Enable output of RMS residual during smoothing iterations
154+
MG_SMOOTH_OUTPUT= YES
146155

147156
% -------------------- FLOW NUMERICAL METHOD DEFINITION -----------------------%
148157
%

SU2_CFD/include/integration/CMultiGridIntegration.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ class CMultiGridIntegration final : public CIntegration {
177177
* \param[in] config - Definition of the particular problem.
178178
*/
179179
void SmoothProlongated_Correction(unsigned short RunTime_EqSystem, CSolver *solver, CGeometry *geometry,
180-
unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config);
180+
unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config, unsigned short iMesh);
181181

182182
/*!
183183
* \brief Restrict solution from fine grid to a coarse grid.

SU2_CFD/src/integration/CMultiGridIntegration.cpp

Lines changed: 99 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include "../../include/integration/CMultiGridIntegration.hpp"
2929
#include "../../../Common/include/parallelization/omp_structure.hpp"
3030

31+
#include "ComputeLinSysResRMS.hpp"
32+
3133

3234
CMultiGridIntegration::CMultiGridIntegration() : CIntegration() { }
3335

@@ -217,7 +219,7 @@ void CMultiGridIntegration::MultiGrid_Cycle(CGeometry ****geometry,
217219
/*--- Compute prolongated solution, and smooth the correction $u^(new)_k = u_k + Smooth(I^k_(k+1)(u_(k+1)-I^(k+1)_k u_k))$ ---*/
218220

219221
GetProlongated_Correction(RunTime_EqSystem, solver_fine, solver_coarse, geometry_fine, geometry_coarse, config);
220-
SmoothProlongated_Correction(RunTime_EqSystem, solver_fine, geometry_fine, config->GetMG_CorrecSmooth(iMesh), 1.25, config);
222+
SmoothProlongated_Correction(RunTime_EqSystem, solver_fine, geometry_fine, config->GetMG_CorrecSmooth(iMesh), config->GetMG_Smooth_Coeff(), config, iMesh);
221223
SetProlongated_Correction(solver_fine, geometry_fine, config, iMesh);
222224

223225

@@ -245,43 +247,52 @@ unsigned short iRKLimit) {
245247
const unsigned short nPreSmooth = config->GetMG_PreSmooth(iMesh);
246248
const unsigned long timeIter = config->GetTimeIter();
247249

250+
// Early exit settings from config
251+
const bool early_exit_enabled = config->GetMG_Smooth_EarlyExit();
252+
const su2double early_exit_threshold = config->GetMG_Smooth_Res_Threshold();
253+
const bool output_enabled = config->GetMG_Smooth_Output();
254+
255+
su2double initial_rms = 0.0;
256+
if (early_exit_enabled || output_enabled) {
257+
initial_rms = ComputeLinSysResRMS(solver_fine, geometry_fine);
258+
if (output_enabled) {
259+
cout << "MG Pre-Smoothing Level " << iMesh << " Initial RMS: " << initial_rms << endl;
260+
}
261+
}
262+
248263
/*--- Do a presmoothing on the grid iMesh to be restricted to the grid iMesh+1 ---*/
249264
for (unsigned short iPreSmooth = 0; iPreSmooth < nPreSmooth; iPreSmooth++) {
250-
251265
/*--- Time and space integration ---*/
252266
for (unsigned short iRKStep = 0; iRKStep < iRKLimit; iRKStep++) {
253-
254267
/*--- Send-Receive boundary conditions, and preprocessing ---*/
255268
solver_fine->Preprocessing(geometry_fine, solver_container_fine, config, iMesh, iRKStep, RunTime_EqSystem, false);
256-
257269
if (iRKStep == 0) {
258-
259270
/*--- Set the old solution ---*/
260271
solver_fine->Set_OldSolution();
261-
262272
if (classical_rk4) solver_fine->Set_NewSolution();
263-
// nijso asks: only call when classical_rk4?
264-
// this copies solution to old solution, which we already did above.
265-
//solver_fine->Set_OldSolution();
266-
267-
/*--- Compute time step, max eigenvalue, and integration scheme (steady and unsteady problems) ---*/
268273
solver_fine->SetTime_Step(geometry_fine, solver_container_fine, config, iMesh, timeIter);
269-
270-
/*--- Restrict the solution and gradient for the adjoint problem ---*/
271-
// nijso asks: why do we call this here but not in the post-smoothing?
272274
Adjoint_Setup(geometry, solver_container, config_container, RunTime_EqSystem, timeIter, iZone);
273-
274275
}
275-
//cout << "pre-smoothing mesh " << iMesh << " rkstep " << iRKStep << endl;
276276
/*--- Space integration ---*/
277277
Space_Integration(geometry_fine, solver_container_fine, numerics_fine, config, iMesh, iRKStep, RunTime_EqSystem);
278-
279278
/*--- Time integration, update solution using the old solution plus the solution increment ---*/
280279
Time_Integration(geometry_fine, solver_container_fine, config, iRKStep, RunTime_EqSystem);
281-
282280
/*--- Send-Receive boundary conditions, and postprocessing ---*/
283281
solver_fine->Postprocessing(geometry_fine, solver_container_fine, config, iMesh);
282+
}
284283

284+
// Early exit check and output
285+
if (early_exit_enabled || output_enabled) {
286+
su2double current_rms = ComputeLinSysResRMS(solver_fine, geometry_fine);
287+
if (output_enabled) {
288+
cout << "MG Pre-Smoothing Level " << iMesh << " Iteration " << iPreSmooth + 1 << "/" << nPreSmooth << " RMS: " << current_rms << endl;
289+
}
290+
if (early_exit_enabled && current_rms < early_exit_threshold * initial_rms) {
291+
if (output_enabled) {
292+
cout << "MG Pre-Smoothing Level " << iMesh << " Early exit at iteration " << iPreSmooth + 1 << endl;
293+
}
294+
break;
295+
}
285296
}
286297
}
287298
}
@@ -293,32 +304,49 @@ void CMultiGridIntegration::PostSmoothing(unsigned short RunTime_EqSystem, CSolv
293304
const unsigned short nPostSmooth = config->GetMG_PostSmooth(iMesh);
294305
const unsigned long timeIter = config->GetTimeIter();
295306

307+
// Early exit settings from config
308+
const bool early_exit_enabled = config->GetMG_Smooth_EarlyExit();
309+
const su2double early_exit_threshold = config->GetMG_Smooth_Res_Threshold();
310+
const bool output_enabled = config->GetMG_Smooth_Output();
311+
312+
su2double initial_rms = 0.0;
313+
if (early_exit_enabled || output_enabled) {
314+
initial_rms = ComputeLinSysResRMS(solver_fine, geometry_fine);
315+
if (output_enabled) {
316+
cout << "MG Post-Smoothing Level " << iMesh << " Initial RMS: " << initial_rms << endl;
317+
}
318+
}
319+
296320
/*--- Do a postsmoothing on the grid iMesh after prolongation from the grid iMesh+1 ---*/
297321
for (unsigned short iPostSmooth = 0; iPostSmooth < nPostSmooth; iPostSmooth++) {
298-
299322
for (unsigned short iRKStep = 0; iRKStep < iRKLimit; iRKStep++) {
300-
301323
solver_fine->Preprocessing(geometry_fine, solver_container_fine, config, iMesh, iRKStep, RunTime_EqSystem, false);
302-
303324
if (iRKStep == 0) {
304-
305325
/*--- Set the old solution ---*/
306326
solver_fine->Set_OldSolution();
307-
308327
if (classical_rk4) solver_fine->Set_NewSolution();
309-
solver_fine->SetTime_Step(geometry_fine, solver_container_fine, config, iMesh, timeIter);
310-
328+
solver_fine->SetTime_Step(geometry_fine, solver_container_fine, config, iMesh, timeIter);
311329
}
312-
313330
/*--- Space integration ---*/
314331
Space_Integration(geometry_fine, solver_container_fine, numerics_fine, config, iMesh, iRKStep, RunTime_EqSystem);
315-
//cout << "post-smoothing mesh " << iMesh << " rkstep " << iRKStep << endl;
316332
/*--- Time integration, update solution using the old solution plus the solution increment ---*/
317333
Time_Integration(geometry_fine, solver_container_fine, config, iRKStep, RunTime_EqSystem);
318-
319334
/*--- Send-Receive boundary conditions, and postprocessing ---*/
320335
solver_fine->Postprocessing(geometry_fine, solver_container_fine, config, iMesh);
336+
}
321337

338+
// Early exit check and output
339+
if (early_exit_enabled || output_enabled) {
340+
su2double current_rms = ComputeLinSysResRMS(solver_fine, geometry_fine);
341+
if (output_enabled) {
342+
cout << "MG Post-Smoothing Level " << iMesh << " Iteration " << iPostSmooth + 1 << "/" << nPostSmooth << " RMS: " << current_rms << endl;
343+
}
344+
if (early_exit_enabled && current_rms < early_exit_threshold * initial_rms) {
345+
if (output_enabled) {
346+
cout << "MG Post-Smoothing Level " << iMesh << " Early exit at iteration " << iPostSmooth + 1 << endl;
347+
}
348+
break;
349+
}
322350
}
323351
}
324352
}
@@ -400,7 +428,7 @@ void CMultiGridIntegration::GetProlongated_Correction(unsigned short RunTime_EqS
400428
}
401429

402430
void CMultiGridIntegration::SmoothProlongated_Correction(unsigned short RunTime_EqSystem, CSolver *solver, CGeometry *geometry,
403-
unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) {
431+
unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config, unsigned short iMesh) {
404432

405433
/*--- Check if there is work to do. ---*/
406434
if (val_nSmooth == 0) return;
@@ -418,7 +446,19 @@ void CMultiGridIntegration::SmoothProlongated_Correction(unsigned short RunTime_
418446
}
419447
END_SU2_OMP_FOR
420448

421-
/*--- Jacobi iterations. ---*/
449+
/*--- Compute initial RMS for adaptive smoothing ---*/
450+
su2double initial_rms = 0.0;
451+
if (config->GetMG_Smooth_EarlyExit()) {
452+
initial_rms = ComputeLinSysResRMS(solver, geometry);
453+
}
454+
455+
/*--- Output initial RMS if enabled ---*/
456+
if (config->GetMG_Smooth_Output()) {
457+
cout << "MG Correction-Smoothing Level " << iMesh << " Initial RMS: " << initial_rms << endl;
458+
}
459+
460+
/*--- Jacobi iterations with adaptive early exit ---*/
461+
unsigned short actual_iterations = val_nSmooth;
422462

423463
for (iSmooth = 0; iSmooth < val_nSmooth; iSmooth++) {
424464

@@ -470,6 +510,35 @@ void CMultiGridIntegration::SmoothProlongated_Correction(unsigned short RunTime_
470510
}
471511
}
472512

513+
/*--- Output RMS residual if enabled ---*/
514+
if (config->GetMG_Smooth_Output()) {
515+
const su2double RMS_Res = ComputeLinSysResRMS(solver, geometry);
516+
cout << "MG Correction-Smoothing Level " << iMesh << " Iteration " << iSmooth+1 << "/" << val_nSmooth << " RMS: " << RMS_Res << endl;
517+
}
518+
519+
/*--- Adaptive early exit check after first iteration ---*/
520+
if (config->GetMG_Smooth_EarlyExit() && iSmooth == 0 && val_nSmooth > 1) {
521+
su2double current_rms = ComputeLinSysResRMS(solver, geometry);
522+
su2double reduction_ratio = current_rms / initial_rms;
523+
524+
// If RMS reduction is sufficient (ratio <= threshold), additional iterations may not be necessary
525+
if (reduction_ratio <= config->GetMG_Smooth_Res_Threshold()) {
526+
if (config->GetMG_Smooth_Output()) {
527+
cout << "MG Correction-Smoothing Level " << iMesh << " Early exit: sufficient RMS reduction ("
528+
<< reduction_ratio << " <= " << config->GetMG_Smooth_Res_Threshold() << ")" << endl;
529+
}
530+
actual_iterations = 1; // Only do this one iteration
531+
break;
532+
}
533+
// If reduction is insufficient (ratio > threshold), continue with remaining iterations
534+
}
535+
536+
}
537+
538+
/*--- Log if iterations were skipped ---*/
539+
if (config->GetMG_Smooth_Output() && actual_iterations < val_nSmooth) {
540+
cout << "MG Correction-Smoothing Level " << iMesh << " completed " << actual_iterations
541+
<< "/" << val_nSmooth << " iterations (adaptive early exit)" << endl;
473542
}
474543

475544
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#pragma once
2+
#include "../../../Common/include/geometry/CGeometry.hpp"
3+
#include "../../include/solvers/CSolver.hpp"
4+
#include <vector>
5+
#include <cmath>
6+
#include "../../../Common/include/CConfig.hpp"
7+
8+
inline su2double ComputeLinSysResRMS(const CSolver* solver, const CGeometry* geometry) {
9+
unsigned short nVar = solver->GetnVar();
10+
unsigned long nPointDomain = geometry->GetnPointDomain();
11+
std::vector<su2double> sumRes(nVar, 0.0);
12+
su2double localSum = 0.0;
13+
for (unsigned long i = 0; i < nPointDomain; ++i) {
14+
const su2double* res = solver->LinSysRes.GetBlock(i);
15+
for (unsigned short v = 0; v < nVar; ++v) {
16+
sumRes[v] += res[v] * res[v];
17+
}
18+
}
19+
for (unsigned short v = 0; v < nVar; ++v) localSum += sumRes[v];
20+
su2double globalSum = 0.0;
21+
SU2_MPI::Allreduce(&localSum, &globalSum, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm());
22+
unsigned long globalNPointDomain = 0;
23+
SU2_MPI::Allreduce(&nPointDomain, &globalNPointDomain, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm());
24+
if (globalNPointDomain == 0) return 0.0;
25+
return std::sqrt(globalSum / (globalNPointDomain * nVar));
26+
}

SU2_CFD/src/solvers/CSolver.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,11 +1955,12 @@ void CSolver::AdaptCFLNumber(CGeometry **geometry,
19551955
const su2double nPointFine = su2double(geometry[iMGLevel-1]->GetGlobal_nPointDomain());
19561956

19571957
/*--- Apply the same scaling factor as used during geometry construction. ---*/
1958-
const su2double factor = 2.0;
1958+
const su2double factor = 1.1;
19591959
const su2double Coeff = pow(nPointFine / nPointCoarse, 1.0 / nDim);
1960-
const su2double CFL_Coarse = factor * config->GetCFL(iMGLevel - 1) / Coeff;
1961-
1962-
config->SetCFL(iMGLevel, CFL_Coarse);
1960+
const su2double CFL_Coarse = factor * config->GetCFL(iMGLevel - 1);// / Coeff;
1961+
cout << "Adapted CFL for MG Level " << iMGLevel << ": " << CFL_Coarse << endl;
1962+
// nijso: comment this if we do not adapt the coarse level CFLs
1963+
//config->SetCFL(iMGLevel, CFL_Coarse);
19631964
}
19641965
}
19651966
END_SU2_OMP_SAFE_GLOBAL_ACCESS

config_template.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,6 +1597,9 @@ MG_POST_SMOOTH= ( 0, 0, 0, 0 )
15971597
% Jacobi implicit smoothing of the correction
15981598
MG_CORRECTION_SMOOTH= ( 0, 0, 0, 0 )
15991599
%
1600+
% Smoothing coefficient for multigrid correction smoothing (1.25 by default)
1601+
MG_SMOOTH_COEFF= 1.25
1602+
%
16001603
% Damping factor for the residual restriction
16011604
MG_DAMP_RESTRICTION= 0.75
16021605
%

0 commit comments

Comments
 (0)