From 9bcf5415edbba5e7ff4e74326780e2ceff6ed3d1 Mon Sep 17 00:00:00 2001 From: Bouwe Andela Date: Wed, 24 Jan 2024 16:42:10 +0100 Subject: [PATCH 1/4] Consider NaNs equal when comparing cubes --- lib/iris/cube.py | 9 ++++++++- lib/iris/tests/unit/cube/test_Cube.py | 9 +++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/iris/cube.py b/lib/iris/cube.py index 5997eaacf5..af0ee1b7bc 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,11 @@ 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 = da.allclose( + self.core_data(), + other.core_data(), + equal_nan=True, + ).compute() 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 From 5e2a974ea7aee35ba6204a5b6526643a1b57e2a6 Mon Sep 17 00:00:00 2001 From: Bouwe Andela Date: Wed, 24 Jan 2024 16:52:03 +0100 Subject: [PATCH 2/4] Add whatsnew entry --- docs/src/whatsnew/latest.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 831f24bfab..28d501d299 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -91,7 +91,8 @@ This document explains the changes made to Iris for this release 💣 Incompatible Changes ======================= -#. N/A +#. `@bouweandela`_ updated cube comparison so cubes with data containing a + :obj:`numpy.nan` are now considered equal (:pull:`5713`) 🚀 Performance Enhancements @@ -113,6 +114,8 @@ This document explains the changes made to Iris for this release #. `@bouweandela`_ made comparing coordinates and arrays to themselves faster. (:pull:`5691`) +#. `@bouweandela`_ made comparing cubes to themselves faster. (:pull:`5713`) + 🔥 Deprecations =============== From 6244cee6c656d59b3168ed6b5d8736819d7af6bd Mon Sep 17 00:00:00 2001 From: Bouwe Andela Date: Mon, 12 Feb 2024 13:37:44 +0100 Subject: [PATCH 3/4] Improve whatsnew Co-authored-by: Martin Yeo <40734014+trexfeathers@users.noreply.github.com> --- docs/src/whatsnew/latest.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 28d501d299..024d225a56 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -91,8 +91,10 @@ This document explains the changes made to Iris for this release 💣 Incompatible Changes ======================= -#. `@bouweandela`_ updated cube comparison so cubes with data containing a - :obj:`numpy.nan` are now considered equal (:pull:`5713`) +#. `@bouweandela`_ 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, 2.0])``, + ``Cube([np.nan, 1.0]) == Cube([np.nan, 1.0])``. (:pull:`5713`) 🚀 Performance Enhancements From ec30de862338e6e6b0dbb2e6032731e36b55cdbd Mon Sep 17 00:00:00 2001 From: Bouwe Andela Date: Mon, 12 Feb 2024 13:50:53 +0100 Subject: [PATCH 4/4] Update whatsnew and use numpy.allclose instead of dask.array.allclose --- docs/src/whatsnew/latest.rst | 11 ++++++----- lib/iris/cube.py | 12 +++++++----- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/src/whatsnew/latest.rst b/docs/src/whatsnew/latest.rst index 024d225a56..12f1268e5f 100644 --- a/docs/src/whatsnew/latest.rst +++ b/docs/src/whatsnew/latest.rst @@ -91,10 +91,10 @@ This document explains the changes made to Iris for this release 💣 Incompatible Changes ======================= -#. `@bouweandela`_ 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, 2.0])``, - ``Cube([np.nan, 1.0]) == Cube([np.nan, 1.0])``. (:pull:`5713`) +#. `@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 @@ -116,7 +116,8 @@ This document explains the changes made to Iris for this release #. `@bouweandela`_ made comparing coordinates and arrays to themselves faster. (:pull:`5691`) -#. `@bouweandela`_ made comparing cubes to themselves faster. (:pull:`5713`) +#. `@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 af0ee1b7bc..b812065ce7 100644 --- a/lib/iris/cube.py +++ b/lib/iris/cube.py @@ -3865,11 +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(), - equal_nan=True, - ).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