grib2io.tables

Functions for retrieving data from NCEP GRIB2 Tables.

  1"""Functions for retrieving data from NCEP GRIB2 Tables."""
  2
  3from functools import lru_cache
  4
  5from typing import Optional, Union, List
  6from numpy.typing import ArrayLike
  7
  8from .section0 import *
  9from .section1 import *
 10from .section3 import *
 11from .section4 import *
 12from .section5 import *
 13from .section6 import *
 14from .originating_centers import *
 15
 16GRIB2_DISCIPLINES = [0, 1, 2, 3, 4, 10, 20]
 17
 18def get_table(table: str, expand: bool=False) -> dict:
 19    """
 20    Return GRIB2 code table as a dictionary.
 21
 22    Parameters
 23    ----------
 24    table
 25        Code table number (e.g. '1.0').
 26
 27        NOTE: Code table '4.1' requires a 3rd value representing the product
 28        discipline (e.g. '4.1.0').
 29    expand
 30        If `True`, expand output dictionary wherever keys are a range.
 31
 32    Returns
 33    -------
 34    get_table
 35        GRIB2 code table as a dictionary.
 36    """
 37    if len(table) == 3 and table == '4.1':
 38        raise Exception('GRIB2 Code Table 4.1 requires a 3rd value representing the discipline.')
 39    if len(table) == 3 and table.startswith('4.2'):
 40        raise Exception('Use function get_varinfo_from_table() for GRIB2 Code Table 4.2')
 41    try:
 42        tbl = globals()['table_'+table.replace('.','_')]
 43        if expand:
 44            _tbl = {}
 45            for k,v in tbl.items():
 46                if '-' in k:
 47                    irng = [int(i) for i in k.split('-')]
 48                    for i in range(irng[0],irng[1]+1):
 49                        _tbl[str(i)] = v
 50                else:
 51                    _tbl[k] = v
 52            tbl = _tbl
 53        return tbl
 54    except(KeyError):
 55        return {}
 56
 57
 58def get_value_from_table(
 59    value: Union[int, str],
 60    table: str,
 61    expand: bool = False,
 62) -> Optional[Union[float, int]]:
 63    """
 64    Return the definition given a GRIB2 code table.
 65
 66    Parameters
 67    ----------
 68    value
 69        Code table value.
 70    table
 71        Code table number.
 72    expand
 73        If `True`, expand output dictionary where keys are a range.
 74
 75    Returns
 76    -------
 77    get_value_from_table
 78        Table value or `None` if not found.
 79    """
 80    try:
 81        tbl = get_table(table,expand=expand)
 82        value = str(value)
 83        return tbl[value]
 84    except(KeyError):
 85        for k in tbl.keys():
 86            if '-' in k:
 87                bounds = k.split('-')
 88                if value >= bounds[0] and value <= bounds[1]:
 89                    return tbl[k]
 90        return None
 91
 92
 93def get_varinfo_from_table(
 94    discipline: Union[int, str],
 95    parmcat: Union[int, str],
 96    parmnum: Union[int, str],
 97    isNDFD: bool = False,
 98):
 99    """
100    Return the GRIB2 variable information.
101
102    NOTE: This functions allows for all arguments to be converted to a string
103    type if arguments are integer.
104
105    Parameters
106    ----------
107    discipline
108        Discipline code value of a GRIB2 message.
109    parmcat
110        Parameter Category value of a GRIB2 message.
111    parmnum
112        Parameter Number value of a GRIB2 message.
113    isNDFD: optional
114        If `True`, signals function to try to get variable information from the
115        supplemental NDFD tables.
116
117    Returns
118    -------
119    full_name
120        Full name of the GRIB2 variable. "Unknown" if variable is not found.
121    units
122        Units of the GRIB2 variable. "Unknown" if variable is not found.
123    shortName
124        Abbreviated name of the GRIB2 variable. "Unknown" if variable is not
125        found.
126    """
127    if isNDFD:
128        try:
129            tblname = f'table_4_2_{discipline}_{parmcat}_ndfd'
130            modname = f'.section4_discipline{discipline}'
131            exec('from '+modname+' import *')
132            return locals()[tblname][str(parmnum)]
133        except(ImportError,KeyError):
134            pass
135    try:
136        tblname = f'table_4_2_{discipline}_{parmcat}'
137        modname = f'.section4_discipline{discipline}'
138        exec('from '+modname+' import *')
139        return locals()[tblname][str(parmnum)]
140    except(ImportError,KeyError):
141        return ['Unknown','Unknown','Unknown']
142
143
144@lru_cache(maxsize=None)
145def get_shortnames(
146    discipline: Optional[Union[int, str]] = None,
147    parmcat: Optional[Union[int, str]] = None,
148    parmnum: Optional[Union[int, str]] = None,
149    isNDFD: bool = False,
150) -> List[str]:
151    """
152    Return a list of variable shortNames.
153
154    If all 3 args are None, then shortNames from all disciplines, parameter
155    categories, and numbers will be returned.
156
157    Parameters
158    ----------
159    discipline
160        GRIB2 discipline code value.
161    parmcat
162        GRIB2 parameter category value.
163    parmnum
164        Parameter Number value of a GRIB2 message.
165    isNDFD: optional
166        If `True`, signals function to try to get variable information from the
167        supplemental NDFD tables.
168
169    Returns
170    -------
171    get_shortnames
172        list of GRIB2 shortNames.
173    """
174    shortnames = list()
175    if discipline is None:
176        discipline = GRIB2_DISCIPLINES
177    else:
178        discipline = [discipline]
179    if parmcat is None:
180        parmcat = list()
181        for d in discipline:
182            parmcat += list(get_table(f'4.1.{d}').keys())
183    else:
184        parmcat = [parmcat]
185    if parmnum is None:
186        parmnum = list(range(256))
187    else:
188        parmnum = [parmnum]
189    for d in discipline:
190
191        for pc in parmcat:
192            for pn in parmnum:
193                shortnames.append(get_varinfo_from_table(d,pc,pn,isNDFD)[2])
194
195    shortnames = sorted(set(shortnames))
196    try:
197        shortnames.remove('unknown')
198        shortnames.remove('Unknown')
199    except(ValueError):
200        pass
201    return shortnames
202
203
204@lru_cache(maxsize=None)
205def get_metadata_from_shortname(shortname: str):
206    """
207    Provide GRIB2 variable metadata attributes given a GRIB2 shortName.
208
209    Parameters
210    ----------
211    shortname
212        GRIB2 variable shortName.
213
214    Returns
215    -------
216    get_metadata_from_shortname
217        list of dictionary items where each dictionary item contains the
218        variable metadata key:value pairs.
219
220        NOTE: Some variable shortNames will exist in multiple parameter
221        category/number tables according to the GRIB2 discipline.
222    """
223    metadata = []
224    for d in GRIB2_DISCIPLINES:
225        parmcat = list(get_table(f'4.1.{d}').keys())
226        for pc in parmcat:
227            for pn in range(256):
228                varinfo = get_varinfo_from_table(d,pc,pn,False)
229                if shortname == varinfo[2]:
230                    metadata.append(dict(discipline=d,parameterCategory=pc,parameterNumber=pn,
231                                         fullName=varinfo[0],units=varinfo[1]))
232    return metadata
233
234
235def get_wgrib2_level_string(pdtn: int, pdt: ArrayLike) -> str:
236    """
237    Return a string that describes the level or layer of the GRIB2 message.
238
239    The format and language of the string is an exact replica of how wgrib2
240    produces the level/layer string in its inventory output.
241
242    Contents of wgrib2 source,
243    [Level.c](https://github.com/NOAA-EMC/NCEPLIBS-wgrib2/blob/develop/wgrib2/Level.c),
244    were converted into a Python dictionary and stored in grib2io as table
245    'wgrib2_level_string'.
246
247    Parameters
248    ----------
249    pdtn
250        GRIB2 Product Definition Template Number
251    pdt
252        Sequence containing GRIB2 Product Definition Template (Section 4).
253
254    Returns
255    -------
256    get_wgrib2_level_string
257        wgrib2-formatted level/layer string.
258    """
259    lvlstr = ''
260    if pdtn == 32:
261        return 'no_level'
262    elif pdtn == 48:
263        idxs = slice(20,26)
264    else:
265        idxs = slice(9,15)
266    type1, sfac1, sval1, type2, sfac2, sval2 = map(int,pdt[idxs])
267    val1 = sval1/10**sfac1
268    if type1 in [100,108]: val1 *= 0.01
269    if type2 != 255:
270        # Layer
271        #assert type2 == type1, "Surface types are not equal: %g - %g" % (type1,type2)
272        val2 = sval2/10**sfac2
273        if type2 in [100,108]: val2 *= 0.01
274        lvlstr = get_value_from_table(type1,table='wgrib2_level_string')[1]
275        vals = (val1,val2)
276    else:
277        # Level
278        lvlstr = get_value_from_table(type1,table='wgrib2_level_string')[0]
279        vals = (val1)
280    if '%g' in lvlstr: lvlstr %= vals
281    return lvlstr
GRIB2_DISCIPLINES = [0, 1, 2, 3, 4, 10, 20]
def get_table(table: str, expand: bool = False) -> dict:
19def get_table(table: str, expand: bool=False) -> dict:
20    """
21    Return GRIB2 code table as a dictionary.
22
23    Parameters
24    ----------
25    table
26        Code table number (e.g. '1.0').
27
28        NOTE: Code table '4.1' requires a 3rd value representing the product
29        discipline (e.g. '4.1.0').
30    expand
31        If `True`, expand output dictionary wherever keys are a range.
32
33    Returns
34    -------
35    get_table
36        GRIB2 code table as a dictionary.
37    """
38    if len(table) == 3 and table == '4.1':
39        raise Exception('GRIB2 Code Table 4.1 requires a 3rd value representing the discipline.')
40    if len(table) == 3 and table.startswith('4.2'):
41        raise Exception('Use function get_varinfo_from_table() for GRIB2 Code Table 4.2')
42    try:
43        tbl = globals()['table_'+table.replace('.','_')]
44        if expand:
45            _tbl = {}
46            for k,v in tbl.items():
47                if '-' in k:
48                    irng = [int(i) for i in k.split('-')]
49                    for i in range(irng[0],irng[1]+1):
50                        _tbl[str(i)] = v
51                else:
52                    _tbl[k] = v
53            tbl = _tbl
54        return tbl
55    except(KeyError):
56        return {}

