grib2io.utils

Collection of utility functions to assist in the encoding and decoding of GRIB2 Messages.

  1"""
  2Collection of utility functions to assist in the encoding and decoding
  3of GRIB2 Messages.
  4"""
  5
  6import datetime
  7import struct
  8from typing import Union, Type, Dict, List
  9
 10import numpy as np
 11from numpy.typing import ArrayLike
 12
 13from .. import tables
 14from .. import templates
 15
 16def int2bin(i: int, nbits: int=8, output: Union[Type[str], Type[List]]=str):
 17    """
 18    Convert integer to binary string or list
 19
 20    The struct module unpack using ">i" will unpack a 32-bit integer from a
 21    binary string.
 22
 23    Parameters
 24    ----------
 25    i
 26        Integer value to convert to binary representation.
 27    nbits : default=8
 28        Number of bits to return.  Valid values are 8 [DEFAULT], 16, 32, and
 29        64.
 30    output : default=str
 31        Return data as `str` [DEFAULT] or `list` (list of ints).
 32
 33    Returns
 34    -------
 35    int2bin
 36        `str` or `list` (list of ints) of binary representation of the integer
 37        value.
 38    """
 39    i = int(i) if not isinstance(i,int) else i
 40    assert nbits in [8,16,32,64]
 41    bitstr = "{0:b}".format(i).zfill(nbits)
 42    if output is str:
 43        return bitstr
 44    elif output is list:
 45        return [int(b) for b in bitstr]
 46
 47
 48def ieee_float_to_int(f):
 49    """
 50    Convert an IEEE 754 32-bit float to a 32-bit integer.
 51
 52    Parameters
 53    ----------
 54    f : float
 55        Floating-point value.
 56
 57    Returns
 58    -------
 59    ieee_float_to_int
 60        `numpy.int32` representation of an IEEE 32-bit float.
 61    """
 62    i = struct.unpack('>i',struct.pack('>f',np.float32(f)))[0]
 63    return np.int32(i)
 64
 65
 66def ieee_int_to_float(i):
 67    """
 68    Convert a 32-bit integer to an IEEE 32-bit float.
 69
 70    Parameters
 71    ----------
 72    i : int
 73        Integer value.
 74
 75    Returns
 76    -------
 77    ieee_int_to_float
 78        `numpy.float32` representation of a 32-bit int.
 79    """
 80    f = struct.unpack('>f',struct.pack('>i',np.int32(i)))[0]
 81    return np.float32(f)
 82
 83
 84def get_leadtime(pdtn: int, pdt: ArrayLike) -> datetime.timedelta:
 85    """
 86    Compute lead time as a datetime.timedelta object.
 87
 88    Using information from GRIB2 Product Definition Template
 89    Number, and Product Definition Template (Section 4).
 90
 91    Parameters
 92    ----------
 93    pdtn
 94        GRIB2 Product Definition Template Number
 95    pdt
 96        Sequence containing GRIB2 Product Definition Template (Section 4).
 97
 98    Returns
 99    -------
100    leadTime
101        datetime.timedelta object representing the lead time of the GRIB2 message.
102    """
103    lt = tables.get_value_from_table(pdt[templates.UnitOfForecastTime._key[pdtn]], 'scale_time_seconds')
104    lt *= pdt[templates.ValueOfForecastTime._key[pdtn]]
105    return datetime.timedelta(seconds=int(lt))
106
107
108def get_duration(pdtn: int, pdt: ArrayLike) -> datetime.timedelta:
109    """
110    Compute a time duration as a datetime.timedelta.
111
112    Uses information from Product Definition Template Number, and Product
113    Definition Template (Section 4).
114
115    Parameters
116    ----------
117    pdtn
118        GRIB2 Product Definition Template Number
119    pdt
120        Sequence containing GRIB2 Product Definition Template (Section 4).
121
122    Returns
123    -------
124    get_duration
125        datetime.timedelta object representing the time duration of the GRIB2
126        message.
127    """
128    if pdtn in templates._timeinterval_pdtns:
129        ntime = pdt[templates.NumberOfTimeRanges._key[pdtn]]
130        duration_unit = tables.get_value_from_table(
131            pdt[templates.UnitOfTimeRangeOfStatisticalProcess._key[pdtn]],
132            'scale_time_seconds')
133        d = ntime * duration_unit * pdt[
134            templates.TimeRangeOfStatisticalProcess._key[pdtn]]
135    else:
136        d = 0
137    return datetime.timedelta(seconds=int(d))
138
139
140def decode_wx_strings(lus: bytes) -> Dict[int, str]:
141    """
142    Decode GRIB2 Local Use Section to obtain NDFD/MDL Weather Strings.
143
144    The decode procedure is defined
145    [here](https://vlab.noaa.gov/web/mdl/nbm-gmos-grib2-wx-info).
146
147    Parameters
148    ----------
149    lus
150        GRIB2 Local Use Section containing NDFD weather strings.
151
152    Returns
153    -------
154    decode_wx_strings
155        Dict of NDFD/MDL weather strings. Keys are an integer value that
156        represent the sequential order of the key in the packed local use
157        section and the value is the weather key.
158    """
159    assert lus[0] == 1
160    # Unpack information related to the simple packing method
161    # the packed weather string data.
162    ngroups = struct.unpack('>H',lus[1:3])[0]
163    nvalues = struct.unpack('>i',lus[3:7])[0]
164    refvalue = struct.unpack('>i',lus[7:11])[0]
165    dsf = struct.unpack('>h',lus[11:13])[0]
166    nbits = lus[13]
167    datatype = lus[14]
168    if datatype == 0: # Floating point
169        refvalue = np.float32(ieee_int_to_float(refvalue)*10**-dsf)
170    elif datatype == 1: # Integer
171        refvalue = np.int32(ieee_int_to_float(refvalue)*10**-dsf)
172    # Upack each byte starting at byte 15 to end of the local use
173    # section, create a binary string and append to the full
174    # binary string.
175    b = ''
176    for i in range(15,len(lus)):
177        iword = struct.unpack('>B',lus[i:i+1])[0]
178        b += bin(iword).split('b')[1].zfill(8)
179    # Iterate over the binary string (b). For each nbits
180    # chunk, convert to an integer, including the refvalue,
181    # and then convert the int to an ASCII character, then
182    # concatenate to wxstring.
183    wxstring = ''
184    for i in range(0,len(b),nbits):
185        wxstring += chr(int(b[i:i+nbits],2)+refvalue)
186    # Return string as list, split by null character.
187    #return list(filter(None,wxstring.split('\0')))
188    return {n:k for n,k in enumerate(list(filter(None,wxstring.split('\0'))))}
189
190
191def get_wgrib2_prob_string(
192    probtype: int,
193    sfacl: int,
194    svall: int,
195    sfacu: int,
196    svalu: int,
197) -> str:
198    """
199    Return a wgrib2-styled string of probabilistic threshold information.
200
201    Logic from wgrib2 source,
202    [Prob.c](https://github.com/NOAA-EMC/NCEPLIBS-wgrib2/blob/develop/wgrib2/Prob.c),
203    is replicated here.
204
205    Parameters
206    ----------
207    probtype
208        Type of probability (Code Table 4.9).
209    sfacl
210        Scale factor of lower limit.
211    svall
212        Scaled value of lower limit.
213    sfacu
214        Scale factor of upper limit.
215    svalu
216        Scaled value of upper limit.
217
218    Returns
219    -------
220    get_wgrib2_prob_string
221        wgrib2-formatted string of probability threshold.
222    """
223    probstr = ''
224    if sfacl == -127: sfacl = 0
225    if sfacu == -127: sfacu = 0
226    lower = svall/(10**sfacl)
227    upper = svalu/(10**sfacu)
228    if probtype == 0:
229        probstr = 'prob <%g' % (lower)
230    elif probtype == 1:
231        probstr = 'prob >%g' % (upper)
232    elif probtype == 2:
233        if lower == upper:
234            probstr = 'prob =%g' % (lower)
235        else:
236            probstr = 'prob >=%g <%g' % (lower,upper)
237    elif probtype == 3:
238        probstr = 'prob >%g' % (lower)
239    elif probtype == 4:
240        probstr = 'prob <%g' % (upper)
241    else:
242        probstr = ''
243    return probstr
def int2bin( i: int, nbits: int = 8, output: Union[Type[str], Type[List]] = <class 'str'>):
17def int2bin(i: int, nbits: int=8, output: Union[Type[str], Type[List]]=str):
18    """
19    Convert integer to binary string or list
20
21    The struct module unpack using ">i" will unpack a 32-bit integer from a
22    binary string.
23
24    Parameters
25    ----------
26    i
27        Integer value to convert to binary representation.
28    nbits : default=8
29        Number of bits to return.  Valid values are 8 [DEFAULT], 16, 32, and
30        64.
31    output : default=str
32        Return data as `str` [DEFAULT] or `list` (list of ints).
33
34    Returns
35    -------
36    int2bin
37        `str` or `list` (list of ints) of binary representation of the integer
38        value.
39    """
40    i = int(i) if not isinstance(i,int) else i
41    assert nbits in [8,16,32,64]
42    bitstr = "{0:b}".format(i).zfill(nbits)
43    if output is str:
44        return bitstr
45    elif output is list:
46        return [int(b) for b in bitstr]

