GRIB2文件不同打包方式的加载速度对比
注:本文是对 2022 年博文《不同打包方式下GRIB2文件加载速度对比:简单打包与JPEG压缩》的更新。
GRIB2 格式文件支持使用不同方式保存要素场数据,可以使用二维数组的一维展开,也可以使用类似 JPEG、PNG 等图片格式对二维数据进行压缩。
本文介绍不同打包方式下从 GRIB2 文件中加载要素场的速度。
打包方式
GRIB2 支持多种打包方式,下表是 GRIB2 标准中的 CODE TABLE 5.0,列出了当前 WMO 标准支持的打包方式(参考 NCEP GRIB2 文档,或 ECMWF GRIB2 文档):
编码 | 说明 |
---|---|
0 | Grid Point Data - Simple Packing |
1 | Matrix Value at Grid Point - Simple Packing |
2 | Grid Point Data - Complex Packing |
3 | Grid Point Data - Complex Packing and Spatial Differencing |
4 | Grid Point Data - IEEE Floating Point Data (see Template 5.4) |
40 | Grid point data - JPEG 2000 code stream format |
41 | Grid point data - Portable Network Graphics (PNG) |
42 | Grid point data - CCSDS recommended lossless compression |
50 | Spectral Data - Simple Packing (see Template 5.50) |
51 | Spectral Data - Complex Packing (see Template 5.51) |
53 | Spectral data for limited area models - complex packing |
61 | Grid Point Data - Simple Packing With Logarithm Pre-processing |
200 | Run Length Packing With Level Values |
不同中心生成的 GRIB2 数据使用不同的打包方式:
- CMA 天气预报模式:JPEG2000 压缩 (grid_jpeg)
- ECMWF 公开数据:CCSDS 无损压缩 (grid_ccsds)
- NCEP GFS:复杂打包 (grid_complex_spatial_differencing)
本文测试 wgrib2 支持的部分打包方式,如下表所示:
wgrib2 name | eccodes packingType | 说明 |
---|---|---|
jpeg | grid_jpeg | JPEG2000 压缩 |
simple | grid_simple | 无压缩,打包缩放后的整数 |
ieee | grid_ieee | IEEE 格式 (每个数据点 4 字节) |
complex1 | grid_complex | complex packing |
complex2 | grid_complex_spatial_differencing | complex packing, pack increments (deltas) |
complex3 | grid_complex_spatial_differencing | complex packing, pack increments after linear extrapolation |
aec | grid_ccsds | 使用 libaec 实现的 CCSDS 压缩 |
准备数据
使用 CMA-MESO V6.0 的等压面产品作为测试数据,原始文件使用 JPEG2000 方式压缩。
使用 wgrib2 -set_grib_type
命令将 GRIB2 文件转为不同的打包方式。
例如下面命令将文件转为 simple 打包方式:
wgrib2 -set_grib_type simple rmf.hgra.2024101200024.grb2 -grib_out rmf.hgra.2024101200024.grb2.simple
转换后的文件列表如下:
6.4G rmf.hgra.2024101200024.grb2
7.8G rmf.hgra.2024101200024.grb2.aec
9.6G rmf.hgra.2024101200024.grb2.complex1
8.1G rmf.hgra.2024101200024.grb2.complex2
7.8G rmf.hgra.2024101200024.grb2.complex3
57G rmf.hgra.2024101200024.grb2.ieee
25G rmf.hgra.2024101200024.grb2.simple
测试
读取代码
使用 reki 库从 GRIB2 文件中加载层次类型为 isobaricInhPa
的所有温度场:
file_path = "./rmf.hgra.2022031000003.grb2"
ds = load_field_from_file(
file_path,
parameter="t",
level_type="isobaricInhPa",
level="all"
)
测试方法
在 CMA 气象超算 HPC2023 的登陆节点上运行上述代码。
使用 PyCharm 内置的 Profile 工具分析代码运行时长,比较 main()
函数和 grib_get_double_array()
函数运行总时长。
其中:
main()
函数是去掉 PyCharm 脚手架耗时的整体运行时长grib_get_double_array()
函数是 reki 调用 ecCodes 解码函数的运行时长
对比两个运行时间可以看到数据解码在处理 GRIB2 消息中的耗时占比。
注意:统计结果仅是 近似值,只用来对比不同打包方式的相对运行时长。
测试结果
不同打包方式的测试结果如下:
packing_type | size(GB) | total(s) | decode(s) | other(s) |
---|---|---|---|---|
jpeg | 6.4 | 182 | 171 | 11 |
simple | 25 | 11 | 1 | 10 |
ieee | 57 | 13 | 1 | 12 |
aec | 7.8 | 11 | 6 | 5 |
complex1 | 9.6 | 10 | 5 | 5 |
complex2 | 8.1 | 10 | 6 | 4 |
complex3 | 7.8 | 11 | 6 | 5 |
main()
函数中其他部分运行时长与 grib_get_double_array()
函数运行时长的关系如下图所示:
图 不同打包方式下核心段代码的运行时长
从测试结果可以看到,JPEG2000压缩方式有最大的压缩比,文件仅为其他压缩方式的2/3以内,但解码耗时提高了一个数量级。 除了基本没有压缩的 simple 和 ieee 外,其他几种压缩方式除了文件大小外没有显著的差异,比如 aec 和 complex3 从文件大小和解码时间来看基本一样。
讨论
CMA-MESO V6.0 也就是 CMA-MESO 1KM 提供全国数据后,最常遇到的问题就是数据加载太慢,也就是 JPEG2000 数据解压耗时过长。 从 JPEG2000 压缩算法着手不太容易,笔者没找到容易使用的免费版 JPEG2000 高效解码库。
有两种方式可以用来解决这个问题。
第一种方式是根据服务需要定制数据。比如对数据进行拆分,存储更小区域的数据,解码速度会显著提高。 假如为每个省局都单独制作一套小区域的数据,数据文件更小,更容易传输,解码时间也会更少。
第二种方式是使用其他压缩方案代替 JPEG2000,以空间换时间。 但需要考虑数据量增长之后现有的网络带宽是否能满足需求。
也许需要两种方式相结合,内部网络不需要考虑带宽时用 aec 等压缩方式,对外服务用裁剪小区域抵消更换压缩方式后文件大小的增长。
附录
完整测试代码
import pandas as pd
import typer
from reki.format.grib.eccodes import load_field_from_file
packing_type_map = dict(
jpeg="",
simple=".simple",
ieee=".ieee",
aec=".aec",
complex1=".complex1",
complex2=".complex2",
complex3=".complex3"
)
def main(packing_type: str):
start_time = pd.Timestamp.now()
print(f"using packing type: {packing_type}")
suffix = packing_type_map[packing_type]
file_path = f"/some/path/to/data/rmf.hgra.2024101200024.grb2{suffix}"
print(file_path)
ds = load_field_from_file(
file_path,
parameter="t",
level_type="isobaricInhPa",
level="all"
)
ds.load()
# print(ds)
end_time = pd.Timestamp.now()
print(end_time - start_time)
if __name__ == "__main__":
typer.run(main)
运行
python a.py jpeg
参考
reki 库是为 CMA 天气模式开发的数据准备 Python 开源工具库,提供检索要素场的便捷方法。