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            if self.gridDefinitionTemplate[10] == 4294967295:
 733                self.gridDefinitionTemplate[10] = -1
 734            divisor = float(self.gridDefinitionTemplate[10])
 735            if scalefact == 0: scalefact = 1.
 736            if divisor <= 0: divisor = 1.e6
 737            self.latitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[11]/divisor
 738            self.longitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[12]/divisor
 739            self.latitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[14]/divisor
 740            self.longitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[15]/divisor
 741            self.gridlengthXDirection = scalefact*self.gridDefinitionTemplate[16]/divisor
 742            self.gridlengthYDirection = scalefact*self.gridDefinitionTemplate[17]/divisor
 743            if self.latitudeFirstGridpoint > self.latitudeLastGridpoint:
 744                self.gridlengthYDirection = -self.gridlengthYDirection
 745            if self.longitudeFirstGridpoint > self.longitudeLastGridpoint:
 746                self.gridlengthXDirection = -self.gridlengthXDirection
 747            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[18],output=list)[0:4]
 748            if self.gridDefinitionTemplateNumber == 1:
 749                self.latitudeSouthernPole = scalefact*self.gridDefinitionTemplate[19]/divisor
 750                self.longitudeSouthernPole = scalefact*self.gridDefinitionTemplate[20]/divisor
 751                self.anglePoleRotation = self.gridDefinitionTemplate[21]
 752        elif self.gridDefinitionTemplateNumber == 10:
 753            # Mercator
 754            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 755            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 756            self.latitudeLastGridpoint = self.gridDefinitionTemplate[13]/1.e6
 757            self.longitudeLastGridpoint = self.gridDefinitionTemplate[14]/1.e6
 758            self.gridlengthXDirection = self.gridDefinitionTemplate[17]/1.e3
 759            self.gridlengthYDirection= self.gridDefinitionTemplate[18]/1.e3
 760            self.proj4_lat_ts = self.gridDefinitionTemplate[12]/1.e6
 761            self.proj4_lon_0 = 0.5*(self.longitudeFirstGridpoint+self.longitudeLastGridpoint)
 762            self.proj4_proj = 'merc'
 763            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[15],output=list)[0:4]
 764        elif self.gridDefinitionTemplateNumber == 20:
 765            # Stereographic
 766            projflag = utils.int2bin(self.gridDefinitionTemplate[16],output=list)[0]
 767            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 768            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 769            self.proj4_lat_ts = self.gridDefinitionTemplate[12]/1.e6
 770            if projflag == 0:
 771                self.proj4_lat_0 = 90
 772            elif projflag == 1:
 773                self.proj4_lat_0 = -90
 774            else:
 775                raise ValueError('Invalid projection center flag = %s'%projflag)
 776            self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6
 777            self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000.
 778            self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000.
 779            self.proj4_proj = 'stere'
 780            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[17],output=list)[0:4]
 781        elif self.gridDefinitionTemplateNumber == 30:
 782            # Lambert Conformal
 783            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 784            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 785            self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000.
 786            self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000.
 787            self.proj4_lat_1 = self.gridDefinitionTemplate[18]/1.e6
 788            self.proj4_lat_2 = self.gridDefinitionTemplate[19]/1.e6
 789            self.proj4_lat_0 = self.gridDefinitionTemplate[12]/1.e6
 790            self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6
 791            self.proj4_proj = 'lcc'
 792            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[17],output=list)[0:4]
 793        elif self.gridDefinitionTemplateNumber == 31:
 794            # Albers Equal Area
 795            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 796            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 797            self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000.
 798            self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000.
 799            self.proj4_lat_1 = self.gridDefinitionTemplate[18]/1.e6
 800            self.proj4_lat_2 = self.gridDefinitionTemplate[19]/1.e6
 801            self.proj4_lat_0 = self.gridDefinitionTemplate[12]/1.e6
 802            self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6
 803            self.proj4_proj = 'aea'
 804            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[17],output=list)[0:4]
 805        elif self.gridDefinitionTemplateNumber == 40 or self.gridDefinitionTemplateNumber == 41:
 806            # Gaussian Grid
 807            scalefact = float(self.gridDefinitionTemplate[9])
 808            if self.gridDefinitionTemplate[10] == 4294967295:
 809                self.gridDefinitionTemplate[10] = -1
 810            divisor = float(self.gridDefinitionTemplate[10])
 811            if scalefact == 0: scalefact = 1.
 812            if divisor <= 0: divisor = 1.e6
 813            self.pointsBetweenPoleAndEquator = self.gridDefinitionTemplate[17]
 814            self.latitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[11]/divisor
 815            self.longitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[12]/divisor
 816            self.latitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[14]/divisor
 817            self.longitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[15]/divisor
 818            if reggrid:
 819                self.gridlengthXDirection = scalefact*self.gridDefinitionTemplate[16]/divisor
 820                if self.longitudeFirstGridpoint > self.longitudeLastGridpoint:
 821                    self.gridlengthXDirection = -self.gridlengthXDirection
 822            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[18],output=list)[0:4]
 823            if self.gridDefinitionTemplateNumber == 41:
 824                self.latitudeSouthernPole = scalefact*self.gridDefinitionTemplate[19]/divisor
 825                self.longitudeSouthernPole = scalefact*self.gridDefinitionTemplate[20]/divisor
 826                self.anglePoleRotation = self.gridDefinitionTemplate[21]
 827        elif self.gridDefinitionTemplateNumber == 50:
 828            # Spectral Coefficients
 829            self.spectralFunctionParameters = (self.gridDefinitionTemplate[0],self.gridDefinitionTemplate[1],self.gridDefinitionTemplate[2])
 830            self.scanModeFlags = [None,None,None,None]
 831        elif self.gridDefinitionTemplateNumber == 90:
 832            # Near-sided Vertical Perspective Satellite Projection
 833            self.proj4_lat_0 = self.gridDefinitionTemplate[9]/1.e6
 834            self.proj4_lon_0 = self.gridDefinitionTemplate[10]/1.e6
 835            self.proj4_h = self.earthMajorAxis * (self.gridDefinitionTemplate[18]/1.e6)
 836            dx = self.gridDefinitionTemplate[12]
 837            dy = self.gridDefinitionTemplate[13]
 838            # if lat_0 is equator, it's a geostationary view.
 839            if self.proj4_lat_0 == 0.: # if lat_0 is equator, it's a
 840                self.proj4_proj = 'geos'
 841            # general case of 'near-side perspective projection' (untested)
 842            else:
 843                self.proj4_proj = 'nsper'
 844                msg = 'Only geostationary perspective is supported. Lat/Lon values returned by grid method may be incorrect.'
 845                warnings.warn(msg)
 846            # latitude of horizon on central meridian
 847            lonmax = 90.-(180./np.pi)*np.arcsin(self.earthMajorAxis/self.proj4_h)
 848            # longitude of horizon on equator
 849            latmax = 90.-(180./np.pi)*np.arcsin(self.earthMinorAxis/self.proj4_h)
 850            # truncate to nearest thousandth of a degree (to make sure
 851            # they aren't slightly over the horizon)
 852            latmax = int(1000*latmax)/1000.
 853            lonmax = int(1000*lonmax)/1000.
 854            # h is measured from surface of earth at equator.
 855            self.proj4_h = self.proj4_h - self.earthMajorAxis
 856            # width and height of visible projection
 857            P = pyproj.Proj(proj=self.proj4_proj,\
 858                            a=self.earthMajorAxis,b=self.earthMinorAxis,\
 859                            lat_0=0,lon_0=0,h=self.proj4_h)
 860            x1,y1 = P(0.,latmax)
 861            x2,y2 = P(lonmax,0.)
 862            width = 2*x2
 863            height = 2*y1
 864            self.gridlengthXDirection = width/dx
 865            self.gridlengthYDirection = height/dy
 866            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[16],output=list)[0:4]
 867        elif self.gridDefinitionTemplateNumber == 110:
 868            # Azimuthal Equidistant
 869            self.proj4_lat_0 = self.gridDefinitionTemplate[9]/1.e6
 870            self.proj4_lon_0 = self.gridDefinitionTemplate[10]/1.e6
 871            self.gridlengthXDirection = self.gridDefinitionTemplate[12]/1000.
 872            self.gridlengthYDirection = self.gridDefinitionTemplate[13]/1000.
 873            self.proj4_proj = 'aeqd'
 874            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[15],output=list)[0:4]
 875        elif self.gridDefinitionTemplateNumber == 204:
 876            # Curvilinear Orthogonal
 877            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[18],output=list)[0:4]
 878        else:
 879            errmsg = 'Unsupported Grid Definition Template Number - 3.%i' % self.gridDefinitionTemplateNumber.value
 880            raise ValueError(errmsg)
 881
 882        # -------------------------------
 883        # Section 4 -- Product Definition
 884        # -------------------------------
 885      
 886        # Template 4.0 - NOTE: That is these attributes apply to other templates.
 887        self.parameterCategory = self.productDefinitionTemplate[0]
 888        self.parameterNumber = self.productDefinitionTemplate[1]
 889        self.fullName,self.units,self.shortName = tables.get_varinfo_from_table(self.discipline.value,
 890                                                                                self.parameterCategory,
 891                                                                                self.parameterNumber)
 892        self.typeOfGeneratingProcess = Grib2Metadata(self.productDefinitionTemplate[2],table='4.3')
 893        self.backgroundGeneratingProcessIdentifier = self.productDefinitionTemplate[3]
 894        self.generatingProcess = Grib2Metadata(self.productDefinitionTemplate[4],table='generating_process')
 895        self.unitOfTimeRange = Grib2Metadata(self.productDefinitionTemplate[7],table='4.4')
 896        self.leadTime = self.productDefinitionTemplate[8]
 897        self.typeOfFirstFixedSurface = Grib2Metadata(self.productDefinitionTemplate[9],table='4.5')
 898        self.scaleFactorOfFirstFixedSurface = self.productDefinitionTemplate[10]
 899        self.unitOfFirstFixedSurface = self.typeOfFirstFixedSurface.definition[1]
 900        self.scaledValueOfFirstFixedSurface = self.productDefinitionTemplate[11]
 901        self.valueOfFirstFixedSurface = self.scaledValueOfFirstFixedSurface/(10.**self.scaleFactorOfFirstFixedSurface)
 902        temp = tables.get_value_from_table(self.productDefinitionTemplate[12],'4.5')
 903        if temp[0] == 'Missing' and temp[1] == 'unknown':
 904            self.typeOfSecondFixedSurface = None
 905            self.scaleFactorOfSecondFixedSurface = None
 906            self.unitOfSecondFixedSurface = None
 907            self.valueOfSecondFixedSurface = None
 908        else:
 909            self.typeOfSecondFixedSurface = Grib2Metadata(self.productDefinitionTemplate[12],table='4.5')
 910            self.scaleFactorOfSecondFixedSurface = self.productDefinitionTemplate[13]
 911            self.unitOfSecondFixedSurface = self.typeOfSecondFixedSurface.definition[1]
 912            self.scaledValueOfSecondFixedSurface = self.productDefinitionTemplate[14]
 913            self.valueOfSecondFixedSurface = self.scaledValueOfSecondFixedSurface/(10.**self.scaleFactorOfSecondFixedSurface)
 914        self.level = tables.get_wgrib2_level_string(*self.productDefinitionTemplate[9:15])
 915
 916        # Template 4.1 -
 917        if self.productDefinitionTemplateNumber == 1:
 918            self.typeOfEnsembleForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.6')
 919            self.perturbationNumber = self.productDefinitionTemplate[16]
 920            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[17]
 921
 922        # Template 4.2 -
 923        elif self.productDefinitionTemplateNumber == 2:
 924            self.typeOfDerivedForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.7')
 925            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[16]
 926
 927        # Template 4.5 -
 928        elif self.productDefinitionTemplateNumber == 5:
 929            self.forecastProbabilityNumber = self.productDefinitionTemplate[15]
 930            self.totalNumberOfForecastProbabilities = self.productDefinitionTemplate[16]
 931            self.typeOfProbability = Grib2Metadata(self.productDefinitionTemplate[17],table='4.9')
 932            self.scaleFactorOfThresholdLowerLimit = self.productDefinitionTemplate[18]
 933            self.scaledValueOfThresholdLowerLimit = self.productDefinitionTemplate[19]
 934            self.scaleFactorOfThresholdUpperLimit = self.productDefinitionTemplate[20]
 935            self.scaledValueOfThresholdUpperLimit = self.productDefinitionTemplate[21]
 936            self.thresholdLowerLimit = 0.0 if self.productDefinitionTemplate[19] == 255 else \
 937                                       self.productDefinitionTemplate[19]/(10.**self.productDefinitionTemplate[18])
 938            self.thresholdUpperLimit = 0.0 if self.productDefinitionTemplate[21] == 255 else \
 939                                       self.productDefinitionTemplate[21]/(10.**self.productDefinitionTemplate[20])
 940            self.threshold = utils.get_wgrib2_prob_string(*self.productDefinitionTemplate[17:22])
 941
 942        # Template 4.6 -
 943        elif self.productDefinitionTemplateNumber == 6:
 944            self.percentileValue = self.productDefinitionTemplate[15]
 945
 946        # Template 4.8 -
 947        elif self.productDefinitionTemplateNumber == 8:
 948            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[15]
 949            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[16]
 950            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[17]
 951            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[18]
 952            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[19]
 953            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[20]
 954            self.numberOfTimeRanges = self.productDefinitionTemplate[21]
 955            self.numberOfMissingValues = self.productDefinitionTemplate[22]
 956            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[23],table='4.10')
 957            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[24],table='4.11')
 958            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[25],table='4.4')
 959            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[26]
 960            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[27],table='4.4')
 961            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[28]
 962
 963        # Template 4.9 -
 964        elif self.productDefinitionTemplateNumber == 9:
 965            self.forecastProbabilityNumber = self.productDefinitionTemplate[15]
 966            self.totalNumberOfForecastProbabilities = self.productDefinitionTemplate[16]
 967            self.typeOfProbability = Grib2Metadata(self.productDefinitionTemplate[17],table='4.9')
 968            self.scaleFactorOfThresholdLowerLimit = self.productDefinitionTemplate[18]
 969            self.scaledValueOfThresholdLowerLimit = self.productDefinitionTemplate[19]
 970            self.scaleFactorOfThresholdUpperLimit = self.productDefinitionTemplate[20]
 971            self.scaledValueOfThresholdUpperLimit = self.productDefinitionTemplate[21]
 972            self.thresholdLowerLimit = 0.0 if self.productDefinitionTemplate[19] == 255 else \
 973                                       self.productDefinitionTemplate[19]/(10.**self.productDefinitionTemplate[18])
 974            self.thresholdUpperLimit = 0.0 if self.productDefinitionTemplate[21] == 255 else \
 975                                       self.productDefinitionTemplate[21]/(10.**self.productDefinitionTemplate[20])
 976            self.threshold = utils.get_wgrib2_prob_string(*self.productDefinitionTemplate[17:22])
 977            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[22]
 978            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[23]
 979            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[24]
 980            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[25]
 981            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[26]
 982            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[27]
 983            self.numberOfTimeRanges = self.productDefinitionTemplate[28]
 984            self.numberOfMissingValues = self.productDefinitionTemplate[29]
 985            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[30],table='4.10')
 986            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[31],table='4.11')
 987            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[32],table='4.4')
 988            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[33]
 989            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[34],table='4.4')
 990            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[35]
 991
 992        # Template 4.10 -
 993        elif self.productDefinitionTemplateNumber == 10:
 994            self.percentileValue = self.productDefinitionTemplate[15]
 995            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[16]
 996            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[17]
 997            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[18]
 998            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[19]
 999            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[20]
