Example #1
0
 def test_exception_mismatched_dimensions(self):
     """Test an error is raised if dimension coordinates do not match"""
     self.cube2.coord("latitude").rename("projection_y_coordinate")
     plugin = CubeCombiner("+")
     msg = "Cannot combine cubes with different dimensions"
     with self.assertRaisesRegex(ValueError, msg):
         plugin.process([self.cube1, self.cube2], "new_cube_name")
 def test_min(self):
     """Test combine finds the min of the cubes correctly."""
     operation = 'min'
     plugin = CubeCombiner(operation)
     result = plugin.combine(self.cube1, self.cube2)
     expected_data = np.full((1, 2, 2), 0.5, dtype=np.float32)
     self.assertArrayAlmostEqual(result.data, expected_data)
 def test_fails_with_multi_point_coord(self):
     """Test that if an error is raised if a coordinate with more than
     one point is given"""
     emsg = 'the expand bounds function should only be used on a'
     with self.assertRaisesRegex(ValueError, emsg):
         CubeCombiner.expand_bounds(self.cubelist[0], self.cubelist,
                                    'latitude', 'mid')
Example #4
0
 def test_multiply_preserves_bounds(self):
     """Test specific case for precipitation type, where multiplying a
     precipitation accumulation by a point-time probability of snow retains
     the bounds on the original accumulation."""
     validity_time = datetime(2015, 11, 19, 0)
     time_bounds = [datetime(2015, 11, 18, 23), datetime(2015, 11, 19, 0)]
     forecast_reference_time = datetime(2015, 11, 18, 22)
     precip_accum = set_up_variable_cube(
         np.full((2, 3, 3), 1.5, dtype=np.float32),
         name="lwe_thickness_of_precipitation_amount",
         units="mm",
         time=validity_time,
         time_bounds=time_bounds,
         frt=forecast_reference_time,
     )
     snow_prob = set_up_variable_cube(
         np.full(precip_accum.shape, 0.2, dtype=np.float32),
         name="probability_of_snow",
         units="1",
         time=validity_time,
         frt=forecast_reference_time,
     )
     plugin = CubeCombiner("multiply")
     result = plugin.process([precip_accum, snow_prob],
                             "lwe_thickness_of_snowfall_amount")
     self.assertArrayAlmostEqual(result.data, np.full((2, 3, 3), 0.3))
     self.assertArrayEqual(result.coord("time"), precip_accum.coord("time"))
 def test_mean(self):
     """Test that the function adds the cubes correctly for mean."""
     operation = 'mean'
     plugin = CubeCombiner(operation)
     result = plugin.combine(self.cube1, self.cube2)
     expected_data = np.full((1, 2, 2), 1.1, dtype=np.float32)
     self.assertArrayAlmostEqual(result.data, expected_data)
Example #6
0
 def test_exception_mismatched_dimensions(self):
     """Test an error is raised if dimension coordinates do not match"""
     self.cube2.coord("lwe_thickness_of_precipitation_amount").rename("snow_depth")
     plugin = CubeCombiner("+")
     msg = "Cannot combine cubes with different dimensions"
     with self.assertRaisesRegex(ValueError, msg):
         plugin.process([self.cube1, self.cube2], "new_cube_name")
Example #7
0
 def test_mean(self):
     """Test that the plugin calculates the mean correctly. """
     plugin = CubeCombiner("mean")
     cubelist = iris.cube.CubeList([self.cube1, self.cube2])
     result = plugin.process(cubelist, "new_cube_name")
     expected_data = np.full((2, 2), 0.55, dtype=np.float32)
     self.assertEqual(result.name(), "new_cube_name")
     self.assertArrayAlmostEqual(result.data, expected_data)
 def test_mean_multi_cube(self):
     """Test that the plugin calculates the mean for three cubes. """
     plugin = CubeCombiner('mean')
     cubelist = iris.cube.CubeList([self.cube1, self.cube2, self.cube3])
     result = plugin.process(cubelist, 'new_cube_name')
     expected_data = np.full((1, 2, 2), 0.4, dtype=np.float32)
     self.assertEqual(result.name(), 'new_cube_name')
     self.assertArrayAlmostEqual(result.data, expected_data)
    def test_exception_for_cube_passed_in(self):
        """Test that the plugin raises an exception if something other than a
        cubelist is passed in."""
        plugin = CubeCombiner('-')
        msg = "Expecting data to be an instance of"

        with self.assertRaisesRegex(TypeError, msg):
            plugin.process(self.cube1, 'new_cube_name')
