grib2io

Introduction

grib2io is a Python package that provides an interface to the NCEP GRIB2 C (g2c) library for the purpose of reading and writing WMO GRIdded Binary, Edition 2 (GRIB2) messages. A physical file can contain one or more GRIB2 messages.

GRIB2 file IO is performed directly in Python. The unpacking/packing of GRIB2 integer, coded metadata and data sections is performed by the g2c library functions via the g2clib Cython wrapper module. The decoding/encoding of GRIB2 metadata is translated into more descriptive, plain language metadata by looking up the integer code values against the appropriate GRIB2 code tables. These code tables are a part of the grib2io module.

 1from ._grib2io import *
 2from ._grib2io import __doc__
 3
 4try:
 5    from . import __config__
 6    __version__ = __config__.grib2io_version
 7except(ImportError):
 8    pass
 9
10__all__ = ['open','Grib2Message','Grib2Metadata','show_config','tables','utils']
11
12def show_config():
13    """
14    Print grib2io build configuration information.
15    """
16    from g2clib import __version__ as g2clib_version
17    have_jpeg = True if 'jasper' in __config__.libraries or 'openjp2' in __config__.libraries else False
18    have_png = True if 'png' in __config__.libraries else False
19    jpeglib = 'OpenJPEG' if 'openjp2' in __config__.libraries else ('Jasper' if 'jasper' in __config__.libraries else None)
20    pnglib = 'libpng' if 'png' in __config__.libraries else None
21    print("grib2io version %s Configuration:\n"%(__version__))
22    print("\tg2c library version:".expandtabs(4),g2clib_version)
23    print("\tJPEG compression support:".expandtabs(4),have_jpeg)
24    if have_jpeg: print("\t\tLibrary:".expandtabs(4),jpeglib)
25    print("\tPNG compression support:".expandtabs(4),have_png)
26    if have_png: print("\t\tLibrary:".expandtabs(4),pnglib)
class open:
 41class open():
 42    """
 43    GRIB2 File Object.  A physical file can contain one or more GRIB2 messages.  When instantiated,
 44    class `grib2io.open`, the file named `filename` is opened for reading (`mode = 'r'`) and is
 45    automatically indexed.  The indexing procedure reads some of the GRIB2 metadata for all GRIB2 Messages.
 46
 47    A GRIB2 Message may contain submessages whereby Section 2-7 can be repeated.  grib2io accommodates
 48    for this by flattening any GRIB2 submessages into multiple individual messages.
 49
 50    Attributes
 51    ----------
 52
 53    **`mode`**: File IO mode of opening the file.
 54
 55    **`name`**: Full path name of the GRIB2 file.
 56
 57    **`messages`**: Count of GRIB2 Messages contained in the file.
 58
 59    **`current_message`**: Current position of the file in units of GRIB2 Messages.
 60
 61    **`size`**: Size of the file in units of bytes.
 62
 63    **`closed`** `True` is file handle is close; `False` otherwise.
 64
 65    **`decode `**: If `True` [DEFAULT] automatically decode metadata from unpacked 
 66    section data for Grib2Messages.
 67
 68    **`variables`**: Tuple containing a unique list of variable short names (i.e. GRIB2 abbreviation names).
 69
 70    **`levels`**: Tuple containing a unique list of wgrib2-formatted level/layer strings.
 71    """
 72    def __init__(self, filename, mode='r', decode=True):
 73        """
 74        `open` Constructor
 75
 76        Parameters
 77        ----------
 78
 79        **`filename`**: File name containing GRIB2 messages.
 80
 81        **`mode `**: File access mode where `r` opens the files for reading only;
 82        `w` opens the file for writing.
 83
 84        **`decode `**: If `True` [DEFAULT] automatically decode metadata from 
 85        unpacked section data for Grib2Messages.
 86        """
 87        if mode in ['a','r','w']:
 88            mode = mode+'b'
 89        self._filehandle = builtins.open(filename,mode=mode,buffering=ONE_MB)
 90        self._hasindex = False
 91        self._index = {}
 92        self.mode = mode
 93        self.name = os.path.abspath(filename)
 94        self.messages = 0
 95        self.current_message = 0
 96        self.size = os.path.getsize(self.name)
 97        self.closed = self._filehandle.closed
 98        self.decode = decode
 99        if 'r' in self.mode: self._build_index()
100        # FIX: Cannot perform reads on mode='a'
101        #if 'a' in self.mode and self.size > 0: self._build_index()
102        if self._hasindex:
103            self.variables = tuple(sorted(set(filter(None,self._index['shortName']))))
104            self.levels = tuple(sorted(set(filter(None,self._index['levelString']))))
105
106
107    def __delete__(self, instance):
108        """
109        """
110        self.close()
111        del self._index
112
113
114    def __enter__(self):
115        """
116        """
117        return self
118
119
120    def __exit__(self, atype, value, traceback):
121        """
122        """
123        self.close()
124
125
126    def __iter__(self):
127        """
128        """
129        return self
130
131
132    def __next__(self):
133        """
134        """
135        if self.current_message < self.messages:
136            return self.read()[0]
137        else:
138            self.seek(0)
139            raise StopIteration
140
141
142    def __repr__(self):
143        """
144        """
145        strings = []
146        keys = self.__dict__.keys()
147        for k in keys:
148            if not k.startswith('_'):
149                strings.append('%s = %s\n'%(k,self.__dict__[k]))
150        return ''.join(strings)
151
152
153    def __getitem__(self, key):
154        """
155        """
156        if isinstance(key,slice):
157            if key.start is None and key.stop is None and key.step is None:
158                beg = 1
159                end = self.messages+1
160                inc = 1
161            else:
162                beg, end, inc = key.indices(self.messages)
163            return [self[i][0] for i in range(beg,end,inc)]
164        elif isinstance(key,int):
165            if key == 0: return None
166            self._filehandle.seek(self._index['offset'][key])
167            return [Grib2Message(msg=self._filehandle.read(self._index['size'][key]),
168                                 source=self,
169                                 num=self._index['messageNumber'][key],
170                                 decode=self.decode)]
171        elif isinstance(key,str):
172            return self.select(shortName=key)
173        else:
174            raise KeyError('Key must be an integer, slice, or GRIB2 variable shortName.')
175
176
177    def _build_index(self):
178        """
179        Perform indexing of GRIB2 Messages.
180        """
181        # Initialize index dictionary
182        self._index['offset'] = [None]
183        self._index['discipline'] = [None]
184        self._index['edition'] = [None]
185        self._index['size'] = [None]
186        self._index['submessageOffset'] = [None]
187        self._index['submessageBeginSection'] = [None]
188        self._index['isSubmessage'] = [None]
189        self._index['messageNumber'] = [None]
190        self._index['identificationSection'] = [None]
191        self._index['refDate'] = [None]
192        self._index['productDefinitionTemplateNumber'] = [None]
193        self._index['productDefinitionTemplate'] = [None]
194        self._index['leadTime'] = [None]
195        self._index['duration'] = [None]
196        self._index['shortName'] = [None]
197        self._index['bitMap'] = [None]
198        self._index['levelString'] = [None]
199        self._index['probString'] = [None]
200
201        # Iterate
202        while True:
203            try:
204                # Read first 4 bytes and decode...looking for "GRIB"
205                pos = self._filehandle.tell()
206                header = struct.unpack('>4s',self._filehandle.read(4))[0].decode()
207
208                # Test header. Then get information from GRIB2 Section 0: the discipline
209                # number, edition number (should always be 2), and GRIB2 message size.
210                # Then iterate to check for submessages.
211                if header == 'GRIB':
212                    _issubmessage = False
213                    _submsgoffset = 0
214                    _submsgbegin = 0
215
216                    # Read and unpack Section 0. Note that this is not done through
217                    # the g2clib.
218                    self._filehandle.seek(self._filehandle.tell()+2)
219                    discipline = int(struct.unpack('>B',self._filehandle.read(1))[0])
220                    edition = int(struct.unpack('>B',self._filehandle.read(1))[0])
221                    assert edition == 2
222                    size = struct.unpack('>Q',self._filehandle.read(8))[0]
223
224                    # Read and unpack Section 1
225                    secsize = struct.unpack('>i',self._filehandle.read(4))[0]
226                    secnum = struct.unpack('>B',self._filehandle.read(1))[0]
227                    assert secnum == 1
228                    self._filehandle.seek(self._filehandle.tell()-5)
229                    _grbmsg = self._filehandle.read(secsize)
230                    _grbpos = 0
231                    _grbsec1,_grbpos = g2clib.unpack1(_grbmsg,_grbpos,np.empty)
232                    _grbsec1 = _grbsec1.tolist()
233                    _refdate = utils.getdate(_grbsec1[5],_grbsec1[6],_grbsec1[7],_grbsec1[8])
234                    secrange = range(2,8)
235                    while 1:
236                        for num in secrange:
237                            secsize = struct.unpack('>i',self._filehandle.read(4))[0]
238                            secnum = struct.unpack('>B',self._filehandle.read(1))[0]
239                            if secnum == num:
240                                if secnum == 3:
241                                    self._filehandle.seek(self._filehandle.tell()-5)
242                                    _grbmsg = self._filehandle.read(secsize)
243                                    _grbpos = 0
244                                    # Unpack Section 3
245                                    _gds,_gdtn,_deflist,_grbpos = g2clib.unpack3(_grbmsg,_grbpos,np.empty)
246                                elif secnum == 4:
247                                    self._filehandle.seek(self._filehandle.tell()-5)
248                                    _grbmsg = self._filehandle.read(secsize)
249                                    _grbpos = 0
250                                    # Unpack Section 4
251                                    _pdt,_pdtnum,_coordlist,_grbpos = g2clib.unpack4(_grbmsg,_grbpos,np.empty)
252                                    _pdt = _pdt.tolist()
253                                    _varinfo = tables.get_varinfo_from_table(discipline,_pdt[0],_pdt[1])
254                                elif secnum == 6:
255                                    self._filehandle.seek(self._filehandle.tell()-5)
256                                    _grbmsg = self._filehandle.read(secsize)
257                                    _grbpos = 0
258                                    # Unpack Section 6. Save bitmap
259                                    _bmap,_bmapflag = g2clib.unpack6(_grbmsg,_gds[1],_grbpos,np.empty)
260                                    if _bmapflag == 0:
261                                        _bmap_save = copy.deepcopy(_bmap)
262                                    elif _bmapflag == 254:
263                                        _bmap = copy.deepcopy(_bmap_save)
264                                else:
265                                    self._filehandle.seek(self._filehandle.tell()+secsize-5)
266                            else:
267                                if num == 2 and secnum == 3:
268                                    pass # Allow this.  Just means no Local Use Section.
269                                else:
270                                    _issubmessage = True
271                                    _submsgoffset = (self._filehandle.tell()-5)-(self._index['offset'][self.messages])
272                                    _submsgbegin = secnum
273                                self._filehandle.seek(self._filehandle.tell()-5)
274                                continue
275                        trailer = struct.unpack('>4s',self._filehandle.read(4))[0].decode()
276                        if trailer == '7777':
277                            self.messages += 1
278                            self._index['offset'].append(pos)
279                            self._index['discipline'].append(discipline)
280                            self._index['edition'].append(edition)
281                            self._index['size'].append(size)
282                            self._index['messageNumber'].append(self.messages)
283                            self._index['isSubmessage'].append(_issubmessage)
284                            self._index['identificationSection'].append(_grbsec1)
285                            self._index['refDate'].append(_refdate)
286                            self._index['productDefinitionTemplateNumber'].append(_pdtnum)
287                            self._index['productDefinitionTemplate'].append(_pdt)
288                            self._index['leadTime'].append(utils.getleadtime(_grbsec1,_pdtnum,_pdt))
289                            self._index['duration'].append(utils.getduration(_pdtnum,_pdt))
290                            self._index['shortName'].append(_varinfo[2])
291                            self._index['bitMap'].append(_bmap)
292                            self._index['levelString'].append(tables.get_wgrib2_level_string(*_pdt[9:15]))
293                            if _pdtnum in [5,9]:
294                                self._index['probString'].append(utils.get_wgrib2_prob_string(*_pdt[17:22]))
295                            else:
296                                self._index['probString'].append('')
297                            if _issubmessage:
298                                self._index['submessageOffset'].append(_submsgoffset)
299                                self._index['submessageBeginSection'].append(_submsgbegin)
300                            else:
301                                self._index['submessageOffset'].append(0)
302                                self._index['submessageBeginSection'].append(_submsgbegin)
303                            break
304                        else:
305                            self._filehandle.seek(self._filehandle.tell()-4)
306                            self.messages += 1
307                            self._index['offset'].append(pos)
308                            self._index['discipline'].append(discipline)
309                            self._index['edition'].append(edition)
310                            self._index['size'].append(size)
311                            self._index['messageNumber'].append(self.messages)
312                            self._index['isSubmessage'].append(_issubmessage)
313                            self._index['identificationSection'].append(_grbsec1)
314                            self._index['refDate'].append(_refdate)
315                            self._index['productDefinitionTemplateNumber'].append(_pdtnum)
316                            self._index['productDefinitionTemplate'].append(_pdt)
317                            self._index['leadTime'].append(utils.getleadtime(_grbsec1,_pdtnum,_pdt))
318                            self._index['duration'].append(utils.getduration(_pdtnum,_pdt))
319                            self._index['shortName'].append(_varinfo[2])
320                            self._index['bitMap'].append(_bmap)
321                            self._index['levelString'].append(tables.get_wgrib2_level_string(*_pdt[9:15]))
322                            if _pdtnum in [5,9]:
323                                self._index['probString'].append(utils.get_wgrib2_prob_string(*_pdt[17:22]))
324                            else:
325                                self._index['probString'].append('')
326                            self._index['submessageOffset'].append(_submsgoffset)
327                            self._index['submessageBeginSection'].append(_submsgbegin)
328                            continue
329
330            except(struct.error):
331                self._filehandle.seek(0)
332                break
333
334        self._hasindex = True
335
336
337    def close(self):
338        """
339        Close the file handle
340        """
341        if not self._filehandle.closed:
342            self._filehandle.close()
343            self.closed = self._filehandle.closed
344
345
346    def read(self, num=1):
347        """    
348        Read num GRIB2 messages from the current position
349
350        Parameters
351        ----------
352
353        **`num`**: integer number of GRIB2 Message to read.
354
355        Returns
356        -------
357
358        **`list`**: list of `grib2io.Grib2Message` instances.
359        """
360        msgs = []
361        if self.tell() >= self.messages: return msgs
362        if num > 0:
363            if num == 1:
364                msgrange = [self.tell()+1]
365            else:
366                beg = self.tell()+1
367                end = self.tell()+1+num if self.tell()+1+num <= self.messages else self.messages
368                msgrange = range(beg,end+1)
369            for n in msgrange:
370                self._filehandle.seek(self._index['offset'][n])
371                msgs.append(Grib2Message(msg=self._filehandle.read(self._index['size'][n]),
372                                         source=self,
373                                         num=self._index['messageNumber'][n],
374                                         decode=self.decode))
375                self.current_message += 1
376        return msgs
377
378
379    def rewind(self):
380        """
381        Set the position of the file to zero in units of GRIB2 messages.
382        """
383        self.seek(0)
384
385
386    def seek(self, pos):
387        """
388        Set the position within the file in units of GRIB2 messages.
389
390        Parameters
391        ----------
392
393        **`pos`**: GRIB2 Message number to set the read pointer to.
394        """
395        if self._hasindex:
396            if pos == 0:
397                self._filehandle.seek(pos)
398                self.current_message = pos
399            elif pos > 0:
400                self._filehandle.seek(self._index['offset'][pos-1])
401                self.current_message = pos
402
403
404    def tell(self):
405        """
406        Returns the position of the file in units of GRIB2 Messages.
407        """
408        return self.current_message
409
410
411    def select(self,**kwargs):
412        """
413        Returns a list of `grib2io.Grib2Message` instances based on the selection **`**kwargs`**.
414
415        The following keywords are currently supported:
416
417        **`duration : int`** specifiying the time duration (in unit of hours) of a GRIB2 Message that is 
418        determined from a period of time.
419
420        **`leadTime : int`** specifying ending lead time (in units of hours) of a GRIB2 Message.
421
422        **`level : str`** wgrib2-formatted layer/level string.
423
424        **`percentile : int`** specify the percentile value.
425
426        **`refDate : int`** specifying the reference date in `YYYYMMDDHH[MMSS]` format.
427
428        **`shortName : str`** the GRIB2 `shortName`.  This is the abbreviation name found in the NCEP GRIB2 tables.
429
430        **`threshold : str`** wgrib2-formatted probability threshold string.
431        """
432        kwargs_allowed = ['duration','leadTime','level','percentile','refDate','shortName','threshold']
433        idxs = {}
434        for k,v in kwargs.items():
435            if k not in kwargs_allowed: continue
436            if k == 'duration':
437                idxs[k] = np.where(np.asarray([i if i is not None else None for i in self._index['duration']])==v)[0]
438            elif k == 'leadTime':
439                idxs[k] = np.where(np.asarray([i if i is not None else None for i in self._index['leadTime']])==v)[0]
440            elif k == 'level':
441                idxs[k] = np.where(np.array(self._index['levelString'])==v)[0]
442            elif k == 'percentile':
443                tmp1 = np.where(np.asarray(self._index["productDefinitionTemplateNumber"])==6)[0]
444                tmp2 = np.where(np.asarray(self._index["productDefinitionTemplateNumber"])==10)[0]
445                idxs[k] = [i for i in np.concatenate((tmp1,tmp2)) if self._index["productDefinitionTemplate"][i][15]==v]
446                del tmp1,tmp2
447            elif k == 'refDate':
448                idxs[k] = np.where(np.asarray(self._index['refDate'])==v)[0]
449            elif k == 'shortName':
450                idxs[k] = np.where(np.array(self._index['shortName'])==v)[0]
451            elif k == 'threshold':
452                idxs[k] = np.where(np.array(self._index['probString'])==v)[0]
453        idxsarr = np.concatenate(tuple(idxs.values()))
454        nidxs = len(idxs.keys())
455        if nidxs == 1:
456            return [self[int(i)][0] for i in idxsarr]
457        elif nidxs > 1:
458            return [self[int(i)][0] for i in [ii[0] for ii in collections.Counter(idxsarr).most_common() if ii[1] == nidxs]]
459
460
461    def write(self, msg):
462        """
463        Writes a packed GRIB2 message to file.
464
465        Parameters
466        ----------
467
468        **`msg`**: instance of `Grib2Message`.
469        """
470        if isinstance(msg,Grib2Message):
471            self._filehandle.write(msg._msg)
472            self.size = os.path.getsize(self.name)
473            self.messages += 1
474            self.current_message += 1
475        else:
476            raise TypeError("msg must be a Grib2Message object.")

GRIB2 File Object. A physical file can contain one or more GRIB2 messages. When instantiated, class grib2io.open, the file named filename is opened for reading (mode = 'r') and is automatically indexed. The indexing procedure reads some of the GRIB2 metadata for all GRIB2 Messages.

A GRIB2 Message may contain submessages whereby Section 2-7 can be repeated. grib2io accommodates for this by flattening any GRIB2 submessages into multiple individual messages.

Attributes

mode: File IO mode of opening the file.

name: Full path name of the GRIB2 file.

messages: Count of GRIB2 Messages contained in the file.

current_message: Current position of the file in units of GRIB2 Messages.

size: Size of the file in units of bytes.

closed True is file handle is close; False otherwise.

decode: If True [DEFAULT] automatically decode metadata from unpacked section data for Grib2Messages.

variables: Tuple containing a unique list of variable short names (i.e. GRIB2 abbreviation names).

