我正在尝试做一些应该相当普遍的事情。将复合数据类型的数组写入 hdf5 文件,扩展文件并将数组的新值写入 out 等等。我想在循环中执行此操作。我将我的数据集初始化为零长度,然后在循环中根据需要对其进行扩展。如果循环是 1 次行程,它可以正常工作:
HDF5 "mydata_1trip.h5" {
GROUP "/" {
DATASET "MYDATA" {
DATATYPE H5T_COMPOUND {
H5T_STD_I32LE "i4_name";
H5T_STD_I16LE "i21_name";
H5T_STD_I16LE "i22_name";
H5T_IEEE_F64LE "r8_name";
}
DATASPACE SIMPLE { ( 2 ) / ( H5S_UNLIMITED ) }
DATA {
(0): {
-100,
-1,
0,
1e+06
},
(1): {
-100,
-1,
0,
1e+06
} } } } }
使用 2 次行程循环,数据集被正确扩展,但第二次写入会覆盖原始数据(并将垃圾放入第二个数据集中)。那么问题似乎出在偏移量上?
HDF5 "mydata_2trip.h5" {
GROUP "/" {
DATASET "MYDATA" {
DATATYPE H5T_COMPOUND {
H5T_STD_I32LE "i4_name";
H5T_STD_I16LE "i21_name";
H5T_STD_I16LE "i22_name";
H5T_IEEE_F64LE "r8_name";
}
DATASPACE SIMPLE { ( 4 ) / ( H5S_UNLIMITED ) }
DATA {
(0): {
-200,
-2,
0,
2e+06
},
(1): {
-200,
-2,
0,
2e+06
},
(2): {
107382520,
1,
0,
0
},
(3): {
107375576,
1,
0,
4.94066e-324
}
}
}
}
}
这是代码
program read_test
USE hdf5
USE ISO_C_BINDING
implicit none
种类参数
INTEGER, PARAMETER :: int_k1 = SELECTED_INT_KIND(1) ! This should map to INTEGER*1 on most modern processors
INTEGER, PARAMETER :: int_k2 = SELECTED_INT_KIND(4) ! This should map to INTEGER*2 on most modern processors
INTEGER, PARAMETER :: int_k4 = SELECTED_INT_KIND(8) ! This should map to INTEGER*4 on most modern processors
INTEGER, PARAMETER :: int_k8 = SELECTED_INT_KIND(16) ! This should map to INTEGER*8 on most modern processors
INTEGER, PARAMETER :: r_k4 = SELECTED_REAL_KIND(5) ! This should map to REAL*4 on most modern processors
INTEGER, PARAMETER :: r_k8 = SELECTED_REAL_KIND(10) ! This should map to REAL*8 on most modern processors
文件
CHARACTER(LEN=*), PARAMETER ::
& H5FILE_NAME="mydata.h5"
CHARACTER(LEN=*), PARAMETER :: DATASETNAME = "MYDATA"
type my_data
sequence
integer(kind=int_k4) :: i4
integer(kind=int_k2) :: i1_2,i2_2
real (kind=r_k8) :: r8
end type
integer(kind=int_k4) :: nsize=2,i
type(my_data),allocatable :: iblock(:)
INTEGER, PARAMETER :: RANK = 1
TYPE(my_data), pointer :: s1(:)
INTEGER(hid_t) :: s1_tid ! File datatype identifier
INTEGER(HID_T) :: file_id ! File identifier
INTEGER(HID_T) :: dset_id ! Dataset identifier
INTEGER(HID_T) :: dataspace ! Dataspace identifier
INTEGER(HID_T) :: memspace ! Memory dataspace identifier
INTEGER(HID_T) :: crp_list ! Dataset creation property identifier
INTEGER(hsize_t) :: DIMS(1) ! Dataspace dimensions
INTEGER(SIZE_T) :: type_size ! Size of the datatype
INTEGER(SIZE_T) :: compound_offset, sizeof_compound
INTEGER(HSIZE_T), DIMENSION(1) :: chunk_dims,size
INTEGER :: hdferr
TYPE(C_PTR) :: f_ptr
最大尺寸
INTEGER(HSIZE_T), DIMENSION(1) :: maxdims
INTEGER(HSIZE_T), DIMENSION(1) :: offset
INTEGER(HSIZE_T), DIMENSION(1) :: count
分配缓冲区:
allocate(iblock(nsize))
dims(1) = nsize
allocate(s1(dims(1)))
初始化 FORTRAN 接口。
CALL h5open_f(hdferr)
使用默认属性创建一个新文件。
CALL h5fcreate_f(h5file_name, H5F_ACC_TRUNC_F, file_id, hdferr)
我们最初将其设置为 0。我们可以在每一步扩展数据集。
maxdims = (/H5S_UNLIMITED_F/)
dims(1) = 0
write(*,*)" dims = ",dims
创建具有无限维度的数据空间。
CALL H5Screate_simple_f(RANK, dims, dataspace, hdferr,maxdims)
然后创建数据集创建属性列表。使用无限维度时,必须对数据集的布局进行分块。块大小的选择会影响性能,包括时间和磁盘空间。如果块非常小,您将有很多开销。如果它们太大,您可能会分配不需要的空间,并且您的文件最终可能会太大。这是一个玩具示例,因此我们将选择一行的块。
修改数据集创建属性,即启用分块
CALL h5pcreate_f(H5P_DATASET_CREATE_F, crp_list, hdferr)
chunk_dims(1) = nsize
CALL h5pset_chunk_f(crp_list, RANK, chunk_dims, hdferr)
创建内存数据类型。
CALL H5Tcreate_f(H5T_COMPOUND_F, H5OFFSETOF(C_LOC(s1(1)),
& C_LOC(s1(2))), s1_tid, hdferr)
CALL H5Tinsert_f(s1_tid, "i4_name",
& H5OFFSETOF(C_LOC(s1(1)),C_LOC(s1(1)%i4)),
& h5kind_to_type(int_k4,H5_INTEGER_KIND), hdferr)
CALL H5Tinsert_f(s1_tid, "i21_name",
& H5OFFSETOF(C_LOC(s1(1)),C_LOC(s1(1)%i1_2)),
& h5kind_to_type(int_k2,H5_INTEGER_KIND), hdferr)
CALL H5Tinsert_f(s1_tid, "i22_name",
& H5OFFSETOF(C_LOC(s1(1)),C_LOC(s1(1)%i2_2)),
& h5kind_to_type(int_k2,H5_INTEGER_KIND), hdferr)
CALL H5Tinsert_f(s1_tid, "r8_name",
& H5OFFSETOF(C_LOC(s1(1)),C_LOC(s1(1)%r8)),
& h5kind_to_type(r_k8,H5_REAL_KIND), hdferr)
创建数据集。
CALL H5Dcreate_f(file_id, datasetname, s1_tid, dataspace,
& dset_id, hdferr,crp_list)
关闭资源。数据集现已创建,因此我们不再需要属性列表。我们不再需要文件数据空间,因为当数据集被扩展时,它将变得无效,因为它仍将保留以前的范围。所以无论如何我们都必须获取更新的文件数据空间。
call h5pclose_f(crp_list,hdferr)
CALL h5sclose_f(dataspace, hdferr)
我们创建一个内存数据空间来指示内存中缓冲区的大小。
dims(1) = nsize
CALL h5screate_simple_f(RANK, dims, dataspace, hdferr)
设置输入数据
do i=1,2
iblock(:)%i4 = -100*i
iblock(:)%i1_2 = i
iblock(:)%i2_2 = -i
iblock(:)%r8 = 1.d6*i
将数据写入 memtype
s1(:) = iblock(:)
我们创建一个内存数据空间来指示内存中缓冲区的大小。dims(1) 已经是 nsize
我们现在需要扩展数据集。我们将数据集的初始大小设置为 0,因此我们需要先扩展它。请注意,我们扩展了数据集本身,而不是它的数据空间。
size(1) = i*nsize
CALL h5dset_extent_f(dset_id, size, hdferr)
dims(1) = nsize
CALL h5screate_simple_f (rank, dims, memspace, hdferr)
CALL h5dget_space_f(dset_id, dataspace, hdferr)
offset(1) = (i-1)*nsize ! if this is in chunks
count(1) = nsize
CALL h5sselect_hyperslab_f(dataspace, H5S_SELECT_SET_F,
& offset, count, hdferr)
将数据数组写入数据集
f_ptr = C_LOC(s1(1))
CALL H5Dwrite_f(dset_id, s1_tid, f_ptr, hdferr)
CALL h5sclose_f(dataspace,hdferr)
enddo
释放资源
CALL H5Tclose_f(s1_tid, hdferr)
CALL h5sclose_f(memspace, hdferr)
CALL h5dclose_f(dset_id, hdferr)
CALL h5fclose_f(file_id, hdferr)
end program read_test