Example #1
0
 def test_string_default(self):
     token = 'air temperature'  # includes space
     result = CellMethod(self.method, coords=token)
     expected = '{}: unknown'.format(self.method)
     self.assertEqual(str(result), expected)
Example #2
0
    def process(self, cube_ens_wdir):
        """Create a cube containing the wind direction averaged over the
        ensemble realizations.

        Args:
            cube_ens_wdir (iris.cube.Cube):
                Cube containing wind direction from multiple ensemble
                realizations.

        Returns:
            iris.cube.Cube:
                Cube containing the wind direction averaged from the
                ensemble realizations.
            cube_r_vals (numpy.ndarray):
                3D array - Radius taken from average complex wind direction
                angle.
            cube_confidence_measure (numpy.ndarray):
                3D array - The average distance from mean normalised - used
                as a confidence value.

        Raises
        ------
        TypeError: If cube_wdir is not a cube.

        """

        if not isinstance(cube_ens_wdir, iris.cube.Cube):
            msg = "Wind direction input is not a cube, but {}"
            raise TypeError(msg.format(type(cube_ens_wdir)))

        try:
            cube_ens_wdir.convert_units("degrees")
        except ValueError as err:
            msg = "Input cube cannot be converted to degrees: {}".format(err)
            raise ValueError(msg)

        self.n_realizations = len(cube_ens_wdir.coord("realization").points)
        y_coord_name = cube_ens_wdir.coord(axis="y").name()
        x_coord_name = cube_ens_wdir.coord(axis="x").name()
        for wdir_slice in cube_ens_wdir.slices(
            ["realization", y_coord_name, x_coord_name]
        ):
            self._reset()
            # Extract wind direction data.
            self.wdir_complex = self.deg_to_complex(wdir_slice.data)
            (self.realization_axis,) = wdir_slice.coord_dims("realization")

            # Copies input cube and remove realization dimension to create
            # cubes for storing results.
            self.wdir_slice_mean = next(wdir_slice.slices_over("realization"))
            self.wdir_slice_mean.remove_coord("realization")

            # Derive average wind direction.
            self.calc_wind_dir_mean()

            # Find radius values for wind direction average.
            self.find_r_values()

            # Calculate the confidence measure based on the difference
            # between the complex average and the individual ensemble
            # realizations.
            self.calc_confidence_measure()

            # Finds any meaningless averages and substitute with
            # the wind direction taken from the first ensemble realization.
            # Mask True if r values below threshold.
            where_low_r = np.where(self.r_vals_slice.data < self.r_thresh, True, False)
            # If the any point in the array contains poor r-values,
            # trigger decider function.
            if where_low_r.any():
                self.wind_dir_decider(where_low_r, wdir_slice)

            # Append to cubelists.
            self.wdir_cube_list.append(self.wdir_slice_mean)
            self.r_vals_cube_list.append(self.r_vals_slice)
            self.confidence_measure_cube_list.append(self.confidence_slice)

        # Combine cubelists into cube.
        cube_mean_wdir = self.wdir_cube_list.merge_cube()
        cube_r_vals = self.r_vals_cube_list.merge_cube()
        cube_confidence_measure = self.confidence_measure_cube_list.merge_cube()

        # Check that the dimensionality of coordinates of the output cube
        # matches the input cube.
        first_slice = next(cube_ens_wdir.slices_over(["realization"]))
        cube_mean_wdir = check_cube_coordinates(first_slice, cube_mean_wdir)

        # Change cube identifiers.
        cube_mean_wdir.add_cell_method(CellMethod("mean", coords="realization"))
        cube_r_vals.long_name = "radius_of_complex_average_wind_from_direction"
        cube_r_vals.units = None
        cube_confidence_measure.long_name = "confidence_measure_of_wind_from_direction"
        cube_confidence_measure.units = None

        return cube_mean_wdir, cube_r_vals, cube_confidence_measure
