Skip to content

Ask an un-set-up field split for its blocks quietly (#827) - #850

Open
lmoresi wants to merge 2 commits into
developmentfrom
bugfix/subksp-banner-827
Open

lmoresi wants to merge 2 commits into
developmentfrom
bugfix/subksp-banner-827

Conversation

@lmoresi

@lmoresi lmoresi commented Oct 15, 2026

Copy link
Copy Markdown
Member

Fixes #827.

A field split has block solvers only after PCSetUp. Asking an un-set-up split for them is a PETSc error, and PETSc prints its ~38-line "Object is in wrong state / Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitGetSubKSP()" banner before the exception reaches Python, so except could not hide it and healthy solves looked broken.

Three paths reached it:

Path Site
viscoelastic solve: the velocity-preconditioner check ran before solving (#827 reproducer) SNES_Stokes._check_velocity_preconditioner
plain warm solve with no linear solve, after a consistent_jacobian change rebuilt the solver same
custom-multigrid "still installed?" test before each solve, on a solver rebuilt by a consistent_jacobian change; every notch run with a non-nested gmsh FMG tail printed it custom_mg._pcmg_still_installed

Change. _fieldsplit_sub_ksps(pc) in utilities/_petsc_tools.py returns the blocks, or [] when there are none yet, with the banner silenced for that one call: the "return" error handler still raises, it only stops the printing, and it is popped on every path. (The "ignore" handler that broke 23 tests in an earlier attempt turns errors into success; this does not.) Both sites use it, and the viscoelastic check moves to after the solve, as on the plain path.

Behaviour change, by design. Before, the viscoelastic check always returned early, so a viscoelastic solve on a mesh without a hierarchy never reported that its velocity block was running GAMG. It now warns and records velocity.fell_back_from_fmg, as a plain solve already did (once per process under the default warning filter).

Tests. tests/test_1077_quiet_unsetup_fieldsplit.py captures fd-level stderr. The three path tests fail on the unfixed code on the banner assertion and pass with the fix; a fourth checks the helper ([] before set-up, two blocks after). Related suites (multigrid, custom-MG hierarchy, rotated free-slip, MG option bundle, restore/continuation, viscoelastic): 77 passed, no banner. A real notch driver run with a gmsh tail: 1 banner before, 0 after.

Adversarial review. Record in docs/reviews/2026-10/subksp-banner-827-adversarial-review.md. Findings: the plain-path site was untested (fixed, test added); the helper leaked into the uw namespace via a star import (fixed, now private); docstring (fixed); the viscoelastic warning is a behaviour change (kept, stated above). Failed attacks: handler stack restored on every path including KeyboardInterrupt; np 2 and np 4 with no banner and no hang (set-up state follows PCSetUp, run on every rank); _pcmg_still_installed semantics unchanged; the other getFieldSplitSubKSP call sites are all after a setUp, inside a solve, or already guarded; no import cycle.

Not in this PR.

  • petsc_generic_snes_solvers.pyx (_discard_preconditioner_setup) carries an identical copy of the silencing pattern; left alone so the solver core is untouched in a bugfix. A follow-up can route it through the helper.
  • Pre-existing: the fallback warning's stacklevel=3 resolves to memprobe.py, so every solve shares one warning location.
  • Pre-existing, unrelated: test_0017_describe_and_render.py::test_every_family_describes_itself_at_the_class_level fails when test_1057_ddt_transport_plugin.py ran earlier in the same process. test_1057 defines a solver subclass TensorTransport with no summary, and the description test enumerates every subclass.

Checklist (UW3 Style Charter — docs/developer/UW3_STYLE_CHARTER.md)

  • I have read the Style Charter and followed it over the surrounding code (S2)
  • No drive-by refactors, renames, or "while I was here" cleanups (S9)
  • Bug fixes ship the regression test, written first, with level_* and tier_* markers (S8)
  • No hedging names (maybe_ / try_ / do_) and no commented-out code (S3, S4)
  • Every exception swallow states its sanctioned failure mode in a comment (S4)
  • New data access uses .array / mesh.X.coords — no with ....access(...), no mesh.data (S7)
  • Parallel safety considered — np2/np4 checked where swarm/mesh/solver dispatch is touched (S11)
  • No pixi.toml / pixi.lock or other dependency changes riding in an unrelated PR
  • AI-assisted work carries the attribution line below

Underworld development team with AI support from Claude Code

A field split has block solvers only after PCSetUp, and asking earlier is a
PETSc error whose ~38-line banner is printed before the exception reaches
Python, so `except` cannot hide it. Two paths reached it:

- the viscoelastic Stokes solve checked the velocity preconditioner before
  solving (the #827 reproducer);
- the custom-multigrid "still installed?" test, run before each solve, on a
  solver rebuilt by a consistent_jacobian change. Every notch run with a
  non-nested FMG tail printed it.

fieldsplit_sub_ksps(pc) returns the blocks, or [] when there are none yet,
with the banner silenced for that one call by a push/pop of the "return"
handler (it still raises; it does not print). Both sites use it, and the
viscoelastic check moves to after the solve, as on the plain path, so it now
inspects a set-up split instead of always returning early.

test_1077 fails on the unfixed code (two cases) and passes with the fix.

Underworld development team with AI support from Claude Code
- Test the plain-path site: a consistent_jacobian change rebuilds the solver,
  the warm solve meets its tolerance with no linear solve, and the post-solve
  check asked the un-set-up split for its blocks. Fails unfixed (banner).
- The helper is private (_fieldsplit_sub_ksps): _petsc_tools is star-imported
  into the uw namespace.
- Docstring: how it works, with Parameters and Returns.
- Review record.

Behaviour change, by design: a viscoelastic solve on a mesh without a
hierarchy now warns that the velocity block fell back to GAMG and records the
fallback, as a plain solve already did. Before, its pre-solve check always
returned early.

Underworld development team with AI support from Claude Code
Copilot AI balanced review requested due to automatic review settings October 15, 2026 14:54

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.

@github-actions

Copy link
Copy Markdown

🔍 Architectural Review Checklist

Thank you for submitting an architectural review! Reviewers should validate:

Design & Architecture

  • Design rationale is clear and well-justified
  • Trade-offs are documented with alternatives considered
  • System architecture is comprehensible
  • Integration points are clearly identified

Implementation

  • Implementation matches documented design
  • Code quality meets project standards
  • Breaking changes are identified and justified
  • Backward compatibility is properly addressed

Testing & Validation

  • Testing strategy is adequate for the changes
  • Test coverage is sufficient
  • Edge cases are properly covered
  • Performance impact has been assessed

Documentation

  • Known limitations are clearly documented
  • Benefits are quantified with metrics
  • User-facing changes are documented
  • Migration guide provided (if needed)

Review Process: See CODE-REVIEW-PROCESS.md

Approval: This PR merge = Review formally approved

@github-actions

Copy link
Copy Markdown

✅ Test Suite: success

This branch has not been deployed

No deployments
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