Пример #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)
Пример #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)
Пример #3
0
def generating_process_type(cube, grib):
    # analysis = 0
    # initialisation = 1
    # forecast = 2
    # more...

    # missing
    gribapi.grib_set_long(grib, "typeOfGeneratingProcess", 255)
Пример #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)
Пример #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)
Пример #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)
Пример #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)
Пример #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)
Пример #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())
Пример #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())
Пример #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)
Пример #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)
Пример #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)
Пример #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)
Пример #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)
Пример #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)
Пример #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)
Пример #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")
Пример #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))
Пример #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)
Пример #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)
Пример #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)
Пример #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)
Пример #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)
Пример #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')
Пример #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)
Пример #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')
Пример #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)
        )
Пример #30
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))
Пример #31
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_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))
Пример #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)
        )
Пример #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)
Пример #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)
Пример #35
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')
Пример #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))
Пример #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)
Пример #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)  
Пример #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'
            )
Пример #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)
Пример #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])
Пример #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)
Пример #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')
Пример #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')
Пример #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)
Пример #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)
Пример #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)
Пример #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)
Пример #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)
Пример #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))
Пример #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))
Пример #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
Пример #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
Пример #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)
Пример #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))
Пример #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])
Пример #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)