Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions test/grid/grid/test_areas.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,30 @@ def test_face_areas_fesom(gridpath):
uxgrid = ux.open_grid(gridpath("ugrid", "fesom", "fesom.mesh.diag.nc"))
total_area = uxgrid.calculate_total_face_area()
nt.assert_almost_equal(total_area, 8.3780, decimal=4)


def test_total_face_area_healpix_uses_cached_equal_areas():
"""Default args must reuse the cached ``face_areas``, not recompute.

HEALPix faces are exactly equal-area, so the cached sum is exactly 4*pi.
Recomputing via quadrature drifts and loses that property.
"""
uxgrid = ux.Grid.from_healpix(zoom=2)

total_area = uxgrid.calculate_total_face_area()

nt.assert_allclose(total_area, np.sum(uxgrid.face_areas.values), rtol=0)
nt.assert_allclose(total_area, 4 * np.pi, rtol=1e-12)


def test_total_face_area_honors_quadrature_kwargs():
"""Non-default quadrature settings must still trigger a fresh computation."""
uxgrid = ux.Grid.from_healpix(zoom=2)

recomputed = uxgrid.calculate_total_face_area(quadrature_rule="gaussian", order=2)

nt.assert_allclose(
recomputed,
np.sum(uxgrid.compute_face_areas(quadrature_rule="gaussian", order=2)),
rtol=0,
)
18 changes: 10 additions & 8 deletions uxarray/grid/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -1992,16 +1992,18 @@ def calculate_total_face_area(
and not latitude_adjusted_area
):
result = np.sum(self.face_areas.values)

result = np.sum(
self.compute_face_areas(
quadrature_rule=quadrature_rule,
order=order,
latitude_adjusted_area=latitude_adjusted_area,
else:
result = np.sum(
self.compute_face_areas(
quadrature_rule=quadrature_rule,
order=order,
latitude_adjusted_area=latitude_adjusted_area,
)
)
)

RTOL = 1e-6 # 1e-7 had warnings in existing CI tests (as of 2026-08-05), 1e-6 did not.
# Choose RTOL. Mostly just an arbitrary decision....
# but noting that 1e-9 had warnings in existing CI tests (as of 2026-08-06), while 1e-8 did not.
RTOL = 1e-7
if result > 4 * np.pi * self.sphere_radius**2 * (1 + RTOL):
warnings.warn(
f"Total face area (={result}) exceeds the surface area of the whole sphere "
Expand Down
Loading