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

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):
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)

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):
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)

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( idsec: Union[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[Union[bool, int, float, complex, str, bytes]]], pdtn: int, pdt: Union[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[Union[bool, int, float, complex, str, bytes]]]) -> datetime.timedelta:
 84def get_leadtime(idsec: ArrayLike, pdtn: int, pdt: ArrayLike) -> datetime.timedelta:
 85    """
 86    Compute lead time as a datetime.timedelta object.
 87
 88    Using information from GRIB2 Identification Section (Section 1), Product
 89    Definition Template Number, and Product Definition Template (Section 4).
 90
 91    Parameters
 92    ----------
 93    idsec
 94        Sequence containing GRIB2 Identification Section (Section 1).
 95    pdtn
 96        GRIB2 Product Definition Template Number
 97    pdt
 98        Sequence containing GRIB2 Product Definition Template (Section 4).
 99
100    Returns
101    -------
102    leadTime
103        datetime.timedelta object representing the lead time of the GRIB2 message.
104    """
105    _key = {8:slice(15,21), 9:slice(22,28), 10:slice(16,22), 11:slice(18,24), 12:slice(17,23)}
106    refdate = datetime.datetime(*idsec[5:11])
107    try:
108        return datetime.datetime(*pdt[_key[pdtn]])-refdate
109    except(KeyError):
110        if pdtn == 48:
111            return datetime.timedelta(hours=pdt[19]*(tables.get_value_from_table(pdt[18],'scale_time_hours')))
112        else:
113            return datetime.timedelta(hours=pdt[8]*(tables.get_value_from_table(pdt[7],'scale_time_hours')))

Compute lead time as a datetime.timedelta object.

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

Parameters
  • idsec: Sequence containing GRIB2 Identification Section (Section 1).
  • 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[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[Union[bool, int, float, complex, str, bytes]]]) -> datetime.timedelta:
116def get_duration(pdtn: int, pdt: ArrayLike) -> datetime.timedelta:
117    """
118    Compute a time duration as a datetime.timedelta.
119
120    Uses information from Product Definition Template Number, and Product
121    Definition Template (Section 4).
122
123    Parameters
124    ----------
125    pdtn
126        GRIB2 Product Definition Template Number
127    pdt
128        Sequence containing GRIB2 Product Definition Template (Section 4).
129
130    Returns
131    -------
132    get_duration
133        datetime.timedelta object representing the time duration of the GRIB2
134        message.
135    """
136    _key = {8:25, 9:32, 10:26, 11:28, 12:27}
137    try:
138        return datetime.timedelta(hours=pdt[_key[pdtn]+1]*tables.get_value_from_table(pdt[_key[pdtn]],'scale_time_hours'))
139    except(KeyError):
140        return datetime.timedelta(hours=0)

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]:
143def decode_wx_strings(lus: bytes) -> Dict[int, str]:
144    """
145    Decode GRIB2 Local Use Section to obtain NDFD/MDL Weather Strings.
146
147    The decode procedure is defined
148    [here](https://vlab.noaa.gov/web/mdl/nbm-gmos-grib2-wx-info).
149
150    Parameters
151    ----------
152    lus
153        GRIB2 Local Use Section containing NDFD weather strings.
154
155    Returns
156    -------
157    decode_wx_strings
158        Dict of NDFD/MDL weather strings. Keys are an integer value that
159        represent the sequential order of the key in the packed local use
160        section and the value is the weather key.
161    """
162    assert lus[0] == 1
163    # Unpack information related to the simple packing method
164    # the packed weather string data.
165    ngroups = struct.unpack('>H',lus[1:3])[0]
166    nvalues = struct.unpack('>i',lus[3:7])[0]
167    refvalue = struct.unpack('>i',lus[7:11])[0]
168    dsf = struct.unpack('>h',lus[11:13])[0]
169    nbits = lus[13]
170    datatype = lus[14]
171    if datatype == 0: # Floating point
172        refvalue = np.float32(ieee_int_to_float(refvalue)*10**-dsf)
173    elif datatype == 1: # Integer
174        refvalue = np.int32(ieee_int_to_float(refvalue)*10**-dsf)
175    # Upack each byte starting at byte 15 to end of the local use
176    # section, create a binary string and append to the full
177    # binary string.
178    b = ''
179    for i in range(15,len(lus)):
180        iword = struct.unpack('>B',lus[i:i+1])[0]
181        b += bin(iword).split('b')[1].zfill(8)
182    # Iterate over the binary string (b). For each nbits
183    # chunk, convert to an integer, including the refvalue,
184    # and then convert the int to an ASCII character, then
185    # concatenate to wxstring.
186    wxstring = ''
187    for i in range(0,len(b),nbits):
188        wxstring += chr(int(b[i:i+nbits],2)+refvalue)
189    # Return string as list, split by null character.
190    #return list(filter(None,wxstring.split('\0')))
191    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:
194def get_wgrib2_prob_string(
195    probtype: int,
196    sfacl: int,
197    svall: int,
198    sfacu: int,
199    svalu: int,
200) -> str:
201    """
202    Return a wgrib2-styled string of probabilistic threshold information.
203
204    Logic from wgrib2 source,
205    [Prob.c](https://github.com/NOAA-EMC/NCEPLIBS-wgrib2/blob/develop/wgrib2/Prob.c),
206    is replicated here.
207
208    Parameters
209    ----------
210    probtype
211        Type of probability (Code Table 4.9).
212    sfacl
213        Scale factor of lower limit.
214    svall
215        Scaled value of lower limit.
216    sfacu
217        Scale factor of upper limit.
218    svalu
219        Scaled value of upper limit.
220
221    Returns
222    -------
223    get_wgrib2_prob_string
224        wgrib2-formatted string of probability threshold.
225    """
226    probstr = ''
227    if sfacl == -127: sfacl = 0
228    if sfacu == -127: sfacu = 0
229    lower = svall/(10**sfacl)
230    upper = svalu/(10**sfacu)
231    if probtype == 0:
232        probstr = 'prob <%g' % (lower)
233    elif probtype == 1:
234        probstr = 'prob >%g' % (upper)
235    elif probtype == 2:
236        if lower == upper:
237            probstr = 'prob =%g' % (lower)
238        else:
239            probstr = 'prob >=%g <%g' % (lower,upper)
240    elif probtype == 3:
241        probstr = 'prob >%g' % (lower)
242    elif probtype == 4:
243        probstr = 'prob <%g' % (upper)
244    else:
245        probstr = ''
246    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.