def test_aggregating_over_masked_cubes_and_coordinates(self): """Test of aggregating over coordinates and cubes in a single call using a masked reliability table. In this instance the latitude and longitude coordinates are collapsed and the values from two input cube combined.""" frt = "forecast_reference_time" expected_points = self.masked_different_frt.coord(frt).points expected_bounds = [[ self.masked_reliability_cube.coord(frt).bounds[0][0], self.masked_different_frt.coord(frt).bounds[-1][1], ]] expected_result = np.array([ [0.0, 0.0, 2.0, 4.0, 2.0], [0.0, 0.625, 2.625, 3.25, 2.0], [0.0, 3.0, 5.0, 4.0, 2.0], ]) plugin = Plugin() result = plugin.process( [self.masked_reliability_cube, self.masked_different_frt], coordinates=["latitude", "longitude"], ) self.assertIsInstance(result.data, np.ma.MaskedArray) assert_array_equal(result.data, expected_result) self.assertEqual(result.coord(frt).points, expected_points) assert_array_equal(result.coord(frt).bounds, expected_bounds)
def test_frt_coord_invalid_bounds(reliability_cube, overlapping_frt): """Test that an exception is raised if the input cubes have forecast reference time bounds that overlap.""" plugin = Plugin() msg = "Reliability calibration tables have overlapping" with pytest.raises(ValueError, match=msg): plugin._check_frt_coord([reliability_cube, overlapping_frt])
def test_single_cube(reliability_cube): """Test the plugin returns an unaltered cube if only one is passed in and no coordinates are given.""" plugin = Plugin() expected = reliability_cube.copy() result = plugin.process([reliability_cube]) assert result == expected
def test_invalid_bounds(self): """Test that an exception is raised if the input cubes have forecast reference time bounds that overlap.""" plugin = Plugin() msg = "Reliability calibration tables have overlapping" with self.assertRaisesRegex(ValueError, msg): plugin._check_frt_coord([self.reliability_cube, self.overlapping_frt])
def test_single_cube(self): """Test the plugin returns an unaltered cube if only one is passed in and no coordinates are given.""" plugin = Plugin() expected = self.reliability_cube.copy() result = plugin.process([self.reliability_cube]) self.assertEqual(result, expected)
def test_matching_bounds(self): """Test that no exception is raised in the input cubes if a cube contains matching bounds.""" lower_bound = self.reliability_cube.coord( "forecast_reference_time").bounds[0][0] self.reliability_cube.coord("forecast_reference_time").bounds = [[ lower_bound, lower_bound ]] plugin = Plugin() plugin._check_frt_coord([self.reliability_cube, self.different_frt])
def test_aggregating_cubes_with_overlapping_frt(self): """Test that attempting to aggregate reliability calibration tables with overlapping forecast reference time bounds raises an exception. The presence of overlapping forecast reference time bounds indicates that the same forecast data has contributed to both tables, thus aggregating them would double count these contributions.""" plugin = Plugin() msg = "Reliability calibration tables have overlapping" with self.assertRaisesRegex(ValueError, msg): plugin.process([self.reliability_cube, self.overlapping_frt])
def test_aggregating_over_single_cube_coordinates(self): """Test of aggregating over coordinates of a single cube. In this instance the latitude and longitude coordinates are collapsed.""" frt = "forecast_reference_time" expected_points = self.reliability_cube.coord(frt).points expected_bounds = self.reliability_cube.coord(frt).bounds plugin = Plugin() result = plugin.process([self.reliability_cube], coordinates=["latitude", "longitude"]) assert_array_equal(result.data, self.lat_lon_collapse) self.assertEqual(result.coord(frt).points, expected_points) assert_array_equal(result.coord(frt).bounds, expected_bounds)
def process(*cubes: cli.inputcube, coordinates: cli.comma_separated_list = None): """Aggregate reliability tables. Aggregate multiple reliability calibration tables and/or aggregate over coordinates within the table(s) to produce a new reliability calibration table. Args: cubes (list of iris.cube.Cube): The cube or cubes containing the reliability calibration tables to aggregate. coordinates (list): A list of coordinates over which to aggregate the reliability calibration table using summation. If the list is empty and a single cube is provided, this cube will be returned unchanged. Returns: iris.cube.Cube: Aggregated reliability table. """ from improver.calibration.reliability_calibration import ( AggregateReliabilityCalibrationTables, ) return AggregateReliabilityCalibrationTables()(cubes, coordinates=coordinates)
def test_process_aggregating_multiple_cubes(reliability_cube, different_frt, expected_table): """Test of aggregating two cubes without any additional coordinate collapsing.""" frt = "forecast_reference_time" expected_points = different_frt.coord(frt).points expected_bounds = [[ reliability_cube.coord(frt).bounds[0][0], different_frt.coord(frt).bounds[-1][1], ]] plugin = Plugin() result = plugin.process([reliability_cube, different_frt]) assert_array_equal(result.data, expected_table * 2) assert_array_equal(result.shape, (3, 5, 3, 3)) assert_array_equal(result.coord(frt).points, expected_points) assert_array_equal(result.coord(frt).bounds, expected_bounds)
def test_process_and_aggregate(create_rel_table_inputs): """Test that aggregation during construction produces the same result as applying the two plugins sequentially.""" # use the spatial coordinates for aggregation - input is a parameterised fixture if create_rel_table_inputs.forecast.coords("spot_index"): agg_coords = ["spot_index"] else: agg_coords = ["longitude", "latitude"] # construct and aggregate as two separate plugins constructed = Plugin( single_value_lower_limit=True, single_value_upper_limit=True ).process(create_rel_table_inputs.forecast, create_rel_table_inputs.truth) aggregated = AggregateReliabilityCalibrationTables().process( [constructed], agg_coords ) # construct plugin with aggregate_coords option constructed_with_agg = Plugin( single_value_lower_limit=True, single_value_upper_limit=True ).process( create_rel_table_inputs.forecast, create_rel_table_inputs.truth, agg_coords ) # check that the two cubes are identical assert constructed_with_agg == aggregated
def test_aggregating_over_cubes_and_coordinates(self): """Test of aggregating over coordinates and cubes in a single call. In this instance the latitude and longitude coordinates are collapsed and the values from two input cube combined.""" frt = 'forecast_reference_time' expected_points = self.different_frt.coord(frt).points expected_bounds = [[ self.reliability_cube.coord(frt).bounds[0][0], self.different_frt.coord(frt).bounds[-1][1] ]] plugin = Plugin() result = plugin.process([self.reliability_cube, self.different_frt], coordinates=['latitude', 'longitude']) assert_array_equal(result.data, self.lat_lon_collapse * 2) self.assertEqual(result.coord(frt).points, expected_points) assert_array_equal(result.coord(frt).bounds, expected_bounds)
def test_process_aggregating_over_cubes_and_coordinates( reliability_cube, different_frt, lat_lon_collapse): """Test of aggregating over coordinates and cubes in a single call. In this instance the latitude and longitude coordinates are collapsed and the values from two input cube combined.""" frt = "forecast_reference_time" expected_points = different_frt.coord(frt).points expected_bounds = [[ reliability_cube.coord(frt).bounds[0][0], different_frt.coord(frt).bounds[-1][1], ]] plugin = Plugin() result = plugin.process( [reliability_cube, different_frt], coordinates=["latitude", "longitude"], ) assert_array_equal(result.data, lat_lon_collapse * 2) assert_array_equal(result.coord(frt).points, expected_points) assert_array_equal(result.coord(frt).bounds, expected_bounds)
def test_valid_bounds(self): """Test that no exception is raised if the input cubes have forecast reference time bounds that do not overlap.""" plugin = Plugin() plugin._check_frt_coord([self.reliability_cube, self.different_frt])