Package 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 GRIB2 Messages. WMO GRIdded Binary, Edition 2 (GRIB2) files store 2-D meteorological data. A physical file can contain one or more GRIB2 messages. File IO is handled in Python returning a binary string of the GRIB2 message which is then passed to the g2c library for decoding or GRIB2 metadata and unpacking of data.
Expand source code
from ._grib2io import *
from ._grib2io import __doc__,__pdoc__
__all__ = ['open','Grib2Message']
Sub-modules
grib2io.tables
Classes
class Grib2Message
-
Class Constructor
Parameters
msg : bytes
Binary string representing the GRIB2 Message read from file.
ref : grib2io.open, optional
Holds the reference to the where this GRIB2 message originated from (i.e. the input file). This allow for interaction with the instance of
open
.num : int, optional
Set to the GRIB2 Message number.
Expand source code
class Grib2Message: __pdoc__['grib2io.Grib2Message.__init__'] = True def __init__(self, msg, ref=None, num=-1): """ Class Constructor Parameters ---------- **`msg : bytes`** Binary string representing the GRIB2 Message read from file. **`ref : grib2io.open, optional`** Holds the reference to the where this GRIB2 message originated from (i.e. the input file). This allow for interaction with the instance of `grib2io.open`. **`num : int, optional`** Set to the GRIB2 Message number. """ self._msg = msg self._pos = 0 self._ref = ref self._datapos = 0 self._msgnum = num # Section 0, Indicator Section self.indicatorSection = [] self.indicatorSection.append(struct.unpack('>4s',self._msg[0:4])[0]) self.indicatorSection.append(struct.unpack('>H',self._msg[4:6])[0]) self.indicatorSection.append(self._msg[6]) self.indicatorSection.append(self._msg[7]) self.indicatorSection.append(struct.unpack('>Q',self._msg[8:16])[0]) self.discipline = tables.get_value_from_table(self.indicatorSection[2],'0.0') self._pos = 16 # Section 1, Indentification Section. self.identificationSection,self._pos = g2clib.unpack1(self._msg,self._pos,np.empty) self.identificationSection = self.identificationSection.tolist() self.originatingCenter = tables.get_value_from_table(self.identificationSection[0],'originating_centers') self.originatingSubCenter = tables.get_value_from_table(self.identificationSection[1],'originating_subcenters') self.masterTableInfo = tables.get_value_from_table(self.identificationSection[2],'1.0') self.localTableInfo = tables.get_value_from_table(self.identificationSection[3],'1.1') self.significanceOfReferenceTime = tables.get_value_from_table(self.identificationSection[4],'1.2') self.year = self.identificationSection[5] self.month = self.identificationSection[6] self.day = self.identificationSection[7] self.hour = self.identificationSection[8] self.minute = self.identificationSection[9] self.second = self.identificationSection[10] self.intreferenceDate = (self.year*1000000)+(self.month*10000)+\ (self.day*100)+self.hour self.dtReferenceDate = datetime.datetime(self.year,self.month,self.day, hour=self.hour,minute=self.minute, second=self.second) self.productionStatus = tables.get_value_from_table(self.identificationSection[11],'1.3') self.typeOfData = tables.get_value_from_table(self.identificationSection[12],'1.4') # After Section 1, perform rest of GRIB2 Decoding inside while loop # to account for sub-messages. while True: if self._msg[self._pos:self._pos+4].decode('ascii','ignore') == '7777': break # Read the length and section number. sectlen = struct.unpack('>i',self._msg[self._pos:self._pos+4])[0] sectnum = struct.unpack('>B',self._msg[self._pos+4:self._pos+5])[0] # Handle submessage accordingly. if self._ref._index['isSubmessage'][num]: if sectnum == self._ref._index['submessageBeginSection'][self._msgnum]: self._pos = self._ref._index['submessageOffset'][self._msgnum] # Section 2, Local Use Section. self.localUseSection = None if sectnum == 2: _lus = self._msg[self._pos+5:self._pos+sectlen] self._pos += sectlen self.localUseSection = _lus # Section 3, Grid Definition Section. elif sectnum == 3: _gds,_gdtn,_deflist,self._pos = g2clib.unpack3(self._msg,self._pos,np.empty) self.gridDefinitionInfo = _gds.tolist() self.gridDefinitionTemplateNumber = int(_gds[4]) self.gridDefinitionTemplate = _gdtn.tolist() self.defList = _deflist.tolist() self.gridDefinitionTemplateNumberInfo = tables.get_value_from_table(self.gridDefinitionTemplateNumber,'3.1') # Section 4, Product Definition Section. elif sectnum == 4: _pdt,_pdtn,_coordlst,self._pos = g2clib.unpack4(self._msg,self._pos,np.empty) self.productDefinitionTemplate = _pdt.tolist() self.productDefinitionTemplateNumber = int(_pdtn) self.coordinateList = _coordlst.tolist() # Section 5, Data Representation Section. elif sectnum == 5: _drt,_drtn,_npts,self._pos = g2clib.unpack5(self._msg,self._pos,np.empty) self.dataRepresentationTemplate = _drt.tolist() self.dataRepresentationTemplateNumber = int(_drtn) self.numberOfDataPoints = _npts # Section 6, Bitmap Section. elif sectnum == 6: _bmap,_bmapflag = g2clib.unpack6(self._msg,self.gridDefinitionInfo[1],self._pos,np.empty) self.bitMapFlag = _bmapflag if self.bitMapFlag == 0: self.bitMap = _bmap elif self.bitMapFlag == 254: # Value of 254 says to use a previous bitmap in the file. self.bitMapFlag = 0 self.bitMap = self._ref._index['bitMap'][self._msgnum] self._pos += sectlen # IMPORTANT: This is here because g2clib.unpack6() does not return updated position. # Section 7, Data Section (data unpacked when data() method is invoked). elif sectnum == 7: self._datapos = self._pos self._pos += sectlen # REMOVE THIS WHEN UNPACKING DATA IS IMPLEMENTED else: errmsg = 'Unknown section number = %i' % sectnum raise ValueError(errmsg) # Section 3 -- Grid Definition reggrid = self.gridDefinitionInfo[2] == 0 # self.gridDefinitionInfo[2]=0 means regular 2-d grid if self.gridDefinitionTemplateNumber in [50,51,52,1200]: earthparams = None else: earthparams = tables.earth_params[str(self.gridDefinitionTemplate[0])] if earthparams['shape'] == 'spherical': if earthparams['radius'] is None: self.earthRadius = self.gridDefinitionTemplate[2]/(10.**self.gridDefinitionTemplate[1]) else: self.earthRadius = earthparams['radius'] self.earthMajorAxis = None self.earthMinorAxis = None elif earthparams['shape'] == 'oblateSpheroid': if earthparams['radius'] is None and earthparams['major_axis'] is None and earthparams['minor_axis'] is None: self.earthRadius = self.gridDefinitionTemplate[2]/(10.**self.gridDefinitionTemplate[1]) self.earthMajorAxis = self.gridDefinitionTemplate[4]/(10.**self.gridDefinitionTemplate[3]) self.earthMinorAxis = self.gridDefinitionTemplate[6]/(10.**self.gridDefinitionTemplate[5]) else: self.earthRadius = earthparams['radius'] self.earthMajorAxis = earthparams['major_axis'] self.earthMinorAxis = earthparams['minor_axis'] if reggrid and self.gridDefinitionTemplateNumber not in [50,51,52,53,100,120,1000,1200]: self.nx = self.gridDefinitionTemplate[7] self.ny = self.gridDefinitionTemplate[8] if not reggrid and self.gridDefinitionTemplateNumber == 40: # 'reduced' gaussian grid. self.ny = self.gridDefinitionTemplate[8] if self.gridDefinitionTemplateNumber in [0,1,203,205,32768,32769]: # regular or rotated lat/lon grid scalefact = float(self.gridDefinitionTemplate[9]) divisor = float(self.gridDefinitionTemplate[10]) if scalefact == 0: scalefact = 1. if divisor <= 0: divisor = 1.e6 self.latitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[11]/divisor self.longitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[12]/divisor self.latitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[14]/divisor self.longitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[15]/divisor self.gridlengthXDirection = scalefact*self.gridDefinitionTemplate[16]/divisor self.gridlengthYDirection = scalefact*self.gridDefinitionTemplate[17]/divisor if self.latitudeFirstGridpoint > self.latitudeLastGridpoint: self.gridlengthYDirection = -self.gridlengthYDirection if self.longitudeFirstGridpoint > self.longitudeLastGridpoint: self.gridlengthXDirection = -self.gridlengthXDirection self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[18],output=list)[0:4] if self.gridDefinitionTemplateNumber == 1: self.latitudeSouthernPole = scalefact*self.gridDefinitionTemplate[19]/divisor self.longitudeSouthernPole = scalefact*self.gridDefinitionTemplate[20]/divisor self.anglePoleRotation = self.gridDefinitionTemplate[21] elif self.gridDefinitionTemplateNumber == 10: # mercator self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6 self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6 self.latitudeLastGridpoint = self.gridDefinitionTemplate[13]/1.e6 self.longitudeLastGridpoint = self.gridDefinitionTemplate[14]/1.e6 self.gridlengthXDirection = self.gridDefinitionTemplate[17]/1.e3 self.gridlengthYDirection= self.gridDefinitionTemplate[18]/1.e3 self.proj4_lat_ts = self.gridDefinitionTemplate[12]/1.e6 self.proj4_lon_0 = 0.5*(self.longitudeFirstGridpoint+self.longitudeLastGridpoint) self.proj4_proj = 'merc' self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[15],output=list)[0:4] elif self.gridDefinitionTemplateNumber == 20: # stereographic projflag = _int2bin(self.gridDefinitionTemplate[16],output=list)[0] self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6 self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6 self.proj4_lat_ts = self.gridDefinitionTemplate[12]/1.e6 if projflag == 0: self.proj4_lat_0 = 90 elif projflag == 1: self.proj4_lat_0 = -90 else: raise ValueError('Invalid projection center flag = %s'%projflag) self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6 self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000. self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000. self.proj4_proj = 'stere' self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[17],output=list)[0:4] elif self.gridDefinitionTemplateNumber == 30: # lambert conformal self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6 self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6 self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000. self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000. self.proj4_lat_1 = self.gridDefinitionTemplate[18]/1.e6 self.proj4_lat_2 = self.gridDefinitionTemplate[19]/1.e6 self.proj4_lat_0 = self.gridDefinitionTemplate[12]/1.e6 self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6 self.proj4_proj = 'lcc' self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[17],output=list)[0:4] elif self.gridDefinitionTemplateNumber == 31: # albers equal area. self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6 self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6 self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000. self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000. self.proj4_lat_1 = self.gridDefinitionTemplate[18]/1.e6 self.proj4_lat_2 = self.gridDefinitionTemplate[19]/1.e6 self.proj4_lat_0 = self.gridDefinitionTemplate[12]/1.e6 self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6 self.proj4_proj = 'aea' self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[17],output=list)[0:4] elif self.gridDefinitionTemplateNumber == 40 or self.gridDefinitionTemplateNumber == 41: # gaussian grid. scalefact = float(self.gridDefinitionTemplate[9]) divisor = float(self.gridDefinitionTemplate[10]) if scalefact == 0: scalefact = 1. if divisor <= 0: divisor = 1.e6 self.pointsBetweenPoleAndEquator = self.gridDefinitionTemplate[17] self.latitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[11]/divisor self.longitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[12]/divisor self.latitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[14]/divisor self.longitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[15]/divisor if reggrid: self.gridlengthXDirection = scalefact*self.gridDefinitionTemplate[16]/divisor if self.longitudeFirstGridpoint > self.longitudeLastGridpoint: self.gridlengthXDirection = -self.gridlengthXDirection self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[18],output=list)[0:4] if self.gridDefinitionTemplateNumber == 41: self.latitudeSouthernPole = scalefact*self.gridDefinitionTemplate[19]/divisor self.longitudeSouthernPole = scalefact*self.gridDefinitionTemplate[20]/divisor self.anglePoleRotation = self.gridDefinitionTemplate[21] elif self.gridDefinitionTemplateNumber == 50: # spectral coefficients. self.spectralFunctionParameters = (self.gridDefinitionTemplate[0],self.gridDefinitionTemplate[1],self.gridDefinitionTemplate[2]) self.scanModeFlags = [None,None,None,None] # doesn't apply elif self.gridDefinitionTemplateNumber == 90: # near-sided vertical perspective satellite projection self.proj4_lat_0 = self.gridDefinitionTemplate[9]/1.e6 self.proj4_lon_0 = self.gridDefinitionTemplate[10]/1.e6 self.proj4_h = self.earthMajorAxis * (self.gridDefinitionTemplate[18]/1.e6) dx = self.gridDefinitionTemplate[12] dy = self.gridDefinitionTemplate[13] # if lat_0 is equator, it's a geostationary view. if self.proj4_lat_0 == 0.: # if lat_0 is equator, it's a self.proj4_proj = 'geos' # general case of 'near-side perspective projection' (untested) else: self.proj4_proj = 'nsper' msg = 'only geostationary perspective is supported. lat/lon values returned by grid method may be incorrect.' warnings.warn(msg) # latitude of horizon on central meridian lonmax = 90.-(180./np.pi)*np.arcsin(self.earthMajorAxis/self.proj4_h) # longitude of horizon on equator latmax = 90.-(180./np.pi)*np.arcsin(self.earthMinorAxis/self.proj4_h) # truncate to nearest thousandth of a degree (to make sure # they aren't slightly over the horizon) latmax = int(1000*latmax)/1000. lonmax = int(1000*lonmax)/1000. # h is measured from surface of earth at equator. self.proj4_h = self.proj4_h - self.earthMajorAxis # width and height of visible projection P = pyproj.Proj(proj=self.proj4_proj,\ a=self.earthMajorAxis,b=self.earthMinorAxis,\ lat_0=0,lon_0=0,h=self.proj4_h) x1,y1 = P(0.,latmax); x2,y2 = P(lonmax,0.) width = 2*x2; height = 2*y1 self.gridlengthXDirection = width/dx self.gridlengthYDirection = height/dy self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[16],output=list)[0:4] elif self.gridDefinitionTemplateNumber == 110: # azimuthal equidistant. self.proj4_lat_0 = self.gridDefinitionTemplate[9]/1.e6 self.proj4_lon_0 = self.gridDefinitionTemplate[10]/1.e6 self.gridlengthXDirection = self.gridDefinitionTemplate[12]/1000. self.gridlengthYDirection = self.gridDefinitionTemplate[13]/1000. self.proj4_proj = 'aeqd' self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[15],output=list)[0:4] elif self.gridDefinitionTemplateNumber == 204: # curvilinear orthogonal self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[18],output=list)[0:4] # Missing value. #if self.dataRepresentationTemplateNumber in [2,3] and self.dataRepresentationTemplate[6] != 0: # self.missingValue = _getieeeint(self.dataRepresentationTemplate[7]) # if self.dataRepresentationTemplate[6] == 2: # self.missingValue2 = _getieeeint(self.dataRepresentationTemplate[8]) # Section 4 -- Product Definition _varinfo = tables.get_varname_from_table(self.indicatorSection[2], self.productDefinitionTemplate[0], self.productDefinitionTemplate[1]) self.varDescription = _varinfo[0] self.units = _varinfo[1] self.varName = _varinfo[2] self.generatingProcess = tables.get_value_from_table(self.productDefinitionTemplate[4],'generating_process') self.unitOfTimeRange = tables.get_value_from_table(self.productDefinitionTemplate[7],'4.4') self.leadTime = self.productDefinitionTemplate[8] _vals = tables.get_value_from_table(self.productDefinitionTemplate[9],'4.5') self.typeOfFirstFixedSurface = _vals[0] self.unitOfFirstFixedSurface = _vals[1] self.valueOfFristFixedSurface = self.productDefinitionTemplate[11]/(10.**self.productDefinitionTemplate[10]) _vals = tables.get_value_from_table(self.productDefinitionTemplate[12],'4.5') self.typeOfSecondFixedSurface = None if _vals[0] == 'Missing' else _vals[0] self.unitOfSecondFixedSurface = None if _vals[1] == 'unknown' else _vals[1] self.valueOfSecondFixedSurface = None if self.typeOfSecondFixedSurface is None else \ self.productDefinitionTemplate[14]/(10.**self.productDefinitionTemplate[13]) if self.productDefinitionTemplateNumber == 1: self.typeOfEnsembleForecast = tables.get_value_from_table(self.productDefinitionTemplate[15],'4.6') self.perturbationNumber = self.productDefinitionTemplate[16] self.numberOfEnsembleForecasts = self.productDefinitionTemplate[17] elif self.productDefinitionTemplateNumber == 2: self.typeOfDerivedForecast = tables.get_value_from_table(self.productDefinitionTemplate[15],'4.7') self.numberOfEnsembleForecasts = self.productDefinitionTemplate[16] elif self.productDefinitionTemplateNumber == 5: self.forecastProbabilityNumber = self.productDefinitionTemplate[15] self.totalNumberOfForecastProbabilities = self.productDefinitionTemplate[16] self.typeOfProbability = tables.get_value_from_table(self.productDefinitionTemplate[16],'4.9') self.thresholdLowerLimit = self.productDefinitionTemplate[18]/(10.**self.productDefinitionTemplate[17]) self.thresholdUpperLimit = self.productDefinitionTemplate[20]/(10.**self.productDefinitionTemplate[19]) elif self.productDefinitionTemplateNumber == 6: self.percentileValue = self.productDefinitionTemplate[15] elif self.productDefinitionTemplateNumber == 8: self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[15] self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[16] self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[17] self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[18] self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[19] self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[20] self.numberOfTimeRanges = self.productDefinitionTemplate[21] self.numberOfMissingValues = self.productDefinitionTemplate[22] self.statisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[23],'4.10') self.typeOfTimeIncrementOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[24],'4.11') self.unitOfTimeRangeOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[25],'4.4') self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[26] self.unitOfTimeRangeOfSuccessiveFields = tables.get_value_from_table(self.productDefinitionTemplate[27],'4.4') self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[28] elif self.productDefinitionTemplateNumber == 9: self.forecastProbabilityNumber = self.productDefinitionTemplate[15] self.totalNumberOfForecastProbabilities = self.productDefinitionTemplate[16] self.typeOfProbability = tables.get_value_from_table(self.productDefinitionTemplate[16],'4.9') self.thresholdLowerLimit = self.productDefinitionTemplate[18]/(10.**self.productDefinitionTemplate[17]) self.thresholdUpperLimit = self.productDefinitionTemplate[20]/(10.**self.productDefinitionTemplate[19]) self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[21] self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[22] self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[23] self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[24] self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[25] self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[26] self.numberOfTimeRanges = self.productDefinitionTemplate[27] self.numberOfMissingValues = self.productDefinitionTemplate[28] self.statisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[29],'4.10') self.typeOfTimeIncrementOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[30],'4.11') self.unitOfTimeRangeOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[31],'4.4') self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[32] self.unitOfTimeRangeOfSuccessiveFields = tables.get_value_from_table(self.productDefinitionTemplate[33],'4.4') self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[34] elif self.productDefinitionTemplateNumber == 10: self.percentileValue = self.productDefinitionTemplate[15] self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[16] self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[17] self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[18] self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[19] self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[20] self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[21] self.numberOfTimeRanges = self.productDefinitionTemplate[22] self.numberOfMissingValues = self.productDefinitionTemplate[23] self.statisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[24],'4.10') self.typeOfTimeIncrementOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[25],'4.11') self.unitOfTimeRangeOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[26],'4.4') self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[27] self.unitOfTimeRangeOfSuccessiveFields = tables.get_value_from_table(self.productDefinitionTemplate[28],'4.4') self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[29] elif self.productDefinitionTemplateNumber == 11: self.typeOfEnsembleForecast = tables.get_value_from_table(self.productDefinitionTemplate[15],'4.6') self.perturbationNumber = self.productDefinitionTemplate[16] self.numberOfEnsembleForecasts = self.productDefinitionTemplate[17] self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[18] self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[19] self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[20] self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[21] self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[22] self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[23] self.numberOfTimeRanges = self.productDefinitionTemplate[24] self.numberOfMissingValues = self.productDefinitionTemplate[25] self.statisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[26],'4.10') self.typeOfTimeIncrementOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[27],'4.11') self.unitOfTimeRangeOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[28],'4.4') self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[29] self.unitOfTimeRangeOfSuccessiveFields = tables.get_value_from_table(self.productDefinitionTemplate[30],'4.4') self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[31] elif self.productDefinitionTemplateNumber == 12: self.typeOfDerivedForecast = tables.get_value_from_table(self.productDefinitionTemplate[15],'4.7') self.numberOfEnsembleForecasts = self.productDefinitionTemplate[16] self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[17] self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[18] self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[19] self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[20] self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[21] self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[22] self.numberOfTimeRanges = self.productDefinitionTemplate[23] self.numberOfMissingValues = self.productDefinitionTemplate[24] self.statisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[25],'4.10') self.typeOfTimeIncrementOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[26],'4.11') self.unitOfTimeRangeOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[27],'4.4') self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[28] self.unitOfTimeRangeOfSuccessiveFields = tables.get_value_from_table(self.productDefinitionTemplate[29],'4.4') self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[30] # Section 5 -- Data Representation if self.dataRepresentationTemplateNumber == 0: # Grid Point Data -- Simple Packing self.refValue = _getieeeint(self.dataRepresentationTemplate[0]) self.binScaleFactor = self.dataRepresentationTemplate[1] self.decScaleFactor = self.dataRepresentationTemplate[2] self.nBitsPacking = self.dataRepresentationTemplate[3] self.typeOfValues = tables.get_value_from_table(self.dataRepresentationTemplate[3],'5.1') elif self.dataRepresentationTemplateNumber == 2: # Grid Point Data -- Complex Packing self.refValue = _getieeeint(self.dataRepresentationTemplate[0]) self.binScaleFactor = self.dataRepresentationTemplate[1] self.decScaleFactor = self.dataRepresentationTemplate[2] self.nBitsPacking = self.dataRepresentationTemplate[3] self.typeOfValues = tables.get_value_from_table(self.dataRepresentationTemplate[4],'5.1') self.groupSplitMethod = tables.get_value_from_table(self.dataRepresentationTemplate[5],'5.4') self.typeOfMissingValue = tables.get_value_from_table(self.dataRepresentationTemplate[6],'5.5') self.priMissingValue = _getieeeint(self.dataRepresentationTemplate[7]) if self.dataRepresentationTemplate[6] in [1,2] else None self.secMissingValue = _getieeeint(self.dataRepresentationTemplate[8]) if self.dataRepresentationTemplate[6] in [1,2] else None self.nGroups = self.dataRepresentationTemplate[9] self.refGroupWidth = self.dataRepresentationTemplate[10] self.nBitsGroupWidth = self.dataRepresentationTemplate[11] self.refGroupLength = self.dataRepresentationTemplate[12] self.groupLengthIncrement = self.dataRepresentationTemplate[13] self.lengthOfLastGroup = self.dataRepresentationTemplate[14] self.nBitsScaledGroupLength = self.dataRepresentationTemplate[15] elif self.dataRepresentationTemplateNumber == 3: # Grid Point Data -- Complex Packing and Spatial Differencing self.refValue = _getieeeint(self.dataRepresentationTemplate[0]) self.binScaleFactor = self.dataRepresentationTemplate[1] self.decScaleFactor = self.dataRepresentationTemplate[2] self.nBitsPacking = self.dataRepresentationTemplate[3] self.typeOfValues = tables.get_value_from_table(self.dataRepresentationTemplate[4],'5.1') self.groupSplitMethod = tables.get_value_from_table(self.dataRepresentationTemplate[5],'5.4') self.typeOfMissingValue = tables.get_value_from_table(self.dataRepresentationTemplate[6],'5.5') self.priMissingValue = _getieeeint(self.dataRepresentationTemplate[7]) if self.dataRepresentationTemplate[6] in [1,2] else None self.secMissingValue = _getieeeint(self.dataRepresentationTemplate[8]) if self.dataRepresentationTemplate[6] in [1,2] else None self.nGroups = self.dataRepresentationTemplate[9] self.refGroupWidth = self.dataRepresentationTemplate[10] self.nBitsGroupWidth = self.dataRepresentationTemplate[11] self.refGroupLength = self.dataRepresentationTemplate[12] self.groupLengthIncrement = self.dataRepresentationTemplate[13] self.lengthOfLastGroup = self.dataRepresentationTemplate[14] self.nBitsScaledGroupLength = self.dataRepresentationTemplate[15] self.spatialDifferenceOrder = tables.get_value_from_table(self.dataRepresentationTemplate[16],'5.6') self.nBytesSpatialDifference = self.dataRepresentationTemplate[17] elif self.dataRepresentationTemplateNumber == 4: # Grid Point Data - IEEE Floating Point Data self.precision = tables.get_value_from_table(self.dataRepresentationTemplate[0],'5.7') elif self.dataRepresentationTemplateNumber == 40: # Grid Point Data - JPEG2000 Compression self.refValue = _getieeeint(self.dataRepresentationTemplate[0]) self.binScaleFactor = self.dataRepresentationTemplate[1] self.decScaleFactor = self.dataRepresentationTemplate[2] self.nBitsPacking = self.dataRepresentationTemplate[3] self.typeOfValues = tables.get_value_from_table(self.dataRepresentationTemplate[4],'5.1') self.typeOfCompression = tables.get_value_from_table(self.dataRepresentationTemplate[5],'5.40') self.targetCompressionRatio = self.dataRepresentationTemplate[6] elif self.dataRepresentationTemplateNumber == 41: # Grid Point Data - PNG Compression self.refValue = _getieeeint(self.dataRepresentationTemplate[0]) self.binScaleFactor = self.dataRepresentationTemplate[1] self.decScaleFactor = self.dataRepresentationTemplate[2] self.nBitsPacking = self.dataRepresentationTemplate[3] self.typeOfValues = tables.get_value_from_table(self.dataRepresentationTemplate[4],'5.1') def data(self,fill_value=DEFAULT_FILL_VALUE,masked_array=True,expand=True,order=None): """ Returns an unpacked data grid. Parameters ---------- **`fill_value : float, optional`** Missing or masked data is filled with this value or default value given by `DEFAULT_FILL_VALUE`. **`masked_array : bool, optional`** When `True` [DEFAULT], return masked array if there is bitmap for missing or masked data. **`expand : bool, optional`** When `True` [DEFAULT], ECMWF 'reduced' gaussian grids are expanded to regular gaussian grids. **`order : int, optional`** 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. Returns ------- **`numpy.ndarray`** A numpy.ndarray with dtype=numpy.float32 with dimensions (ny,nx). """ if not hasattr(self,'scanModeFlags'): raise ValueError('Unsupported grid definition template number %s'%self.gridDefinitionTemplateNumber) else: if self.scanModeFlags[2]: storageorder='F' else: storageorder='C' if order is None: if (self.dataRepresentationTemplateNumber in [2,3] and self.dataRepresentationTemplate[6] != 0) or self.bitMapFlag == 0: order = 0 else: order = 1 drtnum = self.dataRepresentationTemplateNumber drtmpl = np.asarray(self.dataRepresentationTemplate,dtype=np.int32) gdtnum = self.gridDefinitionTemplateNumber gdtmpl = np.asarray(self.gridDefinitionTemplate,dtype=np.int32) ndpts = self.numberOfDataPoints gdsinfo = self.gridDefinitionInfo ngrdpts = gdsinfo[1] ipos = self._datapos fld1 = g2clib.unpack7(self._msg,gdtnum,gdtmpl,drtnum,drtmpl,ndpts,ipos,np.empty,storageorder=storageorder) # Apply bitmap. if self.bitMapFlag == 0: fld = fill_value*np.ones(ngrdpts,'f') np.put(fld,np.nonzero(self.bitMap),fld1) if masked_array: fld = ma.masked_values(fld,fill_value) # Missing values instead of bitmap elif masked_array and hasattr(self,'priMissingValue'): if hasattr(self,'secMissingValue'): mask = np.logical_or(fld1==self.priMissingValue,fld1==self.secMissingValue) else: mask = fld1 == self.priMissingValue fld = ma.array(fld1,mask=mask) else: fld = fld1 if self.nx is not None and self.ny is not None: # Rectangular grid. if ma.isMA(fld): fld = ma.reshape(fld,(self.ny,self.nx)) else: fld = np.reshape(fld,(self.ny,self.nx)) else: if gdsinfo[2] and gdtnum == 40: # ECMWF 'reduced' global gaussian grid. if expand: from redtoreg import _redtoreg self.nx = 2*self.ny lonsperlat = self.defList if ma.isMA(fld): fld = ma.filled(fld) fld = _redtoreg(self.nx,lonsperlat.astype(np.long),\ fld.astype(np.double),fill_value) fld = ma.masked_values(fld,fill_value) else: fld = _redtoreg(self.nx,lonsperlat.astype(np.long),\ fld.astype(np.double),fill_value) # Check scan modes for rect grids. if self.nx is not None and self.ny is not None: if self.scanModeFlags[3]: fldsave = fld.astype('f') # casting makes a copy fld[1::2,:] = fldsave[1::2,::-1] return fld def __repr__(self): """ """ strings = [] keys = self.__dict__.keys() for k in keys: if not k.startswith('_'): strings.append('%s = %s\n'%(k,self.__dict__[k])) return ''.join(strings)
Methods
def __init__(self, msg, ref=None, num=-1)
-
Class Constructor
Parameters
msg : bytes
Binary string representing the GRIB2 Message read from file.
ref : grib2io.open, optional
Holds the reference to the where this GRIB2 message originated from (i.e. the input file). This allow for interaction with the instance of
open
.num : int, optional
Set to the GRIB2 Message number.
Expand source code
def __init__(self, msg, ref=None, num=-1): """ Class Constructor Parameters ---------- **`msg : bytes`** Binary string representing the GRIB2 Message read from file. **`ref : grib2io.open, optional`** Holds the reference to the where this GRIB2 message originated from (i.e. the input file). This allow for interaction with the instance of `grib2io.open`. **`num : int, optional`** Set to the GRIB2 Message number. """ self._msg = msg self._pos = 0 self._ref = ref self._datapos = 0 self._msgnum = num # Section 0, Indicator Section self.indicatorSection = [] self.indicatorSection.append(struct.unpack('>4s',self._msg[0:4])[0]) self.indicatorSection.append(struct.unpack('>H',self._msg[4:6])[0]) self.indicatorSection.append(self._msg[6]) self.indicatorSection.append(self._msg[7]) self.indicatorSection.append(struct.unpack('>Q',self._msg[8:16])[0]) self.discipline = tables.get_value_from_table(self.indicatorSection[2],'0.0') self._pos = 16 # Section 1, Indentification Section. self.identificationSection,self._pos = g2clib.unpack1(self._msg,self._pos,np.empty) self.identificationSection = self.identificationSection.tolist() self.originatingCenter = tables.get_value_from_table(self.identificationSection[0],'originating_centers') self.originatingSubCenter = tables.get_value_from_table(self.identificationSection[1],'originating_subcenters') self.masterTableInfo = tables.get_value_from_table(self.identificationSection[2],'1.0') self.localTableInfo = tables.get_value_from_table(self.identificationSection[3],'1.1') self.significanceOfReferenceTime = tables.get_value_from_table(self.identificationSection[4],'1.2') self.year = self.identificationSection[5] self.month = self.identificationSection[6] self.day = self.identificationSection[7] self.hour = self.identificationSection[8] self.minute = self.identificationSection[9] self.second = self.identificationSection[10] self.intreferenceDate = (self.year*1000000)+(self.month*10000)+\ (self.day*100)+self.hour self.dtReferenceDate = datetime.datetime(self.year,self.month,self.day, hour=self.hour,minute=self.minute, second=self.second) self.productionStatus = tables.get_value_from_table(self.identificationSection[11],'1.3') self.typeOfData = tables.get_value_from_table(self.identificationSection[12],'1.4') # After Section 1, perform rest of GRIB2 Decoding inside while loop # to account for sub-messages. while True: if self._msg[self._pos:self._pos+4].decode('ascii','ignore') == '7777': break # Read the length and section number. sectlen = struct.unpack('>i',self._msg[self._pos:self._pos+4])[0] sectnum = struct.unpack('>B',self._msg[self._pos+4:self._pos+5])[0] # Handle submessage accordingly. if self._ref._index['isSubmessage'][num]: if sectnum == self._ref._index['submessageBeginSection'][self._msgnum]: self._pos = self._ref._index['submessageOffset'][self._msgnum] # Section 2, Local Use Section. self.localUseSection = None if sectnum == 2: _lus = self._msg[self._pos+5:self._pos+sectlen] self._pos += sectlen self.localUseSection = _lus # Section 3, Grid Definition Section. elif sectnum == 3: _gds,_gdtn,_deflist,self._pos = g2clib.unpack3(self._msg,self._pos,np.empty) self.gridDefinitionInfo = _gds.tolist() self.gridDefinitionTemplateNumber = int(_gds[4]) self.gridDefinitionTemplate = _gdtn.tolist() self.defList = _deflist.tolist() self.gridDefinitionTemplateNumberInfo = tables.get_value_from_table(self.gridDefinitionTemplateNumber,'3.1') # Section 4, Product Definition Section. elif sectnum == 4: _pdt,_pdtn,_coordlst,self._pos = g2clib.unpack4(self._msg,self._pos,np.empty) self.productDefinitionTemplate = _pdt.tolist() self.productDefinitionTemplateNumber = int(_pdtn) self.coordinateList = _coordlst.tolist() # Section 5, Data Representation Section. elif sectnum == 5: _drt,_drtn,_npts,self._pos = g2clib.unpack5(self._msg,self._pos,np.empty) self.dataRepresentationTemplate = _drt.tolist() self.dataRepresentationTemplateNumber = int(_drtn) self.numberOfDataPoints = _npts # Section 6, Bitmap Section. elif sectnum == 6: _bmap,_bmapflag = g2clib.unpack6(self._msg,self.gridDefinitionInfo[1],self._pos,np.empty) self.bitMapFlag = _bmapflag if self.bitMapFlag == 0: self.bitMap = _bmap elif self.bitMapFlag == 254: # Value of 254 says to use a previous bitmap in the file. self.bitMapFlag = 0 self.bitMap = self._ref._index['bitMap'][self._msgnum] self._pos += sectlen # IMPORTANT: This is here because g2clib.unpack6() does not return updated position. # Section 7, Data Section (data unpacked when data() method is invoked). elif sectnum == 7: self._datapos = self._pos self._pos += sectlen # REMOVE THIS WHEN UNPACKING DATA IS IMPLEMENTED else: errmsg = 'Unknown section number = %i' % sectnum raise ValueError(errmsg) # Section 3 -- Grid Definition reggrid = self.gridDefinitionInfo[2] == 0 # self.gridDefinitionInfo[2]=0 means regular 2-d grid if self.gridDefinitionTemplateNumber in [50,51,52,1200]: earthparams = None else: earthparams = tables.earth_params[str(self.gridDefinitionTemplate[0])] if earthparams['shape'] == 'spherical': if earthparams['radius'] is None: self.earthRadius = self.gridDefinitionTemplate[2]/(10.**self.gridDefinitionTemplate[1]) else: self.earthRadius = earthparams['radius'] self.earthMajorAxis = None self.earthMinorAxis = None elif earthparams['shape'] == 'oblateSpheroid': if earthparams['radius'] is None and earthparams['major_axis'] is None and earthparams['minor_axis'] is None: self.earthRadius = self.gridDefinitionTemplate[2]/(10.**self.gridDefinitionTemplate[1]) self.earthMajorAxis = self.gridDefinitionTemplate[4]/(10.**self.gridDefinitionTemplate[3]) self.earthMinorAxis = self.gridDefinitionTemplate[6]/(10.**self.gridDefinitionTemplate[5]) else: self.earthRadius = earthparams['radius'] self.earthMajorAxis = earthparams['major_axis'] self.earthMinorAxis = earthparams['minor_axis'] if reggrid and self.gridDefinitionTemplateNumber not in [50,51,52,53,100,120,1000,1200]: self.nx = self.gridDefinitionTemplate[7] self.ny = self.gridDefinitionTemplate[8] if not reggrid and self.gridDefinitionTemplateNumber == 40: # 'reduced' gaussian grid. self.ny = self.gridDefinitionTemplate[8] if self.gridDefinitionTemplateNumber in [0,1,203,205,32768,32769]: # regular or rotated lat/lon grid scalefact = float(self.gridDefinitionTemplate[9]) divisor = float(self.gridDefinitionTemplate[10]) if scalefact == 0: scalefact = 1. if divisor <= 0: divisor = 1.e6 self.latitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[11]/divisor self.longitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[12]/divisor self.latitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[14]/divisor self.longitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[15]/divisor self.gridlengthXDirection = scalefact*self.gridDefinitionTemplate[16]/divisor self.gridlengthYDirection = scalefact*self.gridDefinitionTemplate[17]/divisor if self.latitudeFirstGridpoint > self.latitudeLastGridpoint: self.gridlengthYDirection = -self.gridlengthYDirection if self.longitudeFirstGridpoint > self.longitudeLastGridpoint: self.gridlengthXDirection = -self.gridlengthXDirection self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[18],output=list)[0:4] if self.gridDefinitionTemplateNumber == 1: self.latitudeSouthernPole = scalefact*self.gridDefinitionTemplate[19]/divisor self.longitudeSouthernPole = scalefact*self.gridDefinitionTemplate[20]/divisor self.anglePoleRotation = self.gridDefinitionTemplate[21] elif self.gridDefinitionTemplateNumber == 10: # mercator self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6 self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6 self.latitudeLastGridpoint = self.gridDefinitionTemplate[13]/1.e6 self.longitudeLastGridpoint = self.gridDefinitionTemplate[14]/1.e6 self.gridlengthXDirection = self.gridDefinitionTemplate[17]/1.e3 self.gridlengthYDirection= self.gridDefinitionTemplate[18]/1.e3 self.proj4_lat_ts = self.gridDefinitionTemplate[12]/1.e6 self.proj4_lon_0 = 0.5*(self.longitudeFirstGridpoint+self.longitudeLastGridpoint) self.proj4_proj = 'merc' self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[15],output=list)[0:4] elif self.gridDefinitionTemplateNumber == 20: # stereographic projflag = _int2bin(self.gridDefinitionTemplate[16],output=list)[0] self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6 self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6 self.proj4_lat_ts = self.gridDefinitionTemplate[12]/1.e6 if projflag == 0: self.proj4_lat_0 = 90 elif projflag == 1: self.proj4_lat_0 = -90 else: raise ValueError('Invalid projection center flag = %s'%projflag) self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6 self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000. self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000. self.proj4_proj = 'stere' self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[17],output=list)[0:4] elif self.gridDefinitionTemplateNumber == 30: # lambert conformal self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6 self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6 self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000. self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000. self.proj4_lat_1 = self.gridDefinitionTemplate[18]/1.e6 self.proj4_lat_2 = self.gridDefinitionTemplate[19]/1.e6 self.proj4_lat_0 = self.gridDefinitionTemplate[12]/1.e6 self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6 self.proj4_proj = 'lcc' self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[17],output=list)[0:4] elif self.gridDefinitionTemplateNumber == 31: # albers equal area. self.latitudeFirstGridpoint = self.gridDefinitionTemplate[9]/1.e6 self.longitudeFirstGridpoint = self.gridDefinitionTemplate[10]/1.e6 self.gridlengthXDirection = self.gridDefinitionTemplate[14]/1000. self.gridlengthYDirection = self.gridDefinitionTemplate[15]/1000. self.proj4_lat_1 = self.gridDefinitionTemplate[18]/1.e6 self.proj4_lat_2 = self.gridDefinitionTemplate[19]/1.e6 self.proj4_lat_0 = self.gridDefinitionTemplate[12]/1.e6 self.proj4_lon_0 = self.gridDefinitionTemplate[13]/1.e6 self.proj4_proj = 'aea' self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[17],output=list)[0:4] elif self.gridDefinitionTemplateNumber == 40 or self.gridDefinitionTemplateNumber == 41: # gaussian grid. scalefact = float(self.gridDefinitionTemplate[9]) divisor = float(self.gridDefinitionTemplate[10]) if scalefact == 0: scalefact = 1. if divisor <= 0: divisor = 1.e6 self.pointsBetweenPoleAndEquator = self.gridDefinitionTemplate[17] self.latitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[11]/divisor self.longitudeFirstGridpoint = scalefact*self.gridDefinitionTemplate[12]/divisor self.latitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[14]/divisor self.longitudeLastGridpoint = scalefact*self.gridDefinitionTemplate[15]/divisor if reggrid: self.gridlengthXDirection = scalefact*self.gridDefinitionTemplate[16]/divisor if self.longitudeFirstGridpoint > self.longitudeLastGridpoint: self.gridlengthXDirection = -self.gridlengthXDirection self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[18],output=list)[0:4] if self.gridDefinitionTemplateNumber == 41: self.latitudeSouthernPole = scalefact*self.gridDefinitionTemplate[19]/divisor self.longitudeSouthernPole = scalefact*self.gridDefinitionTemplate[20]/divisor self.anglePoleRotation = self.gridDefinitionTemplate[21] elif self.gridDefinitionTemplateNumber == 50: # spectral coefficients. self.spectralFunctionParameters = (self.gridDefinitionTemplate[0],self.gridDefinitionTemplate[1],self.gridDefinitionTemplate[2]) self.scanModeFlags = [None,None,None,None] # doesn't apply elif self.gridDefinitionTemplateNumber == 90: # near-sided vertical perspective satellite projection self.proj4_lat_0 = self.gridDefinitionTemplate[9]/1.e6 self.proj4_lon_0 = self.gridDefinitionTemplate[10]/1.e6 self.proj4_h = self.earthMajorAxis * (self.gridDefinitionTemplate[18]/1.e6) dx = self.gridDefinitionTemplate[12] dy = self.gridDefinitionTemplate[13] # if lat_0 is equator, it's a geostationary view. if self.proj4_lat_0 == 0.: # if lat_0 is equator, it's a self.proj4_proj = 'geos' # general case of 'near-side perspective projection' (untested) else: self.proj4_proj = 'nsper' msg = 'only geostationary perspective is supported. lat/lon values returned by grid method may be incorrect.' warnings.warn(msg) # latitude of horizon on central meridian lonmax = 90.-(180./np.pi)*np.arcsin(self.earthMajorAxis/self.proj4_h) # longitude of horizon on equator latmax = 90.-(180./np.pi)*np.arcsin(self.earthMinorAxis/self.proj4_h) # truncate to nearest thousandth of a degree (to make sure # they aren't slightly over the horizon) latmax = int(1000*latmax)/1000. lonmax = int(1000*lonmax)/1000. # h is measured from surface of earth at equator. self.proj4_h = self.proj4_h - self.earthMajorAxis # width and height of visible projection P = pyproj.Proj(proj=self.proj4_proj,\ a=self.earthMajorAxis,b=self.earthMinorAxis,\ lat_0=0,lon_0=0,h=self.proj4_h) x1,y1 = P(0.,latmax); x2,y2 = P(lonmax,0.) width = 2*x2; height = 2*y1 self.gridlengthXDirection = width/dx self.gridlengthYDirection = height/dy self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[16],output=list)[0:4] elif self.gridDefinitionTemplateNumber == 110: # azimuthal equidistant. self.proj4_lat_0 = self.gridDefinitionTemplate[9]/1.e6 self.proj4_lon_0 = self.gridDefinitionTemplate[10]/1.e6 self.gridlengthXDirection = self.gridDefinitionTemplate[12]/1000. self.gridlengthYDirection = self.gridDefinitionTemplate[13]/1000. self.proj4_proj = 'aeqd' self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[15],output=list)[0:4] elif self.gridDefinitionTemplateNumber == 204: # curvilinear orthogonal self.scanModeFlags = _int2bin(self.gridDefinitionTemplate[18],output=list)[0:4] # Missing value. #if self.dataRepresentationTemplateNumber in [2,3] and self.dataRepresentationTemplate[6] != 0: # self.missingValue = _getieeeint(self.dataRepresentationTemplate[7]) # if self.dataRepresentationTemplate[6] == 2: # self.missingValue2 = _getieeeint(self.dataRepresentationTemplate[8]) # Section 4 -- Product Definition _varinfo = tables.get_varname_from_table(self.indicatorSection[2], self.productDefinitionTemplate[0], self.productDefinitionTemplate[1]) self.varDescription = _varinfo[0] self.units = _varinfo[1] self.varName = _varinfo[2] self.generatingProcess = tables.get_value_from_table(self.productDefinitionTemplate[4],'generating_process') self.unitOfTimeRange = tables.get_value_from_table(self.productDefinitionTemplate[7],'4.4') self.leadTime = self.productDefinitionTemplate[8] _vals = tables.get_value_from_table(self.productDefinitionTemplate[9],'4.5') self.typeOfFirstFixedSurface = _vals[0] self.unitOfFirstFixedSurface = _vals[1] self.valueOfFristFixedSurface = self.productDefinitionTemplate[11]/(10.**self.productDefinitionTemplate[10]) _vals = tables.get_value_from_table(self.productDefinitionTemplate[12],'4.5') self.typeOfSecondFixedSurface = None if _vals[0] == 'Missing' else _vals[0] self.unitOfSecondFixedSurface = None if _vals[1] == 'unknown' else _vals[1] self.valueOfSecondFixedSurface = None if self.typeOfSecondFixedSurface is None else \ self.productDefinitionTemplate[14]/(10.**self.productDefinitionTemplate[13]) if self.productDefinitionTemplateNumber == 1: self.typeOfEnsembleForecast = tables.get_value_from_table(self.productDefinitionTemplate[15],'4.6') self.perturbationNumber = self.productDefinitionTemplate[16] self.numberOfEnsembleForecasts = self.productDefinitionTemplate[17] elif self.productDefinitionTemplateNumber == 2: self.typeOfDerivedForecast = tables.get_value_from_table(self.productDefinitionTemplate[15],'4.7') self.numberOfEnsembleForecasts = self.productDefinitionTemplate[16] elif self.productDefinitionTemplateNumber == 5: self.forecastProbabilityNumber = self.productDefinitionTemplate[15] self.totalNumberOfForecastProbabilities = self.productDefinitionTemplate[16] self.typeOfProbability = tables.get_value_from_table(self.productDefinitionTemplate[16],'4.9') self.thresholdLowerLimit = self.productDefinitionTemplate[18]/(10.**self.productDefinitionTemplate[17]) self.thresholdUpperLimit = self.productDefinitionTemplate[20]/(10.**self.productDefinitionTemplate[19]) elif self.productDefinitionTemplateNumber == 6: self.percentileValue = self.productDefinitionTemplate[15] elif self.productDefinitionTemplateNumber == 8: self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[15] self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[16] self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[17] self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[18] self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[19] self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[20] self.numberOfTimeRanges = self.productDefinitionTemplate[21] self.numberOfMissingValues = self.productDefinitionTemplate[22] self.statisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[23],'4.10') self.typeOfTimeIncrementOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[24],'4.11') self.unitOfTimeRangeOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[25],'4.4') self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[26] self.unitOfTimeRangeOfSuccessiveFields = tables.get_value_from_table(self.productDefinitionTemplate[27],'4.4') self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[28] elif self.productDefinitionTemplateNumber == 9: self.forecastProbabilityNumber = self.productDefinitionTemplate[15] self.totalNumberOfForecastProbabilities = self.productDefinitionTemplate[16] self.typeOfProbability = tables.get_value_from_table(self.productDefinitionTemplate[16],'4.9') self.thresholdLowerLimit = self.productDefinitionTemplate[18]/(10.**self.productDefinitionTemplate[17]) self.thresholdUpperLimit = self.productDefinitionTemplate[20]/(10.**self.productDefinitionTemplate[19]) self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[21] self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[22] self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[23] self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[24] self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[25] self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[26] self.numberOfTimeRanges = self.productDefinitionTemplate[27] self.numberOfMissingValues = self.productDefinitionTemplate[28] self.statisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[29],'4.10') self.typeOfTimeIncrementOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[30],'4.11') self.unitOfTimeRangeOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[31],'4.4') self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[32] self.unitOfTimeRangeOfSuccessiveFields = tables.get_value_from_table(self.productDefinitionTemplate[33],'4.4') self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[34] elif self.productDefinitionTemplateNumber == 10: self.percentileValue = self.productDefinitionTemplate[15] self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[16] self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[17] self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[18] self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[19] self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[20] self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[21] self.numberOfTimeRanges = self.productDefinitionTemplate[22] self.numberOfMissingValues = self.productDefinitionTemplate[23] self.statisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[24],'4.10') self.typeOfTimeIncrementOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[25],'4.11') self.unitOfTimeRangeOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[26],'4.4') self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[27] self.unitOfTimeRangeOfSuccessiveFields = tables.get_value_from_table(self.productDefinitionTemplate[28],'4.4') self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[29] elif self.productDefinitionTemplateNumber == 11: self.typeOfEnsembleForecast = tables.get_value_from_table(self.productDefinitionTemplate[15],'4.6') self.perturbationNumber = self.productDefinitionTemplate[16] self.numberOfEnsembleForecasts = self.productDefinitionTemplate[17] self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[18] self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[19] self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[20] self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[21] self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[22] self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[23] self.numberOfTimeRanges = self.productDefinitionTemplate[24] self.numberOfMissingValues = self.productDefinitionTemplate[25] self.statisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[26],'4.10') self.typeOfTimeIncrementOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[27],'4.11') self.unitOfTimeRangeOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[28],'4.4') self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[29] self.unitOfTimeRangeOfSuccessiveFields = tables.get_value_from_table(self.productDefinitionTemplate[30],'4.4') self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[31] elif self.productDefinitionTemplateNumber == 12: self.typeOfDerivedForecast = tables.get_value_from_table(self.productDefinitionTemplate[15],'4.7') self.numberOfEnsembleForecasts = self.productDefinitionTemplate[16] self.yearOfEndOfTimePeriod = self.productDefinitionTemplate[17] self.monthOfEndOfTimePeriod = self.productDefinitionTemplate[18] self.dayOfEndOfTimePeriod = self.productDefinitionTemplate[19] self.hourOfEndOfTimePeriod = self.productDefinitionTemplate[20] self.minuteOfEndOfTimePeriod = self.productDefinitionTemplate[21] self.secondOfEndOfTimePeriod = self.productDefinitionTemplate[22] self.numberOfTimeRanges = self.productDefinitionTemplate[23] self.numberOfMissingValues = self.productDefinitionTemplate[24] self.statisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[25],'4.10') self.typeOfTimeIncrementOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[26],'4.11') self.unitOfTimeRangeOfStatisticalProcess = tables.get_value_from_table(self.productDefinitionTemplate[27],'4.4') self.timeRangeOfStatisticalProcess = self.productDefinitionTemplate[28] self.unitOfTimeRangeOfSuccessiveFields = tables.get_value_from_table(self.productDefinitionTemplate[29],'4.4') self.timeIncrementOfSuccessiveFields = self.productDefinitionTemplate[30] # Section 5 -- Data Representation if self.dataRepresentationTemplateNumber == 0: # Grid Point Data -- Simple Packing self.refValue = _getieeeint(self.dataRepresentationTemplate[0]) self.binScaleFactor = self.dataRepresentationTemplate[1] self.decScaleFactor = self.dataRepresentationTemplate[2] self.nBitsPacking = self.dataRepresentationTemplate[3] self.typeOfValues = tables.get_value_from_table(self.dataRepresentationTemplate[3],'5.1') elif self.dataRepresentationTemplateNumber == 2: # Grid Point Data -- Complex Packing self.refValue = _getieeeint(self.dataRepresentationTemplate[0]) self.binScaleFactor = self.dataRepresentationTemplate[1] self.decScaleFactor = self.dataRepresentationTemplate[2] self.nBitsPacking = self.dataRepresentationTemplate[3] self.typeOfValues = tables.get_value_from_table(self.dataRepresentationTemplate[4],'5.1') self.groupSplitMethod = tables.get_value_from_table(self.dataRepresentationTemplate[5],'5.4') self.typeOfMissingValue = tables.get_value_from_table(self.dataRepresentationTemplate[6],'5.5') self.priMissingValue = _getieeeint(self.dataRepresentationTemplate[7]) if self.dataRepresentationTemplate[6] in [1,2] else None self.secMissingValue = _getieeeint(self.dataRepresentationTemplate[8]) if self.dataRepresentationTemplate[6] in [1,2] else None self.nGroups = self.dataRepresentationTemplate[9] self.refGroupWidth = self.dataRepresentationTemplate[10] self.nBitsGroupWidth = self.dataRepresentationTemplate[11] self.refGroupLength = self.dataRepresentationTemplate[12] self.groupLengthIncrement = self.dataRepresentationTemplate[13] self.lengthOfLastGroup = self.dataRepresentationTemplate[14] self.nBitsScaledGroupLength = self.dataRepresentationTemplate[15] elif self.dataRepresentationTemplateNumber == 3: # Grid Point Data -- Complex Packing and Spatial Differencing self.refValue = _getieeeint(self.dataRepresentationTemplate[0]) self.binScaleFactor = self.dataRepresentationTemplate[1] self.decScaleFactor = self.dataRepresentationTemplate[2] self.nBitsPacking = self.dataRepresentationTemplate[3] self.typeOfValues = tables.get_value_from_table(self.dataRepresentationTemplate[4],'5.1') self.groupSplitMethod = tables.get_value_from_table(self.dataRepresentationTemplate[5],'5.4') self.typeOfMissingValue = tables.get_value_from_table(self.dataRepresentationTemplate[6],'5.5') self.priMissingValue = _getieeeint(self.dataRepresentationTemplate[7]) if self.dataRepresentationTemplate[6] in [1,2] else None self.secMissingValue = _getieeeint(self.dataRepresentationTemplate[8]) if self.dataRepresentationTemplate[6] in [1,2] else None self.nGroups = self.dataRepresentationTemplate[9] self.refGroupWidth = self.dataRepresentationTemplate[10] self.nBitsGroupWidth = self.dataRepresentationTemplate[11] self.refGroupLength = self.dataRepresentationTemplate[12] self.groupLengthIncrement = self.dataRepresentationTemplate[13] self.lengthOfLastGroup = self.dataRepresentationTemplate[14] self.nBitsScaledGroupLength = self.dataRepresentationTemplate[15] self.spatialDifferenceOrder = tables.get_value_from_table(self.dataRepresentationTemplate[16],'5.6') self.nBytesSpatialDifference = self.dataRepresentationTemplate[17] elif self.dataRepresentationTemplateNumber == 4: # Grid Point Data - IEEE Floating Point Data self.precision = tables.get_value_from_table(self.dataRepresentationTemplate[0],'5.7') elif self.dataRepresentationTemplateNumber == 40: # Grid Point Data - JPEG2000 Compression self.refValue = _getieeeint(self.dataRepresentationTemplate[0]) self.binScaleFactor = self.dataRepresentationTemplate[1] self.decScaleFactor = self.dataRepresentationTemplate[2] self.nBitsPacking = self.dataRepresentationTemplate[3] self.typeOfValues = tables.get_value_from_table(self.dataRepresentationTemplate[4],'5.1') self.typeOfCompression = tables.get_value_from_table(self.dataRepresentationTemplate[5],'5.40') self.targetCompressionRatio = self.dataRepresentationTemplate[6] elif self.dataRepresentationTemplateNumber == 41: # Grid Point Data - PNG Compression self.refValue = _getieeeint(self.dataRepresentationTemplate[0]) self.binScaleFactor = self.dataRepresentationTemplate[1] self.decScaleFactor = self.dataRepresentationTemplate[2] self.nBitsPacking = self.dataRepresentationTemplate[3] self.typeOfValues = tables.get_value_from_table(self.dataRepresentationTemplate[4],'5.1')
def data(self, fill_value=9.969209968386869e+36, masked_array=True, expand=True, order=None)
-
Returns an unpacked data grid.
Parameters
fill_value : float, optional
Missing or masked data is filled with this value or default value given by
DEFAULT_FILL_VALUE
.masked_array : bool, optional
When
True
[DEFAULT], return masked array if there is bitmap for missing or masked data.expand : bool, optional
When
True
[DEFAULT], ECMWF 'reduced' gaussian grids are expanded to regular gaussian grids.order : int, optional
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.
Returns
numpy.ndarray
A numpy.ndarray with dtype=numpy.float32 with dimensions (ny,nx).
Expand source code
def data(self,fill_value=DEFAULT_FILL_VALUE,masked_array=True,expand=True,order=None): """ Returns an unpacked data grid. Parameters ---------- **`fill_value : float, optional`** Missing or masked data is filled with this value or default value given by `DEFAULT_FILL_VALUE`. **`masked_array : bool, optional`** When `True` [DEFAULT], return masked array if there is bitmap for missing or masked data. **`expand : bool, optional`** When `True` [DEFAULT], ECMWF 'reduced' gaussian grids are expanded to regular gaussian grids. **`order : int, optional`** 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. Returns ------- **`numpy.ndarray`** A numpy.ndarray with dtype=numpy.float32 with dimensions (ny,nx). """ if not hasattr(self,'scanModeFlags'): raise ValueError('Unsupported grid definition template number %s'%self.gridDefinitionTemplateNumber) else: if self.scanModeFlags[2]: storageorder='F' else: storageorder='C' if order is None: if (self.dataRepresentationTemplateNumber in [2,3] and self.dataRepresentationTemplate[6] != 0) or self.bitMapFlag == 0: order = 0 else: order = 1 drtnum = self.dataRepresentationTemplateNumber drtmpl = np.asarray(self.dataRepresentationTemplate,dtype=np.int32) gdtnum = self.gridDefinitionTemplateNumber gdtmpl = np.asarray(self.gridDefinitionTemplate,dtype=np.int32) ndpts = self.numberOfDataPoints gdsinfo = self.gridDefinitionInfo ngrdpts = gdsinfo[1] ipos = self._datapos fld1 = g2clib.unpack7(self._msg,gdtnum,gdtmpl,drtnum,drtmpl,ndpts,ipos,np.empty,storageorder=storageorder) # Apply bitmap. if self.bitMapFlag == 0: fld = fill_value*np.ones(ngrdpts,'f') np.put(fld,np.nonzero(self.bitMap),fld1) if masked_array: fld = ma.masked_values(fld,fill_value) # Missing values instead of bitmap elif masked_array and hasattr(self,'priMissingValue'): if hasattr(self,'secMissingValue'): mask = np.logical_or(fld1==self.priMissingValue,fld1==self.secMissingValue) else: mask = fld1 == self.priMissingValue fld = ma.array(fld1,mask=mask) else: fld = fld1 if self.nx is not None and self.ny is not None: # Rectangular grid. if ma.isMA(fld): fld = ma.reshape(fld,(self.ny,self.nx)) else: fld = np.reshape(fld,(self.ny,self.nx)) else: if gdsinfo[2] and gdtnum == 40: # ECMWF 'reduced' global gaussian grid. if expand: from redtoreg import _redtoreg self.nx = 2*self.ny lonsperlat = self.defList if ma.isMA(fld): fld = ma.filled(fld) fld = _redtoreg(self.nx,lonsperlat.astype(np.long),\ fld.astype(np.double),fill_value) fld = ma.masked_values(fld,fill_value) else: fld = _redtoreg(self.nx,lonsperlat.astype(np.long),\ fld.astype(np.double),fill_value) # Check scan modes for rect grids. if self.nx is not None and self.ny is not None: if self.scanModeFlags[3]: fldsave = fld.astype('f') # casting makes a copy fld[1::2,:] = fldsave[1::2,::-1] return fld
class open
-
GRIB2 File Object. A physical file can contain one or more GRIB2 messages. When instantiated, class
open
, the file namedfilename
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 : str
Mode of opening the file. For reading,
mode = 'rb'
and writing, mode = 'wb'.name : str
Full path name of the GRIB2 file.
messages : int
Count of GRIB2 Messages contained in the file.
current_message : int
Current position of the file in units of GRIB2 Messages.
size : int
Size of the file in units of bytes.
closed : bool
Bool signaling if the file is closed
True
or openFalse
.Class Constructor
Parameters
filename : str
File name.
mode : str, optional, default = 'r'
File handle mode. The default is open for reading ('r').
Expand source code
class open(): """ 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 : str`** Mode of opening the file. For reading, `mode = 'rb'` and writing, mode = 'wb'. **`name : str`** Full path name of the GRIB2 file. **`messages : int`** Count of GRIB2 Messages contained in the file. **`current_message : int`** Current position of the file in units of GRIB2 Messages. **`size : int`** Size of the file in units of bytes. **`closed : bool`** Bool signaling if the file is closed **`True`** or open **`False`**. """ __pdoc__['grib2io.open.__init__'] = True def __init__(self, filename, mode='r'): """ Class Constructor Parameters ---------- **`filename : str`** File name. **`mode : str, optional, default = 'r'`** File handle mode. The default is open for reading ('r'). """ if mode == 'r' or mode == 'w': mode = mode+'b' elif mode == 'a': mode = 'wb' self._filehandle = builtins.open(filename,mode=mode,buffering=ONE_MB) self._hasindex = False self._index = {} self.mode = mode self.name = os.path.abspath(filename) self.messages = 0 self.current_message = 0 self.size = os.path.getsize(self.name) self.closed = self._filehandle.closed if 'r' in self.mode: self._build_index() def __delete__(self, instance): """ """ self.close() del self._index def __enter__(self): """ """ return self def __exit__(self, atype, value, traceback): """ """ self.close() def __iter__(self): """ """ return self def __next__(self): """ """ if self.current_message < self.messages: return self.read(1)[0] else: self.seek(0) raise StopIteration def __repr__(self): """ """ strings = [] keys = self.__dict__.keys() for k in keys: if not k.startswith('_'): strings.append('%s = %s\n'%(k,self.__dict__[k])) return ''.join(strings) def __getitem__(self, key): """ """ if isinstance(key,slice): if key.start is None and key.stop is None and key.step is None: beg = 1 end = self.messages+1 inc = 1 else: beg, end, inc = key.indices(self.messages) return [self[i][0] for i in range(beg,end,inc)] elif isinstance(key,int): if key == 0: return None self._filehandle.seek(self._index['offset'][key]) return [Grib2Message(self._filehandle.read(self._index['size'][key]),ref=self,num=self._index['messageNumber'][key])] else: raise KeyError('Key must be an integer or slice') def _build_index(self): """ Perform indexing of GRIB2 Messages. """ # Initialize index dictionary self._index['offset'] = [None] self._index['discipline'] = [None] self._index['edition'] = [None] self._index['size'] = [None] self._index['submessageOffset'] = [None] self._index['submessageBeginSection'] = [None] self._index['isSubmessage'] = [None] self._index['messageNumber'] = [None] self._index['identificationSection'] = [None] self._index['productDefinitionTemplateNumber'] = [None] self._index['productDefinitionTemplate'] = [None] self._index['varName'] = [None] self._index['bitMap'] = [None] # Iterate while True: try: # Read first 4 bytes and decode...looking for "GRIB" pos = self._filehandle.tell() header = struct.unpack('>4s',self._filehandle.read(4))[0].decode() # Test header. Then get information from GRIB2 Section 0: the discipline # number, edition number (should always be 2), and GRIB2 message size. # Then iterate to check for submessages. if header == 'GRIB': _issubmessage = False _submsgoffset = 0 _submsgbegin = 0 # Read and unpack Section 0. Note that this is not done through # the g2clib. self._filehandle.seek(self._filehandle.tell()+2) discipline = int(struct.unpack('>B',self._filehandle.read(1))[0]) edition = int(struct.unpack('>B',self._filehandle.read(1))[0]) assert edition == 2 size = struct.unpack('>Q',self._filehandle.read(8))[0] # Read and unpack Section 1 secsize = struct.unpack('>i',self._filehandle.read(4))[0] secnum = struct.unpack('>B',self._filehandle.read(1))[0] assert secnum == 1 self._filehandle.seek(self._filehandle.tell()-5) _grbmsg = self._filehandle.read(secsize) _grbpos = 0 _grbsec1,_grbpos = g2clib.unpack1(_grbmsg,_grbpos,np.empty) _grbsec1 = _grbsec1.tolist() secrange = range(2,8) while 1: for num in secrange: secsize = struct.unpack('>i',self._filehandle.read(4))[0] secnum = struct.unpack('>B',self._filehandle.read(1))[0] if secnum == num: if secnum == 3: self._filehandle.seek(self._filehandle.tell()-5) _grbmsg = self._filehandle.read(secsize) _grbpos = 0 # Unpack Section 3 _gds,_gdtn,_deflist,_grbpos = g2clib.unpack3(_grbmsg,_grbpos,np.empty) elif secnum == 4: self._filehandle.seek(self._filehandle.tell()-5) _grbmsg = self._filehandle.read(secsize) _grbpos = 0 # Unpack Section 4 _pdt,_pdtnum,_coordlist,_grbpos = g2clib.unpack4(_grbmsg,_grbpos,np.empty) _pdt = _pdt.tolist() _varinfo = tables.get_varname_from_table(discipline,_pdt[0],_pdt[1]) elif secnum == 6: self._filehandle.seek(self._filehandle.tell()-5) _grbmsg = self._filehandle.read(secsize) _grbpos = 0 # Unpack Section 6. Save bitmap _bmap,_bmapflag = g2clib.unpack6(_grbmsg,_gds[1],_grbpos,np.empty) if _bmapflag == 0: _bmap_save = copy.deepcopy(_bmap) elif _bmapflag == 254: _bmap = copy.deepcopy(_bmap_save) else: self._filehandle.seek(self._filehandle.tell()+secsize-5) else: if num == 2 and secnum == 3: pass # Allow this. Just means no Local Use Section. else: _issubmessage = True _submsgoffset = (self._filehandle.tell()-5)-(self._index['offset'][self.messages]) _submsgbegin = secnum self._filehandle.seek(self._filehandle.tell()-5) continue trailer = struct.unpack('>4s',self._filehandle.read(4))[0].decode() if trailer == '7777': self.messages += 1 self._index['offset'].append(pos) self._index['discipline'].append(discipline) self._index['edition'].append(edition) self._index['size'].append(size) self._index['messageNumber'].append(self.messages) self._index['isSubmessage'].append(_issubmessage) self._index['identificationSection'].append(_grbsec1) self._index['productDefinitionTemplateNumber'].append([_pdtnum]) self._index['productDefinitionTemplate'].append([_pdt]) self._index['varName'].append(_varinfo[2]) self._index['bitMap'].append(_bmap) if _issubmessage: self._index['submessageOffset'].append(_submsgoffset) self._index['submessageBeginSection'].append(_submsgbegin) else: self._index['submessageOffset'].append(0) self._index['submessageBeginSection'].append(_submsgbegin) break else: self._filehandle.seek(self._filehandle.tell()-4) self.messages += 1 self._index['offset'].append(pos) self._index['discipline'].append(discipline) self._index['edition'].append(edition) self._index['size'].append(size) self._index['messageNumber'].append(self.messages) self._index['isSubmessage'].append(_issubmessage) self._index['identificationSection'].append(_grbsec1) self._index['productDefinitionTemplateNumber'].append([_pdtnum]) self._index['productDefinitionTemplate'].append([_pdt]) self._index['varName'].append(_varinfo[2]) self._index['bitMap'].append(_bmap) self._index['submessageOffset'].append(_submsgoffset) self._index['submessageBeginSection'].append(_submsgbegin) continue except(struct.error): self._filehandle.seek(0) break self._hasindex = True def close(self): """ Close the file handle """ if not self._filehandle.closed: self._filehandle.close() self.closed = self._filehandle.closed def read(self, num=0): """ Read num GRIB2 messages from the current position Parameters ---------- **`num : int`** Number of GRIB2 Message to read. Returns ------- **`list`** List of `grib2io.Grib2Message` instances. """ msgs = [] if self.tell() >= self.messages: return msgs if num > 0: if num == 1: msgrange = [self.tell()+1] else: beg = self.tell()+1 end = self.tell()+1+num if self.tell()+1+num <= self.messages else self.messages msgrange = range(beg,end+1) for n in msgrange: self._filehandle.seek(self._index['offset'][n]) msgs.append(Grib2Message(self._filehandle.read(self._index['size'][n]),ref=self,num=self._index['messageNumber'][n])) self.current_message += 1 return msgs def rewind(self): """ Set the position of the file to zero in units of GRIB2 messages. """ self.seek(0) def seek(self, pos): """ Set the position within the file in units of GRIB2 messages. Parameters ---------- **`pos : int`** GRIB2 Message number to set the read pointer to. """ if self._hasindex: if pos == 0: self._filehandle.seek(pos) self.current_message = pos elif pos > 0: self._filehandle.seek(self._index['offset'][pos-1]) self.current_message = pos def tell(self): """ Returns the position of the file in units of GRIB2 Messages. """ return self.current_message
Methods
def __init__(self, filename, mode='r')
-
Class Constructor
Parameters
filename : str
File name.
mode : str, optional, default = 'r'
File handle mode. The default is open for reading ('r').
Expand source code
def __init__(self, filename, mode='r'): """ Class Constructor Parameters ---------- **`filename : str`** File name. **`mode : str, optional, default = 'r'`** File handle mode. The default is open for reading ('r'). """ if mode == 'r' or mode == 'w': mode = mode+'b' elif mode == 'a': mode = 'wb' self._filehandle = builtins.open(filename,mode=mode,buffering=ONE_MB) self._hasindex = False self._index = {} self.mode = mode self.name = os.path.abspath(filename) self.messages = 0 self.current_message = 0 self.size = os.path.getsize(self.name) self.closed = self._filehandle.closed if 'r' in self.mode: self._build_index()
def close(self)
-
Close the file handle
Expand source code
def close(self): """ Close the file handle """ if not self._filehandle.closed: self._filehandle.close() self.closed = self._filehandle.closed
def read(self, num=0)
-
Read num GRIB2 messages from the current position
Parameters
num : int
Number of GRIB2 Message to read.
Returns
list
List of
Grib2Message
instances.Expand source code
def read(self, num=0): """ Read num GRIB2 messages from the current position Parameters ---------- **`num : int`** Number of GRIB2 Message to read. Returns ------- **`list`** List of `grib2io.Grib2Message` instances. """ msgs = [] if self.tell() >= self.messages: return msgs if num > 0: if num == 1: msgrange = [self.tell()+1] else: beg = self.tell()+1 end = self.tell()+1+num if self.tell()+1+num <= self.messages else self.messages msgrange = range(beg,end+1) for n in msgrange: self._filehandle.seek(self._index['offset'][n]) msgs.append(Grib2Message(self._filehandle.read(self._index['size'][n]),ref=self,num=self._index['messageNumber'][n])) self.current_message += 1 return msgs
def rewind(self)
-
Set the position of the file to zero in units of GRIB2 messages.
Expand source code
def rewind(self): """ Set the position of the file to zero in units of GRIB2 messages. """ self.seek(0)
def seek(self, pos)
-
Set the position within the file in units of GRIB2 messages.
Parameters
pos : int
GRIB2 Message number to set the read pointer to.
Expand source code
def seek(self, pos): """ Set the position within the file in units of GRIB2 messages. Parameters ---------- **`pos : int`** GRIB2 Message number to set the read pointer to. """ if self._hasindex: if pos == 0: self._filehandle.seek(pos) self.current_message = pos elif pos > 0: self._filehandle.seek(self._index['offset'][pos-1]) self.current_message = pos
def tell(self)
-
Returns the position of the file in units of GRIB2 Messages.
Expand source code
def tell(self): """ Returns the position of the file in units of GRIB2 Messages. """ return self.current_message