UP | HOME

HDF5 back end

Table of Contents

1 HDF5 back end

1.1 Template for HDF5 definitions

#define $GROUP$_GROUP_NAME          "$group$"
#define $GROUP_NUM$_NAME            "$group_num$"
#define $GROUP$_$GROUP_DSET$_NAME   "$group_dset$"

1.2 Template for HDF5 structures

typedef struct trexio_hdf5_s {
  trexio_t     parent ;
  hid_t      file_id;
  hid_t      $group$_group;
  const char* file_name;
} trexio_hdf5_t;

1.3 Template for HDF5 init/deinit

trexio_exit_code
trexio_hdf5_init (trexio_t* const file)
{

  trexio_hdf5_t* const f = (trexio_hdf5_t*) file;

  /* If file doesn't exist, create it */
  int f_exists = 0;
  struct stat st;

  if (stat(file->file_name, &st) == 0) f_exists = 1;

  if (f_exists == 1) {

    switch (file->mode) {
    case 'r':
      // reading the existing file -> open as RDONLY
      f->file_id = H5Fopen(file->file_name, H5F_ACC_RDONLY, H5P_DEFAULT);
      break;
    case 'a':
      // appending the existing file -> open as RDWR
      f->file_id = H5Fopen(file->file_name, H5F_ACC_RDWR, H5P_DEFAULT);
      break;
    case 'w':
      // writing the existing file -> overwrite it (_TRUNC) [_EXCL | H5F_ACC_DEBUG as an alternative]
      f->file_id = H5Fcreate(file->file_name, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
      break;
    }

  } else {

    switch (file->mode) {
    case 'r':
    case 'a':
      // reading or appending non-existing file -> error
      return TREXIO_FAILURE;
    case 'w':
      // writing non-existing file -> create it
      f->file_id = H5Fcreate(file->file_name, H5F_ACC_EXCL, H5P_DEFAULT, H5P_DEFAULT);
      break;
    }

  }

  /* Create or open groups in the hdf5 file assuming that they exist if file exists */
  switch (file->mode) {
    // the switch for 'r'/'a' is reached only if file exists
    case 'r':
    case 'a':
      f->$group$_group = H5Gopen(f->file_id, $GROUP$_GROUP_NAME, H5P_DEFAULT);
      break;
    case 'w':
      f->$group$_group = H5Gcreate(f->file_id, $GROUP$_GROUP_NAME, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
      break;
  }
  if (f->$group$_group <= 0L) return TREXIO_INVALID_ID;

  return TREXIO_SUCCESS;
}

trexio_exit_code
trexio_hdf5_deinit (trexio_t* const file)
{

  trexio_hdf5_t* f = (trexio_hdf5_t*) file;

  H5Gclose(f->$group$_group);
  f->$group$_group = 0;

  H5Fclose(f->file_id);
  f->file_id = 0;

  return TREXIO_SUCCESS;

}

1.4 Template for HDF5 has/read/write a number

trexio_exit_code
trexio_hdf5_read_$group_num$ (trexio_t* const file, uint64_t* const num)
{

  if (file == NULL) return TREXIO_INVALID_ARG_1;
  if (num  == NULL) return TREXIO_INVALID_ARG_2;

  const trexio_hdf5_t* f = (const trexio_hdf5_t*) file;
  /* Quit if the dimensioning attribute is missing in the file */
  if (H5Aexists(f->$group$_group, $GROUP_NUM$_NAME) == 0) return TREXIO_FAILURE;

  /* Read the nucleus_num attribute of nucleus group */
  const hid_t num_id = H5Aopen(f->$group$_group, $GROUP_NUM$_NAME, H5P_DEFAULT);
  if (num_id <= 0) return TREXIO_INVALID_ID;

  const herr_t status = H5Aread(num_id, H5T_NATIVE_UINT64, num);
  if (status < 0) return TREXIO_FAILURE;

  return TREXIO_SUCCESS;

}
trexio_exit_code
trexio_hdf5_write_$group_num$ (trexio_t* const file, const uint64_t num)
{

  if (file == NULL) return TREXIO_INVALID_ARG_1;
  if (num  == 0L  ) return TREXIO_INVALID_ARG_2;

  trexio_hdf5_t* const f = (trexio_hdf5_t*) file;

  if (H5Aexists(f->$group$_group, $GROUP_NUM$_NAME) == 0) {

    /* Write the dimensioning variables */
    const hid_t dtype = H5Tcopy(H5T_NATIVE_UINT64);
    const hid_t dspace = H5Screate(H5S_SCALAR);

    const hid_t num_id = H5Acreate(f->$group$_group, $GROUP_NUM$_NAME, dtype, dspace,
                     H5P_DEFAULT, H5P_DEFAULT);
    if (num_id <= 0) {
      H5Sclose(dspace);
      H5Tclose(dtype);
      return TREXIO_INVALID_ID;
    }

    const herr_t status = H5Awrite(num_id, dtype, &(num));
    if (status < 0) {
      H5Aclose(num_id);
      H5Sclose(dspace);
      H5Tclose(dtype);
      return TREXIO_FAILURE;
    }

    H5Sclose(dspace);
    H5Aclose(num_id);
    H5Tclose(dtype);
    return TREXIO_SUCCESS;

  } else {

    uint64_t infile_num;
    trexio_exit_code rc = trexio_hdf5_read_$group_num$(file, &(infile_num));
    if (rc != TREXIO_SUCCESS) return rc;

    if (infile_num != num) {

      if (infile_num != 0) {
        printf("%lu -> %lu %s \n", num, infile_num,
               "This variable already exists. Overwriting it is not supported");
        return TREXIO_FAILURE;

      } else {

        const hid_t dtype = H5Tcopy(H5T_NATIVE_UINT64);
        const hid_t num_id = H5Aopen(f->$group$_group, $GROUP_NUM$_NAME, H5P_DEFAULT);
        if (num_id <= 0) return TREXIO_INVALID_ID;

        const herr_t status = H5Awrite(num_id, dtype, &(num));
        if (status < 0) return TREXIO_FAILURE;

        H5Aclose(num_id);
        H5Tclose(dtype);
      }
    }
    return TREXIO_SUCCESS;
  }

}
trexio_exit_code
trexio_hdf5_has_$group_num$ (trexio_t* const file)
{

  if (file == NULL) return TREXIO_INVALID_ARG_1;

  const trexio_hdf5_t* f = (const trexio_hdf5_t*) file;

  htri_t status = H5Aexists(f->$group$_group, $GROUP_NUM$_NAME);
  /* H5Aexists returns positive value if attribute exists, 0 if does not, negative if error */
  if (status > 0){
    return TREXIO_SUCCESS;
  } else if (status == 0) {
    return TREXIO_HAS_NOT;
  } else {
    return TREXIO_FAILURE;
  }

}

1.5 Template for HDF5 has/read/write a dataset

trexio_exit_code
trexio_hdf5_read_$group$_$group_dset$ (trexio_t* const file, $group_dset_dtype$* const $group_dset$,
                                       const uint32_t rank, const uint64_t* dims)
{

  if (file == NULL) return TREXIO_INVALID_ARG_1;
  if ($group_dset$  == NULL) return TREXIO_INVALID_ARG_2;

  const trexio_hdf5_t* f = (const trexio_hdf5_t*) file;

  herr_t status;
  int rrank;
  // get the rank of the dataset in a file
  status = H5LTget_dataset_ndims (f->$group$_group, $GROUP$_$GROUP_DSET$_NAME, &rrank);

  if (status < 0) return TREXIO_FAILURE;

  if (rrank != (int) rank) return TREXIO_INVALID_ARG_3;

  // open the dataset to get its dimensions
  hid_t dset_id = H5Dopen(f->$group$_group, $GROUP$_$GROUP_DSET$_NAME, H5P_DEFAULT);
  if (dset_id <= 0) return TREXIO_INVALID_ID;

  // allocate space for the dimensions to be read
  hsize_t* ddims = CALLOC( (int) rank, hsize_t);
  if (ddims == NULL) return TREXIO_FAILURE;

  // read dimensions from the existing dataset
  status = H5LDget_dset_dims(dset_id, ddims);

  H5Dclose(dset_id);
  if (status < 0) {
    free(ddims);
    return TREXIO_FAILURE;
  }

  for (uint32_t i=0; i<rank; ++i){
    if (ddims[i] != dims[i]) {
      free(ddims);
      return TREXIO_INVALID_ARG_4;
    }
  }
  free(ddims);

  /* High-level H5LT API. No need to deal with dataspaces and datatypes */
  status = H5LTread_dataset(f->$group$_group,
                            $GROUP$_$GROUP_DSET$_NAME,
                            H5T_NATIVE_$GROUP_DSET_H5_DTYPE$,
                            $group_dset$);
  if (status < 0) return TREXIO_FAILURE;

  return TREXIO_SUCCESS;
}
trexio_exit_code
trexio_hdf5_write_$group$_$group_dset$ (trexio_t* const file, const $group_dset_dtype$* $group_dset$,
                                        const uint32_t rank, const uint64_t* dims)
{

  if (file == NULL) return TREXIO_INVALID_ARG_1;
  if ($group_dset$  == NULL) return TREXIO_INVALID_ARG_2;

  trexio_exit_code rc;
  uint64_t $group_dset_dim$;
  // error handling for rc is added by the generator
  rc = trexio_hdf5_read_$group_dset_dim$(file, &($group_dset_dim$));
  if ($group_dset_dim$ == 0L) return TREXIO_INVALID_NUM;

  trexio_hdf5_t* f = (trexio_hdf5_t*) file;

  if ( H5LTfind_dataset(f->$group$_group, $GROUP$_$GROUP_DSET$_NAME) != 1 ) {

    const herr_t status = H5LTmake_dataset(f->$group$_group,
                                           $GROUP$_$GROUP_DSET$_NAME,
                                           (int) rank, (const hsize_t*) dims,
                                           H5T_NATIVE_$GROUP_DSET_H5_DTYPE$,
                                           $group_dset$);
    if (status < 0) return TREXIO_FAILURE;

  } else {

    hid_t dset_id = H5Dopen(f->$group$_group, $GROUP$_$GROUP_DSET$_NAME, H5P_DEFAULT);
    if (dset_id <= 0) return TREXIO_INVALID_ID;

    const herr_t status = H5Dwrite(dset_id,
                                   H5T_NATIVE_$GROUP_DSET_H5_DTYPE$,
                                   H5S_ALL, H5S_ALL, H5P_DEFAULT,
                                   $group_dset$);

    H5Dclose(dset_id);
    if (status < 0) return TREXIO_FAILURE;

  }

  return TREXIO_SUCCESS;

}
trexio_exit_code
trexio_hdf5_has_$group$_$group_dset$ (trexio_t* const file)
{

  if (file == NULL) return TREXIO_INVALID_ARG_1;

  trexio_hdf5_t* f = (trexio_hdf5_t*) file;

  herr_t status = H5LTfind_dataset(f->$group$_group, $GROUP$_$GROUP_DSET$_NAME);
  /* H5LTfind_dataset returns 1 if dataset exists, 0 otherwise */
  if (status == 1){
    return TREXIO_SUCCESS;
  } else if (status == 0) {
    return TREXIO_HAS_NOT;
  } else {
    return TREXIO_FAILURE;
  }

}

Author: TREX-CoE

Created: 2021-05-06 Thu 11:40

Validate