Beispiel #1
0
def test_set_height_levels_single_value():
    """ Tests cube generated with single height level is demoted from dimension to
    scalar coordinate """
    height_levels = [1.5]
    cube = generate_metadata(MANDATORY_ATTRIBUTE_DEFAULTS,
                             height_levels=height_levels)

    assert cube.ndim == 3
    assert cube.shape == (
        ENSEMBLE_MEMBERS_DEFAULT,
        NPOINTS_DEFAULT,
        NPOINTS_DEFAULT,
    )

    expected_spatial_grid_attributes = SPATIAL_GRID_ATTRIBUTE_DEFAULTS[
        SPATIAL_GRID_DEFAULT]
    assert cube.coords()[0].name() == "realization"
    assert cube.coords()[1].name() == expected_spatial_grid_attributes["y"]
    assert cube.coords()[2].name() == expected_spatial_grid_attributes["x"]

    np.testing.assert_array_equal(cube.coord("height").points, height_levels)

    # Assert that no other values have unexpectedly changed by returning changed values
    # to defaults and comparing against default cube
    default_cube = generate_metadata(MANDATORY_ATTRIBUTE_DEFAULTS)
    cube.remove_coord("height")
    assert cube == default_cube
Beispiel #2
0
def test_name_unknown_no_units():
    """ Tests error raised if output variable name not in iris.std_names.STD_NAMES and
    no unit provided """
    name = "temperature"

    with pytest.raises(ValueError, match=name):
        generate_metadata(name)
Beispiel #3
0
def test_spatial_grid_not_supported():
    """ Tests error raised if spatial grid not supported """
    spatial_grid = "other"

    with pytest.raises(ValueError, match=spatial_grid):
        generate_metadata(MANDATORY_ATTRIBUTE_DEFAULTS,
                          spatial_grid=spatial_grid)
Beispiel #4
0
def test_missing_mandatory_attributes(use_attributes):
    """Tests that unspecified mandatory attributes raise an error"""
    attributes = {}
    for key in use_attributes:
        attributes[key] = MANDATORY_ATTRIBUTE_DEFAULTS[key]
    msg = "No values for these mandatory attributes: "
    with pytest.raises(KeyError, match=msg):
        generate_metadata(attributes)
Beispiel #5
0
def test_set_attributes():
    """ Tests cube generated with specified attributes and the rest of the values set
    as default values """
    attributes = {"source": "IMPROVER"}
    cube = generate_metadata(attributes=attributes)

    assert cube.attributes == attributes

    # Assert that no other values have unexpectedly changed by returning changed values
    # to defaults and comparing against default cube
    default_cube = generate_metadata()
    cube.attributes = default_cube.attributes

    assert cube == default_cube
Beispiel #6
0
def test_set_time():
    """ Tests cube generated with specified time and the rest of the values set as
    default values """
    time = datetime(2020, 1, 1, 0, 0)
    cube = generate_metadata(time=time)

    assert iris_time_to_datetime(cube.coord("time"))[0] == time
    assert cube.coord("forecast_period").points > FORECAST_PERIOD_DEFAULT

    # Assert that no other values have unexpectedly changed by returning changed values
    # to defaults and comparing against default cube
    default_cube = generate_metadata()
    cube.coord("time").points = default_cube.coord("time").points
    cube.coord("forecast_period").points = default_cube.coord("forecast_period").points

    assert cube == default_cube
