Skip to content

Tabulate high-order expansion derivatives by recurrence#256

Open
pbrubeck wants to merge 2 commits into
mainfrom
pbrubeck/deriv-recurrence
Open

Tabulate high-order expansion derivatives by recurrence#256
pbrubeck wants to merge 2 commits into
mainfrom
pbrubeck/deriv-recurrence

Conversation

@pbrubeck

@pbrubeck pbrubeck commented Jul 10, 2026

Copy link
Copy Markdown

Fixes firedrakeproject/firedrake#4152

Summary

  • Tabulate arbitrary-order Dubiner expansion derivatives by applying Leibniz to the recurrence factors.
  • Default simplex expansion tabulation to the recurrence path instead of dense differentiation matrices.
  • Add order-4 triangle/tetrahedron coverage for orthonormal and bubble variants.

Tests

  • python -m py_compile FIAT/expansions.py test/FIAT/unit/test_polynomial.py
  • python -m pytest test/FIAT/unit/test_polynomial.py test/FIAT/unit/test_hierarchical.py::test_hierarchical_sparsity test/FIAT/regression/test_regression.py::test_expansions_jet -q

AI tool used: Codex.

@pbrubeck

Copy link
Copy Markdown
Author

Updated verification after the HCT degree-14 follow-up.

What changed:

  • Stabilized high-order Ck vertex supersmoothness constraints by imposing each constraint block on the current nullspace, instead of burying high-order vertex constraints in one large SVD.
  • Added high-order HCT regression coverage for degrees 13 and 14.

Verification:

  • python -m py_compile FIAT/expansions.py FIAT/macro.py test/FIAT/unit/test_hct.py test/FIAT/unit/test_polynomial.py
  • python -m pytest test/FIAT/unit/test_hct.py test/FIAT/unit/test_macro.py -q
  • python -m pytest test/FIAT/unit/test_polynomial.py::test_high_order_expansion_derivatives test/FIAT/regression/test_regression.py::test_expansions_jet -q
  • Firedrake exact issue command for HCT degree 13: passed, V.dim() = 803
  • Firedrake HCT degree 14: passed, V.dim() = 923
  • Firedrake HCT degree sweep 13..17: passed with dimensions 803, 923, 1051, 1187, 1331

AI tool used: Codex.

return pts


@pytest.mark.parametrize("degree, space_dimension", [(13, 127), (14, 144)])

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are rather expensive tests, maybe we don't want them

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use a lower-degree version of the tests? But are they causing any problems in run-time on the test suite?

Comment thread FIAT/expansions.py
@@ -95,7 +142,7 @@ def dubiner_recurrence(dim, n, order, ref_pts, Jinv, scale, variant=None):
results = [numpy.zeros((num_members,) + (dim,)*k + phi0.shape[1:], dtype=phi0.dtype)

@pbrubeck pbrubeck Jul 13, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Storage blows up for large k, we need to exploit symmetry

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't we already have that problem? Or is this intermediate storage as a result of doing Leibniz instead of hand-coding?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only ran recurrences for k<=2

Comment thread FIAT/expansions.py
ddphi[inext] += fprev * ddphi[iprev]
cur = [result[icur] for result in results]
prev = [result[iprev] for result in results]
for rank in range(1, order+1):

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should only take the k-th derivative if the polynomial degree >= k

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We know the answer for degree < k without computing.

@rckirby rckirby left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After we resolve the comments, I think this makes sense to do. The derivative matrices are kind of clunky and tend to go unstable at high order.

Comment thread FIAT/expansions.py
@@ -95,7 +142,7 @@ def dubiner_recurrence(dim, n, order, ref_pts, Jinv, scale, variant=None):
results = [numpy.zeros((num_members,) + (dim,)*k + phi0.shape[1:], dtype=phi0.dtype)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't we already have that problem? Or is this intermediate storage as a result of doing Leibniz instead of hand-coding?

Comment thread FIAT/expansions.py
for axis in range(rank))
product = product.transpose(permutation + tuple(range(rank, product.ndim)))
product = product.reshape((dim,) * rank + operand.shape[operand_rank:])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if not rank? Do we handle None being returned correctly?

Comment thread FIAT/expansions.py
ddphi[inext] += fprev * ddphi[iprev]
cur = [result[icur] for result in results]
prev = [result[iprev] for result in results]
for rank in range(1, order+1):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We know the answer for degree < k without computing.

Comment thread FIAT/expansions.py
return sum(ai != bi for ai, bi in zip(alpha, beta))

# Only use dmats if tabulate failed
# Use dmats only for derivatives above the configured recurrence order.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have cases (outside of tests) where recurrence_order isn't infinite?

return pts


@pytest.mark.parametrize("degree, space_dimension", [(13, 127), (14, 144)])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use a lower-degree version of the tests? But are they causing any problems in run-time on the test suite?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: HCT doesn't work at very high order

2 participants