levels: Tuple containing a unique list of wgrib2-formatted level/layer strings.

open(filename, mode='r', decode=True)
 72    def __init__(self, filename, mode='r', decode=True):
 73        """
 74        `open` Constructor
 75
 76        Parameters
 77        ----------
 78
 79        **`filename`**: File name containing GRIB2 messages.
 80
 81        **`mode `**: File access mode where `r` opens the files for reading only;
 82        `w` opens the file for writing.
 83
 84        **`decode `**: If `True` [DEFAULT] automatically decode metadata from 
 85        unpacked section data for Grib2Messages.
 86        """
 87        if mode in ['a','r','w']:
 88            mode = mode+'b'
 89        self._filehandle = builtins.open(filename,mode=mode,buffering=ONE_MB)
 90        self._hasindex = False
 91        self._index = {}
 92        self.mode = mode
 93        self.name = os.path.abspath(filename)
 94        self.messages = 0
 95        self.current_message = 0
 96        self.size = os.path.getsize(self.name)
 97        self.closed = self._filehandle.closed
 98        self.decode = decode
 99        if 'r' in self.mode: self._build_index()
100        # FIX: Cannot perform reads on mode='a'
101        #if 'a' in self.mode and self.size > 0: self._build_index()
102        if self._hasindex:
103            self.variables = tuple(sorted(set(filter(None,self._index['shortName']))))
104            self.levels = tuple(sorted(set(filter(None,self._index['levelString']))))

open Constructor

Parameters

filename: File name containing GRIB2 messages.

mode: File access mode where r opens the files for reading only; w opens the file for writing.

decode: If True [DEFAULT] automatically decode metadata from unpacked section data for Grib2Messages.

def close(self)
337    def close(self):
338        """
339        Close the file handle
340        """
341        if not self._filehandle.closed:
342            self._filehandle.close()
343            self.closed = self._filehandle.closed

Close the file handle

def read(self, num=1)
346    def read(self, num=1):
347        """    
348        Read num GRIB2 messages from the current position
349
350        Parameters
351        ----------
352
353        **`num`**: integer number of GRIB2 Message to read.
354
355        Returns
356        -------
357
358        **`list`**: list of `grib2io.Grib2Message` instances.
359        """
360        msgs = []
361        if self.tell() >= self.messages: return msgs
362        if num > 0:
363            if num == 1:
364                msgrange = [self.tell()+1]
365            else:
366                beg = self.tell()+1
367                end = self.tell()+1+num if self.tell()+1+num <= self.messages else self.messages
368                msgrange = range(beg,end+1)
369            for n in msgrange:
370                self._filehandle.seek(self._index['offset'][n])
371                msgs.append(Grib2Message(msg=self._filehandle.read(self._index['size'][n]),
372                                         source=self,
373                                         num=self._index['messageNumber'][n],
374                                         decode=self.decode))
375                self.current_message += 1
376        return msgs

Read num GRIB2 messages from the current position

Parameters

num: integer number of GRIB2 Message to read.

Returns

list: list of grib2io.Grib2Message instances.

def rewind(self)
379    def rewind(self):
380        """
381        Set the position of the file to zero in units of GRIB2 messages.
382        """
383        self.seek(0)

Set the position of the file to zero in units of GRIB2 messages.

def seek(self, pos)
386    def seek(self, pos):
387        """
388        Set the position within the file in units of GRIB2 messages.
389
390        Parameters
391        ----------
392
393        **`pos`**: GRIB2 Message number to set the read pointer to.
394        """
395        if self._hasindex:
396            if pos == 0:
397                self._filehandle.seek(pos)
398                self.current_message = pos
399            elif pos > 0:
400                self._filehandle.seek(self._index['offset'][pos-1])
401                self.current_message = pos

Set the position within the file in units of GRIB2 messages.

Parameters

pos: GRIB2 Message number to set the read pointer to.

def tell(self)
404    def tell(self):
405        """
406        Returns the position of the file in units of GRIB2 Messages.
407        """
408        return self.current_message

Returns the position of the file in units of GRIB2 Messages.

def select(self, **kwargs)
411    def select(self,**kwargs):
412        """
413        Returns a list of `grib2io.Grib2Message` instances based on the selection **`**kwargs`**.
414
415        The following keywords are currently supported:
416
417        **`duration : int`** specifiying the time duration (in unit of hours) of a GRIB2 Message that is 
418        determined from a period of time.
419
420        **`leadTime : int`** specifying ending lead time (in units of hours) of a GRIB2 Message.
421
422        **`level : str`** wgrib2-formatted layer/level string.
423
424        **`percentile : int`** specify the percentile value.
425
426        **`refDate : int`** specifying the reference date in `YYYYMMDDHH[MMSS]` format.
427
428        **`shortName : str`** the GRIB2 `shortName`.  This is the abbreviation name found in the NCEP GRIB2 tables.
429
430        **`threshold : str`** wgrib2-formatted probability threshold string.
431        """
432        kwargs_allowed = ['duration','leadTime','level','percentile','refDate','shortName','threshold']
433        idxs = {}
434        for k,v in kwargs.items():
435            if k not in kwargs_allowed: continue
436            if k == 'duration':
437                idxs[k] = np.where(np.asarray([i if i is not None else None for i in self._index['duration']])==v)[0]
438            elif k == 'leadTime':
439                idxs[k] = np.where(np.asarray([i if i is not None else None for i in self._index['leadTime']])==v)[0]
440            elif k == 'level':
441                idxs[k] = np.where(np.array(self._index['levelString'])==v)[0]
442            elif k == 'percentile':
443                tmp1 = np.where(np.asarray(self._index["productDefinitionTemplateNumber"])==6)[0]
444                tmp2 = np.where(np.asarray(self._index["productDefinitionTemplateNumber"])==10)[0]
445                idxs[k] = [i for i in np.concatenate((tmp1,tmp2)) if self._index["productDefinitionTemplate"][i][15]==v]
446                del tmp1,tmp2
447            elif k == 'refDate':
448                idxs[k] = np.where(np.asarray(self._index['refDate'])==v)[0]
449            elif k == 'shortName':
450                idxs[k] = np.where(np.array(self._index['shortName'])==v)[0]
451            elif k == 'threshold':
452                idxs[k] = np.where(np.array(self._index['probString'])==v)[0]
453        idxsarr = np.concatenate(tuple(idxs.values()))
454        nidxs = len(idxs.keys())
455        if nidxs == 1:
456            return [self[int(i)][0] for i in idxsarr]
457        elif nidxs > 1:
458            return [self[int(i)][0] for i in [ii[0] for ii in collections.Counter(idxsarr).most_common() if ii[1] == nidxs]]

Returns a list of grib2io.Grib2Message instances based on the selection **kwargs.

The following keywords are currently supported:

duration : int specifiying the time duration (in unit of hours) of a GRIB2 Message that is determined from a period of time.

leadTime : int specifying ending lead time (in units of hours) of a GRIB2 Message.

level : str wgrib2-formatted layer/level string.

percentile : int specify the percentile value.

refDate : int specifying the reference date in YYYYMMDDHH[MMSS] format.

shortName : str the GRIB2 shortName. This is the abbreviation name found in the NCEP GRIB2 tables.

threshold : str wgrib2-formatted probability threshold string.

def write(self, msg)
461    def write(self, msg):
462        """
463        Writes a packed GRIB2 message to file.
464
465        Parameters
466        ----------
467
468        **`msg`**: instance of `Grib2Message`.
469        """
470        if isinstance(msg,Grib2Message):
471            self._filehandle.write(msg._msg)
472            self.size = os.path.getsize(self.name)
473            self.messages += 1
474            self.current_message += 1
475        else:
476            raise TypeError("msg must be a Grib2Message object.")

Writes a packed GRIB2 message to file.

Parameters

msg: instance of Grib2Message.