1000            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[21]
1001            self.numberOfTimeRanges = self.productDefinitionTemplate[22]
1002            self.numberOfMissingValues = self.productDefinitionTemplate[23]
1003            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[24],table='4.10')
1004            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[25],table='4.11')
1005            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[26],table='4.4')
1006            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[27]
1007            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[28],table='4.4')
1008            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[29]
1009
1010        # Template 4.11 -
1011        elif self.productDefinitionTemplateNumber == 11:
1012            self.typeOfEnsembleForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.6')
1013            self.perturbationNumber = self.productDefinitionTemplate[16]
1014            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[17]
1015            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[18]
1016            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[19]
1017            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[20]
1018            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[21]
1019            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[22]
1020            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[23]
1021            self.numberOfTimeRanges = self.productDefinitionTemplate[24]
1022            self.numberOfMissingValues = self.productDefinitionTemplate[25]
1023            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[26],table='4.10')
1024            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[27],table='4.11')
1025            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[28],table='4.4')
1026            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[29]
1027            self.unitOfTimeRangeOfSuccessiveFields = tables.get_value_from_table(self.productDefinitionTemplate[30],table='4.4')
1028            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[31]
1029
1030        # Template 4.12 -
1031        elif self.productDefinitionTemplateNumber == 12:
1032            self.typeOfDerivedForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.7')
1033            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[16]
1034            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[17]
1035            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[18]
1036            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[19]
1037            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[20]
1038            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[21]
1039            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[22]
1040            self.numberOfTimeRanges = self.productDefinitionTemplate[23]
1041            self.numberOfMissingValues = self.productDefinitionTemplate[24]
1042            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[25],table='4.10')
1043            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[26],table='4.11')
1044            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[27],table='4.4')
1045            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[28]
1046            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[29],table='4.4')
1047            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[30]
1048
1049        # Template 4.15 -
1050        elif self.productDefinitionTemplateNumber == 15:
1051            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[15],table='4.10')
1052            self.typeOfSpatialProcessing = Grib2Metadata(self.productDefinitionTemplate[16],table='4.15')
1053            self.numberOfDataPointsForSpatialProcessing = self.productDefinitionTemplate[17]
1054
1055        else:
1056            if self.productDefinitionTemplateNumber != 0:
1057                errmsg = 'Unsupported Product Definition Template Number - 4.%i' % self.productDefinitionTemplateNumber.value
1058                raise ValueError(errmsg)
1059
1060
1061        self.leadTime = utils.getleadtime(self.identificationSection,
1062                                          self.productDefinitionTemplateNumber.value,
1063                                          self.productDefinitionTemplate)
1064
1065        if self.productDefinitionTemplateNumber.value in [8,9,10,11,12]:
1066            self.dtEndOfTimePeriod = datetime.datetime(self.yearOfEndOfTimePeriod,self.monthOfEndOfTimePeriod,
1067                                     self.dayOfEndOfTimePeriod,hour=self.hourOfEndOfTimePeriod,
1068                                     minute=self.minuteOfEndOfTimePeriod,
1069                                     second=self.secondOfEndOfTimePeriod)
1070
1071        # --------------------------------
1072        # Section 5 -- Data Representation
1073        # --------------------------------
1074
1075        # Template 5.0 - Simple Packing
1076        if self.dataRepresentationTemplateNumber == 0:
1077            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1078            self.binScaleFactor = self.dataRepresentationTemplate[1]
1079            self.decScaleFactor = self.dataRepresentationTemplate[2]
1080            self.nBitsPacking = self.dataRepresentationTemplate[3]
1081            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[3],table='5.1')
1082
1083        # Template 5.2 - Complex Packing
1084        elif self.dataRepresentationTemplateNumber == 2:
1085            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1086            self.binScaleFactor = self.dataRepresentationTemplate[1]
1087            self.decScaleFactor = self.dataRepresentationTemplate[2]
1088            self.nBitsPacking = self.dataRepresentationTemplate[3]
1089            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1090            self.groupSplitMethod = Grib2Metadata(self.dataRepresentationTemplate[5],table='5.4')
1091            self.typeOfMissingValue = Grib2Metadata(self.dataRepresentationTemplate[6],table='5.5')
1092            self.priMissingValue = utils.getieeeint(self.dataRepresentationTemplate[7]) if self.dataRepresentationTemplate[6] in [1,2] else None
1093            self.secMissingValue = utils.getieeeint(self.dataRepresentationTemplate[8]) if self.dataRepresentationTemplate[6] == 2 else None
1094            self.nGroups = self.dataRepresentationTemplate[9]
1095            self.refGroupWidth = self.dataRepresentationTemplate[10]
1096            self.nBitsGroupWidth = self.dataRepresentationTemplate[11]
1097            self.refGroupLength = self.dataRepresentationTemplate[12]
1098            self.groupLengthIncrement = self.dataRepresentationTemplate[13]
1099            self.lengthOfLastGroup = self.dataRepresentationTemplate[14]
1100            self.nBitsScaledGroupLength = self.dataRepresentationTemplate[15]
1101
1102        # Template 5.3 - Complex Packing and Spatial Differencing
1103        elif self.dataRepresentationTemplateNumber == 3:
1104            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1105            self.binScaleFactor = self.dataRepresentationTemplate[1]
1106            self.decScaleFactor = self.dataRepresentationTemplate[2]
1107            self.nBitsPacking = self.dataRepresentationTemplate[3]
1108            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1109            self.groupSplitMethod = Grib2Metadata(self.dataRepresentationTemplate[5],table='5.4')
1110            self.typeOfMissingValue = Grib2Metadata(self.dataRepresentationTemplate[6],table='5.5')
1111            self.priMissingValue = utils.getieeeint(self.dataRepresentationTemplate[7]) if self.dataRepresentationTemplate[6] in [1,2] else None
1112            self.secMissingValue = utils.getieeeint(self.dataRepresentationTemplate[8]) if self.dataRepresentationTemplate[6] == 2 else None
1113            self.nGroups = self.dataRepresentationTemplate[9]
1114            self.refGroupWidth = self.dataRepresentationTemplate[10]
1115            self.nBitsGroupWidth = self.dataRepresentationTemplate[11]
1116            self.refGroupLength = self.dataRepresentationTemplate[12]
1117            self.groupLengthIncrement = self.dataRepresentationTemplate[13]
1118            self.lengthOfLastGroup = self.dataRepresentationTemplate[14]
1119            self.nBitsScaledGroupLength = self.dataRepresentationTemplate[15]
1120            self.spatialDifferenceOrder = Grib2Metadata(self.dataRepresentationTemplate[16],table='5.6')
1121            self.nBytesSpatialDifference = self.dataRepresentationTemplate[17]
1122
1123        # Template 5.4 - IEEE Floating Point Data
1124        elif self.dataRepresentationTemplateNumber == 4:
1125            self.precision = Grib2Metadata(self.dataRepresentationTemplate[0],table='5.7')
1126
1127        # Template 5.40 - JPEG2000 Compression
1128        elif self.dataRepresentationTemplateNumber == 40:
1129            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1130            self.binScaleFactor = self.dataRepresentationTemplate[1]
1131            self.decScaleFactor = self.dataRepresentationTemplate[2]
1132            self.nBitsPacking = self.dataRepresentationTemplate[3]
1133            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1134            self.typeOfCompression = Grib2Metadata(self.dataRepresentationTemplate[5],table='5.40')
1135            self.targetCompressionRatio = self.dataRepresentationTemplate[6]
1136
1137        # Template 5.41 - PNG Compression
1138        elif self.dataRepresentationTemplateNumber == 41:
1139            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1140            self.binScaleFactor = self.dataRepresentationTemplate[1]
1141            self.decScaleFactor = self.dataRepresentationTemplate[2]
1142            self.nBitsPacking = self.dataRepresentationTemplate[3]
1143            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1144
1145        else:
1146            errmsg = 'Unsupported Data Representation Definition Template Number - 5.%i' % self.dataRepresentationTemplateNumber.value
1147            raise ValueError(errmsg)
1148
1149
1150    def data(self, fill_value=DEFAULT_FILL_VALUE, masked_array=True, expand=True, order=None,
1151             map_keys=False):
1152        """
1153        Returns an unpacked data grid.
1154
1155        Parameters
1156        ----------
1157
1158        **`fill_value`**: Missing or masked data is filled with this value or default value given by
1159        `DEFAULT_FILL_VALUE`
1160
1161        **`masked_array`**: If `True` [DEFAULT], return masked array if there is bitmap for missing 
1162        or masked data.
1163
1164        **`expand`**: If `True` [DEFAULT], Reduced Gaussian grids are expanded to regular Gaussian grids.
1165
1166        **`order`**: If 0 [DEFAULT], nearest neighbor interpolation is used if grid has missing 
1167        or bitmapped values. If 1, linear interpolation is used for expanding reduced Gaussian grids.
1168
1169        **`map_keys`**: If `True`, data values will be mapped to the string-based keys that are stored
1170        in the Local Use Section (section 2) of the GRIB2 Message or in a code table as specified in the
1171        units (i.e. "See Table 4.xxx").
1172
1173        Returns
1174        -------
1175
1176        **`numpy.ndarray`**: A numpy.ndarray with shape (ny,nx). By default the array dtype=np.float32, 
1177        but could be np.int32 if Grib2Message.typeOfValues is integer.  The array dtype will be 
1178        string-based if map_keys=True.
1179        """
1180        if not hasattr(self,'scanModeFlags'):
1181            raise ValueError('Unsupported grid definition template number %s'%self.gridDefinitionTemplateNumber)
1182        else:
1183            if self.scanModeFlags[2]:
1184                storageorder='F'
1185            else:
1186                storageorder='C'
1187        if order is None:
1188            if (self.dataRepresentationTemplateNumber in [2,3] and
1189                self.dataRepresentationTemplate[6] != 0) or self.bitMapFlag == 0:
1190                order = 0
1191            else:
1192                order = 1
1193        drtnum = self.dataRepresentationTemplateNumber.value
1194        drtmpl = np.asarray(self.dataRepresentationTemplate,dtype=DEFAULT_NUMPY_INT)
1195        gdtnum = self.gridDefinitionTemplateNumber.value
1196        gdtmpl = np.asarray(self.gridDefinitionTemplate,dtype=DEFAULT_NUMPY_INT)
1197        ndpts = self.numberOfDataPoints
1198        gds = self.gridDefinitionSection
1199        ngrdpts = gds[1]
1200        ipos = self._datapos
1201        fld1 = g2clib.unpack7(self._msg,gdtnum,gdtmpl,drtnum,drtmpl,ndpts,ipos,np.empty,storageorder=storageorder)
1202        # Apply bitmap.
1203        if self.bitMapFlag == 0:
1204            fld = fill_value*np.ones(ngrdpts,'f')
1205            np.put(fld,np.nonzero(self.bitMap),fld1)
1206            if masked_array:
1207                fld = ma.masked_values(fld,fill_value)
1208        # Missing values instead of bitmap
1209        elif masked_array and hasattr(self,'priMissingValue'):
1210            if hasattr(self,'secMissingValue'):
1211                mask = np.logical_or(fld1==self.priMissingValue,fld1==self.secMissingValue)
1212            else:
1213                mask = fld1 == self.priMissingValue
1214            fld = ma.array(fld1,mask=mask)
1215        else:
1216            fld = fld1
1217        if self.nx is not None and self.ny is not None: # Rectangular grid.
1218            if ma.isMA(fld):
1219                fld = ma.reshape(fld,(self.ny,self.nx))
1220            else:
1221                fld = np.reshape(fld,(self.ny,self.nx))
1222        else:
1223            if gds[2] and gdtnum == 40: # Reduced global Gaussian grid.
1224                if expand:
1225                    from . import redtoreg
1226                    self.nx = 2*self.ny
1227                    lonsperlat = self.defList
1228                    if ma.isMA(fld):
1229                        fld = ma.filled(fld)
1230                        fld = redtoreg._redtoreg(self.nx,lonsperlat.astype(np.long),
1231                                                 fld.astype(np.double),fill_value)
1232                        fld = ma.masked_values(fld,fill_value)
1233                    else:
1234                        fld = redtoreg._redtoreg(self.nx,lonsperlat.astype(np.long),
1235                                                 fld.astype(np.double),fill_value)
1236        # Check scan modes for rect grids.
1237        if self.nx is not None and self.ny is not None:
1238            if self.scanModeFlags[3]:
1239                fldsave = fld.astype('f') # casting makes a copy
1240                fld[1::2,:] = fldsave[1::2,::-1]
1241
1242        # Set data to integer according to GRIB metadata
1243        if self.typeOfValues == "Integer": fld = fld.astype(np.int32)
1244
1245        # Map the data values to their respective definitions.
1246        if map_keys:
1247            fld = fld.astype(np.int32).astype(str)
1248            if self.identificationSection[0] == 7 and \
1249               self.identificationSection[1] == 14 and \
1250               self.shortName == 'PWTHER':
1251                # MDL Predominant Weather Grid
1252                #keys = utils.decode_mdl_wx_strings(self._lus)
1253                keys = utils.decode_ndfd_wx_strings(self._lus)
1254                for n,k in enumerate(keys):
1255                    fld = np.where(fld==str(n+1),k,fld)
1256            elif self.identificationSection[0] == 8 and \
1257                 self.identificationSection[1] == 65535 and \
1258                 self.shortName == 'CRAIN':
1259                # NDFD Predominant Weather Grid
1260                keys = utils.decode_ndfd_wx_strings(self._lus)
1261                for n,k in enumerate(keys):
1262                    fld = np.where(fld==str(n+1),k,fld)
1263            else:
1264                # For data whose units are defined in a code table
1265                tbl = re.findall(r'\d\.\d+',self.units,re.IGNORECASE)[0]
1266                for k,v in tables.get_table(tbl).items():
1267                    fld = np.where(fld==k,v,fld)
1268        return fld
1269
1270
1271    def latlons(self):
1272        """Alias for `grib2io.Grib2Message.grid` method"""
1273        return self.grid()
1274
1275
1276    def grid(self):
1277        """
1278        Return lats,lons (in degrees) of grid. Currently can handle reg. lat/lon, 
1279        global Gaussian, mercator, stereographic, lambert conformal, albers equal-area, 
1280        space-view and azimuthal equidistant grids.
1281
1282        Returns
1283        -------
1284
1285        **`lats, lons : numpy.ndarray`**
1286
1287        Returns two numpy.ndarrays with dtype=numpy.float32 of grid latitudes and
1288        longitudes in units of degrees.
1289        """
1290        gdtnum = self.gridDefinitionTemplateNumber
1291        gdtmpl = self.gridDefinitionTemplate
1292        reggrid = self.gridDefinitionSection[2] == 0 # This means regular 2-d grid
1293        self.projparams = {}
1294        if self.earthMajorAxis is not None: self.projparams['a']=self.earthMajorAxis
1295        if self.earthMajorAxis is not None: self.projparams['b']=self.earthMinorAxis
1296        if gdtnum == 0:
1297            # Regular lat/lon grid
1298            lon1, lat1 = self.longitudeFirstGridpoint, self.latitudeFirstGridpoint
1299            lon2, lat2 = self.longitudeLastGridpoint, self.latitudeLastGridpoint
1300            dlon = self.gridlengthXDirection
1301            dlat = self.gridlengthYDirection
1302            lats = np.arange(lat1,lat2+dlat,dlat)
1303            lons = np.arange(lon1,lon2+dlon,dlon)
1304            # flip if scan mode says to.
1305            #if self.scanModeFlags[0]:
1306            #    lons = lons[::-1]
1307            #if not self.scanModeFlags[1]:
1308            #    lats = lats[::-1]
1309            self.projparams['proj'] = 'cyl'
1310            lons,lats = np.meshgrid(lons,lats) # make 2-d arrays.
1311        elif gdtnum == 40: # Gaussian grid (only works for global!)
1312            from utils.gauss_grids import gaussian_latitudes
1313            lon1, lat1 = self.longitudeFirstGridpoint, self.latitudeFirstGridpoint
1314            lon2, lat2 = self.longitudeLastGridpoint, self.latitudeLastGridpoint
1315            nlats = self.ny
1316            if not reggrid: # Reduced Gaussian grid.
1317                nlons = 2*nlats
1318                dlon = 360./nlons
1319            else:
1320                nlons = self.nx
1321                dlon = self.gridlengthXDirection
1322            lons = np.arange(lon1,lon2+dlon,dlon)
1323            # Compute Gaussian lats (north to south)
1324            lats = gaussian_latitudes(nlats)
1325            if lat1 < lat2:  # reverse them if necessary
1326                lats = lats[::-1]
1327            # flip if scan mode says to.
1328            #if self.scanModeFlags[0]:
1329            #    lons = lons[::-1]
1330            #if not self.scanModeFlags[1]:
1331            #    lats = lats[::-1]
1332            self.projparams['proj'] = 'cyl'
1333            lons,lats = np.meshgrid(lons,lats) # make 2-d arrays
1334        elif gdtnum in [10,20,30,31,110]:
1335            # Mercator, Lambert Conformal, Stereographic, Albers Equal Area, Azimuthal Equidistant
1336            dx,dy = self.gridlengthXDirection, self.gridlengthYDirection
1337            lon1,lat1 = self.longitudeFirstGridpoint, self.latitudeFirstGridpoint
1338            if gdtnum == 10: # Mercator.
1339                self.projparams['lat_ts']=self.proj4_lat_ts
1340                self.projparams['proj']=self.proj4_proj
1341                self.projparams['lon_0']=self.proj4_lon_0
1342                pj = pyproj.Proj(self.projparams)
1343                llcrnrx, llcrnry = pj(lon1,lat1)
1344                x = llcrnrx+dx*np.arange(self.nx)
1345                y = llcrnry+dy*np.arange(self.ny)
1346                x,y = np.meshgrid(x, y)
1347                lons,lats = pj(x, y, inverse=True)
1348            elif gdtnum == 20:  # Stereographic
1349                self.projparams['lat_ts']=self.proj4_lat_ts
1350                self.projparams['proj']=self.proj4_proj
1351                self.projparams['lat_0']=self.proj4_lat_0
1352                self.projparams['lon_0']=self.proj4_lon_0
1353                pj = pyproj.Proj(self.projparams)
1354                llcrnrx, llcrnry = pj(lon1,lat1)
1355                x = llcrnrx+dx*np.arange(self.nx)
1356                y = llcrnry+dy*np.arange(self.ny)
1357                x,y = np.meshgrid(x, y)
1358                lons,lats = pj(x, y, inverse=True)
1359            elif gdtnum in [30,31]: # Lambert, Albers
1360                self.projparams['lat_1']=self.proj4_lat_1
1361                self.projparams['lat_2']=self.proj4_lat_2
1362                self.projparams['proj']=self.proj4_proj
1363                self.projparams['lon_0']=self.proj4_lon_0
1364                pj = pyproj.Proj(self.projparams)
1365                llcrnrx, llcrnry = pj(lon1,lat1)
1366                x = llcrnrx+dx*np.arange(self.nx)
1367                y = llcrnry+dy*np.arange(self.ny)
1368                x,y = np.meshgrid(x, y)
1369                lons,lats = pj(x, y, inverse=True)
1370            elif gdtnum == 110: # Azimuthal Equidistant
1371                self.projparams['proj']=self.proj4_proj
1372                self.projparams['lat_0']=self.proj4_lat_0
1373                self.projparams['lon_0']=self.proj4_lon_0
1374                pj = pyproj.Proj(self.projparams)
1375                llcrnrx, llcrnry = pj(lon1,lat1)
1376                x = llcrnrx+dx*np.arange(self.nx)
1377                y = llcrnry+dy*np.arange(self.ny)
1378                x,y = np.meshgrid(x, y)
1379                lons,lats = pj(x, y, inverse=True)
1380        elif gdtnum == 90:
1381            # Satellite Projection
1382            dx = self.gridlengthXDirection
1383            dy = self.gridlengthYDirection
1384            self.projparams['proj']=self.proj4_proj
1385            self.projparams['lon_0']=self.proj4_lon_0
1386            self.projparams['lat_0']=self.proj4_lat_0
1387            self.projparams['h']=self.proj4_h
1388            pj = pyproj.Proj(self.projparams)
1389            x = dx*np.indices((self.ny,self.nx),'f')[1,:,:]
1390            x -= 0.5*x.max()
1391            y = dy*np.indices((self.ny,self.nx),'f')[0,:,:]
1392            y -= 0.5*y.max()
1393            lons,lats = pj(x,y,inverse=True)
1394            # Set lons,lats to 1.e30 where undefined
1395            abslons = np.fabs(lons)
1396            abslats = np.fabs(lats)
1397            lons = np.where(abslons < 1.e20, lons, 1.e30)
1398            lats = np.where(abslats < 1.e20, lats, 1.e30)
1399        else:
1400            raise ValueError('Unsupported grid')
1401
1402        return lats.astype('f'), lons.astype('f')
1403
1404
1405    def addlocal(self, ludata):
1406        """
1407        Add a Local Use Section [(Section 2)](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_sect2.shtml)
1408        to the GRIB2 message.
1409
1410        Parameters
1411        ----------
1412
1413        **`ludata : bytes`**: Local Use data.
1414        """
1415        assert isinstance(ludata,bytes)
1416        self._msg,self._pos = g2clib.grib2_addlocal(self._msg,ludata)
1417        self.hasLocalUseSection = True
1418        self._sections.append(2)
1419
1420
1421    def addgrid(self, gdsinfo, gdtmpl, deflist=None):
1422        """
1423        Add a Grid Definition Section [(Section 3)](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_doc/grib2_sect3.shtml) 
1424        to the GRIB2 message.
1425
1426        Parameters
1427        ----------
1428
1429        **`gdsinfo`**: Sequence containing information needed for the grid definition section.
1430
1431        | Index | Description |
1432        | :---: | :---        |
1433        | 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)|
1434        | gdsinfo[1] | Number of data points|
1435        | gdsinfo[2] | Number of octets for optional list of numbers defining number of points|
1436        | 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)|
1437        | 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)|
1438
1439        **`gdtmpl`**: Sequence of values for the specified Grid Definition Template. Each 
1440        element of this integer array contains an entry (in the order specified) of Grid
1441        Definition Template 3.NN
1442
1443        **`deflist`**: Sequence containing the number of grid points contained in each 
1444        row (or column) of a non-regular grid.  Used if gdsinfo[2] != 0.
1445        """
1446        if 3 in self._sections:
1447            raise ValueError('GRIB2 Message already contains Grid Definition Section.')
1448        if deflist is not None:
1449            _deflist = np.array(deflist,dtype=DEFAULT_NUMPY_INT)
1450        else:
1451            _deflist = None
1452        gdtnum = gdsinfo[4]
1453        if gdtnum in [0,1,2,3,40,41,42,43,44,203,205,32768,32769]:
1454            self.scanModeFlags = utils.int2bin(gdtmpl[18],output=list)[0:4]
1455        elif gdtnum == 10: # mercator
1456            self.scanModeFlags = utils.int2bin(gdtmpl[15],output=list)[0:4]
1457        elif gdtnum == 20: # stereographic
1458            self.scanModeFlags = utils.int2bin(gdtmpl[17],output=list)[0:4]
1459        elif gdtnum == 30: # lambert conformal
1460            self.scanModeFlags = utils.int2bin(gdtmpl[17],output=list)[0:4]
1461        elif gdtnum == 31: # albers equal area.
1462            self.scanModeFlags = utils.int2bin(gdtmpl[17],output=list)[0:4]
1463        elif gdtnum == 90: # near-sided vertical perspective satellite projection
1464            self.scanModeFlags = utils.int2bin(gdtmpl[16],output=list)[0:4]
1465        elif gdtnum == 110: # azimuthal equidistant.
1466            self.scanModeFlags = utils.int2bin(gdtmpl[15],output=list)[0:4]
1467        elif gdtnum == 120:
1468            self.scanModeFlags = utils.int2bin(gdtmpl[6],output=list)[0:4]
1469        elif gdtnum == 204: # curvilinear orthogonal
1470            self.scanModeFlags = utils.int2bin(gdtmpl[18],output=list)[0:4]
1471        elif gdtnum in [1000,1100]:
1472            self.scanModeFlags = utils.int2bin(gdtmpl[12],output=list)[0:4]
1473        self._msg,self._pos = g2clib.grib2_addgrid(self._msg,
1474                                                   np.array(gdsinfo,dtype=DEFAULT_NUMPY_INT),
1475                                                   np.array(gdtmpl,dtype=DEFAULT_NUMPY_INT),
1476                                                   _deflist)
1477        self._sections.append(3)
1478
1479
1480    def addfield(self, field, pdtnum, pdtmpl, coordlist=None, packing="complex-spdiff", **packing_opts): 
1481        """
1482        Add a Product Definition, Data Representation, Bitmap, and Data Sections 
1483        to `Grib2Message` instance (i.e. Sections 4-7).  Must be called after the grid 
1484        definition section has been added (`addfield`).
1485
1486        Parameters
1487        ----------
1488
1489        **`field`**: Numpy array of data values to pack.  If field is a masked array, then 
1490        a bitmap is created from the mask.
1491
1492        **`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)
1493
1494        **`pdtmpl`**: Sequence with the data values for the specified Product Definition 
1495        Template (N=pdtnum).  Each element of this integer array contains an entry (in 
1496        the order specified) of Product Definition Template 4.N.
1497
1498        **`coordlist`**: Sequence containing floating point values intended to document the 
1499        vertical discretization with model data on hybrid coordinate vertical levels. Default is `None`.
1500
1501        **`packing`**: String to specify the type of packing. Valid options are the following:
1502
1503        | Packing Scheme | Description |
1504        | :---:          | :---:       |
1505        | 'simple'         | [Simple packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-0.shtml) | 
1506        | 'complex'        | [Complex packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-2.shtml) | 
1507        | 'complex-spdiff' | [Complex packing with Spatial Differencing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-3.shtml) | 
1508        | 'jpeg'           | [JPEG compression](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-40.shtml) | 
1509        | 'png'            | [PNG compression](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-41.shtml) | 
1510        | 'spectral-simple'| [Spectral Data - Simple packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-50.shtml) | 
1511        | 'spectral-complex'| [Spectral Data - Complex packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-51.shtml) | 
1512
1513        **`**packing_opts`**: Packing keyword arguments. The keywords are the same as Grib2Message attribute names for
1514        the Data Representation Template (Section 5) metadata. Valid keywords per packing scheme are the following:
1515
1516        | Packing Scheme | Keyword Arguments |
1517        | :---:          | :---:                      |
1518        | 'simple'     | `binScaleFactor`, `decScaleFactor` |
1519        | 'complex'     | `binScaleFactor`, `decScaleFactor`, `priMissingValue`, [`secMissingValue`] |
1520        | 'complex-spdiff'     | `binScaleFactor`, `decScaleFactor`, `spatialDifferenceOrder`, `priMissingValue`, [`secMissingValue`] |
1521        | 'jpeg'     | `binScaleFactor`, `decScaleFactor` |
1522        | 'png'     | `binScaleFactor`, `decScaleFactor` |
1523        | 'spectral-simple'     | `binScaleFactor`, `decScaleFactor` |
1524        | 'spectral-complex'     | `binScaleFactor`, `decScaleFactor` |
1525        """
1526        if self._sections[-1] != 3:
1527            raise ValueError('addgrid() must be called before addfield()')
1528        if self.scanModeFlags is not None:
1529            if self.scanModeFlags[3]:
1530                fieldsave = field.astype('f') # Casting makes a copy
1531                field[1::2,:] = fieldsave[1::2,::-1]
1532        fld = field.astype('f')
1533        if ma.isMA(field) and ma.count_masked(field) > 0:
1534            bitmapflag = 0
1535            bmap = 1-np.ravel(field.mask.astype(DEFAULT_NUMPY_INT))
1536        else:
1537            bitmapflag = 255
1538            bmap = None
1539        if coordlist is not None:
1540            crdlist = np.array(coordlist,'f')
1541        else:
1542            crdlist = None
1543
1544        # Set data representation template number and template values
1545        drtnum = -1
1546        drtmpl = np.zeros((DEFAULT_DRT_LEN),dtype=DEFAULT_NUMPY_INT)
1547        if packing == "simple":
1548            drtnum = 0
1549            drtmpl[1] = packing_opts["binScaleFactor"]
1550            drtmpl[2] = packing_opts["decScaleFactor"]
1551        elif packing == "complex" or packing == "complex-spdiff":
1552            if packing == "complex":
1553                drtnum = 2
1554            if packing == "complex-spdiff":
1555                drtnum = 3
1556                drtmpl[16] = packing_opts['spatialDifferenceOrder']
1557            drtmpl[1] = packing_opts["binScaleFactor"]
1558            drtmpl[2] = packing_opts["decScaleFactor"]
1559            if set(("priMissingValue","secMissingValue")).issubset(packing_opts):
1560                drtmpl[6] = 2
1561                drtmpl[7] = utils.putieeeint(packing_opts["priMissingValue"])
1562                drtmpl[8] = utils.putieeeint(packing_opts["secMissingValue"])
1563            else:
1564                if "priMissingValue" in packing_opts.keys():
1565                    drtmpl[6] = 1
1566                    drtmpl[7] = utils.putieeeint(packing_opts["priMissingValue"])
1567                else:
1568                    drtmpl[6] = 0
1569        elif packing == "jpeg":
1570            drtnum = 40
1571            drtmpl[1] = packing_opts["binScaleFactor"]
1572            drtmpl[2] = packing_opts["decScaleFactor"]
1573        elif packing == "png":
1574            drtnum = 41
1575            drtmpl[1] = packing_opts["binScaleFactor"]
1576            drtmpl[2] = packing_opts["decScaleFactor"]
1577        elif packing == "spectral-simple":
1578            drtnum = 50
1579            drtmpl[1] = packing_opts["binScaleFactor"]
1580            drtmpl[2] = packing_opts["decScaleFactor"]
1581        elif packing == "spectral-complex":
1582            drtnum = 51
1583            drtmpl[1] = packing_opts["binScaleFactor"]
1584            drtmpl[2] = packing_opts["decScaleFactor"]
1585
1586        pdtnum = pdtnum.value if isinstance(pdtnum,Grib2Metadata) else pdtnum
1587
1588        self._msg,self._pos = g2clib.grib2_addfield(self._msg,
1589                                                    pdtnum,
1590                                                    np.array(pdtmpl,dtype=DEFAULT_NUMPY_INT),
1591                                                    crdlist,
1592                                                    drtnum,
1593                                                    drtmpl,
1594                                                    np.ravel(fld),
1595                                                    bitmapflag,
1596                                                    bmap)
1597        self._sections.append(4)
1598        self._sections.append(5)
1599        if bmap is not None: self._sections.append(6)
1600        self._sections.append(7)
1601
1602
1603    def end(self):
1604        """
1605        Add End Section (Section 8) to the GRIB2 message. A GRIB2 message 
1606        is not complete without an end section.  Once an end section is added, 
1607        the GRIB2 message can be written to file.
1608        """
1609        self._msg, self._pos = g2clib.grib2_end(self._msg)
1610        self._sections.append(8)
1611
1612    def to_bytes(self, validate=True):
1613        """
1614        Return grib data in byte format. Useful for exporting data in non-file formats.
1615        For example, can be used to output grib data directly to S3 using the boto3 client
1616        without the need to write a temporary file to upload first.
1617
1618        Parameters
1619        ----------
1620        **`validate`**: bool (Default: True) If true, validates first/last four bytes for proper formatting, else
1621        returns None. If False, message is output as is.
1622
1623        Returns
1624        -------
1625        Returns GRIB2 formatted message as bytes.
1626        """
1627        if validate:
1628            if str(self._msg[0:4] + self._msg[-4:], 'utf-8') == 'GRIB7777':
1629                return self._msg
1630            else:
1631                return None
1632        else:
1633            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            if self.gridDefinitionTemplate[10] == 4294967295:
 733                self.gridDefinitionTemplate[10] = -1
 734            divisor = float(self.gridDefinitionTemplate[10])
 735            if scalefact == 0: scalefact = 1.
 736            if divisor <= 0: divisor = 1.e6
 737            self.latitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[11]/divisor
 738            self.longitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[12]/divisor
 739            self.latitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[14]/divisor
 740            self.longitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[15]/divisor
 741            self.gridlengthXDirection = scalefact*self.gridDefinitionTemplate[16]/divisor
 742            self.gridlengthYDirection = scalefact*self.gridDefinitionTemplate[17]/divisor
 743            if self.latitudeFirstGridpoint > self.latitudeLastGridpoint:
 744                self.gridlengthYDirection = -self.gridlengthYDirection
 745            if self.longitudeFirstGridpoint > self.longitudeLastGridpoint:
 746                self.gridlengthXDirection = -self.gridlengthXDirection
 747            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[18],output=list)[0:4]
 748            if self.gridDefinitionTemplateNumber == 1:
 749                self.latitudeSouthernPole = scalefact*self.gridDefinitionTemplate[19]/divisor
 750                self.longitudeSouthernPole = scalefact*self.gridDefinitionTemplate[20]/divisor
 751                self.anglePoleRotation = self.gridDefinitionTemplate[21]
 752        elif self.gridDefinitionTemplateNumber == 10:
 753            # Mercator
 754            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 755            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 756            self.latitudeLastGridpoint = self.gridDefinitionTemplate[13]/1.e6
 757            self.longitudeLastGridpoint = self.gridDefinitionTemplate[14]/1.e6
 758            self.gridlengthXDirection = self.gridDefinitionTemplate[17]/1.e3
 759            self.gridlengthYDirection= self.gridDefinitionTemplate[18]/1.e3
 760            self.proj4_lat_ts = self.gridDefinitionTemplate[12]/1.e6
 761            self.proj4_lon_0 = 0.5*(self.longitudeFirstGridpoint+self.longitudeLastGridpoint)
 762            self.proj4_proj = 'merc'
 763            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[15],output=list)[0:4]
 764        elif self.gridDefinitionTemplateNumber == 20:
 765            # Stereographic
 766            projflag = utils.int2bin(self.gridDefinitionTemplate[16],output=list)[0]
 767            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 768            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 769            self.proj4_lat_ts = self.gridDefinitionTemplate[12]/1.e6
 770            if projflag == 0:
 771                self.proj4_lat_0 = 90
 772            elif projflag == 1:
 773                self.proj4_lat_0 = -90
 774            else:
 775                raise ValueError('Invalid projection center flag = %s'%projflag)
 776            self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6
 777            self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000.
 778            self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000.
 779            self.proj4_proj = 'stere'
 780            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[17],output=list)[0:4]
 781        elif self.gridDefinitionTemplateNumber == 30:
 782            # Lambert Conformal
 783            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 784            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 785            self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000.
 786            self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000.
 787            self.proj4_lat_1 = self.gridDefinitionTemplate[18]/1.e6
 788            self.proj4_lat_2 = self.gridDefinitionTemplate[19]/1.e6
 789            self.proj4_lat_0 = self.gridDefinitionTemplate[12]/1.e6
 790            self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6
 791            self.proj4_proj = 'lcc'
 792            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[17],output=list)[0:4]
 793        elif self.gridDefinitionTemplateNumber == 31:
 794            # Albers Equal Area
 795            self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6
 796            self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6
 797            self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000.
 798            self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000.
 799            self.proj4_lat_1 = self.gridDefinitionTemplate[18]/1.e6
 800            self.proj4_lat_2 = self.gridDefinitionTemplate[19]/1.e6
 801            self.proj4_lat_0 = self.gridDefinitionTemplate[12]/1.e6
 802            self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6
 803            self.proj4_proj = 'aea'
 804            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[17],output=list)[0:4]
 805        elif self.gridDefinitionTemplateNumber == 40 or self.gridDefinitionTemplateNumber == 41:
 806            # Gaussian Grid
 807            scalefact = float(self.gridDefinitionTemplate[9])
 808            if self.gridDefinitionTemplate[10] == 4294967295:
 809                self.gridDefinitionTemplate[10] = -1
 810            divisor = float(self.gridDefinitionTemplate[10])
 811            if scalefact == 0: scalefact = 1.
 812            if divisor <= 0: divisor = 1.e6
 813            self.pointsBetweenPoleAndEquator = self.gridDefinitionTemplate[17]
 814            self.latitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[11]/divisor
 815            self.longitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[12]/divisor
 816            self.latitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[14]/divisor
 817            self.longitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[15]/divisor
 818            if reggrid:
 819                self.gridlengthXDirection = scalefact*self.gridDefinitionTemplate[16]/divisor
 820                if self.longitudeFirstGridpoint > self.longitudeLastGridpoint:
 821                    self.gridlengthXDirection = -self.gridlengthXDirection
 822            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[18],output=list)[0:4]
 823            if self.gridDefinitionTemplateNumber == 41:
 824                self.latitudeSouthernPole = scalefact*self.gridDefinitionTemplate[19]/divisor
 825                self.longitudeSouthernPole = scalefact*self.gridDefinitionTemplate[20]/divisor
 826                self.anglePoleRotation = self.gridDefinitionTemplate[21]
 827        elif self.gridDefinitionTemplateNumber == 50:
 828            # Spectral Coefficients
 829            self.spectralFunctionParameters = (self.gridDefinitionTemplate[0],self.gridDefinitionTemplate[1],self.gridDefinitionTemplate[2])
 830            self.scanModeFlags = [None,None,None,None]
 831        elif self.gridDefinitionTemplateNumber == 90:
 832            # Near-sided Vertical Perspective Satellite Projection
 833            self.proj4_lat_0 = self.gridDefinitionTemplate[9]/1.e6
 834            self.proj4_lon_0 = self.gridDefinitionTemplate[10]/1.e6
 835            self.proj4_h = self.earthMajorAxis * (self.gridDefinitionTemplate[18]/1.e6)
 836            dx = self.gridDefinitionTemplate[12]
 837            dy = self.gridDefinitionTemplate[13]
 838            # if lat_0 is equator, it's a geostationary view.
 839            if self.proj4_lat_0 == 0.: # if lat_0 is equator, it's a
 840                self.proj4_proj = 'geos'
 841            # general case of 'near-side perspective projection' (untested)
 842            else:
 843                self.proj4_proj = 'nsper'
 844                msg = 'Only geostationary perspective is supported. Lat/Lon values returned by grid method may be incorrect.'
 845                warnings.warn(msg)
 846            # latitude of horizon on central meridian
 847            lonmax = 90.-(180./np.pi)*np.arcsin(self.earthMajorAxis/self.proj4_h)
 848            # longitude of horizon on equator
 849            latmax = 90.-(180./np.pi)*np.arcsin(self.earthMinorAxis/self.proj4_h)
 850            # truncate to nearest thousandth of a degree (to make sure
 851            # they aren't slightly over the horizon)
 852            latmax = int(1000*latmax)/1000.
 853            lonmax = int(1000*lonmax)/1000.
 854            # h is measured from surface of earth at equator.
 855            self.proj4_h = self.proj4_h - self.earthMajorAxis
 856            # width and height of visible projection
 857            P = pyproj.Proj(proj=self.proj4_proj,\
 858                            a=self.earthMajorAxis,b=self.earthMinorAxis,\
 859                            lat_0=0,lon_0=0,h=self.proj4_h)
 860            x1,y1 = P(0.,latmax)
 861            x2,y2 = P(lonmax,0.)
 862            width = 2*x2
 863            height = 2*y1
 864            self.gridlengthXDirection = width/dx
 865            self.gridlengthYDirection = height/dy
 866            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[16],output=list)[0:4]
 867        elif self.gridDefinitionTemplateNumber == 110:
 868            # Azimuthal Equidistant
 869            self.proj4_lat_0 = self.gridDefinitionTemplate[9]/1.e6
 870            self.proj4_lon_0 = self.gridDefinitionTemplate[10]/1.e6
 871            self.gridlengthXDirection = self.gridDefinitionTemplate[12]/1000.
 872            self.gridlengthYDirection = self.gridDefinitionTemplate[13]/1000.
 873            self.proj4_proj = 'aeqd'
 874            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[15],output=list)[0:4]
 875        elif self.gridDefinitionTemplateNumber == 204:
 876            # Curvilinear Orthogonal
 877            self.scanModeFlags = utils.int2bin(self.gridDefinitionTemplate[18],output=list)[0:4]
 878        else:
 879            errmsg = 'Unsupported Grid Definition Template Number - 3.%i' % self.gridDefinitionTemplateNumber.value
 880            raise ValueError(errmsg)
 881
 882        # -------------------------------
 883        # Section 4 -- Product Definition
 884        # -------------------------------
 885      
 886        # Template 4.0 - NOTE: That is these attributes apply to other templates.
 887        self.parameterCategory = self.productDefinitionTemplate[0]
 888        self.parameterNumber = self.productDefinitionTemplate[1]
 889        self.fullName,self.units,self.shortName = tables.get_varinfo_from_table(self.discipline.value,
 890                                                                                self.parameterCategory,
 891                                                                                self.parameterNumber)
 892        self.typeOfGeneratingProcess = Grib2Metadata(self.productDefinitionTemplate[2],table='4.3')
 893        self.backgroundGeneratingProcessIdentifier = self.productDefinitionTemplate[3]
 894        self.generatingProcess = Grib2Metadata(self.productDefinitionTemplate[4],table='generating_process')
 895        self.unitOfTimeRange = Grib2Metadata(self.productDefinitionTemplate[7],table='4.4')
 896        self.leadTime = self.productDefinitionTemplate[8]
 897        self.typeOfFirstFixedSurface = Grib2Metadata(self.productDefinitionTemplate[9],table='4.5')
 898        self.scaleFactorOfFirstFixedSurface = self.productDefinitionTemplate[10]
 899        self.unitOfFirstFixedSurface = self.typeOfFirstFixedSurface.definition[1]
 900        self.scaledValueOfFirstFixedSurface = self.productDefinitionTemplate[11]
 901        self.valueOfFirstFixedSurface = self.scaledValueOfFirstFixedSurface/(10.**self.scaleFactorOfFirstFixedSurface)
 902        temp = tables.get_value_from_table(self.productDefinitionTemplate[12],'4.5')
 903        if temp[0] == 'Missing' and temp[1] == 'unknown':
 904            self.typeOfSecondFixedSurface = None
 905            self.scaleFactorOfSecondFixedSurface = None
 906            self.unitOfSecondFixedSurface = None
 907            self.valueOfSecondFixedSurface = None
 908        else:
 909            self.typeOfSecondFixedSurface = Grib2Metadata(self.productDefinitionTemplate[12],table='4.5')
 910            self.scaleFactorOfSecondFixedSurface = self.productDefinitionTemplate[13]
 911            self.unitOfSecondFixedSurface = self.typeOfSecondFixedSurface.definition[1]
 912            self.scaledValueOfSecondFixedSurface = self.productDefinitionTemplate[14]
 913            self.valueOfSecondFixedSurface = self.scaledValueOfSecondFixedSurface/(10.**self.scaleFactorOfSecondFixedSurface)
 914        self.level = tables.get_wgrib2_level_string(*self.productDefinitionTemplate[9:15])
 915
 916        # Template 4.1 -
 917        if self.productDefinitionTemplateNumber == 1:
 918            self.typeOfEnsembleForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.6')
 919            self.perturbationNumber = self.productDefinitionTemplate[16]
 920            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[17]
 921
 922        # Template 4.2 -
 923        elif self.productDefinitionTemplateNumber == 2:
 924            self.typeOfDerivedForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.7')
 925            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[16]
 926
 927        # Template 4.5 -
 928        elif self.productDefinitionTemplateNumber == 5:
 929            self.forecastProbabilityNumber = self.productDefinitionTemplate[15]
 930            self.totalNumberOfForecastProbabilities = self.productDefinitionTemplate[16]
 931            self.typeOfProbability = Grib2Metadata(self.productDefinitionTemplate[17],table='4.9')
 932            self.scaleFactorOfThresholdLowerLimit = self.productDefinitionTemplate[18]
 933            self.scaledValueOfThresholdLowerLimit = self.productDefinitionTemplate[19]
 934            self.scaleFactorOfThresholdUpperLimit = self.productDefinitionTemplate[20]
 935            self.scaledValueOfThresholdUpperLimit = self.productDefinitionTemplate[21]
 936            self.thresholdLowerLimit = 0.0 if self.productDefinitionTemplate[19] == 255 else \
 937                                       self.productDefinitionTemplate[19]/(10.**self.productDefinitionTemplate[18])
 938            self.thresholdUpperLimit = 0.0 if self.productDefinitionTemplate[21] == 255 else \
 939                                       self.productDefinitionTemplate[21]/(10.**self.productDefinitionTemplate[20])
 940            self.threshold = utils.get_wgrib2_prob_string(*self.productDefinitionTemplate[17:22])
 941
 942        # Template 4.6 -
 943        elif self.productDefinitionTemplateNumber == 6:
 944            self.percentileValue = self.productDefinitionTemplate[15]
 945
 946        # Template 4.8 -
 947        elif self.productDefinitionTemplateNumber == 8:
 948            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[15]
 949            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[16]
 950            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[17]
 951            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[18]
 952            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[19]
 953            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[20]
 954            self.numberOfTimeRanges = self.productDefinitionTemplate[21]
 955            self.numberOfMissingValues = self.productDefinitionTemplate[22]
 956            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[23],table='4.10')
 957            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[24],table='4.11')
 958            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[25],table='4.4')
 959            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[26]
 960            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[27],table='4.4')
 961            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[28]
 962
 963        # Template 4.9 -
 964        elif self.productDefinitionTemplateNumber == 9:
 965            self.forecastProbabilityNumber = self.productDefinitionTemplate[15]
 966            self.totalNumberOfForecastProbabilities = self.productDefinitionTemplate[16]
 967            self.typeOfProbability = Grib2Metadata(self.productDefinitionTemplate[17],table='4.9')
 968            self.scaleFactorOfThresholdLowerLimit = self.productDefinitionTemplate[18]
 969            self.scaledValueOfThresholdLowerLimit = self.productDefinitionTemplate[19]
 970            self.scaleFactorOfThresholdUpperLimit = self.productDefinitionTemplate[20]
 971            self.scaledValueOfThresholdUpperLimit = self.productDefinitionTemplate[21]
 972            self.thresholdLowerLimit = 0.0 if self.productDefinitionTemplate[19] == 255 else \
 973                                       self.productDefinitionTemplate[19]/(10.**self.productDefinitionTemplate[18])
 974            self.thresholdUpperLimit = 0.0 if self.productDefinitionTemplate[21] == 255 else \
 975                                       self.productDefinitionTemplate[21]/(10.**self.productDefinitionTemplate[20])
 976            self.threshold = utils.get_wgrib2_prob_string(*self.productDefinitionTemplate[17:22])
 977            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[22]
 978            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[23]
 979            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[24]
 980            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[25]
 981            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[26]
 982            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[27]
 983            self.numberOfTimeRanges = self.productDefinitionTemplate[28]
 984            self.numberOfMissingValues = self.productDefinitionTemplate[29]
 985            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[30],table='4.10')
 986            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[31],table='4.11')
 987            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[32],table='4.4')
 988            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[33]
 989            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[34],table='4.4')
 990            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[35]
 991
 992        # Template 4.10 -
 993        elif self.productDefinitionTemplateNumber == 10:
 994            self.percentileValue = self.productDefinitionTemplate[15]
 995            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[16]
 996            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[17]
 997            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[18]
 998            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[19]
 999            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[20]
