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

Issue:
Warnings when compiling
Problem with a `const`:
```
In file included from src/trexio_hdf5.h:10,
                 from src/trexio_hdf5.c:6:
src/trexio_hdf5.c:8700:39: warning: passing argument 1 of 'free' discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
 8700 |     if (index_p != index_sparse) FREE(index_p);
      |                                       ^~~~~~~
src/trexio_private.h:12:24: note: in definition of macro 'FREE'
   12 | #define FREE(X) { free(X) ; (X)=NULL; }
      |                        ^
In file included from src/trexio_hdf5.h:14,
                 from src/trexio_hdf5.c:6:
/usr/include/stdlib.h:482:25: note: expected 'void *' but argument is of type 'const void *'
  482 | extern void free (void *__ptr) __THROW;
      |                   ~~~~~~^~~~~

```


Discussion / hints:

Fix patch:
diff --git a/Makefile.am b/Makefile.am
index 420a8780..945663ed 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -112,6 +112,7 @@ TESTS_C = \
   tests/io_dset_float_text \
   tests/io_dset_int_text \
   tests/io_dset_sparse_text \
+  tests/io_determinant_text \
   tests/io_safe_dset_float_text \
   tests/io_str_text \
   tests/io_dset_str_text \
@@ -127,6 +128,7 @@ TESTS_C += \
   tests/io_dset_float_hdf5 \
   tests/io_dset_int_hdf5 \
   tests/io_dset_sparse_hdf5 \
+  tests/io_determinant_hdf5 \
   tests/io_safe_dset_float_hdf5 \
   tests/io_str_hdf5 \
   tests/io_dset_str_hdf5 \
diff --git a/python/setup.py b/python/setup.py
index 2348038c..14de5905 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -9,7 +9,7 @@
 
 def parse_setuppy_commands():
     """Check the commands and respond appropriately.
-    At the moment it is adapted to ignore checks for numpy, plgconfig, HDF5 flags
+    At the moment it is adapted to ignore checks for numpy, pkgconfig, HDF5 flags
     when building the distribution tarball with sdist option.
     """
     args = sys.argv[1:]
@@ -93,7 +93,11 @@ def parse_setuppy_commands():
                             sources = [os.path.join(srcpath, code) for code in c_files],
                             include_dirs = [h5_cflags, srcpath, numpy_includedir],
                             libraries = ['hdf5', 'hdf5_hl'],
-                            extra_compile_args = ['-Wno-discarded-qualifiers'],
+                            extra_compile_args = [
+                                '-Wno-discarded-qualifiers',
+                                '-Wno-unused-variable',
+                                '-Wno-unused-but-set-variable'
+                                ],
                             extra_link_args = [h5_ldflags]
                             )
 
diff --git a/src/pytrexio.i b/src/pytrexio.i
index 52a7be97..121d465d 100644
--- a/src/pytrexio.i
+++ b/src/pytrexio.i
@@ -36,6 +36,10 @@
 /* Return num variables as part of the output tuple */
 %apply int *OUTPUT { int32_t* const num};
 %apply int *OUTPUT { int64_t* const num};
+%apply int *OUTPUT { int32_t* const num_up};
+%apply int *OUTPUT { int32_t* const num_dn};
+%apply int *OUTPUT { int64_t* const num_up};
+%apply int *OUTPUT { int64_t* const num_dn};
 %apply float *OUTPUT { float* const num};
 %apply float *OUTPUT { double* const num};
 /* Return TREXIO exit code from trexio_open as part of the output tuple */
@@ -75,6 +79,7 @@ import_array();
 %numpy_typemaps(float, NPY_FLOAT, int64_t)
 %numpy_typemaps(int32_t, NPY_INT32, int64_t)
 %numpy_typemaps(int64_t, NPY_INT64, int64_t)
+%numpy_typemaps(bitfield_t, NPY_INT64, int64_t)
 /* Enable write|read_safe functions to convert numpy arrays from/to double arrays */
 %apply (double* ARGOUT_ARRAY1, int64_t DIM1) {(double* const dset_out, const int64_t dim_out)};
 %apply (double* IN_ARRAY1, int64_t DIM1) {(const double* dset_in, const int64_t dim_in)};
@@ -93,6 +98,12 @@ import_array();
 
 %apply (double* ARGOUT_ARRAY1, int64_t DIM1) {(double* const value_sparse_read, const int64_t size_value_read)};
 %apply (int32_t* ARGOUT_ARRAY1, int64_t DIM1) {(int32_t* const index_sparse_read, const int64_t size_index_read)};
+/* Enable write|read_safe functions to convert numpy arrays from orbital list arrays */
+%apply (int32_t* ARGOUT_ARRAY1, int64_t DIM1) {(int32_t* const dset_up_out, const int64_t dim_up_out)};
+%apply (int32_t* ARGOUT_ARRAY1, int64_t DIM1) {(int32_t* const dset_dn_out, const int64_t dim_dn_out)};
+%apply (int64_t* ARGOUT_ARRAY1, int64_t DIM1) {(int64_t* const dset_up_out, const int64_t dim_up_out)};
+%apply (int64_t* ARGOUT_ARRAY1, int64_t DIM1) {(int64_t* const dset_dn_out, const int64_t dim_dn_out)};
+%apply (bitfield_t* IN_ARRAY1, int64_t DIM1) {(const bitfield_t* dset_in, const int64_t dim_in)};
 
 /* This tells SWIG to treat char ** dset_in pattern as a special case
    Enables access to trexio_[...]_write_dset_str set of functions directly, i.e.
diff --git a/src/templates_front/build.sh b/src/templates_front/build.sh
index 2ce1136e..90e4913f 100644
--- a/src/templates_front/build.sh
+++ b/src/templates_front/build.sh
@@ -38,9 +38,14 @@ echo "" >> trexio_f.f90
 # c front end
 cat populated/pop_*.c >> trexio.c
 cat populated/pop_*.h >> trexio.h
+# add determinant part
+cat hrw_determinant_front.h >> trexio.h
+cat *_determinant_front.c >> trexio.c
 
 # fortran front end
 cat populated/pop_*.f90  >> trexio_f.f90
+# add determinant part
+cat *_determinant_front_fortran.f90 >> trexio_f.f90
 # add helper functions
 cat helper_fortran.f90 >> trexio_f.f90
 cat populated/pop_*.fh_90 >> trexio_f.f90
@@ -48,6 +53,7 @@ cat populated/pop_*.fh_90 >> trexio_f.f90
 # python front end
 cat basic_python.py >> trexio.py
 cat populated/pop_*.py >> trexio.py
+cat *_determinant_front.py >> trexio.py
 
 # suffixes
 cat suffix_s_front.h >> trexio_s.h
diff --git a/src/templates_front/templator_front.org b/src/templates_front/templator_front.org
index 55c35875..2eb003d1 100644
--- a/src/templates_front/templator_front.org
+++ b/src/templates_front/templator_front.org
@@ -43,6 +43,7 @@ typedef int32_t trexio_exit_code;
 #include <stdlib.h>
 #include <stdbool.h>
 #include <string.h>
+#include <err.h>
 
 #include "trexio.h"
 #include "trexio_private.h"
@@ -158,40 +159,46 @@ __trexio_path__ = None
 ** Error handling
 
       #+NAME: table-exit-codes
-   | Macro                         | Code | Description                            |
-   |-------------------------------+------+----------------------------------------|
-   | ~TREXIO_FAILURE~              |   -1 | 'Unknown failure'                      |
-   | ~TREXIO_SUCCESS~              |    0 | 'Success'                              |
-   | ~TREXIO_INVALID_ARG_1~        |    1 | 'Invalid argument 1'                   |
-   | ~TREXIO_INVALID_ARG_2~        |    2 | 'Invalid argument 2'                   |
-   | ~TREXIO_INVALID_ARG_3~        |    3 | 'Invalid argument 3'                   |
-   | ~TREXIO_INVALID_ARG_4~        |    4 | 'Invalid argument 4'                   |
-   | ~TREXIO_INVALID_ARG_5~        |    5 | 'Invalid argument 5'                   |
-   | ~TREXIO_END~                  |    6 | 'End of file'                          |
-   | ~TREXIO_READONLY~             |    7 | 'Read-only file'                       |
-   | ~TREXIO_ERRNO~                |    8 | strerror(errno)                        |
-   | ~TREXIO_INVALID_ID~           |    9 | 'Invalid ID'                           |
-   | ~TREXIO_ALLOCATION_FAILED~    |   10 | 'Allocation failed'                    |
-   | ~TREXIO_HAS_NOT~              |   11 | 'Element absent'                       |
-   | ~TREXIO_INVALID_NUM~          |   12 | 'Invalid (negative or 0) dimension'    |
-   | ~TREXIO_ATTR_ALREADY_EXISTS~  |   13 | 'Attribute already exists'             |
-   | ~TREXIO_DSET_ALREADY_EXISTS~  |   14 | 'Dataset already exists'               |
-   | ~TREXIO_OPEN_ERROR~           |   15 | 'Error opening file'                   |
-   | ~TREXIO_LOCK_ERROR~           |   16 | 'Error locking file'                   |
-   | ~TREXIO_UNLOCK_ERROR~         |   17 | 'Error unlocking file'                 |
-   | ~TREXIO_FILE_ERROR~           |   18 | 'Invalid file'                         |
-   | ~TREXIO_GROUP_READ_ERROR~     |   19 | 'Error reading group'                  |
-   | ~TREXIO_GROUP_WRITE_ERROR~    |   20 | 'Error writing group'                  |
-   | ~TREXIO_ELEM_READ_ERROR~      |   21 | 'Error reading element'                |
-   | ~TREXIO_ELEM_WRITE_ERROR~     |   22 | 'Error writing element'                |
-   | ~TREXIO_UNSAFE_ARRAY_DIM~     |   23 | 'Access to memory beyond allocated'    |
-   | ~TREXIO_ATTR_MISSING~         |   24 | 'Attribute does not exist in the file' |
-   | ~TREXIO_DSET_MISSING~         |   25 | 'Dataset does not exist in the file'   |
-   | ~TREXIO_BACK_END_MISSING~     |   26 | 'Requested back end is disabled'       |
-   | ~TREXIO_INVALID_STR_LEN~      |   30 | 'Invalid max_str_len'                  |
-   | ~TREXIO_INT_SIZE_OVERFLOW~    |   31 | 'Possible integer overflow'            |
-   | ~TREXIO_SAFE_MODE~            |   32 | 'Unsafe operation in safe mode'        |
-   | ~TREXIO_INVALID_ELECTRON_NUM~ |   33 | 'Inconsistent value of electron num'   |
+   | Macro                            | Code | Description                            |
+   |----------------------------------+------+----------------------------------------|
+   | ~TREXIO_FAILURE~                 |   -1 | 'Unknown failure'                      |
+   | ~TREXIO_SUCCESS~                 |    0 | 'Success'                              |
+   | ~TREXIO_INVALID_ARG_1~           |    1 | 'Invalid argument 1'                   |
+   | ~TREXIO_INVALID_ARG_2~           |    2 | 'Invalid argument 2'                   |
+   | ~TREXIO_INVALID_ARG_3~           |    3 | 'Invalid argument 3'                   |
+   | ~TREXIO_INVALID_ARG_4~           |    4 | 'Invalid argument 4'                   |
+   | ~TREXIO_INVALID_ARG_5~           |    5 | 'Invalid argument 5'                   |
+   | ~TREXIO_END~                     |    6 | 'End of file'                          |
+   | ~TREXIO_READONLY~                |    7 | 'Read-only file'                       |
+   | ~TREXIO_ERRNO~                   |    8 | strerror(errno)                        |
+   | ~TREXIO_INVALID_ID~              |    9 | 'Invalid ID'                           |
+   | ~TREXIO_ALLOCATION_FAILED~       |   10 | 'Allocation failed'                    |
+   | ~TREXIO_HAS_NOT~                 |   11 | 'Element absent'                       |
+   | ~TREXIO_INVALID_NUM~             |   12 | 'Invalid (negative or 0) dimension'    |
+   | ~TREXIO_ATTR_ALREADY_EXISTS~     |   13 | 'Attribute already exists'             |
+   | ~TREXIO_DSET_ALREADY_EXISTS~     |   14 | 'Dataset already exists'               |
+   | ~TREXIO_OPEN_ERROR~              |   15 | 'Error opening file'                   |
+   | ~TREXIO_LOCK_ERROR~              |   16 | 'Error locking file'                   |
+   | ~TREXIO_UNLOCK_ERROR~            |   17 | 'Error unlocking file'                 |
+   | ~TREXIO_FILE_ERROR~              |   18 | 'Invalid file'                         |
+   | ~TREXIO_GROUP_READ_ERROR~        |   19 | 'Error reading group'                  |
+   | ~TREXIO_GROUP_WRITE_ERROR~       |   20 | 'Error writing group'                  |
+   | ~TREXIO_ELEM_READ_ERROR~         |   21 | 'Error reading element'                |
+   | ~TREXIO_ELEM_WRITE_ERROR~        |   22 | 'Error writing element'                |
+   | ~TREXIO_UNSAFE_ARRAY_DIM~        |   23 | 'Access to memory beyond allocated'    |
+   | ~TREXIO_ATTR_MISSING~            |   24 | 'Attribute does not exist in the file' |
+   | ~TREXIO_DSET_MISSING~            |   25 | 'Dataset does not exist in the file'   |
+   | ~TREXIO_BACK_END_MISSING~        |   26 | 'Requested back end is disabled'       |
+   | ~TREXIO_INVALID_ARG_6~           |   27 | 'Invalid argument 6'                   |
+   | ~TREXIO_INVALID_ARG_7~           |   28 | 'Invalid argument 7'                   |
+   | ~TREXIO_INVALID_ARG_8~           |   29 | 'Invalid argument 8'                   |
+   | ~TREXIO_INVALID_STR_LEN~         |   30 | 'Invalid max_str_len'                  |
+   | ~TREXIO_INT_SIZE_OVERFLOW~       |   31 | 'Possible integer overflow'            |
+   | ~TREXIO_SAFE_MODE~               |   32 | 'Unsafe operation in safe mode'        |
+   | ~TREXIO_INVALID_ELECTRON_NUM~    |   33 | 'Inconsistent number of electrons'     |
+   | ~TREXIO_INVALID_DETERMINANT_NUM~ |   34 | 'Inconsistent number of determinants'  |
+   | ~TREXIO_INVALID_STATE~           |   35 | 'Inconsistent state of the file'       |
+   | ~TREXIO_VERSION_PARSING_ISSUE~   |   36 | 'Failed to parse package_version'      |
 
    # We need to force Emacs not to indent the Python code:
    # -*- org-src-preserve-indentation: t
@@ -265,10 +272,16 @@ return '\n'.join(result)
    #define TREXIO_ATTR_MISSING            ((trexio_exit_code) 24)
    #define TREXIO_DSET_MISSING            ((trexio_exit_code) 25)
    #define TREXIO_BACK_END_MISSING        ((trexio_exit_code) 26)
+   #define TREXIO_INVALID_ARG_6           ((trexio_exit_code) 27)
+   #define TREXIO_INVALID_ARG_7           ((trexio_exit_code) 28)
+   #define TREXIO_INVALID_ARG_8           ((trexio_exit_code) 29)
    #define TREXIO_INVALID_STR_LEN         ((trexio_exit_code) 30)
    #define TREXIO_INT_SIZE_OVERFLOW       ((trexio_exit_code) 31)
    #define TREXIO_SAFE_MODE               ((trexio_exit_code) 32)
    #define TREXIO_INVALID_ELECTRON_NUM    ((trexio_exit_code) 33)
+   #define TREXIO_INVALID_DETERMINANT_NUM ((trexio_exit_code) 34)
+   #define TREXIO_INVALID_STATE           ((trexio_exit_code) 35)
+   #define TREXIO_VERSION_PARSING_ISSUE   ((trexio_exit_code) 36)
    #+end_src
 
    #+begin_src f90 :tangle prefix_fortran.f90 :exports none
@@ -300,10 +313,16 @@ return '\n'.join(result)
       integer(trexio_exit_code), parameter :: TREXIO_ATTR_MISSING            = 24
       integer(trexio_exit_code), parameter :: TREXIO_DSET_MISSING            = 25
       integer(trexio_exit_code), parameter :: TREXIO_BACK_END_MISSING        = 26
+      integer(trexio_exit_code), parameter :: TREXIO_INVALID_ARG_6           = 27
+      integer(trexio_exit_code), parameter :: TREXIO_INVALID_ARG_7           = 28
+      integer(trexio_exit_code), parameter :: TREXIO_INVALID_ARG_8           = 29
       integer(trexio_exit_code), parameter :: TREXIO_INVALID_STR_LEN         = 30
       integer(trexio_exit_code), parameter :: TREXIO_INT_SIZE_OVERFLOW       = 31
       integer(trexio_exit_code), parameter :: TREXIO_SAFE_MODE               = 32
       integer(trexio_exit_code), parameter :: TREXIO_INVALID_ELECTRON_NUM    = 33
+      integer(trexio_exit_code), parameter :: TREXIO_INVALID_DETERMINANT_NUM = 34
+      integer(trexio_exit_code), parameter :: TREXIO_INVALID_STATE           = 35
+      integer(trexio_exit_code), parameter :: TREXIO_VERSION_PARSING_ISSUE   = 36
    #+end_src
 
    #+begin_src python :tangle prefix_python.py :exports none
@@ -336,10 +355,16 @@ return '\n'.join(result)
    TREXIO_ATTR_MISSING            = 24
    TREXIO_DSET_MISSING            = 25
    TREXIO_BACK_END_MISSING        = 26
+   TREXIO_INVALID_ARG_6           = 27
+   TREXIO_INVALID_ARG_7           = 28
+   TREXIO_INVALID_ARG_8           = 29
    TREXIO_INVALID_STR_LEN         = 30
    TREXIO_INT_SIZE_OVERFLOW       = 31
    TREXIO_SAFE_MODE               = 32
    TREXIO_INVALID_ELECTRON_NUM    = 33
+   TREXIO_INVALID_DETERMINANT_NUM = 34
+   TREXIO_INVALID_STATE           = 35
+   TREXIO_VERSION_PARSING_ISSUE   = 36
    #+end_src
    :END:
 
@@ -466,6 +491,15 @@ return '\n'.join(result)
    case TREXIO_BACK_END_MISSING:
      return "Requested back end is disabled";
      break;
+   case TREXIO_INVALID_ARG_6:
+     return "Invalid argument 6";
+     break;
+   case TREXIO_INVALID_ARG_7:
+     return "Invalid argument 7";
+     break;
+   case TREXIO_INVALID_ARG_8:
+     return "Invalid argument 8";
+     break;
    case TREXIO_INVALID_STR_LEN:
      return "Invalid max_str_len";
      break;
@@ -476,7 +510,16 @@ return '\n'.join(result)
      return "Unsafe operation in safe mode";
      break;
    case TREXIO_INVALID_ELECTRON_NUM:
-     return "Inconsistent value of electron num";
+     return "Inconsistent number of electrons";
+     break;
+   case TREXIO_INVALID_DETERMINANT_NUM:
+     return "Inconsistent number of determinants";
+     break;
+   case TREXIO_INVALID_STATE:
+     return "Inconsistent state of the file";
+     break;
+   case TREXIO_VERSION_PARSING_ISSUE:
+     return "Failed to parse package_version";
      break;
    #+end_example
 
@@ -534,16 +577,10 @@ def string_of_error(return_code: int) -> str:
     """Decode the TREXIO exit code.
 
     Argument is an integer return code that correspond to one of the TREXIO errors.
-
-    Returns string that contains description of TREXIO ~return_code~.
+    Returns a string that contains description of TREXIO ~return_code~.
     """
 
-    try:
-        error_str = pytr.trexio_string_of_error(return_code)
-    except:
-        raise
-
-    return error_str
+    return pytr.trexio_string_of_error(return_code)
   #+end_src
 
 ** Back ends
@@ -691,16 +728,22 @@ struct trexio_s {
   back_end_t        back_end;
   char              mode;
   bool              one_based;
+  int32_t           state;
+  int16_t           version_major;
+  int16_t           version_minor;
+  int16_t           version_patch;
   char              version[16];
-  char              padding[6];   /* Ensures the proper alignment of back ends */
 };
    #+end_src
 
-*** TREXIO_File Python class
+
+   File class for the Python API is defined below.
+   Use of Python class make it more intuitive and more python-ic
+   to work with TREXIO files.
 
    #+begin_src python :tangle basic_python.py
 class File:
-    """TREXIO File object.
+    """trexio.File class.
 
     General information about the TREXIO file.
 
@@ -714,6 +757,9 @@ class File:
     mode: str
         One of the currently supported TREXIO open modes.
         For example, 'r' or 'w'.
+    state: int
+        Active state of the file (needed to write determinant_coefficient).
+        Default is 0.
     isOpen: bool
         Flag indicating whether the current object is still open for I/O
     pytrexio_s:
@@ -730,7 +776,7 @@ class File:
         """TREXIO File class constructor."""
         self.filename = filename
         self.mode = mode
-        self.back_end = back_end
+        self.state = 0
 
         self.isOpen = False
         self.exists = False
@@ -743,6 +789,7 @@ class File:
             self.isOpen = None
             self.exists = None
 
+        self.back_end = self.pytrexio_s.back_end
         self.info = info
 
 
@@ -766,6 +813,29 @@ class File:
             raise Exception("TREXIO File object has not been opened.")
 
 
+    def set_state(self, state):
+        """Set the state of the TREXIO File."""
+        if not isinstance(state, int):
+            raise TypeError("state argument has to be int")
+
+        rc = pytr.trexio_set_state(self.pytrexio_s, state)
+        if rc != TREXIO_SUCCESS:
+            raise Error(rc)
+
+        self.state = state
+
+
+    def get_state(self):
+        """Get the state of the TREXIO File."""
+        rc, state = pytr.trexio_get_state(self.pytrexio_s)
+        if rc != TREXIO_SUCCESS:
+            raise Error(rc)
+
+        if state != self.state:
+            raise Exception("Inconsistent state of the TREXIO file.")
+
+        return self.state
+
     def inquire(self):
         """Inquire whether a TREXIO file exists."""
         self.exists = _inquire(self.filename)
@@ -781,7 +851,7 @@ class File:
             pass
    #+end_src
 
-** Polymorphism of the file handle
+** TODO (Remove) : 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
@@ -934,16 +1004,10 @@ trexio_open(const char* file_name, const char mode,
     return NULL;
   }
 
-  strncpy(result->version, TREXIO_PACKAGE_VERSION, 16);
-  if (result->version[15] != '\0') {
-    if (rc_open != NULL) *rc_open = TREXIO_FAILURE;
-    free(result);
-    return NULL;
-  }
-
   result->back_end    = back_end_local;
   result->mode        = mode;
   result->one_based   = false;  // Need to be flipped in Fortran interface