Beispiel #7
0
def test_default():
    """ Tests default metadata cube generated """
    cube = generate_metadata()

    assert cube.name() == NAME_DEFAULT
    assert cube.standard_name == NAME_DEFAULT
    assert cube.units == UNITS_DEFAULT

    assert cube.ndim == NDIMS_DEFAULT
    assert cube.shape == (ENSEMBLE_MEMBERS_DEFAULT, NPOINTS_DEFAULT, NPOINTS_DEFAULT)

    spatial_grid_values = SPATIAL_GRID_ATTRIBUTE_DEFAULTS[SPATIAL_GRID_DEFAULT]
    assert cube.coords()[0].name() == "realization"
    assert cube.coords()[1].name() == spatial_grid_values["y"]
    assert cube.coords()[2].name() == spatial_grid_values["x"]

    for axis in ("y", "x"):
        assert cube.coord(axis=axis).units == spatial_grid_values["units"]
        assert cube.coord(axis=axis).coord_system == spatial_grid_values["coord_system"]
        assert np.diff(cube.coord(axis=axis).points)[0] == pytest.approx(
            spatial_grid_values["grid_spacing"]
        )

    assert np.count_nonzero(cube.data) == 0

    assert iris_time_to_datetime(cube.coord("time"))[0] == TIME_DEFAULT
    assert cube.coord("time").bounds is None
    assert (
        iris_time_to_datetime(cube.coord("forecast_reference_time"))[0] == FRT_DEFAULT
    )
    assert cube.coord("forecast_period").points == FORECAST_PERIOD_DEFAULT

    assert cube.attributes == ATTRIBUTES_DEFAULT
Beispiel #8
0
def test_disable_ensemble_set_height_levels():
    """ Tests cube generated without realizations dimension but with height dimension """
    ensemble_members = 1
    height_levels = [1.5, 3.0, 4.5]
    cube = generate_metadata(
        MANDATORY_ATTRIBUTE_DEFAULTS,
        ensemble_members=ensemble_members,
        height_levels=height_levels,
    )

    assert cube.ndim == 3
    assert cube.shape == (
        len(height_levels),
        NPOINTS_DEFAULT,
        NPOINTS_DEFAULT,
    )

    expected_spatial_grid_attributes = SPATIAL_GRID_ATTRIBUTE_DEFAULTS[
        SPATIAL_GRID_DEFAULT]
    assert cube.coords()[0].name() == "height"
    assert cube.coords()[1].name() == expected_spatial_grid_attributes["y"]
    assert cube.coords()[2].name() == expected_spatial_grid_attributes["x"]

    np.testing.assert_array_equal(cube.coord("height").points, height_levels)

    # Assert that cube shape is different from default cube shape but metadata unchanged
    _check_cube_shape_different(cube)
Beispiel #9
0
def test_set_attributes():
    """ Tests cube generated with specified attributes and the rest of the values set
    as default values """
    attributes = {"test_attribute": "kittens"}
    cube = generate_metadata(MANDATORY_ATTRIBUTE_DEFAULTS,
                             attributes=attributes)
    expected_attributes = MANDATORY_ATTRIBUTE_DEFAULTS.copy()
    expected_attributes["test_attribute"] = "kittens"
    assert cube.attributes == expected_attributes

    # Assert that no other values have unexpectedly changed by returning changed values
    # to defaults and comparing against default cube
    default_cube = generate_metadata(MANDATORY_ATTRIBUTE_DEFAULTS)
    cube.attributes = default_cube.attributes

    assert cube == default_cube
Beispiel #10
0
def test_set_height_levels():
    """ Tests cube generated with specified height levels as an additional dimension """
    height_levels = [1.5, 3.0, 4.5]
    cube = generate_metadata(height_levels=height_levels)

    assert cube.ndim == 4
    assert cube.shape == (
        ENSEMBLE_MEMBERS_DEFAULT,
        len(height_levels),
        NPOINTS_DEFAULT,
        NPOINTS_DEFAULT,
    )

    expected_spatial_grid_attributes = SPATIAL_GRID_ATTRIBUTE_DEFAULTS[
        SPATIAL_GRID_DEFAULT
    ]
    assert cube.coords()[0].name() == "realization"
    assert cube.coords()[1].name() == "height"
    assert cube.coords()[2].name() == expected_spatial_grid_attributes["y"]
    assert cube.coords()[3].name() == expected_spatial_grid_attributes["x"]

    np.testing.assert_array_equal(cube.coord("height").points, height_levels)

    # Assert that cube shape is different from default cube shape but metadata unchanged
    _check_cube_shape_different(cube)