Example #3
0
def _all_other_rules(f):
    """
    This deals with all the other rules that have not been factored into any of
    the other convert_scalar_coordinate functions above.

    """
    references = []
    standard_name = None
    long_name = None
    units = None
    attributes = {}
    cell_methods = []
    dim_coords_and_dims = []
    aux_coords_and_dims = []

    # Season coordinates (--> scalar coordinates)
    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4]
            and (len(f.lbcode) != 5 or
                 (len(f.lbcode) == 5 and
                  (f.lbcode.ix not in [20, 21, 22, 23]
                   and f.lbcode.iy not in [20, 21, 22, 23]))) and f.lbmon == 12
            and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0 and f.lbmond == 3
            and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord("djf",
                                             long_name="season",
                                             units="no_unit"), None))

    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4]
            and ((len(f.lbcode) != 5) or
                 (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23]
                  and f.lbcode.iy not in [20, 21, 22, 23])) and f.lbmon == 3
            and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0 and f.lbmond == 6
            and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord("mam",
                                             long_name="season",
                                             units="no_unit"), None))

    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4]
            and ((len(f.lbcode) != 5) or
                 (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23]
                  and f.lbcode.iy not in [20, 21, 22, 23])) and f.lbmon == 6
            and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0 and f.lbmond == 9
            and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord("jja",
                                             long_name="season",
                                             units="no_unit"), None))

    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4]
            and ((len(f.lbcode) != 5) or
                 (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23]
                  and f.lbcode.iy not in [20, 21, 22, 23])) and f.lbmon == 9
            and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0
            and f.lbmond == 12 and f.lbdatd == 1 and f.lbhrd == 0
            and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord("son",
                                             long_name="season",
                                             units="no_unit"), None))

    # Special case where year is zero and months match.
    # Month coordinates (--> scalar coordinates)
    if (f.lbtim.ib == 2 and f.lbtim.ic in [1, 2, 4]
            and ((len(f.lbcode) != 5) or
                 (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23]
                  and f.lbcode.iy not in [20, 21, 22, 23])) and f.lbyr == 0
            and f.lbyrd == 0 and f.lbmon == f.lbmond):
        aux_coords_and_dims.append((AuxCoord(f.lbmon,
                                             long_name="month_number",
                                             units="1"), None))
        aux_coords_and_dims.append((
            AuxCoord(
                calendar.month_abbr[f.lbmon],
                long_name="month",
                units="no_unit",
            ),
            None,
        ))
        aux_coords_and_dims.append((
            DimCoord(
                points=f.lbft,
                standard_name="forecast_period",
                units="hours",
            ),
            None,
        ))

    # "Normal" (i.e. not cross-sectional) lats+lons (--> vector coordinates)
    if (f.bdx != 0.0 and f.bdx != f.bmdi and len(f.lbcode) != 5
            and f.lbcode[0] == 1):
        dim_coords_and_dims.append((
            DimCoord.from_regular(
                f.bzx,
                f.bdx,
                f.lbnpt,
                standard_name=f._x_coord_name(),
                units="degrees",
                circular=(f.lbhem in [0, 4]),
                coord_system=f.coord_system(),
            ),
            1,
        ))

    if (f.bdx != 0.0 and f.bdx != f.bmdi and len(f.lbcode) != 5
            and f.lbcode[0] == 2):
        dim_coords_and_dims.append((
            DimCoord.from_regular(
                f.bzx,
                f.bdx,
                f.lbnpt,
                standard_name=f._x_coord_name(),
                units="degrees",
                circular=(f.lbhem in [0, 4]),
                coord_system=f.coord_system(),
                with_bounds=True,
            ),
            1,
        ))

    if (f.bdy != 0.0 and f.bdy != f.bmdi and len(f.lbcode) != 5
            and f.lbcode[0] == 1):
        dim_coords_and_dims.append((
            DimCoord.from_regular(
                f.bzy,
                f.bdy,
                f.lbrow,
                standard_name=f._y_coord_name(),
                units="degrees",
                coord_system=f.coord_system(),
            ),
            0,
        ))

    if (f.bdy != 0.0 and f.bdy != f.bmdi and len(f.lbcode) != 5
            and f.lbcode[0] == 2):
        dim_coords_and_dims.append((
            DimCoord.from_regular(
                f.bzy,
                f.bdy,
                f.lbrow,
                standard_name=f._y_coord_name(),
                units="degrees",
                coord_system=f.coord_system(),
                with_bounds=True,
            ),
            0,
        ))

    if (f.bdy == 0.0 or f.bdy == f.bmdi) and (len(f.lbcode) != 5 or
                                              (len(f.lbcode) == 5
                                               and f.lbcode.iy == 10)):
        dim_coords_and_dims.append((
            DimCoord(
                f.y,
                standard_name=f._y_coord_name(),
                units="degrees",
                bounds=f.y_bounds,
                coord_system=f.coord_system(),
            ),
            0,
        ))

    if (f.bdx == 0.0 or f.bdx == f.bmdi) and (len(f.lbcode) != 5 or
                                              (len(f.lbcode) == 5
                                               and f.lbcode.ix == 11)):
        dim_coords_and_dims.append((
            DimCoord(
                f.x,
                standard_name=f._x_coord_name(),
                units="degrees",
                bounds=f.x_bounds,
                circular=(f.lbhem in [0, 4]),
                coord_system=f.coord_system(),
            ),
            1,
        ))

    # Cross-sectional vertical level types (--> vector coordinates)
    if (len(f.lbcode) == 5 and f.lbcode.iy == 2
            and (f.bdy == 0 or f.bdy == f.bmdi)):
        dim_coords_and_dims.append((
            DimCoord(
                f.y,
                standard_name="height",
                units="km",
                bounds=f.y_bounds,
                attributes={"positive": "up"},
            ),
            0,
        ))

    if len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.iy == 4:
        dim_coords_and_dims.append((
            DimCoord(
                f.y,
                standard_name="depth",
                units="m",
                bounds=f.y_bounds,
                attributes={"positive": "down"},
            ),
            0,
        ))

    if (len(f.lbcode) == 5 and f.lbcode.ix == 10 and f.bdx != 0
            and f.bdx != f.bmdi):
        dim_coords_and_dims.append((
            DimCoord.from_regular(
                f.bzx,
                f.bdx,
                f.lbnpt,
                standard_name=f._y_coord_name(),
                units="degrees",
                coord_system=f.coord_system(),
            ),
            1,
        ))

    if (len(f.lbcode) == 5 and f.lbcode.iy == 1
            and (f.bdy == 0 or f.bdy == f.bmdi)):
        dim_coords_and_dims.append((
            DimCoord(f.y, long_name="pressure", units="hPa",
                     bounds=f.y_bounds),
            0,
        ))

    if (len(f.lbcode) == 5 and f.lbcode.ix == 1
            and (f.bdx == 0 or f.bdx == f.bmdi)):
        dim_coords_and_dims.append((
            DimCoord(f.x, long_name="pressure", units="hPa",
                     bounds=f.x_bounds),
            1,
        ))

    # Cross-sectional time values (--> vector coordinates)
    if len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.iy == 23:
        dim_coords_and_dims.append((
            DimCoord(
                f.y,
                standard_name="time",
                units=cf_units.Unit(
                    "days since 0000-01-01 00:00:00",
                    calendar=cf_units.CALENDAR_360_DAY,
                ),
                bounds=f.y_bounds,
            ),
            0,
        ))

    if len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.ix == 23:
        dim_coords_and_dims.append((
            DimCoord(
                f.x,
                standard_name="time",
                units=cf_units.Unit(
                    "days since 0000-01-01 00:00:00",
                    calendar=cf_units.CALENDAR_360_DAY,
                ),
                bounds=f.x_bounds,
            ),
            1,
        ))

    if (len(f.lbcode) == 5 and f.lbcode[-1] == 3 and f.lbcode.iy == 23
            and f.lbtim.ib == 2 and f.lbtim.ic == 2):
        epoch_days_unit = cf_units.Unit(
            "days since 0000-01-01 00:00:00",
            calendar=cf_units.CALENDAR_360_DAY,
        )
        t1_epoch_days = epoch_days_unit.date2num(f.t1)
        t2_epoch_days = epoch_days_unit.date2num(f.t2)
        # The end time is exclusive, not inclusive.
        dim_coords_and_dims.append((
            DimCoord(
                np.linspace(t1_epoch_days,
                            t2_epoch_days,
                            f.lbrow,
                            endpoint=False),
                standard_name="time",
                units=epoch_days_unit,
                bounds=f.y_bounds,
            ),
            0,
        ))

    # Site number (--> scalar coordinate)
    if (len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.ix == 13
            and f.bdx != 0):
        dim_coords_and_dims.append((
            DimCoord.from_regular(f.bzx,
                                  f.bdx,
                                  f.lbnpt,
                                  long_name="site_number",
                                  units="1"),
            1,
        ))

    # Site number cross-sections (???)
    if (len(f.lbcode) == 5 and 13 in [f.lbcode.ix, f.lbcode.iy]
            and 11 not in [f.lbcode.ix, f.lbcode.iy]
            and hasattr(f, "lower_x_domain") and hasattr(f, "upper_x_domain")
            and all(f.lower_x_domain != -1.0e30)
            and all(f.upper_x_domain != -1.0e30)):
        aux_coords_and_dims.append((
            AuxCoord(
                (f.lower_x_domain + f.upper_x_domain) / 2.0,
                standard_name=f._x_coord_name(),
                units="degrees",
                bounds=np.array([f.lower_x_domain, f.upper_x_domain]).T,
                coord_system=f.coord_system(),
            ),
            1 if f.lbcode.ix == 13 else 0,
        ))

    if (len(f.lbcode) == 5 and 13 in [f.lbcode.ix, f.lbcode.iy]
            and 10 not in [f.lbcode.ix, f.lbcode.iy]
            and hasattr(f, "lower_y_domain") and hasattr(f, "upper_y_domain")
            and all(f.lower_y_domain != -1.0e30)
            and all(f.upper_y_domain != -1.0e30)):
        aux_coords_and_dims.append((
            AuxCoord(
                (f.lower_y_domain + f.upper_y_domain) / 2.0,
                standard_name=f._y_coord_name(),
                units="degrees",
                bounds=np.array([f.lower_y_domain, f.upper_y_domain]).T,
                coord_system=f.coord_system(),
            ),
            1 if f.lbcode.ix == 13 else 0,
        ))

    # LBPROC codings (--> cell method + attributes)
    unhandled_lbproc = True
    zone_method = None
    time_method = None
    if f.lbproc == 0:
        unhandled_lbproc = False
    elif f.lbproc == 64:
        zone_method = "mean"
    elif f.lbproc == 128:
        time_method = "mean"
    elif f.lbproc == 4096:
        time_method = "minimum"
    elif f.lbproc == 8192:
        time_method = "maximum"
    elif f.lbproc == 192:
        time_method = "mean"
        zone_method = "mean"

    if time_method is not None:
        if f.lbtim.ia != 0:
            intervals = "{} hour".format(f.lbtim.ia)
        else:
            intervals = None

        if f.lbtim.ib == 2:
            # Aggregation over a period of time.
            cell_methods.append(
                CellMethod(time_method, coords="time", intervals=intervals))
            unhandled_lbproc = False
        elif f.lbtim.ib == 3 and f.lbproc == 128:
            # Aggregation over a period of time within a year, over a number
            # of years.
            # Only mean (lbproc of 128) is handled as the min/max
            # interpretation is ambiguous e.g. decadal mean of daily max,
            # decadal max of daily mean, decadal mean of max daily mean etc.
            cell_methods.append(
                CellMethod(
                    "{} within years".format(time_method),
                    coords="time",
                    intervals=intervals,
                ))
            cell_methods.append(
                CellMethod("{} over years".format(time_method), coords="time"))
            unhandled_lbproc = False
        else:
            # Generic cell method to indicate a time aggregation.
            cell_methods.append(CellMethod(time_method, coords="time"))
            unhandled_lbproc = False

    if zone_method is not None:
        if f.lbcode == 1:
            cell_methods.append(CellMethod(zone_method, coords="longitude"))
            for coord, _dim in dim_coords_and_dims:
                if coord.standard_name == "longitude":
                    if len(coord.points) == 1:
                        coord.bounds = np.array([0.0, 360.0], dtype=np.float32)
                    else:
                        coord.guess_bounds()
            unhandled_lbproc = False
        elif f.lbcode == 101:
            cell_methods.append(
                CellMethod(zone_method, coords="grid_longitude"))
            for coord, _dim in dim_coords_and_dims:
                if coord.standard_name == "grid_longitude":
                    if len(coord.points) == 1:
                        coord.bounds = np.array([0.0, 360.0], dtype=np.float32)
                    else:
                        coord.guess_bounds()
            unhandled_lbproc = False
        else:
            unhandled_lbproc = True

    if unhandled_lbproc:
        attributes["ukmo__process_flags"] = tuple(
            sorted([
                name for value, name in LBPROC_MAP.items()
                if isinstance(value, int) and f.lbproc & value
            ]))

    if (f.lbsrce % 10000) == 1111:
        attributes["source"] = "Data from Met Office Unified Model"
        # Also define MO-netCDF compliant UM version.
        um_major = (f.lbsrce // 10000) // 100
        if um_major != 0:
            um_minor = (f.lbsrce // 10000) % 100
            attributes["um_version"] = "{:d}.{:d}".format(um_major, um_minor)

    if (f.lbuser[6] != 0 or (f.lbuser[3] // 1000) != 0
            or (f.lbuser[3] % 1000) != 0):
        attributes["STASH"] = f.stash

    if str(f.stash) in STASH_TO_CF:
        standard_name = STASH_TO_CF[str(f.stash)].standard_name
        units = STASH_TO_CF[str(f.stash)].units
        long_name = STASH_TO_CF[str(f.stash)].long_name

    if not f.stash.is_valid and f.lbfc in LBFC_TO_CF:
        standard_name = LBFC_TO_CF[f.lbfc].standard_name
        units = LBFC_TO_CF[f.lbfc].units
        long_name = LBFC_TO_CF[f.lbfc].long_name

    # Orography reference field (--> reference target)
    if f.lbuser[3] == 33:
        references.append(ReferenceTarget("orography", None))

    # Surface pressure reference field (--> reference target)
    if f.lbuser[3] == 409 or f.lbuser[3] == 1:
        references.append(ReferenceTarget("surface_air_pressure", None))

    return (
        references,
        standard_name,
        long_name,
        units,
        attributes,
        cell_methods,
        dim_coords_and_dims,
        aux_coords_and_dims,
    )
 def test_hours(self, mock_set):
     cell_method = CellMethod('sum', 'time', '25 hours')
     set_time_increment(cell_method, mock.sentinel.grib)
     mock_set.assert_any_call(mock.sentinel.grib,
                              'indicatorOfUnitForTimeIncrement', 1)
     mock_set.assert_any_call(mock.sentinel.grib, 'timeIncrement', 25)
Example #5
0
def _all_other_rules(f):
    """
    This deals with all the other rules that have not been factored into any of
    the other convert_scalar_coordinate functions above.

    """
    references = []
    standard_name = None
    long_name = None
    units = None
    attributes = {}
    cell_methods = []
    dim_coords_and_dims = []
    aux_coords_and_dims = []

    # Season coordinates (--> scalar coordinates)
    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4]
            and (len(f.lbcode) != 5 or
                 (len(f.lbcode) == 5 and
                  (f.lbcode.ix not in [20, 21, 22, 23]
                   and f.lbcode.iy not in [20, 21, 22, 23]))) and f.lbmon == 12
            and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0 and f.lbmond == 3
            and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('djf',
                                             long_name='season',
                                             units='no_unit'), None))

    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4]
            and ((len(f.lbcode) != 5) or
                 (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23]
                  and f.lbcode.iy not in [20, 21, 22, 23])) and f.lbmon == 3
            and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0 and f.lbmond == 6
            and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('mam',
                                             long_name='season',
                                             units='no_unit'), None))

    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4]
            and ((len(f.lbcode) != 5) or
                 (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23]
                  and f.lbcode.iy not in [20, 21, 22, 23])) and f.lbmon == 6
            and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0 and f.lbmond == 9
            and f.lbdatd == 1 and f.lbhrd == 0 and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('jja',
                                             long_name='season',
                                             units='no_unit'), None))

    if (f.lbtim.ib == 3 and f.lbtim.ic in [1, 2, 4]
            and ((len(f.lbcode) != 5) or
                 (len(f.lbcode) == 5 and f.lbcode.ix not in [20, 21, 22, 23]
                  and f.lbcode.iy not in [20, 21, 22, 23])) and f.lbmon == 9
            and f.lbdat == 1 and f.lbhr == 0 and f.lbmin == 0
            and f.lbmond == 12 and f.lbdatd == 1 and f.lbhrd == 0
            and f.lbmind == 0):
        aux_coords_and_dims.append((AuxCoord('son',
                                             long_name='season',
                                             units='no_unit'), None))

    # "Normal" (i.e. not cross-sectional) lats+lons (--> vector coordinates)
    if (f.bdx != 0.0 and f.bdx != f.bmdi and len(f.lbcode) != 5
            and f.lbcode[0] == 1):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx,
                                   f.bdx,
                                   f.lbnpt,
                                   standard_name=f._x_coord_name(),
                                   units='degrees',
                                   circular=(f.lbhem in [0, 4]),
                                   coord_system=f.coord_system()), 1))

    if (f.bdx != 0.0 and f.bdx != f.bmdi and len(f.lbcode) != 5
            and f.lbcode[0] == 2):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx,
                                   f.bdx,
                                   f.lbnpt,
                                   standard_name=f._x_coord_name(),
                                   units='degrees',
                                   circular=(f.lbhem in [0, 4]),
                                   coord_system=f.coord_system(),
                                   with_bounds=True), 1))

    if (f.bdy != 0.0 and f.bdy != f.bmdi and len(f.lbcode) != 5
            and f.lbcode[0] == 1):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzy,
                                   f.bdy,
                                   f.lbrow,
                                   standard_name=f._y_coord_name(),
                                   units='degrees',
                                   coord_system=f.coord_system()), 0))

    if (f.bdy != 0.0 and f.bdy != f.bmdi and len(f.lbcode) != 5
            and f.lbcode[0] == 2):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzy,
                                   f.bdy,
                                   f.lbrow,
                                   standard_name=f._y_coord_name(),
                                   units='degrees',
                                   coord_system=f.coord_system(),
                                   with_bounds=True), 0))

    if ((f.bdy == 0.0 or f.bdy == f.bmdi) and
        (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.iy == 10))):
        dim_coords_and_dims.append(
            (DimCoord(f.y,
                      standard_name=f._y_coord_name(),
                      units='degrees',
                      bounds=f.y_bounds,
                      coord_system=f.coord_system()), 0))

    if ((f.bdx == 0.0 or f.bdx == f.bmdi) and
        (len(f.lbcode) != 5 or (len(f.lbcode) == 5 and f.lbcode.ix == 11))):
        dim_coords_and_dims.append(
            (DimCoord(f.x,
                      standard_name=f._x_coord_name(),
                      units='degrees',
                      bounds=f.x_bounds,
                      circular=(f.lbhem in [0, 4]),
                      coord_system=f.coord_system()), 1))

    # Cross-sectional vertical level types (--> vector coordinates)
    if (len(f.lbcode) == 5 and f.lbcode.iy == 2
            and (f.bdy == 0 or f.bdy == f.bmdi)):
        dim_coords_and_dims.append((DimCoord(f.y,
                                             standard_name='height',
                                             units='km',
                                             bounds=f.y_bounds,
                                             attributes={'positive':
                                                         'up'}), 0))

    if (len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.iy == 4):
        dim_coords_and_dims.append((DimCoord(f.y,
                                             standard_name='depth',
                                             units='m',
                                             bounds=f.y_bounds,
                                             attributes={'positive':
                                                         'down'}), 0))

    if (len(f.lbcode) == 5 and f.lbcode.ix == 10 and f.bdx != 0
            and f.bdx != f.bmdi):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx,
                                   f.bdx,
                                   f.lbnpt,
                                   standard_name=f._y_coord_name(),
                                   units='degrees',
                                   coord_system=f.coord_system()), 1))

    if (len(f.lbcode) == 5 and f.lbcode.iy == 1
            and (f.bdy == 0 or f.bdy == f.bmdi)):
        dim_coords_and_dims.append((DimCoord(f.y,
                                             long_name='pressure',
                                             units='hPa',
                                             bounds=f.y_bounds), 0))

    if (len(f.lbcode) == 5 and f.lbcode.ix == 1
            and (f.bdx == 0 or f.bdx == f.bmdi)):
        dim_coords_and_dims.append((DimCoord(f.x,
                                             long_name='pressure',
                                             units='hPa',
                                             bounds=f.x_bounds), 1))

    # Cross-sectional time values (--> vector coordinates)
    if (len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.iy == 23):
        dim_coords_and_dims.append(
            (DimCoord(f.y,
                      standard_name='time',
                      units=cf_units.Unit('days since 0000-01-01 00:00:00',
                                          calendar=cf_units.CALENDAR_360_DAY),
                      bounds=f.y_bounds), 0))

    if (len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.ix == 23):
        dim_coords_and_dims.append(
            (DimCoord(f.x,
                      standard_name='time',
                      units=cf_units.Unit('days since 0000-01-01 00:00:00',
                                          calendar=cf_units.CALENDAR_360_DAY),
                      bounds=f.x_bounds), 1))

    # Site number (--> scalar coordinate)
    if (len(f.lbcode) == 5 and f.lbcode[-1] == 1 and f.lbcode.ix == 13
            and f.bdx != 0):
        dim_coords_and_dims.append(
            (DimCoord.from_regular(f.bzx,
                                   f.bdx,
                                   f.lbnpt,
                                   long_name='site_number',
                                   units='1'), 1))

    # Site number cross-sections (???)
    if (len(f.lbcode) == 5 and 13 in [f.lbcode.ix, f.lbcode.iy]
            and 11 not in [f.lbcode.ix, f.lbcode.iy]
            and hasattr(f, 'lower_x_domain') and hasattr(f, 'upper_x_domain')
            and all(f.lower_x_domain != -1.e+30)
            and all(f.upper_x_domain != -1.e+30)):
        aux_coords_and_dims.append((AuxCoord(
            (f.lower_x_domain + f.upper_x_domain) / 2.0,
            standard_name=f._x_coord_name(),
            units='degrees',
            bounds=np.array([f.lower_x_domain, f.upper_x_domain]).T,
            coord_system=f.coord_system()), 1 if f.lbcode.ix == 13 else 0))

    if (len(f.lbcode) == 5 and 13 in [f.lbcode.ix, f.lbcode.iy]
            and 10 not in [f.lbcode.ix, f.lbcode.iy]
            and hasattr(f, 'lower_y_domain') and hasattr(f, 'upper_y_domain')
            and all(f.lower_y_domain != -1.e+30)
            and all(f.upper_y_domain != -1.e+30)):
        aux_coords_and_dims.append((AuxCoord(
            (f.lower_y_domain + f.upper_y_domain) / 2.0,
            standard_name=f._y_coord_name(),
            units='degrees',
            bounds=np.array([f.lower_y_domain, f.upper_y_domain]).T,
            coord_system=f.coord_system()), 1 if f.lbcode.ix == 13 else 0))

    # LBPROC codings (--> cell method + attributes)
    unhandled_lbproc = True
    zone_method = None
    time_method = None
    if f.lbproc == 0:
        unhandled_lbproc = False
    elif f.lbproc == 64:
        zone_method = 'mean'
    elif f.lbproc == 128:
        time_method = 'mean'
    elif f.lbproc == 4096:
        time_method = 'minimum'
    elif f.lbproc == 8192:
        time_method = 'maximum'
    elif f.lbproc == 192:
        time_method = 'mean'
        zone_method = 'mean'

    if time_method is not None:
        if f.lbtim.ia != 0:
            intervals = '{} hour'.format(f.lbtim.ia)
        else:
            intervals = None

        if f.lbtim.ib == 2:
            # Aggregation over a period of time.
            cell_methods.append(
                CellMethod(time_method, coords='time', intervals=intervals))
            unhandled_lbproc = False
        elif f.lbtim.ib == 3 and f.lbproc == 128:
            # Aggregation over a period of time within a year, over a number
            # of years.
            # Only mean (lbproc of 128) is handled as the min/max
            # interpretation is ambiguous e.g. decadal mean of daily max,
            # decadal max of daily mean, decadal mean of max daily mean etc.
            cell_methods.append(
                CellMethod('{} within years'.format(time_method),
                           coords='time',
                           intervals=intervals))
            cell_methods.append(
                CellMethod('{} over years'.format(time_method), coords='time'))
            unhandled_lbproc = False
        else:
            # Generic cell method to indicate a time aggregation.
            cell_methods.append(CellMethod(time_method, coords='time'))
            unhandled_lbproc = False

    if zone_method is not None:
        if f.lbcode == 1:
            cell_methods.append(CellMethod(zone_method, coords='longitude'))
            unhandled_lbproc = False
        elif f.lbcode == 101:
            cell_methods.append(
                CellMethod(zone_method, coords='grid_longitude'))
            unhandled_lbproc = False
        else:
            unhandled_lbproc = True

    if unhandled_lbproc:
        attributes["ukmo__process_flags"] = tuple(
            sorted([
                name for value, name in six.iteritems(
                    iris.fileformats.pp.lbproc_map)
                if isinstance(value, int) and f.lbproc & value
            ]))

    if (f.lbsrce % 10000) == 1111:
        attributes['source'] = 'Data from Met Office Unified Model'
        # Also define MO-netCDF compliant UM version.
        um_major = (f.lbsrce // 10000) // 100
        if um_major != 0:
            um_minor = (f.lbsrce // 10000) % 100
            attributes['um_version'] = '{:d}.{:d}'.format(um_major, um_minor)

    if (f.lbuser[6] != 0 or (f.lbuser[3] // 1000) != 0
            or (f.lbuser[3] % 1000) != 0):
        attributes['STASH'] = f.stash

    if str(f.stash) in STASH_TO_CF:
        standard_name = STASH_TO_CF[str(f.stash)].standard_name
        units = STASH_TO_CF[str(f.stash)].units
        long_name = STASH_TO_CF[str(f.stash)].long_name

    if (not f.stash.is_valid and f.lbfc in LBFC_TO_CF):
        standard_name = LBFC_TO_CF[f.lbfc].standard_name
        units = LBFC_TO_CF[f.lbfc].units
        long_name = LBFC_TO_CF[f.lbfc].long_name

    # Orography reference field (--> reference target)
    if f.lbuser[3] == 33:
        references.append(ReferenceTarget('orography', None))

    # Surface pressure reference field (--> reference target)
    if f.lbuser[3] == 409 or f.lbuser[3] == 1:
        references.append(ReferenceTarget('surface_air_pressure', None))

    return (references, standard_name, long_name, units, attributes,
            cell_methods, dim_coords_and_dims, aux_coords_and_dims)
Example #6
0
 def expected_cell_method(self,
                          coords=('time',), method='mean', intervals=None):
     keys = dict(coords=coords, method=method, intervals=intervals)
     cell_method = CellMethod(**keys)
     return cell_method
 def test_area(self, mock_set):
     cell_method = CellMethod('sum', 'area', '25 km')
     set_time_increment(cell_method, mock.sentinel.grib)
     mock_set.assert_any_call(mock.sentinel.grib,
                              'indicatorOfUnitForTimeIncrement', 255)
     mock_set.assert_any_call(mock.sentinel.grib, 'timeIncrement', 0)
Example #8
0
 def setUp(self):
     self.cube = stock.realistic_4d()
     cm = CellMethod('mean', 'time', '6hr')
     self.cube.add_cell_method(cm)
     self.representer = CubeRepresentation(self.cube)
     self.representer._get_bits(self.representer._get_lines())
Example #9
0
 def setUp(self):
     self.cube = stock.lat_lon_cube()
     # Rename cube to avoid warning about unknown discipline/parameter.
     self.cube.rename('air_temperature')
     cell_method = CellMethod(method='sum', coords=['time'])
     self.cube.add_cell_method(cell_method)
Example #10
0
def test_error_wrong_accum_cell_method(precip_accum_cube, interpreter):
    """Test error when precipitation accumulation cube has the wrong cell method"""
    precip_accum_cube.cell_methods = []
    precip_accum_cube.add_cell_method(CellMethod(method="mean", coords="time"))
    with pytest.raises(ValueError, match="Expected sum over time"):
        interpreter.run(precip_accum_cube)
Example #11
0
def test_error_forbidden_weather_code_cell_method(wxcode_cube, interpreter):
    """Test error if special case cubes have a cell method that would usually be
    permitted"""
    wxcode_cube.add_cell_method(CellMethod(method="maximum", coords="time"))
    with pytest.raises(ValueError, match="Unexpected cell methods"):
        interpreter.run(wxcode_cube)
Example #12
0
def test_error_ancillary_cell_method(landmask_cube, interpreter):
    """Test error raised when there's a cell method on a static ancillary"""
    landmask_cube.add_cell_method(CellMethod(method="maximum", coords="time"))
    with pytest.raises(ValueError, match="Unexpected cell methods"):
        interpreter.run(landmask_cube)
Example #13
0
 def test_mixture_default(self):
     token = 'air temperature'  # includes space
     coord = Coord(1, long_name=token)
     result = CellMethod(self.method, coords=[coord, token])
     expected = '{}: unknown, unknown'.format(self.method, token, token)
     self.assertEqual(str(result), expected)
Example #14
0
 def test_mixture(self):
     token = 'air_temperature'
     coord = Coord(1, standard_name=token)
     result = CellMethod(self.method, coords=[coord, token])
     expected = '{}: {}, {}'.format(self.method, token, token)
     self.assertEqual(str(result), expected)
Example #15
0
 def test_maximum(self):
     self.cube.cell_methods = (CellMethod('maximum', 'time', '1 hour'),)
     lbproc = _lbproc_rules(self.cube, self.pp_field).lbproc
     self.assertEqual(lbproc, 8192)
Example #16
0
 def test_climatology_max(self):
     field = mock.MagicMock(lbproc=8192, lbtim=mock.Mock(ia=24, ib=3, ic=3))
     res = _all_other_rules(field)[CELL_METHODS_INDEX]
     expected = [CellMethod('maximum', 'time')]
     self.assertEqual(res, expected)
Example #17
0
def convert(grib):
    """
    Converts a GRIB message into the corresponding items of Cube metadata.

    Args:

    * grib:
        A :class:`~iris.fileformats.grib.GribWrapper` object.

    Returns:
        A :class:`iris.fileformats.rules.ConversionMetadata` object.

    """
    factories = []
    references = []
    standard_name = None
    long_name = None
    units = None
    attributes = {}
    cell_methods = []
    dim_coords_and_dims = []
    aux_coords_and_dims = []

    # deprecation warning for this code path for edition 2 messages
    if grib.edition == 2:
        msg = ('This GRIB loader is deprecated and will be removed in '
               'a future release.  Please consider using the new '
               'GRIB loader by setting the :class:`iris.Future` '
               'option `strict_grib_load` to True; e.g.:\n'
               'iris.FUTURE.strict_grib_load = True\n'
               'Please report issues you experience to:\n'
               'https://groups.google.com/forum/#!topic/scitools-iris-dev/'
               'lMsOusKNfaU')
        warnings.warn(msg)

    if \
            (grib.gridType=="reduced_gg"):
        aux_coords_and_dims.append(
            (AuxCoord(grib._y_points,
                      grib._y_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 0))
        aux_coords_and_dims.append(
            (AuxCoord(grib._x_points,
                      grib._x_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 0))

    if \
            (grib.gridType=="regular_ll") and \
            (grib.jPointsAreConsecutive == 0):
        dim_coords_and_dims.append(
            (DimCoord(grib._y_points,
                      grib._y_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 0))
        dim_coords_and_dims.append((DimCoord(grib._x_points,
                                             grib._x_coord_name,
                                             units='degrees',
                                             coord_system=grib._coord_system,
                                             circular=grib._x_circular), 1))

    if \
            (grib.gridType=="regular_ll") and \
            (grib.jPointsAreConsecutive == 1):
        dim_coords_and_dims.append(
            (DimCoord(grib._y_points,
                      grib._y_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 1))
        dim_coords_and_dims.append((DimCoord(grib._x_points,
                                             grib._x_coord_name,
                                             units='degrees',
                                             coord_system=grib._coord_system,
                                             circular=grib._x_circular), 0))

    if \
            (grib.gridType=="regular_gg") and \
            (grib.jPointsAreConsecutive == 0):
        dim_coords_and_dims.append(
            (DimCoord(grib._y_points,
                      grib._y_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 0))
        dim_coords_and_dims.append((DimCoord(grib._x_points,
                                             grib._x_coord_name,
                                             units='degrees',
                                             coord_system=grib._coord_system,
                                             circular=grib._x_circular), 1))

    if \
            (grib.gridType=="regular_gg") and \
            (grib.jPointsAreConsecutive == 1):
        dim_coords_and_dims.append(
            (DimCoord(grib._y_points,
                      grib._y_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 1))
        dim_coords_and_dims.append((DimCoord(grib._x_points,
                                             grib._x_coord_name,
                                             units='degrees',
                                             coord_system=grib._coord_system,
                                             circular=grib._x_circular), 0))

    if \
            (grib.gridType=="rotated_ll") and \
            (grib.jPointsAreConsecutive == 0):
        dim_coords_and_dims.append(
            (DimCoord(grib._y_points,
                      grib._y_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 0))
        dim_coords_and_dims.append((DimCoord(grib._x_points,
                                             grib._x_coord_name,
                                             units='degrees',
                                             coord_system=grib._coord_system,
                                             circular=grib._x_circular), 1))

    if \
            (grib.gridType=="rotated_ll") and \
            (grib.jPointsAreConsecutive == 1):
        dim_coords_and_dims.append(
            (DimCoord(grib._y_points,
                      grib._y_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 1))
        dim_coords_and_dims.append((DimCoord(grib._x_points,
                                             grib._x_coord_name,
                                             units='degrees',
                                             coord_system=grib._coord_system,
                                             circular=grib._x_circular), 0))

    if grib.gridType in ["polar_stereographic", "lambert"]:
        dim_coords_and_dims.append(
            (DimCoord(grib._y_points,
                      grib._y_coord_name,
                      units="m",
                      coord_system=grib._coord_system), 0))
        dim_coords_and_dims.append(
            (DimCoord(grib._x_points,
                      grib._x_coord_name,
                      units="m",
                      coord_system=grib._coord_system), 1))

    if \
            (grib.edition == 1) and \
            (grib.table2Version < 128) and \
            (grib.indicatorOfParameter == 11) and \
            (grib._cf_data is None):
        standard_name = "air_temperature"
        units = "kelvin"

    if \
            (grib.edition == 1) and \
            (grib.table2Version < 128) and \
            (grib.indicatorOfParameter == 33) and \
            (grib._cf_data is None):
        standard_name = "x_wind"
        units = "m s-1"

    if \
            (grib.edition == 1) and \
            (grib.table2Version < 128) and \
            (grib.indicatorOfParameter == 34) and \
            (grib._cf_data is None):
        standard_name = "y_wind"
        units = "m s-1"

    if \
            (grib.edition == 1) and \
            (grib._cf_data is not None):
        standard_name = grib._cf_data.standard_name
        long_name = grib._cf_data.standard_name or grib._cf_data.long_name
        units = grib._cf_data.units

    if \
            (grib.edition == 1) and \
            (grib.table2Version >= 128) and \
            (grib._cf_data is None):
        long_name = "UNKNOWN LOCAL PARAM " + str(
            grib.indicatorOfParameter) + "." + str(grib.table2Version)
        units = "???"

    if \
            (grib.edition == 1) and \
            (grib.table2Version == 1) and \
            (grib.indicatorOfParameter >= 128):
        long_name = "UNKNOWN LOCAL PARAM " + str(
            grib.indicatorOfParameter) + "." + str(grib.table2Version)
        units = "???"

    if \
            (grib.edition == 2) and \
            (grib._cf_data is not None):
        standard_name = grib._cf_data.standard_name
        long_name = grib._cf_data.long_name
        units = grib._cf_data.units

    if \
            (grib.edition == 1) and \
            (grib._phenomenonDateTime != -1.0):
        aux_coords_and_dims.append(
            (DimCoord(points=grib.startStep,
                      standard_name='forecast_period',
                      units=grib._forecastTimeUnit), None))
        aux_coords_and_dims.append(
            (DimCoord(points=grib.phenomenon_points('hours'),
                      standard_name='time',
                      units=Unit('hours since epoch',
                                 CALENDAR_GREGORIAN)), None))

    def add_bounded_time_coords(aux_coords_and_dims, grib):
        t_bounds = grib.phenomenon_bounds('hours')
        period = Unit('hours').convert(t_bounds[1] - t_bounds[0],
                                       grib._forecastTimeUnit)
        aux_coords_and_dims.append(
            (DimCoord(standard_name='forecast_period',
                      units=grib._forecastTimeUnit,
                      points=grib._forecastTime + 0.5 * period,
                      bounds=[grib._forecastTime,
                              grib._forecastTime + period]), None))
        aux_coords_and_dims.append(
            (DimCoord(standard_name='time',
                      units=Unit('hours since epoch', CALENDAR_GREGORIAN),
                      points=0.5 * (t_bounds[0] + t_bounds[1]),
                      bounds=t_bounds), None))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 2):
        add_bounded_time_coords(aux_coords_and_dims, grib)

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 3):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 4):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("sum", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 5):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("_difference", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 51):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 113):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 114):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("sum", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 115):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 116):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("sum", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 117):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 118):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("_covariance", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 123):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 124):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("sum", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 125):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("standard_deviation", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 0):
        aux_coords_and_dims.append(
            (DimCoord(points=Unit(grib._forecastTimeUnit).convert(
                np.int32(grib._forecastTime), "hours"),
                      standard_name='forecast_period',
                      units="hours"), None))
        aux_coords_and_dims.append(
            (DimCoord(points=grib.phenomenon_points('hours'),
                      standard_name='time',
                      units=Unit('hours since epoch',
                                 CALENDAR_GREGORIAN)), None))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber in (8, 9)):
        add_bounded_time_coords(aux_coords_and_dims, grib)

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 0):
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 1):
        cell_methods.append(CellMethod("sum", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 2):
        cell_methods.append(CellMethod("maximum", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 3):
        cell_methods.append(CellMethod("minimum", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 4):
        cell_methods.append(CellMethod("_difference", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 5):
        cell_methods.append(CellMethod("_root_mean_square", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 6):
        cell_methods.append(CellMethod("standard_deviation", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 7):
        cell_methods.append(CellMethod("_convariance", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 8):
        cell_methods.append(CellMethod("_difference", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 9):
        cell_methods.append(CellMethod("_ratio", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.levelType == 'pl'):
        aux_coords_and_dims.append((DimCoord(points=grib.level,
                                             long_name="pressure",
                                             units="hPa"), None))

    if \
            (grib.edition == 1) and \
            (grib.levelType == 'sfc'):

        if (grib._cf_data is not None) and \
        (grib._cf_data.set_height is not None):
            aux_coords_and_dims.append(
                (DimCoord(points=grib._cf_data.set_height,
                          long_name="height",
                          units="m",
                          attributes={'positive': 'up'}), None))
        elif grib.typeOfLevel == 'heightAboveGround':  # required for NCAR
            aux_coords_and_dims.append((DimCoord(points=grib.level,
                                                 long_name="height",
                                                 units="m",
                                                 attributes={'positive':
                                                             'up'}), None))

    if \
            (grib.edition == 1) and \
            (grib.levelType == 'ml') and \
            (hasattr(grib, 'pv')):
        aux_coords_and_dims.append(
            (AuxCoord(grib.level,
                      standard_name='model_level_number',
                      attributes={'positive': 'up'}), None))
        aux_coords_and_dims.append((DimCoord(grib.pv[grib.level],
                                             long_name='level_pressure',
                                             units='Pa'), None))
        aux_coords_and_dims.append((AuxCoord(
            grib.pv[grib.numberOfCoordinatesValues // 2 + grib.level],
            long_name='sigma'), None))
        factories.append(
            Factory(HybridPressureFactory, [{
                'long_name': 'level_pressure'
            }, {
                'long_name': 'sigma'
            },
                                            Reference('surface_pressure')]))

    if \
            (grib.edition == 2) and \
            (grib.typeOfFirstFixedSurface != grib.typeOfSecondFixedSurface):
        warnings.warn("Different vertical bound types not yet handled.")

    if \
            (grib.edition == 2) and \
            (grib.typeOfFirstFixedSurface == 103) and \
            (grib.typeOfSecondFixedSurface == 255):
        aux_coords_and_dims.append(
            (DimCoord(points=grib.scaledValueOfFirstFixedSurface /
                      (10.0**grib.scaleFactorOfFirstFixedSurface),
                      standard_name="height",
                      units="m"), None))

    if \
            (grib.edition == 2) and \
            (grib.typeOfFirstFixedSurface == 103) and \
            (grib.typeOfSecondFixedSurface != 255):
        aux_coords_and_dims.append((DimCoord(
            points=0.5 * (grib.scaledValueOfFirstFixedSurface /
                          (10.0**grib.scaleFactorOfFirstFixedSurface) +
                          grib.scaledValueOfSecondFixedSurface /
                          (10.0**grib.scaleFactorOfSecondFixedSurface)),
            standard_name="height",
            units="m",
            bounds=[
                grib.scaledValueOfFirstFixedSurface /
                (10.0**grib.scaleFactorOfFirstFixedSurface),
                grib.scaledValueOfSecondFixedSurface /
                (10.0**grib.scaleFactorOfSecondFixedSurface)
            ]), None))

    if \
            (grib.edition == 2) and \
            (grib.typeOfFirstFixedSurface == 100) and \
            (grib.typeOfSecondFixedSurface == 255):
        aux_coords_and_dims.append(
            (DimCoord(points=grib.scaledValueOfFirstFixedSurface /
                      (10.0**grib.scaleFactorOfFirstFixedSurface),
                      long_name="pressure",
                      units="Pa"), None))

    if \
            (grib.edition == 2) and \
            (grib.typeOfFirstFixedSurface == 100) and \
            (grib.typeOfSecondFixedSurface != 255):
        aux_coords_and_dims.append((DimCoord(
            points=0.5 * (grib.scaledValueOfFirstFixedSurface /
                          (10.0**grib.scaleFactorOfFirstFixedSurface) +
                          grib.scaledValueOfSecondFixedSurface /
                          (10.0**grib.scaleFactorOfSecondFixedSurface)),
            long_name="pressure",
            units="Pa",
            bounds=[
                grib.scaledValueOfFirstFixedSurface /
                (10.0**grib.scaleFactorOfFirstFixedSurface),
                grib.scaledValueOfSecondFixedSurface /
                (10.0**grib.scaleFactorOfSecondFixedSurface)
            ]), None))

    if \
            (grib.edition == 2) and \
            (grib.typeOfFirstFixedSurface in [105, 119]) and \
            (grib.numberOfCoordinatesValues > 0):
        aux_coords_and_dims.append(
            (AuxCoord(grib.scaledValueOfFirstFixedSurface,
                      standard_name='model_level_number',
                      attributes={'positive': 'up'}), None))
        aux_coords_and_dims.append(
            (DimCoord(grib.pv[grib.scaledValueOfFirstFixedSurface],
                      long_name='level_pressure',
                      units='Pa'), None))
        aux_coords_and_dims.append(
            (AuxCoord(grib.pv[grib.numberOfCoordinatesValues // 2 +
                              grib.scaledValueOfFirstFixedSurface],
                      long_name='sigma'), None))
        factories.append(
            Factory(HybridPressureFactory,
                    [{
                        'long_name': 'level_pressure'
                    }, {
                        'long_name': 'sigma'
                    },
                     Reference('surface_air_pressure')]))

    if grib._originatingCentre != 'unknown':
        aux_coords_and_dims.append((AuxCoord(points=grib._originatingCentre,
                                             long_name='originating_centre',
                                             units='no_unit'), None))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 1):
        aux_coords_and_dims.append((DimCoord(points=grib.perturbationNumber,
                                             long_name='ensemble_member',
                                             units='no_unit'), None))

    if \
            (grib.edition == 2) and \
            grib.productDefinitionTemplateNumber not in (0, 8):
        attributes["GRIB_LOAD_WARNING"] = (
            "unsupported GRIB%d ProductDefinitionTemplate: #4.%d" %
            (grib.edition, grib.productDefinitionTemplateNumber))

    if \
            (grib.edition == 2) and \
            (grib.centre == 'ecmf') and \
            (grib.discipline == 0) and \
            (grib.parameterCategory == 3) and \
            (grib.parameterNumber == 25) and \
            (grib.typeOfFirstFixedSurface == 105):
        references.append(
            ReferenceTarget(
                'surface_air_pressure', lambda cube: {
                    'standard_name': 'surface_air_pressure',
                    'units': 'Pa',
                    'data': np.exp(cube.data)
                }))

    return ConversionMetadata(factories, references, standard_name, long_name,
                              units, attributes, cell_methods,
                              dim_coords_and_dims, aux_coords_and_dims)
Example #18
0
 def test_daily_mean(self):
     # lbtim.ia = 24 -> daily
     field = mock.MagicMock(lbproc=128, lbtim=mock.Mock(ia=24, ib=2, ic=3))
     res = _all_other_rules(field)[CELL_METHODS_INDEX]
     expected = [CellMethod('mean', 'time', '24 hour')]
     self.assertEqual(res, expected)
Example #19
0
 def setUp(self):
     self.cube = stock.simple_3d()
     cm = CellMethod("mean", "time", "6hr")
     self.cube.add_cell_method(cm)
     self.representer = CubeRepresentation(self.cube)
     self.representer._get_bits(self.representer._get_lines())
Example #20
0
 def test_other_lbtim_ib(self):
     # lbtim.ib = 5 -> non-specific aggregation
     field = mock.MagicMock(lbproc=4096, lbtim=mock.Mock(ia=24, ib=5, ic=3))
     res = _all_other_rules(field)[CELL_METHODS_INDEX]
     expected = [CellMethod("minimum", "time")]
     self.assertEqual(res, expected)
 def test_multiple_intervals(self, mock_set):
     cell_method = CellMethod('sum', 'time', ('1 hour', '24 hour'))
     set_time_increment(cell_method, mock.sentinel.grib)
     mock_set.assert_any_call(mock.sentinel.grib,
                              'indicatorOfUnitForTimeIncrement', 255)
     mock_set.assert_any_call(mock.sentinel.grib, 'timeIncrement', 0)
Example #22
0
 def test_hourly_mean(self):
     # lbtim.ia = 1 -> hourly
     field = mock.MagicMock(lbproc=128, lbtim=mock.Mock(ia=1, ib=2, ic=3))
     res = _all_other_rules(field)[CELL_METHODS_INDEX]
     expected = [CellMethod("mean", "time", "1 hour")]
     self.assertEqual(res, expected)
Example #23
0
    def fields(self,
               c_t=None,
               cft=None,
               ctp=None,
               c_h=None,
               c_p=None,
               phn=0,
               mmm=None,
               pse=None):
        # Return a list of 2d cubes representing raw PPFields, from args
        # specifying sequences of (scalar) coordinate values.
        # TODO? : add bounds somehow ?
        #
        # Arguments 'c<xx>' are either a single int value, making a scalar
        # coord, or a string of characters : '0'-'9' (index) or '-' (missing).
        # The indexes select point values from fixed list of possibles.
        #
        # Argument 'c_h' and 'c_p' represent height or pressure values, so
        # ought to be mutually exclusive -- these control LBVC.
        #
        # Argument 'phn' indexes phenomenon types.
        #
        # Argument 'mmm' denotes existence (or not) of a cell method of type
        # 'average' or 'min' or 'max' (values '012' respectively), applying to
        # the time values -- ultimately, this controls LBTIM.
        #
        # Argument 'pse' denotes pseudo-level numbers.
        # These translate into 'LBUSER5' values.

        # Get the number of result cubes, defined by the 'longest' arg.
        def arglen(arg):
            # Get the 'length' of a control argument.
            if arg is None:
                result = 0
            elif isinstance(arg, six.string_types):
                result = len(arg)
            else:
                result = 1
            return result

        n_flds = max(arglen(x) for x in (c_t, cft, ctp, c_h, c_p, mmm))

        # Make basic anonymous test cubes.
        ny, nx = 3, 5
        data = np.arange(n_flds * ny * nx, dtype=np.float32)
        data = data.reshape((n_flds, ny, nx))
        cubes = [Cube(data[i]) for i in range(n_flds)]

        # Define test point values for making coordinates.
        time_unit = 'hours since 1970-01-01'
        period_unit = 'hours'
        height_unit = 'm'
        pressure_unit = 'hPa'
        time_values = 24.0 * np.arange(10)
        height_values = 100.0 * np.arange(1, 11)
        pressure_values = [
            100.0, 150.0, 200.0, 250.0, 300.0, 500.0, 850.0, 1000.0
        ]
        pseudolevel_values = range(1, 11)  # A valid value is >= 1.

        # Test phenomenon details.
        # NOTE: in order to write/readback as identical, these also contain a
        # canonical unit and matching STASH attribute.
        # Those could in principle be looked up, but it's a bit awkward.
        phenomenon_values = [
            ('air_temperature', 'K', 'm01s01i004'),
            ('x_wind', 'm s-1', 'm01s00i002'),
            ('y_wind', 'm s-1', 'm01s00i003'),
            ('specific_humidity', 'kg kg-1', 'm01s00i010'),
        ]

        # Test cell-methods.
        # NOTE: if you add an *interval* to any of these cell-methods, it is
        # not saved into the PP file (?? or maybe not loaded back again ??).
        # This could be a PP save/load bug, or maybe just because no bounds ?
        cell_method_values = [
            CellMethod('mean', 'time'),
            CellMethod('maximum', 'time'),
            CellMethod('minimum', 'time'),
        ]

        # Define helper to decode an argument as a list of test values.
        def arg_vals(arg, vals):
            # Decode an argument to a list of 'n_flds' coordinate point values.
            # (or 'None' where missing)

            # First get a list of value indices from the argument.
            # Can be: a single index value; a list of indices; or a string.
            if (isinstance(arg, Iterable)
                    and not isinstance(arg, six.string_types)):
                # Can also just pass a simple iterable of values.
                inds = [int(val) for val in arg]
            else:
                n_vals = arglen(arg)
                if n_vals == 0:
                    inds = [None] * n_flds
                elif n_vals == 1:
                    inds = [int(arg)] * n_flds
                else:
                    assert isinstance(arg, six.string_types)
                    inds = [None if char == '-' else int(char) for char in arg]

            # Convert indices to selected point values.
            values = [None if ind is None else vals[int(ind)] for ind in inds]

            return values

        # Apply phenomenon_values definitions.
        phenomena = arg_vals(phn, phenomenon_values)
        for cube, (name, units, stash) in zip(cubes, phenomena):
            cube.rename(name)
            # NOTE: in order to get a cube that will write+readback the same,
            # the units must be the canonical one.
            cube.units = units
            # NOTE: in order to get a cube that will write+readback the same,
            # we must include a STASH attribute.
            cube.attributes['STASH'] = STASH.from_msi(stash)

        # Add x and y coords.
        cs = GeogCS(EARTH_RADIUS)
        xvals = np.linspace(0.0, 180.0, nx)
        co_x = DimCoord(np.array(xvals, dtype=np.float32),
                        standard_name='longitude',
                        units='degrees',
                        coord_system=cs)
        yvals = np.linspace(-45.0, 45.0, ny)
        co_y = DimCoord(np.array(yvals, dtype=np.float32),
                        standard_name='latitude',
                        units='degrees',
                        coord_system=cs)
        for cube in cubes:
            cube.add_dim_coord(co_y, 0)
            cube.add_dim_coord(co_x, 1)

        # Add multiple scalar coordinates as defined by the arguments.
        def arg_coords(arg, name, unit, vals=None):
            # Decode an argument to a list of scalar coordinates.
            if vals is None:
                vals = np.arange(n_flds + 2)  # Note allowance
            vals = arg_vals(arg, vals)
            coords = [
                None if val is None else DimCoord([val], units=unit)
                for val in vals
            ]
            # Apply names separately, as 'pressure' is not a standard name.
            for coord in coords:
                if coord:
                    coord.rename(name)
                    # Also fix heights to match what comes from a PP file.
                    if name == 'height':
                        coord.attributes['positive'] = 'up'
            return coords

        def add_arg_coords(arg, name, unit, vals=None):
            # Add scalar coordinates to each cube, for one argument.
            coords = arg_coords(arg, name, unit, vals)
            for cube, coord in zip(cubes, coords):
                if coord:
                    cube.add_aux_coord(coord)

        add_arg_coords(c_t, 'time', time_unit, time_values)
        add_arg_coords(cft, 'forecast_reference_time', time_unit)
        add_arg_coords(ctp, 'forecast_period', period_unit, time_values)
        add_arg_coords(c_h, 'height', height_unit, height_values)
        add_arg_coords(c_p, 'pressure', pressure_unit, pressure_values)
        add_arg_coords(pse, 'pseudo_level', '1', pseudolevel_values)

        # Add cell methods as required.
        methods = arg_vals(mmm, cell_method_values)
        for cube, method in zip(cubes, methods):
            if method:
                cube.add_cell_method(method)

        return cubes
Example #24
0
 def test_custom_max(self):
     field = mock.MagicMock(lbproc=8192, lbtim=mock.Mock(ia=47, ib=2, ic=3))
     res = _all_other_rules(field)[CELL_METHODS_INDEX]
     expected = [CellMethod("maximum", "time", "47 hour")]
     self.assertEqual(res, expected)
Example #25
0
def convert(grib):
    factories = []
    references = []
    standard_name = None
    long_name = None
    units = None
    attributes = {}
    cell_methods = []
    dim_coords_and_dims = []
    aux_coords_and_dims = []

    if \
            (grib.gridType=="reduced_gg"):
        aux_coords_and_dims.append((AuxCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0))
        aux_coords_and_dims.append((AuxCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system), 0))

    if \
            (grib.gridType=="regular_ll") and \
            (grib.jPointsAreConsecutive == 0):
        dim_coords_and_dims.append((DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0))
        dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 1))

    if \
            (grib.gridType=="regular_ll") and \
            (grib.jPointsAreConsecutive == 1):
        dim_coords_and_dims.append((DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1))
        dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 0))

    if \
            (grib.gridType=="regular_gg") and \
            (grib.jPointsAreConsecutive == 0):
        dim_coords_and_dims.append((DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0))
        dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 1))

    if \
            (grib.gridType=="regular_gg") and \
            (grib.jPointsAreConsecutive == 1):
        dim_coords_and_dims.append((DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1))
        dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 0))

    if \
            (grib.gridType=="rotated_ll") and \
            (grib.jPointsAreConsecutive == 0):
        dim_coords_and_dims.append((DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 0))
        dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 1))

    if \
            (grib.gridType=="rotated_ll") and \
            (grib.jPointsAreConsecutive == 1):
        dim_coords_and_dims.append((DimCoord(grib._y_points, grib._y_coord_name, units='degrees', coord_system=grib._coord_system), 1))
        dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units='degrees', coord_system=grib._coord_system, circular=grib._x_circular), 0))

    if grib.gridType in ["polar_stereographic", "lambert"]:
        dim_coords_and_dims.append((DimCoord(grib._y_points, grib._y_coord_name, units="m", coord_system=grib._coord_system), 0))
        dim_coords_and_dims.append((DimCoord(grib._x_points, grib._x_coord_name, units="m", coord_system=grib._coord_system), 1))

    if \
            (grib.edition == 1) and \
            (grib.table2Version < 128) and \
            (grib.indicatorOfParameter == 11) and \
            (grib._cf_data is None):
        standard_name = "air_temperature"
        units = "kelvin"

    if \
            (grib.edition == 1) and \
            (grib.table2Version < 128) and \
            (grib.indicatorOfParameter == 33) and \
            (grib._cf_data is None):
        standard_name = "x_wind"
        units = "m s-1"

    if \
            (grib.edition == 1) and \
            (grib.table2Version < 128) and \
            (grib.indicatorOfParameter == 34) and \
            (grib._cf_data is None):
        standard_name = "y_wind"
        units = "m s-1"

    if \
            (grib.edition == 1) and \
            (grib._cf_data is not None):
        standard_name = grib._cf_data.standard_name
        long_name = grib._cf_data.standard_name or grib._cf_data.long_name
        units = grib._cf_data.units

    if \
            (grib.edition == 1) and \
            (grib.table2Version >= 128) and \
            (grib._cf_data is None):
        long_name = "UNKNOWN LOCAL PARAM " + str(grib.indicatorOfParameter) + "." + str(grib.table2Version)
        units = "???"

    if \
            (grib.edition == 1) and \
            (grib.table2Version == 1) and \
            (grib.indicatorOfParameter >= 128):
        long_name = "UNKNOWN LOCAL PARAM " + str(grib.indicatorOfParameter) + "." + str(grib.table2Version)
        units = "???"

    if \
            (grib.edition == 2) and \
            (grib._cf_data is not None):
        standard_name = grib._cf_data.standard_name
        long_name = grib._cf_data.long_name
        units = grib._cf_data.units

    if \
            (grib.edition == 1) and \
            (grib._phenomenonDateTime != -1.0):
        aux_coords_and_dims.append((DimCoord(points=grib.startStep, standard_name='forecast_period', units=grib._forecastTimeUnit), None))
        aux_coords_and_dims.append((DimCoord(points=grib.phenomenon_points('hours'), standard_name='time', units=Unit('hours since epoch', iris.unit.CALENDAR_GREGORIAN)), None))

    def add_bounded_time_coords(aux_coords_and_dims, grib):
        t_bounds = grib.phenomenon_bounds('hours')
        period = Unit('hours').convert(t_bounds[1] - t_bounds[0],
                                       grib._forecastTimeUnit)
        aux_coords_and_dims.append((
            DimCoord(standard_name='forecast_period',
                     units=grib._forecastTimeUnit,
                     points=grib._forecastTime + 0.5 * period,
                     bounds=[grib._forecastTime, grib._forecastTime + period]),
            None))
        aux_coords_and_dims.append((
            DimCoord(standard_name='time',
                     units=Unit('hours since epoch',
                                iris.unit.CALENDAR_GREGORIAN),
                     points=0.5 * (t_bounds[0] + t_bounds[1]),
                     bounds=t_bounds),
            None))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 3):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 4):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("sum", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 5):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("_difference", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 51):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 113):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 114):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("sum", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 115):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 116):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("sum", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 117):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 118):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("_covariance", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 123):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 124):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("sum", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.timeRangeIndicator == 125):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("standard_deviation", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 0):
        aux_coords_and_dims.append((DimCoord(points=Unit(grib._forecastTimeUnit).convert(np.int32(grib._forecastTime), "hours"), standard_name='forecast_period', units="hours"), None))
        aux_coords_and_dims.append((DimCoord(points=grib.phenomenon_points('hours'), standard_name='time', units=Unit('hours since epoch', iris.unit.CALENDAR_GREGORIAN)), None))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber in (8, 9)):
        add_bounded_time_coords(aux_coords_and_dims, grib)

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 0):
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 1):
        cell_methods.append(CellMethod("sum", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 2):
        cell_methods.append(CellMethod("maximum", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 3):
        cell_methods.append(CellMethod("minimum", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 4):
        cell_methods.append(CellMethod("_difference", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 5):
        cell_methods.append(CellMethod("_root_mean_square", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 6):
        cell_methods.append(CellMethod("standard_deviation", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 7):
        cell_methods.append(CellMethod("_convariance", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 8):
        cell_methods.append(CellMethod("_difference", coords="time"))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 8) and \
            (grib.typeOfStatisticalProcessing == 9):
        cell_methods.append(CellMethod("_ratio", coords="time"))

    if \
            (grib.edition == 1) and \
            (grib.levelType == 'pl'):
        aux_coords_and_dims.append((DimCoord(points=grib.level,  long_name="pressure", units="hPa"), None))

    if \
            (grib.edition == 1) and \
            (grib.levelType == 'sfc') and \
            (grib._cf_data is not None) and \
            (grib._cf_data.set_height is not None):
        aux_coords_and_dims.append((DimCoord(points=grib._cf_data.set_height,  long_name="height", units="m", attributes={'positive':'up'}), None))

    if \
            (grib.edition == 1) and \
            (grib.levelType == 'ml') and \
            (hasattr(grib, 'pv')):
        aux_coords_and_dims.append((AuxCoord(grib.level, standard_name='model_level_number', attributes={'positive': 'up'}), None))
        aux_coords_and_dims.append((DimCoord(grib.pv[grib.level], long_name='level_pressure', units='Pa'), None))
        aux_coords_and_dims.append((AuxCoord(grib.pv[grib.numberOfCoordinatesValues/2 + grib.level], long_name='sigma'), None))
        factories.append(Factory(HybridPressureFactory, [{'long_name': 'level_pressure'}, {'long_name': 'sigma'}, Reference('surface_pressure')]))

    if \
            (grib.edition == 2) and \
            (grib.typeOfFirstFixedSurface != grib.typeOfSecondFixedSurface):
        warnings.warn("Different vertical bound types not yet handled.")

    if \
            (grib.edition == 2) and \
            (grib.typeOfFirstFixedSurface == 103) and \
            (grib.typeOfSecondFixedSurface == 255):
        aux_coords_and_dims.append((DimCoord(points=grib.scaledValueOfFirstFixedSurface/(10.0**grib.scaleFactorOfFirstFixedSurface), standard_name="height", units="m"), None))

    if \
            (grib.edition == 2) and \
            (grib.typeOfFirstFixedSurface == 103) and \
            (grib.typeOfSecondFixedSurface != 255):
        aux_coords_and_dims.append((DimCoord(points=0.5*(grib.scaledValueOfFirstFixedSurface/(10.0**grib.scaleFactorOfFirstFixedSurface) + grib.scaledValueOfSecondFixedSurface/(10.0**grib.scaleFactorOfSecondFixedSurface)), standard_name="height", units="m", bounds=[grib.scaledValueOfFirstFixedSurface/(10.0**grib.scaleFactorOfFirstFixedSurface) , grib.scaledValueOfSecondFixedSurface/(10.0**grib.scaleFactorOfSecondFixedSurface)]), None))

    if \
            (grib.edition == 2) and \
            (grib.typeOfFirstFixedSurface == 100) and \
            (grib.typeOfSecondFixedSurface == 255):
        aux_coords_and_dims.append((DimCoord(points=grib.scaledValueOfFirstFixedSurface/(10.0**grib.scaleFactorOfFirstFixedSurface), long_name="pressure", units="Pa"), None))

    if \
            (grib.edition == 2) and \
            (grib.typeOfFirstFixedSurface == 100) and \
            (grib.typeOfSecondFixedSurface != 255):
        aux_coords_and_dims.append((DimCoord(points=0.5*(grib.scaledValueOfFirstFixedSurface/(10.0**grib.scaleFactorOfFirstFixedSurface) + grib.scaledValueOfSecondFixedSurface/(10.0**grib.scaleFactorOfSecondFixedSurface)), long_name="pressure", units="Pa", bounds=[grib.scaledValueOfFirstFixedSurface/(10.0**grib.scaleFactorOfFirstFixedSurface) , grib.scaledValueOfSecondFixedSurface/(10.0**grib.scaleFactorOfSecondFixedSurface)]), None))

    if \
            (grib.edition == 2) and \
            (grib.typeOfFirstFixedSurface in [105, 119]) and \
            (grib.numberOfCoordinatesValues > 0):
        aux_coords_and_dims.append((AuxCoord(grib.scaledValueOfFirstFixedSurface, standard_name='model_level_number', attributes={'positive': 'up'}), None))
        aux_coords_and_dims.append((DimCoord(grib.pv[grib.scaledValueOfFirstFixedSurface], long_name='level_pressure', units='Pa'), None))
        aux_coords_and_dims.append((AuxCoord(grib.pv[grib.numberOfCoordinatesValues/2 + grib.scaledValueOfFirstFixedSurface], long_name='sigma'), None))
        factories.append(Factory(HybridPressureFactory, [{'long_name': 'level_pressure'}, {'long_name': 'sigma'}, Reference('surface_air_pressure')]))

    if grib._originatingCentre != 'unknown':
        aux_coords_and_dims.append((AuxCoord(points=grib._originatingCentre, long_name='originating_centre', units='no_unit'), None))

    if \
            (grib.edition == 2) and \
            (grib.productDefinitionTemplateNumber == 1):
        aux_coords_and_dims.append((DimCoord(points=grib.perturbationNumber, long_name='ensemble_member', units='no_unit'), None))

    if grib.productDefinitionTemplateNumber not in (0, 8):
        attributes["GRIB_LOAD_WARNING"] = ("unsupported GRIB%d ProductDefinitionTemplate: #4.%d" % (grib.edition, grib.productDefinitionTemplateNumber))

    if \
            (grib.edition == 2) and \
            (grib.centre == 'ecmf') and \
            (grib.discipline == 0) and \
            (grib.parameterCategory == 3) and \
            (grib.parameterNumber == 25) and \
            (grib.typeOfFirstFixedSurface == 105):
        references.append(ReferenceTarget('surface_air_pressure', lambda cube: {'standard_name': 'surface_air_pressure', 'units': 'Pa', 'data': np.exp(cube.data)}))

    return (factories, references, standard_name, long_name, units, attributes,
            cell_methods, dim_coords_and_dims, aux_coords_and_dims)
Example #26
0
 def test_daily_min(self):
     # lbproc = 4096 -> min
     field = mock.MagicMock(lbproc=4096, lbtim=mock.Mock(ia=24, ib=2, ic=3))
     res = _all_other_rules(field)[CELL_METHODS_INDEX]
     expected = [CellMethod("minimum", "time", "24 hour")]
     self.assertEqual(res, expected)
Example #27
0
 def test_maximum(self):
     self.cube.cell_methods = (CellMethod("maximum", "time", "1 hour"), )
     lbproc = _lbproc_rules(self.cube, self.pp_field).lbproc
     self.assertEqual(lbproc, 8192)
Example #28
0
 def test_climatology_min(self):
     field = mock.MagicMock(lbproc=4096, lbtim=mock.Mock(ia=24, ib=3, ic=3))
     res = _all_other_rules(field)[CELL_METHODS_INDEX]
     expected = [CellMethod("minimum", "time")]
     self.assertEqual(res, expected)
Example #29
0
def grib1_convert(grib):
    """
    Converts a GRIB1 message into the corresponding items of Cube metadata.

    Args:

    * grib:
        A :class:`~iris_grib.GribWrapper` object.

    Returns:
        A :class:`iris.fileformats.rules.ConversionMetadata` object.

    """
    if grib.edition != 1:
        emsg = 'GRIB edition {} is not supported by {!r}.'
        raise TranslationError(emsg.format(grib.edition, type(grib).__name__))

    factories = []
    references = []
    standard_name = None
    long_name = None
    units = None
    attributes = {}
    cell_methods = []
    dim_coords_and_dims = []
    aux_coords_and_dims = []

    if \
            (grib.gridType=="reduced_gg"):
        aux_coords_and_dims.append(
            (AuxCoord(grib._y_points,
                      grib._y_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 0))
        aux_coords_and_dims.append(
            (AuxCoord(grib._x_points,
                      grib._x_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 0))

    if \
            (grib.gridType=="regular_ll") and \
            (grib.jPointsAreConsecutive == 0):
        dim_coords_and_dims.append(
            (DimCoord(grib._y_points,
                      grib._y_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 0))
        dim_coords_and_dims.append((DimCoord(grib._x_points,
                                             grib._x_coord_name,
                                             units='degrees',
                                             coord_system=grib._coord_system,
                                             circular=grib._x_circular), 1))

    if \
            (grib.gridType=="regular_ll") and \
            (grib.jPointsAreConsecutive == 1):
        dim_coords_and_dims.append(
            (DimCoord(grib._y_points,
                      grib._y_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 1))
        dim_coords_and_dims.append((DimCoord(grib._x_points,
                                             grib._x_coord_name,
                                             units='degrees',
                                             coord_system=grib._coord_system,
                                             circular=grib._x_circular), 0))

    if \
            (grib.gridType=="regular_gg") and \
            (grib.jPointsAreConsecutive == 0):
        dim_coords_and_dims.append(
            (DimCoord(grib._y_points,
                      grib._y_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 0))
        dim_coords_and_dims.append((DimCoord(grib._x_points,
                                             grib._x_coord_name,
                                             units='degrees',
                                             coord_system=grib._coord_system,
                                             circular=grib._x_circular), 1))

    if \
            (grib.gridType=="regular_gg") and \
            (grib.jPointsAreConsecutive == 1):
        dim_coords_and_dims.append(
            (DimCoord(grib._y_points,
                      grib._y_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 1))
        dim_coords_and_dims.append((DimCoord(grib._x_points,
                                             grib._x_coord_name,
                                             units='degrees',
                                             coord_system=grib._coord_system,
                                             circular=grib._x_circular), 0))

    if \
            (grib.gridType=="rotated_ll") and \
            (grib.jPointsAreConsecutive == 0):
        dim_coords_and_dims.append(
            (DimCoord(grib._y_points,
                      grib._y_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 0))
        dim_coords_and_dims.append((DimCoord(grib._x_points,
                                             grib._x_coord_name,
                                             units='degrees',
                                             coord_system=grib._coord_system,
                                             circular=grib._x_circular), 1))

    if \
            (grib.gridType=="rotated_ll") and \
            (grib.jPointsAreConsecutive == 1):
        dim_coords_and_dims.append(
            (DimCoord(grib._y_points,
                      grib._y_coord_name,
                      units='degrees',
                      coord_system=grib._coord_system), 1))
        dim_coords_and_dims.append((DimCoord(grib._x_points,
                                             grib._x_coord_name,
                                             units='degrees',
                                             coord_system=grib._coord_system,
                                             circular=grib._x_circular), 0))

    if grib.gridType in ["polar_stereographic", "lambert"]:
        dim_coords_and_dims.append(
            (DimCoord(grib._y_points,
                      grib._y_coord_name,
                      units="m",
                      coord_system=grib._coord_system), 0))
        dim_coords_and_dims.append(
            (DimCoord(grib._x_points,
                      grib._x_coord_name,
                      units="m",
                      coord_system=grib._coord_system), 1))

    if \
            (grib.table2Version < 128) and \
            (grib.indicatorOfParameter == 11) and \
            (grib._cf_data is None):
        standard_name = "air_temperature"
        units = "kelvin"

    if \
            (grib.table2Version < 128) and \
            (grib.indicatorOfParameter == 33) and \
            (grib._cf_data is None):
        standard_name = "x_wind"
        units = "m s-1"

    if \
            (grib.table2Version < 128) and \
            (grib.indicatorOfParameter == 34) and \
            (grib._cf_data is None):
        standard_name = "y_wind"
        units = "m s-1"

    if \
            (grib._cf_data is not None):
        standard_name = grib._cf_data.standard_name
        long_name = grib._cf_data.standard_name or grib._cf_data.long_name
        units = grib._cf_data.units

    if \
            (grib.table2Version >= 128) and \
            (grib._cf_data is None):
        long_name = "UNKNOWN LOCAL PARAM " + str(
            grib.indicatorOfParameter) + "." + str(grib.table2Version)
        units = "???"

    if \
            (grib.table2Version == 1) and \
            (grib.indicatorOfParameter >= 128):
        long_name = "UNKNOWN LOCAL PARAM " + str(
            grib.indicatorOfParameter) + "." + str(grib.table2Version)
        units = "???"

    if \
            (grib._phenomenonDateTime != -1.0):
        aux_coords_and_dims.append(
            (DimCoord(points=grib.startStep,
                      standard_name='forecast_period',
                      units=grib._forecastTimeUnit), None))
        aux_coords_and_dims.append(
            (DimCoord(points=grib.phenomenon_points('hours'),
                      standard_name='time',
                      units=Unit('hours since epoch',
                                 CALENDAR_GREGORIAN)), None))

    def add_bounded_time_coords(aux_coords_and_dims, grib):
        t_bounds = grib.phenomenon_bounds('hours')
        period = Unit('hours').convert(t_bounds[1] - t_bounds[0],
                                       grib._forecastTimeUnit)
        aux_coords_and_dims.append(
            (DimCoord(standard_name='forecast_period',
                      units=grib._forecastTimeUnit,
                      points=grib._forecastTime + 0.5 * period,
                      bounds=[grib._forecastTime,
                              grib._forecastTime + period]), None))
        aux_coords_and_dims.append(
            (DimCoord(standard_name='time',
                      units=Unit('hours since epoch', CALENDAR_GREGORIAN),
                      points=0.5 * (t_bounds[0] + t_bounds[1]),
                      bounds=t_bounds), None))

    if \
            (grib.timeRangeIndicator == 2):
        add_bounded_time_coords(aux_coords_and_dims, grib)

    if \
            (grib.timeRangeIndicator == 3):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.timeRangeIndicator == 4):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("sum", coords="time"))

    if \
            (grib.timeRangeIndicator == 5):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("_difference", coords="time"))

    if \
            (grib.timeRangeIndicator == 51):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.timeRangeIndicator == 113):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.timeRangeIndicator == 114):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("sum", coords="time"))

    if \
            (grib.timeRangeIndicator == 115):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.timeRangeIndicator == 116):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("sum", coords="time"))

    if \
            (grib.timeRangeIndicator == 117):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.timeRangeIndicator == 118):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("_covariance", coords="time"))

    if \
            (grib.timeRangeIndicator == 123):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("mean", coords="time"))

    if \
            (grib.timeRangeIndicator == 124):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("sum", coords="time"))

    if \
            (grib.timeRangeIndicator == 125):
        add_bounded_time_coords(aux_coords_and_dims, grib)
        cell_methods.append(CellMethod("standard_deviation", coords="time"))

    if \
            (grib.levelType == 'pl'):
        aux_coords_and_dims.append((DimCoord(points=grib.level,
                                             long_name="pressure",
                                             units="hPa"), None))

    if \
            (grib.levelType == 'sfc'):

        if (grib._cf_data is not None) and \
        (grib._cf_data.set_height is not None):
            aux_coords_and_dims.append(
                (DimCoord(points=grib._cf_data.set_height,
                          long_name="height",
                          units="m",
                          attributes={'positive': 'up'}), None))
        elif grib.typeOfLevel == 'heightAboveGround':  # required for NCAR
            aux_coords_and_dims.append((DimCoord(points=grib.level,
                                                 long_name="height",
                                                 units="m",
                                                 attributes={'positive':
                                                             'up'}), None))

    if \
            (grib.levelType == 'ml') and \
            (hasattr(grib, 'pv')):
        aux_coords_and_dims.append(
            (AuxCoord(grib.level,
                      standard_name='model_level_number',
                      attributes={'positive': 'up'}), None))
        aux_coords_and_dims.append((DimCoord(grib.pv[grib.level],
                                             long_name='level_pressure',
                                             units='Pa'), None))
        aux_coords_and_dims.append((AuxCoord(
            grib.pv[grib.numberOfCoordinatesValues // 2 + grib.level],
            long_name='sigma'), None))
        factories.append(
            Factory(HybridPressureFactory, [{
                'long_name': 'level_pressure'
            }, {
                'long_name': 'sigma'
            },
                                            Reference('surface_pressure')]))

    if grib._originatingCentre != 'unknown':
        aux_coords_and_dims.append((AuxCoord(points=grib._originatingCentre,
                                             long_name='originating_centre',
                                             units='no_unit'), None))

    return ConversionMetadata(factories, references, standard_name, long_name,
                              units, attributes, cell_methods,
                              dim_coords_and_dims, aux_coords_and_dims)
Example #30
0
 def test_string(self):
     token = 'air_temperature'
     result = CellMethod(self.method, coords=token)
     expected = '{}: {}'.format(self.method, token)
     self.assertEqual(str(result), expected)