Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
d1e5d59
cleanup
pcarruscag Apr 12, 2026
62ad49c
fix
pcarruscag Apr 13, 2026
dd8b29f
check that we can recover the current behavior
pcarruscag Apr 13, 2026
31b0421
Revert "check that we can recover the current behavior"
pcarruscag Apr 13, 2026
768b781
fix regressions
bigfooted Apr 13, 2026
6a86303
fix regressions
bigfooted Apr 14, 2026
6e1d9e5
Apply suggestions from code review
bigfooted Apr 14, 2026
cb81b12
Apply suggestions from code review
bigfooted Apr 14, 2026
7b8b7bb
update regression residual
bigfooted Apr 14, 2026
671a0c8
fixed_cl first one
bigfooted Apr 14, 2026
f0b5c20
fix more
bigfooted Apr 14, 2026
953bff9
fix more
bigfooted Apr 15, 2026
1577b02
first update
bigfooted Apr 22, 2026
09c3a64
precompute residual
bigfooted Apr 22, 2026
bd45320
update on different residual strategies
bigfooted Apr 30, 2026
708c8b2
good convergence on 1_2DZP
bigfooted Apr 30, 2026
1fd247b
working with reasonable convergence
bigfooted May 1, 2026
1586663
1_2DZP converges in 1600 iterations
bigfooted May 1, 2026
5543d6a
merge with develop
bigfooted May 3, 2026
42e9247
cleanup
bigfooted May 3, 2026
07a4781
merge w develop
bigfooted May 3, 2026
6c08563
remove linsysrmsres
bigfooted May 3, 2026
5f81ac6
further simplification
bigfooted May 3, 2026
ad764cf
reduce to single residual mg analysis
bigfooted May 3, 2026
b5182ea
case 1,2 converge well
bigfooted May 3, 2026
e60d45f
improved MG CFL cap
bigfooted May 4, 2026
15db526
change const to constexpr
bigfooted May 4, 2026
cb12de3
Potential fix for pull request finding 'CodeQL / Commented-out code'
bigfooted May 4, 2026
987af06
Potential fix for pull request finding 'CodeQL / Commented-out code'
bigfooted May 4, 2026
eeef043
ditch the defect correction tests
bigfooted May 4, 2026
90795e7
Merge branch 'pedro/use_available_residual' of https://github.com/su2…
bigfooted May 4, 2026
b6ac379
synch mlpcpp
bigfooted May 4, 2026
886e2d2
Potential fix for pull request finding 'CodeQL / Commented-out code'
bigfooted May 4, 2026
2b50f85
cleanup comments
bigfooted May 4, 2026
7d27bc9
Merge branch 'pedro/use_available_residual' of https://github.com/su2…
bigfooted May 4, 2026
963e12d
change passivedouble
bigfooted May 4, 2026
b0472e3
fix AD compile error
bigfooted May 4, 2026
31752de
simple scaling for coarse meshes
bigfooted May 5, 2026
b01702a
CODI fix
bigfooted May 5, 2026
8373167
remove mg cfl
bigfooted May 5, 2026
9f4ae4f
Merge branch 'develop' into pedro/use_available_residual
bigfooted May 24, 2026
16be471
implicit_lines config option
bigfooted May 24, 2026
351c023
Merge branch 'pedro/use_available_residual' of https://github.com/su2…
bigfooted May 24, 2026
7cebbb7
cleanup multigrid, simplify damping
bigfooted May 25, 2026
cd678b8
precommit
bigfooted May 25, 2026
3306b81
remove template for damping factor
bigfooted May 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Common/include/CConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1147,6 +1147,8 @@ class CConfig {
/*--- Multigrid options ---*/
unsigned short nMG_PreSmooth_p{0}, nMG_PostSmooth_p{0}, nMG_CorrecSmooth_p{0};
unsigned short *MG_PreSmooth_p{nullptr}, *MG_PostSmooth_p{nullptr}, *MG_CorrecSmooth_p{nullptr};
unsigned short nMG_CflScaling_p{0};
su2double *MG_CflScaling_p{nullptr};

ENUM_STREAMWISE_PERIODIC Kind_Streamwise_Periodic; /*!< \brief Kind of Streamwise periodic flow (pressure drop or massflow) */
bool Streamwise_Periodic_Temperature; /*!< \brief Use real periodicity for Energy equation or otherwise outlet source term. */
Expand Down
3 changes: 3 additions & 0 deletions Common/include/option_structure.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1117,9 +1117,12 @@ struct CMGOptions {
std::vector<unsigned short> MG_PreSmooth; /*!< \brief Multigrid pre-smoothing iterations per level. */
std::vector<unsigned short> MG_PostSmooth; /*!< \brief Multigrid post-smoothing iterations per level. */
std::vector<unsigned short> MG_CorrecSmooth; /*!< \brief Multigrid Jacobi correction-smoothing per level. */
std::vector<su2double> MG_CflScaling; /*!< \brief Per-level CFL scaling factors relative to the previous (finer) level. Entry [i] scales level i+1 from level i. Size = nMGLevels. */
bool MG_Smooth_EarlyExit{false}; /*!< \brief Enable early exit for MG smoothing iterations. */
bool MG_Smooth_Output{false}; /*!< \brief Output compact per-cycle smoothing summary. */
su2double MG_Smooth_StagnationTol{0.0}; /*!< \brief Stagnation early exit: stop if current_rms >= prev_rms * tol. 0 = disabled. */
bool MG_Implicit_Lines{false}; /*!< \brief Enable implicit-lines agglomeration from walls. */
unsigned long MG_Implicit_Lines_MaxLength{20}; /*!< \brief Maximum nodes on a wall-normal implicit line (including wall seed). */
};

/*!
Expand Down
20 changes: 19 additions & 1 deletion Common/src/CConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1989,12 +1989,18 @@ void CConfig::SetConfig_Options() {
addDoubleOption("MG_SMOOTH_RES_THRESHOLD", MGOptions.MG_Smooth_Res_Threshold, 0.5);
/*!\brief MG_SMOOTH_OUTPUT\n DESCRIPTION: Print compact per-cycle smoothing iteration summary. DEFAULT: NO \ingroup Config*/
addBoolOption("MG_SMOOTH_OUTPUT", MGOptions.MG_Smooth_Output, false);
/*!\brief MG_SMOOTH_STAGNATION_TOL\n DESCRIPTION: Early exit smoothing when step-to-step RMS ratio >= this value (0 = disabled). DEFAULT: 0.0 \ingroup Config*/
addDoubleOption("MG_SMOOTH_STAGNATION_TOL", MGOptions.MG_Smooth_StagnationTol, 0.99);
/*!\brief MG_SMOOTH_COEFF\n DESCRIPTION: Smoothing coefficient for the correction prolongation Jacobi smoother. DEFAULT: 1.25 \ingroup Config*/
addDoubleOption("MG_SMOOTH_COEFF", MGOptions.MG_Smooth_Coeff, 1.25);
/*!\brief MG_MIN_MESHSIZE\n DESCRIPTION: Minimum number of CVs on the coarsest multigrid level. Levels that would produce fewer CVs are not created. DEFAULT: 50 \ingroup Config*/
addUnsignedLongOption("MG_MIN_MESHSIZE", MGOptions.MG_Min_MeshSize, 500);
/*!\brief MG_IMPLICIT_LINES\n DESCRIPTION: Enable agglomeration along implicit lines from wall seeds. DEFAULT: NO \ingroup Config*/
addBoolOption("MG_IMPLICIT_LINES", MGOptions.MG_Implicit_Lines, false);
/*!\brief MG_IMPLICIT_LINES_MAX_LENGTH\n DESCRIPTION: Maximum number of nodes on a wall-normal implicit agglomeration line (including the wall seed node). DEFAULT: 20 \ingroup Config*/
addUnsignedLongOption("MG_IMPLICIT_LINES_MAX_LENGTH", MGOptions.MG_Implicit_Lines_MaxLength, 20);
/*!\brief MG_CFL_SCALING\n DESCRIPTION: Per-level CFL scaling factors for coarse MG levels. Entry i is the ratio CFL(i+1)/CFL(i). If fewer values than nMGLevels are given, the last value is repeated. DEFAULT: 0.25 (i.e., 1/4 per level) \ingroup Config*/
addDoubleListOption("MG_CFL_SCALING", nMG_CflScaling_p, MG_CflScaling_p);

/*!\par CONFIG_CATEGORY: Spatial Discretization \ingroup Config*/
/*--- Options related to the spatial discretization ---*/
Expand Down Expand Up @@ -4789,6 +4795,16 @@ void CConfig::SetPostprocessing(SU2_COMPONENT val_software, unsigned short val_i
[](unsigned short ) { return (unsigned short)0; });
fillSmooth(nMG_CorrecSmooth_p, MG_CorrecSmooth_p, MGOptions.MG_CorrecSmooth,
[](unsigned short ) { return (unsigned short)0; });

/*--- Fill MG_CflScaling to size nMGLevels (one entry per coarse level transition). ---*/
MGOptions.MG_CflScaling.resize(nMGLevels);
if (nMG_CflScaling_p != 0) {
for (unsigned short i = 0; i < nMGLevels; ++i)
MGOptions.MG_CflScaling[i] = (i < nMG_CflScaling_p) ? MG_CflScaling_p[i] : MG_CflScaling_p[nMG_CflScaling_p - 1];
} else {
for (unsigned short i = 0; i < nMGLevels; ++i)
MGOptions.MG_CflScaling[i] = 0.25;
}
}

