fix(phase_change): bound Newton relaxation loops by max_iter#1653
Conversation
…de#1646) The three Newton solvers in m_phase_change (s_infinite_pt_relaxation_k, s_infinite_ptg_relaxation_k, s_TSat) looped on a convergence-only condition with no iteration limit. The module parameter max_iter was declared but never referenced (dead since MFlowCode#179), so a cell that fails to converge hung the solver forever (on GPU: kernel never returns, host blocks in cuStreamSynchronize). Reproduced with the stock examples/2D_phasechange_bubble. Bound each loop by max_iter and accept the last iterate on exhaustion, turning an unbounded hang into a bounded, finite step. Reduce the misleading real-literal init (max_iter = 1e8_wp) to a clean integer (100000). Golden-safe: all 18 phase-change regression tests pass byte-identical, confirming the cap sits above the legitimate convergence ceiling and truncates no converging cell.
There was a problem hiding this comment.
Pull request overview
This PR addresses a solver hang in the phase-change module by bounding previously unbounded Newton iteration loops, ensuring non-convergent cells cannot trap the run in an infinite loop (including on GPU where the kernel may never return).
Changes:
- Replace the unused/incorrect
max_iterinitialization (integerfrom a real literal) with a clean integer constant (100000). - Add
max_iterexhaustion guards to the three Newton solvers (s_infinite_pt_relaxation_k,s_infinite_ptg_relaxation_k,s_TSat) so theyexitafter too many iterations and accept the last iterate.
| @@ -320,6 +320,8 @@ contains | |||
| do while ((abs(pS - pO) > palpha_eps) .and. (abs((pS - pO)/pO) > palpha_eps/1.e4_wp) .or. (ns == 0)) | |||
|
@copilot good catch on the Fixed in the follow-up #1654 (which reworks these solvers): the relative criterion is rewritten in multiply form, |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1653 +/- ##
==========================================
- Coverage 60.95% 59.54% -1.42%
==========================================
Files 83 83
Lines 20003 21114 +1111
Branches 2983 3131 +148
==========================================
+ Hits 12193 12572 +379
- Misses 5782 6437 +655
- Partials 2028 2105 +77 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Description
The three Newton solvers in
src/common/m_phase_change.fpp—s_infinite_pt_relaxation_k,s_infinite_ptg_relaxation_k, ands_TSat— looped on a convergence-onlydo whilecondition with no iteration limit. The module parametermax_iterwas declared but never referenced anywhere (grep-confirmed): it has been dead since the original phase-change PR (#179), which declared it — and even added it to the!$acc declarelist — but never wired it into the loop conditions. A later cleanup (#999) removed the stale GPU declaration while migrating to the macro, leaving a fully orphaned declaration. So it is a latent birth defect, not a regression.When a cell fails to converge, the loop never exits and the run hangs indefinitely (on GPU the kernel never returns and the host blocks in
cuStreamSynchronize). Reproduced with the stock, unmodifiedexamples/2D_phasechange_bubble, which hangs att_step = 8independent of compiler, MPI, and grid resolution.Root cause of the non-convergence itself (tracked as a separate follow-up):
s_TSatand the pTg solver compare a dimensional Gibbs-free-energy residual (natural magnitude ~10²–10³) against the fixed toleranceptgalpha_eps = 1e-2under heavyOm = 1e-3underrelaxation, so for low-pressure vapor cells the exit condition is effectively unreachable. This PR does not change that convergence behavior — it only removes the ability to hang.This change:
if (ns >= max_iter) exit, accepting the last iterate on exhaustion. An unbounded hang becomes a bounded, finite step.max_iter = 1e8_wp(anintegerinitialized from a real literal) to a clean integer100000, comfortably above the observed legitimate convergence ceiling.Closes #1646.
Type of change
Testing
Phase Change model 5/6, 1D/2D/3D, 2/3 fluids, model_eqns 2/3) pass byte-identical against the existing golden files. This confirms the cap sits above the legitimate convergence ceiling and truncates no converging cell — one case (2D, model 6) legitimately iterates deep (~145 s vs ~7 s for its siblings) yet still matches bit-for-bit, so the cap is neither too low (clipping valid slow cells) nor merely cosmetic.examples/2D_phasechange_bubble(freezes att_step = 8); with this fix the same case advances past it and continues stepping steadily (ran tot_step = 31)../mfc.sh precheckpasses (formatting, spell, lint, docs, params, case validation).CPU-only change in
src/common/; no GPU code paths altered.Checklist
The change is golden-safe (no behavior change for converging cells), so it adds no new golden test; a dedicated "does not hang" regression would require a case that loops unboundedly without the fix. Happy to add one if reviewers prefer.