Exemple #1
0
 def test_basic(self):
     """Test that a number is returned of the expected value."""
     cycletime = "20171122T0000Z"
     dt = 419808.0
     result = cycletime_to_number(cycletime)
     self.assertIsInstance(result, float)
     self.assertAlmostEqual(result, dt)
Exemple #2
0
 def test_alternative_units_defined(self):
     """Test when alternative units are defined."""
     cycletime = "20171122T0000Z"
     dt = 1511308800.0
     result = cycletime_to_number(
         cycletime, time_unit="seconds since 1970-01-01 00:00:00")
     self.assertAlmostEqual(result, dt)
Exemple #3
0
 def test_alternative_calendar_defined(self):
     """Test when an alternative calendar is defined."""
     cycletime = "20171122T0000Z"
     dt = 419520.0
     result = cycletime_to_number(
         cycletime, calendar="365_day")
     self.assertAlmostEqual(result, dt)
    def _get_cycletime_point(input_cube, cycletime):
        """
        For cycle and model blending, establish the single forecast reference
        time to set on the cube after blending.

        Args:
            input_cube (iris.cube.Cube):
                Cube to be blended
            cycletime (str or None):
                The cycletime in a YYYYMMDDTHHMMZ format e.g. 20171122T0100Z.
                If None, the latest forecast reference time is used.

        Returns:
            numpy.int64:
                Forecast reference time point in units of input cube coordinate
        """
        frt_coord = input_cube.coord("forecast_reference_time")
        if cycletime is None:
            return np.max(frt_coord.points)
        frt_units = frt_coord.units.origin
        frt_calendar = frt_coord.units.calendar
        cycletime_point = cycletime_to_number(cycletime,
                                              time_unit=frt_units,
                                              calendar=frt_calendar)
        return round_close(cycletime_point, dtype=np.int64)
Exemple #5
0
 def test_cycletime_format_defined(self):
     """Test when a cycletime is defined."""
     cycletime = "201711220000"
     dt = 419808.0
     result = cycletime_to_number(
         cycletime, cycletime_format="%Y%m%d%H%M")
     self.assertAlmostEqual(result, dt)
Exemple #6
0
 def test_alternative_units_defined(self):
     """Test when alternative units are defined. The result is cast as
     an integer as seconds should be of this type and compared as such.
     There are small precision errors in the 7th decimal place of the
     returned float."""
     cycletime = "20171122T0000Z"
     dt = 1511308800
     result = cycletime_to_number(
         cycletime, time_unit="seconds since 1970-01-01 00:00:00")
     self.assertEqual(int(np.round(result)), dt)
    def _get_cycletime_point(self, cube):
        """
        For cycle and model blending, establish the current cycletime to set on
        the cube after blending.

        Returns:
            numpy.int64:
                Cycle time point in units matching the input cube forecast reference
                time coordinate
        """
        frt_coord = cube.coord("forecast_reference_time")
        frt_units = frt_coord.units.origin
        frt_calendar = frt_coord.units.calendar
        # raises TypeError if cycletime is None
        cycletime_point = cycletime_to_number(
            self.cycletime, time_unit=frt_units, calendar=frt_calendar
        )
        return round_close(cycletime_point, dtype=np.int64)
Exemple #8
0
def _get_cycletime_point(cube: Cube, cycletime: str) -> int64:
    """
    For cycle and model blending, establish the current cycletime to set on
    the cube after blending.

    Args:
        blended_cube
        cycletime:
            Current cycletime in YYYYMMDDTHHmmZ format

    Returns:
        Cycle time point in units matching the input cube forecast reference
        time coordinate
    """
    frt_coord = cube.coord("forecast_reference_time")
    frt_units = frt_coord.units.origin
    frt_calendar = frt_coord.units.calendar
    # raises TypeError if cycletime is None
    cycletime_point = cycletime_to_number(cycletime,
                                          time_unit=frt_units,
                                          calendar=frt_calendar)
    return round_close(cycletime_point, dtype=np.int64)
