Search code examples
fortranconstantsdimensionshdf5

Why does Fortran HDF5's unlimited maximum dimension parameter (H5S_UNLIMITED_F) evaluate to zero instead of -1?


I'm try to compile a Fortran application to write HDF5 files. My compiler is gfortran 4.7.2. Specifically, I'm trying to create a dataspace with a certain set of current dimensions and maximum dimensions. I want the last dimension to have an unlimited maximum dimension. There isn't much documentation for Fortran HDF5, but I was able to figure out that this can be specified by setting that dimension in question to H5S_UNLIMITED_F. This value is supposed to evaluate to -1, but in my application it instead evaluates to 0, which causes a runtime error because 0 is less than the corresponding current dimension (in my case, 20). This is the error:

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

I compiled one of the Fortran examples that came with HDF5 that uses the same H5S_UNLIMITED_F parameter (h5_extend.f90), but for that application, the parameter evaluates to -1 and there is no problem.

What might I be doing wrong?

Below is a test program I wrote to replicate the problem seen in my project:

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

The first call to h5s_create_simple_f is what fails. If I change the memory dataspace to not use the max_array parameter (since it is optional and in my case perhaps unnecessary), then I still get the same error on the second call to h5s_create_simple_f.

I'm compiling as follows:

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

I've also tried setting max_array(irank) to -1, but that yields an entirely different error.


Solution

  • (The original issue was that H5S_UNLIMITED_F is a variable that is initialised by a call to H5open_f, referencing it before that initialization is not permitted.)

    Are you sure that the call to H5S_create_simple_f is what fails? Your traceback indicates an error from the dataset portion of the library.

    I would expect a failure from dataset creation, because for variable sized datasets you need to specify the chunk size. Create a property list using H5Pcreate_f, then set the chunk size using H5Pset_chunk_f, then provide that property list after the error argument in the call to H5Dcreate_f. Comment if that doesn't make sense and I'll dig out an example.