Repository: TREX-CoE/trexio (language: python)

Issue:
32/64 versions of the functions



Discussion / hints:

Fix patch:
diff --git a/src/.gitignore b/src/.gitignore
index a22dab16..fca8201c 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 cf87abdd..94679e4c 100644
--- a/src/generator.py
+++ b/src/generator.py
@@ -9,17 +9,11 @@
 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 @@
 
                         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 aa6ba4be..debe7a66 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 <assert.h>
   #+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[<<MAX_STRING_LENGTH()>>]);
+			      char result[<<MAX_STRING_LENGTH()>>]);
    #+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[<<MAX_ST
   end interface
   #+end_src
 
+** Back ends
 
+   TREXIO has several back ends:
 
+   1) `TREXIO_HDF5` relies on extensive use of the HDF5 library and the associated file format.
+   The HDF5 file is binary and tailored to high-performance I/O. This back end is the default one.
+   HDF5 can be compiled with MPI for parallel I/O.
+   Note, that HDF5 has to be downloaded and installed independently of TREXIO, which may cause
+   some obstacles, especially when the user is not allowed to install external software.
+   The produced files usually have `.h5` extension.
 
-** Back ends
+   2) `TREXIO_TEXT` relies on basic file I/O in C, namely `fopen, fclose, fprintf, fscanf` etc.
+   from `stdio.h` library. This back end is not optimized for performance. It is supposed to be
+   used for debug purposes or, for example, when the user wants to modify some data manually within the file.
+   This back end is supposed to work "out-of-the-box" since there are no external dependencies, which might
+   be useful for users that do not have access to HDF5 library.
+   The produced files usually have `.txt` extension.
+
+   Additional back ends can be implemented thanks to the modular nature of the front end.
+   This can be achieved by adding a new `case` (corresponding to the desired back end) in the front-end `switch`
+   Then the corresponding back-end `has/read/write_` functions has to be implemented. For example, see the commented
+   lines that correspond to the `TREXIO_JSON` back end (not implemented yet).
 
    #+begin_src c :tangle prefix_front.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 )
+/*#define TREXIO_JSON             ( (back_end_t) 2 )*/
+#define TREXIO_INVALID_BACK_END ( (back_end_t) 2 )
    #+end_src
 
 ** Read/write behavior
@@ -314,9 +336,9 @@ typedef int32_t back_end_t;
 
    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.
+   calling explicitly the write (`TREXIO_HDF5`) or flush (`TREXIO_TEXT`)
+   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.
@@ -346,7 +368,7 @@ struct trexio_s {
   pthread_mutex_t   thread_lock;
   back_end_t        back_end;
   char              mode;
-  char              padding[7];   /* Ensures the proper alignment of back-ends */
+  char              padding[7];   /* Ensures the proper alignment of back ends */
 };
    #+end_src
 
@@ -354,18 +376,39 @@ struct trexio_s {
 
    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
+   ~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 */
+  /* add below specific back-end data */
 }
    #+end_src
 
 ** File opening
 
+   `trexio_open` creates a new ~TREXIO~ file or opens existing one.
+
+   `trexio_open` input:
+     1) `file_name`     - string containing file name
+     2) `mode`          - character containing open mode (see below)
+       1. `'w'`         - (write)  creates a new file as READWRITE (overwrite existing file)
+       2. `'r'`         - (read)   opens existing file as READONLY
+       3. `'a'`         - (append) either opens file in READWRITE mode if it already exists or creates a new one
+     3) `back_end`      - integer number (or the corresponding global parameter) specifying the back end
+       1. `TREXIO_HDF5` - for HDF5 back end (integer alternative: 0)
+       2. `TREXIO_TEXT` - for TEXT back end (integer alternative: 1)
+
+   `trexio_open` output:
+     `trexio_t` file handle
+
+   _**Note: the `file_name` in TEXT back end actually corresponds to the name of the folder where `.txt`
+   data files are stored. The actual name of each `.txt.` file corresponds to the `group` name provided in
+   `trex.config` (e.g. `nucleus.txt` for nucleus-related data like atomic coordinates).
+   These names are populated by the `generator.py` (i.e. they are hard-coded), which is why the user
+   should tend to avoid renaming the `.txt` data files.**_
+
    #+begin_src c :tangle prefix_front.h
 trexio_t* trexio_open(const char* file_name, const char mode, const back_end_t back_end);
    #+end_src
@@ -449,7 +492,7 @@ trexio_t* trexio_open(const char* file_name, const char mode, const back_end_t b
   case TREXIO_TEXT:
     rc = trexio_text_lock(result);
     break;
-
+  /* HDF5 v.>=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,24 +743,94 @@ 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, (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_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_write_$group_num$(file, (uint64_t) num);
+    rc = trexio_hdf5_read_$group_num$(file, &u_num);
     break;
 /*
   case TREXIO_JSON:
-    rc = trexio_json_write_$group_num$(file, (uint64_t) num);
+    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$ (trex_file, num) bind(C)
+   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(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,85 @@ 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;
+
+  /* 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$};
 
   switch (file->back_end) {
 
   case TREXIO_TEXT:
-    rc = trexio_text_read_$group_dset_dim$(file, &$group_dset_dim$);
+    return trexio_text_read_$group$_$group_dset$(file, $group_dset$, rank, dims);
     break;
 
   case TREXIO_HDF5:
-    rc = trexio_hdf5_read_$group_dset_dim$(file, &$group_dset_dim$);
+    return trexio_hdf5_read_$group$_$group_dset$(file, $group_dset$, rank, dims);
     break;
 /*
   case TREXIO_JSON:
-    rc = trexio_json_read_$group_dset_dim$(file, &$group_dset_dim$);
+    return trexio_json_read_$group$_$group_dset$(file, $group_dset$, rank, dims);
     break;
-*/
+,*/
+  default:
+    return TREXIO_FAILURE;  /* Impossible case */
   }