Example #10
0
 def test_exception_for_single_entry_cubelist(self):
     """Test that the plugin raises an exception if a cubelist containing
     only one cube is passed in."""
     plugin = CubeCombiner("-")
     msg = "Expecting 2 or more cubes in cube_list"
     cubelist = iris.cube.CubeList([self.cube1])
     with self.assertRaisesRegex(ValueError, msg):
         plugin.process(cubelist, "new_cube_name")
 def test_basic(self):
     """Test that the function returns a Cube. """
     operation = '*'
     plugin = CubeCombiner(operation)
     result = plugin.combine(self.cube1, self.cube2)
     self.assertIsInstance(result, Cube)
     expected_data = np.full((1, 2, 2), 0.3, dtype=np.float32)
     self.assertArrayAlmostEqual(result.data, expected_data)
Example #12
0
 def test_error_broadcast_coord_is_auxcoord(self):
     """Test that plugin throws an error if the broadcast coord already exists"""
     plugin = CubeCombiner("*")
     cube = self.cube4[:, 0, ...].copy()
     cube.data = np.ones_like(cube.data)
     cubelist = iris.cube.CubeList([self.cube4.copy(), cube])
     msg = "Cannot broadcast to coord threshold as it already exists as an AuxCoord"
     with self.assertRaisesRegex(TypeError, msg):
         plugin.process(cubelist, "new_cube_name", broadcast_to_coords=["threshold"])
Example #13
0
 def test_mixed_dtypes_overflow(self):
     """Test the plugin with a dtype combination that results in float64 data."""
     plugin = CubeCombiner("add")
     cubelist = iris.cube.CubeList(
         [self.cube1, self.cube2.copy(np.ones_like(self.cube2.data, dtype=np.int32))]
     )
     msg = "Operation .* results in float64 data"
     with self.assertRaisesRegex(TypeError, msg):
         plugin.process(cubelist, "new_cube_name")
 def test_basic(self):
     """Test that the plugin returns a Cube. """
     plugin = CubeCombiner('+')
     cubelist = iris.cube.CubeList([self.cube1, self.cube2])
     result = plugin.process(cubelist, 'new_cube_name')
     self.assertIsInstance(result, Cube)
     self.assertEqual(result.name(), 'new_cube_name')
     expected_data = np.full((1, 2, 2), 1.1, dtype=np.float32)
     self.assertArrayAlmostEqual(result.data, expected_data)
Example #15
0
 def test_min(self):
     """Test combine finds the min of the cubes correctly."""
     operation = 'min'
     plugin = CubeCombiner(operation)
     result = plugin.combine(self.cube1, self.cube3, operation)
     expected_data = np.zeros((1, 2, 2, 2))
     expected_data[0, 0, :, :] = 0.1
     expected_data[0, 1, :, :] = 0.6
     self.assertArrayAlmostEqual(result.data, expected_data)
Example #16
0
 def test_minus(self):
     """Test combine minus the cubes correctly. """
     operation = '-'
     plugin = CubeCombiner(operation)
     result = plugin.combine(self.cube1, self.cube2, operation)
     expected_data = np.zeros((1, 2, 2, 2))
     expected_data[0, 0, :, :] = 0.4
     expected_data[0, 1, :, :] = 0.2
     self.assertArrayAlmostEqual(result.data, expected_data)
Example #17
0
 def test_bounds_expansion_midpoint(self):
     """Test option to use the midpoint between the bounds as the time
     coordinate point, rather than the (default) maximum."""
     plugin = CubeCombiner("add")
     cubelist = iris.cube.CubeList([self.cube1, self.cube2])
     result = plugin.process(cubelist, "new_cube_name", use_midpoint=True)
     self.assertEqual(result.name(), "new_cube_name")
     self.assertEqual(result.coord("time").points[0], 1447891200)
     self.assertArrayEqual(result.coord("time").bounds, [[1447887600, 1447894800]])