Beispiel #11
0
def test_set_domain_corner():
    """ Tests cube generated with specified domain corner and the rest of the values
    set as default values """
    domain_corner = (0, 0)
    cube = generate_metadata(domain_corner=domain_corner)

    assert cube.coord(axis="y").points[0] == domain_corner[0]
    assert cube.coord(axis="x").points[0] == domain_corner[1]

    # Assert that no other values have unexpectedly changed by returning changed values
    # to defaults and comparing against default cube
    default_cube = generate_metadata()
    cube.coord(axis="y").points = default_cube.coord(axis="y").points
    cube.coord(axis="x").points = default_cube.coord(axis="x").points
    cube.coord(axis="y").bounds = default_cube.coord(axis="y").bounds
    cube.coord(axis="x").bounds = default_cube.coord(axis="x").bounds
    assert cube == default_cube
Beispiel #12
0
def test_set_name_no_units():
    """ Tests cube generated with specified name, automatically setting units, and the
    rest of the values set as default values """
    name = "air_pressure"
    cube = generate_metadata(name=name)

    assert cube.name() == name
    assert cube.standard_name == name
    assert cube.units == "Pa"

    # Assert that no other values have unexpectedly changed by returning changed values
    # to defaults and comparing against default cube
    default_cube = generate_metadata()
    cube.standard_name = default_cube.standard_name
    cube.units = default_cube.units

    assert cube == default_cube
Beispiel #13
0
def test_set_grid_spacing():
    """ Tests cube generated with specified grid_spacing and the rest of the values set
    as default values """
    grid_spacing = 5
    cube = generate_metadata(grid_spacing=grid_spacing)

    assert np.diff(cube.coord(axis="y").points)[0] == grid_spacing
    assert np.diff(cube.coord(axis="x").points)[0] == grid_spacing

    # Assert that no other values have unexpectedly changed by returning changed values
    # to defaults and comparing against default cube
    default_cube = generate_metadata()
    for axis in ("y", "x"):
        cube.coord(axis=axis).points = default_cube.coord(axis=axis).points
        cube.coord(axis=axis).bounds = default_cube.coord(axis=axis).bounds

    assert cube == default_cube
Beispiel #14
0
def test_set_npoints():
    """ Tests cube generated with specified npoints """
    npoints = 500
    cube = generate_metadata(npoints=npoints)

    assert cube.shape == (ENSEMBLE_MEMBERS_DEFAULT, npoints, npoints)

    # Assert that cube shape is different from default cube shape but metadata unchanged
    _check_cube_shape_different(cube)
Beispiel #15
0
def test_set_spatial_grid(spatial_grid):
    """ Tests different spatial grids generates cubes with default values for that
    spatial grid """
    cube = generate_metadata(
        MANDATORY_ATTRIBUTE_DEFAULTS,
        spatial_grid=spatial_grid,
    )

    expected_spatial_grid_attributes = SPATIAL_GRID_ATTRIBUTE_DEFAULTS[
        spatial_grid]

    assert cube.coords()[0].name() == "realization"
    assert cube.coords()[1].name() == expected_spatial_grid_attributes["y"]
    assert cube.coords()[2].name() == expected_spatial_grid_attributes["x"]

    for axis in ("y", "x"):
        assert cube.coord(
            axis=axis).units == expected_spatial_grid_attributes["units"]
        assert (cube.coord(axis=axis).coord_system ==
                expected_spatial_grid_attributes["coord_system"])
        assert np.diff(cube.coord(axis=axis).points)[0] == pytest.approx(
            expected_spatial_grid_attributes["grid_spacing"])

    # Assert that no other values have unexpectedly changed by returning changed values
    # to defaults and comparing against default cube
    default_cube = generate_metadata(MANDATORY_ATTRIBUTE_DEFAULTS)

    if spatial_grid != SPATIAL_GRID_DEFAULT:
        default_spatial_grid_values = SPATIAL_GRID_ATTRIBUTE_DEFAULTS[
            SPATIAL_GRID_DEFAULT]
        cube.coords()[1].rename(default_spatial_grid_values["y"])
        cube.coords()[2].rename(default_spatial_grid_values["x"])

        for axis in ("y", "x"):
            cube.coord(axis=axis).points = default_cube.coord(axis=axis).points
            cube.coord(axis=axis).bounds = default_cube.coord(axis=axis).bounds
            cube.coord(axis=axis).units = default_spatial_grid_values["units"]
            cube.coord(
                axis=axis
            ).coord_system = default_spatial_grid_values["coord_system"]

        assert cube == default_cube
    else:
        assert cube == default_cube