class Grib2Message:
 479class Grib2Message:
 480    def __init__(self, msg=None, source=None, num=-1, decode=True, discipline=None, idsect=None):
 481        """
 482        Class Constructor. Instantiation of this class can handle a GRIB2 message from an existing 
 483        file or the creation of new GRIB2 message.  To create a new GRIB2 message, provide the 
 484        appropriate values to the arguments `discipline` and `idsect`.  When these 2 arguments 
 485        are not `None`, then a new GRIB2 message is created. NOTE: All other keyword arguments 
 486        are ignored when a new message is created.
 487
 488        ...
 489
 490        Parameters
 491        ----------
 492
 493        **`msg`**: Binary string representing the GRIB2 Message read from file.
 494
 495        **`source`**: Source of where where this GRIB2 message originated 
 496        from (i.e. the input file). This allow for interaction with the 
 497        instance of `grib2io.open`. Default is None.
 498
 499        **`num`**: integer GRIB2 Message number from `grib2io.open`. Default value is -1.
 500
 501        **`decode`**: If True [DEFAULT], decode GRIB2 section lists into metadata 
 502        instance variables.
 503
 504        **`discipline`**: integer GRIB2 Discipline [GRIB2 Table 0.0](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table0-0.shtml)
 505
 506        **`idsect`**: Sequence containing GRIB1 Identification Section values (Section 1).
 507
 508        | Index | Description |
 509        | :---: | :---        |
 510        | idsect[0] | Id of orginating centre - [ON388 - Table 0](https://www.nco.ncep.noaa.gov/pmb/docs/on388/table0.html)|
 511        | idsect[1] | Id of orginating sub-centre - [ON388 - Table C](https://www.nco.ncep.noaa.gov/pmb/docs/on388/tablec.html)|
 512        | idsect[2] | GRIB Master Tables Version Number - [Code Table 1.0](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table1-0.shtml)|
 513        | idsect[3] | GRIB Local Tables Version Number - [Code Table 1.1](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table1-1.shtml)|
 514        | idsect[4] | Significance of Reference Time - [Code Table 1.2](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table1-2.shtml)|
 515        | idsect[5] | Reference Time - Year (4 digits)|
 516        | idsect[6] | Reference Time - Month|
 517        | idsect[7] | Reference Time - Day|
 518        | idsect[8] | Reference Time - Hour|
 519        | idsect[9] | Reference Time - Minute|
 520        | idsect[10] | Reference Time - Second|
 521        | idsect[11] | Production status of data - [Code Table 1.3](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table1-3.shtml)|
 522        | idsect[12] | Type of processed data - [Code Table 1.4](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table1-4.shtml)|
 523        """
 524        self._source = source
 525        self._msgnum = num
 526        self._decode = decode
 527        self._pos = 0
 528        self._datapos = 0
 529        self._sections = []
 530        self.hasLocalUseSection = False
 531        self.isNDFD = False
 532        if discipline is not None and idsect is not None:
 533            # New message
 534            self._msg,self._pos = g2clib.grib2_create(np.array([discipline,GRIB2_EDITION_NUMBER],DEFAULT_NUMPY_INT),
 535                                                      np.array(idsect,DEFAULT_NUMPY_INT))
 536            self._sections += [0,1]
 537        else:
 538            # Existing message
 539            self._msg = msg
 540        #self.md5 = {}
 541        if self._msg is not None and self._source is not None: self.unpack()
 542
 543    def __repr__(self):
 544        """
 545        """
 546        strings = []
 547        for k,v in self.__dict__.items():
 548            if k.startswith('_'): continue
 549            if isinstance(v,str):
 550                strings.append('%s = \'%s\'\n'%(k,v))
 551            elif isinstance(v,int):
 552                strings.append('%s = %d\n'%(k,v))
 553            elif isinstance(v,float):
 554                strings.append('%s = %f\n'%(k,v))
 555            else:
 556                strings.append('%s = %s\n'%(k,v))
 557        return ''.join(strings)
 558
 559
 560    def unpack(self):
 561        """
 562        Unpacks GRIB2 section data from the packed, binary message.
 563        """
 564        # Section 0 - Indicator Section
 565        self.indicatorSection = []
 566        self.indicatorSection.append(struct.unpack('>4s',self._msg[0:4])[0])
 567        self.indicatorSection.append(struct.unpack('>H',self._msg[4:6])[0])
 568        self.indicatorSection.append(self._msg[6])
 569        self.indicatorSection.append(self._msg[7])
 570        self.indicatorSection.append(struct.unpack('>Q',self._msg[8:16])[0])
 571        self._pos = 16
 572        self._sections.append(0)
 573        #self.md5[0] = _getmd5str(self.indicatorSection)
 574
 575        # Section 1 - Identification Section via g2clib.unpack1()
 576        self.identificationSection,self._pos = g2clib.unpack1(self._msg,self._pos,np.empty)
 577        self.identificationSection = self.identificationSection.tolist()
 578        self._sections.append(1)
 579        if self.identificationSection[0:2] == [8,65535]: self.isNDFD = True
 580
 581        # After Section 1, perform rest of GRIB2 Decoding inside while loop
 582        # to account for sub-messages.
 583        sectnum = 1
 584        while True:
 585            if self._msg[self._pos:self._pos+4].decode('ascii','ignore') == '7777':
 586                break
 587
 588            # Read the length and section number.
 589            sectlen = struct.unpack('>i',self._msg[self._pos:self._pos+4])[0]
 590            prevsectnum = sectnum
 591            sectnum = struct.unpack('>B',self._msg[self._pos+4:self._pos+5])[0]
 592
 593            # If the previous section number is > current section number, then
 594            # we have encountered a submessage.
 595            if prevsectnum > sectnum: break
 596
 597            # Handle submessage accordingly.
 598            if isinstance(self._source,open):
 599                if self._source._index['isSubmessage'][self._msgnum]:
 600                    if sectnum == self._source._index['submessageBeginSection'][self._msgnum]:
 601                        self._pos = self._source._index['submessageOffset'][self._msgnum]
 602
 603            # Section 2 - Local Use Section.
 604            if sectnum == 2:
 605                self._lus = self._msg[self._pos+5:self._pos+sectlen]
 606                self._pos += sectlen
 607                self.hasLocalUseSection = True
 608                self._sections.append(2)
 609                #self.md5[2] = _getmd5str(self.identificationSection)
 610
 611            # Section 3 - Grid Definition Section.
 612            elif sectnum == 3:
 613                _gds,_gdt,_deflist,self._pos = g2clib.unpack3(self._msg,self._pos,np.empty)
 614                self.gridDefinitionSection = _gds.tolist()
 615                self.gridDefinitionTemplateNumber = Grib2Metadata(int(_gds[4]),table='3.1')
 616                self.gridDefinitionTemplate = _gdt.tolist()
 617                self.defList = _deflist.tolist()
 618                self._sections.append(3)
 619                #self.md5[3] = _getmd5str([self.gridDefinitionTemplateNumber]+self.gridDefinitionTemplate)
 620
 621            # Section 4 - Product Definition Section.
 622            elif sectnum == 4:
 623                _pdt,_pdtn,_coordlst,self._pos = g2clib.unpack4(self._msg,self._pos,np.empty)
 624                self.productDefinitionTemplate = _pdt.tolist()
 625                self.productDefinitionTemplateNumber = Grib2Metadata(int(_pdtn),table='4.0')
 626                self.coordinateList = _coordlst.tolist()
 627                self._sections.append(4)
 628                #self.md5[4] = _getmd5str([self.productDefinitionTemplateNumber]+self.productDefinitionTemplate)
 629
 630            # Section 5 - Data Representation Section.
 631            elif sectnum == 5:
 632                _drt,_drtn,_npts,self._pos = g2clib.unpack5(self._msg,self._pos,np.empty)
 633                self.dataRepresentationTemplate = _drt.tolist()
 634                self.dataRepresentationTemplateNumber = Grib2Metadata(int(_drtn),table='5.0')
 635                self.numberOfDataPoints = _npts
 636                self._sections.append(5)
 637                #self.md5[5] = _getmd5str([self.dataRepresentationTemplateNumber]+self.dataRepresentationTemplate)
 638
 639            # Section 6 - Bitmap Section.
 640            elif sectnum == 6:
 641                _bmap,_bmapflag = g2clib.unpack6(self._msg,self.gridDefinitionSection[1],self._pos,np.empty)
 642                self.bitMapFlag = _bmapflag
 643                if self.bitMapFlag == 0:
 644                    self.bitMap = _bmap
 645                elif self.bitMapFlag == 254:
 646                    # Value of 254 says to use a previous bitmap in the file.
 647                    self.bitMapFlag = 0
 648                    if isinstance(self._source,open):
 649                        self.bitMap = self._source._index['bitMap'][self._msgnum]
 650                self._pos += sectlen # IMPORTANT: This is here because g2clib.unpack6() does not return updated position.
 651                self._sections.append(6)
 652                #self.md5[6] = None
 653
 654            # Section 7 - Data Section (data unpacked when data() method is invoked).
 655            elif sectnum == 7:
 656                self._datapos = self._pos
 657                self._pos += sectlen # REMOVE THIS WHEN UNPACKING DATA IS IMPLEMENTED
 658                self._sections.append(7)
 659                #self.md5[7] = _getmd5str(self._msg[self._datapos:sectlen+1])
 660
 661            else:
 662                errmsg = 'Unknown section number = %i' % sectnum
 663                raise ValueError(errmsg)
 664
 665        if self._decode: self.decode()
 666
 667    def decode(self):
 668        """
 669        Decode the unpacked GRIB2 integer-coded metadata in human-readable form and linked to GRIB2 tables.
 670        """
 671
 672        # Section 0 - Indictator Section
 673        self.discipline = Grib2Metadata(self.indicatorSection[2],table='0.0')
 674
 675        # Section 1 - Indentification Section.
 676        self.originatingCenter = Grib2Metadata(self.identificationSection[0],table='originating_centers')
 677        self.originatingSubCenter = Grib2Metadata(self.identificationSection[1],table='originating_subcenters')
 678        self.masterTableInfo = Grib2Metadata(self.identificationSection[2],table='1.0')
 679        self.localTableInfo = Grib2Metadata(self.identificationSection[3],table='1.1')
 680        self.significanceOfReferenceTime = Grib2Metadata(self.identificationSection[4],table='1.2')
 681        self.year = self.identificationSection[5]
 682        self.month = self.identificationSection[6]
 683        self.day = self.identificationSection[7]
 684        self.hour = self.identificationSection[8]
 685        self.minute = self.identificationSection[9]
 686        self.second = self.identificationSection[10]
 687        self.refDate = (self.year*1000000)+(self.month*10000)+(self.day*100)+self.hour
 688        self.dtReferenceDate = datetime.datetime(self.year,self.month,self.day,
 689                                                 hour=self.hour,minute=self.minute,
 690                                                 second=self.second)
 691        self.productionStatus = Grib2Metadata(self.identificationSection[11],table='1.3')
 692        self.typeOfData = Grib2Metadata(self.identificationSection[12],table='1.4')
 693
 694        # ----------------------------
 695        # Section 3 -- Grid Definition
 696        # ----------------------------
 697
 698        # Set shape of the Earth parameters
 699        if self.gridDefinitionTemplateNumber.value in [50,51,52,1200]:
 700            earthparams = None
 701        else:
 702            earthparams = tables.earth_params[str(self.gridDefinitionTemplate[0])]
 703        if earthparams['shape'] == 'spherical':
 704            if earthparams['radius'] is None:
 705                self.earthRadius = self.gridDefinitionTemplate[2]/(10.**self.gridDefinitionTemplate[1])
 706                self.earthMajorAxis = None
 707                self.earthMinorAxis = None
 708            else:
 709                self.earthRadius = earthparams['radius']
 710                self.earthMajorAxis = None
 711                self.earthMinorAxis = None
 712        elif earthparams['shape'] == 'oblateSpheroid':
 713            if earthparams['radius'] is None and earthparams['major_axis'] is None and earthparams['minor_axis'] is None:
 714                self.earthRadius = self.gridDefinitionTemplate[2]/(10.**self.gridDefinitionTemplate[1])
 715                self.earthMajorAxis = self.gridDefinitionTemplate[4]/(10.**self.gridDefinitionTemplate[3])
 716                self.earthMinorAxis = self.gridDefinitionTemplate[6]/(10.**self.gridDefinitionTemplate[5])
 717            else:
 718                self.earthRadius = earthparams['radius']
 719                self.earthMajorAxis = earthparams['major_axis']
 720                self.earthMinorAxis = earthparams['minor_axis']
 721
 722        reggrid = self.gridDefinitionSection[2] == 0 # self.gridDefinitionSection[2]=0 means regular 2-d grid
 723        if reggrid and self.gridDefinitionTemplateNumber.value not in [50,51,52,53,100,120,1000,1200]:
 724            self.nx = self.gridDefinitionTemplate[7]
 725            self.ny = self.gridDefinitionTemplate[8]
 726        if not reggrid and self.gridDefinitionTemplateNumber == 40:
 727            # Reduced Gaussian Grid
 728            self.ny = self.gridDefinitionTemplate[8]
 729        if self.gridDefinitionTemplateNumber.value in [0,1,203,205,32768,32769]:
 730            # Regular or Rotated Lat/Lon Grid
 731            scalefact = float(self.gridDefinitionTemplate[9])
 732            divisor = float(self.gridDefinitionTemplate[10])
 733            if scalefact == 0: scalefact = 1.
 734            if divisor <= 0: divisor = 1.e6
 735            self.latitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[11]/divisor
 736            self.longitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[12]/divisor
 737            self.latitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[14]/divisor
 738            self.longitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[15]/divisor
 739            self.gridlengthXDirection = scalefact*self.gridDefinitionTemplate[16]/divisor
 740            self.gridlengthYDirection = scalefact*self.gridDefinitionTemplate[17]/divisor
 741            if self.latitudeFirstGridpoint > self.latitudeLastGridpoint:
 742                self.gridlengthYDirection = -self.gridlengthYDirection
 743            if self.longitudeFirstGridpoint > self.longitudeLastGridpoint:
 744                self.gridlengthXDirection = -self.gridlengthXDirection
 745            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[18],output=list)[0:4]
 746            if self.gridDefinitionTemplateNumber == 1:
 747                self.latitudeSouthernPole = scalefact*self.gridDefinitionTemplate[19]/divisor
 748                self.longitudeSouthernPole = scalefact*self.gridDefinitionTemplate[20]/divisor
 749                self.anglePoleRotation = self.gridDefinitionTemplate[21]
 750        elif self.gridDefinitionTemplateNumber == 10:
 751            # Mercator
 752            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 753            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 754            self.latitudeLastGridpoint = self.gridDefinitionTemplate[13]/1.e6
 755            self.longitudeLastGridpoint = self.gridDefinitionTemplate[14]/1.e6
 756            self.gridlengthXDirection = self.gridDefinitionTemplate[17]/1.e3
 757            self.gridlengthYDirection= self.gridDefinitionTemplate[18]/1.e3
 758            self.proj4_lat_ts = self.gridDefinitionTemplate[12]/1.e6
 759            self.proj4_lon_0 = 0.5*(self.longitudeFirstGridpoint+self.longitudeLastGridpoint)
 760            self.proj4_proj = 'merc'
 761            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[15],output=list)[0:4]
 762        elif self.gridDefinitionTemplateNumber == 20:
 763            # Stereographic
 764            projflag = utils.int2bin(self.gridDefinitionTemplate[16],output=list)[0]
 765            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 766            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 767            self.proj4_lat_ts = self.gridDefinitionTemplate[12]/1.e6
 768            if projflag == 0:
 769                self.proj4_lat_0 = 90
 770            elif projflag == 1:
 771                self.proj4_lat_0 = -90
 772            else:
 773                raise ValueError('Invalid projection center flag = %s'%projflag)
 774            self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6
 775            self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000.
 776            self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000.
 777            self.proj4_proj = 'stere'
 778            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[17],output=list)[0:4]
 779        elif self.gridDefinitionTemplateNumber == 30:
 780            # Lambert Conformal
 781            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 782            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 783            self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000.
 784            self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000.
 785            self.proj4_lat_1 = self.gridDefinitionTemplate[18]/1.e6
 786            self.proj4_lat_2 = self.gridDefinitionTemplate[19]/1.e6
 787            self.proj4_lat_0 = self.gridDefinitionTemplate[12]/1.e6
 788            self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6
 789            self.proj4_proj = 'lcc'
 790            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[17],output=list)[0:4]
 791        elif self.gridDefinitionTemplateNumber == 31:
 792            # Albers Equal Area
 793            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 794            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 795            self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000.
 796            self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000.
 797            self.proj4_lat_1 = self.gridDefinitionTemplate[18]/1.e6
 798            self.proj4_lat_2 = self.gridDefinitionTemplate[19]/1.e6
 799            self.proj4_lat_0 = self.gridDefinitionTemplate[12]/1.e6
 800            self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6
 801            self.proj4_proj = 'aea'
 802            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[17],output=list)[0:4]
 803        elif self.gridDefinitionTemplateNumber == 40 or self.gridDefinitionTemplateNumber == 41:
 804            # Gaussian Grid
 805            scalefact = float(self.gridDefinitionTemplate[9])
 806            divisor = float(self.gridDefinitionTemplate[10])
 807            if scalefact == 0: scalefact = 1.
 808            if divisor <= 0: divisor = 1.e6
 809            self.pointsBetweenPoleAndEquator = self.gridDefinitionTemplate[17]
 810            self.latitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[11]/divisor
 811            self.longitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[12]/divisor
 812            self.latitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[14]/divisor
 813            self.longitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[15]/divisor
 814            if reggrid:
 815                self.gridlengthXDirection = scalefact*self.gridDefinitionTemplate[16]/divisor
 816                if self.longitudeFirstGridpoint > self.longitudeLastGridpoint:
 817                    self.gridlengthXDirection = -self.gridlengthXDirection
 818            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[18],output=list)[0:4]
 819            if self.gridDefinitionTemplateNumber == 41:
 820                self.latitudeSouthernPole = scalefact*self.gridDefinitionTemplate[19]/divisor
 821                self.longitudeSouthernPole = scalefact*self.gridDefinitionTemplate[20]/divisor
 822                self.anglePoleRotation = self.gridDefinitionTemplate[21]
 823        elif self.gridDefinitionTemplateNumber == 50:
 824            # Spectral Coefficients
 825            self.spectralFunctionParameters = (self.gridDefinitionTemplate[0],self.gridDefinitionTemplate[1],self.gridDefinitionTemplate[2])
 826            self.scanModeFlags = [None,None,None,None]
 827        elif self.gridDefinitionTemplateNumber == 90:
 828            # Near-sided Vertical Perspective Satellite Projection
 829            self.proj4_lat_0 = self.gridDefinitionTemplate[9]/1.e6
 830            self.proj4_lon_0 = self.gridDefinitionTemplate[10]/1.e6
 831            self.proj4_h = self.earthMajorAxis * (self.gridDefinitionTemplate[18]/1.e6)
 832            dx = self.gridDefinitionTemplate[12]
 833            dy = self.gridDefinitionTemplate[13]
 834            # if lat_0 is equator, it's a geostationary view.
 835            if self.proj4_lat_0 == 0.: # if lat_0 is equator, it's a
 836                self.proj4_proj = 'geos'
 837            # general case of 'near-side perspective projection' (untested)
 838            else:
 839                self.proj4_proj = 'nsper'
 840                msg = 'Only geostationary perspective is supported. Lat/Lon values returned by grid method may be incorrect.'
 841                warnings.warn(msg)
 842            # latitude of horizon on central meridian
 843            lonmax = 90.-(180./np.pi)*np.arcsin(self.earthMajorAxis/self.proj4_h)
 844            # longitude of horizon on equator
 845            latmax = 90.-(180./np.pi)*np.arcsin(self.earthMinorAxis/self.proj4_h)
 846            # truncate to nearest thousandth of a degree (to make sure
 847            # they aren't slightly over the horizon)
 848            latmax = int(1000*latmax)/1000.
 849            lonmax = int(1000*lonmax)/1000.
 850            # h is measured from surface of earth at equator.
 851            self.proj4_h = self.proj4_h - self.earthMajorAxis
 852            # width and height of visible projection
 853            P = pyproj.Proj(proj=self.proj4_proj,\
 854                            a=self.earthMajorAxis,b=self.earthMinorAxis,\
 855                            lat_0=0,lon_0=0,h=self.proj4_h)
 856            x1,y1 = P(0.,latmax)
 857            x2,y2 = P(lonmax,0.)
 858            width = 2*x2
 859            height = 2*y1
 860            self.gridlengthXDirection = width/dx
 861            self.gridlengthYDirection = height/dy
 862            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[16],output=list)[0:4]
 863        elif self.gridDefinitionTemplateNumber == 110:
 864            # Azimuthal Equidistant
 865            self.proj4_lat_0 = self.gridDefinitionTemplate[9]/1.e6
 866            self.proj4_lon_0 = self.gridDefinitionTemplate[10]/1.e6
 867            self.gridlengthXDirection = self.gridDefinitionTemplate[12]/1000.
 868            self.gridlengthYDirection = self.gridDefinitionTemplate[13]/1000.
 869            self.proj4_proj = 'aeqd'
 870            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[15],output=list)[0:4]
 871        elif self.gridDefinitionTemplateNumber == 204:
 872            # Curvilinear Orthogonal
 873            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[18],output=list)[0:4]
 874        else:
 875            errmsg = 'Unsupported Grid Definition Template Number - 3.%i' % self.gridDefinitionTemplateNumber.value
 876            raise ValueError(errmsg)
 877
 878        # -------------------------------
 879        # Section 4 -- Product Definition
 880        # -------------------------------
 881      
 882        # Template 4.0 - NOTE: That is these attributes apply to other templates.
 883        self.parameterCategory = self.productDefinitionTemplate[0]
 884        self.parameterNumber = self.productDefinitionTemplate[1]
 885        self.fullName,self.units,self.shortName = tables.get_varinfo_from_table(self.discipline.value,
 886                                                                                self.parameterCategory,
 887                                                                                self.parameterNumber)
 888        self.typeOfGeneratingProcess = Grib2Metadata(self.productDefinitionTemplate[2],table='4.3')
 889        self.backgroundGeneratingProcessIdentifier = self.productDefinitionTemplate[3]
 890        self.generatingProcess = Grib2Metadata(self.productDefinitionTemplate[4],table='generating_process')
 891        self.unitOfTimeRange = Grib2Metadata(self.productDefinitionTemplate[7],table='4.4')
 892        self.leadTime = self.productDefinitionTemplate[8]
 893        self.typeOfFirstFixedSurface = Grib2Metadata(self.productDefinitionTemplate[9],table='4.5')
 894        self.scaleFactorOfFirstFixedSurface = self.productDefinitionTemplate[10]
 895        self.unitOfFirstFixedSurface = self.typeOfFirstFixedSurface.definition[1]
 896        self.scaledValueOfFirstFixedSurface = self.productDefinitionTemplate[11]
 897        self.valueOfFirstFixedSurface = self.scaledValueOfFirstFixedSurface/(10.**self.scaleFactorOfFirstFixedSurface)
 898        temp = tables.get_value_from_table(self.productDefinitionTemplate[12],'4.5')
 899        if temp[0] == 'Missing' and temp[1] == 'unknown':
 900            self.typeOfSecondFixedSurface = None
 901            self.scaleFactorOfSecondFixedSurface = None
 902            self.unitOfSecondFixedSurface = None
 903            self.valueOfSecondFixedSurface = None
 904        else:
 905            self.typeOfSecondFixedSurface = Grib2Metadata(self.productDefinitionTemplate[12],table='4.5')
 906            self.scaleFactorOfSecondFixedSurface = self.productDefinitionTemplate[13]
 907            self.unitOfSecondFixedSurface = self.typeOfSecondFixedSurface.definition[1]
 908            self.scaledValueOfSecondFixedSurface = self.productDefinitionTemplate[14]
 909            self.valueOfSecondFixedSurface = self.scaledValueOfSecondFixedSurface/(10.**self.scaleFactorOfSecondFixedSurface)
 910        self.level = tables.get_wgrib2_level_string(*self.productDefinitionTemplate[9:15])
 911
 912        # Template 4.1 -
 913        if self.productDefinitionTemplateNumber == 1:
 914            self.typeOfEnsembleForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.6')
 915            self.perturbationNumber = self.productDefinitionTemplate[16]
 916            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[17]
 917
 918        # Template 4.2 -
 919        elif self.productDefinitionTemplateNumber == 2:
 920            self.typeOfDerivedForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.7')
 921            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[16]
 922
 923        # Template 4.5 -
 924        elif self.productDefinitionTemplateNumber == 5:
 925            self.forecastProbabilityNumber = self.productDefinitionTemplate[15]
 926            self.totalNumberOfForecastProbabilities = self.productDefinitionTemplate[16]
 927            self.typeOfProbability = Grib2Metadata(self.productDefinitionTemplate[17],table='4.9')
 928            self.scaleFactorOfThresholdLowerLimit = self.productDefinitionTemplate[18]
 929            self.scaledValueOfThresholdLowerLimit = self.productDefinitionTemplate[19]
 930            self.scaleFactorOfThresholdUpperLimit = self.productDefinitionTemplate[20]
 931            self.scaledValueOfThresholdUpperLimit = self.productDefinitionTemplate[21]
 932            self.thresholdLowerLimit = 0.0 if self.productDefinitionTemplate[19] == 255 else \
 933                                       self.productDefinitionTemplate[19]/(10.**self.productDefinitionTemplate[18])
 934            self.thresholdUpperLimit = 0.0 if self.productDefinitionTemplate[21] == 255 else \
 935                                       self.productDefinitionTemplate[21]/(10.**self.productDefinitionTemplate[20])
 936            self.threshold = utils.get_wgrib2_prob_string(*self.productDefinitionTemplate[17:22])
 937
 938        # Template 4.6 -
 939        elif self.productDefinitionTemplateNumber == 6:
 940            self.percentileValue = self.productDefinitionTemplate[15]
 941
 942        # Template 4.8 -
 943        elif self.productDefinitionTemplateNumber == 8:
 944            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[15]
 945            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[16]
 946            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[17]
 947            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[18]
 948            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[19]
 949            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[20]
 950            self.numberOfTimeRanges = self.productDefinitionTemplate[21]
 951            self.numberOfMissingValues = self.productDefinitionTemplate[22]
 952            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[23],table='4.10')
 953            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[24],table='4.11')
 954            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[25],table='4.4')
 955            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[26]
 956            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[27],table='4.4')
 957            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[28]
 958
 959        # Template 4.9 -
 960        elif self.productDefinitionTemplateNumber == 9:
 961            self.forecastProbabilityNumber = self.productDefinitionTemplate[15]
 962            self.totalNumberOfForecastProbabilities = self.productDefinitionTemplate[16]
 963            self.typeOfProbability = Grib2Metadata(self.productDefinitionTemplate[17],table='4.9')
 964            self.scaleFactorOfThresholdLowerLimit = self.productDefinitionTemplate[18]
 965            self.scaledValueOfThresholdLowerLimit = self.productDefinitionTemplate[19]
 966            self.scaleFactorOfThresholdUpperLimit = self.productDefinitionTemplate[20]
 967            self.scaledValueOfThresholdUpperLimit = self.productDefinitionTemplate[21]
 968            self.thresholdLowerLimit = 0.0 if self.productDefinitionTemplate[19] == 255 else \
 969                                       self.productDefinitionTemplate[19]/(10.**self.productDefinitionTemplate[18])
 970            self.thresholdUpperLimit = 0.0 if self.productDefinitionTemplate[21] == 255 else \
 971                                       self.productDefinitionTemplate[21]/(10.**self.productDefinitionTemplate[20])
 972            self.threshold = utils.get_wgrib2_prob_string(*self.productDefinitionTemplate[17:22])
 973            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[22]
 974            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[23]
 975            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[24]
 976            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[25]
 977            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[26]
 978            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[27]
 979            self.numberOfTimeRanges = self.productDefinitionTemplate[28]
 980            self.numberOfMissingValues = self.productDefinitionTemplate[29]
 981            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[30],table='4.10')
 982            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[31],table='4.11')
 983            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[32],table='4.4')
 984            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[33]
 985            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[34],table='4.4')
 986            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[35]
 987
 988        # Template 4.10 -
 989        elif self.productDefinitionTemplateNumber == 10:
 990            self.percentileValue = self.productDefinitionTemplate[15]
 991            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[16]
 992            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[17]
 993            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[18]
 994            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[19]
 995            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[20]
 996            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[21]
 997            self.numberOfTimeRanges = self.productDefinitionTemplate[22]
 998            self.numberOfMissingValues = self.productDefinitionTemplate[23]
 999            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[24],table='4.10')