Return GRIB2 code table as a dictionary.

Parameters
  • table: Code table number (e.g. '1.0').

NOTE: Code table '4.1' requires a 3rd value representing the product discipline (e.g. '4.1.0').

  • expand: If True, expand output dictionary wherever keys are a range.
Returns
  • get_table: GRIB2 code table as a dictionary.
def get_value_from_table( value: Union[int, str], table: str, expand: bool = False) -> Union[float, int, NoneType]:
59def get_value_from_table(
60    value: Union[int, str],
61    table: str,
62    expand: bool = False,
63) -> Optional[Union[float, int]]:
64    """
65    Return the definition given a GRIB2 code table.
66
67    Parameters
68    ----------
69    value
70        Code table value.
71    table
72        Code table number.
73    expand
74        If `True`, expand output dictionary where keys are a range.
75
76    Returns
77    -------
78    get_value_from_table
79        Table value or `None` if not found.
80    """
81    try:
82        tbl = get_table(table,expand=expand)
83        value = str(value)
84        return tbl[value]
85    except(KeyError):
86        for k in tbl.keys():
87            if '-' in k:
88                bounds = k.split('-')
89                if value >= bounds[0] and value <= bounds[1]:
90                    return tbl[k]
91        return None

Return the definition given a GRIB2 code table.

