Skip to content

Loosen tolerances for single precision - #260

Merged
pbrubeck merged 28 commits into
firedrakeproject:mainfrom
Corintis:fp32-support
Jul 17, 2026
Merged

Loosen tolerances for single precision#260
pbrubeck merged 28 commits into
firedrakeproject:mainfrom
Corintis:fp32-support

Conversation

@hardik-corintis

@hardik-corintis hardik-corintis commented Jul 16, 2026

Copy link
Copy Markdown

Summary

Most test_macro_grid_transfer/test_macro_multigrid tests (macro elements: alfeld/iso split) fail under a single-precision PETSc build, but pass under double precision — mesh-hierarchy grid-transfer (inject/prolong/restrict) silently returns all-zero or NaN instead of the correct interpolated/projected value.

Root cause: compute_partition_of_unity's point-to-subcell binning tolerance (1e-12) is calibrated for double precision. A symbolic point's Newton-located reference coordinate has ~1e-6 error in single precision, causing points on a subcell boundary to bin to the wrong subcell and zero out locally-supported basis functions there.

Needed for single-precision (fp32) support in firedrake, see firedrakeproject/firedrake#5033.

Changes

  • FIAT/precision.py: calibrate_tolerance(tol, dtype) — returns sqrt(tol) if dtype is single-precision (float32/complex64), else tol unchanged. No dependency on PETSc/petsc4py.
  • FIAT/reference_element.py: ufc_simplex, ufc_hypercube, ufc_cell, and symmetric_simplex now accept an optional dtype kwarg, casting the constructed reference cell's vertices to that precision. This lets a caller (e.g. firedrake) declare the working precision when it builds a reference cell, rather than threading a dtype argument through the whole tabulation API.
  • FIAT/expansions.py: ExpansionSet._tabulate's macro-element subcell-binning tolerance is now read directly from self.ref_el.vertices.dtype, so it automatically reflects the precision the reference cell was built with.
  • Fixed make_lattice silently upcasting to float64 (via numpy.dot against recursivenodes' always-float64 weights) even when given float32 vertices — this is what let a float32 macro-split complex still compute everything in float64.
  • test/FIAT/unit/test_precision.py: parametrized unit tests for calibrate_tolerance, plus two tests (using GEM, not sympy) verifying the tolerance relaxation actually reaches macro-element tabulation and changes classification near a subcell boundary.

Discussion

Per review, this iterated from an earlier, much larger design (threading an explicit dtype parameter through FiniteElement/PolynomialSet/all of finat) down to touching only reference_element.py and expansions.py — the dtype only ever mattered for this one macro-element tolerance, and the rest of the threading reached no real callers.

This also resolves the earlier CI-coverage concern (FIAT's CI never installs petsc4py) — the current design has no PETSc dependency at all, so there's nothing precision-specific left uncovered by ordinary CI.

Still open, tracked in firedrake PR #5033: making firedrake's element-construction code actually pass dtype=scalar_type when it builds reference cells, so this fix reaches real fp32 builds.

AI disclosure: parts of this PR were developed with assistance from Claude (Anthropic). All changes have been reviewed, tested locally, and are understood by the author.

@connorjward connorjward 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.

This is slightly abstraction breaking. It would be nice for FIAT to not know about PETSc at all. I think the 'right' way to do this is to pass information about scalar type (accessible in the form_compiler_parameters) through to FIAT in the right places.

Would this be feasible? Seems like something AI could manage fairly well.

@hardik-corintis

Copy link
Copy Markdown
Author

thanks @connorjward, what do you think? Now we are not using petsc4py but passing the scalar type from firedrake directly.

@connorjward connorjward 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.

Looking pretty good now.

It would be good to have a couple very simple tests.

Comment thread FIAT/expansions.py Outdated
Comment thread FIAT/expansions.py Outdated
Comment thread FIAT/precision.py Outdated
Comment thread FIAT/expansions.py Outdated

@connorjward connorjward 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.

I think I'm pretty happy at this point but I'm not comfortable merging without additional approval.

@rckirby thoughts?

Comment thread test/FIAT/unit/test_precision.py

@connorjward connorjward 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.

I think I am now happy, but as I said before this should get approval from someone else too.

@pbrubeck

pbrubeck commented Jul 17, 2026

Copy link
Copy Markdown

This seems way too invasive, it seems that we only needed to deal with precision in FIAT due to a very niche case.

Comment thread FIAT/expansions.py Outdated
Comment thread FIAT/expansions.py
@pbrubeck

Copy link
Copy Markdown

I think a much nicer approach would be to communicate dtype through the reference cell coordinates

Comment thread FIAT/expansions.py Outdated
@pbrubeck

Copy link
Copy Markdown

FIAT elements are tabulated with the dtype given by the points array, so there is no need to be passing a redundant dtype kwarg

@pbrubeck pbrubeck 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.

This PR does not need such a large diff

Comment thread FIAT/precision.py Outdated
Comment thread FIAT/precision.py Outdated
Co-authored-by: Pablo Brubeck <brubeck@protonmail.com>
Comment thread test/FIAT/unit/test_precision.py Outdated
Comment thread test/FIAT/unit/test_precision.py Outdated
Comment thread test/FIAT/unit/test_precision.py Outdated
Co-authored-by: Pablo Brubeck <brubeck@protonmail.com>
Comment thread test/FIAT/unit/test_precision.py Outdated
hardik-corintis and others added 2 commits July 17, 2026 15:08
Co-authored-by: Pablo Brubeck <brubeck@protonmail.com>
Co-authored-by: Pablo Brubeck <brubeck@protonmail.com>
Comment thread FIAT/reference_element.py Outdated
Comment thread FIAT/reference_element.py Outdated
Comment thread FIAT/reference_element.py Outdated
Comment thread FIAT/precision.py Outdated
hardik-corintis and others added 5 commits July 17, 2026 17:23
Co-authored-by: Pablo Brubeck <brubeck@protonmail.com>
Co-authored-by: Pablo Brubeck <brubeck@protonmail.com>
Co-authored-by: Pablo Brubeck <brubeck@protonmail.com>
Comment thread FIAT/reference_element.py Outdated
Co-authored-by: Pablo Brubeck <brubeck@protonmail.com>
Comment thread FIAT/reference_element.py Outdated
@hardik-corintis
hardik-corintis requested a review from pbrubeck July 17, 2026 16:14
Comment thread FIAT/precision.py Outdated
Co-authored-by: Pablo Brubeck <brubeck@protonmail.com>
Comment thread test/FIAT/unit/test_precision.py Outdated
hardik-corintis and others added 2 commits July 17, 2026 18:43
Co-authored-by: Pablo Brubeck <brubeck@protonmail.com>
Comment thread FIAT/precision.py Outdated
Comment thread test/FIAT/unit/test_precision.py

@pbrubeck pbrubeck 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.

@pbrubeck
pbrubeck merged commit 36ec48e into firedrakeproject:main Jul 17, 2026
9 checks passed
@hardik-corintis
hardik-corintis deleted the fp32-support branch July 17, 2026 17:34
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.

3 participants