1000            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[25],table='4.11')
1001            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[26],table='4.4')
1002            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[27]
1003            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[28],table='4.4')
1004            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[29]
1005
1006        # Template 4.11 -
1007        elif self.productDefinitionTemplateNumber == 11:
1008            self.typeOfEnsembleForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.6')
1009            self.perturbationNumber = self.productDefinitionTemplate[16]
1010            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[17]
1011            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[18]
1012            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[19]
1013            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[20]
1014            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[21]
1015            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[22]
1016            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[23]
1017            self.numberOfTimeRanges = self.productDefinitionTemplate[24]
1018            self.numberOfMissingValues = self.productDefinitionTemplate[25]
1019            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[26],table='4.10')
1020            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[27],table='4.11')
1021            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[28],table='4.4')
1022            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[29]
1023            self.unitOfTimeRangeOfSuccessiveFields = tables.get_value_from_table(self.productDefinitionTemplate[30],table='4.4')
1024            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[31]
1025
1026        # Template 4.12 -
1027        elif self.productDefinitionTemplateNumber == 12:
1028            self.typeOfDerivedForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.7')
1029            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[16]
1030            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[17]
1031            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[18]
1032            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[19]
1033            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[20]
1034            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[21]
1035            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[22]
1036            self.numberOfTimeRanges = self.productDefinitionTemplate[23]
1037            self.numberOfMissingValues = self.productDefinitionTemplate[24]
1038            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[25],table='4.10')
1039            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[26],table='4.11')
1040            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[27],table='4.4')
1041            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[28]
1042            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[29],table='4.4')
1043            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[30]
1044
1045        # Template 4.15 -
1046        elif self.productDefinitionTemplateNumber == 15:
1047            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[15],table='4.10')
1048            self.typeOfSpatialProcessing = Grib2Metadata(self.productDefinitionTemplate[16],table='4.15')
1049            self.numberOfDataPointsForSpatialProcessing = self.productDefinitionTemplate[17]
1050
1051        else:
1052            if self.productDefinitionTemplateNumber != 0:
1053                errmsg = 'Unsupported Product Definition Template Number - 4.%i' % self.productDefinitionTemplateNumber.value
1054                raise ValueError(errmsg)
1055
1056
1057        self.leadTime = utils.getleadtime(self.identificationSection,
1058                                          self.productDefinitionTemplateNumber.value,
1059                                          self.productDefinitionTemplate)
1060
1061        if self.productDefinitionTemplateNumber.value in [8,9,10,11,12]:
1062            self.dtEndOfTimePeriod = datetime.datetime(self.yearOfEndOfTimePeriod,self.monthOfEndOfTimePeriod,
1063                                     self.dayOfEndOfTimePeriod,hour=self.hourOfEndOfTimePeriod,
1064                                     minute=self.minuteOfEndOfTimePeriod,
1065                                     second=self.secondOfEndOfTimePeriod)
1066
1067        # --------------------------------
1068        # Section 5 -- Data Representation
1069        # --------------------------------
1070
1071        # Template 5.0 - Simple Packing
1072        if self.dataRepresentationTemplateNumber == 0:
1073            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1074            self.binScaleFactor = self.dataRepresentationTemplate[1]
1075            self.decScaleFactor = self.dataRepresentationTemplate[2]
1076            self.nBitsPacking = self.dataRepresentationTemplate[3]
1077            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[3],table='5.1')
1078
1079        # Template 5.2 - Complex Packing
1080        elif self.dataRepresentationTemplateNumber == 2:
1081            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1082            self.binScaleFactor = self.dataRepresentationTemplate[1]
1083            self.decScaleFactor = self.dataRepresentationTemplate[2]
1084            self.nBitsPacking = self.dataRepresentationTemplate[3]
1085            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1086            self.groupSplitMethod = Grib2Metadata(self.dataRepresentationTemplate[5],table='5.4')
1087            self.typeOfMissingValue = Grib2Metadata(self.dataRepresentationTemplate[6],table='5.5')
1088            self.priMissingValue = utils.getieeeint(self.dataRepresentationTemplate[7]) if self.dataRepresentationTemplate[6] in [1,2] else None
1089            self.secMissingValue = utils.getieeeint(self.dataRepresentationTemplate[8]) if self.dataRepresentationTemplate[6] == 2 else None
1090            self.nGroups = self.dataRepresentationTemplate[9]
1091            self.refGroupWidth = self.dataRepresentationTemplate[10]
1092            self.nBitsGroupWidth = self.dataRepresentationTemplate[11]
1093            self.refGroupLength = self.dataRepresentationTemplate[12]
1094            self.groupLengthIncrement = self.dataRepresentationTemplate[13]
1095            self.lengthOfLastGroup = self.dataRepresentationTemplate[14]
1096            self.nBitsScaledGroupLength = self.dataRepresentationTemplate[15]
1097
1098        # Template 5.3 - Complex Packing and Spatial Differencing
1099        elif self.dataRepresentationTemplateNumber == 3:
1100            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1101            self.binScaleFactor = self.dataRepresentationTemplate[1]
1102            self.decScaleFactor = self.dataRepresentationTemplate[2]
1103            self.nBitsPacking = self.dataRepresentationTemplate[3]
1104            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1105            self.groupSplitMethod = Grib2Metadata(self.dataRepresentationTemplate[5],table='5.4')
1106            self.typeOfMissingValue = Grib2Metadata(self.dataRepresentationTemplate[6],table='5.5')
1107            self.priMissingValue = utils.getieeeint(self.dataRepresentationTemplate[7]) if self.dataRepresentationTemplate[6] in [1,2] else None
1108            self.secMissingValue = utils.getieeeint(self.dataRepresentationTemplate[8]) if self.dataRepresentationTemplate[6] == 2 else None
1109            self.nGroups = self.dataRepresentationTemplate[9]
1110            self.refGroupWidth = self.dataRepresentationTemplate[10]
1111            self.nBitsGroupWidth = self.dataRepresentationTemplate[11]
1112            self.refGroupLength = self.dataRepresentationTemplate[12]
1113            self.groupLengthIncrement = self.dataRepresentationTemplate[13]
1114            self.lengthOfLastGroup = self.dataRepresentationTemplate[14]
1115            self.nBitsScaledGroupLength = self.dataRepresentationTemplate[15]
1116            self.spatialDifferenceOrder = Grib2Metadata(self.dataRepresentationTemplate[16],table='5.6')
1117            self.nBytesSpatialDifference = self.dataRepresentationTemplate[17]
1118
1119        # Template 5.4 - IEEE Floating Point Data
1120        elif self.dataRepresentationTemplateNumber == 4:
1121            self.precision = Grib2Metadata(self.dataRepresentationTemplate[0],table='5.7')
1122
1123        # Template 5.40 - JPEG2000 Compression
1124        elif self.dataRepresentationTemplateNumber == 40:
1125            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1126            self.binScaleFactor = self.dataRepresentationTemplate[1]
1127            self.decScaleFactor = self.dataRepresentationTemplate[2]
1128            self.nBitsPacking = self.dataRepresentationTemplate[3]
1129            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1130            self.typeOfCompression = Grib2Metadata(self.dataRepresentationTemplate[5],table='5.40')
1131            self.targetCompressionRatio = self.dataRepresentationTemplate[6]
1132
1133        # Template 5.41 - PNG Compression
1134        elif self.dataRepresentationTemplateNumber == 41:
1135            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1136            self.binScaleFactor = self.dataRepresentationTemplate[1]
1137            self.decScaleFactor = self.dataRepresentationTemplate[2]
1138            self.nBitsPacking = self.dataRepresentationTemplate[3]
1139            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1140
1141        else:
1142            errmsg = 'Unsupported Data Representation Definition Template Number - 5.%i' % self.dataRepresentationTemplateNumber.value
1143            raise ValueError(errmsg)
1144
1145
1146    def data(self, fill_value=DEFAULT_FILL_VALUE, masked_array=True, expand=True, order=None,
1147             map_keys=False):
1148        """
1149        Returns an unpacked data grid.
1150
1151        Parameters
1152        ----------
1153
1154        **`fill_value`**: Missing or masked data is filled with this value or default value given by
1155        `DEFAULT_FILL_VALUE`
1156
1157        **`masked_array`**: If `True` [DEFAULT], return masked array if there is bitmap for missing 
1158        or masked data.
1159
1160        **`expand`**: If `True` [DEFAULT], Reduced Gaussian grids are expanded to regular Gaussian grids.
1161
1162        **`order`**: If 0 [DEFAULT], nearest neighbor interpolation is used if grid has missing 
1163        or bitmapped values. If 1, linear interpolation is used for expanding reduced Gaussian grids.
1164
1165        **`map_keys`**: If `True`, data values will be mapped to the string-based keys that are stored
1166        in the Local Use Section (section 2) of the GRIB2 Message or in a code table as specified in the
1167        units (i.e. "See Table 4.xxx").
1168
1169        Returns
1170        -------
1171
1172        **`numpy.ndarray`**: A numpy.ndarray with shape (ny,nx). By default the array dtype=np.float32, 
1173        but could be np.int32 if Grib2Message.typeOfValues is integer.  The array dtype will be 
1174        string-based if map_keys=True.
1175        """
1176        if not hasattr(self,'scanModeFlags'):
1177            raise ValueError('Unsupported grid definition template number %s'%self.gridDefinitionTemplateNumber)
1178        else:
1179            if self.scanModeFlags[2]:
1180                storageorder='F'
1181            else:
1182                storageorder='C'
1183        if order is None:
1184            if (self.dataRepresentationTemplateNumber in [2,3] and
1185                self.dataRepresentationTemplate[6] != 0) or self.bitMapFlag == 0:
1186                order = 0
1187            else:
1188                order = 1
1189        drtnum = self.dataRepresentationTemplateNumber.value
1190        drtmpl = np.asarray(self.dataRepresentationTemplate,dtype=DEFAULT_NUMPY_INT)
1191        gdtnum = self.gridDefinitionTemplateNumber.value
1192        gdtmpl = np.asarray(self.gridDefinitionTemplate,dtype=DEFAULT_NUMPY_INT)
1193        ndpts = self.numberOfDataPoints
1194        gds = self.gridDefinitionSection
1195        ngrdpts = gds[1]
1196        ipos = self._datapos
1197        fld1 = g2clib.unpack7(self._msg,gdtnum,gdtmpl,drtnum,drtmpl,ndpts,ipos,np.empty,storageorder=storageorder)
1198        # Apply bitmap.
1199        if self.bitMapFlag == 0:
1200            fld = fill_value*np.ones(ngrdpts,'f')
1201            np.put(fld,np.nonzero(self.bitMap),fld1)
1202            if masked_array:
1203                fld = ma.masked_values(fld,fill_value)
1204        # Missing values instead of bitmap
1205        elif masked_array and hasattr(self,'priMissingValue'):
1206            if hasattr(self,'secMissingValue'):
1207                mask = np.logical_or(fld1==self.priMissingValue,fld1==self.secMissingValue)
1208            else:
1209                mask = fld1 == self.priMissingValue
1210            fld = ma.array(fld1,mask=mask)
1211        else:
1212            fld = fld1
1213        if self.nx is not None and self.ny is not None: # Rectangular grid.
1214            if ma.isMA(fld):
1215                fld = ma.reshape(fld,(self.ny,self.nx))
1216            else:
1217                fld = np.reshape(fld,(self.ny,self.nx))
1218        else:
1219            if gds[2] and gdtnum == 40: # Reduced global Gaussian grid.
1220                if expand:
1221                    from . import redtoreg
1222                    self.nx = 2*self.ny
1223                    lonsperlat = self.defList
1224                    if ma.isMA(fld):
1225                        fld = ma.filled(fld)
1226                        fld = redtoreg._redtoreg(self.nx,lonsperlat.astype(np.long),
1227                                                 fld.astype(np.double),fill_value)
1228                        fld = ma.masked_values(fld,fill_value)
1229                    else:
1230                        fld = redtoreg._redtoreg(self.nx,lonsperlat.astype(np.long),
1231                                                 fld.astype(np.double),fill_value)
1232        # Check scan modes for rect grids.
1233        if self.nx is not None and self.ny is not None:
1234            if self.scanModeFlags[3]:
1235                fldsave = fld.astype('f') # casting makes a copy
1236                fld[1::2,:] = fldsave[1::2,::-1]
1237
1238        # Set data to integer according to GRIB metadata
1239        if self.typeOfValues == "Integer": fld = fld.astype(np.int32)
1240
1241        # Map the data values to their respective definitions.
1242        if map_keys:
1243            fld = fld.astype(np.int32).astype(str)
1244            if self.identificationSection[0] == 7 and \
1245               self.identificationSection[1] == 14 and \
1246               self.shortName == 'PWTHER':
1247                # MDL Predominant Weather Grid
1248                keys = utils.decode_mdl_wx_strings(self._lus)
1249                for n,k in enumerate(keys):
1250                    fld = np.where(fld==str(n+1),k,fld)
1251            elif self.identificationSection[0] == 8 and \
1252                 self.identificationSection[1] == 65535 and \
1253                 self.shortName == 'CRAIN':
1254                # NDFD Predominant Weather Grid
1255                keys = utils.decode_ndfd_wx_strings(self._lus)
1256                for n,k in enumerate(keys):
1257                    fld = np.where(fld==str(n+1),k,fld)
1258            else:
1259                # For data whose units are defined in a code table
1260                tbl = re.findall(r'\d\.\d+',self.units,re.IGNORECASE)[0]
1261                for k,v in tables.get_table(tbl).items():
1262                    fld = np.where(fld==k,v,fld)
1263        return fld
1264
1265
1266    def latlons(self):
1267        """Alias for `grib2io.Grib2Message.grid` method"""
1268        return self.grid()
1269
1270
1271    def grid(self):
1272        """
1273        Return lats,lons (in degrees) of grid. Currently can handle reg. lat/lon, 
1274        global Gaussian, mercator, stereographic, lambert conformal, albers equal-area, 
1275        space-view and azimuthal equidistant grids.
1276
1277        Returns
1278        -------
1279
1280        **`lats, lons : numpy.ndarray`**
1281
1282        Returns two numpy.ndarrays with dtype=numpy.float32 of grid latitudes and
1283        longitudes in units of degrees.
1284        """
1285        gdtnum = self.gridDefinitionTemplateNumber
1286        gdtmpl = self.gridDefinitionTemplate
1287        reggrid = self.gridDefinitionSection[2] == 0 # This means regular 2-d grid
1288        self.projparams = {}
1289        if self.earthMajorAxis is not None: self.projparams['a']=self.earthMajorAxis
1290        if self.earthMajorAxis is not None: self.projparams['b']=self.earthMinorAxis
1291        if gdtnum == 0:
1292            # Regular lat/lon grid
1293            lon1, lat1 = self.longitudeFirstGridpoint, self.latitudeFirstGridpoint
1294            lon2, lat2 = self.longitudeLastGridpoint, self.latitudeLastGridpoint
1295            dlon = self.gridlengthXDirection
1296            dlat = self.gridlengthYDirection
1297            lats = np.arange(lat1,lat2+dlat,dlat)
1298            lons = np.arange(lon1,lon2+dlon,dlon)
1299            # flip if scan mode says to.
1300            #if self.scanModeFlags[0]:
1301            #    lons = lons[::-1]
1302            #if not self.scanModeFlags[1]:
1303            #    lats = lats[::-1]
1304            self.projparams['proj'] = 'cyl'
1305            lons,lats = np.meshgrid(lons,lats) # make 2-d arrays.
1306        elif gdtnum == 40: # Gaussian grid (only works for global!)
1307            from utils.gauss_grids import gaussian_latitudes
1308            lon1, lat1 = self.longitudeFirstGridpoint, self.latitudeFirstGridpoint
1309            lon2, lat2 = self.longitudeLastGridpoint, self.latitudeLastGridpoint
1310            nlats = self.ny
1311            if not reggrid: # Reduced Gaussian grid.
1312                nlons = 2*nlats
1313                dlon = 360./nlons
1314            else:
1315                nlons = self.nx
1316                dlon = self.gridlengthXDirection
1317            lons = np.arange(lon1,lon2+dlon,dlon)
1318            # Compute Gaussian lats (north to south)
1319            lats = gaussian_latitudes(nlats)
1320            if lat1 < lat2:  # reverse them if necessary
1321                lats = lats[::-1]
1322            # flip if scan mode says to.
1323            #if self.scanModeFlags[0]:
1324            #    lons = lons[::-1]
1325            #if not self.scanModeFlags[1]:
1326            #    lats = lats[::-1]
1327            self.projparams['proj'] = 'cyl'
1328            lons,lats = np.meshgrid(lons,lats) # make 2-d arrays
1329        elif gdtnum in [10,20,30,31,110]:
1330            # Mercator, Lambert Conformal, Stereographic, Albers Equal Area, Azimuthal Equidistant
1331            dx,dy = self.gridlengthXDirection, self.gridlengthYDirection
1332            lon1,lat1 = self.longitudeFirstGridpoint, self.latitudeFirstGridpoint
1333            if gdtnum == 10: # Mercator.
1334                self.projparams['lat_ts']=self.proj4_lat_ts
1335                self.projparams['proj']=self.proj4_proj
1336                self.projparams['lon_0']=self.proj4_lon_0
1337                pj = pyproj.Proj(self.projparams)
1338                llcrnrx, llcrnry = pj(lon1,lat1)
1339                x = llcrnrx+dx*np.arange(self.nx)
1340                y = llcrnry+dy*np.arange(self.ny)
1341                x,y = np.meshgrid(x, y)
1342                lons,lats = pj(x, y, inverse=True)
1343            elif gdtnum == 20:  # Stereographic
1344                self.projparams['lat_ts']=self.proj4_lat_ts
1345                self.projparams['proj']=self.proj4_proj
1346                self.projparams['lat_0']=self.proj4_lat_0
1347                self.projparams['lon_0']=self.proj4_lon_0
1348                pj = pyproj.Proj(self.projparams)
1349                llcrnrx, llcrnry = pj(lon1,lat1)
1350                x = llcrnrx+dx*np.arange(self.nx)
1351                y = llcrnry+dy*np.arange(self.ny)
1352                x,y = np.meshgrid(x, y)
1353                lons,lats = pj(x, y, inverse=True)
1354            elif gdtnum in [30,31]: # Lambert, Albers
1355                self.projparams['lat_1']=self.proj4_lat_1
1356                self.projparams['lat_2']=self.proj4_lat_2
1357                self.projparams['proj']=self.proj4_proj
1358                self.projparams['lon_0']=self.proj4_lon_0
1359                pj = pyproj.Proj(self.projparams)
1360                llcrnrx, llcrnry = pj(lon1,lat1)
1361                x = llcrnrx+dx*np.arange(self.nx)
1362                y = llcrnry+dy*np.arange(self.ny)
1363                x,y = np.meshgrid(x, y)
1364                lons,lats = pj(x, y, inverse=True)
1365            elif gdtnum == 110: # Azimuthal Equidistant
1366                self.projparams['proj']=self.proj4_proj
1367                self.projparams['lat_0']=self.proj4_lat_0
1368                self.projparams['lon_0']=self.proj4_lon_0
1369                pj = pyproj.Proj(self.projparams)
1370                llcrnrx, llcrnry = pj(lon1,lat1)
1371                x = llcrnrx+dx*np.arange(self.nx)
1372                y = llcrnry+dy*np.arange(self.ny)
1373                x,y = np.meshgrid(x, y)
1374                lons,lats = pj(x, y, inverse=True)
1375        elif gdtnum == 90:
1376            # Satellite Projection
1377            dx = self.gridlengthXDirection
1378            dy = self.gridlengthYDirection
1379            self.projparams['proj']=self.proj4_proj
1380            self.projparams['lon_0']=self.proj4_lon_0
1381            self.projparams['lat_0']=self.proj4_lat_0
1382            self.projparams['h']=self.proj4_h
1383            pj = pyproj.Proj(self.projparams)
1384            x = dx*np.indices((self.ny,self.nx),'f')[1,:,:]
1385            x -= 0.5*x.max()
1386            y = dy*np.indices((self.ny,self.nx),'f')[0,:,:]
1387            y -= 0.5*y.max()
1388            lons,lats = pj(x,y,inverse=True)
1389            # Set lons,lats to 1.e30 where undefined
1390            abslons = np.fabs(lons)
1391            abslats = np.fabs(lats)
1392            lons = np.where(abslons < 1.e20, lons, 1.e30)
1393            lats = np.where(abslats < 1.e20, lats, 1.e30)
1394        else:
1395            raise ValueError('Unsupported grid')
1396
1397        return lats.astype('f'), lons.astype('f')
1398
1399
1400    def addlocal(self, ludata):
1401        """
1402        Add a Local Use Section [(Section 2)](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_sect2.shtml)
1403        to the GRIB2 message.
1404
1405        Parameters
1406        ----------
1407
1408        **`ludata : bytes`**: Local Use data.
1409        """
1410        assert isinstance(ludata,bytes)
1411        self._msg,self._pos = g2clib.grib2_addlocal(self._msg,ludata)
1412        self.hasLocalUseSection = True
1413        self._sections.append(2)
1414
1415
1416    def addgrid(self, gdsinfo, gdtmpl, deflist=None):
1417        """
1418        Add a Grid Definition Section [(Section 3)](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_doc/grib2_sect3.shtml) 
1419        to the GRIB2 message.
1420
1421        Parameters
1422        ----------
1423
1424        **`gdsinfo`**: Sequence containing information needed for the grid definition section.
1425
1426        | Index | Description |
1427        | :---: | :---        |
1428        | gdsinfo[0] | Source of grid definition - [Code Table 3.0](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table3-0.shtml)|
1429        | gdsinfo[1] | Number of data points|
1430        | gdsinfo[2] | Number of octets for optional list of numbers defining number of points|
1431        | gdsinfo[3] | Interpetation of list of numbers defining number of points - [Code Table 3.11](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table3-11.shtml)|
1432        | gdsinfo[4] | Grid Definition Template Number - [Code Table 3.1](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table3-1.shtml)|
1433
1434        **`gdtmpl`**: Sequence of values for the specified Grid Definition Template. Each 
1435        element of this integer array contains an entry (in the order specified) of Grid
1436        Definition Template 3.NN
1437
1438        **`deflist`**: Sequence containing the number of grid points contained in each 
1439        row (or column) of a non-regular grid.  Used if gdsinfo[2] != 0.
1440        """
1441        if 3 in self._sections:
1442            raise ValueError('GRIB2 Message already contains Grid Definition Section.')
1443        if deflist is not None:
1444            _deflist = np.array(deflist,dtype=DEFAULT_NUMPY_INT)
1445        else:
1446            _deflist = None
1447        gdtnum = gdsinfo[4]
1448        if gdtnum in [0,1,2,3,40,41,42,43,44,203,205,32768,32769]:
1449            self.scanModeFlags = utils.int2bin(gdtmpl[18],output=list)[0:4]
1450        elif gdtnum == 10: # mercator
1451            self.scanModeFlags = utils.int2bin(gdtmpl[15],output=list)[0:4]
1452        elif gdtnum == 20: # stereographic
1453            self.scanModeFlags = utils.int2bin(gdtmpl[17],output=list)[0:4]
1454        elif gdtnum == 30: # lambert conformal
1455            self.scanModeFlags = utils.int2bin(gdtmpl[17],output=list)[0:4]
1456        elif gdtnum == 31: # albers equal area.
1457            self.scanModeFlags = utils.int2bin(gdtmpl[17],output=list)[0:4]
1458        elif gdtnum == 90: # near-sided vertical perspective satellite projection
1459            self.scanModeFlags = utils.int2bin(gdtmpl[16],output=list)[0:4]
1460        elif gdtnum == 110: # azimuthal equidistant.
1461            self.scanModeFlags = utils.int2bin(gdtmpl[15],output=list)[0:4]
1462        elif gdtnum == 120:
1463            self.scanModeFlags = utils.int2bin(gdtmpl[6],output=list)[0:4]
1464        elif gdtnum == 204: # curvilinear orthogonal
1465            self.scanModeFlags = utils.int2bin(gdtmpl[18],output=list)[0:4]
1466        elif gdtnum in [1000,1100]:
1467            self.scanModeFlags = utils.int2bin(gdtmpl[12],output=list)[0:4]
1468        self._msg,self._pos = g2clib.grib2_addgrid(self._msg,
1469                                                   np.array(gdsinfo,dtype=DEFAULT_NUMPY_INT),
1470                                                   np.array(gdtmpl,dtype=DEFAULT_NUMPY_INT),
1471                                                   _deflist)
1472        self._sections.append(3)
1473
1474
1475    def addfield(self, field, pdtnum, pdtmpl, coordlist=None, packing="complex-spdiff", **packing_opts): 
1476        """
1477        Add a Product Definition, Data Representation, Bitmap, and Data Sections 
1478        to `Grib2Message` instance (i.e. Sections 4-7).  Must be called after the grid 
1479        definition section has been added (`addfield`).
1480
1481        Parameters
1482        ----------
1483
1484        **`field`**: Numpy array of data values to pack.  If field is a masked array, then 
1485        a bitmap is created from the mask.
1486
1487        **`pdtnum`**: integer Product Definition Template Number - [Code Table 4.0](http://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table4-0.shtml)
1488
1489        **`pdtmpl`**: Sequence with the data values for the specified Product Definition 
1490        Template (N=pdtnum).  Each element of this integer array contains an entry (in 
1491        the order specified) of Product Definition Template 4.N.
1492
1493        **`coordlist`**: Sequence containing floating point values intended to document the 
1494        vertical discretization with model data on hybrid coordinate vertical levels. Default is `None`.
1495
1496        **`packing`**: String to specify the type of packing. Valid options are the following:
1497
1498        | Packing Scheme | Description |
1499        | :---:          | :---:       |
1500        | 'simple'         | [Simple packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-0.shtml) | 
1501        | 'complex'        | [Complex packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-2.shtml) | 
1502        | 'complex-spdiff' | [Complex packing with Spatial Differencing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-3.shtml) | 
1503        | 'jpeg'           | [JPEG compression](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-40.shtml) | 
1504        | 'png'            | [PNG compression](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-41.shtml) | 
1505        | 'spectral-simple'| [Spectral Data - Simple packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-50.shtml) | 
1506        | 'spectral-complex'| [Spectral Data - Complex packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-51.shtml) | 
1507
1508        **`**packing_opts`**: Packing keyword arguments. The keywords are the same as Grib2Message attribute names for
1509        the Data Representation Template (Section 5) metadata. Valid keywords per packing scheme are the following:
1510
1511        | Packing Scheme | Keyword Arguments |
1512        | :---:          | :---:                      |
1513        | 'simple'     | `binScaleFactor`, `decScaleFactor` |
1514        | 'complex'     | `binScaleFactor`, `decScaleFactor`, `priMissingValue`, [`secMissingValue`] |
1515        | 'complex-spdiff'     | `binScaleFactor`, `decScaleFactor`, `spatialDifferenceOrder`, `priMissingValue`, [`secMissingValue`] |
1516        | 'jpeg'     | `binScaleFactor`, `decScaleFactor` |
1517        | 'png'     | `binScaleFactor`, `decScaleFactor` |
1518        | 'spectral-simple'     | `binScaleFactor`, `decScaleFactor` |
1519        | 'spectral-complex'     | `binScaleFactor`, `decScaleFactor` |
1520        """
1521        if self._sections[-1] != 3:
1522            raise ValueError('addgrid() must be called before addfield()')
1523        if self.scanModeFlags is not None:
1524            if self.scanModeFlags[3]:
1525                fieldsave = field.astype('f') # Casting makes a copy
1526                field[1::2,:] = fieldsave[1::2,::-1]
1527        fld = field.astype('f')
1528        if ma.isMA(field) and ma.count_masked(field) > 0:
1529            bitmapflag = 0
1530            bmap = 1-np.ravel(field.mask.astype(DEFAULT_NUMPY_INT))
1531        else:
1532            bitmapflag = 255
1533            bmap = None
1534        if coordlist is not None:
1535            crdlist = np.array(coordlist,'f')
1536        else:
1537            crdlist = None
1538
1539        # Set data representation template number and template values
1540        drtnum = -1
1541        drtmpl = np.zeros((DEFAULT_DRT_LEN),dtype=DEFAULT_NUMPY_INT)
1542        if packing == "simple":
1543            drtnum = 0
1544            drtmpl[1] = packing_opts["binScaleFactor"]
1545            drtmpl[2] = packing_opts["decScaleFactor"]
1546        elif packing == "complex" or packing == "complex-spdiff":
1547            if packing == "complex":
1548                drtnum = 2
1549            if packing == "complex-spdiff":
1550                drtnum = 3
1551                drtmpl[16] = packing_opts['spatialDifferenceOrder']
1552            drtmpl[1] = packing_opts["binScaleFactor"]
1553            drtmpl[2] = packing_opts["decScaleFactor"]
1554            if set(("priMissingValue","secMissingValue")).issubset(kwargs):
1555                drtmpl[6] = 2
1556                drtmpl[7] = utils.putieeeint(kwargs["priMissingValue"])
1557                drtmpl[8] = utils.putieeeint(kwargs["secMissingValue"])
1558            else:
1559                if "priMissingValue" in packing_opts.keys():
1560                    drtmpl[6] = 1
1561                    drtmpl[7] = utils.putieeeint(kwargs["priMissingValue"])
1562                else:
1563                    drtmpl[6] = 0
1564        elif packing == "jpeg":
1565            drtnum = 40
1566            drtmpl[1] = packing_opts["binScaleFactor"]
1567            drtmpl[2] = packing_opts["decScaleFactor"]
1568        elif packing == "png":
1569            drtnum = 41
1570            drtmpl[1] = packing_opts["binScaleFactor"]
1571            drtmpl[2] = packing_opts["decScaleFactor"]
1572        elif packing == "spectral-simple":
1573            drtnum = 50
1574            drtmpl[1] = packing_opts["binScaleFactor"]
1575            drtmpl[2] = packing_opts["decScaleFactor"]
1576        elif packing == "spectral-complex":
1577            drtnum = 51
1578            drtmpl[1] = packing_opts["binScaleFactor"]
1579            drtmpl[2] = packing_opts["decScaleFactor"]
1580
1581        pdtnum = pdtnum.value if isinstance(pdtnum,Grib2Metadata) else pdtnum
1582
1583        self._msg,self._pos = g2clib.grib2_addfield(self._msg,
1584                                                    pdtnum,
1585                                                    np.array(pdtmpl,dtype=DEFAULT_NUMPY_INT),
1586                                                    crdlist,
1587                                                    drtnum,
1588                                                    drtmpl,
1589                                                    np.ravel(fld),
1590                                                    bitmapflag,
1591                                                    bmap)
1592        self._sections.append(4)
1593        self._sections.append(5)
1594        if bmap is not None: self._sections.append(6)
1595        self._sections.append(7)
1596
1597
1598    def end(self):
1599        """
1600        Add End Section (Section 8) to the GRIB2 message. A GRIB2 message 
1601        is not complete without an end section.  Once an end section is added, 
1602        the GRIB2 message can be written to file.
1603        """
1604        self._msg, self._pos = g2clib.grib2_end(self._msg)
1605        self._sections.append(8)
1606
1607    def to_bytes(self, validate=True):
1608        """
1609        Return grib data in byte format. Useful for exporting data in non-file formats.
1610        For example, can be used to output grib data directly to S3 using the boto3 client
1611        without the need to write a temporary file to upload first.
1612
1613        Parameters
1614        ----------
1615        **`validate`**: bool (Default: True) If true, validates first/last four bytes for proper formatting, else
1616        returns None. If False, message is output as is.
1617
1618        Returns
1619        -------
1620        Returns GRIB2 formatted message as bytes.
1621        """
1622        if validate:
1623            if str(self._msg[0:4] + self._msg[-4:], 'utf-8') == 'GRIB7777':
1624                return self._msg
1625            else:
1626                return None
1627        else:
1628            return self._msg
Grib2Message( msg=None, source=None, num=-1, decode=True, discipline=None, idsect=None)
480    def __init__(self, msg=None, source=None, num=-1, decode=True, discipline=None, idsect=None):
481        """
482        Class Constructor. Instantiation of this class can handle a GRIB2 message from an existing 
483        file or the creation of new GRIB2 message.  To create a new GRIB2 message, provide the 
484        appropriate values to the arguments `discipline` and `idsect`.  When these 2 arguments 
485        are not `None`, then a new GRIB2 message is created. NOTE: All other keyword arguments 
486        are ignored when a new message is created.
487
488        ...
489
490        Parameters
491        ----------
492
493        **`msg`**: Binary string representing the GRIB2 Message read from file.
494
495        **`source`**: Source of where where this GRIB2 message originated 
496        from (i.e. the input file). This allow for interaction with the 
497        instance of `grib2io.open`. Default is None.
498
499        **`num`**: integer GRIB2 Message number from `grib2io.open`. Default value is -1.
500
501        **`decode`**: If True [DEFAULT], decode GRIB2 section lists into metadata 
502        instance variables.
503
504        **`discipline`**: integer GRIB2 Discipline [GRIB2 Table 0.0](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table0-0.shtml)
505
506        **`idsect`**: Sequence containing GRIB1 Identification Section values (Section 1).
507
508        | Index | Description |
509        | :---: | :---        |
510        | idsect[0] | Id of orginating centre - [ON388 - Table 0](https://www.nco.ncep.noaa.gov/pmb/docs/on388/table0.html)|
511        | idsect[1] | Id of orginating sub-centre - [ON388 - Table C](https://www.nco.ncep.noaa.gov/pmb/docs/on388/tablec.html)|
512        | idsect[2] | GRIB Master Tables Version Number - [Code Table 1.0](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table1-0.shtml)|
513        | idsect[3] | GRIB Local Tables Version Number - [Code Table 1.1](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table1-1.shtml)|
514        | idsect[4] | Significance of Reference Time - [Code Table 1.2](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table1-2.shtml)|
515        | idsect[5] | Reference Time - Year (4 digits)|
516        | idsect[6] | Reference Time - Month|
517        | idsect[7] | Reference Time - Day|
518        | idsect[8] | Reference Time - Hour|
519        | idsect[9] | Reference Time - Minute|
520        | idsect[10] | Reference Time - Second|
521        | idsect[11] | Production status of data - [Code Table 1.3](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table1-3.shtml)|
522        | idsect[12] | Type of processed data - [Code Table 1.4](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table1-4.shtml)|
523        """
524        self._source = source
525        self._msgnum = num
526        self._decode = decode
527        self._pos = 0
528        self._datapos = 0
529        self._sections = []
530        self.hasLocalUseSection = False
531        self.isNDFD = False
532        if discipline is not None and idsect is not None:
533            # New message
534            self._msg,self._pos = g2clib.grib2_create(np.array([discipline,GRIB2_EDITION_NUMBER],DEFAULT_NUMPY_INT),
535                                                      np.array(idsect,DEFAULT_NUMPY_INT))
536            self._sections += [0,1]
537        else:
538            # Existing message
539            self._msg = msg
540        #self.md5 = {}
541        if self._msg is not None and self._source is not None: self.unpack()

