grib2io.tables

Functions for retreiving data from NCEP GRIB2 Tables.

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

Return GRIB2 code table as a dictionary.

Parameters

table : str 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 : bool, optional If True, expand output dictionary where keys are a range.

Returns

Table as a dict.

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

Return the definition given a GRIB2 code table.

Parameters

value : int or str Code table value.

table : str Code table number.

expand : bool, optional If True, expand output dictionary where keys are a range.

Returns

Table value or None if not found.

def get_varinfo_from_table(discipline, parmcat, parmnum, isNDFD=False):
 88def get_varinfo_from_table(discipline,parmcat,parmnum,isNDFD=False):
 89    """
 90    Return the GRIB2 variable information given values of `discipline`,
 91    `parmcat`, and `parmnum`. NOTE: This functions allows for all arguments
 92    to be converted to a string type if arguments are integer.
 93
 94    Parameters
 95    ----------
 96    **`discipline : int or str`**
 97        Discipline code value of a GRIB2 message.
 98
 99    **`parmcat : int or str`**
100        Parameter Category value of a GRIB2 message.
101
102    **`parmnum : int or str`**
103        Parameter Number value of a GRIB2 message.
104
105    **`isNDFD : bool, optional`**
106        If `True`, signals function to try to get variable information from 
107        the supplemental NDFD tables.
108
109    Returns
110    -------
111    **`list`** containing variable information. "Unknown" is given for item of
112    information if variable is not found.
113        - list[0] = full name
114        - list[1] = units
115        - list[2] = short name (abbreviated name)
116    """
117    if isNDFD:
118        try:
119            tblname = f'table_4_2_{discipline}_{parmcat}_ndfd'
120            modname = f'.section4_discipline{discipline}'
121            exec('from '+modname+' import *')
122            return locals()[tblname][str(parmnum)]
123        except(ImportError,KeyError):
124            pass
125            #return ['Unknown','Unknown','Unknown']
126    try:
127        tblname = f'table_4_2_{discipline}_{parmcat}'
128        modname = f'.section4_discipline{discipline}'
129        exec('from '+modname+' import *')
130        return locals()[tblname][str(parmnum)]
131    except(ImportError,KeyError):
132        return ['Unknown','Unknown','Unknown']

Return the GRIB2 variable information given values of discipline, parmcat, and parmnum. NOTE: This functions allows for all arguments to be converted to a string type if arguments are integer.

Parameters

discipline : int or str Discipline code value of a GRIB2 message.

parmcat : int or str Parameter Category value of a GRIB2 message.

parmnum : int or str Parameter Number value of a GRIB2 message.

isNDFD : bool, optional If True, signals function to try to get variable information from the supplemental NDFD tables.

Returns

list containing variable information. "Unknown" is given for item of information if variable is not found. - list[0] = full name - list[1] = units - list[2] = short name (abbreviated name)

@lru_cache(maxsize=None)
def get_shortnames(discipline=None, parmcat=None, parmnum=None, isNDFD=False):
136@lru_cache(maxsize=None)
137def get_shortnames(discipline=None, parmcat=None, parmnum=None, isNDFD=False):
138    """
139    Returns a list of variable shortNames given GRIB2 discipline, parameter
140    category, and parameter number.  If all 3 args are None, then shortNames
141    from all disciplines, parameter categories, and numbers will be returned.
142
143    Parameters
144    ----------
145    **`discipline : int`**
146        GRIB2 discipline code value.
147
148    **`parmcat : int`**
149        GRIB2 parameter category value.
150
151    **`parmnum : int or str`**
152        Parameter Number value of a GRIB2 message.
153
154    Returns
155    -------
156    **`list`** of GRIB2 shortNames.
157    """
158    shortnames = list()
159    if discipline is None:
160        discipline = GRIB2_DISCIPLINES
161    else:
162        discipline = [discipline]
163    if parmcat is None:
164        parmcat = list()
165        for d in discipline:
166            parmcat += list(get_table(f'4.1.{d}').keys())
167    else:
168        parmcat = [parmcat]
169    if parmnum is None:
170        parmnum = list(range(256))
171    else:
172        parmnum = [parmnum]
173    for d in discipline:
174
175        for pc in parmcat:
176            for pn in parmnum:
177                shortnames.append(get_varinfo_from_table(d,pc,pn,isNDFD)[2])
178
179    shortnames = sorted(set(shortnames))
180    try:
181        shortnames.remove('unknown')
182        shortnames.remove('Unknown')
183    except(ValueError):
184        pass
185    return shortnames