Convert integer to binary string or list

The struct module unpack using ">i" will unpack a 32-bit integer from a binary string.

Parameters
  • i: Integer value to convert to binary representation.
  • nbits (default=8): Number of bits to return. Valid values are 8 [DEFAULT], 16, 32, and 64.
  • output (default=str): Return data as str [DEFAULT] or list (list of ints).
Returns
  • int2bin: str or list (list of ints) of binary representation of the integer value.
def ieee_float_to_int(f):
49def ieee_float_to_int(f):
50    """
51    Convert an IEEE 754 32-bit float to a 32-bit integer.
52
53    Parameters
54    ----------
55    f : float
56        Floating-point value.
57
58    Returns
59    -------
60    ieee_float_to_int
61        `numpy.int32` representation of an IEEE 32-bit float.
62    """
63    i = struct.unpack('>i',struct.pack('>f',np.float32(f)))[0]
64    return np.int32(i)

Convert an IEEE 754 32-bit float to a 32-bit integer.

Parameters
  • f (float): Floating-point value.
Returns
  • ieee_float_to_int: numpy.int32 representation of an IEEE 32-bit float.
def ieee_int_to_float(i):
67def ieee_int_to_float(i):
68    """
69    Convert a 32-bit integer to an IEEE 32-bit float.
70
71    Parameters
72    ----------
73    i : int
74        Integer value.
75
76    Returns
77    -------
78    ieee_int_to_float
79        `numpy.float32` representation of a 32-bit int.
80    """
81    f = struct.unpack('>f',struct.pack('>i',np.int32(i)))[0]
82    return np.float32(f)