Parameters
  • value: Code table value.
  • table: Code table number.
  • expand: If True, expand output dictionary where keys are a range.
Returns
  • get_value_from_table: Table value or None if not found.
def get_varinfo_from_table( discipline: Union[int, str], parmcat: Union[int, str], parmnum: Union[int, str], isNDFD: bool = False):
 94def get_varinfo_from_table(
 95    discipline: Union[int, str],
 96    parmcat: Union[int, str],
 97    parmnum: Union[int, str],
 98    isNDFD: bool = False,
 99):
100    """
101    Return the GRIB2 variable information.
102
103    NOTE: This functions allows for all arguments to be converted to a string
104    type if arguments are integer.
105
106    Parameters
107    ----------
108    discipline
109        Discipline code value of a GRIB2 message.
110    parmcat
111        Parameter Category value of a GRIB2 message.
112    parmnum
113        Parameter Number value of a GRIB2 message.
114    isNDFD: optional
115        If `True`, signals function to try to get variable information from the
116        supplemental NDFD tables.
117
118    Returns
119    -------
120    full_name
121        Full name of the GRIB2 variable. "Unknown" if variable is not found.
122    units
123        Units of the GRIB2 variable. "Unknown" if variable is not found.
124    shortName
125        Abbreviated name of the GRIB2 variable. "Unknown" if variable is not
126        found.
127    """
128    if isNDFD:
129        try:
130            tblname = f'table_4_2_{discipline}_{parmcat}_ndfd'
131            modname = f'.section4_discipline{discipline}'
132            exec('from '+modname+' import *')
133            return locals()[tblname][str(parmnum)]
134        except(ImportError,KeyError):
135            pass
136    try:
137        tblname = f'table_4_2_{discipline}_{parmcat}'
138        modname = f'.section4_discipline{discipline}'
139        exec('from '+modname+' import *')
140        return locals()[tblname][str(parmnum)]
141    except(ImportError,KeyError):
142        return ['Unknown','Unknown','Unknown']

