@@ -217,90 +217,64 @@ class CMultiGridIntegration final : public CIntegration {
217217 unsigned short RunTime_EqSystem, unsigned long Iteration, unsigned short iZone);
218218
219219 /* !
220- * \brief Compute adaptive CFL for multigrid coarse levels.
221- * \param[in] config - Problem configuration.
222- * \param[in] solver_coarse - Coarse grid solver.
223- * \param[in] geometry_coarse - Coarse grid geometry.
224- * \param[in] iMesh - Current multigrid level.
225- * \param[in] CFL_fine - Fine grid CFL value (passive).
226- * \param[in] CFL_coarse_current - Current coarse grid CFL value (passive).
227- * \param[in] rms_res_coarse - Coarse-grid RMS residual (already MPI-reduced, from lastPreSmoothRMS).
228- * \return New CFL value for the coarse grid.
229- */
230- passivedouble computeMultigridCFL (CConfig* config, unsigned short iMesh,
231- passivedouble CFL_fine, passivedouble CFL_coarse_current,
232- passivedouble rms_res_coarse);
233-
234- /* !
235- * \brief Adapt the residual restriction damping factor.
220+ * \brief Adapt both restriction and prolongation damping factors from the global-trend signal.
236221 *
237- * Uses \c lastPreSmoothIters[] (filled by the previous multigrid cycle) to assess
238- * whether the pre-smoother is converging fast or slow on coarse levels, then adjusts
239- * \c Damp_Res_Restric in \p config accordingly.
222+ * Uses the cross-cycle EMA ratio (crossCycleRatio = fine_d0 / EMA(fine_d0)) to detect
223+ * long-term convergence or divergence, then adjusts both \c Damp_Res_Restric and
224+ * \c Damp_Correc_Prolong with a single shared signal. The EMA filters per-cycle noise;
225+ * no per-level aggregation or floor counter is needed.
240226 *
241- * Signal logic:
242- * - any coarse level ran its full configured iterations: reduce damping
243- * - all coarse levels exited early: increase damping
244- * - mixed (some full, some partial): no change
245- *
246- * \param[in,out] config - Problem configuration.
227+ * \param[in,out] config - Problem configuration.
228+ * \param[in] crossCycleRatio - Current fine_d0 divided by the EMA of fine_d0.
247229 */
248- void adaptRestrictionDamping (CConfig* config);
230+ void adaptDampingFactors (CConfig* config, passivedouble crossCycleRatio );
249231
250232 /* !
251- * \brief Adapt the correction prolongation damping factor.
252- *
253- * Uses \c lastCorrecSmoothIters[] (filled by the previous multigrid cycle) to assess
254- * whether the correction smoother is struggling or converging fast,
255- * then adjusts \c Damp_Correc_Prolong in \p config accordingly.
256- *
257- * Signal logic:
258- * - any level ran its full correction-smooth iterations: reduce damping
259- * - all levels exited early: increase damping
260- * - mixed: no change
261- *
262- * \param[in,out] config - Problem configuration; \c SetDamp_Correc_Prolong is called to persist the result.
233+ * \brief Helper function for early-exit logic during pre/post-smoothing.
234+ * \param[in] iSmooth - Current smoothing iteration index.
235+ * \param[in] iMesh - Index of the mesh in multigrid computations.
236+ * \param[in] defect - Current RMS defect value.
237+ * \param[in] mgOpts - Reference to multigrid options.
238+ * \param[in] stag_tol - Stagnation tolerance value.
239+ * \param[in] early_exit - Whether early exit is enabled.
240+ * \param[out] lastRMS - Array to store RMS values [start, end].
241+ * \param[out] exitReason - Character for early exit reason ('T', 'S', 'A', or ' ').
242+ * \param[out] worstStepRatio - Worst step-to-step ratio seen.
243+ * \param[out] worstStep - Iteration number of worst step.
263244 */
264- void adaptProlongationDamping (CConfig* config);
245+ void prePostEarlyExit (unsigned short iSmooth, unsigned short iMesh,
246+ passivedouble defect, const CMGOptions& mgOpts,
247+ passivedouble stag_tol, bool early_exit,
248+ passivedouble lastRMS[2 ], char & exitReason,
249+ passivedouble& worstStepRatio, unsigned short & worstStep);
265250
266- /* --- CFL adaptation state variables.
267- * These must be passivedouble: AD::Reset() clears the tape between adjoint recordings,
268- * but class members survive. If these were su2double their stale AD indices would
269- * reference the cleared tape, causing invalid memory access during the backward pass. ---*/
270251 static constexpr int MAX_MG_LEVELS = 10 ;
271- passivedouble current_avg[MAX_MG_LEVELS ] = {};
272- passivedouble prev_avg[MAX_MG_LEVELS ] = {};
273- passivedouble last_res[MAX_MG_LEVELS ] = {};
274- bool last_was_increase[MAX_MG_LEVELS ] = {};
275- int oscillation_count[MAX_MG_LEVELS ] = {};
276- unsigned long last_check_iter[MAX_MG_LEVELS ] = {};
277- unsigned long last_update_iter[MAX_MG_LEVELS ] = {};
278- unsigned long last_reset_iter = std::numeric_limits<unsigned long >::max();
279252
280253 /* --- Early-exit smoothing state (shared across OMP threads via master write + barrier). ---*/
281- bool mg_early_exit_flag = false ; /* !< \brief Shared flag for early exit across OMP threads. */
282- passivedouble mg_initial_smooth_rms = 0.0 ; /* !< \brief Initial RMS before current smoothing phase. */
283- passivedouble mg_last_smooth_rms = 0.0 ; /* !< \brief Last computed RMS; cached to avoid redundant Allreduce. */
254+ bool mg_early_exit_flag = false ; /* !< \brief Shared flag for early exit across OMP threads. */
255+ passivedouble mg_initial_smooth_rms = 0.0 ; /* !< \brief Initial RMS residual before current smoothing phase (FAS). */
256+ passivedouble mg_prev_smooth_rms = 0.0 ; /* !< \brief RMS residual from previous smoothing step; used for stagnation detection. */
257+ passivedouble mg_fine_rms_ema = 0.0 ; /* !< \brief EMA of fine-grid pre-smooth RMS across cycles; cross-cycle trend signal. */
258+ passivedouble last_crossCycleRatio = 1.0 ; /* !< \brief crossCycleRatio from the most recent cycle; stored for display only. */
284259
285260 /* --- Actual iteration counts per MG level, filled each cycle for the compact output summary. ---*/
286261 unsigned short lastPreSmoothIters[MAX_MG_LEVELS +1 ] = {};
287262 unsigned short lastPostSmoothIters[MAX_MG_LEVELS +1 ] = {};
288263 unsigned short lastCorrecSmoothIters[MAX_MG_LEVELS +1 ] = {};
264+ /* --- Early-exit reason per level: 'T'=threshold, 'S'=stagnation, ' '=ran to completion. ---*/
265+ char lastPreSmoothExitReason[MAX_MG_LEVELS +1 ] = {};
266+ char lastPostSmoothExitReason[MAX_MG_LEVELS +1 ] = {};
289267
290- /* --- Per-level residual progress flags: true if the final RMS after that phase was lower
291- * than the initial RMS. Used by the adaptive damping routines to distinguish
292- * "hit max iters but still converging" from "hit max iters and stagnated". ---*/
293- bool lastPreSmoothProgress[MAX_MG_LEVELS +1 ] = {};
294- bool lastPostSmoothProgress[MAX_MG_LEVELS +1 ] = {};
295- bool lastCorrecSmoothProgress[MAX_MG_LEVELS +1 ] = {};
296-
297- /* --- Per-level start/end RMS for the compact output summary.
298- * [0] = initial RMS before smoothing, [1] = final RMS after smoothing.
299- * Filled unconditionally (early-exit path and exhaustion path).
300- * Must be passivedouble: class members survive tape resets; su2double would
301- * carry stale AD indices referencing a cleared tape. ---*/
268+ /* --- Per-level start/end RMS residual for adaptive damping. ---*/
302269 passivedouble lastPreSmoothRMS[MAX_MG_LEVELS +1 ][2 ] = {};
303270 passivedouble lastPostSmoothRMS[MAX_MG_LEVELS +1 ][2 ] = {};
304271 passivedouble lastCorrecSmoothRMS[MAX_MG_LEVELS +1 ][2 ] = {};
305272
273+ /* --- Per-level worst step-to-step amplification seen inside a smoothing phase.
274+ * step==0 means no intra-smoother ratio was available (fewer than 2 sweeps). ---*/
275+ passivedouble lastPreSmoothWorstStepRatio[MAX_MG_LEVELS +1 ] = {};
276+ passivedouble lastPostSmoothWorstStepRatio[MAX_MG_LEVELS +1 ] = {};
277+ unsigned short lastPreSmoothWorstStep[MAX_MG_LEVELS +1 ] = {};
278+ unsigned short lastPostSmoothWorstStep[MAX_MG_LEVELS +1 ] = {};
279+
306280};
0 commit comments