Select H(div)/H(curl) components with a Delta - #271
Open
pbrubeck wants to merge 2 commits into
Open
Conversation
The transformers padded a ListTensor with zeros to place the value of the
wrapped element in the component it maps to. Contracting two of those
over the value index cannot cancel the components that do not coincide,
because the zeros are entries of a tensor rather than a property of the
expression, so every pair of blocks stays in the kernel.
Select the component with a Delta instead. A contraction of two blocks
then carries a product of Deltas, which delta elimination cancels unless
the blocks map to the same component. The transform now takes the value
index and returns the component it selects, rather than returning a list
of components to index.
Interpolating from NCF1/NCE1, with tsfc contracting the blocks once they
are separated, kernel temporaries and wall clock:
NCF 1->4 832K -> 68K 3.07x faster
NCE 1->4 307K -> 110K 2.23x faster
NCE 1->3 131K -> 61K 2.23x faster
Form assembly is unchanged; gem.optimise.contraction already pulled these
ListTensors out to be outermost so that each entry could be factorised.
is_orthogonal now contracts the two maps numerically, which neither
belongs in an element constructor nor scales; see the TODO there.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Jul 29, 2026
rckirby
approved these changes
Aug 5, 2026
rckirby
left a comment
There was a problem hiding this comment.
This seems reasonable. You haven't touched tests. Was this previously untested, or are there tests for correctness that still pass?
Author
I have the tests for these guys in #268 |
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.
Supersedes #270, which GitHub marked merged by mistake:
reordering the stack put this branch's commit into
pbrubeck/fix/dual-enriched,which was still #270's base at the time, and a merged PR cannot be reopened.
Same branch, same commit, retargeted onto
pbrubeck/sum-factorise.An H(div) or H(curl) element is a sum of blocks, each mapping the value of a
wrapped tensor product element into one component of a vector. The transformers
expressed that by padding a
ListTensorwith zeros:Contracting two such blocks over the value index cannot cancel the pairs that map
to different components, because the zeros are entries of a tensor rather than a
property of the expression. So an interpolation between two H(div) spaces keeps
every pair of blocks in the kernel, including the ones that are identically zero.
Select the component with a
Deltainstead:A contraction of two blocks then carries a product of Deltas, which delta
elimination cancels unless the blocks map to the same component. The transform now
takes the value index and returns the component it selects, rather than returning a
list of components to be indexed.
Paired with firedrakeproject/firedrake#5297, which contracts each block once
unconcatenatehas separated them — that is where the Deltas meet pairwise.Neither PR does anything on its own.
Effect
Coarse to fine interpolation, as p-multigrid prolongation. Kernel stack
temporaries and wall clock:
Form assembly is unchanged — identical kernel sizes and times to within noise.
gem.optimise.contractionalready pulled theseListTensors out to be outermost sothat each entry could be factorised, so form compilation had already recovered the
structure by another route. The win is specific to dual evaluation.
Testing
Full FIAT suite. In Firedrake, matrix-free
mult/multTransposeagainst theassembled matrix, and an interpolate/restrict round trip, for NCF/NCE on hexahedra
and RTCF/RTCE on quadrilaterals, spectral and fdm variants.
Note on
is_orthogonalIt now contracts the two maps with the gem interpreter, which neither belongs in an
element constructor nor scales. That is a deliberate temporary workaround and is
flagged with a
TODO: the products of Deltas already say which components coincide,so this should be read off symbolically, without the interpreter and without delta
elimination.
🤖 Generated with Claude Code