由于前面写的一篇关于GRIB与NetCDF的文章《浅析GRIB与NetCDF数据格式的特点及性能对比》在GRIB2与NetCDF4文件体积问题上有一些错误结论,经朋友指正,因此专门做此文予以更正。
摘要
本文利用工具将一个原始ERA5的GRIB1格式文件转换为不同压缩算法下的GRIB2、NetCDF3以及不同压缩等级下的NetCDF4格式文件,同时对他们进行bz2压缩,最后对比它们的文件体积大小。最终的结论是,不论是否使用bz2压缩,体积最小的都是GRIB2家族的文件格式。
数据简介
本次测试使用的原始数据为通过ERA5再分析数据下载的GRIB文件,该原始数据为GRIB1格式,而为了对比不同格式下的体积,我会用一些工具将该数据进行格式转换。
原始数据下载地址:https://doi.org/10.5281/zenodo.6348679
硬件配置
本次测评使用的计算机是2019款的MacBook Pro,具体型号和配置如下图:
使用工具及方法
本文使用的命令行工具包括:
- ecCodes
- wgrib2
- netCDF4
- bzip2
其中ecCodes和netCDF4都可以直接使用conda进行安装,而bzip2和wgrib2需要根据自己的系统查询对应的安装方法在这里不再赘述,本文使用wgrib2是通过docker启动对应镜像的方式进行的: $ docker pull agilesrc/wgrib2
使用wgrib2设置grib2压缩格式的方法
wgirb2可以使用的压缩方法包括:
- ieee : data is ieee format (4 bytes per data point)
- simple : no compression, packed scaled integers
- complex1 : complex packing
- complex1-bitmap : complex and using bitmap for undefined grid points
- complex2 : complex packing, pack increments (deltas)
- complex2-bitmap : complex packing, pack increments (deltas) and using bitmap for undefined
- complex3 : complex packing, pack increments after linear extrapolation
- complex3-bitmap : complex packing, pack increments after linear extrapolation and using bitmap for undefined
- jpeg : jpeg2000 compression
- aec : aec/CCSDS compression
- same : try to keep same packing type as input, if input is in an unsupported output packing, complex1 is used
示例:
$ wgrib2 in.grb -set_grib_type complex3 -grib_out out.grb
使用wgrib2将grib2转化为netcdf格式的方法
示例:
$ wgrib2 ./in.grb2 -netcdf out.nc
使用grib_set对grib1和grib2格式进行切换的方法
grib_set
是ecCodes命令行工具包中的一个命令行工具,用于修改grib文件的属性,也可以对grib1和grib2格式进行切换,然而该命令行并不能转换所有的grib文件,例如gfs的grib2文件有时就无法转换。
ecCodes的安装方法:
$ conda install -c conda-forge -y eccodes
示例:
# 将girb1转换为grib2 $ grib_set -s edition=2 in.grib out.grib2 # 将grib2转换为grib1 $ grib_set -s edition=1 in.grib2 out.grib1
使用nccopy转换netcdf文件格式及压缩格式的方法
nccopy
是netCDF4命令行工具包里的一个命令行工具,它可以实现nc文件的各种格式转换。
netcdf4的安装方法:
$ conda install -c conda-forge -y netCDF4
根据文档nccopy的文档,与转换格式和压缩相关的参数包括:
[-k kind] specify kind of netCDF format for output file, default same as input kind strings: ‘classic’, ’64-bit offset’, ‘cdf5’, ‘netCDF-4’, ‘netCDF-4 classic model’
[-d n] set output deflation compression level, default same as input (0=none 9=max)
示例:
# 将netcdf3文件转换为`netCDF-4 classic model`模式的netcdf4格式,并使用1级压缩 $ nccopy -k 'netCDF-4 classic model' -d 1 era5-sample.nc3 era5-sample-c0.nc4
GRIB1与GRIB2的体积对比
GRIB1格式是不支持压缩的,而GRIB2格式支持压缩,因此我们对比GIRB1和GRIB2格式文件的体积,本质上是对比GRIB1与各种压缩方式下GRIB2文件的体积。
由于我们的原始文件era5-sample.grib
是GRIB1格式,我们先把它转换为GRIB2,在终端执行:
$ grib_set -s edition=2 era5-sample.grib era5-sample.grib2
查看新的GRIB2文件:
$ grib_ls era5-sample.grib2 era5-sample.grib2 edition centre date dataType gridType stepRange typeOfLevel level shortName packingType 2 ecmf 20211028 fc regular_ll 8 heightAboveGround 10 10u grid_simple 2 ecmf 20211028 fc regular_ll 8 heightAboveGround 10 10v grid_simple 2 ecmf 20211028 fc regular_ll 8 heightAboveGround 2 2d grid_simple 2 ecmf 20211028 fc regular_ll 8 heightAboveGround 2 2t grid_simple 2 ecmf 20211028 fc regular_ll 8 surface 0 fal grid_simple 2 ecmf 20211028 fc regular_ll 7-8 surface 0 slhf grid_simple 2 ecmf 20211028 fc regular_ll 7-8 surface 0 ssr grid_simple 2 ecmf 20211028 fc regular_ll 7-8 surface 0 str grid_simple 2 ecmf 20211028 fc regular_ll 8 surface 0 sp grid_simple 2 ecmf 20211028 fc regular_ll 7-8 surface 0 sshf grid_simple 2 ecmf 20211028 fc regular_ll 7-8 surface 0 ssrd grid_simple 2 ecmf 20211028 fc regular_ll 7-8 surface 0 strd grid_simple 2 ecmf 20211028 fc regular_ll 7-8 surface 0 tp grid_simple 13 of 13 messages in era5-sample.grib2 13 of 13 total messages in 1 files
可以看到GRIB的edition
已经变成2了,下面我们要对转换后的GRIB2文件进行压缩,在预装了wgrib2
并支持bash
命令的环境下,在数据目录运行以下脚本:
#!/bin/sh ctypes=( "ieee" "simple" "complex1" "complex2" "complex3" "jpeg" "aec" "same" ) for ctype in "${ctypes[@]}" do wgrib2 -set_grib_type $ctype era5-sample.grib2 -grib_out era5-sample-$ctype.grib2 done
从而获得以下文件:
$ ls -lh era5-sample-*.grib2 -rw-r--r-- 1 clarmylee staff 36M 3 12 14:02 era5-sample-aec.grib2 -rw-r--r-- 1 clarmylee staff 34M 3 12 14:01 era5-sample-complex1.grib2 -rw-r--r-- 1 clarmylee staff 27M 3 12 14:01 era5-sample-complex2.grib2 -rw-r--r-- 1 clarmylee staff 27M 3 12 14:02 era5-sample-complex3.grib2 -rw-r--r-- 1 clarmylee staff 322M 3 12 14:01 era5-sample-ieee.grib2 -rw-r--r-- 1 clarmylee staff 36M 3 12 14:02 era5-sample-jpeg.grib2 -rw-r--r-- 1 clarmylee staff 65M 3 12 14:02 era5-sample-same.grib2 -rw-r--r-- 1 clarmylee staff 65M 3 12 14:01 era5-sample-simple.grib2
下面我们用代码统计一下这些文件的大小并绘制图形
可以看出来体积最大的压缩格式为ieee
,体积最小的为complex3
,而原始的GRIB1格式的文件是除了ieee
以外体积最大的,使用grib_set
直接转换后的GRIB2文件比原始文件略小,而complex3
压缩格式的文件大约是原始文件格式的1/3左右。
以上GRIB文件是在不丧失直接读取能力的存储格式,下面我们再来测试一下,将他们压缩为.bz2
格式以后的体积,在终端执行$ bzip2 -k *grib*
,可以得到以下文件:
$ ls -lh *.bz2 -rw-r--r-- 1 clarmylee staff 25M 3 12 14:02 era5-sample-aec.grib2.bz2 -rw-r--r-- 1 clarmylee staff 33M 3 12 14:01 era5-sample-complex1.grib2.bz2 -rw-r--r-- 1 clarmylee staff 26M 3 12 14:01 era5-sample-complex2.grib2.bz2 -rw-r--r-- 1 clarmylee staff 26M 3 12 14:02 era5-sample-complex3.grib2.bz2 -rw-r--r-- 1 clarmylee staff 55M 3 12 14:01 era5-sample-ieee.grib2.bz2 -rw-r--r-- 1 clarmylee staff 26M 3 12 14:02 era5-sample-jpeg.grib2.bz2 -rw-r--r-- 1 clarmylee staff 31M 3 12 14:02 era5-sample-same.grib2.bz2 -rw-r--r-- 1 clarmylee staff 31M 3 12 14:01 era5-sample-simple.grib2.bz2 -rw-r--r-- 1 clarmylee staff 52M 3 12 13:58 era5-sample.grib.bz2 -rw-r--r-- 1 clarmylee staff 52M 3 12 13:58 era5-sample.grib2.bz2
可以看出来,经过bz2
压缩以后文件体积最小的是基于aec
方法压缩的文件,bz2
压缩效果最明显的是ieee
,而原先体积较小的文件经bz2
算法压缩后的效果甚微。
综上可以看出,在GRIB的生态下,单纯从降低文件体积的角度考虑,在不丧失读取能力的情况下,使用complex3
压缩算法的GRIB2格式进行存储是最优的方案,若可以接受读取能力丧失的情况,那么aec
压缩算法也可以考虑。
NetCDF3与NetCDF4的体积对比
下面我们来讨论一下NetCDF3和NetCDF4之间的文件体积对比,跟GRIB类似的是,旧版本的NetCDF3不支持原生压缩,如果要压缩需要借助类似于bz2
的工具进行,而新版本的NetCDF4支持原生压缩,因此对两种格式的对比实际上就是用NetCDF3与NetCDF4不同压缩等级之间的对比。
grib_to_netcdf命令支持将GRIB转换为下列四种NetCDF存储格式:
- netCDF classic file format
- netCDF 64 bit classic file format (Default)
- netCDF-4 file format
- netCDF-4 classic model file format
以上四种数据格式的底层差异我们在这里不做赘述,仅比较它们的体积,我们先分别将GRIB文件转为这4中nc格式。
$ grib_to_netcdf -k 1 -o era5-sample-class.nc3 era5-sample.grib $ grib_to_netcdf -k 2 -o era5-sample-64class.nc3 era5-sample.grib $ grib_to_netcdf -k 3 -o era5-sample.nc4 era5-sample.grib $ grib_to_netcdf -k 4 -o era5-sample-class.nc4 era5-sample.grib $ ls -lh *nc* -rw-r--r-- 1 clarmylee staff 161M 3 12 15:26 era5-sample-64class.nc3 -rw-r--r-- 1 clarmylee staff 161M 3 12 15:26 era5-sample-class.nc3 -rw-r--r-- 1 clarmylee staff 161M 3 12 15:27 era5-sample-class.nc4 -rw-r--r-- 1 clarmylee staff 161M 3 12 15:26 era5-sample.nc4
可以看到,直接使用grib_to_netcdf
命令转换的各种NetCDF格式的体积没有显著差异,下面我们先使用nccopy
对其中nc4进行原生压缩,执行以下脚本:
#!/bin/sh clevels=( 0 1 2 3 4 5 6 7 8 9 ) for level in "${clevels[@]}" do nccopy -k 'netCDF-4' -d $level era5-sample.nc4 era5-sample-c$level.nc4 done
检查结果:
$ ls -lh era5-sample-*nc* -rw-r--r-- 1 clarmylee staff 161M 3 12 15:26 era5-sample-64class.nc3 -rw-r--r-- 1 clarmylee staff 161M 3 12 15:44 era5-sample-c0.nc4 -rw-r--r-- 1 clarmylee staff 44M 3 12 15:44 era5-sample-c1.nc4 -rw-r--r-- 1 clarmylee staff 44M 3 12 15:44 era5-sample-c2.nc4 -rw-r--r-- 1 clarmylee staff 44M 3 12 15:44 era5-sample-c3.nc4 -rw-r--r-- 1 clarmylee staff 44M 3 12 15:44 era5-sample-c4.nc4 -rw-r--r-- 1 clarmylee staff 44M 3 12 15:44 era5-sample-c5.nc4 -rw-r--r-- 1 clarmylee staff 44M 3 12 15:44 era5-sample-c6.nc4 -rw-r--r-- 1 clarmylee staff 44M 3 12 15:44 era5-sample-c7.nc4 -rw-r--r-- 1 clarmylee staff 44M 3 12 15:44 era5-sample-c8.nc4 -rw-r--r-- 1 clarmylee staff 44M 3 12 15:44 era5-sample-c9.nc4 -rw-r--r-- 1 clarmylee staff 161M 3 12 15:26 era5-sample-class.nc3 -rw-r--r-- 1 clarmylee staff 161M 3 12 15:27 era5-sample-class.nc4
可以看到,在无压缩的状态下,nc4的体积为161M,而使用1-9级压缩后的结果都是44M,也就是说NetCDF4格式下,压缩与非压缩的结果差异很大,而不同等级之间的压缩差异很小,并且非压缩的NetCDF4与NetCDF3的体积一样大。
我们再对其进行bz2
压缩,执行$ bzip2 -k era5-sample-*nc*
然后画出图来看一下:
从上图可以看出来,按照非bz2
算法压缩的形式排序,体积最大的是未经任何压缩的NetCDF4格式的文件,而体积最小的是9级压缩的NetCDF4格式。
若按照bz2
压缩之后的文件体积来看的话,NetCDF3经bz2
压缩以后会比NetCDF4的体积更小。
4种格式体积的交叉对比
下面综合上面所有的压缩或不压缩以及不同压缩级别的格式,汇总在一起来看一下它们的体积对比
上图是按照非bz2
压缩体积从大到小排序的,可以看出来的是,按照不丧失可读性的原始文件排序,依然是complex3
压缩算法下的GRIB2格式的文件体积最小。
而使用bz2
压缩后的格式排序,体积最小的依然是aec
压缩算法下的GRIB2格式。
结论
从上述的对比中,我们可以得出结论,不论是否使用bz2
压缩,体积最小的都是GRIB2家族的文件格式,在非bz2
模式下体积最小的是基于complex3
压缩算法的GRIB2文件,在bz2
模式下体积最小的是基于aec
压缩算法的GRIB2文件,当然这仅仅是从体积的角度来考虑。若要考察读取速度,则还需要额外的实验和测试。
若要引用本文,请使用以下引用格式:
Wentao Li. (2022). 一份GRIB与NetCDF的体积对比报告 (Version v1). Zenodo. https://doi.org/10.5281/zenodo.6348695
近期评论