mirror of
https://github.com/TREX-CoE/trexio.git
synced 2025-04-26 18:34:44 +02:00
623 lines
16 KiB
Org Mode
623 lines
16 KiB
Org Mode
#+Title: TREX Input/Ouput library (TREXIO)
|
|
|
|
* File prefixes :noxport:
|
|
|
|
#+NAME:header
|
|
#+begin_src c
|
|
/* This file was generated from the trexio.org org-mode file.
|
|
To generate it, open trexio.org in Emacs and execute
|
|
M-x org-babel-tangle
|
|
*/
|
|
|
|
|
|
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle trexio.h :noweb yes
|
|
<<header>>
|
|
#ifndef _TREXIO_H
|
|
#define _TREXIO_H
|
|
|
|
#include <stdint.h>
|
|
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle trexio.c :noweb yes
|
|
<<header>>
|
|
#include <pthread.h>
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <pthread.h>
|
|
|
|
#include "trexio.h"
|
|
#include "trexio_s.h"
|
|
#include "trexio_text.h"
|
|
#include "trexio_hdf5.h"
|
|
/*
|
|
#include "trexio_json.h"
|
|
,*/
|
|
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle trexio_s.h :noweb yes
|
|
<<header>>
|
|
#ifndef _TREXIO_S_H
|
|
#define _TREXIO_S_H
|
|
|
|
#include "trexio.h"
|
|
#include <pthread.h>
|
|
#include <assert.h>
|
|
#+end_src
|
|
|
|
* Coding conventions
|
|
|
|
- integer types will be defined using types given in ~stdint.h~
|
|
- pointers are always initialized to ~NULL~
|
|
- when memory is freed, the pointer is set to ~NULL~
|
|
- ~assert.h~ should be used extensively
|
|
- variable names are in lower case
|
|
- ~#define~ constants are in upper case
|
|
- structs are suffixed by ~_s~
|
|
- types are suffixed by ~_t~
|
|
|
|
* Front end
|
|
|
|
All calls to TREXIO are thread-safe.
|
|
|
|
** Error handling
|
|
#+begin_src c :tangle trexio.h
|
|
typedef int32_t trexio_exit_code;
|
|
|
|
#define TREXIO_FAILURE ( (trexio_exit_code) -1 )
|
|
#define TREXIO_SUCCESS ( (trexio_exit_code) 0 )
|
|
#define TREXIO_INVALID_ARG_1 ( (trexio_exit_code) 1 )
|
|
#define TREXIO_INVALID_ARG_2 ( (trexio_exit_code) 2 )
|
|
#define TREXIO_INVALID_ARG_3 ( (trexio_exit_code) 3 )
|
|
#define TREXIO_INVALID_ARG_4 ( (trexio_exit_code) 4 )
|
|
#define TREXIO_INVALID_ARG_5 ( (trexio_exit_code) 5 )
|
|
#define TREXIO_END ( (trexio_exit_code) 10 )
|
|
#define TREXIO_READONLY ( (trexio_exit_code) 11 )
|
|
#+end_src
|
|
|
|
** Back ends
|
|
|
|
#+begin_src c :tangle trexio.h
|
|
typedef int32_t back_end_t;
|
|
|
|
#define TREXIO_HDF5 ( (back_end_t) 0 )
|
|
#define TREXIO_TEXT ( (back_end_t) 1 )
|
|
#define TREXIO_JSON ( (back_end_t) 2 )
|
|
#define TREXIO_INVALID_BACK_END ( (back_end_t) 3 )
|
|
#+end_src
|
|
|
|
** Read/write behavior
|
|
|
|
Every time a reading function is called, the data is read from the
|
|
disk. If data needs to be cached, this is left to the user of the
|
|
library.
|
|
|
|
Writing to TREXIO files is done with transactions (all-or-nothing
|
|
effect) in a per-group fashion. File writes are attempted by
|
|
calling explicitly the flush function, or when the TREXIO file is
|
|
closed. If writing is impossible because the data is not valid, no
|
|
data is written.
|
|
|
|
The order in which the data is written is not necessarily consistent
|
|
with the order in which the function calls were made.
|
|
|
|
The TREXIO files are supposed to be opened by only one program at a
|
|
time: if the same TREXIO file is modified simultaneously by multiple
|
|
concurrent programs, the behavior is not specified.
|
|
|
|
** TREXIO file type
|
|
|
|
~trexio_s~ is the the main type for TREXIO files, visible to the users
|
|
of the library. This type is kept opaque, and all modifications to
|
|
the files will be necessarily done through the use of functions,
|
|
taking such a type as argument.
|
|
|
|
File creation and opening functions will return /TREXIO file handles/,
|
|
namely pointers to ~trexio_s~ types. All functions accessing to the
|
|
TREXIO files will have as a first argument the TREXIO file handle.
|
|
|
|
#+begin_src c :tangle trexio.h
|
|
typedef struct trexio_s trexio_t;
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle trexio_s.h
|
|
struct trexio_s {
|
|
char* file_name;
|
|
pthread_mutex_t thread_lock;
|
|
back_end_t back_end;
|
|
char mode;
|
|
char padding[7]; /* Ensures the proper alignment of back-ends */
|
|
};
|
|
#+end_src
|
|
|
|
** Polymorphism of the file handle
|
|
|
|
Polymorphism of the ~trexio_t~ type is handled by ensuring that the
|
|
corresponding types for all back ends can be safely casted to
|
|
~trexio_t~. This is done by making the back end structs start with
|
|
~struct trexio_s~:
|
|
|
|
#+begin_src c
|
|
struct trexio_back_end_s {
|
|
trexio_t parent ;
|
|
/* add below specific back end data */
|
|
}
|
|
#+end_src
|
|
|
|
** File opening
|
|
|
|
#+begin_src c :tangle trexio.h
|
|
trexio_t* trexio_open(const char* file_name, const char mode, const back_end_t back_end);
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle trexio.c
|
|
trexio_t* trexio_open(const char* file_name, const char mode, const back_end_t back_end) {
|
|
|
|
if (file_name == NULL) return NULL;
|
|
if (file_name[0] == '\0') return NULL;
|
|
|
|
if (back_end < 0) return NULL;
|
|
if (back_end >= TREXIO_INVALID_BACK_END) return NULL;
|
|
|
|
if (mode != 'r' && mode != 'w') return NULL;
|
|
|
|
trexio_t* result = NULL;
|
|
|
|
switch (back_end) {
|
|
|
|
case TREXIO_TEXT:
|
|
result = (trexio_t*) malloc (sizeof(trexio_text_t));
|
|
break;
|
|
|
|
case TREXIO_HDF5:
|
|
result = (trexio_t*) malloc (sizeof(trexio_hdf5_t));
|
|
break;
|
|
/*
|
|
case TREXIO_JSON:
|
|
result = (trexio_t*) malloc (sizeof(trexio_json_t));
|
|
break;
|
|
,*/
|
|
}
|
|
|
|
/* TODO: Error handling */
|
|
assert (result != NULL);
|
|
|
|
result->file_name = (char*) calloc(strlen(file_name)+1,sizeof(char));
|
|
strcpy(result->file_name, file_name);
|
|
result->back_end = back_end;
|
|
result->mode = mode;
|
|
int irc = pthread_mutex_init ( &(result->thread_lock), NULL);
|
|
assert (irc == 0);
|
|
|
|
trexio_exit_code rc = TREXIO_FAILURE;
|
|
|
|
switch (back_end) {
|
|
|
|
case TREXIO_TEXT:
|
|
rc = trexio_text_init(result);
|
|
break;
|
|
|
|
case TREXIO_HDF5:
|
|
rc = trexio_hdf5_init(result);
|
|
break;
|
|
/*
|
|
case TREXIO_JSON:
|
|
rc = trexio_json_init(result);
|
|
break;
|
|
,*/
|
|
}
|
|
if (rc != TREXIO_SUCCESS) return NULL;
|
|
|
|
return result;
|
|
}
|
|
#+end_src
|
|
|
|
** File closing
|
|
|
|
#+begin_src c :tangle trexio.h
|
|
trexio_exit_code trexio_close(trexio_t* file);
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle trexio.c
|
|
trexio_exit_code trexio_close(trexio_t* file) {
|
|
|
|
if (file == NULL) return TREXIO_FAILURE;
|
|
|
|
trexio_exit_code rc;
|
|
|
|
switch (file->back_end) {
|
|
|
|
case TREXIO_TEXT:
|
|
rc = trexio_text_finalize(file);
|
|
break;
|
|
|
|
case TREXIO_HDF5:
|
|
rc = trexio_hdf5_finalize(file);
|
|
break;
|
|
/*
|
|
case TREXIO_JSON:
|
|
rc = trexio_json_finalize(file);
|
|
break;
|
|
,*/
|
|
default:
|
|
assert (1 == 0); /* Impossible case */
|
|
}
|
|
|
|
if (rc != TREXIO_SUCCESS) {
|
|
return TREXIO_FAILURE;
|
|
}
|
|
|
|
free(file->file_name);
|
|
file->file_name = NULL;
|
|
|
|
int irc = pthread_mutex_destroy( &(file->thread_lock) );
|
|
assert (irc == 0);
|
|
|
|
free(file);
|
|
|
|
return TREXIO_SUCCESS;
|
|
}
|
|
#+end_src
|
|
** Reading/writing data
|
|
*** nucleus
|
|
**** num
|
|
#+begin_src c :tangle trexio.h
|
|
trexio_exit_code trexio_read_nucleus_num(trexio_t* file, int64_t* num);
|
|
trexio_exit_code trexio_write_nucleus_num(trexio_t* file, const int64_t num);
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle trexio.c
|
|
trexio_exit_code trexio_read_nucleus_num(trexio_t* file, int64_t* num) {
|
|
if (file == NULL) return TREXIO_INVALID_ARG_1;
|
|
|
|
uint64_t u_num = 0;
|
|
trexio_exit_code rc = TREXIO_FAILURE;
|
|
|
|
switch (file->back_end) {
|
|
|
|
case TREXIO_TEXT:
|
|
rc = trexio_text_read_nucleus_num(file, &u_num);
|
|
break;
|
|
|
|
case TREXIO_HDF5:
|
|
rc = trexio_hdf5_read_nucleus_num(file, &u_num);
|
|
break;
|
|
/*
|
|
case TREXIO_JSON:
|
|
rc =trexio_json_read_nucleus_num(file, &u_num);
|
|
break;
|
|
,*/
|
|
}
|
|
|
|
if (rc != TREXIO_SUCCESS) return rc;
|
|
|
|
/**/ *num = (int64_t) u_num;
|
|
return TREXIO_SUCCESS;
|
|
}
|
|
|
|
trexio_exit_code trexio_write_nucleus_num(trexio_t* file, const int64_t num) {
|
|
if (file == NULL) return TREXIO_INVALID_ARG_1;
|
|
if (num < 0 ) return TREXIO_INVALID_ARG_2;
|
|
|
|
trexio_exit_code rc = TREXIO_FAILURE;
|
|
|
|
switch (file->back_end) {
|
|
|
|
case TREXIO_TEXT:
|
|
rc = trexio_text_write_nucleus_num(file, (uint64_t) num);
|
|
break;
|
|
|
|
case TREXIO_HDF5:
|
|
rc = trexio_hdf5_write_nucleus_num(file, (uint64_t) num);
|
|
break;
|
|
/*
|
|
case TREXIO_JSON:
|
|
rc = trexio_json_write_nucleus_num(file, (uint64_t) num);
|
|
break;
|
|
,*/
|
|
}
|
|
if (rc != TREXIO_SUCCESS) return rc;
|
|
|
|
return TREXIO_SUCCESS;
|
|
}
|
|
#+end_src
|
|
|
|
**** coord
|
|
#+begin_src c :tangle trexio.h
|
|
trexio_exit_code trexio_read_nucleus_coord(trexio_t* file, double* coord);
|
|
trexio_exit_code trexio_write_nucleus_coord(trexio_t* file, const double* coord);
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle trexio.c
|
|
trexio_exit_code trexio_read_nucleus_coord(trexio_t* file, double* coord) {
|
|
if (file == NULL) return TREXIO_INVALID_ARG_1;
|
|
if (coord == NULL) return TREXIO_INVALID_ARG_2;
|
|
|
|
int64_t nucleus_num = -1;
|
|
trexio_exit_code rc = trexio_read_nucleus_num(file, &nucleus_num);
|
|
if (rc != TREXIO_SUCCESS) return rc;
|
|
|
|
int64_t dim_coord = nucleus_num*3;
|
|
if (dim_coord < 0) return TREXIO_FAILURE;
|
|
|
|
switch (file->back_end) {
|
|
|
|
case TREXIO_TEXT:
|
|
return trexio_text_read_nucleus_coord(file, coord, (uint64_t) dim_coord);
|
|
break;
|
|
|
|
case TREXIO_HDF5:
|
|
return trexio_hdf5_read_nucleus_coord(file, coord);
|
|
break;
|
|
/*
|
|
case TREXIO_JSON:
|
|
return trexio_json_read_nucleus_coord(file, coord);
|
|
break;
|
|
,*/
|
|
default:
|
|
return TREXIO_FAILURE; /* Impossible case */
|
|
}
|
|
}
|
|
|
|
trexio_exit_code trexio_write_nucleus_coord(trexio_t* file, const double* coord) {
|
|
if (file == NULL) return TREXIO_INVALID_ARG_1;
|
|
if (coord == NULL) return TREXIO_INVALID_ARG_2;
|
|
|
|
int64_t nucleus_num = -1;
|
|
trexio_exit_code rc = trexio_read_nucleus_num(file, &nucleus_num);
|
|
if (rc != TREXIO_SUCCESS) return rc;
|
|
|
|
int64_t dim_coord = nucleus_num*3;
|
|
if (dim_coord < 0) return TREXIO_FAILURE;
|
|
|
|
switch (file->back_end) {
|
|
|
|
case TREXIO_TEXT:
|
|
return trexio_text_write_nucleus_coord(file, coord, (uint64_t) dim_coord);
|
|
break;
|
|
|
|
case TREXIO_HDF5:
|
|
return trexio_hdf5_write_nucleus_coord(file, coord);
|
|
break;
|
|
/*
|
|
case TREXIO_JSON:
|
|
return trexio_json_write_nucleus_coord(file, coord);
|
|
break;
|
|
,*/
|
|
default:
|
|
return TREXIO_FAILURE; /* Impossible case */
|
|
}
|
|
}
|
|
#+end_src
|
|
|
|
**** charge
|
|
#+begin_src c :tangle trexio.h
|
|
trexio_exit_code trexio_read_nucleus_charge(trexio_t* file, double* charge);
|
|
trexio_exit_code trexio_write_nucleus_charge(trexio_t* file, const double* charge);
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle trexio.c
|
|
trexio_exit_code trexio_read_nucleus_charge(trexio_t* file, double* charge) {
|
|
if (file == NULL) return TREXIO_INVALID_ARG_1;
|
|
if (charge == NULL) return TREXIO_INVALID_ARG_2;
|
|
|
|
int64_t nucleus_num = -1;
|
|
trexio_exit_code rc = trexio_read_nucleus_num(file, &nucleus_num);
|
|
if (rc != TREXIO_SUCCESS) return rc;
|
|
|
|
int64_t dim_charge = nucleus_num;
|
|
if (dim_charge < 0) return TREXIO_FAILURE;
|
|
|
|
switch (file->back_end) {
|
|
|
|
case TREXIO_TEXT:
|
|
return trexio_text_read_nucleus_charge(file, charge, (uint64_t) dim_charge);
|
|
break;
|
|
/*
|
|
case TREXIO_HDF5:
|
|
return trexio_hdf5_read_nucleus_charge(file, charge);
|
|
break;
|
|
|
|
case TREXIO_JSON:
|
|
return trexio_json_read_nucleus_charge(file, charge);
|
|
break;
|
|
,*/
|
|
default:
|
|
return TREXIO_FAILURE; /* Impossible case */
|
|
}
|
|
}
|
|
|
|
trexio_exit_code trexio_write_nucleus_charge(trexio_t* file, const double* charge) {
|
|
if (file == NULL) return TREXIO_INVALID_ARG_1;
|
|
if (charge == NULL) return TREXIO_INVALID_ARG_2;
|
|
|
|
int64_t nucleus_num = -1;
|
|
trexio_exit_code rc = trexio_read_nucleus_num(file, &nucleus_num);
|
|
if (rc != TREXIO_SUCCESS) return rc;
|
|
|
|
int64_t dim_charge = nucleus_num;
|
|
if (dim_charge < 0) return TREXIO_FAILURE;
|
|
|
|
switch (file->back_end) {
|
|
|
|
case TREXIO_TEXT:
|
|
return trexio_text_write_nucleus_charge(file, charge, (uint64_t) dim_charge);
|
|
break;
|
|
/*
|
|
case TREXIO_HDF5:
|
|
return trexio_hdf5_write_nucleus_charge(file, charge);
|
|
break;
|
|
|
|
case TREXIO_JSON:
|
|
return trexio_json_write_nucleus_charge(file, charge);
|
|
break;
|
|
,*/
|
|
default:
|
|
return TREXIO_FAILURE; /* Impossible case */
|
|
}
|
|
}
|
|
#+end_src
|
|
|
|
*** rdm
|
|
**** one_e
|
|
#+begin_src c :tangle trexio.h
|
|
trexio_exit_code trexio_read_rdm_one_e(trexio_t* file, double* one_e);
|
|
trexio_exit_code trexio_write_rdm_one_e(trexio_t* file, const double* one_e);
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle trexio.c
|
|
trexio_exit_code trexio_read_rdm_one_e(trexio_t* file, double* one_e) {
|
|
if (file == NULL) return TREXIO_INVALID_ARG_1;
|
|
if (one_e == NULL) return TREXIO_INVALID_ARG_2;
|
|
|
|
int64_t dim_one_e = -1;
|
|
trexio_exit_code rc = trexio_read_nucleus_num(file, &dim_one_e); /* This dimension is wrong. Should be mo_num */
|
|
if (rc != TREXIO_SUCCESS) return rc;
|
|
if (dim_one_e < 0) return TREXIO_FAILURE;
|
|
|
|
switch (file->back_end) {
|
|
|
|
case TREXIO_TEXT:
|
|
return trexio_text_read_rdm_one_e(file, one_e, (uint64_t) dim_one_e);
|
|
break;
|
|
/*
|
|
case TREXIO_HDF5:
|
|
return trexio_hdf5_read_rdm_one_e(file, one_e);
|
|
break;
|
|
|
|
case TREXIO_JSON:
|
|
return trexio_json_read_rdm_one_e(file, one_e);
|
|
break;
|
|
,*/
|
|
default:
|
|
return TREXIO_FAILURE; /* Impossible case */
|
|
}
|
|
}
|
|
|
|
trexio_exit_code trexio_write_rdm_one_e(trexio_t* file, const double* one_e) {
|
|
if (file == NULL) return TREXIO_INVALID_ARG_1;
|
|
if (one_e == NULL) return TREXIO_INVALID_ARG_2;
|
|
|
|
int64_t nucleus_num = -1;
|
|
trexio_exit_code rc = trexio_read_nucleus_num(file, &nucleus_num);
|
|
if (rc != TREXIO_SUCCESS) return rc;
|
|
|
|
int64_t dim_one_e = nucleus_num * nucleus_num; /* This dimension is wrong. Should be mo_num */
|
|
if (dim_one_e < 0) return TREXIO_FAILURE;
|
|
|
|
switch (file->back_end) {
|
|
|
|
case TREXIO_TEXT:
|
|
return trexio_text_write_rdm_one_e(file, one_e, (uint64_t) dim_one_e);
|
|
break;
|
|
/*
|
|
case TREXIO_HDF5:
|
|
return trexio_hdf5_write_rdm_one_e(file, one_e);
|
|
break;
|
|
|
|
case TREXIO_JSON:
|
|
return trexio_json_write_rdm_one_e(file, one_e);
|
|
break;
|
|
,*/
|
|
default:
|
|
return TREXIO_FAILURE; /* Impossible case */
|
|
}
|
|
}
|
|
#+end_src
|
|
|
|
**** two_e
|
|
|
|
~buffered_read~ functions return ~TREXIO_SUCCESS~ if the complete
|
|
buffer was read or written. If the read data is smaller than the
|
|
buffer because the end is reached, the function returns ~TREXIO_END~.
|
|
|
|
#+begin_src c :tangle trexio.h
|
|
trexio_exit_code trexio_buffered_read_rdm_two_e(trexio_t* file, const int64_t offset, const int64_t size, int64_t* index, double* value);
|
|
trexio_exit_code trexio_buffered_write_rdm_two_e(trexio_t* file, const int64_t offset, const int64_t size, const int64_t* index, const double* value);
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle trexio.c
|
|
trexio_exit_code trexio_buffered_read_rdm_two_e(trexio_t* file, const int64_t offset, const int64_t size, int64_t* index, double* value) {
|
|
if (file == NULL) return TREXIO_INVALID_ARG_1;
|
|
if (offset <= 0 ) return TREXIO_INVALID_ARG_2;
|
|
if (size <= 0 ) return TREXIO_INVALID_ARG_3;
|
|
if (index == NULL) return TREXIO_INVALID_ARG_4;
|
|
if (value == NULL) return TREXIO_INVALID_ARG_5;
|
|
|
|
switch (file->back_end) {
|
|
|
|
case TREXIO_TEXT:
|
|
return trexio_text_buffered_read_rdm_two_e(file, (uint64_t) offset, (uint64_t) size, index, value);
|
|
break;
|
|
/*
|
|
case TREXIO_HDF5:
|
|
return trexio_hdf5_buffered_read_rdm_two_e(file, size);
|
|
break;
|
|
|
|
case TREXIO_JSON:
|
|
return trexio_json_buffered_read_rdm_two_e(file, size);
|
|
break;
|
|
,*/
|
|
default:
|
|
return TREXIO_FAILURE; /* Impossible case */
|
|
}
|
|
}
|
|
|
|
trexio_exit_code trexio_buffered_write_rdm_two_e(trexio_t* file, const int64_t offset, const int64_t size, const int64_t* index, const double* value) {
|
|
if (file == NULL) return TREXIO_INVALID_ARG_1;
|
|
if (offset <= 0 ) return TREXIO_INVALID_ARG_2;
|
|
if (size <= 0 ) return TREXIO_INVALID_ARG_3;
|
|
if (index == NULL) return TREXIO_INVALID_ARG_4;
|
|
if (value == NULL) return TREXIO_INVALID_ARG_5;
|
|
|
|
switch (file->back_end) {
|
|
|
|
case TREXIO_TEXT:
|
|
return trexio_text_buffered_write_rdm_two_e(file, (uint64_t) offset, (uint64_t) size, index, value);
|
|
break;
|
|
/*
|
|
case TREXIO_HDF5:
|
|
return trexio_hdf5_buffered_write_rdm_two_e(file, size);
|
|
break;
|
|
|
|
case TREXIO_JSON:
|
|
return trexio_json_buffered_write_rdm_two_e(file, size);
|
|
break;
|
|
,*/
|
|
default:
|
|
return TREXIO_FAILURE; /* Impossible case */
|
|
}
|
|
}
|
|
#+end_src
|
|
|
|
* Back ends
|
|
|
|
TREXIO has multiple possible back ends:
|
|
|
|
- HDF5: The most efficient back-end, by default
|
|
- Text files: not to be used for production, but useful for debugging
|
|
- JSON: for portability
|
|
|
|
* File suffixes :noxport:
|
|
|
|
#+begin_src c :tangle trexio.h
|
|
#endif
|
|
#+end_src
|
|
|
|
#+begin_src c :tangle trexio_s.h
|
|
#endif
|
|
#+end_src
|
|
|
|
* TODO Things to be done :noexport:
|
|
- [ ] Thread safety
|
|
- [ ] Error handling with errno
|
|
- [ ] HDF5 back-end
|
|
- [ ] JSON back-end
|
|
- [ ] File locking with flock
|
|
- [ ] Caching of the struct saving last modification date in structs
|