Example #1
0
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')
Example #2
0
 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
        )
Example #4
0
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})
Example #5
0
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])
Example #6
0
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')
Example #7
0
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)
Example #8
0
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]
Example #9
0
    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)
Example #10
0
 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)
Example #11
0
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')
Example #12
0
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,
        )
Example #14
0
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])
Example #15
0
 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