Convert a 32-bit integer to an IEEE 32-bit float.

Parameters
  • i (int): Integer value.
Returns
  • ieee_int_to_float: numpy.float32 representation of a 32-bit int.
def get_leadtime( pdtn: int, pdt: Union[Buffer, numpy._typing._array_like._SupportsArray[numpy.dtype[Any]], numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]]], bool, int, float, complex, str, bytes, numpy._typing._nested_sequence._NestedSequence[bool | int | float | complex | str | bytes]]) -> datetime.timedelta:
 85def get_leadtime(pdtn: int, pdt: ArrayLike) -> datetime.timedelta:
 86    """
 87    Compute lead time as a datetime.timedelta object.
 88
 89    Using information from GRIB2 Product Definition Template
 90    Number, and Product Definition Template (Section 4).
 91
 92    Parameters
 93    ----------
 94    pdtn
 95        GRIB2 Product Definition Template Number
 96    pdt
 97        Sequence containing GRIB2 Product Definition Template (Section 4).
 98
 99    Returns
100    -------
101    leadTime
102        datetime.timedelta object representing the lead time of the GRIB2 message.
103    """
104    lt = tables.get_value_from_table(pdt[templates.UnitOfForecastTime._key[pdtn]], 'scale_time_seconds')
105    lt *= pdt[templates.ValueOfForecastTime._key[pdtn]]
106    return datetime.timedelta(seconds=int(lt))

