You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
preconditioner="auto" / "fmg" is documented as giving geometric multigrid whenever the mesh carries a refinement hierarchy. For the Stokes velocity block it does. For every single-field solver — Poisson, Darcy, AdvDiffusionSLCN, Projection, SNES_Vector — it never does, at any refinement depth, even when asked for explicitly.
Measured, off the live PC after setup
solver
mesh
preconditioner=
live PC
Stokes
no hierarchy
auto
gamg
Stokes
refinement=1
auto
mg(2)
Stokes
refinement=2
auto
mg(3)
Poisson
no hierarchy
auto
gamg
Poisson
refinement=1
auto
gamg
Poisson
refinement=1
fmg (explicit)
gamg + warning
Poisson
refinement=2
fmg (explicit)
gamg + warning
Repro: ~/+Simulations/rotated_pmat_audit/fmg_gate_audit.py. It reads the live PC rather than the options database, because the gate leaves no trace in the options — the bundle is simply never written.
This is the #276 lockout, and it is not a bug: PETSc's DMCreateInjection fails at solve time with err62 (Could not locate matching functional for injection) on curved shells and some flat high-degree cases, so rather than let users hit that, the native route is closed for single-field solvers. #276 was closed on that basis, with custom_mg.set_custom_fmg() as the documented way around it.
Why it is worth reopening as a routing question
The workaround is real but it is opt-in, per-solver, and requires the user to build a coarse-mesh tail by hand — for a mesh that already carries one as mesh.dm_hierarchy. So the situation is: the hierarchy exists, geometric MG would work on it, the machinery to use it exists, and the user gets algebraic multigrid unless they know to go and wire it up themselves. On a scalar Poisson over a refined box, custom-P geometric MG converges in 1–3 iterations against GAMG's 13 (measured in custom_mg's own module docstring).
It is also silent in the direction that matters. preconditioner="auto" gives no warning at all — only the explicit "fmg" request warns. Anyone who set up a refined mesh expecting geometric multigrid on their advection–diffusion or projection solve has been running GAMG.
Proposed fix
Route single-field solvers to custom-P instead of falling back to GAMG, using the machinery that already exists:
mesh.dm_hierarchy is exactly a coarse tail — the same shape set_custom_fmg takes;
barycentric/RBF transfers with Galerkin RAP coarse operators need no injection anywhere, which is precisely what dodges err62;
Concretely, in _apply_preconditioner_options, for prefix == "" with n_levels > 1: register a CustomMGHierarchy built from the DMPlex levels rather than setting want_fmg = False. The existing solve-time hook (auto_inject_custom_mg) then installs it with no further change, and the warning can go.
Worth checking as part of it: this looks like it subsumes #425 (use the nested hierarchy for MG transfers on adapt children) — same source of levels, same transfer question.
Scope
This is a behavioural change to a default across every scalar and vector solver, so it wants its own PR and its own validation: the scalar suites, the adaptivity suites, and np2/np4. It is not a rider on #471.
#471 does not fix this, deliberately — the gate is a routing decision (which route a solver may take), not an option value, so it was kept out of the shared option-bundle owner. What #471 does change is the quality of the escape hatch: set_custom_fmg() on a single-field solver previously installed a drifted bundle (richardson at an iteration count nobody set), and now installs the same bundle as every other route. So single-field geometric MG got better where it was already reachable; it did not become reachable.
Found while auditing what #471 does and does not close, prompted by a note from a parallel session that geometric FMG is gated off.
Underworld development team with AI support from Claude Code
preconditioner="auto"/"fmg"is documented as giving geometric multigrid whenever the mesh carries a refinement hierarchy. For the Stokes velocity block it does. For every single-field solver —Poisson,Darcy,AdvDiffusionSLCN,Projection,SNES_Vector— it never does, at any refinement depth, even when asked for explicitly.Measured, off the live PC after setup
preconditioner=gamgmg(2)mg(3)gamggamggamg+ warninggamg+ warningRepro:
~/+Simulations/rotated_pmat_audit/fmg_gate_audit.py. It reads the live PC rather than the options database, because the gate leaves no trace in the options — the bundle is simply never written.Cause
SolverBaseClass._apply_preconditioner_options:This is the #276 lockout, and it is not a bug: PETSc's
DMCreateInjectionfails at solve time with err62 (Could not locate matching functional for injection) on curved shells and some flat high-degree cases, so rather than let users hit that, the native route is closed for single-field solvers. #276 was closed on that basis, withcustom_mg.set_custom_fmg()as the documented way around it.Why it is worth reopening as a routing question
The workaround is real but it is opt-in, per-solver, and requires the user to build a coarse-mesh tail by hand — for a mesh that already carries one as
mesh.dm_hierarchy. So the situation is: the hierarchy exists, geometric MG would work on it, the machinery to use it exists, and the user gets algebraic multigrid unless they know to go and wire it up themselves. On a scalar Poisson over a refined box, custom-P geometric MG converges in 1–3 iterations against GAMG's 13 (measured incustom_mg's own module docstring).It is also silent in the direction that matters.
preconditioner="auto"gives no warning at all — only the explicit"fmg"request warns. Anyone who set up a refined mesh expecting geometric multigrid on their advection–diffusion or projection solve has been running GAMG.Proposed fix
Route single-field solvers to custom-P instead of falling back to GAMG, using the machinery that already exists:
mesh.dm_hierarchyis exactly a coarse tail — the same shapeset_custom_fmgtakes;custom_mg.build_transfers(added in One owner for the geometric-MG option bundle; rotated free-slip picks up a mesh-owned hierarchy (#468, #467) #471) is already the single "which hierarchy does this solver get?" rule, with the opportunistic barycentric→RBF fallback and degrade-to-GAMG on failure, so a build that does not work still cannot crash a solve.Concretely, in
_apply_preconditioner_options, forprefix == ""withn_levels > 1: register aCustomMGHierarchybuilt from the DMPlex levels rather than settingwant_fmg = False. The existing solve-time hook (auto_inject_custom_mg) then installs it with no further change, and the warning can go.Worth checking as part of it: this looks like it subsumes #425 (use the nested hierarchy for MG transfers on adapt children) — same source of levels, same transfer question.
Scope
This is a behavioural change to a default across every scalar and vector solver, so it wants its own PR and its own validation: the scalar suites, the adaptivity suites, and np2/np4. It is not a rider on #471.
Relationship to #471
#471 does not fix this, deliberately — the gate is a routing decision (which route a solver may take), not an option value, so it was kept out of the shared option-bundle owner. What #471 does change is the quality of the escape hatch:
set_custom_fmg()on a single-field solver previously installed a drifted bundle (richardson at an iteration count nobody set), and now installs the same bundle as every other route. So single-field geometric MG got better where it was already reachable; it did not become reachable.Found while auditing what #471 does and does not close, prompted by a note from a parallel session that geometric FMG is gated off.
Underworld development team with AI support from Claude Code