Returns a list of variable shortNames given GRIB2 discipline, parameter category, and parameter number. If all 3 args are None, then shortNames from all disciplines, parameter categories, and numbers will be returned.

Parameters

discipline : int GRIB2 discipline code value.

parmcat : int GRIB2 parameter category value.

parmnum : int or str Parameter Number value of a GRIB2 message.

Returns

list of GRIB2 shortNames.

@lru_cache(maxsize=None)
def get_metadata_from_shortname(shortname):
189@lru_cache(maxsize=None)
190def get_metadata_from_shortname(shortname):
191    """
192    Provide GRIB2 variable metadata attributes given a GRIB2 shortName.
193
194    Parameters
195    ----------
196    **`shortname : str`**
197        GRIB2 variable shortName.
198
199    Returns
200    -------
201    **`list`** of dictionary items where each dictionary items contains the variable
202    metadata key:value pairs. **NOTE:** Some variable shortNames will exist in multiple
203    parameter category/number tables according to the GRIB2 discipline.
204    """
205    metadata = []
206    for d in GRIB2_DISCIPLINES:
207        parmcat = list(get_table(f'4.1.{d}').keys())
208        for pc in parmcat:
209            for pn in range(256):
210                varinfo = get_varinfo_from_table(d,pc,pn,False)
211                if shortname == varinfo[2]:
212                    metadata.append(dict(discipline=d,parameterCategory=pc,parameterNumber=pn,
213                                         fullName=varinfo[0],units=varinfo[1]))
214    return metadata

Provide GRIB2 variable metadata attributes given a GRIB2 shortName.

Parameters

shortname : str GRIB2 variable shortName.

Returns

list of dictionary items where each dictionary items 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, pdt):
217def get_wgrib2_level_string(pdtn, pdt):
218    """
219    Return a string that describes the level or layer of the GRIB2 message. The
220    format and language of the string is an exact replica of how wgrib2 produces
221    the level/layer string in its inventory output.
222
223    Contents of wgrib2 source, [Level.c](https://github.com/NOAA-EMC/NCEPLIBS-wgrib2/blob/develop/wgrib2/Level.c),
224    were converted into a Python dictionary and stored in grib2io as table
225    'wgrib2_level_string'.
226
227    Parameters
228    ----------
229    **`pdtn :  int`**
230        GRIB2 Product Definition Template Number
231
232    **`pdt : list or array_like`**
233        Sequence containing GRIB2 Product Definition Template (Section 4).
234
235    Returns
236    -------
237    wgrib2-formatted level/layer string.
238    """
239    if pdtn == 48:
240        idxs = slice(20,26)
241    else:
242        idxs = slice(9,15)
243    type1, sfac1, sval1, type2, sfac2, sval2 = map(int,pdt[idxs])
244    lvlstr = ''
245    val1 = sval1/10**sfac1
246    if type1 in [100,108]: val1 *= 0.01
247    if type2 != 255:
248        # Layer
249        #assert type2 == type1, "Surface types are not equal: %g - %g" % (type1,type2)
250        val2 = sval2/10**sfac2
251        if type2 in [100,108]: val2 *= 0.01
252        lvlstr = get_value_from_table(type1,table='wgrib2_level_string')[1]
253        vals = (val1,val2)
254    else:
255        # Level
256        lvlstr = get_value_from_table(type1,table='wgrib2_level_string')[0]
257        vals = (val1)
258    if '%g' in lvlstr: lvlstr %= vals
259    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 : int GRIB2 Product Definition Template Number

pdt : list or array_like Sequence containing GRIB2 Product Definition Template (Section 4).

Returns

wgrib2-formatted level/layer string.