Class Constructor. Instantiation of this class can handle a GRIB2 message from an existing file or the creation of new GRIB2 message. To create a new GRIB2 message, provide the appropriate values to the arguments discipline and idsect. When these 2 arguments are not None, then a new GRIB2 message is created. NOTE: All other keyword arguments are ignored when a new message is created.

...

Parameters

msg: Binary string representing the GRIB2 Message read from file.

source: Source of where where this GRIB2 message originated from (i.e. the input file). This allow for interaction with the instance of grib2io.open. Default is None.

num: integer GRIB2 Message number from grib2io.open. Default value is -1.

decode: If True [DEFAULT], decode GRIB2 section lists into metadata instance variables.

discipline: integer GRIB2 Discipline GRIB2 Table 0.0

idsect: Sequence containing GRIB1 Identification Section values (Section 1).

Index Description
idsect[0] Id of orginating centre - ON388 - Table 0
idsect[1] Id of orginating sub-centre - ON388 - Table C
idsect[2] GRIB Master Tables Version Number - Code Table 1.0
idsect[3] GRIB Local Tables Version Number - Code Table 1.1
idsect[4] Significance of Reference Time - Code Table 1.2
idsect[5] Reference Time - Year (4 digits)
idsect[6] Reference Time - Month
idsect[7] Reference Time - Day
idsect[8] Reference Time - Hour
idsect[9] Reference Time - Minute
idsect[10] Reference Time - Second
idsect[11] Production status of data - Code Table 1.3
idsect[12] Type of processed data - Code Table 1.4
def unpack(self)
560    def unpack(self):
561        """
562        Unpacks GRIB2 section data from the packed, binary message.
563        """
564        # Section 0 - Indicator Section
565        self.indicatorSection = []
566        self.indicatorSection.append(struct.unpack('>4s',self._msg[0:4])[0])
567        self.indicatorSection.append(struct.unpack('>H',self._msg[4:6])[0])
568        self.indicatorSection.append(self._msg[6])
569        self.indicatorSection.append(self._msg[7])
570        self.indicatorSection.append(struct.unpack('>Q',self._msg[8:16])[0])
571        self._pos = 16
572        self._sections.append(0)
573        #self.md5[0] = _getmd5str(self.indicatorSection)
574
575        # Section 1 - Identification Section via g2clib.unpack1()
576        self.identificationSection,self._pos = g2clib.unpack1(self._msg,self._pos,np.empty)
577        self.identificationSection = self.identificationSection.tolist()
578        self._sections.append(1)
579        if self.identificationSection[0:2] == [8,65535]: self.isNDFD = True
580
581        # After Section 1, perform rest of GRIB2 Decoding inside while loop
582        # to account for sub-messages.
583        sectnum = 1
584        while True:
585            if self._msg[self._pos:self._pos+4].decode('ascii','ignore') == '7777':
586                break
587
588            # Read the length and section number.
589            sectlen = struct.unpack('>i',self._msg[self._pos:self._pos+4])[0]
590            prevsectnum = sectnum
591            sectnum = struct.unpack('>B',self._msg[self._pos+4:self._pos+5])[0]
592
593            # If the previous section number is > current section number, then
594            # we have encountered a submessage.
595            if prevsectnum > sectnum: break
596
597            # Handle submessage accordingly.
598            if isinstance(self._source,open):
599                if self._source._index['isSubmessage'][self._msgnum]:
600                    if sectnum == self._source._index['submessageBeginSection'][self._msgnum]:
601                        self._pos = self._source._index['submessageOffset'][self._msgnum]
602
603            # Section 2 - Local Use Section.
604            if sectnum == 2:
605                self._lus = self._msg[self._pos+5:self._pos+sectlen]
606                self._pos += sectlen
607                self.hasLocalUseSection = True
608                self._sections.append(2)
609                #self.md5[2] = _getmd5str(self.identificationSection)
610
611            # Section 3 - Grid Definition Section.
612            elif sectnum == 3:
613                _gds,_gdt,_deflist,self._pos = g2clib.unpack3(self._msg,self._pos,np.empty)
614                self.gridDefinitionSection = _gds.tolist()
615                self.gridDefinitionTemplateNumber = Grib2Metadata(int(_gds[4]),table='3.1')
616                self.gridDefinitionTemplate = _gdt.tolist()
617                self.defList = _deflist.tolist()
618                self._sections.append(3)
619                #self.md5[3] = _getmd5str([self.gridDefinitionTemplateNumber]+self.gridDefinitionTemplate)
620
621            # Section 4 - Product Definition Section.
622            elif sectnum == 4:
623                _pdt,_pdtn,_coordlst,self._pos = g2clib.unpack4(self._msg,self._pos,np.empty)
624                self.productDefinitionTemplate = _pdt.tolist()
625                self.productDefinitionTemplateNumber = Grib2Metadata(int(_pdtn),table='4.0')
626                self.coordinateList = _coordlst.tolist()
627                self._sections.append(4)
628                #self.md5[4] = _getmd5str([self.productDefinitionTemplateNumber]+self.productDefinitionTemplate)
629
630            # Section 5 - Data Representation Section.
631            elif sectnum == 5:
632                _drt,_drtn,_npts,self._pos = g2clib.unpack5(self._msg,self._pos,np.empty)
633                self.dataRepresentationTemplate = _drt.tolist()
634                self.dataRepresentationTemplateNumber = Grib2Metadata(int(_drtn),table='5.0')
635                self.numberOfDataPoints = _npts
636                self._sections.append(5)
637                #self.md5[5] = _getmd5str([self.dataRepresentationTemplateNumber]+self.dataRepresentationTemplate)
638
639            # Section 6 - Bitmap Section.
640            elif sectnum == 6:
641                _bmap,_bmapflag = g2clib.unpack6(self._msg,self.gridDefinitionSection[1],self._pos,np.empty)
642                self.bitMapFlag = _bmapflag
643                if self.bitMapFlag == 0:
644                    self.bitMap = _bmap
645                elif self.bitMapFlag == 254:
646                    # Value of 254 says to use a previous bitmap in the file.
647                    self.bitMapFlag = 0
648                    if isinstance(self._source,open):
649                        self.bitMap = self._source._index['bitMap'][self._msgnum]
650                self._pos += sectlen # IMPORTANT: This is here because g2clib.unpack6() does not return updated position.
651                self._sections.append(6)
652                #self.md5[6] = None
653
654            # Section 7 - Data Section (data unpacked when data() method is invoked).
655            elif sectnum == 7:
656                self._datapos = self._pos
657                self._pos += sectlen # REMOVE THIS WHEN UNPACKING DATA IS IMPLEMENTED
658                self._sections.append(7)
659                #self.md5[7] = _getmd5str(self._msg[self._datapos:sectlen+1])
660
661            else:
662                errmsg = 'Unknown section number = %i' % sectnum
663                raise ValueError(errmsg)
664
665        if self._decode: self.decode()

Unpacks GRIB2 section data from the packed, binary message.

