# Python script to read a GRIB file and transform it to a NetCDF using full python
# libraries (pupygrib)
# L. Fita. CIMA, November 2018
# More information at: http://www.xn--llusfb-5va.cat/python/PyNCplot
#
# pyNCplot and its component nc_var.py comes with ABSOLUTELY NO WARRANTY.
# This work is licendes under a Creative Commons
# Attribution-ShareAlike 4.0 International License (http://creativecommons.org/licenses/by-sa/4.0)
#
## e.g. # python read_grib.py -g ERAI_pl200503_130.grib -o ERAI_pl200503_T.nc -t 'minutes!since!1949-12-01!00:00:00'
# FROM: https://pypi.org/project/pupygrib/
from optparse import OptionParser
import numpy as np
import pupygrib
import os
from netCDF4 import Dataset as NetCDFFile
import generic_tools as gen
import nc_var_tools as ncvar
errormsg = 'ERROR -- error -- ERROR -- error'
def grib128_ncname(varid):
""" Function to provide CF name from a ECMWF GRIB table 128 variable ID
>>> grib128_ncname(130)
['T', 'Temperature', 'K', 'air_temperature', 'air temperature']
"""
fname = 'grib128_ncname'
folder = os.path.dirname(os.path.realpath(__file__))
infile = folder + '/transform_128ECMWF.html'
if not os.path.isfile(infile):
print errormsg
print ' ' + fname + ": File '" + infile + "' does not exist !!"
quit(-1)
of = open(infile, 'r')
idS = str(varid).zfill(3)
for line in of:
if len(line) > 28:
#print line[0:27], ':', idS, line[0:27] == '
' + idS + ' | '
if line[0:27] == '' + idS + ' | ':
linevals = line.replace('\n','').split('')
varn = linevals[1].replace('','')
Lvarn = linevals[2].replace(' | ','')
units = linevals[3].replace(' | ','')
units = units.replace('','').replace('','')
units = units.replace('','').replace('','')
units = units.replace('','').replace('','')
#print varn, Lvarn, units
cfvalues = gen.variables_values(varn)
break
return [varn,Lvarn,units,cfvalues[0], cfvalues[1], cfvalues[4].replace('|', ' ')]
parser = OptionParser()
parser.add_option("-g", "--grib_file", dest="gribfile", help="GRIB file to use",
metavar="FILE")
parser.add_option("-o", "--output_file", dest="ncfile", help="name of NC file to generate",
metavar="FILE")
parser.add_option("-t", "--timeunits", dest="timeunits",
help="CF reference of time values [Tunits] since [DateRef] ('!', for spaces minutes!since!1949-12-01!00:00:00 as default)",
metavar="STRING")
(opts, args) = parser.parse_args()
####### #######
## MAIN
#######
if opts.gribfile is None:
print errormsg
print " no grib input file name provided !!"
print " you should provide one file name as -g [FileName]"
quit(-1)
if not os.path.isfile(opts.gribfile):
print errormsg
print " no grib file '" + opts.gribfile + "' found !!"
quit(-1)
else:
ifile = opts.gribfile
if opts.ncfile is None:
print errormsg
print " no netcdf output file name provided !!"
print " you should provide one file name as -o [FileName]"
quit(-1)
else:
ofile = opts.ncfile
if opts.timeunits is None:
print errormsg
print " no time units provided !!"
print " using the default ones as 'minutes since 1949-12-01 00:00:00'"
else:
timeu = opts.timeunits.replace('!', ' ')
with open(ifile, 'rb') as stream:
for i, msg in enumerate(pupygrib.read(stream), 1):
if i == 1:
lons, lats = msg.get_coordinates()
onewnc = NetCDFFile(ofile, 'w')
# Create dimension
dimx = lons.shape[1]
dimy = lons.shape[0]
newdim = onewnc.createDimension('lon',dimx)
newdim = onewnc.createDimension('lat',dimy)
newdim = onewnc.createDimension('time',None)
newdim = onewnc.createDimension('Lstring',64)
dlon = msg[2].longitudeOfLastGridPoint - msg[2].longitudeOfFirstGridPoint
dlat = msg[2].latitudeOfLastGridPoint - msg[2].latitudeOfFirstGridPoint
print dlon, dlat
if dlat < 0.:
lons[:,:] = lons[::-1,:]
lats[:,:] = lats[::-1,:]
# Create dimension-varibale
newvar = onewnc.createVariable('lon', 'f8', ('lat', 'lon'))
newvar[:] = lons[:]
ncvar.basicvardef(newvar, 'lon', 'Longitude', 'degrees_east')
newvar.setncattr('axis', 'X')
newvar.setncattr('_CoordinateAxisType', 'Lon')
newvar = onewnc.createVariable('lat', 'f8', ('lat', 'lon'))
newvar[:] = lats[:]
ncvar.basicvardef(newvar, 'lat', 'Latitude', 'degrees_north')
newvar.setncattr('axis', 'Y')
newvar.setncattr('_CoordinateAxisType', 'Lat')
newvartime = onewnc.createVariable('time', 'f8', ('time'))
ncvar.basicvardef(newvartime, 'time', 'time', timeu)
newvar.setncattr('axis', 'T')
newvar.setncattr('_CoordinateAxisType', 'Time')
newvartimeS = onewnc.createVariable('timeS', 'c', ('time', 'Lstring'))
ncvar.basicvardef(newvartimeS, 'time', 'time', 'YmdHMS')
newvar.setncattr('axis', 'T')
newvar.setncattr('_CoordinateAxisType', 'Time')
values = msg.get_values()
century = msg[1].centuryOfReferenceTimeOfData
year = msg[1].yearOfCentury
month = msg[1].month
day = msg[1].day
hour = msg[1].hour
minute = msg[1].minute
levtype = msg[1].indicatorOfTypeOfLevel
level = msg[1].level
varid = msg[1].indicatorOfParameter
offset = msg[1].offset
scalefactor = msg[1].decimalScaleFactor
timerange = msg[1].timeRangeIndicator
if levtype == 100:
if not onewnc.variables.has_key('press'):
print ' we got a variable with a pressure value !!'
pressv = []
newdim = onewnc.createDimension('press', None)
newvarpress = onewnc.createVariable('press', 'f8', ('press'))
newvarpress[0] = level*100.
ncvar.basicvardef(newvarpress, 'air_pressure', 'air pressure', 'Pa')
newvarpress.setncattr('axis', 'Z')
newvarpress.setncattr('_CoordinateAxisType', 'Press')
if not gen.searchInlist(pressv, level*100.):
pressv.append(level*100.)
iz = gen.index_vec(pressv, level*100.)
newvarpress[iz] = level*100.
else:
iz = gen.index_vec(pressv, level*100.)
elif levtype == 1:
if not onewnc.variables.has_key('height'):
print ' we got a variable with a height value !!'
heightv = []
newdim = onewnc.createDimension('height', None)
newvarheight = onewnc.createVariable('height', 'f8', ('height'))
newvarheight[0] = level
ncvar.basicvardef(newvarheight, 'height', 'height', 'm')
newvarheight.setncattr('axis', 'Z')
newvarheight.setncattr('_CoordinateAxisType', 'Height')
if not gen.searchInlist(heightv, level):
heightv.append(level)
iz = gen.index_vec(heightv, level)
newvarheight[iz] = level
else:
iz = gen.index_vec(heightv, level)
#print "Message :", i, values.mean(), values.shape, ':', msg[1].centuryOfReferenceTimeOfData, \
# msg[1].yearOfCentury, msg[1].month, msg[1].day, msg[1].hour, msg[1].minute, \
# msg[1].indicatorOfTypeOfLevel, msg[1].level, msg[1].localDefinitionNumber, msg[1].indicatorOfParameter, \
# msg[1].offset, msg[1].decimalScaleFactor, msg[1].timeRangeIndicator
#print 'msg:', dir(msg)
#for i in range(6):
# print 'msg ' + str(i) + ':', dir(msg[i])
varparams = grib128_ncname(varid)
if i==1: print varparams
timeS=str((century-1)*100 + year) + str(month).zfill(2) + str(day).zfill(2)+\
str(hour).zfill(2) + str(minute).zfill(2) + '00'
if i == 1: timevs = [timeS]
if not gen.searchInlist(timevs, timeS): timevs.append(timeS)
it = gen.index_vec(timevs, timeS)
#print 'timeS:', timeS, 'it:', it, 'lev:', level, 'iz:', iz
cftime = gen.datetimeStr_conversion(timeS,'YmdHMS','cfTime,'+timeu)
newvartimeS[it,0:14] = timeS
newvartime[it] = cftime
if not onewnc.variables.has_key(varparams[3]):
if levtype == 1:
dimns = ['time', 'height', 'lat', 'lon']
elif levtype == 100:
dimns = ['time', 'press', 'lat', 'lon']
else:
dimns = ['time', 'lat', 'lon']
newvar = onewnc.createVariable(varparams[3], 'f', tuple(dimns))
ncvar.basicvardef(newvar, varparams[4], varparams[5], varparams[2])
else:
newvar = onewnc.variables[varparams[3]]
if dlat < 0.:
values[:] = values[::-1,:]
if levtype == 1 or levtype == 100:
newvar[it,iz,:,:] = values[:]
else:
newvar[it,:,:] = values[:]
onewnc.sync()
# Global values
ncvar.add_global_PyNCplot(onewnc, 'red_grib.py', ' ', '0.1')
onewnc.close()
print "Successfull writting of '" + ofile + "' !!"
|