+  result->state       = 0;      // By default the file corresponds to a ground state
   int irc = pthread_mutex_init ( &(result->thread_lock), NULL);
   if (irc != 0) {
     if (rc_open != NULL) *rc_open = TREXIO_FAILURE;
@@ -1028,6 +1092,7 @@ trexio_open(const char* file_name, const char mode,
   }
 
   if (rc == TREXIO_HAS_NOT) {
+  /* Write TREXIO_PACKAGE_VERSION upon creation of the file */
     switch (back_end_local) {
 
     case TREXIO_TEXT:
@@ -1045,15 +1110,69 @@ trexio_open(const char* file_name, const char mode,
 #endif
 
     }
+
+    if (rc != TREXIO_SUCCESS) {
+      if (rc_open != NULL) *rc_open = rc;
+      free(result);
+      return NULL;
+    }
+
+    result->version_major = TREXIO_VERSION_MAJOR;
+    result->version_minor = TREXIO_VERSION_MINOR;
+    result->version_patch = TREXIO_VERSION_PATCH;
+    strncpy(result->version, TREXIO_PACKAGE_VERSION, 16);
+
+  } else {
+  /* Otherwise read the metadata_package_version to get the TREXIO version upon creation of the file */
+    char version_origin[16];
+
+    switch (back_end_local) {
+
+    case TREXIO_TEXT:
+      rc = trexio_text_read_metadata_package_version(result, version_origin, 16);
+      break;
+
+    case TREXIO_HDF5:
+#ifdef HAVE_HDF5
+      rc = trexio_hdf5_read_metadata_package_version(result, version_origin, 16);
+      break;
+#else
+      if (rc_open != NULL) *rc_open = TREXIO_BACK_END_MISSING;
+      free(result);
+      return NULL;
+#endif
+
+    }
+
+    if (rc != TREXIO_SUCCESS) {
+      if (rc_open != NULL) *rc_open = rc;
+      free(result);
+      return NULL;
+    }
+
+    int16_t version_major, version_minor, version_patch;
+    int rc_scan = sscanf(version_origin,
+                         "%3" SCNd16 ".%5" SCNd16 ".%5" SCNd16,
+                         &version_major, &version_minor, &version_patch);
+    if (rc_scan != 3) {
+      if (rc_open != NULL) *rc_open = TREXIO_VERSION_PARSING_ISSUE;
+      free(result);
+      return NULL;
+    }
+
+    result->version_major = version_major;
+    result->version_minor = version_minor;
+    result->version_patch = version_patch;
+    strncpy(result->version, version_origin, 16);
+
   }
 
-  if (rc != TREXIO_SUCCESS) {
-    if (rc_open != NULL) *rc_open = rc;
+  if (result->version[15] != '\0' || result->version_major == 0) {
+    if (rc_open != NULL) *rc_open = TREXIO_FAILURE;
     free(result);
     return NULL;
   }
 
-
   /* Mark the file as unsafe upon opening in UNSAFE 'u' mode */
   if (mode == 'u') {
 
@@ -1218,10 +1337,8 @@ trexio_close (trexio_t* file)
 
   /* Things to be done before closing the file in the back-end */
   rc = trexio_pre_close(file);
-  if (rc != TREXIO_SUCCESS) {
-    return rc;
-  }
-  
+  if (rc != TREXIO_SUCCESS) return rc;
+
   /* Terminate the back end */
   switch (file->back_end) {
 
@@ -1308,12 +1425,9 @@ def _close(trexio_file):
     Parameter is a ~trexio_file~ object that has been created by a call to ~open~ function.
     """
 
-    try:
-        rc = pytr.trexio_close(trexio_file)
-        if rc != TREXIO_SUCCESS:
-            raise Error(rc)
-    except:
-        raise
+    rc = pytr.trexio_close(trexio_file)
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
    #+end_src
 
 ** File existence
@@ -1399,8 +1513,76 @@ def _inquire(file_name: str) -> bool:
         raise Error(rc)
    #+end_src
 
+** File state
+
+    ~trexio_set_state~ set an existing ~trexio_t~ file handle to a given state.
+    ~trexio_get_state~ returns current sate of the ~trexio_t~ file handle.
+
+    input parameters:
+      ~file~  -- TREXIO file handle.
+      ~state~ -- ~int32_t~ number of state.
+
+    output:
+      ~trexio_exit_code~ exit code.
+
+*** C
+
+    #+begin_src c :tangle prefix_front.h :exports none
+trexio_exit_code trexio_set_state(trexio_t* file, const int32_t num);
+trexio_exit_code trexio_get_state(trexio_t* file, int32_t* const num);
+    #+end_src
+
+    #+begin_src c :tangle prefix_front.c
+trexio_exit_code
+trexio_set_state (trexio_t* file, const int32_t num)
+{
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+
+  file->state = num;
+
+  return TREXIO_SUCCESS;
+}
+
+trexio_exit_code
+trexio_get_state (trexio_t* file, int32_t* const num)
+{
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+  if (num  == NULL) return TREXIO_INVALID_ARG_2;
+
+  *num = file->state;
+
+  return TREXIO_SUCCESS;
+}
+    #+end_src
+
+*** Fortran
+
+    #+begin_src f90 :tangle prefix_fortran.f90
+interface
+   integer(trexio_exit_code) function trexio_set_state (trex_file, state) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int64_t), intent(in), value :: trex_file
+     integer(c_int32_t), intent(in), value :: state
+   end function trexio_set_state
+end interface
+
+interface
+   integer(trexio_exit_code) function trexio_get_state (trex_file, state) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int64_t), intent(in), value :: trex_file
+     integer(c_int32_t), intent(out)       :: state
+   end function trexio_get_state
+end interface
+    #+end_src
+
+*** Python
+
+    See TREXIO File Python class.
+
 ** Tasks to be done before closing
-   
+
     #+begin_src c :tangle trexio_private.h :exports none
 trexio_exit_code trexio_pre_close(trexio_t* file);
     #+end_src
@@ -1412,74 +1594,94 @@ trexio_pre_close (trexio_t* file)
 
   if (file == NULL) return TREXIO_FILE_ERROR;
 
-  { /* Up-spin and down-spin electrons */
-    trexio_exit_code rc;
-    
-    int32_t nup, ndn, nelec;
-    bool has_up   = (trexio_has_electron_up_num(file) == TREXIO_SUCCESS);
-    bool has_dn   = (trexio_has_electron_dn_num(file) == TREXIO_SUCCESS);
-    bool has_updn = (trexio_has_electron_num(file) == TREXIO_SUCCESS);
-    
-    if (file->mode != 'r') {
-      if (has_updn && has_up && has_dn) {
-        rc = trexio_read_electron_up_num(file, &nup);
-        if (rc != TREXIO_SUCCESS) return rc;
-        
-        rc = trexio_read_electron_dn_num(file, &ndn);
-        if (rc != TREXIO_SUCCESS) return rc;
-        
-        rc = trexio_read_electron_num(file, &nelec);
-        if (rc != TREXIO_SUCCESS) return rc;
-        
-        if (nelec != nup + ndn) {
-          if (file->mode == 'u') {
-            nelec = nup + ndn;
-            rc = trexio_write_electron_num(file, nelec);
-            if (rc != TREXIO_SUCCESS) return rc;
-          } else {
-            return TREXIO_INVALID_ELECTRON_NUM;
-          }
+  trexio_exit_code rc;
+
+  /* Check consistency between number of determinants and coefficients stored in the file */
+
+  if (file->version_major >= 2 && file->version_minor >= 2) {
+
+    bool has_det   = (trexio_has_determinant_list(file) == TREXIO_SUCCESS);
+    bool has_coeff = (trexio_has_determinant_coefficient(file) == TREXIO_SUCCESS);
+    int64_t ndet, ncoeff;
+
+    if (has_det && has_coeff) {
+      rc = trexio_read_determinant_num_64(file, &ndet);
+      if (rc != TREXIO_SUCCESS) return rc;
+
+      rc = trexio_read_determinant_coefficient_size(file, &ncoeff);
+      if (rc != TREXIO_SUCCESS) return rc;
+
+      /* Maybe be even more direct and use assert here so that the user's code crushes in case of inconsistency */
+      if (ndet != ncoeff) return TREXIO_INVALID_DETERMINANT_NUM;
+    }
+
+  }
+  /* Up-spin and down-spin electrons */
+
+  int32_t nup, ndn, nelec;
+  bool has_up   = (trexio_has_electron_up_num(file) == TREXIO_SUCCESS);
+  bool has_dn   = (trexio_has_electron_dn_num(file) == TREXIO_SUCCESS);
+  bool has_updn = (trexio_has_electron_num(file) == TREXIO_SUCCESS);
+
+  if (file->mode != 'r') {
+    if (has_updn && has_up && has_dn) {
+      rc = trexio_read_electron_up_num(file, &nup);
+      if (rc != TREXIO_SUCCESS) return rc;
+
+      rc = trexio_read_electron_dn_num(file, &ndn);
+      if (rc != TREXIO_SUCCESS) return rc;
+
+      rc = trexio_read_electron_num(file, &nelec);
+      if (rc != TREXIO_SUCCESS) return rc;
+
+      if (nelec != nup + ndn) {
+        if (file->mode == 'u') {
+          nelec = nup + ndn;
+          rc = trexio_write_electron_num(file, nelec);
+          if (rc != TREXIO_SUCCESS) return rc;
+        } else {
+          return TREXIO_INVALID_ELECTRON_NUM;
         }
-      } else if (has_up && has_dn) {
-        rc = trexio_read_electron_up_num(file, &nup);
-        if (rc != TREXIO_SUCCESS) return rc;
-        
-        rc = trexio_read_electron_dn_num(file, &ndn);
-        if (rc != TREXIO_SUCCESS) return rc;
-        
-        nelec = nup + ndn;
-        rc = trexio_write_electron_num(file, nelec);
-        if (rc != TREXIO_SUCCESS) return rc;
-      } else if (has_up) {
-        rc = trexio_read_electron_up_num(file, &nup);
-        if (rc != TREXIO_SUCCESS) return rc;
-        
-        ndn = 0;
-        rc = trexio_write_electron_dn_num(file, ndn);
-        if (rc != TREXIO_SUCCESS) return rc;
-        
-        nelec = nup;
-        rc = trexio_write_electron_num(file, nelec);
-        if (rc != TREXIO_SUCCESS) return rc;
-      } else if (has_dn) {
-        rc = trexio_read_electron_dn_num(file, &ndn);
-        if (rc != TREXIO_SUCCESS) return rc;
-        
-        nup = 0;
-        rc = trexio_write_electron_up_num(file, nup);
-        if (rc != TREXIO_SUCCESS) return rc;
-        
-        nelec = ndn;
-        rc = trexio_write_electron_num(file, nelec);
-        if (rc != TREXIO_SUCCESS) return rc;
       }
+    } else if (has_up && has_dn) {
+      rc = trexio_read_electron_up_num(file, &nup);
+      if (rc != TREXIO_SUCCESS) return rc;
+
+      rc = trexio_read_electron_dn_num(file, &ndn);
+      if (rc != TREXIO_SUCCESS) return rc;
+
+      nelec = nup + ndn;
+      rc = trexio_write_electron_num(file, nelec);
+      if (rc != TREXIO_SUCCESS) return rc;
+    } else if (has_up) {
+      rc = trexio_read_electron_up_num(file, &nup);
+      if (rc != TREXIO_SUCCESS) return rc;
+
+      ndn = 0;
+      rc = trexio_write_electron_dn_num(file, ndn);
+      if (rc != TREXIO_SUCCESS) return rc;
+
+      nelec = nup;
+      rc = trexio_write_electron_num(file, nelec);
+      if (rc != TREXIO_SUCCESS) return rc;
+    } else if (has_dn) {
+      rc = trexio_read_electron_dn_num(file, &ndn);
+      if (rc != TREXIO_SUCCESS) return rc;
+
+      nup = 0;
+      rc = trexio_write_electron_up_num(file, nup);
+      if (rc != TREXIO_SUCCESS) return rc;
+
+      nelec = ndn;
+      rc = trexio_write_electron_num(file, nelec);
+      if (rc != TREXIO_SUCCESS) return rc;
     }
   }
-  
+
   return TREXIO_SUCCESS;
 }
     #+end_src
-   
+
 * Templates for front end
 ** Description
 
@@ -1879,12 +2081,9 @@ def write_$group_num$(trexio_file, num_w: $group_num_py_dtype$) -> None:
         - Exception from some other error (e.g. RuntimeError).
     """
 
-    try:
-        rc = pytr.trexio_write_$group_num$(trexio_file.pytrexio_s, num_w)
-        if rc != TREXIO_SUCCESS:
-            raise Error(rc)
-    except:
-        raise
+    rc = pytr.trexio_write_$group_num$(trexio_file.pytrexio_s, num_w)
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
      #+end_src
 
      #+begin_src python :tangle read_attr_num_front.py
@@ -1902,12 +2101,9 @@ def read_$group_num$(trexio_file) -> $group_num_py_dtype$:
         - Exception from some other error (e.g. RuntimeError).
     """
 
-    try:
-        rc, num_r = pytr.trexio_read_$group_num$(trexio_file.pytrexio_s)
-        if rc != TREXIO_SUCCESS:
-            raise Error(rc)
-    except:
-        raise
+    rc, num_r = pytr.trexio_read_$group_num$(trexio_file.pytrexio_s)
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
 
     return num_r
      #+end_src
@@ -1922,21 +2118,15 @@ def has_$group_num$(trexio_file) -> bool:
           True if the variable exists, False otherwise
 
     Raises:
-        - Exception from trexio.Error class if TREXIO return code ~rc~ is TREXIO_FAILURE and prints the error message using string_of_error.
+        - trexio.Error if TREXIO return code ~rc~ is TREXIO_FAILURE and prints the error message using string_of_error.
         - Exception from some other error (e.g. RuntimeError).
     """
 
-    try:
-        rc = pytr.trexio_has_$group_num$(trexio_file.pytrexio_s)
-        if rc == TREXIO_FAILURE:
-            raise Error(rc)
-    except:
-        raise
+    rc = pytr.trexio_has_$group_num$(trexio_file.pytrexio_s)
+    if rc == TREXIO_FAILURE:
+        raise Error(rc)
 
-    if rc == TREXIO_SUCCESS:
-        return True
-    else:
-        return False
+    return rc == TREXIO_SUCCESS
      #+end_src
 
 ** Templates for front end has/read/write a dataset of numerical data
@@ -2545,7 +2735,7 @@ def write_$group_dset$(trexio_file, dset_w) -> None:
         Array of $group_dset$ values to be written. If array data type does not correspond to int64 or float64, the conversion is performed.
 
     Raises:
-        - Exception from AssertionError if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message using trexio_string_of_error.
+        - trexio.Error if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message.
         - Exception from some other error (e.g. RuntimeError).
     """
 
@@ -2618,7 +2808,7 @@ def read_$group_dset$(trexio_file, dim = None, doReshape = None, dtype = None):
         1D NumPy array with ~dim~ elements corresponding to $group_dset$ values read from the TREXIO file.
 
     Raises:
-        - Exception from AssertionError if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message using trexio_string_of_error.
+        - trexio.Error if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message.
         - Exception from some other error (e.g. RuntimeError).
 """
 
@@ -2645,44 +2835,32 @@ def read_$group_dset$(trexio_file, dim = None, doReshape = None, dtype = None):
     if shape is None and doReshape:
         raise ValueError("Reshaping failure: shape is None.")
 
-    try:
-        rc, dset_64 = pytr.trexio_read_safe_$group_dset$_64(trexio_file.pytrexio_s, dim)
 
-        if rc != TREXIO_SUCCESS:
-            raise Error(rc)
-    except:
-        raise
+    rc, dset_64 = pytr.trexio_read_safe_$group_dset$_64(trexio_file.pytrexio_s, dim)
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
 
 
     isConverted = False
     dset_converted = None
     if dtype is not None:
-
         try:
             assert isinstance(dtype, type)
         except AssertionError:
             raise TypeError("dtype argument has to be an instance of the type class (e.g. np.float32).")
 
-
         if not dtype==np.int64 or not dtype==np.float64:
-            try:
-                dset_converted = np.array(dset_64, dtype=dtype)
-            except:
-                raise
-
+            dset_converted = np.array(dset_64, dtype=dtype)
             isConverted = True
 
     # additional assert can be added here to check that read_safe functions returns numpy array of proper dimension
 
     if doReshape:
-        try:
-            # in-place reshaping did not work so I have to make a copy
-            if isConverted:
-                dset_reshaped = np.reshape(dset_converted, shape, order='C')
-            else:
-                dset_reshaped = np.reshape(dset_64, shape, order='C')
-        except:
-            raise
+        # in-place reshaping did not work so I have to make a copy
+        if isConverted:
+            dset_reshaped = np.reshape(dset_converted, shape, order='C')
+        else:
+            dset_reshaped = np.reshape(dset_64, shape, order='C')
 
     if isConverted:
         return dset_converted
@@ -2702,21 +2880,15 @@ def has_$group_dset$(trexio_file) -> bool:
           True if the variable exists, False otherwise
 
     Raises:
-        - Exception from trexio.Error class if TREXIO return code ~rc~ is TREXIO_FAILURE and prints the error message using string_of_error.
+        - trexio.Error if TREXIO return code ~rc~ is TREXIO_FAILURE and prints the error message using string_of_error.
         - Exception from some other error (e.g. RuntimeError).
     """
 
-    try:
-        rc = pytr.trexio_has_$group_dset$(trexio_file.pytrexio_s)
-        if rc == TREXIO_FAILURE:
-            raise Error(rc)
-    except:
-        raise
+    rc = pytr.trexio_has_$group_dset$(trexio_file.pytrexio_s)
+    if rc == TREXIO_FAILURE:
+        raise Error(rc)
 
-    if rc == TREXIO_SUCCESS:
-        return True
-    else:
-        return False
+    return rc == TREXIO_SUCCESS
      #+end_src
 
 ** Templates for front end has/read/write a dataset of sparse data
@@ -2841,7 +3013,7 @@ trexio_read_$group_dset$(trexio_t* const file,
   if (rc != TREXIO_SUCCESS) return rc;
 
   // introduce a new variable which will be modified with the number of integrals being read if EOF is encountered
-  int64_t eof_read_size = 0UL;
+  int64_t eof_read_size = 0L;
 
   switch (file->back_end) {
 
@@ -3176,14 +3348,14 @@ def write_$group_dset$(trexio_file: File, offset_file: int, buffer_size: int, in
     buffer_size: int
         The number of integrals to write in the file from the provided sparse arrays.
 
-    values: list OR numpy.ndarray
+    indices: list OR numpy.ndarray
         Array of $group_dset$ indices to be written. If array data type does not correspond to int32, the conversion is performed.
 
     values: list OR numpy.ndarray
         Array of $group_dset$ values to be written. If array data type does not correspond to float64, the conversion is performed.
 
     Raises:
-        - Exception from AssertionError if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message using trexio_string_of_error.
+        - trexio.Error if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message.
         - Exception from some other error (e.g. RuntimeError).
     """
 
@@ -3337,12 +3509,9 @@ def read_$group_dset$_size(trexio_file) -> int:
         - Exception from some other error (e.g. RuntimeError).
     """
 
-    try:
-        rc, num_integral = pytr.trexio_read_$group_dset$_size(trexio_file.pytrexio_s)
-        if rc != TREXIO_SUCCESS:
-            raise Error(rc)
-    except:
-        raise
+    rc, num_integral = pytr.trexio_read_$group_dset$_size(trexio_file.pytrexio_s)
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
 
     return num_integral
      #+end_src
@@ -3357,21 +3526,15 @@ def has_$group_dset$(trexio_file) -> bool:
           True if the variable exists, False otherwise
 
     Raises:
-        - Exception from trexio.Error class if TREXIO return code ~rc~ is TREXIO_FAILURE and prints the error message using string_of_error.
+        - trexio.Error if TREXIO return code ~rc~ is TREXIO_FAILURE and prints the error message using string_of_error.
         - Exception from some other error (e.g. RuntimeError).
     """
 
-    try:
-        rc = pytr.trexio_has_$group_dset$(trexio_file.pytrexio_s)
-        if rc == TREXIO_FAILURE:
-            raise Error(rc)
-    except:
-        raise
+    rc = pytr.trexio_has_$group_dset$(trexio_file.pytrexio_s)
+    if rc == TREXIO_FAILURE:
+        raise Error(rc)
 
-    if rc == TREXIO_SUCCESS:
-        return True
-    else:
-        return False
+    return rc == TREXIO_SUCCESS
      #+end_src
 
 ** Templates for front end has/read/write a dataset of strings
@@ -3754,14 +3917,9 @@ def write_$group_dset$(trexio_file, dset_w: list) -> None:
 
     max_str_length = len(max(dset_w, key=len)) + 1
 
-    try:
-        rc = pytr.trexio_write_$group_dset$(trexio_file.pytrexio_s, dset_w, max_str_length)
-
-        if rc != TREXIO_SUCCESS:
-            raise Error(rc)
-    except:
-        raise
-
+    rc = pytr.trexio_write_$group_dset$(trexio_file.pytrexio_s, dset_w, max_str_length)
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
      #+end_src
 
      #+begin_src python :tangle read_dset_str_front.py
@@ -3796,22 +3954,15 @@ def read_$group_dset$(trexio_file, dim = None) -> list:
             dim *= dims_list[i]
 
 
-    try:
-        rc, dset_1d_r = pytr.trexio_read_$group_dset$_low(trexio_file.pytrexio_s, PYTREXIO_MAX_STR_LENGTH)
-
-        if rc != TREXIO_SUCCESS:
-            raise Error(rc)
-    except:
-        raise
+    rc, dset_1d_r = pytr.trexio_read_$group_dset$_low(trexio_file.pytrexio_s, PYTREXIO_MAX_STR_LENGTH)
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
 
 
-    try:
-        dset_full = dset_1d_r.split(pytr.TREXIO_DELIM)
-        dset_2d_r = [dset_full[i] for i in range(dim) if dset_full[i]]
-        if not dset_2d_r:
-            raise ValueError(f"Output of {read_$group_dset$.__name__} function cannot be an empty list.")
-    except:
-        raise
+    dset_full = dset_1d_r.split(pytr.TREXIO_DELIM)
+    dset_2d_r = [dset_full[i] for i in range(dim) if dset_full[i]]
+    if not dset_2d_r:
+        raise ValueError(f"Output of {read_$group_dset$.__name__} function cannot be an empty list.")
 
     return dset_2d_r
      #+end_src
@@ -3826,21 +3977,15 @@ def has_$group_dset$(trexio_file) -> bool:
           True if the variable exists, False otherwise
 
     Raises:
-        - Exception from trexio.Error class if TREXIO return code ~rc~ is TREXIO_FAILURE and prints the error message using string_of_error.
+        - trexio.Error if TREXIO return code ~rc~ is TREXIO_FAILURE and prints the error message using string_of_error.
         - Exception from some other error (e.g. RuntimeError).
     """
 
-    try:
-        rc = pytr.trexio_has_$group_dset$(trexio_file.pytrexio_s)
-        if rc == TREXIO_FAILURE:
-            raise Error(rc)
-    except:
-        raise
+    rc = pytr.trexio_has_$group_dset$(trexio_file.pytrexio_s)
+    if rc == TREXIO_FAILURE:
+        raise Error(rc)
 
-    if rc == TREXIO_SUCCESS:
-        return True
-    else:
-        return False
+    return rc == TREXIO_SUCCESS
      #+end_src
 
 ** Templates for front end has/read/write a single string attribute
@@ -4053,13 +4198,9 @@ def write_$group_str$(trexio_file, str_w: str) -> None:
 
     max_str_length = len(str_w) + 1
 
-    try:
-        rc = pytr.trexio_write_$group_str$(trexio_file.pytrexio_s, str_w, max_str_length)
-
-        if rc != TREXIO_SUCCESS:
-            raise Error(rc)
-    except:
-        raise
+    rc = pytr.trexio_write_$group_str$(trexio_file.pytrexio_s, str_w, max_str_length)
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
      #+end_src
 
      #+begin_src python :tangle read_attr_str_front.py
@@ -4077,13 +4218,9 @@ def read_$group_str$(trexio_file) -> str:
         - Exception from some other error (e.g. RuntimeError).
     """
 
-    try:
-        rc, str_r = pytr.trexio_read_$group_str$(trexio_file.pytrexio_s, PYTREXIO_MAX_STR_LENGTH)
-
-        if rc != TREXIO_SUCCESS:
-            raise Error(rc)
-    except:
-        raise
+    rc, str_r = pytr.trexio_read_$group_str$(trexio_file.pytrexio_s, PYTREXIO_MAX_STR_LENGTH)
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
 
     return str_r
      #+end_src
@@ -4098,21 +4235,15 @@ def has_$group_str$(trexio_file) -> bool:
           True if the variable exists, False otherwise
 
     Raises:
-        - Exception from trexio.Error class if TREXIO return code ~rc~ is TREXIO_FAILURE and prints the error message using string_of_error.
+        - trexio.Error if TREXIO return code ~rc~ is TREXIO_FAILURE and prints the error message using string_of_error.
         - Exception from some other error (e.g. RuntimeError).
     """
 
-    try:
-        rc = pytr.trexio_has_$group_str$(trexio_file.pytrexio_s)
-        if rc == TREXIO_FAILURE:
-            raise Error(rc)
-    except:
-        raise
+    rc = pytr.trexio_has_$group_str$(trexio_file.pytrexio_s)
+    if rc == TREXIO_FAILURE:
+        raise Error(rc)
 
-    if rc == TREXIO_SUCCESS:
-        return True
-    else:
-        return False
+    return rc == TREXIO_SUCCESS
      #+end_src
 
 ** Templates for front end delete an entire group (UNSAFE MODE)
@@ -4196,70 +4327,1043 @@ def delete_$group$(trexio_file) -> None:
     if rc != TREXIO_SUCCESS:
         raise Error(rc)
      #+end_src
-* General helper functions
+* Source code for the determinant part
+
+   Storage of the determinants is a particular case,
+   which requires special treatment, but has to be coded only once
+   (since there is only one group that corresponds to it).
+   Thus, there is no need to auto-generate this part via templates.
+
+   This section concerns API calls related to Slater determinants.
+
+   | Function name                              | Description                            |
+   |--------------------------------------------+----------------------------------------|
+   | ~trexio_has_determinant_coefficient~       | Check if an attribute exists in a file |
+   | ~trexio_has_determinant_list~              | Check if an attribute exists in a file |
+   | ~trexio_write_determinant_coefficient~     | Write an attribute                     |
+   | ~trexio_write_determinant_list~            | Write an attribute                     |
+   | ~trexio_read_determinant_coefficient~      | Read an attribute                      |
+   | ~trexio_read_determinant_list~             | Read an attribute                      |
+   | ~trexio_read_determinant_coefficient_size~ | Get the number of the coefficients     |
+
+*** C source code
+
+     #+begin_src c :tangle hrw_determinant_front.h :exports none
+trexio_exit_code trexio_has_determinant_list(trexio_t* const file);
+trexio_exit_code trexio_has_determinant_coefficient(trexio_t* const file);
+trexio_exit_code trexio_read_determinant_list(trexio_t* const file, const int64_t offset_file, int64_t* const buffer_size, int64_t* const dset);
+trexio_exit_code trexio_read_safe_determinant_list(trexio_t* const file, const int64_t offset_file, int64_t* const buffer_size_read, int64_t* const dset_out, const int64_t dim_out);
+trexio_exit_code trexio_read_determinant_coefficient(trexio_t* const file, const int64_t offset_file, int64_t* const buffer_size, double* const dset);
+trexio_exit_code trexio_read_safe_determinant_coefficient(trexio_t* const file, const int64_t offset_file, int64_t* const buffer_size_read, double* const dset_out, const int64_t dim_out);
+trexio_exit_code trexio_write_determinant_list(trexio_t* const file, const int64_t offset_file, const int64_t buffer_size, const int64_t* dset);
+trexio_exit_code trexio_write_safe_determinant_list(trexio_t* const file, const int64_t offset_file, const int64_t buffer_size, const int64_t* dset_in, const int64_t dim_in);
+trexio_exit_code trexio_write_determinant_coefficient(trexio_t* const file, const int64_t offset_file, const int64_t buffer_size, const double* dset);
+trexio_exit_code trexio_write_safe_determinant_coefficient(trexio_t* const file, const int64_t offset_file, const int64_t buffer_size, const double* dset_in, const int64_t dim_in);
+trexio_exit_code trexio_read_determinant_coefficient_size(trexio_t* const file, int64_t* const size_max);
+     #+end_src
 
-  This section contains general helper functions like ~trexio_info~.
+     #+begin_src c :tangle read_determinant_front.c
+trexio_exit_code
+trexio_read_determinant_list (trexio_t* const file, const int64_t offset_file, int64_t* const buffer_size_read, int64_t* const dset)
+{
 
-  ~trexio_info~ prints information about the TREXIO configuration (see =config.h= file).
-  In particular:
+  if (file  == NULL) return TREXIO_INVALID_ARG_1;
+  if (dset  == NULL) return TREXIO_INVALID_ARG_2;
+  if (trexio_has_determinant_list(file) != TREXIO_SUCCESS) return TREXIO_DSET_MISSING;
 
-  1) ~TREXIO_PACKAGE_VERSION~ [string]
-  2) ~HAVE_HDF5~ [bool]
-  3) ~HDF5_VERSION~ [string] (optional, only if ~HAVE_HDF5~ is ~true~)
-  4) ~TREXIO_GIT_HASH~ [string]
+  trexio_exit_code rc;
 
-  ~trexio_mark_safety~ checks if the file has been open in UNSAFE mode.
-  If it was, the ~metadata_unsafe~ attribute can be overwritten with the value provided in a second argument of the function.
-  Since ~metadata_unsafe~ is set to ~1~ (~true~) upon the first opening of the file in UNSAFE mode, this value is immutable.
-  However, if the user validated that the file is correct (e.g. using ~trexio-tools~),
-  then value of the ~metadata_unsafe~ attribute can be changed using the aforementioned function.
+  /* Read the number of mos */
+  int64_t mo_num = 0L;
+  rc = trexio_read_mo_num_64(file, &mo_num);
+  if (rc != TREXIO_SUCCESS) return rc;
+  if (mo_num == 0L) return TREXIO_INVALID_NUM;
 
-** C
+  /* Compute how many integer numbers is needed to represent a determinant */
+  uint32_t int_num = 0;
+  int_num = (mo_num - 1)/64 + 1;
 
-     #+begin_src c :tangle prefix_front.h :exports none
- trexio_exit_code trexio_info(void);
- trexio_exit_code trexio_mark_safety(trexio_t* const file, const int32_t safety_flag);
-     #+end_src
+  uint32_t rank = 2;
+  uint64_t det_size = (uint64_t) (*buffer_size_read);
+  uint64_t dims[2] = {det_size, int_num*2UL};
 
-     #+begin_src c :tangle prefix_front.c
- trexio_exit_code
- trexio_info (void)
- {
-   printf("TREXIO_PACKAGE_VERSION : %s\n", TREXIO_PACKAGE_VERSION);
-
- #ifdef TREXIO_GIT_HASH
-   printf("TREXIO_GIT_HASH        : %s\n", TREXIO_GIT_HASH);
- #else
-   printf("GIT_HASH is stored in the config.h file, which is missing.");
- #endif
-
- #ifdef HAVE_HDF5
-   printf("HAVE_HDF5              : true\n");
-   printf("%s\n", H5_VERS_INFO);
- #else
-   printf("HAVE_HDF5              : false\n");
-   printf("TREXIO configured without the HDF5 library\n");
- #endif
-
-   return TREXIO_SUCCESS;
- }
-     #+end_src
+  // introduce a new variable which will be modified with the number of integrals being read if EOF is encountered
+  int64_t eof_read_size = 0L;
 
-     #+begin_src c :tangle prefix_front.c
- trexio_exit_code
- trexio_mark_safety (trexio_t* const file, const int32_t safety_flag)
- {
+  switch (file->back_end) {
 
-  if (file == NULL) return TREXIO_INVALID_ARG_1;
-  /* 1 for true ; 0 for false */
-  if (safety_flag != 0 && safety_flag != 1) return TREXIO_INVALID_ARG_2;
-  /* Cannot mark the file in safe mode */
-  if (file->mode != 'u') return TREXIO_FAILURE;
+  case TREXIO_TEXT:
+    rc = trexio_text_read_determinant_list(file, offset_file, rank, dims, &eof_read_size, dset);
+    break;
+
+  case TREXIO_HDF5:
+#ifdef HAVE_HDF5
+    rc = trexio_hdf5_read_determinant_list(file, offset_file, rank, dims, &eof_read_size, dset);
+    break;
+#else
+    rc = TREXIO_BACK_END_MISSING;
+    break;
+#endif
+/*
+  case TREXIO_JSON:
+    return trexio_json_read_$group_dset$(...);
+    break;
+,*/
+  default:
+    rc = TREXIO_FAILURE;  /* Impossible case */
+    break;
+  }
+
+  if (rc != TREXIO_SUCCESS && rc != TREXIO_END) return rc;
+
+  if (rc == TREXIO_END) *buffer_size_read = eof_read_size;
+
+  return rc;
+
+}
+
+
+trexio_exit_code
+trexio_read_determinant_coefficient (trexio_t* const file, const int64_t offset_file, int64_t* const buffer_size_read, double* const dset)
+{
+
+  if (file  == NULL) return TREXIO_INVALID_ARG_1;
+  if (dset  == NULL) return TREXIO_INVALID_ARG_2;
+  if (trexio_has_determinant_coefficient(file) != TREXIO_SUCCESS) return TREXIO_DSET_MISSING;
+
+  trexio_exit_code rc;
+
+  uint32_t rank = 1;
+  uint64_t det_size = (uint64_t) (*buffer_size_read);
+  uint64_t dims[1] = {det_size};
+
+  // introduce a new variable which will be modified with the number of integrals being read if EOF is encountered
+  int64_t eof_read_size = 0L;
+
+  switch (file->back_end) {
+
+  case TREXIO_TEXT:
+    rc = trexio_text_read_determinant_coefficient(file, offset_file, rank, dims, &eof_read_size, dset);
+    break;
+
+  case TREXIO_HDF5:
+#ifdef HAVE_HDF5
+    rc = trexio_hdf5_read_determinant_coefficient(file, offset_file, rank, dims, &eof_read_size, dset);
+    break;
+#else
+    rc = TREXIO_BACK_END_MISSING;
+    break;
+#endif
+/*
+  case TREXIO_JSON:
+    return trexio_json_read_$group_dset$(...);
+    break;
+,*/
+  default:
+    rc = TREXIO_FAILURE;  /* Impossible case */
+    break;
+  }
+
+  if (rc != TREXIO_SUCCESS && rc != TREXIO_END) return rc;
+
+  if (rc == TREXIO_END) *buffer_size_read = eof_read_size;
+
+  return rc;
+
+}
+
+
+trexio_exit_code
+trexio_read_determinant_coefficient_size(trexio_t* const file, int64_t* const size_max)
+{
+  if (file  == NULL) return TREXIO_INVALID_ARG_1;
+  if (size_max == NULL) return TREXIO_INVALID_ARG_2;
+  if (trexio_has_determinant_coefficient(file) != TREXIO_SUCCESS) return TREXIO_DSET_MISSING;
+
+  switch (file->back_end) {
+
+  case TREXIO_TEXT:
+    return trexio_text_read_determinant_coefficient_size(file, size_max);
+    break;
+
+  case TREXIO_HDF5:
+#ifdef HAVE_HDF5
+    return trexio_hdf5_read_determinant_coefficient_size(file, size_max);
+    break;
+#else
+    return TREXIO_BACK_END_MISSING;
+#endif
+/*
+  case TREXIO_JSON:
+    return trexio_json_read_
+    break;
+,*/
+  default:
+    return TREXIO_FAILURE;  /* Impossible case */
+  }
+}
+
+trexio_exit_code
+trexio_read_safe_determinant_list (trexio_t* const file, const int64_t offset_file, int64_t* const buffer_size_read, int64_t* const dset_out, const int64_t dim_out)
+{
+  return trexio_read_determinant_list(file, offset_file, buffer_size_read, dset_out);
+}
+
+trexio_exit_code
+trexio_read_safe_determinant_coefficient (trexio_t* const file, const int64_t offset_file, int64_t* const buffer_size_read, double* const dset_out, const int64_t dim_out)
+{
+  return trexio_read_determinant_coefficient(file, offset_file, buffer_size_read, dset_out);
+}
+     #+end_src
+
+     #+begin_src c :tangle write_determinant_front.c
+trexio_exit_code
+trexio_write_determinant_list (trexio_t* const file, const int64_t offset_file, const int64_t buffer_size, const int64_t* dset)
+{
+
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+  if (dset == NULL) return TREXIO_INVALID_ARG_2;
+
+  trexio_exit_code rc;
+
+  /* Read the number of mos */
+  int64_t mo_num = 0L;
+  rc = trexio_read_mo_num_64(file, &mo_num);
+  if (rc != TREXIO_SUCCESS) return rc;
+  if (mo_num == 0L) return TREXIO_INVALID_NUM;
+
+  /* Compute how many integer numbers is needed to represent a determinant */
+  uint32_t int_num = 0;
+  int_num = (mo_num - 1)/64 + 1;
+
+  uint32_t rank = 2;
+  uint64_t dims[2] = {buffer_size, int_num*2UL};
+
+  assert(file->back_end < TREXIO_INVALID_BACK_END);
+
+  switch (file->back_end) {
+
+  case TREXIO_TEXT:
+    rc = trexio_text_write_determinant_list(file, offset_file, rank, dims, dset);
+    break;
+
+  case TREXIO_HDF5:
+#ifdef HAVE_HDF5
+    rc = trexio_hdf5_write_determinant_list(file, offset_file, rank, dims, dset);
+    break;
+#else
+    return TREXIO_BACK_END_MISSING;
+    break;
+#endif
+/*
+  case TREXIO_JSON:
+    rc = trexio_json_read_
+    break;
+,*/
+  }
+
+  if (rc != TREXIO_SUCCESS) return rc;
+
+  // Update the determinant_num value with the number of determinants written
+  int64_t det_num = 0L;
+  // Read the determinant_num if it exists already
+  if (trexio_has_determinant_num(file) == TREXIO_SUCCESS) {
+     rc = trexio_read_determinant_num_64(file, &det_num);
+     if (rc != TREXIO_SUCCESS) return rc;
+  }
+  // Check for the INT64 overflow before writing an updated value
+  if (INT64_MAX - det_num > buffer_size) {
+    det_num += buffer_size;
+  } else {
+    return TREXIO_INT_SIZE_OVERFLOW;
+  }
+  // Overwrite previous value. Here we have to temporarily set the file->mode to 'u' to trick the API
+  //   in order to overwrite existing determinant_num. Otherwise the API returns TREXIO_NUM_ALREADY_EXISTS.
+  char mode_tmp = file->mode;
+  file->mode = 'u';
+  rc = trexio_write_determinant_num_64(file, det_num);
+  file->mode = mode_tmp;
+  if (rc != TREXIO_SUCCESS) return rc;
+
+  return TREXIO_SUCCESS;
+}
+
+trexio_exit_code
+trexio_write_determinant_coefficient (trexio_t* const file, const int64_t offset_file, const int64_t buffer_size, const double* dset)
+{
+
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+  if (dset == NULL) return TREXIO_INVALID_ARG_2;
+
+  uint32_t rank = 1;
+  uint64_t dims[1] = {buffer_size};
+
+  assert(file->back_end < TREXIO_INVALID_BACK_END);
+
+  switch (file->back_end) {
+
+  case TREXIO_TEXT:
+    return trexio_text_write_determinant_coefficient(file, offset_file, rank, dims, dset);
+    break;
+
+  case TREXIO_HDF5:
+#ifdef HAVE_HDF5
+    return trexio_hdf5_write_determinant_coefficient(file, offset_file, rank, dims, dset);
+    break;
+#else
+    return TREXIO_BACK_END_MISSING;
+    break;
+#endif
+/*
+  case TREXIO_JSON:
+    rc = trexio_json_read_
+    break;
+,*/
+  }
+
+  return TREXIO_FAILURE;
+}
+
+trexio_exit_code
+trexio_write_safe_determinant_list (trexio_t* const file, const int64_t offset_file, const int64_t buffer_size, const int64_t* dset_in, const int64_t dim_in)
+{
+  return trexio_write_determinant_list(file, offset_file, buffer_size, dset_in);
+}
+
+trexio_exit_code
+trexio_write_safe_determinant_coefficient (trexio_t* const file, const int64_t offset_file, const int64_t buffer_size, const double* dset_in, const int64_t dim_in)
+{
+  return trexio_write_determinant_coefficient(file, offset_file, buffer_size, dset_in);
+}
+     #+end_src
+
+     #+begin_src c :tangle has_determinant_front.c
+trexio_exit_code
+trexio_has_determinant_list (trexio_t* const file)
+{
+
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+
+  assert(file->back_end < TREXIO_INVALID_BACK_END);
+
+  switch (file->back_end) {
+
+  case TREXIO_TEXT:
+    return trexio_text_has_determinant_list(file);
+
+  case TREXIO_HDF5:
+#ifdef HAVE_HDF5
+    return trexio_hdf5_has_determinant_list(file);
+#else
+    return TREXIO_BACK_END_MISSING;
+#endif
+/*
+  case TREXIO_JSON:
+    return trexio_json_has_
+    break;
+,*/
+  }
+
+  return TREXIO_FAILURE;
+}
+
+trexio_exit_code
+trexio_has_determinant_coefficient (trexio_t* const file)
+{
+
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+
+  assert(file->back_end < TREXIO_INVALID_BACK_END);
+
+  switch (file->back_end) {
+
+  case TREXIO_TEXT:
+    return trexio_text_has_determinant_coefficient(file);
+
+  case TREXIO_HDF5:
+#ifdef HAVE_HDF5
+    return trexio_hdf5_has_determinant_coefficient(file);
+#else
+    return TREXIO_BACK_END_MISSING;
+#endif
+/*
+  case TREXIO_JSON:
+    return trexio_json_has_
+    break;
+,*/
+  }
+
+  return TREXIO_FAILURE;
+}
+     #+end_src
+
+*** Fortran interface
+
+    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_determinant_front_fortran.f90
+interface
+   integer(trexio_exit_code) function trexio_write_determinant_list (trex_file, &
+                                               offset_file, buffer_size, list) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int64_t), intent(in), value :: trex_file
+     integer(c_int64_t), intent(in), value :: offset_file
+     integer(c_int64_t), intent(in), value :: buffer_size
+     integer(c_int64_t), intent(in)        :: list(*)
+   end function trexio_write_determinant_list
+end interface
+
+interface
+   integer(trexio_exit_code) function trexio_write_safe_determinant_list (trex_file, &
+                                                    offset_file, buffer_size, &
+                                                    list, list_size) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int64_t), intent(in), value :: trex_file
+     integer(c_int64_t), intent(in), value :: offset_file
+     integer(c_int64_t), intent(in), value :: buffer_size
+     integer(c_int64_t), intent(in)        :: list(*)
+     integer(c_int64_t), intent(in), value :: list_size
+   end function trexio_write_safe_determinant_list
+end interface
+
+interface
+   integer(trexio_exit_code) function trexio_write_determinant_coefficient(trex_file, &
+                                               offset_file, buffer_size, coefficient) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int64_t), intent(in), value :: trex_file
+     integer(c_int64_t), intent(in), value :: offset_file
+     integer(c_int64_t), intent(in), value :: buffer_size
+     real(c_double), intent(in)            :: coefficient(*)
+   end function trexio_write_determinant_coefficient
+end interface
+
+interface
+   integer(trexio_exit_code) function trexio_write_safe_determinant_coefficient (trex_file, &
+                                                    offset_file, buffer_size, &
+                                                    coefficient, coefficient_size) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int64_t), intent(in), value :: trex_file
+     integer(c_int64_t), intent(in), value :: offset_file
+     integer(c_int64_t), intent(in), value :: buffer_size
+     real(c_double), intent(in)            :: coefficient(*)
+     integer(c_int64_t), intent(in), value :: coefficient_size
+   end function trexio_write_safe_determinant_coefficient
+end interface
+     #+end_src
+
+     #+begin_src f90 :tangle read_determinant_front_fortran.f90
+interface
+   integer(trexio_exit_code) function trexio_read_determinant_list(trex_file, &
+                                              offset_file, buffer_size, list) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int64_t), intent(in), value :: trex_file
+     integer(c_int64_t), intent(in), value :: offset_file
+     integer(c_int64_t), intent(inout)     :: buffer_size
+     integer(c_int64_t), intent(out)       :: list(*)
+   end function trexio_read_determinant_list
+end interface
+
+interface
+   integer(trexio_exit_code) function trexio_read_safe_determinant_list (trex_file, &
+                                                   offset_file, buffer_size, &
+                                                   list, list_size) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int64_t), intent(in), value :: trex_file
+     integer(c_int64_t), intent(in), value :: offset_file
+     integer(c_int64_t), intent(inout)     :: buffer_size
+     integer(c_int64_t), intent(out)       :: list(*)
+     integer(c_int64_t), intent(in), value :: list_size
+   end function trexio_read_safe_determinant_list
+end interface
+
+interface
+   integer(trexio_exit_code) function trexio_read_safe_determinant_coefficient (trex_file, &
+                                                   offset_file, buffer_size, &
+                                                   coefficient, coefficient_size) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int64_t), intent(in), value :: trex_file
+     integer(c_int64_t), intent(in), value :: offset_file
+     integer(c_int64_t), intent(inout)     :: buffer_size
+     real(c_double), intent(out)           :: coefficient(*)
+     integer(c_int64_t), intent(in), value :: coefficient_size
+   end function trexio_read_safe_determinant_coefficient
+end interface
+
+interface
+   integer(trexio_exit_code) function trexio_read_determinant_coefficient(trex_file, &
+                                              offset_file, buffer_size, coefficient) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int64_t), intent(in), value :: trex_file
+     integer(c_int64_t), intent(in), value :: offset_file
+     integer(c_int64_t), intent(inout)     :: buffer_size
+     real(c_double), intent(out)           :: coefficient(*)
+   end function trexio_read_determinant_coefficient
+end interface
+
+interface
+   integer(trexio_exit_code) function trexio_read_determinant_coefficient_size (trex_file, &
+                                                   size_max) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int64_t), intent(in), value :: trex_file
+     integer(c_int64_t), intent(out) :: size_max
+   end function trexio_read_determinant_coefficient_size
+end interface
+     #+end_src
+
+     #+begin_src f90 :tangle has_determinant_front_fortran.f90
+interface
+   integer(trexio_exit_code) function trexio_has_determinant_list (trex_file) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int64_t), intent(in), value :: trex_file
+   end function trexio_has_determinant_list
+end interface
+
+interface
+   integer(trexio_exit_code) function trexio_has_determinant_coefficient (trex_file) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int64_t), intent(in), value :: trex_file
+   end function trexio_has_determinant_coefficient
+end interface
+     #+end_src
+
+*** Python interface
+
+     #+begin_src python :tangle write_determinant_front.py
+def write_determinant_list(trexio_file: File, offset_file: int, buffer_size: int, determinants: list) -> None:
+    """Write the determinant list in the TREXIO file.
+
+    Parameters:
+
+    trexio_file:
+        TREXIO File object.
+
+    offset_file: int
+        The number of determinants to be skipped in the file when writing.
+
+    buffer_size: int
+        The number of determinants to write in the file.
+
+    determinants: list OR numpy.ndarray
+        Array of determinant_list to be written. If array data type does not correspond to int64, the conversion is performed.
+
+    Raises:
+        - trexio.Error if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message.
+        - Exception from some other error (e.g. RuntimeError).
+    """
+
+    try:
+        import numpy as np
+    except ImportError:
+        raise Exception("NumPy cannot be imported.")
+
+    if not isinstance(offset_file, int):
+        raise TypeError("offset_file argument has to be an integer.")
+    if not isinstance(buffer_size, int):
+        raise TypeError("buffer_size argument has to be an integer.")
+    if not isinstance(determinants, (list, tuple, np.ndarray)):
+        raise TypeError("determinants argument has to be an array (list, tuple or NumPy ndarray).")
+
+    convert = False
+    flatten = False
+    if isinstance(determinants, np.ndarray):
+       # convert to int64 if input determinants are in a different precision
+       if not determinants.dtype==np.int64:
+           convert= True
+
+       if len(determinants.shape) > 1:
+           flatten = True
+           if convert:
+               dets_64 = np.int64(determinants).flatten()
+           else:
+               dets_64 = np.array(determinants, dtype=np.int64).flatten()
+       else:
+           if convert:
+               dets_64 = np.int64(determinants)
+    else:
+       # if input array is a multidimensional list or tuple, we have to convert it
+       try:
+           # if list is flat - the attempt to compute len() will raise a TypeError
+           _ = len(determinants[0])
+           dets_64 = np.array(determinants, dtype=np.int64).flatten()
+           flatten = True
+       except TypeError:
+           pass
+
+    if flatten or convert:
+        rc = pytr.trexio_write_safe_determinant_list(trexio_file.pytrexio_s, offset_file, buffer_size, dets_64)
+    else:
+        rc = pytr.trexio_write_safe_determinant_list(trexio_file.pytrexio_s, offset_file, buffer_size, determinants)
+
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
+
+def write_determinant_coefficient(trexio_file: File, offset_file: int, buffer_size: int, coefficients: list) -> None:
+    """Write the determinant coefficients in the TREXIO file.
+
+    Parameters:
+
+    trexio_file:
+        TREXIO File object.
+
+    offset_file: int
+        The number of coefficients to be skipped in the file when writing.
+
+    buffer_size: int
+        The number of coefficients to write in the file.
+
+    coefficients: list OR numpy.ndarray
+        Array of determinant_coefficient to be written. If array data type does not correspond to int64, the conversion is performed.
+
+    Raises:
+        - trexio.Error if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message.
+        - Exception from some other error (e.g. RuntimeError).
+    """
+
+    try:
+        import numpy as np
+    except ImportError:
+        raise Exception("NumPy cannot be imported.")
+
+    if not isinstance(offset_file, int):
+        raise TypeError("offset_file argument has to be an integer.")
+    if not isinstance(buffer_size, int):
+        raise TypeError("buffer_size argument has to be an integer.")
+    if not isinstance(coefficients, (list, tuple, np.ndarray)):
+        raise TypeError("coefficients argument has to be an array (list, tuple or NumPy ndarray).")
+
+    if isinstance(coefficients, np.ndarray) and not coefficients.dtype==np.float64:
+        # convert to float64 if input is in a different precision
+        coefficients_64 = np.float64(coefficients)
+        rc = pytr.trexio_write_safe_determinant_coefficient(trexio_file.pytrexio_s, offset_file, buffer_size, coefficients_64)
+    else:
+        rc = pytr.trexio_write_safe_determinant_coefficient(trexio_file.pytrexio_s, offset_file, buffer_size, coefficients)
+
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
+     #+end_src
+
+     #+begin_src python :tangle read_determinant_front.py
+def read_determinant_list(trexio_file: File, offset_file: int, buffer_size: int) -> tuple:
+    """Read determinant_list from the TREXIO file.
+
+    Parameters:
+
+    trexio_file:
+        TREXIO File object.
+
+    offset_file: int
+        The number of determinants to be skipped in the file when reading.
+
+    buffer_size: int
+        The number of determinants to read from the file.
+
+    Returns:
+        (determinants, n_int_read, eof_flag) tuple where
+          - determinants are NumPy arrays [numpy.ndarray] with the default int64 precision;
+          - n_int_read [int] is the number of determinants read from the trexio_file
+            (either strictly equal to buffer_size or less than buffer_size if EOF has been reached);
+          - eof_flag [bool] is True when EOF has been reached (i.e. when call to low-level pytrexio API returns TREXIO_END)
+                               False otherwise.
+
+    Raises:
+        - trexio.Error if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message.
+        - Exception from some other error (e.g. RuntimeError).
+    """
+
+    try:
+        import numpy as np
+    except ImportError:
+        raise Exception("NumPy cannot be imported.")
+
+    if not isinstance(offset_file, int):
+        raise TypeError("offset_file argument has to be an integer.")
+    if not isinstance(buffer_size, int):
+        raise TypeError("buffer_size argument has to be an integer.")
+
+
+    # read the number of determinants already in the file
+    det_num = read_determinant_num(trexio_file)
+    # calculate the int_num (number of int bit fields per determinant)
+    mo_num = read_mo_num(trexio_file)
+    int_num = 2*int((mo_num-1)/64+1)
+
+    # additional modification needed to avoid allocating more memory than needed if EOF will be reached during read
+    overflow = offset_file + buffer_size - det_num
+    eof_flag = False
+    if overflow > 0:
+        verified_size = buffer_size - overflow
+        eof_flag = True
+    else:
+        verified_size = buffer_size
+
+    # main call to the low-level (SWIG-wrapped) trexio_read function, which also requires the sizes of the output to be provided
+    # read_buf_size contains the number of elements being read from the file, useful when EOF has been reached
+    rc, n_int_read, determinants = pytr.trexio_read_safe_determinant_list(trexio_file.pytrexio_s,
+                                                                          offset_file,
+                                                                          verified_size,
+                                                                          verified_size * int_num)
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
+    if n_int_read == 0:
+        raise ValueError("No integrals have been read from the file.")
+    if determinants is None:
+        raise ValueError("Returned NULL array from the low-level pytrexio API.")
+
+    # conversion to custom types can be performed on the user side, here we only reshape the returned flat array according to int_num
+    dets_reshaped = np.reshape(determinants, (verified_size, int_num), order='C')
+
+    return (dets_reshaped, n_int_read, eof_flag)
+
+def read_determinant_coefficient(trexio_file: File, offset_file: int, buffer_size: int) -> tuple:
+    """Read determinant_coefficient from the TREXIO file.
+
+    Parameters:
+
+    trexio_file:
+        TREXIO File object.
+
+    offset_file: int
+        The number of coefficient to be skipped in the file when reading.
+
+    buffer_size: int
+        The number of coefficients to read from the file.
+
+    Returns:
+        (coefficients, n_int_read, eof_flag) tuple where
+          - coefficients are NumPy arrays [numpy.ndarray] with the default int64 precision;
+          - n_int_read [int] is the number of coefficients read from the trexio_file
+            (either strictly equal to buffer_size or less than buffer_size if EOF has been reached);
+          - eof_flag [bool] is True when EOF has been reached (i.e. when call to low-level pytrexio API returns TREXIO_END)
+                               False otherwise.
+
+    Raises:
+        - trexio.Error if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message.
+        - Exception from some other error (e.g. RuntimeError).
+    """
+
+    try:
+        import numpy as np
+    except ImportError:
+        raise Exception("NumPy cannot be imported.")
+
+    if not isinstance(offset_file, int):
+        raise TypeError("offset_file argument has to be an integer.")
+    if not isinstance(buffer_size, int):
+        raise TypeError("buffer_size argument has to be an integer.")
+
+
+    # read the number of determinants already in the file
+    det_num = read_determinant_coefficient_size(trexio_file)
+
+    # additional modification needed to avoid allocating more memory than needed if EOF will be reached during read
+    overflow = offset_file + buffer_size - det_num
+    eof_flag = False
+    if overflow > 0:
+        verified_size = buffer_size - overflow
+        eof_flag = True
+    else:
+        verified_size = buffer_size
+
+    # main call to the low-level (SWIG-wrapped) trexio_read function, which also requires the sizes of the output to be provided
+    # read_buf_size contains the number of elements being read from the file, useful when EOF has been reached
+    rc, n_int_read, coefficients = pytr.trexio_read_safe_determinant_coefficient(trexio_file.pytrexio_s,
+                                                                                 offset_file,
+                                                                                 verified_size,
+                                                                                 verified_size)
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
+    if n_int_read == 0:
+        raise ValueError("No integrals have been read from the file.")
+    if coefficients is None:
+        raise ValueError("Returned NULL array from the low-level pytrexio API.")
+
+    return (coefficients, n_int_read, eof_flag)
+
+
+def read_determinant_coefficient_size(trexio_file) -> int:
+    """Read the number of determinant coefficients stored in the TREXIO file.
+
+    Parameter is a ~TREXIO File~ object that has been created by a call to ~open~ function.
+
+    Returns:
+        ~num~: int
+        Integer value of corresponding to the size of the determinant_coefficient array from ~trexio_file~.
+
+    Raises:
+        - Exception from AssertionError if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message using trexio_string_of_error.
+        - Exception from some other error (e.g. RuntimeError).
+    """
+
+    rc, num = pytr.trexio_read_determinant_coefficient_size(trexio_file.pytrexio_s)
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
+
+    return num
+     #+end_src
+
+     #+end_src
+
+     #+begin_src python :tangle has_determinant_front.py
+def has_determinant_list(trexio_file) -> bool:
+    """Check that determinant_list exists in the TREXIO file.
+
+    Parameter is a ~TREXIO File~ object that has been created by a call to ~open~ function.
+
+    Returns:
+          True if the variable exists, False otherwise
+
+    Raises:
+        - trexio.Error if TREXIO return code ~rc~ is TREXIO_FAILURE and prints the error message using string_of_error.
+        - Exception from some other error (e.g. RuntimeError).
+    """
+
+    rc = pytr.trexio_has_determinant_list(trexio_file.pytrexio_s)
+    if rc == TREXIO_FAILURE:
+        raise Error(rc)
+
+    return rc == TREXIO_SUCCESS
+
+def has_determinant_coefficient(trexio_file) -> bool:
+    """Check that determinant_coefficient exists in the TREXIO file.
+
+    Parameter is a ~TREXIO File~ object that has been created by a call to ~open~ function.
+
+    Returns:
+          True if the variable exists, False otherwise
+
+    Raises:
+        - trexio.Error if TREXIO return code ~rc~ is TREXIO_FAILURE and prints the error message using string_of_error.
+        - Exception from some other error (e.g. RuntimeError).
+    """
+
+    rc = pytr.trexio_has_determinant_coefficient(trexio_file.pytrexio_s)
+    if rc == TREXIO_FAILURE:
+        raise Error(rc)
+
+    return rc == TREXIO_SUCCESS
+     #+end_src
+
+* General helper functions
+
+  This section contains general helper functions like ~trexio_info~.
+
+  ~trexio_info~ prints information about the TREXIO configuration (see =config.h= file).
+  In particular:
+
+  1) ~TREXIO_PACKAGE_VERSION~ [string]
+  2) ~HAVE_HDF5~ [bool]
+  3) ~HDF5_VERSION~ [string] (optional, only if ~HAVE_HDF5~ is ~true~)
+  4) ~TREXIO_GIT_HASH~ [string]
+
+  ~trexio_mark_safety~ checks if the file has been open in UNSAFE mode.
+  If it was, the ~metadata_unsafe~ attribute can be overwritten with the value provided in a second argument of the function.
+  Since ~metadata_unsafe~ is set to ~1~ (~true~) upon the first opening of the file in UNSAFE mode, this value is immutable.
+  However, if the user validated that the file is correct (e.g. using ~trexio-tools~),
+  then value of the ~metadata_unsafe~ attribute can be changed using the aforementioned function.
 
-  return trexio_write_metadata_unsafe(file, safety_flag);
- }
+  ~trexio_to_orbital_list~ function converts the list of integer bit fields of a
+  given determinant into a list of indices of the occupied orbitals (for one spin component).
+  ~trexio_to_orbital_list_up_dn~ function does the same but for both up- and down-spin components
+  of the determinant and returns two list of orbitals each corresponding to a different component.
+
+** C
+
+     #+begin_src c :tangle prefix_front.h
+trexio_exit_code trexio_info(void);
+trexio_exit_code trexio_mark_safety(trexio_t* const file, const int32_t safety_flag);
+     #+end_src
+
+     #+begin_src c :tangle prefix_front.h
+typedef int64_t  bitfield_t;
+
+#define ORBITAL_SHIFT  1
+#define INT_SIZE       64
+#define NORB_PER_INT   ( 8*sizeof(bitfield_t) )
+
+/* Popcount and trailz */
+#if INT_SIZE == 64
+
+  extern int __builtin_popcountll (unsigned long long x_0);
+  #define popcnt(X) __builtin_popcountll((unsigned long long) X)
+
+  extern int __builtin_ctzll (unsigned long long x_0);
+  #define trailz(X) __builtin_ctzll((unsigned long long) X)
+
+#elif INT_SIZE == 32
+
+  extern int __builtin_popcountl (unsigned long x_0);
+  #define popcnt(X) __builtin_popcountl((unsigned long) X)
+
+  extern int __builtin_ctzl(unsigned long x_0);
+  #define trailz(X) __builtin_ctzl((unsigned long) X)
+
+#elif INT_SIZE == 16
+
+  extern int __builtin_popcount (unsigned int x_0);
+  #define popcnt(X) __builtin_popcount((unsigned int) X)
+
+  extern int __builtin_ctz (unsigned int x_0);
+  #define trailz(X) __builtin_ctz((unsigned int) X)
+
+#else
+
+ #error("Invalid INT_SIZE")
+
+#endif
+
+trexio_exit_code trexio_to_orbital_list (const int32_t N_int, const bitfield_t* d1, int32_t* const list, int32_t* const occupied_num);
+trexio_exit_code trexio_to_orbital_list_up_dn (const int32_t N_int, const bitfield_t* d1, int32_t* const list_up, int32_t* const list_dn, int32_t* const occ_num_up, int32_t* const occ_num_dn);
+trexio_exit_code trexio_safe_to_orbital_list (const int32_t N_int, const bitfield_t* dset_in, const int64_t dim_in, int32_t* const dset_out, const int64_t dim_out, int32_t* const num);
+trexio_exit_code trexio_safe_to_orbital_list_up_dn (const int32_t N_int, const bitfield_t* dset_in, const int64_t dim_in, int32_t* const dset_up_out, const int64_t dim_up_out, int32_t* const dset_dn_out, const int64_t dim_dn_out, int32_t* const num_up, int32_t* const num_dn);
      #+end_src
 
+     #+begin_src c :tangle prefix_front.c
+trexio_exit_code trexio_to_orbital_list(const int32_t N_int,
+                                        const bitfield_t* d1,
+                                        int32_t* const list,
+                                        int32_t* const occupied_num)
+{
+  if (N_int <= 0) return TREXIO_INVALID_ARG_1;
+  if (d1 == NULL) return TREXIO_INVALID_ARG_2;
+  if (list == NULL) return TREXIO_INVALID_ARG_3;
+  if (occupied_num == NULL) return TREXIO_INVALID_ARG_4;
+
+  bitfield_t  tmp;
+  int32_t     shift;
+  int32_t     k;
+  int32_t     pos;
+
+  k = 0;
+  shift = ORBITAL_SHIFT;
+
+  for (int32_t i=0 ; i<N_int ; i++)
+  {
+      tmp = d1[i];
+
+      while (tmp != (bitfield_t) 0)
+      {
+          pos = trailz(tmp);
+          if (pos < 0) return TREXIO_FAILURE;
+
+          list[k] = ( (int32_t) pos) + shift;
+          tmp ^= ( ((bitfield_t) 1) << pos);
+          k++;
+      }
+      shift += NORB_PER_INT;
+  }
+
+  ,*occupied_num = (int32_t) k;
+  return TREXIO_SUCCESS;
+}
+    #+end_src
+
+    #+begin_src c :tangle prefix_front.c
+trexio_exit_code trexio_to_orbital_list_up_dn(const int32_t N_int,
+                                              const bitfield_t* d1,
+                                              int32_t* const list_up,
+                                              int32_t* const list_dn,
+                                              int32_t* const occ_num_up,
+                                              int32_t* const occ_num_dn)
+{
+  if (N_int <= 0) return TREXIO_INVALID_ARG_1;
+  if (d1 == NULL) return TREXIO_INVALID_ARG_2;
+  if (list_up == NULL) return TREXIO_INVALID_ARG_3;
+  if (list_dn == NULL) return TREXIO_INVALID_ARG_4;
+  if (occ_num_up == NULL) return TREXIO_INVALID_ARG_5;
+  if (occ_num_dn == NULL) return TREXIO_INVALID_ARG_6;
+
+  trexio_exit_code rc;
+
+  /* First process up-spin electrons */
+  rc = trexio_to_orbital_list(N_int, &d1[0], list_up, occ_num_up);
+  if (rc != TREXIO_SUCCESS) return rc;
+
+  /* Now process down-spin electrons */
+  rc = trexio_to_orbital_list(N_int, &d1[N_int], list_dn, occ_num_dn);
+  if (rc != TREXIO_SUCCESS) return rc;
+
+  return TREXIO_SUCCESS;
+}
+    #+end_src
+
+    #+begin_src c :tangle prefix_front.c
+trexio_exit_code
+trexio_safe_to_orbital_list (const int32_t N_int,
+			     const bitfield_t* dset_in,
+                             const int64_t dim_in,
+			     int32_t* const dset_out,
+                             const int64_t dim_out,
+			     int32_t* const num)
+{
+  return trexio_to_orbital_list(N_int, dset_in, dset_out, num);
+}
+
+trexio_exit_code
+trexio_safe_to_orbital_list_up_dn (const int32_t N_int,
+			           const bitfield_t* dset_in,
+                                   const int64_t dim_in,
+			           int32_t* const dset_up_out,
+                                   const int64_t dim_up_out,
+			           int32_t* const dset_dn_out,
+                                   const int64_t dim_dn_out,
+			           int32_t* const num_up,
+			           int32_t* const num_dn)
+{
+  return trexio_to_orbital_list_up_dn(N_int, dset_in, dset_up_out, dset_dn_out, num_up, num_dn);
+}
+    #+end_src
+
+    #+begin_src c :tangle prefix_front.c
+trexio_exit_code
+trexio_info (void)
+{
+  printf("TREXIO_PACKAGE_VERSION : %s\n", TREXIO_PACKAGE_VERSION);
+
+#ifdef TREXIO_GIT_HASH
+  printf("TREXIO_GIT_HASH        : %s\n", TREXIO_GIT_HASH);
+#else
+  printf("GIT_HASH is stored in the config.h file, which is missing.");
+#endif
+
+#ifdef HAVE_HDF5
+  printf("HAVE_HDF5              : true\n");
+  printf("%s\n", H5_VERS_INFO);
+#else
+  printf("HAVE_HDF5              : false\n");
+  printf("TREXIO configured without the HDF5 library\n");
+#endif
+
+  return TREXIO_SUCCESS;
+}
+    #+end_src
+
+    #+begin_src c :tangle prefix_front.c
+trexio_exit_code
+trexio_mark_safety (trexio_t* const file, const int32_t safety_flag)
+{
+
+ if (file == NULL) return TREXIO_INVALID_ARG_1;
+ /* 1 for true ; 0 for false */
+ if (safety_flag != 0 && safety_flag != 1) return TREXIO_INVALID_ARG_2;
+ /* Cannot mark the file in safe mode */
+ if (file->mode != 'u') return TREXIO_FAILURE;
+
+ return trexio_write_metadata_unsafe(file, safety_flag);
+}
+    #+end_src
+
 ** Fortran
 
    #+begin_src f90 :tangle prefix_fortran.f90
@@ -4270,18 +5374,104 @@ interface
 end interface
    #+end_src
 
+
+   #+begin_src f90 :tangle prefix_fortran.f90
+interface
+   integer(trexio_exit_code) function trexio_to_orbital_list(N_int, d1, list, occupied_num) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int32_t), intent(in), value :: N_int
+     integer(c_int64_t), intent(in)        :: d1(*)
+     integer(c_int32_t), intent(out)       :: list(*)
+     integer(c_int32_t), intent(inout)     :: occupied_num
+   end function trexio_to_orbital_list
+end interface
+
+interface
+   integer(trexio_exit_code) function trexio_to_orbital_list_up_dn(N_int, d1, list_up, list_dn, occ_num_up, occ_num_dn) bind(C)
+     use, intrinsic :: iso_c_binding
+     import
+     integer(c_int32_t), intent(in), value :: N_int
+     integer(c_int64_t), intent(in)        :: d1(*)
+     integer(c_int32_t), intent(out)       :: list_up(*)
+     integer(c_int32_t), intent(out)       :: list_dn(*)
+     integer(c_int32_t), intent(inout)     :: occ_num_up
+     integer(c_int32_t), intent(inout)     :: occ_num_dn
+   end function trexio_to_orbital_list_up_dn
+end interface
+   #+end_src
+
 ** Python
 
    #+begin_src python :tangle basic_python.py
 def info():
-    """Print the info about the installed TREXIO library.
-    """
+    """Print the info about the installed TREXIO library."""
 
     rc = pytr.trexio_info()
     if rc != TREXIO_SUCCESS:
         raise Error(rc)
    #+end_src
 
+
+   #+begin_src python :tangle basic_python.py
+def to_orbital_list(n_int: int, determinant: list) -> list:
+    """Convert a given determinant into a list of occupied orbitals.
+
+    Input:
+        ~determinant~ - list of bit fields (integers)
+        ~n_int~ - number of bit fields per determinant of a given spin
+
+    Returns:
+        ~orbital_list~: list
+
+    Raises:
+        - Exception from AssertionError if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message using trexio_string_of_error.
+        - Exception from some other error (e.g. RuntimeError).
+    """
+
+    # max possible size of the orbital list per spin component (upper limit on the number of MOs)
+    size_max = n_int * 64
+
+    rc, orbital_list, occ_num = pytr.trexio_safe_to_orbital_list(n_int, determinant, size_max)
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
+    if len(orbital_list) < occ_num:
+        raise Exception("Inconsistent size of the orbital_list.")
+
+    return orbital_list
+
+
+def to_orbital_list_up_dn(n_int: int, determinant: list) -> tuple:
+    """Convert a given determinant into two lists of occupied orbitals.
+
+    Input:
+        ~determinant~ - list of bit fields (integers)
+        ~n_int~ - number of bit fields per determinant of a given spin
+
+    Returns:
+        result: tuple with the following items:
+          ~orbital_list_up~: list of orbitals occupied by up-spin electrons
+          ~orbital_list_dn~: list of orbitals occupied by down-spin electrons
+
+    Raises:
+        - Exception from AssertionError if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message using trexio_string_of_error.
+        - Exception from some other error (e.g. RuntimeError).
+    """
+
+    # max possible size of the orbital list per spin component (upper limit on the number of MOs)
+    size_max = n_int * 64
+
+    rc, orbital_list_up, orbital_list_dn, occ_num_up, occ_num_dn = pytr.trexio_safe_to_orbital_list_up_dn(n_int, determinant, size_max, size_max)
+    if rc != TREXIO_SUCCESS:
+        raise Error(rc)
+    if len(orbital_list_up) < occ_num_up:
+        raise Exception("Inconsistent size of the orbital_list for up-spin electrons.")
+    if len(orbital_list_dn) < occ_num_dn:
+        raise Exception("Inconsistent size of the orbital_list for down-spin electrons.")
+
+    return (orbital_list_up[0:occ_num_up], orbital_list_dn[0:occ_num_dn])
+   #+end_src
+
 * Fortran helper/wrapper functions
 
   The function below adapts the original C-based ~trexio_open~ for Fortran.
diff --git a/src/templates_hdf5/build.sh b/src/templates_hdf5/build.sh
index cff18b46..88a70a50 100644
--- a/src/templates_hdf5/build.sh
+++ b/src/templates_hdf5/build.sh
@@ -14,5 +14,8 @@ cat populated/pop_delete_group_hdf5.c >> trexio_hdf5.c
 cat populated/pop_hrw_*.h >> trexio_hdf5.h
 cat populated/pop_delete_group_hdf5.h >> trexio_hdf5.h
 
+cat hrw_determinant_hdf5.h >> trexio_hdf5.h
+cat *_determinant_hdf5.c >> trexio_hdf5.c
+
 cat helpers_hdf5.c  >> trexio_hdf5.c
 cat suffix_hdf5.h   >> trexio_hdf5.h
diff --git a/src/templates_hdf5/templator_hdf5.org b/src/templates_hdf5/templator_hdf5.org
index d1027aca..f6c788ae 100644
--- a/src/templates_hdf5/templator_hdf5.org
+++ b/src/templates_hdf5/templator_hdf5.org
@@ -265,6 +265,7 @@ 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;
+  if (f->$group$_group == (hsize_t) 0) return TREXIO_HAS_NOT;
 
   htri_t status = H5Aexists(f->$group$_group, $GROUP_NUM$_NAME);
   /* H5Aexists returns positive value if attribute exists, 0 if does not, negative if error */
@@ -399,6 +400,7 @@ 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;
+  if (f->$group$_group == (hsize_t) 0) return TREXIO_HAS_NOT;
 
   herr_t status = H5LTfind_dataset(f->$group$_group, $GROUP_DSET$_NAME);
   /* H5LTfind_dataset returns 1 if dataset exists, 0 otherwise */
@@ -441,7 +443,7 @@ trexio_hdf5_write_$group_dset$ (trexio_t* const file,
   trexio_hdf5_t* f = (trexio_hdf5_t*) file;
 
   hid_t index_dtype;
-  const void* index_p;
+  void* index_p = NULL;
   uint64_t size_ranked = (uint64_t) size * $group_dset_rank$;
   /* Determine the optimal type for storing indices depending on the size_max (usually mo_num or ao_num) */
   if (size_max < UINT8_MAX) {
@@ -461,7 +463,7 @@ trexio_hdf5_write_$group_dset$ (trexio_t* const file,
     index_p = index;
     index_dtype = H5T_NATIVE_UINT16;
   } else {
-    index_p = (const int32_t*) index_sparse;
+    index_p = (int32_t*) index_sparse;
     index_dtype = H5T_NATIVE_INT32;
   }
 
@@ -546,11 +548,11 @@ trexio_hdf5_read_$group_dset$ (trexio_t* const file,
   trexio_exit_code rc_read;
 
   // attempt to read indices
-  rc_read = trexio_hdf5_open_read_dset_sparse(f->$group$_group, dset_index_name, offset_i, count_i, NULL, is_index, index_read);
+  rc_read = trexio_hdf5_open_read_dset_sparse(f->$group$_group, dset_index_name, $group_dset_rank$, offset_i, count_i, NULL, is_index, index_read);
   if (rc_read != TREXIO_SUCCESS && rc_read != TREXIO_END) return rc_read;
   // attempt to read values
   // when EOF is encountered - the count_v[0] is modified and contains the number of elements being read
-  rc_read = trexio_hdf5_open_read_dset_sparse(f->$group$_group, dset_value_name, offset_v, count_v, eof_read_size, is_value, value_read);
+  rc_read = trexio_hdf5_open_read_dset_sparse(f->$group$_group, dset_value_name, 1, offset_v, count_v, eof_read_size, is_value, value_read);
   if (rc_read != TREXIO_SUCCESS && rc_read != TREXIO_END) return rc_read;
 
   return rc_read;
@@ -564,6 +566,7 @@ trexio_hdf5_read_$group_dset$_size (trexio_t* const file, int64_t* const size_ma
 {
 
   if (file == NULL) return TREXIO_INVALID_ARG_1;
+  if (size_max == NULL) return TREXIO_INVALID_ARG_2;
 
   const trexio_hdf5_t* f = (const trexio_hdf5_t*) file;
 
@@ -600,6 +603,7 @@ 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;
+  if (f->$group$_group == (hsize_t) 0) return TREXIO_HAS_NOT;
 
   herr_t status = H5LTfind_dataset(f->$group$_group, $GROUP_DSET$_NAME "_values");
   /* H5LTfind_dataset returns 1 if dataset exists, 0 otherwise */
@@ -798,6 +802,7 @@ 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;
+  if (f->$group$_group == (hsize_t) 0) return TREXIO_HAS_NOT;
 
   herr_t status = H5LTfind_dataset(f->$group$_group, $GROUP_DSET$_NAME);
   /* H5LTfind_dataset returns 1 if dataset exists, 0 otherwise */
@@ -927,6 +932,7 @@ trexio_hdf5_has_$group_str$ (trexio_t* const file)
   if (file == NULL) return TREXIO_INVALID_ARG_1;
 
   const trexio_hdf5_t* f = (const trexio_hdf5_t*) file;
+  if (f->$group$_group == (hsize_t) 0) return TREXIO_HAS_NOT;
 
   htri_t status = H5Aexists(f->$group$_group, $GROUP_STR$_NAME);
   /* H5Aexists returns positive value if attribute exists, 0 if does not, negative if error */
@@ -977,6 +983,262 @@ trexio_hdf5_delete_$group$ (trexio_t* const file)
 }
    #+end_src
 
+* Source code for the determinant part
+
+   Each array is stored in a separate HDF5 dataset due to the fact that determinant I/O has to be decoupled.
+   Chunks are used to read/write the data to prevent memory overflow. Chunks have a given ~int64_t dims[0]*dims[1]~.
+   Size specifies the number of data items (e.g. determinants) to process.
+
+   #+begin_src c :tangle hrw_determinant_hdf5.h :exports none
+trexio_exit_code trexio_hdf5_has_determinant_list(trexio_t* const file);
+trexio_exit_code trexio_hdf5_read_determinant_list(trexio_t* const file, const int64_t offset_file, const uint32_t rank, const uint64_t* dims, int64_t* const eof_read_size, int64_t* const list);
+trexio_exit_code trexio_hdf5_write_determinant_list(trexio_t* const file, const int64_t offset_file, const uint32_t rank, const uint64_t* dims, const int64_t* list);
+trexio_exit_code trexio_hdf5_has_determinant_coefficient(trexio_t* const file);
+trexio_exit_code trexio_hdf5_read_determinant_coefficient(trexio_t* const file, const int64_t offset_file, const uint32_t rank, const uint64_t* dims, int64_t* const eof_read_size, double* const coeff);
+trexio_exit_code trexio_hdf5_write_determinant_coefficient(trexio_t* const file, const int64_t offset_file, const uint32_t rank, const uint64_t* dims, const double* coeff);
+trexio_exit_code trexio_hdf5_read_determinant_coefficient_size(trexio_t* const file, int64_t* const size_max);
+   #+end_src
+
+   #+begin_src c :tangle read_determinant_hdf5.c
+trexio_exit_code trexio_hdf5_read_determinant_list(trexio_t* const file,
+                                                   const int64_t offset_file,
+                                                   const uint32_t rank,
+                                                   const uint64_t* dims,
+                                                   int64_t* const eof_read_size,
+                                                   int64_t* const list)
+{
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+  if (eof_read_size == NULL) return TREXIO_INVALID_ARG_5;
+  if (list == NULL) return TREXIO_INVALID_ARG_6;
+
+  const trexio_hdf5_t* f = (const trexio_hdf5_t*) file;
+
+  char dset_det_name[256] = "determinant_list";
+
+  hsize_t offset[1] = {(hsize_t) offset_file * dims[1]};
+  hsize_t count[1]  = {(hsize_t) dims[0] * dims[1]};
+
+  /* Attempt to read determinants (if EOF -> eof_read_size is modified with the number of elements read and return code is TREXIO_END)
+     0 argument below is requires to skip internal treatment specific to sparse indices (i.e. their de-compression).*/
+  return trexio_hdf5_open_read_dset_sparse(f->determinant_group, dset_det_name, (uint32_t) dims[1], offset, count, eof_read_size, 0, list);
+}
+
+trexio_exit_code trexio_hdf5_read_determinant_coefficient(trexio_t* const file,
+                                                   const int64_t offset_file,
+                                                   const uint32_t rank,
+                                                   const uint64_t* dims,
+                                                   int64_t* const eof_read_size,
+                                                   double* const coeff)
+{
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+  if (eof_read_size == NULL) return TREXIO_INVALID_ARG_5;
+  if (coeff == NULL) return TREXIO_INVALID_ARG_6;
+
+  char dset_coeff_name[128];
+  memset(dset_coeff_name, 0, sizeof(dset_coeff_name));
+  const int32_t trexio_state = file->state;
+
+  if (trexio_state != 0) {
+    sprintf(dset_coeff_name, "determinant_coefficient_state_%" PRId32, trexio_state);
+  } else {
+    strncpy(dset_coeff_name, "determinant_coefficient", 24);
+  }
+
+  const trexio_hdf5_t* f = (const trexio_hdf5_t*) file;
+
+  hsize_t offset[1] = {(hsize_t) offset_file};
+  hsize_t count[1]  = {(hsize_t) dims[0]};
+
+  /* Attempt to read determinants (if EOF -> eof_read_size is modified with the number of elements read and return code is TREXIO_END)
+     0 argument below is requires to skip internal treatment specific to sparse indices (i.e. their de-compression).*/
+  return trexio_hdf5_open_read_dset_sparse(f->determinant_group, dset_coeff_name, 1, offset, count, eof_read_size, 0, coeff);
+}
+   #+end_src
+
+   #+begin_src c :tangle write_determinant_hdf5.c
+trexio_exit_code trexio_hdf5_write_determinant_list(trexio_t* const file,
+                                                    const int64_t offset_file,
+		                                    const uint32_t rank,
+                                                    const uint64_t* dims,
+                                                    const int64_t* list)
+{
+
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+  if (list == NULL) return TREXIO_INVALID_ARG_5;
+
+  trexio_hdf5_t* f = (trexio_hdf5_t*) file;
+
+  hid_t det_dtype = H5T_NATIVE_INT64;
+  uint64_t size_ranked = dims[1]*dims[0];
+
+  /* Arrays of chunk dims that will be used for chunking the dataset */
+  const hsize_t chunk_dims[1] = {size_ranked};
+
+  /* Indices and values are stored as 2 independent datasets in the HDF5 file */
+  char dset_det_name[256] = "determinant_list";
+
+  trexio_exit_code rc_write = TREXIO_FAILURE;
+  /* NOTE: chunk size is set upon creation of the HDF5 dataset and cannot be changed ! */
+  if ( H5LTfind_dataset(f->determinant_group, dset_det_name) != 1 ) {
+  /* If the file does not exist -> create it and write */
+
+  /* Create chunked dataset with det_dtype datatype and write indices into it */
+    rc_write = trexio_hdf5_create_write_dset_sparse(f->determinant_group, dset_det_name, det_dtype, chunk_dims, list);
+    if (rc_write != TREXIO_SUCCESS) return rc_write;
+
+  } else {
+  /* If the file exists -> open it and write */
+    hsize_t offset_data[1] = {(hsize_t) offset_file * dims[1]};
+
+  /* Create chunked dataset with det_dtype datatype and write indices into it */
+    rc_write = trexio_hdf5_open_write_dset_sparse(f->determinant_group, dset_det_name, det_dtype, chunk_dims, offset_data, list);
+    if (rc_write != TREXIO_SUCCESS) return rc_write;
+
+  }
+
+  return TREXIO_SUCCESS;
+}
+
+trexio_exit_code trexio_hdf5_write_determinant_coefficient(trexio_t* const file,
+                                                    const int64_t offset_file,
+		                                    const uint32_t rank,
+                                                    const uint64_t* dims,
+                                                    const double* coeff)
+{
+
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+  if (coeff == NULL) return TREXIO_INVALID_ARG_5;
+
+  char dset_coeff_name[128];
+  memset(dset_coeff_name, 0, sizeof(dset_coeff_name));
+  const int32_t trexio_state = file->state;
+
+  if (trexio_state != 0) {
+    sprintf(dset_coeff_name, "determinant_coefficient_state_%" PRId32, trexio_state);
+  } else {
+    strncpy(dset_coeff_name, "determinant_coefficient", 24);
+  }
+
+  trexio_hdf5_t* f = (trexio_hdf5_t*) file;
+
+  hid_t det_dtype = H5T_NATIVE_DOUBLE;
+
+  /* Arrays of chunk dims that will be used for chunking the dataset */
+  const hsize_t chunk_dims[1] = {(hsize_t) dims[0]};
+
+  trexio_exit_code rc_write = TREXIO_FAILURE;
+  /* NOTE: chunk size is set upon creation of the HDF5 dataset and cannot be changed ! */
+  if ( H5LTfind_dataset(f->determinant_group, dset_coeff_name) != 1 ) {
+  /* If the file does not exist -> create it and write */
+
+  /* Create chunked dataset with det_dtype datatype and write indices into it */
+    rc_write = trexio_hdf5_create_write_dset_sparse(f->determinant_group, dset_coeff_name, det_dtype, chunk_dims, coeff);
+    if (rc_write != TREXIO_SUCCESS) return rc_write;
+
+  } else {
+  /* If the file exists -> open it and write */
+    hsize_t offset_data[1] = {(hsize_t) offset_file};
+
+  /* Create chunked dataset with det_dtype datatype and write indices into it */
+    rc_write = trexio_hdf5_open_write_dset_sparse(f->determinant_group, dset_coeff_name, det_dtype, chunk_dims, offset_data, coeff);
+    if (rc_write != TREXIO_SUCCESS) return rc_write;
+
+  }
+
+  return TREXIO_SUCCESS;
+}
+
+trexio_exit_code
+trexio_hdf5_read_determinant_coefficient_size (trexio_t* const file, int64_t* const size_max)
+{
+
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+  if (size_max == NULL) return TREXIO_INVALID_ARG_2;
+
+  char dset_coeff_name[128];
+  memset(dset_coeff_name, 0, sizeof(dset_coeff_name));
+  const int32_t trexio_state = file->state;
+
+  if (trexio_state != 0) {
+    sprintf(dset_coeff_name, "determinant_coefficient_state_%" PRId32, trexio_state);
+  } else {
+    strncpy(dset_coeff_name, "determinant_coefficient", 24);
+  }
+
+  const trexio_hdf5_t* f = (const trexio_hdf5_t*) file;
+
+  hid_t dset_id = H5Dopen(f->determinant_group, dset_coeff_name, H5P_DEFAULT);
+  if (dset_id <= 0) return TREXIO_INVALID_ID;
+
+  hid_t fspace_id = H5Dget_space(dset_id);
+  if (fspace_id < 0) {
+    H5Dclose(dset_id);
+    return TREXIO_INVALID_ID;
+  }
+
+  // allocate space for the dimensions to be read
+  hsize_t ddims[1] = {0};
+
+  // get the rank and dimensions of the dataset
+  H5Sget_simple_extent_dims(fspace_id, ddims, NULL);
+
+  H5Dclose(dset_id);
+  H5Sclose(fspace_id);
+
+  *size_max = (int64_t) ddims[0];
+
+  return TREXIO_SUCCESS;
+}
+   #+end_src
+
+   #+begin_src c :tangle has_determinant_hdf5.c
+trexio_exit_code trexio_hdf5_has_determinant_list(trexio_t* const file)
+{
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+
+  trexio_hdf5_t* f = (trexio_hdf5_t*) file;
+  if (f->determinant_group == (hsize_t) 0) return TREXIO_HAS_NOT;
+
+  herr_t status = H5LTfind_dataset(f->determinant_group, "determinant_list");
+  /* 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;
+  }
+}
+
+trexio_exit_code trexio_hdf5_has_determinant_coefficient(trexio_t* const file)
+{
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+
+  trexio_hdf5_t* f = (trexio_hdf5_t*) file;
+  if (f->determinant_group == (hsize_t) 0) return TREXIO_HAS_NOT;
+
+  char dset_coeff_name[128];
+  memset(dset_coeff_name, 0, sizeof(dset_coeff_name));
+  const int32_t trexio_state = file->state;
+
+  if (trexio_state != 0) {
+    sprintf(dset_coeff_name, "determinant_coefficient_state_%" PRId32, trexio_state);
+  } else {
+    strncpy(dset_coeff_name, "determinant_coefficient", 24);
+  }
+
+  herr_t status = H5LTfind_dataset(f->determinant_group, dset_coeff_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
+
 * Helper functions
 
   #+begin_src c :tangle helpers_hdf5.c
@@ -1113,6 +1375,7 @@ trexio_hdf5_open_write_dset_sparse (const hid_t group_id,
 trexio_exit_code
 trexio_hdf5_open_read_dset_sparse (const hid_t group_id,
                                    const char* dset_name,
+                                   const uint32_t dset_rank,
                                    const hsize_t* offset_file,
                                    hsize_t* const size_read,
                                    int64_t* const eof_read_size,
@@ -1121,6 +1384,7 @@ trexio_hdf5_open_read_dset_sparse (const hid_t group_id,
                                    )
 {
   const int h5_rank = 1;
+  if (dset_rank == 0) return TREXIO_INVALID_ARG_3;
 
   // get the dataset handle
   hid_t dset_id = H5Dopen(group_id, dset_name, H5P_DEFAULT);
@@ -1151,9 +1415,9 @@ trexio_hdf5_open_read_dset_sparse (const hid_t group_id,
   if (max_offset > ddims[0]) {
     is_EOF = 1;
     // lower the value of count to reduce the number of elements which will be read
-    size_read[0] -= max_offset - ddims[0];
+    size_read[0] -= (max_offset - ddims[0]);
     // modified the value of eof_read_size passed by address
-    if (eof_read_size != NULL) *eof_read_size = size_read[0];
+    if (eof_read_size != NULL) *eof_read_size = size_read[0]/dset_rank;
   }
 
   // special case when reading int indices
@@ -1238,7 +1502,7 @@ trexio_hdf5_open_read_dset_sparse (const hid_t group_id,
   #+begin_src c :tangle suffix_hdf5.h
 trexio_exit_code trexio_hdf5_create_write_dset_sparse (const hid_t group_id, const char* dset_name, const hid_t dtype_id, const hsize_t* chunk_dims, const void* data_sparse);
 trexio_exit_code trexio_hdf5_open_write_dset_sparse (const hid_t group_id, const char* dset_name, const hid_t dtype_id, const hsize_t* chunk_dims, const hsize_t* offset_file, const void* data_sparse);
-trexio_exit_code trexio_hdf5_open_read_dset_sparse (const hid_t group_id, const char* dset_name, const hsize_t* offset_file, hsize_t* const size_read, int64_t* const eof_read_size, const int is_index, void* const data_sparse);
+trexio_exit_code trexio_hdf5_open_read_dset_sparse (const hid_t group_id, const char* dset_name, const uint32_t dset_rank, const hsize_t* offset_file, hsize_t* const size_read, int64_t* const eof_read_size, const int is_index, void* const data_sparse);
 
 #endif
   #+end_src
diff --git a/src/templates_text/build.sh b/src/templates_text/build.sh
index 9e285119..b5d73f68 100644
--- a/src/templates_text/build.sh
+++ b/src/templates_text/build.sh
@@ -10,6 +10,9 @@ cat populated/pop_struct_text_group_dset.h >> trexio_text.h
 cat populated/pop_struct_text_group.h >> trexio_text.h
 cat basic_text.h   >> trexio_text.h
 
+cat hrw_determinant_text.h >> trexio_text.h
+cat *_determinant_text.c >> trexio_text.c
+
 cat populated/pop_free_group_text.c >> trexio_text.c
 cat populated/pop_read_group_text.c >> trexio_text.c
 cat populated/pop_flush_group_text.c >> trexio_text.c
diff --git a/src/templates_text/templator_text.org b/src/templates_text/templator_text.org
index 066fd856..0c042490 100644
--- a/src/templates_text/templator_text.org
+++ b/src/templates_text/templator_text.org
@@ -3,6 +3,18 @@
 #+SETUPFILE: ../../docs/theme.setup
 # -*- mode: org -*-
 
+  The "file" produced by the text back end is a directory with one
+  file per group.
+
+  When the file is open, it is locked by the current process. No other
+  process can read/write the same file. This guarantees that the
+  representation in memory is consistent with the file and avoid
+  re-reading the file before writing.
+  To lock the file, we lock the =.lock= file which is present in the
+  directory.
+
+  The file is written when closed, or when the flush function is called.
+
 * Constant file prefixes (not used by the generator)               :noexport:
 
   #+begin_src emacs-lisp
@@ -61,21 +73,7 @@
 
   #+end_src
 
-* TEXT back end
-
-  The "file" produced by the text back end is a directory with one
-  file per group.
-
-  When the file is open, it is locked by the current process. No other
-  process can read/write the same file. This guarantees that the
-  representation in memory is consistent with the file and avoid
-  re-reading the file before writing.
-  To lock the file, we lock the =.lock= file which is present in the
-  directory.
-
-  The file is written when closed, or when the flush function is called.
-
-** Template for group-related structures in text back end
+* Template for group-related structures in text back end
 
     #+begin_src c :tangle struct_text_group_dset.h
 typedef struct $group$_s {
@@ -91,7 +89,7 @@ typedef struct $group$_s {
 } $group$_t;
     #+end_src
 
-** Template for general structure in text back end
+* Template for general structure in text back end
 
     #+begin_src c :tangle struct_text_group.h
 typedef struct trexio_text_s {
@@ -101,7 +99,7 @@ typedef struct trexio_text_s {
 } trexio_text_t;
     #+end_src
 
-** Initialize function (constant part)
+* Initialize function (constant part)
 
     #+begin_src c :tangle basic_text.h :exports none
 trexio_exit_code trexio_text_init(trexio_t* const file);
@@ -246,7 +244,7 @@ trexio_text_unlock (trexio_t* const file)
 }
     #+end_src
 
-** Deinitialize function (templated part)
+* Deinitialize function (templated part)
 
     #+begin_src c :tangle basic_text_group.c
 trexio_exit_code
@@ -265,7 +263,7 @@ trexio_text_deinit (trexio_t* const file)
 }
     #+end_src
 
-** Template for text read a group
+* Template for text read a group
 
     #+begin_src c :tangle read_group_text.h :exports none
 $group$_t* trexio_text_read_$group$(trexio_text_t* const file);
@@ -567,7 +565,7 @@ trexio_text_read_$group$ (trexio_text_t* const file)
 }
    #+end_src
 
-** Template for text flush a group
+* Template for text flush a group
 
     #+begin_src c :tangle flush_group_text.h :exports none
 trexio_exit_code trexio_text_flush_$group$(trexio_text_t* const file);
@@ -632,7 +630,7 @@ trexio_text_flush_$group$ (trexio_text_t* const file)
 }
    #+end_src
 
-** Template for text free memory
+* Template for text free memory
 
      Memory is allocated when reading. The following function frees memory.
 
@@ -678,7 +676,7 @@ trexio_text_free_$group$ (trexio_text_t* const file)
 }
     #+end_src
 
-** Template for has/read/write a numerical attribute
+* Template for has/read/write a numerical attribute
 
     #+begin_src c :tangle hrw_attr_num_text.h :exports none
 trexio_exit_code trexio_text_has_$group_num$ (trexio_t* const file);
@@ -742,7 +740,7 @@ trexio_text_has_$group_num$ (trexio_t* const file)
 }
    #+end_src
 
-** Template for has/read/write a dataset of numerical data
+* Template for has/read/write a dataset of numerical data
 
      The ~group_dset~ array is assumed allocated with the appropriate size.
 
@@ -837,7 +835,7 @@ trexio_text_has_$group_dset$ (trexio_t* const file)
 
 }
    #+end_src
-** Template for has/read/write a dataset of strings
+* Template for has/read/write a dataset of strings
 
      The ~group_dset~ array is assumed allocated with the appropriate size.
 
@@ -937,7 +935,7 @@ trexio_text_has_$group_dset$ (trexio_t* const file)
 
 }
    #+end_src
-** Template for has/read/write a string attribute
+* Template for has/read/write a string attribute
 
    #+begin_src c :tangle hrw_attr_str_text.h :exports none
 trexio_exit_code trexio_text_has_$group_str$ (trexio_t* const file);
@@ -1012,7 +1010,7 @@ trexio_text_has_$group_str$ (trexio_t* const file)
 
 }
    #+end_src
-** Template for has/read/write the dataset of sparse data
+* Template for has/read/write the dataset of sparse data
 
    Each sparse array is stored in a separate =.txt= file due to the fact that sparse I/O has to be decoupled
    from conventional write/read/flush behaviour of the TEXT back end. Chunks are used to read/write sparse data
@@ -1284,7 +1282,7 @@ trexio_exit_code trexio_text_has_$group_dset$(trexio_t* const file)
 }
    #+end_src
 
-** Template for text delete a group (UNSAFE mode)
+* Template for text delete a group (UNSAFE mode)
 
   #+begin_src c :tangle delete_group_text.h :exports none
 trexio_exit_code trexio_text_delete_$group$ (trexio_t* const file);
@@ -1313,6 +1311,411 @@ trexio_text_delete_$group$ (trexio_t* const file)
 }
    #+end_src
 
+* Source code for the determinant part
+
+   Each array is stored in a separate =.txt= file due to the fact that determinant I/O has to be decoupled
+   from conventional write/read/flush behaviour of the TEXT back end. Chunks are used to read/write the data
+   to prevent memory overflow. Chunks have a given ~int64_t size~.
+   Size specifies the number of data items, e.g. determinants.
+
+
+   #+begin_src c :tangle hrw_determinant_text.h :exports none
+trexio_exit_code trexio_text_has_determinant_list(trexio_t* const file);
+trexio_exit_code trexio_text_read_determinant_list(trexio_t* const file, const int64_t offset_file, const uint32_t rank, const uint64_t* dims, int64_t* const eof_read_size, int64_t* const list);
+trexio_exit_code trexio_text_write_determinant_list(trexio_t* const file, const int64_t offset_file, const uint32_t rank, const uint64_t* dims, const int64_t* list);
+trexio_exit_code trexio_text_has_determinant_coefficient(trexio_t* const file);
+trexio_exit_code trexio_text_read_determinant_coefficient(trexio_t* const file, const int64_t offset_file, const uint32_t rank, const uint64_t* dims, int64_t* const eof_read_size, double* const coeff);
+trexio_exit_code trexio_text_write_determinant_coefficient(trexio_t* const file, const int64_t offset_file, const uint32_t rank, const uint64_t* dims, const double* coeff);
+trexio_exit_code trexio_text_read_determinant_coefficient_size(trexio_t* const file, int64_t* const size_max);
+   #+end_src
+
+   #+begin_src c :tangle read_determinant_text.c
+trexio_exit_code trexio_text_read_determinant_list(trexio_t* const file,
+                                                   const int64_t offset_file,
+                                                   const uint32_t rank,
+                                                   const uint64_t* dims,
+                                                   int64_t* const eof_read_size,
+                                                   int64_t* const list)
+{
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+  if (eof_read_size == NULL) return TREXIO_INVALID_ARG_5;
+  if (list == NULL) return TREXIO_INVALID_ARG_6;
+
+  const char determinant_list_file_name[256] = "/determinant_list.txt";
+  /* The full path to the destination TXT file with sparse data. This will include TREXIO directory name. */
+  char file_full_path[TREXIO_MAX_FILENAME_LENGTH];
+
+  /* Copy directory name in file_full_path */
+  strncpy (file_full_path, file->file_name, TREXIO_MAX_FILENAME_LENGTH);
+  /* Append name of the file with sparse data */
+  strncat (file_full_path, determinant_list_file_name,
+           TREXIO_MAX_FILENAME_LENGTH-strlen(determinant_list_file_name));
+
+  /* Open the file in "r" (read) mode to guarantee that no truncation happens upon consecutive reads */
+  FILE* f = fopen(file_full_path, "r");
+  if(f == NULL) return TREXIO_FILE_ERROR;
+
+  /* Specify the line length in order to offset properly.
+     Each 64-bit integer takes at most 10 slots and requires one space,
+     we have int_num integers per up-spin determinant,
+     then this number is doubled because we have the same number for down-spin electrons,
+     and then one newline char.
+   ,*/
+  uint64_t line_length = dims[1]*11UL + 1UL; // 10 digits per int64_t bitfield + 1 space = 11 spots + 1 newline char
+
+  /* Offset in the file according to the provided  value of offset_file and optimal line_length */
+  fseek(f, (long) offset_file * line_length, SEEK_SET);
+
+  /* Read the data from the file and check the return code of fprintf to verify that > 0 bytes have been read or reached EOF */
+  int rc;
+  /* Declare fixed buffer which will be used to read the determinant string <a1 a2 ... a/\ b1 b2 ... b\/> */
+  char buffer[1024];
+  uint32_t buf_size = sizeof(buffer);
+  /* Parameters to post-process the buffer and to get bit fields integers */
+  uint64_t accum = 0UL;
+  uint32_t shift_int64 = 11U;
+  /* Counter for number of elements beind processed */
+  uint64_t count = 0UL;
+  for (uint64_t i=0UL; i < dims[0]; ++i) {
+
+    accum = 0UL;
+    memset(buffer, 0, buf_size);
+
+    if(fgets(buffer, buf_size-1, f) == NULL){
+
+      fclose(f);
+      ,*eof_read_size = count;
+      return TREXIO_END;
+
+    } else {
+
+   /* The format string is not anymore static but rather dynamic (the number of ints depend on the mo_num)
+      Thus, we parse the buffer string int_num*2 times to get the bit field determinants.
+    ,*/
+      for (uint32_t j=0; j < (uint32_t) dims[1]; ++j) {
+        rc = sscanf(buffer+accum, "%10" SCNd64, list + dims[1]*i + j);
+        if(rc <= 0) {
+          fclose(f);
+          return TREXIO_FAILURE;
+        }
+        accum += shift_int64;
+      }
+      count += 1UL;
+
+    }
+  }
+
+  /* Close the TXT file */
+  rc = fclose(f);
+  if(rc != 0) return TREXIO_FILE_ERROR;
+
+  return TREXIO_SUCCESS;
+}
+
+trexio_exit_code trexio_text_read_determinant_coefficient(trexio_t* const file,
+                                                          const int64_t offset_file,
+                                                          const uint32_t rank,
+                                                          const uint64_t* dims,
+                                                          int64_t* const eof_read_size,
+                                                          double* const coeff)
+{
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+  if (eof_read_size == NULL) return TREXIO_INVALID_ARG_5;
+  if (coeff == NULL) return TREXIO_INVALID_ARG_6;
+
+  char coeff_file_name[256];
+  memset(coeff_file_name, 0, sizeof(coeff_file_name));
+  const int32_t trexio_state = file->state;
+
+  if (trexio_state != 0) {
+    sprintf(coeff_file_name, "/determinant_coefficient_state_%" PRId32 ".txt", trexio_state);
+  } else {
+    strncpy(coeff_file_name, "/determinant_coefficient.txt", 32);
+  }
+
+  /* The full path to the destination TXT file with sparse data. This will include TREXIO directory name. */
+  char file_full_path[TREXIO_MAX_FILENAME_LENGTH];
+  /* Copy directory name in file_full_path */
+  strncpy (file_full_path, file->file_name, TREXIO_MAX_FILENAME_LENGTH);
+  /* Append name of the file with sparse data */
+  strncat (file_full_path, coeff_file_name,
+           TREXIO_MAX_FILENAME_LENGTH-strlen(coeff_file_name));
+
+  /* Open the file in "r" (read) mode to guarantee that no truncation happens upon consecutive reads */
+  FILE* f = fopen(file_full_path, "r");
+  if(f == NULL) return TREXIO_FILE_ERROR;
+
+  /* Specify the line length in order to offset properly.
+     Each double value 24 elements + one newline char.
+   ,*/
+  uint64_t line_length = 25UL;
+
+  /* Offset in the file according to the provided  value of offset_file and optimal line_length */
+  fseek(f, (long) offset_file * line_length, SEEK_SET);
+
+  /* Read the data from the file and check the return code of fprintf to verify that > 0 bytes have been read or reached EOF */
+  int rc;
+  /* Declare fixed buffer which will be used to read the determinant string <a1 a2 ... a/\ b1 b2 ... b\/> */
+  char buffer[64];
+  uint32_t buf_size = sizeof(buffer);
+  /* Counter for number of elements beind processed */
+  uint64_t count = 0UL;
+
+  for (uint64_t i=0UL; i < dims[0]; ++i) {
+
+    memset(buffer, 0, buf_size);
+    if(fgets(buffer, buf_size-1, f) == NULL){
+
+      fclose(f);
+      ,*eof_read_size = count;
+      return TREXIO_END;
+
+    } else {
+
+      rc = sscanf(buffer, "%lf", coeff + i);
+      if(rc <= 0) {
+        fclose(f);
+        return TREXIO_FAILURE;
+      }
+      count += 1UL;
+
+    }
+  }
+
+  /* Close the TXT file */
+  rc = fclose(f);
+  if(rc != 0) return TREXIO_FILE_ERROR;
+
+  return TREXIO_SUCCESS;
+}
+
+trexio_exit_code
+trexio_text_read_determinant_coefficient_size(trexio_t* const file, int64_t* const size_max)
+{
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+  if (size_max == NULL) return TREXIO_INVALID_ARG_2;
+
+  char coeff_file_name[256];
+  memset(coeff_file_name, 0, sizeof(coeff_file_name));
+  const int32_t trexio_state = file->state;
+
+  if (trexio_state != 0) {
+    sprintf(coeff_file_name, "/determinant_coefficient_state_%" PRId32 ".txt.size", trexio_state);
+  } else {
+    strncpy(coeff_file_name, "/determinant_coefficient.txt.size", 64);
+  }
+
+  /* The full path to the destination TXT file with sparse data. This will include TREXIO directory name. */
+  char file_full_path[TREXIO_MAX_FILENAME_LENGTH];
+  /* Copy directory name in file_full_path */
+  strncpy (file_full_path, file->file_name, TREXIO_MAX_FILENAME_LENGTH);
+  /* Append name of the file with sparse data */
+  strncat (file_full_path, coeff_file_name,
+           TREXIO_MAX_FILENAME_LENGTH-strlen(coeff_file_name));
+
+  /* Open the file in "r" (read) mode to guarantee that no truncation happens upon consecutive reads */
+  FILE* f = fopen(file_full_path, "r");
+  if(f == NULL) return TREXIO_FILE_ERROR;
+
+  /* Read the data from the file and check the return code of fprintf to verify that > 0 bytes have been read or reached EOF */
+  int rc;
+  int64_t size_item, size_accum=0L;
+
+  /* Read the values from the file. BEWARE OF POSSIBLE MAX_INT64 OVERFLOW ! */
+  while(fscanf(f, "%" SCNd64, &size_item) != EOF) {
+    /* Check that summation will not overflow the int64_t value */
+    if (INT64_MAX - size_accum > size_item) {
+      size_accum += size_item;
+    } else {
+      fclose(f);
+      ,*size_max = -1L;
+      return TREXIO_INT_SIZE_OVERFLOW;
+    }
+  }
+
+  /* Close the TXT file */
+  rc = fclose(f);
+  if(rc != 0) return TREXIO_FILE_ERROR;
+
+  /* Overwrite the value at the input address and return TREXIO_SUCCESS */
+  ,*size_max = size_accum;
+  return TREXIO_SUCCESS;
+}
+   #+end_src
+
+   #+begin_src c :tangle write_determinant_text.c
+trexio_exit_code trexio_text_write_determinant_list(trexio_t* const file,
+                                                    const int64_t offset_file,
+                                                    const uint32_t rank,
+                                                    const uint64_t* dims,
+                                                    const int64_t* list)
+{
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+  if (list == NULL) return TREXIO_INVALID_ARG_5;
+
+  const char determinant_list_file_name[256] = "/determinant_list.txt";
+  /* The full path to the destination TXT file with sparse data. This will include TREXIO directory name. */
+  char file_full_path[TREXIO_MAX_FILENAME_LENGTH];
+
+  /* Copy directory name in file_full_path */
+  strncpy (file_full_path, file->file_name, TREXIO_MAX_FILENAME_LENGTH);
+  /* Append name of the file with sparse data */
+  strncat (file_full_path, determinant_list_file_name,
+           TREXIO_MAX_FILENAME_LENGTH-strlen(determinant_list_file_name));
+
+  /* Open the file in "a" (append) mode to guarantee that no truncation happens upon consecutive writes */
+  FILE* f = fopen(file_full_path, "a");
+  if(f == NULL) return TREXIO_FILE_ERROR;
+
+  /* Write the data in the file and check the return code of fprintf to verify that > 0 bytes have been written */
+  int rc;
+  for (uint64_t i=0UL; i < dims[0]; ++i) {
+
+    /* The loop below is needed to write a line with int bit fields for alpha and beta electrons */
+    for (uint32_t j=0; j < (uint32_t) dims[1]; ++j) {
+      rc = fprintf(f, "%10" PRId64 " ", *(list + i*dims[1] + j));
+      if(rc <= 0) {
+        fclose(f);
+        return TREXIO_FAILURE;
+      }
+    }
+    fprintf(f, "%s", "\n");
+
+  }
+
+  /* Close the TXT file */
+  rc = fclose(f);
+  if (rc != 0) return TREXIO_FILE_ERROR;
+
+  /* Exit upon success */
+  return TREXIO_SUCCESS;
+}
+
+trexio_exit_code trexio_text_write_determinant_coefficient(trexio_t* const file,
+                                                           const int64_t offset_file,
+                                                           const uint32_t rank,
+                                                           const uint64_t* dims,
+                                                           const double* coeff)
+{
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+  if (coeff == NULL) return TREXIO_INVALID_ARG_5;
+
+  char coeff_file_name[256];
+  memset(coeff_file_name, 0, sizeof(coeff_file_name));
+  const int32_t trexio_state = file->state;
+
+  if (trexio_state != 0) {
+    sprintf(coeff_file_name, "/determinant_coefficient_state_%" PRId32 ".txt", trexio_state);
+  } else {
+    strncpy(coeff_file_name, "/determinant_coefficient.txt", 32);
+  }
+
+  /* The full path to the destination TXT file with sparse data. This will include TREXIO directory name. */
+  char file_full_path[TREXIO_MAX_FILENAME_LENGTH];
+  /* Copy directory name in file_full_path */
+  strncpy (file_full_path, file->file_name, TREXIO_MAX_FILENAME_LENGTH);
+  /* Append name of the file with sparse data */
+  strncat (file_full_path, coeff_file_name,
+           TREXIO_MAX_FILENAME_LENGTH-strlen(coeff_file_name));
+
+  /* Open the file in "a" (append) mode to guarantee that no truncation happens upon consecutive writes */
+  FILE* f = fopen(file_full_path, "a");
+  if(f == NULL) return TREXIO_FILE_ERROR;
+
+  /* Write the data in the file and check the return code of fprintf to verify that > 0 bytes have been written */
+  int rc;
+  for (uint64_t i=0UL; i < dims[0]; ++i) {
+
+    rc = fprintf(f, "%24.16e\n", *(coeff + i));
+    if(rc <= 0) {
+      fclose(f);
+      return TREXIO_FAILURE;
+    }
+
+  }
+
+  /* Close the TXT file */
+  rc = fclose(f);
+  if (rc != 0) return TREXIO_FILE_ERROR;
+
+  /* Append .size to the file_full_path in order to write additional info about the written buffer of data */
+  strncat(file_full_path, ".size", 6);
+
+  /* Open the new file in "a" (append) mode to append info about the buffer that has been just written */
+  FILE *f_wSize = fopen(file_full_path, "a");
+  if (f_wSize == NULL) return TREXIO_FILE_ERROR;
+
+  /* Write the buffer_size */
+  rc = fprintf(f_wSize, "%" PRIu64 "\n", dims[0]);
+  if (rc <= 0) {
+    fclose(f_wSize);
+    return TREXIO_FAILURE;
+  }
+
+  /* Close the TXT file */
+  rc = fclose(f_wSize);
+  if (rc != 0) return TREXIO_FILE_ERROR;
+
+  /* Exit upon success */
+  return TREXIO_SUCCESS;
+}
+
+   #+end_src
+
+   #+begin_src c :tangle has_determinant_text.c
+trexio_exit_code trexio_text_has_determinant_list(trexio_t* const file)
+{
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+
+  const char determinant_list_file_name[256] = "/determinant_list.txt";
+  /* The full path to the destination TXT file with sparse data. This will include TREXIO directory name. */
+  char file_full_path[TREXIO_MAX_FILENAME_LENGTH];
+
+  /* Copy directory name in file_full_path */
+  strncpy (file_full_path, file->file_name, TREXIO_MAX_FILENAME_LENGTH);
+  /* Append name of the file with sparse data */
+  strncat (file_full_path, determinant_list_file_name,
+           TREXIO_MAX_FILENAME_LENGTH-strlen(determinant_list_file_name));
+
+  /* Check the return code of access function to determine whether the file with data exists or not */
+  if (access(file_full_path, F_OK) == 0){
+    return TREXIO_SUCCESS;
+  } else {
+    return TREXIO_HAS_NOT;
+  }
+}
+
+trexio_exit_code trexio_text_has_determinant_coefficient(trexio_t* const file)
+{
+  if (file == NULL) return TREXIO_INVALID_ARG_1;
+
+  char coeff_file_name[256];
+  memset(coeff_file_name, 0, sizeof(coeff_file_name));
+  const int32_t trexio_state = file->state;
+
+  if (trexio_state != 0) {
+    sprintf(coeff_file_name, "/determinant_coefficient_state_%" PRId32 ".txt", trexio_state);
+  } else {
+    strncpy(coeff_file_name, "/determinant_coefficient.txt", 32);
+  }
+
+  /* The full path to the destination TXT file with sparse data. This will include TREXIO directory name. */
+  char file_full_path[TREXIO_MAX_FILENAME_LENGTH];
+  /* Copy directory name in file_full_path */
+  strncpy (file_full_path, file->file_name, TREXIO_MAX_FILENAME_LENGTH);
+  /* Append name of the file with sparse data */
+  strncat (file_full_path, coeff_file_name,
+           TREXIO_MAX_FILENAME_LENGTH-strlen(coeff_file_name));
+
+  /* Check the return code of access function to determine whether the file with data exists or not */
+  if (access(file_full_path, F_OK) == 0){
+    return TREXIO_SUCCESS;
+  } else {
+    return TREXIO_HAS_NOT;
+  }
+}
+   #+end_src
+
 * Constant file suffixes (not used by the generator)               :noexport:
 
   #+begin_src c :tangle suffix_text.h
diff --git a/tools/generator_tools.py b/tools/generator_tools.py
index c58e5f40..e5bfd02d 100644
--- a/tools/generator_tools.py
+++ b/tools/generator_tools.py
@@ -517,7 +517,7 @@ def get_dtype_dict (dtype: str, target: str, rank = None, int_len_printf = None)
         group_dset_format_printf_16 = '"'
         group_dset_format_printf_32 = '"'
         group_dset_format_scanf  = ''
-        for i in range(rank):
+        for _ in range(rank):
             group_dset_format_printf_8  += item_printf_8
             group_dset_format_printf_16 += item_printf_16
             group_dset_format_printf_32 += item_printf_32
@@ -644,11 +644,16 @@ def split_dset_dict_detailed (datasets: dict) -> tuple:
     dset_string_dict = {}
     dset_sparse_dict = {}
     for k,v in datasets.items():
+
         # create a temp dictionary
         tmp_dict = {}
         rank = len(v[1])
         datatype = v[0]
 
+        # skip the data which has 'special' datatype (e.g. determinants for which the code is not templated)
+        if 'special' in datatype:
+            continue
+
         # define whether the dset is sparse
         is_sparse = False
         int_len_printf = {}
diff --git a/trex.org b/trex.org
index 8d1e7337..0970ab39 100644
--- a/trex.org
+++ b/trex.org
@@ -635,7 +635,74 @@ prim_factor =
    #+end_src
    :end:
 
-* TODO Slater determinants
+* Slater determinants (determinant group)
+
+  The configuration interaction (CI) wave function $\Psi$
+  can be expanded in the basis of Slater determinants $D_I$ as follows
+
+  \[
+  | \Psi> = \sum_I C_I | D_I> |
+  \]
+
+  For relatively small expansions, a given determinant can be represented as a list of ~mo.num~ occupation numbers.
+  However, this requires a lot of extra memory and would be technically impossible for larger expansions
+  (~millions of determinants). This is why the determinants are stored as bit fields in the TREXIO file
+  (see ~int bitfield~ type in the table below). By default, the chemist notation is used, namely
+
+  \[
+  | D_I > = | \alpha_1 \alpha_2 \ldots \alpha_{n\uparrow} \beta_1 \beta_2 \ldots \beta_{n\downarrow} > |
+  \]
+
+  where $\alpha$ and $\beta$ denote $\uparrow$-spin and $\downarrow$-spin electrons, respectively,
+  $n\uparrow$ and $n\downarrow$ correspond to ~electron.up_num~ and ~electron.dn_num~, respectively.
+  Internally, bit fields for $\alpha$ and $\beta$ electrons are stored separately,
+  which is why the ~determinant.list~ attribute has a second dimension.
+
+  #+NAME: determinant
+  | Variable      | Type            | Dimensions                    | Description                                            |
+  |---------------+-----------------+-------------------------------+--------------------------------------------------------|
+  | ~num~         | ~dim~           |                               | Number of determinants                                 |
+  | ~list~        | ~int special~   | ~(determinant.num)~           | List of determinants as integer bit fields             |
+  | ~coefficient~ | ~float special~ | ~(state.num,determinant.num)~ | Coefficients of the determinants from the CI expansion |
+
+  #+CALL: json(data=determinant, title="determinant")
+
+  #+RESULTS:
+  :RESULTS:
+  #+begin_src python :tangle trex.json
+      "determinant": {
+		  "num" : [ "dim"          , []                                 ]
+	,        "list" : [ "int special"  , [ "determinant.num" ]              ]
+	, "coefficient" : [ "float special", [ "determinant.num", "state.num" ] ]
+      } ,
+  #+end_src
+  :END:
+
+* Excited states (state group)
+
+  By default, the ~determinant~ group corresponds to the ground state.
+  However, it should be also possible to store the coefficients that
+  correspond to excited state wave functions for the same set of
+  determinants. This is the goal of the present group
+
+  #+NAME: state
+  | Variable | Type  | Dimensions    | Description                                    |
+  |----------+-------+---------------+------------------------------------------------|
+  | ~num~    | ~dim~ |               | Number of states (including the ground state)  |
+  | ~label~  | ~str~ | ~(state.num)~ | Label of a given state (e.g. 'S' for singlets) |
+
+  #+CALL: json(data=state, title="state")
+
+  #+RESULTS:
+  :RESULTS:
+  #+begin_src python :tangle trex.json
+      "state": {
+	    "num" : [ "dim", []              ]
+	, "label" : [ "str", [ "state.num" ] ]
+      } ,
+  #+end_src
+  :END:
+
 * Reduced density matrices (rdm group)
 
   The reduced density matrices are defined in the basis of molecular
@@ -724,9 +791,9 @@ prim_factor =
   | ~point~  | ~float~ | ~(3, electron.num, qmc.num)~ | 3N-dimensional points                 |
   | ~psi~    | ~float~ | ~(qmc.num)~                  | Wave function evaluated at the points |
   | ~e_loc~  | ~float~ | ~(qmc.num)~                  | Local energy evaluated at the points  |
-   
+
    #+CALL: json(data=qmc, title="qmc", last=1)
-   
+
    #+RESULTS:
    :results:
    #+begin_src python :tangle trex.json


Test patch:
diff --git a/python/test/test_api.py b/python/test/test_api.py
index e347c350..45285592 100644
--- a/python/test/test_api.py
+++ b/python/test/test_api.py
@@ -118,17 +118,40 @@
 trexio.write_nucleus_coord(test_file, coords)
 
 
-# write mo_num (needed later to write sparse mo_2e_int_eri integrals)
-trexio.write_mo_num(test_file, 600)
+# write ao_num (needed later to write sparse ao_2e_int_eri integrals)
+trexio.write_ao_num(test_file, 600)
 
 # write sparse data in the file
 num_integrals = 100
 indices = [i for i in range(num_integrals*4)]
 values  = [(3.14 + float(i)) for i in range(num_integrals)]
 
-trexio.write_mo_2e_int_eri(test_file, 0, num_integrals, indices, values)
+trexio.write_ao_2e_int_eri(test_file, 0, num_integrals, indices, values)
 
 
+# write mo_num (needed later to write determinants)
+mo_num = 150
+trexio.write_mo_num(test_file, mo_num)
+
+int_num = 2*int((mo_num-1)/64+1)
+
+# write determinants in the file
+num_dets = 50
+offset = 0
+dets = [i for i in range(num_dets*int_num)]
+coeffs = [(3.14 + float(i)) for i in range(num_dets)]
+coeffs_s2 = [(6.28 + float(i)) for i in range(num_dets)]
+
+trexio.write_determinant_list(test_file, offset, num_dets, dets)
+trexio.write_determinant_coefficient(test_file, offset, num_dets, coeffs)
+
+test_file.set_state(2)
+trexio.write_determinant_coefficient(test_file, offset, num_dets, coeffs_s2)
+test_file.set_state(0)
+
+# manually check the consistency between coefficient_size and number of determinants
+assert trexio.read_determinant_coefficient_size(test_file) == trexio.read_determinant_num(test_file)
+
 # write nucleus_point_group in the file
 point_group = 'B3U'
 
@@ -210,7 +233,9 @@
 assert trexio.has_nucleus_coord(test_file2)
 assert trexio.has_nucleus_label(test_file2)
 assert trexio.has_nucleus_point_group(test_file2)
-assert trexio.has_mo_2e_int_eri(test_file2)
+assert trexio.has_ao_2e_int_eri(test_file2)
+assert trexio.has_determinant_list(test_file2)
+assert trexio.has_determinant_coefficient(test_file2)
 
 # read nucleus_num from file
 rnum = trexio.read_nucleus_num(test_file2)
@@ -254,14 +279,14 @@
 #rcoords_reshaped_2 = trexio.read_nucleus_coord(test_file2, doReshape=False)
 
 # read number of integrals already present in the file
-assert trexio.has_mo_2e_int_eri(test_file2)
-assert trexio.read_mo_2e_int_eri_size(test_file2)==num_integrals
+assert trexio.has_ao_2e_int_eri(test_file2)
+assert trexio.read_ao_2e_int_eri_size(test_file2)==num_integrals
 
-# read sparse arrays on mo_2e_int_eri integrals
+# read sparse arrays on ao_2e_int_eri integrals
 buf_size = 60
 offset_file = 0
 # read full buf_size (i.e. the one that does not reach EOF)
-indices_sparse_np, value_sparse_np, read_buf_size, eof = trexio.read_mo_2e_int_eri(test_file2, offset_file, buf_size)
+indices_sparse_np, value_sparse_np, read_buf_size, eof = trexio.read_ao_2e_int_eri(test_file2, offset_file, buf_size)
 print(f'First complete sparse read size: {read_buf_size}')
 #print(indices_sparse_np)
 assert not eof
@@ -271,7 +296,7 @@
 offset_file += buf_size
 
 # read incomplete buf_size (i.e. the one that does reach EOF)
-indices_sparse_np, value_sparse_np, read_buf_size, eof2 = trexio.read_mo_2e_int_eri(test_file2, offset_file, buf_size)
+indices_sparse_np, value_sparse_np, read_buf_size, eof2 = trexio.read_ao_2e_int_eri(test_file2, offset_file, buf_size)
 print(f'Second incomplete sparse read size: {read_buf_size}')
 #print(indices_sparse_np)
 assert eof2
@@ -279,6 +304,39 @@
 assert indices_sparse_np[0][0]==offset_file*4
 assert indices_sparse_np[read_buf_size-1][3]==(offset_file+read_buf_size)*4-1
 
+# read number of determinants already present in the file
+assert trexio.has_determinant_list(test_file2)
+assert trexio.read_determinant_num(test_file2)==num_dets
+
+# read determinants (list of ints and float coefficients)
+buf_size = 20
+offset_file = 0
+# read full buf_size (i.e. the one that does not reach EOF)
+dets_np, read_buf_size, eof = trexio.read_determinant_list(test_file2, offset_file, buf_size)
+print(f'First complete read of determinant list: {read_buf_size}')
+#print(indices_sparse_np)
+assert not eof
+assert read_buf_size==buf_size
+assert dets_np[0][0]==0
+assert dets_np[read_buf_size-1][int_num-1]==read_buf_size*int_num-1
+
+coefficients_np, read_buf_size, eof = trexio.read_determinant_coefficient(test_file2, offset_file, buf_size)
+print(f'First complete read of determinant coefficients: {read_buf_size}')
+#print(indices_sparse_np)
+assert not eof
+assert read_buf_size==buf_size
+
+# convert one determinant into a list of orbitals
+
+dets_tmp = dets_np[read_buf_size-1][:]
+#print(dets_tmp)
+
+# divide by 2 because in this test int_num is the total number of integers (i.e. up-spin + down_spin)
+orb_list_up, orb_list_dn = trexio.to_orbital_list_up_dn(int(int_num/2), dets_tmp)
+assert(orb_list_up[0] == 2)
+assert(orb_list_dn[0] == 1)
+#print(orb_list_up)
+#print(orb_list_dn)
 
 # read array of nuclear labels
 rlabels_2d = trexio.read_nucleus_label(test_file2, dim=nucleus_num)
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index f1c2264f..d415c170 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -7,6 +7,7 @@ set(Tests_text
   io_dset_float_text
   io_dset_str_text
   io_dset_sparse_text
+  io_determinant_text
   io_safe_dset_float_text
   io_dset_int_text
   io_num_text
@@ -23,6 +24,7 @@ if(ENABLE_HDF5)
     io_dset_float_hdf5
     io_dset_str_hdf5
     io_dset_sparse_hdf5
+    io_determinant_hdf5
     io_safe_dset_float_hdf5
     io_dset_int_hdf5
     io_num_hdf5
diff --git a/tests/io_determinant_hdf5.c b/tests/io_determinant_hdf5.c
new file mode 100644
index 00000000..7ca2e7cc
--- /dev/null
+++ b/tests/io_determinant_hdf5.c
@@ -0,0 +1,340 @@
+#include "trexio.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#define TEST_BACKEND  TREXIO_HDF5
+#define TREXIO_FILE   "test_determinant.h5"
+#define RM_COMMAND    "rm -f " TREXIO_FILE
+#define SIZE          100
+#define N_CHUNKS      5
+#define STATE_TEST    2
+#define MO_NUM        150
+
+static int test_write_determinant (const char* file_name, const back_end_t backend, const int64_t offset) {
+
+/* Try to write an array of sparse data into the TREXIO file */
+
+  trexio_t* file = NULL;
+  trexio_exit_code rc;
+
+/*================= START OF TEST ==================*/
+
+  // open file in 'write' mode
+  file = trexio_open(file_name, 'w', backend, &rc);
+  assert (file != NULL);
+  assert (rc == TREXIO_SUCCESS);
+
+  // parameters to be written
+  int64_t* det_list;
+  double*  det_coef;
+
+  int mo_num = MO_NUM;
+
+  det_list = (int64_t*) calloc(2*3*SIZE, sizeof(int64_t));
+  det_coef = (double*) calloc(SIZE, sizeof(double));
+
+  for(int i=0; i<SIZE; i++){
+    det_list[6*i]   = 6*i;
+    det_list[6*i+1] = 6*i+1;
+    det_list[6*i+2] = 6*i+2;
+    det_list[6*i+3] = 6*i+3;
+    det_list[6*i+4] = 6*i+4;
+    det_list[6*i+5] = 6*i+5;
+    det_coef[i]     = 3.14 + (double) i;
+  }
+
+  // write mo_num which will be used to determine the optimal size of int indices
+  if (trexio_has_mo_num(file) == TREXIO_HAS_NOT) {
+    rc = trexio_write_mo_num(file, mo_num);
+    assert(rc == TREXIO_SUCCESS);
+  }
+
+  // write dataset chunks of sparse data in the file (including FAKE statements)
+  uint64_t chunk_size = (uint64_t) SIZE/N_CHUNKS;
+  uint64_t offset_f = 0UL;
+  uint64_t offset_d = 0UL;
+  if (offset != 0L) offset_f += offset;
+
+  // write n_chunks times using write_sparse
+  for(int i=0; i<N_CHUNKS; ++i){
+
+    rc = trexio_write_determinant_list(file, offset_f, chunk_size, &det_list[6*offset_d]);
+    assert(rc == TREXIO_SUCCESS);
+
+    rc = trexio_write_determinant_coefficient(file, offset_f, chunk_size, &det_coef[offset_d]);
+    assert(rc == TREXIO_SUCCESS);
+
+    // The block below will write the coefficients for STATE_TEST
+    rc = trexio_set_state(file, STATE_TEST);
+    assert(rc == TREXIO_SUCCESS);
+
+    rc = trexio_write_determinant_coefficient(file, offset_f, chunk_size, &det_coef[offset_d]);
+    assert(rc == TREXIO_SUCCESS);
+
+    // set state back to the default 0 (ground state)
+    rc = trexio_set_state(file, 0);
+    assert(rc == TREXIO_SUCCESS);
+    // =================================================
+
+    offset_d += chunk_size;
+    offset_f += chunk_size;
+  }
+
+  // manually check the consistency of the determinant_num and coefficient_size after writing
+  int64_t coeff_size = 0L;
+  int64_t determinant_num = 0L;
+
+  rc = trexio_read_determinant_num_64(file, &determinant_num);
+  assert(rc == TREXIO_SUCCESS);
+
+  rc = trexio_read_determinant_coefficient_size(file, &coeff_size);
+  assert(rc == TREXIO_SUCCESS);
+  assert(determinant_num == coeff_size);
+
+  rc = trexio_set_state(file, STATE_TEST);
+  assert(rc == TREXIO_SUCCESS);
+
+  rc = trexio_read_determinant_coefficient_size(file, &coeff_size);
+  assert(rc == TREXIO_SUCCESS);
+  assert(determinant_num == coeff_size);
+
+  // close current session
+  rc = trexio_close(file);
+  assert (rc == TREXIO_SUCCESS);
+
+  // free the allocated memeory
+  free(det_list);
+  free(det_coef);
+
+/*================= END OF TEST ==================*/
+
+  return 0;
+}
+
+static int test_has_determinant(const char* file_name, const back_end_t backend) {
+
+/* Try to check the existence of a dataset of sparse data in the TREXIO file */
+
+  trexio_t* file = NULL;
+  trexio_exit_code rc;
+
+/*================= START OF TEST ==================*/
+
+  // open file
+  file = trexio_open(file_name, 'r', backend, &rc);
+  assert (file != NULL);
+  assert (rc == TREXIO_SUCCESS);
+
+  // now check that previously written determinant_list exists
+  rc = trexio_has_determinant_list(file);
+  assert(rc==TREXIO_SUCCESS);
+
+  // now check that previously written determinant_coefficient exists
+  rc = trexio_has_determinant_coefficient(file);
+  assert(rc==TREXIO_SUCCESS);
+
+  // also check for STATE_TEST
+  rc = trexio_set_state(file, STATE_TEST);
+  assert(rc == TREXIO_SUCCESS);
+
+  rc = trexio_has_determinant_coefficient(file);
+  assert(rc==TREXIO_SUCCESS);
+
+  rc = trexio_set_state(file, 0);
+  assert(rc == TREXIO_SUCCESS);
+
+  // close current session
+  rc = trexio_close(file);
+  assert (rc == TREXIO_SUCCESS);
+
+/*================= END OF TEST ==================*/
+
+  return 0;
+}
+
+static int test_read_determinant (const char* file_name, const back_end_t backend, const int64_t offset) {
+
+/* Try to read one chunk of dataset of sparse data in the TREXIO file */
+
+  trexio_t* file = NULL;
+  trexio_exit_code rc;
+
+/*================= START OF TEST ==================*/
+
+  // open file
+  file = trexio_open(file_name, 'r', backend, &rc);
+  assert (file != NULL);
+  assert (rc == TREXIO_SUCCESS);
+
+  // compute how many integer bit fields is needed per determinant (for a given spin)
+  int64_t mo_num;
+  rc = trexio_read_mo_num_64(file, &mo_num);
+  assert (rc == TREXIO_SUCCESS);
+  assert (mo_num == MO_NUM);
+
+  int int_num = (mo_num - 1)/64 + 1;
+  assert (int_num == 3);
+
+  // define arrays to read into
+  int64_t* det_list_read;
+  double*  det_coef_read;
+  double*  det_coef_s2_read;
+  double check_diff;
+  uint64_t size_r = 40L;
+
+  det_list_read = (int64_t*) calloc(2*int_num*size_r,sizeof(int64_t));
+  det_coef_read = (double*)  calloc(size_r,sizeof(double));
+  det_coef_s2_read = (double*)  calloc(size_r,sizeof(double));
+
+  // specify the read parameters, here:
+  // 1 chunk of 10 elements using offset of 40 (i.e. lines No. 40--59) into elements of the array starting from 5
+  int64_t chunk_read = 10L;
+  int64_t offset_file_read = 40L;
+  int offset_data_read = 5;
+  int64_t read_size_check;
+  read_size_check = chunk_read;
+
+  if (offset != 0L) offset_file_read += offset;
+
+  // read one chunk using the aforementioned parameters
+  rc = trexio_read_determinant_list(file, offset_file_read, &chunk_read, &det_list_read[2*int_num*offset_data_read]);
+  assert(rc == TREXIO_SUCCESS);
+  assert(chunk_read == read_size_check);
+  assert(det_list_read[0] == 0);
+  assert(det_list_read[2*int_num*offset_data_read] == 2 * int_num * (int64_t) (offset_file_read-offset));
+
+  rc = trexio_read_determinant_coefficient(file, offset_file_read, &chunk_read, &det_coef_read[offset_data_read]);
+  assert(rc == TREXIO_SUCCESS);
+  assert(chunk_read == read_size_check);
+
+  check_diff = det_coef_read[0] - 0.;
+  assert(check_diff*check_diff < 1e-14);
+
+  check_diff = det_coef_read[offset_data_read] - (3.14 + (double) (offset_file_read-offset));
+  //printf("%lf %lf\n", check_diff, det_coef_read[offset_data_read]);
+  assert(check_diff*check_diff < 1e-14);
+
+  // read one chuk of coefficients for a different state
+  rc = trexio_set_state(file, STATE_TEST);
+  assert(rc == TREXIO_SUCCESS);
+
+  rc = trexio_read_determinant_coefficient(file, offset_file_read, &chunk_read, &det_coef_s2_read[offset_data_read]);
+  assert(rc == TREXIO_SUCCESS);
+  assert(chunk_read == read_size_check);
+
+  check_diff = det_coef_s2_read[0] - 0.;
+  assert(check_diff*check_diff < 1e-14);
+
+  rc = trexio_set_state(file, 0);
+  assert(rc == TREXIO_SUCCESS);
+
+  // now attempt to read so that one encounters end of file during reading (i.e. offset_file_read + chunk_read > size_max)
+  offset_file_read = 97L;
+  offset_data_read = 1;
+  int64_t eof_read_size_check = SIZE - offset_file_read; // if offset_file_read=97 => only 3 integrals will be read out of total of 100
+
+  if (offset != 0L) offset_file_read += offset;
+
+  chunk_read = read_size_check;
+  // read one chunk that will reach EOF and return TREXIO_END code
+  rc = trexio_read_determinant_list(file, offset_file_read, &chunk_read, &det_list_read[2*int_num*offset_data_read]);
+  /*
+  printf("%s\n", trexio_string_of_error(rc));
+  for (int i=0; i<size_r; i++) {
+    printf("%lld %lld\n", det_list_read[6*i], det_list_read[6*i+5]);
+  }
+  */
+  assert(rc == TREXIO_END);
+  assert(chunk_read == eof_read_size_check);
+  assert(det_list_read[2*int_num*size_r-1] == 0);
+  assert(det_list_read[2*int_num*offset_data_read] == 2 * int_num * (int64_t) (offset_file_read-offset));
+
+  chunk_read = read_size_check;
+  rc = trexio_read_determinant_coefficient(file, offset_file_read, &chunk_read, &det_coef_read[offset_data_read]);
+  /*
+  printf("%s\n", trexio_string_of_error(rc));
+  for (int i=0; i<size_r; i++) {
+    printf("%lf\n", det_coef_read[i]);
+  }
+  */
+  assert(rc == TREXIO_END);
+  assert(chunk_read == eof_read_size_check);
+
+  check_diff= det_coef_read[size_r-1] - 0.;
+  //printf("%lf %lf\n", check_diff, det_coef_read[size_r-1]);
+  assert(check_diff*check_diff < 1e-14);
+
+  // check the value of determinant_num
+  int32_t det_num = 0;
+  int32_t size_check = SIZE;
+  if (offset != 0L) size_check += offset;
+
+  rc = trexio_read_determinant_num(file, &det_num);
+  assert(rc == TREXIO_SUCCESS);
+  assert(det_num == size_check);
+
+
+  // check conversion of determinants into orbital lists
+  int64_t  size_list = NORB_PER_INT * int_num;
+  int32_t* orb_list_up = (int32_t*) calloc(size_list, sizeof(int32_t));
+  int32_t* orb_list_dn = (int32_t*) calloc(size_list, sizeof(int32_t));
+  int32_t  occ_num_up, occ_num_dn;
+
+  rc = trexio_to_orbital_list_up_dn (int_num, &det_list_read[2*int_num*5], orb_list_up, orb_list_dn, &occ_num_up, &occ_num_dn);
+  assert (rc == TREXIO_SUCCESS);
+  assert (occ_num_up == 14);
+  assert (occ_num_dn == 17);
+  /* // DEBUG printing
+  printf("occ_num_up : %d ; occ_num_dn : %d \n", occ_num_up, occ_num_dn);
+  for (int i=0; i<occ_num_up; i++) {
+     printf("%d ", orb_list_up[i]);
+  }
+  printf("| ");
+  for (int i=0; i<occ_num_dn; i++) {
+     printf("%d ", orb_list_dn[i]);
+  }
+  printf("\n");
+  */
+
+
+  // close current session
+  rc = trexio_close(file);
+  assert (rc == TREXIO_SUCCESS);
+
+  // free the memory
+  free(det_list_read);
+  free(det_coef_read);
+  free(det_coef_s2_read);
+  free(orb_list_up);
+  free(orb_list_dn);
+
+/*================= END OF TEST ==================*/
+
+  return 0;
+}
+
+
+int main(){
+
+/*============== Test launcher ================*/
+
+  int rc;
+  rc = system(RM_COMMAND);
+  assert (rc == 0);
+
+  // check the first write attempt (SIZE elements written in N_CHUNKS chunks)
+  test_write_determinant (TREXIO_FILE, TEST_BACKEND, 0);
+  test_has_determinant   (TREXIO_FILE, TEST_BACKEND);
+  test_read_determinant  (TREXIO_FILE, TEST_BACKEND, 0);
+
+  // check the second write attempt (SIZE elements written in N_CHUNKS chunks)
+  test_write_determinant (TREXIO_FILE, TEST_BACKEND, SIZE);
+  test_read_determinant  (TREXIO_FILE, TEST_BACKEND, SIZE);
+
+  rc = system(RM_COMMAND);
+  assert (rc == 0);
+
+  return 0;
+}
diff --git a/tests/io_determinant_text.c b/tests/io_determinant_text.c
new file mode 100644
index 00000000..73bcd461
--- /dev/null
+++ b/tests/io_determinant_text.c
@@ -0,0 +1,340 @@
+#include "trexio.h"
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#define TEST_BACKEND  TREXIO_TEXT
+#define TREXIO_FILE   "test_determinant.dir"
+#define RM_COMMAND    "rm -rf " TREXIO_FILE
+#define SIZE          100
+#define N_CHUNKS      5
+#define STATE_TEST    2
+#define MO_NUM        150
+
+static int test_write_determinant (const char* file_name, const back_end_t backend, const int64_t offset) {
+
+/* Try to write an array of sparse data into the TREXIO file */
+
+  trexio_t* file = NULL;
+  trexio_exit_code rc;
+
+/*================= START OF TEST ==================*/
+
+  // open file in 'write' mode
+  file = trexio_open(file_name, 'w', backend, &rc);
+  assert (file != NULL);
+  assert (rc == TREXIO_SUCCESS);
+
+  // parameters to be written
+  int64_t* det_list;
+  double*  det_coef;
+
+  int mo_num = MO_NUM;
+
+  det_list = (int64_t*) calloc(2*3*SIZE, sizeof(int64_t));
+  det_coef = (double*) calloc(SIZE, sizeof(double));
+
+  for(int i=0; i<SIZE; i++){
+    det_list[6*i]   = 6*i;
+    det_list[6*i+1] = 6*i+1;
+    det_list[6*i+2] = 6*i+2;
+    det_list[6*i+3] = 6*i+3;
+    det_list[6*i+4] = 6*i+4;
+    det_list[6*i+5] = 6*i+5;
+    det_coef[i]     = 3.14 + (double) i;
+  }
+
+  // write mo_num which will be used to determine the optimal size of int indices
+  if (trexio_has_mo_num(file) == TREXIO_HAS_NOT) {
+    rc = trexio_write_mo_num(file, mo_num);
+    assert(rc == TREXIO_SUCCESS);
+  }
+
+  // write dataset chunks of sparse data in the file (including FAKE statements)
+  uint64_t chunk_size = (uint64_t) SIZE/N_CHUNKS;
+  uint64_t offset_f = 0UL;
+  uint64_t offset_d = 0UL;
+  if (offset != 0L) offset_f += offset;
+
+  // write n_chunks times using write_sparse
+  for(int i=0; i<N_CHUNKS; ++i){
+
+    rc = trexio_write_determinant_list(file, offset_f, chunk_size, &det_list[6*offset_d]);
+    assert(rc == TREXIO_SUCCESS);
+
+    rc = trexio_write_determinant_coefficient(file, offset_f, chunk_size, &det_coef[offset_d]);
+    assert(rc == TREXIO_SUCCESS);
+
+    // The block below will write the coefficients for STATE_TEST
+    rc = trexio_set_state(file, STATE_TEST);
+    assert(rc == TREXIO_SUCCESS);
+
+    rc = trexio_write_determinant_coefficient(file, offset_f, chunk_size, &det_coef[offset_d]);
+    assert(rc == TREXIO_SUCCESS);
+
+    // set state back to the default 0 (ground state)
+    rc = trexio_set_state(file, 0);
+    assert(rc == TREXIO_SUCCESS);
+    // =================================================
+
+    offset_d += chunk_size;
+    offset_f += chunk_size;
+  }
+
+  // manually check the consistency of the determinant_num and coefficient_size after writing
+  int64_t coeff_size = 0L;
+  int64_t determinant_num = 0L;
+
+  rc = trexio_read_determinant_num_64(file, &determinant_num);
+  assert(rc == TREXIO_SUCCESS);
+
+  rc = trexio_read_determinant_coefficient_size(file, &coeff_size);
+  assert(rc == TREXIO_SUCCESS);
+  assert(determinant_num == coeff_size);
+
+  rc = trexio_set_state(file, STATE_TEST);
+  assert(rc == TREXIO_SUCCESS);
+
+  rc = trexio_read_determinant_coefficient_size(file, &coeff_size);
+  assert(rc == TREXIO_SUCCESS);
+  assert(determinant_num == coeff_size);
+
+  // close current session
+  rc = trexio_close(file);
+  assert (rc == TREXIO_SUCCESS);
+
+  // free the allocated memeory
+  free(det_list);
+  free(det_coef);
+
+/*================= END OF TEST ==================*/
+
+  return 0;
+}
+
+static int test_has_determinant(const char* file_name, const back_end_t backend) {
+
+/* Try to check the existence of a dataset of sparse data in the TREXIO file */
+
+  trexio_t* file = NULL;
+  trexio_exit_code rc;
+
+/*================= START OF TEST ==================*/
+
+  // open file
+  file = trexio_open(file_name, 'r', backend, &rc);
+  assert (file != NULL);
+  assert (rc == TREXIO_SUCCESS);
+
+  // now check that previously written determinant_list exists
+  rc = trexio_has_determinant_list(file);
+  assert(rc==TREXIO_SUCCESS);
+
+  // now check that previously written determinant_coefficient exists
+  rc = trexio_has_determinant_coefficient(file);
+  assert(rc==TREXIO_SUCCESS);
+
+  // also check for STATE_TEST
+  rc = trexio_set_state(file, STATE_TEST);
+  assert(rc == TREXIO_SUCCESS);
+
+  rc = trexio_has_determinant_coefficient(file);
+  assert(rc==TREXIO_SUCCESS);
+
+  rc = trexio_set_state(file, 0);
+  assert(rc == TREXIO_SUCCESS);
+
+  // close current session
+  rc = trexio_close(file);
+  assert (rc == TREXIO_SUCCESS);
+
+/*================= END OF TEST ==================*/
+
+  return 0;
+}
+
+static int test_read_determinant (const char* file_name, const back_end_t backend, const int64_t offset) {
+
+/* Try to read one chunk of dataset of sparse data in the TREXIO file */
+
+  trexio_t* file = NULL;
+  trexio_exit_code rc;
+
+/*================= START OF TEST ==================*/
+
+  // open file
+  file = trexio_open(file_name, 'r', backend, &rc);
+  assert (file != NULL);
+  assert (rc == TREXIO_SUCCESS);
+
+  // compute how many integer bit fields is needed per determinant (for a given spin)
+  int64_t mo_num;
+  rc = trexio_read_mo_num_64(file, &mo_num);
+  assert (rc == TREXIO_SUCCESS);
+  assert (mo_num == MO_NUM);
+
+  int int_num = (mo_num - 1)/64 + 1;
+  assert (int_num == 3);
+
+  // define arrays to read into
+  int64_t* det_list_read;
+  double*  det_coef_read;
+  double*  det_coef_s2_read;
+  double check_diff;
+  uint64_t size_r = 40L;
+
+  det_list_read = (int64_t*) calloc(2*int_num*size_r,sizeof(int64_t));
+  det_coef_read = (double*)  calloc(size_r,sizeof(double));
+  det_coef_s2_read = (double*)  calloc(size_r,sizeof(double));
+
+  // specify the read parameters, here:
+  // 1 chunk of 10 elements using offset of 40 (i.e. lines No. 40--59) into elements of the array starting from 5
+  int64_t chunk_read = 10L;
+  int64_t offset_file_read = 40L;
+  int offset_data_read = 5;
+  int64_t read_size_check;
+  read_size_check = chunk_read;
+
+  if (offset != 0L) offset_file_read += offset;
+
+  // read one chunk using the aforementioned parameters
+  rc = trexio_read_determinant_list(file, offset_file_read, &chunk_read, &det_list_read[2*int_num*offset_data_read]);
+  assert(rc == TREXIO_SUCCESS);
+  assert(chunk_read == read_size_check);
+  assert(det_list_read[0] == 0);
+  assert(det_list_read[2*int_num*offset_data_read] == 2 * int_num * (int64_t) (offset_file_read-offset));
+
+  rc = trexio_read_determinant_coefficient(file, offset_file_read, &chunk_read, &det_coef_read[offset_data_read]);
+  assert(rc == TREXIO_SUCCESS);
+  assert(chunk_read == read_size_check);
+
+  check_diff = det_coef_read[0] - 0.;
+  assert(check_diff*check_diff < 1e-14);
+
+  check_diff = det_coef_read[offset_data_read] - (3.14 + (double) (offset_file_read-offset));
+  //printf("%lf %lf\n", check_diff, det_coef_read[offset_data_read]);
+  assert(check_diff*check_diff < 1e-14);
+
+  // read one chuk of coefficients for a different state
+  rc = trexio_set_state(file, STATE_TEST);
+  assert(rc == TREXIO_SUCCESS);
+
+  rc = trexio_read_determinant_coefficient(file, offset_file_read, &chunk_read, &det_coef_s2_read[offset_data_read]);
+  assert(rc == TREXIO_SUCCESS);
+  assert(chunk_read == read_size_check);
+
+  check_diff = det_coef_s2_read[0] - 0.;
+  assert(check_diff*check_diff < 1e-14);
+
+  rc = trexio_set_state(file, 0);
+  assert(rc == TREXIO_SUCCESS);
+
+  // now attempt to read so that one encounters end of file during reading (i.e. offset_file_read + chunk_read > size_max)
+  offset_file_read = 97L;
+  offset_data_read = 1;
+  int64_t eof_read_size_check = SIZE - offset_file_read; // if offset_file_read=97 => only 3 integrals will be read out of total of 100
+
+  if (offset != 0L) offset_file_read += offset;
+
+  chunk_read = read_size_check;
+  // read one chunk that will reach EOF and return TREXIO_END code
+  rc = trexio_read_determinant_list(file, offset_file_read, &chunk_read, &det_list_read[2*int_num*offset_data_read]);
+  /*
+  printf("%s\n", trexio_string_of_error(rc));
+  for (int i=0; i<size_r; i++) {
+    printf("%lld %lld\n", det_list_read[6*i], det_list_read[6*i+5]);
+  }
+  */
+  assert(rc == TREXIO_END);
+  assert(chunk_read == eof_read_size_check);
+  assert(det_list_read[2*int_num*size_r-1] == 0);
+  assert(det_list_read[2*int_num*offset_data_read] == 2 * int_num * (int64_t) (offset_file_read-offset));
+
+  chunk_read = read_size_check;
+  rc = trexio_read_determinant_coefficient(file, offset_file_read, &chunk_read, &det_coef_read[offset_data_read]);
+  /*
+  printf("%s\n", trexio_string_of_error(rc));
+  for (int i=0; i<size_r; i++) {
+    printf("%lf\n", det_coef_read[i]);
+  }
+  */
+  assert(rc == TREXIO_END);
+  assert(chunk_read == eof_read_size_check);
+
+  check_diff= det_coef_read[size_r-1] - 0.;
+  //printf("%lf %lf\n", check_diff, det_coef_read[size_r-1]);
+  assert(check_diff*check_diff < 1e-14);
+
+  // check the value of determinant_num
+  int32_t det_num = 0;
+  int32_t size_check = SIZE;
+  if (offset != 0L) size_check += offset;
+
+  rc = trexio_read_determinant_num(file, &det_num);
+  assert(rc == TREXIO_SUCCESS);
+  assert(det_num == size_check);
+
+
+  // check conversion of determinants into orbital lists
+  int64_t  size_list = NORB_PER_INT * int_num;
+  int32_t* orb_list_up = (int32_t*) calloc(size_list, sizeof(int32_t));
+  int32_t* orb_list_dn = (int32_t*) calloc(size_list, sizeof(int32_t));
+  int32_t  occ_num_up, occ_num_dn;
+
+  rc = trexio_to_orbital_list_up_dn (int_num, &det_list_read[2*int_num*5], orb_list_up, orb_list_dn, &occ_num_up, &occ_num_dn);
+  assert (rc == TREXIO_SUCCESS);
+  assert (occ_num_up == 14);
+  assert (occ_num_dn == 17);
+  /* // DEBUG printing
+  printf("occ_num_up : %d ; occ_num_dn : %d \n", occ_num_up, occ_num_dn);
+  for (int i=0; i<occ_num_up; i++) {
+     printf("%d ", orb_list_up[i]);
+  }
+  printf("| ");
+  for (int i=0; i<occ_num_dn; i++) {
+     printf("%d ", orb_list_dn[i]);
+  }
+  printf("\n");
+  */
+
+
+  // close current session
+  rc = trexio_close(file);
+  assert (rc == TREXIO_SUCCESS);
+
+  // free the memory
+  free(det_list_read);
+  free(det_coef_read);
+  free(det_coef_s2_read);
+  free(orb_list_up);
+  free(orb_list_dn);
+
+/*================= END OF TEST ==================*/
+
+  return 0;
+}
+
+
+int main(){
+
+/*============== Test launcher ================*/
+
+  int rc;
+  rc = system(RM_COMMAND);
+  assert (rc == 0);
+
+  // check the first write attempt (SIZE elements written in N_CHUNKS chunks)
+  test_write_determinant (TREXIO_FILE, TEST_BACKEND, 0);
+  test_has_determinant   (TREXIO_FILE, TEST_BACKEND);
+  test_read_determinant  (TREXIO_FILE, TEST_BACKEND, 0);
+
+  // check the second write attempt (SIZE elements written in N_CHUNKS chunks)
+  test_write_determinant (TREXIO_FILE, TEST_BACKEND, SIZE);
+  test_read_determinant  (TREXIO_FILE, TEST_BACKEND, SIZE);
+
+  rc = system(RM_COMMAND);
+  assert (rc == 0);
+
+  return 0;
+}
diff --git a/tests/test_f.f90 b/tests/test_f.f90
index 421ed0b8..adc33fd1 100644
--- a/tests/test_f.f90
+++ b/tests/test_f.f90
@@ -55,7 +55,7 @@ subroutine test_write(file_name, back_end)
 
   integer(trexio_exit_code) :: rc = 1
 
-  integer :: num, basis_shell_num
+  integer :: nucleus_num, mo_num, ao_num, basis_shell_num
 
   integer :: basis_nucleus_index(24)
   double precision :: charge(12)
@@ -65,23 +65,37 @@ subroutine test_write(file_name, back_end)
   character(len=:), allocatable :: label(:)
 
   ! sparse data
-  integer(4) :: index_sparse_mo_2e_int_eri(4,100)
-  double precision :: value_sparse_mo_2e_int_eri(100)
+  integer(4) :: index_sparse_ao_2e_int_eri(4,100)
+  double precision :: value_sparse_ao_2e_int_eri(100)
 
-  integer :: i, n_buffers = 5
-  integer(8) :: buf_size, offset
-  buf_size = 100/n_buffers
+  ! determinants
+  integer*8 :: det_list(6, 50)
+  integer*8 :: det_num
 
+  integer :: i, j, n_buffers = 5
+  integer(8) :: buf_size_sparse, buf_size_det, offset
+
+  buf_size_sparse = 100/n_buffers
+  buf_size_det    = 50/n_buffers
+
+  ! fill sparse indices and values
   do i = 1, 100
-    index_sparse_mo_2e_int_eri(1,i) = 4*i   - 3
-    index_sparse_mo_2e_int_eri(2,i) = 4*i+1 - 3
-    index_sparse_mo_2e_int_eri(3,i) = 4*i+2 - 3
-    index_sparse_mo_2e_int_eri(4,i) = 4*i+3 - 3
-    value_sparse_mo_2e_int_eri(i) = 3.14 + float(i)
+    index_sparse_ao_2e_int_eri(1,i) = 4*i   - 3
+    index_sparse_ao_2e_int_eri(2,i) = 4*i+1 - 3
+    index_sparse_ao_2e_int_eri(3,i) = 4*i+2 - 3
+    index_sparse_ao_2e_int_eri(4,i) = 4*i+3 - 3
+    value_sparse_ao_2e_int_eri(i) = 3.14 + float(i)
+  enddo
+
+  ! fill determinant list
+  do i = 1, 50
+    do j = 1, 6
+      det_list(j,i) = 6*i+(j-1) - 5
+    enddo
   enddo
 
   ! parameters to be written
-  num = 12
+  nucleus_num = 12
   charge = (/ 6., 6., 6., 6., 6., 6., 1., 1., 1., 1., 1., 1.  /)
   coord  = reshape( (/ 0.00000000d0,  1.39250319d0 ,  0.00000000d0 , &
                       -1.20594314d0,  0.69625160d0 ,  0.00000000d0 , &
@@ -97,6 +111,10 @@ subroutine test_write(file_name, back_end)
                        0.00000000d0,  2.47304151d0 ,  0.00000000d0 /), &
                        shape(coord) )
 
+  ! the first dimension of det_list (6) corresponds to mo_num=150; adapt the former if the latter is changed
+  mo_num = 150
+  ao_num = 1000
+
   basis_shell_num = 24
   basis_nucleus_index = (/ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24 /)
 
@@ -118,10 +136,13 @@ subroutine test_write(file_name, back_end)
   rc = trexio_has_nucleus_charge(trex_file)
   call trexio_assert(rc, TREXIO_HAS_NOT, 'SUCCESS HAS NOT 2')
 
-  rc = trexio_has_mo_2e_int_eri(trex_file)
+  rc = trexio_has_ao_2e_int_eri(trex_file)
   call trexio_assert(rc, TREXIO_HAS_NOT, 'SUCCESS HAS NOT 3')
 
-  rc = trexio_write_nucleus_num(trex_file, num)
+  rc = trexio_has_determinant_list(trex_file)
+  call trexio_assert(rc, TREXIO_HAS_NOT, 'SUCCESS HAS NOT 4')
+
+  rc = trexio_write_nucleus_num(trex_file, nucleus_num)
   call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS WRITE NUM')
 
   rc = trexio_write_nucleus_charge(trex_file, charge)
@@ -144,19 +165,33 @@ subroutine test_write(file_name, back_end)
   rc = trexio_write_basis_nucleus_index(trex_file, basis_nucleus_index)
   call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS WRITE INDEX')
 
-  ! write mo_num which will be used to determine the optimal size of int indices
+  ! write ao_num which will be used to determine the optimal size of int indices
+  if (trexio_has_ao_num(trex_file) == TREXIO_HAS_NOT) then
+    rc = trexio_write_ao_num(trex_file, ao_num)
+    call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS WRITE AO NUM')
+  endif
+  ! write mo_num which will be used to determine the optimal size of the determinants bit fields
   if (trexio_has_mo_num(trex_file) == TREXIO_HAS_NOT) then
-    rc = trexio_write_mo_num(trex_file, 1000)
+    rc = trexio_write_mo_num(trex_file, mo_num)
     call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS WRITE MO NUM')
   endif
 
+
   offset = 0
   do i = 1,n_buffers
-    rc = trexio_write_mo_2e_int_eri(trex_file, offset, buf_size, &
-	                            index_sparse_mo_2e_int_eri(1,offset+1), &
-				    value_sparse_mo_2e_int_eri(offset+1))
+    rc = trexio_write_ao_2e_int_eri(trex_file, offset, buf_size_sparse, &
+	                                  index_sparse_ao_2e_int_eri(1,offset+1), &
+				                            value_sparse_ao_2e_int_eri(offset+1))
     call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS WRITE SPARSE')
-    offset = offset + buf_size
+    offset = offset + buf_size_sparse
+  enddo
+
+  offset = 0
+  do i = 1,n_buffers
+    rc = trexio_write_determinant_list(trex_file, offset, buf_size_det, &
+	                                     det_list(1,offset+1))
+    call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS WRITE DET LIST')
+    offset = offset + buf_size_det
   enddo
 
   rc = trexio_has_nucleus_num(trex_file)
@@ -165,9 +200,12 @@ subroutine test_write(file_name, back_end)
   rc = trexio_has_nucleus_coord(trex_file)
   call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS HAS 2')
 
-  rc = trexio_has_mo_2e_int_eri(trex_file)
+  rc = trexio_has_ao_2e_int_eri(trex_file)
   call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS HAS 3')
 
+  rc = trexio_has_determinant_list(trex_file)
+  call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS HAS 4')
+
   rc = trexio_close(trex_file)
   call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS CLOSE')
 
@@ -203,8 +241,8 @@ subroutine test_read(file_name, back_end)
   character(len=32) :: sym_str
 
   ! sparse data
-  integer(4) :: index_sparse_mo_2e_int_eri(4,20)
-  double precision :: value_sparse_mo_2e_int_eri(20)
+  integer(4) :: index_sparse_ao_2e_int_eri(4,20)
+  double precision :: value_sparse_ao_2e_int_eri(20)
   integer(8) :: read_buf_size = 10
   integer(8) :: read_buf_size_save = 10
   integer(8) :: offset_read = 40
@@ -213,13 +251,29 @@ subroutine test_read(file_name, back_end)
   integer(8) :: offset_data_eof = 1
   integer(8) :: size_toread = 0
 
+  ! determinant data
+  integer*8 :: det_list(6,50)
+  integer*8 :: read_buf_det_size = 20
+  integer*8 :: offset_det_read = 10
+  integer*8 :: offset_det_data_read = 5
+  integer*8 :: determinant_num
+
+  ! orbital lists
+  integer*4 :: orb_list_up(150)
+  integer*4 :: orb_list_dn(150)
+  integer*4 :: occ_num_up, occ_num_dn
+
   character*(128) :: str
 
   num = 12
   basis_shell_num = 24
 
-  index_sparse_mo_2e_int_eri = 0
-  value_sparse_mo_2e_int_eri = 0.0d0
+  index_sparse_ao_2e_int_eri = 0
+  value_sparse_ao_2e_int_eri = 0.0d0
+
+  det_list = 0_8
+  orb_list_up = 0
+  orb_list_dn = 0
 
 ! ================= START OF TEST ===================== !
 
@@ -289,15 +343,15 @@ subroutine test_read(file_name, back_end)
   endif
 
 
-  rc = trexio_read_mo_2e_int_eri(trex_file, offset_read, read_buf_size, &
-	                         index_sparse_mo_2e_int_eri(1, offset_data_read + 1), &
-			         value_sparse_mo_2e_int_eri(offset_data_read + 1))
+  rc = trexio_read_ao_2e_int_eri(trex_file, offset_read, read_buf_size, &
+	                         index_sparse_ao_2e_int_eri(1, offset_data_read + 1), &
+			         value_sparse_ao_2e_int_eri(offset_data_read + 1))
   !do  i = 1,20
-  !  write(*,*) index_sparse_mo_2e_int_eri(1,i)
+  !  write(*,*) index_sparse_ao_2e_int_eri(1,i)
   !enddo
   call trexio_assert(rc, TREXIO_SUCCESS)
-  if (index_sparse_mo_2e_int_eri(1, 1) == 0 .and. &
-      index_sparse_mo_2e_int_eri(1, offset_data_read + 1) == offset_read*4 + 1) then
+  if (index_sparse_ao_2e_int_eri(1, 1) == 0 .and. &
+      index_sparse_ao_2e_int_eri(1, offset_data_read + 1) == offset_read*4 + 1) then
     write(*,*) 'SUCCESS READ SPARSE DATA'
   else
     print *, 'FAILURE SPARSE DATA CHECK'
@@ -307,17 +361,17 @@ subroutine test_read(file_name, back_end)
 
   ! attempt to read reaching EOF: should return TREXIO_END and
   ! NOT increment the existing values in the buffer (only upd with what has been read)
-  rc = trexio_read_mo_2e_int_eri(trex_file, offset_eof, read_buf_size, &
-	                         index_sparse_mo_2e_int_eri(1, offset_data_eof + 1), &
-			         value_sparse_mo_2e_int_eri(offset_data_eof + 1))
+  rc = trexio_read_ao_2e_int_eri(trex_file, offset_eof, read_buf_size, &
+	                         index_sparse_ao_2e_int_eri(1, offset_data_eof + 1), &
+			         value_sparse_ao_2e_int_eri(offset_data_eof + 1))
   !do  i = 1,20
-  !  write(*,*) index_sparse_mo_2e_int_eri(1,i)
+  !  write(*,*) index_sparse_ao_2e_int_eri(1,i)
   !enddo
   call trexio_assert(rc, TREXIO_END)
   if (read_buf_size == 3 .and. &
-      index_sparse_mo_2e_int_eri(1, 1) == 0 .and. &
-      index_sparse_mo_2e_int_eri(1, offset_data_read + 1) == offset_read*4 + 1 .and. &
-      index_sparse_mo_2e_int_eri(1, offset_data_eof + 1) == offset_eof*4 + 1) then
+      index_sparse_ao_2e_int_eri(1, 1) == 0 .and. &
+      index_sparse_ao_2e_int_eri(1, offset_data_read + 1) == offset_read*4 + 1 .and. &
+      index_sparse_ao_2e_int_eri(1, offset_data_eof + 1) == offset_eof*4 + 1) then
     write(*,*) 'SUCCESS READ SPARSE DATA EOF'
     read_buf_size = read_buf_size_save
   else
@@ -325,7 +379,8 @@ subroutine test_read(file_name, back_end)
     call exit(-1)
   endif
 
-  rc = trexio_read_mo_2e_int_eri_size(trex_file, size_toread)
+  ! read the size (number of integrals) of the sparse dataset
+  rc = trexio_read_ao_2e_int_eri_size(trex_file, size_toread)
   call trexio_assert(rc, TREXIO_SUCCESS)
   if (size_toread == 100) then
     write(*,*) 'SUCCESS READ SPARSE SIZE'
@@ -334,7 +389,45 @@ subroutine test_read(file_name, back_end)
     call exit(-1)
   endif
 
+  ! read a chunk of determinants
+  rc = trexio_read_determinant_list(trex_file, offset_det_read, read_buf_det_size, &
+	                            det_list(1, offset_det_data_read + 1))
+  !do  i = 1,50
+  !  write(*,*) det_list(1,i)
+  !enddo
+  call trexio_assert(rc, TREXIO_SUCCESS)
+  if (det_list(1, 1) == 0 .and. &
+      det_list(1, offset_det_data_read + 1) == offset_det_read*6 + 1) then
+    write(*,*) 'SUCCESS READ DET LIST'
+  else
+    print *, 'FAILURE DET LIST CHECK'
+    call exit(-1)
+  endif
+
+  ! read the total number of stored determinants
+  rc = trexio_read_determinant_num_64(trex_file, determinant_num)
+  call trexio_assert(rc, TREXIO_SUCCESS)
+  if (determinant_num == 50_8) then
+    write(*,*) 'SUCCESS READ DET NUM'
+  else
+    print *, 'FAILURE DET NUM CHECK'
+    call exit(-1)
+  endif
+
+  ! convert one given determinant into lists of orbitals
+  rc = trexio_to_orbital_list_up_dn(3, det_list(:, offset_det_data_read+1), orb_list_up, orb_list_dn, occ_num_up, occ_num_dn)
+  !write(*,*) occ_num_up, occ_num_dn
+  !write(*,*) orb_list_up(1:occ_num_up)
+  !write(*,*) det_list(:, offset_det_data_read+1)
+  call trexio_assert(rc, TREXIO_SUCCESS)
+  if (occ_num_up == 16 .and. occ_num_dn == 5) then
+    write(*,*) 'SUCCESS CONVERT DET LIST'
+  else
+    print *, 'FAILURE DET CONVERT CHECK'
+    call exit(-1)
+  endif
 
+  ! close the file
   rc = trexio_close(trex_file)
   call trexio_assert(rc, TREXIO_SUCCESS)
 
@@ -365,7 +458,7 @@ subroutine test_read_void(file_name, back_end)
   call trexio_assert(rc, TREXIO_OPEN_ERROR)
 
   call trexio_string_of_error(rc, str)
-  print *, trim(str)
+  print *, 'Test error message: ', trim(str)
 
 ! ================= END OF TEST ===================== !