Example #18
0
 def test_mean(self):
     """Test that the function adds the cubes correctly for mean."""
     operation = '+'
     plugin = CubeCombiner(operation)
     result = plugin.combine(self.cube1, self.cube3, operation)
     expected_data = np.zeros((1, 2, 2, 2))
     expected_data[0, 0, :, :] = 0.6
     expected_data[0, 1, :, :] = 1.4
     self.assertArrayAlmostEqual(result.data, expected_data)
Example #19
0
 def test_mean(self):
     """Test that the plugin calculates the mean correctly. """
     plugin = CubeCombiner('mean')
     cubelist = iris.cube.CubeList([self.cube1, self.cube2])
     result = plugin.process(cubelist, 'new_cube_name')
     expected_data = np.zeros((1, 2, 2, 2))
     expected_data[:, 0, :, :] = 0.3
     expected_data[:, 1, :, :] = 0.5
     self.assertEqual(result.name(), 'new_cube_name')
     self.assertArrayAlmostEqual(result.data, expected_data)
Example #20
0
 def test_basic(self):
     """Test that the plugin returns a Cube. """
     plugin = CubeCombiner('+')
     cubelist = iris.cube.CubeList([self.cube1, self.cube1])
     result = plugin.process(cubelist, 'new_cube_name')
     self.assertIsInstance(result, Cube)
     self.assertEqual(result.name(), 'new_cube_name')
     expected_data = np.zeros((1, 2, 2, 2))
     expected_data[:, 0, :, :] = 1.0
     expected_data[:, 1, :, :] = 1.2
     self.assertArrayAlmostEqual(result.data, expected_data)
Example #21
0
 def test_with_mask(self):
     """Test that the plugin preserves the mask if any of the inputs are
     masked"""
     expected_data = np.full((1, 2, 2), 1.2, dtype=np.float32)
     mask = [[[False, True], [False, False]]]
     self.cube1.data = np.ma.MaskedArray(self.cube1.data, mask=mask)
     plugin = CubeCombiner("add")
     result = plugin.process([self.cube1, self.cube2, self.cube3], "new_cube_name")
     self.assertIsInstance(result.data, np.ma.MaskedArray)
     self.assertArrayAlmostEqual(result.data.data, expected_data)
     self.assertArrayEqual(result.data.mask, mask)
Example #22
0
 def test_basic(self):
     """Test that the plugin returns a Cube and doesn't modify the inputs."""
     plugin = CubeCombiner("+")
     cubelist = iris.cube.CubeList([self.cube1, self.cube2])
     input_copy = deepcopy(cubelist)
     result = plugin.process(cubelist, "new_cube_name")
     self.assertIsInstance(result, Cube)
     self.assertEqual(result.name(), "new_cube_name")
     expected_data = np.full((2, 2), 1.1, dtype=np.float32)
     self.assertArrayAlmostEqual(result.data, expected_data)
     self.assertCubeListEqual(input_copy, cubelist)
Example #23
0
 def test_bounds_expansion(self):
     """Test that the plugin calculates the sum of the input cubes
     correctly and expands the time coordinate bounds on the
     resulting output."""
     plugin = CubeCombiner("add")
     cubelist = iris.cube.CubeList([self.cube1, self.cube2])
     result = plugin.process(cubelist, "new_cube_name")
     expected_data = np.full((1, 2, 2), 1.1, dtype=np.float32)
     self.assertEqual(result.name(), "new_cube_name")
     self.assertArrayAlmostEqual(result.data, expected_data)
     self.assertEqual(result.coord("time").points[0], 1447894800)
     self.assertArrayEqual(result.coord("time").bounds, [[1447887600, 1447894800]])
Example #24
0
 def test_basic(self):
     """Test that the function returns a Cube. """
     operation = '*'
     plugin = CubeCombiner(operation)
     cube1 = self.cube1
     cube2 = cube1.copy()
     result = plugin.combine(cube1, cube2, operation)
     self.assertIsInstance(result, Cube)
     expected_data = np.zeros((1, 2, 2, 2))
     expected_data[0, 0, :, :] = 0.25
     expected_data[0, 1, :, :] = 0.36
     self.assertArrayAlmostEqual(result.data, expected_data)
