pynio迁移至cfgrib读取NOAA NBM GRIB2文件的变量名匹配问题咨询
GRIB2读取工具pynio与cfgrib变量名差异原因及适配方法
差异核心原因
- 命名逻辑设计不同:pynio直接将GRIB2字段的要素类型、层级、统计方式等元信息直接拼接为变量名,比如
CEIL_P0_L215中CEIL是云底高要素编码,P0是地面层标识,L215对应特定高度层编码,累计量还会追加accXh这类统计后缀;而cfgrib默认采用ECMWF定义的标准短名作为变量名,层级、统计属性不会塞进变量名,而是作为数据集的维度/坐标属性存储,这就是同要素不同层级的变量在cfgrib里名称相同、分散在不同子数据集的核心原因。 - 底层编码映射规则不同:pynio使用NCAR自研的GRIB2编码映射表,cfgrib则依赖ECMWF的eccodes库编码表,两者对部分NBM本地扩展编码的字段映射规则不一致,也是变量名不对应的原因之一。
- 非物理场变量的产生逻辑:cfgrib会自动将GRIB2里的层类型标识、坐标描述字段转为独立变量,
atmosphere、atmosphereSingleLayer就属于层类型标识变量,不属于实际预报数值场。 - 未知变量产生原因:如果GRIB2字段的产品定义、要素编码没有被当前版本的eccodes库收录,就会被标记为
unknown,和eccodes版本、NBM文件使用的本地扩展编码有关。
用cfgrib匹配pynio字段的实现方法
第一步:拆解pynio变量名的元信息规则
pynio输出的变量名结构为[要素编码]_[产品类型]_[层编码]_[可选统计后缀],先将你需要用到的原变量名拆解为对应的元信息组合,比如APCP_P8_L1_acc1h对应的元信息为:要素=逐小时累计降水、产品类型=概率预报、层=地面、统计周期=1小时累计。
第二步:遍历子数据集匹配元信息
不要仅提取变量名,同步读取变量属性和数据集的坐标属性做匹配,参考实现代码如下:
import cfgrib # 自定义原pynio变量对应的匹配规则,可根据自身需求扩展 PYNIO_VAR_MAPPING = { "APCP_P8_L1_acc1h": { "shortName": "tp", "typeOfLevel": "surface", "stepType": "accum", "stepRange": "1" }, "CEIL_P0_L2": { "shortName": "ceil", "typeOfLevel": "cloudBase", "level": 2 } } result = {} datasets = cfgrib.open_datasets("foo.grib2") for ds in datasets: # 只遍历data_vars跳过坐标变量,直接过滤atmosphere这类无效变量 for var_name in ds.data_vars: var = ds[var_name] # 遍历匹配规则 for pynio_name, match_cond in list(PYNIO_VAR_MAPPING.items()): is_match = True for k, expect_val in match_cond.items(): # 依次比对变量属性、数据集坐标属性 if k in var.attrs and var.attrs[k] != expect_val: is_match = False elif k in ds.coords and ds.coords[k].values != expect_val: is_match = False if is_match: result[pynio_name] = var.values # 匹配完成后移除规则,避免重复匹配 del PYNIO_VAR_MAPPING[pynio_name] break if not PYNIO_VAR_MAPPING: # 所有变量匹配完成后提前退出 break
第三步:处理未知编码字段
如果遇到unknown变量,可直接读取其GRIB原始编码属性(discipline、parameterCategory、parameterNumber),和pynio返回的对应变量编码手动比对,添加自定义匹配规则即可。
内容的提问来源于stack exchange,提问作者Grant Petty
相关产品推荐
相关产品推荐