Beispiel #16
0
def test_set_frt():
    """ Tests cube generated with specified forecast reference time and the rest of the
    values set as default values """
    frt = datetime(2017, 1, 1, 0, 0)
    cube = generate_metadata(frt=frt)

    assert iris_time_to_datetime(cube.coord("forecast_reference_time"))[0] == frt
    assert cube.coord("forecast_period").points > 0

    # Assert that no other values have unexpectedly changed by returning changed values
    # to defaults and comparing against default cube
    default_cube = generate_metadata()

    cube.coord("forecast_reference_time").points = default_cube.coord(
        "forecast_reference_time"
    ).points
    cube.coord("forecast_period").points = default_cube.coord("forecast_period").points

    assert cube == default_cube
Beispiel #17
0
def test_set_time_period():
    """ Tests cube generated with time bounds calculated using specified time_period
    and the rest of the values set as default values """
    time_period = 150
    cube = generate_metadata(time_period=time_period)

    assert iris_time_to_datetime(cube.coord("time"))[0] == TIME_DEFAULT
    assert cube.coord("forecast_period").points == FORECAST_PERIOD_DEFAULT
    assert cube.coord("time").bounds[0][0] == datetime_to_iris_time(
        datetime(2017, 11, 10, 1, 30)
    )
    assert cube.coord("time").bounds[0][1] == datetime_to_iris_time(TIME_DEFAULT)

    # Assert that no other values have unexpectedly changed by returning changed values
    # to defaults and comparing against default cube
    default_cube = generate_metadata()
    cube.coord("time").bounds = None
    cube.coord("forecast_period").bounds = None

    assert cube == default_cube
Beispiel #18
0
def test_name_unknown_with_units():
    """ Tests cube generated with specified name which isn't a CF standard name,
    specified units, and the rest of the values set as default values"""
    name = "lapse_rate"
    units = "K m-1"
    cube = generate_metadata(name=name, units=units)

    # "lapse_rate" not CF standard so standard_name expected None
    assert cube.name() == name
    assert cube.standard_name is None
    assert cube.units == units

    # Assert that no other values have unexpectedly changed by returning changed values
    # to defaults and comparing against default cube
    default_cube = generate_metadata()
    # Iris.cube.Cube.rename() assigns standard_name if valid
    cube.rename(default_cube.standard_name)
    cube.units = default_cube.units

    assert cube == default_cube
Beispiel #19
0
def test_set_ensemble_members():
    """ Tests cube generated with specified number of ensemble members """
    ensemble_members = 4
    cube = generate_metadata(ensemble_members=ensemble_members)

    assert cube.ndim == 3
    assert cube.shape == (ensemble_members, NPOINTS_DEFAULT, NPOINTS_DEFAULT)
    assert cube.coords()[0].name() == "realization"

    # Assert that cube shape is different from default cube shape but metadata unchanged
    _check_cube_shape_different(cube)
