diff --git a/.devel b/.devel new file mode 100644 index 0000000..e69de29 diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 7a23aa0..16ccd6c 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -15,7 +15,7 @@ jobs: get_commit_message: name: Get commit message - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 outputs: message: ${{ steps.commit_message.outputs.message }} steps: @@ -34,8 +34,8 @@ jobs: trexio_ubuntu: - runs-on: ubuntu-latest - name: x86 Ubuntu latest + runs-on: ubuntu-20.04 + name: x86 Ubuntu 20.04 needs: get_commit_message steps: @@ -52,10 +52,10 @@ jobs: ./configure --enable-silent-rules - name: compile TREXIO - run: make -j 2 + run: make -j2 - name: check TREXIO - run: make check + run: make -j2 check - name: create virtual environment run: | @@ -82,13 +82,27 @@ jobs: name: pytrexio-source path: ./trexio-*.tar.gz - - name: clean - run: make clean + - name: maintainer clean + run: make maintainer-clean + + - name: reconfigure with clang and AddressSanitizer + run: | + ./autogen.sh + ./configure CC=clang-11 CFLAGS="-O2 -fsanitize=address -fno-omit-frame-pointer" LDFLAGS="-fsanitize=address" --enable-silent-rules + + - name: recompile TREXIO + run: make -j2 + + - name: recheck TREXIO for memory leaks + run: make -j2 check + + - name: maintainer clean + run: make maintainer-clean trexio_macos: - runs-on: macos-latest - name: x86 MacOS latest + runs-on: macos-11 + name: x86 MacOS 11 steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index f6b8ded..5dbdf19 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -16,7 +16,7 @@ jobs: get_commit_message: if: ${{ github.event.workflow_run.conclusion == 'success' }} name: Get commit message - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 outputs: message: ${{ steps.commit_message.outputs.message }} steps: @@ -39,7 +39,7 @@ jobs: if: >- contains(needs.get_commit_message.outputs.message, '[wheel build]') || (github.repository == 'TREX-CoE/trexio' && startsWith(github.ref, 'refs/tags/v')) - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 strategy: matrix: manylinux_tag: [2010_x86_64, 2014_x86_64, 2_24_x86_64] @@ -152,7 +152,7 @@ jobs: working-directory: python - name: Install Python dependencies - run: pip install --upgrade pip setuptools build delocate + run: pip install --upgrade pip setuptools build delocate pytest - name: Build wheel for a given version of CPython run: | @@ -169,7 +169,7 @@ jobs: working-directory: python - name: Test the wheel - run: python test_api.py + run: pytest -v test_api.py working-directory: python/test - name: Upload produced wheels as artifacts @@ -182,7 +182,7 @@ jobs: publish_wheels: name: Publish all wheels on PyPI needs: [build_linux_wheels, build_macos_wheels] - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 steps: - name: Checkout the branch @@ -222,7 +222,7 @@ jobs: #- name: Publish distribution 📦 to Test PyPI # uses: pypa/gh-action-pypi-publish@master - # with: + # with: # password: ${{ secrets.TEST_PYPI_API_TOKEN }} # repository_url: https://test.pypi.org/legacy/ #verbose: true diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 8cda186..61a06c9 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -20,7 +20,7 @@ jobs: run: sudo apt-get update - name: install dependencies - run: sudo apt-get install emacs26 + run: sudo apt-get install emacs # this step is needed to pull the git submodule org-html-themes #- name: initialize submodules diff --git a/.gitignore b/.gitignore index 0750780..ed98b3a 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,3 @@ trex.json *~ .*.swp /build* -# output of debian build (debuild) -libtrexio-* -libtrexio_* diff --git a/.gitmodules b/.gitmodules index 73629a9..e5fe356 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "python/examples"] path = python/examples - url = git@github.com:TREX-CoE/trexio-tutorials.git + url = https://github.com/TREX-CoE/trexio-tutorials.git [submodule "docs/org-html-themes"] path = docs/org-html-themes - url = git@github.com:fniessen/org-html-themes.git + url = https://github.com/fniessen/org-html-themes.git diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..fd16ba2 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,10 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v3.2.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files diff --git a/CMakeLists.txt b/CMakeLists.txt index faf56bd..ba6f6c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 3.16) # Initialize the CMake project. project(Trexio - VERSION 2.2.0 + VERSION 2.3.0 DESCRIPTION "TREX I/O library" LANGUAGES C Fortran ) @@ -16,7 +16,7 @@ set(CMAKE_C_STANDARD_REQUIRED ON) # Optional configure for developer mode to generate source code from org-mode files. option(TREXIO_DEVEL "TREXIO developer mode (for code generation)." OFF) -if(EXISTS "${CMAKE_SOURCE_DIR}/.git/config") +if(EXISTS "${CMAKE_SOURCE_DIR}/.devel") set(TREXIO_DEVEL ON) find_package(Python3 REQUIRED) if(Python3_FOUND) diff --git a/ChangeLog b/ChangeLog index 1335fa7..9643694 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,35 @@ CHANGES ======= +2.3 +--- + +- Fixed Fortran interface on 32-bit (e.g. i386) architectures +- Changed the structure of the state group +- Sparse data type is patched to work with different dimensions +- Safer cleaning of the output files in TREXIO_TEXT tests +- The global `state` switch is replaced with `state_id` attribute +- Added `float buffered` type for vectors like CI/CSF coefficients +- .git folder is no longer needed to activate TREXIO_DEVEL mode +- Renamed debian folder into helpers-debian +- Added trexio_to_bitfield_list functionality +- Added `trexio_has_group` functionality +- Added OCaml binding +- Added spin and energy in MOs +- Added CSF group +- Added Cholesky-decomposed two-electron integrals +- Added Cholesky-decomposed RDMs for Gammcor +- Added `trexio_flush` functionality +- Optional compilation `--without-fortran` + 2.2 --- +- Added `dim_readonly` data type for read-only dimensions +- Added I/O for the CI determinants (lists and coefficients) in #91 +- Merged local and non-local components of pseudopotential integrals in #89 +- Added QMC components to the format in #89 +- Added debian packaging in #84 - Added support for Python-ic `with` statements - Merged local and non-local pseudopotential integrals in #86 - Fixed backwards incompatibility of the `TREXIO_TEXT` back end in #82 diff --git a/Makefile.am b/Makefile.am index 420a878..c05072d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,7 +34,11 @@ ACLOCAL_AMFLAGS = -I m4 CLEANFILES = trexio.mod +if HAVE_FORTRAN BUILT_SOURCES = trexio.mod +else +BUILT_SOURCES = +endif EXTRA_DIST = .git_hash PACKAGE_VERSION = @PACKAGE_VERSION@ @@ -45,10 +49,13 @@ pkgconfig_DATA = pkgconfig/trexio.pc # =============== BUILD =============== # -trexio_h = $(srcdir)/include/trexio.h -trexio_f = $(srcdir)/include/trexio_f.f90 +trexio_h = include/trexio.h +include_HEADERS = $(trexio_h) -include_HEADERS = $(trexio_h) $(trexio_f) +if HAVE_FORTRAN +trexio_f = include/trexio_f.f90 +include_HEADERS += $(trexio_f) +endif AM_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/include @@ -56,7 +63,6 @@ lib_LTLIBRARIES = src/libtrexio.la SOURCES = \ - $(trexio_h) \ src/trexio.c \ src/trexio_private.h \ src/trexio_s.h \ @@ -75,7 +81,7 @@ ORG_FILES = \ trex.org -src_libtrexio_la_SOURCES = $(SOURCES) +src_libtrexio_la_SOURCES = $(trexio_h) $(SOURCES) # Include CMake-related files in the distribution. EXTRA_DIST += CMakeLists.txt \ @@ -85,25 +91,6 @@ EXTRA_DIST += CMakeLists.txt \ cmake/FindTREXIO.cmake -# Include files needed to produce the debian package. -DEB_FILES = \ - debian/changelog \ - debian/compat \ - debian/control \ - debian/copyright \ - debian/patches \ - debian/README.Debian \ - debian/README.md \ - debian/rules \ - debian/source \ - debian/watch - -EXTRA_DIST += $(DEB_FILES) - -debian_from_dist: $(DEB_FILES) $(SOURCES) $(trexio_h) - cp ../trexio-$(PACKAGE_VERSION).tar.gz ../libtrexio_$(PACKAGE_VERSION).orig.tar.gz - debuild - # =============== TESTS =============== # TESTS_C = \ @@ -112,6 +99,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 +115,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 \ @@ -134,17 +123,20 @@ TESTS_C += \ tests/overwrite_all_hdf5 endif -TESTS_F = \ - tests/test_f +TESTS = $(TESTS_C) + +if HAVE_FORTRAN +TESTS_F = tests/test_f +TESTS += $(TESTS_F) +endif -TESTS = $(TESTS_C) $(TESTS_F) check_PROGRAMS = $(TESTS) # specify common LDADD options for all tests LDADD = src/libtrexio.la -test_trexio_f = $(srcdir)/tests/trexio_f.f90 -CLEANFILES += $(test_trexio_f) +if HAVE_FORTRAN +test_trexio_f = tests/trexio_f.f90 $(test_trexio_f): $(trexio_f) cp $(trexio_f) $(test_trexio_f) @@ -152,10 +144,16 @@ $(test_trexio_f): $(trexio_f) trexio.mod: tests/trexio_f.o tests_test_f_SOURCES = $(test_trexio_f) tests/test_f.f90 +endif clean-local: -rm -rf -- *.dir/ *.h5 __pycache__/ +# =============== GUIX MANIFEST =============== # + +trexio_scm = $(srcdir)/tools/trexio.scm +EXTRA_DIST += $(trexio_scm) + # =============== DOCUMENTATION =============== # HTML_TANGLED = docs/index.html \ @@ -193,9 +191,15 @@ HDF5_CPPFLAGS = @HDF5_CPPFLAGS@ if TREXIO_DEVEL -CLEANFILES += $(SOURCES) $(trexio_f) $(trexio_h) $(HTML_TANGLED) $(htmlizer) .git_hash +CLEANFILES += $(SOURCES) $(trexio_h) $(HTML_TANGLED) $(htmlizer) .git_hash -BUILT_SOURCES += $(SOURCES) $(trexio_f) $(test_trexio_f) +BUILT_SOURCES += $(SOURCES) $(trexio_h) + +if HAVE_FORTRAN +CLEANFILES += $(trexio_f) +BUILT_SOURCES += $(trexio_f) $(test_trexio_f) +$(trexio_f): $(trexio_h) +endif .git_hash: FORCE git log | head -1 | cut -d ' ' -f 2 > .git_hash @@ -205,10 +209,10 @@ all: .git_hash GENERATOR_FILES = $(srcdir)/tools/generator.py \ $(srcdir)/tools/generator_tools.py -$(SOURCES): $(trexio_f) +$(SOURCES): $(trexio_h) src/trexio.c: $(trexio_h) -$(trexio_f): $(ORG_FILES) $(GENERATOR_FILES) +$(trexio_h): $(ORG_FILES) $(GENERATOR_FILES) cd $(srcdir)/tools && ./build_trexio.sh $(htmlizer): $(ORG_FILES) $(srcdir)/src/README.org @@ -225,6 +229,22 @@ cppcheck.out: $(trexio_h) --language=c --std=c99 -rp --platform=unix64 \ -I../include *.c *.h 2>../$@ +################# +# OCaml binding # +################# + +ocaml/trexio/_build/default/lib/trexio.cma: + $(MAKE) -C ocaml/trexio + +ocaml: ocaml/trexio/_build/default/lib/trexio.cma + +ocaml-install: ocaml/trexio/_build/default/lib/trexio.cma + opam install ocaml/trexio + +################## +# Python binding # +################## + setup_py = $(srcdir)/python/setup.py setup_cfg = $(srcdir)/python/setup.cfg pytrexio_py = $(srcdir)/python/pytrexio/pytrexio.py @@ -236,8 +256,9 @@ numpy_i = $(srcdir)/src/numpy.i python-test: $(TEST_PY) - python3 $(TEST_PY) + python3 -m pytest -v $(TEST_PY) $(RM) -r -- __pycache__ + $(RM) -f -- test_file_py.h5 unsafe_test_file_py.h5 python-install: $(pytrexio_py) $(setup_py) $(setup_cfg) cd python && \ @@ -269,12 +290,30 @@ $(numpy_i): check-numpy: cd tools && ./check_numpy_i.sh +# Include files needed to produce the debian package. +DEB_FILES = \ + helpers-debian/changelog \ + helpers-debian/compat \ + helpers-debian/control \ + helpers-debian/copyright \ + helpers-debian/rules \ + helpers-debian/source \ + helpers-debian/libtrexio0.install \ + helpers-debian/libtrexio-dev.install \ + helpers-debian/source \ + helpers-debian/README.source + +debian_from_dist: $(DEB_FILES) $(SOURCES) $(trexio_h) + cp ../trexio-$(PACKAGE_VERSION).tar.gz ../libtrexio_$(PACKAGE_VERSION).orig.tar.gz + debuild + + CLEANFILES += $(pytrexio_c) \ $(pytrexio_py) \ $(trexio_py) \ python/src/*.c \ python/src/*.h -.PHONY: cppcheck python-test python-install python-sdist check-numpy FORCE +.PHONY: cppcheck python-test python-install python-sdist check-numpy FORCE ocaml endif diff --git a/README.md b/README.md index 7a3a26c..9d5c364 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # TREXIO + [![build](https://github.com/TREX-CoE/trexio/actions/workflows/actions.yml/badge.svg)](https://github.com/TREX-CoE/trexio/actions/workflows/actions.yml) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/TREX-CoE/trexio) @@ -9,10 +10,10 @@ TREX library for efficient I/O. ## Minimal requirements (for users): -- Autotools (autoconf >= 2.69, automake >= 1.11, libtool >= 2.2) or CMake (>= 3.16) +- Autotools (autoconf >= 2.69, automake >= 1.11, libtool >= 2.2) or CMake (>= 3.16) - C compiler (gcc/icc/clang) - Fortran compiler (gfortran/ifort) -- HDF5 library (>= 1.8) [optional, recommended for high performance] +- HDF5 library (>= 1.8) [optional, recommended for high performance] ## Installation procedure from the tarball (for users): @@ -34,7 +35,7 @@ TREX library for efficient I/O. - python3 (>= 3.6) - Emacs (>= 26.0) -- SWIG (>= 4.0) +- SWIG (>= 4.0) [required for the Python API] ## Installation procedure from the GitHub repo clone (for developers): @@ -61,6 +62,48 @@ The aforementioned instructions rely on [Autotools](https://www.gnu.org/software **Note: when linking against an MPI-enabled HDF5 library one usually has to specify the MPI wrapper for the C compiler by adding, e.g., `-DCMAKE_C_COMPILER=mpicc` to the `cmake` command.** +## Installation procedure for conda users + +[![Anaconda-Server Badge](https://anaconda.org/conda-forge/trexio/badges/version.svg)](https://anaconda.org/conda-forge/trexio) +[![Anaconda-Server Badge](https://anaconda.org/conda-forge/trexio/badges/platforms.svg)](https://anaconda.org/conda-forge/trexio) + +The official releases of TREXIO `>2.0.0` are also available via the `conda-forge` channel. +The pre-compiled stable binaries of `trexio` can be installed as follows: + +``` +conda install trexio -c conda-forge +``` + +More details can be found in the corresponding [trexio-feedstock](https://github.com/conda-forge/trexio-feedstock). +Note that both parallel (see `mpi_openmpi` prefix) and serial (`nompi`) variants are provided. + +## Installation procedure for Guix users + +The official releases of TREXIO `>=2.0.0` can be installed using the +[GNU Guix](https://guix.gnu.org) functional package manager. +The [trexio.scm](https://github.com/TREX-CoE/trexio/blob/master/tools/trexio.scm) +Schema file contains the manifest specification for the `trexio` package. +It can be installed within the selected `$GUIX_PROFILE` as follows: + +``` +guix package \ + --profile=$GUIX_PROFILE \ + --cores= \ + --install-from-file=trexio.scm +``` + +## Installation procedure for Spack users + +The official releases `>=2.0.0` and the development version of TREXIO can be installed using the +[Spack](https://spack.io/) package manager. +The [trexio/package.py](https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/trexio/package.py) +file contains the Spack specifications required to build different variants of `trexio` library. +It can be installed as follows + +``` +spack install --jobs trexio +``` + ## Compilation without the HDF5 library By default, the configuration step proceeds to search for the [HDF5 library](https://portal.hdfgroup.org/display/HDF5/HDF5). @@ -120,6 +163,24 @@ These quantities can be accessed using the corresponding `trexio_[has|read|write For more details regarding the installation and usage of the TREXIO Python API, see [this page](python/README.md). +The aforementioned instructions are adapted for users installing from the source code distribution (periodically updated). +In order to install the Python API with the latest changes, follow the developer installation guide and run the following command in the end + +``` +make python-install +``` + +**Note: this implies that both HDF5 and SWIG are installed and available. +At the moment, it is not possible to configure the Python API without HDF5 library.** + +We rely on the `pytest` package for unit testing. It can be installed via `pip install pytest`. To test the installation, run + +``` +make python-test +``` + +We highly recommend to use virtual environments to avoid compatibility issues and to improve reproducibility. + ## Tutorial diff --git a/cmake/FindTREXIO.cmake b/cmake/FindTREXIO.cmake index 9c847a3..a2aa9c4 100644 --- a/cmake/FindTREXIO.cmake +++ b/cmake/FindTREXIO.cmake @@ -6,7 +6,7 @@ # TREXIO_INCLUDE_DIRS - The TREXIO include directories; # TREXIO_LIBRARIES - The libraries needed to use TREXIO; -# If TREXIO has been installed in a non-standard location, one can set an +# If TREXIO has been installed in a non-standard location, one can set an # environment variable $TREXIO_DIR in the current shell: # $ export TREXIO_DIR= # to indicate the prefix used during the TREXIO installation @@ -45,13 +45,13 @@ set(TREXIO_SEARCH_PATHS /opt ) -find_path(TREXIO_INCLUDE_DIR - NAMES trexio.h +find_path(TREXIO_INCLUDE_DIR + NAMES trexio.h HINTS $ENV{TREXIO_DIR} PATH_SUFFIXES include/trexio include PATHS ${TREXIO_SEARCH_PATHS} ) - + # No need to specify platform-specific prefix (e.g. libtrexio on Unix) or # suffix (e.g. .so on Unix or .dylib on MacOS) in NAMES. CMake takes care of that. @@ -70,8 +70,8 @@ INCLUDE(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(TREXIO DEFAULT_MSG TREXIO_LIBRARY TREXIO_INCLUDE_DIR ) MARK_AS_ADVANCED(TREXIO_INCLUDE_DIR TREXIO_LIBRARY) -# Mot setting _INCLUDE_DIR and _LIBRARIES is considered a bug, +# Mot setting _INCLUDE_DIR and _LIBRARIES is considered a bug, # see https://gitlab.kitware.com/cmake/community/-/wikis/doc/tutorials/How-To-Find-Libraries set(TREXIO_LIBRARIES ${TREXIO_LIBRARY}) -set(TREXIO_INCLUDE_DIRS ${TREXIO_INCLUDE_DIR}) +set(TREXIO_INCLUDE_DIRS ${TREXIO_INCLUDE_DIR}) diff --git a/configure.ac b/configure.ac index 51cf821..1370fbf 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) -AC_INIT([trexio],[2.2.0],[https://github.com/TREX-CoE/trexio/issues]) +AC_INIT([trexio],[2.3.0],[https://github.com/TREX-CoE/trexio/issues]) AC_CONFIG_SRCDIR([Makefile.in]) AC_CONFIG_HEADERS([include/config.h]) @@ -16,11 +16,11 @@ AM_PROG_AR LT_PREREQ([2.2]) LT_INIT -# Activate developer mode when the source is the git repository. +# Activate developer mode if a dummy file is present (true when cloning the git repository). # Otherwise, it is the source distribution and the developer mode should not be activated. -TEST_IFEXISTS=".git" -AC_CHECK_FILE([$TEST_IFEXISTS], - [enable_maintainer_mode="yes"], +TEST_IFEXISTS=".devel" +AS_IF([test -f $TEST_IFEXISTS], + [enable_maintainer_mode="yes"] ) VERSION_MAJOR=`echo ${PACKAGE_VERSION} | cut -d. -f1` @@ -50,12 +50,18 @@ AS_IF([test "$ac_cv_prog_cc_c99" = "no"], [AC_MSG_ERROR([The compiler does not support C99])]) AC_PROG_CC_C_O -# Fortran -AC_PROG_FC -AC_FC_FREEFORM -AC_FC_SRCEXT([f90]) -AC_PROG_FC_C_O -AC_FC_LIBRARY_LDFLAGS + +# Fortran API [default: --with-fortran], do not disable in the dev mode +AC_ARG_WITH(fortran, [AS_HELP_STRING([--without-fortran],[do not test and install the Fortran API])], ok=$withval, ok=yes) +if test "$ok" = "yes"; then + AC_PROG_FC + AC_FC_FREEFORM + AC_FC_SRCEXT([f90]) + AC_PROG_FC_C_O + AC_FC_LIBRARY_LDFLAGS +fi + +AM_CONDITIONAL([HAVE_FORTRAN],[test "$ok" = "yes"]) # pkg-config PKG_PROG_PKG_CONFIG() @@ -66,6 +72,31 @@ AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_GREP +# Specific options required with some compilers +case $FC in + *gfortran*) + FCFLAGS="$FCFLAGS -fPIC" + ;; + *flang*) + FCFLAGS="$FCFLAGS -fPIC" + ;; + *ifort*) + FCFLAGS="$FCFLAGS -fPIC" + ;; +esac + +case $CC in + *gcc*) + CFLAGS="$CFLAGS -fPIC" + ;; + *clang*) + CFLAGS="$CFLAGS -fPIC" + ;; + *icc*) + CFLAGS="$CFLAGS -fPIC" + ;; +esac + ## --------- ## Libraries @@ -144,7 +175,7 @@ AC_TYPE_UINT32_T AC_TYPE_UINT64_T # Checks for library functions. -AC_FUNC_MALLOC +# AC_FUNC_MALLOC AC_CHECK_FUNCS([memset mkdir strerror]) if test "x$enable_maintainer_mode" == "xyes"; then @@ -153,6 +184,27 @@ else TREXIO_DEVEL="" fi + +AC_ARG_WITH(efence, [AS_HELP_STRING([--with-efence],[use ElectricFence library])], ok=$withval, ok=no) +if test "$ok" = "yes"; then + AC_CHECK_LIB([efence], [malloc]) + ARGS="${ARGS} efence" +fi + +AC_ARG_ENABLE(malloc-trace, [AS_HELP_STRING([--enable-malloc-trace],[use debug malloc/free])], ok=$enableval, ok=no) +if test "$ok" = "yes"; then + AC_DEFINE(MALLOC_TRACE,"malloc_trace.dat",[Define to use debugging malloc/free]) + ARGS="${ARGS} malloc-trace" +fi + +AC_ARG_ENABLE(prof, [AS_HELP_STRING([--enable-prof],[compile for profiling])], ok=$enableval, ok=no) +if test "$ok" = "yes"; then + CFLAGS="${CFLAGS} -pg" + AC_DEFINE(ENABLE_PROF,1,[Define when using the profiler tool]) + ARGS="${ARGS} prof" +fi + + AM_CONDITIONAL([TREXIO_DEVEL],[test "x$TREXIO_DEVEL" != x]) if test "x${TREXIO_DEVEL}" != "x"; then diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index ef0bcce..0000000 --- a/debian/changelog +++ /dev/null @@ -1,5 +0,0 @@ -libtrexio (2.1.0-1) UNRELEASED; urgency=low - - * Initial release. - - -- Evgeny Posenitskiy Wed, 16 Feb 2022 15:07:02 +0100 diff --git a/debian/control b/debian/control deleted file mode 100644 index 1415deb..0000000 --- a/debian/control +++ /dev/null @@ -1,15 +0,0 @@ -Source: libtrexio -Section: science -Priority: optional -Maintainer: Evgeny Posenitskiy -Build-Depends: gfortran, pkg-config, libhdf5-dev, debhelper (>=11~), dh-autoreconf -Standards-Version: 4.1.4 -Homepage: https://trex-coe.github.io/trexio/ - -Package: libtrexio -Architecture: any -Multi-Arch: foreign -Depends: ${misc:Depends}, ${shlibs:Depends} -Description: I/O library for quantum chemistry. - This Debian binary package was auto-generated by the - debmake(1) command provided by the debmake package. diff --git a/debian/rules b/debian/rules deleted file mode 100755 index 0544799..0000000 --- a/debian/rules +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/make -f -# You must remove unused comment lines for the released package. -#export DH_VERBOSE = 1 -#export DEB_BUILD_MAINT_OPTIONS = hardening=+all -#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic -#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed - -%: - dh $@ --with autoreconf diff --git a/examples.org b/examples.org index eaa7d58..241c63e 100644 --- a/examples.org +++ b/examples.org @@ -3,7 +3,8 @@ #+SETUPFILE: docs/theme.setup -* Accessing sparse quantities +* Accessing sparse quantities (integrals) + ** Fortran :PROPERTIES: :header-args: :tangle print_energy.f90 @@ -270,3 +271,83 @@ program print_energy end program #+end_src + + +* Reading determinants + +** Fortran + :PROPERTIES: + :header-args: :tangle print_dets.f90 + :END: + + #+begin_src f90 +program test + + use trexio + implicit none + + character*(128) :: filename ! Name of the input file + integer(trexio_exit_code) :: rc ! Return code for error checking + integer(trexio_t) :: trex_determinant_file ! TREXIO file handle + character*(128) :: err_msg ! Error message + + + integer*8, allocatable :: buffer(:,:,:) + integer(8) :: offset, icount, BUFSIZE + integer :: ndet, int64_num, m + + integer :: occ_num_up, occ_num_dn + integer, allocatable :: orb_list_up(:), orb_list_dn(:) + + call getarg(1, filename) + + trex_determinant_file = trexio_open(filename, 'r', TREXIO_AUTO, rc) + if (rc /= TREXIO_SUCCESS) then + call trexio_string_of_error(rc, err_msg) + print *, 'Error opening TREXIO file: '//trim(err_msg) + stop + end if + + rc = trexio_read_determinant_num(trex_determinant_file, ndet) + if (rc /= TREXIO_SUCCESS) then + call trexio_string_of_error(rc, err_msg) + print *, 'Error reading determinant_num: '//trim(err_msg) + stop + end if + print *, 'ndet', ndet + + rc = trexio_get_int64_num(trex_determinant_file, int64_num) + if (rc /= TREXIO_SUCCESS) then + call trexio_string_of_error(rc, err_msg) + print *, 'Error reading int64_num: '//trim(err_msg) + stop + end if + print *, 'int64_num', int64_num + + BUFSIZE = 1000_8 + allocate(buffer(int64_num, 2, BUFSIZE)) + allocate(orb_list_up(int64_num*64), orb_list_dn(int64_num*64)) + + offset = 0_8 + icount = BUFSIZE + do while (icount == BUFSIZE) + if (offset < ndet) then + rc = trexio_read_determinant_list(trex_determinant_file, offset, icount, buffer) + offset = offset + icount + else + icount = 0 + end if + print *, '---' + do m=1,icount + rc = trexio_to_orbital_list_up_dn(int64_num, buffer(1,1,m), & + orb_list_up, orb_list_dn, occ_num_up, occ_num_dn) + print '(100(I3,X))', (orb_list_up(1:occ_num_up)), (orb_list_dn(1:occ_num_dn)) + print *, '' + end do + end do + + deallocate(buffer, orb_list_dn, orb_list_up) + +end + #+end_src + diff --git a/debian/README.Debian b/helpers-debian/README.Debian similarity index 100% rename from debian/README.Debian rename to helpers-debian/README.Debian diff --git a/debian/README.md b/helpers-debian/README.md similarity index 100% rename from debian/README.md rename to helpers-debian/README.md diff --git a/helpers-debian/README.source b/helpers-debian/README.source new file mode 100644 index 0000000..6af23bb --- /dev/null +++ b/helpers-debian/README.source @@ -0,0 +1,15 @@ +libtrexio for Debian +------------------- + +TREXIO distribution tarballs contain the source code required to build the C +library and the Fortran module based on the ISO_C_BINDING. + +The build system is Autotools and follows the common installation path, i.e. +./autogeh.sh && ./configure && make && make install + +For details about the development version (i.e. compiling from the GitHub +repository clone) contact the upstream maintainers. + + + -- Evgeny Tue, 27 Sep 2022 10:34:39 +0200 + diff --git a/helpers-debian/changelog b/helpers-debian/changelog new file mode 100644 index 0000000..96d2f25 --- /dev/null +++ b/helpers-debian/changelog @@ -0,0 +1,5 @@ +libtrexio (2.2.1-1) UNRELEASED; urgency=medium + + * Initial release (Closes: #1020772) + + -- Evgeny Tue, 27 Sep 2022 10:34:39 +0200 diff --git a/debian/compat b/helpers-debian/compat similarity index 100% rename from debian/compat rename to helpers-debian/compat diff --git a/helpers-debian/control b/helpers-debian/control new file mode 100644 index 0000000..e385b05 --- /dev/null +++ b/helpers-debian/control @@ -0,0 +1,30 @@ +Source: libtrexio +Section: science +Priority: optional +Maintainer: Evgeny +Build-Depends: debhelper-compat (= 12), + gfortran, + pkg-config, + libhdf5-dev +Standards-Version: 4.4.1 +Homepage: https://github.com/TREX-CoE/trexio +#Vcs-Browser: https://salsa.debian.org/debian/libtrexio +#Vcs-Git: https://salsa.debian.org/debian/libtrexio.git + +Package: libtrexio-dev +Section: libdevel +Architecture: any +Multi-Arch: same +Depends: libtrexio0 (= ${binary:Version}), ${misc:Depends} +Description: TREX I/O library for efficient data I/O in quantum chemistry. + . + This package contains the static C library, C headers + and the Fortran modules necessary for developers. + +Package: libtrexio0 +Architecture: any +Multi-Arch: same +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: TREX I/O library for efficient data I/O in quantum chemistry. + . + This package contains the shared C library. diff --git a/debian/copyright b/helpers-debian/copyright similarity index 92% rename from debian/copyright rename to helpers-debian/copyright index 8b5c36a..fbbccef 100644 --- a/debian/copyright +++ b/helpers-debian/copyright @@ -1,11 +1,30 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: libtrexio -Source: -# -# Please double check copyright with the licensecheck(1) command. +Upstream-Contact: Evgeny +Source: + +Files: debian/* +Copyright: 2022 Evgeny +License: GPL-2+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU General + Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". Files: .git_hash AUTHORS + ChangeLog Makefile.am CMakeLists.txt NEWS @@ -35,6 +54,8 @@ Files: .git_hash tests/io_dset_int_text.c tests/io_dset_sparse_hdf5.c tests/io_dset_sparse_text.c + tests/io_determinant_hdf5.c + tests/io_determinant_text.c tests/io_dset_str_hdf5.c tests/io_dset_str_text.c tests/io_num_hdf5.c @@ -47,6 +68,9 @@ Files: .git_hash tests/open_text.c tests/overwrite_all_hdf5.c tests/overwrite_all_text.c + tests/delete_group_hdf5.c + tests/delete_group_text.c + tests/pre_close.c tests/test_f.f90 tests/trexio_f.f90 Copyright: 2020 TREX Center of Excellence @@ -75,9 +99,6 @@ License: BSD-3-Clause CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - . - On Debian systems, the complete text of the BSD 3-clause "New" or "Revised" - License can be found in `/usr/share/common-licenses/BSD'. Files: Makefile.in aclocal.m4 @@ -277,9 +298,6 @@ License: GPL-3.0+ with autoconf exception the same distribution terms that you use for the rest of that program. This Exception is an additional permission under section 7 of the GNU General Public License, version 3 ("GPLv3"). - . - On Debian systems, the complete text of the GNU General Public License - Version 3 can be found in `/usr/share/common-licenses/GPL-3'. Files: m4/ax_pkg_swig.m4 Copyright: 2008 Alan W. Irwin @@ -331,14 +349,11 @@ License: GPL-2.0+ with unknown exception *** check multiple exceptions *** #---------------------------------------------------------------------------- # Files marked as NO_LICENSE_TEXT_FOUND may be covered by the following -# license/copyright files. - #---------------------------------------------------------------------------- # License file: COPYING - BSD 3-Clause License . - Copyright (c) 2021, TREX Center of Excellence - All rights reserved. + Copyright 2020 TREX Center of Excellence + License BSD-3-Clause . Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -364,3 +379,4 @@ License: GPL-2.0+ with unknown exception *** check multiple exceptions *** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/helpers-debian/libtrexio-dev.install b/helpers-debian/libtrexio-dev.install new file mode 100644 index 0000000..b973af4 --- /dev/null +++ b/helpers-debian/libtrexio-dev.install @@ -0,0 +1,4 @@ +usr/include/* +usr/lib/*/lib*.so +usr/lib/*/lib*.a +usr/lib/*/pkgconfig/* diff --git a/helpers-debian/libtrexio0.install b/helpers-debian/libtrexio0.install new file mode 100644 index 0000000..3ddde58 --- /dev/null +++ b/helpers-debian/libtrexio0.install @@ -0,0 +1 @@ +usr/lib/*/lib*.so.* diff --git a/debian/patches/series b/helpers-debian/patches/series similarity index 100% rename from debian/patches/series rename to helpers-debian/patches/series diff --git a/helpers-debian/rules b/helpers-debian/rules new file mode 100755 index 0000000..1a7509a --- /dev/null +++ b/helpers-debian/rules @@ -0,0 +1,21 @@ +#!/usr/bin/make -f + + +# output every command that modifies files on the build system. +#export DH_VERBOSE = 1 + + +# see FEATURE AREAS in dpkg-buildflags(1) +#export DEB_BUILD_MAINT_OPTIONS = hardening=+all + +# see ENVIRONMENT in dpkg-buildflags(1) +# package maintainers to append CFLAGS +#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic +# package maintainers to append LDFLAGS +#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed + + +%: + dh $@ + + diff --git a/debian/source/format b/helpers-debian/source/format similarity index 100% rename from debian/source/format rename to helpers-debian/source/format diff --git a/debian/source/local-options b/helpers-debian/source/local-options similarity index 100% rename from debian/source/local-options rename to helpers-debian/source/local-options diff --git a/debian/watch b/helpers-debian/watch similarity index 100% rename from debian/watch rename to helpers-debian/watch diff --git a/m4/ax_lib_hdf5.m4 b/m4/ax_lib_hdf5.m4 index 074c2a8..86f97fb 100644 --- a/m4/ax_lib_hdf5.m4 +++ b/m4/ax_lib_hdf5.m4 @@ -257,7 +257,7 @@ HDF5 support is being disabled (equivalent to --with-hdf5=no). AC_MSG_WARN([Unable to compile HDF5 test program]) fi dnl Look for HDF5's high level library - AC_HAVE_LIBRARY([hdf5_hl], [HDF5_LIBS="-lhdf5_hl $HDF5_LIBS"], [], []) + AC_CHECK_LIB([hdf5_hl], [main],[HDF5_LIBS="-lhdf5_hl $HDF5_LIBS"], [], []) CC=$ax_lib_hdf5_save_CC CPPFLAGS=$ax_lib_hdf5_save_CPPFLAGS diff --git a/ocaml/trexio/.ocamlinit b/ocaml/trexio/.ocamlinit new file mode 100644 index 0000000..e1a4ac5 --- /dev/null +++ b/ocaml/trexio/.ocamlinit @@ -0,0 +1,3 @@ +#use "topfind";; +open Printf;; + diff --git a/ocaml/trexio/Makefile b/ocaml/trexio/Makefile new file mode 100644 index 0000000..91d0b69 --- /dev/null +++ b/ocaml/trexio/Makefile @@ -0,0 +1,9 @@ +default: sources + dune build + +lib/trexio.ml: ../../trex.json read_json.py src/trexio.ml src/trexio.mli src/trexio_stubs.c + ./read_json.py + +sources: lib/trexio.ml + +.PHONY: sources default diff --git a/ocaml/trexio/README.md b/ocaml/trexio/README.md new file mode 100644 index 0000000..a1bc2fa --- /dev/null +++ b/ocaml/trexio/README.md @@ -0,0 +1,9 @@ +# TREXIO OCaml interface + +## Building the source code + +The hand-written source files are located in the `src` directory. These files contain +the pieces of code that can't be generated automatically. The source code distributed +in the OPAM package is generated by the `read_json.py` script, and is written in files +located in the `lib` directory. + diff --git a/ocaml/trexio/dune-project b/ocaml/trexio/dune-project new file mode 100644 index 0000000..7793cce --- /dev/null +++ b/ocaml/trexio/dune-project @@ -0,0 +1,36 @@ +(lang dune 3.1) + +(name trexio) +(version 2.3.0) + +(generate_opam_files true) + +(source + (github trex-coe/trexio_ocaml)) + +(authors + "Anthony Scemama " + "Evgeny Posenitskiy " +) + +(maintainers + "Anthony Scemama " +) + +(license "BSD-3-Clause") + +(documentation "https://trex-coe.github.io/trexio/") + +(package + (name trexio) + (synopsis "Binding for the TREXIO Input/Output library") + (description "TREXIO is a file format and library for storing wave functions and integrals for quantum chemistry.") + (depends + dune + (dune-configurator :build) + (conf-pkg-config :build)) + (tags + ("Quantum chemistry" "Library")) +) + +; See the complete stanza docs at https://dune.readthedocs.io/en/stable/dune-files.html#dune-project diff --git a/ocaml/trexio/lib/config/discover.ml b/ocaml/trexio/lib/config/discover.ml new file mode 100644 index 0000000..4362729 --- /dev/null +++ b/ocaml/trexio/lib/config/discover.ml @@ -0,0 +1,22 @@ +module C = Configurator.V1 + +let () = +C.main ~name:"trexio" (fun c -> +let default : C.Pkg_config.package_conf = + { libs = ["-ltrexio"] + ; cflags = ["-fPIC"] + } +in +let conf = + match C.Pkg_config.get c with + | None -> default + | Some pc -> + match (C.Pkg_config.query pc ~package:"trexio") with + | None -> default + | Some deps -> deps +in + + +C.Flags.write_sexp "c_flags.sexp" conf.cflags; +C.Flags.write_sexp "c_library_flags.sexp" conf.libs) + diff --git a/ocaml/trexio/lib/config/dune b/ocaml/trexio/lib/config/dune new file mode 100644 index 0000000..187bd5e --- /dev/null +++ b/ocaml/trexio/lib/config/dune @@ -0,0 +1,3 @@ +(executable + (name discover) + (libraries dune-configurator)) diff --git a/ocaml/trexio/lib/dune b/ocaml/trexio/lib/dune new file mode 100644 index 0000000..d2ff260 --- /dev/null +++ b/ocaml/trexio/lib/dune @@ -0,0 +1,19 @@ +(library + (name trexio) + (public_name trexio) + (foreign_stubs + (language c) + (names trexio_stubs) + (flags (:include c_flags.sexp) "-fPIC")) + (c_library_flags (:include c_library_flags.sexp)) +) + +(rule + (targets c_flags.sexp c_library_flags.sexp) + (action (run ./config/discover.exe))) + +(env + (dev + (flags )) + (release + (ocamlopt_flags ))) diff --git a/ocaml/trexio/read_json.py b/ocaml/trexio/read_json.py new file mode 100755 index 0000000..d41bc00 --- /dev/null +++ b/ocaml/trexio/read_json.py @@ -0,0 +1,659 @@ +#!/usr/bin/env python + +import json + +json_file = "../../trex.json" +stubs_file= "trexio_stubs.c" +ml_file = "trexio.ml" +mli_file = ml_file+"i" + +def write_stubs(data): + + with open("src/"+stubs_file,'r') as f: + content = f.readlines() + index = -1 + for i, line in enumerate(content): + if line.startswith("/**** ****/"): + index = i + break + content_pre = ''.join(content[:index]) + content_post = ''.join(content[index:]) + + with open("lib/"+stubs_file,'w') as f: + f.write(content_pre) + + for group in data: + t = """ +CAMLprim value caml_delete_{group}(value file) +{ + CAMLparam1(file); + trexio_exit_code rc = trexio_delete_{group}( File_val(file) ); + if (rc == TREXIO_SUCCESS) { + CAMLreturn ( Val_unit ); + } else { + caml_failwith(trexio_string_of_error(rc)); + } +} + +CAMLprim value caml_has_{group}(value file) +{ + CAMLparam1(file); + trexio_exit_code rc = trexio_has_{group}( File_val(file) ); + if (rc == TREXIO_SUCCESS) { + CAMLreturn ( Val_bool(true) ); + } else { + CAMLreturn ( Val_bool(false) ); + } +} +""" + f.write( t.replace("{group}",group) ) + + for element in data[group]: + t = """ +CAMLprim value caml_has_{group}_{element}(value file) +{ + CAMLparam1(file); + trexio_exit_code rc = trexio_has_{group}_{element}( File_val(file) ); + CAMLreturn ( Val_bool(rc == TREXIO_SUCCESS) ); +} +""" + f.write( t.replace("{group}", group) + .replace("{element}", element) ) + + # Scalar elements + if data[group][element][1] == []: + + if data[group][element][0] in [ "int", "dim", "index" ]: + t = """ +CAMLprim value caml_read_{group}_{element}(value file) +{ + CAMLparam1(file); + int64_t result; + trexio_exit_code rc = trexio_read_{group}_{element}_64( File_val(file), &result ); + if (rc == TREXIO_SUCCESS) { + CAMLreturn ( Val_int(result) ); + } else { + caml_failwith(trexio_string_of_error(rc)); + } +} + +CAMLprim value caml_write_{group}_{element}(value file, value data) +{ + CAMLparam2(file, data); + trexio_exit_code rc = trexio_write_{group}_{element}_64( File_val(file), (int64_t) Int_val(data) ); + if (rc == TREXIO_SUCCESS) { + CAMLreturn ( Val_unit ); + } else { + caml_failwith(trexio_string_of_error(rc)); + } +} +""" + f.write( t.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", data[group][element][0]) ) + + elif data[group][element][0] in [ "float" ]: + t = """ +CAMLprim value caml_read_{group}_{element}(value file) +{ + CAMLparam1(file); + double result; + trexio_exit_code rc = trexio_read_{group}_{element}_64( File_val(file), &result ); + if (rc == TREXIO_SUCCESS) { + CAMLreturn ( caml_copy_double(result) ); + } else { + caml_failwith(trexio_string_of_error(rc)); + } +} + +CAMLprim value caml_write_{group}_{element}(value file, value data) +{ + CAMLparam2(file, data); + trexio_exit_code rc = trexio_write_{group}_{element}_64( File_val(file), (double) Double_val(data) ); + if (rc == TREXIO_SUCCESS) { + CAMLreturn ( Val_unit ); + } else { + caml_failwith(trexio_string_of_error(rc)); + } +} +""" + f.write( t.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", data[group][element][0]) ) + + elif data[group][element][0] in [ "string" ]: + t = """ +CAMLprim value caml_read_{group}_{element}(value file, value max_str_len_in) +{ + CAMLparam2(file, max_str_len_in); + int32_t max_str_len = Int_val(max_str_len_in); + char result[max_str_len]; + trexio_exit_code rc = trexio_read_{group}_{element}( File_val(file), result, max_str_len); + if (rc == TREXIO_SUCCESS) { + CAMLreturn ( caml_copy_string(result) ); + } else { + caml_failwith(trexio_string_of_error(rc)); + } +} + +CAMLprim value caml_write_{group}_{element}(value file, value data) +{ + CAMLparam2(file, data); + const char* val = String_val(data); + trexio_exit_code rc = trexio_write_{group}_{element}( File_val(file), val, (int32_t) strlen(val)); + if (rc == TREXIO_SUCCESS) { + CAMLreturn ( Val_unit ); + } else { + caml_failwith(trexio_string_of_error(rc)); + } +} +""" + f.write( t.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", data[group][element][0]) ) + + if data[group][element][0] in [ "dim readonly" ]: + t = """ +CAMLprim value caml_read_{group}_{element}(value file) +{ + CAMLparam1(file); + int64_t result; + trexio_exit_code rc = trexio_read_{group}_{element}_64( File_val(file), &result ); + if (rc == TREXIO_SUCCESS) { + CAMLreturn ( Val_int(result) ); + } else { + caml_failwith(trexio_string_of_error(rc)); + } +} + +""" + f.write( t.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", data[group][element][0].split()[0]) ) + + # Array elements + else: + + if data[group][element][0] in [ "float" ]: + t = """ +CAMLprim value caml_read_safe_{group}_{element}(value file_in, value size_max_in) +{ + CAMLparam2 ( file_in, size_max_in ); + CAMLlocal1 ( result ); + + trexio_t* file = File_val( file_in ); + int64_t size_max = (int64_t) Int_val(size_max_in); + + double* read_data = (double*) malloc (size_max * sizeof(double)); + trexio_exit_code rc = trexio_read_safe_{group}_{element}_64(file, read_data, size_max); + if (rc != TREXIO_SUCCESS) { + caml_failwith(trexio_string_of_error(rc)); + } + + result = caml_alloc(size_max * Double_wosize, Double_array_tag); + for (size_t i=0 ; i {type}\n" , + "val write_{group}_{element}: trexio_file -> {type} -> unit\n" ] + for i in t: + f.write( i.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", data[group][element][0]) ) + + elif data[group][element][0] in [ "string" ]: + t = [ "val read_{group}_{element} : ?max_str_len:int -> trexio_file -> {type}\n" , + "val write_{group}_{element}: trexio_file -> {type} -> unit\n" ] + for i in t: + f.write( i.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", data[group][element][0]) ) + + elif data[group][element][0] in [ "dim readonly" ]: + t = [ "val read_{group}_{element} : trexio_file -> {type}\n" ] + for i in t: + f.write( i.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", data[group][element][0].split()[0]) ) + + # Arrays + else: + + if data[group][element][0] in [ "int", "float", "dim", "index" ]: + t = [ "val read_safe_{group}_{element} : trexio_file -> int -> {type} array\n" , + "val write_safe_{group}_{element}: trexio_file -> int -> {type} array -> unit\n" + "val read_{group}_{element} : trexio_file -> {type} array\n" , + "val write_{group}_{element}: trexio_file -> {type} array -> unit\n" +] + for i in t: + f.write( i.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", data[group][element][0]) ) + + elif data[group][element][0] in [ "string" ]: + t = [ "val read_safe_{group}_{element} : trexio_file -> int -> int -> {type} array\n" , + "val write_safe_{group}_{element}: trexio_file -> int -> int -> {type} array -> unit\n" + "val read_{group}_{element} : ?max_str_len:int -> trexio_file -> {type} array\n" , + "val write_{group}_{element}: trexio_file -> {type} array -> unit\n" +] + for i in t: + f.write( i.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", data[group][element][0]) ) + + elif data[group][element][0] in [ "float sparse" ]: + size = len(data[group][element][1]) + typ = "(" + "*".join( [ "int" for _ in range(size) ]) + " * float) array" + t = [ "val read_{group}_{element} : trexio_file -> offset:dim -> buffer_size:dim -> {type}\n" , + "val write_{group}_{element} : trexio_file -> offset:dim -> {type} -> unit\n" , + ] + for i in t: + f.write( i.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", typ) ) + + f.write(content_post) + + +def write_ml(data): + + with open("src/"+ml_file,'r') as f: + content = f.readlines() + index = -1 + for i, line in enumerate(content): + if line.startswith("(**** ****)"): + index = i + break + content_pre = ''.join(content[:index]) + content_post = ''.join(content[index:]) + + with open("lib/"+ml_file,'w') as f: + f.write(content_pre) + + for group in data: + t = "external delete_{group}: trexio_file -> unit = \"caml_delete_{group}\"\n" + t += "external has_{group}: trexio_file -> bool = \"caml_has_{group}\"\n" + f.write( t.replace("{group}",group) ) + + for element in data[group]: + t = "external has_{group}_{element}: trexio_file -> bool = \"caml_has_{group}_{element}\"\n" + f.write( t.replace("{group}", group) + .replace("{element}", element) ) + + # Scalar elements + if data[group][element][1] == []: + + if data[group][element][0] in [ "int", "float", "dim", "index" ]: + t = [ "external read_{group}_{element} : trexio_file -> {type} = \"caml_read_{group}_{element}\"\n" , + "external write_{group}_{element}: trexio_file -> {type} -> unit = \"caml_write_{group}_{element}\"\n" ] + for i in t: + f.write( i.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", data[group][element][0]) ) + + if data[group][element][0] in [ "string" ]: + t = [ "external read_{group}_{element}_c : trexio_file -> int -> {type} = \"caml_read_{group}_{element}\"\n" , + "let read_{group}_{element} ?(max_str_len=8192) f = read_{group}_{element}_c f max_str_len\n", + "external write_{group}_{element}: trexio_file -> {type} -> unit = \"caml_write_{group}_{element}\"\n" ] + for i in t: + f.write( i.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", data[group][element][0]) ) + + elif data[group][element][0] in [ "dim readonly" ]: + t = [ "external read_{group}_{element} : trexio_file -> {type} = \"caml_read_{group}_{element}\"\n" ] + for i in t: + f.write( i.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", data[group][element][0].split()[0]) ) + + # Arrays + else: + + if data[group][element][0] in [ "int", "float", "dim", "index" ]: + t = [ "external read_safe_{group}_{element} : trexio_file -> int -> {type} array = \"caml_read_safe_{group}_{element}\"\n" , + "external write_safe_{group}_{element}: trexio_file -> int -> {type} array -> unit = \"caml_write_safe_{group}_{element}\"\n", + "let read_{group}_{element} f = \n let size = 1 in \n"] + t_prime = [] + for dim in data[group][element][1]: + try: # A dimensioning variable + dim_group, dim_element = dim.split('.') + t_prime += [f" let size = size * read_{dim_group}_{dim_element} f in\n"] + except: # Only an integer + t_prime += [f" let size = size * {dim} in\n"] + + t += t_prime + t += [ " read_safe_{group}_{element} f size\n\n" ] + t += [ "let write_{group}_{element} f a = \n let size = 1 in \n"] + t += t_prime + t += [ " write_safe_{group}_{element} f size a\n\n" ] + for i in t: + f.write( i.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", data[group][element][0]) ) + + elif data[group][element][0] in [ "string" ]: + t = [ "external read_safe_{group}_{element} : trexio_file -> int -> int -> {type} array = \"caml_read_safe_{group}_{element}\"\n" , + "external write_safe_{group}_{element}: trexio_file -> int -> int -> {type} array -> unit = \"caml_write_safe_{group}_{element}\"\n", + "let read_{group}_{element} ?(max_str_len=1024) f = \n let size = 1 in \n"] + t_prime = [] + for dim in data[group][element][1]: + try: # A dimensioning variable + dim_group, dim_element = dim.split('.') + t_prime += [f" let size = size * read_{dim_group}_{dim_element} f in\n"] + except: # Only an integer + t_prime += [f" let size = size * {dim} in\n"] + + t += t_prime + t += [ " read_safe_{group}_{element} f size max_str_len\n\n" , + "let write_{group}_{element} f a = \n let size = 1 in \n", + " let max_str_len = Array.map String.length a\n" , + " |> Array.fold_left (fun x y -> if x>y then x else y) 0\n", + " |> (+) 1 in\n" ] + t += t_prime + t += [ " write_safe_{group}_{element} f size max_str_len a\n\n" ] + for i in t: + f.write( i.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", data[group][element][0]) ) + + + elif data[group][element][0] in [ "float sparse" ]: + size = len(data[group][element][1]) + typ = "(" + "*".join( [ "int" for _ in range(size) ]) + " * float) array" + t = [ "external read_{group}_{element} : trexio_file -> offset:dim -> buffer_size:dim -> {type} = \"caml_read_{group}_{element}\"\n" , + "external write_{group}_{element} : trexio_file -> offset:dim -> {type} -> unit = \"caml_write_{group}_{element}\"\n" + ] + for i in t: + f.write( i.replace("{group}", group) + .replace("{element}", element) + .replace("{type}", typ) ) + + f.write(content_post) + + + + +def main(): + + with open(json_file,'r') as f: + data = json.load(f) + for group in data: + for element in data[group]: + if data[group][element][0] == "str": + data[group][element][0] = "string" + + write_ml(data) + write_mli(data) + write_stubs(data) + +if __name__ == "__main__": + main() + diff --git a/ocaml/trexio/src/trexio.ml b/ocaml/trexio/src/trexio.ml new file mode 100644 index 0000000..fd2ea41 --- /dev/null +++ b/ocaml/trexio/src/trexio.ml @@ -0,0 +1,37 @@ + +type trexio_file + +type trexio_exit_code = int + +type trexio_backend = +| HDF5 +| TEXT +| AUTO + +type index = int +type dim = int + +external open_file : string -> char -> trexio_backend -> trexio_file = "caml_open_file" +external close_file : trexio_file -> unit = "caml_close_file" +external inquire_file : string -> bool = "caml_inquire_file" +external set_one_based : trexio_file -> unit = "caml_set_one_based" +external get_state : trexio_file -> int = "caml_get_state" +external set_state : trexio_file -> int -> unit = "caml_set_state" +external info : unit -> unit = "caml_info" + +external to_orbital_list : Int64.t array -> int list = "caml_to_orbital_list" + + +(**** ****) + +external read_determinant_list : trexio_file -> offset:int -> buffer_size:int -> (bytes * bytes) array = "caml_read_determinant_list" +external write_determinant_list : trexio_file -> offset:int -> (bytes * bytes) array -> unit = "caml_write_determinant_list" + +external read_determinant_coefficient : trexio_file -> offset:int -> buffer_size:int -> float array = "caml_read_determinant_coefficient" +external write_determinant_coefficient : trexio_file -> offset:int -> float array -> unit = "caml_write_determinant_coefficient" + + +let to_orbital_list_up_dn (up,dn) = + (to_orbital_list up, to_orbital_list dn) + + diff --git a/ocaml/trexio/src/trexio.mli b/ocaml/trexio/src/trexio.mli new file mode 100644 index 0000000..e86cfd2 --- /dev/null +++ b/ocaml/trexio/src/trexio.mli @@ -0,0 +1,41 @@ +(* +(** Constants *) +val package_version : string +val version_major : int +val version_minor : int +val version_patch : int +val git_hash : string +*) + +(** Open/close *) + +type trexio_file +type trexio_exit_code +type trexio_backend = + | HDF5 + | TEXT + | AUTO + +type index = int +type dim = int + +val open_file : string -> char -> trexio_backend -> trexio_file +val inquire_file : string -> bool +val close_file : trexio_file -> unit +val set_one_based : trexio_file -> unit +val get_state : trexio_file -> int +val set_state : trexio_file -> int -> unit +val info : unit -> unit + +val to_orbital_list : Int64.t array -> int list +val to_orbital_list_up_dn : (Int64.t array)*(Int64.t array) -> (int list)*(int list) + +(**** ****) + +val read_determinant_list : trexio_file -> offset:int -> buffer_size:int -> (bytes * bytes) array +val write_determinant_list : trexio_file -> offset:int -> (bytes * bytes) array -> unit + +val read_determinant_coefficient : trexio_file -> offset:int -> buffer_size:int -> float array +val write_determinant_coefficient : trexio_file -> offset:int -> float array -> unit + + diff --git a/ocaml/trexio/src/trexio_stubs.c b/ocaml/trexio/src/trexio_stubs.c new file mode 100644 index 0000000..d459f82 --- /dev/null +++ b/ocaml/trexio/src/trexio_stubs.c @@ -0,0 +1,268 @@ +#include +#include +#include +#define CAML_NAME_SPACE +#include +#include +#include +#include +#include +#include + +static trexio_t* File_val( value file ) +{ + return *((trexio_t**) Data_abstract_val(file)); +} + + +CAMLprim value caml_open_file(value filename, value mode, value backend) +{ + CAMLparam3(filename, mode, backend); + + trexio_exit_code rc = 0; + value v = caml_alloc(1, Abstract_tag); + + trexio_t* result = trexio_open (String_val(filename), + Int_val(mode), + Int_val(backend), + &rc); + + *((trexio_t **) Data_abstract_val(v)) = result; + + if (rc == TREXIO_SUCCESS) { + CAMLreturn( v ); + } else { + caml_failwith(trexio_string_of_error(rc)); + } +} + + +CAMLprim value caml_close_file(value file) +{ + CAMLparam1(file); + trexio_exit_code rc = trexio_close( File_val(file) ); + if (rc == TREXIO_SUCCESS) { + CAMLreturn ( Val_unit ); + } else { + caml_failwith(trexio_string_of_error(rc)); + } +} + + +CAMLprim value caml_inquire_file(value filename) +{ + CAMLparam1 (filename); + trexio_exit_code rc = trexio_inquire( String_val (filename) ); + CAMLreturn(Val_bool(rc == TREXIO_SUCCESS)); +} + + +CAMLprim value caml_set_one_based(value file) +{ + CAMLparam1(file); + trexio_exit_code rc = trexio_set_one_based( File_val(file) ); + if (rc == TREXIO_SUCCESS) { + CAMLreturn ( Val_unit ); + } else { + caml_failwith(trexio_string_of_error(rc)); + } +} + + +CAMLprim value caml_set_state(value file, value state) +{ + CAMLparam2(file, state); + printf("%d\n", Int_val(state)); + trexio_exit_code rc = trexio_set_state( File_val(file), (int32_t) Int_val(state) ); + if (rc == TREXIO_SUCCESS) { + CAMLreturn ( Val_unit ); + } else { + caml_failwith(trexio_string_of_error(rc)); + } +} + + +CAMLprim value caml_get_state(value file) +{ + CAMLparam1(file); + int32_t result; + trexio_exit_code rc = trexio_get_state( File_val(file), &result ); + if (rc == TREXIO_SUCCESS) { + CAMLreturn ( Val_int(result) ); + } else { + caml_failwith(trexio_string_of_error(rc)); + } +} + + +CAMLprim value caml_info(value unit) +{ + CAMLparam1(unit); + trexio_exit_code rc = trexio_info(); + if (rc == TREXIO_SUCCESS) { + CAMLreturn ( Val_unit ); + } else { + caml_failwith(trexio_string_of_error(rc)); + } +} + + +CAMLprim value caml_to_orbital_list(value bitfield) +{ + CAMLparam1 ( bitfield ); + CAMLlocal2 ( result, cons ); + + int32_t N_int = Wosize_val(bitfield); + bitfield_t* d1 = (bitfield_t*) malloc (N_int * sizeof(bitfield_t)); + for (int i=0 ; i= 0 ; --i) { + cons = caml_alloc(2, 0); + Store_field(cons, 0, Val_int(list[i])); // head + Store_field(cons, 1, result); // head + result = cons; + } + + free(list); + CAMLreturn(result); +} + + +/**** ****/ + +CAMLprim value caml_read_determinant_list(value file_in, value offset_in, value buffer_size_in) +{ + CAMLparam3 ( file_in, offset_in, buffer_size_in ); + CAMLlocal4 ( result, detup, detdn, det ); + + trexio_t* file = File_val(file_in); + int64_t offset = Int_val( offset_in ); + int64_t buffer_size = Int_val( buffer_size_in ); + + int32_t int_num = 0; + trexio_exit_code rc = trexio_get_int64_num(file, &int_num); + if (rc != TREXIO_SUCCESS) { + caml_failwith(trexio_string_of_error(rc)); + } + + int64_t* buffer = (int64_t*) malloc ( buffer_size * int_num * 2 * sizeof(int64_t) ); + + rc = trexio_read_determinant_list (file, offset, &buffer_size, buffer); + if (rc != TREXIO_SUCCESS) { + caml_failwith(trexio_string_of_error(rc)); + } + + result = caml_alloc(buffer_size, 0); + size_t icount = 0; + for (size_t i=0 ; i= 3.6) -- numpy (>= 1.17.3) - +- numpy (>= 1.17.3) ## Installation from PyPI @@ -31,10 +30,11 @@ For more details, see the corresponding part of the [Python documentation](https ## Additional requirements (for installation from source) -- C compiler (gcc/icc/clang) +- C compiler (gcc/icc/clang) - HDF5 library (>= 1.8) - pkgconfig (Python package) - build (Python package) +- pytest (Python package) ## Installation from source @@ -44,10 +44,10 @@ For more details, see the corresponding part of the [Python documentation](https 4. `pip install -r requirements.txt` (this installs all required python dependencies) 5. Export custom environment variables needed for the installation following the procedure below and replacing `/path/to/hdf5/` with your paths. The following two steps can be skipped if HDF5 is properly configured for `pkg-config` (i.e. if executing `pkg-config --libs hdf5` returns a list of options). - 1. `export H5_CFLAGS=-I/path/to/hdf5/include` - 2. `export H5_LDFLAGS=-L/path/to/hdf5/lib` + - `export H5_CFLAGS=-I/path/to/hdf5/include` + - `export H5_LDFLAGS=-L/path/to/hdf5/lib` 6. `pip install .` (this installs `trexio` in your environment) -7. `cd test && python test_api.py` (this executes several tests that verify the installation) +7. `cd test && python -m pytest -v test_api.py` (this executes several tests that verify the installation) You are ready to go! diff --git a/python/build_manylinux_wheels.sh b/python/build_manylinux_wheels.sh index 85705e0..d6fc96f 100755 --- a/python/build_manylinux_wheels.sh +++ b/python/build_manylinux_wheels.sh @@ -82,11 +82,14 @@ function build_wheel_for_py() # install the produced manylinux wheel in the virtual environment python3 -m pip install wheelhouse/trexio-${TR_VERSION}-${CPYTHON}-manylinux*.whl + # install pytest for testing + pip install pytest # run test script - cd test && python3 test_api.py && cd .. + pytest -v test/test_api.py # cleaning - rm -rf -- dist/ build/ trexio.egg-info/ + rm -rf -- dist/ build/ trexio.egg-info/ + rm -- test_file_py.h5 unsafe_test_file_py.h5 # deactivate the current environment deactivate diff --git a/python/install_pytrexio.sh b/python/install_pytrexio.sh index 764bc85..8542874 100755 --- a/python/install_pytrexio.sh +++ b/python/install_pytrexio.sh @@ -28,6 +28,7 @@ fi # Install/upgrade packages required for the installation python3 -m pip install --upgrade setuptools build pip python3 -m pip install -r requirements.txt +python3 -m pip install pytest # export NUMPY_INCLUDEDIR environment variable needed for the proper setup #source tools/set_NUMPY_INCLUDEDIR.sh diff --git a/python/pytrexio/_version.py b/python/pytrexio/_version.py index c68196d..67bc602 100644 --- a/python/pytrexio/_version.py +++ b/python/pytrexio/_version.py @@ -1 +1 @@ -__version__ = "1.2.0" +__version__ = "1.3.0" diff --git a/python/setup.py b/python/setup.py index 2348038..aaba434 100644 --- a/python/setup.py +++ b/python/setup.py @@ -9,7 +9,7 @@ from setuptools import setup, Extension 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,12 @@ pytrexio_module = Extension('pytrexio._pytrexio', 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 = [ + '-std=c99', + '-Wno-discarded-qualifiers', + '-Wno-unused-variable', + '-Wno-unused-but-set-variable' + ], extra_link_args = [h5_ldflags] ) diff --git a/python/test/benzene_data.py b/python/test/benzene_data.py new file mode 100644 index 0000000..d64f917 --- /dev/null +++ b/python/test/benzene_data.py @@ -0,0 +1,49 @@ + +# for the nucleus group +nucleus_num = 12 + +point_group = 'D6h' + +nucleus_label = ['C', 'C', 'C', 'C', 'C', 'C', 'H', 'H', 'H', 'H', 'H', 'H'] + +nucleus_charge = [6., 6., 6., 6., 6., 6., 1., 1., 1., 1., 1., 1.] + +nucleus_coord = [ +[ 0.00000000 , 1.39250319 , 0.00000000 ], +[-1.20594314 , 0.69625160 , 0.00000000 ], +[-1.20594314 , -0.69625160 , 0.00000000 ], +[ 0.00000000 , -1.39250319 , 0.00000000 ], +[ 1.20594314 , -0.69625160 , 0.00000000 ], +[ 1.20594314 , 0.69625160 , 0.00000000 ], +[-2.14171677 , 1.23652075 , 0.00000000 ], +[-2.14171677 , -1.23652075 , 0.00000000 ], +[ 0.00000000 , -2.47304151 , 0.00000000 ], +[ 2.14171677 , -1.23652075 , 0.00000000 ], +[ 2.14171677 , 1.23652075 , 0.00000000 ], +[ 0.00000000 , 2.47304151 , 0.00000000 ], +] + +# for the basis_nucleus_index +basis_shell_num = 24 +nucleus_index = [i for i in range(basis_shell_num)] + +# for sparse AO_INT_2E +ao_num = 600 +# prepare the sparse data representation +num_integrals = 100 +indices = [i for i in range(num_integrals*4)] +values = [(3.14 + float(i)) for i in range(num_integrals)] + +# for determinants +mo_num = 150 +int64_num = int((mo_num - 1)/64 + 1) +# prepate the CI data +det_num = 2000 +dets = [i for i in range(det_num * int64_num * 2)] +coeffs = [float(i/det_num) for i in range(det_num)] +coeffs_s2 = [float(i*2/det_num) for i in range(det_num)] + +det_test = [1, 2, 3, 2, 1, 3] + +orb_up_test = [0, 65, 128, 129] +orb_dn_test = [1, 64, 128, 129] diff --git a/python/test/test_api.py b/python/test/test_api.py index e347c35..4dff3f6 100644 --- a/python/test/test_api.py +++ b/python/test/test_api.py @@ -1,325 +1,337 @@ #!/usr/bin/env python3 -import os -import shutil import numpy as np - +import pytest import trexio +from benzene_data import * -#=========================================================# -#======== SETUP THE BACK END AND OUTPUT FILE NAME ========# -#=========================================================# - -# 0: TREXIO_HDF5 ; 1: TREXIO_TEXT -TEST_TREXIO_BACKEND = 0 -OUTPUT_FILENAME_TEXT = 'test_py_swig.dir' -OUTPUT_FILENAME_HDF5 = 'test_py_swig.h5' - - -# define TREXIO file name -if TEST_TREXIO_BACKEND == trexio.TREXIO_HDF5: - output_filename = OUTPUT_FILENAME_HDF5 -elif TEST_TREXIO_BACKEND == trexio.TREXIO_TEXT: - output_filename = OUTPUT_FILENAME_TEXT -else: - raise ValueError ('Specify one of the supported back ends as TEST_TREXIO_BACKEND') - - -# remove TREXIO file if exists in the current directory -try: - if TEST_TREXIO_BACKEND == trexio.TREXIO_HDF5: - os.remove(output_filename) - elif TEST_TREXIO_BACKEND == trexio.TREXIO_TEXT: - shutil.rmtree(output_filename) -except: - print('Nothing to remove.') -#=========================================================# -#============ WRITE THE DATA IN THE TEST FILE ============# -#=========================================================# +FILENAME = 'test_file_py.h5' +BACK_END = trexio.TREXIO_HDF5 -trexio.info() +def clean(): + """Remove test files.""" + import os -# test with ... as ... block -with trexio.File(output_filename, mode='w', back_end=TEST_TREXIO_BACKEND) as tfile: - trexio.write_metadata_description(tfile, "Test file produced by the Python API") - assert trexio.has_metadata_description(tfile) - assert tfile.isOpen - -# the file handle can remain existing but the file itself is closed upon exit from the `with` block -assert not tfile.isOpen - - -# create TREXIO file and open it for writing -test_file = trexio.File(output_filename, mode='w', back_end=TEST_TREXIO_BACKEND) -assert test_file.exists - -# Print docstring of the trexio.open function -#print(trexio.open.__doc__) - -nucleus_num = 12 - -try: - trexio.write_nucleus_num(test_file, -100) -except trexio.Error: - print("Raise error for an attempt to write negative nucleus_num: checked.") - -# write nucleus_num in the file -try: - trexio.write_nucleus_num(test_file, nucleus_num) -except: - raise - -try: - trexio.write_nucleus_num(test_file, nucleus_num*2) -except trexio.Error: - print("Raise error for an attempt to overwrite nucleus_num: checked.") + try: + os.remove(FILENAME) + os.remove('unsafe_' + FILENAME) + except FileNotFoundError: + pass -# initialize charge arrays as a list and convert it to numpy array -charges = [6., 6., 6., 6., 6., 6., 1., 1., 1., 1., 1., 1.] -#charges_np = np.array(charges, dtype=np.float32) -charges_np = np.array(charges, dtype=np.int32) - -# function call below works with both lists and numpy arrays, dimension needed for memory-safety is derived -# from the size of the list/array by SWIG using typemaps from numpy.i -trexio.write_nucleus_charge(test_file, charges_np) - -basis_shell_num = 24 -# initialize arrays of nuclear indices as a list and convert it to numpy array -indices = [i for i in range(basis_shell_num)] -# type cast is important here because by default numpy transforms a list of integers into int64 array -indices_np = np.array(indices, dtype=np.int64) - -# first write basis_shell_num because it is needed to check dimensions of basis_nucleus_index in TREXIO >= 2.0.0 -trexio.write_basis_shell_num(test_file, basis_shell_num) - -# function call below works with both lists and numpy arrays, dimension needed for memory-safety is derived -# from the size of the list/array by SWIG using typemacs from numpy.i -trexio.write_basis_nucleus_index(test_file, indices_np) - -# initialize a list of nuclear coordinates -coords = [ - [ 0.00000000 , 1.39250319 , 0.00000000 ], - [-1.20594314 , 0.69625160 , 0.00000000 ], - [-1.20594314 , -0.69625160 , 0.00000000 ], - [ 0.00000000 , -1.39250319 , 0.00000000 ], - [ 1.20594314 , -0.69625160 , 0.00000000 ], - [ 1.20594314 , 0.69625160 , 0.00000000 ], - [-2.14171677 , 1.23652075 , 0.00000000 ], - [-2.14171677 , -1.23652075 , 0.00000000 ], - [ 0.00000000 , -2.47304151 , 0.00000000 ], - [ 2.14171677 , -1.23652075 , 0.00000000 ], - [ 2.14171677 , 1.23652075 , 0.00000000 ], - [ 0.00000000 , 2.47304151 , 0.00000000 ], - ] - -# write coordinates in the file -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 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) - - -# write nucleus_point_group in the file -point_group = 'B3U' - -trexio.write_nucleus_point_group(test_file, point_group) - - -# write nucleus_label in the file -labels = [ - 'C', - 'C', - 'C', - 'C', - 'C', - 'C', - 'H', - 'H', - 'H', - 'H', - 'H', - 'H'] - -trexio.write_nucleus_label(test_file,labels) - -# close TREXIO file -# this call is no longer needed as we introduced TREXIO_File class which has a desctructor that closes the file -#trexio.close(test_file) -# without calling destructor on test_file the TREXIO_FILE is not getting created and the data is not written when using TEXT back end. -# This, the user still has to explicitly call destructor on test_file object instead of the trexio.close function. -# This is only an issue when the data is getting written and read in the same session (e.g. in Jupyter notebook) -del test_file - - -#==========================================================# -#========== DELETE THE GROUP FROM THE TEST FILE ===========# -#==========================================================# - -unsafe_file = trexio.File(output_filename, 'u', TEST_TREXIO_BACKEND) - -# overwrite existing data (only allowed in 'u' - unsafe mode) -trexio.write_nucleus_num(unsafe_file, nucleus_num) -trexio.write_nucleus_charge(unsafe_file, charges_np) -trexio.write_nucleus_coord(unsafe_file, coords) -trexio.write_nucleus_label(unsafe_file,labels) -trexio.write_nucleus_point_group(unsafe_file, point_group) - -print("Overwriting the data in UNSAFE mode: checked") - -# delete existing group (only allowed in 'u' - unsafe mode) -trexio.delete_nucleus(unsafe_file) - -assert not trexio.has_nucleus_num(unsafe_file) -assert not trexio.has_nucleus_charge(unsafe_file) -assert not trexio.has_nucleus_coord(unsafe_file) -assert not trexio.has_nucleus_label(unsafe_file) -assert not trexio.has_nucleus_point_group(unsafe_file) - -print("Deleting nucleus group in UNSAFE mode: checked") - -# restore the deleted data -trexio.write_nucleus_num(unsafe_file, nucleus_num) -trexio.write_nucleus_charge(unsafe_file, charges_np) -trexio.write_nucleus_coord(unsafe_file, coords) -trexio.write_nucleus_label(unsafe_file,labels) -trexio.write_nucleus_point_group(unsafe_file, point_group) - -del unsafe_file - -#==========================================================# -#============ READ THE DATA FROM THE TEST FILE ============# -#==========================================================# - -# open previously created TREXIO file, now in 'read' mode -test_file2 = trexio.File(output_filename, 'r', trexio.TREXIO_AUTO) -assert test_file2.exists - -# check for existence of some of the previously written variables -assert trexio.has_nucleus_num(test_file2) -assert trexio.has_nucleus_charge(test_file2) -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) - -# read nucleus_num from file -rnum = trexio.read_nucleus_num(test_file2) -assert rnum==nucleus_num - -# safe call to read_nucleus_charge array of float values -rcharges_np = trexio.read_nucleus_charge(test_file2, dim=nucleus_num) -assert rcharges_np.dtype is np.dtype(np.float64) -np.testing.assert_array_almost_equal(rcharges_np, charges_np, decimal=8) - -# unsafe call to read_safe should fail with error message corresponding to TREXIO_UNSAFE_ARRAY_DIM -try: - rcharges_fail = trexio.read_nucleus_charge(test_file2, dim=nucleus_num*5) -except trexio.Error: - print("Unsafe call to safe API: checked") - -# safe call to read array of int values (nuclear indices) -rindices_np_16 = trexio.read_basis_nucleus_index(test_file2, dim=basis_shell_num, dtype=np.int16) -assert rindices_np_16.dtype is np.dtype(np.int16) -for i in range(basis_shell_num): - assert rindices_np_16[i]==indices_np[i] - -rindices_np_32 = trexio.read_basis_nucleus_index(test_file2, dim=basis_shell_num, dtype=np.int32) -assert rindices_np_32.dtype is np.dtype(np.int32) -for i in range(basis_shell_num): - assert rindices_np_32[i]==indices_np[i] - -rindices_np_64 = trexio.read_basis_nucleus_index(test_file2) -assert rindices_np_64.dtype is np.dtype(np.int64) -assert rindices_np_64.size==basis_shell_num -for i in range(basis_shell_num): - assert rindices_np_64[i]==indices_np[i] - -# read nuclear coordinates without providing optional argument dim -rcoords_np = trexio.read_nucleus_coord(test_file2) - -assert rcoords_np.size==nucleus_num*3 -np.testing.assert_array_almost_equal(rcoords_np, np.array(coords).reshape(nucleus_num,3), decimal=8) - -# set doReshape to False to get a flat 1D array (e.g. when reading matrices like nuclear coordinates) -#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 - -# read sparse arrays on mo_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) -print(f'First complete sparse read size: {read_buf_size}') -#print(indices_sparse_np) -assert not eof -assert read_buf_size==buf_size -assert indices_sparse_np[0][0]==0 -assert indices_sparse_np[read_buf_size-1][3]==read_buf_size*4-1 -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) -print(f'Second incomplete sparse read size: {read_buf_size}') -#print(indices_sparse_np) -assert eof2 -assert read_buf_size==(num_integrals - buf_size) -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 array of nuclear labels -rlabels_2d = trexio.read_nucleus_label(test_file2, dim=nucleus_num) -print(rlabels_2d) -for i in range(nucleus_num): - assert rlabels_2d[i]==labels[i] - -# read a string corresponding to nuclear point group -rpoint_group = trexio.read_nucleus_point_group(test_file2) -assert rpoint_group==point_group - -# another way to read only if the variable exists -if trexio.has_ao_num(test_file2): - rao_num = trexio.read_ao_num(test_file2) -else: - print("Pass on reading the non-existing variable ao_num: checked") - -# close TREXIO file -#trexio.close(test_file2) - -# cleaning (remove the TREXIO file) -try: - if TEST_TREXIO_BACKEND == trexio.TREXIO_HDF5: - os.remove(output_filename) - elif TEST_TREXIO_BACKEND == trexio.TREXIO_TEXT: - shutil.rmtree(output_filename) -except: - print(f'No output file {output_filename} has been produced') - -#==========================================================# - -#==========================================================# -#======= OPEN NON-EXISTING FILE TO TEST TREXIO.OPEN =======# -#==========================================================# - -try: - void_file = trexio.File('non_existing.file', 'r', TEST_TREXIO_BACKEND) -except trexio.Error as e: - if e.error == trexio.TREXIO_OPEN_ERROR: - print("Opening non-existing file returns TREXIO_OPEN_ERROR: checked") - else: - raise ValueError("[DEV]: error handling of trexio_open function has changed; check the consistency") - -#==========================================================# + +def test_info(): + """Print the output of the trexio.info function.""" + trexio.info() + + +def test_void(): + """Check raise of an error upon I/O on non-existing file.""" + with pytest.raises(trexio.Error): + _ = trexio.File('void.file', 'r', BACK_END) + + +def test_orbital_list(): + """Convert one determinant into a list of orbitals.""" + orb_list_up, orb_list_dn = trexio.to_orbital_list_up_dn(int64_num, det_test) + assert orb_list_up[0] == 0 + assert orb_list_dn[0] == 1 + + +def test_bitfield_list(): + """Convert lists of occupied up- and down-spin orbitals into determinants.""" + # convert det_test list into a numpy array for .all() assertion to work + det_test_np = np.array(det_test, dtype=np.int64) + + det_list_up = trexio.to_bitfield_list(int64_num, orb_up_test) + assert (det_list_up == det_test_np[:int64_num]).all() + det_list_dn = trexio.to_bitfield_list(int64_num, orb_dn_test) + assert (det_list_dn == det_test_np[int64_num:]).all() + + +class TestIO: + """Unit tests for writing/reading different blocks of the TREXIO file.""" + + filename = FILENAME + back_end = BACK_END + mode = 'w' + test_file = None + + clean() + + + def __del__(self): + if self.test_file: + if self.test_file.isOpen: + self.test_file.close() + + + def open(self, filename=None, mode=None, back_end=None): + """Create a TREXIO file and open it for writing.""" + if not filename: + filename = self.filename + else: + self.filename = filename + if not mode: + mode = self.mode + else: + self.mode = mode + if not back_end: + back_end = self.back_end + else: + self.back_end = back_end + + self.test_file = trexio.File(filename, mode, back_end) + assert self.test_file.exists + + + def test_close(self): + """Close the file.""" + self.open() + if self.test_file.isOpen: + self.test_file.close() + assert not self.test_file.isOpen + + + def test_errors(self): + """Test some exceptions based on trexio.Error class.""" + self.open(filename='unsafe_' + self.filename, mode='w', back_end=self.back_end) + # try to write a negative number (should raise an error) + with pytest.raises(trexio.Error): + trexio.write_nucleus_num(self.test_file, -100) + + trexio.write_nucleus_num(self.test_file, nucleus_num) + + # try to overwrite a number (should raise an error) + with pytest.raises(trexio.Error): + trexio.write_nucleus_num(self.test_file, nucleus_num * 2) + + + def test_num(self): + """Write a number.""" + self.open() + trexio.write_nucleus_num(self.test_file, nucleus_num) + assert trexio.has_nucleus_num(self.test_file) + + + def test_str(self): + """Write a string.""" + self.open() + trexio.write_nucleus_point_group(self.test_file, point_group) + assert trexio.has_nucleus_point_group(self.test_file) + + + def test_array_str(self): + """Write an array of strings.""" + self.open() + if not trexio.has_nucleus_num(self.test_file): + self.test_num() + trexio.write_nucleus_label(self.test_file, nucleus_label) + assert trexio.has_nucleus_label(self.test_file) + + + def test_array_1D(self): + """Write array of charges.""" + self.open() + if not trexio.has_nucleus_num(self.test_file): + self.test_num() + trexio.write_nucleus_charge(self.test_file, nucleus_charge) + assert trexio.has_nucleus_charge(self.test_file) + + + def test_array_2D(self): + """Write array of coordinates.""" + self.open() + if not trexio.has_nucleus_num(self.test_file): + self.test_num() + trexio.write_nucleus_coord(self.test_file, nucleus_coord) + assert trexio.has_nucleus_coord(self.test_file) + + + def test_indices(self): + """Write array of indices.""" + self.open() + # type cast is important here because by default numpy transforms a list of integers into int64 array + indices_np = np.array(nucleus_index, dtype=np.int64) + # first write basis_shell_num because it is needed to check dimensions of basis_nucleus_index + trexio.write_basis_shell_num(self.test_file, basis_shell_num) + # now write the indices + trexio.write_basis_nucleus_index(self.test_file, indices_np) + assert trexio.has_basis_nucleus_index(self.test_file) + + + def test_sparse(self): + """Write a sparse array.""" + self.open() + # write ao_num (needed later to write sparse ao_2e_int_eri integrals) + trexio.write_ao_num(self.test_file, ao_num) + # one complete write (no chunking) + offset = 0 + trexio.write_ao_2e_int_eri(self.test_file, offset, num_integrals, indices, values) + assert trexio.has_ao_2e_int_eri(self.test_file) + + + def test_determinant(self): + """Write CI determinants and coefficients.""" + self.open() + # write mo_num (needed later to write determinants) + trexio.write_mo_num(self.test_file, mo_num) + # get the number of bit-strings per spin component + int_num = trexio.get_int64_num(self.test_file) + assert int_num == int64_num + # write the data for the ground state + offset = 0 + trexio.write_state_id(self.test_file, 0) + trexio.write_determinant_list(self.test_file, offset, det_num, dets) + assert trexio.has_determinant_list(self.test_file) + trexio.write_determinant_coefficient(self.test_file, offset, det_num, coeffs) + assert trexio.has_determinant_coefficient(self.test_file) + # manually check the consistency between coefficient_size and number of determinants + assert trexio.read_determinant_coefficient_size(self.test_file) == trexio.read_determinant_num(self.test_file) + + + def test_delete_group(self): + """Delete a group.""" + self.open(filename='unsafe_' + self.filename, mode='u', back_end=self.back_end) + + self.test_num() + self.test_array_1D() + self.test_array_2D() + + assert trexio.has_nucleus(self.test_file) + + trexio.delete_nucleus(self.test_file) + + assert not trexio.has_nucleus_num(self.test_file) + assert not trexio.has_nucleus_charge(self.test_file) + assert not trexio.has_nucleus_coord(self.test_file) + assert not trexio.has_nucleus(self.test_file) + + + def test_has_group(self): + """Check existense of a group.""" + self.open() + assert trexio.has_nucleus(self.test_file) + assert not trexio.has_rdm(self.test_file) + + + def test_context_manager(self): + """Test the with ... as ... context handling.""" + with trexio.File(filename=self.filename, mode='u', back_end=self.back_end) as tfile: + trexio.write_metadata_description(tfile, 'Test file produced by the Python API') + assert trexio.has_metadata_description(tfile) + assert tfile.isOpen + # the file handle can remain existing but the file itself is closed upon exit from the `with` block + assert not tfile.isOpen + + + def test_read_num(self): + """Read a number.""" + self.open(mode='r') + num_r = trexio.read_nucleus_num(self.test_file) + assert num_r == nucleus_num + + + def test_read_array_1D(self): + """Read an array.""" + self.open(mode='r') + charges_np_r = trexio.read_nucleus_charge(self.test_file) + assert charges_np_r.dtype is np.dtype(np.float64) + assert charges_np_r.size == nucleus_num + np.testing.assert_array_almost_equal(charges_np_r, np.array(nucleus_charge), decimal=8) + + + def test_read_array_2D(self): + """Read an array.""" + self.open(mode='r') + # read nuclear coordinates without providing optional argument dim + coords_np = trexio.read_nucleus_coord(self.test_file) + assert coords_np.dtype is np.dtype(np.float64) + assert coords_np.size == nucleus_num * 3 + np.testing.assert_array_almost_equal(coords_np, np.array(nucleus_coord).reshape(nucleus_num,3), decimal=8) + + + def test_read_errors(self): + """Test some reading errors.""" + self.open(mode='r') + # unsafe call to read_safe should fail with error message corresponding to TREXIO_UNSAFE_ARRAY_DIM + with pytest.raises(trexio.Error): + _ = trexio.read_nucleus_charge(self.test_file, dim=nucleus_num/2) + + + def test_read_integers(self): + """Read some integer arrays.""" + self.open(mode='r') + + indices_np_16 = trexio.read_basis_nucleus_index(self.test_file, dtype=np.int16) + assert indices_np_16.dtype is np.dtype(np.int16) + assert (indices_np_16 == np.array(nucleus_index)).all() + + indices_np_32 = trexio.read_basis_nucleus_index(self.test_file, dtype=np.int32) + assert indices_np_32.dtype is np.dtype(np.int32) + assert (indices_np_32 == np.array(nucleus_index)).all() + + indices_np_64 = trexio.read_basis_nucleus_index(self.test_file) + assert indices_np_64.dtype is np.dtype(np.int64) + assert indices_np_64.size == basis_shell_num + assert (indices_np_64 == np.array(nucleus_index)).all() + + + def test_sparse_read(self): + """Read a sparse array.""" + self.open(mode='r') + # 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_ao_2e_int_eri(self.test_file, offset_file, buf_size) + #print(f'First complete sparse read size: {read_buf_size}') + assert not eof + assert read_buf_size == buf_size + assert indices_sparse_np[0][0] == 0 + assert indices_sparse_np[read_buf_size-1][3] == read_buf_size * 4 - 1 + + 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, eof = trexio.read_ao_2e_int_eri(self.test_file, offset_file, buf_size) + #print(f'Second incomplete sparse read size: {read_buf_size}') + assert eof + assert read_buf_size == (num_integrals - buf_size) + 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 + + + def test_determinant_read(self): + """Read the CI determinants.""" + self.open(mode='r') + # read determinants (list of ints and float coefficients) + buf_size = 100 + 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(self.test_file, offset_file, buf_size) + #print(f'First complete read of determinant list: {read_buf_size}') + assert not eof + assert read_buf_size == buf_size + assert dets_np[0][0] == 0 + assert dets_np[read_buf_size-1][int64_num*2-1] == read_buf_size * int64_num * 2- 1 + + coefficients_np, read_buf_size, eof = trexio.read_determinant_coefficient(self.test_file, offset_file, buf_size) + #print(f'First complete read of determinant coefficients: {read_buf_size}') + assert not eof + assert read_buf_size == buf_size + + + def test_array_str_read(self): + """Read an array of strings.""" + self.open(mode='r') + labels_r = trexio.read_nucleus_label(self.test_file) + assert len(labels_r) == nucleus_num + assert labels_r == nucleus_label + + + def test_str_read(self): + """Read a string.""" + self.open(mode='r') + point_group_r = trexio.read_nucleus_point_group(self.test_file) + assert point_group_r == point_group diff --git a/src/pytrexio.i b/src/pytrexio.i index 52a7be9..b6e5485 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,15 @@ 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)}; +%apply (int32_t* IN_ARRAY1, int32_t DIM1) {(const int32_t* orb_list, const int32_t occupied_num)}; +/* For some reasons SWIG does not apply the proper bitfield_t typemap, so one has to manually specify int64_t* ARGOUT_ARRAY1 below */ +%apply (int64_t* ARGOUT_ARRAY1, int32_t DIM1) {(bitfield_t* const bit_list, const int32_t N_int)}; /* 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 2ce1136..3d0057a 100644 --- a/src/templates_front/build.sh +++ b/src/templates_front/build.sh @@ -38,9 +38,18 @@ 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 + +# private API header file +cat populated/private_pop_front.h >> trexio_private.h +echo "#endif" >> trexio_private.h # 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 +57,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 55c3587..76c8b72 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 #include #include +#include #include "trexio.h" #include "trexio_private.h" @@ -72,6 +73,8 @@ typedef int32_t trexio_exit_code; <
> #ifndef _TREXIO_PRIVATE_H #define _TREXIO_PRIVATE_H + +#include "trexio.h" #+end_src ** Fortran @@ -84,7 +87,7 @@ module trexio integer, parameter :: trexio_exit_code = c_int32_t integer, parameter :: trexio_back_end_t = c_int32_t - integer, parameter :: trexio_t = c_int64_t + integer, parameter :: trexio_t = c_size_t character(kind=c_char), parameter :: TREXIO_DELIM = c_new_line #+end_src @@ -97,6 +100,12 @@ module trexio This package is a top-level wrapper of the SWIG-generated pytrexio module. """ +from os import path + +try: + import numpy as np +except ImportError: + raise Exception("NumPy cannot be imported.") try: import pytrexio.pytrexio as pytr @@ -107,7 +116,6 @@ except ImportError: PYTREXIO_MAX_STR_LENGTH = 2048 # setuptools do not assign __version__ variable to the trexio package, so we set it manually -from os import path __trexio_path__ = path.dirname(path.abspath(__file__)) with open(path.join(path.join(__trexio_path__, 'pytrexio'), '_version.py')) as version_file: __version__ = version_file.read().split('"')[1] @@ -130,12 +138,13 @@ __trexio_path__ = None ** Memory allocation Memory allocation of structures can be facilitated by using the - following macro, which ensures that the size of the allocated + following macros, which ensure that the size of the allocated object is the same as the size of the data type pointed by the pointer. + For CALLOC, we allocate N+1 to avoid errors when N=0. #+begin_src c :tangle trexio_private.h #define MALLOC(T) (T*) malloc (sizeof(T)) -#define CALLOC(N,T) (T*) calloc ( (N) , sizeof(T) ) +#define CALLOC(N,T) (T*) calloc ( (N)+1 , sizeof(T) ) #+end_src When a pointer is freed, it should be set to ~NULL~. @@ -158,40 +167,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 +280,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 +321,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 +363,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 +499,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 +518,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 +585,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 @@ -562,7 +607,7 @@ def string_of_error(return_code: int) -> str: Then the corresponding back-end ~has/read/write~ functions has to be implemented. For example, see the commented lines that correspond to the ~TREXIO_JSON~ back end (not implemented yet). - _Note_: It is important to increment the value of ~TREXIO_INVALID_BACK_END~ when a new back end is added. Otherwise, it will not be available. + _Note_: It is important to increment the value of ~TREXIO_INVALID_BACK_END~ when a new back end is implemented. Otherwise, it will not be available. *** C @@ -691,16 +736,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 +765,9 @@ class File: mode: str One of the currently supported TREXIO open modes. For example, 'r' or 'w'. + state: int + Active (excited or ground) state of the file. + Default is 0. isOpen: bool Flag indicating whether the current object is still open for I/O pytrexio_s: @@ -730,7 +784,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 +797,7 @@ class File: self.isOpen = None self.exists = None + self.back_end = self.pytrexio_s.back_end self.info = info @@ -766,6 +821,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,20 +859,6 @@ class File: pass #+end_src -** Polymorphism of the file handle - - Polymorphism of the ~trexio_t~ type is handled by ensuring that the - corresponding types for all back ends can be safely casted to - ~trexio_t~. This is done by making the back-end structs start with - ~struct trexio_s~: - - #+begin_src c -struct trexio_back_end_s { - trexio_t parent ; - /* add below specific back-end data */ -} - #+end_src - ** File opening ~trexio_open~ creates a new TREXIO file or opens the existing one. @@ -934,16 +998,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 +1086,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 +1104,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') { @@ -1184,7 +1297,7 @@ interface integer(trexio_exit_code) function trexio_set_one_based(trex_file) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file end function trexio_set_one_based end interface #+end_src @@ -1218,10 +1331,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) { @@ -1294,7 +1405,7 @@ interface integer(trexio_exit_code) function trexio_close (trex_file) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file end function trexio_close end interface #+end_src @@ -1308,12 +1419,87 @@ 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 flushing + + ~trexio_flush~ flushes all buffers into the ~trexio_t~ file. + + input parameters: + ~file~ -- TREXIO file handle. + + output: + ~trexio_exit_code~ exit code. + +*** C + + #+begin_src c :tangle prefix_front.h :exports none +trexio_exit_code trexio_flush(trexio_t* file); + #+end_src + + #+begin_src c :tangle prefix_front.c +trexio_exit_code +trexio_flush (trexio_t* file) +{ + + if (file == NULL) return TREXIO_FILE_ERROR; + + trexio_exit_code rc = TREXIO_FAILURE; + + assert(file->back_end < TREXIO_INVALID_BACK_END); + + /* Terminate the back end */ + switch (file->back_end) { + + case TREXIO_TEXT: + rc = trexio_text_flush(file); + break; + + case TREXIO_HDF5: +#ifdef HAVE_HDF5 + rc = trexio_hdf5_flush(file); + break; +#else + return TREXIO_BACK_END_MISSING; +#endif +/* + case TREXIO_JSON: + rc = trexio_json_flush(file); + break; +,*/ + } + + return rc; +} + #+end_src + +*** Fortran + + #+begin_src f90 :tangle prefix_fortran.f90 +interface + integer(trexio_exit_code) function trexio_flush (trex_file) bind(C) + use, intrinsic :: iso_c_binding + import + integer(trexio_t), intent(in), value :: trex_file + end function trexio_flush +end interface + #+end_src + +*** Python + + #+begin_src python :tangle basic_python.py +def flush(trexio_file): + """Flush buffers into the TREXIO file. + + Parameter is a ~trexio_file~ object that has been created by a call to ~open~ function. + """ + + rc = pytr.trexio_flush(trexio_file) + if rc != TREXIO_SUCCESS: + raise Error(rc) #+end_src ** File existence @@ -1399,8 +1585,100 @@ def _inquire(file_name: str) -> bool: raise Error(rc) #+end_src +** File state + + **Note:** the use of the functions below is discouraged as of version 2.3.0. + Please use ~trexio_write_state_id~ and ~trexio_read_state_id~ to get the state + corresponding to a given ~trexio_t~ file. There can be only one ~state_id~ per file, + namely data for excited state wave functions have to go in a file different from + the ground state one (see the ~state~ group description for more info about how + you can link the ground state TREXIO file with its excited states). + + ~trexio_set_state~ set an existing ~trexio_t~ file handle to a given state + and write it as ~state_id~ attribute. + ~trexio_get_state~ returns current state of the ~trexio_t~ file handle. + + input parameters: + ~file~ -- TREXIO file handle. + ~state~ -- ~int32_t~ ID of a state (0 for ground 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; + + /* Write state_id in the file (as of v.2.3.0) */ + trexio_exit_code rc = trexio_has_state_id(file); + if (rc == TREXIO_HAS_NOT || file->mode == 'u') { + trexio_exit_code rc_w = trexio_write_state_id(file, num); + if (rc_w != TREXIO_SUCCESS) return rc_w; + } + + 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; + + /* Read state_id from the file (as of v.2.3.0) */ + int32_t state_id = 0; + trexio_exit_code rc = trexio_has_state_id(file); + if (rc == TREXIO_SUCCESS) { + trexio_exit_code rc_r = trexio_read_state_id(file, &state_id); + if (rc_r != TREXIO_SUCCESS) return rc_r; + } + + /* If the state is not in a file then state_id=0, i.e. ground state */ + *num = state_id; + + 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(trexio_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(trexio_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 +1690,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 @@ -1559,6 +1857,98 @@ trexio_pre_close (trexio_t* file) considered dimensioning variables and cannot be negative or 0. An attempt to write negative or 0 value will result in ~TREXIO_INVALID_ARG_2~ exit code. +** Templates for front end has_group functions +*** Introduction + + This section concerns API calls related to TREXIO groups + + | Function name | Description | + |----------------------+-----------------------------------| + | ~trexio_has_$group$~ | Check if a group exists in a file | + +*** C templates for front end + + The ~C~ templates that correspond to each of the abovementioned + functions can be found below. First parameter is the ~TREXIO~ file + handle. + +**** Function declarations + + #+begin_src c :tangle hrw_group_front.h :exports none +trexio_exit_code trexio_has_$group$(trexio_t* const file); + #+end_src + +**** Source code + + #+begin_src c :tangle has_group_front.c +trexio_exit_code +trexio_has_$group$ (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_$group$(file); + + case TREXIO_HDF5: +#ifdef HAVE_HDF5 + return trexio_hdf5_has_$group$(file); +#else + return TREXIO_BACK_END_MISSING; +#endif +/* + case TREXIO_JSON: + return trexio_json_has_$group$(file); + break; +,*/ + } + + return TREXIO_FAILURE; +} + #+end_src + +*** Fortran templates for front end + + The ~Fortran~ templates that provide an access to the ~C~ API calls from Fortran. + These templates are based on the use of ~iso_c_binding~. Pointers have to be passed by value. + + #+begin_src f90 :tangle has_group_front_fortran.f90 +interface + integer(trexio_exit_code) function trexio_has_$group$ (trex_file) bind(C) + use, intrinsic :: iso_c_binding + import + integer(trexio_t), intent(in), value :: trex_file + end function trexio_has_$group$ +end interface + #+end_src + +*** Python templates for front end + + #+begin_src python :tangle has_group_front.py +def has_$group$(trexio_file) -> bool: + """Check that $group$ group 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_$group$(trexio_file.pytrexio_s) + if rc == TREXIO_FAILURE: + raise Error(rc) + + return rc == TREXIO_SUCCESS + #+end_src + ** Templates for front end has/read/write a single numerical attribute *** Introduction @@ -1789,7 +2179,7 @@ interface integer(trexio_exit_code) function trexio_write_$group_num$_64 (trex_file, num) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file $group_num_f_dtype_double$, intent(in), value :: num end function trexio_write_$group_num$_64 end interface @@ -1800,7 +2190,7 @@ interface integer(trexio_exit_code) function trexio_read_$group_num$_64 (trex_file, num) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file $group_num_f_dtype_double$, intent(out) :: num end function trexio_read_$group_num$_64 end interface @@ -1811,7 +2201,7 @@ interface integer(trexio_exit_code) function trexio_write_$group_num$_32 (trex_file, num) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file $group_num_f_dtype_single$, intent(in), value :: num end function trexio_write_$group_num$_32 end interface @@ -1822,7 +2212,7 @@ interface integer(trexio_exit_code) function trexio_read_$group_num$_32 (trex_file, num) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file $group_num_f_dtype_single$, intent(out) :: num end function trexio_read_$group_num$_32 end interface @@ -1833,7 +2223,7 @@ interface integer(trexio_exit_code) function trexio_write_$group_num$ (trex_file, num) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file $group_num_f_dtype_default$, intent(in), value :: num end function trexio_write_$group_num$ end interface @@ -1844,7 +2234,7 @@ interface integer(trexio_exit_code) function trexio_read_$group_num$ (trex_file, num) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file $group_num_f_dtype_default$, intent(out) :: num end function trexio_read_$group_num$ end interface @@ -1855,7 +2245,7 @@ interface integer(trexio_exit_code) function trexio_has_$group_num$ (trex_file) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file end function trexio_has_$group_num$ end interface #+end_src @@ -1879,12 +2269,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 +2289,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 +2306,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 @@ -2459,7 +2837,7 @@ interface integer(trexio_exit_code) function trexio_write_$group_dset$_64 (trex_file, dset) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file $group_dset_f_dtype_double$, intent(in) :: dset$group_dset_f_dims$ end function trexio_write_$group_dset$_64 end interface @@ -2470,7 +2848,7 @@ interface integer(trexio_exit_code) function trexio_read_$group_dset$_64 (trex_file, dset) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file $group_dset_f_dtype_double$, intent(out) :: dset$group_dset_f_dims$ end function trexio_read_$group_dset$_64 end interface @@ -2481,7 +2859,7 @@ interface integer(trexio_exit_code) function trexio_write_$group_dset$_32 (trex_file, dset) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file $group_dset_f_dtype_single$, intent(in) :: dset$group_dset_f_dims$ end function trexio_write_$group_dset$_32 end interface @@ -2492,7 +2870,7 @@ interface integer(trexio_exit_code) function trexio_read_$group_dset$_32 (trex_file, dset) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file $group_dset_f_dtype_single$, intent(out) :: dset$group_dset_f_dims$ end function trexio_read_$group_dset$_32 end interface @@ -2503,7 +2881,7 @@ interface integer(trexio_exit_code) function trexio_write_$group_dset$ (trex_file, dset) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file $group_dset_f_dtype_default$, intent(in) :: dset$group_dset_f_dims$ end function trexio_write_$group_dset$ end interface @@ -2514,7 +2892,7 @@ interface integer(trexio_exit_code) function trexio_read_$group_dset$ (trex_file, dset) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file $group_dset_f_dtype_default$, intent(out) :: dset$group_dset_f_dims$ end function trexio_read_$group_dset$ end interface @@ -2525,7 +2903,7 @@ interface integer(trexio_exit_code) function trexio_has_$group_dset$ (trex_file) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file end function trexio_has_$group_dset$ end interface #+end_src @@ -2545,15 +2923,10 @@ 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). """ - try: - import numpy as np - except ImportError: - raise Exception("NumPy cannot be imported.") - doConversion = False doFlatten = False if not isinstance(dset_w, (list, tuple)): @@ -2618,71 +2991,59 @@ 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). """ - try: - import numpy as np - except ImportError: - raise Exception("NumPy cannot be imported.") - if doReshape is None: doReshape = True # if dim is not specified, read dimensions from the TREXIO file dims_list = None - if dim is None or doReshape: + if doReshape: $group_dset_dim$ = read_$group_dset_dim$(trexio_file) dims_list = [$group_dset_dim_list$] - dim = 1 + dim_real = 1 for i in range($group_dset_rank$): - dim *= dims_list[i] + dim_real *= dims_list[i] + if dim: + if dim_real != dim: + raise Error(TREXIO_UNSAFE_ARRAY_DIM) + else: + dim = dim_real shape = tuple(dims_list) 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 +3063,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 @@ -2836,22 +3191,34 @@ trexio_read_$group_dset$(trexio_t* const file, rc = trexio_read_$group_dset$_size(file, &size_max); if (rc != TREXIO_SUCCESS) return rc; - int64_t num; - rc = trexio_read_$group_dset_sparse_dim$_64(file, &num); - if (rc != TREXIO_SUCCESS) return rc; + /* To be set by generator : number of unique dimensions + (e.g. 1 for ERI in AO basis because only ao_num is present in the list of dimensions) */ + const uint32_t unique_rank = $group_dset_unique_rank$; + int64_t unique_dims[$group_dset_unique_rank$]; + + // Below part is populated by the generator when unique_rank > 1 + rc = trexio_read_$group_dset_unique_dim$_64(file, &unique_dims[$dim_id$]); if (rc != TREXIO_SUCCESS) return rc; + + /* Find the maximal value along all dimensions to define the compression technique in the back end */ + int64_t max_dim = unique_dims[0]; + if (unique_rank != 1) { + for (uint32_t i = 1; i < unique_rank; i++) { + if (unique_dims[i] > max_dim) max_dim = unique_dims[i]; + } + } // 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) { case TREXIO_TEXT: - rc = trexio_text_read_$group_dset$(file, offset_file, *buffer_size, num, &eof_read_size, index_sparse, value_sparse); + rc = trexio_text_read_$group_dset$(file, offset_file, *buffer_size, max_dim, &eof_read_size, index_sparse, value_sparse); break; case TREXIO_HDF5: #ifdef HAVE_HDF5 - rc = trexio_hdf5_read_$group_dset$(file, offset_file, *buffer_size, num, &eof_read_size, index_sparse, value_sparse); + rc = trexio_hdf5_read_$group_dset$(file, offset_file, *buffer_size, max_dim, &eof_read_size, index_sparse, value_sparse); break; #else rc = TREXIO_BACK_END_MISSING; @@ -2945,9 +3312,10 @@ trexio_write_$group_dset$(trexio_t* const file, if (index_sparse == NULL) return TREXIO_INVALID_ARG_4; if (value_sparse == NULL) return TREXIO_INVALID_ARG_5; - const uint32_t rank = $group_dset_rank$; // To be set by generator : number of indices + /* To be set by generator : number of indices */ + const uint32_t rank = $group_dset_rank$; - int64_t size_max=0L; // Max number of integrals (already in the file) + int64_t size_max = 0L; // Max number of integrals (already in the file) trexio_exit_code rc; /* Read the max number of integrals stored in the file */ @@ -2955,9 +3323,21 @@ trexio_write_$group_dset$(trexio_t* const file, if (rc != TREXIO_SUCCESS && rc != TREXIO_DSET_MISSING) return rc; if (rc == TREXIO_DSET_MISSING) size_max = 0L; - int64_t num; - rc = trexio_read_$group_dset_sparse_dim$_64(file, &num); - if (rc != TREXIO_SUCCESS) return rc; + /* To be set by generator : number of unique dimensions + (e.g. 1 for ERI in AO basis because only ao_num is present in the list of dimensions) */ + const uint32_t unique_rank = $group_dset_unique_rank$; + int64_t unique_dims[$group_dset_unique_rank$]; + + // Below part is populated by the generator when unique_rank > 1 + rc = trexio_read_$group_dset_unique_dim$_64(file, &unique_dims[$dim_id$]); if (rc != TREXIO_SUCCESS) return rc; + + /* Find the maximal value along all dimensions to define the compression technique in the back end */ + int64_t max_dim = unique_dims[0]; + if (unique_rank != 1) { + for (uint32_t i = 1; i < unique_rank; i++) { + if (unique_dims[i] > max_dim) max_dim = unique_dims[i]; + } + } // shift indices to be zero-based if Fortran API is used if (file->one_based) { @@ -2974,13 +3354,13 @@ trexio_write_$group_dset$(trexio_t* const file, switch (file->back_end) { case TREXIO_TEXT: - rc = trexio_text_write_$group_dset$(file, offset_file, buffer_size, num, + rc = trexio_text_write_$group_dset$(file, offset_file, buffer_size, max_dim, size_max, index_sparse_p, value_sparse); break; case TREXIO_HDF5: #ifdef HAVE_HDF5 - rc = trexio_hdf5_write_$group_dset$(file, offset_file, buffer_size, num, + rc = trexio_hdf5_write_$group_dset$(file, offset_file, buffer_size, max_dim, index_sparse_p, value_sparse); break; #else @@ -3005,13 +3385,13 @@ trexio_write_$group_dset$(trexio_t* const file, switch (file->back_end) { case TREXIO_TEXT: - rc = trexio_text_write_$group_dset$(file, offset_file, buffer_size, num, + rc = trexio_text_write_$group_dset$(file, offset_file, buffer_size, max_dim, size_max, index_sparse, value_sparse); break; case TREXIO_HDF5: #ifdef HAVE_HDF5 - rc = trexio_hdf5_write_$group_dset$(file, offset_file, buffer_size, num, + rc = trexio_hdf5_write_$group_dset$(file, offset_file, buffer_size, max_dim, index_sparse, value_sparse); break; #else @@ -3078,7 +3458,7 @@ interface index_sparse, value_sparse) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_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_int32_t), intent(in) :: index_sparse(*) @@ -3093,7 +3473,7 @@ interface value_sparse, value_size) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_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_int32_t), intent(in) :: index_sparse(*) @@ -3111,7 +3491,7 @@ interface index_sparse, value_sparse) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_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_int32_t), intent(out) :: index_sparse(*) @@ -3126,7 +3506,7 @@ interface value_sparse, value_size) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_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_int32_t), intent(out) :: index_sparse(*) @@ -3143,7 +3523,7 @@ interface size_max) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file integer(c_int64_t), intent(out) :: size_max end function trexio_read_$group_dset$_size end interface @@ -3154,7 +3534,7 @@ interface integer(trexio_exit_code) function trexio_has_$group_dset$ (trex_file) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file end function trexio_has_$group_dset$ end interface #+end_src @@ -3176,22 +3556,17 @@ 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). """ - 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): @@ -3278,11 +3653,6 @@ def read_$group_dset$(trexio_file: File, offset_file: int, buffer_size: int) -> - 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): @@ -3337,12 +3707,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 +3724,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 @@ -3653,7 +4014,7 @@ interface integer(trexio_exit_code) function trexio_write_$group_dset$_low (trex_file, dset, max_str_len) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file character(kind=c_char), intent(in) :: dset(*) integer(c_int32_t), intent(in), value :: max_str_len end function trexio_write_$group_dset$_low @@ -3677,7 +4038,7 @@ interface integer(trexio_exit_code) function trexio_has_$group_dset$ (trex_file) bind(C) use, intrinsic :: iso_c_binding import - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file end function trexio_has_$group_dset$ end interface #+end_src @@ -3685,7 +4046,7 @@ end interface #+begin_src f90 :tangle helper_read_dset_str_front_fortran.fh_90 integer(trexio_exit_code) function trexio_read_$group_dset$ (trex_file, dset, max_str_len) implicit none - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file integer(c_int32_t), intent(in), value :: max_str_len character(len=*), intent(inout) :: dset(*) @@ -3714,7 +4075,7 @@ end interface #+begin_src f90 :tangle helper_write_dset_str_front_fortran.fh_90 integer(trexio_exit_code) function trexio_write_$group_dset$ (trex_file, dset, max_str_len) implicit none - integer(c_int64_t), intent(in), value :: trex_file + integer(trexio_t), intent(in), value :: trex_file integer(c_int32_t), intent(in), value :: max_str_len character(len=*), intent(in) :: dset(*) @@ -3754,14 +4115,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 @@ -3786,32 +4142,28 @@ def read_$group_dset$(trexio_file, dim = None) -> list: - Exception from some other error (e.g. RuntimeError). """ - # if dim is not specified, read dimensions from the TREXIO file - if dim is None: - $group_dset_dim$ = read_$group_dset_dim$(trexio_file) + $group_dset_dim$ = read_$group_dset_dim$(trexio_file) - dims_list = [$group_dset_dim_list$] - dim = 1 - for i in range($group_dset_rank$): - dim *= dims_list[i] + dims_list = [$group_dset_dim_list$] + dim_real = 1 + for i in range($group_dset_rank$): + dim_real *= dims_list[i] + + if dim: + if dim_real != dim: + raise Error(TREXIO_UNSAFE_ARRAY_DIM) + else: + dim = dim_real + + 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: - 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 - - - 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 +4178,435 @@ 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 + return rc == TREXIO_SUCCESS + #+end_src + +** Templates for front end has/read/write a buffered vector + + This corresponds to the ~buffer~ data type and is particularly useful for incremental additiona of values like + it was done for ~sparse~ data but without the need to supply tuples of indices. + + + | Function name | Description | Precision | + |----------------------------------+------------------------------------------------+-----------| + | ~trexio_has_$group_dset$~ | Check if a buffered dset is present in a file | --- | + | ~trexio_read_$group_dset$~ | Read values of a vector in buffers | Double | + | ~trexio_read_$group_dset$_size~ | Read the number of elements stored in the file | Double | + | ~trexio_write_$group_dset$~ | Write values of a vector in buffers | Double | + | ~trexio_read_safe_$group_dset$~ | Safe (bounded) read (for Python API) | Double | + | ~trexio_write_safe_$group_dset$~ | Safe (bounded) write (for Python API) | Double | + +*** C source code + + #+begin_src c :tangle hrw_buffered_front.h :exports none +trexio_exit_code trexio_has_$group_dset$(trexio_t* const file); +trexio_exit_code trexio_read_$group_dset$(trexio_t* const file, const int64_t offset_file, int64_t* const buffer_size, double* const dset); +trexio_exit_code trexio_read_safe_$group_dset$(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_$group_dset$(trexio_t* const file, const int64_t offset_file, const int64_t buffer_size, const double* dset); +trexio_exit_code trexio_write_safe_$group_dset$(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_$group_dset$_size(trexio_t* const file, int64_t* const size_max); + #+end_src + + #+begin_src c :tangle read_buffered_front.c +trexio_exit_code +trexio_read_$group_dset$ (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_$group_dset$(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_$group_dset$(file, offset_file, rank, dims, &eof_read_size, dset); + break; + + case TREXIO_HDF5: +#ifdef HAVE_HDF5 + rc = trexio_hdf5_read_$group_dset$(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; +} + #+end_src + + #+begin_src c :tangle read_buffered_front.c +trexio_exit_code +trexio_read_$group_dset$_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_$group_dset$(file) != TREXIO_SUCCESS) return TREXIO_DSET_MISSING; + + switch (file->back_end) { + + case TREXIO_TEXT: + return trexio_text_read_$group_dset$_size(file, size_max); + break; + + case TREXIO_HDF5: +#ifdef HAVE_HDF5 + return trexio_hdf5_read_$group_dset$_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 */ + } +} + #+end_src + + #+begin_src c :tangle read_buffered_front.c +trexio_exit_code +trexio_read_safe_$group_dset$ (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_$group_dset$(file, offset_file, buffer_size_read, dset_out); +} + #+end_src + + #+begin_src c :tangle write_buffered_front.c +trexio_exit_code +trexio_write_$group_dset$ (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_$group_dset$(file, offset_file, rank, dims, dset); + break; + + case TREXIO_HDF5: +#ifdef HAVE_HDF5 + return trexio_hdf5_write_$group_dset$(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; +} + #+end_src + + #+begin_src c :tangle write_buffered_front.c +trexio_exit_code +trexio_write_safe_$group_dset$ (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_$group_dset$(file, offset_file, buffer_size, dset_in); +} + #+end_src + + #+begin_src c :tangle has_buffered_front.c +trexio_exit_code +trexio_has_$group_dset$ (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_$group_dset$(file); + + case TREXIO_HDF5: +#ifdef HAVE_HDF5 + return trexio_hdf5_has_$group_dset$(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_buffered_front_fortran.f90 +interface + integer(trexio_exit_code) function trexio_write_$group_dset$(trex_file, & + offset_file, buffer_size, dset) bind(C) + use, intrinsic :: iso_c_binding + import + integer(trexio_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) :: dset(*) + end function trexio_write_$group_dset$ +end interface + +interface + integer(trexio_exit_code) function trexio_write_safe_$group_dset$ (trex_file, & + offset_file, buffer_size, & + dset, dset_size) bind(C) + use, intrinsic :: iso_c_binding + import + integer(trexio_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) :: dset(*) + integer(c_int64_t), intent(in), value :: dset_size + end function trexio_write_safe_$group_dset$ +end interface + #+end_src + + #+begin_src f90 :tangle read_buffered_front_fortran.f90 +interface + integer(trexio_exit_code) function trexio_read_safe_$group_dset$ (trex_file, & + offset_file, buffer_size, & + dset, dset_size) bind(C) + use, intrinsic :: iso_c_binding + import + integer(trexio_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) :: dset(*) + integer(c_int64_t), intent(in), value :: dset_size + end function trexio_read_safe_$group_dset$ +end interface + +interface + integer(trexio_exit_code) function trexio_read_$group_dset$(trex_file, & + offset_file, buffer_size, dset) bind(C) + use, intrinsic :: iso_c_binding + import + integer(trexio_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) :: dset(*) + end function trexio_read_$group_dset$ +end interface + +interface + integer(trexio_exit_code) function trexio_read_$group_dset$_size (trex_file, & + size_max) bind(C) + use, intrinsic :: iso_c_binding + import + integer(trexio_t), intent(in), value :: trex_file + integer(c_int64_t), intent(out) :: size_max + end function trexio_read_$group_dset$_size +end interface + #+end_src + + #+begin_src f90 :tangle has_buffered_front_fortran.f90 +interface + integer(trexio_exit_code) function trexio_has_$group_dset$ (trex_file) bind(C) + use, intrinsic :: iso_c_binding + import + integer(trexio_t), intent(in), value :: trex_file + end function trexio_has_$group_dset$ +end interface + #+end_src + +*** Python interface + + #+begin_src python :tangle write_buffered_front.py +def write_$group_dset$(trexio_file: File, offset_file: int, buffer_size: int, dset) -> None: + """Write the $group_dset$ in the TREXIO file. + + Parameters: + + trexio_file: + TREXIO File object. + + offset_file: int + The number of values to be skipped in the file when writing. + + buffer_size: int + The number of values to write in the file. + + dset: list OR numpy.ndarray + Array of $group_dset$ 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). + """ + + 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(dset, (list, tuple, np.ndarray)): + raise TypeError("dset argument has to be an array (list, tuple or NumPy ndarray).") + + if isinstance(dset, np.ndarray) and not coefficients.dtype==np.float64: + # convert to float64 if input is in a different precision + dset_64 = np.float64(dset) + rc = pytr.trexio_write_safe_$group_dset$(trexio_file.pytrexio_s, offset_file, buffer_size, dset_64) else: - return False + rc = pytr.trexio_write_safe_$group_dset$(trexio_file.pytrexio_s, offset_file, buffer_size, dset) + + if rc != TREXIO_SUCCESS: + raise Error(rc) + #+end_src + + #+begin_src python :tangle read_buffered_front.py +def read_$group_dset$(trexio_file: File, offset_file: int, buffer_size: int) -> tuple: + """Read $group_dset$ from the TREXIO file. + + Parameters: + + trexio_file: + TREXIO File object. + + offset_file: int + The number of values to be skipped in the file when reading. + + buffer_size: int + The number of values to read from the file. + + Returns: + (dset, n_int_read, eof_flag) tuple where + - dset is the NumPy array [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). + """ + + 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 values already in the file + det_num = read_$group_dset$_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, dset = pytr.trexio_read_safe_$group_dset$(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 dset is None: + raise ValueError("Returned NULL array from the low-level pytrexio API.") + + return (dset, n_int_read, eof_flag) + + +def read_$group_dset$_size(trexio_file) -> int: + """Read the number of elements 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 $group_dset$ 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_$group_dset$_size(trexio_file.pytrexio_s) + if rc != TREXIO_SUCCESS: + raise Error(rc) + + return num + #+end_src + + #+begin_src python :tangle has_buffered_front.py +def has_$group_dset$(trexio_file) -> bool: + """Check that $group_dset$ 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_$group_dset$(trexio_file.pytrexio_s) + if rc == TREXIO_FAILURE: + raise Error(rc) + + return rc == TREXIO_SUCCESS #+end_src ** Templates for front end has/read/write a single string attribute @@ -4053,13 +4819,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 +4839,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 +4856,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,6 +4948,480 @@ def delete_$group$(trexio_file) -> None: if rc != TREXIO_SUCCESS: raise Error(rc) #+end_src + +* 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_list~ | Check if an attribute exists in a file | + | ~trexio_write_determinant_list~ | Write an attribute | + | ~trexio_read_determinant_list~ | Read an attribute | + | ~trexio_get_int64_num~ | Get the number of int64 bit fields per determinant | + +*** 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_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_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_get_int64_num(trexio_t* const file, int32_t* const num); + #+end_src + + #+begin_src c :tangle read_determinant_front.c +trexio_exit_code +trexio_get_int64_num(trexio_t* const file, int32_t* const num) +{ + + if (file == NULL) return TREXIO_INVALID_ARG_1; + if (num == NULL) return TREXIO_INVALID_ARG_2; + + /* Read the number of mos */ + int64_t mo_num = 0L; + trexio_exit_code 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 */ + int32_t int_num = 0; + int_num = (mo_num - 1L)/64 + 1; + + *num = int_num; + + return TREXIO_SUCCESS; +} + #+end_src + + #+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) +{ + + 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; + + /* Get the number of int bit fields per determinant */ + int32_t int_num = 0; + trexio_exit_code rc = trexio_get_int64_num(file, &int_num); + if (rc != TREXIO_SUCCESS) return rc; + + uint32_t rank = 2; + uint64_t det_size = (uint64_t) (*buffer_size_read); + uint64_t dims[2] = {det_size, int_num*2UL}; + + // 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_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; +} + #+end_src + + #+begin_src c :tangle read_determinant_front.c +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); +} + #+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; + + /* Get the number of int bit fields per determinant */ + int32_t int_num = 0; + trexio_exit_code rc = trexio_get_int64_num(file, &int_num); + if (rc != TREXIO_SUCCESS) return rc; + + 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; +} + #+end_src + + #+begin_src c :tangle write_determinant_front.c +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); +} + #+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; +} + #+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(trexio_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(trexio_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 + #+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(trexio_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(trexio_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 + #+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(trexio_t), intent(in), value :: trex_file + end function trexio_has_determinant_list +end interface + +interface + integer(trexio_exit_code) function trexio_get_int64_num (trex_file, num) bind(C) + use, intrinsic :: iso_c_binding + import + integer(trexio_t), intent(in), value :: trex_file + integer(c_int32_t), intent(out) :: num + end function trexio_get_int64_num +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). + """ + + 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) + #+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). + """ + + 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) + int_num = 2 * get_int64_num(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, 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 get_int64_num(trexio_file) -> int: + """Compute the number of int64 bit fields corresponding to the TREXIO file. + + Parameter is a ~TREXIO File~ object that has been created by a call to ~open~ function. + + Returns: + ~num~: int + Number of int64 bit fields per determinant. + + 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_get_int64_num(trexio_file.pytrexio_s) + if rc != TREXIO_SUCCESS: + raise Error(rc) + + return num + #+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 + #+end_src + * General helper functions This section contains general helper functions like ~trexio_info~. @@ -4214,51 +5440,234 @@ def delete_$group$(trexio_file) -> None: 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. + ~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. + + ~trexio_to_bitfield_list~ function converts the list of occupied orbitals (up- or down-spin) + into the corresponding ~int64_t~ bitfield representation of the determinant. + ** C - #+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); + #+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); + +typedef int64_t bitfield_t; + +#define TREXIO_ORBITAL_SHIFT 1 +#define TREXIO_INT_SIZE 64 +#define TREXIO_NORB_PER_INT ( 8*sizeof(bitfield_t) ) +#define TREXIO_NORB_PER_INT_SHIFT ( trailz( TREXIO_NORB_PER_INT ) ) + +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); +trexio_exit_code trexio_to_bitfield_list (const int32_t* orb_list, const int32_t occupied_num, bitfield_t* const bit_list, const int32_t N_int); #+end_src + + #+begin_src c :tangle prefix_front.c +trexio_exit_code trexio_to_bitfield_list (const int32_t* orb_list, + const int32_t occupied_num, + bitfield_t* const bit_list, + const int32_t N_int) +{ + if (orb_list == NULL) return TREXIO_INVALID_ARG_1; + if (occupied_num <= 0) return TREXIO_INVALID_ARG_2; + if (bit_list == NULL) return TREXIO_INVALID_ARG_3; + if (N_int <= 0) return TREXIO_INVALID_ARG_4; + + uint32_t i; + uint32_t k; + uint32_t iorb; + + for (int32_t j = 0 ; j < N_int ; j++) { + bit_list[j] = (bitfield_t) 0; + } + + for (int32_t pos = 0 ; pos < occupied_num ; pos++) { + iorb = ((uint32_t) (orb_list[pos] + 1)) - TREXIO_ORBITAL_SHIFT; + i = (uint32_t) (iorb >> TREXIO_NORB_PER_INT_SHIFT); + k = (uint32_t) (iorb & (TREXIO_NORB_PER_INT - 1) ); + bit_list[i] |= ((bitfield_t) 1) << k; + } + + return TREXIO_SUCCESS; +} + #+end_src + + #+begin_src c :tangle prefix_front.c - trexio_exit_code - trexio_info (void) - { - printf("TREXIO_PACKAGE_VERSION : %s\n", TREXIO_PACKAGE_VERSION); +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; - #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 + bitfield_t tmp; + int32_t shift; + int32_t k; + int32_t pos; - #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 + k = 0; + shift = TREXIO_ORBITAL_SHIFT; - return TREXIO_SUCCESS; - } + for (int32_t i=0 ; imode != 'u') return TREXIO_FAILURE; + #+begin_src c :tangle prefix_front.c +trexio_exit_code +trexio_info (void) +{ + printf("TREXIO_PACKAGE_VERSION : %s\n", TREXIO_PACKAGE_VERSION); - return trexio_write_metadata_unsafe(file, safety_flag); - } - #+end_src +#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 @@ -4270,18 +5679,150 @@ interface end interface #+end_src + #+begin_src f90 :tangle prefix_fortran.f90 +interface + integer(trexio_exit_code) function trexio_to_bitfield_list_c(list, occupied_num, det_list, N_int) & + bind(C, name="trexio_to_bitfield_list") + use, intrinsic :: iso_c_binding + import + integer(c_int32_t), intent(in) :: list(*) + integer(c_int32_t), intent(in), value :: occupied_num + integer(c_int64_t), intent(inout) :: det_list(*) + integer(c_int32_t), intent(in), value :: N_int + end function trexio_to_bitfield_list_c +end interface + #+end_src + + #+begin_src f90 :tangle prefix_fortran.f90 +interface + integer(trexio_exit_code) function trexio_to_orbital_list_c(N_int, d1, list, occupied_num) & + bind(C, name="trexio_to_orbital_list") + 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(inout) :: list(*) + integer(c_int32_t), intent(inout) :: occupied_num + end function trexio_to_orbital_list_c +end interface + #+end_src + + #+begin_src f90 :tangle prefix_fortran.f90 +interface + integer(trexio_exit_code) function trexio_to_orbital_list_up_dn_c(N_int, d1, list_up, list_dn, occ_num_up, occ_num_dn) & + bind(C, name="trexio_to_orbital_list_up_dn") + 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(inout) :: list_up(*) + integer(c_int32_t), intent(inout) :: 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_c +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_bitfield_list(n_int: int, orbitals: list) -> list: + """Convert a list of occupied orbitals into a bitfield determinant. + + Input: + ~orbitals~ - list of occupied orbital indices fields (integers) + ~n_int~ - number of bitfields per determinant of a given spin + + Returns: + ~bitfield_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). + """ + + + rc, bitfield_list = pytr.trexio_to_bitfield_list(orbitals, n_int) + if rc != TREXIO_SUCCESS: + raise Error(rc) + if len(bitfield_list) != n_int: + raise Exception("Inconsistent size of the bitfield_list.") + + return bitfield_list + #+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[0:occ_num] + #+end_src + + + #+begin_src python :tangle basic_python.py +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. @@ -4328,7 +5869,81 @@ contains filename_c = trim(filename) // c_null_char trexio_inquire = trexio_inquire_c(filename_c) end function trexio_inquire + #+end_src + The subroutines below wrap the ~to_orbital_list~ functions to shift the MO indices + by 1 since in Fortran arrays are 1-based and C/Python they are 0-based. + + #+begin_src f90 :tangle helper_fortran.f90 + integer(trexio_exit_code) function trexio_to_bitfield_list(list, occupied_num, det_list, N_int) + use, intrinsic :: iso_c_binding + implicit none + + integer(c_int32_t), intent(in) :: list(*) + integer(c_int32_t), intent(in), value :: occupied_num + integer(c_int64_t), intent(out) :: det_list(*) + integer(c_int32_t), intent(in), value :: N_int + integer(c_int32_t) :: list_0based(occupied_num) + + integer :: i + do i = 1,occupied_num + list_0based(i) = list(i) - 1 + enddo + + trexio_to_bitfield_list = trexio_to_bitfield_list_c(list_0based, occupied_num, det_list, N_int) + if (trexio_to_bitfield_list /= TREXIO_SUCCESS) then + return + endif + + end function trexio_to_bitfield_list + + + integer(trexio_exit_code) function trexio_to_orbital_list(N_int, d1, list, occupied_num) + use, intrinsic :: iso_c_binding + implicit none + + 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(out) :: occupied_num + + integer :: i + + trexio_to_orbital_list = trexio_to_orbital_list_c(N_int, d1, list, occupied_num) + if (trexio_to_orbital_list /= TREXIO_SUCCESS) then + return + endif + + do i = 1,occupied_num + list(i) = list(i) + 1 + enddo + end function trexio_to_orbital_list + + + integer(trexio_exit_code) function trexio_to_orbital_list_up_dn(N_int, d1, list_up, list_dn, occ_num_up, occ_num_dn) + use, intrinsic :: iso_c_binding + implicit none + 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(out) :: occ_num_up + integer(c_int32_t), intent(out) :: occ_num_dn + + integer :: i + + trexio_to_orbital_list_up_dn = trexio_to_orbital_list_up_dn_c(N_int, d1, list_up, list_dn, occ_num_up, occ_num_dn) + if (trexio_to_orbital_list_up_dn /= TREXIO_SUCCESS) then + return + endif + + do i = 1,occ_num_up + list_up(i) = list_up(i) + 1 + enddo + do i = 1,occ_num_dn + list_dn(i) = list_dn(i) + 1 + enddo + end function trexio_to_orbital_list_up_dn #+end_src The subroutine below transforms an array of Fortran strings into one big string using ~TREXIO_DELIM~ symbol @@ -4409,7 +6024,7 @@ contains else call trexio_string_of_error(trexio_rc, str) print *, trim(str) - error stop 1 + stop 1 endif end subroutine trexio_assert @@ -4425,10 +6040,6 @@ contains #endif #+end_src - #+begin_src c :tangle trexio_private.h -#endif - #+end_src - #+begin_src f90 :tangle suffix_fortran.f90 end module trexio #+end_src diff --git a/src/templates_hdf5/build.sh b/src/templates_hdf5/build.sh index cff18b4..88a70a5 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 d1027ac..a695d6a 100644 --- a/src/templates_hdf5/templator_hdf5.org +++ b/src/templates_hdf5/templator_hdf5.org @@ -60,6 +60,11 @@ * Template for HDF5 structures + Polymorphism of the ~trexio_t~ type is handled by ensuring that the + corresponding types for all back ends can be safely casted to + ~trexio_t~. This is done by making the back-end structs start with + ~trexio_t parent~ attribute: + #+begin_src c :tangle struct_hdf5.h typedef struct trexio_hdf5_s { trexio_t parent ; @@ -74,6 +79,21 @@ typedef struct trexio_hdf5_s { trexio_exit_code trexio_hdf5_init(trexio_t* const file); trexio_exit_code trexio_hdf5_deinit(trexio_t* const file); trexio_exit_code trexio_hdf5_inquire(const char* file_name); +trexio_exit_code trexio_hdf5_flush(trexio_t* const file); + #+end_src + + #+begin_src c :tangle basic_hdf5.c +trexio_exit_code +trexio_hdf5_flush(trexio_t* const file) +{ + + trexio_hdf5_t* f = (trexio_hdf5_t*) file; + + herr_t rc = H5Fflush(f->file_id, H5F_SCOPE_GLOBAL); + if (rc < 0) return TREXIO_FAILURE; + + return TREXIO_SUCCESS; +} #+end_src #+begin_src c :tangle basic_hdf5.c @@ -174,6 +194,38 @@ trexio_hdf5_deinit (trexio_t* const file) } #+end_src +* Template for HDF5 has a group + + #+begin_src c :tangle hrw_group_hdf5.h :exports none +trexio_exit_code trexio_hdf5_has_$group$ (trexio_t* const file); + #+end_src + + + #+begin_src c :tangle has_group_hdf5.c +trexio_exit_code +trexio_hdf5_has_$group$ (trexio_t* const file) +{ + + if (file == NULL) return TREXIO_INVALID_ARG_1; + + const trexio_hdf5_t* f = (const trexio_hdf5_t*) file; + + struct H5G_info_t group_info; + + /* H5Gget_info return info about the HDF5 group as a group_info struct */ + herr_t status = H5Gget_info(f->$group$_group, &group_info); + if (status < 0) return TREXIO_FAILURE; + + /* If nlinks==0 --> the group is empty, i.e. non-existent */ + if (group_info.nlinks == (hsize_t) 0) { + return TREXIO_HAS_NOT; + } else { + return TREXIO_SUCCESS; + } + +} + #+end_src + * Template for HDF5 has/read/write a numerical attribute #+begin_src c :tangle hrw_attr_num_hdf5.h :exports none @@ -265,6 +317,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 +452,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 +495,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 +515,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 +600,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 +618,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 +655,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 */ @@ -614,6 +670,141 @@ trexio_hdf5_has_$group_dset$ (trexio_t* const file) } #+end_src +* Template for HDF5 has/read/write a dataset of buffered vectors + + Chunked I/O in HDF5 for ~buffered~ data. + + #+begin_src c :tangle hrw_buffered_hdf5.h :exports none +trexio_exit_code trexio_hdf5_has_$group_dset$(trexio_t* const file); +trexio_exit_code trexio_hdf5_read_$group_dset$(trexio_t* const file, const int64_t offset_file, const uint32_t rank, const uint64_t* dims, int64_t* const eof_read_size, double* const dset); +trexio_exit_code trexio_hdf5_write_$group_dset$(trexio_t* const file, const int64_t offset_file, const uint32_t rank, const uint64_t* dims, const double* dset); +trexio_exit_code trexio_hdf5_read_$group_dset$_size(trexio_t* const file, int64_t* const size_max); + #+end_src + + #+begin_src c :tangle read_buffered_hdf5.c +trexio_exit_code trexio_hdf5_read_$group_dset$(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 dset) +{ + if (file == NULL) return TREXIO_INVALID_ARG_1; + if (eof_read_size == NULL) return TREXIO_INVALID_ARG_5; + if (dset == NULL) return TREXIO_INVALID_ARG_6; + + const char dset_name[256] = "$group_dset$"; + + 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 values (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->$group$_group, dset_name, 1, offset, count, eof_read_size, 0, dset); +} + #+end_src + + #+begin_src c :tangle write_buffered_hdf5.c +trexio_exit_code trexio_hdf5_write_$group_dset$(trexio_t* const file, + const int64_t offset_file, + const uint32_t rank, + const uint64_t* dims, + const double* dset) +{ + + if (file == NULL) return TREXIO_INVALID_ARG_1; + if (dset == NULL) return TREXIO_INVALID_ARG_5; + + const char dset_name[256] = "$group_dset$"; + + trexio_hdf5_t* f = (trexio_hdf5_t*) file; + + hid_t 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->$group$_group, dset_name) != 1 ) { + /* If the file does not exist -> create it and write */ + + /* Create chunked dataset with dtype datatype and write indices into it */ + rc_write = trexio_hdf5_create_write_dset_sparse(f->$group$_group, dset_name, dtype, chunk_dims, dset); + 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 dtype datatype and write indices into it */ + rc_write = trexio_hdf5_open_write_dset_sparse(f->$group$_group, dset_name, dtype, chunk_dims, offset_data, dset); + if (rc_write != TREXIO_SUCCESS) return rc_write; + + } + + return TREXIO_SUCCESS; +} + +trexio_exit_code +trexio_hdf5_read_$group_dset$_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; + + const char dset_name[256] = "$group_dset$"; + + const trexio_hdf5_t* f = (const trexio_hdf5_t*) file; + + hid_t dset_id = H5Dopen(f->$group$_group, dset_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_buffered_hdf5.c +trexio_exit_code trexio_hdf5_has_$group_dset$(trexio_t* const file) +{ + if (file == NULL) return TREXIO_INVALID_ARG_1; + + trexio_hdf5_t* f = (trexio_hdf5_t*) file; + if (f->$group$_group == (hsize_t) 0) return TREXIO_HAS_NOT; + + const char dset_name[256] = "$group_dset$"; + + herr_t status = H5LTfind_dataset(f->$group$_group, dset_name); + /* H5LTfind_dataset returns 1 if dataset exists, 0 otherwise */ + if (status == 1){ + return TREXIO_SUCCESS; + } else if (status == 0) { + return TREXIO_HAS_NOT; + } else { + return TREXIO_FAILURE; + } +} + #+end_src + * Template for HDF5 has/read/write a dataset of strings #+begin_src c :tangle hrw_dset_str_hdf5.h :exports none @@ -798,6 +989,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 +1119,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 +1170,108 @@ 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); + #+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); +} + #+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; +} + #+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; + } +} + #+end_src + * Helper functions #+begin_src c :tangle helpers_hdf5.c @@ -1113,6 +1408,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 +1417,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 +1448,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 +1535,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 9e28511..93732f0 100644 --- a/src/templates_text/build.sh +++ b/src/templates_text/build.sh @@ -10,6 +10,12 @@ 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_has_group_text.c >> trexio_text.c +cat populated/pop_hrw_group_text.h >> trexio_text.h + 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 @@ -24,23 +30,27 @@ cat populated/pop_has_dset_str_text.c >> trexio_text.c cat populated/pop_has_dset_sparse_text.c >> trexio_text.c cat populated/pop_has_attr_num_text.c >> trexio_text.c cat populated/pop_has_attr_str_text.c >> trexio_text.c +cat populated/pop_has_buffered_text.c >> trexio_text.c cat populated/pop_read_dset_data_text.c >> trexio_text.c cat populated/pop_read_dset_str_text.c >> trexio_text.c cat populated/pop_read_dset_sparse_text.c >> trexio_text.c cat populated/pop_read_attr_str_text.c >> trexio_text.c cat populated/pop_read_attr_num_text.c >> trexio_text.c +cat populated/pop_read_buffered_text.c >> trexio_text.c cat populated/pop_write_dset_data_text.c >> trexio_text.c cat populated/pop_write_dset_str_text.c >> trexio_text.c cat populated/pop_write_dset_sparse_text.c >> trexio_text.c cat populated/pop_write_attr_str_text.c >> trexio_text.c cat populated/pop_write_attr_num_text.c >> trexio_text.c +cat populated/pop_write_buffered_text.c >> trexio_text.c cat populated/pop_hrw_dset_data_text.h >> trexio_text.h cat populated/pop_hrw_dset_str_text.h >> trexio_text.h cat populated/pop_hrw_dset_sparse_text.h >> trexio_text.h cat populated/pop_hrw_attr_num_text.h >> trexio_text.h cat populated/pop_hrw_attr_str_text.h >> trexio_text.h +cat populated/pop_hrw_buffered_text.h >> trexio_text.h cat suffix_text.h >> trexio_text.h diff --git a/src/templates_text/templator_text.org b/src/templates_text/templator_text.org index 066fd85..9ed7858 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,12 @@ typedef struct $group$_s { } $group$_t; #+end_src -** Template for general structure in text back end +* Template for general structure in text back end + + Polymorphism of the ~trexio_t~ type is handled by ensuring that the + corresponding types for all back ends can be safely casted to + ~trexio_t~. This is done by making the back-end structs start with + ~trexio_t parent~ attribute: #+begin_src c :tangle struct_text_group.h typedef struct trexio_text_s { @@ -101,7 +104,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); @@ -109,6 +112,23 @@ trexio_exit_code trexio_text_inquire(const char* file_name); trexio_exit_code trexio_text_deinit(trexio_t* const file); trexio_exit_code trexio_text_lock(trexio_t* const file); trexio_exit_code trexio_text_unlock(trexio_t* const file); +trexio_exit_code trexio_text_flush(trexio_t* const file); +bool trexio_text_file_exists(const char* file_name); + #+end_src + + #+begin_src c :tangle basic_text.c +bool +trexio_text_file_exists (const char* file_name) +{ + /* Check if the file with "file_name" exists */ + struct stat st; + + int rc = stat(file_name, &st); + + bool file_exists = rc == 0; + + return file_exists; +} #+end_src #+begin_src c :tangle basic_text.c @@ -124,7 +144,15 @@ trexio_text_inquire (const char* file_name) if (file_exists) { - bool is_a_directory = st.st_mode & S_IFDIR; + bool is_a_directory = false; +#ifdef S_IFDIR + is_a_directory = st.st_mode & S_IFDIR; +#elif S_ISDIR + is_a_directory = S_ISDIR(s.st_mode); +#else + printf("Some important macros are missing for directory handling.\n"); + return TREXIO_FAILURE; +#endif if (!is_a_directory) return TREXIO_FILE_ERROR; return TREXIO_SUCCESS; @@ -246,7 +274,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 +293,27 @@ trexio_text_deinit (trexio_t* const file) } #+end_src -** Template for text read a group +* Flush function (templated part) + + #+begin_src c :tangle basic_text_group.c +trexio_exit_code +trexio_text_flush (trexio_t* const file) +{ + + if (file == NULL) return TREXIO_INVALID_ARG_1; + + trexio_exit_code rc; + trexio_text_t* f = (trexio_text_t*) file; + + /* Error handling for this call is added by the generator */ + rc = trexio_text_flush_$group$(f); + + return TREXIO_SUCCESS; + +} + #+end_src + +* 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); @@ -335,12 +383,7 @@ trexio_text_read_$group$ (trexio_text_t* const file) rc = fscanf(f, "%u", &($group$->rank_$group_dset$)); if (rc != 1) { - FREE(buffer); - fclose(f); - /* Set pointer to the struct so that the garbage collector can do the job on file handle */ - file->$group$ = $group$; - rc_free = trexio_text_free_$group$(file); - assert(rc_free == TREXIO_SUCCESS); + trexio_text_free_read_$group$(buffer, f, file, $group$); return NULL; } @@ -351,24 +394,14 @@ trexio_text_read_$group$ (trexio_text_t* const file) uint32_t j=0; rc = fscanf(f, "%1023s %u", buffer, &j); if ((rc != 2) || (strcmp(buffer, "dims_$group_dset$") != 0) || (j!=i)) { - FREE(buffer); - fclose(f); - /* Set pointer to the struct so that the garbage collector can do the job on file handle */ - file->$group$ = $group$; - rc_free = trexio_text_free_$group$(file); - assert(rc_free == TREXIO_SUCCESS); + trexio_text_free_read_$group$(buffer, f, file, $group$); return NULL; } rc = fscanf(f, "%" SCNu64 "\n", &($group$->dims_$group_dset$[i])); assert(!(rc != 1)); if (rc != 1) { - FREE(buffer); - fclose(f); - /* Set pointer to the struct so that the garbage collector can do the job on file handle */ - file->$group$ = $group$; - rc_free = trexio_text_free_$group$(file); - assert(rc_free == TREXIO_SUCCESS); + trexio_text_free_read_$group$(buffer, f, file, $group$); return NULL; } @@ -381,24 +414,14 @@ trexio_text_read_$group$ (trexio_text_t* const file) /* Allocate arrays */ $group$->$group_dset$ = CALLOC(size_$group_dset$, $group_dset_dtype$); if ($group$->$group_dset$ == NULL) { - FREE(buffer); - fclose(f); - /* Set pointer to the struct so that the garbage collector can do the job on file handle */ - file->$group$ = $group$; - rc_free = trexio_text_free_$group$(file); - assert(rc_free == TREXIO_SUCCESS); + trexio_text_free_read_$group$(buffer, f, file, $group$); return NULL; } for (uint64_t i=0 ; i$group_dset$[i])); if (rc != 1) { - FREE(buffer); - fclose(f); - /* Set pointer to the struct so that the garbage collector can do the job on file handle */ - file->$group$ = $group$; - rc_free = trexio_text_free_$group$(file); - assert(rc_free == TREXIO_SUCCESS); + trexio_text_free_read_$group$(buffer, f, file, $group$); return NULL; } } @@ -407,43 +430,33 @@ trexio_text_read_$group$ (trexio_text_t* const file) // START REPEAT GROUP_DSET_STR } else if (strcmp(buffer, "$group_dset$") == 0) { - if(size_$group_dset$ != 0) { + if (size_$group_dset$ != 0) { /* Allocate arrays */ $group$->$group_dset$ = CALLOC(size_$group_dset$, $group_dset_dtype$); if ($group$->$group_dset$ == NULL) { - FREE(buffer); - fclose(f); - /* Set pointer to the struct so that the garbage collector can do the job on file handle */ - file->$group$ = $group$; - rc_free = trexio_text_free_$group$(file); - assert(rc_free == TREXIO_SUCCESS); + trexio_text_free_read_$group$(buffer, f, file, $group$); return NULL; } /* WARNING: this tmp array allows to avoid allocation of space for each element of array of string - BUT it's size has to be number_of_str*max_len_str where max_len_str is somewhat arbitrary, e.g. 32. - ,*/ + * BUT it's size has to be number_of_str*max_len_str where max_len_str is somewhat arbitrary, e.g. 32. + */ char* tmp_$group_dset$; tmp_$group_dset$ = CALLOC(size_$group_dset$*32, char); for (uint64_t i=0 ; i$group_dset$[i] = tmp_$group_dset$; /* conventional fcanf with "%s" only return the string before the first space character - ,* to read string with spaces use "%[^\n]" possible with space before or after, i.e. " %[^\n]" - ,* Q: depending on what ? */ - rc = fscanf(f, " %1023[^\n]", tmp_$group_dset$); - assert(!(rc != 1)); + * to read string with spaces use "%[^\n]" possible with space before or after, i.e. " %[^\n]" + */ + rc = fscanf(f, " %1023[^\n]", buffer); if (rc != 1) { - FREE(buffer); - fclose(f); - /* Set pointer to the struct so that the garbage collector can do the job on file handle */ - file->$group$ = $group$; - rc_free = trexio_text_free_$group$(file); - assert(rc_free == TREXIO_SUCCESS); + trexio_text_free_read_$group$(buffer, f, file, $group$); return NULL; } - size_t tmp_$group_dset$_len = strlen($group$->$group_dset$[i]); + size_t tmp_$group_dset$_len = strlen(buffer); + strncpy(tmp_$group_dset$, buffer, 32); tmp_$group_dset$ += tmp_$group_dset$_len + 1; } } @@ -456,41 +469,25 @@ trexio_text_read_$group$ (trexio_text_t* const file) /* additional parameter $group_num$_isSet is needed to suppress warning when fscanf into bool variable using %u or %d */ rc = fscanf(f, "%u", &($group_num$_isSet)); $group$->$group_num$_isSet = (bool) $group_num$_isSet; - assert(!(rc != 1)); if (rc != 1) { - FREE(buffer); - fclose(f); - /* Set pointer to the struct so that the garbage collector can do the job on file handle */ - file->$group$ = $group$; - rc_free = trexio_text_free_$group$(file); - assert(rc_free == TREXIO_SUCCESS); + trexio_text_free_read_$group$(buffer, f, file, $group$); return NULL; } if ($group$->$group_num$_isSet == true) { + rc = fscanf(f, "%1023s", buffer); - assert(!((rc != 1) || (strcmp(buffer, "$group_num$") != 0))); if ((rc != 1) || (strcmp(buffer, "$group_num$") != 0)) { - FREE(buffer); - fclose(f); - /* Set pointer to the struct so that the garbage collector can do the job on file handle */ - file->$group$ = $group$; - rc_free = trexio_text_free_$group$(file); - assert(rc_free == TREXIO_SUCCESS); + trexio_text_free_read_$group$(buffer, f, file, $group$); return NULL; } rc = fscanf(f, "%$group_num_format_scanf$", &($group$->$group_num$)); - assert(!(rc != 1)); if (rc != 1) { - FREE(buffer); - fclose(f); - /* Set pointer to the struct so that the garbage collector can do the job on file handle */ - file->$group$ = $group$; - rc_free = trexio_text_free_$group$(file); - assert(rc_free == TREXIO_SUCCESS); + trexio_text_free_read_$group$(buffer, f, file, $group$); return NULL; } + } // END REPEAT GROUP_NUM @@ -498,57 +495,34 @@ trexio_text_read_$group$ (trexio_text_t* const file) } else if (strcmp(buffer, "len_$group_str$") == 0) { rc = fscanf(f, "%" SCNu64 "", &($group$->len_$group_str$)); - assert(!(rc != 1)); if (rc != 1) { - FREE(buffer); - fclose(f); - /* Set pointer to the struct so that the garbage collector can do the job on file handle */ - file->$group$ = $group$; - rc_free = trexio_text_free_$group$(file); - assert(rc_free == TREXIO_SUCCESS); + trexio_text_free_read_$group$(buffer, f, file, $group$); return NULL; } rc = fscanf(f, "%1023s", buffer); - assert(!((rc != 1) || (strcmp(buffer, "$group_str$") != 0))); if ((rc != 1) || (strcmp(buffer, "$group_str$") != 0)) { - FREE(buffer); - fclose(f); - /* Set pointer to the struct so that the garbage collector can do the job on file handle */ - file->$group$ = $group$; - rc_free = trexio_text_free_$group$(file); - assert(rc_free == TREXIO_SUCCESS); + trexio_text_free_read_$group$(buffer, f, file, $group$); return NULL; } if ($group$->len_$group_str$ != 0) { $group$->$group_str$ = CALLOC($group$->len_$group_str$, char); - assert (!($group$->$group_str$ == NULL)); if ($group$->$group_str$ == NULL) { - FREE(buffer); - fclose(f); - /* Set pointer to the struct so that the garbage collector can do the job on file handle */ - file->$group$ = $group$; - rc_free = trexio_text_free_$group$(file); - assert(rc_free == TREXIO_SUCCESS); + trexio_text_free_read_$group$(buffer, f, file, $group$); return NULL; } - rc = fscanf(f, " %1023[^\n]", $group$->$group_str$); - assert(!(rc != 1)); + rc = fscanf(f, " %1023[^\n]", buffer); if (rc != 1) { - FREE(buffer); - fclose(f); - /* Set pointer to the struct so that the garbage collector can do the job on file handle */ - file->$group$ = $group$; - rc_free = trexio_text_free_$group$(file); - assert(rc_free == TREXIO_SUCCESS); + trexio_text_free_read_$group$(buffer, f, file, $group$); return NULL; } + /* Safer string conversion to avoid buffer overflow in fscanf */ + strncpy($group$->$group_str$, buffer, $group$->len_$group_str$); } - // END REPEAT GROUP_ATTR_STR } else { continue; @@ -563,11 +537,51 @@ trexio_text_read_$group$ (trexio_text_t* const file) file->$group$ = $group$; return $group$; - } #+end_src -** Template for text flush a group +* Template for text has a group + + #+begin_src c :tangle hrw_group_text.h :exports none +trexio_exit_code trexio_text_has_$group$(trexio_t* const file); + #+end_src + + #+begin_src c :tangle has_group_text.c +trexio_exit_code +trexio_text_has_$group$ (trexio_t* const file) +{ + + if (file == NULL) return TREXIO_INVALID_ARG_1; + + /* Flush the group to make sure the group.txt file is created */ + if (file->mode != 'r') { + trexio_exit_code rc = trexio_text_flush_$group$((trexio_text_t*) file); + if (rc != TREXIO_SUCCESS) return TREXIO_FAILURE; + } + + /* Build the file name */ + char $group$_full_path[TREXIO_MAX_FILENAME_LENGTH]; + + const char* $group$_file_name = "/$group$.txt"; + + strncpy ($group$_full_path, file->file_name, TREXIO_MAX_FILENAME_LENGTH); + strncat ($group$_full_path, $group$_file_name, + TREXIO_MAX_FILENAME_LENGTH-strlen($group$_file_name)); + + if ($group$_full_path[TREXIO_MAX_FILENAME_LENGTH-1] != '\0') return TREXIO_FAILURE; + + bool file_exists; + file_exists = trexio_text_file_exists($group$_full_path); + + if (file_exists) { + return TREXIO_SUCCESS; + } else { + return TREXIO_HAS_NOT; + } +} + #+end_src + +* 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 +646,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. @@ -661,7 +675,7 @@ trexio_text_free_$group$ (trexio_text_t* const file) // START REPEAT GROUP_DSET_STR if ($group$->$group_dset$ != NULL) { - if($group$->rank_$group_dset$ != 0) FREE ($group$->$group_dset$[0]); + if ($group$->rank_$group_dset$ != 0) FREE ($group$->$group_dset$[0]); FREE ($group$->$group_dset$); } // END REPEAT GROUP_DSET_STR @@ -678,7 +692,26 @@ trexio_text_free_$group$ (trexio_text_t* const file) } #+end_src -** Template for has/read/write a numerical attribute + This function is called upon the non-successful exit from the ~trexio_text_read_group~ function. + + #+begin_src c :tangle free_group_text.c +trexio_exit_code +trexio_text_free_read_$group$ (char* buffer, FILE* txt_file, trexio_text_t* trexio_file, $group$_t* $group$) +{ + trexio_exit_code rc_free; + + FREE(buffer); + fclose(txt_file); + /* Set pointer to the struct so that the garbage collector can do the job on file handle */ + trexio_file->$group$ = $group$; + rc_free = trexio_text_free_$group$(trexio_file); + assert(rc_free == TREXIO_SUCCESS); + + return TREXIO_SUCCESS; +} + #+end_src + +* 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 +775,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 +870,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 +970,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 +1045,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 @@ -1055,8 +1088,7 @@ trexio_exit_code trexio_text_write_$group_dset$(trexio_t* const file, /* 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; - + if (f == NULL) return TREXIO_FILE_ERROR; /* Specify the line length in order to offset properly. For example, for 4-index quantities the line_length is 69 because 10 per index + 4 spaces + 24 for floating point value + 1 for the new line char. @@ -1091,7 +1123,7 @@ trexio_exit_code trexio_text_write_$group_dset$(trexio_t* const file, rc = fprintf(f, format_str, $group_dset_sparse_indices_printf$, ,*(value_sparse + i)); - if(rc <= 0) { + if (rc <= 0) { fclose(f); return TREXIO_FAILURE; } @@ -1119,6 +1151,23 @@ trexio_exit_code trexio_text_write_$group_dset$(trexio_t* const file, rc = fclose(f_wSize); if (rc != 0) return TREXIO_FILE_ERROR; + const char $group$_file_name[256] = "/$group$.txt"; + + memset (file_full_path, 0, 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, $group$_file_name, + TREXIO_MAX_FILENAME_LENGTH-strlen($group$_file_name)); + + bool file_exists = trexio_text_file_exists(file_full_path); + + /* Create an empty file for the trexio_text_has_group to work */ + if (!file_exists) { + FILE *fp = fopen(file_full_path, "ab+"); + fclose(fp); + } + /* Exit upon success */ return TREXIO_SUCCESS; } @@ -1152,7 +1201,7 @@ trexio_exit_code trexio_text_read_$group_dset$(trexio_t* const file, /* 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; + if (f == NULL) return TREXIO_FILE_ERROR; /* Specify the line length in order to offset properly. For example, for 4-index quantities the line_length is 69 because 10 per index + 4 spaces + 24 for floating point value + 1 for the new line char @@ -1178,7 +1227,7 @@ trexio_exit_code trexio_text_read_$group_dset$(trexio_t* const file, memset(buffer, 0, sizeof(buffer)); - if(fgets(buffer, 1023, f) == NULL){ + if (fgets(buffer, 1023, f) == NULL){ fclose(f); ,*eof_read_size = count; @@ -1189,7 +1238,7 @@ trexio_exit_code trexio_text_read_$group_dset$(trexio_t* const file, rc = sscanf(buffer, "$group_dset_format_scanf$", $group_dset_sparse_indices_scanf$, value_sparse + i); - if(rc <= 0) { + if (rc <= 0) { fclose(f); return TREXIO_FAILURE; } @@ -1200,7 +1249,7 @@ trexio_exit_code trexio_text_read_$group_dset$(trexio_t* const file, /* Close the TXT file */ rc = fclose(f); - if(rc != 0) return TREXIO_FILE_ERROR; + if (rc != 0) return TREXIO_FILE_ERROR; return TREXIO_SUCCESS; } @@ -1227,7 +1276,7 @@ trexio_exit_code trexio_text_read_$group_dset$_size(trexio_t* const file, int64_ /* 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; + 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 */ @@ -1248,7 +1297,7 @@ trexio_exit_code trexio_text_read_$group_dset$_size(trexio_t* const file, int64_ /* Close the TXT file */ rc = fclose(f); - if(rc != 0) return TREXIO_FILE_ERROR; + if (rc != 0) return TREXIO_FILE_ERROR; /* Overwrite the value at the input address and return TREXIO_SUCCESS */ ,*size_max = size_accum; @@ -1284,7 +1333,237 @@ trexio_exit_code trexio_text_has_$group_dset$(trexio_t* const file) } #+end_src -** Template for text delete a group (UNSAFE mode) +* Template for has/read/write a buffered vector + + Each array is stored in a separate =.txt= file due to the fact that buffered 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 vector elements to be written. + + #+begin_src c :tangle hrw_buffered_text.h :exports none +trexio_exit_code trexio_text_has_$group_dset$(trexio_t* const file); +trexio_exit_code trexio_text_read_$group_dset$(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 dset); +trexio_exit_code trexio_text_write_$group_dset$(trexio_t* const file, const int64_t offset_file, const uint32_t rank, const uint64_t* dims, const double* dset); +trexio_exit_code trexio_text_read_$group_dset$_size(trexio_t* const file, int64_t* const size_max); + #+end_src + + #+begin_src c :tangle read_buffered_text.c +trexio_exit_code trexio_text_read_$group_dset$(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 dset) +{ + if (file == NULL) return TREXIO_INVALID_ARG_1; + if (eof_read_size == NULL) return TREXIO_INVALID_ARG_5; + if (dset == NULL) return TREXIO_INVALID_ARG_6; + + const char file_name[256] = "/$group_dset$.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, file_name, TREXIO_MAX_FILENAME_LENGTH - sizeof(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; + 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", dset + 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_$group_dset$_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; + + const char file_name[256] = "/$group_dset$.txt.size"; + + /* 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, file_name, TREXIO_MAX_FILENAME_LENGTH - sizeof(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_buffered_text.c +trexio_exit_code trexio_text_write_$group_dset$(trexio_t* const file, + const int64_t offset_file, + const uint32_t rank, + const uint64_t* dims, + const double* dset) +{ + if (file == NULL) return TREXIO_INVALID_ARG_1; + if (dset == NULL) return TREXIO_INVALID_ARG_5; + + const char file_name[256] = "/$group_dset$.txt"; + const int append_str_len = 6; + + /* 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, file_name, TREXIO_MAX_FILENAME_LENGTH - sizeof(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", *(dset+ 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", append_str_len); + + /* 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; + + /* Additional part for the trexio_text_has_group to work */ + const char group_file_name[256] = "/$group$.txt"; + + memset (file_full_path, 0, 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, group_file_name, TREXIO_MAX_FILENAME_LENGTH - sizeof(group_file_name)); + + bool file_exists = trexio_text_file_exists(file_full_path); + + /* Create an empty file for the trexio_text_has_group to work */ + if (!file_exists) { + FILE *fp = fopen(file_full_path, "ab+"); + fclose(fp); + } + + /* Exit upon success */ + return TREXIO_SUCCESS; +} + + #+end_src + + #+begin_src c :tangle has_buffered_text.c +trexio_exit_code trexio_text_has_$group_dset$(trexio_t* const file) +{ + if (file == NULL) return TREXIO_INVALID_ARG_1; + + const char file_name[256] = "/$group_dset$.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, file_name, TREXIO_MAX_FILENAME_LENGTH - sizeof(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 +* 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 +1592,195 @@ 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); + #+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 */ + 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; +} + #+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; + + /* Additional part for the trexio_text_has_group to work */ + const char det_file_name[256] = "/determinant.txt"; + + memset (file_full_path, 0, 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, det_file_name, + TREXIO_MAX_FILENAME_LENGTH-strlen(det_file_name)); + + bool file_exists = trexio_text_file_exists(file_full_path); + + /* Create an empty file for the trexio_text_has_group to work */ + if (!file_exists) { + FILE *fp = fopen(file_full_path, "ab+"); + fclose(fp); + } + + /* 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; + } +} + #+end_src + * Constant file suffixes (not used by the generator) :noexport: #+begin_src c :tangle suffix_text.h diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f1c2264..d415c17 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/delete_group_text.c b/tests/delete_group_text.c index 87e4c46..37f338b 100644 --- a/tests/delete_group_text.c +++ b/tests/delete_group_text.c @@ -5,7 +5,7 @@ #define TEST_BACKEND TREXIO_TEXT #define TREXIO_FILE "test_del.dir" -#define RM_COMMAND "rm -rf " TREXIO_FILE +#define RM_COMMAND "rm -f -- " TREXIO_FILE "/*.txt " TREXIO_FILE "/*.txt.size " TREXIO_FILE "/.lock && rm -fd -- " TREXIO_FILE static int test_write_delete_group (const char* file_name, const back_end_t backend) { diff --git a/tests/io_all.c b/tests/io_all.c index e476efd..9096d29 100644 --- a/tests/io_all.c +++ b/tests/io_all.c @@ -26,11 +26,11 @@ int main() { assert (rc == 0); } - rc = system("rm -rf test_all.dir"); + rc = system("rm -f -- test_all.dir/*.txt test_all.dir/*.txt.size test_all.dir/.lock && rm -fd -- test_all.dir"); assert (rc == 0); test_write("test_all.dir", TREXIO_TEXT); test_read ("test_all.dir", TREXIO_TEXT); - rc = system("rm -rf test_all.dir"); + rc = system("rm -f -- test_all.dir/*.txt test_all.dir/*.txt.size test_all.dir/.lock && rm -fd -- test_all.dir"); assert (rc == 0); return 0; @@ -94,6 +94,10 @@ int test_write(const char* file_name, const back_end_t backend) { rc = trexio_write_nucleus_coord(file,coord); assert (rc == TREXIO_SUCCESS); + // check the force flushing + rc = trexio_flush(file); + assert (rc == TREXIO_SUCCESS); + rc = trexio_write_nucleus_label(file, label, 32); assert (rc == TREXIO_SUCCESS); rc = trexio_write_nucleus_point_group(file, sym, 32); diff --git a/tests/io_determinant_hdf5.c b/tests/io_determinant_hdf5.c new file mode 100644 index 0000000..5538680 --- /dev/null +++ b/tests/io_determinant_hdf5.c @@ -0,0 +1,326 @@ +#include "trexio.h" +#include +#include +#include +#include + +#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; + + // 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); + } + + // get the number of int64 bit fields per determinant + int int_num; + rc = trexio_get_int64_num(file, &int_num); + assert(rc == TREXIO_SUCCESS); + assert(int_num == (MO_NUM-1)/64 + 1); + + // allocate memory and fill with values to be written + det_list = (int64_t*) calloc(2 * int_num * SIZE, sizeof(int64_t)); + det_coef = (double*) calloc(SIZE, sizeof(double)); + + for(int i=0; i 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 +#include +#include +#include + +#define TEST_BACKEND TREXIO_TEXT +#define TREXIO_FILE "test_determinant.dir" +#define RM_COMMAND "rm -f -- " TREXIO_FILE "/*.txt " TREXIO_FILE "/*.txt.size " TREXIO_FILE "/.lock && rm -fd -- " 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; + + // 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); + } + + // get the number of int64 bit fields per determinant + int int_num; + rc = trexio_get_int64_num(file, &int_num); + assert(rc == TREXIO_SUCCESS); + assert(int_num == (MO_NUM-1)/64 + 1); + + // allocate memory and fill with values to be written + det_list = (int64_t*) calloc(2 * int_num * SIZE, sizeof(int64_t)); + det_coef = (double*) calloc(SIZE, sizeof(double)); + + for(int i=0; i 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_max) - offset_file_read = 97; + 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 @@ -159,11 +167,6 @@ static int test_read_dset_sparse (const char* file_name, const back_end_t backen assert(chunk_read == eof_read_size_check); assert(index_read[4*size_r-1] == 0); assert(index_read[4*offset_data_read] == 4 * (int32_t) (offset_file_read-offset)); - /* - for(int i=0; i #define TEST_BACKEND TREXIO_TEXT -#define TREXIO_FILE "test_dset_sparse.dir" -#define RM_COMMAND "rm -rf " TREXIO_FILE +#define TREXIO_FILE "test_pre_close.dir" +#define RM_COMMAND "rm -f -- " TREXIO_FILE "/*.txt " TREXIO_FILE "/*.txt.size " TREXIO_FILE "/.lock && rm -fd -- " TREXIO_FILE static int test_pre_close_1 (const char* file_name, const back_end_t backend) { diff --git a/tests/test_f.f90 b/tests/test_f.f90 index 421ed0b..c625b95 100644 --- a/tests/test_f.f90 +++ b/tests/test_f.f90 @@ -6,20 +6,20 @@ program test_trexio integer :: rc logical :: have_hdf5 - print * , "============================================" + print'(a)' , "============================================" print'(a,a)' , " TREXIO VERSION STRING : ", TREXIO_PACKAGE_VERSION print'(a,i3)', " TREXIO MAJOR VERSION : ", TREXIO_VERSION_MAJOR print'(a,i3)', " TREXIO MINOR VERSION : ", TREXIO_VERSION_MINOR - print * , "============================================" + print'(a)' , "============================================" rc = trexio_info() - call system('rm -rf -- test_write_f.dir') + call system('rm -f -- test_write_f.dir/*.txt test_write_f.dir/*.txt.size test_write_f.dir/.lock && rm -fd -- test_write_f.dir') print *, 'call test_write(''test_write_f.dir'', TREXIO_TEXT)' call test_write('test_write_f.dir', TREXIO_TEXT) print *, 'call test_read(''test_write_f.dir'', TREXIO_TEXT)' call test_read('test_write_f.dir', TREXIO_TEXT) - call system('rm -rf -- test_write_f.dir') + call system('rm -f -- test_write_f.dir/*.txt test_write_f.dir/*.txt.size test_write_f.dir/.lock && rm -fd -- test_write_f.dir') call test_read_void('test_write_f.dir', TREXIO_TEXT) @@ -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) @@ -63,25 +63,42 @@ subroutine test_write(file_name, back_end) character(len=:), allocatable :: sym_str character(len=:), allocatable :: label(:) + double precision, allocatable :: energy(:) + integer , allocatable :: spin(:) ! 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 :: int_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 +114,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 +139,19 @@ 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_has_nucleus(trex_file) + call trexio_assert(rc, TREXIO_HAS_NOT, 'SUCCESS HAS NOT 5') + + rc = trexio_has_ao_2e_int(trex_file) + call trexio_assert(rc, TREXIO_HAS_NOT, 'SUCCESS HAS NOT 6') + + 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 +174,50 @@ 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 + allocate(energy(mo_num)) + do i=1,mo_num + energy(i) = dble(i)-100.d0 + enddo + rc = trexio_write_mo_energy(trex_file, energy) + call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS WRITE ENERGY') + deallocate(energy) + + allocate(spin(mo_num)) + spin(:) = 0 + do i=mo_num/2+1,mo_num + spin(i) = 1 + enddo + rc = trexio_write_mo_spin(trex_file, spin) + call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS WRITE SPIN') + deallocate(spin) + + 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 +226,18 @@ 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_has_nucleus(trex_file) + call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS HAS 5') + + rc = trexio_has_ao_2e_int(trex_file) + call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS HAS 6') + rc = trexio_close(trex_file) call trexio_assert(rc, TREXIO_SUCCESS, 'SUCCESS CLOSE') @@ -201,10 +271,13 @@ subroutine test_read(file_name, back_end) character(len=4) :: label(12) ! also works with allocatable arrays character(len=32) :: sym_str + integer :: mo_num + double precision, allocatable :: energy(:) + integer , allocatable :: spin(:) ! 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 +286,31 @@ 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 :: det_list_check(3) + integer*8 :: read_buf_det_size = 20 + integer*8 :: offset_det_read = 10 + integer*8 :: offset_det_data_read = 5 + integer*8 :: determinant_num + integer :: int_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 ===================== ! @@ -259,9 +350,11 @@ subroutine test_read(file_name, back_end) endif - rc = trexio_read_nucleus_label(trex_file, label, 2) + rc = trexio_read_nucleus_label(trex_file, label, 4) call trexio_assert(rc, TREXIO_SUCCESS) - if (trim(label(2)) == 'Na') then + if (trim(label(2)) == 'Na' .and. & + trim(label(4)) == 'C 66' .and. & + trim(label(5)) == 'C') then write(*,*) 'SUCCESS READ LABEL' else print *, 'FAILURE LABEL CHECK' @@ -289,15 +382,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 +400,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 +418,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 +428,99 @@ subroutine test_read(file_name, back_end) call exit(-1) endif + ! obtain a number of int64 bit fields per determinant + rc = trexio_get_int64_num(trex_file, int_num) + call trexio_assert(rc, TREXIO_SUCCESS) + if (int_num == 3) then + write(*,*) 'SUCCESS GET INT64_NUM' + else + print *, 'FAILURE DET INT64_NUM CHECK' + 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 + ! Print occupied orbitals for an up-spin component of a given determinant + !write(*,*) orb_list_up(1:occ_num_up) + ! Print integers representanting a given determinant fully (up- and down-spin components) + !write(*,*) det_list(:, offset_det_data_read+1) + ! Print binary representation of the first integer bit field of a given determinant + !write(*,'(B64.64)') det_list(1, 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 + + ! convert one orbital list into a bitfield determinant representation + rc = trexio_to_bitfield_list(orb_list_up, occ_num_up, det_list_check, 3) + !write(*,*) occ_num_up, occ_num_dn + ! Print occupied orbitals for an up-spin component of a given determinant + !write(*,*) orb_list_up(1:occ_num_up) + ! Print integers representanting a given determinant fully (up- and down-spin components) + !write(*,*) det_list(1:3, offset_det_data_read+1) + !write(*,*) det_list_check(1:3) + ! Print binary representation of the first integer bit field of a given determinant + !write(*,'(B64.64)') det_list(1, offset_det_data_read+1) + call trexio_assert(rc, TREXIO_SUCCESS) + if (det_list_check(1) == det_list(1, offset_det_data_read+1) .and. & + det_list_check(2) == det_list(2, offset_det_data_read+1) .and. & + det_list_check(3) == det_list(3, offset_det_data_read+1)) then + write(*,*) 'SUCCESS CONVERT ORB LIST' + else + print *, 'FAILURE ORB CONVERT CHECK' + call exit(-1) + endif + + rc = trexio_read_mo_num(trex_file, mo_num) + call trexio_assert(rc, TREXIO_SUCCESS) + + allocate(spin(mo_num), energy(mo_num)) + rc = trexio_read_mo_energy(trex_file, energy) + call trexio_assert(rc, TREXIO_SUCCESS) + + if (energy(10) /= -90.d0) then + print *, 'Failure to read MO energy: ', energy(10) + call exit(-1) + end if + + rc = trexio_read_mo_spin(trex_file, spin) + call trexio_assert(rc, TREXIO_SUCCESS) + + if (sum(spin) /= mo_num/2) then + print *, 'Failure to read MO spin', mo_num, sum(spin) + call exit(-1) + end if + + ! close the file rc = trexio_close(trex_file) call trexio_assert(rc, TREXIO_SUCCESS) @@ -352,7 +538,7 @@ subroutine test_read_void(file_name, back_end) character*(*), intent(in) :: file_name integer, intent(in) :: back_end - integer(8) :: trex_file + integer(trexio_t) :: trex_file integer :: rc = 1 character(128) :: str @@ -365,7 +551,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 ===================== ! diff --git a/tools/generator.py b/tools/generator.py index 9904921..26606fc 100644 --- a/tools/generator.py +++ b/tools/generator.py @@ -12,12 +12,12 @@ detailed_nums = get_detailed_num_dict(trex_config) detailed_strs = get_detailed_str_dict(trex_config) # helper dictionaries that contain names of groups, nums or dsets as keys dsets = get_dset_dict(trex_config) -detailed_dsets_nostr, detailed_dsets_str, detailed_dsets_sparse = split_dset_dict_detailed(dsets) +detailed_dsets_nostr, detailed_dsets_str, detailed_dsets_sparse, detailed_dsets_buf = split_dset_dict_detailed(dsets) detailed_dsets = detailed_dsets_nostr.copy() detailed_dsets.update(detailed_dsets_str) # build a big dictionary with all pre-processed data detailed_all = { - 'datasets' : dict(detailed_dsets_nostr, **detailed_dsets_str, **detailed_dsets_sparse), + 'datasets' : dict(detailed_dsets_nostr, **detailed_dsets_str, **detailed_dsets_sparse, **detailed_dsets_buf), 'groups' : group_dict, 'numbers' : detailed_nums, 'strings' : detailed_strs @@ -62,10 +62,14 @@ for fname in files_todo['dset_str']: for fname in files_todo['dset_sparse']: recursive_populate_file(fname, template_paths, detailed_dsets_sparse) +# populate has/read/write_buffered functions with recursive scheme +for fname in files_todo['buffered']: + recursive_populate_file(fname, template_paths, detailed_dsets_buf) + # populate group-related functions with mixed scheme for fname in files_todo['group']: # recursive scheme for delete_group functions - if 'delete' in fname: + if 'delete' in fname or 'has' in fname: recursive_populate_file(fname, template_paths, group_dict) # mixed (iterative+recursive) scheme [text backend] else: diff --git a/tools/generator_tools.py b/tools/generator_tools.py index c58e5f4..2cde76f 100644 --- a/tools/generator_tools.py +++ b/tools/generator_tools.py @@ -37,8 +37,11 @@ def get_files_todo(source_files: dict) -> dict: all_files += source_files[key] files_todo = {} - files_todo['all'] = [f for f in all_files if 'read' in f or 'write' in f or 'has' in f or 'flush' in f or 'free' in f or 'hrw' in f or 'delete' in f] - for key in ['dset_data', 'dset_str', 'dset_sparse', 'attr_num', 'attr_str', 'group']: + files_todo['all'] = [ + f for f in all_files + if 'read' in f or 'write' in f or 'has' in f or 'flush' in f or 'free' in f or 'hrw' in f or 'delete' in f + ] + for key in ['dset_data', 'dset_str', 'dset_sparse', 'attr_num', 'attr_str', 'group', 'buffered']: files_todo[key] = list(filter(lambda x: key in x, files_todo['all'])) files_todo['group'].append('struct_text_group_dset.h') @@ -105,17 +108,23 @@ def recursive_populate_file(fname: str, paths: dict, detailed_source: dict) -> N triggers = ['group_dset_dtype', 'group_dset_py_dtype', 'group_dset_h5_dtype', 'default_prec', 'is_index', 'group_dset_f_dtype_default', 'group_dset_f_dtype_double', 'group_dset_f_dtype_single', 'group_dset_dtype_default', 'group_dset_dtype_double', 'group_dset_dtype_single', - 'group_dset_rank', 'group_dset_dim_list', 'group_dset_f_dims', + 'group_dset_rank', 'group_dset_unique_rank', 'group_dset_dim_list', 'group_dset_f_dims', 'group_num_f_dtype_default', 'group_num_f_dtype_double', 'group_num_f_dtype_single', 'group_num_dtype_default', 'group_num_dtype_double', 'group_num_dtype_single', - 'group_num_h5_dtype', 'group_num_py_dtype', - 'group_dset_format_scanf', 'group_dset_format_printf', 'group_dset_sparse_dim', + 'group_num_h5_dtype', 'group_num_py_dtype', 'group_dset_format_scanf', 'group_dset_format_printf', 'group_dset_sparse_indices_printf', 'group_dset_sparse_indices_scanf', 'sparse_format_printf_8', 'sparse_format_printf_16', 'sparse_format_printf_32', 'sparse_line_length_8', 'sparse_line_length_16', 'sparse_line_length_32', 'group_dset', 'group_num', 'group_str', 'group'] for item in detailed_source.keys(): + + # special case to exclude write functions for readonly dimensions (like determinant_num) from the public API + if 'write' in fname and 'front' in fname and ('.f90' in fname or '.py' in fname): + if 'trex_json_int_type' in detailed_source[item].keys(): + if 'readonly' in detailed_source[item]['trex_json_int_type']: + continue + with open(join(templ_path,fname), 'r') as f_in : with open(join(templ_path,fname_new), 'a') as f_out : num_written = [] @@ -137,14 +146,27 @@ def recursive_populate_file(fname: str, paths: dict, detailed_source: dict) -> N continue # special case to uncomment check for positive dimensioning variables in templates elif 'uncommented by the generator for dimensioning' in line: - # only uncomment and write the line if `num` is in the name + # only uncomment and write the line if `dim` is in the name if 'dim' in detailed_source[item]['trex_json_int_type']: templine = line.replace('//', '') f_out.write(templine) + # special case to get the max dimension of sparse datasets with different dimensions + elif 'trexio_read_$group_dset_unique_dim$_64' in line: + for i in range(int(detailed_source[item]['group_dset_unique_rank'])): + templine = line.replace('$group_dset_unique_dim$', detailed_source[item]['unique_dims'][i]).replace('$dim_id$', str(i)) + f_out.write(templine) # general case of recursive replacement of inline triggers else: populated_line = recursive_replace_line(line, triggers, detailed_source[item]) - f_out.write(populated_line) + # special case to include some functions in the private header + if 'trex_json_int_type' in detailed_source[item].keys(): + if 'readonly' in detailed_source[item]['trex_json_int_type'] and 'write' in line and 'front.h' in fname: + with open(join(templ_path,'populated/private_pop_front.h'), 'a') as f_priv: + f_priv.write(populated_line) + else: + f_out.write(populated_line) + else: + f_out.write(populated_line) f_out.write("\n") @@ -214,7 +236,7 @@ def iterative_populate_file (filename: str, paths: dict, detailed_all: dict) -> for line in f_in : id = check_triggers(line, triggers) if id == 0: - # special case for proper error handling when deallocting text groups + # special case for proper error handling when deallocating text groups error_handler = ' if (rc != TREXIO_SUCCESS) return rc;\n' populated_line = iterative_replace_line(line, '$group$', detailed_all['groups'], add_line=error_handler) f_out.write(populated_line) @@ -477,7 +499,22 @@ def get_dtype_dict (dtype: str, target: str, rank = None, int_len_printf = None) f'group_{target}_format_scanf' : 'lf', f'group_{target}_py_dtype' : 'float' }) - elif dtype in ['int', 'dim', 'index']: + elif 'buffered' in dtype: + dtype_dict.update({ + 'default_prec' : '64', + f'group_{target}_dtype' : 'double', + f'group_{target}_h5_dtype' : 'native_double', + f'group_{target}_f_dtype_default' : 'real(c_double)', + f'group_{target}_f_dtype_double' : 'real(c_double)', + f'group_{target}_f_dtype_single' : 'real(c_float)', + f'group_{target}_dtype_default' : 'double', + f'group_{target}_dtype_double' : 'double', + f'group_{target}_dtype_single' : 'float', + f'group_{target}_format_printf' : '24.16e', + f'group_{target}_format_scanf' : 'lf', + f'group_{target}_py_dtype' : 'float' + }) + elif dtype in ['int', 'dim', 'dim readonly', 'index']: dtype_dict.update({ 'default_prec' : '32', f'group_{target}_dtype' : 'int64_t', @@ -517,7 +554,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 @@ -568,16 +605,17 @@ def get_detailed_num_dict (configuration: dict) -> dict: tmp_num = f'{k1}_{k2}' if not 'str' in v2[0]: tmp_dict = {} + tmp_dict['group'] = k1 tmp_dict['group_num'] = tmp_num - num_dict[tmp_num] = tmp_dict - tmp_dict.update(get_dtype_dict(v2[0], 'num')) - if v2[0] in ['int', 'dim']: + if v2[0] in ['int', 'dim', 'dim readonly']: tmp_dict['trex_json_int_type'] = v2[0] else: tmp_dict['trex_json_int_type'] = '' + num_dict[tmp_num] = tmp_dict + return num_dict @@ -638,17 +676,23 @@ def split_dset_dict_detailed (datasets: dict) -> tuple: configuration (dict) : configuration from `trex.json` Returns: - dset_numeric_dict, dset_string_dict (tuple) : dictionaries corresponding to all numeric- and string-based datasets, respectively. + (tuple) : dictionaries corresponding to all types of datasets in trexio. """ dset_numeric_dict = {} - dset_string_dict = {} - dset_sparse_dict = {} + dset_string_dict = {} + dset_sparse_dict = {} + dset_buffer_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 = {} @@ -674,11 +718,18 @@ def split_dset_dict_detailed (datasets: dict) -> tuple: else: tmp_dict['is_index'] = 'false' + # add the list of dimensions + tmp_dict['dims'] = [dim.replace('.','_') for dim in v[1]] + + # get a list of unique dimensions for sparse datasets + if is_sparse: + tmp_dict['unique_dims'] = list(set(tmp_dict['dims'])) + tmp_dict['group_dset_unique_rank'] = str(len(tmp_dict['unique_dims'])) + # add the rank tmp_dict['rank'] = rank tmp_dict['group_dset_rank'] = str(rank) - # add the list of dimensions - tmp_dict['dims'] = [dim.replace('.','_') for dim in v[1]] + # build a list of dimensions to be inserted in the dims array initialization, e.g. {ao_num, ao_num} dim_list = tmp_dict['dims'][0] if rank > 1: @@ -695,8 +746,6 @@ def split_dset_dict_detailed (datasets: dict) -> tuple: tmp_dict['group_dset_f_dims'] = dim_f_list if is_sparse: - # store the max possible dim of the sparse dset (e.g. mo_num) - tmp_dict['group_dset_sparse_dim'] = tmp_dict['dims'][0] # build printf/scanf sequence and compute line length for n-index sparse quantity index_printf = f'*(index_sparse + {str(rank)}*i' index_scanf = f'index_sparse + {str(rank)}*i' @@ -731,12 +780,14 @@ def split_dset_dict_detailed (datasets: dict) -> tuple: # split datasets in numeric- and string- based if 'str' in datatype: dset_string_dict[k] = tmp_dict + elif 'buffered' in datatype: + dset_buffer_dict[k] = tmp_dict elif is_sparse: dset_sparse_dict[k] = tmp_dict else: dset_numeric_dict[k] = tmp_dict - return (dset_numeric_dict, dset_string_dict, dset_sparse_dict) + return (dset_numeric_dict, dset_string_dict, dset_sparse_dict, dset_buffer_dict) def check_dim_consistency(num: dict, dset: dict) -> None: @@ -757,7 +808,10 @@ def check_dim_consistency(num: dict, dset: dict) -> None: if dim not in dim_tocheck: dim_tocheck.append(dim) - num_onlyDim = [attr_name for attr_name, specs in num.items() if specs['trex_json_int_type']=='dim'] + num_onlyDim = [ + attr_name for attr_name, specs in num.items() + if 'dim' in specs['trex_json_int_type'] + ] for dim in dim_tocheck: if not dim in num_onlyDim: diff --git a/tools/trexio.scm b/tools/trexio.scm index 5f8deb9..72c7f7e 100644 --- a/tools/trexio.scm +++ b/tools/trexio.scm @@ -1,15 +1,15 @@ -(define-module (gnu packages trexio) +(define-module (trexio) #:use-module (guix packages) #:use-module (gnu packages pkg-config) #:use-module (gnu packages glib) #:use-module (gnu packages gcc) #:use-module (gnu packages autotools) - #:use-module (gnu packages maths) + #:use-module (gnu packages maths) ;; contains hdf5 #:use-module (guix download) #:use-module (guix build-system gnu) #:use-module (guix licenses)) -(define-public trexio +(define-public trexio-2.0 (package (name "trexio") (version "2.0") @@ -20,15 +20,48 @@ ".tar.gz")) (sha256 (base32 + ;; the hash below is produced by guix download "1d2cn4w2r9gfid5b9wrq9q290kqdnbjdmvli76s1i5r58kdg5vkf" )))) (build-system gnu-build-system) (arguments '(#:configure-flags '("--enable-silent-rules"))) - (inputs `(("hdf5" ,hdf5-1.12) ("gfortran", gfortran))) - (synopsis "TREX I/O lbrary: trexio package") - (description "APIs in C and Fortran to exchange wavefunction data. - Supports HDF5 and TEXT back ends.") + (inputs `(("hdf5" ,hdf5) ("gfortran", gfortran))) + (synopsis "TREX I/O library") + (description "The TREXIO library defines a standard format for storing wave functions, together with + a C-compatible API such that it can be easily used in any programming language.") (home-page "https://trex-coe.github.io/trexio") (license bsd-3))) +(define-public trexio-2.1 + (package/inherit trexio-2.0 + (version "2.1.0") + (source (origin + (method url-fetch) + (uri (string-append "https://github.com/TREX-CoE/trexio/releases/download/v" version + "/trexio-" version + ".tar.gz")) + (sha256 + (base32 + ;; the hash below is produced by guix download + "10syfw4mq3wpp9anahmxnm7660bm1ya5xd9l5njai3xr8g4nca13" + )))))) + +(define-public trexio-2.2 + (package/inherit trexio-2.0 + (version "2.2.0") + (source (origin + (method url-fetch) + (uri (string-append "https://github.com/TREX-CoE/trexio/releases/download/v" version + "/trexio-" version + ".tar.gz")) + (sha256 + (base32 + ;; the hash below is produced by guix download + "1n9n1gbk5hgvg73am991xrv7ap002rz719a3nvh8m8ff9x10qd76" + )))))) + +(define-public trexio + ;; Default version of TREXIO. + trexio-2.2) + trexio diff --git a/trex.org b/trex.org index 8d1e733..d167b83 100644 --- a/trex.org +++ b/trex.org @@ -22,6 +22,10 @@ variables cannot be negative. This additional constraint is required because ~dim~ attributes are used internally to allocate memory and to check array boundaries in the memory-safe API. Most of the times, the ~dim~ variables contain the ~num~ suffix. +You may also encounter some ~dim readonly~ variables. +It means that the value is automatically computed and written by the +TREXIO library, thus it is read-only and cannot be (over)written by the +user. In Fortran, arrays are 1-based and in most other languages the arrays are 0-based. Hence, we introduce the ~index~ type which is a @@ -31,8 +35,16 @@ For sparse data structures such as electron replusion integrals, the data can be too large to fit in memory and the data needs to be fetched using multiple function calls to perform I/O on buffers. For more information on how to read/write sparse data structures, see -the [[./examples.html][examples]]. +the [[./examples.html][examples]]. The ~sparse~ data representation implies the +[[https://en.wikipedia.org/wiki/Sparse_matrix#Coordinate_list_(COO)][coordinate list]] representation, namely the user has to write a list +of indices and values. +For the Configuration Interfaction (CI) and Configuration State Function (CSF) +groups, the ~buffered~ data type is introduced, which allows similar incremental +I/O as for ~sparse~ data but without the need to write indices of the sparse values. + +For determinant lists (integer bit fields), the ~special~ attribute is present in the type. +This means that the source code is not produced by the generator, but hand-written. #+begin_src python :tangle trex.json :exports none { @@ -64,19 +76,19 @@ the [[./examples.html][examples]]. #+CALL: json(data=metadata, title="metadata") #+RESULTS: - :RESULTS: + :results: #+begin_src python :tangle trex.json "metadata": { - "code_num" : [ "dim", [] ] - , "code" : [ "str", [ "metadata.code_num" ] ] - , "author_num" : [ "dim", [] ] - , "author" : [ "str", [ "metadata.author_num" ] ] - , "package_version" : [ "str", [] ] - , "description" : [ "str", [] ] - , "unsafe" : [ "int", [] ] + "code_num" : [ "dim", [] ] + , "code" : [ "str", [ "metadata.code_num" ] ] + , "author_num" : [ "dim", [] ] + , "author" : [ "str", [ "metadata.author_num" ] ] + , "package_version" : [ "str", [] ] + , "description" : [ "str", [] ] + , "unsafe" : [ "int", [] ] } , #+end_src - :END: + :end: * Electron (electron group) @@ -191,20 +203,20 @@ If you encounter the aforementioned issue, please report it to our [[https://git #+CALL: json(data=ecp, title="ecp") #+RESULTS: - :RESULTS: + :results: #+begin_src python :tangle trex.json "ecp": { - "max_ang_mom_plus_1" : [ "int" , [ "nucleus.num" ] ] - , "z_core" : [ "int" , [ "nucleus.num" ] ] - , "num" : [ "dim" , [] ] - , "ang_mom" : [ "int" , [ "ecp.num" ] ] - , "nucleus_index" : [ "index", [ "ecp.num" ] ] - , "exponent" : [ "float", [ "ecp.num" ] ] - , "coefficient" : [ "float", [ "ecp.num" ] ] - , "power" : [ "int" , [ "ecp.num" ] ] + "max_ang_mom_plus_1" : [ "int" , [ "nucleus.num" ] ] + , "z_core" : [ "int" , [ "nucleus.num" ] ] + , "num" : [ "dim" , [] ] + , "ang_mom" : [ "int" , [ "ecp.num" ] ] + , "nucleus_index" : [ "index", [ "ecp.num" ] ] + , "exponent" : [ "float", [ "ecp.num" ] ] + , "coefficient" : [ "float", [ "ecp.num" ] ] + , "power" : [ "int" , [ "ecp.num" ] ] } , #+end_src - :END: + :end: ** Example @@ -310,6 +322,7 @@ power = [ | ~nucleus_index~ | ~index~ | ~(basis.shell_num)~ | One-to-one correspondence between shells and atomic indices | | ~shell_ang_mom~ | ~int~ | ~(basis.shell_num)~ | One-to-one correspondence between shells and angular momenta | | ~shell_factor~ | ~float~ | ~(basis.shell_num)~ | Normalization factor of each shell ($\mathcal{N}_s$) | + | ~r_power~ | ~int~ | ~(basis.shell_num)~ | Power to which $r$ is raised ($n_s$) | | ~shell_index~ | ~index~ | ~(basis.prim_num)~ | One-to-one correspondence between primitives and shell index | | ~exponent~ | ~float~ | ~(basis.prim_num)~ | Exponents of the primitives ($\gamma_{ks}$) | | ~coefficient~ | ~float~ | ~(basis.prim_num)~ | Coefficients of the primitives ($a_{ks}$) | @@ -318,22 +331,23 @@ power = [ #+CALL: json(data=basis, title="basis") #+RESULTS: - :RESULTS: + :results: #+begin_src python :tangle trex.json "basis": { - "type" : [ "str" , [] ] - , "prim_num" : [ "dim" , [] ] - , "shell_num" : [ "dim" , [] ] - , "nucleus_index" : [ "index", [ "basis.shell_num" ] ] - , "shell_ang_mom" : [ "int" , [ "basis.shell_num" ] ] - , "shell_factor" : [ "float", [ "basis.shell_num" ] ] - , "shell_index" : [ "index", [ "basis.prim_num" ] ] - , "exponent" : [ "float", [ "basis.prim_num" ] ] - , "coefficient" : [ "float", [ "basis.prim_num" ] ] - , "prim_factor" : [ "float", [ "basis.prim_num" ] ] + "type" : [ "str" , [] ] + , "prim_num" : [ "dim" , [] ] + , "shell_num" : [ "dim" , [] ] + , "nucleus_index" : [ "index", [ "basis.shell_num" ] ] + , "shell_ang_mom" : [ "int" , [ "basis.shell_num" ] ] + , "shell_factor" : [ "float", [ "basis.shell_num" ] ] + , "r_power" : [ "int" , [ "basis.shell_num" ] ] + , "shell_index" : [ "index", [ "basis.prim_num" ] ] + , "exponent" : [ "float", [ "basis.prim_num" ] ] + , "coefficient" : [ "float", [ "basis.prim_num" ] ] + , "prim_factor" : [ "float", [ "basis.prim_num" ] ] } , #+end_src - :END: + :end: ** Example @@ -464,16 +478,16 @@ prim_factor = #+CALL: json(data=ao, title="ao") #+RESULTS: - :RESULTS: + :results: #+begin_src python :tangle trex.json "ao": { - "cartesian" : [ "int" , [] ] - , "num" : [ "dim" , [] ] - , "shell" : [ "index", [ "ao.num" ] ] - , "normalization" : [ "float", [ "ao.num" ] ] + "cartesian" : [ "int" , [] ] + , "num" : [ "dim" , [] ] + , "shell" : [ "index", [ "ao.num" ] ] + , "normalization" : [ "float", [ "ao.num" ] ] } , #+end_src - :END: + :end: ** One-electron integrals (~ao_1e_int~ group) :PROPERTIES: @@ -492,13 +506,18 @@ prim_factor = over atomic orbitals. #+NAME: ao_1e_int - | Variable | Type | Dimensions | Description | - |--------------------+---------+--------------------+--------------------------------------------------------| - | ~overlap~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert q \rangle$ | - | ~kinetic~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert \hat{T}_e \vert q \rangle$ | - | ~potential_n_e~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert \hat{V}_{\text{ne}} \vert q \rangle$ | - | ~ecp~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert \hat{V}_{\text{ecp}} \vert q \rangle$ | - | ~core_hamiltonian~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert \hat{h} \vert q \rangle$ | + | Variable | Type | Dimensions | Description | + |-----------------------+---------+--------------------+-----------------------------------------------------------------------------------| + | ~overlap~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert q \rangle$ (real part, general case) | + | ~kinetic~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert \hat{T}_e \vert q \rangle$ (real part, general case) | + | ~potential_n_e~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert \hat{V}_{\text{ne}} \vert q \rangle$ (real part, general case) | + | ~ecp~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert \hat{V}_{\text{ecp}} \vert q \rangle$ (real part, general case) | + | ~core_hamiltonian~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert \hat{h} \vert q \rangle$ (real part, general case) | + | ~overlap_im~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert q \rangle$ (imaginary part) (imaginary part) | + | ~kinetic_im~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert \hat{T}_e \vert q \rangle$ (imaginary part) | + | ~potential_n_e_im~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert \hat{V}_{\text{ne}} \vert q \rangle$ (imaginary part) | + | ~ecp_im~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert \hat{V}_{\text{ECP}} \vert q \rangle$ (imaginary part) | + | ~core_hamiltonian_im~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert \hat{h} \vert q \rangle$ (imaginary part) | #+CALL: json(data=ao_1e_int, title="ao_1e_int") @@ -506,11 +525,16 @@ prim_factor = :results: #+begin_src python :tangle trex.json "ao_1e_int": { - "overlap" : [ "float", [ "ao.num", "ao.num" ] ] - , "kinetic" : [ "float", [ "ao.num", "ao.num" ] ] - , "potential_n_e" : [ "float", [ "ao.num", "ao.num" ] ] - , "ecp" : [ "float", [ "ao.num", "ao.num" ] ] - , "core_hamiltonian" : [ "float", [ "ao.num", "ao.num" ] ] + "overlap" : [ "float", [ "ao.num", "ao.num" ] ] + , "kinetic" : [ "float", [ "ao.num", "ao.num" ] ] + , "potential_n_e" : [ "float", [ "ao.num", "ao.num" ] ] + , "ecp" : [ "float", [ "ao.num", "ao.num" ] ] + , "core_hamiltonian" : [ "float", [ "ao.num", "ao.num" ] ] + , "overlap_im" : [ "float", [ "ao.num", "ao.num" ] ] + , "kinetic_im" : [ "float", [ "ao.num", "ao.num" ] ] + , "potential_n_e_im" : [ "float", [ "ao.num", "ao.num" ] ] + , "ecp_im" : [ "float", [ "ao.num", "ao.num" ] ] + , "core_hamiltonian_im" : [ "float", [ "ao.num", "ao.num" ] ] } , #+end_src :end: @@ -556,30 +580,36 @@ prim_factor = * Molecular orbitals (mo group) #+NAME: mo - | Variable | Type | Dimensions | Description | - |---------------+---------+--------------------+--------------------------------------------------------------------------| - | ~type~ | ~str~ | | Free text to identify the set of MOs (HF, Natural, Local, CASSCF, /etc/) | - | ~num~ | ~dim~ | | Number of MOs | - | ~coefficient~ | ~float~ | ~(ao.num, mo.num)~ | MO coefficients | - | ~class~ | ~str~ | ~(mo.num)~ | Choose among: Core, Inactive, Active, Virtual, Deleted | - | ~symmetry~ | ~str~ | ~(mo.num)~ | Symmetry in the point group | - | ~occupation~ | ~float~ | ~(mo.num)~ | Occupation number | + | Variable | Type | Dimensions | Description | + |------------------+---------+--------------------+--------------------------------------------------------------------------| + | ~type~ | ~str~ | | Free text to identify the set of MOs (HF, Natural, Local, CASSCF, /etc/) | + | ~num~ | ~dim~ | | Number of MOs | + | ~coefficient~ | ~float~ | ~(ao.num, mo.num)~ | MO coefficients (real part, general case) | + | ~coefficient_im~ | ~float~ | ~(ao.num, mo.num)~ | MO coefficients (imaginary part, for periodic calculations) | + | ~class~ | ~str~ | ~(mo.num)~ | Choose among: Core, Inactive, Active, Virtual, Deleted | + | ~symmetry~ | ~str~ | ~(mo.num)~ | Symmetry in the point group | + | ~occupation~ | ~float~ | ~(mo.num)~ | Occupation number | + | ~energy~ | ~float~ | ~(mo.num)~ | For canonical MOs, corresponding eigenvalue | + | ~spin~ | ~int~ | ~(mo.num)~ | For UHF wave functions, 0 is $\alpha$ and 1 is $\beta$ | #+CALL: json(data=mo, title="mo") #+RESULTS: - :RESULTS: + :results: #+begin_src python :tangle trex.json "mo": { - "type" : [ "str" , [] ] - , "num" : [ "dim" , [] ] - , "coefficient" : [ "float", [ "mo.num", "ao.num" ] ] - , "class" : [ "str" , [ "mo.num" ] ] - , "symmetry" : [ "str" , [ "mo.num" ] ] - , "occupation" : [ "float", [ "mo.num" ] ] + "type" : [ "str" , [] ] + , "num" : [ "dim" , [] ] + , "coefficient" : [ "float", [ "mo.num", "ao.num" ] ] + , "coefficient_im" : [ "float", [ "mo.num", "ao.num" ] ] + , "class" : [ "str" , [ "mo.num" ] ] + , "symmetry" : [ "str" , [ "mo.num" ] ] + , "occupation" : [ "float", [ "mo.num" ] ] + , "energy" : [ "float", [ "mo.num" ] ] + , "spin" : [ "int" , [ "mo.num" ] ] } , #+end_src - :END: + :end: ** One-electron integrals (~mo_1e_int~ group) @@ -588,13 +618,18 @@ prim_factor = the basis of molecular orbitals. #+NAME: mo_1e_int - | Variable | Type | Dimensions | Description | - |--------------------+---------+--------------------+--------------------------------------------------------| - | ~overlap~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert j \rangle$ | - | ~kinetic~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert \hat{T}_e \vert j \rangle$ | - | ~potential_n_e~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert \hat{V}_{\text{ne}} \vert j \rangle$ | - | ~ecp~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert \hat{V}_{\text{ECP}} \vert j \rangle$ | - | ~core_hamiltonian~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert \hat{h} \vert j \rangle$ | + | Variable | Type | Dimensions | Description | + |-----------------------+---------+--------------------+-----------------------------------------------------------------------------------| + | ~overlap~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert j \rangle$ (real part, general case) | + | ~kinetic~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert \hat{T}_e \vert j \rangle$ (real part, general case) | + | ~potential_n_e~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert \hat{V}_{\text{ne}} \vert j \rangle$ (real part, general case) | + | ~ecp~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert \hat{V}_{\text{ECP}} \vert j \rangle$ (real part, general case) | + | ~core_hamiltonian~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert \hat{h} \vert j \rangle$ (real part, general case) | + | ~overlap_im~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert j \rangle$ (imaginary part) (imaginary part) | + | ~kinetic_im~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert \hat{T}_e \vert j \rangle$ (imaginary part) | + | ~potential_n_e_im~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert \hat{V}_{\text{ne}} \vert j \rangle$ (imaginary part) | + | ~ecp_im~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert \hat{V}_{\text{ECP}} \vert j \rangle$ (imaginary part) | + | ~core_hamiltonian_im~ | ~float~ | ~(mo.num, mo.num)~ | $\langle i \vert \hat{h} \vert j \rangle$ (imaginary part) | #+CALL: json(data=mo_1e_int, title="mo_1e_int") @@ -602,26 +637,41 @@ prim_factor = :results: #+begin_src python :tangle trex.json "mo_1e_int": { - "overlap" : [ "float", [ "mo.num", "mo.num" ] ] - , "kinetic" : [ "float", [ "mo.num", "mo.num" ] ] - , "potential_n_e" : [ "float", [ "mo.num", "mo.num" ] ] - , "ecp" : [ "float", [ "mo.num", "mo.num" ] ] - , "core_hamiltonian" : [ "float", [ "mo.num", "mo.num" ] ] + "overlap" : [ "float", [ "mo.num", "mo.num" ] ] + , "kinetic" : [ "float", [ "mo.num", "mo.num" ] ] + , "potential_n_e" : [ "float", [ "mo.num", "mo.num" ] ] + , "ecp" : [ "float", [ "mo.num", "mo.num" ] ] + , "core_hamiltonian" : [ "float", [ "mo.num", "mo.num" ] ] + , "overlap_im" : [ "float", [ "mo.num", "mo.num" ] ] + , "kinetic_im" : [ "float", [ "mo.num", "mo.num" ] ] + , "potential_n_e_im" : [ "float", [ "mo.num", "mo.num" ] ] + , "ecp_im" : [ "float", [ "mo.num", "mo.num" ] ] + , "core_hamiltonian_im" : [ "float", [ "mo.num", "mo.num" ] ] } , #+end_src :end: ** Two-electron integrals (~mo_2e_int~ group) - The operators as the same as those defined in the + The operators are the same as those defined in the [[#ao_two_e][AO two-electron integrals section]]. Here, the integrals are given in the basis of molecular orbitals. + The Cholesky decomposition of the integrals can also be stored: + + \[ + \A_{ijkl} = \sum_{\alpha} G_{il\alpha} G_{jl\alpha} + \] + #+NAME: mo_2e_int - | Variable | Type | Dimensions | Description | - |----------+----------------+------------------------------------+-----------------------------------------| - | ~eri~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num)~ | Electron repulsion integrals | - | ~eri_lr~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num)~ | Long-range Electron repulsion integrals | + | Variable | Type | Dimensions | Description | + |-----------------------+----------------+---------------------------------------------------+-----------------------------------------------| + | ~eri~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num)~ | Electron repulsion integrals | + | ~eri_lr~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num)~ | Long-range Electron repulsion integrals | + | ~eri_cholesky_num~ | ~dim~ | | Number of Cholesky vectors for ERI | + | ~eri_cholesky~ | ~float sparse~ | ~(mo.num, mo.num, mo_2e_int.eri_cholesky_num)~ | Cholesky decomposition of the ERI | + | ~eri_lr_cholesky_num~ | ~dim~ | | Number of Cholesky vectors for long range ERI | + | ~eri_lr_cholesky~ | ~float sparse~ | ~(mo.num, mo.num, mo_2e_int.eri_lr_cholesky_num)~ | Cholesky decomposition of the long range ERI | #+CALL: json(data=mo_2e_int, title="mo_2e_int") @@ -629,19 +679,141 @@ prim_factor = :results: #+begin_src python :tangle trex.json "mo_2e_int": { - "eri" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] - , "eri_lr" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] + "eri" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] + , "eri_lr" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] + , "eri_cholesky_num" : [ "dim" , [] ] + , "eri_cholesky" : [ "float sparse", [ "mo_2e_int.eri_cholesky_num", "mo.num", "mo.num" ] ] + , "eri_lr_cholesky_num" : [ "dim" , [] ] + , "eri_lr_cholesky" : [ "float sparse", [ "mo_2e_int.eri_lr_cholesky_num", "mo.num", "mo.num" ] ] } , #+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 occupied orbitals. + However, this becomes unfeasible for larger expansions and requires more advanced data structures. + The bit field representation is used here, namely a given determinant is represented as $N_{\text{int}}$ + 64-bit integers where j-th bit is set to 1 if there is an electron in the j-th orbital and 0 otherwise. + This gives access to larger determinant expansions by optimising the storage of the determinant lists + in the memory. + + \[ + 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. + + Note: the ~special~ attribute is present in the types, meaning that the source node is not + produced by the code generator. + + An illustration on how to read determinants is presented in the [[./examples.html][examples]]. + + #+NAME: determinant + | Variable | Type | Dimensions | Description | + |---------------+------------------+---------------------+--------------------------------------------------------| + | ~num~ | ~dim readonly~ | | Number of determinants | + | ~list~ | ~int special~ | ~(determinant.num)~ | List of determinants as integer bit fields | + | ~coefficient~ | ~float buffered~ | ~(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 readonly" , [] ] + , "list" : [ "int special" , [ "determinant.num" ] ] + , "coefficient" : [ "float buffered", [ "determinant.num" ] ] + } , + #+end_src + :end: + +* Configuration state functions (csf group) + + The configuration interaction (CI) wave function $\Psi$ can be + expanded in the basis of [[https://en.wikipedia.org/wiki/Configuration_state_function][configuration state functions]] (CSFs) + $\Psi_I$ as follows + + \[ + \Psi = \sum_I C_I \psi_I. + \] + + Each CSF is a linear combination of Slater determinants. Slater + determinants are stored in the =determinant= section. In this group + we store the CI coefficients in the basis of CSFs, and the + matrix $\langle D_I | \psi_J \rangle$ needed to project the CSFs in + the basis of Slater determinants. + + #+NAME: csf + | Variable | Type | Dimensions | Description | + |-------------------+------------------+-----------------------------+------------------------------------------------| + | ~num~ | ~dim readonly~ | | Number of CSFs | + | ~coefficient~ | ~float buffered~ | ~(csf.num)~ | Coefficients of the CSFs from the CI expansion | + | ~det_coefficient~ | ~float sparse~ | ~(determinant.num,csf.num)~ | Projection on the determinant basis | + + #+CALL: json(data=csf, title="csf") + + #+RESULTS: + :results: + #+begin_src python :tangle trex.json + "csf": { + "num" : [ "dim readonly" , [] ] + , "coefficient" : [ "float buffered", [ "csf.num" ] ] + , "det_coefficient" : [ "float sparse" , [ "csf.num", "determinant.num" ] ] + } , + #+end_src + :end: + +* Excited states (state group) + + This group contains information about excited state. Since TREXIO version 2.3.0 + the state-specific data (e.g. CI/CSF coeffcients, RDMs) is written in a separate + file in order to avoid over-complicated internal logics and global state switches. + + The ~file_name~ and ~label~ arrays have to be written only for the master file, + e.g. the one containing the ground state wave function. + The ~id~ and ~current_label~ attributes have to be specified for each file + (containing both ground and excited state data). + + #+NAME: state + | Variable | Type | Dimensions | Description | + |-----------------+-------+---------------+-----------------------------------------------------------------------------------------------| + | ~num~ | ~dim~ | | Number of states (including the ground state) | + | ~id~ | ~int~ | | Index of a current state (0 is ground state) | + | ~label~ | ~str~ | ~(state.num)~ | Labels of all states related to this file (e.g. 'S' for singlets) | + | ~current_label~ | ~str~ | | Labels of the current state that is in a file | + | ~file_name~ | ~str~ | ~(state.num)~ | Names of the TREXIO files linked to the current one (i.e. containing data for excited states) | + + #+CALL: json(data=state, title="state") + + #+RESULTS: + :results: + #+begin_src python :tangle trex.json + "state": { + "num" : [ "dim", [] ] + , "id" : [ "int", [] ] + , "label" : [ "str", [ "state.num" ] ] + , "current_label" : [ "str", [] ] + , "file_name" : [ "str", [ "state.num" ] ] + } , + #+end_src + :end: + * Reduced density matrices (rdm group) The reduced density matrices are defined in the basis of molecular orbitals. - The $\uparrow$-spin and $\downarrow$-spin components of the one-body + The \uparrow-spin and \downarrow-spin components of the one-body density matrix are given by \begin{eqnarray*} \gamma_{ij}^{\uparrow} &=& \langle \Psi | \hat{a}^{\dagger}_{j\alpha}\, \hat{a}_{i\alpha} | \Psi \rangle \\ @@ -677,17 +849,43 @@ prim_factor = \frac{1}{2} \sum_{ijlk} \Gamma_{ijkl} \langle k l | i j \rangle \] + + To compress the storage, the Cholesky decomposition of the RDMs can + be stored: + + \[ + \Gamma_{ijkl} = \sum_{\alpha} G_{ij\alpha} G_{kl\alpha} + \] + + Warning: as opposed to electron repulsion integrals, the + decomposition is made such that the Cholesky vectors are expanded + in a two-electron basis + $f_{ij}(\mathbf{r}_1,\mathbf{r}_2) = \phi_i(\mathbf{r}_1) \phi_j(\mathbf{r}_2)$, + whereas in electron repulsion integrals each Cholesky vector is + expressed in a basis of a one-electron function + $g_{ik}(\mathbf{r}_1) = \phi_i(\mathbf{r}_1) \phi_k(\mathbf{r}_1)$. + #+NAME: rdm - | Variable | Type | Dimensions | Description | - |-----------+----------------+------------------------------------+-----------------------------------------------------------------------| - | ~1e~ | ~float~ | ~(mo.num, mo.num)~ | One body density matrix | - | ~1e_up~ | ~float~ | ~(mo.num, mo.num)~ | \uparrow-spin component of the one body density matrix | - | ~1e_dn~ | ~float~ | ~(mo.num, mo.num)~ | \downarrow-spin component of the one body density matrix | - | ~2e~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num)~ | Two-body reduced density matrix (spin trace) | - | ~2e_upup~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num)~ | \uparrow\uparrow component of the two-body reduced density matrix | - | ~2e_dndn~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num)~ | \downarrow\downarrow component of the two-body reduced density matrix | - | ~2e_updn~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num)~ | \uparrow\downarrow component of the two-body reduced density matrix | - | ~2e_dnup~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num)~ | \downarrow\uparrow component of the two-body reduced density matrix | + | Variable | Type | Dimensions | Description | + |------------------------+----------------+----------------------------------------------+-----------------------------------------------------------------------| + | ~1e~ | ~float~ | ~(mo.num, mo.num)~ | One body density matrix | + | ~1e_up~ | ~float~ | ~(mo.num, mo.num)~ | \uparrow-spin component of the one body density matrix | + | ~1e_dn~ | ~float~ | ~(mo.num, mo.num)~ | \downarrow-spin component of the one body density matrix | + | ~2e~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num)~ | Two-body reduced density matrix (spin trace) | + | ~2e_upup~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num)~ | \uparrow\uparrow component of the two-body reduced density matrix | + | ~2e_dndn~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num)~ | \downarrow\downarrow component of the two-body reduced density matrix | + | ~2e_updn~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num)~ | \uparrow\downarrow component of the two-body reduced density matrix | + | ~2e_dnup~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num)~ | \downarrow\uparrow component of the two-body reduced density matrix | + | ~2e_cholesky_num~ | ~dim~ | | Number of Cholesky vectors | + | ~2e_cholesky~ | ~float sparse~ | ~(mo.num, mo.num, rdm.2e_cholesky_num)~ | Cholesky decomposition of the Two-body RDM (spin trace) | + | ~2e_upup_cholesky_num~ | ~dim~ | | Number of Cholesky vectors | + | ~2e_upup_cholesky~ | ~float sparse~ | ~(mo.num, mo.num, rdm.2e_upup_cholesky_num)~ | Cholesky decomposition of the Two-body RDM (\uparrow\uparrow) | + | ~2e_dndn_cholesky_num~ | ~dim~ | | Number of Cholesky vectors | + | ~2e_dndn_cholesky~ | ~float sparse~ | ~(mo.num, mo.num, rdm.2e_dndn_cholesky_num)~ | Cholesky decomposition of the Two-body RDM (\downarrow\downarrow) | + | ~2e_updn_cholesky_num~ | ~dim~ | | Number of Cholesky vectors | + | ~2e_updn_cholesky~ | ~float sparse~ | ~(mo.num, mo.num, rdm.2e_updn_cholesky_num)~ | Cholesky decomposition of the Two-body RDM (\uparrow\downarrow) | + | ~2e_dnup_cholesky_num~ | ~dim~ | | Number of Cholesky vectors | + | ~2e_dnup_cholesky~ | ~float sparse~ | ~(mo.num, mo.num, rdm.2e_dnup_cholesky_num)~ | Cholesky decomposition of the Two-body RDM (\downarrow\uparrow) | #+CALL: json(data=rdm, title="rdm") @@ -695,14 +893,66 @@ prim_factor = :results: #+begin_src python :tangle trex.json "rdm": { - "1e" : [ "float" , [ "mo.num", "mo.num" ] ] - , "1e_up" : [ "float" , [ "mo.num", "mo.num" ] ] - , "1e_dn" : [ "float" , [ "mo.num", "mo.num" ] ] - , "2e" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] - , "2e_upup" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] - , "2e_dndn" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] - , "2e_updn" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] - , "2e_dnup" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] + "1e" : [ "float" , [ "mo.num", "mo.num" ] ] + , "1e_up" : [ "float" , [ "mo.num", "mo.num" ] ] + , "1e_dn" : [ "float" , [ "mo.num", "mo.num" ] ] + , "2e" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] + , "2e_upup" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] + , "2e_dndn" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] + , "2e_updn" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] + , "2e_dnup" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] + , "2e_cholesky_num" : [ "dim" , [] ] + , "2e_cholesky" : [ "float sparse", [ "rdm.2e_cholesky_num", "mo.num", "mo.num" ] ] + , "2e_upup_cholesky_num" : [ "dim" , [] ] + , "2e_upup_cholesky" : [ "float sparse", [ "rdm.2e_upup_cholesky_num", "mo.num", "mo.num" ] ] + , "2e_dndn_cholesky_num" : [ "dim" , [] ] + , "2e_dndn_cholesky" : [ "float sparse", [ "rdm.2e_dndn_cholesky_num", "mo.num", "mo.num" ] ] + , "2e_updn_cholesky_num" : [ "dim" , [] ] + , "2e_updn_cholesky" : [ "float sparse", [ "rdm.2e_updn_cholesky_num", "mo.num", "mo.num" ] ] + , "2e_dnup_cholesky_num" : [ "dim" , [] ] + , "2e_dnup_cholesky" : [ "float sparse", [ "rdm.2e_dnup_cholesky_num", "mo.num", "mo.num" ] ] + } , + #+end_src + :end: + +* Cell (cell group) + + #+NAME: cell + | Variable | Type | Dimensions | Description | + |----------+---------+------------+-------------------------| + | ~a~ | ~float~ | ~(3)~ | First unit cell vector | + | ~b~ | ~float~ | ~(3)~ | Second unit cell vector | + | ~c~ | ~float~ | ~(3)~ | Third unit cell vector | + + #+CALL: json(data=cell, title="cell") + + #+RESULTS: + :results: + #+begin_src python :tangle trex.json + "cell": { + "a" : [ "float", [ "3" ] ] + , "b" : [ "float", [ "3" ] ] + , "c" : [ "float", [ "3" ] ] + } , + #+end_src + :end: + +* Periodic boundary calculations (pbc group) + + #+NAME: pbc + | Variable | Type | Dimensions | Description | + |------------+---------+------------+-------------------------| + | ~periodic~ | ~int~ | | ~1~: true or ~0~: false | + | ~k_point~ | ~float~ | ~(3)~ | k-point sampling | + + #+CALL: json(data=pbc, title="pbc") + + #+RESULTS: + :results: + #+begin_src python :tangle trex.json + "pbc": { + "periodic" : [ "int" , [] ] + , "k_point" : [ "float", [ "3" ] ] } , #+end_src :end: @@ -724,9 +974,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