def test_fails_input_not_a_cube(self): """Test it raises a Type Error if not supplied with a cube.""" coord = "time" plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_mean') notacube = 0.0 msg = ('The first argument must be an instance of ' + 'iris.cube.Cube') with self.assertRaisesRegexp(TypeError, msg): plugin.process(notacube)
def test_weights_sum_to_1(self): """Test that if a weights cube is provided which is properly normalised, i.e. the weights sum to one over the blending dimension, no exception is raised.""" coord = "forecast_reference_time" plugin = WeightedBlendAcrossWholeDimension(coord) plugin.check_weights(self.weights3d.data, 0)
def test_fails_coord_not_in_cube(self): """Test it raises CoordinateNotFoundError if the blending coord is not found in the cube.""" coord = "notset" plugin = WeightedBlendAcrossWholeDimension(coord) msg = ('Coordinate to be collapsed not found in cube.') with self.assertRaisesRegex(CoordinateNotFoundError, msg): plugin.process(self.cube)
def test_unmatched_validity_time_exemption(self): """Test that no ValueError is raised for unmatched validity times if we use the timeblending=True flag. As long as no exception is raised this test passes.""" self.cube.remove_coord("time") self.cube.coord("forecast_reference_time").rename("time") plugin = WeightedBlendAcrossWholeDimension(self.coord, timeblending=True) plugin.check_compatible_time_points(self.cube)
def tests_threshold_splicing_works_weighted_max(self): """Test weighted_max works with a threshold dimension.""" coord = "time" plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_maximum') weights = np.array([0.8, 0.2]) result = plugin.process(self.cube_threshold, weights) expected_result_array = np.ones((2, 2, 2)) * 0.4 self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_weighted_max_weights_none(self): """Test it works for weighted max with weights set to None.""" coord = "time" plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_maximum') weights = None result = plugin.process(self.cube, weights) expected_result_array = np.ones((2, 2)) self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_weights_equal_array(self): """Test it works with weights set to array (0.8, 0.2).""" coord = "time" plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_mean') weights = np.array([0.8, 0.2]) result = plugin.process(self.cube, weights) expected_result_array = np.ones((2, 2)) * 1.2 self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_coord_adjust_set(self): """Test it works with coord adjust set.""" coord = "time" coord_adjust = example_coord_adjust plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_mean', coord_adjust) result = plugin.process(self.cube) self.assertAlmostEqual(result.coord(coord).points, [402193.5])
def test_incompatible_weights_and_data_cubes(self): """Test an exception is raised if the weights cube and the data cube have incompatible coordinates.""" self.weights1d.coord(self.coord).rename("threshold") plugin = WeightedBlendAcrossWholeDimension(self.coord) msg = ("threshold is a coordinate on the weights cube but it " "is not found on the cube we are trying to collapse.") with self.assertRaisesRegex(ValueError, msg): plugin.shape_weights(self.cube, self.weights1d)
def test_weighted_max_non_equal_weights_array(self): """Test it works for weighted_max with weights [0.2, 0.8] given as a array.""" coord = "time" plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_maximum') weights = np.array([0.2, 0.8]) result = plugin.process(self.cube, weights) expected_result_array = np.ones((2, 2)) * 1.6 self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_3D_weights_3D_cube_weighted_mean(self): """Test a 3D cube of weights results in a 3D array of weights of the same shape as the data cube.""" coord = "forecast_reference_time" plugin = WeightedBlendAcrossWholeDimension(coord) result = plugin.shape_weights(self.cube, self.weights3d) self.assertEqual(self.cube.shape, result.shape) self.assertArrayEqual(self.weights3d.data, result)
def test_fails_perc_coord_not_dim(self): """Test it raises a Value Error if percentile coord not a dim.""" coord = "forecast_reference_time" plugin = WeightedBlendAcrossWholeDimension(coord) new_cube = self.cube.copy() new_cube.add_aux_coord(AuxCoord([10.0], long_name="percentile")) msg = "The percentile coord must be a dimension " "of the cube." with self.assertRaisesRegex(ValueError, msg): plugin.check_percentile_coord(new_cube)
def test_without_weights(self): """Test function when a data cube is provided, but no weights cube which should result in equal weightings.""" plugin = WeightedBlendAcrossWholeDimension(self.coord) result = plugin.weighted_mean(self.cube, None) expected = np.full((2, 2), 2.0) self.assertIsInstance(result, iris.cube.Cube) self.assertArrayAlmostEqual(result.data, expected)
def test_incompatible_weights_and_data_cubes_shape(self): """Test an exception is raised if the weights cube and the data cube have incompatible shapes.""" coord = "forecast_reference_time" plugin = WeightedBlendAcrossWholeDimension(coord) msg = "Weights cube is not a compatible shape" with self.assertRaisesRegex(ValueError, msg): plugin.shape_weights(self.cube[:1], self.weights1d)
def test_percentiles_weights_none(self): """Test it works for percentiles with weights set to None.""" coord = "time" plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_mean') weights = None perc_cube = percentile_cube() result = plugin.process(perc_cube, weights) expected_result_array = np.reshape(BLENDED_PERCENTILE_DATA1, (6, 2, 2)) self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_forecast_reference_time_exception(self): """Test that a ValueError is raised if the coordinate to be blended is forecast_reference_time and the points on the time coordinate are not equal.""" coord = "forecast_reference_time" plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_mean') msg = ('For blending using the forecast_reference_time') with self.assertRaisesRegexp(ValueError, msg): plugin.process(self.cube)
def test_fails_coord_not_in_weights_cube(self): """Test it raises CoordinateNotFoundError if the blending coord is not found in the weights cube.""" coord = "forecast_reference_time" self.weights1d.remove_coord("forecast_reference_time") plugin = WeightedBlendAcrossWholeDimension(coord) msg = ('Coordinate to be collapsed not found in weights cube.') with self.assertRaisesRegex(CoordinateNotFoundError, msg): plugin.process(self.cube, self.weights1d)
def test_fails_perc_coord_not_dim(self): """Test it raises a Value Error if not percentile coord not a dim.""" coord = "time" plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_mean') new_cube = self.cube.copy() new_cube.add_aux_coord( AuxCoord([10.0], long_name="percentile_over_time")) msg = ('The percentile coord must be a dimension ' 'of the cube.') with self.assertRaisesRegexp(ValueError, msg): plugin.process(new_cube)
def test_with_weights(self): """Test function when a data cube and a weights cube are provided.""" coord = "forecast_reference_time" plugin = WeightedBlendAcrossWholeDimension(coord) result = plugin.weighted_mean(self.cube, self.weights1d) expected = np.full((2, 2), 1.5) self.assertIsInstance(result, iris.cube.Cube) self.assertArrayAlmostEqual(result.data, expected)
def test_with_weights(self): """Test function when a data cube and a weights cube are provided.""" perc_cube = percentile_cube() coord = "forecast_reference_time" plugin = WeightedBlendAcrossWholeDimension(coord) perc_coord = perc_cube.coord("percentile") result = plugin.percentile_weighted_mean(perc_cube, self.weights1d, perc_coord) self.assertIsInstance(result, iris.cube.Cube) self.assertArrayAlmostEqual(result.data, BLENDED_PERCENTILE_DATA)
def test_fails_more_than_one_perc_coord(self): """Test it raises a Value Error if more than one percentile coord.""" coord = "time" plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_mean') new_cube = percentile_cube() new_cube.add_aux_coord( AuxCoord([10.0], long_name="percentile_over_dummy")) msg = ('There should only be one percentile coord ' 'on the cube.') with self.assertRaisesRegexp(ValueError, msg): plugin.process(new_cube)
def test_weights_do_not_sum_to_1_error(self): """Test that if a weights cube is provided which is not properly normalised, i.e. the weights do not sum to one over the blending dimension, an error is raised.""" plugin = WeightedBlendAcrossWholeDimension(self.coord) weights = self.weights3d.data weights[0, 0, 1] = 1.0 msg = "Weights do not sum to 1 over the blending coordinate." with self.assertRaisesRegex(ValueError, msg): plugin.check_weights(weights, 0)
def test_scalar_coord(self): """Test plugin throws an error if trying to blending across a scalar coordinate.""" coord = "dummy_scalar_coord" plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_mean') weights = ([1.0]) msg = 'has no associated dimension' with self.assertRaisesRegex(ValueError, msg): _ = plugin.process(self.cube_with_scalar, weights)
def test_fails_percentile_data_max_mode(self): """Test a Value Error is raised if the maximum mode is applied to percentile data.""" coord = "forecast_reference_time" plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_maximum') new_cube = percentile_cube() msg = ('The "weighted_maximum" mode is not supported for percentile ' 'data.') with self.assertRaisesRegex(ValueError, msg): plugin.check_percentile_coord(new_cube)
def test_fails_weights_shape(self): """Test it raises a Value Error if weights shape does not match coord shape.""" coord = "time" plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_mean') weights = [0.1, 0.2, 0.7] msg = ('The weights array must match the shape ' + 'of the coordinate in the input cube') with self.assertRaisesRegexp(ValueError, msg): plugin.process(self.cube, weights)
def test_without_weights(self): """Test function when a data cube is provided, but no weights cube which should result in equal weightings.""" plugin = WeightedBlendAcrossWholeDimension(self.coord) perc_coord = self.perc_cube.coord("percentile") result = plugin.percentile_weighted_mean(self.perc_cube, None, perc_coord) self.assertIsInstance(result, iris.cube.Cube) self.assertArrayAlmostEqual(result.data, BLENDED_PERCENTILE_DATA_EQUAL_WEIGHTS)
def tests_threshold_splicing_works_with_threshold(self): """Test splicing works when the blending is over threshold.""" coord = "threshold" plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_mean') weights = np.array([0.8, 0.2]) self.cube_threshold.data[0, :, :, :] = 0.5 self.cube_threshold.data[1, :, :, :] = 0.8 result = plugin.process(self.cube_threshold, weights) expected_result_array = np.ones((2, 2, 2)) * 0.56 self.assertArrayAlmostEqual(result.data, expected_result_array)
def test_unmatched_validity_time_exception(self): """Test that a ValueError is raised if the validity time of the slices over the blending coordinate differ. We should only be blending data at equivalent times unless we are triangular time blending.""" self.cube.remove_coord("time") self.cube.coord("forecast_reference_time").rename("time") coord = "forecast_reference_time" plugin = WeightedBlendAcrossWholeDimension(coord) msg = "Attempting to blend data for different validity times." with self.assertRaisesRegex(ValueError, msg): plugin.check_compatible_time_points(self.cube)
def test_without_weights(self): """Test function when a data cube is provided, but no weights cube which should result in equal weightings.""" coord = "forecast_reference_time" plugin = WeightedBlendAcrossWholeDimension(coord, 'weighted_maximum') result = plugin.weighted_maximum(self.cube, None) expected = np.full((2, 2), 1.) self.assertIsInstance(result, iris.cube.Cube) self.assertArrayAlmostEqual(result.data, expected)
def test_scalar_coord(self): """Test plugin throws an error if trying to blending across a scalar coordinate.""" coord = "dummy_scalar_coord" new_scalar_coord = AuxCoord(1, long_name=coord, units='no_unit') self.cube.add_aux_coord(new_scalar_coord) plugin = WeightedBlendAcrossWholeDimension(coord) weights = ([1.0]) msg = 'has no associated dimension' with self.assertRaisesRegex(ValueError, msg): plugin.process(self.cube, weights)