def decode(self)
 667    def decode(self):
 668        """
 669        Decode the unpacked GRIB2 integer-coded metadata in human-readable form and linked to GRIB2 tables.
 670        """
 671
 672        # Section 0 - Indictator Section
 673        self.discipline = Grib2Metadata(self.indicatorSection[2],table='0.0')
 674
 675        # Section 1 - Indentification Section.
 676        self.originatingCenter = Grib2Metadata(self.identificationSection[0],table='originating_centers')
 677        self.originatingSubCenter = Grib2Metadata(self.identificationSection[1],table='originating_subcenters')
 678        self.masterTableInfo = Grib2Metadata(self.identificationSection[2],table='1.0')
 679        self.localTableInfo = Grib2Metadata(self.identificationSection[3],table='1.1')
 680        self.significanceOfReferenceTime = Grib2Metadata(self.identificationSection[4],table='1.2')
 681        self.year = self.identificationSection[5]
 682        self.month = self.identificationSection[6]
 683        self.day = self.identificationSection[7]
 684        self.hour = self.identificationSection[8]
 685        self.minute = self.identificationSection[9]
 686        self.second = self.identificationSection[10]
 687        self.refDate = (self.year*1000000)+(self.month*10000)+(self.day*100)+self.hour
 688        self.dtReferenceDate = datetime.datetime(self.year,self.month,self.day,
 689                                                 hour=self.hour,minute=self.minute,
 690                                                 second=self.second)
 691        self.productionStatus = Grib2Metadata(self.identificationSection[11],table='1.3')
 692        self.typeOfData = Grib2Metadata(self.identificationSection[12],table='1.4')
 693
 694        # ----------------------------
 695        # Section 3 -- Grid Definition
 696        # ----------------------------
 697
 698        # Set shape of the Earth parameters
 699        if self.gridDefinitionTemplateNumber.value in [50,51,52,1200]:
 700            earthparams = None
 701        else:
 702            earthparams = tables.earth_params[str(self.gridDefinitionTemplate[0])]
 703        if earthparams['shape'] == 'spherical':
 704            if earthparams['radius'] is None:
 705                self.earthRadius = self.gridDefinitionTemplate[2]/(10.**self.gridDefinitionTemplate[1])
 706                self.earthMajorAxis = None
 707                self.earthMinorAxis = None
 708            else:
 709                self.earthRadius = earthparams['radius']
 710                self.earthMajorAxis = None
 711                self.earthMinorAxis = None
 712        elif earthparams['shape'] == 'oblateSpheroid':
 713            if earthparams['radius'] is None and earthparams['major_axis'] is None and earthparams['minor_axis'] is None:
 714                self.earthRadius = self.gridDefinitionTemplate[2]/(10.**self.gridDefinitionTemplate[1])
 715                self.earthMajorAxis = self.gridDefinitionTemplate[4]/(10.**self.gridDefinitionTemplate[3])
 716                self.earthMinorAxis = self.gridDefinitionTemplate[6]/(10.**self.gridDefinitionTemplate[5])
 717            else:
 718                self.earthRadius = earthparams['radius']
 719                self.earthMajorAxis = earthparams['major_axis']
 720                self.earthMinorAxis = earthparams['minor_axis']
 721
 722        reggrid = self.gridDefinitionSection[2] == 0 # self.gridDefinitionSection[2]=0 means regular 2-d grid
 723        if reggrid and self.gridDefinitionTemplateNumber.value not in [50,51,52,53,100,120,1000,1200]:
 724            self.nx = self.gridDefinitionTemplate[7]
 725            self.ny = self.gridDefinitionTemplate[8]
 726        if not reggrid and self.gridDefinitionTemplateNumber == 40:
 727            # Reduced Gaussian Grid
 728            self.ny = self.gridDefinitionTemplate[8]
 729        if self.gridDefinitionTemplateNumber.value in [0,1,203,205,32768,32769]:
 730            # Regular or Rotated Lat/Lon Grid
 731            scalefact = float(self.gridDefinitionTemplate[9])
 732            divisor = float(self.gridDefinitionTemplate[10])
 733            if scalefact == 0: scalefact = 1.
 734            if divisor <= 0: divisor = 1.e6
 735            self.latitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[11]/divisor
 736            self.longitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[12]/divisor
 737            self.latitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[14]/divisor
 738            self.longitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[15]/divisor
 739            self.gridlengthXDirection = scalefact*self.gridDefinitionTemplate[16]/divisor
 740            self.gridlengthYDirection = scalefact*self.gridDefinitionTemplate[17]/divisor
 741            if self.latitudeFirstGridpoint > self.latitudeLastGridpoint:
 742                self.gridlengthYDirection = -self.gridlengthYDirection
 743            if self.longitudeFirstGridpoint > self.longitudeLastGridpoint:
 744                self.gridlengthXDirection = -self.gridlengthXDirection
 745            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[18],output=list)[0:4]
 746            if self.gridDefinitionTemplateNumber == 1:
 747                self.latitudeSouthernPole = scalefact*self.gridDefinitionTemplate[19]/divisor
 748                self.longitudeSouthernPole = scalefact*self.gridDefinitionTemplate[20]/divisor
 749                self.anglePoleRotation = self.gridDefinitionTemplate[21]
 750        elif self.gridDefinitionTemplateNumber == 10:
 751            # Mercator
 752            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 753            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 754            self.latitudeLastGridpoint = self.gridDefinitionTemplate[13]/1.e6
 755            self.longitudeLastGridpoint = self.gridDefinitionTemplate[14]/1.e6
 756            self.gridlengthXDirection = self.gridDefinitionTemplate[17]/1.e3
 757            self.gridlengthYDirection= self.gridDefinitionTemplate[18]/1.e3
 758            self.proj4_lat_ts = self.gridDefinitionTemplate[12]/1.e6
 759            self.proj4_lon_0 = 0.5*(self.longitudeFirstGridpoint+self.longitudeLastGridpoint)
 760            self.proj4_proj = 'merc'
 761            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[15],output=list)[0:4]
 762        elif self.gridDefinitionTemplateNumber == 20:
 763            # Stereographic
 764            projflag = utils.int2bin(self.gridDefinitionTemplate[16],output=list)[0]
 765            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 766            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 767            self.proj4_lat_ts = self.gridDefinitionTemplate[12]/1.e6
 768            if projflag == 0:
 769                self.proj4_lat_0 = 90
 770            elif projflag == 1:
 771                self.proj4_lat_0 = -90
 772            else:
 773                raise ValueError('Invalid projection center flag = %s'%projflag)
 774            self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6
 775            self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000.
 776            self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000.
 777            self.proj4_proj = 'stere'
 778            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[17],output=list)[0:4]
 779        elif self.gridDefinitionTemplateNumber == 30:
 780            # Lambert Conformal
 781            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 782            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 783            self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000.
 784            self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000.
 785            self.proj4_lat_1 = self.gridDefinitionTemplate[18]/1.e6
 786            self.proj4_lat_2 = self.gridDefinitionTemplate[19]/1.e6
 787            self.proj4_lat_0 = self.gridDefinitionTemplate[12]/1.e6
 788            self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6
 789            self.proj4_proj = 'lcc'
 790            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[17],output=list)[0:4]
 791        elif self.gridDefinitionTemplateNumber == 31:
 792            # Albers Equal Area
 793            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 794            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 795            self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000.
 796            self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000.
 797            self.proj4_lat_1 = self.gridDefinitionTemplate[18]/1.e6
 798            self.proj4_lat_2 = self.gridDefinitionTemplate[19]/1.e6
 799            self.proj4_lat_0 = self.gridDefinitionTemplate[12]/1.e6
 800            self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6
 801            self.proj4_proj = 'aea'
 802            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[17],output=list)[0:4]
 803        elif self.gridDefinitionTemplateNumber == 40 or self.gridDefinitionTemplateNumber == 41:
 804            # Gaussian Grid
 805            scalefact = float(self.gridDefinitionTemplate[9])
 806            divisor = float(self.gridDefinitionTemplate[10])
 807            if scalefact == 0: scalefact = 1.
 808            if divisor <= 0: divisor = 1.e6
 809            self.pointsBetweenPoleAndEquator = self.gridDefinitionTemplate[17]
 810            self.latitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[11]/divisor
 811            self.longitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[12]/divisor
 812            self.latitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[14]/divisor
 813            self.longitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[15]/divisor
 814            if reggrid:
 815                self.gridlengthXDirection = scalefact*self.gridDefinitionTemplate[16]/divisor
 816                if self.longitudeFirstGridpoint > self.longitudeLastGridpoint:
 817                    self.gridlengthXDirection = -self.gridlengthXDirection
 818            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[18],output=list)[0:4]
 819            if self.gridDefinitionTemplateNumber == 41:
 820                self.latitudeSouthernPole = scalefact*self.gridDefinitionTemplate[19]/divisor
 821                self.longitudeSouthernPole = scalefact*self.gridDefinitionTemplate[20]/divisor
 822                self.anglePoleRotation = self.gridDefinitionTemplate[21]
 823        elif self.gridDefinitionTemplateNumber == 50:
 824            # Spectral Coefficients
 825            self.spectralFunctionParameters = (self.gridDefinitionTemplate[0],self.gridDefinitionTemplate[1],self.gridDefinitionTemplate[2])
 826            self.scanModeFlags = [None,None,None,None]
 827        elif self.gridDefinitionTemplateNumber == 90:
 828            # Near-sided Vertical Perspective Satellite Projection
 829            self.proj4_lat_0 = self.gridDefinitionTemplate[9]/1.e6
 830            self.proj4_lon_0 = self.gridDefinitionTemplate[10]/1.e6
 831            self.proj4_h = self.earthMajorAxis * (self.gridDefinitionTemplate[18]/1.e6)
 832            dx = self.gridDefinitionTemplate[12]
 833            dy = self.gridDefinitionTemplate[13]
 834            # if lat_0 is equator, it's a geostationary view.
 835            if self.proj4_lat_0 == 0.: # if lat_0 is equator, it's a
 836                self.proj4_proj = 'geos'
 837            # general case of 'near-side perspective projection' (untested)
 838            else:
 839                self.proj4_proj = 'nsper'
 840                msg = 'Only geostationary perspective is supported. Lat/Lon values returned by grid method may be incorrect.'
 841                warnings.warn(msg)
 842            # latitude of horizon on central meridian
 843            lonmax = 90.-(180./np.pi)*np.arcsin(self.earthMajorAxis/self.proj4_h)
 844            # longitude of horizon on equator
 845            latmax = 90.-(180./np.pi)*np.arcsin(self.earthMinorAxis/self.proj4_h)
 846            # truncate to nearest thousandth of a degree (to make sure
 847            # they aren't slightly over the horizon)
 848            latmax = int(1000*latmax)/1000.
 849            lonmax = int(1000*lonmax)/1000.
 850            # h is measured from surface of earth at equator.
 851            self.proj4_h = self.proj4_h - self.earthMajorAxis
 852            # width and height of visible projection
 853            P = pyproj.Proj(proj=self.proj4_proj,\
 854                            a=self.earthMajorAxis,b=self.earthMinorAxis,\
 855                            lat_0=0,lon_0=0,h=self.proj4_h)
 856            x1,y1 = P(0.,latmax)
 857            x2,y2 = P(lonmax,0.)
 858            width = 2*x2
 859            height = 2*y1
 860            self.gridlengthXDirection = width/dx
 861            self.gridlengthYDirection = height/dy
 862            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[16],output=list)[0:4]
 863        elif self.gridDefinitionTemplateNumber == 110:
 864            # Azimuthal Equidistant
 865            self.proj4_lat_0 = self.gridDefinitionTemplate[9]/1.e6
 866            self.proj4_lon_0 = self.gridDefinitionTemplate[10]/1.e6
 867            self.gridlengthXDirection = self.gridDefinitionTemplate[12]/1000.
 868            self.gridlengthYDirection = self.gridDefinitionTemplate[13]/1000.
 869            self.proj4_proj = 'aeqd'
 870            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[15],output=list)[0:4]
 871        elif self.gridDefinitionTemplateNumber == 204:
 872            # Curvilinear Orthogonal
 873            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[18],output=list)[0:4]
 874        else:
 875            errmsg = 'Unsupported Grid Definition Template Number - 3.%i' % self.gridDefinitionTemplateNumber.value
 876            raise ValueError(errmsg)
 877
 878        # -------------------------------
 879        # Section 4 -- Product Definition
 880        # -------------------------------
 881      
 882        # Template 4.0 - NOTE: That is these attributes apply to other templates.
 883        self.parameterCategory = self.productDefinitionTemplate[0]
 884        self.parameterNumber = self.productDefinitionTemplate[1]
 885        self.fullName,self.units,self.shortName = tables.get_varinfo_from_table(self.discipline.value,
 886                                                                                self.parameterCategory,
 887                                                                                self.parameterNumber)
 888        self.typeOfGeneratingProcess = Grib2Metadata(self.productDefinitionTemplate[2],table='4.3')
 889        self.backgroundGeneratingProcessIdentifier = self.productDefinitionTemplate[3]
 890        self.generatingProcess = Grib2Metadata(self.productDefinitionTemplate[4],table='generating_process')
 891        self.unitOfTimeRange = Grib2Metadata(self.productDefinitionTemplate[7],table='4.4')
 892        self.leadTime = self.productDefinitionTemplate[8]
 893        self.typeOfFirstFixedSurface = Grib2Metadata(self.productDefinitionTemplate[9],table='4.5')
 894        self.scaleFactorOfFirstFixedSurface = self.productDefinitionTemplate[10]
 895        self.unitOfFirstFixedSurface = self.typeOfFirstFixedSurface.definition[1]
 896        self.scaledValueOfFirstFixedSurface = self.productDefinitionTemplate[11]
 897        self.valueOfFirstFixedSurface = self.scaledValueOfFirstFixedSurface/(10.**self.scaleFactorOfFirstFixedSurface)
 898        temp = tables.get_value_from_table(self.productDefinitionTemplate[12],'4.5')
 899        if temp[0] == 'Missing' and temp[1] == 'unknown':
 900            self.typeOfSecondFixedSurface = None
 901            self.scaleFactorOfSecondFixedSurface = None
 902            self.unitOfSecondFixedSurface = None
 903            self.valueOfSecondFixedSurface = None
 904        else:
 905            self.typeOfSecondFixedSurface = Grib2Metadata(self.productDefinitionTemplate[12],table='4.5')
 906            self.scaleFactorOfSecondFixedSurface = self.productDefinitionTemplate[13]
 907            self.unitOfSecondFixedSurface = self.typeOfSecondFixedSurface.definition[1]
 908            self.scaledValueOfSecondFixedSurface = self.productDefinitionTemplate[14]
 909            self.valueOfSecondFixedSurface = self.scaledValueOfSecondFixedSurface/(10.**self.scaleFactorOfSecondFixedSurface)
 910        self.level = tables.get_wgrib2_level_string(*self.productDefinitionTemplate[9:15])
 911
 912        # Template 4.1 -
 913        if self.productDefinitionTemplateNumber == 1:
 914            self.typeOfEnsembleForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.6')
 915            self.perturbationNumber = self.productDefinitionTemplate[16]
 916            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[17]
 917
 918        # Template 4.2 -
 919        elif self.productDefinitionTemplateNumber == 2:
 920            self.typeOfDerivedForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.7')
 921            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[16]
 922
 923        # Template 4.5 -
 924        elif self.productDefinitionTemplateNumber == 5:
 925            self.forecastProbabilityNumber = self.productDefinitionTemplate[15]
 926            self.totalNumberOfForecastProbabilities = self.productDefinitionTemplate[16]
 927            self.typeOfProbability = Grib2Metadata(self.productDefinitionTemplate[17],table='4.9')
 928            self.scaleFactorOfThresholdLowerLimit = self.productDefinitionTemplate[18]
 929            self.scaledValueOfThresholdLowerLimit = self.productDefinitionTemplate[19]
 930            self.scaleFactorOfThresholdUpperLimit = self.productDefinitionTemplate[20]
 931            self.scaledValueOfThresholdUpperLimit = self.productDefinitionTemplate[21]
 932            self.thresholdLowerLimit = 0.0 if self.productDefinitionTemplate[19] == 255 else \
 933                                       self.productDefinitionTemplate[19]/(10.**self.productDefinitionTemplate[18])
 934            self.thresholdUpperLimit = 0.0 if self.productDefinitionTemplate[21] == 255 else \
 935                                       self.productDefinitionTemplate[21]/(10.**self.productDefinitionTemplate[20])
 936            self.threshold = utils.get_wgrib2_prob_string(*self.productDefinitionTemplate[17:22])
 937
 938        # Template 4.6 -
 939        elif self.productDefinitionTemplateNumber == 6:
 940            self.percentileValue = self.productDefinitionTemplate[15]
 941
 942        # Template 4.8 -
 943        elif self.productDefinitionTemplateNumber == 8:
 944            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[15]
 945            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[16]
 946            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[17]
 947            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[18]
 948            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[19]
 949            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[20]
 950            self.numberOfTimeRanges = self.productDefinitionTemplate[21]
 951            self.numberOfMissingValues = self.productDefinitionTemplate[22]
 952            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[23],table='4.10')
 953            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[24],table='4.11')
 954            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[25],table='4.4')
 955            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[26]
 956            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[27],table='4.4')
 957            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[28]
 958
 959        # Template 4.9 -
 960        elif self.productDefinitionTemplateNumber == 9:
 961            self.forecastProbabilityNumber = self.productDefinitionTemplate[15]
 962            self.totalNumberOfForecastProbabilities = self.productDefinitionTemplate[16]
 963            self.typeOfProbability = Grib2Metadata(self.productDefinitionTemplate[17],table='4.9')
 964            self.scaleFactorOfThresholdLowerLimit = self.productDefinitionTemplate[18]
 965            self.scaledValueOfThresholdLowerLimit = self.productDefinitionTemplate[19]
 966            self.scaleFactorOfThresholdUpperLimit = self.productDefinitionTemplate[20]
 967            self.scaledValueOfThresholdUpperLimit = self.productDefinitionTemplate[21]
 968            self.thresholdLowerLimit = 0.0 if self.productDefinitionTemplate[19] == 255 else \
 969                                       self.productDefinitionTemplate[19]/(10.**self.productDefinitionTemplate[18])
 970            self.thresholdUpperLimit = 0.0 if self.productDefinitionTemplate[21] == 255 else \
 971                                       self.productDefinitionTemplate[21]/(10.**self.productDefinitionTemplate[20])
 972            self.threshold = utils.get_wgrib2_prob_string(*self.productDefinitionTemplate[17:22])
 973            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[22]
 974            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[23]
 975            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[24]
 976            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[25]
 977            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[26]
 978            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[27]
 979            self.numberOfTimeRanges = self.productDefinitionTemplate[28]
 980            self.numberOfMissingValues = self.productDefinitionTemplate[29]
 981            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[30],table='4.10')
 982            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[31],table='4.11')
 983            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[32],table='4.4')
 984            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[33]
 985            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[34],table='4.4')
 986            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[35]
 987
 988        # Template 4.10 -
 989        elif self.productDefinitionTemplateNumber == 10:
 990            self.percentileValue = self.productDefinitionTemplate[15]
 991            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[16]
 992            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[17]
 993            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[18]
 994            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[19]
 995            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[20]
 996            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[21]
 997            self.numberOfTimeRanges = self.productDefinitionTemplate[22]
 998            self.numberOfMissingValues = self.productDefinitionTemplate[23]
 999            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[24],table='4.10')