1000            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[21]
1001            self.numberOfTimeRanges = self.productDefinitionTemplate[22]
1002            self.numberOfMissingValues = self.productDefinitionTemplate[23]
1003            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[24],table='4.10')
1004            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[25],table='4.11')
1005            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[26],table='4.4')
1006            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[27]
1007            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[28],table='4.4')
1008            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[29]
1009
1010        # Template 4.11 -
1011        elif self.productDefinitionTemplateNumber == 11:
1012            self.typeOfEnsembleForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.6')
1013            self.perturbationNumber = self.productDefinitionTemplate[16]
1014            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[17]
1015            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[18]
1016            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[19]
1017            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[20]
1018            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[21]
1019            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[22]
1020            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[23]
1021            self.numberOfTimeRanges = self.productDefinitionTemplate[24]
1022            self.numberOfMissingValues = self.productDefinitionTemplate[25]
1023            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[26],table='4.10')
1024            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[27],table='4.11')
1025            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[28],table='4.4')
1026            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[29]
1027            self.unitOfTimeRangeOfSuccessiveFields = tables.get_value_from_table(self.productDefinitionTemplate[30],table='4.4')
1028            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[31]
1029
1030        # Template 4.12 -
1031        elif self.productDefinitionTemplateNumber == 12:
1032            self.typeOfDerivedForecast = Grib2Metadata(self.productDefinitionTemplate[15],table='4.7')
1033            self.numberOfEnsembleForecasts = self.productDefinitionTemplate[16]
1034            self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[17]
1035            self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[18]
1036            self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[19]
1037            self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[20]
1038            self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[21]
1039            self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[22]
1040            self.numberOfTimeRanges = self.productDefinitionTemplate[23]
1041            self.numberOfMissingValues = self.productDefinitionTemplate[24]
1042            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[25],table='4.10')
1043            self.typeOfTimeIncrementOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[26],table='4.11')
1044            self.unitOfTimeRangeOfStatisticalProcess = Grib2Metadata(self.productDefinitionTemplate[27],table='4.4')
1045            self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[28]
1046            self.unitOfTimeRangeOfSuccessiveFields = Grib2Metadata(self.productDefinitionTemplate[29],table='4.4')
1047            self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[30]
1048
1049        # Template 4.15 -
1050        elif self.productDefinitionTemplateNumber == 15:
1051            self.statisticalProcess = Grib2Metadata(self.productDefinitionTemplate[15],table='4.10')
1052            self.typeOfSpatialProcessing = Grib2Metadata(self.productDefinitionTemplate[16],table='4.15')
1053            self.numberOfDataPointsForSpatialProcessing = self.productDefinitionTemplate[17]
1054
1055        else:
1056            if self.productDefinitionTemplateNumber != 0:
1057                errmsg = 'Unsupported Product Definition Template Number - 4.%i' % self.productDefinitionTemplateNumber.value
1058                raise ValueError(errmsg)
1059
1060
1061        self.leadTime = utils.getleadtime(self.identificationSection,
1062                                          self.productDefinitionTemplateNumber.value,
1063                                          self.productDefinitionTemplate)
1064
1065        if self.productDefinitionTemplateNumber.value in [8,9,10,11,12]:
1066            self.dtEndOfTimePeriod = datetime.datetime(self.yearOfEndOfTimePeriod,self.monthOfEndOfTimePeriod,
1067                                     self.dayOfEndOfTimePeriod,hour=self.hourOfEndOfTimePeriod,
1068                                     minute=self.minuteOfEndOfTimePeriod,
1069                                     second=self.secondOfEndOfTimePeriod)
1070
1071        # --------------------------------
1072        # Section 5 -- Data Representation
1073        # --------------------------------
1074
1075        # Template 5.0 - Simple Packing
1076        if self.dataRepresentationTemplateNumber == 0:
1077            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1078            self.binScaleFactor = self.dataRepresentationTemplate[1]
1079            self.decScaleFactor = self.dataRepresentationTemplate[2]
1080            self.nBitsPacking = self.dataRepresentationTemplate[3]
1081            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[3],table='5.1')
1082
1083        # Template 5.2 - Complex Packing
1084        elif self.dataRepresentationTemplateNumber == 2:
1085            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1086            self.binScaleFactor = self.dataRepresentationTemplate[1]
1087            self.decScaleFactor = self.dataRepresentationTemplate[2]
1088            self.nBitsPacking = self.dataRepresentationTemplate[3]
1089            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1090            self.groupSplitMethod = Grib2Metadata(self.dataRepresentationTemplate[5],table='5.4')
1091            self.typeOfMissingValue = Grib2Metadata(self.dataRepresentationTemplate[6],table='5.5')
1092            self.priMissingValue = utils.getieeeint(self.dataRepresentationTemplate[7]) if self.dataRepresentationTemplate[6] in [1,2] else None
1093            self.secMissingValue = utils.getieeeint(self.dataRepresentationTemplate[8]) if self.dataRepresentationTemplate[6] == 2 else None
1094            self.nGroups = self.dataRepresentationTemplate[9]
1095            self.refGroupWidth = self.dataRepresentationTemplate[10]
1096            self.nBitsGroupWidth = self.dataRepresentationTemplate[11]
1097            self.refGroupLength = self.dataRepresentationTemplate[12]
1098            self.groupLengthIncrement = self.dataRepresentationTemplate[13]
1099            self.lengthOfLastGroup = self.dataRepresentationTemplate[14]
1100            self.nBitsScaledGroupLength = self.dataRepresentationTemplate[15]
1101
1102        # Template 5.3 - Complex Packing and Spatial Differencing
1103        elif self.dataRepresentationTemplateNumber == 3:
1104            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1105            self.binScaleFactor = self.dataRepresentationTemplate[1]
1106            self.decScaleFactor = self.dataRepresentationTemplate[2]
1107            self.nBitsPacking = self.dataRepresentationTemplate[3]
1108            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1109            self.groupSplitMethod = Grib2Metadata(self.dataRepresentationTemplate[5],table='5.4')
1110            self.typeOfMissingValue = Grib2Metadata(self.dataRepresentationTemplate[6],table='5.5')
1111            self.priMissingValue = utils.getieeeint(self.dataRepresentationTemplate[7]) if self.dataRepresentationTemplate[6] in [1,2] else None
1112            self.secMissingValue = utils.getieeeint(self.dataRepresentationTemplate[8]) if self.dataRepresentationTemplate[6] == 2 else None
1113            self.nGroups = self.dataRepresentationTemplate[9]
1114            self.refGroupWidth = self.dataRepresentationTemplate[10]
1115            self.nBitsGroupWidth = self.dataRepresentationTemplate[11]
1116            self.refGroupLength = self.dataRepresentationTemplate[12]
1117            self.groupLengthIncrement = self.dataRepresentationTemplate[13]
1118            self.lengthOfLastGroup = self.dataRepresentationTemplate[14]
1119            self.nBitsScaledGroupLength = self.dataRepresentationTemplate[15]
1120            self.spatialDifferenceOrder = Grib2Metadata(self.dataRepresentationTemplate[16],table='5.6')
1121            self.nBytesSpatialDifference = self.dataRepresentationTemplate[17]
1122
1123        # Template 5.4 - IEEE Floating Point Data
1124        elif self.dataRepresentationTemplateNumber == 4:
1125            self.precision = Grib2Metadata(self.dataRepresentationTemplate[0],table='5.7')
1126
1127        # Template 5.40 - JPEG2000 Compression
1128        elif self.dataRepresentationTemplateNumber == 40:
1129            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1130            self.binScaleFactor = self.dataRepresentationTemplate[1]
1131            self.decScaleFactor = self.dataRepresentationTemplate[2]
1132            self.nBitsPacking = self.dataRepresentationTemplate[3]
1133            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1134            self.typeOfCompression = Grib2Metadata(self.dataRepresentationTemplate[5],table='5.40')
1135            self.targetCompressionRatio = self.dataRepresentationTemplate[6]
1136
1137        # Template 5.41 - PNG Compression
1138        elif self.dataRepresentationTemplateNumber == 41:
1139            self.refValue = utils.getieeeint(self.dataRepresentationTemplate[0])
1140            self.binScaleFactor = self.dataRepresentationTemplate[1]
1141            self.decScaleFactor = self.dataRepresentationTemplate[2]
1142            self.nBitsPacking = self.dataRepresentationTemplate[3]
1143            self.typeOfValues = Grib2Metadata(self.dataRepresentationTemplate[4],table='5.1')
1144
1145        else:
1146            errmsg = 'Unsupported Data Representation Definition Template Number - 5.%i' % self.dataRepresentationTemplateNumber.value
1147            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)
1150    def data(self, fill_value=DEFAULT_FILL_VALUE, masked_array=True, expand=True, order=None,
1151             map_keys=False):
1152        """
1153        Returns an unpacked data grid.
1154
1155        Parameters
1156        ----------
1157
1158        **`fill_value`**: Missing or masked data is filled with this value or default value given by
1159        `DEFAULT_FILL_VALUE`
1160
1161        **`masked_array`**: If `True` [DEFAULT], return masked array if there is bitmap for missing 
1162        or masked data.
1163
1164        **`expand`**: If `True` [DEFAULT], Reduced Gaussian grids are expanded to regular Gaussian grids.
1165
1166        **`order`**: If 0 [DEFAULT], nearest neighbor interpolation is used if grid has missing 
1167        or bitmapped values. If 1, linear interpolation is used for expanding reduced Gaussian grids.
1168
1169        **`map_keys`**: If `True`, data values will be mapped to the string-based keys that are stored
1170        in the Local Use Section (section 2) of the GRIB2 Message or in a code table as specified in the
1171        units (i.e. "See Table 4.xxx").
1172
1173        Returns
1174        -------
1175
1176        **`numpy.ndarray`**: A numpy.ndarray with shape (ny,nx). By default the array dtype=np.float32, 
1177        but could be np.int32 if Grib2Message.typeOfValues is integer.  The array dtype will be 
1178        string-based if map_keys=True.
1179        """
1180        if not hasattr(self,'scanModeFlags'):
1181            raise ValueError('Unsupported grid definition template number %s'%self.gridDefinitionTemplateNumber)
1182        else:
1183            if self.scanModeFlags[2]:
1184                storageorder='F'
1185            else:
1186                storageorder='C'
1187        if order is None:
1188            if (self.dataRepresentationTemplateNumber in [2,3] and
1189                self.dataRepresentationTemplate[6] != 0) or self.bitMapFlag == 0:
1190                order = 0
1191            else:
1192                order = 1
1193        drtnum = self.dataRepresentationTemplateNumber.value
1194        drtmpl = np.asarray(self.dataRepresentationTemplate,dtype=DEFAULT_NUMPY_INT)
1195        gdtnum = self.gridDefinitionTemplateNumber.value
1196        gdtmpl = np.asarray(self.gridDefinitionTemplate,dtype=DEFAULT_NUMPY_INT)
1197        ndpts = self.numberOfDataPoints
1198        gds = self.gridDefinitionSection
1199        ngrdpts = gds[1]
1200        ipos = self._datapos
1201        fld1 = g2clib.unpack7(self._msg,gdtnum,gdtmpl,drtnum,drtmpl,ndpts,ipos,np.empty,storageorder=storageorder)
1202        # Apply bitmap.
1203        if self.bitMapFlag == 0:
1204            fld = fill_value*np.ones(ngrdpts,'f')
1205            np.put(fld,np.nonzero(self.bitMap),fld1)
1206            if masked_array:
1207                fld = ma.masked_values(fld,fill_value)
1208        # Missing values instead of bitmap
1209        elif masked_array and hasattr(self,'priMissingValue'):
1210            if hasattr(self,'secMissingValue'):
1211                mask = np.logical_or(fld1==self.priMissingValue,fld1==self.secMissingValue)
1212            else:
1213                mask = fld1 == self.priMissingValue
1214            fld = ma.array(fld1,mask=mask)
1215        else:
1216            fld = fld1
1217        if self.nx is not None and self.ny is not None: # Rectangular grid.
1218            if ma.isMA(fld):
1219                fld = ma.reshape(fld,(self.ny,self.nx))
1220            else:
1221                fld = np.reshape(fld,(self.ny,self.nx))
1222        else:
1223            if gds[2] and gdtnum == 40: # Reduced global Gaussian grid.
1224                if expand:
1225                    from . import redtoreg
1226                    self.nx = 2*self.ny
1227                    lonsperlat = self.defList
1228                    if ma.isMA(fld):
1229                        fld = ma.filled(fld)
1230                        fld = redtoreg._redtoreg(self.nx,lonsperlat.astype(np.long),
1231                                                 fld.astype(np.double),fill_value)
1232                        fld = ma.masked_values(fld,fill_value)
1233                    else:
1234                        fld = redtoreg._redtoreg(self.nx,lonsperlat.astype(np.long),
1235                                                 fld.astype(np.double),fill_value)
1236        # Check scan modes for rect grids.
1237        if self.nx is not None and self.ny is not None:
1238            if self.scanModeFlags[3]:
1239                fldsave = fld.astype('f') # casting makes a copy
1240                fld[1::2,:] = fldsave[1::2,::-1]
1241
1242        # Set data to integer according to GRIB metadata
1243        if self.typeOfValues == "Integer": fld = fld.astype(np.int32)
1244
1245        # Map the data values to their respective definitions.
1246        if map_keys:
1247            fld = fld.astype(np.int32).astype(str)
1248            if self.identificationSection[0] == 7 and \
1249               self.identificationSection[1] == 14 and \
1250               self.shortName == 'PWTHER':
1251                # MDL Predominant Weather Grid
1252                #keys = utils.decode_mdl_wx_strings(self._lus)
1253                keys = utils.decode_ndfd_wx_strings(self._lus)
1254                for n,k in enumerate(keys):
1255                    fld = np.where(fld==str(n+1),k,fld)
1256            elif self.identificationSection[0] == 8 and \
1257                 self.identificationSection[1] == 65535 and \
1258                 self.shortName == 'CRAIN':
1259                # NDFD Predominant Weather Grid
1260                keys = utils.decode_ndfd_wx_strings(self._lus)
1261                for n,k in enumerate(keys):
1262                    fld = np.where(fld==str(n+1),k,fld)
1263            else:
1264                # For data whose units are defined in a code table
1265                tbl = re.findall(r'\d\.\d+',self.units,re.IGNORECASE)[0]
1266                for k,v in tables.get_table(tbl).items():
1267                    fld = np.where(fld==k,v,fld)
1268        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)
1271    def latlons(self):
1272        """Alias for `grib2io.Grib2Message.grid` method"""
1273        return self.grid()