Return the GRIB2 variable information.

NOTE: This functions allows for all arguments to be converted to a string type if arguments are integer.

Parameters
  • discipline: Discipline code value of a GRIB2 message.
  • parmcat: Parameter Category value of a GRIB2 message.
  • parmnum: Parameter Number value of a GRIB2 message.
  • isNDFD (optional): If True, signals function to try to get variable information from the supplemental NDFD tables.
Returns
  • full_name: Full name of the GRIB2 variable. "Unknown" if variable is not found.
  • units: Units of the GRIB2 variable. "Unknown" if variable is not found.
  • shortName: Abbreviated name of the GRIB2 variable. "Unknown" if variable is not found.
@lru_cache(maxsize=None)
def get_shortnames( discipline: Union[int, str, NoneType] = None, parmcat: Union[int, str, NoneType] = None, parmnum: Union[int, str, NoneType] = None, isNDFD: bool = False) -> List[str]:
145@lru_cache(maxsize=None)
146def get_shortnames(
147    discipline: Optional[Union[int, str]] = None,
148    parmcat: Optional[Union[int, str]] = None,
149    parmnum: Optional[Union[int, str]] = None,
150    isNDFD: bool = False,
151) -> List[str]:
152    """
153    Return a list of variable shortNames.
154
155    If all 3 args are None, then shortNames from all disciplines, parameter
156    categories, and numbers will be returned.
157
158    Parameters
159    ----------
160    discipline
161        GRIB2 discipline code value.
162    parmcat
163        GRIB2 parameter category value.
164    parmnum
165        Parameter Number value of a GRIB2 message.
166    isNDFD: optional
167        If `True`, signals function to try to get variable information from the
168        supplemental NDFD tables.
169
170    Returns
171    -------
172    get_shortnames
173        list of GRIB2 shortNames.
174    """
175    shortnames = list()
176    if discipline is None:
177        discipline = GRIB2_DISCIPLINES
178    else:
179        discipline = [discipline]
180    if parmcat is None:
181        parmcat = list()
182        for d in discipline:
183            parmcat += list(get_table(f'4.1.{d}').keys())
184    else:
185        parmcat = [parmcat]
186    if parmnum is None:
187        parmnum = list(range(256))
188    else:
189        parmnum = [parmnum]
190    for d in discipline:
191
192        for pc in parmcat:
193            for pn in parmnum:
194                shortnames.append(get_varinfo_from_table(d,pc,pn,isNDFD)[2])
195
196    shortnames = sorted(set(shortnames))
197    try:
198        shortnames.remove('unknown')
199        shortnames.remove('Unknown')
200    except(ValueError):
201        pass
202    return shortnames

Return a list of variable shortNames.

If all 3 args are None, then shortNames from all disciplines, parameter categories, and numbers will be returned.

