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
{{ message }}
Repository navigation
preconditioner="fmg" is inert on the semi-Lagrangian solvers: their solve() pre-runs setup and skips the base _build resolution #683
The base _build is where a solver's preconditioner choice is resolved against the mesh hierarchy (_apply_preconditioner_options), before snes.setFromOptions() reads the option bundle. The semi-Lagrangian solvers (AdvDiffusion, and the other solvers.py solvers on the same pattern) run the three setup stages directly inside their own solve():
_setup_solver ends with self.is_setup = True, so the super().solve() that follows enters _build, hits if self.is_setup: return, and the resolution never runs. _pc_resolved stays False and nothing is recorded in pc_fallbacks.
Measured (feature/levelset-supg, amr-dev), a structured quad box with refinement=2 (three levels), AdvDiffusion with preconditioner = "fmg", one solve:
The request is silently ignored: GAMG stays live, no warning, no record. preconditioner = "gamg" looks correct only because GAMG is what the scalar base pushes in __init__.
The Eulerian SUPG solver (#673) had the same pattern and the same symptom; it now builds through self._build(verbose) in place of the three calls, which is the one-line fix. The same change applies to each solve() in systems/solvers.py that pre-runs the stages (lines around 857, 1103, 1695 at 417f7b8). The pre-run exists so that update_pre_solve sees a built solver, but the history update needs the field, not the SNES, so the order can stay as it is.
Underworld development team with AI support from Claude Code
and _apply_preconditioner_options does not appear in solvers.py at all — it lives only in the base class (petsc_generic_snes_solvers.pyx:252-287), whose own comments say it "runs on EVERY _build" and is where "the resolution decision" is made. The semi-Lagrangian path never reaches _build, so preconditioner="fmg" is still inert there.
Worth noting the contrast at solvers.py:1719: the Stokes-family path runs the same three stages and_check_velocity_preconditioner(), so it at least reports a fallback. The SL path does neither — it neither resolves the choice nor says it ignored one.
Checked in the untouched-issue triage (33 days, no activity).
Activity
Match the Krylov tolerance to the SNES tolerance, and make preconditi…
Navier-Stokes with Eulerian SUPG momentum transport, and a partition-…
lmoresi commentedon Oct 7, 2026
Confirmed live on
development(f4c19cf2).solvers.py:1127still runs the three setup stages directly inside the semi-Lagrangiansolve():and
_apply_preconditioner_optionsdoes not appear insolvers.pyat all — it lives only in the base class (petsc_generic_snes_solvers.pyx:252-287), whose own comments say it "runs on EVERY_build" and is where "the resolution decision" is made. The semi-Lagrangian path never reaches_build, sopreconditioner="fmg"is still inert there.Worth noting the contrast at
solvers.py:1719: the Stokes-family path runs the same three stages and_check_velocity_preconditioner(), so it at least reports a fallback. The SL path does neither — it neither resolves the choice nor says it ignored one.Checked in the untouched-issue triage (33 days, no activity).