PCPatch: support exterior facet integrals#4878
PCPatch: support exterior facet integrals#4878miguelcoolchips wants to merge 11 commits intofiredrakeproject:mainfrom
Conversation
|
A significant proportion of the changes in this PR are just reformatting. This makes it quite difficult to identify and review the actual changes. |
You are right. Do you know if Firedrake has formatting rules? I could not see such a thing in the pyproject.toml file PS: I changed this PR to draft until the PETSc MR has been merged |
Thanks! If you run |
The formatting/linting is detailed in the contributing guide. https://www.firedrakeproject.org/contribute.html#pre-submission-checklist |
This PR has been formatted |
| # Solve with a direct solver for reference | ||
| u_direct = Function(V) | ||
| problem = LinearVariationalProblem(a, L, u_direct) | ||
| direct = LinearVariationalSolver(problem, solver_parameters={"ksp_type": "preonly", "pc_type": "lu"}) |
There was a problem hiding this comment.
Could this test take ASMStarPC solver parameters and assert that both solvers take the same number of iterations?
Co-authored-by: Pablo Brubeck <brubeck@protonmail.com>
Co-authored-by: Pablo Brubeck <brubeck@protonmail.com>
…rectly
PCPatch passes all facets "exterior to the patch" (including patch-boundary
interior facets) to the exterior facet callback. The previous code mapped
these via point2facetnumber without bounds-checking, causing:
- Wrong operator contributions from patch-boundary interior facets
(mapped to garbage indices or -1 treated as valid)
- Out-of-bounds access (SIGSEGV) in parallel where interior facet plex
point indices exceed the size of point2facetnumber
Fixes:
1. Build an extended point2facetnumber array of size fEnd (covering all
facet plex points), initialised to -1, then fill in valid exterior facet
indices. This prevents OOB access in parallel.
2. In the C wrappers (ComputeResidual/ComputeJacobian), filter both the
facet index array (whichPoints) and the corresponding DOF rows (dofArray)
together, keeping only entries that map to genuine global exterior facets
(point2facetnumber >= 0). Previously only whichPoints was filtered,
misaligning it with dofArray.
Update test_patch_pc_exterior_facets to compare iteration counts against
ASMStarPC (as suggested by reviewer @pbrubeck), split into two functions:
- test_patch_pc_exterior_facets_dx_ds: parallel([1,3]), tests ds only
- test_patch_pc_exterior_facets_dx_dS_ds: serial only (parallel interior
facet counts diverge between ASMStarPC/PatchPC, a pre-existing limitation)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Build point2facetnumber with size fEnd (covering all facet plex points on the rank) instead of max(facets)+1. This ensures that when PCPatch passes patch-boundary interior facets to the exterior facet callback (as they are "exterior to the patch"), they map to -1 rather than causing an out-of-bounds access in parallel. This makes the exterior facet handling in PatchPC identical to the interior facet case, removing the need for the previously introduced ad-hoc extended array in patch.py. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
getDepthStratum(1) gives edges in 2D but cells in 1D, so its fEnd is too small for 1D meshes where facets are vertices at depth 0. Use dm.getChart() instead to get pEnd, which covers all entity types and ensures any valid plex point index is within the array bounds. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
connorjward
left a comment
There was a problem hiding this comment.
Thanks. I think I am now happy with the implementation. @pbrubeck are the tests reasonable?
This PR was generated by AI and it depends on this PETSc MR: https://gitlab.com/petsc/petsc/-/merge_requests/9024 (merged)
Summary
PatchPC currently supports cell integrals (dx) and interior facet integrals (dS), but raises NotImplementedError when a form contains exterior facet integrals (ds). This PR extends PatchPC to handle exterior_facet integral types, enabling problems that involve boundary integrals -- such as DG formulations with boundary flux terms or Nitsche weak boundary conditions -- to be solved with patch-based preconditioners.
Motivation
Many finite element formulations naturally produce exterior facet integrals. For example:
Previously, any such form passed to PatchPC would fail with:
This blocked the use of
PatchPC(including Vanka relaxation in multigrid) for an important class of problems.Changes
firedrake/preconditioners/patch.pymatrix_funptrandresidual_funptr: Extended to accept"exterior_facet"as a valid integral type. Exterior facet kernels are accumulated into a newext_facet_kernelslist and returned alongside cell and interior facet kernels. When the integral type is"exterior_facet", the exterior facet local numbering dat (mesh.exterior_facets.local_facet_dat) is appended to the kernel arguments.make_c_arguments: Extended therequire_facet_numberlogic to handle"exterior_facet"integrals, usingmesh.exterior_facets.local_facet_dat._kernel_args_andmesh.exterior_facets.point2facetnumber.PatchBase.initialize: Cell, interior facet, and exterior facet kernel setup is now conditional on the respective kernel lists being non-empty, rather than assuming a cell kernel always exists. For exterior facet kernels, the method builds the C wrapper, compiles the callback function, constructs thectypesstruct (withpoint2facetfrommesh.exterior_facets.point2facetnumber), and registers the callback viaset_patch_jacobian(..., exterior_facets=True)andset_patch_residual(..., exterior_facets=True).firedrake/cython/patchimpl.pyxexterior_facets=Falseparameter toset_patch_residualandset_patch_jacobian.elif exterior_facets:branches that call the new PETSc API functionsPCPatchSetComputeOperatorExteriorFacetsandPCPatchSetComputeFunctionExteriorFacets.firedrake/cython/petschdr.pxiPCPatchSetComputeOperatorExteriorFacetsandPCPatchSetComputeFunctionExteriorFacets.tests/firedrake/regression/test_patch_pc.pytest_patch_pc_exterior_facets, parametrized over"dx_and_ds"and"dx_dS_and_ds"integral combinations. Each case solves a DG(1) problem on aUnitSquareMeshwith both a direct LU solver andPatchPC(star patches, vertex-centered), then asserts the solutions match to withinatol=1e-8.Dependencies
This PR requires a corresponding PETSc change that adds:
PCPatchSetComputeOperatorExteriorFacetsandPCPatchSetComputeFunctionExteriorFacetsAPI functionsextFacetsToPatchCellindex set in thePC_PATCHstruct for mapping exterior facets to their owning cell within each patchTest plan
test_patch_pc_exterior_facets[dx_and_ds]-- DG problem withdx + dsintegrals, PatchPC matches direct solvertest_patch_pc_exterior_facets[dx_dS_and_ds]-- DG problem withdx + dS + dsintegrals, PatchPC matches direct solvertest_jacobi_sor_equivalencetests continue to pass (cell-only and interior facet paths unchanged)The following snippet shows the feature working on a Stokes problem with Nitsche boundary conditions
Output