/*--- Override MG Smooth parameters ---*/
Expand Down Expand Up @@ -7534,10 +7550,12 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) {
MGTable.AddColumn("Presmooth", 10);
MGTable.AddColumn("PostSmooth", 10);
MGTable.AddColumn("CorrectSmooth", 10);
MGTable.AddColumn("CFL Scaling", 12);
MGTable.SetAlign(PrintingToolbox::CTablePrinter::RIGHT);
MGTable.PrintHeader();
for (unsigned short iLevel = 0; iLevel < nMGLevels+1; iLevel++) {
MGTable << iLevel << MGOptions.MG_PreSmooth[iLevel] << MGOptions.MG_PostSmooth[iLevel] << MGOptions.MG_CorrecSmooth[iLevel];
const string cflStr = (iLevel == 0) ? "-" : std::to_string(MGOptions.MG_CflScaling[iLevel-1]).substr(0,6);
MGTable << iLevel << MGOptions.MG_PreSmooth[iLevel] << MGOptions.MG_PostSmooth[iLevel] << MGOptions.MG_CorrecSmooth[iLevel] << cflStr;
}
MGTable.PrintFooter();
}
Expand Down
20 changes: 12 additions & 8 deletions Common/src/geometry/CMultiGridGeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1280,24 +1280,28 @@ su2double CMultiGridGeometry::ComputeLocalCurvature(const CGeometry* fine_grid,
void CMultiGridGeometry::AgglomerateImplicitLines(unsigned long& Index_CoarseCV, const CGeometry* fine_grid,
const CConfig* config, CMultiGridQueue& MGQueue_InnerCV) {
/*--- Parameters ---*/
const su2double ANGLE_THRESHOLD_DEG = 20.0; /*!< Stop line if direction deviates more than this. */
constexpr unsigned long MAX_LINE_LENGTH = 20; /*!< Max nodes on implicit line (including wall). */
const su2double ANGLE_THRESHOLD_DEG = 20.0; /*!< Stop line if direction deviates more than this. */
const unsigned long MAX_LINE_LENGTH = config->GetMGOptions().MG_Implicit_Lines_MaxLength;
const su2double cos_threshold = cos(ANGLE_THRESHOLD_DEG * PI_NUMBER / 180.0);

const unsigned long nPointFine = fine_grid->GetnPoint();

/*--- Collect implicit lines starting at wall vertices.
/*--- Collect implicit lines starting at viscous (no-slip) wall vertices only.
* Seeding from non-wall boundaries (farfield, inlet, outlet, symmetry) would
* claim interior BL cells before the wall lines can reach them, leaving
* wall-seeded lines with length < 3 (discarded). Restricting to viscous walls
* ensures the boundary-layer cells are agglomerated wall-first.
* Each line: [wall_node, interior_1, interior_2, ...].
* The wall node (index 0) is already agglomerated by boundary agglomeration;
* only interior nodes (index >= 1) are paired into coarse CVs. ---*/
vector<vector<unsigned long>> lines;

for (auto iMarker = 0u; iMarker < fine_grid->GetnMarker(); iMarker++) {
/*--- Skip non-physical markers ---*/
if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE ||
config->GetMarker_All_KindBC(iMarker) == INTERNAL_BOUNDARY ||
config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY)
continue;
/*--- Only seed lines from viscous (no-slip) wall markers.
* Non-wall boundaries (farfield, inlet, outlet, symmetry) must NOT seed
* lines because they would prematurely claim boundary-layer interior nodes. ---*/
const auto bc = config->GetMarker_All_KindBC(iMarker);
if (bc != HEAT_FLUX && bc != ISOTHERMAL && bc != CHT_WALL_INTERFACE && bc != SMOLUCHOWSKI_MAXWELL) continue;

for (auto iVertex = 0ul; iVertex < fine_grid->GetnVertex(iMarker); iVertex++) {
const auto iPoint = fine_grid->vertex[iMarker][iVertex]->GetNode();
Expand Down
85 changes: 35 additions & 50 deletions SU2_CFD/include/integration/CMultiGridIntegration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,32 +216,15 @@ class CMultiGridIntegration final : public CIntegration {
void Adjoint_Setup(CGeometry ****geometry, CSolver *****solver_container, CConfig **config,
unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone);

/*!
* \brief Compute adaptive CFL for multigrid coarse levels.
* \param[in] config - Problem configuration.
* \param[in] solver_coarse - Coarse grid solver.
* \param[in] geometry_coarse - Coarse grid geometry.
* \param[in] iMesh - Current multigrid level.
* \param[in] CFL_fine - Fine grid CFL value (passive).
* \param[in] CFL_coarse_current - Current coarse grid CFL value (passive).
* \param[in] rms_res_coarse - Coarse-grid RMS residual (already MPI-reduced, from lastPreSmoothRMS).
* \return New CFL value for the coarse grid.
*/
passivedouble computeMultigridCFL(CConfig* config, unsigned short iMesh,
passivedouble CFL_fine, passivedouble CFL_coarse_current,
passivedouble rms_res_coarse);

/*!
* \brief Adapt the residual restriction damping factor.
*
* Uses \c lastPreSmoothIters[] (filled by the previous multigrid cycle) to assess
* whether the pre-smoother is converging fast or slow on coarse levels, then adjusts
* \c Damp_Res_Restric in \p config accordingly.
* Uses \c lastPreSmoothWorstStepRatio[] (filled by the previous multigrid cycle) to
* assess whether the pre-smoother is amplifying or converging on coarse levels, then
* adjusts \c Damp_Res_Restric in \p config accordingly.
*
* Signal logic:
* - any coarse level ran its full configured iterations: reduce damping
* - all coarse levels exited early: increase damping
* - mixed (some full, some partial): no change
* Two tuning parameters: THRESHOLD (improving boundary, default 0.85) and
* SCALE_DOWN (default 0.75); SCALE_UP is derived as 1 + (1-SCALE_DOWN)/4 = 1.0625.
*
* \param[in,out] config - Problem configuration.
*/
Expand All @@ -259,48 +242,50 @@ class CMultiGridIntegration final : public CIntegration {
* - all levels exited early: increase damping
* - mixed: no change
*
* Uses the inter-cycle rho signal to detect Phase-2 stagnation and adjusts
* \c Damp_Correc_Prolong in \p config accordingly.
*
* Signal logic (rho = d0_k / d1_{k-1}, the fine-grid cycle convergence factor):
* - rho >= 1.0 (fine residual not decreasing) -> SCALE_DOWN
* - rho < GOOD_THRESHOLD -> SCALE_UP
* - otherwise -> no change
*
* \param[in,out] config - Problem configuration; \c SetDamp_Correc_Prolong is called to persist the result.
* \param[in] rho - Inter-cycle fine-grid convergence factor from \c mg_rho_signal.
*/
void adaptProlongationDamping(CConfig* config);
void adaptProlongationDamping(CConfig* config, passivedouble rho);

/*--- CFL adaptation state variables.
* These must be passivedouble: AD::Reset() clears the tape between adjoint recordings,
* but class members survive. If these were su2double their stale AD indices would
* reference the cleared tape, causing invalid memory access during the backward pass. ---*/
static constexpr int MAX_MG_LEVELS = 10;
passivedouble current_avg[MAX_MG_LEVELS] = {};
passivedouble prev_avg[MAX_MG_LEVELS] = {};
passivedouble last_res[MAX_MG_LEVELS] = {};
bool last_was_increase[MAX_MG_LEVELS] = {};
int oscillation_count[MAX_MG_LEVELS] = {};
unsigned long last_check_iter[MAX_MG_LEVELS] = {};
unsigned long last_update_iter[MAX_MG_LEVELS] = {};
unsigned long last_reset_iter = std::numeric_limits<unsigned long>::max();

/*--- Early-exit smoothing state (shared across OMP threads via master write + barrier). ---*/
bool mg_early_exit_flag = false; /*!< \brief Shared flag for early exit across OMP threads. */
passivedouble mg_initial_smooth_rms = 0.0; /*!< \brief Initial RMS before current smoothing phase. */
passivedouble mg_last_smooth_rms = 0.0; /*!< \brief Last computed RMS; cached to avoid redundant Allreduce. */
bool mg_early_exit_flag = false; /*!< \brief Shared flag for early exit across OMP threads. */
passivedouble mg_initial_smooth_rms = 0.0; /*!< \brief Initial RMS residual before current smoothing phase (FAS). */
passivedouble mg_prev_smooth_rms = 0.0; /*!< \brief RMS residual from previous smoothing step; used for stagnation detection. */
passivedouble mg_fine_rms_ema = 0.0; /*!< \brief EMA of fine-grid pre-smooth RMS residual across outer iterations; cross-cycle blowup detection. */
passivedouble last_crossCycleRatio = 1.0; /*!< \brief crossCycleRatio from the most recent cycle; stored for display only. */
passivedouble mg_prev_d1_fine = 0.0; /*!< \brief Level-0 end-of-pre-smooth defect saved from the previous MG cycle; denominator of the rho signal (Proposal A). */
passivedouble mg_rho_signal = 1.0; /*!< \brief rho_k = d0_k / d1_{k-1}: inter-cycle fine-grid convergence factor; drives adaptProlongationDamping. */
int mg_restrict_floor_count = 0; /*!< \brief Consecutive cycles spent at restrict-damp CLAMP_MIN while still amplifying; freezes SCALE_DOWN once structural. */
int mg_prolong_floor_count = 0; /*!< \brief Consecutive cycles spent at prolong-damp CLAMP_MIN while still amplifying; freezes SCALE_DOWN once structural. */

/*--- Actual iteration counts per MG level, filled each cycle for the compact output summary. ---*/
unsigned short lastPreSmoothIters[MAX_MG_LEVELS+1] = {};
unsigned short lastPostSmoothIters[MAX_MG_LEVELS+1] = {};
unsigned short lastCorrecSmoothIters[MAX_MG_LEVELS+1] = {};
/*--- Early-exit reason per level: 'T'=threshold, 'S'=stagnation, ' '=ran to completion. ---*/
char lastPreSmoothExitReason[MAX_MG_LEVELS+1] = {};
char lastPostSmoothExitReason[MAX_MG_LEVELS+1] = {};

/*--- Per-level residual progress flags: true if the final RMS after that phase was lower
* than the initial RMS. Used by the adaptive damping routines to distinguish
* "hit max iters but still converging" from "hit max iters and stagnated". ---*/
bool lastPreSmoothProgress[MAX_MG_LEVELS+1] = {};
bool lastPostSmoothProgress[MAX_MG_LEVELS+1] = {};
bool lastCorrecSmoothProgress[MAX_MG_LEVELS+1] = {};

/*--- Per-level start/end RMS for the compact output summary.
* [0] = initial RMS before smoothing, [1] = final RMS after smoothing.
* Filled unconditionally (early-exit path and exhaustion path).
* Must be passivedouble: class members survive tape resets; su2double would
* carry stale AD indices referencing a cleared tape. ---*/
/*--- Per-level start/end RMS residual for adaptive damping. ---*/
passivedouble lastPreSmoothRMS[MAX_MG_LEVELS+1][2] = {};
passivedouble lastPostSmoothRMS[MAX_MG_LEVELS+1][2] = {};
passivedouble lastCorrecSmoothRMS[MAX_MG_LEVELS+1][2] = {};

/*--- Per-level worst step-to-step amplification seen inside a smoothing phase.
* step==0 means no intra-smoother ratio was available (fewer than 2 sweeps). ---*/
passivedouble lastPreSmoothWorstStepRatio[MAX_MG_LEVELS+1] = {};
passivedouble lastPostSmoothWorstStepRatio[MAX_MG_LEVELS+1] = {};
unsigned short lastPreSmoothWorstStep[MAX_MG_LEVELS+1] = {};
unsigned short lastPostSmoothWorstStep[MAX_MG_LEVELS+1] = {};

};
21 changes: 10 additions & 11 deletions SU2_CFD/src/drivers/CDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,16 @@ void CDriver::InitializeGeometryFVM(CConfig *config, CGeometry **&geometry) {

geometry[iMGlevel] = new CMultiGridGeometry(geometry[iMGlevel-1], config, iMGlevel);

/*--- Protect against the situation that we were not able to complete
the agglomeration for this level, i.e., there weren't enough points.
Check immediately so the expensive post-construction steps are skipped. ---*/

if (config->GetnMGLevels() != requestedMGlevels) {
delete geometry[iMGlevel];
geometry[iMGlevel] = nullptr;
break;
}

/*--- Compute points surrounding points. ---*/

geometry[iMGlevel]->SetPoint_Connectivity(geometry[iMGlevel-1]);
Expand All @@ -836,17 +846,6 @@ void CDriver::InitializeGeometryFVM(CConfig *config, CGeometry **&geometry) {

geometry[iMGlevel]->SetMGLevel(iMGlevel);

/*--- Protect against the situation that we were not able to complete
the agglomeration for this level, i.e., there weren't enough points.
We need to check if we changed the total number of levels and delete
the incomplete CMultiGridGeometry object. ---*/

if (config->GetnMGLevels() != requestedMGlevels) {
delete geometry[iMGlevel];
geometry[iMGlevel] = nullptr;
break;
}

}

if (config->GetWrt_MultiGrid()) geometry[MESH_0]->ColorMGLevels(config->GetnMGLevels(), geometry);
Expand Down
Loading
Loading