Evaluate interpolations on the reference cell in compute_form_data - #512
Merged
jorgensd merged 5 commits intoSep 11, 2026
Merged
Conversation
pbrubeck
added a commit
to firedrakeproject/firedrake
that referenced
this pull request
Sep 8, 2026
TSFC mapped an interpolation's operand onto the target element's reference cell in a pass of its own, run before compute_form_data, and carried its own copy of the inverse Piola maps to do it. UFL does both now, so this deletes apply_mapping, InterpolatePullbackApplier and the pre-pass in the driver, and preprocess_interpolate calls ufl.apply_inverse_pullback for the standalone case. Needs FEniCS/ufl#511 and FEniCS/ufl#512. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155wQMTMSGiF9a6TbyTVK5P
pbrubeck
added a commit
to firedrakeproject/firedrake
that referenced
this pull request
Sep 8, 2026
pbrubeck/interpolate-reference-lowering is pbrubeck/interpolate-holes plus FEniCS/ufl#511 and FEniCS/ufl#512. Revert to the plain companion branch once those merge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155wQMTMSGiF9a6TbyTVK5P
This was referenced Sep 8, 2026
pbrubeck
force-pushed
the
pbrubeck/interpolate-reference-lowering
branch
from
September 8, 2026 10:51
df1414a to
336fa7a
Compare
pbrubeck
added a commit
to firedrakeproject/firedrake
that referenced
this pull request
Sep 9, 2026
TSFC mapped an interpolation's operand onto the target element's reference cell in a pass of its own, run before compute_form_data, and carried its own copy of the inverse Piola maps to do it. UFL does both now, so this deletes apply_mapping, InterpolatePullbackApplier and the pre-pass in the driver, and preprocess_interpolate calls ufl.apply_inverse_pullback for the standalone case. Needs FEniCS/ufl#511 and FEniCS/ufl#512. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155wQMTMSGiF9a6TbyTVK5P
pbrubeck
added a commit
to firedrakeproject/firedrake
that referenced
this pull request
Sep 9, 2026
This PR needs firedrakeproject/fiat#261 and the UFL work in FEniCS/ufl#511 and FEniCS/ufl#512, none of which has merged, so CI installs both branches over the pins in pyproject.toml. Drop this commit once they land; nothing else on the branch touches .github. The step runs after Firedrake is installed, so that resolving its dependencies cannot pull fenics-ufl back from FEniCS/ufl@main over the branch, and calls firedrake-clean so no kernel cached against the released UFL survives. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
pbrubeck
added a commit
to firedrakeproject/firedrake
that referenced
this pull request
Sep 9, 2026
This PR needs firedrakeproject/fiat#261 and the UFL work in FEniCS/ufl#511 and FEniCS/ufl#512, none of which has merged, so CI installs both branches over the pins in pyproject.toml. Drop this commit once they land; nothing else on the branch touches .github. The step runs after Firedrake is installed, so that resolving its dependencies cannot pull fenics-ufl back from FEniCS/ufl@main over the branch, and calls firedrake-clean so no kernel cached against the released UFL survives. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
pbrubeck
added a commit
to firedrakeproject/firedrake
that referenced
this pull request
Sep 9, 2026
This PR needs firedrakeproject/fiat#261 and the UFL work in FEniCS/ufl#511 and FEniCS/ufl#512, none of which has merged, so CI installs both branches over the pins in pyproject.toml. Drop this commit once they land; nothing else on the branch touches .github. Both installs sit inside the 'Install Firedrake' step, ahead of the Firedrake install rather than after it: that step ends with firedrake-clean, which imports Firedrake, and Firedrake cannot be imported against the released UFL. A step of its own after the install therefore never gets to run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
pbrubeck
added a commit
to firedrakeproject/firedrake
that referenced
this pull request
Sep 10, 2026
This PR needs firedrakeproject/fiat#294 and the UFL work in FEniCS/ufl#511 and FEniCS/ufl#512, none of which has merged, so CI installs both branches over the pins in pyproject.toml. Drop this commit once they land; nothing else on the branch touches .github. Both installs sit inside the Install Firedrake step, ahead of the Firedrake install rather than after it: that step ends with firedrake-clean, which imports Firedrake, and Firedrake cannot be imported against the released dependencies. A step of its own after the install therefore never gets to run.
pbrubeck
force-pushed
the
pbrubeck/interpolate-reference-lowering
branch
2 times, most recently
from
September 10, 2026 23:40
6cdee45 to
ea2bddd
Compare
A form compiler evaluates an Interpolate on the reference cell of its target element, so the operand has to be mapped there and the result pulled back for the integrand that holds it. TSFC did this in a pass of its own, before it called compute_form_data, and carried its own copy of the inverse maps. apply_interpolate_pullbacks does it here, at the start of compute_form_data and under the same switch as the other pull backs, on top of the pull backs' apply_inverse. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155wQMTMSGiF9a6TbyTVK5P
Both interpolation pull back passes were the older MultiFunction style, while the rest of the algorithms package has moved to DAGTraverser. InterpolatePullbackApplier becomes a DAGTraverser, with the Interpolate rule a postorder handler, and apply_interpolate_pullbacks maps it over the integrands directly, as the traverser walks the DAG itself. apply_inverse_pullback keeps its signature for TSFC and now wraps InversePullbackApplier, which carries the element and the fallback domain as traverser state. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BP8aGcL37egqaMX9zXAYgX
FunctionPullbackApplier was the last MultiFunction in the module, so it joins the interpolation pass as a DAGTraverser: the form argument rule dispatches on FormArgument and the traverser's own memoisation replaces memoized_handler. apply_inverse_pullback goes back to being a plain function. It is a rule on a single node, not a traversal: it must not recurse into its argument, or the interpolations there would be lowered a second time by the pass that runs after it. Wrapping it in a traverser only hid that. The two traversers are separate passes because compute_form_data runs them at different points, with derivative expansion and degree estimation in between. Neither pass had tests. test_apply_function_pullbacks covers the pull back of form arguments in a form, the round trip of apply_inverse_pullback against each pull back (through cancel_jacobian_products, which cancels the Jacobian factors the two maps insert), its shape and domain checks, and the lowering of plain, nested and in-form interpolations. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
FormArgument itself declares neither ufl_function_space nor ufl_element, so annotating the handler with it fails mypy. Its subclasses Argument and Coefficient are what actually reach the rule, and both carry them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
pbrubeck
force-pushed
the
pbrubeck/interpolate-reference-lowering
branch
from
September 11, 2026 08:35
6ad84df to
fcd6122
Compare
jorgensd
approved these changes
Sep 11, 2026
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
A form compiler evaluates an
Interpolateon the reference cell of its target element. The operand therefore has to be mapped to that reference cell, and the result pulled back to the physical cell for the integrand that holds it. TSFC did that in a pass of its own, run just before it calledcompute_form_data, and carried its own copy of the inverse Piola maps to do it.This moves the step into UFL:
apply_inverse_pullback(expr, element, domain)maps a physical expression onto an element's reference cell, checking the shape on the way in and out. It is the inverse of whatFunctionPullbackApplierdoes to a form argument, and it is TSFC'sapply_mappingwith the maps themselves replaced bypullback.apply_inverse.InterpolatePullbackApplierrewrites eachInterpolatein an integrand, andapply_interpolate_pullbacksmaps it over a form.compute_form_dataruns it at the start, underdo_apply_function_pullbacks, so the operand a form compiler sees is the one the target element dual-evaluates. It runs before the other lowering, which is where TSFC's own pass ran, so the estimated degrees and everything downstream see the same form they see today.The node is built as a
ufl.Interpolaterather than by reconstructing the one in the integrand, because the mapped operand no longer has the physical value shape that a subclass may check.Stacking
Based on #71, which gives the pull backs their
apply_inverse, which in turn is based onpbrubeck/interpolate-holes(#497), whereInterpolate.ufl_elementcomes from.Those are the same branches as #511 and #512, which propose the same two commits upstream against
main.Firedrake's side of the move — deleting
apply_mapping,InterpolatePullbackApplierand the pre-pass intsfc/driver.py, 200 lines in all — is onpbrubeck/form-interp-tsfc. With this branch in place,tests/tsfcand the interpolation, assembly, multigrid and vertex-only suites are green.🤖 Generated with Claude Code
https://claude.ai/code/session_0155wQMTMSGiF9a6TbyTVK5P