diff --git a/test/grid/grid/test_areas.py b/test/grid/grid/test_areas.py index f11cbde8d..f1d99f74f 100644 --- a/test/grid/grid/test_areas.py +++ b/test/grid/grid/test_areas.py @@ -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, + ) diff --git a/uxarray/grid/grid.py b/uxarray/grid/grid.py index 9bd17e8a2..eaa328b40 100644 --- a/uxarray/grid/grid.py +++ b/uxarray/grid/grid.py @@ -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 "