Wenqi Sun
by Wenqi Sun
1 min read

Categories

Tags

欧洲中心的GRIB数据文件的编解码将使用ecCodes来进行

本文主要介绍如何使用ecCodes来读取欧洲中心细网格模式输出的GRIB文件中的变量(地表和气压层)

说明

  • ecCodes最简单的的安装方法是使用Anaconda(conda install -c conda-forge python-eccodes)
  • 在从文件读取变量之前最好使用grib_dump命令对文件内容有一个大体的了解

代码

# -*- coding: UTF-8 -*-
import sys
import eccodes
import numpy as np
from datetime import datetime, timedelta

def getVar(file, varname):
    ### file表示要读取的GRIB文件(字符串类型)
    ### varname表示要读取的变量名(字符串类型)     
    var_summary = dict() #存储变量信息   

    iid = eccodes.codes_index_new_from_file(file, keys=['shortName'])
    vars_all = eccodes.codes_index_get(iid, key='shortName') #all variables in the file
    if varname not in vars_all:
        print("Error: {0} is not in the list of variables")
        sys.exit()
    var_summary['shortname'] = varname

    eccodes.codes_index_select(iid, key='shortName', value=varname)
    gid = eccodes.codes_new_from_index(iid)

    ### variable type
    try:
        level_type = 'sfc' if varname=='ptype' else eccodes.codes_get(gid, 'indicatorOfTypeOfLevel')
        var_summary['type'] = 'surface' if level_type=='sfc' else 'pressure levels(hPa)'
    except:
        print('The function only read the surface or pressure level variables, {0} is model level variable' \
              .format(varname))
        sys.exit()

    ### time info
    ymdh_start_utc = str(eccodes.codes_get(gid, 'dataDate')) + '%02d'%(eccodes.codes_get(gid, 'dataTime')//100)
    delta_hours = int(eccodes.codes_get(gid, 'endStep'))

    ymdh_start_bj_date = datetime.strptime(ymdh_start_utc,'%Y%m%d%H') + timedelta(hours=8) #transform from utc to beijing
    ymdh_pred_bj_date = ymdh_start_bj_date + timedelta(hours=delta_hours)

    ymdh_start_bj = ymdh_start_bj_date.strftime('%Y%m%d%H')
    ymdh_pred_bj = ymdh_pred_bj_date.strftime('%Y%m%d%H')
    var_summary['start_time'] = ymdh_start_bj
    var_summary['predict_time'] = ymdh_pred_bj

    ### long name and unit
    long_name = eccodes.codes_get(gid, 'name')
    unit = eccodes.codes_get(gid, 'units')
    var_summary['longname'] = long_name
    var_summary['unit'] = unit

    ### lat/lon info
    lat_ec_start = eccodes.codes_get(gid, 'latitudeOfFirstGridPointInDegrees')
    lat_ec_end = eccodes.codes_get(gid, 'latitudeOfLastGridPointInDegrees')
    lat_ec_delta = eccodes.codes_get(gid, 'jDirectionIncrementInDegrees')
    s_to_n = False if eccodes.codes_get(gid, 'jScansPositively')==0 else True

    lon_ec_start = eccodes.codes_get(gid, 'longitudeOfFirstGridPointInDegrees')
    lon_ec_end = eccodes.codes_get(gid, 'longitudeOfLastGridPointInDegrees')
    lon_ec_delta = eccodes.codes_get(gid, 'iDirectionIncrementInDegrees')
    w_to_e = False if eccodes.codes_get(gid, 'iScansNegatively')==1 else True
    lon_ec_start = 360+lon_ec_start if lon_ec_start<0 else lon_ec_start #change to the range 0-360
    lon_ec_end = 360+lon_ec_end if lon_ec_end<0 else lon_ec_end #change to the range 0-360

    var_summary['lat_start'] = lat_ec_start  
    var_summary['lat_end'] = lat_ec_end
    var_summary['lat_delta'] = lat_ec_delta
    var_summary['south_to_north'] = s_to_n
    var_summary['lon_start'] = lon_ec_start  
    var_summary['lon_end'] = lon_ec_end
    var_summary['lon_delta'] = lon_ec_delta
    var_summary['west_to_east'] = w_to_e

    ### levels and data values
    levels = []
    data_levels = []
    numlat = eccodes.codes_get(gid, 'Nj')
    numlon = eccodes.codes_get(gid, 'Ni')
    while gid:
        level = eccodes.codes_get(gid, 'level')
        data_ec = eccodes.codes_get_values(gid).reshape(numlat, numlon)
        levels.append(level)
        data_levels.append(data_ec)
        eccodes.codes_release(gid)
        gid = eccodes.codes_new_from_index(iid)
    eccodes.codes_index_release(iid)

    if level_type=='pl': var_summary['levels']=sorted(levels)
    var_summary['values'] = np.array(data_levels)[np.argsort(levels)]

    return var_summary