1

我正在尝试做一些应该相当普遍的事情。将复合数据类型的数组写入 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
4

0 回答 0