Example #25
0
 def test_unmatched_coords_ignored(self):
     """Test coordinates that are not present on all cubes are ignored,
     regardless of input order"""
     expected_coord_set = {"time", "forecast_period"}
     height = iris.coords.AuxCoord([1.5], "height", units="m")
     self.cube1.add_aux_coord(height)
     result = CubeCombiner("+")._get_expanded_coord_names(
         [self.cube1, self.cube2, self.cube3])
     self.assertSetEqual(set(result), expected_coord_set)
     result = CubeCombiner("+")._get_expanded_coord_names(
         [self.cube3, self.cube2, self.cube1])
     self.assertSetEqual(set(result), expected_coord_set)
 def test_revised_attributes(self):
     """Test that the plugin passes through the relevant dictionary to
     modify an attribute and that these modifications are present in the
     returned cube."""
     plugin = CubeCombiner('mean')
     revised_attributes = {'attribute_to_update': 'second_value'}
     cubelist = iris.cube.CubeList([self.cube1, self.cube2])
     result = plugin.process(cubelist,
                             'new_cube_name',
                             revised_attributes=revised_attributes)
     self.assertEqual(result.attributes['attribute_to_update'],
                      'second_value')
Example #27
0
 def test_mixed_dtypes(self):
     """Test that the plugin calculates the sum correctly and doesn't mangle dtypes."""
     plugin = CubeCombiner("add")
     cubelist = iris.cube.CubeList(
         [self.cube1, self.cube2.copy(np.ones_like(self.cube2.data, dtype=np.int8))]
     )
     result = plugin.process(cubelist, "new_cube_name")
     expected_data = np.full((2, 2), 1.5, dtype=np.float32)
     self.assertEqual(result.name(), "new_cube_name")
     self.assertArrayAlmostEqual(result.data, expected_data)
     self.assertTrue(cubelist[0].dtype == np.float32)
     self.assertTrue(cubelist[1].dtype == np.int8)
     self.assertTrue(result.dtype == np.float32)
Example #28
0
 def test_error_broadcast_coord_not_found(self):
     """Test that plugin throws an error if the broadcast coord is not present anywhere"""
     plugin = CubeCombiner("*")
     cube = self.cube4[:, 0, ...].copy()
     cube.data = np.ones_like(cube.data)
     cubelist = iris.cube.CubeList([self.cube4.copy(), cube])
     msg = (
         "Cannot find coord kittens in "
         "<iris 'Cube' of probability_of_lwe_thickness_of_precipitation_amount_above_threshold / \(1\) "
         "\(realization: 3; lwe_thickness_of_precipitation_amount: 2; latitude: 2; longitude: 2\)> "
         "to broadcast to."
     )
     with self.assertRaisesRegex(CoordinateNotFoundError, msg):
         plugin.process(cubelist, "new_cube_name", broadcast_to_coords=["kittens"])
Example #29
0
 def test_error_broadcast_coord_wrong_order(self):
     """Test that plugin throws an error if the broadcast coord is not on the first cube"""
     plugin = CubeCombiner("*")
     cube = self.cube4[:, 0, ...].copy()
     cube.data = np.ones_like(cube.data)
     cube.remove_coord("lwe_thickness_of_precipitation_amount")
     cubelist = iris.cube.CubeList([cube, self.cube4.copy()])
     msg = (
         "Cannot find coord threshold in "
         "<iris 'Cube' of probability_of_lwe_thickness_of_precipitation_amount_above_threshold / \(1\) "
         "\(realization: 3; latitude: 2; longitude: 2\)> to broadcast to"
     )
     with self.assertRaisesRegex(CoordinateNotFoundError, msg):
         plugin.process(cubelist, "new_cube_name", broadcast_to_coords=["threshold"])
Example #30
0
 def test_broadcast_coord(self):
     """Test that plugin broadcasts to a coord and doesn't change the inputs."""
     plugin = CubeCombiner("*")
     cube = self.cube4[:, 0, ...].copy()
     cube.data = np.ones_like(cube.data)
     cube.remove_coord("lwe_thickness_of_precipitation_amount")
     cubelist = iris.cube.CubeList([self.cube4.copy(), cube])
     input_copy = deepcopy(cubelist)
     result = plugin.process(cubelist,
                             "new_cube_name",
                             broadcast_to_coords=["threshold"])
     self.assertIsInstance(result, Cube)
     self.assertEqual(result.name(), "new_cube_name")
     self.assertArrayAlmostEqual(result.data, self.cube4.data)
     self.assertCubeListEqual(input_copy, cubelist)