+}
+     #+end_src
 
-  if (rc != TREXIO_SUCCESS) return rc;
+     #+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;
+  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;
 
@@ -727,15 +1017,15 @@ trexio_exit_code trexio_read_$group$_$group_dset$(trexio_t* const file, $group_d
   switch (file->back_end) {
 
   case TREXIO_TEXT:
-    return trexio_text_read_$group$_$group_dset$(file, $group_dset$, rank, dims);
+    return trexio_text_write_$group$_$group_dset$(file, $group_dset$, rank, dims);
     break;
 
   case TREXIO_HDF5:
-    return trexio_hdf5_read_$group$_$group_dset$(file, $group_dset$, rank, dims);
+    return trexio_hdf5_write_$group$_$group_dset$(file, $group_dset$, rank, dims);
     break;
 /*
   case TREXIO_JSON:
-    return trexio_json_read_$group$_$group_dset$(file, $group_dset$);
+    return trexio_json_write_$group$_$group_dset$(file, $group_dset$, rank, dims);
     break;
 ,*/
   default:
@@ -744,52 +1034,126 @@ 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 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;
-  uint64_t $group_dset_dim$ = 0;
+  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; i<rank; ++i){
+    dim_size *= dims[i];
+  }
+
+  $group_dset_dtype_double$* $group_dset$_64 = CALLOC(dim_size, $group_dset_dtype_double$);
+  if ($group_dset$_64 == NULL) return TREXIO_ALLOCATION_FAILED;
+
   switch (file->back_end) {
 
   case TREXIO_TEXT:
-    rc = trexio_text_read_$group_dset_dim$(file, &$group_dset_dim$);
+    rc = trexio_text_read_$group$_$group_dset$(file, $group_dset$_64, rank, dims);
     break;
 
   case TREXIO_HDF5:
-    rc = trexio_hdf5_read_$group_dset_dim$(file, &$group_dset_dim$);
+    rc = trexio_hdf5_read_$group$_$group_dset$(file, $group_dset$_64, rank, dims);
     break;
 /*
   case TREXIO_JSON:
-    rc = trexio_json_read_$group_dset_dim$(file, &$group_dset_dim$);
+    rc = trexio_json_read_$group$_$group_dset$(file, $group_dset$_64, rank, dims);
     break;
-*/
+,*/
+  default:
+    return TREXIO_FAILURE;  /* Impossible case */
   }
 
-  if (rc != TREXIO_SUCCESS) return rc;
+  if (rc != TREXIO_SUCCESS){
+    FREE($group_dset$_64);
+    return rc;
+  }
+
+  for (uint64_t i=0; i<dim_size; ++i){
+    $group_dset$[i] = ($group_dset_dtype_single$) $group_dset$_64[i];
+  }
+
+  FREE($group_dset$_64);
+  return TREXIO_SUCCESS;
+}
+     #+end_src
+
+     #+begin_src c :tangle write_dset_32_front.c
+trexio_exit_code trexio_write_$group$_$group_dset$_32(trexio_t* const file, const $group_dset_dtype_single$* $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; i<rank; ++i){
+    dim_size *= dims[i];
+  }
+
+  $group_dset_dtype_double$* $group_dset$_64 = CALLOC(dim_size, $group_dset_dtype_double$);
+  if ($group_dset$_64 == NULL) return TREXIO_ALLOCATION_FAILED;
+
+  /* A type conversion from single precision to double reqired since back end only accepts 64-bit data */
+  for (uint64_t i=0; i<dim_size; ++i){
+    $group_dset$_64[i] = ($group_dset_dtype_double$) $group_dset$[i];
+  }
+
   switch (file->back_end) {
 
   case TREXIO_TEXT:
-    return trexio_text_write_$group$_$group_dset$(file, $group_dset$, rank, dims);
+    rc = trexio_text_write_$group$_$group_dset$(file, $group_dset$_64, rank, dims);
     break;
 
   case TREXIO_HDF5:
-    return trexio_hdf5_write_$group$_$group_dset$(file, $group_dset$, rank, dims);
+    rc = trexio_hdf5_write_$group$_$group_dset$(file, $group_dset$_64, rank, dims);
     break;
 /*
   case TREXIO_JSON:
-    return trexio_json_write_$group$_$group_dset$(file, $group_dset$);
+    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
 
@@ -817,23 +1181,67 @@ trexio_exit_code trexio_has_$group$_$group_dset$(trexio_t* const file) {
 }
      #+end_src
 
+*** 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_dset_front_fortran.f90
+     #+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
-
-
-


Test patch:
diff --git a/src/test.c b/src/test.c
index 1dfcf54b..60cf46af 100644
--- a/src/test.c
+++ b/src/test.c
@@ -1,6 +1,5 @@
 #include "trexio.h"
 #include <assert.h>
-#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -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 28f2f143..2d975f5f 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)