From 5ee386439f24754327c0b425b525837f8d27e702 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Mon, 18 Nov 2019 12:41:08 +0000 Subject: [PATCH 1/6] copy includes ancillary variables and cell measures --- lib/iris/cube.py | 8 ++++++++ lib/iris/tests/unit/cube/test_Cube.py | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/lib/iris/cube.py b/lib/iris/cube.py index 55ed96441b..fe35c2babb 100644 --- a/lib/iris/cube.py +++ b/lib/iris/cube.py @@ -3522,6 +3522,12 @@ def _deepcopy(self, memo, data=None): new_dim_coords_and_dims = deepcopy(self._dim_coords_and_dims, memo) new_aux_coords_and_dims = deepcopy(self._aux_coords_and_dims, memo) + new_ancillary_variables_and_dims = deepcopy( + self._ancillary_variables_and_dims, memo + ) + new_cell_measures_and_dims = deepcopy( + self._cell_measures_and_dims, memo + ) # Record a mapping from old coordinate IDs to new coordinates, # for subsequent use in creating updated aux_factories. @@ -3541,6 +3547,8 @@ def _deepcopy(self, memo, data=None): dm.core_data(), dim_coords_and_dims=new_dim_coords_and_dims, aux_coords_and_dims=new_aux_coords_and_dims, + ancillary_variables_and_dims=new_ancillary_variables_and_dims, + cell_measures_and_dims=new_ancillary_variables_and_dims, ) new_cube.metadata = deepcopy(self.metadata, memo) diff --git a/lib/iris/tests/unit/cube/test_Cube.py b/lib/iris/tests/unit/cube/test_Cube.py index df9d193cad..2f143e7341 100644 --- a/lib/iris/tests/unit/cube/test_Cube.py +++ b/lib/iris/tests/unit/cube/test_Cube.py @@ -1710,6 +1710,18 @@ def test(self): cube = stock.simple_3d() self._check_copy(cube, cube.copy()) + def test_copy_ancillary_variables(self): + cube = stock.simple_3d() + avr = AncillaryVariable([2, 3], long_name="foo") + cube.add_ancillary_variable(avr, 0) + self._check_copy(cube, cube.copy()) + + def test_copy_cell_measures(self): + cube = stock.simple_3d() + cms = CellMeasure([2, 3], measure="area", long_name="foo") + cube.add_cell_measure(cms, 0) + self._check_copy(cube, cube.copy()) + def test__masked_emptymask(self): cube = Cube(ma.array([0, 1])) self._check_copy(cube, cube.copy()) From 4f12772002524676e8a5272cf7c5eca249397547 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Mon, 18 Nov 2019 13:12:26 +0000 Subject: [PATCH 2/6] fix assignment --- lib/iris/cube.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/iris/cube.py b/lib/iris/cube.py index fe35c2babb..5eb7dffb42 100644 --- a/lib/iris/cube.py +++ b/lib/iris/cube.py @@ -3548,7 +3548,7 @@ def _deepcopy(self, memo, data=None): dim_coords_and_dims=new_dim_coords_and_dims, aux_coords_and_dims=new_aux_coords_and_dims, ancillary_variables_and_dims=new_ancillary_variables_and_dims, - cell_measures_and_dims=new_ancillary_variables_and_dims, + cell_measures_and_dims=new_cell_measures_and_dims, ) new_cube.metadata = deepcopy(self.metadata, memo) From e452064861f666220929d7016076b3d5914f8830 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Tue, 19 Nov 2019 15:50:21 +0000 Subject: [PATCH 3/6] fix equality again --- lib/iris/analysis/__init__.py | 31 +++++++++++++++++++++++++++---- lib/iris/cube.py | 30 ++++++++++++++++++++++-------- 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/lib/iris/analysis/__init__.py b/lib/iris/analysis/__init__.py index 1932a4dc9d..3cd7ad7afa 100644 --- a/lib/iris/analysis/__init__.py +++ b/lib/iris/analysis/__init__.py @@ -186,7 +186,7 @@ def matches_any(self, predicate): return any(self.matches(predicate)) -def coord_comparison(*cubes): +def coord_comparison(*cubes, object_type="coord"): """ Convenience function to help compare coordinates on one or more cubes by their metadata. @@ -240,7 +240,14 @@ def coord_comparison(*cubes): print('All equal coordinates: ', result['equal']) """ - all_coords = [cube.coords() for cube in cubes] + if object_type == "coord": + all_coords = [cube.coords() for cube in cubes] + elif object_type == "cell measure": + all_coords = [cube.cell_measures() for cube in cubes] + elif object_type == "ancillary variable": + all_coords = [cube.ancillary_variables() for cube in cubes] + else: + raise Exception grouped_coords = [] # set of coordinates id()s of coordinates which have been processed @@ -334,7 +341,18 @@ def diff_shape_fn(cube, coord): # dimension on their respective cubes # (None -> group describes a different dimension) def diff_data_dim_fn(cube, coord): - return cube.coord_dims(coord) != first_cube.coord_dims(first_coord) + if object_type == "coord": + return cube.coord_dims(coord) != first_cube.coord_dims( + first_coord + ) + elif object_type == "cell measure": + return cube.cell_measure_dims( + coord + ) != first_cube.cell_measure_dims(first_coord) + elif object_type == "ancillary variable": + return cube.ancillary_variable_dims( + coord + ) != first_cube.ancillary_variable_dims(first_coord) if coord_group.matches_any(diff_data_dim_fn): different_data_dimension.add(coord_group) @@ -342,7 +360,12 @@ def diff_data_dim_fn(cube, coord): # get all coordinate groups which don't describe a dimension # (None -> doesn't describe a dimension) def no_data_dim_fn(cube, coord): - return cube.coord_dims(coord) == () + if object_type == "coord": + return cube.coord_dims(coord) == () + elif object_type == "cell measure": + return cube.cell_measure_dims(coord) == () + elif object_type == "ancillary variable": + return cube.ancillary_variable_dims(coord) == () if coord_group.matches_all(no_data_dim_fn): no_data_dimension.add(coord_group) diff --git a/lib/iris/cube.py b/lib/iris/cube.py index 5eb7dffb42..21475fafea 100644 --- a/lib/iris/cube.py +++ b/lib/iris/cube.py @@ -3522,12 +3522,12 @@ def _deepcopy(self, memo, data=None): new_dim_coords_and_dims = deepcopy(self._dim_coords_and_dims, memo) new_aux_coords_and_dims = deepcopy(self._aux_coords_and_dims, memo) - new_ancillary_variables_and_dims = deepcopy( - self._ancillary_variables_and_dims, memo - ) new_cell_measures_and_dims = deepcopy( self._cell_measures_and_dims, memo ) + new_ancillary_variables_and_dims = deepcopy( + self._ancillary_variables_and_dims, memo + ) # Record a mapping from old coordinate IDs to new coordinates, # for subsequent use in creating updated aux_factories. @@ -3547,8 +3547,8 @@ def _deepcopy(self, memo, data=None): dm.core_data(), dim_coords_and_dims=new_dim_coords_and_dims, aux_coords_and_dims=new_aux_coords_and_dims, - ancillary_variables_and_dims=new_ancillary_variables_and_dims, cell_measures_and_dims=new_cell_measures_and_dims, + ancillary_variables_and_dims=new_ancillary_variables_and_dims, ) new_cube.metadata = deepcopy(self.metadata, memo) @@ -3575,13 +3575,27 @@ def __eq__(self, other): ) if result: - result = set(self._cell_measures_and_dims) == set( - other._cell_measures_and_dims + coord_comparison = iris.analysis.coord_comparison( + self, + other, + object_type="cell measure", + ) + # if there are any cell measures which are not equal + result = not ( + coord_comparison["not_equal"] + or coord_comparison["non_equal_data_dimension"] ) if result: - result = set(self._ancillary_variables_and_dims) == set( - other._ancillary_variables_and_dims + coord_comparison = iris.analysis.coord_comparison( + self, + other, + object_type="ancillary variable", + ) + # if there are any ancillary variables which are not equal + result = not ( + coord_comparison["not_equal"] + or coord_comparison["non_equal_data_dimension"] ) # Having checked everything else, check approximate data equality. From 294a0d7f9d17f3e5edf2c51d32a3f1097c1b6148 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Tue, 19 Nov 2019 16:19:58 +0000 Subject: [PATCH 4/6] black fixes --- lib/iris/cube.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/iris/cube.py b/lib/iris/cube.py index 21475fafea..737d753e9d 100644 --- a/lib/iris/cube.py +++ b/lib/iris/cube.py @@ -3576,9 +3576,7 @@ def __eq__(self, other): if result: coord_comparison = iris.analysis.coord_comparison( - self, - other, - object_type="cell measure", + self, other, object_type="cell measure", ) # if there are any cell measures which are not equal result = not ( @@ -3588,9 +3586,7 @@ def __eq__(self, other): if result: coord_comparison = iris.analysis.coord_comparison( - self, - other, - object_type="ancillary variable", + self, other, object_type="ancillary variable", ) # if there are any ancillary variables which are not equal result = not ( From 0e416d87c43445aacf2cd5c0bf1aad8aa8d34b34 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Wed, 20 Nov 2019 09:39:07 +0000 Subject: [PATCH 5/6] clean up equality fix --- ...fix_2019-Nov-19_cell_measure_copy_loss.txt | 2 ++ lib/iris/analysis/__init__.py | 36 +++++-------------- lib/iris/cube.py | 4 +-- 3 files changed, 13 insertions(+), 29 deletions(-) create mode 100644 docs/iris/src/whatsnew/contributions_3.0.0/bugfix_2019-Nov-19_cell_measure_copy_loss.txt diff --git a/docs/iris/src/whatsnew/contributions_3.0.0/bugfix_2019-Nov-19_cell_measure_copy_loss.txt b/docs/iris/src/whatsnew/contributions_3.0.0/bugfix_2019-Nov-19_cell_measure_copy_loss.txt new file mode 100644 index 0000000000..3a0bbfaf56 --- /dev/null +++ b/docs/iris/src/whatsnew/contributions_3.0.0/bugfix_2019-Nov-19_cell_measure_copy_loss.txt @@ -0,0 +1,2 @@ +* Copying a cube would previously ignore any attached class:`iris.coords.CellMeasure`. + These are now copied over. \ No newline at end of file diff --git a/lib/iris/analysis/__init__.py b/lib/iris/analysis/__init__.py index 3cd7ad7afa..0544cd8cb4 100644 --- a/lib/iris/analysis/__init__.py +++ b/lib/iris/analysis/__init__.py @@ -186,7 +186,7 @@ def matches_any(self, predicate): return any(self.matches(predicate)) -def coord_comparison(*cubes, object_type="coord"): +def coord_comparison(*cubes, object_get=None): """ Convenience function to help compare coordinates on one or more cubes by their metadata. @@ -240,14 +240,12 @@ def coord_comparison(*cubes, object_type="coord"): print('All equal coordinates: ', result['equal']) """ - if object_type == "coord": - all_coords = [cube.coords() for cube in cubes] - elif object_type == "cell measure": - all_coords = [cube.cell_measures() for cube in cubes] - elif object_type == "ancillary variable": - all_coords = [cube.ancillary_variables() for cube in cubes] - else: - raise Exception + if object_get is None: + from iris.cube import Cube + + object_get = Cube.coords + + all_coords = [object_get(cube) for cube in cubes] grouped_coords = [] # set of coordinates id()s of coordinates which have been processed @@ -341,18 +339,7 @@ def diff_shape_fn(cube, coord): # dimension on their respective cubes # (None -> group describes a different dimension) def diff_data_dim_fn(cube, coord): - if object_type == "coord": - return cube.coord_dims(coord) != first_cube.coord_dims( - first_coord - ) - elif object_type == "cell measure": - return cube.cell_measure_dims( - coord - ) != first_cube.cell_measure_dims(first_coord) - elif object_type == "ancillary variable": - return cube.ancillary_variable_dims( - coord - ) != first_cube.ancillary_variable_dims(first_coord) + return coord.cube_dims(cube) != first_coord.cube_dims(first_cube) if coord_group.matches_any(diff_data_dim_fn): different_data_dimension.add(coord_group) @@ -360,12 +347,7 @@ def diff_data_dim_fn(cube, coord): # get all coordinate groups which don't describe a dimension # (None -> doesn't describe a dimension) def no_data_dim_fn(cube, coord): - if object_type == "coord": - return cube.coord_dims(coord) == () - elif object_type == "cell measure": - return cube.cell_measure_dims(coord) == () - elif object_type == "ancillary variable": - return cube.ancillary_variable_dims(coord) == () + return coord.cube_dims(cube) == () if coord_group.matches_all(no_data_dim_fn): no_data_dimension.add(coord_group) diff --git a/lib/iris/cube.py b/lib/iris/cube.py index 737d753e9d..3ff77fa1ad 100644 --- a/lib/iris/cube.py +++ b/lib/iris/cube.py @@ -3576,7 +3576,7 @@ def __eq__(self, other): if result: coord_comparison = iris.analysis.coord_comparison( - self, other, object_type="cell measure", + self, other, object_get=Cube.cell_measures, ) # if there are any cell measures which are not equal result = not ( @@ -3586,7 +3586,7 @@ def __eq__(self, other): if result: coord_comparison = iris.analysis.coord_comparison( - self, other, object_type="ancillary variable", + self, other, object_get=Cube.ancillary_variables, ) # if there are any ancillary variables which are not equal result = not ( From f549b7341470cd8f80be408445c2348b8761a350 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Wed, 20 Nov 2019 10:41:00 +0000 Subject: [PATCH 6/6] address review comments --- lib/iris/tests/unit/cube/test_Cube.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/iris/tests/unit/cube/test_Cube.py b/lib/iris/tests/unit/cube/test_Cube.py index 2f143e7341..c25b330491 100644 --- a/lib/iris/tests/unit/cube/test_Cube.py +++ b/lib/iris/tests/unit/cube/test_Cube.py @@ -1718,7 +1718,7 @@ def test_copy_ancillary_variables(self): def test_copy_cell_measures(self): cube = stock.simple_3d() - cms = CellMeasure([2, 3], measure="area", long_name="foo") + cms = CellMeasure([2, 3], long_name="foo") cube.add_cell_measure(cms, 0) self._check_copy(cube, cube.copy()) @@ -2280,15 +2280,15 @@ def test_ancillary_diff_data(self): def test_cell_measure_fail(self): cube1 = Cube([0, 1]) cube2 = Cube([0, 1]) - cms = CellMeasure([2, 3], measure="area", long_name="foo") + cms = CellMeasure([2, 3], long_name="foo") cube2.add_cell_measure(cms, 0) self.assertFalse(cube1 == cube2) def test_cell_measure_reorder(self): cube1 = Cube([0, 1]) cube2 = Cube([0, 1]) - cms1 = CellMeasure([2, 3], measure="area", long_name="foo") - cms2 = CellMeasure([4, 5], measure="area", long_name="bar") + cms1 = CellMeasure([2, 3], long_name="foo") + cms2 = CellMeasure([4, 5], long_name="bar") # Add the same cell measure to cube1 and cube2 in # opposite orders. cube1.add_cell_measure(cms1, 0) @@ -2300,8 +2300,8 @@ def test_cell_measure_reorder(self): def test_cell_measure_diff_data(self): cube1 = Cube([0, 1]) cube2 = Cube([0, 1]) - cms1 = CellMeasure([2, 3], measure="area", long_name="foo") - cms2 = CellMeasure([4, 5], measure="area", long_name="foo") + cms1 = CellMeasure([2, 3], long_name="foo") + cms2 = CellMeasure([4, 5], long_name="foo") cube1.add_cell_measure(cms1, 0) cube2.add_cell_measure(cms2, 0) self.assertFalse(cube1 == cube2)