Compute lead time as a datetime.timedelta object.

Using information from GRIB2 Product Definition Template Number, and Product Definition Template (Section 4).

Parameters
  • pdtn: GRIB2 Product Definition Template Number
  • pdt: Sequence containing GRIB2 Product Definition Template (Section 4).
Returns
  • leadTime: datetime.timedelta object representing the lead time of the GRIB2 message.
def get_duration( pdtn: int, pdt: Union[Buffer, numpy._typing._array_like._SupportsArray[numpy.dtype[Any]], numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]]], bool, int, float, complex, str, bytes, numpy._typing._nested_sequence._NestedSequence[bool | int | float | complex | str | bytes]]) -> datetime.timedelta:
109def get_duration(pdtn: int, pdt: ArrayLike) -> datetime.timedelta:
110    """
111    Compute a time duration as a datetime.timedelta.
112
113    Uses information from Product Definition Template Number, and Product
114    Definition Template (Section 4).
115
116    Parameters
117    ----------
118    pdtn
119        GRIB2 Product Definition Template Number
120    pdt
121        Sequence containing GRIB2 Product Definition Template (Section 4).
122
123    Returns
124    -------
125    get_duration
126        datetime.timedelta object representing the time duration of the GRIB2
127        message.
128    """
129    if pdtn in templates._timeinterval_pdtns:
130        ntime = pdt[templates.NumberOfTimeRanges._key[pdtn]]
131        duration_unit = tables.get_value_from_table(
132            pdt[templates.UnitOfTimeRangeOfStatisticalProcess._key[pdtn]],
133            'scale_time_seconds')
134        d = ntime * duration_unit * pdt[
135            templates.TimeRangeOfStatisticalProcess._key[pdtn]]
136    else:
137        d = 0
138    return datetime.timedelta(seconds=int(d))

Compute a time duration as a datetime.timedelta.

Uses information from Product Definition Template Number, and Product Definition Template (Section 4).

Parameters
  • pdtn: GRIB2 Product Definition Template Number
  • pdt: Sequence containing GRIB2 Product Definition Template (Section 4).
Returns
  • get_duration: datetime.timedelta object representing the time duration of the GRIB2 message.
