0

我正在努力解决这个问题。

我创建了一个具有以下维度和变量的 netcdf4 文件(特别注意无限point维度):

dimensions:
    point = UNLIMITED ; // (275935 currently)
    realization = 24 ;
variables:
    short mod_hs(realization, point) ;
        mod_hs:scale_factor = 0.01 ;
    short mod_ws(realization, point) ;
        mod_ws:scale_factor = 0.01 ;
    short obs_hs(point) ;
        obs_hs:scale_factor = 0.01 ;
    short obs_ws(point) ;
        obs_ws:scale_factor = 0.01 ;
    short fchr(point) ;
    float obs_lat(point) ;
    float obs_lon(point) ;
    double obs_datetime(point) ;
}

我有一个 Python 程序,它在循环中用数据填充这个文件(因此无限的记录维度 - 我不知道先验文件有多大)。

填充文件后,大小为 103MB。

我的问题是从这个文件中读取数据非常慢。我猜这与分块和无限point维度有关?

ncks --fix_rec_dmn在该文件上运行,(经过大量搅动)它生成了一个新的 netCDF 文件,该文件的大小仅为 32MB(对于它包含的数据来说,这大约是正确的大小)。

这是大小上的巨大差异 - 为什么原始文件如此臃肿?此外 - 访问此文件中的数据要快几个数量级。例如,在 Python 中,读取hs变量的内容在原始文件上需要 2 秒,而在固定记录维度文件上需要 40 毫秒。

我遇到的问题是我的一些文件包含很多点并且似乎太大而无法运行ncks(我的机器内存不足,我有 8GB),所以我无法将所有数据转换为固定记录维度.

谁能解释为什么文件大小如此不同,以及如何使原始文件更小,阅读效率更高?

顺便说一句 - 我没有使用 zlib 压缩(我选择将浮点值缩放为整数 short)。

克里斯

编辑 我的 Python 代码本质上是在 3 个月内从多个单独的模型预测文件中构建一个包含并置模型和观测数据的单个时间序列文件。我的预测模型每天运行 4 次,我汇总了 3 个月的数据,因此大约有 120 个文件。

该程序从每个文件中提取预测周期的子集(et T+24h -> T+48h),因此连接文件并不是一件简单的事情。

这是我的代码在做什么的粗略近似(它实际上读/写了更多变量,但为了清楚起见,我在这里只显示 2):

# Create output file:
dout = nc.Dataset(fn, mode='w', clobber=True, format="NETCDF4")

dout.createDimension('point', size=None)
dout.createDimension('realization', size=24)

for varname in ['mod_hs','mod_ws']:
    v = ncd.createVariable(varname, np.short, 
            dimensions=('point', 'realization'), zlib=False)
    v.scale_factor = 0.01

# Cycle over dates
date = <some start start>
end_dat = <some end date>

# Keeo track if record dimension ('point') size:
n = 0

while date < end_date: 
    din = nc.Dataset("<path to input file>", mode='r')
    fchr = din.variables['fchr'][:]

    # get mask for specific forecast hour range
    m = np.logical_and(fchr >= 24, fchr < 48)
    sz = np.count_nonzero(m)

    if sz == 0:
        continue

    dout.variables['mod_hs'][n:n+sz,:] = din.variables['mod_hs'][:][m,:]
    dout.variables['mod_ws'][n:n+sz,:] = din.variables['mod_wspd'][:][m,:]

    # Increment record dimension count:
    n += sz

    din.close()

    # Goto next file
    date += dt.timedelta(hours=6)

dout.close()

有趣的是,如果我将输出文件格式NETCDF3_CLASSIC而不是NETCDF4输出大小设置为我期望的大小。NETCDF4 输出似乎臃肿。

4

3 回答 3

1

我的经验是,记录维度的默认块大小取决于下面的 netCDF 库的版本。对于 4.3.3.1,它是 524288。275935 条记录大约是半个记录块。ncks 自动选择(不告诉您)比 netCDF 默认值更合理的块大小,因此输出得到了更好的优化。我认为这就是正在发生的事情。见http://nco.sf.net/nco.html#cnk

于 2015-11-07T20:27:14.153 回答
0

如果可能,请尝试提供无需修改即可工作的代码,我必须进行编辑才能使其正常工作,但这并不太难。

import netCDF4 as nc
import numpy as np
dout = nc.Dataset('testdset.nc4', mode='w', clobber=True, format="NETCDF4")
dout.createDimension('point', size=None)
dout.createDimension('realization', size=24)
for varname in ['mod_hs','mod_ws']:
    v = dout.createVariable(varname, np.short, 
            dimensions=('point', 'realization'), zlib=False,chunksizes=[1000,24])
    v.scale_factor = 0.01
date = 1
end_date = 5000
n = 0
while date < end_date: 
    sz=100
    dout.variables['mod_hs'][n:n+sz,:] = np.ones((sz,24))
    dout.variables['mod_ws'][n:n+sz,:] = np.ones((sz,24))
    n += sz
    date += 1
dout.close()

主要区别在于 createVariable 命令。对于文件大小,在创建变量时没有提供“块大小”,与添加它时相比,我也得到了两倍大的文件。因此,对于文件大小,它应该可以解决问题。对于从文件中读取变量,我实际上没有注意到任何区别,也许我应该添加更多变量?无论如何,现在应该清楚如何添加块大小了,您可能需要进行一些测试以获得针对您的问题的良好配置。如果它仍然不适合您,请随时询问更多信息,如果您想了解更多关于分块的信息,请阅读hdf5 文档

于 2015-10-30T22:06:00.483 回答
0

我认为您的问题是无限维度的默认块大小为 1,这会创建大量内部 HDF5 结构。通过显式设置块大小(对于无限维度显然可以),第二个示例在空间和时间上做得更好。

无限维度需要在 HDF5/netCDF4 中进行分块,因此如果您想要无限维度,您必须考虑分块性能,正如您所发现的那样。

更多在这里:

https://www.unidata.ucar.edu/software/netcdf/docs/netcdf_perf_chunking.html

于 2015-11-06T03:20:13.627 回答