Skip to content

Automated goal-oriented adaptivity - #5273

Open
pbrubeck wants to merge 52 commits into
mainfrom
pbrubeck/goal-adaptive-callback
Open

pbrubeck wants to merge 52 commits into
mainfrom
pbrubeck/goal-adaptive-callback

Conversation

@pbrubeck

@pbrubeck pbrubeck commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Description

Automates dual-weighted residual goal-oriented adaptive mesh refinement.

  • dwr_marking_callback(goal_functional) API.
  • Configuration through prefixed PETSc.Options() keys.
  • Enriched primal/dual solves via _SNESContext.solve_jacobian_transpose(), residual localization, and Dörfler marking.
  • Top-level solve(..., marking_callback=...) forwarding.
  • Demo from Rognes and Logg 2012

Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/dmhooks.py Resolved
Comment thread firedrake/dmhooks.py Resolved
Base automatically changed from pbrubeck/mg-redist to main July 31, 2026 10:37
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/dwr.py Resolved
@pytest.mark.parametrize(
("adapt_option", "criterion"),
(("snes_adapt_sequence", "refine"),
("snes_adapt_multigrid", "none")),

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This requires https://gitlab.com/petsc/petsc/-/merge_requests/9447

Suggested change
("snes_adapt_multigrid", "none")),
# ("snes_adapt_multigrid", "none")),

@pbrubeck
pbrubeck force-pushed the pbrubeck/goal-adaptive-callback branch from 145b3a8 to feae504 Compare July 31, 2026 16:49
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/dmhooks.py Resolved
@pbrubeck
pbrubeck force-pushed the pbrubeck/goal-adaptive-callback branch 2 times, most recently from 9abb66d to 0ca2b28 Compare July 31, 2026 17:44
Comment thread firedrake/dmhooks.py Resolved
Comment thread firedrake/solving_utils.py Resolved
Comment thread firedrake/variational_solver.py Resolved
Comment thread firedrake/variational_solver.py Resolved
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/solving_utils.py Resolved
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/variational_solver.py Resolved
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/dwr.py Resolved
Comment thread firedrake/dwr.py Outdated
nullspace = None if ctx._nullspace is None else ctx._nullspace.rediscretise(high_space)
transpose_nullspace = None if ctx._nullspace_T is None else ctx._nullspace_T.rediscretise(high_space)
near_nullspace = None if ctx._near_nullspace is None else ctx._near_nullspace.rediscretise(high_space)
parameters = get_default_options(DefaultOptionSet(prefix, ("dwr_",)))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Josh and Pablo to work out what this means.

Comment thread firedrake/dwr.py Outdated
Comment on lines +298 to +302
parameters = get_default_options(DefaultOptionSet(prefix, ("dwr_",)))
parameters.pop("snes_adapt_sequence", None)
primal_solver = NonlinearVariationalSolver(
high_problem,
options_prefix=prefix + "dwr_enriched_",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The prefixes between the default options set and the specific solver should be consistent.
Either:

Suggested change
parameters = get_default_options(DefaultOptionSet(prefix, ("dwr_",)))
parameters.pop("snes_adapt_sequence", None)
primal_solver = NonlinearVariationalSolver(
high_problem,
options_prefix=prefix + "dwr_enriched_",
parameters = get_default_options(DefaultOptionSet(prefix, ("dwr_enriched_",)))
parameters.pop("snes_adapt_sequence", None)
primal_solver = NonlinearVariationalSolver(
high_problem,
options_prefix=prefix + "dwr_enriched_",

or

Suggested change
parameters = get_default_options(DefaultOptionSet(prefix, ("dwr_",)))
parameters.pop("snes_adapt_sequence", None)
primal_solver = NonlinearVariationalSolver(
high_problem,
options_prefix=prefix + "dwr_enriched_",
parameters = get_default_options(DefaultOptionSet(prefix, ("dwr_",)))
parameters.pop("snes_adapt_sequence", None)
primal_solver = NonlinearVariationalSolver(
high_problem,
options_prefix=prefix + "dwr_",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I changed the common prefix to goal_ because DWR is too obscure (now the PR does not mention DWR).

There are a couple other solvers (goal_cell_ and goal_facet_, projectors) under this common prefix. Therefore, I cannot take your suggestion.

pbrubeck and others added 7 commits October 6, 2026 17:13
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The marker is now a single object that every refined solver context
shares. On each call it moves its goal functional and exact solution to
the current mesh through the coefficient mapping of the refined context,
and it appends a GoalEstimate to its estimates history. Each estimate
records the number of degrees of freedom, the goal, the discretisation
and solver errors, and the true error and effectivity index when the
exact solution is known.

The marker reads its options from the prefix of the shared SNES, so it
holds no options prefix of its own. This removes the
GoalOrientedMarker.reconstruct method, its _reconstruct hook in
mg/ufl_utils.py, and NonlinearVariationalSolver.get_marking_callback.

Move the solve_jacobian tests to test_solving_interface.py, and define
forms and keyword argument values on separate lines in the tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pbrubeck
pbrubeck force-pushed the pbrubeck/snes-weakref branch from 255fc03 to 0c52bdc Compare October 9, 2026 09:55
@pbrubeck
pbrubeck removed this pull request from stack #5444 October 9, 2026 09:55
Base automatically changed from pbrubeck/snes-weakref to main October 9, 2026 17:38
pbrubeck and others added 6 commits October 11, 2026 15:38
# Conflicts:
#	firedrake/solving_utils.py
#	tests/firedrake/multigrid/test_snes_adapt.py
The adjoint of a NonlinearVariationalSolveBlock is solved as a linear
system, with keyword arguments copied from the forward solver. The
linear solve rejects the callbacks of the forward solver, so the
Hessian of a functional failed with "Illegal keyword argument" for a
solver with a marking_callback or a pre/post Jacobian or function
callback. These callbacks are now removed together with the appctx.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Remove goal_test_derivative_order, goal_enriched_family and the
  biharmonic test. The DWR indicators use one cell solve and one facet
  solve.
- Mark cells with eta_K >= fraction * max eta, without sorting, as in the
  adaptive multigrid demo.
- Use snes.getSolution() as the work vector, as in #5498. This requires
  PETSc !9704.
- check_convergence raises when the SNES fails and its KSP converged.
- Revert the transform type guard: inserted_options with an empty prefix
  already keeps a value that the user set.
- Rewrite the docstrings, comments and goal-oriented tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
!9704 is based on the PETSc release branch, so it also includes !9672
and !9673.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pbrubeck
pbrubeck force-pushed the pbrubeck/goal-adaptive-callback branch from d478d4b to 4d41c8f Compare October 15, 2026 08:30

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

base:main Run this PR using a main (dev) build LLM used An LLM was used in the production of this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants