Beispiel #1
0
def time_range(cube, grib):
    """Grib encoding of forecast_period."""
    fp_coord = cube.coord("forecast_period")
    if fp_coord.has_bounds():
        raise iris.exceptions.TranslationError(
            "Bounds not expected for 'forecast_period'")

    if fp_coord.units == iris.unit.Unit("hours"):
        grib_time_code = 1
    elif fp_coord.units == iris.unit.Unit("minutes"):
        grib_time_code = 0
    elif fp_coord.units == iris.unit.Unit("seconds"):
        grib_time_code = 13
    else:
        raise iris.exceptions.TranslationError(
            "Unexpected units for 'forecast_period' : %s" % fp_coord.units)

    fp = fp_coord.points[0]
    if fp - int(fp):
        warnings.warn("forecast_period encoding problem: scaling required.")
    fp = int(fp)

    # Turn negative forecast times into grib negative numbers?
    from iris.fileformats.grib import hindcast_workaround
    if hindcast_workaround and fp < 0:
        msg = "Encoding negative forecast period from {} to ".format(fp)
        fp = 2**31 + abs(fp)
        msg += "{}".format(np.int32(fp))
        warnings.warn(msg)

    gribapi.grib_set_long(grib, "indicatorOfUnitOfTimeRange", grib_time_code)
    gribapi.grib_set_long(grib, "forecastTime", fp)
Beispiel #2
0
def time_range(cube, grib):
    """Grib encoding of forecast_period."""
    fp_coord = cube.coord("forecast_period")
    if fp_coord.has_bounds():
        raise iris.exceptions.TranslationError(
            "Bounds not expected for 'forecast_period'")

    if fp_coord.units == iris.unit.Unit("hours"):
        grib_time_code = 1
    elif fp_coord.units == iris.unit.Unit("minutes"):
        grib_time_code = 0
    elif fp_coord.units == iris.unit.Unit("seconds"):
        grib_time_code = 13
    else:
        raise iris.exceptions.TranslationError(
            "Unexpected units for 'forecast_period' : %s" % fp_coord.units)

    fp = fp_coord.points[0]
    if fp - int(fp):
        warnings.warn("forecast_period encoding problem: scaling required.")
    fp = int(fp)

    # Turn negative forecast times into grib negative numbers?
    from iris.fileformats.grib import hindcast_workaround
    if hindcast_workaround and fp < 0:
        msg = "Encoding negative forecast period from {} to ".format(fp)
        fp = 2**31 + abs(fp)
        msg += "{}".format(np.int32(fp))
        warnings.warn(msg)

    gribapi.grib_set_long(grib, "indicatorOfUnitOfTimeRange", grib_time_code)
    gribapi.grib_set_long(grib, "forecastTime", fp)
Beispiel #3
0
def generating_process_type(cube, grib):
    # analysis = 0
    # initialisation = 1
    # forecast = 2
    # more...

    # missing
    gribapi.grib_set_long(grib, "typeOfGeneratingProcess", 255)
Beispiel #4
0
def generating_process_type(cube, grib):
    # analysis = 0
    # initialisation = 1
    # forecast = 2
    # more...

    # missing
    gribapi.grib_set_long(grib, "typeOfGeneratingProcess", 255)
    def test_load_probability_forecast(self):
        # Test GribWrapper interpretation of PDT 4.9 data.
        # NOTE:
        #   Currently Iris has only partial support for PDT 4.9.
        #   Though it can load the data, key metadata (thresholds) is lost.
        #   At present, we are not testing for this.

        # Make a testing grib message in memory, with gribapi.
        grib_message = gribapi.grib_new_from_samples('GRIB2')
        gribapi.grib_set_long(grib_message, 'productDefinitionTemplateNumber',
                              9)
        gribapi.grib_set_string(grib_message, 'stepRange', '10-55')
        grib_wrapper = iris.fileformats.grib.GribWrapper(grib_message)

        # Define two expected datetimes for _periodEndDateTime as
        # gribapi v1.9.16 mis-calculates this.
        # See https://software.ecmwf.int/wiki/display/GRIB/\
        #     GRIB+API+version+1.9.18+released
        try:
            # gribapi v1.9.16 has no __version__ attribute.
            gribapi_ver = gribapi.__version__
        except AttributeError:
            gribapi_ver = gribapi.grib_get_api_version()

        if StrictVersion(gribapi_ver) < StrictVersion('1.9.18'):
            exp_end_date = datetime.datetime(year=2007,
                                             month=3,
                                             day=25,
                                             hour=12,
                                             minute=0,
                                             second=0)
        else:
            exp_end_date = datetime.datetime(year=2007,
                                             month=3,
                                             day=25,
                                             hour=19,
                                             minute=0,
                                             second=0)

        # Check that it captures the statistics time period info.
        # (And for now, nothing else)
        self.assertEqual(
            grib_wrapper._referenceDateTime,
            datetime.datetime(year=2007,
                              month=3,
                              day=23,
                              hour=12,
                              minute=0,
                              second=0))
        self.assertEqual(
            grib_wrapper._periodStartDateTime,
            datetime.datetime(year=2007,
                              month=3,
                              day=23,
                              hour=22,
                              minute=0,
                              second=0))
        self.assertEqual(grib_wrapper._periodEndDateTime, exp_end_date)
Beispiel #6
0
def identification(cube, grib):
    centre(cube, grib)
    reference_time(cube, grib)

    # operational product, operational test, research product, etc
    # (missing for now)
    gribapi.grib_set_long(grib, "productionStatusOfProcessedData", 255)
    # analysis, forecast, processed satellite, processed radar,
    # (analysis and forecast products for now)
    gribapi.grib_set_long(grib, "typeOfProcessedData", 2)
Beispiel #7
0
def identification(cube, grib):
    centre(cube, grib)
    reference_time(cube, grib)

    # operational product, operational test, research product, etc
    # (missing for now)
    gribapi.grib_set_long(grib, "productionStatusOfProcessedData", 255)
    # analysis, forecast, processed satellite, processed radar,
    # (analysis and forecast products for now)
    gribapi.grib_set_long(grib, "typeOfProcessedData", 2)
Beispiel #8
0
def product_definition_template_0(cube, grib):
    """
    Set keys within the provided grib message based on Product
    Definition Template 4.0.

    Template 4.0 is used to represent an analysis or forecast at
    a horizontal level at a point in time.

    """
    gribapi.grib_set_long(grib, "productDefinitionTemplateNumber", 0)
    product_definition_template_common(cube, grib)
Beispiel #9
0
def product_definition_template_0(cube, grib):
    """
    Set keys within the provided grib message based on Product
    Definition Template 4.0.

    Template 4.0 is used to represent an analysis or forecast at
    a horizontal level at a point in time.

    """
    gribapi.grib_set_long(grib, "productDefinitionTemplateNumber", 0)
    product_definition_template_common(cube, grib)
Beispiel #10
0
def data(cube, grib):

    # mdi
    if isinstance(cube.data, numpy.ma.core.MaskedArray):
        gribapi.grib_set_long(grib, "missingValue", cube.data.fill_value)
        data = cube.data.filled()
    else:
        gribapi.grib_set_long(grib, "missingValue", -1e9)
        data = cube.data
    
    # values
    gribapi.grib_set_double_array(grib, "values", data.flatten())
Beispiel #11
0
def set_data(source, grib):
    """
    Sets the actual data of a grib message.
    """
    var_name = get_varible_name(source)
    # treat masked arrays differently
    if isinstance(source[var_name].values, np.ma.core.MaskedArray):
        gribapi.grib_set(grib, "bitmapPresent", 1)
        # use the missing value from the masked array as default
        missing_value = source[var_name].values.get_fill_value()
        # but give the netCDF specified missing value preference
        missing_value = source[var_name].attrs.get('missing_value',
                                                        missing_value)
        gribapi.grib_set_double(grib, "missingValue",
                                float(missing_value))
        data = source[var_name].values.filled()
    else:
        gribapi.grib_set_double(grib, "missingValue", 9999)
        data = source[var_name].values[:]
    gribapi.grib_set_long(grib, "bitsPerValue", 12)
    #gribapi.grib_set_long(grib, "bitsPerValueAndRepack", 12)
    gribapi.grib_set_long(grib, "decimalPrecision", 2)
    gribapi.grib_set_long(grib, "decimalScaleFactor", 2)
    #gribapi.grib_set_long(grib, "binaryScaleFactor", 0)
    gribapi.grib_set_long(grib, "dataRepresentationType", 0)
    # get the grib code for the variable
    code = reverse_codes[conv.to_grib1[var_name]]
    _, grib_unit = codes[code]
    # default to the grib default unit
    unit = source[var_name].attrs.get('units', grib_unit)
    mult = 1.
    if not unit == grib_unit:
        mult = units._speed[unit] / units._speed[grib_unit]
    # add the data
    gribapi.grib_set_double_array(grib, "values", mult * data.flatten())
Beispiel #12
0
def grid_definition_template_0(cube, grib):
    """
    Set keys within the provided grib message based on
    Grid Definition Template 3.0.

    Template 3.0 is used to represent "latitude/longitude (or equidistant
    cylindrical, or Plate Carree)".
    The coordinates are regularly spaced, true latitudes and longitudes.

    """
    # Constant resolution, aka 'regular' true lat-lon grid.
    gribapi.grib_set_long(grib, "gridDefinitionTemplateNumber", 0)
    horizontal_grid_common(cube, grib)
    latlon_points_regular(cube, grib)
Beispiel #13
0
def time_range(cube, grib):
    """Grib encoding of forecast_period."""
    try:
        fp_coord = cube.coord("forecast_period")
    except iris.exceptions.CoordinateNotFoundError:
        fp_coord = None

    if fp_coord is not None:
        _, _, fp, grib_time_code = _non_missing_forecast_period(cube)
    else:
        _, _, fp, grib_time_code = _missing_forecast_period(cube)

    gribapi.grib_set_long(grib, "indicatorOfUnitOfTimeRange", grib_time_code)
    gribapi.grib_set_long(grib, "forecastTime", fp)
Beispiel #14
0
def grid_definition_template_0(cube, grib):
    """
    Set keys within the provided grib message based on
    Grid Definition Template 3.0.

    Template 3.0 is used to represent "latitude/longitude (or equidistant
    cylindrical, or Plate Carree)".
    The coordinates are regularly spaced, true latitudes and longitudes.

    """
    # Constant resolution, aka 'regular' true lat-lon grid.
    gribapi.grib_set_long(grib, "gridDefinitionTemplateNumber", 0)
    horizontal_grid_common(cube, grib)
    latlon_points_regular(cube, grib)
Beispiel #15
0
def type_of_statistical_processing(cube, grib, coord):
    """Search for processing over the given coord."""
    stat_code = 255  # (grib code table 4.10)

    # if the last cell method applies only to the given coord...
    cell_method = cube.cell_methods[-1]
    coord_names = cell_method.coord_names
    if len(coord_names) == 1 and coord_names[0] == coord.name():
        stat_codes = {'mean': 0, 'sum': 1, 'maximum': 2, 'minimum': 3,
                      'standard_deviation': 6}
        stat_code = stat_codes[cell_method.method]
    if stat_code == 255:
        warnings.warn("Unable to determine type of statistical processing")
    gribapi.grib_set_long(grib, "typeOfStatisticalProcessing", stat_code)
Beispiel #16
0
def time_range(cube, grib):
    """Grib encoding of forecast_period."""
    try:
        fp_coord = cube.coord("forecast_period")
    except iris.exceptions.CoordinateNotFoundError:
        fp_coord = None

    if fp_coord is not None:
        _, _, fp, grib_time_code = _non_missing_forecast_period(cube)
    else:
        _, _, fp, grib_time_code = _missing_forecast_period(cube)

    gribapi.grib_set_long(grib, "indicatorOfUnitOfTimeRange", grib_time_code)
    gribapi.grib_set_long(grib, "forecastTime", fp)
Beispiel #17
0
def grid_template(cube, grib):
    cs = cube.coord(dimensions=[0]).coord_system
    if isinstance(cs, iris.coord_systems.GeogCS):
        # template 3.0
        gribapi.grib_set_long(grib, "gridDefinitionTemplateNumber", 0)
        latlon_common(cube, grib)

    # rotated
    elif isinstance(cs, iris.coord_systems.RotatedGeogCS):
        # template 3.1
        gribapi.grib_set_long(grib, "gridDefinitionTemplateNumber", 1)
        latlon_common(cube, grib)
        rotated_pole(cube, grib)
    else:
        raise ValueError("Currently unhandled CoordSystem: %s" % cs)
Beispiel #18
0
def grid_template(cube, grib):
    cs = cube.coord(dimensions=[0]).coord_system
    if isinstance(cs, iris.coord_systems.GeogCS):
        # template 3.0
        gribapi.grib_set_long(grib, "gridDefinitionTemplateNumber", 0)
        latlon_common(cube, grib)

    # rotated
    elif isinstance(cs, iris.coord_systems.RotatedGeogCS):
        # template 3.1
        gribapi.grib_set_long(grib, "gridDefinitionTemplateNumber", 1)
        latlon_common(cube, grib)
        rotated_pole(cube, grib)
    else:
        raise ValueError("Currently unhandled CoordSystem: %s" % cs)
Beispiel #19
0
def product_template(cube, grib):
    # This will become more complex if we cover more templates, such as 4.15

    # forecast (template 4.0)
    if not cube.coord("time").has_bounds():
        gribapi.grib_set_long(grib, "productDefinitionTemplateNumber", 0)
        product_common(cube, grib)
    
    # time processed (template 4.8)
    elif cube.cell_methods and cube.cell_methods[-1].coord_names[0] == "time":
        gribapi.grib_set_long(grib, "productDefinitionTemplateNumber", 8)
        product_common(cube, grib)
        time_processing_period(cube, grib)
        
    else:
        raise iris.exceptions.TranslationError("A suitable product template could not be deduced")
Beispiel #20
0
def product_definition_template_8(cube, grib):
    """
    Set keys within the provided grib message based on Product
    Definition Template 4.8.

    Template 4.8 is used to represent an aggregation over a time
    interval.

    """
    gribapi.grib_set_long(grib, "productDefinitionTemplateNumber", 8)
    product_definition_template_common(cube, grib)
    try:
        time_processing_period(cube, grib)
    except ValueError as e:
        raise ValueError('Saving to GRIB2 failed: the cube is not suitable'
                         ' for saving as a time processed statistic GRIB'
                         ' message. {}'.format(e))
Beispiel #21
0
def type_of_statistical_processing(cube, grib, coord):
    """Search for processing over the given coord."""
    # if the last cell method applies only to the given coord...
    cell_method = cube.cell_methods[-1]
    coord_names = cell_method.coord_names
    if len(coord_names) != 1:
        raise ValueError('There are multiple coord names referenced by '
                         'the primary cell method: {!r}. Multiple coordinate '
                         'names are not supported.'.format(coord_names))
    if coord_names[0] != coord.name():
        raise ValueError('The coord name referenced by the primary cell method'
                         ', {!r},  is not the expected coord name {!r}.'
                         ''.format(coord_names[0], coord.name()))
    stat_codes = {'mean': 0, 'sum': 1, 'maximum': 2, 'minimum': 3,
                  'standard_deviation': 6}
    # 255 is the code in template 4.8 for 'unknown' statistical method
    stat_code = stat_codes.get(cell_method.method, 255)
    gribapi.grib_set_long(grib, "typeOfStatisticalProcessing", stat_code)
Beispiel #22
0
def grid_template(cube, grib):

    cs0 = cube.coord(dimensions=[0]).coord_system
    cs1 = cube.coord(dimensions=[1]).coord_system
        
    if not cs0.has_rotated_pole():
        
        # template 3.0
        gribapi.grib_set_long(grib, "gridDefinitionTemplateNumber", 0)
        latlon_common(cube, grib)            

    # rotated
    else:

        # template 3.1
        gribapi.grib_set_long(grib, "gridDefinitionTemplateNumber", 1)
        latlon_common(cube, grib)
        rotated_pole(cube, grib)
Beispiel #23
0
    def test_load_probability_forecast(self):
        # Test GribWrapper interpretation of PDT 4.9 data.
        # NOTE:
        #   Currently iris-grib has only partial support for PDT 4.9.
        #   Though it can load the data, key metadata (thresholds) is lost.
        #   At present, we are not testing for this.

        # Make a testing grib message in memory, with gribapi.
        grib_message = gribapi.grib_new_from_samples('GRIB2')
        gribapi.grib_set_long(grib_message, 'productDefinitionTemplateNumber',
                              9)
        gribapi.grib_set_string(grib_message, 'stepRange', '10-55')
        grib_wrapper = iris.fileformats.grib.GribWrapper(grib_message)

        # Define two expected datetimes for _periodEndDateTime as
        # gribapi v1.9.16 mis-calculates this.
        # See https://software.ecmwf.int/wiki/display/GRIB/\
        #     GRIB+API+version+1.9.18+released
        try:
            # gribapi v1.9.16 has no __version__ attribute.
            gribapi_ver = gribapi.__version__
        except AttributeError:
            gribapi_ver = gribapi.grib_get_api_version()

        if StrictVersion(gribapi_ver) < StrictVersion('1.9.18'):
            exp_end_date = datetime.datetime(year=2007, month=3, day=25,
                                             hour=12, minute=0, second=0)
        else:
            exp_end_date = datetime.datetime(year=2007, month=3, day=25,
                                             hour=19, minute=0, second=0)

        # Check that it captures the statistics time period info.
        # (And for now, nothing else)
        self.assertEqual(
            grib_wrapper._referenceDateTime,
            datetime.datetime(year=2007, month=3, day=23,
                              hour=12, minute=0, second=0)
        )
        self.assertEqual(
            grib_wrapper._periodStartDateTime,
            datetime.datetime(year=2007, month=3, day=23,
                              hour=22, minute=0, second=0)
        )
        self.assertEqual(grib_wrapper._periodEndDateTime, exp_end_date)
Beispiel #24
0
def grid_definition_template_1(cube, grib):
    """
    Set keys within the provided grib message based on
    Grid Definition Template 3.1.

    Template 3.1 is used to represent "rotated latitude/longitude (or
    equidistant cylindrical, or Plate Carree)".
    The coordinates are regularly spaced, rotated latitudes and longitudes.

    """
    # Constant resolution, aka 'regular' rotated lat-lon grid.
    gribapi.grib_set_long(grib, "gridDefinitionTemplateNumber", 1)

    # Record details of the rotated coordinate system.
    rotated_pole(cube, grib)

    # Encode the lat/lon points.
    horizontal_grid_common(cube, grib)
    latlon_points_regular(cube, grib)
Beispiel #25
0
def grid_definition_template_1(cube, grib):
    """
    Set keys within the provided grib message based on
    Grid Definition Template 3.1.

    Template 3.1 is used to represent "rotated latitude/longitude (or
    equidistant cylindrical, or Plate Carree)".
    The coordinates are regularly spaced, rotated latitudes and longitudes.

    """
    # Constant resolution, aka 'regular' rotated lat-lon grid.
    gribapi.grib_set_long(grib, "gridDefinitionTemplateNumber", 1)

    # Record details of the rotated coordinate system.
    rotated_pole(cube, grib)

    # Encode the lat/lon points.
    horizontal_grid_common(cube, grib)
    latlon_points_regular(cube, grib)
Beispiel #26
0
def product_template(cube, grib):
    # This will become more complex if we cover more templates, such as 4.15

    # forecast (template 4.0)
    if not cube.coord("time").has_bounds():
        gribapi.grib_set_long(grib, "productDefinitionTemplateNumber", 0)
        product_common(cube, grib)
        return

    # time processed (template 4.8)
    if _cube_is_time_statistic(cube):
        gribapi.grib_set_long(grib, "productDefinitionTemplateNumber", 8)
        product_common(cube, grib)
        time_processing_period(cube, grib)
        return

    # Don't know how to handle this kind of data
    raise iris.exceptions.TranslationError(
        'A suitable product template could not be deduced')
Beispiel #27
0
def type_of_statistical_processing(cube, grib, coord):
    """Search for processing over the given coord."""
    stat_code = 255  # (grib code table 4.10)

    # if the last cell method applies only to the given coord...
    cell_method = cube.cell_methods[-1]
    coord_names = cell_method.coord_names
    if len(coord_names) == 1 and coord_names[0] == coord.name():
        stat_codes = {
            'mean': 0,
            'sum': 1,
            'maximum': 2,
            'minimum': 3,
            'standard_deviation': 6
        }
        stat_code = stat_codes[cell_method.method]
    if stat_code == 255:
        warnings.warn("Unable to determine type of statistical processing")
    gribapi.grib_set_long(grib, "typeOfStatisticalProcessing", stat_code)
Beispiel #28
0
def product_template(cube, grib):
    # This will become more complex if we cover more templates, such as 4.15

    # forecast (template 4.0)
    if not cube.coord("time").has_bounds():
        gribapi.grib_set_long(grib, "productDefinitionTemplateNumber", 0)
        product_common(cube, grib)
        return

    # time processed (template 4.8)
    if _cube_is_time_statistic(cube):
        gribapi.grib_set_long(grib, "productDefinitionTemplateNumber", 8)
        product_common(cube, grib)
        time_processing_period(cube, grib)
        return

    # Don't know how to handle this kind of data
    raise iris.exceptions.TranslationError(
        'A suitable product template could not be deduced')
Beispiel #29
0
    def test_load_probability_forecast(self):
        # Test GribWrapper interpretation of PDT 4.9 data.
        # NOTE: 
        #   Currently Iris has only partial support for PDT 4.9.
        #   Though it can load the data, key metadata (thresholds) is lost.
        #   At present, we are not testing for this.

        # Make a testing grib message in memory, with gribapi.
        grib_message = gribapi.grib_new_from_samples('GRIB2')
        gribapi.grib_set_long(grib_message, 'productDefinitionTemplateNumber', 9)
        gribapi.grib_set_string(grib_message, 'stepRange', '10-55')
        grib_wrapper = iris.fileformats.grib.GribWrapper(grib_message)
        
        # Check that it captures the statistics time period info.
        # (And for now, nothing else)
        self.assertEqual(
            grib_wrapper._referenceDateTime,
            datetime.datetime(year=2007, month=03, day=23, 
                              hour=12, minute=0, second=0)
        )
    def test_warn_unknown_pdts(self):
        # Test loading of an unrecognised GRIB Product Definition Template.

        # Get a temporary file by name (deleted afterward by context).
        with self.temp_filename() as temp_gribfile_path:
            # Write a test grib message to the temporary file.
            with open(temp_gribfile_path, 'wb') as temp_gribfile:
                grib_message = gribapi.grib_new_from_samples('GRIB2')
                # Set the PDT to something unexpected.
                gribapi.grib_set_long(
                    grib_message, 'productDefinitionTemplateNumber', 5)
                gribapi.grib_write(grib_message, temp_gribfile)

            # Load the message from the file as a cube.
            cube_generator = iris.fileformats.grib.load_cubes(
                temp_gribfile_path)
            with self.assertRaises(iris.exceptions.TranslationError) as te:
                cube = next(cube_generator)
                self.assertEqual('Product definition template [5]'
                                 ' is not supported', str(te.exception))
    def test_warn_unknown_pdts(self):
        # Test loading of an unrecognised GRIB Product Definition Template.

        # Get a temporary file by name (deleted afterward by context).
        with self.temp_filename() as temp_gribfile_path:
            # Write a test grib message to the temporary file.
            with open(temp_gribfile_path, 'wb') as temp_gribfile:
                grib_message = gribapi.grib_new_from_samples('GRIB2')
                # Set the PDT to something unexpected.
                gribapi.grib_set_long(grib_message,
                                      'productDefinitionTemplateNumber', 5)
                gribapi.grib_write(grib_message, temp_gribfile)

            # Load the message from the file as a cube.
            cube_generator = iris_grib.load_cubes(temp_gribfile_path)
            with self.assertRaises(iris.exceptions.TranslationError) as te:
                cube = next(cube_generator)
            self.assertEqual(
                'Product definition template [5]'
                ' is not supported', str(te.exception))
Beispiel #32
0
    def test_load_probability_forecast(self):
        # Test GribWrapper interpretation of PDT 4.9 data.
        # NOTE:
        #   Currently Iris has only partial support for PDT 4.9.
        #   Though it can load the data, key metadata (thresholds) is lost.
        #   At present, we are not testing for this.

        # Make a testing grib message in memory, with gribapi.
        grib_message = gribapi.grib_new_from_samples('GRIB2')
        gribapi.grib_set_long(grib_message, 'productDefinitionTemplateNumber',
                              9)
        gribapi.grib_set_string(grib_message, 'stepRange', '10-55')
        grib_wrapper = iris.fileformats.grib.GribWrapper(grib_message)

        # Check that it captures the statistics time period info.
        # (And for now, nothing else)
        self.assertEqual(
            grib_wrapper._referenceDateTime,
            datetime.datetime(year=2007, month=03, day=23,
                              hour=12, minute=0, second=0)
        )
Beispiel #33
0
    def _regularise_shape(grib_message):
        """
        Calculate the regularised shape of the reduced message and push
        dummy regularised values into the message to force the gribapi
        to update the message grid type from reduced to regular.

        """
        # Make sure to read any missing values as NaN.
        gribapi.grib_set_double(grib_message, "missingValue", np.nan)

        # Get full longitude values, these describe the longitude value of
        # *every* point in the grid, they are not 1d monotonic coordinates.
        lons = gribapi.grib_get_double_array(grib_message, "longitudes")

        # Compute the new longitude coordinate for the regular grid.
        new_nx = max(gribapi.grib_get_long_array(grib_message, "pl"))
        new_x_step = (max(lons) - min(lons)) / (new_nx - 1)
        if gribapi.grib_get_long(grib_message, "iScansNegatively"):
            new_x_step *= -1

        gribapi.grib_set_long(grib_message, "Nx", int(new_nx))
        gribapi.grib_set_double(grib_message, "iDirectionIncrementInDegrees",
                                float(new_x_step))
        # Spoof gribapi with false regularised values.
        nj = gribapi.grib_get_long(grib_message, 'Nj')
        temp = np.zeros((nj * new_nx,), dtype=np.float)
        gribapi.grib_set_double_array(grib_message, 'values', temp)
        gribapi.grib_set_long(grib_message, "jPointsAreConsecutive", 0)
        gribapi.grib_set_long(grib_message, "PLPresent", 0)
Beispiel #34
0
    def _regularise_shape(grib_message):
        """
        Calculate the regularised shape of the reduced message and push
        dummy regularised values into the message to force the gribapi
        to update the message grid type from reduced to regular.

        """
        # Make sure to read any missing values as NaN.
        gribapi.grib_set_double(grib_message, "missingValue", np.nan)

        # Get full longitude values, these describe the longitude value of
        # *every* point in the grid, they are not 1d monotonic coordinates.
        lons = gribapi.grib_get_double_array(grib_message, "longitudes")

        # Compute the new longitude coordinate for the regular grid.
        new_nx = max(gribapi.grib_get_long_array(grib_message, "pl"))
        new_x_step = (max(lons) - min(lons)) / (new_nx - 1)
        if gribapi.grib_get_long(grib_message, "iScansNegatively"):
            new_x_step *= -1

        gribapi.grib_set_long(grib_message, "Nx", int(new_nx))
        gribapi.grib_set_double(grib_message, "iDirectionIncrementInDegrees",
                                float(new_x_step))
        # Spoof gribapi with false regularised values.
        nj = gribapi.grib_get_long(grib_message, 'Nj')
        temp = np.zeros((nj * new_nx,), dtype=np.float)
        gribapi.grib_set_double_array(grib_message, 'values', temp)
        gribapi.grib_set_long(grib_message, "jPointsAreConsecutive", 0)
        gribapi.grib_set_long(grib_message, "PLPresent", 0)
    def test_warn_unknown_pdts(self):
        # Test loading of an unrecognised GRIB Product Definition Template.

        # Get a temporary file by name (deleted afterward by context).
        with self.temp_filename() as temp_gribfile_path:
            # Write a test grib message to the temporary file.
            with open(temp_gribfile_path, 'wb') as temp_gribfile:
                grib_message = gribapi.grib_new_from_samples('GRIB2')
                # Set the PDT to something unexpected.
                gribapi.grib_set_long(grib_message,
                                      'productDefinitionTemplateNumber', 5)
                gribapi.grib_write(grib_message, temp_gribfile)

            # Load the message from the file as a cube.
            cube_generator = iris.fileformats.grib.load_cubes(
                temp_gribfile_path)
            cube = next(cube_generator)

            # Check the cube has an extra "warning" attribute.
            self.assertEqual(
                cube.attributes['GRIB_LOAD_WARNING'],
                'unsupported GRIB2 ProductDefinitionTemplate: #4.5')
Beispiel #36
0
def latlon_first_last(x_coord, y_coord, grib):
    
    if x_coord.has_bounds() or y_coord.has_bounds():
        warnings.warn("Ignoring xy bounds")

# XXX Pending #1125
#    gribapi.grib_set_double(grib, "latitudeOfFirstGridPointInDegrees", float(y_coord.points[0]))
#    gribapi.grib_set_double(grib, "latitudeOfLastGridPointInDegrees", float(y_coord.points[-1]))
#    gribapi.grib_set_double(grib, "longitudeOfFirstGridPointInDegrees", float(x_coord.points[0]))
#    gribapi.grib_set_double(grib, "longitudeOfLastGridPointInDegrees", float(x_coord.points[-1]))
# WORKAROUND
    gribapi.grib_set_long(grib, "latitudeOfFirstGridPoint", int(y_coord.points[0]*1000000))
    gribapi.grib_set_long(grib, "latitudeOfLastGridPoint", int(y_coord.points[-1]*1000000))
    gribapi.grib_set_long(grib, "longitudeOfFirstGridPoint", int((x_coord.points[0]%360)*1000000))
    gribapi.grib_set_long(grib, "longitudeOfLastGridPoint", int((x_coord.points[-1]%360)*1000000))
Beispiel #37
0
def time_range(cube, grib):
    """Grib encoding of forecast_period.""" 
    
    fp_coord = cube.coord("forecast_period")
    if fp_coord.has_bounds():
        raise iris.exceptions.TranslationError("Bounds not expected for 'forecast_period'")
    
    if fp_coord.units == iris.unit.Unit("hours"):
        grib_time_code = 1
    elif fp_coord.units == iris.unit.Unit("minutes"):
        grib_time_code = 0
    elif fp_coord.units == iris.unit.Unit("seconds"):
        grib_time_code = 13
    else:
        raise iris.exceptions.TranslationError("Unexpected units for 'forecast_period' : %s" % fp_coord.units)
    
    fp = fp_coord.points[0]
    if fp - int(fp):
        warnings.warn("forecast_period encoding problem : Scaling required.")
    fp = int(fp)
    
    gribapi.grib_set_long(grib, "indicatorOfUnitOfTimeRange", grib_time_code)
    gribapi.grib_set_long(grib, "forecastTime", fp)
Beispiel #38
0
def type_of_statistical_processing(cube, grib, coord):
    """Search for processing over the given coord."""
    
    stat_code = 255  # (grib code table 4.10)
    
    # if the last cell method applies only to the given coord...
    cell_method = cube.cell_methods[-1]
    if len(cell_method.coord_names) == 1 and cell_method.coord_names[0] == coord.name():
        if cell_method.method == 'mean':
            stat_code = 0
        elif cell_method.method == 'accumulation':
            stat_code = 1
        elif cell_method.method == 'minimum':
            stat_code = 2
        elif cell_method.method == 'maximum':
            stat_code = 3
        elif cell_method.method == 'standard_deviation':
            stat_code = 6

    if stat_code == 255:    
        warnings.warn("Unable to determine type of statistical processing")
        
    gribapi.grib_set_long(grib, "typeOfStatisticalProcessing", stat_code)  
Beispiel #39
0
    def test_warn_unknown_pdts(self):
        # Test loading of an unrecognised GRIB Product Definition Template.

        # Get a temporary file by name (deleted afterward by context).
        with self.temp_filename() as temp_gribfile_path:
            # Write a test grib message to the temporary file.
            with open(temp_gribfile_path, 'wb') as temp_gribfile:
                grib_message = gribapi.grib_new_from_samples('GRIB2')
                # Set the PDT to something unexpected.
                gribapi.grib_set_long(
                    grib_message, 'productDefinitionTemplateNumber', 5)
                gribapi.grib_write(grib_message, temp_gribfile)

            # Load the message from the file as a cube.
            cube_generator = iris.fileformats.grib.load_cubes(
                temp_gribfile_path)
            cube = cube_generator.next()

            # Check the cube has an extra "warning" attribute.
            self.assertEqual(
                cube.attributes['GRIB_LOAD_WARNING'],
                'unsupported GRIB2 ProductDefinitionTemplate: #4.5'
            )
Beispiel #40
0
def type_of_statistical_processing(cube, grib, coord):
    """Search for processing over the given coord."""
    # if the last cell method applies only to the given coord...
    cell_method = cube.cell_methods[-1]
    coord_names = cell_method.coord_names
    if len(coord_names) != 1:
        raise ValueError('There are multiple coord names referenced by '
                         'the primary cell method: {!r}. Multiple coordinate '
                         'names are not supported.'.format(coord_names))
    if coord_names[0] != coord.name():
        raise ValueError('The coord name referenced by the primary cell method'
                         ', {!r},  is not the expected coord name {!r}.'
                         ''.format(coord_names[0], coord.name()))
    stat_codes = {
        'mean': 0,
        'sum': 1,
        'maximum': 2,
        'minimum': 3,
        'standard_deviation': 6
    }
    # 255 is the code in template 4.8 for 'unknown' statistical method
    stat_code = stat_codes.get(cell_method.method, 255)
    gribapi.grib_set_long(grib, "typeOfStatisticalProcessing", stat_code)
Beispiel #41
0
def set_product(source, grib):
    """
    Sets the 'inidcatorOfParameter', 'table2Version', 'indicatorOfTypeOfLevel'
    and 'level' parameters in a grib message by inferring their values from
    the only non-coordinate in source.
    """
    var_name = get_varible_name(source)
    grib_var_name = conv.to_grib1[var_name]
    gribapi.grib_set_long(grib, 'indicatorOfParameter',
                          reverse_codes[grib_var_name])
    gribapi.grib_set_long(grib, 'table2Version', 2)

    gribapi.grib_set_long(grib, 'indicatorOfTypeOfLevel',
                          indicator_of_level[grib_var_name])
    gribapi.grib_set_long(grib, 'level',
                          level[grib_var_name])
Beispiel #42
0
def set_time(source, grib):
    """
    Sets the dataDate, dataTime, unitOfTimeRange, P2, timeRangeIndicator,
    parameters in the grib message 'grib' using the time variable in source.
    """
    if source['time'].size != 1:
        raise ValueError("expected a single time step")
    # analysis, forecast start, verify time, obs time,
    # (start of forecast for now)
    unit = source['time'].attrs['units']
    # reference time is assumed to be the origin of the source
    # time variable.  This is the case with GFS but perhaps
    # not with other forecasts.
    rt = conv.decode_cf_datetime([0], unit)[0]
    gribapi.grib_set_long(grib, "dataDate", "%04d%02d%02d" % (rt.year,
                                                              rt.month,
                                                              rt.day))
    gribapi.grib_set_long(grib, "dataTime", "%02d%02d" % (rt.hour, rt.minute))
    # taken from ECMWF grib tables
    unit_codes = {'minute': 0,
             'hour': 1,
             'day': 2,
             'month': 3,
             'year': 4,
             'second': 254}
    grib_time_code = None
    for k, v in unit_codes.iteritems():
        if unit.lower().startswith(k):
            grib_time_code = v
    if grib_time_code is None:
        raise ValueError("Unexpected unit")
    gribapi.grib_set_long(grib, 'unitOfTimeRange', 1)
    vt = np.asscalar(source['time'].values)
    assert int(vt) == vt
    gribapi.grib_set_long(grib, 'P2', vt)
    # forecast is valid at reference + P2
    gribapi.grib_set_long(grib, "timeRangeIndicator", 10)
Beispiel #43
0
def product_template(cube, grib):
    # This will become more complex if we cover more templates, such as 4.15

    # forecast (template 4.0)
    if not cube.coord("time").has_bounds():
        gribapi.grib_set_long(grib, "productDefinitionTemplateNumber", 0)
        product_common(cube, grib)
        return

    # time processed (template 4.8)
    if _cube_is_time_statistic(cube):
        gribapi.grib_set_long(grib, "productDefinitionTemplateNumber", 8)
        product_common(cube, grib)
        try:
            time_processing_period(cube, grib)
        except ValueError as e:
            raise ValueError('Saving to GRIB2 failed: the cube is not suitable'
                             ' for saving as a time processed statistic GRIB'
                             ' message. {}'.format(e))
        return

    # Don't know how to handle this kind of data
    raise iris.exceptions.TranslationError(
        'A suitable product template could not be deduced')
Beispiel #44
0
def product_template(cube, grib):
    # This will become more complex if we cover more templates, such as 4.15

    # forecast (template 4.0)
    if not cube.coord("time").has_bounds():
        gribapi.grib_set_long(grib, "productDefinitionTemplateNumber", 0)
        product_common(cube, grib)
        return

    # time processed (template 4.8)
    if _cube_is_time_statistic(cube):
        gribapi.grib_set_long(grib, "productDefinitionTemplateNumber", 8)
        product_common(cube, grib)
        try:
            time_processing_period(cube, grib)
        except ValueError as e:
            raise ValueError('Saving to GRIB2 failed: the cube is not suitable'
                             ' for saving as a time processed statistic GRIB'
                             ' message. {}'.format(e))
        return

    # Don't know how to handle this kind of data
    raise iris.exceptions.TranslationError(
        'A suitable product template could not be deduced')
Beispiel #45
0
def identification(cube, grib):
    centre(cube, grib)
    reference_time(cube, grib)

    # operational product, operational test, research product, etc
    # (missing for now)
    gribapi.grib_set_long(grib, "productionStatusOfProcessedData", 255)

    # Code table 1.4
    # analysis, forecast, processed satellite, processed radar,
    if cube.coords('realization'):
        # assume realization will always have 1 and only 1 point
        # as cubes saving to GRIB2 a 2D horizontal slices
        if cube.coord('realization').points[0] != 0:
            gribapi.grib_set_long(grib, "typeOfProcessedData", 4)
        else:
            gribapi.grib_set_long(grib, "typeOfProcessedData", 3)
    else:
        gribapi.grib_set_long(grib, "typeOfProcessedData", 2)
Beispiel #46
0
def rotated_pole(cube, grib):

    cs = cube.coord(dimensions=[0]).coord_system

# XXX Pending #1125
#    gribapi.grib_set_double(grib, "latitudeOfSouthernPoleInDegrees", float(cs.n_pole.latitude))
#    gribapi.grib_set_double(grib, "longitudeOfSouthernPoleInDegrees", float(cs.n_pole.longitude))
#    gribapi.grib_set_double(grib, "angleOfRotationInDegrees", 0)
# WORKAROUND
    gribapi.grib_set_long(grib, "latitudeOfSouthernPole", -int(cs.grid_north_pole_latitude*1000000))
    gribapi.grib_set_long(grib, "longitudeOfSouthernPole", int(((cs.grid_north_pole_longitude+180)%360)*1000000))
    gribapi.grib_set_long(grib, "angleOfRotation", 0)
Beispiel #47
0
def identification(cube, grib):
    centre(cube, grib)
    reference_time(cube, grib)

    # operational product, operational test, research product, etc
    # (missing for now)
    gribapi.grib_set_long(grib, "productionStatusOfProcessedData", 255)

    # Code table 1.4
    # analysis, forecast, processed satellite, processed radar,
    if cube.coords('realization'):
        # assume realization will always have 1 and only 1 point
        # as cubes saving to GRIB2 a 2D horizontal slices
        if cube.coord('realization').points[0] != 0:
            gribapi.grib_set_long(grib, "typeOfProcessedData", 4)
        else:
            gribapi.grib_set_long(grib, "typeOfProcessedData", 3)
    else:
        gribapi.grib_set_long(grib, "typeOfProcessedData", 2)
Beispiel #48
0
def identification(cube, grib):
    centre(cube, grib)
    reference_time(cube, grib)

    # operational product, operational test, research product, etc table 1.3
    # http://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_table1-3.shtml   
    gribapi.grib_set_long(grib, "productionStatusOfProcessedData", 0) # required 0 for NCMRWF
    # set it as operational product

    # Code table 1.4
    # analysis, forecast, processed satellite, processed radar,
    if cube.coords('realization'):
        # assume realization will always have 1 and only 1 point
        # as cubes saving to GRIB2 a 2D horizontal slices
        if cube.coord('realization').points[0] != 0:
            gribapi.grib_set_long(grib, "typeOfProcessedData", 4)
        else:
            gribapi.grib_set_long(grib, "typeOfProcessedData", 3)
    else:
        gribapi.grib_set_long(grib, "typeOfProcessedData", 2)
Beispiel #49
0
def identification(cube, grib):
    centre(cube, grib)
    reference_time(cube, grib)

    # operational product, operational test, research product, etc table 1.3
    # http://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_table1-3.shtml
    gribapi.grib_set_long(grib, "productionStatusOfProcessedData",
                          0)  # required 0 for NCMRWF
    # set it as operational product

    # Code table 1.4
    # analysis, forecast, processed satellite, processed radar,
    if cube.coords('realization'):
        # assume realization will always have 1 and only 1 point
        # as cubes saving to GRIB2 a 2D horizontal slices
        if cube.coord('realization').points[0] != 0:
            gribapi.grib_set_long(grib, "typeOfProcessedData", 4)
        else:
            gribapi.grib_set_long(grib, "typeOfProcessedData", 3)
    else:
        gribapi.grib_set_long(grib, "typeOfProcessedData", 2)
Beispiel #50
0
def reference_time(cube, grib):

    # analysis, forecast start, verify time, obs time, (start of forecast for now)
    gribapi.grib_set_long(grib, "significanceOfReferenceTime", 1)
      
    # calculate reference time
    pt_coord = cube.coord("time")
    pt = pt_coord.bounds[0,0] if pt_coord.has_bounds() else pt_coord.points[0]  # always in hours
    ft = cube.coord("forecast_period").points[0]   # always in hours
    rt = pt - ft
    rt = iris.unit.num2date(rt, pt_coord.units.name, pt_coord.units.calendar)
    
    gribapi.grib_set_long(grib, "dataDate", "%04d%02d%02d" % (rt.year, rt.month, rt.day))
    gribapi.grib_set_long(grib, "dataTime", "%02d%02d" % (rt.hour, rt.minute))
