Skip to content

Commit

Permalink
Change Cell equality to equate nans (fixes #4681) (#4701)
Browse files Browse the repository at this point in the history
* nans in cells satisfy equality

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* address review comments

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
stephenworsley and pre-commit-ci[bot] committed Apr 29, 2022
1 parent 1d0dcf5 commit 3f3604f
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 1 deletion.
6 changes: 6 additions & 0 deletions docs/src/whatsnew/latest.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ This document explains the changes made to Iris for this release
to ``stderr`` when a :class:`~iris.fileformats.cf.CFReader` that fails to
initialise is garbage collected. (:issue:`3312`, :pull:`4646`)

#. `@stephenworsley`_ aligned the behaviour of :obj:`~iris.coords.Cell` equality
to match :obj:`~iris.coords.Coord` equality with respect to NaN values.
Two NaN valued Cells are now considered equal. This fixes :issue:`4681` and
causes NaN valued scalar coordinates to be able to merge be preserved during
cube merging. (:pull:`4701`)


💣 Incompatible Changes
=======================
Expand Down
13 changes: 13 additions & 0 deletions lib/iris/coords.py
Original file line number Diff line number Diff line change
Expand Up @@ -1353,14 +1353,27 @@ def __eq__(self, other):
compared.
"""

def nan_equality(x, y):
return (
isinstance(x, (float, np.number))
and np.isnan(x)
and isinstance(y, (float, np.number))
and np.isnan(y)
)

if isinstance(other, (int, float, np.number)) or hasattr(
other, "timetuple"
):
if self.bound is not None:
return self.contains_point(other)
elif nan_equality(self.point, other):
return True
else:
return self.point == other
elif isinstance(other, Cell):
if nan_equality(self.point, other.point):
return True
return (self.point == other.point) and (
self.bound == other.bound or self.bound == other.bound[::-1]
)
Expand Down
29 changes: 28 additions & 1 deletion lib/iris/tests/integration/merge/test_merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
# before importing anything else.
import iris.tests as tests # isort:skip

from iris.coords import DimCoord
import numpy as np

from iris.coords import AuxCoord, DimCoord
from iris.cube import Cube, CubeList


Expand All @@ -33,5 +35,30 @@ def test_form_contiguous_dimcoord(self):
self.assertArrayEqual(coord2.bounds, coord1.bounds[::-1, ::-1])


class TestNaNs(tests.IrisTest):
def test_merge_nan_coords(self):
# Test that nan valued coordinates merge together.
cube1 = Cube(np.ones([3, 4]), "air_temperature", units="K")
coord1 = DimCoord([1, 2, 3], long_name="x")
coord2 = DimCoord([0, 1, 2, 3], long_name="y")
nan_coord1 = AuxCoord(np.nan, long_name="nan1")
nan_coord2 = AuxCoord([np.nan] * 4, long_name="nan2")
cube1.add_dim_coord(coord1, 0)
cube1.add_dim_coord(coord2, 1)
cube1.add_aux_coord(nan_coord1)
cube1.add_aux_coord(nan_coord2, 1)
cubes = CubeList(cube1.slices_over("x"))
cube2 = cubes.merge_cube()

self.assertArrayEqual(
np.isnan(nan_coord1.points),
np.isnan(cube2.coord("nan1").points),
)
self.assertArrayEqual(
np.isnan(nan_coord2.points),
np.isnan(cube2.coord("nan2").points),
)


if __name__ == "__main__":
tests.main()
8 changes: 8 additions & 0 deletions lib/iris/tests/unit/coords/test_Cell.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ def test_PartialDateTime_other(self):
self.assertNotEqual(cell, PartialDateTime(month=3, hour=12))
self.assertNotEqual(cell, PartialDateTime(month=4))

def test_nan_other(self):
# Check that nans satisfy equality.
cell1 = Cell(np.nan)
cell2 = Cell(np.nan)
self.assertEqual(cell1, np.nan)
self.assertEqual(np.nan, cell1)
self.assertEqual(cell1, cell2)


class Test_contains_point(tests.IrisTest):
def test_datetimelike_bounded_cell(self):
Expand Down

0 comments on commit 3f3604f

Please sign in to comment.