Example #1
0
def process(
    cube: cli.inputcube,
    advection_velocity: inputadvection,
    orographic_enhancement: cli.inputcube = None,
    *,
    attributes_config: cli.inputjson = None,
    max_lead_time: int = 360,
    lead_time_interval: int = 15,
):
    """Module to extrapolate input cubes given advection velocity fields.

    Args:
        cube (iris.cube.Cube):
            The data to be advected.
        advection_velocity (iris.cube.CubeList):
            Advection cubes of U and V.
            These must have the names of either:
            precipitation_advection_x_velocity or grid_eastward_wind
            precipitation_advection_y_velocity or grid_northward_wind
        orographic_enhancement (iris.cube.Cube):
            Cube containing orographic enhancement forecasts for the lead times
            at which an extrapolation nowcast is required.
        attributes_config (dict):
            Dictionary containing the required changes to the attributes.
        max_lead_time (int):
            Maximum lead time required (mins).
        lead_time_interval (int):
            Interval between required lead times (mins).

    Returns:
        iris.cube.CubeList:
            New cubes with updated time and extrapolated data.
    """
    from improver.nowcasting.pysteps_advection import PystepsExtrapolate
    from improver.utilities.cube_manipulation import MergeCubes

    u_cube, v_cube = advection_velocity

    # extrapolate input data to required lead times
    forecast_plugin = PystepsExtrapolate(lead_time_interval, max_lead_time)
    forecast_cubes = forecast_plugin(cube,
                                     u_cube,
                                     v_cube,
                                     orographic_enhancement,
                                     attributes_dict=attributes_config)

    return MergeCubes()(forecast_cubes)
 def test_set_attributes(self):
     """Test plugin returns a cube with the specified attributes."""
     attributes_dict = {
         "mosg__grid_version": "1.0.0",
         "mosg__model_configuration": "nc_det",
         "source": "Met Office Nowcast",
         "institution": "Met Office",
         "title": "Nowcast on UK 2 km Standard Grid",
     }
     plugin = PystepsExtrapolate(self.interval, self.max_lead_time)
     result = plugin(
         self.rain_cube,
         self.ucube,
         self.vcube,
         self.orogenh_cube,
         attributes_dict=attributes_dict.copy(),
     )
     result[0].attributes.pop("history")
     self.assertEqual(result[0].attributes, attributes_dict)
    def setUp(self):
        """Set up test velocity and rainfall cubes"""
        # Skip if pysteps not available
        pytest.importorskip("pysteps")

        analysis_time = datetime.datetime(2019, 9, 10, 15)
        wind_data = 4 * np.ones((8, 8), dtype=np.float32)
        self.ucube = set_up_variable_cube(
            wind_data,
            name="precipitation_advection_x_velocity",
            units="m/s",
            spatial_grid="equalarea",
            time=analysis_time,
            frt=analysis_time,
        )
        self.vcube = set_up_variable_cube(
            wind_data,
            name="precipitation_advection_y_velocity",
            units="m/s",
            spatial_grid="equalarea",
            time=analysis_time,
            frt=analysis_time,
        )
        self.rain_cube = _make_initial_rain_cube(analysis_time)

        self.interval = 15
        self.max_lead_time = 120
        self.orogenh_cube = _make_orogenh_cube(analysis_time, self.interval,
                                               self.max_lead_time)
        self.plugin = PystepsExtrapolate(self.interval, self.max_lead_time)

        # set up all grids with 3.6 km spacing (1 m/s = 3.6 km/h,
        # using a 15 minute time step this is one grid square per step)
        xmin = 0
        ymin = 200000
        step = 3600
        xpoints = np.arange(xmin, xmin + 8 * step, step).astype(np.float32)
        ypoints = np.arange(ymin, ymin + 8 * step, step).astype(np.float32)
        for cube in [
                self.ucube, self.vcube, self.rain_cube, self.orogenh_cube
        ]:
            cube.coord(axis="x").points = xpoints
            cube.coord(axis="y").points = ypoints
