Automated goal-oriented adaptivity - #5273
Open
pbrubeck wants to merge 5 commits into
Open
Conversation
pbrubeck
commented
Jul 22, 2026
pbrubeck
commented
Jul 24, 2026
pbrubeck
commented
Jul 24, 2026
pbrubeck
commented
Jul 28, 2026
pbrubeck
commented
Jul 31, 2026
pbrubeck
commented
Jul 31, 2026
pbrubeck
commented
Jul 31, 2026
pbrubeck
commented
Jul 31, 2026
pbrubeck
commented
Jul 31, 2026
Comment on lines
+69
to
+71
| f"dwr_{kind}_{key}": value | ||
| for kind in ("cell", "facet") | ||
| for key, value in {"ksp_type": "cg", "pc_type": "jacobi"}.items() |
Contributor
Author
There was a problem hiding this comment.
don't use dict comprehensions or f-strings, these need to be human readable.
pbrubeck
commented
Jul 31, 2026
Comment on lines
+52
to
+54
| geo = SplineGeometry() | ||
| geo.AddRectangle((0, 0), (1, 1), bc="boundary") | ||
| mesh = Mesh(geo.GenerateMesh(maxh=0.5)) |
Contributor
Author
There was a problem hiding this comment.
use UnitSquareMesh
pbrubeck
commented
Jul 31, 2026
| @pytest.mark.parametrize( | ||
| ("adapt_option", "criterion"), | ||
| (("snes_adapt_sequence", "refine"), | ||
| ("snes_adapt_multigrid", "none")), |
Contributor
Author
There was a problem hiding this comment.
This requires https://gitlab.com/petsc/petsc/-/merge_requests/9447
Suggested change
| ("snes_adapt_multigrid", "none")), | |
| # ("snes_adapt_multigrid", "none")), |
pbrubeck
force-pushed
the
pbrubeck/goal-adaptive-callback
branch
from
July 31, 2026 16:49
145b3a8 to
feae504
Compare
pbrubeck
commented
Jul 31, 2026
pbrubeck
commented
Jul 31, 2026
pbrubeck
force-pushed
the
pbrubeck/goal-adaptive-callback
branch
2 times, most recently
from
July 31, 2026 17:44
9abb66d to
0ca2b28
Compare
pbrubeck
commented
Jul 31, 2026
pbrubeck
commented
Jul 31, 2026
pbrubeck
commented
Jul 31, 2026
pbrubeck
commented
Jul 31, 2026
pbrubeck
commented
Aug 1, 2026
pbrubeck
commented
Aug 1, 2026
pbrubeck
commented
Aug 1, 2026
pbrubeck
commented
Aug 3, 2026
pbrubeck
commented
Aug 3, 2026
pbrubeck
commented
Aug 3, 2026
pbrubeck
commented
Aug 3, 2026
Comment on lines
+317
to
+318
| def solve_jacobian_transpose(self, rhs: Cofunction, | ||
| solution: Function) -> None: |
Contributor
Author
There was a problem hiding this comment.
Where should this function live?
- NonlinearVariationalSolver: exposes it to the user, needs adjoint
- _SNESContext: too obscure to be useful to a user
- DWRMarkingCallback: prevents code reusability
pbrubeck
commented
Aug 3, 2026
pbrubeck
commented
Aug 3, 2026
pbrubeck
commented
Aug 3, 2026
pbrubeck
commented
Aug 3, 2026
pbrubeck
commented
Aug 3, 2026
pbrubeck
commented
Aug 3, 2026
pbrubeck
commented
Aug 3, 2026
pbrubeck
commented
Aug 3, 2026
Comment on lines
+335
to
+337
| if b.norm() == 0: | ||
| x.set(0) | ||
| return |
Contributor
Author
There was a problem hiding this comment.
Suggested change
| if b.norm() == 0: | |
| x.set(0) | |
| return |
pbrubeck
commented
Aug 3, 2026
| if self.snes.getDM() != solution_dm: | ||
| # DMAdaptorAdapt() consumed a reference to work, which the | ||
| # adapted-away DM keeps as its template global vector. | ||
| work.incRef() |
Contributor
Author
There was a problem hiding this comment.
isn't better to destroy the work Vec?
pbrubeck
commented
Aug 3, 2026
| second_goal = assemble(solver.get_goal_functional()) | ||
|
|
||
| assert first_dim > old_dim | ||
| assert isinstance(first_goal, float) |
pbrubeck
force-pushed
the
pbrubeck/goal-adaptive-callback
branch
from
August 4, 2026 08:45
64c97c5 to
4a95b41
Compare
pbrubeck
force-pushed
the
pbrubeck/goal-adaptive-callback
branch
from
August 4, 2026 14:33
4a95b41 to
de30e69
Compare
pbrubeck
commented
Aug 5, 2026
Comment on lines
+61
to
+62
| + dot(div(sigma), v) | ||
| + dot(u, div(tau)) |
Contributor
Author
There was a problem hiding this comment.
Suggested change
| + dot(div(sigma), v) | |
| + dot(u, div(tau)) | |
| + inner(div(sigma), v) | |
| + inner(u, div(tau)) |
pbrubeck
commented
Aug 5, 2026
Comment on lines
+63
to
+65
| + (sigma[0, 1] - sigma[1, 0])*eta | ||
| + gamma*(tau[0, 1] - tau[1, 0]) | ||
| )*dx - dot(body_force, v)*dx - dot(u0, dot(tau, n))*ds |
Contributor
Author
There was a problem hiding this comment.
Suggested change
| + (sigma[0, 1] - sigma[1, 0])*eta | |
| + gamma*(tau[0, 1] - tau[1, 0]) | |
| )*dx - dot(body_force, v)*dx - dot(u0, dot(tau, n))*ds | |
| + inner(sigma[0, 1] - sigma[1, 0], eta) | |
| + inner(gamma, tau[0, 1] - tau[1, 0]) | |
| )*dx - inner(body_force, v)*dx - inner(u0, dot(tau, n))*ds |
DWRMarkingCallback estimates the dual-weighted-residual error indicator
for a user-supplied goal functional and turns it into the DG0 marker
Function that NonlinearVariationalSolver's existing marking-callback
adaptive-refinement machinery expects, so goal-oriented mesh adaptivity
is driven the same way as any other marking callback.
Estimating the DWR indicator needs a dual (adjoint) solve on an enriched
space, and a primal solve's Jacobian is symmetric only in specific cases,
so _SNESContext grows solve_jacobian_transpose() to solve the dual
problem against the transposed primal Jacobian. Finding "the" ksp behind
solve_jacobian_transpose() and PMG's/adaptive-refinement's reconstructed
_SNESContexts is unreliable via a weakref carried across every
reconstruct() call (PETSc returns a fresh Python wrapper on every
getKSP()/getDM(), and the weakref has to be explicitly re-attached each
time); composing it directly on the DM instead (dm.setAttr("_ksp", ksp))
survives reconstruction for free since PETSc's attribute compose/query
operates on the underlying PetscObject. _refine_adaptive() carries the
composed ksp forward onto each newly-refined DM, alongside the
parent/ctx-coarsener/appctx propagation it already does.
NonlinearVariationalSolver.set_marking_callback() now recognises a
DWRMarkingCallback and runs its setup() against the primal solution and
options prefix; get_goal_functional() exposes the (possibly-adapted)
goal functional for inspection after solve().
Also along the way:
- add_hooks/SetupHooks now record the appctx a saved hook stack was
built for and only replay it when the current appctx matches. Adaptive
refinement replaces the appctx on every adapted solve, so replaying a
stale hook stack anchored the DM chain on an already-torn-down root DM
and surfaced as PETSc error 101 out of DMRefine() on a solver's second
solve().
- NonlinearVariationalSolver.solve() no longer caches its PETSc work
vector across calls (the problem may have been reconstructed onto an
adapted mesh since the last solve) and incRef()s it whenever
DMAdaptorAdapt() has swapped the solution DM out from under the solve,
since DMAdaptorAdapt() steals a reference to it as the adapted-away
DM's template global vector; without the extra ref a second collection
of the same vector double-frees it and segfaults the interpreter.
- _refine_adaptive() snaps to solution_mesh.unique() and, for a
MeshSequenceGeometry, calls set_hierarchy() after adding the refined
mesh, so goal-oriented adaptivity works on mesh sequences too.
Walks through DWRMarkingCallback on a Poisson problem: setting a goal functional, attaching the callback to a solver via set_marking_callback(), and inspecting the adapted mesh and goal value after solve().
pbrubeck
force-pushed
the
pbrubeck/goal-adaptive-callback
branch
from
August 6, 2026 09:20
378d836 to
44b9ce1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Automates dual-weighted residual goal-oriented adaptive mesh refinement.
dwr_marking_callback(goal_functional)API.PETSc.Options()keys._SNESContext.solve_jacobian_transpose(), residual localization, and Dörfler marking.solve(..., marking_callback=...)forwarding.