Beispiel #20
0
def test_set_name_units():
    """ Tests cube generated with specified name and units, and the rest of the values
    set as default values"""
    name = "air_pressure"
    units = "pascal"
    cube = generate_metadata(MANDATORY_ATTRIBUTE_DEFAULTS,
                             name=name,
                             units=units)

    assert cube.name() == name
    assert cube.standard_name == name
    assert cube.units == units

    # Assert that no other values have unexpectedly changed by returning changed values
    # to defaults and comparing against default cube
    default_cube = generate_metadata(MANDATORY_ATTRIBUTE_DEFAULTS)
    cube.standard_name = default_cube.standard_name
    cube.units = default_cube.units

    assert cube == default_cube
Beispiel #21
0
def test_disable_ensemble(ensemble_members):
    """ Tests cube generated without realizations dimension """
    cube = generate_metadata(ensemble_members=ensemble_members)

    assert cube.ndim == 2
    assert cube.shape == (NPOINTS_DEFAULT, NPOINTS_DEFAULT)

    spatial_grid_values = SPATIAL_GRID_ATTRIBUTE_DEFAULTS[SPATIAL_GRID_DEFAULT]
    assert cube.coords()[0].name() == spatial_grid_values["y"]
    assert cube.coords()[1].name() == spatial_grid_values["x"]

    # Assert that cube shape is different from default cube shape but metadata unchanged
    _check_cube_shape_different(cube)
Beispiel #22
0
def process(
    mandatory_attributes_json: cli.inputjson,
    *,
    name="air_pressure_at_sea_level",
    units=None,
    spatial_grid="latlon",
    time_period: int = None,
    json_input: cli.inputjson = None,
    ensemble_members: int = 8,
    grid_spacing: float = None,
    domain_corner: cli.comma_separated_list_of_float = None,
    npoints: int = 71,
):
    """ Generate a cube with metadata only.

    Args:
        mandatory_attributes_json (Dict):
            Specifies the values of the mandatory attributes, title, institution and
            source.
        name (Optional[str]):
            Output variable name, or if creating a probability cube the name of the
            underlying variable to which the probability field applies.
        units (Optional[str]):
            Output variable units, or if creating a probability cube the units of the
            underlying variable / threshold.
        spatial_grid (Optional[str]):
            What type of x/y coordinate values to use.  Permitted values are
            "latlon" or "equalarea".
        time_period (Optional[int]):
            The period in minutes between the time bounds. This is used to calculate
            the lower time bound. If unset the diagnostic will be instantaneous, i.e.
            without time bounds.
        json_input (Optional[Dict]):
            Dictionary containing values for one or more of: "name", "units", "time",
            "time_bounds", "frt", "spp__relative_to_threshold", "attributes"
            (dictionary of additional metadata attributes) and "coords" (dictionary).
            "coords" can contain "height_levels" (list of height/pressure level values),
            and one of "realizations", "percentiles" or "thresholds" (list of dimension
            values).
        ensemble_members (Optional[int]):
            Number of ensemble members. Default 8. Will not be used if "realizations",
            "percentiles" or "thresholds" provided in json_input.
        grid_spacing (Optional[float]):
            Resolution of grid (metres or degrees).
        domain_corner (Optional[Tuple[float, float]]):
            Bottom left corner of grid domain (y,x) (degrees for latlon or metres for
            equalarea).
        npoints (Optional[int]):
            Number of points along each of the y and x spatial axes.

    Returns:
        iris.cube.Cube:
            Output of generate_metadata()
    """
    # Set arguments to pass to generate_metadata function and remove json_input for
    # processing contents before adding
    generate_metadata_args = locals()
    for key in ["mandatory_attributes_json", "json_input"]:
        generate_metadata_args.pop(key, None)

    from improver.synthetic_data.generate_metadata import generate_metadata
    from improver.synthetic_data.utilities import (
        get_height_levels,
        get_leading_dimension,
    )
    from improver.utilities.temporal import cycletime_to_datetime

    if json_input is not None:
        # Get leading dimension and height/pressure data from json_input
        if "coords" in json_input:
            coord_data = json_input["coords"]

            (
                json_input["leading_dimension"],
                json_input["cube_type"],
            ) = get_leading_dimension(coord_data)
            json_input["height_levels"], json_input["pressure"] = get_height_levels(
                coord_data
            )

            json_input.pop("coords", None)

        # Convert str time, frt and time_bounds to datetime
        if "time" in json_input:
            json_input["time"] = cycletime_to_datetime(json_input["time"])

        if "frt" in json_input:
            json_input["frt"] = cycletime_to_datetime(json_input["frt"])

        if "time_bounds" in json_input:
            time_bounds = []
            for tb in json_input["time_bounds"]:
                time_bounds.append(cycletime_to_datetime(tb))
            json_input["time_bounds"] = time_bounds

        # Update generate_metadata_args with the json_input data
        generate_metadata_args.update(json_input)
    return generate_metadata(mandatory_attributes_json, **generate_metadata_args)