Exemple #9
0
def conform_metadata(cube, cube_orig, coord, cycletime=None):
    """Ensure that the metadata conforms after blending together across
    the chosen coordinate.

    The metadata adjustments are:
        - Forecast reference time: If a cycletime is not present, the
          most recent available forecast_reference_time is used.
          If a cycletime is present, the cycletime is used as the
          forecast_reference_time instead.
        - Forecast period: If a forecast_period coordinate is present,
          and cycletime is not present, the lowest forecast_period is
          used. If a forecast_period coordinate is present, and the
          cycletime is present, forecast_periods are forceably re-calculated
          from the time and forecast_reference_time coordinates so that their
          values are self-consistent.
        - Forecast reference time and time: If forecast_reference_time and
          time coordinates are present, then a forecast_period coordinate is
          calculated and added to the cube.
        - Model_id, model_realization and realization coordinates are removed.
        - A title attribute is added to the cube if none is found. Otherwise
          the attributes are unchanged.

    Args:
        cube (iris.cube.Cube):
            Cube containing the metadata to be adjusted.
        cube_orig (iris.cube.Cube):
            Cube containing metadata that may be useful for adjusting
            metadata on the `cube` variable.
        coord (str):
            Coordinate that has been blended. This allows specific metadata
            changes to be limited to whichever coordinate is being blended.
        cycletime (str):
            The cycletime in a YYYYMMDDTHHMMZ format e.g. 20171122T0100Z.

    Returns:
        cube (iris.cube.Cube):
            Cube containing the adjusted metadata.

    """
    # unify time coordinates for cycle and grid (model) blends
    if coord in ["forecast_reference_time", "model_id"]:
        # if cycle blending, update forecast reference time and remove bounds
        if cube.coords("forecast_reference_time"):
            if cycletime is None:
                new_cycletime = (np.max(
                    cube_orig.coord("forecast_reference_time").points))
            else:
                cycletime_units = (
                    cube_orig.coord("forecast_reference_time").units.origin)
                cycletime_calendar = (
                    cube.coord("forecast_reference_time").units.calendar)
                new_cycletime = cycletime_to_number(
                    cycletime,
                    time_unit=cycletime_units,
                    calendar=cycletime_calendar)
                # Preserve the data type to avoid converting ints to floats.
                frt_type = cube.coord("forecast_reference_time").dtype
                new_cycletime = np.round(new_cycletime).astype(frt_type)
            cube.coord("forecast_reference_time").points = new_cycletime
            cube.coord("forecast_reference_time").bounds = None

        # recalculate forecast period coordinate
        if cube.coords("forecast_period"):
            forecast_period = forecast_period_coord(
                cube, force_lead_time_calculation=True)
            forecast_period.convert_units(cube.coord("forecast_period").units)
            forecast_period.var_name = cube.coord("forecast_period").var_name
            cube.replace_coord(forecast_period)
        elif cube.coords("forecast_reference_time") and cube.coords("time"):
            forecast_period = forecast_period_coord(cube)
            ndim = cube.coord_dims("time")
            cube.add_aux_coord(forecast_period, data_dims=ndim)

    # update blended cube attributes
    if "title" not in cube.attributes.keys():
        cube.attributes["title"] = "IMPROVER Model Forecast"

    # remove appropriate scalar coordinates
    for crd in ["model_id", "model_configuration", "realization"]:
        if cube.coords(crd) and cube.coord(crd).shape == (1, ):
            cube.remove_coord(crd)

    return cube
def conform_metadata(cube,
                     cube_orig,
                     coord,
                     cycletime=None,
                     coords_for_bounds_removal=None):
    """Ensure that the metadata conforms after blending together across
    the chosen coordinate.

    The metadata adjustments are:
        - Forecast reference time: If a cycletime is not present, the
          most recent available forecast_reference_time is used.
          If a cycletime is present, the cycletime is used as the
          forecast_reference_time instead.
        - Forecast period: If a forecast_period coordinate is present,
          and cycletime is not present, the lowest forecast_period is
          used. If a forecast_period coordinate is present, and the
          cycletime is present, forecast_periods are forceably calculated
          from the time and forecast_reference_time coordinate. This is
          because, if the cycletime is present, then the
          forecast_reference_time will also have been just re-calculated, so
          the forecast_period coordinate needs to be reset to match the
          newly calculated forecast_reference_time.
        - Forecast reference time and time: If forecast_reference_time and
          time coordinates are present, then a forecast_period coordinate is
          calculated and added to the cube.
        - Model_id, model_realization and realization coordinates are removed.
        - Remove bounds from the scalar coordinates, if the coordinates
          are specified within the coords_for_bounds_removal argument.

    Args:
        cube (iris.cube.Cube):
            Cube containing the metadata to be adjusted.
        cube_orig (iris.cube.Cube):
            Cube containing metadata that may be useful for adjusting
            metadata on the `cube` variable.
        coord (str):
            Coordinate that has been blended. This allows specific metadata
            changes to be limited to whichever coordinate is being blended.

    Keyword Args:
        cycletime (str):
            The cycletime in a YYYYMMDDTHHMMZ format e.g. 20171122T0100Z.
        coords_for_bounds_removal (None or list):
            List of coordinates that are scalar and should have their bounds
            removed.

    Returns:
        cube (iris.cube.Cube):
            Cube containing the adjusted metadata.

    """
    if coord in ["forecast_reference_time", "model"]:
        if cube.coords("forecast_reference_time"):
            if cycletime is None:
                new_cycletime = (np.max(
                    cube_orig.coord("forecast_reference_time").points))
            else:
                cycletime_units = (
                    cube_orig.coord("forecast_reference_time").units.origin)
                cycletime_calendar = (
                    cube.coord("forecast_reference_time").units.calendar)
                new_cycletime = cycletime_to_number(
                    cycletime,
                    time_unit=cycletime_units,
                    calendar=cycletime_calendar)
                # Preserve the data type to avoid converting ints to floats.
                fr_type = cube.coord("forecast_reference_time").dtype
                new_cycletime = np.round(new_cycletime).astype(fr_type)
            cube.coord("forecast_reference_time").points = new_cycletime
            cube.coord("forecast_reference_time").bounds = None

        if cube.coords("forecast_period"):
            forecast_period = (forecast_period_coord(
                cube, force_lead_time_calculation=True))
            forecast_period.bounds = None
            forecast_period.convert_units(cube.coord("forecast_period").units)
            forecast_period.var_name = cube.coord("forecast_period").var_name
            cube.replace_coord(forecast_period)
        elif cube.coords("forecast_reference_time") and cube.coords("time"):
            forecast_period = (forecast_period_coord(cube))
            ndim = cube.coord_dims("time")
            cube.add_aux_coord(forecast_period, data_dims=ndim)

    for coord in ["model_id", "model_realization", "realization"]:
        if cube.coords(coord) and cube.coord(coord).shape == (1, ):
            cube.remove_coord(coord)

    if coords_for_bounds_removal is None:
        coords_for_bounds_removal = []

    for coord in cube.coords():
        if coord.name() in coords_for_bounds_removal:
            if coord.shape == (1, ) and coord.has_bounds():
                coord.bounds = None
    return cube