Alias for grib2io.Grib2Message.grid method

def grid(self)
1276    def grid(self):
1277        """
1278        Return lats,lons (in degrees) of grid. Currently can handle reg. lat/lon, 
1279        global Gaussian, mercator, stereographic, lambert conformal, albers equal-area, 
1280        space-view and azimuthal equidistant grids.
1281
1282        Returns
1283        -------
1284
1285        **`lats, lons : numpy.ndarray`**
1286
1287        Returns two numpy.ndarrays with dtype=numpy.float32 of grid latitudes and
1288        longitudes in units of degrees.
1289        """
1290        gdtnum = self.gridDefinitionTemplateNumber
1291        gdtmpl = self.gridDefinitionTemplate
1292        reggrid = self.gridDefinitionSection[2] == 0 # This means regular 2-d grid
1293        self.projparams = {}
1294        if self.earthMajorAxis is not None: self.projparams['a']=self.earthMajorAxis
1295        if self.earthMajorAxis is not None: self.projparams['b']=self.earthMinorAxis
1296        if gdtnum == 0:
1297            # Regular lat/lon grid
1298            lon1, lat1 = self.longitudeFirstGridpoint, self.latitudeFirstGridpoint
1299            lon2, lat2 = self.longitudeLastGridpoint, self.latitudeLastGridpoint
1300            dlon = self.gridlengthXDirection
1301            dlat = self.gridlengthYDirection
1302            lats = np.arange(lat1,lat2+dlat,dlat)
1303            lons = np.arange(lon1,lon2+dlon,dlon)
1304            # flip if scan mode says to.
1305            #if self.scanModeFlags[0]:
1306            #    lons = lons[::-1]
1307            #if not self.scanModeFlags[1]:
1308            #    lats = lats[::-1]
1309            self.projparams['proj'] = 'cyl'
1310            lons,lats = np.meshgrid(lons,lats) # make 2-d arrays.
1311        elif gdtnum == 40: # Gaussian grid (only works for global!)
1312            from utils.gauss_grids import gaussian_latitudes
1313            lon1, lat1 = self.longitudeFirstGridpoint, self.latitudeFirstGridpoint
1314            lon2, lat2 = self.longitudeLastGridpoint, self.latitudeLastGridpoint
1315            nlats = self.ny
1316            if not reggrid: # Reduced Gaussian grid.
1317                nlons = 2*nlats
1318                dlon = 360./nlons
1319            else:
1320                nlons = self.nx
1321                dlon = self.gridlengthXDirection
1322            lons = np.arange(lon1,lon2+dlon,dlon)
1323            # Compute Gaussian lats (north to south)
1324            lats = gaussian_latitudes(nlats)
1325            if lat1 < lat2:  # reverse them if necessary
1326                lats = lats[::-1]
1327            # flip if scan mode says to.
1328            #if self.scanModeFlags[0]:
1329            #    lons = lons[::-1]
1330            #if not self.scanModeFlags[1]:
1331            #    lats = lats[::-1]
1332            self.projparams['proj'] = 'cyl'
1333            lons,lats = np.meshgrid(lons,lats) # make 2-d arrays
1334        elif gdtnum in [10,20,30,31,110]:
1335            # Mercator, Lambert Conformal, Stereographic, Albers Equal Area, Azimuthal Equidistant
1336            dx,dy = self.gridlengthXDirection, self.gridlengthYDirection
1337            lon1,lat1 = self.longitudeFirstGridpoint, self.latitudeFirstGridpoint
1338            if gdtnum == 10: # Mercator.
1339                self.projparams['lat_ts']=self.proj4_lat_ts
1340                self.projparams['proj']=self.proj4_proj
1341                self.projparams['lon_0']=self.proj4_lon_0
1342                pj = pyproj.Proj(self.projparams)
1343                llcrnrx, llcrnry = pj(lon1,lat1)
1344                x = llcrnrx+dx*np.arange(self.nx)
1345                y = llcrnry+dy*np.arange(self.ny)
1346                x,y = np.meshgrid(x, y)
1347                lons,lats = pj(x, y, inverse=True)
1348            elif gdtnum == 20:  # Stereographic
1349                self.projparams['lat_ts']=self.proj4_lat_ts
1350                self.projparams['proj']=self.proj4_proj
1351                self.projparams['lat_0']=self.proj4_lat_0
1352                self.projparams['lon_0']=self.proj4_lon_0
1353                pj = pyproj.Proj(self.projparams)
1354                llcrnrx, llcrnry = pj(lon1,lat1)
1355                x = llcrnrx+dx*np.arange(self.nx)
1356                y = llcrnry+dy*np.arange(self.ny)
1357                x,y = np.meshgrid(x, y)
1358                lons,lats = pj(x, y, inverse=True)
1359            elif gdtnum in [30,31]: # Lambert, Albers
1360                self.projparams['lat_1']=self.proj4_lat_1
1361                self.projparams['lat_2']=self.proj4_lat_2
1362                self.projparams['proj']=self.proj4_proj
1363                self.projparams['lon_0']=self.proj4_lon_0
1364                pj = pyproj.Proj(self.projparams)
1365                llcrnrx, llcrnry = pj(lon1,lat1)
1366                x = llcrnrx+dx*np.arange(self.nx)
1367                y = llcrnry+dy*np.arange(self.ny)
1368                x,y = np.meshgrid(x, y)
1369                lons,lats = pj(x, y, inverse=True)
1370            elif gdtnum == 110: # Azimuthal Equidistant
1371                self.projparams['proj']=self.proj4_proj
1372                self.projparams['lat_0']=self.proj4_lat_0
1373                self.projparams['lon_0']=self.proj4_lon_0
1374                pj = pyproj.Proj(self.projparams)
1375                llcrnrx, llcrnry = pj(lon1,lat1)
1376                x = llcrnrx+dx*np.arange(self.nx)
1377                y = llcrnry+dy*np.arange(self.ny)
1378                x,y = np.meshgrid(x, y)
1379                lons,lats = pj(x, y, inverse=True)
1380        elif gdtnum == 90:
1381            # Satellite Projection
1382            dx = self.gridlengthXDirection
1383            dy = self.gridlengthYDirection
1384            self.projparams['proj']=self.proj4_proj
1385            self.projparams['lon_0']=self.proj4_lon_0
1386            self.projparams['lat_0']=self.proj4_lat_0
1387            self.projparams['h']=self.proj4_h
1388            pj = pyproj.Proj(self.projparams)
1389            x = dx*np.indices((self.ny,self.nx),'f')[1,:,:]
1390            x -= 0.5*x.max()
1391            y = dy*np.indices((self.ny,self.nx),'f')[0,:,:]
1392            y -= 0.5*y.max()
1393            lons,lats = pj(x,y,inverse=True)
1394            # Set lons,lats to 1.e30 where undefined
1395            abslons = np.fabs(lons)
1396            abslats = np.fabs(lats)
1397            lons = np.where(abslons < 1.e20, lons, 1.e30)
1398            lats = np.where(abslats < 1.e20, lats, 1.e30)
1399        else:
1400            raise ValueError('Unsupported grid')
1401
1402        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)
1405    def addlocal(self, ludata):
1406        """
1407        Add a Local Use Section [(Section 2)](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_sect2.shtml)
1408        to the GRIB2 message.
1409
1410        Parameters
1411        ----------
1412
1413        **`ludata : bytes`**: Local Use data.
1414        """
1415        assert isinstance(ludata,bytes)
1416        self._msg,self._pos = g2clib.grib2_addlocal(self._msg,ludata)
1417        self.hasLocalUseSection = True
1418        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)
1421    def addgrid(self, gdsinfo, gdtmpl, deflist=None):
1422        """
1423        Add a Grid Definition Section [(Section 3)](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_doc/grib2_sect3.shtml) 
1424        to the GRIB2 message.
1425
1426        Parameters
1427        ----------
1428
1429        **`gdsinfo`**: Sequence containing information needed for the grid definition section.
1430
1431        | Index | Description |
1432        | :---: | :---        |
1433        | 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)|
1434        | gdsinfo[1] | Number of data points|
1435        | gdsinfo[2] | Number of octets for optional list of numbers defining number of points|
1436        | 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)|
1437        | 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)|
1438
1439        **`gdtmpl`**: Sequence of values for the specified Grid Definition Template. Each 
1440        element of this integer array contains an entry (in the order specified) of Grid
1441        Definition Template 3.NN
1442
1443        **`deflist`**: Sequence containing the number of grid points contained in each 
1444        row (or column) of a non-regular grid.  Used if gdsinfo[2] != 0.
1445        """
1446        if 3 in self._sections:
1447            raise ValueError('GRIB2 Message already contains Grid Definition Section.')
1448        if deflist is not None:
1449            _deflist = np.array(deflist,dtype=DEFAULT_NUMPY_INT)
1450        else:
1451            _deflist = None
1452        gdtnum = gdsinfo[4]
1453        if gdtnum in [0,1,2,3,40,41,42,43,44,203,205,32768,32769]:
1454            self.scanModeFlags = utils.int2bin(gdtmpl[18],output=list)[0:4]
1455        elif gdtnum == 10: # mercator
1456            self.scanModeFlags = utils.int2bin(gdtmpl[15],output=list)[0:4]
1457        elif gdtnum == 20: # stereographic
1458            self.scanModeFlags = utils.int2bin(gdtmpl[17],output=list)[0:4]
1459        elif gdtnum == 30: # lambert conformal
1460            self.scanModeFlags = utils.int2bin(gdtmpl[17],output=list)[0:4]
1461        elif gdtnum == 31: # albers equal area.
1462            self.scanModeFlags = utils.int2bin(gdtmpl[17],output=list)[0:4]
1463        elif gdtnum == 90: # near-sided vertical perspective satellite projection
1464            self.scanModeFlags = utils.int2bin(gdtmpl[16],output=list)[0:4]
1465        elif gdtnum == 110: # azimuthal equidistant.
1466            self.scanModeFlags = utils.int2bin(gdtmpl[15],output=list)[0:4]
1467        elif gdtnum == 120:
1468            self.scanModeFlags = utils.int2bin(gdtmpl[6],output=list)[0:4]
1469        elif gdtnum == 204: # curvilinear orthogonal
1470            self.scanModeFlags = utils.int2bin(gdtmpl[18],output=list)[0:4]
1471        elif gdtnum in [1000,1100]:
1472            self.scanModeFlags = utils.int2bin(gdtmpl[12],output=list)[0:4]
1473        self._msg,self._pos = g2clib.grib2_addgrid(self._msg,
1474                                                   np.array(gdsinfo,dtype=DEFAULT_NUMPY_INT),
1475                                                   np.array(gdtmpl,dtype=DEFAULT_NUMPY_INT),
1476                                                   _deflist)
1477        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)
1480    def addfield(self, field, pdtnum, pdtmpl, coordlist=None, packing="complex-spdiff", **packing_opts): 
1481        """
1482        Add a Product Definition, Data Representation, Bitmap, and Data Sections 
1483        to `Grib2Message` instance (i.e. Sections 4-7).  Must be called after the grid 
1484        definition section has been added (`addfield`).
1485
1486        Parameters
1487        ----------
1488
1489        **`field`**: Numpy array of data values to pack.  If field is a masked array, then 
1490        a bitmap is created from the mask.
1491
1492        **`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)
1493
1494        **`pdtmpl`**: Sequence with the data values for the specified Product Definition 
1495        Template (N=pdtnum).  Each element of this integer array contains an entry (in 
1496        the order specified) of Product Definition Template 4.N.
1497
1498        **`coordlist`**: Sequence containing floating point values intended to document the 
1499        vertical discretization with model data on hybrid coordinate vertical levels. Default is `None`.
1500
1501        **`packing`**: String to specify the type of packing. Valid options are the following:
1502
1503        | Packing Scheme | Description |
1504        | :---:          | :---:       |
1505        | 'simple'         | [Simple packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-0.shtml) | 
1506        | 'complex'        | [Complex packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-2.shtml) | 
1507        | 'complex-spdiff' | [Complex packing with Spatial Differencing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-3.shtml) | 
1508        | 'jpeg'           | [JPEG compression](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-40.shtml) | 
1509        | 'png'            | [PNG compression](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-41.shtml) | 
1510        | 'spectral-simple'| [Spectral Data - Simple packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-50.shtml) | 
1511        | 'spectral-complex'| [Spectral Data - Complex packing](https://www.nco.ncep.noaa.gov/pmb/docs/grib2/grib2_doc/grib2_temp5-51.shtml) | 
1512
1513        **`**packing_opts`**: Packing keyword arguments. The keywords are the same as Grib2Message attribute names for
1514        the Data Representation Template (Section 5) metadata. Valid keywords per packing scheme are the following:
1515
1516        | Packing Scheme | Keyword Arguments |
1517        | :---:          | :---:                      |
1518        | 'simple'     | `binScaleFactor`, `decScaleFactor` |
1519        | 'complex'     | `binScaleFactor`, `decScaleFactor`, `priMissingValue`, [`secMissingValue`] |
1520        | 'complex-spdiff'     | `binScaleFactor`, `decScaleFactor`, `spatialDifferenceOrder`, `priMissingValue`, [`secMissingValue`] |
1521        | 'jpeg'     | `binScaleFactor`, `decScaleFactor` |
1522        | 'png'     | `binScaleFactor`, `decScaleFactor` |
1523        | 'spectral-simple'     | `binScaleFactor`, `decScaleFactor` |
1524        | 'spectral-complex'     | `binScaleFactor`, `decScaleFactor` |
1525        """
1526        if self._sections[-1] != 3:
1527            raise ValueError('addgrid() must be called before addfield()')
1528        if self.scanModeFlags is not None:
1529            if self.scanModeFlags[3]:
1530                fieldsave = field.astype('f') # Casting makes a copy
1531                field[1::2,:] = fieldsave[1::2,::-1]
1532        fld = field.astype('f')
1533        if ma.isMA(field) and ma.count_masked(field) > 0:
1534            bitmapflag = 0
1535            bmap = 1-np.ravel(field.mask.astype(DEFAULT_NUMPY_INT))
1536        else:
1537            bitmapflag = 255
1538            bmap = None
1539        if coordlist is not None:
1540            crdlist = np.array(coordlist,'f')
1541        else:
1542            crdlist = None
1543
1544        # Set data representation template number and template values
1545        drtnum = -1
1546        drtmpl = np.zeros((DEFAULT_DRT_LEN),dtype=DEFAULT_NUMPY_INT)
1547        if packing == "simple":
1548            drtnum = 0
1549            drtmpl[1] = packing_opts["binScaleFactor"]
1550            drtmpl[2] = packing_opts["decScaleFactor"]
1551        elif packing == "complex" or packing == "complex-spdiff":
1552            if packing == "complex":
1553                drtnum = 2
1554            if packing == "complex-spdiff":
1555                drtnum = 3
1556                drtmpl[16] = packing_opts['spatialDifferenceOrder']
1557            drtmpl[1] = packing_opts["binScaleFactor"]
1558            drtmpl[2] = packing_opts["decScaleFactor"]
1559            if set(("priMissingValue","secMissingValue")).issubset(packing_opts):
1560                drtmpl[6] = 2
1561                drtmpl[7] = utils.putieeeint(packing_opts["priMissingValue"])
1562                drtmpl[8] = utils.putieeeint(packing_opts["secMissingValue"])
1563            else:
1564                if "priMissingValue" in packing_opts.keys():
1565                    drtmpl[6] = 1
1566                    drtmpl[7] = utils.putieeeint(packing_opts["priMissingValue"])
1567                else:
1568                    drtmpl[6] = 0
1569        elif packing == "jpeg":
1570            drtnum = 40
1571            drtmpl[1] = packing_opts["binScaleFactor"]
1572            drtmpl[2] = packing_opts["decScaleFactor"]
1573        elif packing == "png":
1574            drtnum = 41
1575            drtmpl[1] = packing_opts["binScaleFactor"]
1576            drtmpl[2] = packing_opts["decScaleFactor"]
1577        elif packing == "spectral-simple":
1578            drtnum = 50
1579            drtmpl[1] = packing_opts["binScaleFactor"]
1580            drtmpl[2] = packing_opts["decScaleFactor"]
1581        elif packing == "spectral-complex":
1582            drtnum = 51
1583            drtmpl[1] = packing_opts["binScaleFactor"]
1584            drtmpl[2] = packing_opts["decScaleFactor"]
1585
1586        pdtnum = pdtnum.value if isinstance(pdtnum,Grib2Metadata) else pdtnum
1587
1588        self._msg,self._pos = g2clib.grib2_addfield(self._msg,
1589                                                    pdtnum,
1590                                                    np.array(pdtmpl,dtype=DEFAULT_NUMPY_INT),
1591                                                    crdlist,
1592                                                    drtnum,
1593                                                    drtmpl,
1594                                                    np.ravel(fld),
1595                                                    bitmapflag,
1596                                                    bmap)
1597        self._sections.append(4)
1598        self._sections.append(5)
1599        if bmap is not None: self._sections.append(6)
1600        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)
1603    def end(self):
1604        """
1605        Add End Section (Section 8) to the GRIB2 message. A GRIB2 message 
1606        is not complete without an end section.  Once an end section is added, 
1607        the GRIB2 message can be written to file.
1608        """
1609        self._msg, self._pos = g2clib.grib2_end(self._msg)
1610        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)
1612    def to_bytes(self, validate=True):
1613        """
1614        Return grib data in byte format. Useful for exporting data in non-file formats.
1615        For example, can be used to output grib data directly to S3 using the boto3 client
1616        without the need to write a temporary file to upload first.
1617
1618        Parameters
1619        ----------
1620        **`validate`**: bool (Default: True) If true, validates first/last four bytes for proper formatting, else
1621        returns None. If False, message is output as is.
1622
1623        Returns
1624        -------
1625        Returns GRIB2 formatted message as bytes.
1626        """
1627        if validate:
1628            if str(self._msg[0:4] + self._msg[-4:], 'utf-8') == 'GRIB7777':
1629                return self._msg
1630            else:
1631                return None
1632        else:
1633            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:
1636class Grib2Metadata():
1637    """
1638    Class to hold GRIB2 metadata both as numeric code value as stored in
1639    GRIB2 and its plain langauge definition.
1640
1641    **`value : int`**
1642
1643    GRIB2 metadata integer code value.
1644
1645    **`table : str, optional`**
1646
1647    GRIB2 table to lookup the `value`. Default is None.
1648    """
1649    def __init__(self, value, table=None):
1650        self.value = value
1651        self.table = table
1652        if self.table is None:
1653            self.definition = None
1654        else:
1655            self.definition = tables.get_value_from_table(self.value,self.table)
1656    def __call__(self):
1657        return self.value
1658    def __repr__(self):
1659        return '%s(%d, table = %s)' % (self.__class__.__name__,self.value,self.table)
1660    def __str__(self):
1661        return '%d - %s' % (self.value,self.definition)
1662    def __eq__(self,other):
1663        return self.value == other
1664    def __gt__(self,other):
1665        return self.value > other
1666    def __ge__(self,other):
1667        return self.value >= other
1668    def __lt__(self,other):
1669        return self.value < other
1670    def __le__(self,other):
1671        return self.value <= other
1672    def __contains__(self,other):
1673        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)
1649    def __init__(self, value, table=None):
1650        self.value = value
1651        self.table = table
1652        if self.table is None:
1653            self.definition = None
1654        else:
1655            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.