1000            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[25],table='4.11')
1001            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[26],table='4.4')
1002            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[27]
1003            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[28],table='4.4')
1004            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[29]
1005
1006        # Template 4.11 -
1007        elif self.productDefinitionTemplateNumber == 11:
1008            self.typeOfEnsembleForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.6')
1009            self.perturbationNumber = self.productDefinitionTemplate[16]
1010            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[17]
1011            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[18]
1012            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[19]
1013            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[20]
1014            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[21]
1015            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[22]
1016            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[23]
1017            self.numberOfTimeRanges = self.productDefinitionTemplate[24]
1018            self.numberOfMissingValues = self.productDefinitionTemplate[25]
1019            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[26],table='4.10')
1020            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[27],table='4.11')
1021            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[28],table='4.4')
1022            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[29]
1023            self.unitOfTimeRangeOfSuccessiveFields = tables.get_value_from_table(self.productDefinitionTemplate[30],table='4.4')
1024            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[31]
1025
1026        # Template 4.12 -
1027        elif self.productDefinitionTemplateNumber == 12:
1028            self.typeOfDerivedForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.7')
1029            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[16]
1030            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[17]
1031            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[18]
1032            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[19]
1033            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[20]
1034            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[21]
1035            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[22]
1036            self.numberOfTimeRanges = self.productDefinitionTemplate[23]
1037            self.numberOfMissingValues = self.productDefinitionTemplate[24]
1038            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[25],table='4.10')
1039            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[26],table='4.11')
1040            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[27],table='4.4')
1041            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[28]
1042            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[29],table='4.4')
1043            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[30]
1044
1045        # Template 4.15 -
1046        elif self.productDefinitionTemplateNumber == 15:
1047            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[15],table='4.10')
1048            self.typeOfSpatialProcessing = Grib2Metadata(self.productDefinitionTemplate[16],table='4.15')
1049            self.numberOfDataPointsForSpatialProcessing = self.productDefinitionTemplate[17]
1050
1051        else:
1052            if self.productDefinitionTemplateNumber != 0:
1053                errmsg = 'Unsupported Product Definition Template Number - 4.%i' % self.productDefinitionTemplateNumber.value
1054                raise ValueError(errmsg)
1055
1056
1057        self.leadTime = utils.getleadtime(self.identificationSection,
1058                                          self.productDefinitionTemplateNumber.value,
1059                                          self.productDefinitionTemplate)
1060
1061        if self.productDefinitionTemplateNumber.value in [8,9,10,11,12]:
1062            self.dtEndOfTimePeriod = datetime.datetime(self.yearOfEndOfTimePeriod,self.monthOfEndOfTimePeriod,
1063                                     self.dayOfEndOfTimePeriod,hour=self.hourOfEndOfTimePeriod,
1064                                     minute=self.minuteOfEndOfTimePeriod,
1065                                     second=self.secondOfEndOfTimePeriod)
1066
1067        # --------------------------------
1068        # Section 5 -- Data Representation
1069        # --------------------------------
1070
1071        # Template 5.0 - Simple Packing
1072        if self.dataRepresentationTemplateNumber == 0:
1073            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1074            self.binScaleFactor = self.dataRepresentationTemplate[1]
1075            self.decScaleFactor = self.dataRepresentationTemplate[2]
1076            self.nBitsPacking = self.dataRepresentationTemplate[3]
1077            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[3],table='5.1')
1078
1079        # Template 5.2 - Complex Packing
1080        elif self.dataRepresentationTemplateNumber == 2:
1081            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1082            self.binScaleFactor = self.dataRepresentationTemplate[1]
1083            self.decScaleFactor = self.dataRepresentationTemplate[2]
1084            self.nBitsPacking = self.dataRepresentationTemplate[3]
1085            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1086            self.groupSplitMethod = Grib2Metadata(self.dataRepresentationTemplate[5],table='5.4')
1087            self.typeOfMissingValue = Grib2Metadata(self.dataRepresentationTemplate[6],table='5.5')
1088            self.priMissingValue = utils.getieeeint(self.dataRepresentationTemplate[7]) if self.dataRepresentationTemplate[6] in [1,2] else None
1089            self.secMissingValue = utils.getieeeint(self.dataRepresentationTemplate[8]) if self.dataRepresentationTemplate[6] == 2 else None
1090            self.nGroups = self.dataRepresentationTemplate[9]
1091            self.refGroupWidth = self.dataRepresentationTemplate[10]
1092            self.nBitsGroupWidth = self.dataRepresentationTemplate[11]
1093            self.refGroupLength = self.dataRepresentationTemplate[12]
1094            self.groupLengthIncrement = self.dataRepresentationTemplate[13]
1095            self.lengthOfLastGroup = self.dataRepresentationTemplate[14]
1096            self.nBitsScaledGroupLength = self.dataRepresentationTemplate[15]
1097
1098        # Template 5.3 - Complex Packing and Spatial Differencing
1099        elif self.dataRepresentationTemplateNumber == 3:
1100            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1101            self.binScaleFactor = self.dataRepresentationTemplate[1]
1102            self.decScaleFactor = self.dataRepresentationTemplate[2]
1103            self.nBitsPacking = self.dataRepresentationTemplate[3]
1104            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1105            self.groupSplitMethod = Grib2Metadata(self.dataRepresentationTemplate[5],table='5.4')
1106            self.typeOfMissingValue = Grib2Metadata(self.dataRepresentationTemplate[6],table='5.5')
1107            self.priMissingValue = utils.getieeeint(self.dataRepresentationTemplate[7]) if self.dataRepresentationTemplate[6] in [1,2] else None
1108            self.secMissingValue = utils.getieeeint(self.dataRepresentationTemplate[8]) if self.dataRepresentationTemplate[6] == 2 else None
1109            self.nGroups = self.dataRepresentationTemplate[9]
1110            self.refGroupWidth = self.dataRepresentationTemplate[10]
1111            self.nBitsGroupWidth = self.dataRepresentationTemplate[11]
1112            self.refGroupLength = self.dataRepresentationTemplate[12]
1113            self.groupLengthIncrement = self.dataRepresentationTemplate[13]
1114            self.lengthOfLastGroup = self.dataRepresentationTemplate[14]
1115            self.nBitsScaledGroupLength = self.dataRepresentationTemplate[15]
1116            self.spatialDifferenceOrder = Grib2Metadata(self.dataRepresentationTemplate[16],table='5.6')
1117            self.nBytesSpatialDifference = self.dataRepresentationTemplate[17]
1118
1119        # Template 5.4 - IEEE Floating Point Data
1120        elif self.dataRepresentationTemplateNumber == 4:
1121            self.precision = Grib2Metadata(self.dataRepresentationTemplate[0],table='5.7')
1122
1123        # Template 5.40 - JPEG2000 Compression
1124        elif self.dataRepresentationTemplateNumber == 40:
1125            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1126            self.binScaleFactor = self.dataRepresentationTemplate[1]
1127            self.decScaleFactor = self.dataRepresentationTemplate[2]
1128            self.nBitsPacking = self.dataRepresentationTemplate[3]
1129            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1130            self.typeOfCompression = Grib2Metadata(self.dataRepresentationTemplate[5],table='5.40')
1131            self.targetCompressionRatio = self.dataRepresentationTemplate[6]
1132
1133        # Template 5.41 - PNG Compression
1134        elif self.dataRepresentationTemplateNumber == 41:
1135            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1136            self.binScaleFactor = self.dataRepresentationTemplate[1]
1137            self.decScaleFactor = self.dataRepresentationTemplate[2]
1138            self.nBitsPacking = self.dataRepresentationTemplate[3]
1139            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1140
1141        else:
1142            errmsg = 'Unsupported Data Representation Definition Template Number - 5.%i' % self.dataRepresentationTemplateNumber.value
1143            raise ValueError(errmsg)

Decode the unpacked GRIB2 integer-coded metadata in human-readable form and linked to GRIB2 tables.

def data( self, fill_value=9.969209968386869e+36, masked_array=True, expand=True, order=None, map_keys=False)
1146    def data(self, fill_value=DEFAULT_FILL_VALUE, masked_array=True, expand=True, order=None,
1147             map_keys=False):
1148        """
1149        Returns an unpacked data grid.
1150
1151        Parameters
1152        ----------
1153
1154        **`fill_value`**: Missing or masked data is filled with this value or default value given by
1155        `DEFAULT_FILL_VALUE`
1156
1157        **`masked_array`**: If `True` [DEFAULT], return masked array if there is bitmap for missing 
1158        or masked data.
1159
1160        **`expand`**: If `True` [DEFAULT], Reduced Gaussian grids are expanded to regular Gaussian grids.
1161
1162        **`order`**: If 0 [DEFAULT], nearest neighbor interpolation is used if grid has missing 
1163        or bitmapped values. If 1, linear interpolation is used for expanding reduced Gaussian grids.
1164
1165        **`map_keys`**: If `True`, data values will be mapped to the string-based keys that are stored
1166        in the Local Use Section (section 2) of the GRIB2 Message or in a code table as specified in the
1167        units (i.e. "See Table 4.xxx").
1168
1169        Returns
1170        -------
1171
1172        **`numpy.ndarray`**: A numpy.ndarray with shape (ny,nx). By default the array dtype=np.float32, 
1173        but could be np.int32 if Grib2Message.typeOfValues is integer.  The array dtype will be 
1174        string-based if map_keys=True.
1175        """
1176        if not hasattr(self,'scanModeFlags'):
1177            raise ValueError('Unsupported grid definition template number %s'%self.gridDefinitionTemplateNumber)
1178        else:
1179            if self.scanModeFlags[2]:
1180                storageorder='F'
1181            else:
1182                storageorder='C'
1183        if order is None:
1184            if (self.dataRepresentationTemplateNumber in [2,3] and
1185                self.dataRepresentationTemplate[6] != 0) or self.bitMapFlag == 0:
1186                order = 0
1187            else:
1188                order = 1
1189        drtnum = self.dataRepresentationTemplateNumber.value
1190        drtmpl = np.asarray(self.dataRepresentationTemplate,dtype=DEFAULT_NUMPY_INT)
1191        gdtnum = self.gridDefinitionTemplateNumber.value
1192        gdtmpl = np.asarray(self.gridDefinitionTemplate,dtype=DEFAULT_NUMPY_INT)
1193        ndpts = self.numberOfDataPoints
1194        gds = self.gridDefinitionSection
1195        ngrdpts = gds[1]
1196        ipos = self._datapos
1197        fld1 = g2clib.unpack7(self._msg,gdtnum,gdtmpl,drtnum,drtmpl,ndpts,ipos,np.empty,storageorder=storageorder)
1198        # Apply bitmap.
1199        if self.bitMapFlag == 0:
1200            fld = fill_value*np.ones(ngrdpts,'f')
1201            np.put(fld,np.nonzero(self.bitMap),fld1)
1202            if masked_array:
1203                fld = ma.masked_values(fld,fill_value)
1204        # Missing values instead of bitmap
1205        elif masked_array and hasattr(self,'priMissingValue'):
1206            if hasattr(self,'secMissingValue'):
1207                mask = np.logical_or(fld1==self.priMissingValue,fld1==self.secMissingValue)
1208            else:
1209                mask = fld1 == self.priMissingValue
1210            fld = ma.array(fld1,mask=mask)
1211        else:
1212            fld = fld1
1213        if self.nx is not None and self.ny is not None: # Rectangular grid.
1214            if ma.isMA(fld):
1215                fld = ma.reshape(fld,(self.ny,self.nx))
1216            else:
1217                fld = np.reshape(fld,(self.ny,self.nx))
1218        else:
1219            if gds[2] and gdtnum == 40: # Reduced global Gaussian grid.
1220                if expand:
1221                    from . import redtoreg
1222                    self.nx = 2*self.ny
1223                    lonsperlat = self.defList
1224                    if ma.isMA(fld):
1225                        fld = ma.filled(fld)
1226                        fld = redtoreg._redtoreg(self.nx,lonsperlat.astype(np.long),
1227                                                 fld.astype(np.double),fill_value)
1228                        fld = ma.masked_values(fld,fill_value)
1229                    else:
1230                        fld = redtoreg._redtoreg(self.nx,lonsperlat.astype(np.long),
1231                                                 fld.astype(np.double),fill_value)
1232        # Check scan modes for rect grids.
1233        if self.nx is not None and self.ny is not None:
1234            if self.scanModeFlags[3]:
1235                fldsave = fld.astype('f') # casting makes a copy
1236                fld[1::2,:] = fldsave[1::2,::-1]
1237
1238        # Set data to integer according to GRIB metadata
1239        if self.typeOfValues == "Integer": fld = fld.astype(np.int32)
1240
1241        # Map the data values to their respective definitions.
1242        if map_keys:
1243            fld = fld.astype(np.int32).astype(str)
1244            if self.identificationSection[0] == 7 and \
1245               self.identificationSection[1] == 14 and \
1246               self.shortName == 'PWTHER':
1247                # MDL Predominant Weather Grid
1248                keys = utils.decode_mdl_wx_strings(self._lus)
1249                for n,k in enumerate(keys):
1250                    fld = np.where(fld==str(n+1),k,fld)
1251            elif self.identificationSection[0] == 8 and \
1252                 self.identificationSection[1] == 65535 and \
1253                 self.shortName == 'CRAIN':
1254                # NDFD Predominant Weather Grid
1255                keys = utils.decode_ndfd_wx_strings(self._lus)
1256                for n,k in enumerate(keys):
1257                    fld = np.where(fld==str(n+1),k,fld)
1258            else:
1259                # For data whose units are defined in a code table
1260                tbl = re.findall(r'\d\.\d+',self.units,re.IGNORECASE)[0]
1261                for k,v in tables.get_table(tbl).items():
1262                    fld = np.where(fld==k,v,fld)
1263        return fld

Returns an unpacked data grid.

Parameters

fill_value: Missing or masked data is filled with this value or default value given by DEFAULT_FILL_VALUE

masked_array: If True [DEFAULT], return masked array if there is bitmap for missing or masked data.

expand: If True [DEFAULT], Reduced Gaussian grids are expanded to regular Gaussian grids.

order: If 0 [DEFAULT], nearest neighbor interpolation is used if grid has missing or bitmapped values. If 1, linear interpolation is used for expanding reduced Gaussian grids.

map_keys: If True, data values will be mapped to the string-based keys that are stored in the Local Use Section (section 2) of the GRIB2 Message or in a code table as specified in the units (i.e. "See Table 4.xxx").

Returns

numpy.ndarray: A numpy.ndarray with shape (ny,nx). By default the array dtype=np.float32, but could be np.int32 if Grib2Message.typeOfValues is integer. The array dtype will be string-based if map_keys=True.

def latlons(self)
1266    def latlons(self):
1267        """Alias for `grib2io.Grib2Message.grid` method"""
1268        return self.grid()

Alias for grib2io.Grib2Message.grid method

def grid(self)
1271    def grid(self):
1272        """
1273        Return lats,lons (in degrees) of grid. Currently can handle reg. lat/lon, 
1274        global Gaussian, mercator, stereographic, lambert conformal, albers equal-area, 
1275        space-view and azimuthal equidistant grids.
1276
1277        Returns
1278        -------
1279
1280        **`lats, lons : numpy.ndarray`**
1281
1282        Returns two numpy.ndarrays with dtype=numpy.float32 of grid latitudes and
1283        longitudes in units of degrees.
1284        """
1285        gdtnum = self.gridDefinitionTemplateNumber
1286        gdtmpl = self.gridDefinitionTemplate
1287        reggrid = self.gridDefinitionSection[2] == 0 # This means regular 2-d grid
1288        self.projparams = {}
1289        if self.earthMajorAxis is not None: self.projparams['a']=self.earthMajorAxis
1290        if self.earthMajorAxis is not None: self.projparams['b']=self.earthMinorAxis
1291        if gdtnum == 0:
1292            # Regular lat/lon grid
1293            lon1, lat1 = self.longitudeFirstGridpoint, self.latitudeFirstGridpoint
1294            lon2, lat2 = self.longitudeLastGridpoint, self.latitudeLastGridpoint
1295            dlon = self.gridlengthXDirection
1296            dlat = self.gridlengthYDirection
1297            lats = np.arange(lat1,lat2+dlat,dlat)
1298            lons = np.arange(lon1,lon2+dlon,dlon)
1299            # flip if scan mode says to.
1300            #if self.scanModeFlags[0]:
1301            #    lons = lons[::-1]
1302            #if not self.scanModeFlags[1]:
1303            #    lats = lats[::-1]
1304            self.projparams['proj'] = 'cyl'
1305            lons,lats = np.meshgrid(lons,lats) # make 2-d arrays.
1306        elif gdtnum == 40: # Gaussian grid (only works for global!)
1307            from utils.gauss_grids import gaussian_latitudes
1308            lon1, lat1 = self.longitudeFirstGridpoint, self.latitudeFirstGridpoint
1309            lon2, lat2 = self.longitudeLastGridpoint, self.latitudeLastGridpoint
1310            nlats = self.ny
1311            if not reggrid: # Reduced Gaussian grid.
1312                nlons = 2*nlats
1313                dlon = 360./nlons
1314            else:
1315                nlons = self.nx
1316                dlon = self.gridlengthXDirection
1317            lons = np.arange(lon1,lon2+dlon,dlon)
1318            # Compute Gaussian lats (north to south)
1319            lats = gaussian_latitudes(nlats)
1320            if lat1 < lat2:  # reverse them if necessary
1321                lats = lats[::-1]
1322            # flip if scan mode says to.
1323            #if self.scanModeFlags[0]:
1324            #    lons = lons[::-1]
1325            #if not self.scanModeFlags[1]:
1326            #    lats = lats[::-1]
1327            self.projparams['proj'] = 'cyl'
1328            lons,lats = np.meshgrid(lons,lats) # make 2-d arrays
1329        elif gdtnum in [10,20,30,31,110]:
1330            # Mercator, Lambert Conformal, Stereographic, Albers Equal Area, Azimuthal Equidistant
1331            dx,dy = self.gridlengthXDirection, self.gridlengthYDirection
1332            lon1,lat1 = self.longitudeFirstGridpoint, self.latitudeFirstGridpoint
1333            if gdtnum == 10: # Mercator.
1334                self.projparams['lat_ts']=self.proj4_lat_ts
1335                self.projparams['proj']=self.proj4_proj
1336                self.projparams['lon_0']=self.proj4_lon_0
1337                pj = pyproj.Proj(self.projparams)
1338                llcrnrx, llcrnry = pj(lon1,lat1)
1339                x = llcrnrx+dx*np.arange(self.nx)
1340                y = llcrnry+dy*np.arange(self.ny)
1341                x,y = np.meshgrid(x, y)
1342                lons,lats = pj(x, y, inverse=True)
1343            elif gdtnum == 20:  # Stereographic
1344                self.projparams['lat_ts']=self.proj4_lat_ts
1345                self.projparams['proj']=self.proj4_proj
1346                self.projparams['lat_0']=self.proj4_lat_0
1347                self.projparams['lon_0']=self.proj4_lon_0
1348                pj = pyproj.Proj(self.projparams)
1349                llcrnrx, llcrnry = pj(lon1,lat1)
1350                x = llcrnrx+dx*np.arange(self.nx)
1351                y = llcrnry+dy*np.arange(self.ny)
1352                x,y = np.meshgrid(x, y)
1353                lons,lats = pj(x, y, inverse=True)
1354            elif gdtnum in [30,31]: # Lambert, Albers
1355                self.projparams['lat_1']=self.proj4_lat_1
1356                self.projparams['lat_2']=self.proj4_lat_2
1357                self.projparams['proj']=self.proj4_proj
1358                self.projparams['lon_0']=self.proj4_lon_0
1359                pj = pyproj.Proj(self.projparams)
1360                llcrnrx, llcrnry = pj(lon1,lat1)
1361                x = llcrnrx+dx*np.arange(self.nx)
1362                y = llcrnry+dy*np.arange(self.ny)
1363                x,y = np.meshgrid(x, y)
1364                lons,lats = pj(x, y, inverse=True)
1365            elif gdtnum == 110: # Azimuthal Equidistant
1366                self.projparams['proj']=self.proj4_proj
1367                self.projparams['lat_0']=self.proj4_lat_0
1368                self.projparams['lon_0']=self.proj4_lon_0
1369                pj = pyproj.Proj(self.projparams)
1370                llcrnrx, llcrnry = pj(lon1,lat1)
1371                x = llcrnrx+dx*np.arange(self.nx)
1372                y = llcrnry+dy*np.arange(self.ny)
1373                x,y = np.meshgrid(x, y)
1374                lons,lats = pj(x, y, inverse=True)
1375        elif gdtnum == 90:
1376            # Satellite Projection
1377            dx = self.gridlengthXDirection
1378            dy = self.gridlengthYDirection
1379            self.projparams['proj']=self.proj4_proj
1380            self.projparams['lon_0']=self.proj4_lon_0
1381            self.projparams['lat_0']=self.proj4_lat_0
1382            self.projparams['h']=self.proj4_h
1383            pj = pyproj.Proj(self.projparams)
1384            x = dx*np.indices((self.ny,self.nx),'f')[1,:,:]
1385            x -= 0.5*x.max()
1386            y = dy*np.indices((self.ny,self.nx),'f')[0,:,:]
1387            y -= 0.5*y.max()
1388            lons,lats = pj(x,y,inverse=True)
1389            # Set lons,lats to 1.e30 where undefined
1390            abslons = np.fabs(lons)
1391            abslats = np.fabs(lats)
1392            lons = np.where(abslons < 1.e20, lons, 1.e30)
1393            lats = np.where(abslats < 1.e20, lats, 1.e30)
1394        else:
1395            raise ValueError('Unsupported grid')
1396
1397        return lats.astype('f'), lons.astype('f')