def decode_wx_strings(lus: bytes) -> Dict[int, str]:
141def decode_wx_strings(lus: bytes) -> Dict[int, str]:
142    """
143    Decode GRIB2 Local Use Section to obtain NDFD/MDL Weather Strings.
144
145    The decode procedure is defined
146    [here](https://vlab.noaa.gov/web/mdl/nbm-gmos-grib2-wx-info).
147
148    Parameters
149    ----------
150    lus
151        GRIB2 Local Use Section containing NDFD weather strings.
152
153    Returns
154    -------
155    decode_wx_strings
156        Dict of NDFD/MDL weather strings. Keys are an integer value that
157        represent the sequential order of the key in the packed local use
158        section and the value is the weather key.
159    """
160    assert lus[0] == 1
161    # Unpack information related to the simple packing method
162    # the packed weather string data.
163    ngroups = struct.unpack('>H',lus[1:3])[0]
164    nvalues = struct.unpack('>i',lus[3:7])[0]
165    refvalue = struct.unpack('>i',lus[7:11])[0]
166    dsf = struct.unpack('>h',lus[11:13])[0]
167    nbits = lus[13]
168    datatype = lus[14]
169    if datatype == 0: # Floating point
170        refvalue = np.float32(ieee_int_to_float(refvalue)*10**-dsf)
171    elif datatype == 1: # Integer
172        refvalue = np.int32(ieee_int_to_float(refvalue)*10**-dsf)
173    # Upack each byte starting at byte 15 to end of the local use
174    # section, create a binary string and append to the full
175    # binary string.
176    b = ''
177    for i in range(15,len(lus)):
178        iword = struct.unpack('>B',lus[i:i+1])[0]
179        b += bin(iword).split('b')[1].zfill(8)
180    # Iterate over the binary string (b). For each nbits
181    # chunk, convert to an integer, including the refvalue,
182    # and then convert the int to an ASCII character, then
183    # concatenate to wxstring.
184    wxstring = ''
185    for i in range(0,len(b),nbits):
186        wxstring += chr(int(b[i:i+nbits],2)+refvalue)
187    # Return string as list, split by null character.
188    #return list(filter(None,wxstring.split('\0')))
189    return {n:k for n,k in enumerate(list(filter(None,wxstring.split('\0'))))}

Decode GRIB2 Local Use Section to obtain NDFD/MDL Weather Strings.

The decode procedure is defined here.

Parameters
  • lus: GRIB2 Local Use Section containing NDFD weather strings.
Returns
  • decode_wx_strings: Dict of NDFD/MDL weather strings. Keys are an integer value that represent the sequential order of the key in the packed local use section and the value is the weather key.
def get_wgrib2_prob_string(probtype: int, sfacl: int, svall: int, sfacu: int, svalu: int) -> str:
192def get_wgrib2_prob_string(
193    probtype: int,
194    sfacl: int,
195    svall: int,
196    sfacu: int,
197    svalu: int,
198) -> str:
199    """
200    Return a wgrib2-styled string of probabilistic threshold information.
201
202    Logic from wgrib2 source,
203    [Prob.c](https://github.com/NOAA-EMC/NCEPLIBS-wgrib2/blob/develop/wgrib2/Prob.c),
204    is replicated here.
205
206    Parameters
207    ----------
208    probtype
209        Type of probability (Code Table 4.9).
210    sfacl
211        Scale factor of lower limit.
212    svall
213        Scaled value of lower limit.
214    sfacu
215        Scale factor of upper limit.
216    svalu
217        Scaled value of upper limit.
218
219    Returns
220    -------
221    get_wgrib2_prob_string
222        wgrib2-formatted string of probability threshold.
223    """
224    probstr = ''
225    if sfacl == -127: sfacl = 0
226    if sfacu == -127: sfacu = 0
227    lower = svall/(10**sfacl)
228    upper = svalu/(10**sfacu)
229    if probtype == 0:
230        probstr = 'prob <%g' % (lower)
231    elif probtype == 1:
232        probstr = 'prob >%g' % (upper)
233    elif probtype == 2:
234        if lower == upper:
235            probstr = 'prob =%g' % (lower)
236        else:
237            probstr = 'prob >=%g <%g' % (lower,upper)
238    elif probtype == 3:
239        probstr = 'prob >%g' % (lower)
240    elif probtype == 4:
241        probstr = 'prob <%g' % (upper)
242    else:
243        probstr = ''
244    return probstr

Return a wgrib2-styled string of probabilistic threshold information.

Logic from wgrib2 source, Prob.c, is replicated here.

Parameters
  • probtype: Type of probability (Code Table 4.9).
  • sfacl: Scale factor of lower limit.
  • svall: Scaled value of lower limit.
  • sfacu: Scale factor of upper limit.
  • svalu: Scaled value of upper limit.
Returns
  • get_wgrib2_prob_string: wgrib2-formatted string of probability threshold.