Example #4
0
def generate_advection_velocities_from_winds(
    cubes, background_flow, orographic_enhancement
):
    """Generate advection velocities as perturbations from a non-zero background
    flow

    Args:
        cubes (iris.cube.CubeList):
            Two rainfall observations separated by a time difference
        background_flow (iris.cube.CubeList):
            u- and v-components of a non-zero background flow field
        orographic_enhancement (iris.cube.Cube):
            Field containing orographic enhancement data valid for both
            input cube times

        Returns:
        iris.cube.CubeList:
            u- and v- advection velocities
    """
    cubes.sort(key=lambda x: x.coord("time").points[0])

    lead_time_seconds = (
        cubes[1].coord("time").cell(0).point - cubes[0].coord("time").cell(0).point
    ).total_seconds()
    lead_time_minutes = int(lead_time_seconds / 60)

    # advect earlier cube forward to match time of later cube, using steering flow
    advected_cube = PystepsExtrapolate(lead_time_minutes, lead_time_minutes)(
        cubes[0], *background_flow, orographic_enhancement
    )[-1]

    # calculate velocity perturbations required to match forecast to observation
    cube_list = ApplyOrographicEnhancement("subtract")(
        [advected_cube, cubes[1]], orographic_enhancement
    )
    perturbations = OpticalFlow(data_smoothing_radius_km=8.0, iterations=20)(
        *cube_list, boxsize=18
    )

    # sum perturbations and original flow field to get advection velocities
    total_advection = _perturb_background_flow(background_flow, perturbations)
    return total_advection
Example #5
0
def process(
    cube: cli.inputcube,
    advection_velocity: inputadvection,
    orographic_enhancement: cli.inputcube,
    *,
    attributes_config: cli.inputjson = None,
    max_lead_time=360,
    lead_time_interval=15,
    accumulation_period=15,
    accumulation_units="m",
):
    """Module to extrapolate and accumulate the weather with 1 min fidelity.

    Args:
        cube (iris.cube.Cube):
            The input Cube to be processed.
        advection_velocity (iris.cube.CubeList):
            Advection cubes of U and V.
            These must have the names of either:
            precipitation_advection_x_velocity or grid_eastward_wind
            precipitation_advection_y_velocity or grid_northward_wind
        orographic_enhancement (iris.cube.Cube):
            Cube containing the orographic enhancement fields. May have data
            for multiple times in the cube.
        attributes_config (dict):
            Dictionary containing the required changes to the attributes.
        max_lead_time (int):
            Maximum lead time required (mins).
        lead_time_interval (int):
            Interval between required lead times (mins).
        accumulation_period (int):
            The period over which the accumulation is calculated (mins).
            Only full accumulation periods will be computed. At lead times
            that are shorter than the accumulation period, no accumulation
            output will be produced.
        accumulation_units (str):
            Desired units in which the accumulations should be expressed.
            e.g. 'mm'

    Returns:
        iris.cube.CubeList:
            New cubes with accumulated data.

    Raises:
        ValueError:
            If advection_velocity doesn't contain x and y velocity.
    """
    import numpy as np

    from improver.nowcasting.accumulation import Accumulation
    from improver.nowcasting.pysteps_advection import PystepsExtrapolate
    from improver.utilities.cube_manipulation import MergeCubes

    u_cube, v_cube = advection_velocity

    if not (u_cube and v_cube):
        raise ValueError("Neither u_cube or v_cube can be None")

    # extrapolate input data to the maximum required lead time
    forecast_plugin = PystepsExtrapolate(ACCUMULATION_FIDELITY, max_lead_time)
    forecast_cubes = forecast_plugin(cube,
                                     u_cube,
                                     v_cube,
                                     orographic_enhancement,
                                     attributes_dict=attributes_config)
    lead_times = np.arange(lead_time_interval, max_lead_time + 1,
                           lead_time_interval)

    # Accumulate high frequency rate into desired accumulation intervals.
    plugin = Accumulation(
        accumulation_units=accumulation_units,
        accumulation_period=accumulation_period * 60,
        forecast_periods=lead_times * 60,
    )
    result = plugin(forecast_cubes)

    return MergeCubes()(result)