Beispiel #23
0
def test_spatial_grid_not_supported():
    """ Tests error raised if spatial grid not supported """
    spatial_grid = "other"

    with pytest.raises(ValueError, match=spatial_grid):
        generate_metadata(spatial_grid=spatial_grid)
Beispiel #24
0
def _check_cube_shape_different(cube):
    """ Asserts that cube shape has been changed from default but name, units and
    attributes are unchanged """
    default_cube = generate_metadata()
    assert cube.shape != default_cube.shape
    assert iris.util.describe_diff(cube, default_cube) is None
Beispiel #25
0
def test_leading_dimension(cube_type, spp__relative_to_threshold):
    """ Tests cube generated with leading dimension specified using percentile and
    probability flags, and different values for spp__relative_to_threshold """
    if cube_type == "other":
        # Tests that error is raised when cube type isn't supported
        msg = 'Cube type {} not supported. Specify one of "variable", "percentile" or "probability".'.format(
            cube_type
        )

        with pytest.raises(ValueError, match=msg):
            generate_metadata(
                cube_type=cube_type,
                spp__relative_to_threshold=spp__relative_to_threshold,
            )
    else:
        leading_dimension = [10, 20, 30, 40, 50, 60, 70, 80]

        if spp__relative_to_threshold is not None:
            cube = generate_metadata(
                leading_dimension=leading_dimension,
                cube_type=cube_type,
                spp__relative_to_threshold=spp__relative_to_threshold,
            )
        else:
            cube = generate_metadata(
                leading_dimension=leading_dimension, cube_type=cube_type,
            )
            spp__relative_to_threshold = RELATIVE_TO_THRESHOLD_DEFAULT

        if cube_type == "percentile":
            cube_name = NAME_DEFAULT
            coord_name = "percentile"
        elif cube_type == "probability":
            cube_name = "probability_of_{}_{}_threshold".format(
                NAME_DEFAULT, spp__relative_to_threshold
            )
            coord_name = NAME_DEFAULT

            assert cube.coord(coord_name).attributes == {
                "spp__relative_to_threshold": spp__relative_to_threshold
            }
            cube.coord(coord_name).attributes = {}
        else:
            cube_name = NAME_DEFAULT
            coord_name = "realization"

        assert cube.name() == cube_name
        assert cube.ndim == 3
        assert cube.shape == (len(leading_dimension), NPOINTS_DEFAULT, NPOINTS_DEFAULT)
        assert cube.coords()[0].name() == coord_name
        np.testing.assert_array_equal(cube.coord(coord_name).points, leading_dimension)

        # Assert that no other values have unexpectedly changed by returning changed
        # values to defaults and comparing against default cube
        default_cube = generate_metadata()

        cube.coord(coord_name).points = default_cube.coord("realization").points
        cube.coord(coord_name).rename("realization")
        cube.coord("realization").units = "1"
        cube.rename(default_cube.standard_name)
        cube.units = default_cube.units

        assert cube == default_cube
Beispiel #26
0
def test_domain_corner_incorrect_length(domain_corner):
    """Tests error raised if domain corner not length 2"""
    msg = "Domain corner"
    with pytest.raises(ValueError, match=msg):
        generate_metadata(domain_corner=domain_corner)