What happens
SNES_Stokes_SaddlePt.__init__ sets fieldsplit_velocity_ksp_max_it = 200. On a problem where GAMG needs more than that per velocity solve, the sub-KSP stops at the cap and reports DIVERGED_ITS, but the overall solve still looks fine: snes.getConvergedReason() is positive, and nothing in the ordinary output says the inner block was cut off.
Measured
Unit box, Taylor-Hood P2-P1, free slip, viscosity contrast 1e4 concentrated in a Gaussian band of half-width 0.05, GAMG, defaults otherwise (with #584 applied):
|
cycles per velocity solve |
flops |
wall |
sub-KSP reason |
| default cap (200) |
158-201 |
1.37e10 |
1.8 s |
DIVERGED_ITS |
| cap raised to 20000 |
172-511 |
2.10e10 |
2.7 s |
converged |
The tell is that the count sits exactly on the cap. The truncated run is not merely incomplete — it is cheaper-looking, so a comparison against it flatters whatever it is compared with. It cost me a wrong conclusion: I reported the truncated 1.37e10 as evidence that the corrected defaults beat a hand-configured solver by 1.5x, when the two are in fact identical (2.1034e10 either way) and the entire difference was the cap.
At refinement 3 the same configuration needs 175-629 cycles, and at refinement 4, 269-591. The cap is reached on ordinary geodynamics problems, not exotic ones.
Why it matters
A user solving a model with a strong localised viscosity structure gets an answer that has not converged to the requested tolerance, with no indication. The failure is quiet in exactly the regime where a user is least able to tell a solver defect from a modelling problem.
What to consider
Raising the cap is not obviously the fix — a cap is a legitimate safety net, and #576 showed that raising one can be entirely inert. The defect is the silence. Options worth weighing: surface the sub-KSP's converged reason in the solve report and in any non-convergence warning; treat a sub-block DIVERGED_ITS as a failure of the outer solve rather than an internal detail; or warn when a count lands on the cap, which is the cheap and unambiguous signal.
Related: #584, and the existing solve_report machinery in test_0203_solver_wallclock_guard, which already models the idea that a sub-block count can be incomplete and says so.
Underworld development team with AI support from Claude Code
What happens
SNES_Stokes_SaddlePt.__init__setsfieldsplit_velocity_ksp_max_it = 200. On a problem where GAMG needs more than that per velocity solve, the sub-KSP stops at the cap and reportsDIVERGED_ITS, but the overall solve still looks fine:snes.getConvergedReason()is positive, and nothing in the ordinary output says the inner block was cut off.Measured
Unit box, Taylor-Hood P2-P1, free slip, viscosity contrast 1e4 concentrated in a Gaussian band of half-width 0.05, GAMG, defaults otherwise (with #584 applied):
The tell is that the count sits exactly on the cap. The truncated run is not merely incomplete — it is cheaper-looking, so a comparison against it flatters whatever it is compared with. It cost me a wrong conclusion: I reported the truncated 1.37e10 as evidence that the corrected defaults beat a hand-configured solver by 1.5x, when the two are in fact identical (2.1034e10 either way) and the entire difference was the cap.
At refinement 3 the same configuration needs 175-629 cycles, and at refinement 4, 269-591. The cap is reached on ordinary geodynamics problems, not exotic ones.
Why it matters
A user solving a model with a strong localised viscosity structure gets an answer that has not converged to the requested tolerance, with no indication. The failure is quiet in exactly the regime where a user is least able to tell a solver defect from a modelling problem.
What to consider
Raising the cap is not obviously the fix — a cap is a legitimate safety net, and #576 showed that raising one can be entirely inert. The defect is the silence. Options worth weighing: surface the sub-KSP's converged reason in the solve report and in any non-convergence warning; treat a sub-block
DIVERGED_ITSas a failure of the outer solve rather than an internal detail; or warn when a count lands on the cap, which is the cheap and unambiguous signal.Related: #584, and the existing
solve_reportmachinery intest_0203_solver_wallclock_guard, which already models the idea that a sub-block count can be incomplete and says so.Underworld development team with AI support from Claude Code