Beispiel #51
0
def reference_time(cube, grib):
    # Set the reference time.
    # (analysis, forecast start, verify time, obs time, etc)
    try:
        fp_coord = cube.coord("forecast_period")
    except iris.exceptions.CoordinateNotFoundError:
        fp_coord = None

    if fp_coord is not None:
        rt, rt_meaning, _, _ = _non_missing_forecast_period(cube)
    else:
        rt, rt_meaning, _, _ = _missing_forecast_period(cube)

    gribapi.grib_set_long(grib, "significanceOfReferenceTime", rt_meaning)
    gribapi.grib_set_long(grib, "dataDate",
                          "%04d%02d%02d" % (rt.year, rt.month, rt.day))
    gribapi.grib_set_long(grib, "dataTime", "%02d%02d" % (rt.hour, rt.minute))
Beispiel #52
0
def centre(cube, grib):
    # TODO: read centre from cube
    #gribapi.grib_set_long(grib, "centre", 74)  # UKMO
    gribapi.grib_set_long(grib, "centre", 29)  # required for NCMRWF
    gribapi.grib_set_long(grib, "subCentre", 0)  # exeter is not in the spec
Beispiel #53
0
def centre(cube, grib):
    # TODO: read centre from cube
    gribapi.grib_set_long(grib, "centre", 74)  # UKMO
    gribapi.grib_set_long(grib, "subCentre", 0)  # exeter is not in the spec
Beispiel #54
0
def shape_of_the_earth(cube, grib):

    # assume latlon
    cs = cube.coord(dimensions=[0]).coord_system

    # Turn them all missing to start with (255 for byte, -1 for long)
    gribapi.grib_set_long(grib, "scaleFactorOfRadiusOfSphericalEarth", 255)
    gribapi.grib_set_long(grib, "scaledValueOfRadiusOfSphericalEarth", -1)
    gribapi.grib_set_long(grib, "scaleFactorOfEarthMajorAxis", 255)
    gribapi.grib_set_long(grib, "scaledValueOfEarthMajorAxis", -1)
    gribapi.grib_set_long(grib, "scaleFactorOfEarthMinorAxis", 255)
    gribapi.grib_set_long(grib, "scaledValueOfEarthMinorAxis", -1)

    ellipsoid = cs
    if isinstance(cs, iris.coord_systems.RotatedGeogCS):
        ellipsoid = cs.ellipsoid

    if ellipsoid.inverse_flattening == 0.0:
        gribapi.grib_set_long(grib, "shapeOfTheEarth", 1)
        gribapi.grib_set_long(grib, "scaleFactorOfRadiusOfSphericalEarth", 0)
        gribapi.grib_set_long(grib, "scaledValueOfRadiusOfSphericalEarth",
                              ellipsoid.semi_major_axis)
    else:
        gribapi.grib_set_long(grib, "shapeOfTheEarth", 7)
        gribapi.grib_set_long(grib, "scaleFactorOfEarthMajorAxis", 0)
        gribapi.grib_set_long(grib, "scaledValueOfEarthMajorAxis",
                              ellipsoid.semi_major_axis)
        gribapi.grib_set_long(grib, "scaleFactorOfEarthMinorAxis", 0)
        gribapi.grib_set_long(grib, "scaledValueOfEarthMinorAxis",
                              ellipsoid.semi_minor_axis)
Beispiel #55
0
def scanning_mode_flags(x_coord, y_coord, grib):
    gribapi.grib_set_long(grib, "iScansPositively",
                          int(x_coord.points[1] - x_coord.points[0] > 0))
    gribapi.grib_set_long(grib, "jScansPositively",
                          int(y_coord.points[1] - y_coord.points[0] > 0))
Beispiel #56
0
def grid_dims(x_coord, y_coord, grib):
    gribapi.grib_set_long(grib, "Ni", x_coord.shape[0])
    gribapi.grib_set_long(grib, "Nj", y_coord.shape[0])
Beispiel #57
0
def shape_of_the_earth(cube, grib):
    # assume latlon
    cs = cube.coord(dimensions=[0]).coord_system

    # Initially set shape_of_earth keys to missing (255 for byte, -1 for long).
    gribapi.grib_set_long(grib, "scaleFactorOfRadiusOfSphericalEarth", 255)
    gribapi.grib_set_long(grib, "scaledValueOfRadiusOfSphericalEarth", -1)
    gribapi.grib_set_long(grib, "scaleFactorOfEarthMajorAxis", 255)
    gribapi.grib_set_long(grib, "scaledValueOfEarthMajorAxis", -1)
    gribapi.grib_set_long(grib, "scaleFactorOfEarthMinorAxis", 255)
    gribapi.grib_set_long(grib, "scaledValueOfEarthMinorAxis", -1)

    if isinstance(cs, GeogCS):
        ellipsoid = cs
    else:
        ellipsoid = cs.ellipsoid
        if ellipsoid is None:
            msg = "Could not determine shape of the earth from coord system "\
                  "of horizontal grid."
            raise iris.exceptions.TranslationError(msg)

    # Spherical earth.
    if ellipsoid.inverse_flattening == 0.0:
        gribapi.grib_set_long(grib, "shapeOfTheEarth", 1)
        gribapi.grib_set_long(grib, "scaleFactorOfRadiusOfSphericalEarth", 0)
        gribapi.grib_set_long(grib, "scaledValueOfRadiusOfSphericalEarth",
                              ellipsoid.semi_major_axis)
    # Oblate spheroid earth.
    else:
        gribapi.grib_set_long(grib, "shapeOfTheEarth", 7)
        gribapi.grib_set_long(grib, "scaleFactorOfEarthMajorAxis", 0)
        gribapi.grib_set_long(grib, "scaledValueOfEarthMajorAxis",
                              ellipsoid.semi_major_axis)
        gribapi.grib_set_long(grib, "scaleFactorOfEarthMinorAxis", 0)
        gribapi.grib_set_long(grib, "scaledValueOfEarthMinorAxis",
                              ellipsoid.semi_minor_axis)