def process(self, cubes, coordinates=None): """ Aggregate the input reliability calibration table cubes and return the result. Args: cubes (list or iris.cube.CubeList): The cube or cubes containing the reliability calibration tables to aggregate. coordinates (list or None): A list of coordinates over which to aggregate the reliability calibration table using summation. If the argument is None and a single cube is provided, this cube will be returned unchanged. """ coordinates = [] if coordinates is None else coordinates try: (cube, ) = cubes except ValueError: cubes = iris.cube.CubeList(cubes) self._check_frt_coord(cubes) cube = cubes.merge_cube() coordinates.append("forecast_reference_time") else: if not coordinates: return cube result = collapsed(cube, coordinates, iris.analysis.SUM) frt = create_unified_frt_coord(cube.coord("forecast_reference_time")) result.replace_coord(frt) return result
def test_coordinate_input_with_bounds(self): """Test the forecast reference time coordinate has the expected point, bounds, and type for an input multiple forecast reference times, each with bounds.""" frt = "forecast_reference_time" cube = iris.cube.CubeList( [self.reliability_cube, self.different_frt] ).merge_cube() frt_coord = cube.coord(frt) expected_points = self.different_frt.coord(frt).points[0] expected_bounds = [ [ self.reliability_cube.coord(frt).bounds[0][0], self.different_frt.coord(frt).bounds[0][-1], ] ] result = create_unified_frt_coord(frt_coord) self.assertIsInstance(result, iris.coords.DimCoord) assert_array_equal(result.points, expected_points) assert_array_equal(result.bounds, expected_bounds) self.assertEqual(result.name(), frt_coord.name()) self.assertEqual(result.units, frt_coord.units)
def test_coordinate_single_frt_input(self): """Test the forecast reference time coordinate has the expected point, bounds, and type for an input with a single forecast reference time point.""" frt = "forecast_reference_time" frt_coord = self.forecast_1.coord(frt) expected_points = self.forecast_1.coord(frt).points[0] expected_bounds = [[self.forecast_1.coord(frt).points[0], expected_points]] result = create_unified_frt_coord(frt_coord) self.assertIsInstance(result, iris.coords.DimCoord) assert_array_equal(result.points, expected_points) assert_array_equal(result.bounds, expected_bounds) self.assertEqual(result.name(), frt_coord.name()) self.assertEqual(result.units, frt_coord.units)
def test_create_unified_frt_single_frt_input(forecast_grid): """Test the forecast reference time coordinate has the expected point, bounds, and type for an input with a single forecast reference time point.""" frt = "forecast_reference_time" forecast_1 = forecast_grid[0, ...] frt_coord = forecast_1.coord(frt) expected_points = forecast_1.coord(frt).points[0] expected_bounds = [[forecast_1.coord(frt).points[0], expected_points]] result = create_unified_frt_coord(frt_coord) assert isinstance(result, iris.coords.DimCoord) assert_array_equal(result.points, expected_points) assert_array_equal(result.bounds, expected_bounds) assert result.name() == frt_coord.name() assert result.units == frt_coord.units
def _create_reliability_table_cube(self, forecast, threshold_coord): """ Construct a reliability table cube and populate it with the provided data. The returned cube will include a cycle hour coordinate, which describes the model cycle hour at which the forecast data was produced. It will further include the forecast period, threshold coordinate, and spatial coordinates from the forecast cube. Args: forecast (iris.cube.Cube): A cube slice across the spatial dimensions of the forecast data. This slice provides the time and threshold values that relate to the reliability_table_data. threshold_coord (iris.coords.DimCoord): The threshold coordinate. Returns: iris.cube.Cube: A reliability table cube. """ def _get_coords_and_dims(coord_names): """Obtain the requested coordinates and their dimension index from the forecast slice cube.""" coords_and_dims = [] leading_coords = [probability_bins_coord, reliability_index_coord] for coord_name in coord_names: crd = forecast_slice.coord(coord_name) crd_dim = forecast_slice.coord_dims(crd) crd_dim = crd_dim[0] + len(leading_coords) if crd_dim else () coords_and_dims.append((crd, crd_dim)) return coords_and_dims forecast_slice = next(forecast.slices_over(["time", threshold_coord])) expected_shape = self.expected_table_shape + forecast_slice.shape dummy_data = np.zeros((expected_shape)) diagnostic = find_threshold_coordinate(forecast).name() attributes = self._define_metadata(forecast) # Define reliability table specific coordinates probability_bins_coord = self._create_probability_bins_coord() ( reliability_index_coord, reliability_name_coord, ) = self._create_reliability_table_coords() frt_coord = create_unified_frt_coord( forecast.coord("forecast_reference_time")) # List of required non-spatial coordinates from the forecast non_spatial_coords = ["forecast_period", diagnostic] # Construct a list of coordinates in the desired order dim_coords = [forecast.coord(axis=dim).name() for dim in ["x", "y"]] dim_coords_and_dims = _get_coords_and_dims(dim_coords) aux_coords_and_dims = _get_coords_and_dims(non_spatial_coords) dim_coords_and_dims.append((reliability_index_coord, 0)) aux_coords_and_dims.append((reliability_name_coord, 0)) dim_coords_and_dims.append((probability_bins_coord, 1)) reliability_cube = iris.cube.Cube( dummy_data, units=1, attributes=attributes, dim_coords_and_dims=dim_coords_and_dims, aux_coords_and_dims=aux_coords_and_dims, ) reliability_cube.add_aux_coord(frt_coord) reliability_cube.rename("reliability_calibration_table") return reliability_cube