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
  4from typing import Optional, Union, List
  5from numpy.typing import ArrayLike
  6import itertools
  7import importlib
  8import numpy as np
  9
 10from .section0 import *
 11from .section1 import *
 12from .section3 import *
 13from .section4 import *
 14from .section5 import *
 15from .section6 import *
 16from .originating_centers import *
 17from .ndfd_additionals import *
 18from .cf import *
 19
 20_varinfo_tables_datastore = {}
 21
 22# Note 209 is MRMS
 23GRIB2_DISCIPLINES = [0, 1, 2, 3, 4, 10, 20, 209]
 24
 25AEROSOL_PDTNS = [46, 48]  # 47, 49, 80, 81, 82, 83, 84, 85] <- these don't seem to be working
 26AEROSOL_PARAMS = list(itertools.chain(range(0,19),range(50,82),range(100,113),range(192,197)))
 27
 28def _load_varinfo_tables(modname: str):
 29    """
 30    Load variable information tables from sub modules into the local
 31    varinfo table datastore (_varinfo_tables_datastore).
 32
 33    Parameters
 34    ----------
 35    modname
 36        Module name to extract variable info tables from.
 37    """
 38    module = importlib.import_module(modname, package=__name__)
 39    names = getattr(module, '__all__', [name for name in dir(module) if name.startswith('table_')])
 40    _varinfo_tables_datastore.update({name: getattr(module, name) for name in names})
 41
 42
 43def get_table(table: str, expand: bool=False) -> dict:
 44    """
 45    Return GRIB2 code table as a dictionary.
 46
 47    Parameters
 48    ----------
 49    table
 50        Code table number (e.g. '1.0').
 51
 52        NOTE: Code table '4.1' requires a 3rd value representing the product
 53        discipline (e.g. '4.1.0').
 54    expand
 55        If `True`, expand output dictionary wherever keys are a range.
 56
 57    Returns
 58    -------
 59    get_table
 60        GRIB2 code table as a dictionary.
 61    """
 62    if len(table) == 3 and table == '4.1':
 63        raise Exception('GRIB2 Code Table 4.1 requires a 3rd value representing the discipline.')
 64    if len(table) == 3 and table.startswith('4.2'):
 65        raise Exception('Use function get_varinfo_from_table() for GRIB2 Code Table 4.2')
 66    try:
 67        tbl = globals()['table_'+table.replace('.','_')]
 68        if expand:
 69            _tbl = {}
 70            for k,v in tbl.items():
 71                if '-' in k:
 72                    irng = [int(i) for i in k.split('-')]
 73                    for i in range(irng[0],irng[1]+1):
 74                        _tbl[str(i)] = v
 75                else:
 76                    _tbl[k] = v
 77            tbl = _tbl
 78        return tbl
 79    except(KeyError):
 80        return {}
 81
 82
 83def get_value_from_table(
 84    value: Union[int, str],
 85    table: str,
 86    expand: bool = False,
 87) -> Optional[Union[float, int]]:
 88    """
 89    Return the definition given a GRIB2 code table.
 90
 91    Parameters
 92    ----------
 93    value
 94        Code table value.
 95    table
 96        Code table number.
 97    expand
 98        If `True`, expand output dictionary where keys are a range.
 99
100    Returns
101    -------
102    get_value_from_table
103        Table value or `None` if not found.
104    """
105    try:
106        tbl = get_table(table,expand=expand)
107        value = str(value)
108        return tbl[value]
109    except(KeyError):
110        for k in tbl.keys():
111            if '-' in k:
112                bounds = k.split('-')
113                if value >= bounds[0] and value <= bounds[1]:
114                    return tbl[k]
115        return None
116
117
118def get_varinfo_from_table(
119    discipline: Union[int, str],
120    parmcat: Union[int, str],
121    parmnum: Union[int, str],
122    isNDFD: bool = False,
123):
124    """
125    Return the GRIB2 variable information.
126
127    NOTE: This functions allows for all arguments to be converted to a string
128    type if arguments are integer.
129
130    Parameters
131    ----------
132    discipline
133        Discipline code value of a GRIB2 message.
134    parmcat
135        Parameter Category value of a GRIB2 message.
136    parmnum
137        Parameter Number value of a GRIB2 message.
138    isNDFD: optional
139        If `True`, then attempt to get variable information from the
140        supplemental NDFD tables, otherwise fallback to default tables.
141
142    Returns
143    -------
144    full_name
145        Full name of the GRIB2 variable. "Unknown" if variable is not found.
146    units
147        Units of the GRIB2 variable. "Unknown" if variable is not found.
148    shortName
149        Abbreviated name of the GRIB2 variable. "Unknown" if variable is not
150        found.
151    """
152    template = f'table_4_2_{discipline}_{parmcat}'
153    tbls = []
154    if isNDFD:
155        tbls.append(template+'_ndfd')
156    tbls.append(template)
157    for tbl in tbls:
158        vartbl = None
159        modname = f'.section4_discipline{discipline}'
160        if tbl not in _varinfo_tables_datastore.keys():
161            _load_varinfo_tables(modname)
162        try:
163            vartbl = _varinfo_tables_datastore[tbl][str(parmnum)]
164        except(KeyError):
165            pass
166        if vartbl is not None:
167            break
168    if vartbl is None:
169        vartbl = ['Unknown','Unknown','Unknown']
170    return vartbl
171
172
173@lru_cache(maxsize=None)
174def get_shortnames(
175    discipline: Optional[Union[int, str]] = None,
176    parmcat: Optional[Union[int, str]] = None,
177    parmnum: Optional[Union[int, str]] = None,
178    isNDFD: bool = False,
179) -> List[str]:
180    """
181    Return a list of variable shortNames.
182
183    If all 3 args are None, then shortNames from all disciplines, parameter
184    categories, and numbers will be returned.
185
186    Parameters
187    ----------
188    discipline
189        GRIB2 discipline code value.
190    parmcat
191        GRIB2 parameter category value.
192    parmnum
193        Parameter Number value of a GRIB2 message.
194    isNDFD: optional
195        If `True`, signals function to try to get variable information from the
196        supplemental NDFD tables.
197
198    Returns
199    -------
200    get_shortnames
201        list of GRIB2 shortNames.
202    """
203    shortnames = list()
204    if discipline is None:
205        discipline = GRIB2_DISCIPLINES
206    else:
207        discipline = [discipline]
208    if parmcat is None:
209        parmcat = list()
210        for d in discipline:
211            parmcat += list(get_table(f'4.1.{d}').keys())
212    else:
213        parmcat = [parmcat]
214    if parmnum is None:
215        parmnum = list(range(256))
216    else:
217        parmnum = [parmnum]
218    for d in discipline:
219
220        for pc in parmcat:
221            for pn in parmnum:
222                shortnames.append(get_varinfo_from_table(d,pc,pn,isNDFD)[2])
223
224    shortnames = sorted(set(shortnames))
225    try:
226        shortnames.remove('unknown')
227        shortnames.remove('Unknown')
228    except(ValueError):
229        pass
230    return shortnames
231
232
233@lru_cache(maxsize=None)
234def get_metadata_from_shortname(shortname: str):
235    """
236    Provide GRIB2 variable metadata attributes given a GRIB2 shortName.
237
238    Parameters
239    ----------
240    shortname
241        GRIB2 variable shortName.
242
243    Returns
244    -------
245    get_metadata_from_shortname
246        list of dictionary items where each dictionary item contains the
247        variable metadata key:value pairs.
248
249        NOTE: Some variable shortNames will exist in multiple parameter
250        category/number tables according to the GRIB2 discipline.
251    """
252    metadata = []
253    for d in GRIB2_DISCIPLINES:
254        parmcat = list(get_table(f'4.1.{d}').keys())
255        for pc in parmcat:
256            for pn in range(256):
257                varinfo = get_varinfo_from_table(d,pc,pn,False)
258                if shortname == varinfo[2]:
259                    metadata.append(dict(discipline=d,parameterCategory=pc,parameterNumber=pn,
260                                         fullName=varinfo[0],units=varinfo[1]))
261    return metadata
262
263
264def get_wgrib2_level_string(pdtn: int, pdt: ArrayLike) -> str:
265    """
266    Return a string that describes the level or layer of the GRIB2 message.
267
268    The format and language of the string is an exact replica of how wgrib2
269    produces the level/layer string in its inventory output.
270
271    Contents of wgrib2 source,
272    [Level.c](https://github.com/NOAA-EMC/NCEPLIBS-wgrib2/blob/develop/wgrib2/Level.c),
273    were converted into a Python dictionary and stored in grib2io as table
274    'wgrib2_level_string'.
275
276    Parameters
277    ----------
278    pdtn
279        GRIB2 Product Definition Template Number
280    pdt
281        Sequence containing GRIB2 Product Definition Template (Section 4).
282
283    Returns
284    -------
285    get_wgrib2_level_string
286        wgrib2-formatted level/layer string.
287    """
288    lvlstr = ''
289    if pdtn == 32:
290        return 'no_level'
291    elif pdtn == 48:
292        idxs = slice(20,26)
293    else:
294        idxs = slice(9,15)
295    type1, sfac1, sval1, type2, sfac2, sval2 = map(int,pdt[idxs])
296    val1 = sval1/10**sfac1
297    if type1 in [100,108]: val1 *= 0.01
298    if type2 != 255:
299        # Layer
300        #assert type2 == type1, "Surface types are not equal: %g - %g" % (type1,type2)
301        val2 = sval2/10**sfac2
302        if type2 in [100,108]: val2 *= 0.01
303        lvlstr = get_value_from_table(type1,table='wgrib2_level_string')[1]
304        vals = (val1,val2)
305    else:
306        # Level
307        lvlstr = get_value_from_table(type1,table='wgrib2_level_string')[0]
308        vals = (val1)
309    if '%g' in lvlstr: lvlstr %= vals
310    return lvlstr
311
312
313def _build_aerosol_shortname(obj) -> str:
314    """
315    """
316    _OPTICAL_WAVELENGTH_MAPPING = get_table('aerosol_optical_wavelength')
317    _LEVEL_MAPPING = get_table('aerosol_level')
318    _PARAMETER_MAPPING = get_table('aerosol_parameter')
319    _AERO_TYPE_MAPPING = get_table('aerosol_type')
320
321    # Build shortname from aerosol components
322    parts = []
323
324    # Get aerosol type
325    aero_type = str(obj.typeOfAerosol.value) if obj.typeOfAerosol is not None else ""
326
327    # Add size information if applicable
328    aero_size = ""
329    if hasattr(obj, 'scaledValueOfFirstSize'):
330        if float(obj.scaledValueOfFirstSize) > 0:
331            first_size = float(obj.scaledValueOfFirstSize)
332
333            # Map common PM sizes
334            size_map = {1: 'pm1', 25: 'pm25', 10: 'pm10', 20: 'pm20'}
335            aero_size = size_map.get(first_size, f"pm{int(first_size)}")
336
337            # Check for size intervals
338            if (hasattr(obj, 'scaledValueOfSecondSize') and
339                obj.scaledValueOfSecondSize is not None and
340                hasattr(obj, 'typeOfIntervalForAerosolSize') and
341                obj.typeOfIntervalForAerosolSize.value == 6):
342
343                second_size = float(obj.scaledValueOfSecondSize)
344                if second_size > 0:
345                    if (first_size == 2.5 and second_size == 10):
346                        aero_size = 'PM25to10'
347                    elif (first_size == 10 and second_size == 20):
348                        aero_size = 'PM10to20'
349                    else:
350                        aero_size = f"PM{int(first_size)}to{int(second_size)}"
351
352    # Add optical and wavelength information
353    var_wavelength = ''
354    if (hasattr(obj, 'parameterNumber') and
355        hasattr(obj, 'scaledValueOfFirstWavelength') and
356        hasattr(obj, 'scaledValueOfSecondWavelength')):
357
358        optical_type = str(obj.parameterNumber)
359        if obj.scaledValueOfFirstWavelength > 0:
360            first_wl = obj.scaledValueOfFirstWavelength
361            second_wl = obj.scaledValueOfSecondWavelength
362
363            # Special case for AE between 440-870nm
364            if optical_type == '111' and first_wl == 440 and second_wl == 870:
365                key = (optical_type, '440TO870')
366            else:
367                # Find matching wavelength band
368                for wl_key, wl_info in _OPTICAL_WAVELENGTH_MAPPING.items():
369                    if (wl_key[0] == optical_type and  # Check optical_type first
370                        int(wl_key[1]) == first_wl and
371                        (second_wl is None or int(wl_key[2]) == second_wl)):
372                        key = wl_key
373                        break
374                else:
375                    # If no match found, use raw values
376                    key = (optical_type, str(first_wl),
377                          str(second_wl) if second_wl is not None else '')
378
379            # FIX THIS...
380            if key in _OPTICAL_WAVELENGTH_MAPPING.keys():
381                var_wavelength = _OPTICAL_WAVELENGTH_MAPPING[key]
382
383    # Add level information
384    level_str = ''
385    if hasattr(obj, 'typeOfFirstFixedSurface'):
386        first_level = str(obj.typeOfFirstFixedSurface.value)
387        first_value = str(obj.scaledValueOfFirstFixedSurface) if obj.scaledValueOfFirstFixedSurface > 0 else ''
388        if first_level in _LEVEL_MAPPING:
389            level_str = f"{_LEVEL_MAPPING[first_level]}{first_value}"
390
391    # Get parameter type
392    param = ''
393    if hasattr(obj, 'parameterNumber'):
394        param_num = str(obj.parameterNumber)
395        if param_num in _PARAMETER_MAPPING:
396            param = _PARAMETER_MAPPING[param_num]
397
398    # Build the final shortname
399    if var_wavelength and aero_type in _AERO_TYPE_MAPPING:
400        shortname = f"{_AERO_TYPE_MAPPING[aero_type]}{var_wavelength}"
401    elif aero_type in _AERO_TYPE_MAPPING:
402        parts = []
403        if level_str:
404            parts.append(level_str)
405        parts.append(_AERO_TYPE_MAPPING[aero_type])
406        if aero_size:
407            parts.append(aero_size)
408        if param:
409            parts.append(param)
410        shortname = '_'.join(parts) if len(parts) > 1 else parts[0]
411    else:
412        return get_varinfo_from_table(obj.section0[2], *obj.section4[2:4], isNDFD=obj._isNDFD)[2]
413
414    return shortname
415
416
417@lru_cache(maxsize=None)
418def get_table_names(var_tables: bool=False) -> tuple:
419    """
420    Return the names of available GRIB2 tables.
421
422    The table dictionaries as they exist in grib2io are prefixed
423    with "table_". When accessing a table through the available
424    functions, the prefix is not necessary.
425
426    Parameters
427    ----------
428    var_tables : bool, optional
429        If True, include names of variable tables.
430        If False (default), include only non-variable tables.
431
432    Returns
433    -------
434    tuple of str
435        A tuple sorted names of available tables.
436    """
437    tables = [
438        name.replace("table_","") for name, val in globals().items()
439        if isinstance(val, dict) and name.startswith("table_")
440    ]
441
442    tables = [
443        t.replace("_",".") if t.startswith(tuple("0123456789")) else t for t in tables
444    ]
445
446    if var_tables:
447        for d in GRIB2_DISCIPLINES:
448            modname = f'.section4_discipline{d}'
449            _load_varinfo_tables(modname)
450        vt = [t.replace("table_","").replace("_",".") for t in _varinfo_tables_datastore.keys()]
451        tables.extend(vt)
452
453    return tuple(sorted(tables))
GRIB2_DISCIPLINES = [0, 1, 2, 3, 4, 10, 20, 209]
AEROSOL_PDTNS = [46, 48]
AEROSOL_PARAMS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 192, 193, 194, 195, 196]
def get_table(table: str, expand: bool = False) -> dict:
44def get_table(table: str, expand: bool=False) -> dict:
45    """
46    Return GRIB2 code table as a dictionary.
47
48    Parameters
49    ----------
50    table
51        Code table number (e.g. '1.0').
52
53        NOTE: Code table '4.1' requires a 3rd value representing the product
54        discipline (e.g. '4.1.0').
55    expand
56        If `True`, expand output dictionary wherever keys are a range.
57
58    Returns
59    -------
60    get_table
61        GRIB2 code table as a dictionary.
62    """
63    if len(table) == 3 and table == '4.1':
64        raise Exception('GRIB2 Code Table 4.1 requires a 3rd value representing the discipline.')
65    if len(table) == 3 and table.startswith('4.2'):
66        raise Exception('Use function get_varinfo_from_table() for GRIB2 Code Table 4.2')
67    try:
68        tbl = globals()['table_'+table.replace('.','_')]
69        if expand:
70            _tbl = {}
71            for k,v in tbl.items():
72                if '-' in k:
73                    irng = [int(i) for i in k.split('-')]
74                    for i in range(irng[0],irng[1]+1):
75                        _tbl[str(i)] = v
76                else:
77                    _tbl[k] = v
78            tbl = _tbl
79        return tbl
80    except(KeyError):
81        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]:
 84def get_value_from_table(
 85    value: Union[int, str],
 86    table: str,
 87    expand: bool = False,
 88) -> Optional[Union[float, int]]:
 89    """
 90    Return the definition given a GRIB2 code table.
 91
 92    Parameters
 93    ----------
 94    value
 95        Code table value.
 96    table
 97        Code table number.
 98    expand
 99        If `True`, expand output dictionary where keys are a range.
100
101    Returns
102    -------
103    get_value_from_table
104        Table value or `None` if not found.
105    """
106    try:
107        tbl = get_table(table,expand=expand)
108        value = str(value)
109        return tbl[value]
110    except(KeyError):
111        for k in tbl.keys():
112            if '-' in k:
113                bounds = k.split('-')
114                if value >= bounds[0] and value <= bounds[1]:
115                    return tbl[k]
116        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):
119def get_varinfo_from_table(
120    discipline: Union[int, str],
121    parmcat: Union[int, str],
122    parmnum: Union[int, str],
123    isNDFD: bool = False,
124):
125    """
126    Return the GRIB2 variable information.
127
128    NOTE: This functions allows for all arguments to be converted to a string
129    type if arguments are integer.
130
131    Parameters
132    ----------
133    discipline
134        Discipline code value of a GRIB2 message.
135    parmcat
136        Parameter Category value of a GRIB2 message.
137    parmnum
138        Parameter Number value of a GRIB2 message.
139    isNDFD: optional
140        If `True`, then attempt to get variable information from the
141        supplemental NDFD tables, otherwise fallback to default tables.
142
143    Returns
144    -------
145    full_name
146        Full name of the GRIB2 variable. "Unknown" if variable is not found.
147    units
148        Units of the GRIB2 variable. "Unknown" if variable is not found.
149    shortName
150        Abbreviated name of the GRIB2 variable. "Unknown" if variable is not
151        found.
152    """
153    template = f'table_4_2_{discipline}_{parmcat}'
154    tbls = []
155    if isNDFD:
156        tbls.append(template+'_ndfd')
157    tbls.append(template)
158    for tbl in tbls:
159        vartbl = None
160        modname = f'.section4_discipline{discipline}'
161        if tbl not in _varinfo_tables_datastore.keys():
162            _load_varinfo_tables(modname)
163        try:
164            vartbl = _varinfo_tables_datastore[tbl][str(parmnum)]
165        except(KeyError):
166            pass
167        if vartbl is not None:
168            break
169    if vartbl is None:
170        vartbl = ['Unknown','Unknown','Unknown']
171    return vartbl

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, then attempt to get variable information from the supplemental NDFD tables, otherwise fallback to default 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]:
174@lru_cache(maxsize=None)
175def get_shortnames(
176    discipline: Optional[Union[int, str]] = None,
177    parmcat: Optional[Union[int, str]] = None,
178    parmnum: Optional[Union[int, str]] = None,
179    isNDFD: bool = False,
180) -> List[str]:
181    """
182    Return a list of variable shortNames.
183
184    If all 3 args are None, then shortNames from all disciplines, parameter
185    categories, and numbers will be returned.
186
187    Parameters
188    ----------
189    discipline
190        GRIB2 discipline code value.
191    parmcat
192        GRIB2 parameter category value.
193    parmnum
194        Parameter Number value of a GRIB2 message.
195    isNDFD: optional
196        If `True`, signals function to try to get variable information from the
197        supplemental NDFD tables.
198
199    Returns
200    -------
201    get_shortnames
202        list of GRIB2 shortNames.
203    """
204    shortnames = list()
205    if discipline is None:
206        discipline = GRIB2_DISCIPLINES
207    else:
208        discipline = [discipline]
209    if parmcat is None:
210        parmcat = list()
211        for d in discipline:
212            parmcat += list(get_table(f'4.1.{d}').keys())
213    else:
214        parmcat = [parmcat]
215    if parmnum is None:
216        parmnum = list(range(256))
217    else:
218        parmnum = [parmnum]
219    for d in discipline:
220
221        for pc in parmcat:
222            for pn in parmnum:
223                shortnames.append(get_varinfo_from_table(d,pc,pn,isNDFD)[2])
224
225    shortnames = sorted(set(shortnames))
226    try:
227        shortnames.remove('unknown')
228        shortnames.remove('Unknown')
229    except(ValueError):
230        pass
231    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):
234@lru_cache(maxsize=None)
235def get_metadata_from_shortname(shortname: str):
236    """
237    Provide GRIB2 variable metadata attributes given a GRIB2 shortName.
238
239    Parameters
240    ----------
241    shortname
242        GRIB2 variable shortName.
243
244    Returns
245    -------
246    get_metadata_from_shortname
247        list of dictionary items where each dictionary item contains the
248        variable metadata key:value pairs.
249
250        NOTE: Some variable shortNames will exist in multiple parameter
251        category/number tables according to the GRIB2 discipline.
252    """
253    metadata = []
254    for d in GRIB2_DISCIPLINES:
255        parmcat = list(get_table(f'4.1.{d}').keys())
256        for pc in parmcat:
257            for pn in range(256):
258                varinfo = get_varinfo_from_table(d,pc,pn,False)
259                if shortname == varinfo[2]:
260                    metadata.append(dict(discipline=d,parameterCategory=pc,parameterNumber=pn,
261                                         fullName=varinfo[0],units=varinfo[1]))
262    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[Buffer, numpy._typing._array_like._SupportsArray[numpy.dtype[Any]], numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]]], complex, bytes, str, numpy._typing._nested_sequence._NestedSequence[complex | bytes | str]]) -> str:
265def get_wgrib2_level_string(pdtn: int, pdt: ArrayLike) -> str:
266    """
267    Return a string that describes the level or layer of the GRIB2 message.
268
269    The format and language of the string is an exact replica of how wgrib2
270    produces the level/layer string in its inventory output.
271
272    Contents of wgrib2 source,
273    [Level.c](https://github.com/NOAA-EMC/NCEPLIBS-wgrib2/blob/develop/wgrib2/Level.c),
274    were converted into a Python dictionary and stored in grib2io as table
275    'wgrib2_level_string'.
276
277    Parameters
278    ----------
279    pdtn
280        GRIB2 Product Definition Template Number
281    pdt
282        Sequence containing GRIB2 Product Definition Template (Section 4).
283
284    Returns
285    -------
286    get_wgrib2_level_string
287        wgrib2-formatted level/layer string.
288    """
289    lvlstr = ''
290    if pdtn == 32:
291        return 'no_level'
292    elif pdtn == 48:
293        idxs = slice(20,26)
294    else:
295        idxs = slice(9,15)
296    type1, sfac1, sval1, type2, sfac2, sval2 = map(int,pdt[idxs])
297    val1 = sval1/10**sfac1
298    if type1 in [100,108]: val1 *= 0.01
299    if type2 != 255:
300        # Layer
301        #assert type2 == type1, "Surface types are not equal: %g - %g" % (type1,type2)
302        val2 = sval2/10**sfac2
303        if type2 in [100,108]: val2 *= 0.01
304        lvlstr = get_value_from_table(type1,table='wgrib2_level_string')[1]
305        vals = (val1,val2)
306    else:
307        # Level
308        lvlstr = get_value_from_table(type1,table='wgrib2_level_string')[0]
309        vals = (val1)
310    if '%g' in lvlstr: lvlstr %= vals
311    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.
@lru_cache(maxsize=None)
def get_table_names(var_tables: bool = False) -> tuple:
418@lru_cache(maxsize=None)
419def get_table_names(var_tables: bool=False) -> tuple:
420    """
421    Return the names of available GRIB2 tables.
422
423    The table dictionaries as they exist in grib2io are prefixed
424    with "table_". When accessing a table through the available
425    functions, the prefix is not necessary.
426
427    Parameters
428    ----------
429    var_tables : bool, optional
430        If True, include names of variable tables.
431        If False (default), include only non-variable tables.
432
433    Returns
434    -------
435    tuple of str
436        A tuple sorted names of available tables.
437    """
438    tables = [
439        name.replace("table_","") for name, val in globals().items()
440        if isinstance(val, dict) and name.startswith("table_")
441    ]
442
443    tables = [
444        t.replace("_",".") if t.startswith(tuple("0123456789")) else t for t in tables
445    ]
446
447    if var_tables:
448        for d in GRIB2_DISCIPLINES:
449            modname = f'.section4_discipline{d}'
450            _load_varinfo_tables(modname)
451        vt = [t.replace("table_","").replace("_",".") for t in _varinfo_tables_datastore.keys()]
452        tables.extend(vt)
453
454    return tuple(sorted(tables))

Return the names of available GRIB2 tables.

The table dictionaries as they exist in grib2io are prefixed with "table_". When accessing a table through the available functions, the prefix is not necessary.

Parameters
  • var_tables (bool, optional): If True, include names of variable tables. If False (default), include only non-variable tables.
Returns
  • tuple of str: A tuple sorted names of available tables.