HDF5 用于使用 fortran 编写的数据文件
Posted
技术标签:
【中文标题】HDF5 用于使用 fortran 编写的数据文件【英文标题】:HDF5 for data files written with fortran 【发布时间】:2013-02-26 08:14:42 【问题描述】:HDF5 数据存储使用 C 约定,即如果我将矩阵 A(N,M,K) 存储在二进制文件中,则存储数据的最快变化维度将具有大小 N。显然,当我使用HDF5的Fortran封装,HDF5自动转置矩阵,与C一致。
我有一个大小为(256 x 128 x 256)的数据存储在由 fortran 编写的未格式化二进制文件中。我正在尝试使用下面给出的程序将其转换为 h5 格式。但最终输出给了我存储矩阵的维度为 (128,256,256)。我不知道该怎么做才能确保最终的 hd5 文件可以在可视化软件 (Paraview) 中正确可视化。
PROGRAM H5_RDWT
USE HDF5 ! This module contains all necessary modules
IMPLICIT NONE
CHARACTER(LEN=6), parameter :: out_file = "out.h5" ! File name
CHARACTER(LEN=6), parameter :: in_file = "in.dat" ! File name
CHARACTER(LEN=4), parameter :: dsetname = "vort"! Dataset name
CHARACTER(LEN=50) :: len
INTEGER(HID_T) :: in_file_id ! File identifier
INTEGER(HID_T) :: out_file_id ! File identifier
INTEGER(HID_T) :: dset_id ! Dataset identifier
INTEGER(HID_T) :: dspace_id ! Dataspace identifier
INTEGER :: in_file_id = 23
INTEGER :: nx = 256, ny=128, nz=256
INTEGER(HSIZE_T), DIMENSION(3) :: dims ! Dataset dimensions
INTEGER :: rank = 3 ! Dataset rank
INTEGER :: error ! Error flag
INTEGER :: i, j, k, ii, jj, kk ! Indices
REAL, allocatable :: buff_r(:,:,:) ! buffer for reading from input file
dims(1) = nx
dims(2) = ny
dims(3) = nz
allocate(buff_r(nx,ny,nz))
! Read the input data.
open (in_file_id,FILE=in_file,form='unformatted',access='direct',recl=4*nx*ny*nz)
read (in_file_id,rec=1) buff_r
! Initialize FORTRAN interface of HDF5.
CALL h5open_f(error)
! Create a new file.
CALL h5fcreate_f (out_file, H5F_ACC_TRUNC_F, out_file_id, error)
! Create the dataspace.
CALL h5screate_simple_f(rank, dims, dspace_id, error)
! Create the dataset with default properties.
CALL h5dcreate_f(out_file_id, dsetname, H5T_NATIVE_REAL, dspace_id, &
dset_id, error)
! Write the dataset.
CALL h5dwrite_f(dset_id, H5T_NATIVE_REAL, buff_r, dims, error)
! End access to the dataset and release resources used by it.
CALL h5dclose_f(dset_id, error)
! Terminate access to the data space.
CALL h5sclose_f(dspace_id, error)
! Close the file.
CALL h5fclose_f(out_file_id, error)
! Close FORTRAN interface.
CALL h5close_f(error)
deallocate(buff_r)
END PROGRAM H5_RDWT
为了说明发生了什么,我正在使用以下脚本生成一个示例数据文件:
program main
!-------- initialize variables -------------
character(8) :: fname
integer, parameter:: n = 32
real*8, dimension(n,n,2*n) :: re
integer i,j,k, recl
Inquire( iolength = recl ) re
!------ fill in the array with sample data ----
do k = 1, 2*n
do j = 1, n
do i = 1, n
re(i,j,k) = 1.0
end do
end do
end do
!------ write in data in a file -----------
write(fname, "(A)") "data.dat"
open (10, file=fname, form='unformatted', access='direct', recl=recl)
write(10,rec=1) re
close(10)
stop
end program main
我复制粘贴了 Ian Bush 的程序,并将 nx、ny 和 nz 的值分别更改为 32、32 和 64。我希望生成的 h5 文件具有尺寸(32、32、64)。但结果是(64,32,32)。这是我的机器上发生的事情:
[pradeep@laptop]$gfortran generate_data.f90
[pradeep@laptop]$./a.out
[pradeep@laptop]$ls -l data.dat
-rw-r--r-- 1 pradeep staff 524288 Mar 12 14:04 data.dat
[pradeep@laptop]$h5fc convert_to_h5.f90
[pradeep@laptop]$./a.out
[pradeep@laptop]$ls -l out.h5
-rw-r--r-- 1 pradeep staff 526432 Mar 12 14:05 out.h5
[pradeep@laptop]$h5dump -H out.h5
HDF5 "out.h5"
GROUP "/"
DATASET "data"
DATATYPE H5T_IEEE_F64LE
DATASPACE SIMPLE ( 64, 32, 32 ) / ( 64, 32, 32 )
如果您看到相同的内容,请与我确认。
【问题讨论】:
【参考方案1】:我在查看使用 Fortran 应用程序编写的 HDF5 文件时也遇到了问题。基本问题是 Fortran 和 C 存储多维数组的方式不同(Fortran 是列优先的,C 是行优先的),并且由于 Fortran HDF5 库是 C HDF5 库的接口,因此 Fortran 包装器会在传递数据之前转置维度进入 C 代码。同样,当 Fortran 应用程序读取 HDF5 文件时,Fortran 包装器会再次转置维度。
因此,如果您使用 Fortran 应用程序进行所有的写作和阅读,您应该不会注意到任何差异。如果您使用 Fortran 应用程序编写文件,然后使用 C 应用程序(例如 h5dump)读取它,则尺寸将出现转置。这不是错误,而是它的工作原理。
如果您想正确显示数据,请使用 Fortran 应用程序读取数据或使用 C 应用程序并先转置数据。 (或者您可以在首先写入数据之前转置数据。)
正如已经提到的,这一切都在文档的第 7.3.2.5 节中得到了很好的解释:http://www.hdfgroup.org/HDF5/doc/UG/UG_frame12Dataspaces.html
【讨论】:
【参考方案2】:真的是长评论而不是答案......
您能解释一下为什么您认为它不起作用吗?一旦我纠正了您代码中的几处问题
1) in_file_id 用 2 种不同的类型声明了两次
2) 直接访问文件的 Recl 不一定以字节为单位 - 通过输出列表查询更便携
我得到以下内容,它生成了一个带有随机数据的虚拟文件,似乎可以工作:
ian@ian-pc:~/test/stack$ cat hdf5.f90
PROGRAM H5_RDWT
USE HDF5 ! This module contains all necessary modules
IMPLICIT NONE
CHARACTER(LEN=6), parameter :: out_file = "out.h5" ! File name
CHARACTER(LEN=6), parameter :: in_file = "in.dat" ! File name
CHARACTER(LEN=4), parameter :: dsetname = "vort"! Dataset name
CHARACTER(LEN=50) :: len
!!$ INTEGER(HID_T) :: in_file_id ! File identifier
INTEGER(HID_T) :: out_file_id ! File identifier
INTEGER(HID_T) :: dset_id ! Dataset identifier
INTEGER(HID_T) :: dspace_id ! Dataspace identifier
INTEGER(HID_T) :: in_file_id = 23
INTEGER :: nx = 256, ny=128, nz=256
INTEGER(HSIZE_T), DIMENSION(3) :: dims ! Dataset dimensions
INTEGER :: rank = 3 ! Dataset rank
Integer :: recl
INTEGER :: error ! Error flag
INTEGER :: i, j, k, ii, jj, kk ! Indices
REAL, allocatable :: buff_r(:,:,:) ! buffer for reading from input file
dims(1) = nx
dims(2) = ny
dims(3) = nz
allocate(buff_r(nx,ny,nz))
Inquire( iolength = recl ) buff_r
! Read the input data.
open (in_file_id,FILE=in_file,form='unformatted',access='direct',recl=recl)
read (in_file_id,rec=1) buff_r
! Initialize FORTRAN interface of HDF5.
CALL h5open_f(error)
! Create a new file.
CALL h5fcreate_f (out_file, H5F_ACC_TRUNC_F, out_file_id, error)
! Create the dataspace.
CALL h5screate_simple_f(rank, dims, dspace_id, error)
! Create the dataset with default properties.
CALL h5dcreate_f(out_file_id, dsetname, H5T_NATIVE_REAL, dspace_id, &
dset_id, error)
! Write the dataset.
CALL h5dwrite_f(dset_id, H5T_NATIVE_REAL, buff_r, dims, error)
! End access to the dataset and release resources used by it.
CALL h5dclose_f(dset_id, error)
! Terminate access to the data space.
CALL h5sclose_f(dspace_id, error)
! Close the file.
CALL h5fclose_f(out_file_id, error)
! Close FORTRAN interface.
CALL h5close_f(error)
deallocate(buff_r)
END PROGRAM H5_RDWT
ian@ian-pc:~/test/stack$ h5fc hdf5.f90
ian@ian-pc:~/test/stack$ ./a.out
ian@ian-pc:~/test/stack$ ls -l out.h5
-rw-rw-r-- 1 ian ian 33556576 Mar 11 10:29 out.h5
ian@ian-pc:~/test/stack$ ncdump out.h5 | head
netcdf out
dimensions:
phony_dim_0 = 256 ;
phony_dim_1 = 128 ;
variables:
float vort(phony_dim_0, phony_dim_1, phony_dim_0) ;
data:
vort =
0.9975595, 0.5668247, 0.9659153, 0.7479277, 0.3673909, 0.4806369,
ian@ian-pc:~/test/stack$
那你为什么认为有问题?
【讨论】:
感谢您指出错误。感谢您的推荐评论。该程序运行良好。但它给了我一个转置矩阵。例如,如果使用 fortran 我写了一个大小为 (256,128,256) 的 3D 数组,当我检查输出文件的数组尺寸时,它是 (128,256,256)。要检查输出的 h5 文件的尺寸,我使用“h5dump -H out.h5” 这是我在 HDF5 支持小组中联系的一个人的回复:hdfgroup.org/HDF5/doc/UG/UG_frame12Dataspaces.html,第 7.3.2.5 节。 C 与 Fortran 数据空间。但我不确定如何正确实现它以读取 fortran 二进制文件并以 h5 格式重写它 好吧,我完全糊涂了。我的 h5dump -H out.h5 输出给出了 DATASPACE SIMPLE ( 256, 128, 256 ) / ( 256, 128, 256 ) ,类似于 ncdump 在我的“答案”中报告的内容。我根本看不出你是怎么得到 (128, 256, 256) 的! 未格式化的读取在此阶段无关紧要。您可以跳过读取并设置 buff_r=0,它不会影响输出矩阵的标注方式。 除此之外,如果 recl!=4*nxnynz 报告错误,我会验证它是否符合您的预期。【参考方案3】:出于安全原因,我建议您将矩阵分解为矢量形式,并将它们作为一维数据集存储在 HDF5 文件中。然后,在阅读时以相同的方式组装它们。使用H5SSELECT_HYPERSLAB_F
写入/读取矩阵切片。
【讨论】:
Fortran 的 HDF5 库绑定完全能够处理多维数据集,您的建议部分消除了使用 HDF5 的兴趣。我建议不要关注它。以上是关于HDF5 用于使用 fortran 编写的数据文件的主要内容,如果未能解决你的问题,请参考以下文章
在 Fortran 中读取 HDF5 数据集的子集时出现问题
在 FORTRAN / MPI / HDF5 ( 1.10.1 ) 中使用 h5fopen_f 打开文件时出错
如何使用 Fortran API 将字符串数组写入 HDF5 数据集?