Skip to content

Count sub-solves that stop at their iteration cap (#625) - #631

Merged
lmoresi merged 1 commit into
developmentfrom
bugfix/subsolve-cap-detection
Aug 23, 2026
Merged

Count sub-solves that stop at their iteration cap (#625)#631
lmoresi merged 1 commit into
developmentfrom
bugfix/subsolve-cap-detection

Conversation

@lmoresi

@lmoresi lmoresi commented Aug 22, 2026

Copy link
Copy Markdown
Member

What this fixes

PETSc's KSPCheckSolve deliberately does not treat DIVERGED_MAX_IT on a
sub-KSP as a failure — truncating an inner solve is normal. So a block can run
out of iterations on every application and the outer solve still reports
CONVERGED. Nothing in the output says otherwise.

That silence is what #625 is made of, and it is expensive because
S = -B A^-1 B^T is applied through the velocity solve. Truncate those and
the pressure Krylov is chasing an operator that moves between applications, so
it cannot converge either and caps in turn. Measured on SolCx at h=1/30,
changing only fieldsplit_velocity_ksp_max_it:

velocity cap sec outer pressure/app velocity/app v err
200 (default) 976.0 44 200.0 200.0 1.2302e-1
5000 25.6 2 30.0 618.0 1.2302e-1

38x, from a number that is not in the pressure block, with an identical
answer. Every pathology measured in that campaign turned out to be a cap: the
pressure block, the velocity block beneath it, and the velocity block again
under augmentation. All three would have been visible on sight.

The change

solve_report.sub[...].capped counts the applications that ended at the cap.
The count comes from each application's converged reason, via a post-solve
hook — not from comparing an iteration count against max_it, because a solve
that converges on its last permitted iteration is converged and counting would
misreport it.

str(report) gains — N AT THE ITERATION CAP when non-zero.

No numerical behaviour changes. The counter is observation, and no default
is touched.

Also: the FMG/penalty pairing, recorded in the nonlinear-solver skill

The same campaign established a pairing worth writing down. Matched on one mesh
(2592 cells), same discrete solve, only the velocity preconditioner differing:

lambda velocity PC sec outer Schur/app velocity/app velocity total
0 GAMG 15.49 2 125.5 94.7 24802
0 FMG 3.88 1 59.0 8.8 546
10 GAMG 20.68 7 22.3 199.9 capped 33976
10 FMG 3.06 1 18.0 13.5 270

With FMG, penalty = 10 improves every axis at once. With GAMG the same value
makes the solve slower, because grad-div augmentation is exactly what drives
GAMG into its cap. The two cannot be recommended independently.

The accuracy cost is a consistent perturbation rather than a changed answer —
same convergence rate, gap shrinking 1.102 → 1.087 → 1.066 across three
refinements — which is what makes the pairing safe to recommend. UW3's penalty
is grad-div, not a true augmented Lagrangian (div(P2) is not inside P0), so
it does perturb the discrete solution; it just converges away.

The default is deliberately NOT changed here. Flipping penalty on for FMG
would alter answers by ~7% at working resolutions, and the evidence so far is
one 2-D linear benchmark. See the issue for what still needs measuring.

Testing

tests/test_0205_subsolve_cap_detection.py — 3 tests: a hard cap is counted on
every application, a cap never approached reports zero (the negative control,
without which a counter stuck at applications would pass), and the count
distinguishes some-from-all rather than collapsing to a boolean.

Existing instrumentation suites unaffected: test_0203, test_0204,
test_1017 — 18 passed.

Underworld development team with AI support from Claude Code

… pairing

PETSc's KSPCheckSolve deliberately does not treat DIVERGED_MAX_IT on a sub-KSP
as a failure, so a block can run out of iterations on every application and the
outer solve still reports CONVERGED. That silence is what #625 is made of.

It is expensive because S = -B A^-1 B^T is applied THROUGH the velocity solve.
Truncate those and the pressure Krylov is chasing an operator that moves
between applications, so it cannot converge either and caps in turn. Measured
on SolCx at h=1/30, changing only fieldsplit_velocity_ksp_max_it from 200 to
5000: 976 s to 25.6 s, outer 44 to 2, pressure 200/application to 30, and an
identical velocity error. Thirty-eight times, from a number that is not in the
pressure block.

solve_report.sub[...].capped now counts the applications that ended that way,
read from each application's converged reason via a post-solve hook rather than
by comparing an iteration count against the cap -- a solve that converges on its
last permitted iteration is converged, and counting would misreport it.

The skill records the pairing this exposed: with FMG, penalty=10 improves every
axis at once (21% faster, Schur count 3.3x smaller, total velocity work halved),
because FMG absorbs grad-div augmentation where GAMG is driven into its cap by
it. With GAMG the same penalty makes the solve slower, so the two must not be
recommended independently. The accuracy cost is a consistent perturbation --
same convergence rate, gap shrinking 1.102 -> 1.087 -> 1.066 under refinement --
which is what makes the pairing safe to recommend at all.

No numerical behaviour changes here: the counter is observation, and the
defaults are untouched.

Underworld development team with AI support from Claude Code
Copilot AI lite review requested due to automatic review settings August 22, 2026 10:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@lmoresi
lmoresi merged commit 70e4cdb into development Aug 23, 2026
2 checks passed
@lmoresi
lmoresi deleted the bugfix/subsolve-cap-detection branch August 23, 2026 02:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants