class TestAll(unittest.TestCase): """Test fixes for allvars.""" def setUp(self): """Prepare tests.""" self.cube = Cube([[1.0, 2.0], [3.0, 4.0]], var_name='co2', units='J') self.cube.add_dim_coord( DimCoord([0, 1], standard_name='time', units=Unit('days since 0000-01-01 00:00:00', calendar='gregorian')), 0) self.cube.add_dim_coord(DimCoord([0, 1], long_name='AR5PL35'), 1) self.fix = AllVars() def test_get(self): """Test fix get""" self.assertListEqual(Fix.get_fixes('CMIP5', 'MIROC-ESM', 'tos'), [AllVars()]) def test_fix_metadata_plev(self): """Test plev fix.""" time = self.cube.coord('time') time.units = Unit("days since 1-1-1", time.units.calendar) cube = self.fix.fix_metadata([self.cube])[0] cube.coord('air_pressure') def test_fix_metadata_no_plev(self): """Test plev fix wotk with no plev.""" self.cube.remove_coord('AR5PL35') cube = self.fix.fix_metadata([self.cube])[0] with self.assertRaises(CoordinateNotFoundError): cube.coord('air_pressure')
def _remove_scalar_coords(cube: Cube, coords_to_remove: List[str]) -> None: """Removes named coordinates from the input cube.""" for coord in coords_to_remove: try: cube.remove_coord(coord) except CoordinateNotFoundError: continue
def _create_template_cube(self, cube: Cube) -> Cube: """ Create a template cube to store the timezone masks. This cube has only one scalar coordinate which is time, denoting when it is valid; this is only relevant if using daylight savings. The attribute includes_daylight_savings is set to indicate this. Args: cube: A cube with the desired grid from which coordinates are taken for inclusion in the template. Returns: A template cube in which each timezone mask can be stored. """ time_point = np.array(self.time.timestamp(), dtype=np.int64) time_coord = iris.coords.DimCoord( time_point, "time", units=Unit("seconds since 1970-01-01 00:00:00", calendar="gregorian"), ) for crd in cube.coords(dim_coords=False): cube.remove_coord(crd) cube.add_aux_coord(time_coord) attributes = generate_mandatory_attributes([cube]) attributes["includes_daylight_savings"] = str(self.include_dst) return create_new_diagnostic_cube( "timezone_mask", 1, cube, attributes, dtype=np.int8 )
def _set_blended_time_coords(blended_cube: Cube, cycletime: Optional[str]) -> None: """ For cycle and model blending: - Add a "blend_time" coordinate equal to the current cycletime - Update the forecast reference time and forecast period coordinate points to reflect the current cycle time (behaviour is DEPRECATED) - Remove any bounds from the forecast reference time (behaviour is DEPRECATED) - Mark the forecast reference time and forecast period as DEPRECATED Modifies cube in place. Args: blended_cube cycletime: Current cycletime in YYYYMMDDTHHmmZ format """ try: cycletime_point = _get_cycletime_point(blended_cube, cycletime) except TypeError: raise ValueError( "Current cycle time is required for cycle and model blending") add_blend_time(blended_cube, cycletime) blended_cube.coord("forecast_reference_time").points = [cycletime_point] blended_cube.coord("forecast_reference_time").bounds = None if blended_cube.coords("forecast_period"): blended_cube.remove_coord("forecast_period") new_forecast_period = forecast_period_coord(blended_cube) time_dim = blended_cube.coord_dims("time") blended_cube.add_aux_coord(new_forecast_period, data_dims=time_dim) for coord in ["forecast_period", "forecast_reference_time"]: msg = f"{coord} will be removed in future and should not be used" blended_cube.coord(coord).attributes.update( {"deprecation_message": msg})
class TestAll(unittest.TestCase): """Test fixes for all vars.""" def setUp(self): """Prepare tests.""" self.cube = Cube([1.0, 2.0], var_name='co2', units='J') self.cube.add_dim_coord( DimCoord([0.0, 1.0], standard_name='time', units=Unit('days since 0001-01', calendar='gregorian')), 0) self.fix = AllVars() def test_get(self): """Test fix get""" self.assertListEqual(Fix.get_fixes('CMIP5', 'FGOALS-G2', 'tas'), [AllVars()]) def test_fix_metadata(self): """Test calendar fix.""" cube = self.fix.fix_metadata([self.cube])[0] time = cube.coord('time') self.assertEqual(time.units.origin, 'day since 1-01-01 00:00:00.000000') self.assertEqual(time.units.calendar, 'gregorian') def test_fix_metadata_dont_gail_if_not_time(self): """Test calendar fix.""" self.cube.remove_coord('time') self.fix.fix_metadata([self.cube])
class TestAll(unittest.TestCase): def setUp(self): self.cube = Cube([[1.0, 2.0], [3.0, 4.0]], var_name='co2', units='J') self.cube.add_dim_coord( DimCoord( [0, 1], standard_name='time', units=Unit( 'days since 0000-01-01 00:00:00', calendar='gregorian')), 0) self.cube.add_dim_coord(DimCoord([0, 1], long_name='AR5PL35'), 1) self.fix = allvars() def test_fix_metadata_plev(self): time = self.cube.coord('time') time.units = Unit("days since 1-1-1", time.units.calendar) cube = self.fix.fix_metadata([self.cube])[0] cube.coord('air_pressure') def test_fix_metadata_no_plev(self): self.cube.remove_coord('AR5PL35') cube = self.fix.fix_metadata([self.cube])[0] with self.assertRaises(CoordinateNotFoundError): cube.coord('air_pressure')
class Test_convert_number_of_grid_cells_into_distance(IrisTest): """Test the convert_number_of_grid_cells_into_distance method""" def setUp(self): """Set up a cube with x and y coordinates""" data = np.ones((3, 4)) self.cube = Cube(data, standard_name="air_temperature",) self.cube.add_dim_coord( DimCoord(np.linspace(2000.0, 6000.0, 3), 'projection_x_coordinate', units='m'), 0) self.cube.add_dim_coord( DimCoord(np.linspace(2000.0, 8000.0, 4), "projection_y_coordinate", units='m'), 1) def test_basic(self): """Test the function does what it's meant to in a simple case.""" result_radius = convert_number_of_grid_cells_into_distance( self.cube, 2) expected_result = 4000.0 self.assertAlmostEqual(result_radius, expected_result) self.assertIs(type(expected_result), float) def test_check_input_in_km(self): """ Test that the output is still in metres when the input coordinates are in a different unit. """ result_radius = convert_number_of_grid_cells_into_distance( self.cube, 2) for coord in self.cube.coords(): coord.convert_units("km") expected_result = 4000.0 self.assertAlmostEqual(result_radius, expected_result) self.assertIs(type(expected_result), float) def test_not_equal_areas(self): """ Check it raises an error when the input is not an equal areas grid. """ self.cube.remove_coord("projection_x_coordinate") self.cube.add_dim_coord( DimCoord(np.linspace(200.0, 600.0, 3), 'projection_x_coordinate', units='m'), 0) with self.assertRaisesRegex( ValueError, "The size of the intervals along the x and y axis" " should be equal."): convert_number_of_grid_cells_into_distance(self.cube, 2) def test_check_different_input_radius(self): """Check it works for different input values.""" result_radius = convert_number_of_grid_cells_into_distance( self.cube, 5) expected_result = 10000.0 self.assertAlmostEqual(result_radius, expected_result) self.assertIs(type(expected_result), float)
def update_blended_metadata( cube: Cube, blend_coord: str, coords_to_remove: Optional[List[str]] = None, cycletime: Optional[str] = None, attributes_dict: Optional[Dict[str, str]] = None, model_id_attr: Optional[str] = None, ) -> None: """ Update metadata as required after blending - For cycle and model blending, set a single forecast reference time and period using current cycletime - For model blending, add attribute detailing the contributing models - Remove scalar coordinates that were previously associated with the blend dimension - Update attributes as specified via process arguments - Set any missing mandatory arguments to their default values Modifies cube in place. Args: cube: Blended cube blend_coord: Name of coordinate over which blending has been performed coords_to_remove: Name of scalar coordinates to be removed from the blended cube cycletime: Current cycletime in YYYYMMDDTHHmmZ format model_id_attr: Name of attribute for use in model blending, to record the names of contributing models on the blended output attributes_dict: Optional user-defined attributes to add to the cube """ if blend_coord in ["forecast_reference_time", MODEL_BLEND_COORD]: _set_blended_time_coords(cube, cycletime) if blend_coord == MODEL_BLEND_COORD: (contributing_models,) = cube.coord(MODEL_NAME_COORD).points # iris concatenates string coordinates as a "|"-separated string cube.attributes[model_id_attr] = " ".join( sorted(contributing_models.split("|")) ) if coords_to_remove is not None: for coord in coords_to_remove: cube.remove_coord(coord) if attributes_dict is not None: amend_attributes(cube, attributes_dict) for attr in MANDATORY_ATTRIBUTES: if attr not in cube.attributes: cube.attributes[attr] = MANDATORY_ATTRIBUTE_DEFAULTS[attr]
def _add_forecast_period(advected_cube: Cube, timestep: timedelta) -> None: """Add or replace a forecast period on the advected cube""" try: advected_cube.remove_coord("forecast_period") except CoordinateNotFoundError: pass forecast_period_seconds = np.int32(timestep.total_seconds()) forecast_period_coord = AuxCoord(forecast_period_seconds, standard_name="forecast_period", units="seconds") advected_cube.add_aux_coord(forecast_period_coord)
def _add_forecast_reference_time(input_time: Coord, advected_cube: Cube) -> None: """Add or replace a forecast reference time on the advected cube""" try: advected_cube.remove_coord("forecast_reference_time") except CoordinateNotFoundError: pass frt_coord_name = "forecast_reference_time" frt_coord_spec = TIME_COORDS[frt_coord_name] frt_coord = input_time.copy() frt_coord.rename(frt_coord_name) frt_coord.convert_units(frt_coord_spec.units) frt_coord.points = round_close(frt_coord.points, dtype=frt_coord_spec.dtype) advected_cube.add_aux_coord(frt_coord)
class TestAllVars(unittest.TestCase): """Tests for fixes of all variables.""" def setUp(self): """Set up tests.""" vardef = get_var_info('CMIP6', 'Omon', 'tos') self.fix = AllVars(vardef) self.cube = Cube(np.random.rand(2, 2, 2), var_name='tos') self.cube.add_aux_coord( AuxCoord(np.random.rand(2, 2), var_name='nav_lat', standard_name='latitude'), (1, 2)) self.cube.add_aux_coord( AuxCoord(np.random.rand(2, 2), var_name='nav_lon', standard_name='longitude'), (1, 2)) def test_fix_metadata_ocean_var(self): """Test ``fix_metadata`` for ocean variables.""" cell_area = Cube(np.random.rand(2, 2), standard_name='cell_area') cubes = self.fix.fix_metadata(CubeList([self.cube, cell_area])) self.assertEqual(len(cubes), 1) cube = cubes[0] self.assertEqual(cube.var_name, 'tos') self.assertEqual(cube.coord('latitude').var_name, 'lat') self.assertEqual(cube.coord('longitude').var_name, 'lon') def test_fix_data_no_lat(self): """Test ``fix_metadata`` when no latitude is present.""" self.cube.remove_coord('latitude') cubes = self.fix.fix_metadata(CubeList([self.cube])) self.assertEqual(len(cubes), 1) cube = cubes[0] self.assertEqual(cube.coord('longitude').var_name, 'lon') with self.assertRaises(CoordinateNotFoundError): self.cube.coord('latitude') def test_fix_data_no_lon(self): """Test ``fix_metadata`` when no longitude is present.""" self.cube.remove_coord('longitude') cubes = self.fix.fix_metadata(CubeList([self.cube])) self.assertEqual(len(cubes), 1) cube = cubes[0] self.assertEqual(cube.coord('latitude').var_name, 'lat') with self.assertRaises(CoordinateNotFoundError): self.cube.coord('longitude') def test_fix_data_no_lat_lon(self): """Test ``fix_metadata`` for cubes with no latitude and longitude.""" self.cube.remove_coord('latitude') self.cube.remove_coord('longitude') cubes = self.fix.fix_metadata(CubeList([self.cube])) self.assertEqual(len(cubes), 1) with self.assertRaises(CoordinateNotFoundError): self.cube.coord('latitude') with self.assertRaises(CoordinateNotFoundError): self.cube.coord('longitude')
class TestAllVars(unittest.TestCase): """Test fixes for all vars.""" def setUp(self): """Prepare tests.""" self.cube = Cube([1.0, 2.0], var_name='co2', units='J') reference_dates = [ datetime(300, 1, 16, 12), # e.g. piControl datetime(1850, 1, 16, 12) # e.g. historical ] esgf_time_units = { 'unit': 'days since 0001-01-01', 'calendar': 'proleptic_gregorian' } time_points = date2num(reference_dates, **esgf_time_units) self.cube.add_dim_coord( DimCoord(time_points, 'time', 'time', 'time', Unit(**esgf_time_units)), data_dim=0) self.fix = AllVars(None) def test_get(self): """Test getting of fix.""" self.assertListEqual( Fix.get_fixes('CMIP5', 'ACCESS1-3', 'Amon', 'tas'), [AllVars(None)]) def test_fix_metadata(self): """Test fix for bad calendar.""" cube = self.fix.fix_metadata([self.cube])[0] time = cube.coord('time') dates = num2date(time.points, time.units.name, time.units.calendar) self.assertEqual(time.units.calendar, 'gregorian') self.assertEqual(dates[0].strftime('%Y%m%d%H%M'), '30001161200') self.assertEqual(dates[1].strftime('%Y%m%d%H%M'), '185001161200') def test_fix_metadata_if_not_time(self): """Test calendar fix do not fail if no time coord present.""" self.cube.remove_coord('time') self.fix.fix_metadata([self.cube])
def create_coefficient_cube( self, data: ndarray, template: Cube, cube_name: str, attributes: Dict ) -> Cube: """ Update metadata in smoothing_coefficients cube. Remove any time coordinates and rename. Args: data: The smoothing coefficient data to store in the cube. template: A gradient cube, the dimensions of which are used as a template for the coefficient cube. cube_name: A name for the resultant cube attributes: A dictionary of attributes for the new cube. Returns: A new cube of smoothing_coefficients """ for coord in template.coords(dim_coords=False): for coord_name in ["time", "period", "realization"]: if coord_name in coord.name(): template.remove_coord(coord) attributes["title"] = "Recursive filter smoothing coefficients" attributes.pop("history", None) attributes["power"] = self.power return create_new_diagnostic_cube( cube_name, "1", template, MANDATORY_ATTRIBUTE_DEFAULTS.copy(), optional_attributes=attributes, data=data, )
class TestAllVars(unittest.TestCase): """Test all vars fixes.""" def setUp(self): """Prepare tests.""" self.cube = Cube([1.0], var_name='co2', units='J') self.cube.add_aux_coord( AuxCoord(0, 'time', 'time', 'time', Unit('days since 1850-01-01', 'julian'))) self.fix = AllVars() def test_get(self): self.assertListEqual(Fix.get_fixes('CMIP5', 'ACCESS1-0', 'tas'), [AllVars()]) def test_fix_metadata(self): """Test fix for bad calendar.""" cube = self.fix.fix_metadata([self.cube])[0] self.assertEqual(cube.coord('time').units.calendar, 'gregorian') def test_fix_metadata_if_not_time(self): """Test calendar fix do not fail if no time coord present.""" self.cube.remove_coord('time') self.fix.fix_metadata([self.cube])
def _remove_blend_time(cube: Cube) -> Cube: """If present on input, remove existing blend time coordinate (as this will be replaced on blending)""" if "blend_time" in get_coord_names(cube): cube.remove_coord("blend_time") return cube