class Test__update_metadata(IrisTest): """Test the _update_metadata method.""" def setUp(self): """Create a cube like this: probability_of_lwe_precipitation_rate_above_threshold / (1) Dimension coordinates: lwe_precipitation_rate: 1; projection_y_coordinate: 16; projection_x_coordinate: 16; Scalar coordinates: forecast_period: 14400 seconds forecast_reference_time: 2017-11-10 00:00:00 time: 2017-11-10 04:00:00 Cell methods: mean: realization The lwe_precipitation_rate coordinate will have the attribute: spp__relative_to_threshold: above. """ data = np.ones((1, 16, 16), dtype=np.float32) thresholds = np.array([0.5], dtype=np.float32) self.cube = set_up_probability_cube( data, thresholds, variable_name="lwe_precipitation_rate", threshold_units="mm h-1", ) self.cube.add_cell_method(CellMethod("mean", coords="realization")) self.plugin = Plugin() def test_basic(self): """Test that the method returns the expected cube type and that the metadata are as expected. We expect a new name, the threshold coord to be removed and cell methods to be discarded.""" result = self.plugin._update_metadata(self.cube) self.assertIsInstance(result, Cube) self.assertEqual(result.name(), "probability_of_rate_of_lightning_above_threshold") msg = "No threshold coord found" with self.assertRaisesRegex(CoordinateNotFoundError, msg): find_threshold_coordinate(result) self.assertEqual(result.cell_methods, ()) def test_input(self): """Test that the method does not modify the input cube data.""" incube = self.cube.copy() self.plugin._update_metadata(incube) self.assertArrayAlmostEqual(incube.data, self.cube.data) self.assertEqual(incube.metadata, self.cube.metadata) def test_missing_threshold_coord(self): """Test that the method raises an error in Iris if the cube doesn't have a threshold coordinate to remove.""" self.cube.remove_coord(find_threshold_coordinate(self.cube)) msg = "No threshold coord found" with self.assertRaisesRegex(CoordinateNotFoundError, msg): self.plugin._update_metadata(self.cube)
class Test__update_metadata(IrisTest): """Test the _update_metadata method.""" def setUp(self): """Create a cube with a single non-zero point like this: precipitation_amount / (kg m^-2) Dimension coordinates: realization: 1; time: 1; projection_y_coordinate: 3; projection_x_coordinate: 3; Auxiliary coordinates: forecast_period (on time coord): 4.0 hours Scalar coordinates: forecast_reference_time: 2015-11-23 03:00:00 threshold: 0.5 mm hr-1 Data: All points contain float(1.) except the zero point [0, 0, 1, 1] which is float(0.) """ self.cube = add_forecast_reference_time_and_forecast_period( set_up_cube()) coord = DimCoord(0.5, long_name="threshold", units='mm hr^-1') self.cube.add_aux_coord(coord) self.cube.add_cell_method(CellMethod('mean', coords='realization')) self.plugin = Plugin() def test_basic(self): """Test that the method returns the expected cube type and that the metadata are as expected. We expect a new name, the threshold coord to be removed and cell methods to be discarded.""" result = self.plugin._update_metadata(self.cube) self.assertIsInstance(result, Cube) self.assertEqual(result.name(), "probability_of_lightning") msg = ("Expected to find exactly 1 threshold coordinate, but found " "none.") with self.assertRaisesRegex(CoordinateNotFoundError, msg): result.coord('threshold') self.assertEqual(result.cell_methods, ()) def test_input(self): """Test that the method does not modify the input cube data.""" incube = self.cube.copy() self.plugin._update_metadata(incube) self.assertArrayAlmostEqual(incube.data, self.cube.data) self.assertEqual(incube.metadata, self.cube.metadata) def test_missing_threshold_coord(self): """Test that the method raises an error in Iris if the cube doesn't have a threshold coordinate to remove.""" self.cube.remove_coord('threshold') msg = ("Expected to find exactly 1 threshold coordinate, but found no") with self.assertRaisesRegex(CoordinateNotFoundError, msg): self.plugin._update_metadata(self.cube)
def test_result_with_vii(self): """Test that the method returns the expected data when vii is present""" # Set precip_cube forecast period to be zero. self.precip_cube.coord('forecast_period').points = [0.] expected = self.set_up_vii_input_output() # No halo - we're only testing this method. # 2000m is the grid-length, so halo includes only one pixel. plugin = Plugin(2000.) result = plugin.process( CubeList([ self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube ])) self.assertIsInstance(result, Cube) self.assertArrayAlmostEqual(result.data, expected.data)
def setUp(self): """Create a cube like this: probability_of_lwe_precipitation_rate_above_threshold / (1) Dimension coordinates: lwe_precipitation_rate: 1; projection_y_coordinate: 16; projection_x_coordinate: 16; Scalar coordinates: forecast_period: 14400 seconds forecast_reference_time: 2017-11-10 00:00:00 time: 2017-11-10 04:00:00 Cell methods: mean: realization The lwe_precipitation_rate coordinate will have the attribute: spp__relative_to_threshold: above. """ data = np.ones((1, 16, 16), dtype=np.float32) thresholds = np.array([0.5], dtype=np.float32) self.cube = set_up_probability_cube( data, thresholds, variable_name="lwe_precipitation_rate", threshold_units="mm h-1", ) self.cube.add_cell_method(CellMethod("mean", coords="realization")) self.plugin = Plugin()
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.cube: Metadata describes the nowcast lightning fields to be calculated. forecast_period: 0 seconds (simulates nowcast data) self.fg_cube: Has 4 hour forecast period, to test impact at lr2 self.ltng_cube: forecast_period: 0 seconds (simulates nowcast data) self.precip_cube: Has extra coordinate of length(3) "threshold" containing points [0.5, 7., 35.] mm h-1. self.vii_cube: Has extra coordinate of length(3) "threshold" containing points [0.5, 1., 2.] kg m-2. """ ( self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube, ) = set_up_lightning_test_cubes() self.plugin = Plugin()
def test_result_with_vii_longfc(self): """Test that the method returns the expected data when vii is present and forecast time is 4 hours""" expected = self.set_up_vii_input_output() # test_vii_null with no precip will now return 0.0067 expected.data[5, 5] = 0.0067 # test_vii_small with no and light precip will now return zero expected.data[7, 5:7] = 0. # test_vii_large with no and light precip now return zero # and 0.25 for heavy precip expected.data[8, 5:8] = [0., 0., 0.25] # No halo - we're only testing this method. # 2000m is the grid-length, so halo includes only one pixel. plugin = Plugin(2000.) result = plugin.process( CubeList([ self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube ])) self.assertIsInstance(result, Cube) self.assertArrayAlmostEqual(result.data, expected.data)
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): 4.0 hours (simulates UM data) Scalar coordinates: forecast_reference_time: 2015-11-23 03:00:00 Data: self.fg_cube: forecast_period (on time coord): 0.0 hours (simulates nowcast data) All points contain float(1.) Cube name is "probability_of_lightning". self.precip_cube: With extra coordinate of length(3) "threshold" containing points [0.5, 7., 35.] mm hr-1. All points contain float(1.) except the zero point [0, 0, 1, 1] which is float(0.) and [1:, 0, ...] which are float(0.) Cube name is "probability_of_precipitation". Cube has added attribute {'relative_to_threshold': 'above'} """ 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.precip_cube = (add_forecast_reference_time_and_forecast_period( set_up_cube(num_realization_points=3, zero_point_indices=((0, 1, 1), ), num_grid_points=3))) threshold_coord = self.precip_cube.coord('realization') threshold_coord.points = [0.5, 7.0, 35.0] threshold_coord.rename('threshold') threshold_coord.units = cf_units.Unit('mm hr-1') self.precip_cube.rename("probability_of_precipitation") self.precip_cube.attributes.update({'relative_to_threshold': 'above'}) self.precip_cube.data[1:, 0, ...] = 0. self.plugin = Plugin()
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 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.fg_cube: Has 4 hour forecast period self.precip_cube: Has extra coordinate of length(3) "threshold" containing points [0.5, 7., 35.] mm h-1. """ (_, self.fg_cube, _, self.precip_cube, _) = set_up_lightning_test_cubes() self.plugin = Plugin() self.precip_threshold_coord = find_threshold_coordinate(self.precip_cube)
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 setUp(self): """Create a cube with a single non-zero point like this: precipitation_amount / (kg m^-2) Dimension coordinates: realization: 1; time: 1; projection_y_coordinate: 3; projection_x_coordinate: 3; Auxiliary coordinates: forecast_period (on time coord): 4.0 hours Scalar coordinates: forecast_reference_time: 2015-11-23 03:00:00 threshold: 0.5 mm hr-1 Data: All points contain float(1.) except the zero point [0, 0, 1, 1] which is float(0.) """ self.cube = add_forecast_reference_time_and_forecast_period( set_up_cube()) coord = DimCoord(0.5, long_name="threshold", units='mm hr^-1') self.cube.add_aux_coord(coord) self.cube.add_cell_method(CellMethod('mean', coords='realization')) self.plugin = Plugin()
def setUp(self): """Create test cubes and plugin instance. The cube coordinates look like this: Dimension coordinates: projection_y_coordinate: 16; projection_x_coordinate: 16; Scalar coordinates: time: 2015-11-23 07:00:00 forecast_reference_time: 2015-11-23 07:00:00 forecast_period: 0 seconds self.fg_cube: Has 4 hour forecast period, to test impact on "lightning risk 2 level" output (see improver.nowcasting.lightning for details) self.ltng_cube: forecast_period: 0 seconds (simulates nowcast data) self.precip_cube: Has extra coordinate of length(3) "threshold" containing points [0.5, 7., 35.] mm h-1. Has a 4 hour forecast period. self.vii_cube: Has extra coordinate of length(3) "threshold" containing points [0.5, 1., 2.] kg m-2. """ (_, self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube) = set_up_lightning_test_cubes(grid_points=16) # reset some data and give precip cube a 4 hour forecast period self.precip_cube.data[0, ...] = 1. self.precip_cube.coord("forecast_period").points = [4 * 3600.] # sort out spatial coordinates - need smaller grid length (set to 2 km) for cube in [ self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube ]: points_array = 2000. * np.arange(16).astype(np.float32) cube.coord(axis='x').points = points_array cube.coord(axis='y').points = points_array self.plugin = Plugin()
class Test_process(IrisTest): """Test the nowcast lightning plugin.""" def setUp(self): """Create test cubes and plugin instance. The cube coordinates look like this: Dimension coordinates: projection_y_coordinate: 16; projection_x_coordinate: 16; Scalar coordinates: time: 2015-11-23 07:00:00 forecast_reference_time: 2015-11-23 07:00:00 forecast_period: 0 seconds self.fg_cube: Has 4 hour forecast period, to test impact on "lightning risk 2 level" output (see improver.nowcasting.lightning for details) self.ltng_cube: forecast_period: 0 seconds (simulates nowcast data) self.precip_cube: Has extra coordinate of length(3) "threshold" containing points [0.5, 7., 35.] mm h-1. Has a 4 hour forecast period. self.vii_cube: Has extra coordinate of length(3) "threshold" containing points [0.5, 1., 2.] kg m-2. """ (_, self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube) = set_up_lightning_test_cubes(grid_points=16) # reset some data and give precip cube a 4 hour forecast period self.precip_cube.data[0, ...] = 1. self.precip_cube.coord("forecast_period").points = [4 * 3600.] # sort out spatial coordinates - need smaller grid length (set to 2 km) for cube in [ self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube ]: points_array = 2000. * np.arange(16).astype(np.float32) cube.coord(axis='x').points = points_array cube.coord(axis='y').points = points_array self.plugin = Plugin() def set_up_vii_input_output(self): """Used to modify setUp() to set up four standard VII tests.""" # Repeat all tests relating to vii from Test__modify_first_guess expected = self.fg_cube.copy() # expected.data contains all ones except where modified below: # Set up precip_cube with increasing intensity along x-axis # y=5; no precip self.precip_cube.data[:, 5:9, 5] = 0. # y=6; light precip self.precip_cube.data[0, 5:9, 6] = 0.1 self.precip_cube.data[1, 5:9, 6] = 0. # y=7; heavy precip self.precip_cube.data[:2, 5:9, 7] = 1. self.precip_cube.data[2, 5:9, 7] = 0. # y=8; intense precip self.precip_cube.data[:, 5:9, 8] = 1. # test_vii_null - with lightning-halo self.vii_cube.data[:, 5, 5:9] = 0. self.vii_cube.data[0, 5, 5:9] = 0.5 self.ltng_cube.data[5, 5:9] = 0. self.fg_cube.data[5, 5:9] = 0. expected.data[5, 5:9] = [0.05, 0.25, 0.25, 1.] # test_vii_zero self.vii_cube.data[:, 6, 5:9] = 0. self.ltng_cube.data[6, 5:9] = -1. self.fg_cube.data[6, 5:9] = 0. expected.data[6, 5:9] = [0., 0., 0.25, 1.] # test_vii_small # Set lightning data to -1 so it has a Null impact self.vii_cube.data[:, 7, 5:9] = 0. self.vii_cube.data[0, 7, 5:9] = 0.5 self.ltng_cube.data[7, 5:9] = -1. self.fg_cube.data[7, 5:9] = 0. expected.data[7, 5:9] = [0.05, 0.05, 0.25, 1.] # test_vii_large # Set lightning data to -1 so it has a Null impact self.vii_cube.data[:, 8, 5:9] = 1. self.ltng_cube.data[8, 5:9] = -1. self.fg_cube.data[8, 5:9] = 0. expected.data[8, 5:9] = [0.9, 0.9, 0.9, 1.] return expected def test_basic(self): """Test that the method returns the expected cube type with coords""" result = self.plugin.process( CubeList([self.fg_cube, self.ltng_cube, self.precip_cube])) self.assertIsInstance(result, Cube) # We expect the threshold coordinate to have been removed. threshold_coord = find_threshold_coordinate(self.precip_cube).name() self.assertCountEqual( find_dimension_coordinate_mismatch(result, self.precip_cube), [threshold_coord]) self.assertEqual(result.name(), 'probability_of_rate_of_lightning_above_threshold') self.assertEqual(result.units, '1') def test_basic_with_vii(self): """Test that the method returns the expected cube type when vii is present""" result = self.plugin.process( CubeList([ self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube ])) self.assertIsInstance(result, Cube) # We expect the threshold coordinate to have been removed. threshold_coord = find_threshold_coordinate(self.precip_cube).name() self.assertCountEqual( find_dimension_coordinate_mismatch(result, self.precip_cube), [threshold_coord]) self.assertEqual(result.name(), 'probability_of_rate_of_lightning_above_threshold') self.assertEqual(result.units, '1') def test_no_first_guess_cube(self): """Test that the method raises an error if the first_guess cube is omitted from the cubelist""" msg = (r"Got 0 cubes for constraint Constraint\(name=\'probability_of_" r"rate_of_lightning_above_threshold\'\), expecting 1.") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.process(CubeList([self.ltng_cube, self.precip_cube])) def test_no_lightning_cube(self): """Test that the method raises an error if the lightning cube is omitted from the cubelist""" msg = (r"Got 0 cubes for constraint Constraint\(name=\'rate_of_" r"lightning\'\), expecting 1.") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.process(CubeList([self.fg_cube, self.precip_cube])) def test_no_precip_cube(self): """Test that the method raises an error if the precip cube is omitted from the cubelist""" msg = (r"Got 0 cubes for constraint Constraint\(name=\'probability_of_" r"lwe_precipitation_rate_above_threshold\'\), expecting 1.") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.process(CubeList([self.fg_cube, self.ltng_cube])) def test_precip_has_no_thresholds(self): """Test that the method raises an error if the threshold coord is omitted from the precip_cube""" threshold_coord = find_threshold_coordinate(self.precip_cube) self.precip_cube.remove_coord(threshold_coord) msg = "No threshold coord found" with self.assertRaisesRegex(CoordinateNotFoundError, msg): self.plugin.process( CubeList([self.fg_cube, self.ltng_cube, self.precip_cube])) def test_result_with_vii(self): """Test that the method returns the expected data when vii is present""" # Set precip_cube forecast period to be zero. self.precip_cube.coord('forecast_period').points = [0.] expected = self.set_up_vii_input_output() # No halo - we're only testing this method. # 2000m is the grid-length, so halo includes only one pixel. plugin = Plugin(2000.) result = plugin.process( CubeList([ self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube ])) self.assertIsInstance(result, Cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_result_with_vii_longfc(self): """Test that the method returns the expected data when vii is present and forecast time is 4 hours""" expected = self.set_up_vii_input_output() # test_vii_null with no precip will now return 0.0067 expected.data[5, 5] = 0.0067 # test_vii_small with no and light precip will now return zero expected.data[7, 5:7] = 0. # test_vii_large with no and light precip now return zero # and 0.25 for heavy precip expected.data[8, 5:8] = [0., 0., 0.25] # No halo - we're only testing this method. # 2000m is the grid-length, so halo includes only one pixel. plugin = Plugin(2000.) result = plugin.process( CubeList([ self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube ])) self.assertIsInstance(result, 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.0, 2.0] 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.0] 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.0, 4.0] 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.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.0 self.fg_cube.data[1, 1] = 0.0 expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[1, 1] = 0.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.0 self.ice_cube.data[0, 1, 1] = 0.5 self.fg_cube.data[1, 1] = 0.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.0 self.fg_cube.data[1, 1] = 0.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 (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_apply_precip(IrisTest): """Test the apply_precip 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.fg_cube: Has 4 hour forecast period self.precip_cube: Has extra coordinate of length(3) "threshold" containing points [0.5, 7., 35.] mm h-1. """ (_, self.fg_cube, _, self.precip_cube, _) = set_up_lightning_test_cubes() self.plugin = Plugin() self.precip_threshold_coord = find_threshold_coordinate( self.precip_cube) def test_basic(self): """Test that the method returns the expected cube type""" result = self.plugin.apply_precip(self.fg_cube, self.precip_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.precip_cube.copy() self.plugin.apply_precip(cube_a, cube_b) self.assertArrayAlmostEqual(cube_a.data, self.fg_cube.data) self.assertArrayAlmostEqual(cube_b.data, self.precip_cube.data) def test_nearby_threshold_low(self): """Test that the method accepts a threshold point within machine tolerance.""" self.precip_threshold_coord.points = [0.5000000001, 7.0, 35.0] self.plugin.apply_precip(self.fg_cube, self.precip_cube) def test_missing_threshold_low(self): """Test that the method raises an error if the precip_cube doesn't have a threshold coordinate for 0.5.""" self.precip_threshold_coord.points = [1.0, 7.0, 35.0] msg = "No matching any precip cube for" with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.apply_precip(self.fg_cube, self.precip_cube) def test_missing_threshold_mid(self): """Test that the method raises an error if the precip_cube doesn't have a threshold coordinate for 7.0.""" self.precip_threshold_coord.points = [0.5, 8.0, 35.0] msg = "No matching high precip cube for" with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.apply_precip(self.fg_cube, self.precip_cube) def test_missing_threshold_high(self): """Test that the method raises an error if the precip_cube doesn't have a threshold coordinate for 35.0.""" self.precip_threshold_coord.points = [0.5, 7.0, 20.0] msg = "No matching intense precip cube for" with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.apply_precip(self.fg_cube, self.precip_cube) def test_precip_zero(self): """Test that zero precip probs reduce high lightning risk a lot""" expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[1, 1] = 0.0067 result = self.plugin.apply_precip(self.fg_cube, self.precip_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_precip_small(self): """Test that small precip probs reduce high lightning risk a bit""" self.precip_cube.data[:, 1, 1] = 0.0 self.precip_cube.data[0, 1, 1] = 0.075 expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[1, 1] = 0.625 result = self.plugin.apply_precip(self.fg_cube, self.precip_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_precip_light(self): """Test that high probs of light precip do not reduce high lightning risk""" self.precip_cube.data[:, 1, 1] = 0.0 self.precip_cube.data[0, 1, 1] = 0.8 expected = self.fg_cube.copy() # expected.data contains all ones result = self.plugin.apply_precip(self.fg_cube, self.precip_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_precip_heavy(self): """Test that prob of heavy precip increases zero lightning risk""" self.precip_cube.data[0, 1, 1] = 1.0 self.precip_cube.data[1, 1, 1] = 0.5 # Set first-guess to zero self.fg_cube.data[1, 1] = 0.0 expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[1, 1] = 0.25 result = self.plugin.apply_precip(self.fg_cube, self.precip_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_precip_heavy_null(self): """Test that low prob of heavy precip does not increase low lightning risk""" self.precip_cube.data[0, 1, 1] = 1.0 self.precip_cube.data[1, 1, 1] = 0.3 # Set first-guess to zero self.fg_cube.data[1, 1] = 0.1 expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[1, 1] = 0.1 result = self.plugin.apply_precip(self.fg_cube, self.precip_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_precip_intense(self): """Test that prob of intense precip increases zero lightning risk""" expected = self.fg_cube.copy() # expected.data contains all ones self.precip_cube.data[0, 1, 1] = 1.0 self.precip_cube.data[1, 1, 1] = 1.0 self.precip_cube.data[2, 1, 1] = 0.5 # Set first-guess to zero self.fg_cube.data[1, 1] = 0.0 result = self.plugin.apply_precip(self.fg_cube, self.precip_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_precip_intense_null(self): """Test that low prob of intense precip does not increase low lightning risk""" self.precip_cube.data[0, 1, 1] = 1.0 self.precip_cube.data[1, 1, 1] = 1.0 self.precip_cube.data[2, 1, 1] = 0.1 # Set first-guess to zero self.fg_cube.data[1, 1] = 0.1 expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[1, 1] = 0.25 # Heavy-precip result only result = self.plugin.apply_precip(self.fg_cube, self.precip_cube) self.assertArrayAlmostEqual(result.data, expected.data)
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): 4.0 hours (simulates UM data) Scalar coordinates: forecast_reference_time: 2015-11-23 03:00:00 Data: self.cube: Describes the nowcast fields to be calculated. forecast_period (on time coord): 0.0 hours (simulates nowcast data) All points contain float(1.) except the zero point [0, 1, 1] which is float(0.) self.fg_cube: All points contain float(1.) self.ltng_cube: forecast_period (on time coord): 0.0 hours (simulates nowcast data) All points contain float(1.) self.precip_cube: With extra coordinate of length(3) "threshold" containing points [0.5, 7., 35.] mm hr-1. All points contain float(1.) except the zero point [0, 0, 1, 1] which is float(0.) and [1:, 0, ...] which are float(0.) self.vii_cube: With extra coordinate of length(3) "threshold" containing points [0.5, 1., 2.] kg m^-2. forecast_period (on time coord): 0.0 hours (simulates nowcast data) Time and forecast_period dimensions "sqeezed" to be Scalar coords. All points contain float(0.) """ self.cube = add_forecast_reference_time_and_forecast_period( set_up_cube_with_no_realizations(zero_point_indices=((0, 1, 1), ), num_grid_points=3), fp_point=0.0) self.fg_cube = add_forecast_reference_time_and_forecast_period( set_up_cube_with_no_realizations(zero_point_indices=[], num_grid_points=3)) self.ltng_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.precip_cube = (add_forecast_reference_time_and_forecast_period( set_up_cube(num_realization_points=3, zero_point_indices=((0, 1, 1), ), num_grid_points=3), fp_point=0.0)) threshold_coord = self.precip_cube.coord('realization') threshold_coord.points = [0.5, 7.0, 35.0] threshold_coord.rename('threshold') threshold_coord.units = cf_units.Unit('mm hr-1') self.precip_cube.data[1:, 0, ...] = 0. # iris.util.queeze is applied here to demote the singular coord "time" # to a scalar coord. self.vii_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.vii_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.vii_cube.data = np.zeros_like(self.vii_cube.data) self.plugin = Plugin()
class Test__modify_first_guess(IrisTest): """Test the _modify_first_guess 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.cube: Metadata describes the nowcast lightning fields to be calculated. forecast_period: 0 seconds (simulates nowcast data) self.fg_cube: Has 4 hour forecast period, to test impact at lr2 self.ltng_cube: forecast_period: 0 seconds (simulates nowcast data) self.precip_cube: Has extra coordinate of length(3) "threshold" containing points [0.5, 7., 35.] mm h-1. self.vii_cube: Has extra coordinate of length(3) "threshold" containing points [0.5, 1., 2.] kg m-2. """ ( self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube, ) = set_up_lightning_test_cubes() self.plugin = Plugin() def test_basic(self): """Test that the method returns the expected cube type""" result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube) self.assertIsInstance(result, Cube) def test_input_with_vii(self): """Test that the method does not modify the input cubes.""" cube_a = self.cube.copy() cube_b = self.fg_cube.copy() cube_c = self.ltng_cube.copy() cube_d = self.precip_cube.copy() cube_e = self.vii_cube.copy() self.plugin._modify_first_guess(cube_a, cube_b, cube_c, cube_d, cube_e) self.assertArrayAlmostEqual(cube_a.data, self.cube.data) self.assertArrayAlmostEqual(cube_b.data, self.fg_cube.data) self.assertArrayAlmostEqual(cube_c.data, self.ltng_cube.data) self.assertArrayAlmostEqual(cube_d.data, self.precip_cube.data) self.assertArrayAlmostEqual(cube_e.data, self.vii_cube.data) def test_missing_lightning(self): """Test that the method raises an error if the lightning cube doesn't match the meta-data cube time coordinate.""" self.ltng_cube.coord("time").points = [1.0] msg = "No matching lightning cube for" with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) def test_missing_first_guess(self): """Test that the method raises an error if the first-guess cube doesn't match the meta-data cube time coordinate.""" self.fg_cube.coord("time").points = [1.0] msg = "is not available within the input cube within the " "allowed difference" with self.assertRaisesRegex(ValueError, msg): self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) def test_cube_has_no_time_coord(self): """Test that the method raises an error if the meta-data cube has no time coordinate.""" self.cube.remove_coord("time") msg = "Expected to find exactly 1 time coordinate, but found none." with self.assertRaisesRegex(CoordinateNotFoundError, msg): self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) def test_precip_zero(self): """Test that apply_precip is being called""" # Set lightning data to "no-data" so it has a Null impact self.ltng_cube.data = np.full_like(self.ltng_cube.data, -1.0) # No halo - we're only testing this method. expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[1, 1] = 0.0067 result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) self.assertArrayAlmostEqual(result.data, expected.data) def test_vii_large(self): """Test that ApplyIce is being called""" # Set lightning data to zero so it has a Null impact self.vii_cube.data[:, 1, 1] = 1.0 self.ltng_cube.data[1, 1] = -1.0 self.fg_cube.data[1, 1] = 0.0 # No halo - we're only testing this method. expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[1, 1] = 0.9 result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_null(self): """Test that large precip probs and -1 lrates have no impact""" # Set prob(precip) data for lowest threshold to to 0.1, the highest # value that has no impact. self.precip_cube.data[0, 1, 1] = 0.1 # Set lightning data to -1 so it has a Null impact self.ltng_cube.data = np.full_like(self.ltng_cube.data, -1.0) # No halo - we're only testing this method. expected = self.fg_cube.copy() # expected.data should be an unchanged copy of fg_cube. result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) self.assertArrayAlmostEqual(result.data, expected.data) def test_lrate_large(self): """Test that large lightning rates increase zero lightning risk""" expected = self.fg_cube.copy() # expected.data contains all ones # Set prob(precip) data for lowest threshold to to 1., so it has a Null # impact when lightning is present. self.precip_cube.data[0, 1, 1] = 1.0 # Set first-guess data zero point that will be increased self.fg_cube.data[1, 1] = 0.0 # No halo - we're only testing this method. result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) self.assertArrayAlmostEqual(result.data, expected.data) def test_lrate_large_shortfc(self): """Test that nearly-large lightning rates increases zero lightning risk when forecast_period is non-zero""" expected = self.fg_cube.copy() # expected.data contains all ones # Set precip data to 1. so it has a Null impact # Set prob(precip) data for lowest threshold to to 1., so it has a Null # impact when lightning is present. self.precip_cube.data[0, 1, 1] = 1.0 # Test the impact of the lightning-rate function. # A highish lightning value at one-hour lead time isn't high enough to # get to the high lightning category. self.ltng_cube.data[1, 1] = 0.8 self.cube.coord("forecast_period").points = [3600.0] # seconds # Set first-guess data zero point that will be increased self.fg_cube.data[1, 1] = 0.0 # This time, lightning probability increases only to 0.25, not 1. expected.data[1, 1] = 0.25 # No halo - we're only testing this method. result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) self.assertArrayAlmostEqual(result.data, expected.data) def test_lrate_large_null(self): """Test that large lightning rates do not increase high lightning risk""" expected = self.fg_cube.copy() # expected.data contains all ones # Set precip data to 1. so it has a Null impact # Set prob(precip) data for lowest threshold to to 1., so it has a Null # impact when lightning is present. self.precip_cube.data[0, 1, 1] = 1.0 # Set first-guess data zero point that will be increased self.fg_cube.data[1, 1] = 1.0 # No halo - we're only testing this method. result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) self.assertArrayAlmostEqual(result.data, expected.data) def test_lrate_small(self): """Test that lightning nearby (encoded as lightning rate zero) increases lightning risk at point""" # Set prob(precip) data for lowest threshold to to 1., so it has a Null # impact when lightning is present. self.precip_cube.data[0, 1, 1] = 1.0 # Set lightning data to zero to represent the data halo self.ltng_cube.data[1, 1] = 0.0 # Set first-guess data zero point that will be increased self.fg_cube.data[1, 1] = 0.0 # No halo - we're only testing this method. expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[1, 1] = 0.25 result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) self.assertArrayAlmostEqual(result.data, expected.data)
class Test_apply_precip(IrisTest): """Test the apply_precip 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): 4.0 hours (simulates UM data) Scalar coordinates: forecast_reference_time: 2015-11-23 03:00:00 Data: self.fg_cube: forecast_period (on time coord): 0.0 hours (simulates nowcast data) All points contain float(1.) Cube name is "probability_of_lightning". self.precip_cube: With extra coordinate of length(3) "threshold" containing points [0.5, 7., 35.] mm hr-1. All points contain float(1.) except the zero point [0, 0, 1, 1] which is float(0.) and [1:, 0, ...] which are float(0.) Cube name is "probability_of_precipitation". Cube has added attribute {'relative_to_threshold': 'above'} """ 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.precip_cube = (add_forecast_reference_time_and_forecast_period( set_up_cube(num_realization_points=3, zero_point_indices=((0, 1, 1), ), num_grid_points=3))) threshold_coord = self.precip_cube.coord('realization') threshold_coord.points = [0.5, 7.0, 35.0] threshold_coord.rename('threshold') threshold_coord.units = cf_units.Unit('mm hr-1') self.precip_cube.rename("probability_of_precipitation") self.precip_cube.attributes.update({'relative_to_threshold': 'above'}) self.precip_cube.data[1:, 0, ...] = 0. self.plugin = Plugin() def test_basic(self): """Test that the method returns the expected cube type""" result = self.plugin.apply_precip(self.fg_cube, self.precip_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.precip_cube.copy() self.plugin.apply_precip(cube_a, cube_b) self.assertArrayAlmostEqual(cube_a.data, self.fg_cube.data) self.assertArrayAlmostEqual(cube_b.data, self.precip_cube.data) def test_nearby_threshold_low(self): """Test that the method accepts a threshold point within machine tolerance.""" self.precip_cube.coord('threshold').points = [0.5000000001, 7., 35.] self.plugin.apply_precip(self.fg_cube, self.precip_cube) def test_missing_threshold_low(self): """Test that the method raises an error if the precip_cube doesn't have a threshold coordinate for 0.5.""" self.precip_cube.coord('threshold').points = [1.0, 7., 35.] msg = ("No matching any precip cube for") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.apply_precip(self.fg_cube, self.precip_cube) def test_missing_threshold_mid(self): """Test that the method raises an error if the precip_cube doesn't have a threshold coordinate for 7.0.""" self.precip_cube.coord('threshold').points = [0.5, 8., 35.] msg = ("No matching high precip cube for") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.apply_precip(self.fg_cube, self.precip_cube) def test_missing_threshold_high(self): """Test that the method raises an error if the precip_cube doesn't have a threshold coordinate for 35.0.""" self.precip_cube.coord('threshold').points = [0.5, 7., 20.] msg = ("No matching intense precip cube for") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.apply_precip(self.fg_cube, self.precip_cube) def test_precip_zero(self): """Test that zero precip probs reduce high lightning risk a lot""" expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0.0067 result = self.plugin.apply_precip(self.fg_cube, self.precip_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_precip_small(self): """Test that small precip probs reduce high lightning risk a bit""" self.precip_cube.data[:, 0, 1, 1] = 0. self.precip_cube.data[0, 0, 1, 1] = 0.075 expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0.625 result = self.plugin.apply_precip(self.fg_cube, self.precip_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_precip_light(self): """Test that high probs of light precip do not reduce high lightning risk""" self.precip_cube.data[:, 0, 1, 1] = 0. self.precip_cube.data[0, 0, 1, 1] = 0.8 expected = self.fg_cube.copy() # expected.data contains all ones result = self.plugin.apply_precip(self.fg_cube, self.precip_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_precip_heavy(self): """Test that prob of heavy precip increases zero lightning risk""" self.precip_cube.data[0, 0, 1, 1] = 1.0 self.precip_cube.data[1, 0, 1, 1] = 0.5 # Set first-guess to zero self.fg_cube.data[0, 1, 1] = 0.0 expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0.25 result = self.plugin.apply_precip(self.fg_cube, self.precip_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_precip_heavy_null(self): """Test that low prob of heavy precip does not increase low lightning risk""" self.precip_cube.data[0, 0, 1, 1] = 1.0 self.precip_cube.data[1, 0, 1, 1] = 0.3 # Set first-guess to zero self.fg_cube.data[0, 1, 1] = 0.1 expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0.1 result = self.plugin.apply_precip(self.fg_cube, self.precip_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_precip_intense(self): """Test that prob of intense precip increases zero lightning risk""" expected = self.fg_cube.copy() # expected.data contains all ones self.precip_cube.data[0, 0, 1, 1] = 1.0 self.precip_cube.data[1, 0, 1, 1] = 1.0 self.precip_cube.data[2, 0, 1, 1] = 0.5 # Set first-guess to zero self.fg_cube.data[0, 1, 1] = 0.0 result = self.plugin.apply_precip(self.fg_cube, self.precip_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_precip_intense_null(self): """Test that low prob of intense precip does not increase low lightning risk""" self.precip_cube.data[0, 0, 1, 1] = 1.0 self.precip_cube.data[1, 0, 1, 1] = 1.0 self.precip_cube.data[2, 0, 1, 1] = 0.1 # Set first-guess to zero self.fg_cube.data[0, 1, 1] = 0.1 expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0.25 # Heavy-precip result only result = self.plugin.apply_precip(self.fg_cube, self.precip_cube) self.assertArrayAlmostEqual(result.data, expected.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_process(IrisTest): """Test the nowcast lightning plugin.""" 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: 16; projection_x_coordinate: 16; Auxiliary coordinates: forecast_period (on time coord): 4.0 hours (simulates UM 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.ltng_cube: forecast_period (on time coord): 0.0 hours (simulates nowcast data) All points contain float(1.) Cube name is "rate_of_lightning". Cube units are "min^-1". self.precip_cube: With extra coordinate of length(3) "threshold" containing points [0.5, 7., 35.] mm hr-1. All points contain float(1.) except the zero point [0, 0, 7, 7] which is float(0.) and [1:, 0, ...] which are float(0.) Cube name is "probability_of_precipitation". Cube has added attribute {'relative_to_threshold': 'above'} self.vii_cube: forecast_period (on time coord): 0.0 hours (simulates nowcast data) With extra coordinate of length(3) "threshold" containing points [0.5, 1., 2.] kg m^-2. forecast_period (on time coord): 0.0 hours (simulates nowcast data) 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=[])) self.fg_cube.rename("probability_of_lightning") self.ltng_cube = add_forecast_reference_time_and_forecast_period( set_up_cube_with_no_realizations(zero_point_indices=[]), fp_point=0.0) self.ltng_cube.rename("rate_of_lightning") self.ltng_cube.units = cf_units.Unit("min^-1") self.precip_cube = (add_forecast_reference_time_and_forecast_period( set_up_cube(num_realization_points=3))) threshold_coord = self.precip_cube.coord('realization') threshold_coord.points = [0.5, 7.0, 35.0] threshold_coord.rename('threshold') threshold_coord.units = cf_units.Unit('mm hr-1') self.precip_cube.rename("probability_of_precipitation") self.precip_cube.attributes.update({'relative_to_threshold': 'above'}) self.precip_cube.data[1:, 0, ...] = 0. self.vii_cube = squeeze( add_forecast_reference_time_and_forecast_period(set_up_cube( num_realization_points=3, zero_point_indices=[]), fp_point=0.0)) threshold_coord = self.vii_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.vii_cube.data = np.zeros_like(self.vii_cube.data) self.vii_cube.rename("probability_of_vertical_integral_of_ice") self.plugin = Plugin() def set_up_vii_input_output(self): """Used to modify setUp() to set up four standard VII tests.""" # Repeat all tests relating to vii from Test__modify_first_guess expected = self.fg_cube.copy() # expected.data contains all ones except where modified below: # Set up precip_cube with increasing intensity along x-axis # y=5; no precip self.precip_cube.data[:, 0, 5:9, 5] = 0. # y=6; light precip self.precip_cube.data[0, 0, 5:9, 6] = 0.1 self.precip_cube.data[1, 0:, 5:9, 6] = 0. # y=7; heavy precip self.precip_cube.data[:2, 0, 5:9, 7] = 1. self.precip_cube.data[2, 0, 5:9, 7] = 0. # y=8; intense precip self.precip_cube.data[:, 0, 5:9, 8] = 1. # test_vii_null - with lightning-halo self.vii_cube.data[:, 5, 5:9] = 0. self.vii_cube.data[0, 5, 5:9] = 0.5 self.ltng_cube.data[0, 5, 5:9] = 0. self.fg_cube.data[0, 5, 5:9] = 0. expected.data[0, 5, 5:9] = [0.05, 0.25, 0.25, 1.] # test_vii_zero self.vii_cube.data[:, 6, 5:9] = 0. self.ltng_cube.data[0, 6, 5:9] = -1. self.fg_cube.data[0, 6, 5:9] = 0. expected.data[0, 6, 5:9] = [0., 0., 0.25, 1.] # test_vii_small # Set lightning data to -1 so it has a Null impact self.vii_cube.data[:, 7, 5:9] = 0. self.vii_cube.data[0, 7, 5:9] = 0.5 self.ltng_cube.data[0, 7, 5:9] = -1. self.fg_cube.data[0, 7, 5:9] = 0. expected.data[0, 7, 5:9] = [0.05, 0.05, 0.25, 1.] # test_vii_large # Set lightning data to -1 so it has a Null impact self.vii_cube.data[:, 8, 5:9] = 1. self.ltng_cube.data[0, 8, 5:9] = -1. self.fg_cube.data[0, 8, 5:9] = 0. expected.data[0, 8, 5:9] = [0.9, 0.9, 0.9, 1.] return expected def test_basic(self): """Test that the method returns the expected cube type with coords""" result = self.plugin.process( CubeList([self.fg_cube, self.ltng_cube, self.precip_cube])) self.assertIsInstance(result, Cube) # We expect the threshold coordinate to have been removed. self.assertCountEqual( find_dimension_coordinate_mismatch(result, self.precip_cube), ['threshold']) self.assertTrue(result.name() == 'probability_of_lightning') def test_basic_with_vii(self): """Test that the method returns the expected cube type when vii is present""" result = self.plugin.process( CubeList([ self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube ])) self.assertIsInstance(result, Cube) # We expect the threshold coordinate to have been removed. self.assertCountEqual( find_dimension_coordinate_mismatch(result, self.precip_cube), ['threshold']) self.assertTrue(result.name() == 'probability_of_lightning') def test_no_first_guess_cube(self): """Test that the method raises an error if the first_guess cube is omitted from the cubelist""" msg = (r"Got 0 cubes for constraint Constraint\(name=\'probability_of_" r"lightning\'\), expecting 1.") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.process(CubeList([self.ltng_cube, self.precip_cube])) def test_no_lightning_cube(self): """Test that the method raises an error if the lightning cube is omitted from the cubelist""" msg = (r"Got 0 cubes for constraint Constraint\(name=\'rate_of_" r"lightning\'\), expecting 1.") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.process(CubeList([self.fg_cube, self.precip_cube])) def test_no_precip_cube(self): """Test that the method raises an error if the precip cube is omitted from the cubelist""" msg = (r"Got 0 cubes for constraint Constraint\(name=\'probability_of_" r"precipitation\'\), expecting 1.") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin.process(CubeList([self.fg_cube, self.ltng_cube])) def test_precip_has_no_thresholds(self): """Test that the method raises an error if the threshold coord is omitted from the precip_cube""" self.precip_cube.remove_coord('threshold') msg = (r"Expected to find exactly 1 threshold coordinate, but found n") with self.assertRaisesRegex(CoordinateNotFoundError, msg): self.plugin.process( CubeList([self.fg_cube, self.ltng_cube, self.precip_cube])) def test_result_with_vii(self): """Test that the method returns the expected data when vii is present""" # Set precip_cube forecast period to be zero. self.precip_cube.coord('forecast_period').points = [0.] expected = self.set_up_vii_input_output() # No halo - we're only testing this method. # 2000m is the grid-length, so halo includes only one pixel. plugin = Plugin(2000.) result = plugin.process( CubeList([ self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube ])) self.assertIsInstance(result, Cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_result_with_vii_longfc(self): """Test that the method returns the expected data when vii is present and forecast time is 4 hours""" expected = self.set_up_vii_input_output() # test_vii_null with no precip will now return 0.0067 expected.data[0, 5, 5] = 0.0067 # test_vii_small with no and light precip will now return zero expected.data[0, 7, 5:7] = 0. # test_vii_large with no and light precip now return zero # and 0.25 for heavy precip expected.data[0, 8, 5:8] = [0., 0., 0.25] # No halo - we're only testing this method. # 2000m is the grid-length, so halo includes only one pixel. plugin = Plugin(2000.) result = plugin.process( CubeList([ self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube ])) self.assertIsInstance(result, Cube) self.assertArrayAlmostEqual(result.data, expected.data)
class Test__modify_first_guess(IrisTest): """Test the _modify_first_guess 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): 4.0 hours (simulates UM data) Scalar coordinates: forecast_reference_time: 2015-11-23 03:00:00 Data: self.cube: Describes the nowcast fields to be calculated. forecast_period (on time coord): 0.0 hours (simulates nowcast data) All points contain float(1.) except the zero point [0, 1, 1] which is float(0.) self.fg_cube: All points contain float(1.) self.ltng_cube: forecast_period (on time coord): 0.0 hours (simulates nowcast data) All points contain float(1.) self.precip_cube: With extra coordinate of length(3) "threshold" containing points [0.5, 7., 35.] mm hr-1. All points contain float(1.) except the zero point [0, 0, 1, 1] which is float(0.) and [1:, 0, ...] which are float(0.) self.vii_cube: With extra coordinate of length(3) "threshold" containing points [0.5, 1., 2.] kg m^-2. forecast_period (on time coord): 0.0 hours (simulates nowcast data) Time and forecast_period dimensions "sqeezed" to be Scalar coords. All points contain float(0.) """ self.cube = add_forecast_reference_time_and_forecast_period( set_up_cube_with_no_realizations(zero_point_indices=((0, 1, 1), ), num_grid_points=3), fp_point=0.0) self.fg_cube = add_forecast_reference_time_and_forecast_period( set_up_cube_with_no_realizations(zero_point_indices=[], num_grid_points=3)) self.ltng_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.precip_cube = (add_forecast_reference_time_and_forecast_period( set_up_cube(num_realization_points=3, zero_point_indices=((0, 1, 1), ), num_grid_points=3), fp_point=0.0)) threshold_coord = self.precip_cube.coord('realization') threshold_coord.points = [0.5, 7.0, 35.0] threshold_coord.rename('threshold') threshold_coord.units = cf_units.Unit('mm hr-1') self.precip_cube.data[1:, 0, ...] = 0. # iris.util.queeze is applied here to demote the singular coord "time" # to a scalar coord. self.vii_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.vii_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.vii_cube.data = np.zeros_like(self.vii_cube.data) self.plugin = Plugin() def test_basic(self): """Test that the method returns the expected cube type""" result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube) self.assertIsInstance(result, Cube) def test_input_with_vii(self): """Test that the method does not modify the input cubes.""" cube_a = self.cube.copy() cube_b = self.fg_cube.copy() cube_c = self.ltng_cube.copy() cube_d = self.precip_cube.copy() cube_e = self.vii_cube.copy() self.plugin._modify_first_guess(cube_a, cube_b, cube_c, cube_d, cube_e) self.assertArrayAlmostEqual(cube_a.data, self.cube.data) self.assertArrayAlmostEqual(cube_b.data, self.fg_cube.data) self.assertArrayAlmostEqual(cube_c.data, self.ltng_cube.data) self.assertArrayAlmostEqual(cube_d.data, self.precip_cube.data) self.assertArrayAlmostEqual(cube_e.data, self.vii_cube.data) def test_missing_lightning(self): """Test that the method raises an error if the lightning cube doesn't match the meta-data cube time coordinate.""" self.ltng_cube.coord('time').points = [1.0] msg = ("No matching lightning cube for") with self.assertRaisesRegex(ConstraintMismatchError, msg): self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) def test_missing_first_guess(self): """Test that the method raises an error if the first-guess cube doesn't match the meta-data cube time coordinate.""" self.fg_cube.coord('time').points = [1.0] msg = ("is not available within the input cube within the " "allowed difference") with self.assertRaisesRegex(ValueError, msg): self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) def test_cube_has_no_time_coord(self): """Test that the method raises an error if the meta-data cube has no time coordinate.""" self.cube.remove_coord('time') msg = ("Expected to find exactly 1 time coordinate, but found none.") with self.assertRaisesRegex(CoordinateNotFoundError, msg): self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) def test_precip_zero(self): """Test that apply_precip is being called""" # Set lightning data to "no-data" so it has a Null impact self.ltng_cube.data = np.full_like(self.ltng_cube.data, -1.) # No halo - we're only testing this method. expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0.0067 result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) self.assertArrayAlmostEqual(result.data, expected.data) def test_vii_large(self): """Test that ApplyIce is being called""" # Set lightning data to zero so it has a Null impact self.vii_cube.data[:, 1, 1] = 1. self.ltng_cube.data[0, 1, 1] = -1. self.fg_cube.data[0, 1, 1] = 0. # No halo - we're only testing this method. expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0.9 result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, self.vii_cube) self.assertArrayAlmostEqual(result.data, expected.data) def test_null(self): """Test that large precip probs and -1 lrates have no impact""" # Set prob(precip) data for lowest threshold to to 0.1, the highest # value that has no impact. self.precip_cube.data[0, 0, 1, 1] = 0.1 # Set lightning data to -1 so it has a Null impact self.ltng_cube.data = np.full_like(self.ltng_cube.data, -1.) # No halo - we're only testing this method. expected = self.fg_cube.copy() # expected.data should be an unchanged copy of fg_cube. result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) self.assertArrayAlmostEqual(result.data, expected.data) def test_lrate_large(self): """Test that large lightning rates increase zero lightning risk""" expected = self.fg_cube.copy() # expected.data contains all ones # Set precip data to 1. so it has a Null impact # Set prob(precip) data for lowest threshold to to 1., so it has a Null # impact when lightning is present. self.precip_cube.data[0, 0, 1, 1] = 1. # Set first-guess data zero point that will be increased self.fg_cube.data[0, 1, 1] = 0. # No halo - we're only testing this method. result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) self.assertArrayAlmostEqual(result.data, expected.data) def test_lrate_large_shortfc(self): """Test that nearly-large lightning rates increases zero lightning risk when forecast_period is non-zero""" expected = self.fg_cube.copy() # expected.data contains all ones # Set precip data to 1. so it has a Null impact # Set prob(precip) data for lowest threshold to to 1., so it has a Null # impact when lightning is present. self.precip_cube.data[0, 0, 1, 1] = 1. # Test the impact of the lightning-rate function. # A highish lightning value at one-hour lead time isn't high enough to # get to the high lightning category. self.ltng_cube.data[0, 1, 1] = 0.8 self.cube.coord('forecast_period').points = [1.] # hours # Set first-guess data zero point that will be increased self.fg_cube.data[0, 1, 1] = 0. # This time, lightning probability increases only to 0.25, not 1. expected.data[0, 1, 1] = 0.25 # No halo - we're only testing this method. result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) self.assertArrayAlmostEqual(result.data, expected.data) def test_lrate_large_null(self): """Test that large lightning rates do not increase high lightning risk""" expected = self.fg_cube.copy() # expected.data contains all ones # Set precip data to 1. so it has a Null impact # Set prob(precip) data for lowest threshold to to 1., so it has a Null # impact when lightning is present. self.precip_cube.data[0, 0, 1, 1] = 1. # Set first-guess data zero point that will be increased self.fg_cube.data[0, 1, 1] = 1. # No halo - we're only testing this method. result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) self.assertArrayAlmostEqual(result.data, expected.data) def test_lrate_small(self): """Test that lightning nearby (encoded as lightning rate zero) increases lightning risk at point""" # Set prob(precip) data for lowest threshold to to 1., so it has a Null # impact when lightning is present. self.precip_cube.data[0, 0, 1, 1] = 1. # Set lightning data to zero to represent the data halo self.ltng_cube.data[0, 1, 1] = 0. # Set first-guess data zero point that will be increased self.fg_cube.data[0, 1, 1] = 0. # No halo - we're only testing this method. expected = self.fg_cube.copy() # expected.data contains all ones except: expected.data[0, 1, 1] = 0.25 result = self.plugin._modify_first_guess(self.cube, self.fg_cube, self.ltng_cube, self.precip_cube, None) self.assertArrayAlmostEqual(result.data, expected.data)
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: 16; projection_x_coordinate: 16; Auxiliary coordinates: forecast_period (on time coord): 4.0 hours (simulates UM 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.ltng_cube: forecast_period (on time coord): 0.0 hours (simulates nowcast data) All points contain float(1.) Cube name is "rate_of_lightning". Cube units are "min^-1". self.precip_cube: With extra coordinate of length(3) "threshold" containing points [0.5, 7., 35.] mm hr-1. All points contain float(1.) except the zero point [0, 0, 7, 7] which is float(0.) and [1:, 0, ...] which are float(0.) Cube name is "probability_of_precipitation". Cube has added attribute {'relative_to_threshold': 'above'} self.vii_cube: forecast_period (on time coord): 0.0 hours (simulates nowcast data) With extra coordinate of length(3) "threshold" containing points [0.5, 1., 2.] kg m^-2. forecast_period (on time coord): 0.0 hours (simulates nowcast data) 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=[])) self.fg_cube.rename("probability_of_lightning") self.ltng_cube = add_forecast_reference_time_and_forecast_period( set_up_cube_with_no_realizations(zero_point_indices=[]), fp_point=0.0) self.ltng_cube.rename("rate_of_lightning") self.ltng_cube.units = cf_units.Unit("min^-1") self.precip_cube = (add_forecast_reference_time_and_forecast_period( set_up_cube(num_realization_points=3))) threshold_coord = self.precip_cube.coord('realization') threshold_coord.points = [0.5, 7.0, 35.0] threshold_coord.rename('threshold') threshold_coord.units = cf_units.Unit('mm hr-1') self.precip_cube.rename("probability_of_precipitation") self.precip_cube.attributes.update({'relative_to_threshold': 'above'}) self.precip_cube.data[1:, 0, ...] = 0. self.vii_cube = squeeze( add_forecast_reference_time_and_forecast_period(set_up_cube( num_realization_points=3, zero_point_indices=[]), fp_point=0.0)) threshold_coord = self.vii_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.vii_cube.data = np.zeros_like(self.vii_cube.data) self.vii_cube.rename("probability_of_vertical_integral_of_ice") self.plugin = Plugin()