Beispiel #1
0
def test_dims_mismatch_error():
    """Test the process function with mismatched dimensions"""
    rain, snow = setup_cubes(snow_data=np.array([[0, 0.5]], dtype=np.float32))
    with pytest.raises(
        ValueError, match="Rain and snow cubes are not on the same grid"
    ):
        SnowFraction()(iris.cube.CubeList([rain, snow]))
Beispiel #2
0
def process(*cubes: cli.inputcube, model_id_attr: str = None):
    """
    Calculates a snow-fraction field from fields of snow and rain (rate or
    accumulation). Where no precipitation is present, the data are filled in from
    the nearest precipitating point.

    snow_fraction = snow / (snow + rain)

    Args:
        cubes (iris.cube.CubeList or list):
            Contains cubes of rain and snow, both must be either rates or accumulations.
        model_id_attr (str):
            Name of the attribute used to identify the source model for
            blending.

    Returns:
        iris.cube.Cube:
            A single cube containing the snow-fraction data.

    """
    from iris.cube import CubeList

    from improver.precipitation_type.snow_fraction import SnowFraction

    return SnowFraction(model_id_attr=model_id_attr)(CubeList(cubes))
Beispiel #3
0
def test_non_coercing_units_error():
    """Test the process function with input cubes of incompatible units"""
    rain, snow = setup_cubes()
    rain.units = Unit("K")
    with pytest.raises(
        ValueError, match=r"Unable to convert from 'Unit\('m s-1'\)' to 'Unit\('K'\)'."
    ):
        SnowFraction()(iris.cube.CubeList([rain, snow]))
Beispiel #4
0
def test_coercing_units():
    """Test the process function with input cubes of different but compatible units"""
    rain, snow = setup_cubes()
    rain.convert_units("mm h-1")
    result = SnowFraction()(iris.cube.CubeList([rain, snow]))
    assert str(result.units) == "1"
    np.testing.assert_allclose(result.data, EXPECTED_DATA)
    assert rain.units == "mm h-1"
    assert snow.units == "m s-1"
Beispiel #5
0
def test_wrong_input_names_error():
    """Test the process function with incorrect input cubes"""
    rain, snow = setup_cubes()
    rain.rename("kittens")
    snow.rename("puppies")
    with pytest.raises(
        ValueError,
        match=r"Could not find both rain and snow in \['kittens', 'puppies'\]",
    ):
        SnowFraction()(iris.cube.CubeList([rain, snow]))
Beispiel #6
0
def test_masked_data_error(mask_what):
    """Test the process function with masked data points"""
    rain, snow = setup_cubes()
    mask = [[False, False], [False, True]]
    if "rain" in mask_what:
        rain.data = np.ma.masked_array(rain.data, mask)
    if "snow" in mask_what:
        snow.data = np.ma.masked_array(snow.data, mask)
    with pytest.raises(ValueError, match=r"Unexpected masked data in input cube\(s\)"):
        SnowFraction()(iris.cube.CubeList([rain, snow]))
Beispiel #7
0
def test_input_name_matches_both_phases_error():
    """Test the process function with an input cube that has both rain and snow in its name"""
    rain, snow = setup_cubes()
    rain.rename("its_raining_snowy_kittens")
    snow.rename("puppies")
    with pytest.raises(
        ValueError,
        match="Failed to find unique rain and snow cubes from \['its_raining_snowy_kittens', 'puppies'\]",
    ):
        SnowFraction()(iris.cube.CubeList([rain, snow]))
Beispiel #8
0
def test_acclen_mismatch_error():
    """Test the process function with mismatched accumulation lengths"""
    rain, snow = setup_cubes(name="thickness_of_{phase}fall_amount")
    time_coords = construct_scalar_time_coords(
        [c.point for c in snow.coord("time").cells()],
        (datetime(2017, 11, 10, 1, 0), datetime(2017, 11, 10, 4, 0)),
        snow.coord("forecast_reference_time").cell(0).point,
    )
    _ = [snow.replace_coord(coord) for coord, _ in time_coords]
    with pytest.raises(
        ValueError, match="Rain and snow cubes do not have the same time coord"
    ):
        SnowFraction()(iris.cube.CubeList([rain, snow]))
Beispiel #9
0
def test_basic(cube_name, mask_what, model_id_attr):
    """Run a test with four values, including one with no precip that will trigger
    divide-by-zero.
    Check data and metadata of result. Check with and without masked arrays (because
    divide-by-zero gives a different result, even when input mask is all-False as in
    this test) and with and without a model_id_attr value.
    """
    rain, snow = setup_cubes(name=cube_name)
    if "rain" in mask_what:
        rain.data = np.ma.masked_array(rain.data)
    if "snow" in mask_what:
        snow.data = np.ma.masked_array(snow.data)

    expected_attributes = COMMON_ATTRS.copy()
    if model_id_attr:
        expected_attributes[model_id_attr] = rain.attributes[model_id_attr]
    result = SnowFraction(model_id_attr=model_id_attr)(iris.cube.CubeList([rain, snow]))
    assert isinstance(result, iris.cube.Cube)
    assert not isinstance(result.data, np.ma.masked_array)
    assert str(result.units) == "1"
    assert result.name() == "snow_fraction"
    assert result.attributes == expected_attributes
    np.testing.assert_allclose(result.data, EXPECTED_DATA)
Beispiel #10
0
def test_missing_cube_error():
    """Test the process function with one cube missing"""
    rain, _ = setup_cubes()
    with pytest.raises(ValueError, match="Expected exactly 2 input cubes, found 1"):
        SnowFraction()(iris.cube.CubeList([rain]))