Ejemplo n.º 1
0
def test_process(with_percentiles, input_as_cube, input_has_time_bounds):
    """Checks that the plugin process method returns a cube with expected data and
    time coord for our test data"""
    data_shape = [3, 4]
    data = np.array(
        [np.zeros(data_shape, dtype=np.float32), np.ones(data_shape, dtype=np.float32)]
    )
    expected_data = [[0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1]]
    if with_percentiles:
        cube = make_percentile_cube(data_shape, time_bounds=input_has_time_bounds)
        data = np.array([data, data, data])
        expected_data = np.array([expected_data, expected_data, expected_data])
    else:
        cube = make_input_cube(data_shape, time_bounds=input_has_time_bounds)
    cube.data = data
    local_time = datetime(2017, 11, 10, 5, 0)
    timezone_cube = make_timezone_cube()
    row1 = [cube.coord("time").units.date2num(datetime(2017, 11, 10, 4, 0))] * 4
    row2 = [cube.coord("time").units.date2num(datetime(2017, 11, 10, 5, 0))] * 4
    row3 = [cube.coord("time").units.date2num(datetime(2017, 11, 10, 6, 0))] * 4
    expected_times = [row1, row2, row3]
    expected_bounds = np.array(expected_times).reshape((3, 4, 1)) + [[[-3600, 0]]]
    if not input_as_cube:
        # Split cube into a list of cubes
        cube = [c for c in cube.slices_over("time")]
    result = TimezoneExtraction()(cube, timezone_cube, local_time)
    assert_metadata_ok(result)
    assert np.isclose(result.data, expected_data).all()
    assert np.isclose(result.coord("time").points, expected_times).all()
    if input_has_time_bounds:
        assert np.isclose(result.coord("time").bounds, expected_bounds).all()
    else:
        assert result.coord("time").bounds is None
Ejemplo n.º 2
0
def process(
    timezone_cube: cli.inputcube,
    local_time: str,
    *cubes: cli.inputcube,
):
    """Calculates timezone-offset data for the specified UTC output times

    Args:
        timezone_cube (iris.cube.Cube):
            Cube describing the UTC offset for the local time at each grid location.
            Must have the same spatial coords as input_cube.
            Use generate-timezone-mask-ancillary to create this.
        local_time (str):
            The "local" time of the output cube as %Y%m%dT%H%M. This will form a
            scalar "time_in_local_timezone" coord on the output cube, while the "time"
            coord will be auxillary to the spatial coords and will show the UTC time
            that matches the local_time at each point.
        cubes (list of iris.cube.Cube):
            Source data to be remapped onto time-zones. Must contain an exact 1-to-1
            mapping of times to time-zones. Multiple input files will be merged into one
            cube.

    Returns:
        iris.cube.Cube:
            Processed cube.
    """
    from datetime import datetime
    from improver.utilities.temporal import TimezoneExtraction

    local_datetime = datetime.strptime(local_time, "%Y%m%dT%H%M")
    return TimezoneExtraction()(cubes, timezone_cube, local_datetime)
Ejemplo n.º 3
0
def test_check_timezones_are_unique_fail(offset):
    """Checks that check_timezones_are_unique fails if we break our test cube"""
    timezone_cube = make_timezone_cube()
    timezone_cube.data[0, 0, 0] += offset
    with pytest.raises(
        ValueError,
        match=r"Timezone cube does not map exactly one time zone to each spatial point",
    ):
        TimezoneExtraction().check_timezones_are_unique(timezone_cube)
Ejemplo n.º 4
0
def test_bad_dtype():
    """Checks that the plugin raises a useful error if the output are float64"""
    cube = make_input_cube([3, 4])
    local_time = datetime(2017, 11, 10, 5, 0)
    timezone_cube = make_timezone_cube()
    timezone_cube.data = timezone_cube.data.astype(np.int32)
    with pytest.raises(
        TypeError,
        match=r"Operation multiply on types \{dtype\(\'.*32\'\), dtype\(\'.*32\'\)\} results in",
    ):
        TimezoneExtraction()(cube, timezone_cube, local_time)
