Skip to content

TSFC: support same-mesh ufl.Interpolate in Form kernels - #5258

Open
pbrubeck wants to merge 72 commits into
mainfrom
pbrubeck/form-interp-tsfc
Open

TSFC: support same-mesh ufl.Interpolate in Form kernels#5258
pbrubeck wants to merge 72 commits into
mainfrom
pbrubeck/form-interp-tsfc

Conversation

@pbrubeck

@pbrubeck pbrubeck commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Description

  • Support same-mesh Interpolate nodes in normal TSFC Form kernels.
  • Fuse standalone Interpolate and Form(Interpolate) codegen.
  • Corollary: native mat_type="aij" support for same-mesh Interpolation across MixedFunctionSpaces
  • Corollary: interpolation into VertexOnlyMesh also goes through the unified TSFC codegen.
  • Kept cross-mesh interpolation on BaseFormAssembler.

Depends on
firedrakeproject/fiat#294

Comment thread tsfc/modified_terminals.py
Comment thread tsfc/fem.py Outdated
Comment thread tsfc/ufl_utils.py Outdated
Comment thread firedrake/assemble.py Outdated
@pbrubeck
pbrubeck marked this pull request as draft July 16, 2026 11:18
@pbrubeck

Copy link
Copy Markdown
Contributor Author

This PR should reimplement SameMeshInterpolator as a dispatcher to {Zero|One|Two}FormAssembler. We want to unify the TSFC codepaths for Form assembly and same-mesh interpolation.

Comment thread firedrake/assemble.py Outdated
Comment thread firedrake/assemble.py Outdated
Comment thread firedrake/assemble.py
Comment thread firedrake/assemble.py Outdated
Comment thread firedrake/assemble.py Outdated
Comment thread firedrake/assemble.py Outdated
Comment thread firedrake/assemble.py Outdated
Comment thread firedrake/assemble.py
Comment thread firedrake/assemble.py Outdated
Comment thread firedrake/assemble.py Outdated
Comment thread tests/firedrake/regression/test_adjoint_operators.py
Comment thread tsfc/fem.py Outdated
Comment thread demos/plate_bending_mitc/plate_bending_mitc.py.rst Outdated
@pbrubeck
pbrubeck force-pushed the pbrubeck/form-interp-tsfc branch from a844911 to f7f5ee3 Compare July 17, 2026 14:42
Comment thread tsfc/driver.py Outdated
Comment thread firedrake/interpolation.py Outdated
Comment thread tsfc/driver.py Outdated
Comment thread firedrake/interpolation.py Outdated
Comment thread firedrake/assemble.py Outdated
Comment thread demos/plate_bending_mitc/plate_bending_mitc.py.rst Outdated
Comment thread demos/plate_bending_mitc/plate_bending_mitc.py.rst Outdated
@pbrubeck
pbrubeck force-pushed the pbrubeck/form-interp-tsfc branch from 37fe40f to 4cce203 Compare September 10, 2026 16:38
@pbrubeck pbrubeck added the base:main Run this PR using a main (dev) build label Sep 11, 2026
@pbrubeck

pbrubeck commented Sep 12, 2026

Copy link
Copy Markdown
Contributor Author

Commit vs main:

  • 34 files: +1,385 / −1,042 (net +343)
  • Tests: 12 files, +457 / −38 (net +419)
  • Non-tests: 22 files, +928 / −1,004 (net −76)
  • firedrake/interpolation.py: net −224
  • tsfc/fem.py: net +151
  • firedrake/assemble.py: net +112

pbrubeck and others added 4 commits September 13, 2026 01:36
translate_element contracted an interpolation's target basis index where
no assignment variable carries it, so gem.unconcatenate could not split
the Concatenate that a direct sum tabulates into, and compiling a form
over such an interpolation failed in gem.refactorise.  Contract through
split_contraction instead, which splits the contraction itself.

The summands of a direct sum evaluate on points of their own, but
translate_interpolate contracted the union of every summand's points, so
each block picked up a factor of the other blocks' point counts.  Leave
those points free and contract them block by block, once the sum is
split.  test_form_interp_direct_sum covers this: an interpolation into a
nodal space is the identity on that space, which the union of the points
is not.

spectral.flatten ordered the quadrature indices for sum factorisation and
dropped every other sum index, which left the interpolation's basis
contraction dense.  Order the others after the quadrature indices, so
that sum factorisation covers them too.  The flop count of the new test
form then grows as p^5.7 over degrees 3 to 8, rather than p^8, which
tracks the p^5.8 of the same form written without an interpolation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KWajdMc5VFPbPuB1cupu9F
A fused kernel iterates over the cells of the expression that holds it, and a Form takes its subdomain data from its integrals alone, so the subset that a nested Interpolate carries never reaches the parloop iteration set. Fusing an interpolation whose source mesh covers only part of the target therefore read through invalid map entries: submesh cases segfaulted or returned wrong values, and a nested interpolation silently dropped the zero fill of the intermediate space.

Fuse only an interpolation that maps cells to cells and that needs no subset. is_submesh_domain, is_same_mesh_interp and interp_cell_subset state that rule once, and SameMeshInterpolator, Interpolate._interpolator and _domain_is_compatible now share it instead of each restating it.

An interpolation that crosses a codimension no longer fuses, so a trace onto a facet submesh assembles through its own interpolator rather than failing in code generation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016XyPBm8Hscju5UoWM7ojhU
validate_domains now takes a ufl.Interpolate as well as a Form, and
compile_expression_dual_evaluation calls it before it builds anything.
It admits the same mesh, submeshes of one family, and a point cloud
immersed in the source mesh, and raises MismatchingDomainError for any
other pair, which BaseFormAssembler owns. compile_form lowers an
interpolation through compile_expression_dual_evaluation directly.

BaseFormAssembler's visitor selects its assembler through
get_form_assembler rather than repeating the rank dispatch.

One name and one resolver serve the runtime tabulation that both
kernel-argument dispatchers ask for, in place of a configurable prefix
that the Firedrake callers rejected.

get_assembly_entity_node_map serves assembly and interpolation, so the
VertexOnlyMesh map policy no longer has a second copy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xw8suJa8EppFtunEvxQfq8
Comment thread tsfc/fem.py Outdated
Comment on lines +677 to +688
source_mesh = self.source_mesh.unique()
target_mesh = self.target_mesh.unique()
target, source = target_mesh.topology, source_mesh.topology
if target is not source and is_same_dim_submesh(source_mesh, target_mesh):
composed_map, result_integral_type = source.trans_mesh_entity_map(target, "cell", "everywhere", None)
if result_integral_type != "cell":
raise AssertionError("Only cell-cell interpolation supported.")
indices_active = composed_map.indices_active_with_halo
make_subset = not indices_active.all()
make_subset = target.comm.allreduce(make_subset, op=MPI.LOR)
if make_subset:
if not self.allow_missing_dofs:
raise ValueError("Iteration (sub)set unclear: run with `allow_missing_dofs=True`.")
if not target.comm.allreduce(indices_active.all(), op=MPI.LAND):
subset = op2.Subset(target.cell_set, numpy.where(indices_active))
else:
# Do not need subset as target <= source.
pass
if subset is not None and not self.allow_missing_dofs:
raise ValueError("Iteration (sub)set unclear: run with `allow_missing_dofs=True`.")

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.

revert this block

with self._adjoint_weight.vec_ro as weight, self._weighted_dual_arg.dat.vec as dual:
dual.pointwiseMult(dual, weight)

def _get_tensor(self) -> Function:

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.

move before _needs_adjoint_weighting

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.

3 participants