diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 831f24bfab..12f1268e5f 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -91,7 +91,10 @@ This document explains the changes made to Iris for this release 💣 Incompatible Changes ======================= -#. N/A +#. `@bouweandela`_ and `@trexfeathers`_ (reviewer) updated :class:`~iris.cube.Cube` + comparison so equality is now possible between cubes with data containing a + :obj:`numpy.nan`. e.g. ``Cube([np.nan, 1.0]) == Cube([np.nan, 1.0])`` will now + evaluate to :obj:`True`, while previously this would have been :obj:`False`. (:pull:`5713`) 🚀 Performance Enhancements @@ -113,6 +116,9 @@ This document explains the changes made to Iris for this release #. `@bouweandela`_ made comparing coordinates and arrays to themselves faster. (:pull:`5691`) +#. `@bouweandela`_ and `@trexfeathers`_ (reviewer) made comparing cubes to + themselves faster. (:pull:`5713`) + 🔥 Deprecations =============== diff --git a/lib/iris/cube.py b/lib/iris/cube.py index 5997eaacf5..b812065ce7 100644 --- a/lib/iris/cube.py +++ b/lib/iris/cube.py @@ -3824,6 +3824,9 @@ def _deepcopy(self, memo, data=None): # START OPERATOR OVERLOADS def __eq__(self, other): + if other is self: + return True + result = NotImplemented if isinstance(other, Cube): @@ -3862,7 +3865,13 @@ def __eq__(self, other): if result: # TODO: why do we use allclose() here, but strict equality in # _DimensionalMetadata (via util.array_equal())? - result = da.allclose(self.core_data(), other.core_data()).compute() + result = bool( + np.allclose( + self.core_data(), + other.core_data(), + equal_nan=True, + ) + ) return result # Must supply __ne__, Python does not defer to __eq__ for negative equality diff --git a/lib/iris/tests/unit/cube/test_Cube.py b/lib/iris/tests/unit/cube/test_Cube.py index b6adb0113c..3de44eefa0 100644 --- a/lib/iris/tests/unit/cube/test_Cube.py +++ b/lib/iris/tests/unit/cube/test_Cube.py @@ -2841,11 +2841,20 @@ def test_unit_multiply(self): class Test__eq__data(tests.IrisTest): """Partial cube equality testing, for data type only.""" + def test_cube_identical_to_itself(self): + cube = Cube([1.0]) + self.assertTrue(cube == cube) + def test_data_float_eq(self): cube1 = Cube([1.0]) cube2 = Cube([1.0]) self.assertTrue(cube1 == cube2) + def test_data_float_nan_eq(self): + cube1 = Cube([np.nan, 1.0]) + cube2 = Cube([np.nan, 1.0]) + self.assertTrue(cube1 == cube2) + def test_data_float_eqtol(self): val1 = np.array(1.0, dtype=np.float32) # NOTE: Since v2.3, Iris uses "allclose". Prior to that we used