Return lats,lons (in degrees) of grid. Currently can handle reg. lat/lon, global Gaussian, mercator, stereographic, lambert conformal, albers equal-area, space-view and azimuthal equidistant grids.

Returns

lats, lons : numpy.ndarray

Returns two numpy.ndarrays with dtype=numpy.float32 of grid latitudes and longitudes in units of degrees.

def addlocal(self, ludata)
1400    def addlocal(self, ludata):
1401        """
1402        Add a Local Use Section [(Section 2)](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_sect2.shtml)
1403        to the GRIB2 message.
1404
1405        Parameters
1406        ----------
1407
1408        **`ludata : bytes`**: Local Use data.
1409        """
1410        assert isinstance(ludata,bytes)
1411        self._msg,self._pos = g2clib.grib2_addlocal(self._msg,ludata)
1412        self.hasLocalUseSection = True
1413        self._sections.append(2)

Add a Local Use Section (Section 2) to the GRIB2 message.

Parameters

ludata : bytes: Local Use data.

def addgrid(self, gdsinfo, gdtmpl, deflist=None)
1416    def addgrid(self, gdsinfo, gdtmpl, deflist=None):
1417        """
1418        Add a Grid Definition Section [(Section 3)](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_doc/grib2_sect3.shtml) 
1419        to the GRIB2 message.
1420
1421        Parameters
1422        ----------
1423
1424        **`gdsinfo`**: Sequence containing information needed for the grid definition section.
1425
1426        | Index | Description |
1427        | :---: | :---        |
1428        | gdsinfo[0] | Source of grid definition - [Code Table 3.0](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table3-0.shtml)|
1429        | gdsinfo[1] | Number of data points|
1430        | gdsinfo[2] | Number of octets for optional list of numbers defining number of points|
1431        | gdsinfo[3] | Interpetation of list of numbers defining number of points - [Code Table 3.11](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table3-11.shtml)|
1432        | gdsinfo[4] | Grid Definition Template Number - [Code Table 3.1](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table3-1.shtml)|
1433
1434        **`gdtmpl`**: Sequence of values for the specified Grid Definition Template. Each 
1435        element of this integer array contains an entry (in the order specified) of Grid
1436        Definition Template 3.NN
1437
1438        **`deflist`**: Sequence containing the number of grid points contained in each 
1439        row (or column) of a non-regular grid.  Used if gdsinfo[2] != 0.
1440        """
1441        if 3 in self._sections:
1442            raise ValueError('GRIB2 Message already contains Grid Definition Section.')
1443        if deflist is not None:
1444            _deflist = np.array(deflist,dtype=DEFAULT_NUMPY_INT)
1445        else:
1446            _deflist = None
1447        gdtnum = gdsinfo[4]
1448        if gdtnum in [0,1,2,3,40,41,42,43,44,203,205,32768,32769]:
1449            self.scanModeFlags = utils.int2bin(gdtmpl[18],output=list)[0:4]
1450        elif gdtnum == 10: # mercator
1451            self.scanModeFlags = utils.int2bin(gdtmpl[15],output=list)[0:4]
1452        elif gdtnum == 20: # stereographic
1453            self.scanModeFlags = utils.int2bin(gdtmpl[17],output=list)[0:4]
1454        elif gdtnum == 30: # lambert conformal
1455            self.scanModeFlags = utils.int2bin(gdtmpl[17],output=list)[0:4]
1456        elif gdtnum == 31: # albers equal area.
1457            self.scanModeFlags = utils.int2bin(gdtmpl[17],output=list)[0:4]
1458        elif gdtnum == 90: # near-sided vertical perspective satellite projection
1459            self.scanModeFlags = utils.int2bin(gdtmpl[16],output=list)[0:4]
1460        elif gdtnum == 110: # azimuthal equidistant.
1461            self.scanModeFlags = utils.int2bin(gdtmpl[15],output=list)[0:4]
1462        elif gdtnum == 120:
1463            self.scanModeFlags = utils.int2bin(gdtmpl[6],output=list)[0:4]
1464        elif gdtnum == 204: # curvilinear orthogonal
1465            self.scanModeFlags = utils.int2bin(gdtmpl[18],output=list)[0:4]
1466        elif gdtnum in [1000,1100]:
1467            self.scanModeFlags = utils.int2bin(gdtmpl[12],output=list)[0:4]
1468        self._msg,self._pos = g2clib.grib2_addgrid(self._msg,
1469                                                   np.array(gdsinfo,dtype=DEFAULT_NUMPY_INT),
1470                                                   np.array(gdtmpl,dtype=DEFAULT_NUMPY_INT),
1471                                                   _deflist)
1472        self._sections.append(3)

Add a Grid Definition Section (Section 3) to the GRIB2 message.

Parameters

gdsinfo: Sequence containing information needed for the grid definition section.

Index Description
gdsinfo[0] Source of grid definition - Code Table 3.0
gdsinfo[1] Number of data points
gdsinfo[2] Number of octets for optional list of numbers defining number of points
gdsinfo[3] Interpetation of list of numbers defining number of points - Code Table 3.11
gdsinfo[4] Grid Definition Template Number - Code Table 3.1

gdtmpl: Sequence of values for the specified Grid Definition Template. Each element of this integer array contains an entry (in the order specified) of Grid Definition Template 3.NN

deflist: Sequence containing the number of grid points contained in each row (or column) of a non-regular grid. Used if gdsinfo[2] != 0.

def addfield( self, field, pdtnum, pdtmpl, coordlist=None, packing='complex-spdiff', **packing_opts)
1475    def addfield(self, field, pdtnum, pdtmpl, coordlist=None, packing="complex-spdiff", **packing_opts): 
1476        """
1477        Add a Product Definition, Data Representation, Bitmap, and Data Sections 
1478        to `Grib2Message` instance (i.e. Sections 4-7).  Must be called after the grid 
1479        definition section has been added (`addfield`).
1480
1481        Parameters
1482        ----------
1483
1484        **`field`**: Numpy array of data values to pack.  If field is a masked array, then 
1485        a bitmap is created from the mask.
1486
1487        **`pdtnum`**: integer Product Definition Template Number - [Code Table 4.0](http://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_table4-0.shtml)
1488
1489        **`pdtmpl`**: Sequence with the data values for the specified Product Definition 
1490        Template (N=pdtnum).  Each element of this integer array contains an entry (in 
1491        the order specified) of Product Definition Template 4.N.
1492
1493        **`coordlist`**: Sequence containing floating point values intended to document the 
1494        vertical discretization with model data on hybrid coordinate vertical levels. Default is `None`.
1495
1496        **`packing`**: String to specify the type of packing. Valid options are the following:
1497
1498        | Packing Scheme | Description |
1499        | :---:          | :---:       |
1500        | 'simple'         | [Simple packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-0.shtml) | 
1501        | 'complex'        | [Complex packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-2.shtml) | 
1502        | 'complex-spdiff' | [Complex packing with Spatial Differencing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-3.shtml) | 
1503        | 'jpeg'           | [JPEG compression](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-40.shtml) | 
1504        | 'png'            | [PNG compression](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-41.shtml) | 
1505        | 'spectral-simple'| [Spectral Data - Simple packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-50.shtml) | 
1506        | 'spectral-complex'| [Spectral Data - Complex packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-51.shtml) | 
1507
1508        **`**packing_opts`**: Packing keyword arguments. The keywords are the same as Grib2Message attribute names for
1509        the Data Representation Template (Section 5) metadata. Valid keywords per packing scheme are the following:
1510
1511        | Packing Scheme | Keyword Arguments |
1512        | :---:          | :---:                      |
1513        | 'simple'     | `binScaleFactor`, `decScaleFactor` |
1514        | 'complex'     | `binScaleFactor`, `decScaleFactor`, `priMissingValue`, [`secMissingValue`] |
1515        | 'complex-spdiff'     | `binScaleFactor`, `decScaleFactor`, `spatialDifferenceOrder`, `priMissingValue`, [`secMissingValue`] |
1516        | 'jpeg'     | `binScaleFactor`, `decScaleFactor` |
1517        | 'png'     | `binScaleFactor`, `decScaleFactor` |
1518        | 'spectral-simple'     | `binScaleFactor`, `decScaleFactor` |
1519        | 'spectral-complex'     | `binScaleFactor`, `decScaleFactor` |
1520        """
1521        if self._sections[-1] != 3:
1522            raise ValueError('addgrid() must be called before addfield()')
1523        if self.scanModeFlags is not None:
1524            if self.scanModeFlags[3]:
1525                fieldsave = field.astype('f') # Casting makes a copy
1526                field[1::2,:] = fieldsave[1::2,::-1]
1527        fld = field.astype('f')
1528        if ma.isMA(field) and ma.count_masked(field) > 0:
1529            bitmapflag = 0
1530            bmap = 1-np.ravel(field.mask.astype(DEFAULT_NUMPY_INT))
1531        else:
1532            bitmapflag = 255
1533            bmap = None
1534        if coordlist is not None:
1535            crdlist = np.array(coordlist,'f')
1536        else:
1537            crdlist = None
1538
1539        # Set data representation template number and template values
1540        drtnum = -1
1541        drtmpl = np.zeros((DEFAULT_DRT_LEN),dtype=DEFAULT_NUMPY_INT)
1542        if packing == "simple":
1543            drtnum = 0
1544            drtmpl[1] = packing_opts["binScaleFactor"]
1545            drtmpl[2] = packing_opts["decScaleFactor"]
1546        elif packing == "complex" or packing == "complex-spdiff":
1547            if packing == "complex":
1548                drtnum = 2
1549            if packing == "complex-spdiff":
1550                drtnum = 3
1551                drtmpl[16] = packing_opts['spatialDifferenceOrder']
1552            drtmpl[1] = packing_opts["binScaleFactor"]
1553            drtmpl[2] = packing_opts["decScaleFactor"]
1554            if set(("priMissingValue","secMissingValue")).issubset(kwargs):
1555                drtmpl[6] = 2
1556                drtmpl[7] = utils.putieeeint(kwargs["priMissingValue"])
1557                drtmpl[8] = utils.putieeeint(kwargs["secMissingValue"])
1558            else:
1559                if "priMissingValue" in packing_opts.keys():
1560                    drtmpl[6] = 1
1561                    drtmpl[7] = utils.putieeeint(kwargs["priMissingValue"])
1562                else:
1563                    drtmpl[6] = 0
1564        elif packing == "jpeg":
1565            drtnum = 40
1566            drtmpl[1] = packing_opts["binScaleFactor"]
1567            drtmpl[2] = packing_opts["decScaleFactor"]
1568        elif packing == "png":
1569            drtnum = 41
1570            drtmpl[1] = packing_opts["binScaleFactor"]
1571            drtmpl[2] = packing_opts["decScaleFactor"]
1572        elif packing == "spectral-simple":
1573            drtnum = 50
1574            drtmpl[1] = packing_opts["binScaleFactor"]
1575            drtmpl[2] = packing_opts["decScaleFactor"]
1576        elif packing == "spectral-complex":
1577            drtnum = 51
1578            drtmpl[1] = packing_opts["binScaleFactor"]
1579            drtmpl[2] = packing_opts["decScaleFactor"]
1580
1581        pdtnum = pdtnum.value if isinstance(pdtnum,Grib2Metadata) else pdtnum
1582
1583        self._msg,self._pos = g2clib.grib2_addfield(self._msg,
1584                                                    pdtnum,
1585                                                    np.array(pdtmpl,dtype=DEFAULT_NUMPY_INT),
1586                                                    crdlist,
1587                                                    drtnum,
1588                                                    drtmpl,
1589                                                    np.ravel(fld),
1590                                                    bitmapflag,
1591                                                    bmap)
1592        self._sections.append(4)
1593        self._sections.append(5)
1594        if bmap is not None: self._sections.append(6)
1595        self._sections.append(7)

Add a Product Definition, Data Representation, Bitmap, and Data Sections to Grib2Message instance (i.e. Sections 4-7). Must be called after the grid definition section has been added (addfield).

Parameters

field: Numpy array of data values to pack. If field is a masked array, then a bitmap is created from the mask.

pdtnum: integer Product Definition Template Number - Code Table 4.0

pdtmpl: Sequence with the data values for the specified Product Definition Template (N=pdtnum). Each element of this integer array contains an entry (in the order specified) of Product Definition Template 4.N.

coordlist: Sequence containing floating point values intended to document the vertical discretization with model data on hybrid coordinate vertical levels. Default is None.

packing: String to specify the type of packing. Valid options are the following:

Packing Scheme Description
'simple' Simple packing
'complex' Complex packing
'complex-spdiff' Complex packing with Spatial Differencing
'jpeg' JPEG compression
'png' PNG compression
'spectral-simple' Spectral Data - Simple packing
'spectral-complex' Spectral Data - Complex packing

**packing_opts: Packing keyword arguments. The keywords are the same as Grib2Message attribute names for the Data Representation Template (Section 5) metadata. Valid keywords per packing scheme are the following:

Packing Scheme Keyword Arguments
'simple' binScaleFactor, decScaleFactor
'complex' binScaleFactor, decScaleFactor, priMissingValue, [secMissingValue]
'complex-spdiff' binScaleFactor, decScaleFactor, spatialDifferenceOrder, priMissingValue, [secMissingValue]
'jpeg' binScaleFactor, decScaleFactor
'png' binScaleFactor, decScaleFactor
'spectral-simple' binScaleFactor, decScaleFactor
'spectral-complex' binScaleFactor, decScaleFactor
def end(self)
1598    def end(self):
1599        """
1600        Add End Section (Section 8) to the GRIB2 message. A GRIB2 message 
1601        is not complete without an end section.  Once an end section is added, 
1602        the GRIB2 message can be written to file.
1603        """
1604        self._msg, self._pos = g2clib.grib2_end(self._msg)
1605        self._sections.append(8)

Add End Section (Section 8) to the GRIB2 message. A GRIB2 message is not complete without an end section. Once an end section is added, the GRIB2 message can be written to file.

def to_bytes(self, validate=True)
1607    def to_bytes(self, validate=True):
1608        """
1609        Return grib data in byte format. Useful for exporting data in non-file formats.
1610        For example, can be used to output grib data directly to S3 using the boto3 client
1611        without the need to write a temporary file to upload first.
1612
1613        Parameters
1614        ----------
1615        **`validate`**: bool (Default: True) If true, validates first/last four bytes for proper formatting, else
1616        returns None. If False, message is output as is.
1617
1618        Returns
1619        -------
1620        Returns GRIB2 formatted message as bytes.
1621        """
1622        if validate:
1623            if str(self._msg[0:4] + self._msg[-4:], 'utf-8') == 'GRIB7777':
1624                return self._msg
1625            else:
1626                return None
1627        else:
1628            return self._msg

Return grib data in byte format. Useful for exporting data in non-file formats. For example, can be used to output grib data directly to S3 using the boto3 client without the need to write a temporary file to upload first.

Parameters

validate: bool (Default: True) If true, validates first/last four bytes for proper formatting, else returns None. If False, message is output as is.

Returns

Returns GRIB2 formatted message as bytes.

class Grib2Metadata:
1631class Grib2Metadata():
1632    """
1633    Class to hold GRIB2 metadata both as numeric code value as stored in
1634    GRIB2 and its plain langauge definition.
1635
1636    **`value : int`**
1637
1638    GRIB2 metadata integer code value.
1639
1640    **`table : str, optional`**
1641
1642    GRIB2 table to lookup the `value`. Default is None.
1643    """
1644    def __init__(self, value, table=None):
1645        self.value = value
1646        self.table = table
1647        if self.table is None:
1648            self.definition = None
1649        else:
1650            self.definition = tables.get_value_from_table(self.value,self.table)
1651    def __call__(self):
1652        return self.value
1653    def __repr__(self):
1654        return '%s(%d, table = %s)' % (self.__class__.__name__,self.value,self.table)
1655    def __str__(self):
1656        return '%d - %s' % (self.value,self.definition)
1657    def __eq__(self,other):
1658        return self.value == other
1659    def __gt__(self,other):
1660        return self.value > other
1661    def __ge__(self,other):
1662        return self.value >= other
1663    def __lt__(self,other):
1664        return self.value < other
1665    def __le__(self,other):
1666        return self.value <= other
1667    def __contains__(self,other):
1668        return other in self.definition

Class to hold GRIB2 metadata both as numeric code value as stored in GRIB2 and its plain langauge definition.

value : int

GRIB2 metadata integer code value.

table : str, optional

GRIB2 table to lookup the value. Default is None.

Grib2Metadata(value, table=None)
1644    def __init__(self, value, table=None):
1645        self.value = value
1646        self.table = table
1647        if self.table is None:
1648            self.definition = None
1649        else:
1650            self.definition = tables.get_value_from_table(self.value,self.table)
def show_config()
13def show_config():
14    """
15    Print grib2io build configuration information.
16    """
17    from g2clib import __version__ as g2clib_version
18    have_jpeg = True if 'jasper' in __config__.libraries or 'openjp2' in __config__.libraries else False
19    have_png = True if 'png' in __config__.libraries else False
20    jpeglib = 'OpenJPEG' if 'openjp2' in __config__.libraries else ('Jasper' if 'jasper' in __config__.libraries else None)
21    pnglib = 'libpng' if 'png' in __config__.libraries else None
22    print("grib2io version %s Configuration:\n"%(__version__))
23    print("\tg2c library version:".expandtabs(4),g2clib_version)
24    print("\tJPEG compression support:".expandtabs(4),have_jpeg)
25    if have_jpeg: print("\t\tLibrary:".expandtabs(4),jpeglib)
26    print("\tPNG compression support:".expandtabs(4),have_png)
27    if have_png: print("\t\tLibrary:".expandtabs(4),pnglib)

Print grib2io build configuration information.