为啥 Fortran HDF5 的无限最大维度参数 (H5S_UNLIMITED_F) 的计算结果为零而不是 -1?

Posted

技术标签:

【中文标题】为啥 Fortran HDF5 的无限最大维度参数 (H5S_UNLIMITED_F) 的计算结果为零而不是 -1?【英文标题】:Why does Fortran HDF5's unlimited maximum dimension parameter (H5S_UNLIMITED_F) evaluate to zero instead of -1?为什么 Fortran HDF5 的无限最大维度参数 (H5S_UNLIMITED_F) 的计算结果为零而不是 -1? 【发布时间】:2013-07-16 05:15:27 【问题描述】:

我正在尝试编译一个 Fortran 应用程序来编写 HDF5 文件。我的编译器是 gfortran 4.7.2。具体来说,我正在尝试创建一个具有一组当前维度和最大维度的数据空间。我希望最后一个维度具有无限的最大维度。 Fortran HDF5 的文档不多,但我发现可以通过将相关维度设置为H5S_UNLIMITED_F 来指定这一点。该值应该计算为 -1,但在我的应用程序中,它的计算结果为 0,这会导致运行时错误,因为 0 小于相应的当前维度(在我的情况下为 20)。这是错误:

HDF5-DIAG: Error detected in HDF5 (1.8.11) thread 0:
  #000: H5S.c line 1388 in H5Screate_simple(): maxdims is smaller than dims
    major: Invalid arguments to routine
    minor: Bad value

我编译了 HDF5 附带的 Fortran 示例之一,它使用相同的 H5S_UNLIMITED_F 参数 (h5_extend.f90),但对于该应用程序,该参数的计算结果为 -1 并且没有问题。

我可能做错了什么?

以下是我编写的一个测试程序,用于复制项目中出现的问题:

program simple_test

use hdf5
implicit none

integer :: irank, hdferr
integer(hsize_t) :: ny, nx, nz
real, dimension(:,:,:), allocatable :: dset
character (len = 256) :: hdf_file, dlab
integer(hid_t) :: file_handle, mem_space, file_space, dset_handle
integer(hsize_t), dimension(:), allocatable :: dim_array, max_array

irank = 3
ny = 10
nx = 15
nz = 20
allocate (dset(ny, nx, nz))
hdf_file = 'simple_test.hdf5'
dlab = 'simple_data'
allocate (dim_array(irank))
allocate (max_array(irank))

dim_array = (/ ny, nx, nz /)
max_array = (/ ny, nx, H5S_UNLIMITED_F /)

print *, 'h5s_unlimited_f: ', h5s_unlimited_f
print *, 'dim_array: ', dim_array
print *, 'max_array: ', max_array

call h5open_f(hdferr)
if (hdferr .eq. -1) then
    print *, 'Error opening HDF5 Fortran interface.'
end if

! Create a new file.
call h5fcreate_f(hdf_file, H5F_ACC_TRUNC_F, file_handle, hdferr)
if (hdferr .eq. -1) then
    print *, 'Error creating HDF5 file.'
end if

! Create memory dataspace.
call h5screate_simple_f(irank, dim_array, mem_space, hdferr, max_array)
if (hdferr .eq. -1) then
    print *, 'Error creating HDF5 memory dataspace.'
end if

! Create the dataset.
call h5dcreate_f(file_handle, trim(dlab), H5T_IEEE_F32LE, mem_space, &
        dset_handle, hdferr)
if (hdferr .eq. -1) then
    print *, 'Error creating HDF5 dataset.'
end if

! Create file dataspace.
call h5screate_simple_f(irank, dim_array, file_space, hdferr, max_array)
if (hdferr .eq. -1) then
    print *, 'Error creating HDF5 file dataspace.'
end if

call h5dwrite_f(dset_handle, H5T_IEEE_F32LE, dset, dim_array, hdferr, &
        mem_space, file_space)
if (hdferr .eq. -1) then
    print *, 'Error writing HDF5 dataset.'
end if

call h5close_f(hdferr)
if (hdferr .eq. -1) then
    print *, 'Error closing HDF5 Fortran interface.'
end if

deallocate (dset)
deallocate (dim_array)
deallocate (max_array)

end program simple_test

第一次调用h5s_create_simple_f 失败了。如果我将内存数据空间更改为不使用 max_array 参数(因为它是可选的,在我的情况下可能是不必要的),那么在第二次调用 h5s_create_simple_f 时我仍然会遇到相同的错误。

我编译如下:

gfortran -c simple_test.f90 -o simple_test.o -I<hdf5_include_path>
gfortran -o simple_test simple_test.o -L<hdf5_lib_path> -lhdf5_fortran -lhdf5hl_fortran

我也尝试将 max_array(irank) 设置为 -1,但这会产生完全不同的错误。

【问题讨论】:

【参考方案1】:

(最初的问题是 H5S_UNLIMITED_F 是一个通过调用 H5open_f 进行初始化的变量,在不允许初始化之前引用它。)

您确定对H5S_create_simple_f 的调用失败了吗?您的回溯表明库的数据集部分存在错误。

我预计数据集创建会失败,因为对于可变大小的数据集,您需要指定块大小。使用H5Pcreate_f 创建一个属性列表,然后使用H5Pset_chunk_f 设置块大小,然后在调用H5Dcreate_f 的错误参数之后提供该属性列表。如果这没有意义,请发表评论,我会举一个例子。

【讨论】:

我的程序输出Error creating HDF5 memory dataspace,有或没有属性列表和分块调用。该输出表明第一个 h5s_create_simple_f 失败。这里的重要元素是 h5s_unlimited_f 正在评估为 0(而不是文档中指定的 -1),print 语句确认了这一点。 在您第一次引用 h5s_unlimited_f 变量之后,您调用 H5open_f() 来初始化库。它不会被初始化。 很确定它就在那里!再检查一遍。 :) 啊!你是对的!如果我在h5_open_f 之后引用它,它确实会正确评估为-1。就是这样。我现在正在调查其他错误,但我不太担心那部分。 是的,您对数据集创建的建议也很关键!这解决了其余的错误。无论如何,我很快就会研究分块,但不正确的h5s_unlimited_f 让我分心。也感谢这些提示。

以上是关于为啥 Fortran HDF5 的无限最大维度参数 (H5S_UNLIMITED_F) 的计算结果为零而不是 -1?的主要内容,如果未能解决你的问题,请参考以下文章

从 Fortran 中的 HDF 文件中读取长度未知的数组

HDF5:构建 Fortran 库 (Windows)

链接静态 HDF5 Fortran 库

在 Fortran 中获取 HDF5 文件名的长度?

在 fortran 中将写入附加到 hdf5 文件

如何使用 Fortran API 将字符串数组写入 HDF5 数据集?