Parameters
  • discipline: GRIB2 discipline code value.
  • parmcat: GRIB2 parameter category value.
  • parmnum: Parameter Number value of a GRIB2 message.
  • isNDFD (optional): If True, signals function to try to get variable information from the supplemental NDFD tables.
Returns
  • get_shortnames: list of GRIB2 shortNames.
@lru_cache(maxsize=None)
def get_metadata_from_shortname(shortname: str):
205@lru_cache(maxsize=None)
206def get_metadata_from_shortname(shortname: str):
207    """
208    Provide GRIB2 variable metadata attributes given a GRIB2 shortName.
209
210    Parameters
211    ----------
212    shortname
213        GRIB2 variable shortName.
214
215    Returns
216    -------
217    get_metadata_from_shortname
218        list of dictionary items where each dictionary item contains the
219        variable metadata key:value pairs.
220
221        NOTE: Some variable shortNames will exist in multiple parameter
222        category/number tables according to the GRIB2 discipline.
223    """
224    metadata = []
225    for d in GRIB2_DISCIPLINES:
226        parmcat = list(get_table(f'4.1.{d}').keys())
227        for pc in parmcat:
228            for pn in range(256):
229                varinfo = get_varinfo_from_table(d,pc,pn,False)
230                if shortname == varinfo[2]:
231                    metadata.append(dict(discipline=d,parameterCategory=pc,parameterNumber=pn,
232                                         fullName=varinfo[0],units=varinfo[1]))
233    return metadata

Provide GRIB2 variable metadata attributes given a GRIB2 shortName.

Parameters
  • shortname: GRIB2 variable shortName.
Returns
  • get_metadata_from_shortname: list of dictionary items where each dictionary item contains the variable metadata key:value pairs.

NOTE: Some variable shortNames will exist in multiple parameter category/number tables according to the GRIB2 discipline.

def get_wgrib2_level_string( 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]]]) -> str:
236def get_wgrib2_level_string(pdtn: int, pdt: ArrayLike) -> str:
237    """
238    Return a string that describes the level or layer of the GRIB2 message.
239
240    The format and language of the string is an exact replica of how wgrib2
241    produces the level/layer string in its inventory output.
242
243    Contents of wgrib2 source,
244    [Level.c](https://github.com/NOAA-EMC/NCEPLIBS-wgrib2/blob/develop/wgrib2/Level.c),
245    were converted into a Python dictionary and stored in grib2io as table
246    'wgrib2_level_string'.
247
248    Parameters
249    ----------
250    pdtn
251        GRIB2 Product Definition Template Number
252    pdt
253        Sequence containing GRIB2 Product Definition Template (Section 4).
254
255    Returns
256    -------
257    get_wgrib2_level_string
258        wgrib2-formatted level/layer string.
259    """
260    lvlstr = ''
261    if pdtn == 32:
262        return 'no_level'
263    elif pdtn == 48:
264        idxs = slice(20,26)
265    else:
266        idxs = slice(9,15)
267    type1, sfac1, sval1, type2, sfac2, sval2 = map(int,pdt[idxs])
268    val1 = sval1/10**sfac1
269    if type1 in [100,108]: val1 *= 0.01
270    if type2 != 255:
271        # Layer
272        #assert type2 == type1, "Surface types are not equal: %g - %g" % (type1,type2)
273        val2 = sval2/10**sfac2
274        if type2 in [100,108]: val2 *= 0.01
275        lvlstr = get_value_from_table(type1,table='wgrib2_level_string')[1]
276        vals = (val1,val2)
277    else:
278        # Level
279        lvlstr = get_value_from_table(type1,table='wgrib2_level_string')[0]
280        vals = (val1)
281    if '%g' in lvlstr: lvlstr %= vals
282    return lvlstr

Return a string that describes the level or layer of the GRIB2 message.

The format and language of the string is an exact replica of how wgrib2 produces the level/layer string in its inventory output.

Contents of wgrib2 source, Level.c, were converted into a Python dictionary and stored in grib2io as table 'wgrib2_level_string'.

Parameters
  • pdtn: GRIB2 Product Definition Template Number
  • pdt: Sequence containing GRIB2 Product Definition Template (Section 4).
Returns
  • get_wgrib2_level_string: wgrib2-formatted level/layer string.