def test_ice_large_with_fc(self): """Test that large VII probs do increase zero lightning risk when forecast lead time is non-zero (three forecast_period points)""" self.ice_cube.data[:, 1, 1] = 1.0 self.fg_cube.data[1, 1] = 0.0 frt_point = self.fg_cube.coord("forecast_reference_time").points[0] fg_cube_input = CubeList([]) for fc_time in np.array([1, 2.5, 3]) * 3600: # seconds fg_cube_next = self.fg_cube.copy() fg_cube_next.coord("time").points = [frt_point + fc_time] fg_cube_next.coord("forecast_period").points = [fc_time] fg_cube_input.append(squeeze(fg_cube_next)) fg_cube_input = fg_cube_input.merge_cube() expected = fg_cube_input.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0.54 expected.data[1, 1, 1] = 0.0 expected.data[2, 1, 1] = 0.0 result = self.plugin.apply_ice(fg_cube_input, self.ice_cube) self.assertArrayAlmostEqual(result.data, expected.data)
class Test__create_template_slice(IrisTest): """Test create_template_slice method""" def setUp(self): """ Set up a basic input cube. Input cube has 2 thresholds on and 3 forecast_reference_times """ thresholds = [10, 20] data = np.ones((2, 2, 3), dtype=np.float32) cycle1 = set_up_probability_cube( data, thresholds, spatial_grid="equalarea", time=datetime(2017, 11, 10, 4, 0), frt=datetime(2017, 11, 10, 0, 0), ) cycle2 = set_up_probability_cube( data, thresholds, spatial_grid="equalarea", time=datetime(2017, 11, 10, 4, 0), frt=datetime(2017, 11, 10, 1, 0), ) cycle3 = set_up_probability_cube( data, thresholds, spatial_grid="equalarea", time=datetime(2017, 11, 10, 4, 0), frt=datetime(2017, 11, 10, 2, 0), ) self.cube_to_collapse = CubeList([cycle1, cycle2, cycle3]).merge_cube() self.cube_to_collapse = squeeze(self.cube_to_collapse) self.cube_to_collapse.rename("weights") # This input array has 3 forecast reference times and 2 thresholds. # The two thresholds have the same weights. self.cube_to_collapse.data = np.array( [ [[[1, 0, 1], [1, 1, 1]], [[1, 0, 1], [1, 1, 1]]], [[[0, 0, 1], [0, 1, 1]], [[0, 0, 1], [0, 1, 1]]], [[[1, 1, 1], [1, 1, 1]], [[1, 1, 1], [1, 1, 1]]], ], dtype=np.float32, ) self.cube_to_collapse.data = np.ma.masked_equal( self.cube_to_collapse.data, 0) self.plugin = SpatiallyVaryingWeightsFromMask( "forecast_reference_time") def test_multi_dim_blend_coord_fail(self): """Test error is raised when we have a multi-dimensional blend_coord""" # Add a surface altitude coordinate which covers x and y dimensions. altitudes = np.array([[10, 20, 30], [20, 30, 10]]) altitudes_coord = AuxCoord(altitudes, standard_name="surface_altitude", units="m") self.cube_to_collapse.add_aux_coord(altitudes_coord, data_dims=(2, 3)) message = "Blend coordinate must only be across one dimension." plugin = SpatiallyVaryingWeightsFromMask("surface_altitude") with self.assertRaisesRegex(ValueError, message): plugin._create_template_slice(self.cube_to_collapse) def test_varying_mask_fail(self): """Test error is raised when mask varies along collapsing dim""" # Check fails when blending along threshold coordinate, as mask # varies along this coordinate. threshold_coord = find_threshold_coordinate(self.cube_to_collapse) message = "The mask on the input cube can only vary along the blend_coord" plugin = SpatiallyVaryingWeightsFromMask(threshold_coord.name()) with self.assertRaisesRegex(ValueError, message): plugin._create_template_slice(self.cube_to_collapse) def test_scalar_blend_coord_fail(self): """Test error is raised when blend_coord is scalar""" message = "Blend coordinate must only be across one dimension." with self.assertRaisesRegex(ValueError, message): self.plugin._create_template_slice(self.cube_to_collapse[0]) def test_basic(self): """Test a correct template slice is returned for simple case""" expected = self.cube_to_collapse.copy()[:, 0, :, :] result = self.plugin._create_template_slice(self.cube_to_collapse) self.assertEqual(expected.metadata, result.metadata) self.assertArrayAlmostEqual(expected.data, result.data) def test_basic_no_change(self): """Test a correct template slice is returned for a case where no slicing is needed""" input_cube = self.cube_to_collapse.copy()[:, 0, :, :] expected = input_cube.copy() result = self.plugin._create_template_slice(input_cube) self.assertEqual(expected.metadata, result.metadata) self.assertArrayAlmostEqual(expected.data, result.data) def test_aux_blending_coord(self): """Test a correct template slice is returned when blending_coord is an AuxCoord""" expected = self.cube_to_collapse.copy()[:, 0, :, :] plugin = SpatiallyVaryingWeightsFromMask("forecast_period") result = self.plugin._create_template_slice(self.cube_to_collapse) self.assertEqual(expected.metadata, result.metadata) self.assertArrayAlmostEqual(expected.data, result.data)
class Test_apply_ice(IrisTest): """Test the apply_ice method.""" def setUp(self): """Create cubes with a single zero prob(precip) point. The cubes look like this: precipitation_amount / (kg m^-2) Dimension coordinates: time: 1; projection_y_coordinate: 3; projection_x_coordinate: 3; Auxiliary coordinates: forecast_period (on time coord): 0.0 hours (simulates nowcast data) Scalar coordinates: forecast_reference_time: 2015-11-23 03:00:00 Data: self.fg_cube: All points contain float(1.) Cube name is "probability_of_lightning". self.ice_cube: With extra coordinate of length(3) "threshold" containing points [0.5, 1., 2.] kg m^-2. Time and forecast_period dimensions "sqeezed" to be Scalar coords. All points contain float(0.) Cube name is "probability_of_vertical_integral_of_ice". """ self.fg_cube = add_forecast_reference_time_and_forecast_period( set_up_cube_with_no_realizations(zero_point_indices=[], num_grid_points=3), fp_point=0.0) self.fg_cube.rename("probability_of_lightning") self.ice_cube = squeeze( add_forecast_reference_time_and_forecast_period(set_up_cube( num_realization_points=3, zero_point_indices=[], num_grid_points=3), fp_point=0.0)) threshold_coord = self.ice_cube.coord('realization') threshold_coord.points = [0.5, 1.0, 2.0] threshold_coord.rename('threshold') threshold_coord.units = cf_units.Unit('kg m^-2') self.ice_cube.data = np.zeros_like(self.ice_cube.data) self.ice_cube.rename("probability_of_vertical_integral_of_ice") self.plugin = Plugin() def test_basic(self): """Test that the method returns the expected cube type""" result = self.plugin.apply_ice(self.fg_cube, self.ice_cube) self.assertIsInstance(result, Cube) def test_input(self): """Test that the method does not modify the input cubes.""" cube_a = self.fg_cube.copy() cube_b = self.ice_cube.copy() self.plugin.apply_ice(cube_a, cube_b) self.assertArrayAlmostEqual(cube_a.data, self.fg_cube.data) self.assertArrayAlmostEqual(cube_b.data, self.ice_cube.data) def test_missing_threshold_low(self): """Test that the method raises an error if the ice_cube doesn't have a threshold coordinate for 0.5.""" self.ice_cube.coord('threshold').points = [0.4, 1., 2.] msg = (r"No matching prob\(Ice\) cube for threshold 0.5") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.apply_ice(self.fg_cube, self.ice_cube) def test_missing_threshold_mid(self): """Test that the method raises an error if the ice_cube doesn't have a threshold coordinate for 1.0.""" self.ice_cube.coord('threshold').points = [0.5, 0.9, 2.] msg = (r"No matching prob\(Ice\) cube for threshold 1.") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.apply_ice(self.fg_cube, self.ice_cube) def test_missing_threshold_high(self): """Test that the method raises an error if the ice_cube doesn't have a threshold coordinate for 2.0.""" self.ice_cube.coord('threshold').points = [0.5, 1., 4.] msg = (r"No matching prob\(Ice\) cube for threshold 2.") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.apply_ice(self.fg_cube, self.ice_cube) def test_ice_null(self): """Test that small VII probs do not increase moderate lightning risk""" self.ice_cube.data[:, 1, 1] = 0. self.ice_cube.data[0, 1, 1] = 0.5 self.fg_cube.data[0, 1, 1] = 0.25 expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0.25 result = self.plugin.apply_ice(self.fg_cube, self.ice_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_ice_zero(self): """Test that zero VII probs do not increase zero lightning risk""" self.ice_cube.data[:, 1, 1] = 0. self.fg_cube.data[0, 1, 1] = 0. expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0. result = self.plugin.apply_ice(self.fg_cube, self.ice_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_ice_small(self): """Test that small VII probs do increase zero lightning risk""" self.ice_cube.data[:, 1, 1] = 0. self.ice_cube.data[0, 1, 1] = 0.5 self.fg_cube.data[0, 1, 1] = 0. expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0.05 result = self.plugin.apply_ice(self.fg_cube, self.ice_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_ice_large(self): """Test that large VII probs do increase zero lightning risk""" self.ice_cube.data[:, 1, 1] = 1. self.fg_cube.data[0, 1, 1] = 0. expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0.9 result = self.plugin.apply_ice(self.fg_cube, self.ice_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_ice_large_with_fc(self): """Test that large VII probs do increase zero lightning risk when forecast lead time is non-zero (two forecast_period points)""" self.ice_cube.data[:, 1, 1] = 1. self.fg_cube.data[0, 1, 1] = 0. self.fg_cube.coord('forecast_period').points = [1.] # hours fg_cube_next = self.fg_cube.copy() time_pt, = self.fg_cube.coord('time').points fg_cube_next.coord('time').points = [time_pt + 2.] # hours fg_cube_next.coord('forecast_period').points = [3.] # hours self.fg_cube = CubeList([squeeze(self.fg_cube), squeeze(fg_cube_next)]).merge_cube() expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0.54 expected.data[1, 1, 1] = 0.0 result = self.plugin.apply_ice(self.fg_cube, self.ice_cube) self.assertArrayAlmostEqual(result.data, expected.data)
class Test_apply_ice(IrisTest): """Test the apply_ice method.""" def setUp(self): """Create test cubes and plugin instance. The cube coordinates look like this: Dimension coordinates: projection_y_coordinate: 3; projection_x_coordinate: 3; Scalar coordinates: time: 2015-11-23 07:00:00 forecast_reference_time: 2015-11-23 07:00:00 forecast_period: 0 seconds self.vii_cube: Has extra coordinate of length(3) "threshold" containing points [0.5, 1., 2.] kg m-2. """ (_, self.fg_cube, _, _, self.ice_cube) = (set_up_lightning_test_cubes( validity_time=dt(2015, 11, 23, 7), fg_frt=dt(2015, 11, 23, 7))) self.plugin = Plugin() self.ice_threshold_coord = find_threshold_coordinate(self.ice_cube) def test_basic(self): """Test that the method returns the expected cube type""" result = self.plugin.apply_ice(self.fg_cube, self.ice_cube) self.assertIsInstance(result, Cube) def test_input(self): """Test that the method does not modify the input cubes.""" cube_a = self.fg_cube.copy() cube_b = self.ice_cube.copy() self.plugin.apply_ice(cube_a, cube_b) self.assertArrayAlmostEqual(cube_a.data, self.fg_cube.data) self.assertArrayAlmostEqual(cube_b.data, self.ice_cube.data) def test_missing_threshold_low(self): """Test that the method raises an error if the ice_cube doesn't have a threshold coordinate for 0.5.""" self.ice_threshold_coord.points = [0.4, 1., 2.] msg = (r"No matching prob\(Ice\) cube for threshold 0.5") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.apply_ice(self.fg_cube, self.ice_cube) def test_missing_threshold_mid(self): """Test that the method raises an error if the ice_cube doesn't have a threshold coordinate for 1.0.""" self.ice_threshold_coord.points = [0.5, 0.9, 2.] msg = (r"No matching prob\(Ice\) cube for threshold 1.") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.apply_ice(self.fg_cube, self.ice_cube) def test_missing_threshold_high(self): """Test that the method raises an error if the ice_cube doesn't have a threshold coordinate for 2.0.""" self.ice_threshold_coord.points = [0.5, 1., 4.] msg = (r"No matching prob\(Ice\) cube for threshold 2.") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.apply_ice(self.fg_cube, self.ice_cube) def test_ice_null(self): """Test that small VII probs do not increase moderate lightning risk""" self.ice_cube.data[:, 1, 1] = 0. self.ice_cube.data[0, 1, 1] = 0.5 self.fg_cube.data[1, 1] = 0.25 expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[1, 1] = 0.25 result = self.plugin.apply_ice(self.fg_cube, self.ice_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_ice_zero(self): """Test that zero VII probs do not increase zero lightning risk""" self.ice_cube.data[:, 1, 1] = 0. self.fg_cube.data[1, 1] = 0. expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[1, 1] = 0. result = self.plugin.apply_ice(self.fg_cube, self.ice_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_ice_small(self): """Test that small VII probs do increase zero lightning risk""" self.ice_cube.data[:, 1, 1] = 0. self.ice_cube.data[0, 1, 1] = 0.5 self.fg_cube.data[1, 1] = 0. expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[1, 1] = 0.05 result = self.plugin.apply_ice(self.fg_cube, self.ice_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_ice_large(self): """Test that large VII probs do increase zero lightning risk""" self.ice_cube.data[:, 1, 1] = 1. self.fg_cube.data[1, 1] = 0. expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[1, 1] = 0.9 result = self.plugin.apply_ice(self.fg_cube, self.ice_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_ice_large_with_fc(self): """Test that large VII probs do increase zero lightning risk when forecast lead time is non-zero (two forecast_period points)""" self.ice_cube.data[:, 1, 1] = 1. self.fg_cube.data[1, 1] = 0. self.fg_cube.coord('forecast_period').points = [3600] # 1 hour fg_cube_next = self.fg_cube.copy() time_pt, = self.fg_cube.coord('time').points fg_cube_next.coord('time').points = [time_pt + 7200] # 2 hours fg_cube_next.coord('forecast_period').points = [10800] # 3 hours self.fg_cube = CubeList([squeeze(self.fg_cube), squeeze(fg_cube_next)]).merge_cube() expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0.54 expected.data[1, 1, 1] = 0.0 result = self.plugin.apply_ice(self.fg_cube, self.ice_cube) self.assertArrayAlmostEqual(result.data, expected.data)