From 208e9c316f96350a67c4008ec68c524c537fbba4 Mon Sep 17 00:00:00 2001 From: Spencer Bryngelson Date: Thu, 16 Jul 2026 21:21:23 -0400 Subject: [PATCH] fix(phase_change): bound Newton relaxation loops by max_iter (#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 #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. --- src/common/m_phase_change.fpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/common/m_phase_change.fpp b/src/common/m_phase_change.fpp index 6cfe012cb8..8221dbbdb8 100644 --- a/src/common/m_phase_change.fpp +++ b/src/common/m_phase_change.fpp @@ -24,7 +24,7 @@ module m_phase_change !> @name Parameters for the first order transition phase change !> @{ - integer, parameter :: max_iter = 1e8_wp !< max # of iterations + integer, parameter :: max_iter = 100000 !< max Newton iterations before accepting the last iterate real(wp), parameter :: pCr = 4.94e7_wp !< Critical pressure of water [Pa] real(wp), parameter :: TCr = 385.05_wp + 273.15_wp !< Critical temperature of water [K] real(wp), parameter :: mixM = 1.0e-8_wp !< Mixture mass fraction threshold for triggering phase change @@ -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)) ! increasing counter ns = ns + 1 + ! guard against non-convergence: accept the last iterate rather than looping forever + if (ns >= max_iter) exit ! updating old pressure pO = pS @@ -395,6 +397,8 @@ contains ! Updating counter for the iterative procedure ns = ns + 1 + ! guard against non-convergence: accept the last iterate rather than looping forever + if (ns >= max_iter) exit ! Auxiliary variables to help in the calculation of the residue mCP = 0.0_wp; mCPD = 0.0_wp; mCVGP = 0.0_wp; mCVGP2 = 0.0_wp; mQ = 0.0_wp; mQD = 0.0_wp @@ -591,6 +595,8 @@ contains do while ((abs(FT) > ptgalpha_eps) .or. (ns == 0)) ! increasing counter ns = ns + 1 + ! guard against non-convergence: accept the last iterate rather than looping forever + if (ns >= max_iter) exit ! calculating residual FT = TSat*((cvs(lp)*gs_min(lp) - cvs(vp)*gs_min(vp))*(1 - log(TSat)) - (qvps(lp) - qvps(vp)) + cvs(lp)*(gs_min(lp) &