mirror of
https://github.com/TREX-CoE/trexio.git
synced 2025-01-09 20:48:53 +01:00
415 lines
10 KiB
Org Mode
415 lines
10 KiB
Org Mode
#+TITLE: HDF5 back end
|
|
#+PROPERTY: comments org
|
|
#+SETUPFILE: ../../docs/theme.setup
|
|
# -*- mode: org -*-
|
|
|
|
* Constant file prefixes (not used by the generator) :noexport:
|
|
|
|
#+begin_src emacs-lisp
|
|
(setq-local org-babel-default-header-args:c '((:comments . "both")))
|
|
org-babel-default-header-args:c
|
|
#+end_src
|
|
|
|
#+RESULTS:
|
|
: ((:comments . both))
|
|
|
|
#+NAME:header
|
|
#+begin_src c
|
|
/* This file was generated from the org-mode file.
|
|
To generate it, open templator_hdf5.org file in Emacs and execute
|
|
M-x org-babel-tangle
|
|
*/
|
|
|
|
#+end_src
|
|
|
|
|
|
#+begin_src c :tangle prefix_hdf5.h :noweb yes
|
|
<<header>>
|
|
#ifndef TREXIO_HDF5_H
|
|
#define TREXIO_HDF5_H
|
|
|
|
#include "trexio.h"
|
|
#include "trexio_private.h"
|
|
#include "trexio_s.h"
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "hdf5.h"
|
|
#include "hdf5_hl.h" // needed for high-level APIs like H5LT, requires additional linking in Makefile
|
|
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle prefix_hdf5.c :noweb yes
|
|
<<header>>
|
|
#include "trexio_hdf5.h"
|
|
|
|
#+end_src
|
|
|
|
* HDF5 back end
|
|
** Template for HDF5 definitions
|
|
|
|
#+begin_src c :tangle def_hdf5.c
|
|
#define $GROUP$_GROUP_NAME "$group$"
|
|
#define $GROUP_NUM$_NAME "$group_num$"
|
|
#define $GROUP_DSET$_NAME "$group_dset$"
|
|
#+end_src
|
|
|
|
** Template for HDF5 structures
|
|
|
|
#+begin_src c :tangle struct_hdf5.h
|
|
typedef struct trexio_hdf5_s {
|
|
trexio_t parent ;
|
|
hid_t file_id;
|
|
hid_t $group$_group;
|
|
const char* file_name;
|
|
} trexio_hdf5_t;
|
|
#+end_src
|
|
|
|
|
|
#+begin_src c :tangle struct_hdf5.h :exports none
|
|
trexio_exit_code trexio_hdf5_init(trexio_t* const file);
|
|
trexio_exit_code trexio_hdf5_deinit(trexio_t* const file);
|
|
#+end_src
|
|
|
|
** Template for HDF5 init/deinit
|
|
|
|
#+begin_src c :tangle basic_hdf5.c
|
|
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 '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':
|
|
// reading 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) {
|
|
case 'r':
|
|
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;
|
|
|
|
}
|
|
#+end_src
|
|
|
|
** Template for HDF5 has/read/write a number
|
|
|
|
#+begin_src c :tangle hrw_num_hdf5.h :exports none
|
|
trexio_exit_code trexio_hdf5_has_$group_num$ (trexio_t* const file);
|
|
trexio_exit_code trexio_hdf5_read_$group_num$ (trexio_t* const file, uint64_t* const num);
|
|
trexio_exit_code trexio_hdf5_write_$group_num$(trexio_t* const file, const uint64_t num);
|
|
#+end_src
|
|
|
|
|
|
#+begin_src c :tangle read_num_hdf5.c
|
|
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;
|
|
|
|
}
|
|
#+end_src
|
|
|
|
|
|
#+begin_src c :tangle write_num_hdf5.c
|
|
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) {
|
|
|
|
return TREXIO_NUM_ALREADY_EXISTS;
|
|
|
|
} 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;
|
|
}
|
|
|
|
}
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle has_num_hdf5.c
|
|
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;
|
|
}
|
|
|
|
}
|
|
#+end_src
|
|
|
|
** Template for HDF5 has/read/write a dataset
|
|
|
|
#+begin_src c :tangle hrw_dset_hdf5.h :exports none
|
|
trexio_exit_code trexio_hdf5_has_$group_dset$(trexio_t* const file);
|
|
trexio_exit_code trexio_hdf5_read_$group_dset$(trexio_t* const file, $group_dset_dtype$* const $group_dset$, const uint32_t rank, const uint64_t* dims);
|
|
trexio_exit_code trexio_hdf5_write_$group_dset$(trexio_t* const file, const $group_dset_dtype$* $group_dset$, const uint32_t rank, const uint64_t* dims);
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle read_dset_hdf5.c
|
|
trexio_exit_code
|
|
trexio_hdf5_read_$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_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_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_DSET$_NAME,
|
|
H5T_NATIVE_$GROUP_DSET_H5_DTYPE$,
|
|
$group_dset$);
|
|
if (status < 0) return TREXIO_FAILURE;
|
|
|
|
return TREXIO_SUCCESS;
|
|
}
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle write_dset_hdf5.c
|
|
trexio_exit_code
|
|
trexio_hdf5_write_$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_DSET$_NAME) != 1 ) {
|
|
|
|
const herr_t status = H5LTmake_dataset(f->$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_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;
|
|
|
|
}
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle has_dset_hdf5.c
|
|
trexio_exit_code
|
|
trexio_hdf5_has_$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_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;
|
|
}
|
|
|
|
}
|
|
#+end_src
|
|
|
|
* Constant file suffixes (not used by the generator) :noexport:
|
|
|
|
#+begin_src c :tangle suffix_hdf5.h
|
|
|
|
#endif
|
|
#+end_src
|
|
|
|
|