From c43259176d163f101496213b7bfa306608fca7ad Mon Sep 17 00:00:00 2001 From: Evgeny Posenitskiy <45995097+q-posev@users.noreply.github.com> Date: Wed, 7 Apr 2021 17:37:04 +0200 Subject: [PATCH] Add 32-bit funcs and document front end (#39) * 32-bit functions * adapt tests since the default write/read_num is now 32-bit * minor cleaning in the generator * add test for _32 functionality * rm stdint-based types from test * documentation * rm trailing whitespaces in emacs * change TREXIO_INVALID_BACK_END * update gitignore --- src/.gitignore | 3 +- src/generator.py | 28 +- src/templates_front/templator_front.org | 614 +++++++++++++++++++----- src/test.c | 24 +- src/test.f90 | 4 +- 5 files changed, 540 insertions(+), 133 deletions(-) diff --git a/src/.gitignore b/src/.gitignore index a22dab1..fca8201 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -20,8 +20,9 @@ trexio_hdf5.c trexio_f.f90 trexio.mod -test +test_c test_f *.h5 trexio_test/ +trexio_test_fort/ diff --git a/src/generator.py b/src/generator.py index cf87abd..94679e4 100644 --- a/src/generator.py +++ b/src/generator.py @@ -9,17 +9,11 @@ fileDir = dirname(abspath(__file__)) parentDir = dirname(fileDir) with open(join(parentDir,'trex.json'), 'r') as f: - config0 = json.load(f) + config = json.load(f) print('Metadata I/O currently not supported') # TODO, for now remove metadata-related stuff -del config0['metadata'] - -config = {} -#for k,v in config0.items(): -# if k == 'nucleus' or k == 'ecp': -# config[k] = v -config = config0 +del config['metadata'] # for now remove rdm because it is hardcoded del config['rdm'] @@ -288,16 +282,26 @@ for fname in files_funcs_dsets: if params['dtype'] == 'double': h5_dtype = 'double' - f_dtype = 'real(8)' + f_dtype_double = 'real(8)' + f_dtype_single = 'real(4)' + c_dtype_double = 'double' + c_dtype_single = 'float' + elif params['dtype'] == 'int64_t': h5_dtype = 'long' - f_dtype = 'integer(8)' + f_dtype_double = 'integer(8)' + f_dtype_single = 'integer(4)' + c_dtype_double = 'int64_t' + c_dtype_single = 'int32_t' + + templine1 = templine2.replace('$group_dset_dtype_double$', c_dtype_double) + templine2 = templine1.replace('$group_dset_dtype_single$', c_dtype_single) templine1 = templine2.replace('$group_dset_h5_dtype$', h5_dtype) templine2 = templine1.replace('$group_dset_h5_dtype$'.upper(), h5_dtype.upper()) - templine1 = templine2.replace('$group_dset_f_dtype$', f_dtype) - templine2 = templine1.replace('$group_dset_f_dtype$'.upper(), f_dtype.upper()) + templine1 = templine2.replace('$group_dset_f_dtype_double$', f_dtype_double) + templine2 = templine1.replace('$group_dset_f_dtype_single$', f_dtype_single) templine1 = templine2.replace('$group_dset_rank$', str(params['rank'])) templine2 = templine1 diff --git a/src/templates_front/templator_front.org b/src/templates_front/templator_front.org index aa6ba4b..debe7a6 100644 --- a/src/templates_front/templator_front.org +++ b/src/templates_front/templator_front.org @@ -1,7 +1,11 @@ -#+Title: Templator for frontend +#+Title: Templator for front end * Constant file prefixes (not used by generator) :noexport: + Prefixes in C contain mainly `#include` as well as some + `#define` and `typedef` statements. + Prefixes in Fortran contain back-end definitions. + #+NAME:header #+begin_src c /* This file was generated from the templator_front.org org-mode file. @@ -22,7 +26,7 @@ module trexio integer, parameter :: TREXIO_HDF5 = 0 integer, parameter :: TREXIO_TEXT = 1 ! integer, parameter :: TREXIO_JSON = 2 - integer, parameter :: TREXIO_INVALID_BACK_END = 3 + integer, parameter :: TREXIO_INVALID_BACK_END = 2 #+end_src #+end_src @@ -64,7 +68,6 @@ typedef int32_t trexio_exit_code; #include #+end_src - * Coding conventions - integer types will be defined using types given in ~stdint.h~ @@ -75,6 +78,7 @@ typedef int32_t trexio_exit_code; - ~#define~ constants are in upper case - structs are suffixed by ~_s~ - types are suffixed by ~_t~ + - API calls return ~trexio_exit_code~ (except for ~trexio_open~ function) ** Memory allocation @@ -94,10 +98,10 @@ typedef int32_t trexio_exit_code; #define FREE(X) { free(X) ; (X)=NULL; } #+end_src - * Front end - All calls to TREXIO are thread-safe. + All calls to TREXIO are thread-safe. + TREXIO front end is modular, which simplifies impelementation of new back ends. ** Error handling @@ -198,7 +202,7 @@ return '\n'.join(result) const char* trexio_string_of_error(const trexio_exit_code error); void trexio_string_of_error_f(const trexio_exit_code error, - char result[<>]); + char result[<>]); #+end_src The text strings are extracted from the previous table. @@ -223,46 +227,46 @@ return '\n'.join(result) #+RESULTS: cases #+begin_example case TREXIO_FAILURE: - return "Unknown failure"; + return "Unknown failure"; break; case TREXIO_SUCCESS: - return ; + return ; break; case TREXIO_INVALID_ARG_1: - return "Invalid argument 1"; + return "Invalid argument 1"; break; case TREXIO_INVALID_ARG_2: - return "Invalid argument 2"; + return "Invalid argument 2"; break; case TREXIO_INVALID_ARG_3: - return "Invalid argument 3"; + return "Invalid argument 3"; break; case TREXIO_INVALID_ARG_4: - return "Invalid argument 4"; + return "Invalid argument 4"; break; case TREXIO_INVALID_ARG_5: - return "Invalid argument 5"; + return "Invalid argument 5"; break; case TREXIO_END: - return "End of file"; + return "End of file"; break; case TREXIO_READONLY: - return "Read-only file"; + return "Read-only file"; break; case TREXIO_ERRNO: - return strerror(errno); + return strerror(errno); break; case TREXIO_INVALID_ID: - return "Invalid ID"; + return "Invalid ID"; break; case TREXIO_ALLOCATION_FAILED: - return "Allocation failed"; + return "Allocation failed"; break; case TREXIO_HAS_NOT: - return "Element absent"; + return "Element absent"; break; case TREXIO_INVALID_NUM: - return "Invalid exit code"; + return "Invalid exit code"; break; #+end_example @@ -292,18 +296,36 @@ void trexio_string_of_error_f(const trexio_exit_code error, char result[<=1.10 has file locking activated by default */ case TREXIO_HDF5: rc = TREXIO_SUCCESS; break; @@ -483,6 +526,14 @@ end interface ** File closing + `trexio_close` closes an existing `trexio_t` file. + + `trexio_close` input: + `file` - TREXIO file handle. + + `trexio_close` output: + `trexio_exit_code` exit code. + #+begin_src c :tangle prefix_front.h trexio_exit_code trexio_close(trexio_t* file); #+end_src @@ -565,16 +616,95 @@ end interface #+end_src * Templates for front end -** Template for frontend has/read/write a number + + Consider the following block of `trex.json`: + + { + "nucleus": { + "num" : [ "int" , [ ] ] + , "charge" : [ "float", [ "nucleus.num" ] ] + , "coord" : [ "float", [ "nucleus.num", "3" ] ] + , "label" : [ "char" , [ "nucleus.num", "32" ] ] + } + } + + ~TREXIO~ is generated automatically by the `generator.py` Python script + based on the tree-like configuration provided in the `trex.json` file. + Because of that, generalized templates can be implemented and re-used. + This approach minimizes the number of bugs as compared with manual copy-paste-modify scheme. + + All templates presented below use the `$var$` notation to indicate the variable, + which will be replaced by the `generator.py`. Sometimes the upper case is used, i.e. + `$VAR$` (for example, in `#define` statements). + More detailed description of each variable can be found below: + + | Template variable | Description | Example | + |-------------------------------+--------------------------------------------------+------------------| + | ~$group$~ | 'Name of the group' | nucleus | + | ~$group_num$~ | 'Name of the dimensioning variable (scalar)' | nucleus_num | + | ~$group_dset$~ | 'Name of the dataset (vector/matrix/tensor)' | nucleus_coord | + | ~$group_dset_rank$~ | 'Rank of the dataset' | 2 | + | ~$group_dset_dim$~ | 'Selected dimension of the dataset' | nucleus_num | + | ~$group_dset_dim_list$~ | 'All dimensions of the dataset' | {nucleus_num, 3} | + | ~$group_dset_dtype$~ | 'Basic type of the dataset (int/float/char)' | float | + | ~$group_dset_h5_dtype$~ | 'Type of the dataset in HDF5' | double | + | ~$group_dset_std_dtype_in$~ | 'Input type of the dataset in TEXT [fscanf] ' | %lf | + | ~$group_dset_std_dtype_out$~ | 'Output type of the dataset in TEXT [fprintf]' | %24.16e | + | ~$group_dset_dtype_single$~ | 'Single precision type of the dataset [C]' | float | + | ~$group_dset_dtype_double$~ | 'Double precision type of the dataset [C]' | double | + | ~$group_dset_f_dtype_single$~ | 'Single precision type of the dataset [Fortran]' | real(4) | + | ~$group_dset_f_dtype_double$~ | 'Double precision type of the dataset [Fortran]' | real(8) | + + Note: parent group name is always added to the child objects upon consruction of TREXIO + (e.g. `num` of `nucleus` group becomes `nucleus_num` and should be accessed accordingly within TREXIO). + + TREXIO generator parses the `trex.json` file. TREXIO operates with names of variables + based on the 1-st (parent group) and 2-nd (child object) levels of `trex.json`. + The parsed configutation is divided in 2 parts: + + 1) Dimensioning variables (containing `num`). These are always scalar integers. + 2) Datasets. These can be vectors, matrices or tensors. The types are indicated in `trex.json`. + Currently supported types: int, float. TODO: strings. + + For each of the aforementioned objects, TREXIO provides `has`,`read` and `write` functionality. + TREXIO supports I/O with single or double precision for integer and floating point numbers. + + +** Templates for front end has/read/write a dimension + + This section concerns API calls related to dimensioning variables. + + | Function name | Description | Precision | + |-------------------------------+----------------------------------------------------+-----------| + | ~trexio_has_$group_num$~ | 'Check if a dimensioning variable exists in a file | --- | + | ~trexio_read_$group_num$~ | 'Read a dimensioning variable ' | Single | + | ~trexio_write_$group_num$~ | 'Write a dimensioning variable' | Single | + | ~trexio_read_$group_num$_32~ | 'Read a dimensioning variable ' | Single | + | ~trexio_write_$group_num$_32~ | 'Write a dimensioning variable' | Single | + | ~trexio_read_$group_num$_64~ | 'Read a dimensioning variable ' | Double | + | ~trexio_write_$group_num$_64~ | 'Write a dimensioning variable' | Double | + +*** C templates for front end f + + The C templates that correspond to each of the abovementioned functions can be found below. + First parameter is the ~TREXIO~ file handle. Second parameter is the variable to be written/read + to/from the ~TREXIO~ file (except for `trexio_has_` functions). + Suffixes `_32` and `_64` correspond to API calls dealing with single and double precision, respectively. + The basic (non-suffixed) API call on dimensioning variables deals with single precision (see Table above). + #+begin_src c :tangle hrw_num_front.h trexio_exit_code trexio_has_$group_num$(trexio_t* const file); -trexio_exit_code trexio_read_$group_num$(trexio_t* const file, int64_t* const num); -trexio_exit_code trexio_write_$group_num$(trexio_t* const file, const int64_t num); +trexio_exit_code trexio_read_$group_num$(trexio_t* const file, int32_t* const num); +trexio_exit_code trexio_write_$group_num$(trexio_t* const file, const int32_t num); +trexio_exit_code trexio_read_$group_num$_32(trexio_t* const file, int32_t* const num); +trexio_exit_code trexio_write_$group_num$_32(trexio_t* const file, const int32_t num); +trexio_exit_code trexio_read_$group_num$_64(trexio_t* const file, int64_t* const num); +trexio_exit_code trexio_write_$group_num$_64(trexio_t* const file, const int64_t num); #+end_src - #+begin_src c :tangle read_num_front.c -trexio_exit_code trexio_read_$group_num$(trexio_t* const file, int64_t* const num) { + #+begin_src c :tangle read_num_64_front.c +trexio_exit_code trexio_read_$group_num$_64(trexio_t* const file, int64_t* const num) { if (file == NULL) return TREXIO_INVALID_ARG_1; uint64_t u_num = 0; @@ -603,8 +733,8 @@ trexio_exit_code trexio_read_$group_num$(trexio_t* const file, int64_t* const nu } #+end_src - #+begin_src c :tangle write_num_front.c -trexio_exit_code trexio_write_$group_num$(trexio_t* const file, const int64_t num) { + #+begin_src c :tangle write_num_64_front.c +trexio_exit_code trexio_write_$group_num$_64(trexio_t* const file, const int64_t num) { if (file == NULL) return TREXIO_INVALID_ARG_1; if (num < 0 ) return TREXIO_INVALID_ARG_2; @@ -613,15 +743,15 @@ trexio_exit_code trexio_write_$group_num$(trexio_t* const file, const int64_t nu switch (file->back_end) { case TREXIO_TEXT: - rc = trexio_text_write_$group_num$(file, (uint64_t) num); + rc = trexio_text_write_$group_num$(file, (int64_t) num); break; case TREXIO_HDF5: - rc = trexio_hdf5_write_$group_num$(file, (uint64_t) num); + rc = trexio_hdf5_write_$group_num$(file, (int64_t) num); break; /* case TREXIO_JSON: - rc = trexio_json_write_$group_num$(file, (uint64_t) num); + rc = trexio_json_write_$group_num$(file, (int64_t) num); break; ,*/ } @@ -631,6 +761,76 @@ trexio_exit_code trexio_write_$group_num$(trexio_t* const file, const int64_t nu } #+end_src + #+begin_src c :tangle read_num_32_front.c +trexio_exit_code trexio_read_$group_num$_32(trexio_t* const file, int32_t* const 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_$group_num$(file, &u_num); + break; + + case TREXIO_HDF5: + rc = trexio_hdf5_read_$group_num$(file, &u_num); + break; +/* + case TREXIO_JSON: + rc =trexio_json_read_$group_num$(file, &u_num); + break; +,*/ + } + + if (rc != TREXIO_SUCCESS) return rc; + + *num = (int32_t) u_num; + return TREXIO_SUCCESS; +} + #+end_src + + #+begin_src c :tangle write_num_32_front.c +trexio_exit_code trexio_write_$group_num$_32(trexio_t* const file, const int32_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_$group_num$(file, (int64_t) num); + break; + + case TREXIO_HDF5: + rc = trexio_hdf5_write_$group_num$(file, (int64_t) num); + break; +/* + case TREXIO_JSON: + rc = trexio_json_write_$group_num$(file, (int64_t) num); + break; +,*/ + } + if (rc != TREXIO_SUCCESS) return rc; + + return TREXIO_SUCCESS; +} + #+end_src + + #+begin_src c :tangle read_num_def_front.c +trexio_exit_code trexio_read_$group_num$(trexio_t* const file, int32_t* const num) { + return trexio_read_$group_num$_32(file, num); +} + #+end_src + + #+begin_src c :tangle write_num_def_front.c +trexio_exit_code trexio_write_$group_num$(trexio_t* const file, const int32_t num) { + return trexio_write_$group_num$_32(file, num); +} + #+end_src + #+begin_src c :tangle has_num_front.c trexio_exit_code trexio_has_$group_num$(trexio_t* const file) { if (file == NULL) return TREXIO_INVALID_ARG_1; @@ -656,22 +856,67 @@ trexio_exit_code trexio_has_$group_num$(trexio_t* const file) { } #+end_src - #+begin_src f90 :tangle write_num_front_fortran.f90 +*** Fortran templates for front end + + The Fortran templates that provide an access to the C API calls from Fortran. + These templates are based on the use of `iso_c_binding`. Pointers have to be passed by value. + + #+begin_src f90 :tangle write_num_64_front_fortran.f90 +interface + integer function trexio_write_$group_num$_64 (trex_file, num) bind(C) + use, intrinsic :: iso_c_binding + integer(8), intent(in), value :: trex_file + integer(8), intent(in), value :: num + end function trexio_write_$group_num$_64 +end interface + #+end_src + + #+begin_src f90 :tangle read_num_64_front_fortran.f90 +interface + integer function trexio_read_$group_num$_64 (trex_file, num) bind(C) + use, intrinsic :: iso_c_binding + integer(8), intent(in), value :: trex_file + integer(8), intent(out) :: num + end function trexio_read_$group_num$_64 +end interface + #+end_src + + #+begin_src f90 :tangle write_num_32_front_fortran.f90 +interface + integer function trexio_write_$group_num$_32 (trex_file, num) bind(C) + use, intrinsic :: iso_c_binding + integer(8), intent(in), value :: trex_file + integer(4), intent(in), value :: num + end function trexio_write_$group_num$_32 +end interface + #+end_src + + #+begin_src f90 :tangle read_num_32_front_fortran.f90 +interface + integer function trexio_read_$group_num$_32 (trex_file, num) bind(C) + use, intrinsic :: iso_c_binding + integer(8), intent(in), value :: trex_file + integer(4), intent(out) :: num + end function trexio_read_$group_num$_32 +end interface + #+end_src + + #+begin_src f90 :tangle write_num_def_front_fortran.f90 interface integer function trexio_write_$group_num$ (trex_file, num) bind(C) use, intrinsic :: iso_c_binding integer(8), intent(in), value :: trex_file - integer(8), intent(in), value :: num + integer(4), intent(in), value :: num end function trexio_write_$group_num$ end interface #+end_src - #+begin_src f90 :tangle read_num_front_fortran.f90 + #+begin_src f90 :tangle read_num_def_front_fortran.f90 interface integer function trexio_read_$group_num$ (trex_file, num) bind(C) use, intrinsic :: iso_c_binding integer(8), intent(in), value :: trex_file - integer(8), intent(out) :: num + integer(4), intent(out) :: num end function trexio_read_$group_num$ end interface #+end_src @@ -684,40 +929,49 @@ interface end function trexio_has_$group_num$ end interface #+end_src +** Templates for front end has/read/write a dataset + + This section concerns API calls related to datasets. + + | Function name | Description | Precision | + |----------------------------------------+--------------------------------------+-----------| + | ~trexio_has_$group$_$group_dset$~ | 'Check if a dataset exists in a file | --- | + | ~trexio_read_$group$_$group_dset$~ | 'Read a dataset ' | Double | + | ~trexio_write_$group$_$group_dset$~ | 'Write a dataset' | Double | + | ~trexio_read_$group$_$group_dset$_32~ | 'Read a dataset' | Single | + | ~trexio_write_$group$_$group_dset$_32~ | 'Write a dataset' | Single | + | ~trexio_read_$group$_$group_dset$_64~ | 'Read a dataset' | Double | + | ~trexio_write_$group$_$group_dset$_64~ | 'Write a dataset' | Double | + +*** C templates for front end + + The C templates that correspond to each of the abovementioned functions can be found below. + First parameter is the ~TREXIO~ file handle. Second parameter is the variable to be written/read + to/from the ~TREXIO~ file (except for `trexio_has_` functions). + Suffixes `_32` and `_64` correspond to API calls dealing with single and double precision, respectively. + The basic (non-suffixed) API call on datasets deals with double precision (see Table above). -** Template for frontend has/read/write a dataset #+begin_src c :tangle hrw_dset_front.h trexio_exit_code trexio_has_$group$_$group_dset$(trexio_t* const file); -trexio_exit_code trexio_read_$group$_$group_dset$(trexio_t* const file, $group_dset_dtype$* const $group_dset$); -trexio_exit_code trexio_write_$group$_$group_dset$(trexio_t* const file, const $group_dset_dtype$* $group_dset$); +trexio_exit_code trexio_read_$group$_$group_dset$(trexio_t* const file, $group_dset_dtype_double$* const $group_dset$); +trexio_exit_code trexio_write_$group$_$group_dset$(trexio_t* const file, const $group_dset_dtype_double$* $group_dset$); +trexio_exit_code trexio_read_$group$_$group_dset$_32(trexio_t* const file, $group_dset_dtype_single$* const $group_dset$); +trexio_exit_code trexio_write_$group$_$group_dset$_32(trexio_t* const file, const $group_dset_dtype_single$* $group_dset$); +trexio_exit_code trexio_read_$group$_$group_dset$_64(trexio_t* const file, $group_dset_dtype_double$* const $group_dset$); +trexio_exit_code trexio_write_$group$_$group_dset$_64(trexio_t* const file, const $group_dset_dtype_double$* $group_dset$); #+end_src - #+begin_src c :tangle read_dset_front.c -trexio_exit_code trexio_read_$group$_$group_dset$(trexio_t* const file, $group_dset_dtype$* const $group_dset$) { + #+begin_src c :tangle read_dset_64_front.c +trexio_exit_code trexio_read_$group$_$group_dset$_64(trexio_t* const file, $group_dset_dtype_double$* const $group_dset$) { 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$ = 0; + int64_t $group_dset_dim$ = 0; - switch (file->back_end) { - - case TREXIO_TEXT: - rc = trexio_text_read_$group_dset_dim$(file, &$group_dset_dim$); - break; - - case TREXIO_HDF5: - rc = trexio_hdf5_read_$group_dset_dim$(file, &$group_dset_dim$); - break; -/* - case TREXIO_JSON: - rc = trexio_json_read_$group_dset_dim$(file, &$group_dset_dim$); - break; -*/ - } - - if (rc != TREXIO_SUCCESS) return rc; + /* Error handling for this call is added by the generator */ + rc = trexio_read_$group_dset_dim$_64(file, &($group_dset_dim$)); if ($group_dset_dim$ == 0L) return TREXIO_INVALID_NUM; @@ -735,7 +989,7 @@ trexio_exit_code trexio_read_$group$_$group_dset$(trexio_t* const file, $group_d break; /* case TREXIO_JSON: - return trexio_json_read_$group$_$group_dset$(file, $group_dset$); + return trexio_json_read_$group$_$group_dset$(file, $group_dset$, rank, dims); break; ,*/ default: @@ -744,30 +998,17 @@ trexio_exit_code trexio_read_$group$_$group_dset$(trexio_t* const file, $group_d } #+end_src - #+begin_src c :tangle write_dset_front.c -trexio_exit_code trexio_write_$group$_$group_dset$(trexio_t* const file, const $group_dset_dtype$* $group_dset$) { + #+begin_src c :tangle write_dset_64_front.c +trexio_exit_code trexio_write_$group$_$group_dset$_64(trexio_t* const file, const $group_dset_dtype_double$* $group_dset$) { 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$ = 0; - switch (file->back_end) { + int64_t $group_dset_dim$ = 0; - case TREXIO_TEXT: - rc = trexio_text_read_$group_dset_dim$(file, &$group_dset_dim$); - break; + /* Error handling for this call is added by the generator */ + rc = trexio_read_$group_dset_dim$_64(file, &($group_dset_dim$)); - case TREXIO_HDF5: - rc = trexio_hdf5_read_$group_dset_dim$(file, &$group_dset_dim$); - break; -/* - case TREXIO_JSON: - rc = trexio_json_read_$group_dset_dim$(file, &$group_dset_dim$); - break; -*/ - } - - if (rc != TREXIO_SUCCESS) return rc; if ($group_dset_dim$ == 0L) return TREXIO_INVALID_NUM; uint32_t rank = $group_dset_rank$; @@ -784,7 +1025,7 @@ trexio_exit_code trexio_write_$group$_$group_dset$(trexio_t* const file, const $ break; /* case TREXIO_JSON: - return trexio_json_write_$group$_$group_dset$(file, $group_dset$); + return trexio_json_write_$group$_$group_dset$(file, $group_dset$, rank, dims); break; ,*/ default: @@ -793,6 +1034,129 @@ trexio_exit_code trexio_write_$group$_$group_dset$(trexio_t* const file, const $ } #+end_src + #+begin_src c :tangle read_dset_32_front.c +trexio_exit_code trexio_read_$group$_$group_dset$_32(trexio_t* const file, $group_dset_dtype_single$* const $group_dset$) { + if (file == NULL) return TREXIO_INVALID_ARG_1; + if ($group_dset$ == NULL) return TREXIO_INVALID_ARG_2; + + trexio_exit_code rc; + int64_t $group_dset_dim$ = 0; + + /* Error handling for this call is added by the generator */ + rc = trexio_read_$group_dset_dim$_64(file, &($group_dset_dim$)); + + if ($group_dset_dim$ == 0L) return TREXIO_INVALID_NUM; + + uint32_t rank = $group_dset_rank$; + uint64_t dims[$group_dset_rank$] = {$group_dset_dim_list$}; + + uint64_t dim_size = 1; + for (unsigned int i=0; iback_end) { + + case TREXIO_TEXT: + rc = trexio_text_read_$group$_$group_dset$(file, $group_dset$_64, rank, dims); + break; + + case TREXIO_HDF5: + rc = trexio_hdf5_read_$group$_$group_dset$(file, $group_dset$_64, rank, dims); + break; +/* + case TREXIO_JSON: + rc = trexio_json_read_$group$_$group_dset$(file, $group_dset$_64, rank, dims); + break; +,*/ + default: + return TREXIO_FAILURE; /* Impossible case */ + } + + if (rc != TREXIO_SUCCESS){ + FREE($group_dset$_64); + return rc; + } + + for (uint64_t i=0; iback_end) { + + case TREXIO_TEXT: + rc = trexio_text_write_$group$_$group_dset$(file, $group_dset$_64, rank, dims); + break; + + case TREXIO_HDF5: + rc = trexio_hdf5_write_$group$_$group_dset$(file, $group_dset$_64, rank, dims); + break; +/* + case TREXIO_JSON: + rc = trexio_json_write_$group$_$group_dset$(file, $group_dset$_64, rank, dims); + break; +,*/ + default: + return TREXIO_FAILURE; /* Impossible case */ + } + + FREE($group_dset$_64); + + if (rc != TREXIO_SUCCESS) return rc; + + return TREXIO_SUCCESS; +} + #+end_src + + #+begin_src c :tangle read_dset_def_front.c +trexio_exit_code trexio_read_$group$_$group_dset$(trexio_t* const file, $group_dset_dtype_double$* const $group_dset$) { + return trexio_read_$group$_$group_dset$_64(file, $group_dset$); +} + #+end_src + + #+begin_src c :tangle write_dset_def_front.c +trexio_exit_code trexio_write_$group$_$group_dset$(trexio_t* const file, const $group_dset_dtype_double$* $group_dset$) { + return trexio_write_$group$_$group_dset$_64(file, $group_dset$); +} + #+end_src + #+begin_src c :tangle has_dset_front.c trexio_exit_code trexio_has_$group$_$group_dset$(trexio_t* const file) { if (file == NULL) return TREXIO_INVALID_ARG_1; @@ -817,23 +1181,67 @@ trexio_exit_code trexio_has_$group$_$group_dset$(trexio_t* const file) { } #+end_src +*** Fortran templates for front end - #+begin_src f90 :tangle write_dset_front_fortran.f90 + The Fortran templates that provide an access to the C API calls from Fortran. + These templates are based on the use of `iso_c_binding`. Pointers have to be passed by value. + + #+begin_src f90 :tangle write_dset_64_front_fortran.f90 +interface + integer function trexio_write_$group$_$group_dset$_64 (trex_file, dset) bind(C) + use, intrinsic :: iso_c_binding + integer(8), intent(in), value :: trex_file + $group_dset_f_dtype_double$, intent(in) :: dset(*) + end function trexio_write_$group$_$group_dset$_64 +end interface + #+end_src + + #+begin_src f90 :tangle read_dset_64_front_fortran.f90 +interface + integer function trexio_read_$group$_$group_dset$_64 (trex_file, dset) bind(C) + use, intrinsic :: iso_c_binding + integer(8), intent(in), value :: trex_file + $group_dset_f_dtype_double$, intent(out) :: dset(*) + end function trexio_read_$group$_$group_dset$_64 +end interface + #+end_src + + #+begin_src f90 :tangle write_dset_32_front_fortran.f90 +interface + integer function trexio_write_$group$_$group_dset$_32 (trex_file, dset) bind(C) + use, intrinsic :: iso_c_binding + integer(8), intent(in), value :: trex_file + $group_dset_f_dtype_single$, intent(in) :: dset(*) + end function trexio_write_$group$_$group_dset$_32 +end interface + #+end_src + + #+begin_src f90 :tangle read_dset_32_front_fortran.f90 +interface + integer function trexio_read_$group$_$group_dset$_32 (trex_file, dset) bind(C) + use, intrinsic :: iso_c_binding + integer(8), intent(in), value :: trex_file + $group_dset_f_dtype_single$, intent(out) :: dset(*) + end function trexio_read_$group$_$group_dset$_32 +end interface + #+end_src + + #+begin_src f90 :tangle write_dset_def_front_fortran.f90 interface integer function trexio_write_$group$_$group_dset$ (trex_file, dset) bind(C) use, intrinsic :: iso_c_binding integer(8), intent(in), value :: trex_file - $group_dset_f_dtype$, intent(in) :: dset(*) + $group_dset_f_dtype_double$, intent(in) :: dset(*) end function trexio_write_$group$_$group_dset$ end interface #+end_src - #+begin_src f90 :tangle read_dset_front_fortran.f90 + #+begin_src f90 :tangle read_dset_def_front_fortran.f90 interface integer function trexio_read_$group$_$group_dset$ (trex_file, dset) bind(C) use, intrinsic :: iso_c_binding integer(8), intent(in), value :: trex_file - $group_dset_f_dtype$, intent(out) :: dset(*) + $group_dset_f_dtype_double$, intent(out) :: dset(*) end function trexio_read_$group$_$group_dset$ end interface #+end_src @@ -847,17 +1255,13 @@ interface end interface #+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 - - * Fortran helper/wrapper functions + The function below adapts the original C-based `trexio_open` for Fortran. + This is needed due to the fact that strings in C are terminated by NULL character `\0` + unlike strings in Fortran. + Note, that Fortran interface calls the main ~TREXIO~ API, which is written in C. + #+begin_src f90 :tangle suffix_fortran.f90 contains integer(8) function trexio_open (filename, mode, backend) @@ -873,8 +1277,7 @@ contains end function trexio_open #+end_src - -* File suffixes :noxport: +* File suffixes :noexport: #+begin_src c :tangle suffix_front.h #endif @@ -887,6 +1290,3 @@ contains #+begin_src f90 :tangle suffix_fortran.f90 end module trexio #+end_src - - - diff --git a/src/test.c b/src/test.c index 1dfcf54..60cf46a 100644 --- a/src/test.c +++ b/src/test.c @@ -1,6 +1,5 @@ #include "trexio.h" #include -#include #include #include @@ -19,7 +18,7 @@ int main() { test_write(); test_read(); - printf("%s\n", trexio_string_of_error(TREXIO_INVALID_ARG_2)); + printf("Test error message: %s\n", trexio_string_of_error(TREXIO_INVALID_ARG_2)); return 0 ; } @@ -32,7 +31,8 @@ int test_h5write() { trexio_exit_code rc; // parameters to be written - int64_t num = 12; + int num = 12; + double charge[12] = {6., 6., 6., 6., 6., 6., 1., 1., 1., 1., 1., 1.}; double coord[36] = { 0.00000000 , 1.39250319 , 0.00000000 , @@ -66,6 +66,8 @@ int test_h5write() { assert (rc == TREXIO_SUCCESS); rc = trexio_write_nucleus_coord(file,coord); assert (rc == TREXIO_SUCCESS); + rc = trexio_write_nucleus_charge(file,charge); + assert (rc == TREXIO_SUCCESS); // check if the written data exists in the file rc = trexio_has_nucleus_num(file); @@ -112,7 +114,7 @@ int test_h5read() { trexio_t* file = NULL; trexio_exit_code rc; - int64_t num; + int num; double* coord; /*================= START OF TEST ==================*/ @@ -167,8 +169,8 @@ int test_write() { trexio_exit_code rc; // parameters to be written - int64_t num = 12; - double charge[12] = {6., 6., 6., 6., 6., 6., 1., 1., 1., 1., 1., 1.}; + int num = 12; + float charge[12] = {6., 6., 6., 6., 6., 6., 1., 1., 1., 1., 1., 1.}; double coord[36] = { 0.00000000 , 1.39250319 , 0.00000000 , -1.20594314 , 0.69625160 , 0.00000000 , @@ -197,7 +199,7 @@ int test_write() { rc = trexio_write_nucleus_num(file,num); assert (rc == TREXIO_SUCCESS); - rc = trexio_write_nucleus_charge(file,charge); + rc = trexio_write_nucleus_charge_32(file,charge); assert (rc == TREXIO_SUCCESS); rc = trexio_write_nucleus_coord(file,coord); @@ -224,8 +226,8 @@ int test_read() { trexio_t* file = NULL; trexio_exit_code rc; - int64_t num; - double* charge; + int num; + float* charge; double* coord; /*================= START OF TEST ==================*/ @@ -237,8 +239,8 @@ int test_read() { assert (rc == TREXIO_SUCCESS); assert (num == 12); - charge = (double*) calloc(num, sizeof(double)); - rc = trexio_read_nucleus_charge(file,charge); + charge = (float*) calloc(num, sizeof(float)); + rc = trexio_read_nucleus_charge_32(file,charge); assert (rc == TREXIO_SUCCESS); assert(charge[10] == 1.); diff --git a/src/test.f90 b/src/test.f90 index 28f2f14..2d975f5 100644 --- a/src/test.f90 +++ b/src/test.f90 @@ -15,7 +15,7 @@ subroutine test_write() integer(8) :: trex_file integer :: rc = 1 - integer(8) :: num + integer :: num double precision :: charge(12) double precision :: coord(36) @@ -94,7 +94,7 @@ subroutine test_read() integer(8) :: trex_file integer :: rc = 1 - integer(8) :: num, num_read + integer :: num, num_read double precision :: charge(12) double precision :: coord(3,12)