Ejemplo n.º 5
0
def test_create_output_cube(with_cell_method):
    """Tests that the create_output_cube method builds a cube with appropriate
    meta-data. The Time coord is tested in test_process as it depends on multiple
    methods."""
    data_shape = [3, 4]
    cube = make_input_cube(data_shape)
    if with_cell_method:
        cell_method = CellMethod("minimum", coords="time")
        cube.add_cell_method(cell_method)
    local_time = datetime(2017, 11, 9, 12, 0)
    plugin = TimezoneExtraction()
    plugin.output_data = np.zeros(data_shape, dtype=np.float32)
    plugin.time_points = np.full(
        data_shape,
        fill_value=Unit(TIME_COORDS["time"].units).date2num(
            datetime(2017, 11, 10, 4, 0)),
        dtype=np.int64,
    )
    plugin.time_bounds = None
    result = plugin.create_output_cube(cube, local_time)
    assert_metadata_ok(result)
    assert result.name() == cube.name()
    assert result.units == cube.units
    result_local_time = result.coord("time_in_local_timezone")
    assert [cell.point for cell in result_local_time.cells()] == [local_time]
    expected_shape = data_shape
    assert result.shape == tuple(expected_shape)
    assert result.attributes == cube.attributes
    if with_cell_method:
        assert result.cell_methods == tuple([cell_method])
Ejemplo n.º 6
0
def test_check_input_cube_time(local_time, expect_success):
    """Checks that check_input_cube_time can differentiate between arguments that match
    expected times and arguments that don't."""
    cube = make_input_cube([3, 4])
    timezone_cube = make_timezone_cube()
    plugin = TimezoneExtraction()
    plugin.check_input_cube_dims(cube, timezone_cube)
    if expect_success:
        plugin.check_input_cube_time(cube, local_time)
    else:
        with pytest.raises(
            ValueError, match=r"Time coord on input cube does not match required times."
        ):
            plugin.check_input_cube_time(cube, local_time)
Ejemplo n.º 7
0
def test_bad_spatial_coords():
    """Checks that the plugin raises a useful error if the longitude coord is shifted by
    180 degrees"""
    cube = make_input_cube([3, 4])
    local_time = datetime(2017, 11, 10, 5, 0)
    timezone_cube = make_timezone_cube()
    timezone_cube.data = timezone_cube.data.astype(np.int32)
    longitude_coord = timezone_cube.coord("longitude")
    timezone_cube.replace_coord(longitude_coord.copy(longitude_coord.points + 180))
    with pytest.raises(
        ValueError,
        match=r"Spatial coordinates on input_cube and timezone_cube do not match.",
    ):
        TimezoneExtraction()(cube, timezone_cube, local_time)
Ejemplo n.º 8
0
def test_check_input_cube_dims(include_time_coord):
    """Checks that check_input_cube_dims can differentiate between an input cube
    with time, y, x coords and one where time is missing. Also checks that timezone_cube
    has been reordered correctly."""
    cube = make_input_cube([3, 4])
    timezone_cube = make_timezone_cube()
    plugin = TimezoneExtraction()
    if include_time_coord:
        plugin.check_input_cube_dims(cube, timezone_cube)
        assert plugin.timezone_cube.coord_dims("UTC_offset") == tuple(
            [plugin.timezone_cube.ndim - 1])
    else:
        cube.remove_coord("time")
        with pytest.raises(
                ValueError,
                match=r"Expected coords on input_cube: time, y, x "):
            plugin.check_input_cube_dims(cube, timezone_cube)
Ejemplo n.º 9
0
def process(
    local_time: str, *cubes: cli.inputcube,
):
    """Calculates timezone-offset data for the specified UTC output times

    Args:
        local_time (str):
            The "local" time of the output cube as %Y%m%dT%H%M. This will form a
            scalar "time_in_local_timezone" coord on the output cube, while the "time"
            coord will be auxillary to the spatial coords and will show the UTC time
            that matches the local_time at each point.  This can also be provided in
            the form of a filepath where the 'local_time' is denoted in this format
            at the beginning of the basename.
        cubes (list of iris.cube.Cube):
            Source data to be remapped onto time-zones. Must contain an exact 1-to-1
            mapping of times to time-zones. Multiple input files will be merged into one
            cube.
            Assumes the final argument is a timezone_cube, which is a cube describing
            the UTC offset for the local time at each grid location.
            Must have the same spatial coords as input_cube.
            Use generate-timezone-mask-ancillary to create this.

    Returns:
        iris.cube.Cube:
            Processed cube.
    """
    import os
    from datetime import datetime

    from improver.utilities.temporal import TimezoneExtraction

    timezone_cube = cubes[-1]
    cubes = cubes[:-1]

    local_time = os.path.basename(local_time)[:13]
    local_datetime = datetime.strptime(local_time, "%Y%m%dT%H%M")
    return TimezoneExtraction()(cubes, timezone_cube, local_datetime)
Ejemplo n.º 10
0
def test_check_timezones_are_unique_pass():
    """Checks that check_timezones_are_unique allows our test cube"""
    timezone_cube = make_timezone_cube()
    TimezoneExtraction().check_timezones_are_unique(timezone_cube)