diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 147d50c..e42bfad 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -20,7 +20,7 @@ jobs: message: ${{ steps.commit_message.outputs.message }} steps: - name: Checkout the repo - uses: actions/checkout@v2 + uses: actions/checkout@e2f20e631ae6d7dd3b768f56a5d2af784dd54791 # Gets the correct commit message for pull request with: ref: ${{ github.event.pull_request.head.sha }} @@ -31,15 +31,25 @@ jobs: COMMIT_MSG=$(git log --no-merges -1 --oneline) echo "::set-output name=message::$COMMIT_MSG" - trexio_ubuntu: - - runs-on: ubuntu-20.04 name: x86 Ubuntu 20.04 + runs-on: ubuntu-20.04 needs: get_commit_message steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@e2f20e631ae6d7dd3b768f56a5d2af784dd54791 + + - name: check versions + run: | + grep AC_INIT configure.ac | tr -d '[]' | awk -F, '{ print $2 }' > configure_v + grep -w VERSION CMakeLists.txt | grep -v 'cmake_minimum_required' | awk '{ print $2 }' > cmake_v + grep version python/pytrexio/_version.py | tr -d '"' | awk '{ print $3 }' > python_v + grep version rust/trexio/Cargo.toml | grep -v features | tr -d '"' | awk '{ print $3 }' > rust_v + grep version ocaml/trexio/dune-project | tr -d '()' | awk '{ print $2 }' > ocaml_v + diff configure_v cmake_v + diff configure_v python_v + diff configure_v rust_v + diff configure_v ocaml_v - name: install dependencies run: | @@ -84,7 +94,7 @@ jobs: if: >- contains(needs.get_commit_message.outputs.message, '[wheel build]') || github.event_name == 'release' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@82c141cc518b40d92cc801eee768e7aafc9c2fa2 with: name: pytrexio-source path: ./trexio-*.tar.gz @@ -114,29 +124,38 @@ jobs: run: make maintainer-clean trexio_macos: - - runs-on: macos-11 - name: x86 MacOS 11 + name: x86 MacOS 12 + runs-on: macos-12 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@e2f20e631ae6d7dd3b768f56a5d2af784dd54791 - name: install dependencies run: | brew install emacs brew install hdf5 brew install automake + brew --prefix hdf5 - name: configure with autotools run: | ./autogen.sh - ./configure FC=gfortran-10 --enable-silent-rules + ./configure FC=gfortran-12 --enable-silent-rules - name: compile TREXIO - run: make -j 2 + run: make -j3 - name: check TREXIO - run: make check + run: make -j3 check + + - name: compile Python API + run: | + export H5_CFLAGS="-I$(brew --prefix hdf5)/include" + export H5_LDFLAGS="-L$(brew --prefix hdf5)/lib" + make python-install + + - name: test Python API + run: make python-test - name: Archive test log file if: failure() diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index 5dbdf19..7cda44a 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -21,7 +21,7 @@ jobs: message: ${{ steps.commit_message.outputs.message }} steps: - name: Checkout the repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Gets the correct commit message for pull request with: ref: ${{ github.event.pull_request.head.sha }} @@ -42,14 +42,14 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - manylinux_tag: [2010_x86_64, 2014_x86_64, 2_24_x86_64] + manylinux_tag: [2014_x86_64, 2_24_x86_64] steps: - name: Checkout the branch - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v1 + uses: actions/setup-python@v4 with: python-version: '3.9' @@ -94,102 +94,18 @@ jobs: name: pytrexio-manylinux-${{ matrix.manylinux_tag }} path: ./python/wheelhouse/*.whl - build_macos_wheels: - name: Build MacOS wheels for different versions of CPython - needs: get_commit_message - if: >- - contains(needs.get_commit_message.outputs.message, '[wheel build]') || - (github.repository == 'TREX-CoE/trexio' && startsWith(github.ref, 'refs/tags/v')) - runs-on: ${{ matrix.os }} - strategy: - matrix: - os: [macos-10.15] - python-version: ['3.6', '3.7', '3.8', '3.9', '3.10'] -# TODO: normally, one could include macos-11 and the OS list above but the produced wheels receive an error upon installation: -# ERROR: trexio-1.1.0-cp39-cp39-macosx_11_0_x86_64.whl is not a supported wheel on this platform. -# This happens even with the MACOSX_DEPLOYMENT_TARGET trick. Perhaps it can be solved by configuring the build system -# to produce the wheels for MacOS-11 from the very beginning - #exclude: - # - os: macos-11 - env: - H5_LDFLAGS: '-L/usr/local/Cellar/hdf5/1.12.1/lib' - H5_CFLAGS: '-I/usr/local/Cellar/hdf5/1.12.1/include' - steps: - - uses: actions/checkout@v2 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - - name: Display Python version - run: python --version - - - name: Install HDF5 - run: brew install hdf5@1.12 - - # This step is needed to produce wheels with the correct platform tag for MacOS-11 (Big Sur) - #- name: Set MACOSX_DEPLOYMENT_TARGET environment variable - # if: ${{ matrix.os == 'macos-11' }} - # run: echo "MACOSX_DEPLOYMENT_TARGET=11.0" >> $GITHUB_ENV - - - name: Compute the PYTREXIO_VERSION environment variable - run: echo "PYTREXIO_VERSION=$(grep __version__ python/pytrexio/_version.py | cut -d\ -f3 | tr -d '"')" >> $GITHUB_ENV - - - name: Print the PYTREXIO_VERSION - run: echo ${{ env.PYTREXIO_VERSION }} - - - name: Download the Python API distribution tarball - uses: dawidd6/action-download-artifact@v2 - with: - workflow: actions.yml - workflow_conclusion: success - name: pytrexio-source - path: python - - - name: Extract the Python distribution - run: gzip -cd trexio-${{ env.PYTREXIO_VERSION }}.tar.gz | tar xvf - - working-directory: python - - - name: Install Python dependencies - run: pip install --upgrade pip setuptools build delocate pytest - - - name: Build wheel for a given version of CPython - run: | - mkdir wheelhouse/ - cd trexio-${{ env.PYTREXIO_VERSION }}/ - python -m build --wheel --outdir=./ - delocate-wheel trexio-*.whl - mv trexio-*.whl ../wheelhouse/ - working-directory: python - - # Some issues with Python 3.10 wheels on MacOS-11 - - name: Install the wheel - run: python -m pip install wheelhouse/trexio-*.whl - working-directory: python - - - name: Test the wheel - run: pytest -v test_api.py - working-directory: python/test - - - name: Upload produced wheels as artifacts - uses: actions/upload-artifact@v2 - with: - name: pytrexio-${{ matrix.os }} - path: ./python/wheelhouse/*.whl - publish_wheels: name: Publish all wheels on PyPI - needs: [build_linux_wheels, build_macos_wheels] + needs: [build_linux_wheels] runs-on: ubuntu-20.04 steps: - name: Checkout the branch - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v1 + uses: actions/setup-python@v4 with: python-version: '3.9' @@ -215,8 +131,7 @@ jobs: run: | ls -R mv pytrexio-manylinux-*/trexio-*.whl ./ - mv pytrexio-macos-*/trexio-*.whl ./ - rm -rf -- pytrexio-manylinux-*/ pytrexio-macos-*/ + rm -rf -- pytrexio-manylinux-*/ ls -sh -w 1 working-directory: dist diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..65bd022 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,28 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." +authors: +- family-names: "Scemama" + given-names: "Anthony" + orcid: "https://orcid.org/0000-0003-4955-7136" +- family-names: "Posenitskiy" + given-names: "Evgeny" + orcid: "https://orcid.org/0000-0002-1623-0594" +title: "TREX I/O library " +version: 2.3.1 +date-released: 2023-04-26 +url: "https://github.com/TREX-CoE/trexio" +preferred-citation: + type: article + authors: + - family-names: "Posenitskiy" + given-names: "Evgeny" + - family-names: "et al." + given-names: "" + doi: "10.1063/5.0148161" + journal: "The Journal of Chemical Physics" + month: 5 + start: 174801 # First page number + title: "TREXIO: A file format and library for quantum chemistry" + issue: 17 + volume: 158 + year: 2023 \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index ba6f6c6..e48e917 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.3.0 + VERSION 2.5.0 DESCRIPTION "TREX I/O library" LANGUAGES C Fortran ) @@ -15,8 +15,9 @@ 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) +option(TREXIO_TESTS "Whether to perform tests for TREXIO" ON) -if(EXISTS "${CMAKE_SOURCE_DIR}/.devel") +if(EXISTS "${PROJECT_SOURCE_DIR}/.devel") set(TREXIO_DEVEL ON) find_package(Python3 REQUIRED) if(Python3_FOUND) @@ -48,8 +49,8 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/.devel") set(TREXIO_USER_NAME $ENV{USER}) # replace placeholders in the templace config.h.in file to produce config.h # config.h is needed to insert TREXIO_PACKAGE_VERSION and TREXIO_GIT_HASH into trexio.h - configure_file(${CMAKE_SOURCE_DIR}/include/cmake_config.h.in - ${CMAKE_SOURCE_DIR}/include/config.h + configure_file(${PROJECT_SOURCE_DIR}/include/cmake_config.h.in + ${PROJECT_SOURCE_DIR}/include/config.h @ONLY) endif() @@ -60,5 +61,7 @@ include_directories(include) add_subdirectory(src) # Add subdirectory with unit tests. -enable_testing() -add_subdirectory(tests) +if(TREXIO_TESTS) + enable_testing() + add_subdirectory(tests) +endif() diff --git a/ChangeLog b/ChangeLog index 748a7b1..0f199e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,24 @@ CHANGES ======= +2.5 +--- + +- Added index permutations in integrals + +2.4 +--- + +- Added state/energy +- Made state/id an index instead of an int +- Added JSON configuration data as a C variable in trexio.h +- Added JSON configuration file in tar.gz release +- Added Rust interface + 2.3 --- +- Removed dependency to hdf5_hl - 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 @@ -19,14 +34,11 @@ CHANGES - Added OCaml binding - Added spin and energy in MOs - Added CSF group -- Added index permutations -- Added phase change in determinant list to bitstring conversion - Added Jastrow group - Added Amplitude group - Added Cholesky-decomposed two-electron integrals - Added Cholesky-decomposed RDMs for Gammcor - Added `trexio_flush` functionality -- Added `trexio_cp` - Optional compilation `--without-fortran` 2.2 diff --git a/Makefile.am b/Makefile.am index 2209dad..cfc6217 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,10 +34,9 @@ ACLOCAL_AMFLAGS = -I m4 CLEANFILES = trexio.mod +BUILT_SOURCES = trex.json if HAVE_FORTRAN -BUILT_SOURCES = trexio.mod -else -BUILT_SOURCES = +BUILT_SOURCES += trexio.mod endif EXTRA_DIST = .git_hash @@ -77,22 +76,73 @@ endif ORG_FILES = \ src/templates_front/templator_front.org \ src/templates_text/templator_text.org \ - src/templates_hdf5/templator_hdf5.org \ trex.org +if HAVE_HDF5 +ORG_FILES += src/templates_hdf5/templator_hdf5.org +endif src_libtrexio_la_SOURCES = $(trexio_h) $(SOURCES) # Include CMake-related files in the distribution. EXTRA_DIST += CMakeLists.txt \ + trex.json \ src/CMakeLists.txt \ tests/CMakeLists.txt \ + tests/test_macros.h \ cmake/cmake_uninstall.cmake.in \ cmake/FindTREXIO.cmake # =============== TESTS =============== # +TEST_FILES = \ + tests/delete_group.c \ + tests/delete_group_hdf5.c \ + tests/delete_group_text.c \ + tests/io_all.c \ + tests/io_determinant.c \ + tests/io_determinant_hdf5.c \ + tests/io_determinant_text.c \ + tests/io_dset_float.c \ + tests/io_dset_float_hdf5.c \ + tests/io_dset_float_text.c \ + tests/io_dset_int.c \ + tests/io_dset_int_hdf5.c \ + tests/io_dset_int_text.c \ + tests/io_dset_sparse.c \ + tests/io_dset_sparse_hdf5.c \ + tests/io_dset_sparse_text.c \ + tests/io_dset_str.c \ + tests/io_dset_str_hdf5.c \ + tests/io_dset_str_text.c \ + tests/io_jastrow.c \ + tests/io_jastrow_hdf5.c \ + tests/io_jastrow_text.c \ + tests/io_num.c \ + tests/io_num_hdf5.c \ + tests/io_num_text.c \ + tests/io_safe_dset_float.c \ + tests/io_safe_dset_float_hdf5.c \ + tests/io_safe_dset_float_text.c \ + tests/io_str.c \ + tests/io_str_hdf5.c \ + tests/io_str_text.c \ + tests/open.c \ + tests/open_hdf5.c \ + tests/open_text.c \ + tests/overwrite_all.c \ + tests/overwrite_all_hdf5.c \ + tests/overwrite_all_text.c \ + tests/pre_close.c \ + tests/template_hdf5.c \ + tests/template_text.c \ + tests/test_f.f90 \ + tests/test_macros.h \ + tests/trexio_f.f90 + +EXTRA_DIST += $(TEST_FILES) + TESTS_C = \ tests/open_text \ tests/io_num_text \ @@ -160,11 +210,13 @@ EXTRA_DIST += $(trexio_scm) HTML_TANGLED = docs/index.html \ docs/examples.html \ - docs/templator_hdf5.html \ docs/trex.html \ docs/README.html \ docs/templator_front.html \ docs/templator_text.html +if HAVE_HDF5 +HTML_TANGLED += docs/templator_hdf5.html +endif htmldir = $(docdir) # This $(htmlizer) file and the corresponding target rule allow to avoid circular dependency, @@ -217,6 +269,8 @@ src/trexio.c: $(trexio_h) $(trexio_h): $(ORG_FILES) $(GENERATOR_FILES) cd $(srcdir)/tools && ./build_trexio.sh +trex.json: $(trexio_h) + $(htmlizer): $(ORG_FILES) $(srcdir)/src/README.org touch $(htmlizer) cd $(srcdir)/tools && ./build_doc.sh @@ -257,10 +311,18 @@ pytrexio_i = $(srcdir)/src/pytrexio.i numpy_i = $(srcdir)/src/numpy.i +if HAVE_HDF5 +python-test: $(TEST_PY) + python3 -m pytest -v --all $(TEST_PY) + $(RM) -r -- __pycache__ + $(RM) -f -- test_file_py.h5 unsafe_test_file_py.h5 + $(RM) -rf -- test_file_py.dir unsafe_test_file_py.dir +else python-test: $(TEST_PY) python3 -m pytest -v $(TEST_PY) - $(RM) -r -- __pycache__ - $(RM) -f -- test_file_py.h5 unsafe_test_file_py.h5 + $(RM) -r -- __pycache__ + $(RM) -rf -- test_file_py.dir unsafe_test_file_py.dir +endif python-install: $(pytrexio_py) $(setup_py) $(setup_cfg) cd python && \ @@ -270,11 +332,15 @@ python-sdist: $(pytrexio_py) $(setup_py) $(setup_cfg) cd python && \ python3 -m build --sdist +if HAVE_HDF5 $(pytrexio_py): $(pytrexio_c) cd tools && ./prepare_python.sh +else +$(pytrexio_py): $(pytrexio_c) + cd tools && ./prepare_python.sh --without-hdf5 +endif # Build Python module and C wrapper code for TREXIO using SWIG -# [?] swig -python -threads pytrexio.i ----> Add thread support for all the interface $(pytrexio_c): $(ORG_FILES) $(GENERATOR_FILES) $(trexio_h) $(pytrexio_i) $(numpy_i) @if [[ $(SWIG).x != ".x" ]] ; then \ cp $(trexio_h) src/ ; \ @@ -303,7 +369,7 @@ DEB_FILES = \ helpers-debian/libtrexio0.install \ helpers-debian/libtrexio-dev.install \ helpers-debian/source \ - helpers-debian/README.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 @@ -313,6 +379,9 @@ debian_from_dist: $(DEB_FILES) $(SOURCES) $(trexio_h) CLEANFILES += $(pytrexio_c) \ $(pytrexio_py) \ $(trexio_py) \ + $(srcdir)/src/trexio.py \ + $(srcdir)/src/pytrexio.py \ + $(srcdir)/src/trexio.h \ python/src/*.c \ python/src/*.h diff --git a/README.md b/README.md index 9d5c364..1347d7f 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,50 @@ - # 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) -TREX library for efficient I/O. +TREXIO is an open-source file format and library developed for the storage and +manipulation of data produced by quantum chemistry calculations. It is designed +with the goal of providing a reliable and efficient method of storing and +exchanging wave function parameters and matrix elements. The library consists +of a front-end implemented in the C programming language and two different +back-ends: a text back-end and a binary back-end utilizing the HDF5 library +which enables fast read and write operations. It is compatible with a variety +of platforms and has interfaces for the Fortran, Python, OCaml and Rust +programming languages. + +* [TREXIO](#trexio) + * [Installation](#installation) + * [Installation using a package manager](#installation-using-a-package-manager) + * [Debian/Ubuntu](#debianubuntu) + * [Conda](#conda) + * [Spack](#spack) + * [Guix](#guix) + * [Installation from source](#installation-from-source) + * [Minimal requirements (for users):](#minimal-requirements-for-users) + * [Recommended: Installation from the release tarball](#recommended-installation-from-the-release-tarball) + * [Compilation without the HDF5 library](#compilation-without-the-hdf5-library) + * [For TREXIO developers: from the GitHub repo clone](#for-trexio-developers-from-the-github-repo-clone) + * [Using CMake instead of Autotools](#using-cmake-instead-of-autotools) + * [Using TREXIO](#using-trexio) + * [Naming convention](#naming-convention) + * [Tutorial](#tutorial) + * [Documentation](#documentation) + * [Linking to your program](#linking-to-your-program) + * [Distributing TREXIO with your code](#distributing-trexio-with-your-code) + * [APIs for other languages](#apis-for-other-languages) + * [Python](#python) + * [Rust](#rust) + * [OCaml](#ocaml) + * [Citation](#citation) + * [Miscellaneous](#miscellaneous) -## Minimal requirements (for users): - -- 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] - - -## Installation procedure from the tarball (for users): - -1. Download the `trexio-.tar.gz` file -2. `gzip -cd trexio-.tar.gz | tar xvf -` -3. `cd trexio-` -4. `./configure` -5. `make` -6. `make check` -7. `sudo make install` - - -**Note: on systems with no `sudo` access, one can replace `./configure` with `./configure prefix=${PWD}/build` in order to execute `make install/uninstall` commands without `sudo` privileges.** - -**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., `CC=mpicc` to the `./configure` command.** - -## Additional requirements (for developers): - -- python3 (>= 3.6) -- Emacs (>= 26.0) -- SWIG (>= 4.0) [required for the Python API] - -## Installation procedure from the GitHub repo clone (for developers): - -1. `git clone https://github.com/TREX-CoE/trexio.git` -2. `cd trexio` -3. `./autogen.sh` -4. `./configure` -5. `make` -6. `make check` -7. `sudo make install` - -## Installation procedure for CMake users (from the tarball or GitHub repo clone): - -The aforementioned instructions rely on [Autotools](https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html) build system. -[CMake](https://cmake.org) users can achieve the same with the following steps (an example of out-of-source build): - -1. `cmake -S. -Bbuild` -2. `cd build` -3. `make` -4. `ctest` (or `make test`) -5. `sudo make install` - -**Note: on systems with no `sudo` access, one can add `-DCMAKE_INSTALL_PREFIX=build` as an argument to the `cmake` command so that `make install/uninstall` can be run without `sudo` privileges.** - -**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 +## Installation +### Installation using a package manager +#### Conda [![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) @@ -71,28 +53,13 @@ The official releases of TREXIO `>2.0.0` are also available via the `conda-forge The pre-compiled stable binaries of `trexio` can be installed as follows: ``` -conda install trexio -c conda-forge +conda install -c conda-forge trexio ``` 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 +#### Spack The official releases `>=2.0.0` and the development version of TREXIO can be installed using the [Spack](https://spack.io/) package manager. @@ -101,10 +68,71 @@ file contains the Spack specifications required to build different variants of ` It can be installed as follows ``` -spack install --jobs trexio +spack install --jobs `getconf _NPROCESSORS_ONLN` trexio ``` -## Compilation without the HDF5 library +#### Guix + +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 as follows: + +``` +guix package --cores=`getconf _NPROCESSORS_ONLN` --install-from-file=trexio.scm +``` + +#### Debian/Ubuntu + +The official release of TREXIO `2.2.0` is available as a Debian (`.deb`) package thanks to the [Debichem Team](https://wiki.debian.org/Debichem). +The source code is hosted [here](https://salsa.debian.org/debichem-team/libtrexio) and +the pre-built binary files are available via the [Debian package registry](https://packages.debian.org/bookworm/libtrexio-dev). + +TREXIO is also available on [Ubuntu 23.04 (Lunar Lobster)](https://packages.ubuntu.com/lunar/libtrexio-dev) and newer and can be installed as follows: + +``` +sudo apt-get update && sudo apt-get install libtrexio-dev +``` + +### Installation from source +#### Minimal requirements (for users): + +- 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] + + +#### Recommended: Installation from the release tarball + +1. Download the `trexio-.tar.gz` file from the GitHub release page +2. `gzip -cd trexio-.tar.gz | tar xvf -` +3. `cd trexio-` +4. `./configure` +5. ```make -j 4 ``` +6. ```make -j 4 check``` +7. `sudo make install` + +In environments where `sudo` access is unavailable, a common workaround for +executing `make install/uninstall` commands without requiring superuser +privileges involves a modification to the `./configure` command. +This modification typically includes specifying an installation prefix within +the user's home directory to circumvent the need for system-wide installation +permissions. For instance, `./configure prefix=$HOME/.local` can be employed, +where `$HOME/.local` is often recommended for user-space software installations. +However, this is merely a suggestion, and users are free to choose any suitable +directory as their installation prefix, depending on their specific +requirements and system configurations. + +Regarding the integration with an MPI (Message Passing Interface) enabled HDF5 +library, it's typical to specify the MPI compiler wrapper for the C compiler. +This is done by appending a directive like `CC=mpicc` to the `./configure` +command. However, as TREXIO does not utilize MPI features, it is advisable to +link against a non-MPI (serial) version of the HDF5 library for the sake of +simplicity. + +#### Compilation without the HDF5 library By default, the configuration step proceeds to search for the [HDF5 library](https://portal.hdfgroup.org/display/HDF5/HDF5). This search can be disabled if HDF5 is not present/installable on the user machine. @@ -113,31 +141,41 @@ To build TREXIO without HDF5 back end, append `--without-hdf5` option to `config - `./configure --without-hdf5` - `cmake -S. -Bbuild -DENABLE_HDF5=OFF` -## Linking to your program +#### For TREXIO developers: from the GitHub repo clone -The `make install` command takes care of installing the TREXIO shared library on the user machine. -Once installed, add `-ltrexio` to the list of compiler options. +Additional requirements: -In some cases (e.g. when using custom `prefix` during configuration), the TREXIO library might end up installed in a directory, which is absent in the default `$LIBRARY_PATH`. -In order to link the program against TREXIO, the search paths can be modified as follows: +- Python3 (>= 3.6) +- Emacs (>= 26.0) +- SWIG (>= 4.0) [required for the Python API] -`export LIBRARY_PATH=$LIBRARY_PATH:/lib` +**Note:** The source code is auto-generated from the Emacs org-mode (`.org`) files following the literate programming approach. This is why the `src` directory is initially empty. -(same holds for `$LD_LIBRARY_PATH`). The `` has to be replaced by the prefix used during the installation. +1. `git clone https://github.com/TREX-CoE/trexio.git` +2. `cd trexio` +3. `./autogen.sh` +4. `./configure` +5. ```make -j 4``` +6. ```make -j 4 check``` +7. `sudo make install` -If your project relies on CMake build system, feel free to use the -[FindTREXIO.cmake](https://github.com/TREX-CoE/trexio/blob/master/cmake/FindTREXIO.cmake) -module to find and link TREXIO library automatically. +#### Using CMake instead of Autotools -In Fortran applications, make sure that the `trexio_f.f90` module file is included in the source tree. -You might have to manually copy it into your program source directory. -The `trexio_f.f90` module file can be found in the `include/` directory of the TREXIO source code distribution. +The aforementioned instructions rely on [Autotools](https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html) build system. +[CMake](https://cmake.org) users can achieve the same with the following steps (an example of out-of-source build): -**Note:** there is no need to include `trexio.h` header file during compilation of Fortran programs. -Only the installed library and the Fortran module file are required. +1. `cmake -S. -Bbuild` +2. `cd build` +3. ```make -j 4``` +4. ```ctest -j 4``` +5. `sudo make install` +**Note**: on systems with no `sudo` access, one can add `-DCMAKE_INSTALL_PREFIX=build` as an argument to the `cmake` command so that `make install/uninstall` can be run without `sudo` privileges. -## Naming convention +**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. + +## Using TREXIO +### Naming convention The primary TREXIO API is composed of the following functions: @@ -156,7 +194,58 @@ There is no naming conflict when, for example, `num` variable exists both in the These quantities can be accessed using the corresponding `trexio_[has|read|write]_nucleus_num` and `trexio_[has|read|write]_mo_num`, respectively. -## Python API +### Tutorial + +TREXIO tutorials in Jupyter notebook format can be found in the +[corresponding GitHub repository](https://github.com/TREX-CoE/trexio-tutorials) +or on [Binder](https://mybinder.org/v2/gh/TREX-CoE/trexio-tutorials/HEAD). + +For example, the tutorial covering TREXIO basics using benzene molecule as an example can be viewed and executed online by clicking on this badge: +[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/TREX-CoE/trexio-tutorials/HEAD?filepath=notebooks%2Ftutorial_benzene.ipynb) + + +### Documentation + +[Documentation generated from TREXIO org-mode files.](https://trex-coe.github.io/trexio/) + + +### Linking to your program + +The `make install` command takes care of installing the TREXIO shared library on the user machine. +After installation, append `-ltrexio` to the list of compiler (`$LIBS`) options. + +In some cases (e.g. when using custom installation prefix during configuration), the TREXIO library might end up installed in a directory, which is absent in the default `$LD_LIBRARY_PATH`. +In order to link the program against TREXIO, the search path can be modified as follows: + +`export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib` + +where the `` has to be replaced by the prefix used during the installation. + +If your project relies on CMake build system, feel free to use the +[FindTREXIO.cmake](https://github.com/TREX-CoE/trexio/blob/master/cmake/FindTREXIO.cmake) +module to find and link TREXIO library automatically. + +In Fortran applications, make sure that the `trexio_f.f90` module file is included in the source tree. +You might have to manually copy it into your program source directory. +The `trexio_f.f90` module file can be found in the `include/` directory of the TREXIO source code distribution. + +**Note:** there is no need to include `trexio.h` header file during compilation of Fortran programs. +Only the installed library and the Fortran module file are required. + + +### Distributing TREXIO with your code + +The TREXIO software is distributed under the 3-clause BSD license, renowned for +its permissiveness. Consequently, it is entirely acceptable for you to +provide the TREXIO release tarball in conjunction with your own code. +Should you opt to include TREXIO with your software, it is recommended to +distribute the release tarball, instead of the content of the git repository. +The release tarballs contain pre-generated source files. This not only +accelerates the compilation process but also significantly reduces dependency +requirements. + +## APIs for other languages +### Python [![PyPI version](https://badge.fury.io/py/trexio.svg)](https://badge.fury.io/py/trexio) @@ -170,8 +259,7 @@ In order to install the Python API with the latest changes, follow the developer 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.** +**Note: this implies that SWIG is installed and available.** We rely on the `pytest` package for unit testing. It can be installed via `pip install pytest`. To test the installation, run @@ -182,24 +270,62 @@ make python-test We highly recommend to use virtual environments to avoid compatibility issues and to improve reproducibility. -## Tutorial +### Rust -TREXIO tutorials in Jupyter notebook format can be found in the -[corresponding GitHub repository](https://github.com/TREX-CoE/trexio-tutorials) -or on [Binder](https://mybinder.org/v2/gh/TREX-CoE/trexio-tutorials/HEAD). +The Rust API is available on Crates.io, so you can simply run +``` +cargo add trexio +``` +to your Rust project. -For example, the tutorial covering TREXIO basics using benzene molecule as an example can be viewed and executed online by clicking on this badge: -[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/TREX-CoE/trexio-tutorials/HEAD?filepath=notebooks%2Ftutorial_benzene.ipynb) +If you prefer to install the Rust API provided with this repository: +``` +cargo add --path /path/to/trexio/rust/trexio +``` +### OCaml -## Documentation +The TREXIO OCaml API is available in OPAM: +``` +opam install trexio +``` -[Documentation generated from TREXIO org-mode files.](https://trex-coe.github.io/trexio/) +If you prefer to install it from this repository, +``` +cd ocaml/trexio +make +opam install . +``` + +## Citation + +The journal article reference describing TREXIO can be cited as follows: + +``` +@article{10.1063/5.0148161, + author = {Posenitskiy, Evgeny and Chilkuri, Vijay Gopal and Ammar, Abdallah and Hapka, Michał and Pernal, Katarzyna and Shinde, Ravindra and Landinez Borda, Edgar Josué and Filippi, Claudia and Nakano, Kosuke and Kohulák, Otto and Sorella, Sandro and de Oliveira Castro, Pablo and Jalby, William and Ríos, Pablo López and Alavi, Ali and Scemama, Anthony}, + title = "{TREXIO: A file format and library for quantum chemistry}", + journal = {The Journal of Chemical Physics}, + volume = {158}, + number = {17}, + year = {2023}, + month = {05}, + issn = {0021-9606}, + doi = {10.1063/5.0148161}, + url = {https://doi.org/10.1063/5.0148161}, + note = {174801}, + eprint = {https://pubs.aip.org/aip/jcp/article-pdf/doi/10.1063/5.0148161/17355866/174801\_1\_5.0148161.pdf}, +} +``` + +Journal paper: [![doi](https://img.shields.io/badge/doi-10.1063/5.0148161-5077AB.svg)](https://doi.org/10.1063/5.0148161) + +ArXiv paper: [![arXiv](https://img.shields.io/badge/arXiv-2302.14793-b31b1b.svg)](https://arxiv.org/abs/2302.14793) ### Miscellaneous -Note: The code should be compliant with the C99 +The code should be compliant with the C99 [CERT C coding standard](https://resources.sei.cmu.edu/downloads/secure-coding/assets/sei-cert-c-coding-standard-2016-v01.pdf). This can be checked with the `cppcheck` tool. diff --git a/cmake/FindTREXIO.cmake b/cmake/FindTREXIO.cmake index a2aa9c4..e58f616 100644 --- a/cmake/FindTREXIO.cmake +++ b/cmake/FindTREXIO.cmake @@ -11,6 +11,7 @@ # $ export TREXIO_DIR= # to indicate the prefix used during the TREXIO installation # (typically `./configure prefix= ..` or `cmake -DCMAKE_INSTALL_DIR= ..`) +# Alternatively, TREXIO_DIR can be provided in a CMake cache. # This file should be located WITHIN your project source tree. # (e.g. in cmake/FindTREXIO.cmake) @@ -45,9 +46,13 @@ set(TREXIO_SEARCH_PATHS /opt ) +if (NOT TREXIO_DIR) + set(TREXIO_DIR $ENV{TREXIO_DIR}) +endif() + find_path(TREXIO_INCLUDE_DIR NAMES trexio.h - HINTS $ENV{TREXIO_DIR} + HINTS "${TREXIO_DIR}" PATH_SUFFIXES include/trexio include PATHS ${TREXIO_SEARCH_PATHS} ) @@ -57,7 +62,7 @@ find_path(TREXIO_INCLUDE_DIR # suffix (e.g. .so on Unix or .dylib on MacOS) in NAMES. CMake takes care of that. find_library(TREXIO_LIBRARY NAMES trexio - HINTS $ENV{TREXIO_DIR} + HINTS "${TREXIO_DIR}" PATH_SUFFIXES lib64 lib PATHS ${TREXIO_SEARCH_PATHS} ) diff --git a/configure.ac b/configure.ac index d9ebc09..aad67a8 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.3.0],[https://github.com/TREX-CoE/trexio/issues]) +AC_INIT([trexio],[2.5.0],[https://github.com/TREX-CoE/trexio/issues]) AC_CONFIG_SRCDIR([Makefile.in]) AC_CONFIG_HEADERS([include/config.h]) @@ -41,6 +41,25 @@ AC_SUBST([UNAME]) ## Checks for programs ## ------------------- +# Fortran API [default: --with-fortran], do not disable in the dev mode +AC_PROG_FC +AC_ARG_WITH(fortran, [AS_HELP_STRING([--without-fortran],[do not test and install the Fortran API])], ok=$withval, ok=yes) +AS_IF([test "$ok" = "yes"],[ + AC_FC_FREEFORM + AC_FC_SRCEXT([f90]) + AC_PROG_FC_C_O + AC_FC_LIBRARY_LDFLAGS + + # Specific options required with some compilers + AS_CASE([$FC], + [*gfortran*], [FCFLAGS="$FCFLAGS -fPIC"], + [*flang*], [FCFLAGS="$FCFLAGS -fPIC"], + [*ifort*], [FCFLAGS="$FCFLAGS -fPIC"], + []) + +]) +AM_CONDITIONAL([HAVE_FORTRAN],[test "$ok" = "yes"]) + AC_LANG(C) AC_PROG_CC @@ -52,51 +71,18 @@ AC_PROG_CC_C_O AM_PROG_CC_C_O -# 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() -PKG_CFLAGS="" -PKG_LIBS="" 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 +AS_CASE([$CC], + [*gcc*], [CFLAGS="$CFLAGS -fPIC"], + [*clang*], [CFLAGS="$CFLAGS -fPIC"], + [*icc*], [CFLAGS="$CFLAGS -fPIC"], + []) # Check if `cp -r -n` works, otherwise use `cp -r` AC_CHECK_PROGS(CP_PROG, [cp]) @@ -109,7 +95,7 @@ AC_RUN_IFELSE( execl("/bin/sh", "sh", "-c", "mkdir tmpdir1 && \ touch tmpdir1/test_file && \ $CP_PROG -r -n tmpdir1 tmpdir2 && \ -exec ls tmpdir2/test_file", NULL); +exec ls tmpdir2/test_file > /dev/null", NULL); ])], [ rm -rf tmpdir1 tmpdir2 CP_COMMAND="\"$CP_PROG\", \"-r\", \"-n\"" @@ -135,64 +121,108 @@ AC_CHECK_HEADERS([fcntl.h inttypes.h stdint.h stdbool.h stdlib.h string.h unistd ### HDF5 ### ---- -# Configure with HDF5 (default: --with-hdf5 using pkg-config) [optional]: -# ./configure [--with-hdf5 or --with-hdf5=yes] - -# Configure with user-provided path to HDF5: -# ./configure --with-hdf5=/usr/lib/x86_64-linux-gnu/hdf5/serial - -# Configure without HDF5: -# ./configure --without-hdf5 [or --with-hdf5=no] - - PKG_HDF5="" -AX_LIB_HDF5() +HDF5_LIBS="" +HDF5_LDFLAGS="" +HDF5_CFLAGS="" +HDF5_CPPFLAGS="" +AC_ARG_WITH([hdf5], + AS_HELP_STRING([--with-hdf5=PATH], [Path to HDF5 library and headers]), [ + with_hdf5="$withval"], [with_hdf5="yes"]) -if test "x${with_hdf5}" = xno; then - AC_MSG_WARN([ - ------------------------------------------ - Configuring with the HDF5 library is - recommended to build efficient TREXIO. - ------------------------------------------]) -else - AC_CHECK_LIB([hdf5_hl],[main],[],[AC_MSG_ERROR( ------------------------------------ -Error: hdf5_hl library is required ------------------------------------ -)],[])ac_cv_lib_hdf5_hl=ac_cv_lib_hdf5_hl_main +AS_IF([test "x$with_hdf5" == "xno"], [], + [test "x$with_hdf5" != "xyes"], [ + HDF5_LIBS="-lhdf5" + HDF5_PATH="$with_hdf5" + HDF5_LDFLAGS="-L$HDF5_PATH/lib" + HDF5_CPPFLAGS="-I$HDF5_PATH/include" + AC_DEFINE([HAVE_HDF5], 1, [Define to 1 if HDF5 is available]) ], + [ + PKG_CHECK_EXISTS([hdf5], [ + PKG_CHECK_MODULES([HDF5], [hdf5 >= 1.8]) + PKG_HDF5="hdf5" + ], + [ AC_PATH_PROG([H5CC],[h5cc],[not_found]) + AS_IF([test "$H5CC" != "not_found"], [ + HDF5_LIBS="-lhdf5" + AC_REQUIRE([AC_PROG_SED]) + AC_REQUIRE([AC_PROG_AWK]) + AC_REQUIRE([AC_PROG_GREP]) + # Look for "HDF5 Version: X.Y.Z" + HDF5_VERSION=$(eval $H5CC -showconfig | $GREP 'HDF5 Version:' \ + | $AWK '{print $[]3}') -fi + # A ideal situation would be where everything we needed was + # in the AM_* variables. However most systems are not like this + # and seem to have the values in the non-AM variables. + # + # We try the following to find the flags: + # (1) Look for "NAME:" tags + # (2) Look for "H5_NAME:" tags + # (3) Look for "AM_NAME:" tags + # + HDF5_tmp_flags=$(eval $H5CC -showconfig \ + | $GREP 'FLAGS\|Extra libraries:' \ + | $AWK -F: '{printf("%s "), $[]2}' ) -CFLAGS="${HDF5_CFLAGS} ${CFLAGS}" + dnl Find the installation directory and append include/ + HDF5_tmp_inst=$(eval $H5CC -showconfig \ + | $GREP 'Installation point:' \ + | $AWK '{print $[]NF}' ) + + dnl Add this to the CPPFLAGS + HDF5_CPPFLAGS="-I${HDF5_tmp_inst}/include" + + HDF5_SHOW=$(eval $H5CC -show) + + dnl Now sort the flags out based upon their prefixes + for arg in $HDF5_SHOW $HDF5_tmp_flags ; do + case "$arg" in + -I*) echo $HDF5_CPPFLAGS | $GREP -e "$arg" 2>&1 >/dev/null \ + || HDF5_CPPFLAGS="$HDF5_CPPFLAGS $arg" + ;; + -L*) echo $HDF5_LDFLAGS | $GREP -e "$arg" 2>&1 >/dev/null \ + || HDF5_LDFLAGS="$HDF5_LDFLAGS $arg" + ;; + -l*) echo $HDF5_LIBS | $GREP -e "$arg" 2>&1 >/dev/null \ + || HDF5_LIBS="$HDF5_LIBS $arg" + ;; + esac + done + + ]) + ]) + AC_DEFINE([HAVE_HDF5], 1, [Define to 1 if HDF5 is available]) + ]) + +AM_CONDITIONAL([HAVE_HDF5],[test "x$with_hdf5" != "xno"]) + +AC_SUBST([PKG_HDF5]) +AC_SUBST([HDF5_LDFLAGS]) +AC_SUBST([HDF5_LIBS]) +AC_SUBST([HDF5_CFLAGS]) +AC_SUBST([HDF5_CPPFLAGS]) CPPFLAGS="${HDF5_CPPFLAGS} ${CPPFLAGS}" +CFLAGS="${HDF5_CFLAGS} ${CFLAGS}" LDFLAGS="${HDF5_LDFLAGS} ${LDFLAGS}" LIBS="${HDF5_LIBS} ${LIBS}" -# Check if HDF5 is available with pkg-config. - -PKG_CHECK_MODULES([HDF5], [hdf5 >= 1.8], [ - PKG_HDF5="hdf5" - ],[ - PKG_HDF5="" - ]) -PKG_CFLAGS="${HDF5_CFLAGS}" -PKG_LIBS="${HDF5_LIBS}" - -AC_SUBST([PKG_HDF5]) -AC_SUBST([PKG_CFLAGS]) -AC_SUBST([PKG_LIBS]) - -AM_CONDITIONAL([HAVE_HDF5],[test "$with_hdf5" = "yes"]) +AS_IF([test "x$with_hdf5" != "xno"], [ + OLD_LIBS=$LIBS + AC_CHECK_LIB([hdf5], [H5Fcreate], [], [ + AC_MSG_ERROR([-lhdf5 fails, use ./configure --with-hdf5=...]) ]) + AC_CHECK_HEADER([hdf5.h], [], [ + AC_MSG_ERROR([hdf5.h not found, use ./configure --with-hdf5=...]) ]) + LIBS=$OLD_LIBS +]) # The block below should only execute if the ax_lib_hdf5.m4 macro failed to find HDF5. # It is only needed to manually build Python API because setup.py depends on HDF5. -if test "$HDF5_LDFLAGS" = "" || "$HDF5_CFLAGS" = ""; then - HDF5_LDFLAGS="${PKG_LIBS}" - HDF5_CFLAGS="${PKG_CFLAGS}" - AC_SUBST([HDF5_CFLAGS]) - AC_SUBST([HDF5_LDFLAGS]) -fi +#if test x"$HDF5_LDFLAGS" = "x" || x"$HDF5_CFLAGS" = "x"; then +# AC_SUBST([HDF5_CFLAGS]) +# AC_SUBST([HDF5_LDFLAGS]) +#fi # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_INT32_T @@ -286,7 +316,7 @@ AC_CONFIG_FILES([Makefile pkgconfig/trexio.pc]) AC_OUTPUT -echo \ +AS_ECHO([ \ "------------------------------------------------- ${PACKAGE_NAME} Version ${PACKAGE_VERSION} ${GIT_HASH} ${TREXIO_DEVEL} @@ -309,4 +339,4 @@ where the optional is: all - build C library and Fortran binding check - run unit tests install - install the library ---------------------------------------------------" +--------------------------------------------------"]) diff --git a/examples.org b/docs/examples.org similarity index 56% rename from examples.org rename to docs/examples.org index 241c63e..d21be98 100644 --- a/examples.org +++ b/docs/examples.org @@ -1,8 +1,146 @@ #+TITLE: Examples #+STARTUP: latexpreview -#+SETUPFILE: docs/theme.setup +#+SETUPFILE: ./theme.setup +* Writing nuclear coordinates + Here is a demonstration of how to use TREXIO to write the nuclear + coordinates of a water molecule to a file. It shows the basic steps + involved in opening a file, writing the data, and closing the file, + as well as the necessary TREXIO functions to perform these actions. + +** C + #+begin_src c +#include +#include + +int main() { + int num = 3; // Number of atoms + double coord[][3] = { + // xyz coordinates in atomic units + 0. , 0. , -0.24962655, + 0. , 2.70519714, 1.85136466, + 0. , -2.70519714, 1.85136466 }; + + trexio_exit_code rc; + + // Open the TREXIO file + trexio_t* f = trexio_open("water.trexio", 'w', TREXIO_HDF5, &rc); + if (rc != TREXIO_SUCCESS) { + fprintf(stderr, "Error: %s\n", trexio_string_of_error(rc)); + return -1; + } + + // Write the number of nuclei + rc = trexio_write_nucleus_num (f, num); + if (rc != TREXIO_SUCCESS) { + fprintf(stderr, "Error: %s\n", trexio_string_of_error(rc)); + return -1; + } + + // Write the nuclear coordinates + rc = trexio_write_nucleus_coord (f, &coord[0][0]); + if (rc != TREXIO_SUCCESS) { + fprintf(stderr, "Error: %s\n", trexio_string_of_error(rc)); + return -1; + } + + // Close the TREXIO file + rc = trexio_close(f); + if (rc != TREXIO_SUCCESS) { + fprintf(stderr, "Error: %s\n", trexio_string_of_error(rc)); + return -1; + } + return 0; +} + #+end_src + +** Python + + This code uses the TREXIO Python binding to create a new TREXIO file named + =water.trexio=, and write the nuclear coordinates of a water molecule. + + The ~coord~ variable is a list of three lists, each containing the x, y, + and z coordinates of the water molecule's nuclei. + + The ~with~ statement is used to ensure the file is properly closed after + the write is complete. + + The ~trexio.write_nucleus_num~ function is used to write the number of + nuclei in the system. + + The ~trexio.write_nucleus_coord~ function is used to write the nuclear + coordinates of the system. + + #+begin_src python +import trexio +coord = [ # xyz coordinates in atomic units + [0. , 0., -0.24962655], + [0. , 2.70519714, 1.85136466], + [0. , -2.70519714, 1.85136466] +] +# The Python API calls can raise `trexio.Error` +# exceptions to be handled via try/except clauses +# in the user application +with trexio.File("water.trexio", 'w', + back_end=trexio.TREXIO_HDF5) as f: + trexio.write_nucleus_num(f, len(coord)) + trexio.write_nucleus_coord(f, coord) + + #+end_src + +** Fortran + #+begin_src f90 +program trexio_water + use trexio + + integer, parameter :: num=3 ! Number of nuclei + double precision :: coord(3,3) ! Array of atom coordinates + + integer(trexio_t) :: f ! The TREXIO file handle + integer(trexio_exit_code) :: rc ! TREXIO return code + character*(128) :: err_msg ! String holding the error message + + coord(:,:) = reshape( (/ 0.d0 , 0.d0 , -0.24962655d0, & + 0.d0 , 2.70519714d0, 1.85136466d0, & + 0.d0 , -2.70519714d0, 1.85136466d0 /), & + shape(coord) ) + + ! Open the TREXIO file + f = trexio_open ('water.trexio', 'w', TREXIO_HDF5, rc) + if (rc /= TREXIO_SUCCESS) then + call trexio_string_of_error(rc, err_msg) + print *, 'Error: '//trim(err_msg) + call exit(-1) + end if + + ! Write the number of nuclei + rc = trexio_write_nucleus_num (f, num) + if (rc /= TREXIO_SUCCESS) then + call trexio_string_of_error(rc, err_msg) + print *, 'Error: '//trim(err_msg) + call exit(-1) + end if + + ! Write the nuclear coordinates + rc = trexio_write_nucleus_coord (f, coord) + if (rc /= TREXIO_SUCCESS) then + call trexio_string_of_error(rc, err_msg) + print *, 'Error: '//trim(err_msg) + call exit(-1) + end if + + ! Close the TREXIO file + rc = trexio_close(f) + if (rc /= TREXIO_SUCCESS) then + call trexio_string_of_error(rc, err_msg) + print *, 'Error: '//trim(err_msg) + call exit(-1) + end if + +end program + #+end_src + * Accessing sparse quantities (integrals) ** Fortran @@ -62,7 +200,7 @@ program print_energy #+begin_src f90 call getarg(1, filename) - f = trexio_open (filename, 'r', TREXIO_HDF5, rc) + f = 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) @@ -272,9 +410,141 @@ program print_energy end program #+end_src +** Python + :PROPERTIES: + :header-args: :tangle print_energy.py + :END: + + #+begin_src python +import sys +import trexio +import numpy as np + +BUFSIZE = 100000 + #+end_src + + This program computes the energy as: + + \[ + E = E_{\text{NN}} + \sum_{ij} \gamma_{ij}\, \langle j | h | i \rangle\, + +\, \frac{1}{2} \sum_{ijkl} \Gamma_{ijkl}\, \langle k l | i j + \rangle\; \textrm{ with } \; 0 < i,j,k,l \le n + \] + One needs to read from the TREXIO file: + + - $n$ :: The number of molecular orbitals + - $E_{\text{NN}}$ :: The nuclear repulsion energy + - $\gamma_{ij}$ :: The one-body reduced density matrix + - $\langle j |h| i \rangle$ :: The one-electron Hamiltonian integrals + - $\Gamma_{ijkl}$ :: The two-body reduced density matrix + - $\langle k l | i j \rangle$ :: The electron repulsion integrals + +*** Obtain the name of the TREXIO file from the command line, and open it for reading + + #+begin_src python +filename = sys.argv[1] +f = trexio.File(filename, 'r', trexio.TREXIO_AUTO) + #+end_src + +*** Read the nuclear repulsion energy + + #+begin_src python +E_nn = trexio.read_nucleus_repulsion(f) + #+end_src + +*** Read the number of molecular orbitals + + #+begin_src python +n = trexio.read_mo_num(f) + #+end_src + +*** Read one-electron quantities + + #+begin_src python +if not trexio.has_mo_1e_int_core_hamiltonian(f): + print("No core hamiltonian in file") + sys.exit(-1) + +h0 = trexio.read_mo_1e_int_core_hamiltonian(f) + +if not trexio.has_rdm_1e(f): + print("No 1e RDM in file") + sys.exit(-1) + +D = trexio.read_rdm_1e(f) + #+end_src + +*** Read two-electron quantities + +**** Electron repulsion integrals + + #+begin_src python +if not trexio.has_mo_2e_int_eri(f): + print("No electron repulsion integrals in file") + sys.exit(-1) + +size_max = trexio.read_mo_2e_int_eri_size(f) + +offset = 0 +icount = BUFSIZE +feof = False +W = np.zeros( (n,n,n,n) ) +while not feof: + buffer_index, buffer_values, icount, feof = trexio.read_mo_2e_int_eri(f, offset, icount) + for m in range(icount): + i, j, k, l = buffer_index[m] + W[i,j,k,l] = buffer_values[m] + W[k,j,i,l] = buffer_values[m] + W[i,l,k,j] = buffer_values[m] + W[k,l,i,j] = buffer_values[m] + W[j,i,l,k] = buffer_values[m] + W[j,k,l,i] = buffer_values[m] + W[l,i,j,k] = buffer_values[m] + W[l,k,j,i] = buffer_values[m] + #+end_src + +**** Reduced density matrix + + #+begin_src python +if not trexio.has_rdm_2e(f): + print("No two-body density matrix in file") + +offset = 0 +icount = BUFSIZE +feof = False +G = np.zeros( (n,n,n,n) ) +while not feof: + buffer_index, buffer_values, icount, feof = trexio.read_rdm_2e(f, offset, icount) + for m in range(icount): + i, j, k, l = buffer_index[m] + G[i,j,k,l] = buffer_values[m] + + #+end_src + +*** Compute the energy + + When the orbitals are real, we can use + \begin{eqnarray*} + E &=& E_{\text{NN}} + \sum_{ij} \gamma_{ij}\, \langle j | h | i \rangle\, + +\, \frac{1}{2} \sum_{ijkl} \Gamma_{ijkl}\, \langle k l | i j + \rangle \\ + &=& E_{\text{NN}} + \sum_{ij} \gamma_{ij}\, \langle i | h | j \rangle\, + +\, \frac{1}{2} \sum_{ijkl} \Gamma_{ijkl}\, \langle i j | k l + \rangle \\ + \end{eqnarray*} + + #+begin_src python +G = np.reshape(G, (n*n, n*n) ) +W = np.reshape(W, (n*n, n*n) ) +E = E_nn +E += 0.5*sum( [ np.dot(G[:,l], W[:,l]) for l in range(n*n) ] ) +E += sum( [ np.dot(D[:,l], h0[:,l]) for l in range(n) ] ) + +print (f"Energy: {E}") + #+end_src * Reading determinants - + ** Fortran :PROPERTIES: :header-args: :tangle print_dets.f90 diff --git a/docs/intro.org b/docs/intro.org new file mode 100644 index 0000000..0abc923 --- /dev/null +++ b/docs/intro.org @@ -0,0 +1,60 @@ +#+TITLE: Motivation +#+STARTUP: latexpreview +#+SETUPFILE: ./theme.setup + + +#+BEGIN_EXPORT html + + +TREXIO logo + + +#+END_EXPORT + +Quantum chemistry relies on quantum mechanics to explain and predict +the properties and behaviors of atoms, molecules, and materials. +Although density functional theory (DFT) is one of the most widely +used approaches thanks to its excellent ratio between computational +cost and accuracy, another important tool is wave function theory +(WFT), which describes the behavior of a quantum system in terms of +its wave function. +In order to perform WFT calculations, it is necessary to manipulate a +large number of parameters, such as the expansion coefficients of the +wave function and the matrix elements of the Hamiltonian operator. +These parameters can be numerous and difficult to handle, making it +important to have a robust and efficient method for storing and +accessing them. + +Reproducible research remains a challenging topic, despite recent +advances such as the introduction of the FAIR (findable, accessible, +interoperable, reusable) data principles. A key +aspect of reproducibility is software interoperability, which refers +to the ability of different programs to work together and exchange +information, allowing different systems to communicate and exchange +data in order to function as a cohesive whole. +Interoperable software is prevalent nowadays and is a key component of +the Unix philosophy. In Unix shells, the most +straightforward application of software interoperability is made +through the use of the /pipe/ operator, where the output of a +program is the input of another program. +Similarly, shell scripts are created through the composition of +smaller programs, exchanging data through files or pipes. + +A major challenge of reproducible research is the unified input/output +(I/O) of data within a particular research domain. The Unix +philosophy recommends the use of text files because they are +architecture-independent, readable in any language, and can be read as +a stream, which is useful for making programs communicate over a +network. +However, storing data in a text format can result in larger file sizes +and conversion from ASCII to binary format can be computationally +expensive for large data sets. To address this concern, +domain-specific binary formats have been developed, such as the Joint +Photographic Experts Group (JPEG) format for digital images +and the Moving Picture Experts Group (MPEG) format for videos. +These binary formats are utilized through a standardized application +programming interface (API). + +In the field of wave function theory such a standard format and API is +still lacking, and the purpose of the TREXIO library is to fill this gap. diff --git a/docs/lib.org b/docs/lib.org new file mode 100644 index 0000000..a45e73e --- /dev/null +++ b/docs/lib.org @@ -0,0 +1,311 @@ +#+TITLE: The TREXIO library +#+STARTUP: latexpreview +#+SETUPFILE: ./theme.setup + + +* Format specification + +#+BEGIN_EXPORT html + + +TREX in a library + + +#+END_EXPORT +# + The TREXIO format is designed to store all the necessary information + to represent a wave function. + One notable feature of TREXIO is that it is self-contained, meaning + that all the parameters needed to recreate the wave function are + explicitly stored within the file, eliminating the need for external + databases. For example, instead of storing the name of a basis set + (such as cc-pVDZ), the actual basis set parameters used in the + calculation are stored. + +** Organization of the data + + The data in TREXIO are organized into *groups*, each containing + multiple *attributes* defined by their *type* and *dimensions*. Each + attribute within a group corresponds to a single scalar or array + variable in a code. In what follows, the notation + ~.~ will be used to identify an attribute within a + group. For example, ~nucleus.charge~ refers to the + ~charge~ attribute in the ~nucleus~ group. It is an array of type + ~float~ with dimensions ~nucleus.num~, the attribute describing the + number of nuclei. + +** Data types + + So that TREXIO can be used in any language, we use a limited number + of data types. The main data types are ~int~ for integers, + ~float~ for floating-point values, and ~str~ for + character strings. For complex numbers, their real and imaginary + parts are stored as ~float~. To minimize the risk of integer + overflow and accuracy loss, numerical data types are stored using + 64-bit representations by default. However, in specific cases where + integers are bounded (such as orbital indices in four-index + integrals), the smallest possible representation is used to reduce the + file size. The API handles any necessary type conversions. + + There are also two types derived from ~int~: ~dim~ and ~index~. + ~dim~ is used for dimensioning variables, which are positive integers + used to specify the dimensions of an array. In the previous example, + ~nucleus.num~ is a dimensioning variable that specifies the + dimensions of the ~nucleus.charge~ array. ~index~ is used for + integers that correspond to array indices, because some languages + (such as C or Python) use zero-based indexing, while others (such as + Fortran) use one-based indexing. For convenience, values of the + ~index~ type are shifted by one when TREXIO is used in one-based + languages to be consistent with the semantics of the language. + 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. + + Arrays can be stored in either dense or sparse formats. If the + sparse format is selected, the data is stored in coordinate format. + For example, the element ~A(i,j,k,l)~ is stored as a quadruplet of + integers $(i,j,k,l)$ along with the corresponding value. Typically, + two-dimensional arrays are stored as dense arrays, while arrays with + higher dimensions are stored in sparse format. + For sparse data structures 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]]. + + For the Configuration Interaction (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. + + Some data may be complex. In that case, the real part should be stored + in the variable, and the imaginary part will be stored in the variable + with the same name suffixed by ~_im~. + +* The TREXIO library + +#+BEGIN_EXPORT html + + +TREX in a library + + +#+END_EXPORT + + The TREXIO library is written is the C language, and is licensed under + the open-source 3-clause BSD license to allow for use in all types of + quantum chemistry software, whether commercial or not. + + The design of the library is divided into two main sections: the + front-end and the back-end. The front-end serves as the interface + between users and the library, while the back-end acts as the + interface between the library and the physical storage. + +** The front-end + + By using the TREXIO library, users can store and extract data in a + consistent and organized manner. The library provides a user-friendly + API, including functions for reading, writing, and checking for the + existence of data. The functions follow the pattern + ~trexio_[has|read|write]__~, where the + group and attribute specify the particular data being accessed. It + also includes an error handling mechanism, in which each function call + returns an exit code of type ~trexio_exit_code~, explaining + the type of error. + This can be used to catch exceptions and improve debugging in the + upstream user application. + + To ensure the consistency of the data, the attributes can only be + written if all the other attributes on which they explicitly depend + have been written. For example, as the ~nucleus.coord~ array is + dimensioned by the number of nuclei ~nucleus.num~, the ~nucleus.coord~ + attribute can only be written after ~nucleus.num~. However, the + library is not aware of non-explicit dependencies, such as the + relation between the electron repulsion integrals (ERIs) and MO + coefficients. A complete control of the consistency of the data is + therefore impossible, so the attributes were chosen to be by default + /immutable/. By only allowing data to be written only once, the + risk of modifying data in a way that creates inconsistencies is + reduced. For example, if the ERIs have already been written, it would + be inconsistent to later modify the MO coefficients. To allow for + flexibility, the library also allows for the use of an /unsafe/ + mode, in which data can be overwritten. However, this mode carries + the risk of producing inconsistent files, and the ~metadata~ group's + ~unsafe~ attribute is set to ~1~ to indicate that the file has + potentially been modified in a dangerous way. This attribute can be + manually reset to ~0~ if the user is confident that the modifications + made are safe. + +** The back-end + + At present, TREXIO supports two back-ends: one relying only on the + C standard library to produce plain text files (the so-called /text/ + back-end), and one relying on the HDF5 library. + + With the text back-end, the TREXIO "file" is a directory containing + multiple text files, one for each group. This back end is intended + to be used in development environments, as it gives access to the + user to the standard tools such as ~diff~ and ~grep~. + In addition, text files are better adapted than binary files for + version control systems such as Git, so this format can be also + used for storing reference data for unit tests. + + HDF5 is a binary file format and library for storing and managing + large amounts of data in a hierarchical structure. It allows users + to manipulate data in a way similar to how files and directories + are manipulated within the file system. The HDF5 library provides + optimal performance through its memory mapping mechanism and + supports advanced features such as serial and parallel I/O, + chunking, and compression filters. However, HDF5 files are in + binary format, which requires additional tools such as ~h5dump~ to + view them in a human-readable format. It is widely used in + scientific and engineering applications, and is known for its high + performance and ability to handle large data sets efficiently. + + The TREXIO HDF5 back-end is the recommended choice for production + environments, as it provides high I/O performance. Furthermore, + all data is stored in a single file, making it especially suitable + for parallel file systems like Lustre. These file systems are + optimized for large, sequential I/O operations and are not + well-suited for small, random I/O operations. When multiple small + files are used, the file system may become overwhelmed with + metadata operations like creating, deleting, or modifying files, + which can adversely affect performance. + + In a benchmarking program designed to compare the two back-ends of + the library, the HDF5 back-end was found to be significantly faster + than the text back-end. The program wrote a wave function made up + of 100 million Slater determinants and measured the time taken to + write the Slater determinants and CI coefficients. The HDF5 + back-end achieved a speed of $10.4\times10^6$ Slater determinants + per second and a data transfer rate of 406 MB/s, while the text + back-end had a speed of $1.1\times10^6$ determinants per second and + a transfer rate of 69 MB/s. These results were obtained on a DELL + 960 GB mix-use solid-state drive (SSD). The HDF5 back-end was able + to achieve a performance level close to the peak performance of the + SSD, while the text back-end's performance was limited by the speed + of the CPU for performing binary to ASCII conversions. + + In addition to the HDF5 and text back-ends, it is also possible to + introduce new back-ends to the library. For example, a back-end + could be created to support object storage systems, such as those + used in cloud-based applications or for archiving in open data + repositories. + +** Supported languages + + One of the main benefits of using C as the interface for a library is + that it is easy to use from other programming languages. Many + programming languages, such as Python or Julia, provide built-in + support for calling C functions, which means that it is relatively + straightforward to write a wrapper that allows a library written in C + to be called from another language. + In general, libraries with a C interface are the easiest to use from + other programming languages, because C is widely supported and has a + simple, stable application binary interface (ABI). Other languages, + such as Fortran and C++, may have more complex ABIs and may + require more work to interface with them. + + TREXIO has been employed in codes developed in various programming + languages, including C, C++, Fortran, Python, OCaml, and Julia. While + Julia is designed to enable the use of C functions without the need + for additional manual interfacing, the TREXIO C header file was + automatically integrated into Julia programs using the + ~CBindings.jl~ package. + In contrast, specific bindings have been provided for Fortran, Python, + and OCaml to simplify the user experience. + + In particular, the binding for Fortran is not distributed as multiple + compiled Fortran module files (~.mod~), but instead as a single + Fortran source file (~.F90~). The distribution of the source file + instead of the compiled module has multiple benefits. It ensures that + the TREXIO module is always compiled with the same compiler as the + client code, avoiding the compatibility problem of ~.mod~ files + between different compiler versions and vendors. The single-file + model requires very little changes in the build system of the user's + codes, and it facilitates the search for the interface of a particular + function. In addition, advanced text editors can parse the TREXIO + interface to propose interactive auto-completion of the TREXIO + function names to the developers. + + Finally, the Python module, partly generated with SWIG and fully + compatible with NumPy, allows Python users to interact with the + library in a more intuitive and user-friendly way. Using the Python + interface is likely the easiest way to begin using TREXIO and + understanding its features. In order to help users get started with + TREXIO and understand its functionality, tutorials in Jupyter + notebooks are available on GitHub + (https://github.com/TREX-CoE/trexio-tutorials), and can be executed + via the Binder platform. + + +** Source code generation and documentation + + Source code generation is a valuable technique that can significantly + improve the efficiency and consistency of software development. By + using templates to generate code automatically, developers can avoid + manual coding and reduce the risk of errors or inconsistencies. This + approach is particularly useful when a large number of functions + follow similar patterns, as in the case of the TREXIO library, where + functions are named according to the pattern + ~trexio_[has|read|write]__~. + By generating these functions from the format specification using + templates, the developers can ensure that the resulting code follows a + consistent structure and is free from errors or inconsistencies. + + The description of the format is written in a text file in the Org + format. Org is a structured plain text format, containing information + expressed in a lightweight markup language similar to the popular + Markdown language. While Org was introduced as a mode of the GNU + Emacs text editor, its basic functionalities have been implemented in + most text editors such as Vim, Atom or VS Code. + + There are multiple benefits in using the Org format. The first + benefit is that the Org syntax is easy to learn and allows for the + insertion of equations in \LaTeX{} syntax. Additionally, Org files + can be easily converted to HyperText Markup Language (HTML) or + Portable Document Format (PDF) for generating documentation. The + second benefit is that GNU Emacs is a programmable text editor and + code blocks in Org files can be executed interactively, similar to + Jupyter notebooks. These code blocks can also manipulate data defined + in tables and this feature is used to automatically transform tables + describing groups and attributes in the documentation into a + JavaScript Object Notation (JSON) file. + This JSON file is then used by a Python script to generate the needed + functions in C language, as well as header files and some files + required for the Fortran, Python, and OCaml interfaces. + + With this approach, contributions to the development of the TREXIO + library can be made simply by adding new tables to the Org file, which + can be submitted as /pull requests/ on the project's GitHub + repository (https://github.com/trex-coe/trexio). Overall, this + process allows for a more efficient and consistent development process + and enables contributions from a wider range of individuals, + regardless of their programming skills. + +** Availability + + The TREXIO library is designed to be portable and easy to install + on a wide range of systems. It follows the C99 standard to ensure + compatibility with older systems, and can be configured with either + the GNU Autotools or the CMake build systems. The only external + dependency is the HDF5 library, which is widely available on HPC + platforms and as packages on major Linux distributions. Note that + it is possible to disable the HDF5 back-end at configuration time, + allowing TREXIO to operate only with the text back-end and have + zero external dependencies. This can be useful for users who may + not be able to install HDF5 on certain systems. + + TREXIO is distributed as a tarball containing the source code, + generated code, documentation, and Fortran interface. It is also + available as a binary ~.deb~ package for Debian-based Linux + distributions and as packages for Guix, Spack and Conda. The Python + module can be found in the PyPI repository, the OCaml binding is + available in the official OPAM repository, and the ~.deb~ packages + are available in Ubuntu 23.04. diff --git a/docs/theme.setup b/docs/theme.setup index f259c95..a42c4ef 100644 --- a/docs/theme.setup +++ b/docs/theme.setup @@ -1,11 +1,11 @@ # -*- mode: org; -*- #+HTML_LINK_HOME: index.html -#+OPTIONS: H:4 num:t toc:t \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t d:(HIDE) +#+OPTIONS: H:4 num:t toc:nil \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t d:(HIDE) ####### #+SETUPFILE: ../docs/org-html-themes/org/theme-readtheorg.setup -#+INFOJS_OPT: toc:t mouse:underline path:org-info.js +#+INFOJS_OPT: mouse:underline path:org-info.js #+HTML_HEAD: #+STARTUP: align nodlcheck hidestars oddeven lognotestate diff --git a/docs/trex_lib.png b/docs/trex_lib.png new file mode 100644 index 0000000..8c4be97 Binary files /dev/null and b/docs/trex_lib.png differ diff --git a/docs/trex_specs.png b/docs/trex_specs.png new file mode 100644 index 0000000..cb8ffc0 Binary files /dev/null and b/docs/trex_specs.png differ diff --git a/docs/trexio.png b/docs/trexio.png new file mode 100644 index 0000000..f672a27 Binary files /dev/null and b/docs/trexio.png differ diff --git a/docs/trexio_logo.png b/docs/trexio_logo.png new file mode 100644 index 0000000..2ef008a Binary files /dev/null and b/docs/trexio_logo.png differ diff --git a/m4/ax_lib_hdf5.m4 b/m4/ax_lib_hdf5.m4 deleted file mode 100644 index 86f97fb..0000000 --- a/m4/ax_lib_hdf5.m4 +++ /dev/null @@ -1,323 +0,0 @@ -# =========================================================================== -# https://www.gnu.org/software/autoconf-archive/ax_lib_hdf5.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_LIB_HDF5([serial/parallel]) -# -# DESCRIPTION -# -# This macro provides tests of the availability of HDF5 library. -# -# The optional macro argument should be either 'serial' or 'parallel'. The -# former only looks for serial HDF5 installations via h5cc. The latter -# only looks for parallel HDF5 installations via h5pcc. If the optional -# argument is omitted, serial installations will be preferred over -# parallel ones. -# -# The macro adds a --with-hdf5 option accepting one of three values: -# -# no - do not check for the HDF5 library. -# yes - do check for HDF5 library in standard locations. -# path - complete path to the HDF5 helper script h5cc or h5pcc. -# -# If HDF5 is successfully found, this macro calls -# -# AC_SUBST(HDF5_VERSION) -# AC_SUBST(HDF5_CC) -# AC_SUBST(HDF5_CFLAGS) -# AC_SUBST(HDF5_CPPFLAGS) -# AC_SUBST(HDF5_LDFLAGS) -# AC_SUBST(HDF5_LIBS) -# AC_SUBST(HDF5_FC) -# AC_SUBST(HDF5_FFLAGS) -# AC_SUBST(HDF5_FLIBS) -# AC_SUBST(HDF5_TYPE) -# AC_DEFINE(HAVE_HDF5) -# -# and sets with_hdf5="yes". Additionally, the macro sets -# with_hdf5_fortran="yes" if a matching Fortran wrapper script is found. -# Note that Autoconf's Fortran support is not used to perform this check. -# H5CC and H5FC will contain the appropriate serial or parallel HDF5 -# wrapper script locations. -# -# If HDF5 is disabled or not found, this macros sets with_hdf5="no" and -# with_hdf5_fortran="no". -# -# Your configuration script can test $with_hdf to take any further -# actions. HDF5_{C,CPP,LD}FLAGS may be used when building with C or C++. -# HDF5_F{FLAGS,LIBS} should be used when building Fortran applications. -# -# To use the macro, one would code one of the following in "configure.ac" -# before AC_OUTPUT: -# -# 1) dnl Check for HDF5 support -# AX_LIB_HDF5() -# -# 2) dnl Check for serial HDF5 support -# AX_LIB_HDF5([serial]) -# -# 3) dnl Check for parallel HDF5 support -# AX_LIB_HDF5([parallel]) -# -# One could test $with_hdf5 for the outcome or display it as follows -# -# echo "HDF5 support: $with_hdf5" -# -# You could also for example, override the default CC in "configure.ac" to -# enforce compilation with the compiler that HDF5 uses: -# -# AX_LIB_HDF5([parallel]) -# if test "$with_hdf5" = "yes"; then -# CC="$HDF5_CC" -# else -# AC_MSG_ERROR([Unable to find HDF5, we need parallel HDF5.]) -# fi -# -# The HDF5_TYPE environment variable returns "parallel" or "serial", -# depending on which type of library is found. -# -# LICENSE -# -# Copyright (c) 2009 Timothy Brown -# Copyright (c) 2010 Rhys Ulerich -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 20 - -AC_DEFUN([AX_LIB_HDF5], [ - -AC_REQUIRE([AC_PROG_SED]) -AC_REQUIRE([AC_PROG_AWK]) -AC_REQUIRE([AC_PROG_GREP]) - -dnl Check first argument is one of the recognized values. -dnl Fail eagerly if is incorrect as this simplifies case statements below. -if test "m4_normalize(m4_default([$1],[]))" = "" ; then - : # Recognized value -elif test "m4_normalize(m4_default([$1],[]))" = "serial" ; then - : # Recognized value -elif test "m4_normalize(m4_default([$1],[]))" = "parallel"; then - : # Recognized value -else - AC_MSG_ERROR([ -Unrecognized value for AX[]_LIB_HDF5 within configure.ac. -If supplied, argument 1 must be either 'serial' or 'parallel'. -]) -fi - -dnl Add a default --with-hdf5 configuration option. -AC_ARG_WITH([hdf5], - AS_HELP_STRING( - [--with-hdf5=[yes/no/PATH]], - m4_case(m4_normalize([$1]), - [serial], [location of h5cc for serial HDF5 configuration], - [parallel], [location of h5pcc for parallel HDF5 configuration], - [location of h5cc or h5pcc for HDF5 configuration]) - ), - [if test "$withval" = "no"; then - with_hdf5="no" - elif test "$withval" = "yes"; then - with_hdf5="yes" - else - with_hdf5="yes" - H5CC="$withval" - fi], - [with_hdf5="yes"] -) - -dnl Set defaults to blank -HDF5_CC="" -HDF5_VERSION="" -HDF5_CFLAGS="" -HDF5_CPPFLAGS="" -HDF5_LDFLAGS="" -HDF5_LIBS="" -HDF5_FC="" -HDF5_FFLAGS="" -HDF5_FLIBS="" -HDF5_TYPE="" - -dnl Try and find hdf5 compiler tools and options. -if test "$with_hdf5" = "yes"; then - if test -z "$H5CC"; then - dnl Check to see if H5CC is in the path. - AC_PATH_PROGS( - [H5CC], - m4_case(m4_normalize([$1]), - [serial], [h5cc], - [parallel], [h5pcc], - [h5cc h5pcc]), - []) - else - AC_MSG_CHECKING([Using provided HDF5 C wrapper]) - AC_MSG_RESULT([$H5CC]) - fi - AC_MSG_CHECKING([for HDF5 type]) - AS_CASE([$H5CC], - [*h5pcc], [HDF5_TYPE=parallel], - [*h5cc], [HDF5_TYPE=serial], - [HDF5_TYPE=neither]) - AC_MSG_RESULT([$HDF5_TYPE]) - AC_MSG_CHECKING([for HDF5 libraries]) - if test ! -f "$H5CC" || test ! -x "$H5CC"; then - AC_MSG_RESULT([no]) - AC_MSG_WARN(m4_case(m4_normalize([$1]), - [serial], [ -Unable to locate serial HDF5 compilation helper script 'h5cc'. -Please specify --with-hdf5= as the full path to h5cc. -HDF5 support is being disabled (equivalent to --with-hdf5=no). -], [parallel],[ -Unable to locate parallel HDF5 compilation helper script 'h5pcc'. -Please specify --with-hdf5= as the full path to h5pcc. -HDF5 support is being disabled (equivalent to --with-hdf5=no). -], [ -Unable to locate HDF5 compilation helper scripts 'h5cc' or 'h5pcc'. -Please specify --with-hdf5= as the full path to h5cc or h5pcc. -HDF5 support is being disabled (equivalent to --with-hdf5=no). -])) - with_hdf5="no" - with_hdf5_fortran="no" - else - dnl Get the h5cc output - HDF5_SHOW=$(eval $H5CC -show) - - dnl Get the actual compiler used - HDF5_CC=$(eval $H5CC -show | head -n 1 | $AWK '{print $[]1}') - if test "$HDF5_CC" = "ccache"; then - HDF5_CC=$(eval $H5CC -show | head -n 1 | $AWK '{print $[]2}') - fi - - dnl h5cc provides both AM_ and non-AM_ options - dnl depending on how it was compiled either one of - dnl these are empty. Lets roll them both into one. - - dnl Look for "HDF5 Version: X.Y.Z" - HDF5_VERSION=$(eval $H5CC -showconfig | $GREP 'HDF5 Version:' \ - | $AWK '{print $[]3}') - - dnl A ideal situation would be where everything we needed was - dnl in the AM_* variables. However most systems are not like this - dnl and seem to have the values in the non-AM variables. - dnl - dnl We try the following to find the flags: - dnl (1) Look for "NAME:" tags - dnl (2) Look for "H5_NAME:" tags - dnl (3) Look for "AM_NAME:" tags - dnl - HDF5_tmp_flags=$(eval $H5CC -showconfig \ - | $GREP 'FLAGS\|Extra libraries:' \ - | $AWK -F: '{printf("%s "), $[]2}' ) - - dnl Find the installation directory and append include/ - HDF5_tmp_inst=$(eval $H5CC -showconfig \ - | $GREP 'Installation point:' \ - | $AWK '{print $[]NF}' ) - - dnl Add this to the CPPFLAGS - HDF5_CPPFLAGS="-I${HDF5_tmp_inst}/include" - - dnl Now sort the flags out based upon their prefixes - for arg in $HDF5_SHOW $HDF5_tmp_flags ; do - case "$arg" in - -I*) echo $HDF5_CPPFLAGS | $GREP -e "$arg" 2>&1 >/dev/null \ - || HDF5_CPPFLAGS="$HDF5_CPPFLAGS $arg" - ;; - -L*) echo $HDF5_LDFLAGS | $GREP -e "$arg" 2>&1 >/dev/null \ - || HDF5_LDFLAGS="$HDF5_LDFLAGS $arg" - ;; - -l*) echo $HDF5_LIBS | $GREP -e "$arg" 2>&1 >/dev/null \ - || HDF5_LIBS="$HDF5_LIBS $arg" - ;; - esac - done - - HDF5_LIBS="-lhdf5 $HDF5_LIBS" - AC_MSG_RESULT([yes (version $[HDF5_VERSION])]) - - dnl See if we can compile - AC_LANG_PUSH([C]) - ax_lib_hdf5_save_CC=$CC - ax_lib_hdf5_save_CPPFLAGS=$CPPFLAGS - ax_lib_hdf5_save_LIBS=$LIBS - ax_lib_hdf5_save_LDFLAGS=$LDFLAGS - CC=$HDF5_CC - CPPFLAGS=$HDF5_CPPFLAGS - LIBS=$HDF5_LIBS - LDFLAGS=$HDF5_LDFLAGS - AC_CHECK_HEADER([hdf5.h], [ac_cv_hadf5_h=yes], [ac_cv_hadf5_h=no]) - AC_CHECK_LIB([hdf5], [H5Fcreate], [ac_cv_libhdf5=yes], - [ac_cv_libhdf5=no]) - if test "$ac_cv_hadf5_h" = "no" && test "$ac_cv_libhdf5" = "no" ; then - AC_MSG_WARN([Unable to compile HDF5 test program]) - fi - dnl Look for HDF5's high level library - AC_CHECK_LIB([hdf5_hl], [main],[HDF5_LIBS="-lhdf5_hl $HDF5_LIBS"], [], []) - - CC=$ax_lib_hdf5_save_CC - CPPFLAGS=$ax_lib_hdf5_save_CPPFLAGS - LIBS=$ax_lib_hdf5_save_LIBS - LDFLAGS=$ax_lib_hdf5_save_LDFLAGS - AC_LANG_POP([C]) - - AC_MSG_CHECKING([for matching HDF5 Fortran wrapper]) - dnl Presume HDF5 Fortran wrapper is just a name variant from H5CC - H5FC=$(eval echo -n $H5CC | $SED -n 's/cc$/fc/p') - if test -x "$H5FC"; then - AC_MSG_RESULT([$H5FC]) - with_hdf5_fortran="yes" - AC_SUBST([H5FC]) - - dnl Again, pry any remaining -Idir/-Ldir from compiler wrapper - for arg in `$H5FC -show` - do - case "$arg" in #( - -I*) echo $HDF5_FFLAGS | $GREP -e "$arg" >/dev/null \ - || HDF5_FFLAGS="$HDF5_FFLAGS $arg" - ;;#( - -L*) echo $HDF5_FFLAGS | $GREP -e "$arg" >/dev/null \ - || HDF5_FFLAGS="$HDF5_FFLAGS $arg" - dnl HDF5 installs .mod files in with libraries, - dnl but some compilers need to find them with -I - echo $HDF5_FFLAGS | $GREP -e "-I${arg#-L}" >/dev/null \ - || HDF5_FFLAGS="$HDF5_FFLAGS -I${arg#-L}" - ;; - esac - done - - dnl Make Fortran link line by inserting Fortran libraries - for arg in $HDF5_LIBS - do - case "$arg" in #( - -lhdf5_hl) HDF5_FLIBS="$HDF5_FLIBS -lhdf5hl_fortran $arg" - ;; #( - -lhdf5) HDF5_FLIBS="$HDF5_FLIBS -lhdf5_fortran $arg" - ;; #( - *) HDF5_FLIBS="$HDF5_FLIBS $arg" - ;; - esac - done - else - AC_MSG_RESULT([no]) - with_hdf5_fortran="no" - fi - - AC_SUBST([HDF5_VERSION]) - AC_SUBST([HDF5_CC]) - AC_SUBST([HDF5_CFLAGS]) - AC_SUBST([HDF5_CPPFLAGS]) - AC_SUBST([HDF5_LDFLAGS]) - AC_SUBST([HDF5_LIBS]) - AC_SUBST([HDF5_FC]) - AC_SUBST([HDF5_FFLAGS]) - AC_SUBST([HDF5_FLIBS]) - AC_SUBST([HDF5_TYPE]) - AC_DEFINE([HAVE_HDF5], [1], [Defined if you have HDF5 support]) - fi -fi -]) diff --git a/ocaml/trexio/Makefile b/ocaml/trexio/Makefile index 91d0b69..f01743b 100644 --- a/ocaml/trexio/Makefile +++ b/ocaml/trexio/Makefile @@ -4,6 +4,13 @@ default: sources 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 +lib/trexio.h: + cp ../../include/trexio.h lib/ + +sources: lib/trexio.ml lib/trexio.h + +clean: + rm lib/trexio.h lib/trexio.ml lib/trexio.mli lib/trexio_stubs.c + dune clean .PHONY: sources default diff --git a/ocaml/trexio/compile-lib.sh b/ocaml/trexio/compile-lib.sh new file mode 100755 index 0000000..2a0dce3 --- /dev/null +++ b/ocaml/trexio/compile-lib.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +PREFIX=$1 +TASK=$2 +PKGCONFIG_COMMAND="pkg-config --libs --cflags trexio" + +INSTALLED="no" + +# Try with system defaults +if cc test.c >/dev/null 2>&1 ; then + exit +fi + +# Try with pkg-config +if eval $PKGCONFIG_COMMAND >/dev/null 2>&1; then + exit +fi + +# Compile C library +set -e +if test "$TASK" = "build" ; then + tar -zxf trexio-*.tar.gz + cd trexio-* +# ./configure --prefix=${PREFIX} --without-fortran --enable-static --disable-shared + ./configure --prefix=${PWD}/.. --without-fortran --enable-static --disable-shared + make -j 4 + make -j install + cd ../ +elif test "$TASK" = "install" ; then + cd trexio-* + make install + rm -rf trexio-*/ +fi diff --git a/ocaml/trexio/dune-project b/ocaml/trexio/dune-project index 7793cce..71fc87f 100644 --- a/ocaml/trexio/dune-project +++ b/ocaml/trexio/dune-project @@ -1,9 +1,9 @@ (lang dune 3.1) (name trexio) -(version 2.3.0) +(version 2.5.0) -(generate_opam_files true) +(generate_opam_files false) (source (github trex-coe/trexio_ocaml)) diff --git a/ocaml/trexio/read_json.py b/ocaml/trexio/read_json.py index d41bc00..ef4e598 100755 --- a/ocaml/trexio/read_json.py +++ b/ocaml/trexio/read_json.py @@ -7,6 +7,21 @@ stubs_file= "trexio_stubs.c" ml_file = "trexio.ml" mli_file = ml_file+"i" +def check_version(): + with open('trexio.opam','r') as f: + for line in f: + if line.startswith("version"): + ocaml_version = line.split(':')[1].strip()[1:-1] + break + with open('../../configure.ac','r') as f: + for line in f: + if line.startswith("AC_INIT"): + trexio_version = line.split(',')[1].strip()[1:-1] + break + if ocaml_version != trexio_version: + print(f"Inconsistent versions:\nTREXIO:{trexio_version}\nOCaml: {ocaml_version}\n") + raise + def write_stubs(data): with open("src/"+stubs_file,'r') as f: @@ -643,10 +658,12 @@ def write_ml(data): def main(): + check_version() with open(json_file,'r') as f: data = json.load(f) for group in data: for element in data[group]: + print(f"{group}_{element}") if data[group][element][0] == "str": data[group][element][0] = "string" diff --git a/ocaml/trexio/trexio.opam b/ocaml/trexio/trexio.opam new file mode 100644 index 0000000..5d41dca --- /dev/null +++ b/ocaml/trexio/trexio.opam @@ -0,0 +1,49 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +version: "2.4.2" +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." +maintainer: ["Anthony Scemama "] +authors: [ + "Anthony Scemama " + "Evgeny Posenitskiy " +] +license: "BSD-3-Clause" +tags: ["Quantum chemistry" "Library"] +homepage: "https://github.com/trex-coe/trexio_ocaml" +doc: "https://trex-coe.github.io/trexio/" +bug-reports: "https://github.com/trex-coe/trexio_ocaml/issues" +depends: [ + "dune" {>= "3.1"} + "dune-configurator" {build} + "conf-pkg-config" {build} + "odoc" {with-doc} +] +depexts: [ + ["hdf5"] {os-distribution = "alpine"} + ["epel-release" "hdf5-devel"] {os-distribution = "centos"} + ["libhdf5-dev"] {os-distribution = "debian"} + ["hdf5"] {os-distribution = "homebrew"} + ["libhdf5-dev"] {os-distribution = "ubuntu"} +] +build: [ + ["dune" "subst"] {dev} + ["./compile-lib.sh" "%{prefix}%" "build"] + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +install: [ + ["./compile-lib.sh" "%{prefix}%" "install"] + ["dune" "install"] +] +dev-repo: "git+https://github.com/trex-coe/trexio_ocaml.git" diff --git a/python/MANIFEST.in b/python/MANIFEST.in index 2d44f50..6dd4749 100644 --- a/python/MANIFEST.in +++ b/python/MANIFEST.in @@ -4,6 +4,7 @@ include examples/notebooks/* include examples/README.md include requirements.txt tools/set_NUMPY_INCLUDEDIR.sh include test/benzene_data.py +include test/conftest.py exclude examples/LICENSE exclude examples/requirements.txt diff --git a/python/README.md b/python/README.md index 078389c..8c95b88 100644 --- a/python/README.md +++ b/python/README.md @@ -27,6 +27,10 @@ However, it is good practice to first check for updates of the build-system pack **Note: we highly recommend to use virtual environments to avoid compatibility issues and to improve reproducibility.** For more details, see the corresponding part of the [Python documentation](https://docs.python.org/3/library/venv.html#creating-virtual-environments). +**Note: our build farm (GitHub Actions) does not support ARM64 architectures (including the Mac M1/M2 chips). Therefore, `pip install trexio` does not work on an ARM64-based machine. Thus, we recommend to install TREXIO from source on an ARM64-based machine. If one uses a Mac where HDF5 is installed with brew (i.e., `brew install hdf5`), a workaround is to execute the following 2 lines before doing `pip install trexio`:** + +- `export H5_CFLAGS="-I$(brew --prefix hdf5)/include"` +- `export H5_LDFLAGS="-L$(brew --prefix hdf5)/lib"` ## Additional requirements (for installation from source) diff --git a/python/build_manylinux_wheels.sh b/python/build_manylinux_wheels.sh index d6fc96f..1da66ea 100755 --- a/python/build_manylinux_wheels.sh +++ b/python/build_manylinux_wheels.sh @@ -89,7 +89,7 @@ function build_wheel_for_py() # cleaning rm -rf -- dist/ build/ trexio.egg-info/ - rm -- test_file_py.h5 unsafe_test_file_py.h5 + #rm -- test_file_py.h5 unsafe_test_file_py.h5 # deactivate the current environment deactivate @@ -103,7 +103,7 @@ function build_wheel_for_py() # build wheels for all versions of CPython in this container -for CPYVERSION in 36 37 38 39 310 +for CPYVERSION in 37 38 39 310 do build_wheel_for_py ${CPYVERSION} done diff --git a/python/install_pytrexio.sh b/python/install_pytrexio.sh index 8542874..d6a0767 100755 --- a/python/install_pytrexio.sh +++ b/python/install_pytrexio.sh @@ -16,7 +16,45 @@ done # check that both variables are set if [[ -z ${H5_LDFLAGS_LOCAL} ]] || [[ -z ${H5_CFLAGS_LOCAL} ]]; then if [[ -z ${H5_LDFLAGS} ]] || [[ -z ${H5_CFLAGS} ]]; then - echo "Paths to the HDF5 installation are not provided. pkgconfig will try to detect them." + # If pkg-config fails, try to locate hdf5 using h5cc + which h5cc &> /dev/null && HAS_H5CC=1 + pkg-config --libs hdf5 + if [[ $? -ne 0 && $HAS_H5CC == "1" ]] ; then + HDF5_tmp_flags=$(h5cc -showconfig \ + | grep 'FLAGS\|Extra libraries:' \ + | awk -F: '{printf("%s "), $2}' ) + echo $HDF5_tmp_flags + + # Find the installation directory and append include/ + HDF5_tmp_inst=$(h5cc -showconfig \ + | grep 'Installation point:' \ + | awk '{print $NF}' ) + echo $HDF5_tmp_inst + + # Add this to the CPPFLAGS + HDF5_CPPFLAGS="-I${HDF5_tmp_inst}/include" + + HDF5_SHOW=$(h5cc -show) + + # Now sort the flags out based upon their prefixes + for arg in $HDF5_SHOW $HDF5_tmp_flags ; do + case "$arg" in + -I*) echo $HDF5_CPPFLAGS | grep -e "$arg" 2>&1 >/dev/null \ + || HDF5_CPPFLAGS="$HDF5_CPPFLAGS $arg" + ;; + -L*) echo $HDF5_LDFLAGS | grep -e "$arg" 2>&1 >/dev/null \ + || HDF5_LDFLAGS="$HDF5_LDFLAGS $arg" + ;; + -l*) echo $HDF5_LIBS | grep -e "$arg" 2>&1 >/dev/null \ + || HDF5_LIBS="$HDF5_LIBS $arg" + ;; + esac + done + export H5_LDFLAGS="$HDF5_LDFLAGS" + export H5_CFLAGS="$HDF5_CPPFLAGS" + else + echo "Paths to the HDF5 installation are not provided. pkgconfig will try to detect them." + fi else echo "Using exported H5_LDFLAGS and H5_CFLAGS environment variables." fi diff --git a/python/pyproject.toml b/python/pyproject.toml index 7ca82aa..b8ca0a0 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -3,25 +3,6 @@ requires = [ "setuptools>=42", "wheel", "pkgconfig", - # Numpy requirements for different OS/architectures - # Copied from https://github.com/scipy/scipy/blob/master/pyproject.toml (which is also licensed under BSD) - "numpy==1.17.3; python_version=='3.6' and (platform_machine!='arm64' or platform_system!='Darwin') and platform_machine!='aarch64' and platform_python_implementation != 'PyPy'", - "numpy==1.17.3; python_version=='3.7' and (platform_machine!='arm64' or platform_system!='Darwin') and platform_machine!='aarch64' and platform_python_implementation != 'PyPy'", - "numpy==1.18.3; python_version=='3.8' and (platform_machine!='arm64' or platform_system!='Darwin') and platform_machine!='aarch64' and platform_python_implementation != 'PyPy'", - "numpy==1.19.3; python_version=='3.9' and (platform_machine!='arm64' or platform_system!='Darwin') and platform_python_implementation != 'PyPy'", - "numpy==1.21.4; python_version=='3.10' and platform_python_implementation != 'PyPy'", - # Aarch64(Python 3.9 requirements are the same as AMD64) - "numpy==1.19.2; python_version=='3.6' and platform_machine=='aarch64'", - "numpy==1.19.2; python_version=='3.7' and platform_machine=='aarch64'", - "numpy==1.19.2; python_version=='3.8' and platform_machine=='aarch64'", - # Darwin Arm64 - "numpy>=1.20.0; python_version=='3.8' and platform_machine=='arm64' and platform_system=='Darwin'", - "numpy>=1.20.0; python_version=='3.9' and platform_machine=='arm64' and platform_system=='Darwin'", - # For Python versions which aren't yet officially supported, - # we specify an unpinned NumPy which allows source distributions - # to be used and allows wheels to be used as soon as they - # become available. - "numpy; python_version>='3.11'", - "numpy; python_version>='3.8' and platform_python_implementation=='PyPy'", + "oldest-supported-numpy" ] build-backend = "setuptools.build_meta" diff --git a/python/pytrexio/_version.py b/python/pytrexio/_version.py index 67bc602..50062f8 100644 --- a/python/pytrexio/_version.py +++ b/python/pytrexio/_version.py @@ -1 +1 @@ -__version__ = "1.3.0" +__version__ = "2.5.0" diff --git a/python/requirements.txt b/python/requirements.txt index 123153a..eddf522 100644 --- a/python/requirements.txt +++ b/python/requirements.txt @@ -1,4 +1,4 @@ setuptools>=42 pkgconfig -numpy<1.23.0 +numpy<1.27.0 numpy>=1.17.3 diff --git a/python/setup.py b/python/setup.py index aaba434..2134e92 100644 --- a/python/setup.py +++ b/python/setup.py @@ -40,7 +40,7 @@ if numpy_isUndefined and not do_sdist: rootpath = os.path.dirname(os.path.abspath(__file__)) srcpath = os.path.join(rootpath, 'src') -c_files = ['trexio.c', 'trexio_hdf5.c', 'trexio_text.c', 'pytrexio_wrap.c'] +c_files = ['trexio.c', 'trexio_text.c'] with open("README.md", "r") as fh: @@ -61,12 +61,15 @@ if not version_r: # The block below is needed to derive additional flags related to the HDF5 library, # which is required to build pytrexio extension module during the setup.py execution +h5_present = False h5_ldflags_withl = os.environ.get("H5_LDFLAGS", None) h5_cflags_withI = os.environ.get("H5_CFLAGS", None) h5_ldflags_isUndefined = h5_ldflags_withl is None or h5_ldflags_withl=="" h5_cflags_isUndefined = h5_cflags_withI is None or h5_cflags_withI=="" +h5_present = (not h5_ldflags_isUndefined) & (not h5_cflags_isUndefined) + if (h5_ldflags_isUndefined or h5_cflags_isUndefined) and not do_sdist: try: @@ -76,31 +79,51 @@ if (h5_ldflags_isUndefined or h5_cflags_isUndefined) and not do_sdist: try: assert pk.exists('hdf5') + h5_present = True except AssertionError: - raise Exception("pkg-config could not locate HDF5") + print("pkg-config could not locate HDF5; installing TREXIO with TEXT back-end only!") - h5_cflags_withI = pk.cflags('hdf5') - h5_ldflags_withl = pk.libs('hdf5') + if h5_present: + h5_cflags_withI = pk.cflags('hdf5') + h5_ldflags_withl = pk.libs('hdf5') - -h5_cflags = h5_cflags_withI.replace("-I","").split(" ")[0] if not do_sdist else "" -h5_ldflags = h5_ldflags_withl.split(" ")[0] if not do_sdist else "" +if h5_present: + h5_cflags = h5_cflags_withI.replace("-I","").split(" ")[0] if not do_sdist else "" + h5_ldflags = h5_ldflags_withl.split(" ")[0] if not do_sdist else "" + c_files.append('trexio_hdf5.c') # ============================ End of the HDF5 block ============================ # # Define pytrexio extension module based on TREXIO source codes + SWIG-generated wrapper -pytrexio_module = Extension('pytrexio._pytrexio', +c_files.append('pytrexio_wrap.c') +compile_args = [ + '-std=c99', + '-Wno-discarded-qualifiers', + '-Wno-unused-variable', + '-Wno-unused-but-set-variable' + ] +# if config.h is present then we are building via Autotools +if os.path.isfile(os.path.join(srcpath, "config.h")): + compile_args.append('-DHAVE_CONFIG_H') +# explicit hack needed when building from sdist tarball +if h5_present: + compile_args.append('-DHAVE_HDF5') + +# define C extension module +if h5_present: + 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 = [ - '-std=c99', - '-Wno-discarded-qualifiers', - '-Wno-unused-variable', - '-Wno-unused-but-set-variable' - ], + libraries = ['hdf5' ], + extra_compile_args = compile_args, extra_link_args = [h5_ldflags] ) +else: + pytrexio_module = Extension('pytrexio._pytrexio', + sources = [os.path.join(srcpath, code) for code in c_files], + include_dirs = [srcpath, numpy_includedir], + extra_compile_args = compile_args + ) setup(name = 'trexio', diff --git a/python/test/conftest.py b/python/test/conftest.py new file mode 100644 index 0000000..725b94c --- /dev/null +++ b/python/test/conftest.py @@ -0,0 +1,17 @@ +# content of conftest.py +import pytest + + +def pytest_addoption(parser): + parser.addoption( + "--all", action="store_true", help="Run all back-ends" + ) + + +def pytest_generate_tests(metafunc): + if "backend" in metafunc.fixturenames: + if metafunc.config.getoption("all"): + backends = ['hdf5', 'text'] + else: + backends = ['text'] + metafunc.parametrize("backend", backends) diff --git a/python/test/test_api.py b/python/test/test_api.py index 4dff3f6..3ce3d9a 100644 --- a/python/test/test_api.py +++ b/python/test/test_api.py @@ -6,19 +6,22 @@ import trexio from benzene_data import * -FILENAME = 'test_file_py.h5' -BACK_END = trexio.TREXIO_HDF5 - - -def clean(): +def clean(back_end, filename): """Remove test files.""" - import os - - try: - os.remove(FILENAME) - os.remove('unsafe_' + FILENAME) - except FileNotFoundError: - pass + if back_end == trexio.TREXIO_HDF5: + import os + try: + os.remove(filename) + os.remove('unsafe_' + filename) + except FileNotFoundError: + pass + else: + import shutil + try: + shutil.rmtree(filename) + shutil.rmtree('unsafe_' + filename) + except FileNotFoundError: + pass def test_info(): @@ -29,7 +32,7 @@ def test_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) + _ = trexio.File('void.file', 'r', trexio.TREXIO_TEXT) def test_orbital_list(): @@ -53,20 +56,30 @@ def test_bitfield_list(): 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() + @pytest.fixture(autouse=True) + def setup(self, backend): + self.mode = 'w' + self.test_file = None + if backend == 'hdf5': + self.back_end = trexio.TREXIO_HDF5 + self.filename = 'test_file_py.h5' + elif backend == 'text': + self.back_end = trexio.TREXIO_TEXT + self.filename = 'test_file_py.dir' + else: + raise ValueError("Wrong TREXIO back-end supplied to pytest.") - def __del__(self): - if self.test_file: - if self.test_file.isOpen: - self.test_file.close() + def test_clean(self): + """Clean existing files.""" + clean(self.back_end, self.filename) + #def __del__(self): + # """Class destructor.""" + # 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: @@ -107,12 +120,17 @@ class TestIO: with pytest.raises(trexio.Error): trexio.write_nucleus_num(self.test_file, nucleus_num * 2) + if self.test_file.isOpen: + self.test_file.close() + 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) + if self.test_file.isOpen: + self.test_file.close() def test_str(self): @@ -120,6 +138,8 @@ class TestIO: self.open() trexio.write_nucleus_point_group(self.test_file, point_group) assert trexio.has_nucleus_point_group(self.test_file) + if self.test_file.isOpen: + self.test_file.close() def test_array_str(self): @@ -129,6 +149,8 @@ class TestIO: self.test_num() trexio.write_nucleus_label(self.test_file, nucleus_label) assert trexio.has_nucleus_label(self.test_file) + if self.test_file.isOpen: + self.test_file.close() def test_array_1D(self): @@ -138,6 +160,8 @@ class TestIO: self.test_num() trexio.write_nucleus_charge(self.test_file, nucleus_charge) assert trexio.has_nucleus_charge(self.test_file) + if self.test_file.isOpen: + self.test_file.close() def test_array_2D(self): @@ -147,6 +171,8 @@ class TestIO: self.test_num() trexio.write_nucleus_coord(self.test_file, nucleus_coord) assert trexio.has_nucleus_coord(self.test_file) + if self.test_file.isOpen: + self.test_file.close() def test_indices(self): @@ -159,6 +185,8 @@ class TestIO: # now write the indices trexio.write_basis_nucleus_index(self.test_file, indices_np) assert trexio.has_basis_nucleus_index(self.test_file) + if self.test_file.isOpen: + self.test_file.close() def test_sparse(self): @@ -170,6 +198,8 @@ class TestIO: 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) + if self.test_file.isOpen: + self.test_file.close() def test_determinant(self): @@ -189,31 +219,39 @@ class TestIO: 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) + if self.test_file.isOpen: + self.test_file.close() 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() + trexio.write_nucleus_num(self.test_file, nucleus_num) + trexio.write_nucleus_charge(self.test_file, nucleus_charge) + trexio.flush(self.test_file) + assert trexio.has_nucleus_num(self.test_file) + assert trexio.has_nucleus_charge(self.test_file) 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) + if self.test_file.isOpen: + self.test_file.close() + 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) + if self.test_file.isOpen: + self.test_file.close() def test_context_manager(self): @@ -231,6 +269,8 @@ class TestIO: self.open(mode='r') num_r = trexio.read_nucleus_num(self.test_file) assert num_r == nucleus_num + if self.test_file.isOpen: + self.test_file.close() def test_read_array_1D(self): @@ -240,6 +280,8 @@ class TestIO: 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) + if self.test_file.isOpen: + self.test_file.close() def test_read_array_2D(self): @@ -250,6 +292,8 @@ class TestIO: 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) + if self.test_file.isOpen: + self.test_file.close() def test_read_errors(self): @@ -258,6 +302,8 @@ class TestIO: # 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) + if self.test_file.isOpen: + self.test_file.close() def test_read_integers(self): @@ -276,7 +322,8 @@ class TestIO: 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() - + if self.test_file.isOpen: + self.test_file.close() def test_sparse_read(self): """Read a sparse array.""" @@ -300,7 +347,8 @@ class TestIO: 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 - + if self.test_file.isOpen: + self.test_file.close() def test_determinant_read(self): """Read the CI determinants.""" @@ -320,7 +368,8 @@ class TestIO: #print(f'First complete read of determinant coefficients: {read_buf_size}') assert not eof assert read_buf_size == buf_size - + if self.test_file.isOpen: + self.test_file.close() def test_array_str_read(self): """Read an array of strings.""" @@ -328,6 +377,8 @@ class TestIO: labels_r = trexio.read_nucleus_label(self.test_file) assert len(labels_r) == nucleus_num assert labels_r == nucleus_label + if self.test_file.isOpen: + self.test_file.close() def test_str_read(self): @@ -335,3 +386,5 @@ class TestIO: self.open(mode='r') point_group_r = trexio.read_nucleus_point_group(self.test_file) assert point_group_r == point_group + if self.test_file.isOpen: + self.test_file.close() diff --git a/rust/trexio/.gitignore b/rust/trexio/.gitignore new file mode 100644 index 0000000..1027d3c --- /dev/null +++ b/rust/trexio/.gitignore @@ -0,0 +1,5 @@ +Cargo.lock +src/generated.rs +target/ +wrapper.h + diff --git a/rust/trexio/Cargo.toml b/rust/trexio/Cargo.toml new file mode 100644 index 0000000..12c2258 --- /dev/null +++ b/rust/trexio/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "trexio" +version = "2.5.0" +edition = "2021" +license = "BSD-3-Clause" +authors = ["Anthony Scemama ", "Evgeny Posenitskiy"] +description = "TREXIO is an open-source file format and library developed for the storage and manipulation of data produced by quantum chemistry calculations. It is designed with the goal of providing a reliable and efficient method of storing and exchanging wave function parameters and matrix elements." +repository = "https://github.com/trex-coe/trexio" +keywords = ["quantum", "chemistry"] +readme = "README.md" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[build-dependencies] +bindgen = "0.65.1" +serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } +reqwest = { version = "0.11", features = ["blocking", "rustls-tls"] } +tar = "0.4" +flate2 = "1.0" + +[lib] +doctest = false + +[dependencies] +hdf5 = "0.8.1" diff --git a/rust/trexio/Makefile b/rust/trexio/Makefile new file mode 100644 index 0000000..bb6fc05 --- /dev/null +++ b/rust/trexio/Makefile @@ -0,0 +1,10 @@ +default: src/generated.rs + cargo build + cargo test + +src/generated.rs: build.py + python3 build.py + +test: default + - cargo test -- --show-output + diff --git a/rust/trexio/README.md b/rust/trexio/README.md new file mode 100644 index 0000000..0774ebe --- /dev/null +++ b/rust/trexio/README.md @@ -0,0 +1,42 @@ +# TREXIO + + +TREXIO is an open-source file format and library developed for the storage and +manipulation of data produced by quantum chemistry calculations. It is designed +with the goal of providing a reliable and efficient method of storing and +exchanging wave function parameters and matrix elements. + +This crate is the Rust binding for the TREXIO C library: +![GitHub release (latest by date)](https://img.shields.io/github/v/release/TREX-CoE/trexio) + + +## Documentation + +[TREXIO Documentation.](https://trex-coe.github.io/trexio/) + + +## Citation + +The journal article reference describing TREXIO can be cited as follows: + +``` +@article{10.1063/5.0148161, + author = {Posenitskiy, Evgeny and Chilkuri, Vijay Gopal and Ammar, Abdallah and Hapka, Michał and Pernal, Katarzyna and Shinde, Ravindra and Landinez Borda, Edgar Josué and Filippi, Claudia and Nakano, Kosuke and Kohulák, Otto and Sorella, Sandro and de Oliveira Castro, Pablo and Jalby, William and Ríos, Pablo López and Alavi, Ali and Scemama, Anthony}, + title = "{TREXIO: A file format and library for quantum chemistry}", + journal = {The Journal of Chemical Physics}, + volume = {158}, + number = {17}, + year = {2023}, + month = {05}, + issn = {0021-9606}, + doi = {10.1063/5.0148161}, + url = {https://doi.org/10.1063/5.0148161}, + note = {174801}, + eprint = {https://pubs.aip.org/aip/jcp/article-pdf/doi/10.1063/5.0148161/17355866/174801\_1\_5.0148161.pdf}, +} +``` + +Journal paper: [![doi](https://img.shields.io/badge/doi-10.1063/5.0148161-5077AB.svg)](https://doi.org/10.1063/5.0148161) + +ArXiv paper: [![arXiv](https://img.shields.io/badge/arXiv-2302.14793-b31b1b.svg)](https://arxiv.org/abs/2302.14793) + diff --git a/rust/trexio/build.rs b/rust/trexio/build.rs new file mode 100644 index 0000000..7625038 --- /dev/null +++ b/rust/trexio/build.rs @@ -0,0 +1,729 @@ +extern crate reqwest; +extern crate tar; +extern crate flate2; + +const WRAPPER_H: &str = "wrapper.h"; +const GENERATED_RS: &str = "generated.rs"; + +use std::env; +use std::path::PathBuf; +use std::collections::HashMap; +use std::fs::File; +use std::io::{self, BufRead, BufReader, Write}; +use serde_json::Value; +use flate2::read::GzDecoder; +use tar::Archive; + + + +fn download_trexio() -> PathBuf { + let version = env::var("CARGO_PKG_VERSION").unwrap(); + println!("Version : {}", version); + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let trexio_url = format!("https://github.com/TREX-CoE/trexio/releases/download/v{version}/trexio-{version}.tar.gz"); + + // Download the .tar.gz archive + let tar_gz = out_path.join("trexio.tar.gz"); + let trexio_dir= out_path.join("trexio_dir"); + let mut resp = reqwest::blocking::get(trexio_url).expect("Failed to download the archive"); + let mut out = File::create(tar_gz.clone()).expect("Failed to create archive file"); + std::io::copy(&mut resp, &mut out).expect("Failed to copy content"); + + // Unpack the .tar.gz archive + let tar_gz = File::open(tar_gz).unwrap(); + let tar = GzDecoder::new(tar_gz); + let mut archive = Archive::new(tar); + archive.unpack(trexio_dir.clone()).expect("Failed to unpack"); + + // Assume that the archive extracts to a directory named 'trexio-0.1.0' + trexio_dir.join(format!("trexio-{}", version)) +} + + +fn install_trexio(trexio_dir: &PathBuf) -> PathBuf { + println!("{}", trexio_dir.display()); + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let install_path = out_path.join("trexio_install"); + + // Run configure script + let configure_status = std::process::Command::new("./configure") + .arg(format!("--prefix={}",install_path.display())) + .arg("--without-fortran") + .current_dir(&trexio_dir) + .status() + .unwrap(); + + assert!(configure_status.success()); + + // Run make + let make_status = std::process::Command::new("make") + .arg("install") + .current_dir(&trexio_dir) + .status() + .unwrap(); + + assert!(make_status.success()); + install_path +} + + +/// This function reads from `trexio.h`, extracts the exit codes and backends, and writes them to `wrapper.h`. +fn make_interface(trexio_h: &PathBuf) -> io::Result<()> { + let mut err = HashMap::new(); + let mut be = HashMap::new(); + + let trexio_file = File::open(trexio_h)?; + let trexio_reader = BufReader::new(trexio_file); + + for line in trexio_reader.lines() { + let line = line?; + let buf = line.trim_start(); + + if buf.starts_with("#define TREXIO_") && buf.contains("(trexio_exit_code)") { + let buf2 = buf.replace(")", ""); + let buf2 = buf2.replace("(", ""); + let buf2: Vec<&str> = buf2.split_whitespace().collect(); + err.insert(buf2[1].to_string(), buf2[3].trim().parse::().unwrap()); + } + + if buf.starts_with("#define TREXIO_") && buf.contains("(back_end_t)") { + let buf2 = buf.replace(")", ""); + let buf2 = buf2.replace("(", ""); + let buf2: Vec<&str> = buf2.split_whitespace().collect(); + be.insert(buf2[1].to_string(), buf2[3].trim().parse::().unwrap()); + } + } + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let wrapper_h = out_path.join(WRAPPER_H); + let mut wrapper_file = File::create(wrapper_h)?; + write!(&mut wrapper_file, "#include \n")?; + + for (k, v) in &err { + write!(&mut wrapper_file, "#undef {}\n", k)?; + write!(&mut wrapper_file, "const trexio_exit_code {} = {};\n", k, v)?; + } + + for (k, v) in &be { + write!(&mut wrapper_file, "#undef {}\n", k)?; + write!(&mut wrapper_file, "const back_end_t {} = {};\n", k, v)?; + } + + write!(&mut wrapper_file, "#undef TREXIO_AUTO\n")?; + write!(&mut wrapper_file, "const back_end_t TREXIO_AUTO = TREXIO_INVALID_BACK_END;\n")?; + + Ok(()) +} + + +/// Type conversions for Rust API +fn convert_r(typ: &str) -> String { + match typ { + "int" => "i64", + "int special" => "usize", + "float" | "float sparse" | "float buffered" => "f64", + "dim" | "dim readonly" | "index" => "usize", + "str" => "str", + _ => panic!("Unknown type to convert: {}", typ) + }.to_string() +} + +/// Type conversion to call C functions +fn convert_c(typ: &str) -> String { + match typ { + "int" | "int special" | "dim" | "dim readonly" | "index" => "i64", + "float" | "float sparse" | "float buffered" => "f64", + "str" => "str", + _ => panic!("Unknown type to convert: {}", typ) + }.to_string() +} + + +/// Generate has-functions for checking the existence of groups and elements in a TREXIO file. +/// +/// # Parameters +/// * `data` - The JSON-like data containing the groups and elements. +/// +/// # Returns +/// A `Vec` containing the generated Rust code as strings. +fn make_has_functions(data: &Value) -> Vec { + let mut r = Vec::new(); + + if let Value::Object(groups) = data { + for (group, elements) in groups.iter() { + let group_l = group.to_lowercase(); + + let has_group_func = format!( + "/// Checks if the group `{group}` exists in the file. +/// # Parameters +/// +/// None +/// +/// # Returns +/// +/// * `Result` - Returns `Ok(true)` if the element exists in the file, +/// otherwise returns `Ok(false)`. An error during the execution results in `Err(ExitCode)`. +pub fn has_{group_l}(&self) -> Result {{ + let rc = unsafe {{ c::trexio_has_{group}(self.ptr) }}; + match rc {{ + c::TREXIO_SUCCESS => Ok(true), + c::TREXIO_HAS_NOT => Ok(false), + x => Err(ExitCode::from(x)), + }} +}}"); + + r.push(has_group_func); + + if let Value::Object(elements_map) = elements { + for (element, _types_value) in elements_map.iter() { + let element_l = element.to_lowercase(); + + let has_element_func = format!( + "/// Checks if the element `{element}` of the group `{group}` exists in the file. +/// +/// # Parameters +/// +/// None +/// +/// # Returns +/// +/// * `Result` - Returns `Ok(true)` if the element exists in the file, +/// otherwise returns `Ok(false)`. An error during the execution results in `Err(ExitCode)`. +pub fn has_{group_l}_{element_l}(&self) -> Result {{ + let rc = unsafe {{ c::trexio_has_{group}_{element}(self.ptr) }}; + match rc {{ + c::TREXIO_SUCCESS => Ok(true), + c::TREXIO_HAS_NOT => Ok(false), + x => Err(ExitCode::from(x)), + }} +}}"); + + r.push(has_element_func); + } + } + } + } + r +} + + + + +fn make_scalar_functions(data: &serde_json::Value) -> Vec { + let mut r: Vec = Vec::new(); + + for group in data.as_object().unwrap().keys() { + let group_l = group.to_lowercase(); + + for (element, attributes) in data[group].as_object().unwrap() { + let typ = attributes[0].as_str().unwrap(); + let type_c = convert_c(typ); + let type_r = convert_r(typ); + let element_l = element.to_lowercase(); + + if attributes[1].as_array().unwrap().is_empty() { + match typ { + "int" | "float" | "dim" | "index" => { + let s = format!(r#" +/// Reads the scalar element `{element}` from the group `{group}` in the file. +/// +/// # Parameters +/// +/// None +/// +/// # Returns +/// +/// * `Result<{type_r}, ExitCode>` - Returns the scalar element as a `{type_r}` upon successful +/// operation. If the operation fails, it returns `Err(ExitCode)`. +pub fn read_{group_l}_{element_l}(&self) -> Result<{type_r}, ExitCode> {{ + let mut data_c: {type_c} = 0{type_c}; + let (rc, data) = unsafe {{ + let rc = c::trexio_read_{group}_{element}_64(self.ptr, &mut data_c); + (rc, data_c.try_into().expect("try_into failed in read_{group_l}_{element_l}")) + }}; + rc_return(data, rc) +}} + +/// Writes the scalar element `{element}` into the group `{group}` in the file. +/// +/// # Parameters +/// +/// * `data: {type_r}` - A `{type_r}` scalar element that will be written into `{element}` in the group `{group}`. +/// +/// # Returns +/// +/// * `Result<(), ExitCode>` - Returns `Ok(())` upon successful operation, otherwise returns `Err(ExitCode)`. +pub fn write_{group_l}_{element_l}(&self, data: {type_r}) -> Result<(), ExitCode> {{ + let data: {type_c} = data.try_into().expect("try_into failed in write_{group_l}_{element_l}"); + let rc = unsafe {{ c::trexio_write_{group}_{element}_64(self.ptr, data) }}; + rc_return((), rc) +}} +"#); + r.push(s); + }, + "str" => { + let s = format!(r#" +/// Reads the string attribute `{element}` contained in the group `{group}`. +/// # Parameters +/// +/// * `capacity: usize` - The maximum buffer size allocated for the string to be read. +/// +/// # Returns +/// +/// * `Result` - Returns the attribute as a `String` upon successful operation. +/// If the operation fails, it returns `Err(ExitCode)`. +pub fn read_{group_l}_{element_l}(&self, capacity: usize) -> Result {{ + let data_c = CString::new(vec![ b' ' ; capacity]).expect("CString::new failed"); + let (rc, data) = unsafe {{ + let data_c = data_c.into_raw() as *mut c_char; + let rc = c::trexio_read_{group}_{element}(self.ptr, data_c, capacity.try_into().expect("try_into failed in read_{group_l}_{element_l}")); + (rc, CString::from_raw(data_c)) + }}; + let result : String = CString::into_string(data).expect("into_string failed in read_{group_l}_{element_l}"); + rc_return(result, rc) +}} + + +/// Writes the string attribute `{element}` into the group `{group}`. +/// +/// # Parameters +/// +/// * `data: &str` - The string attribute that will be written into the `{element}` field in the `{group}` group. +/// +/// # Returns +/// +/// * `Result<(), ExitCode>` - Returns `Ok(())` upon successful operation. +/// If the operation fails, it returns `Err(ExitCode)`. +pub fn write_{group_l}_{element_l}(&self, data: &str) -> Result<(), ExitCode> {{ + let size : i32 = data.len().try_into().expect("try_into failed in write_{group_l}_{element_l}"); + let data = string_to_c(data); + let data = data.as_ptr() as *const c_char; + let rc = unsafe {{ c::trexio_write_{group}_{element}(self.ptr, data, size) }}; + rc_return((), rc) +}} +"#); + r.push(s); + }, + "dim readonly" => { + let s = format!(r#" +/// Reads the dimensioning variable `{element}` from the group `{group}`. +/// +/// # Parameters +/// +/// None. +/// +/// # Returns +/// +/// * `Result<{type_r}, ExitCode>` - Returns the dimensioning variable `{element}` of type `{type_r}` +/// upon successful operation. If the operation fails, it returns `Err(ExitCode)`. +pub fn read_{group_l}_{element_l}(&self) -> Result<{type_r}, ExitCode> {{ + let mut data_c: {type_c} = 0{type_c}; + let (rc, data) = unsafe {{ + let rc = c::trexio_read_{group}_{element}_64(self.ptr, &mut data_c); + (rc, data_c.try_into().expect("try_into failed in read_{group_l}_{element_l}")) + }}; + rc_return(data, rc) +}} +"#); + r.push(s); + }, + _ => {} + } + } + } + } + r +} + + + +fn make_array_functions(data: &serde_json::Value) -> Vec { + let mut r: Vec = Vec::new(); + + for group in data.as_object().unwrap().keys() { + let group_l = group.to_lowercase(); + + for (element, attributes) in data[group].as_object().unwrap() { + let typ = attributes[0].as_str().unwrap(); + let type_c = convert_c(typ); + let type_r = convert_r(typ); + let element_l = element.to_lowercase(); + let dimensions = attributes[1].as_array().unwrap(); + let dimensions: Vec<&str> = dimensions.iter().map(|x| x.as_str().unwrap()).collect(); + let dimensions_str = format!("{:?}", dimensions).replace("\"",""); + if ! dimensions.is_empty() { + match typ { + "int" | "float" | "dim" | "index" => { + r.push(format!(r#" +/// Reads the `{element}` array from the group `{group}` in the file. +/// +/// # Dimensions +/// +/// The array is of dimension `{dimensions_str}`. +/// +/// # Returns +/// +/// * `Result, ExitCode>` - Returns a flattened one-dimensional vector that contains +/// the elements of the `{element}` array. If the operation is unsuccessful, it returns `Err(ExitCode)`. +/// +///"#)); + if dimensions.len() > 1 { + r.push(format!(r#" +/// # Example +/// +/// To reshape the one-dimensional vector back into a two-dimensional array, you can use the [`chunks`] method: +/// +/// ```text +/// let one_d_array = trexio_file.read_{}_{}()?;"#, group_l, element_l)); + if let Some(dim) = dimensions.first() { + if dim.contains('.') { + let parts: Vec<&str> = dim.split('.').collect(); + r.push(format!("/// let {}_{} = trexio_file.read_{}_{}()?;", parts[0], parts[1], parts[0], parts[1])); + r.push(format!("/// let two_d_array: Vec<_> = one_d_array.chunks({}_{}).collect();", parts[0], parts[1])); + } else { + r.push(format!("/// let two_d_array: Vec<_> = one_d_array.chunks({}).collect();", dim)); + } + } + r.push(String::from("/// ```")); + r.push(String::from("///\n/// [`chunks`]: slice::chunks")); + } + r.push(format!(r#"pub fn read_{}_{}(&self) -> Result, ExitCode> {{ + let mut size = 1;"#, group_l, element_l, type_r)); + + for dim in &dimensions { + if dim.contains('.') { + let parts: Vec<&str> = dim.split('.').collect(); + r.push(format!(" size *= self.read_{}_{}()?;", parts[0], parts[1])); + } else { + r.push(format!(" size *= {};", dim)); + } + } + r.push(format!(r#" let mut data: Vec<{type_r}> = Vec::with_capacity(size); + let rc = unsafe {{ + let data_c = data.as_mut_ptr() as *mut {type_c}; + let rc = c::trexio_read_safe_{group}_{element}_64(self.ptr, data_c, size.try_into().expect("try_into failed in read_{group}_{element} (size)")); + data.set_len(size); + rc + }}; + rc_return(data, rc) +}}"#)); + r.push(format!(r#" +/// Writes the `{element}` array into the group `{group}` in the file. +/// +/// # Parameters +/// +/// * `data: &[{type_r}]` - A one-dimensional vector that contains the elements of the `{element}` array +/// to be written into the file. The vector should be flattened from a two-dimensional array with +/// dimensions `{dimensions_str}`. +/// +/// # Returns +/// +/// * `Result<(), ExitCode>` - Returns `Ok(())` if the operation is successful, +/// otherwise returns `Err(ExitCode)`.""", """\ +pub fn write_{group_l}_{element_l}(&self, data: &[{type_r}]) -> Result<(), ExitCode> {{ + let size: i64 = data.len().try_into().expect("try_into failed in write_{group_l}_{element_l}"); + let data = data.as_ptr() as *const {type_c}; + let rc = unsafe {{ c::trexio_write_safe_{group}_{element}_64(self.ptr, data, size) }}; + rc_return((), rc) +}} +"#)); + } + , + "str" => { + r.push(format!(r#" +/// Reads the `{element}` array from the group `{group}` in the file. +/// +/// # Dimensions +/// +/// The array is of dimension `{dimensions_str}`. +/// +/// # Returns +/// +/// * `Result, ExitCode>` - Returns a flattened one-dimensional vector that contains +/// the elements of the `{element}` array. If the operation is unsuccessful, it returns `Err(ExitCode)`. +/// +/// "#)); + if dimensions.len() > 1 { + r.push(format!(r#"/// # Example +/// +/// To reshape the one-dimensional vector back into a two-dimensional array, you can use the [`chunks`] method: +/// +/// ```text +/// let one_d_array = trexio_file.read_{}_{}()?;"#, group_l, element_l)); + if let Some(dim) = dimensions.first() { + if dim.contains('.') { + let parts: Vec<&str> = dim.split('.').collect(); + r.push(format!("/// let {}_{} = trexio_file.read_{}_{}()?;", parts[0], parts[1], parts[0], parts[1])); + r.push(format!("/// let two_d_array: Vec<_> = one_d_array.chunks({}_{}).collect();", parts[0], parts[1])); + } else { + r.push(format!("/// let two_d_array: Vec<_> = one_d_array.chunks({}).collect();", dim)); + } + } + r.push(String::from("/// ```")); + r.push(String::from("///\n/// [`chunks`]: slice::chunks")); + } + r.push(format!(r#"pub fn read_{}_{}(&self, capacity: usize) -> Result, ExitCode> {{ + let mut size = 1;"#, group_l, element_l)); + for dim in &dimensions { + if dim.contains('.') { + let parts: Vec<&str> = dim.split('.').collect(); + r.push(format!(" size *= self.read_{}_{}()?;", parts[0], parts[1])); + } else { + r.push(format!(" size *= {};", dim)); + } + } + r.push(format!(r#" // Allocate an array of *mut i8 pointers (initialized to null) + let mut dset_out: Vec<*mut i8> = vec![std::ptr::null_mut(); size]; + + // Allocate C-style strings and populate dset_out + for item in dset_out.iter_mut().take(size) {{ + let c_str: *mut i8 = unsafe {{ std::alloc::alloc_zeroed(std::alloc::Layout::array::(capacity).unwrap()) as *mut i8 }}; + if c_str.is_null() {{ + return Err(ExitCode::AllocationFailed); + }} + *item = c_str; + }} + + + let rc = unsafe {{ + c::trexio_read_{group}_{element}(self.ptr, dset_out.as_mut_ptr(), capacity.try_into().expect("try_into failed in read_{group}_{element} (capacity)") ) + }}; + + // Convert the populated C strings to Rust Strings + let mut rust_strings = Vec::new(); + for &c_str in &dset_out {{ + let rust_str = unsafe {{ + std::ffi::CStr::from_ptr(c_str) + .to_string_lossy() + .into_owned() + }}; + rust_strings.push(rust_str); + }} + + // Clean up allocated C strings + for &c_str in &dset_out {{ + unsafe {{ std::alloc::dealloc(c_str as *mut u8, std::alloc::Layout::array::(capacity).unwrap()) }}; + }} + + rc_return(rust_strings, rc) +}} + +/// Writes the `{element}` array into the group `{group}` in the file. +/// +/// # Parameters +/// +/// * `data: &[{type_r}]` - A one-dimensional vector that contains the elements of the `{element}` array +/// to be written into the file. The vector should be flattened from a two-dimensional array with +/// dimensions `{dimensions_str}`. +/// +/// # Returns +/// +/// * `Result<(), ExitCode>` - Returns `Ok(())` if the operation is successful, +/// otherwise returns `Err(ExitCode)`. +pub fn write_{group_l}_{element_l}(&self, data: &[&str]) -> Result<(), ExitCode> {{ + let mut size = 0; + // Find longest string + for s in data {{ + let l = s.len(); + size = if l>size {{l}} else {{size}}; + }} + size += 1; + let data_c : Vec = data.iter().map(|&x| string_to_c(x)).collect::>(); + let data_c : Vec<*const c_char> = data_c.iter().map(|x| x.as_ptr() as *const c_char).collect::>(); + let size : i32 = size.try_into().expect("try_into failed in write_{group}_{element} (size)"); + let data_c = data_c.as_ptr() as *mut *const c_char; + let rc = unsafe {{ c::trexio_write_{group}_{element}(self.ptr, data_c, size) }}; + rc_return((), rc) +}} +"#)); + }, + "float sparse" => { + let size = dimensions.len(); + let typ = [ "(", (vec![ "usize" ; size ]).join(", ").as_str(),", f64)"].join(""); + r.push(format!(r#" +/// Reads a buffer of {element} from group {group}. +/// +/// # Parameters +/// +/// * `offset: usize` - The starting point in the array from which data will be read. +/// * `buffer_size: usize` - The size of the buffer in which read data will be stored. +/// +/// # Returns +/// +/// * `Result, ExitCode>` - Returns a vector of tuples containing +/// the indices and the value of the element. The vector has a length of at most `buffer_size`. +/// +/// # Notes +/// +/// The reading process is a buffered operation, meaning that only a segment of the full array +/// is read into the memory. +pub fn read_{group_l}_{element_l}(&self, offset: usize, buffer_size:usize) -> Result, ExitCode> {{ + let mut idx = Vec::::with_capacity({size}*buffer_size); + let mut val = Vec::::with_capacity(buffer_size); + let idx_ptr = idx.as_ptr() as *mut i32; + let val_ptr = val.as_ptr() as *mut f64; + let offset: i64 = offset.try_into().expect("try_into failed in read_{group}_{element} (offset)"); + let mut buffer_size_read: i64 = buffer_size.try_into().expect("try_into failed in read_{group}_{element} (buffer_size)"); + let rc = unsafe {{ c::trexio_read_safe_{group}_{element}(self.ptr, + offset, &mut buffer_size_read, idx_ptr, buffer_size_read, val_ptr, buffer_size_read) + }}; + let rc = match ExitCode::from(rc) {{ + ExitCode::End => ExitCode::to_c(&ExitCode::Success), + _ => rc + }}; + let buffer_size_read: usize = buffer_size_read.try_into().expect("try_into failed in read_{group}_{element} (buffer_size)"); + unsafe {{ idx.set_len({size}*buffer_size_read) }}; + unsafe {{ val.set_len(buffer_size_read) }}; + let idx: Vec::<&[i32]> = idx.chunks({size}).collect(); + + let mut result = Vec::<{typ}>::with_capacity(buffer_size); + for (i, v) in zip(idx, val) {{ + result.push( ("#)); + let mut x = Vec::new(); + for k in 0..size { + x.push(format!("i[{k}].try_into().unwrap()")) + }; + x.push("v));\n }\n rc_return(result, rc)\n}".to_string()); + r.push(x.join(", ")); + r.push(format!(r#"/// Writes a buffer of {element} from group {group}. +/// +/// # Parameters +/// +/// * `offset: usize` - The starting point in the array at which data will be written. +/// * `data: &[{typ}]` - A slice of tuples containing the indices and the value of the element. +/// +/// # Returns +/// +/// * `Result<(), ExitCode>` - Returns `Ok(())` if the writing operation is successful, +/// otherwise returns `Err(ExitCode)`. +/// +/// # Notes +/// +/// The writing process is a buffered operation, meaning that only a segment of the full array +/// is written into the file. +pub fn write_{group_l}_{element_l}(&self, offset: usize, data: &[{typ}]) -> Result<(), ExitCode> {{ + let mut idx = Vec::::with_capacity({size}*data.len()); + let mut val = Vec::::with_capacity(data.len()); + + for d in data {{ "#)); + let mut x = Vec::new(); + for k in 0..size { + x.push(format!(" idx.push(d.{k}.try_into().unwrap());")) + }; + r.push(x.join("\n")); + r.push(format!(r#" + val.push(d.{size}); + }} + + let size_max: i64 = data.len().try_into().expect("try_into failed in write_{group}_{element} (size_max)"); + let buffer_size = size_max; + let idx_ptr = idx.as_ptr() as *const i32; + let val_ptr = val.as_ptr() as *const f64; + let offset: i64 = offset.try_into().expect("try_into failed in write_{group}_{element} (offset)"); + let rc = unsafe {{ c::trexio_write_safe_{group}_{element}(self.ptr, + offset, buffer_size, idx_ptr, size_max, val_ptr, size_max) }}; + rc_return((), rc) +}}"#)); + }, + _ => {} + } + } + } + } + r +} + + + + + + + + + +/// Reads the JSON file, processes its contents, and generates Rust functions according to the specifications in the JSON data. +fn make_functions(json_path: &PathBuf) -> std::io::Result<()> { + let file = File::open(json_path).unwrap(); + let data: Value = serde_json::from_reader(file).unwrap(); + + let mut r: Vec = vec![ + String::from(" +use std::ffi::CString; +use std::iter::zip; + +/// This implementation block includes additional functions automatically generated from tables. +/// For more details, refer to [TREXIO tables documentation](https://trex-coe.github.io/trexio/trex.html). +impl File { + #![allow(clippy::unnecessary_cast)] + #![allow(clippy::useless_conversion)] + #![allow(clippy::type_complexity)] +"), + ]; + + r.append(&mut make_has_functions(&data)); + r.append(&mut make_scalar_functions(&data)); + r.append(&mut make_array_functions(&data)); + + r.push(String::from("}")); + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let generated_rs = out_path.join(GENERATED_RS); + let mut f = File::create(&generated_rs)?; + f.write_all(r.join("\n").as_bytes())?; + Ok(()) +} + + + + + +fn main() { + let source_path = download_trexio(); + println!("source path: {}", source_path.display()); + + let install_path = install_trexio(&source_path); + println!("install path: {}", install_path.display()); + + // Tell cargo to look for shared libraries in the specified directory + println!("cargo:rustc-link-search={}/lib", install_path.display()); + + // Tell cargo to tell rustc to link the system trexio shared library. + println!("cargo:rustc-link-lib=trexio"); + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let trexio_h = install_path.join("include").join("trexio.h"); + println!("trexio.h: {}", trexio_h.display()); + + make_interface(&trexio_h).unwrap(); + // The bindgen::Builder is the main entry point + // to bindgen, and lets you build up options for + // the resulting bindings. + let wrapper_h = out_path.join(WRAPPER_H); + println!("wrapper.h: {}", wrapper_h.display()); + + let bindings = bindgen::Builder::default() + // The input header we would like to generate + // bindings for. + .header(wrapper_h.to_str().unwrap()) + // Tell cargo to invalidate the built crate whenever any of the + // included header files changed. + .parse_callbacks(Box::new(bindgen::CargoCallbacks)) + // Finish the builder and generate the bindings. + .generate() + // Unwrap the Result and panic on failure. + .expect("Unable to generate bindings"); + + // Write the bindings to the $OUT_DIR/bindings.rs file. + let bindings_path = out_path.join("bindings.rs"); + println!("bindings.rs: {}", bindings_path.display()); + + bindings + .write_to_file(&bindings_path) + .expect("Couldn't write bindings!"); + + let json_path = source_path.join("trex.json"); + println!("json path: {}", json_path.display()); + + make_functions(&json_path).unwrap(); +} diff --git a/rust/trexio/src/back_end.rs b/rust/trexio/src/back_end.rs new file mode 100644 index 0000000..6349b88 --- /dev/null +++ b/rust/trexio/src/back_end.rs @@ -0,0 +1,35 @@ +use crate::c; + +#[derive(Debug, PartialEq)] +pub enum BackEnd { + /// The TREXIO "file" is a directory with text files for each group. + /// A fallback when HDF5 is not available. + Text, + + /// Should be used for production. The TREXIO file is a single HDF5 file. + Hdf5, + + /// Automatic discovery of the appropriate backend + Auto, +} + +impl BackEnd { + /// Creation from a C value + pub fn from(b: c::back_end_t) -> Self { + match b { + c::TREXIO_TEXT => Self::Text, + c::TREXIO_HDF5 => Self::Hdf5, + c::TREXIO_AUTO => Self::Auto, + _ => panic!("Invalid backend"), + } + } + + /// Conversion to a C value + pub fn to_c(self) -> c::back_end_t { + match self { + Self::Text => c::TREXIO_TEXT, + Self::Hdf5 => c::TREXIO_HDF5, + Self::Auto => c::TREXIO_AUTO, + } + } +} diff --git a/rust/trexio/src/bitfield.rs b/rust/trexio/src/bitfield.rs new file mode 100644 index 0000000..dd0119c --- /dev/null +++ b/rust/trexio/src/bitfield.rs @@ -0,0 +1,208 @@ +#[derive(Debug, PartialEq)] +pub struct Bitfield { + data: Vec, +} + +use crate::c; +use crate::ExitCode; + +impl Bitfield { + /// Creates a new bitfield , using a number of i64 elements consistent + /// with the number of MOs in the TREXIO file. + pub fn from(n_int: usize, orb_list: &[usize]) -> (Self, f64) { + let orb_list: Vec = orb_list.iter().map(|&x| x as i32).collect(); + let occ_num = orb_list + .len() + .try_into() + .expect("try_into failed in Bitfield::from"); + let orb_list_ptr: *const i32 = orb_list.as_ptr(); + let n_int32: i32 = n_int.try_into().expect("try_into failed in Bitfield::from"); + let mut b = vec![0i64; n_int]; + let bit_list = b.as_mut_ptr() as *mut c::bitfield_t; + std::mem::forget(b); + let rc = unsafe { c::trexio_to_bitfield_list(orb_list_ptr, occ_num, bit_list, n_int32) }; + + let data = unsafe { Vec::from_raw_parts(bit_list, n_int, n_int) }; + + let result = Bitfield { data }; + + match ExitCode::from(rc) { + ExitCode::Success => (result, 1.0), + ExitCode::PhaseChange => (result, -1.0), + x => panic!("TREXIO Error {}", x), + } + } + + pub fn from_vec(v: &[i64]) -> Bitfield { + Bitfield { data: v.to_vec() } + } + + pub fn from_alpha_beta(alpha: &Bitfield, beta: &Bitfield) -> Bitfield { + if alpha.data.len() != beta.data.len() { + panic!("alpha and beta parts have different lengths"); + }; + let mut data = alpha.data.clone(); + data.extend_from_slice(&beta.data); + Bitfield { data } + } + + /// Returns the alpha part + pub fn alpha(&self) -> Bitfield { + let n_int = self.data.len() / 2; + Bitfield { + data: (self.data[0..n_int]).to_vec(), + } + } + + /// Returns the beta part + pub fn beta(&self) -> Bitfield { + let n_int = self.data.len() / 2; + Bitfield { + data: (self.data[n_int..2 * n_int]).to_vec(), + } + } + + /// Converts to a format usable in the C library + pub fn as_ptr(&self) -> *const c::bitfield_t { + let len = self.data.len(); + let result = &self.data[0..len]; + result.as_ptr() as *const c::bitfield_t + } + + /// Converts to a format usable in the C library + pub fn as_mut_ptr(&mut self) -> *mut c::bitfield_t { + let len = self.data.len(); + let result = &mut self.data[0..len]; + result.as_mut_ptr() as *mut c::bitfield_t + } + + /// Converts the bitfield into a list of orbital indices (0-based) + pub fn to_orbital_list(&self) -> Vec { + let n_int: i32 = self + .data + .len() + .try_into() + .expect("try_into failed in to_orbital_list"); + let d1 = self.as_ptr(); + let cap = self.data.len() * 64; + let mut list = vec![0i32; cap]; + let list_c: *mut i32 = list.as_mut_ptr(); + std::mem::forget(list); + + let mut occ_num: i32 = 0; + + let rc = unsafe { c::trexio_to_orbital_list(n_int, d1, list_c, &mut occ_num) }; + match ExitCode::from(rc) { + ExitCode::Success => (), + x => panic!("TREXIO Error {}", x), + }; + + let occ_num = occ_num as usize; + let list = unsafe { Vec::from_raw_parts(list_c, occ_num, cap) }; + + let mut result: Vec = Vec::with_capacity(occ_num); + for i in list.iter() { + result.push(*i as usize); + } + result + } + + /// Converts the bitfield into a vector + pub fn as_vec(&self) -> &[i64] { + &self.data + } + + /// Converts the determinant into a list of orbital indices (0-based) + pub fn to_orbital_list_up_dn(&self) -> (Vec, Vec) { + let n_int: i32 = (self.data.len() / 2) + .try_into() + .expect("try_into failed in to_orbital_list"); + let d1 = self.as_ptr(); + let cap = self.data.len() / 2 * 64; + let mut b = vec![0i32; cap]; + let list_up_c: *mut i32 = b.as_mut_ptr(); + std::mem::forget(b); + let mut b = vec![0i32; cap]; + let list_dn_c: *mut i32 = b.as_mut_ptr(); + std::mem::forget(b); + + let mut occ_num_up: i32 = 0; + let mut occ_num_dn: i32 = 0; + + let rc = unsafe { + c::trexio_to_orbital_list_up_dn( + n_int, + d1, + list_up_c, + list_dn_c, + &mut occ_num_up, + &mut occ_num_dn, + ) + }; + match ExitCode::from(rc) { + ExitCode::Success => (), + x => panic!("TREXIO Error {}", x), + }; + + let occ_num_up = occ_num_up as usize; + let occ_num_dn = occ_num_dn as usize; + let list_up = unsafe { Vec::from_raw_parts(list_up_c, occ_num_up, cap) }; + let list_dn = unsafe { Vec::from_raw_parts(list_dn_c, occ_num_dn, cap) }; + + let mut result_up: Vec = Vec::with_capacity(occ_num_up); + for i in list_up.iter() { + result_up.push(*i as usize); + } + + let mut result_dn: Vec = Vec::with_capacity(occ_num_dn); + for i in list_dn.iter() { + result_dn.push(*i as usize); + } + (result_up, result_dn) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn creation_from_list() { + let list0 = vec![0, 1, 2, 3, 4]; + let list1 = vec![0, 1, 2, 4, 3]; + let list2 = vec![0, 1, 4, 2, 3]; + + let (alpha0, phase0) = Bitfield::from(2, &list0); + let list = alpha0.to_orbital_list(); + assert_eq!(list, list0); + + let (alpha1, phase1) = Bitfield::from(2, &list1); + let list = alpha1.to_orbital_list(); + assert_eq!(list, list0); + assert_eq!(phase1, -phase0); + + let (alpha2, phase2) = Bitfield::from(2, &list2); + let list = alpha2.to_orbital_list(); + assert_eq!(list, list0); + assert_eq!(phase2, phase0); + } + + #[test] + fn creation_alpha_beta() { + let (alpha, _) = Bitfield::from(2, &[0, 1, 2, 3, 4]); + let (beta, _) = Bitfield::from(2, &[0, 1, 2, 4, 5]); + let det = Bitfield::from_alpha_beta(&alpha, &beta); + let list = det.to_orbital_list(); + assert_eq!(list, [0, 1, 2, 3, 4, 128, 129, 130, 132, 133]); + assert_eq!(det.alpha(), alpha); + assert_eq!(det.beta(), beta); + } + + #[test] + #[should_panic] + fn creation_alpha_beta_with_different_nint() { + let (alpha, _) = Bitfield::from(1, &[0, 1, 2, 3, 4]); + let (beta, _) = Bitfield::from(2, &[0, 1, 2, 4, 5]); + let _ = Bitfield::from_alpha_beta(&alpha, &beta); + } +} diff --git a/rust/trexio/src/c.rs b/rust/trexio/src/c.rs new file mode 100644 index 0000000..cd503e4 --- /dev/null +++ b/rust/trexio/src/c.rs @@ -0,0 +1,6 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(dead_code)] + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/rust/trexio/src/exit_code.rs b/rust/trexio/src/exit_code.rs new file mode 100644 index 0000000..dce0467 --- /dev/null +++ b/rust/trexio/src/exit_code.rs @@ -0,0 +1,219 @@ +use crate::c; + +#[derive(Debug, PartialEq)] +pub enum ExitCode { + /// Unknown failure + Failure, + + /// Everything went fine + Success, + + /// Invalid argument + InvalidArg(usize), + + /// End of file + End, + + /// Read-only file + ReadOnly, + + /// Error returned by Errno + Errno, + + /// Invalid ID + InvalidId, + + /// Allocation failed + AllocationFailed, + + /// Element absent + HasNot, + + /// Invalid (negative or 0) dimension + InvalidNum, + + /// Attribute already exists + AttrAlreadyExists, + + /// Dataset already exists + DsetAlreadyExists, + + /// Error opening file + OpenError, + + /// Error locking file + LockError, + + /// Error unlocking file + UnlockError, + + /// Invalid file + FileError, + + /// Error reading group + GroupReadError, + + /// Error writing group + GroupWriteError, + + /// Error reading element + ElemReadError, + + /// Error writing element + ElemWriteError, + + /// Access to memory beyond allocated + UnsafeArrayDim, + + /// Attribute does not exist in the file + AttrMissing, + + /// Dataset does not exist in the file + DsetMissing, + + /// Requested back end is disabled + BackEndMissing, + + /// Invalid max_str_len + InvalidStrLen, + + /// Possible integer overflow + IntSizeOverflow, + + /// Unsafe operation in safe mode + SafeMode, + + /// Inconsistent number of electrons + InvalidElectronNum, + + /// Inconsistent number of determinants + InvalidDeterminantNum, + + /// Inconsistent state of the file + InvalidState, + + /// Failed to parse package_version + VersionParsingIssue, + + /// The function succeeded with a change of sign + PhaseChange, +} + +impl ExitCode { + /// Creation from a C value + pub fn from(rc: c::trexio_exit_code) -> Self { + match rc { + c::TREXIO_FAILURE => Self::Failure, + c::TREXIO_SUCCESS => Self::Success, + c::TREXIO_INVALID_ARG_1 => Self::InvalidArg(1), + c::TREXIO_INVALID_ARG_2 => Self::InvalidArg(2), + c::TREXIO_INVALID_ARG_3 => Self::InvalidArg(3), + c::TREXIO_INVALID_ARG_4 => Self::InvalidArg(4), + c::TREXIO_INVALID_ARG_5 => Self::InvalidArg(5), + c::TREXIO_END => Self::End, + c::TREXIO_READONLY => Self::ReadOnly, + c::TREXIO_ERRNO => Self::Errno, + c::TREXIO_INVALID_ID => Self::InvalidId, + c::TREXIO_ALLOCATION_FAILED => Self::AllocationFailed, + c::TREXIO_HAS_NOT => Self::HasNot, + c::TREXIO_INVALID_NUM => Self::InvalidNum, + c::TREXIO_ATTR_ALREADY_EXISTS => Self::AttrAlreadyExists, + c::TREXIO_DSET_ALREADY_EXISTS => Self::DsetAlreadyExists, + c::TREXIO_OPEN_ERROR => Self::OpenError, + c::TREXIO_LOCK_ERROR => Self::LockError, + c::TREXIO_UNLOCK_ERROR => Self::UnlockError, + c::TREXIO_FILE_ERROR => Self::FileError, + c::TREXIO_GROUP_READ_ERROR => Self::GroupReadError, + c::TREXIO_GROUP_WRITE_ERROR => Self::GroupWriteError, + c::TREXIO_ELEM_READ_ERROR => Self::ElemReadError, + c::TREXIO_ELEM_WRITE_ERROR => Self::ElemWriteError, + c::TREXIO_UNSAFE_ARRAY_DIM => Self::UnsafeArrayDim, + c::TREXIO_ATTR_MISSING => Self::AttrMissing, + c::TREXIO_DSET_MISSING => Self::DsetMissing, + c::TREXIO_BACK_END_MISSING => Self::BackEndMissing, + c::TREXIO_INVALID_ARG_6 => Self::InvalidArg(6), + c::TREXIO_INVALID_ARG_7 => Self::InvalidArg(7), + c::TREXIO_INVALID_ARG_8 => Self::InvalidArg(8), + c::TREXIO_INVALID_STR_LEN => Self::InvalidStrLen, + c::TREXIO_INT_SIZE_OVERFLOW => Self::IntSizeOverflow, + c::TREXIO_SAFE_MODE => Self::SafeMode, + c::TREXIO_INVALID_ELECTRON_NUM => Self::InvalidElectronNum, + c::TREXIO_INVALID_DETERMINANT_NUM => Self::InvalidDeterminantNum, + c::TREXIO_INVALID_STATE => Self::InvalidState, + c::TREXIO_VERSION_PARSING_ISSUE => Self::VersionParsingIssue, + c::TREXIO_PHASE_CHANGE => Self::PhaseChange, + _ => panic!("Unknown exit code"), + } + } + + /// Conversion to a C value + pub fn to_c(&self) -> c::trexio_exit_code { + match self { + Self::Failure => c::TREXIO_FAILURE, + Self::Success => c::TREXIO_SUCCESS, + Self::InvalidArg(1) => c::TREXIO_INVALID_ARG_1, + Self::InvalidArg(2) => c::TREXIO_INVALID_ARG_2, + Self::InvalidArg(3) => c::TREXIO_INVALID_ARG_3, + Self::InvalidArg(4) => c::TREXIO_INVALID_ARG_4, + Self::InvalidArg(5) => c::TREXIO_INVALID_ARG_5, + Self::End => c::TREXIO_END, + Self::ReadOnly => c::TREXIO_READONLY, + Self::Errno => c::TREXIO_ERRNO, + Self::InvalidId => c::TREXIO_INVALID_ID, + Self::AllocationFailed => c::TREXIO_ALLOCATION_FAILED, + Self::HasNot => c::TREXIO_HAS_NOT, + Self::InvalidNum => c::TREXIO_INVALID_NUM, + Self::AttrAlreadyExists => c::TREXIO_ATTR_ALREADY_EXISTS, + Self::DsetAlreadyExists => c::TREXIO_DSET_ALREADY_EXISTS, + Self::OpenError => c::TREXIO_OPEN_ERROR, + Self::LockError => c::TREXIO_LOCK_ERROR, + Self::UnlockError => c::TREXIO_UNLOCK_ERROR, + Self::FileError => c::TREXIO_FILE_ERROR, + Self::GroupReadError => c::TREXIO_GROUP_READ_ERROR, + Self::GroupWriteError => c::TREXIO_GROUP_WRITE_ERROR, + Self::ElemReadError => c::TREXIO_ELEM_READ_ERROR, + Self::ElemWriteError => c::TREXIO_ELEM_WRITE_ERROR, + Self::UnsafeArrayDim => c::TREXIO_UNSAFE_ARRAY_DIM, + Self::AttrMissing => c::TREXIO_ATTR_MISSING, + Self::DsetMissing => c::TREXIO_DSET_MISSING, + Self::BackEndMissing => c::TREXIO_BACK_END_MISSING, + Self::InvalidArg(6) => c::TREXIO_INVALID_ARG_6, + Self::InvalidArg(7) => c::TREXIO_INVALID_ARG_7, + Self::InvalidArg(8) => c::TREXIO_INVALID_ARG_8, + Self::InvalidStrLen => c::TREXIO_INVALID_STR_LEN, + Self::IntSizeOverflow => c::TREXIO_INT_SIZE_OVERFLOW, + Self::SafeMode => c::TREXIO_SAFE_MODE, + Self::InvalidElectronNum => c::TREXIO_INVALID_ELECTRON_NUM, + Self::InvalidDeterminantNum => c::TREXIO_INVALID_DETERMINANT_NUM, + Self::InvalidState => c::TREXIO_INVALID_STATE, + Self::VersionParsingIssue => c::TREXIO_VERSION_PARSING_ISSUE, + Self::PhaseChange => c::TREXIO_PHASE_CHANGE, + _ => panic!("Unknown exit code"), + } + } + + pub fn to_str(&self) -> Result<&'static str, Utf8Error> { + let c_error = self.to_c(); + let c_buf: *const c_char = unsafe { c::trexio_string_of_error(c_error) }; + let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) }; + c_str.to_str() + } +} + +use std::error::Error; +use std::ffi::c_char; +use std::ffi::CStr; +use std::fmt; +use std::str::Utf8Error; + +impl fmt::Display for ExitCode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.to_str().unwrap()) + } +} + +impl Error for ExitCode { + fn description(&self) -> &str { + self.to_str().unwrap() + } +} diff --git a/rust/trexio/src/lib.rs b/rust/trexio/src/lib.rs new file mode 100644 index 0000000..e82974b --- /dev/null +++ b/rust/trexio/src/lib.rs @@ -0,0 +1,261 @@ +//! TREXIO is an open-source file format and library developed for the storage and manipulation of +//! data produced by quantum chemistry calculations. It was designed with the goal of providing a +//! reliable and efficient method of storing and exchanging wave function parameters and matrix +//! elements. +//! +//! For comprehensive documentation, consult: [TREXIO Documentation](https://trex-coe.github.io/trexio/) +//! +//! The C library source code is available on GitHub: [TREXIO GitHub Repository](https://github.com/trex-coe/trexio) +//! + +use ::std::os::raw::c_char; + +mod c; + +/// Enumeration representing the various error codes that might be returned by function calls. +/// These error codes are mapped to those defined in the original C TREXIO library. +pub mod exit_code; +pub use exit_code::ExitCode; +use exit_code::ExitCode::InvalidArg; + +/// Enum representing the different backends that TREXIO can employ for data storage. +pub mod back_end; +pub use back_end::BackEnd; + +/// Structure representing bit fields. Mainly utilized for encapsulating determinant descriptions. +pub mod bitfield; +pub use bitfield::Bitfield; + +/// A constant string representing the package version of the linked C TREXIO library. +pub const PACKAGE_VERSION: &str = + unsafe { std::str::from_utf8_unchecked(c::TREXIO_PACKAGE_VERSION) }; + +/// Utility function to convert Rust results into TREXIO exit codes. +fn rc_return(result: T, rc: c::trexio_exit_code) -> Result { + let rc = ExitCode::from(rc); + match rc { + ExitCode::Success => Ok(result), + x => Err(x), + } +} + +/// Utility function to convert Rust string to C-compatible string. +fn string_to_c(s: &str) -> std::ffi::CString { + std::ffi::CString::new(s).unwrap() +} + +/// Function to print out diagnostic information about the linked C TREXIO library. +pub fn info() -> Result<(), ExitCode> { + let rc = unsafe { c::trexio_info() }; + rc_return((), rc) +} + +/// Type representing a TREXIO file. Wraps a pointer to the underlying C structure. +pub struct File { + ptr: *mut c::trexio_t, +} + +impl File { + /// Opens a TREXIO file. Returns a `File` instance that can be used for subsequent I/O operations. + /// + /// # Parameters + /// - `file_name`: The path to the TREXIO file. + /// - `mode`: Specifies the file access mode. `'r'` for read-only, `'w'` for safe write (write + /// if the data doesn't exist), `'u'` for unsafe write (update existing data). + /// - `back_end`: Specifies the backend used for data storage. + /// + /// # Returns + /// - `Result`: `File` instance or an error code. + pub fn open(file_name: &str, mode: char, back_end: BackEnd) -> Result { + let file_name_c = string_to_c(file_name); + let file_name_c = file_name_c.as_ptr() as *const c_char; + let mode = mode as c_char; + let back_end = back_end.to_c(); + let rc: *mut c::trexio_exit_code = &mut c::TREXIO_SUCCESS.clone(); + let result = unsafe { c::trexio_open(file_name_c, mode, back_end, rc) }; + let rc = unsafe { *rc }; + rc_return(File { ptr: result }, rc) + } + + /// Closes the current TREXIO file and releases associated resources. + /// + /// # Returns + /// - `Result<(), ExitCode>`: An error code in case of failure. + pub fn close(self) -> Result<(), ExitCode> { + let rc = unsafe { c::trexio_close(self.ptr) }; + rc_return((), rc) + } + + /// Inquires if a file with the specified name exists. + /// + /// # Parameters + /// + /// * `file_name: &str` - The name of the file to inquire about. + /// + /// # Returns + /// + /// * `Result` - Returns `Ok(true)` if the file exists, + /// `Ok(false)` otherwise. Returns `Err(ExitCode)` if an error occurs + /// during the operation. + pub fn inquire(file_name: &str) -> Result { + let file_name_c = string_to_c(file_name); + let file_name_c = file_name_c.as_ptr() as *const c_char; + let rc = unsafe { c::trexio_inquire(file_name_c) }; + match ExitCode::from(rc) { + ExitCode::Failure => Ok(false), + ExitCode::Success => Ok(true), + x => Err(x), + } + } + + /// Retrieves the ID of the electronic state stored in the file. + /// + /// # Parameters + /// + /// None + /// + /// # Returns + /// + /// * `Result` - Returns the ID as `Ok(usize)` if the operation is successful, + /// otherwise returns `Err(ExitCode)`. + pub fn get_state(&self) -> Result { + let mut num = 0i32; + let rc = unsafe { c::trexio_get_state(self.ptr, &mut num) }; + let result: usize = num.try_into().expect("try_into failed in get_state"); + rc_return(result, rc) + } + + /// Sets the ID of the electronic state to be stored in the file. + /// + /// # Parameters + /// + /// * `num: usize` - The ID of the electronic state. + /// + /// # Returns + /// + /// * `Result<(), ExitCode>` - Returns `Ok(())` if the operation is successful, + /// otherwise returns `Err(ExitCode)`. + pub fn set_state(&self, num: usize) -> Result<(), ExitCode> { + let num: i32 = num.try_into().expect("try_into failed in set_state"); + let rc = unsafe { c::trexio_set_state(self.ptr, num) }; + rc_return((), rc) + } + + /// Retrieves the number of `i64` required to store a determinant as a bit-field. + /// This corresponds to \(\frac{\text{mo\_num}}{64}+1\). + /// + /// # Parameters + /// + /// None + /// + /// # Returns + /// + /// * `Result` - Returns the number of `i64` as `Ok(usize)` if the operation is successful, + /// otherwise returns `Err(ExitCode)`. + pub fn get_int64_num(&self) -> Result { + let mut num = 0i32; + let rc = unsafe { c::trexio_get_int64_num(self.ptr, &mut num) }; + let num: usize = num.try_into().expect("try_into failed in get_int64_num"); + rc_return(num, rc) + } + + /// Writes a vector of determinants, represented as [Bitfield] objects. + /// + /// # Parameters + /// + /// * `offset: usize` - The number of determinants to skip in the file before writing. + /// * `determinants: &[Bitfield]` - The array of determinants to write. + /// + /// # Returns + /// + /// * `Result<(), ExitCode>` - Returns `Ok(())` if the operation is successful, + /// otherwise returns `Err(ExitCode)`. + pub fn write_determinant_list( + &self, + offset: usize, + determinants: &[Bitfield], + ) -> Result<(), ExitCode> { + let n_int = self.get_int64_num()?; + match determinants.len() { + 0 => return Ok(()), + _ => { + if determinants[0].as_vec().len() != 2 * n_int { + return Err(InvalidArg(3)); + } + } + }; + let offset: i64 = offset + .try_into() + .expect("try_into failed in write_determinant_list"); + let buffer_size: i64 = determinants + .len() + .try_into() + .expect("try_into failed in write_determinant_list"); + let mut one_d_array: Vec = Vec::with_capacity(determinants.len() * n_int); + for det in determinants { + for i in det.as_vec() { + one_d_array.push(*i); + } + } + let dset: *const i64 = one_d_array.as_ptr(); + let rc = unsafe { c::trexio_write_determinant_list(self.ptr, offset, buffer_size, dset) }; + rc_return((), rc) + } + + /// Reads a vector of determinants, represented as [Bitfield] objects. + /// + /// # Parameters + /// + /// * `offset: usize` - The number of determinants to skip in the file before reading. + /// * `buffer_size: usize` - The number of determinants to read. + /// + /// # Returns + /// + /// * `Result, ExitCode>` - Returns the read determinants as `Ok(Vec)` + /// if the operation is successful, otherwise returns `Err(ExitCode)`. + pub fn read_determinant_list( + &self, + offset: usize, + buffer_size: usize, + ) -> Result, ExitCode> { + let n_int = self.get_int64_num()?; + let mut one_d_array: Vec = Vec::with_capacity(buffer_size * 2 * n_int); + let one_d_array_ptr = one_d_array.as_ptr() as *mut i64; + let rc = unsafe { + let offset: i64 = offset + .try_into() + .expect("try_into failed in read_determinant_list (offset)"); + let mut buffer_size_read: i64 = buffer_size + .try_into() + .expect("try_into failed in read_determinant_list (buffer_size)"); + let rc = c::trexio_read_determinant_list( + self.ptr, + offset, + &mut buffer_size_read, + one_d_array_ptr, + ); + let buffer_size_read: usize = buffer_size_read + .try_into() + .expect("try_into failed in read_determinant_list (buffer_size)"); + one_d_array.set_len(n_int * 2usize * buffer_size_read); + match ExitCode::from(rc) { + ExitCode::End => ExitCode::to_c(&ExitCode::Success), + ExitCode::Success => { + assert_eq!(buffer_size_read, buffer_size); + rc + } + _ => rc, + } + }; + let result: Vec = one_d_array + .chunks(2 * n_int) + .collect::>() + .iter() + .map(|x| (Bitfield::from_vec(x))) + .collect::>(); + rc_return(result, rc) + } +} + +include!(concat!(env!("OUT_DIR"), "/generated.rs")); + diff --git a/rust/trexio/tests/read_write.rs b/rust/trexio/tests/read_write.rs new file mode 100644 index 0000000..ebdd88f --- /dev/null +++ b/rust/trexio/tests/read_write.rs @@ -0,0 +1,292 @@ +use trexio::back_end::BackEnd; +use trexio::bitfield::Bitfield; + +fn write(file_name: &str, back_end: BackEnd) -> Result<(), trexio::ExitCode> { + // Prepare data to be written + + let nucleus_num = 12; + let state_id = 2; + let charge = vec![6., 6., 6., 6., 6., 6., 1., 1., 1., 1., 1., 1.0f64]; + let coord = vec![ + [0.00000000f64, 1.39250319, 0.00], + [-1.20594314, 0.69625160, 0.00], + [-1.20594314, -0.69625160, 0.00], + [0.00000000, -1.39250319, 0.00], + [1.20594314, -0.69625160, 0.00], + [1.20594314, 0.69625160, 0.00], + [-2.14171677, 1.23652075, 0.00], + [-2.14171677, -1.23652075, 0.00], + [0.00000000, -2.47304151, 0.00], + [2.14171677, -1.23652075, 0.00], + [2.14171677, 1.23652075, 0.00], + [0.00000000, 2.47304151, 0.00], + ]; + let flat_coord = coord.into_iter().flatten().collect::>(); + let mo_num = 150; + let ao_num = 1000; + let basis_shell_num = 24; + let basis_nucleus_index: Vec = (0..24).collect(); + + let label = vec![ + "C", "Na", "C", "C 66", "C", "C", "H 99", "Ru", "H", "H", "H", "H", + ]; + + let sym_str = "B3U with some comments"; + + println!("Write {}", file_name); + assert!(!trexio::File::inquire(file_name)?); + + let trex_file = trexio::File::open(file_name, 'w', back_end)?; + + assert!(!trex_file.has_nucleus()?); + assert!(!trex_file.has_nucleus_num()?); + assert!(!trex_file.has_nucleus_charge()?); + assert!(!trex_file.has_ao_2e_int()?); + assert!(!trex_file.has_ao_2e_int_eri()?); + assert!(!trex_file.has_determinant_list()?); + + trex_file.write_nucleus_num(nucleus_num)?; + trex_file.write_nucleus_charge(&charge)?; + trex_file.write_nucleus_point_group(sym_str)?; + trex_file.write_nucleus_coord(&flat_coord)?; + trex_file.write_nucleus_label(&label)?; + trex_file.write_basis_shell_num(basis_shell_num)?; + trex_file.write_basis_nucleus_index(&basis_nucleus_index)?; + trex_file.write_state_id(state_id)?; + + if !trex_file.has_ao_num()? { + trex_file.write_ao_num(ao_num)?; + } + + if !trex_file.has_mo_num()? { + trex_file.write_mo_num(mo_num)?; + } + + let mut energy = Vec::with_capacity(mo_num); + for i in 0..mo_num { + let e: f64 = i as f64 - 100.0f64; + energy.push(e); + } + trex_file.write_mo_energy(&energy)?; + + let mut spin = vec![0; mo_num]; + for i in mo_num / 2..mo_num { + spin[i] = 1; + } + trex_file.write_mo_spin(&spin)?; + + // Integrals + let nmax = 100; + let mut ao_2e_int_eri = Vec::<(usize, usize, usize, usize, f64)>::with_capacity(nmax); + + let n_buffers = 5; + let bufsize = nmax / n_buffers; + + for i in 0..100 { + // Quadruplet of indices + value + let data = (4 * i, 4 * i + 1, 4 * i + 2, 4 * i + 3, 3.14 + (i as f64)); + ao_2e_int_eri.push(data); + } + + let mut offset = 0; + for _ in 0..n_buffers { + trex_file.write_ao_2e_int_eri(offset, &ao_2e_int_eri[offset..offset + bufsize])?; + offset += bufsize; + } + + // Determinants + let det_num = 50; + let mut det_list = Vec::with_capacity(det_num); + for i in 0..det_num { + let mut d = [0i64; 6]; + for j in 0..6 { + d[j] = 6 * (i as i64) + (j as i64); + } + det_list.push(Bitfield::from_vec(&d)); + } + + let n_buffers = 5; + let bufsize = 50 / n_buffers; + let mut offset = 0; + for _ in 0..n_buffers { + trex_file.write_determinant_list(offset, &det_list[offset..offset + bufsize])?; + offset += bufsize; + } + + trex_file.close() +} + +fn read(file_name: &str, back_end: BackEnd) -> Result<(), trexio::ExitCode> { + println!("Read {}", file_name); + assert!(trexio::File::inquire(file_name)?); + + let trex_file = trexio::File::open(file_name, 'r', back_end)?; + + assert!(trex_file.has_nucleus()?); + assert!(trex_file.has_nucleus_num()?); + assert!(trex_file.has_nucleus_charge()?); + assert!(trex_file.has_ao_2e_int()?); + assert!(trex_file.has_ao_2e_int_eri()?); + assert!(trex_file.has_determinant_list()?); + + let nucleus_num = trex_file.read_nucleus_num()?; + assert_eq!(nucleus_num, 12); + + let sym_str = trex_file.read_nucleus_point_group(64)?; + assert_eq!(sym_str, "B3U with some comments"); + + let charge = trex_file.read_nucleus_charge()?; + assert_eq!( + charge, + vec![6., 6., 6., 6., 6., 6., 1., 1., 1., 1., 1., 1.0f64] + ); + + let coord = trex_file.read_nucleus_coord()?; + assert_eq!( + coord, + vec![ + 0.00000000f64, + 1.39250319, + 0.00, + -1.20594314, + 0.69625160, + 0.00, + -1.20594314, + -0.69625160, + 0.00, + 0.00000000, + -1.39250319, + 0.00, + 1.20594314, + -0.69625160, + 0.00, + 1.20594314, + 0.69625160, + 0.00, + -2.14171677, + 1.23652075, + 0.00, + -2.14171677, + -1.23652075, + 0.00, + 0.00000000, + -2.47304151, + 0.00, + 2.14171677, + -1.23652075, + 0.00, + 2.14171677, + 1.23652075, + 0.00, + 0.00000000, + 2.47304151, + 0.00 + ] + ); + + let label = trex_file.read_nucleus_label(6)?; + assert_eq!( + label, + vec!["C", "Na", "C", "C 66", "C", "C", "H 99", "Ru", "H", "H", "H", "H"] + ); + + let basis_shell_num = trex_file.read_basis_shell_num()?; + assert_eq!(basis_shell_num, 24); + + let basis_nucleus_index = trex_file.read_basis_nucleus_index()?; + let ref_val: Vec = (0..24).collect(); + assert_eq!(basis_nucleus_index, ref_val); + + let state_id = trex_file.read_state_id()?; + assert_eq!(state_id, 2); + + let ao_num = trex_file.read_ao_num()?; + assert_eq!(ao_num, 1000); + + let mo_num = trex_file.read_mo_num()?; + assert_eq!(mo_num, 150); + + let mut energy_ref = Vec::with_capacity(mo_num); + for i in 0..mo_num { + let e: f64 = i as f64 - 100.0f64; + energy_ref.push(e); + } + let energy = trex_file.read_mo_energy()?; + assert_eq!(energy, energy_ref); + + let mut spin_ref = vec![0; mo_num]; + for i in mo_num / 2..mo_num { + spin_ref[i] = 1; + } + let spin = trex_file.read_mo_spin()?; + assert_eq!(spin, spin_ref); + + // Integrals + let nmax = 100; + let mut ao_2e_int_eri_ref = Vec::<(usize, usize, usize, usize, f64)>::with_capacity(nmax); + + let n_buffers = 8; + let bufsize = nmax / n_buffers + 10; + + for i in 0..100 { + // Quadruplet of indices + value + let data = (4 * i, 4 * i + 1, 4 * i + 2, 4 * i + 3, 3.14 + (i as f64)); + ao_2e_int_eri_ref.push(data); + } + + let mut offset = 0; + let mut ao_2e_int_eri = Vec::<(usize, usize, usize, usize, f64)>::with_capacity(nmax); + for _ in 0..n_buffers { + let buffer = trex_file.read_ao_2e_int_eri(offset, bufsize)?; + offset += buffer.len(); + ao_2e_int_eri.extend(buffer); + } + assert_eq!(ao_2e_int_eri_ref, ao_2e_int_eri); + + // Determinants + let det_num = trex_file.read_determinant_num()?; + assert_eq!(det_num, 50); + + let mut det_list_ref = Vec::with_capacity(det_num); + for i in 0..det_num { + let mut d = [0i64; 6]; + for j in 0..6 { + d[j] = 6 * (i as i64) + (j as i64); + } + det_list_ref.push(Bitfield::from_vec(&d)); + } + + let n_buffers = 8; + let bufsize = det_num / n_buffers + 20; + let mut offset = 0; + let mut det_list: Vec = Vec::with_capacity(det_num); + for _ in 0..n_buffers { + let buffer = trex_file.read_determinant_list(offset, bufsize)?; + offset += buffer.len(); + det_list.extend(buffer); + } + assert_eq!(det_list_ref, det_list); + + trex_file.close() +} + +#[test] +pub fn info() { + let _ = trexio::info(); +} + +use std::fs; + +#[test] +pub fn text_backend() { + let _ = write("tmp/test_write.dir", trexio::BackEnd::Text).unwrap(); + let _ = read("tmp/test_write.dir", trexio::BackEnd::Text).unwrap(); + fs::remove_dir_all("tmp/test_write.dir").unwrap() +} + +#[test] +pub fn hdf5_backend() { + let _ = write("tmp/test_write.hdf5", trexio::BackEnd::Hdf5).unwrap(); + let _ = read("tmp/test_write.hdf5", trexio::BackEnd::Hdf5).unwrap(); + fs::remove_file("tmp/test_write.hdf5").unwrap() +} diff --git a/rust/trexio/tmp/.gitignore b/rust/trexio/tmp/.gitignore new file mode 100644 index 0000000..72e8ffc --- /dev/null +++ b/rust/trexio/tmp/.gitignore @@ -0,0 +1 @@ +* diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0dc8bd4..16ec5df 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,7 +19,7 @@ set(TREXIO_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/trexio.c ${CMAKE_CURRENT_SOURCE_DIR}/trexio_text.c ) -set(TREXIO_PUBLIC_HEADERS ${CMAKE_SOURCE_DIR}/include/trexio.h) +set(TREXIO_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/trexio.h) set(TREXIO_PRIVATE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/trexio_s.h ${CMAKE_CURRENT_SOURCE_DIR}/trexio_private.h @@ -66,7 +66,7 @@ option(ENABLE_HDF5 "Enable HDF5 support" ON) if(ENABLE_HDF5) # Try to detect HDF5 installation using built-in FindHDF5.cmake macro. - find_package(HDF5 REQUIRED COMPONENTS C HL) + find_package(HDF5 REQUIRED COMPONENTS C) if(HDF5_FOUND) message(STATUS "HDF5 version :: ${HDF5_VERSION}") @@ -87,9 +87,7 @@ if(ENABLE_HDF5) # - include directories with HDF5 header files target_include_directories(trexio PRIVATE ${HDF5_C_INCLUDE_DIRS}) # - link to HDF5 C libraries - target_link_libraries(trexio PRIVATE - ${HDF5_C_HL_LIBRARIES} - ${HDF5_C_LIBRARIES}) + target_link_libraries(trexio PRIVATE ${HDF5_C_LIBRARIES}) endif() # Private headers have to be listed as sources, otherwise they are installed @@ -103,7 +101,7 @@ include(FortranCInterface) FortranCInterface_VERIFY() # Fortran module -set(TREXIO_MOD_FILE ${CMAKE_SOURCE_DIR}/include/trexio_f.f90) +set(TREXIO_MOD_FILE ${PROJECT_SOURCE_DIR}/include/trexio_f.f90) # Export to parent scope so tests directory picks this up. set(TREXIO_MOD_FILE ${TREXIO_MOD_FILE} PARENT_SCOPE) # Add TREXIO Fortran module as a library. @@ -117,7 +115,7 @@ if(TREXIO_DEVEL) set(ORG_FILES templates_front/templator_front.org templates_text/templator_text.org - ${CMAKE_SOURCE_DIR}/trex.org + ${PROJECT_SOURCE_DIR}/trex.org ) if(ENABLE_HDF5) list(APPEND ORG_FILES templates_hdf5/templator_hdf5.org) @@ -129,8 +127,8 @@ if(TREXIO_DEVEL) ${TREXIO_PRIVATE_HEADERS} ${TREXIO_MOD_FILE} COMMAND ./build_trexio.sh - DEPENDS ${ORG_FILES} ${CMAKE_SOURCE_DIR}/include/config.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tools + DEPENDS ${ORG_FILES} ${PROJECT_SOURCE_DIR}/include/config.h + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tools COMMENT "Generating TREXIO source code from org-mode files." VERBATIM) @@ -158,7 +156,7 @@ install(FILES ${TREXIO_MOD_FILE} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) # https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake if(NOT TARGET uninstall) configure_file( - "${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" + "${PROJECT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) diff --git a/src/README.org b/src/README.org index 0b6efb2..62b516c 100644 --- a/src/README.org +++ b/src/README.org @@ -2,34 +2,75 @@ #+PROPERTY: comments org #+SETUPFILE: ../docs/theme.setup +-------------------------------- #+BEGIN_EXPORT html #+END_EXPORT +-------------------------------- ------------------- +TREXIO is an open-source file format and library developed for the storage and +manipulation of data produced by quantum chemistry calculations. It was +designed with the goal of providing a reliable and efficient method of storing +and exchanging wave function parameters and matrix elements. - - [[./tutorial_benzene.html][Tutorial]] +The library consists of a front-end implemented in the C programming language +and two different back-ends: a text back-end and a binary back-end utilizing +the HDF5 library enabling fast read and write speeds. It is compatible with a +variety of platforms and has interfaces for Fortran, Python, and OCaml. + +If you use TREXIO, please cite this article published in the [[https://doi.org/10.1063/5.0148161][Journal of Chemical Physics]]: +#+begin_src latex +@article{trexio_2023, + author = {Posenitskiy, Evgeny and Chilkuri, Vijay Gopal and Ammar, Abdallah and Hapka, Micha{\l} and Pernal, Katarzyna and Shinde, Ravindra and Landinez Borda, Edgar Josu{\'{e}} and Filippi, Claudia and Nakano, Kosuke and Kohul{\'{a}}k, Otto and Sorella, Sandro and de Oliveira Castro, Pablo and Jalby, William and R{\'{\i}}os, Pablo L{\'{o}}pez and Alavi, Ali and Scemama, Anthony}, + title = {{TREXIO: A file format and library for quantum chemistry}}, + journal = {J. Chem. Phys.}, + volume = {158}, + number = {17}, + year = {2023}, + month = may, + issn = {0021-9606}, + publisher = {AIP Publishing}, + doi = {10.1063/5.0148161} +} +#+end_src +If you don't have access to the journal, you can access the manuscript on +[[https://doi.org/10.48550/arXiv.2302.14793][arXiv:2302.14793]]. + +-------------------------------- + +#+BEGIN_EXPORT html + + + +
+#+END_EXPORT + + - [[./intro.html][Motivation]] + - [[./lib.html][The TREXIO library]] - [[./trex.html][Data stored with TREXIO]] - - [[./examples.html][How-to guide]] + - [[./tutorial_benzene.html][Tutorial]] + - [[./examples.html][Examples]] - [[./templator_front.html][Front end API]] - [[./templator_hdf5.html][HDF5 back end]] - [[./templator_text.html][TEXT back end]] +#+BEGIN_EXPORT html + +T-Rex talking about chemistry +
+#+END_EXPORT -------------------------------- - - The TREXIO library defines a standard format for storing wave functions, - together with an C-compatible API such that it can be easily used in any - programming language. - - The source code of the library is available at https://github.com/trex-coe/trexio and bug reports should be submitted at https://github.com/trex-coe/trexio/issues. + The TREXIO library is licensed under the open-source 3-clause BSD license. + ------------------ [[https://trex-coe.eu/sites/default/files/inline-images/euflag.jpg]] [[https://trex-coe.eu][TREX: Targeting Real Chemical Accuracy at the Exascale]] project has received funding from the European Union’s Horizon 2020 - Research and Innovation program - under grant agreement no. 952165. The content of this document does not represent the opinion of the European Union, and the European Union is not responsible for any use that might be made of such content. diff --git a/src/pytrexio.i b/src/pytrexio.i index b6e5485..2fadc52 100644 --- a/src/pytrexio.i +++ b/src/pytrexio.i @@ -34,14 +34,14 @@ num variable is modified by address */ /* 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 int32_t *OUTPUT { int32_t* const num}; +%apply int64_t *OUTPUT { int64_t* const num}; +%apply int32_t *OUTPUT { int32_t* const num_up}; +%apply int32_t *OUTPUT { int32_t* const num_dn}; +%apply int64_t *OUTPUT { int64_t* const num_up}; +%apply int64_t *OUTPUT { int64_t* const num_dn}; %apply float *OUTPUT { float* const num}; -%apply float *OUTPUT { double* const num}; +%apply double *OUTPUT { double* const num}; /* Return TREXIO exit code from trexio_open as part of the output tuple */ %apply int *OUTPUT { trexio_exit_code* const rc_open}; /* Return number of sparse data points stored in the file as part of the output tuple */ @@ -108,6 +108,14 @@ import_array(); /* 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)}; +/* NAO functions */ +%apply double *OUTPUT { double* const log_r_out, double* const amplitude}; +%apply (double *ARGOUT_ARRAY1, int DIM1) {(double* const amplitudes, int amplitude_cnt)}; +%apply (double* IN_ARRAY1, int DIM1) {(double* grid_r, int n_grid_r), + (double* interpolator, int n_interp), (double* nucleus_coords, int n_nuc_co), (double* normalization, int n_norm)}; +%apply (int64_t* IN_ARRAY1, int DIM1) {(int64_t* grid_start, int n_grid_st), + (int64_t* grid_size, int n_grid_si), (int64_t* nucleus_index, int n_nuc_id)}; + /* 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. by converting input list of strings from Python into char ** of C diff --git a/src/templates_front/templator_front.org b/src/templates_front/templator_front.org index 697bc69..c21b253 100644 --- a/src/templates_front/templator_front.org +++ b/src/templates_front/templator_front.org @@ -20,14 +20,271 @@ ** C + We include in thr trexio.h file a text variable that contains the + contents of the ~trex.json~ confguration file, generated from the + ~trex.org~ file. + + #+NAME: trex_json + #+begin_src python :results drawer +res = "/* JSON configuration\n" +with open('../../trex.json','r') as f: + for line in f: + res += line.rstrip()+'\n' +res += "*/" +return res + #+end_src + + #+RESULTS: trex_json + :results: + /* JSON configuration + { + + "metadata": { + "code_num" : [ "dim", [] ] + , "code" : [ "str", [ "metadata.code_num" ] ] + , "author_num" : [ "dim", [] ] + , "author" : [ "str", [ "metadata.author_num" ] ] + , "package_version" : [ "str", [] ] + , "description" : [ "str", [] ] + , "unsafe" : [ "int", [] ] + } , + + "nucleus": { + "num" : [ "dim" , [] ] + , "charge" : [ "float", [ "nucleus.num" ] ] + , "coord" : [ "float", [ "nucleus.num", "3" ] ] + , "label" : [ "str" , [ "nucleus.num" ] ] + , "point_group" : [ "str" , [] ] + , "repulsion" : [ "float", [] ] + } , + + "cell": { + "a" : [ "float", [ "3" ] ] + , "b" : [ "float", [ "3" ] ] + , "c" : [ "float", [ "3" ] ] + , "G_a" : [ "float", [ "3" ] ] + , "G_b" : [ "float", [ "3" ] ] + , "G_c" : [ "float", [ "3" ] ] + , "two_pi" : [ "int" , [] ] + } , + + "pbc": { + "periodic" : [ "int" , [] ] + , "k_point" : [ "float", [ "3" ] ] + } , + + "electron": { + "num" : [ "dim", [] ] + , "up_num" : [ "int", [] ] + , "dn_num" : [ "int", [] ] + } , + + "state": { + "num" : [ "dim" , [] ] + , "id" : [ "index", [] ] + , "energy" : [ "float", [] ] + , "current_label" : [ "str" , [] ] + , "label" : [ "str" , [ "state.num" ] ] + , "file_name" : [ "str" , [ "state.num" ] ] + } , + + "basis": { + "type" : [ "str" , [] ] + , "prim_num" : [ "dim" , [] ] + , "shell_num" : [ "dim" , [] ] + , "nao_grid_num" : [ "dim" , [] ] + , "interp_coeff_cnt" : [ "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" ] ] + , "nao_grid_start" : [ "index", [ "basis.shell_num" ] ] + , "nao_grid_size" : [ "dim" , [ "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" ] ] + , "e_cut" : [ "float", [] ] + , "nao_grid_radius" : [ "float", [ "basis.nao_grid_num" ] ] + , "nao_grid_phi" : [ "float", [ "basis.nao_grid_num" ] ] + , "nao_grid_grad" : [ "float", [ "basis.nao_grid_num" ] ] + , "nao_grid_lap" : [ "float", [ "basis.nao_grid_num" ] ] + , "interpolator_kind" : [ "str" , [] ] + , "interpolator_phi" : [ "float", [ "basis.nao_grid_num", "basis.interp_coeff_cnt" ] ] + , "interpolator_grad" : [ "float", [ "basis.nao_grid_num", "basis.interp_coeff_cnt" ] ] + , "interpolator_lap" : [ "float", [ "basis.nao_grid_num", "basis.interp_coeff_cnt" ] ] + } , + + "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" ] ] + } , + + "grid": { + "description" : [ "str" , [] ] + , "rad_precision" : [ "float", [] ] + , "num" : [ "dim" , [] ] + , "max_ang_num" : [ "int" , [] ] + , "min_ang_num" : [ "int" , [] ] + , "coord" : [ "float", [ "grid.num" ] ] + , "weight" : [ "float", [ "grid.num" ] ] + , "ang_num" : [ "dim" , [] ] + , "ang_coord" : [ "float", [ "grid.ang_num" ] ] + , "ang_weight" : [ "float", [ "grid.ang_num" ] ] + , "rad_num" : [ "dim" , [] ] + , "rad_coord" : [ "float", [ "grid.rad_num" ] ] + , "rad_weight" : [ "float", [ "grid.rad_num" ] ] + } , + + "ao": { + "cartesian" : [ "int" , [] ] + , "num" : [ "dim" , [] ] + , "shell" : [ "index", [ "ao.num" ] ] + , "normalization" : [ "float", [ "ao.num" ] ] + } , + + "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_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" ] ] + } , + + "ao_2e_int": { + "eri" : [ "float sparse", [ "ao.num", "ao.num", "ao.num", "ao.num" ] ] + , "eri_lr" : [ "float sparse", [ "ao.num", "ao.num", "ao.num", "ao.num" ] ] + , "eri_cholesky_num" : [ "dim" , [] ] + , "eri_cholesky" : [ "float sparse", [ "ao_2e_int.eri_cholesky_num", "ao.num", "ao.num" ] ] + , "eri_lr_cholesky_num" : [ "dim" , [] ] + , "eri_lr_cholesky" : [ "float sparse", [ "ao_2e_int.eri_lr_cholesky_num", "ao.num", "ao.num" ] ] + } , + + "mo": { + "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" ] ] + } , + + "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_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" ] ] + } , + + "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_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" ] ] + } , + + "determinant": { + "num" : [ "dim readonly" , [] ] + , "list" : [ "int special" , [ "determinant.num" ] ] + , "coefficient" : [ "float buffered", [ "determinant.num" ] ] + } , + + "csf": { + "num" : [ "dim readonly" , [] ] + , "coefficient" : [ "float buffered", [ "csf.num" ] ] + , "det_coefficient" : [ "float sparse" , [ "csf.num", "determinant.num" ] ] + } , + + "amplitude": { + "single" : [ "float sparse", [ "mo.num", "mo.num" ] ] + , "single_exp" : [ "float sparse", [ "mo.num", "mo.num" ] ] + , "double" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] + , "double_exp" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num" ] ] + , "triple" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num" ] ] + , "triple_exp" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num" ] ] + , "quadruple" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num" ] ] + , "quadruple_exp" : [ "float sparse", [ "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num", "mo.num" ] ] + } , + + "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_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" ] ] + } , + + "jastrow": { + "type" : [ "str" , [] ] + , "en_num" : [ "dim" , [] ] + , "ee_num" : [ "dim" , [] ] + , "een_num" : [ "dim" , [] ] + , "en" : [ "float" , [ "jastrow.en_num" ] ] + , "ee" : [ "float" , [ "jastrow.ee_num" ] ] + , "een" : [ "float" , [ "jastrow.een_num" ] ] + , "en_nucleus" : [ "index" , [ "jastrow.en_num" ] ] + , "een_nucleus" : [ "index" , [ "jastrow.een_num" ] ] + , "ee_scaling" : [ "float" , [] ] + , "en_scaling" : [ "float" , [ "nucleus.num" ] ] + } , + + "qmc": { + "num" : [ "dim" , [] ] + , "point" : [ "float", [ "qmc.num", "electron.num", "3" ] ] + , "psi" : [ "float", [ "qmc.num" ] ] + , "e_loc" : [ "float", [ "qmc.num" ] ] + } + + } + */ + :end: + + #+begin_src c :tangle prefix_front.h :noweb yes <
> #ifndef TREXIO_H #define TREXIO_H +#ifdef __cplusplus +extern "C" { +#endif + #include #include +<> typedef int32_t trexio_exit_code; #+end_src @@ -38,6 +295,7 @@ typedef int32_t trexio_exit_code; #include "config.h" #endif +#include #include #include #include @@ -673,7 +931,6 @@ bool trexio_has_backend(back_end_t back_end) { #+begin_src f90 :tangle prefix_fortran.f90 interface logical(c_bool) function trexio_has_back_end (back_end) bind(C) - use, intrinsic :: iso_c_binding import integer(trexio_back_end_t), intent(in), value :: back_end end function trexio_has_back_end @@ -681,7 +938,6 @@ end interface interface logical(c_bool) function trexio_has_backend (back_end) bind(C) - use, intrinsic :: iso_c_binding import integer(trexio_back_end_t), intent(in), value :: back_end end function trexio_has_backend @@ -738,7 +994,6 @@ typedef struct trexio_s trexio_t; #+begin_src c :tangle prefix_s_front.h struct trexio_s { - char file_name[TREXIO_MAX_FILENAME_LENGTH]; pthread_mutex_t thread_lock; back_end_t back_end; char mode; @@ -748,6 +1003,7 @@ struct trexio_s { int16_t version_minor; int16_t version_patch; char version[16]; + char file_name[TREXIO_MAX_FILENAME_LENGTH]; }; #+end_src @@ -851,6 +1107,14 @@ class File: return self.state + + def flush(self): + """Flush the data on disk.""" + rc = pytr.trexio_flush(self.pytrexio_s) + if rc != TREXIO_SUCCESS: + raise Error(rc) + + def inquire(self): """Inquire whether a TREXIO file exists.""" self.exists = _inquire(self.filename) @@ -1504,7 +1768,7 @@ def flush(trexio_file): Parameter is a ~trexio_file~ object that has been created by a call to ~open~ function. """ - rc = pytr.trexio_flush(trexio_file) + rc = pytr.trexio_flush(trexio_file.pytrexio_s) if rc != TREXIO_SUCCESS: raise Error(rc) #+end_src @@ -1594,7 +1858,8 @@ def _inquire(file_name: str) -> bool: ** File copy - ~trexio_cp~ copies a TREXIO file using =cp=. + ~trexio_cp~ copies a TREXIO file using =cp=. The destination file + is not overwritten if it exists, an error is returned. **Input parameters:** 1) ~source_file_name~ - string containing the name of the source file @@ -1626,12 +1891,13 @@ trexio_cp(const char* source, const char* dest) back_end_t back_end_local = TREXIO_AUTO; /* Try to determine the applicable backend if the back_end argument is TREXIO_AUTO */ -#ifdef HAVE_HDF5 /* Check if the TREXIO file exists and if it is a directory */ trexio_exit_code rc_text = trexio_text_inquire(source); if (rc_text == TREXIO_SUCCESS) { back_end_local = TREXIO_TEXT; - } else { + } +#ifdef HAVE_HDF5 + else { /* If not, check if it is an HDF5 file */ trexio_exit_code rc_hdf5 = trexio_hdf5_inquire(source); if (rc_hdf5 == TREXIO_SUCCESS) { @@ -1640,11 +1906,12 @@ trexio_cp(const char* source, const char* dest) /* File is neither a directory nor an HDF5 file -> return an error */ return TREXIO_FILE_ERROR; } -#else - /* In the current implementation if HDF5 back end is not available - then there is only back end left */ - back_end_local = TREXIO_TEXT; -#endif } +#else + else { + return TREXIO_FILE_ERROR; + } +#endif assert (back_end_local != TREXIO_AUTO); if (trexio_inquire(dest) == TREXIO_SUCCESS) { @@ -1728,6 +1995,12 @@ def _cp(source: str, destination: str): and write it as ~state_id~ attribute. ~trexio_get_state~ returns current state of the ~trexio_t~ file handle. + **Warning:** The ~trexio_set_state~ and ~trexio_get_state~ functions still + use the old convention where the ground state was state ~0~. From version 2.4.0, + the ~state_id~ variable has changed to ~index~ type, so using the more recent + ~trexio_write_state_id~ and ~trexio_read_state_id~ will give different results + in Fortran. + input parameters: ~file~ -- TREXIO file handle. ~state~ -- ~int32_t~ ID of a state (0 for ground state). @@ -2128,24 +2401,35 @@ trexio_read_$group_num$_64 (trexio_t* const file, $group_num_dtype_double$* cons if (num == NULL) return TREXIO_INVALID_ARG_2; if (trexio_has_$group_num$(file) != TREXIO_SUCCESS) return TREXIO_ATTR_MISSING; + trexio_exit_code rc = TREXIO_GROUP_READ_ERROR; + switch (file->back_end) { case TREXIO_TEXT: - return trexio_text_read_$group_num$(file, num); + rc = trexio_text_read_$group_num$(file, num); + break; case TREXIO_HDF5: #ifdef HAVE_HDF5 - return trexio_hdf5_read_$group_num$(file, num); + rc = trexio_hdf5_read_$group_num$(file, num); #else - return TREXIO_BACK_END_MISSING; + rc = TREXIO_BACK_END_MISSING; #endif + break; /* case TREXIO_JSON: - return trexio_json_read_$group_num$(file, num); + rc = trexio_json_read_$group_num$(file, num); + break; ,*/ } - return TREXIO_FAILURE; + if (rc != TREXIO_SUCCESS) return rc; + + /* Handle index type */ + if ($is_index$) { + ,*num += ($group_num_dtype_double$) 1; + } + return rc; } #+end_src @@ -2157,20 +2441,26 @@ trexio_write_$group_num$_64 (trexio_t* const file, const $group_num_dtype_double //if (num <= 0L) return TREXIO_INVALID_NUM; /* this line is uncommented by the generator for dimensioning variables; do NOT remove! */ if (trexio_has_$group_num$(file) == TREXIO_SUCCESS && file->mode != 'u') return TREXIO_ATTR_ALREADY_EXISTS; + /* Handle index type */ + $group_num_dtype_double$ num_write = num; + if ($is_index$) { + num_write -= ($group_num_dtype_double$) 1; + } + switch (file->back_end) { case TREXIO_TEXT: - return trexio_text_write_$group_num$(file, num); + return trexio_text_write_$group_num$(file, num_write); case TREXIO_HDF5: #ifdef HAVE_HDF5 - return trexio_hdf5_write_$group_num$(file, num); + return trexio_hdf5_write_$group_num$(file, num_write); #else return TREXIO_BACK_END_MISSING; #endif /* case TREXIO_JSON: - return trexio_json_write_$group_num$(file, num); + return trexio_json_write_$group_num$(file, num_write); ,*/ } @@ -2215,6 +2505,12 @@ trexio_read_$group_num$_32 (trexio_t* const file, $group_num_dtype_single$* cons if (rc != TREXIO_SUCCESS) return rc; ,*num = ($group_num_dtype_single$) num_64; + + /* Handle index type */ + if ($is_index$) { + ,*num += ($group_num_dtype_single$) 1; + } + return TREXIO_SUCCESS; } #+end_src @@ -2228,20 +2524,26 @@ trexio_write_$group_num$_32 (trexio_t* const file, const $group_num_dtype_single //if (num <= 0) return TREXIO_INVALID_NUM; /* this line is uncommented by the generator for dimensioning variables; do NOT remove! */ if (trexio_has_$group_num$(file) == TREXIO_SUCCESS && file->mode != 'u') return TREXIO_ATTR_ALREADY_EXISTS; + /* Handle index type */ + $group_num_dtype_single$ num_write = num; + if ($is_index$) { + num_write -= ($group_num_dtype_single$) 1; + } + switch (file->back_end) { case TREXIO_TEXT: - return trexio_text_write_$group_num$(file, ($group_num_dtype_double$) num); + return trexio_text_write_$group_num$(file, ($group_num_dtype_double$) num_write); case TREXIO_HDF5: #ifdef HAVE_HDF5 - return trexio_hdf5_write_$group_num$(file, ($group_num_dtype_double$) num); + return trexio_hdf5_write_$group_num$(file, ($group_num_dtype_double$) num_write); #else return TREXIO_BACK_END_MISSING; #endif /* case TREXIO_JSON: - return trexio_json_write_$group_num$(file, ($group_num_dtype_double$) num); + return trexio_json_write_$group_num$(file, ($group_num_dtype_double$) num_write); break; ,*/ } @@ -3323,7 +3625,7 @@ trexio_read_$group_dset$(trexio_t* const file, /* 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$; +#define 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 @@ -3331,11 +3633,12 @@ trexio_read_$group_dset$(trexio_t* const file, /* 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]; - } +#if (unique_rank != 1) + for (uint32_t i = 1; i < unique_rank; i++) { + if (unique_dims[i] > max_dim) max_dim = unique_dims[i]; } +#endif +#undef unique_rank // introduce a new variable that will be modified with the number of integrals being read if EOF is encountered int64_t eof_read_size = 0L; @@ -3455,7 +3758,7 @@ trexio_write_$group_dset$(trexio_t* const file, /* 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$; +#define 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 @@ -3463,11 +3766,12 @@ trexio_write_$group_dset$(trexio_t* const file, /* 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]; - } +#if (unique_rank != 1) + for (uint32_t i = 1; i < unique_rank; i++) { + if (unique_dims[i] > max_dim) max_dim = unique_dims[i]; } +#endif +#undef unique_rank // shift indices to be zero-based if Fortran API is used if (file->one_based) { @@ -4626,7 +4930,7 @@ def write_$group_dset$(trexio_file: File, offset_file: int, buffer_size: int, ds 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: + if isinstance(dset, np.ndarray) and not dset.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) @@ -5579,6 +5883,12 @@ def has_determinant_list(trexio_file) -> bool: bitfield representation of the determinant. If the creation of the bitfield requires a change of sign, the return code is ~TREXIO_PHASE_CHANGE~. + ~trexio_convert_nao_radius~ functions convert a radius from the center of an NAO to its logarithmic interpolation grid. + + ~trexio_evaluate_nao_radial~ function evaluates the radial function of an NAO for a given distance from the center. + + ~trexio_evaluate_nao_radial_all~ evaluates all radial functions at a given position in space. + ** C #+begin_src c :tangle prefix_front.h @@ -5597,6 +5907,35 @@ trexio_exit_code trexio_to_orbital_list_up_dn (const int32_t N_int, const bitfie 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); + +trexio_exit_code trexio_convert_nao_radius_32 (const float r, + const float* const grid_r, float* const log_r_out); +trexio_exit_code trexio_convert_nao_radius_64 (const double r, + const double* const grid_r, double* const log_r_out); +trexio_exit_code trexio_convert_nao_radius_py (const double r, + double* grid_r, int32_t n_grid_r, double* const log_r_out); +trexio_exit_code trexio_evaluate_nao_radial (const int32_t shell_index, + const double r, const int32_t* const grid_start, const int32_t* const grid_size, + const double* const grid_r, const double* const interpolator, + const double* const normalization, double* const amplitude); + +trexio_exit_code trexio_evaluate_nao_radial_all (const int32_t shell_num, + const int32_t* const nucleus_index, const double* const nucleus_coords, + const int32_t* const grid_start, const int32_t* const grid_size, + const double* const grid_r, const double* const interpolator, const double* const normalization, + const double rx, const double ry, const double rz, double* const amplitude); + +trexio_exit_code trexio_evaluate_nao_radial_py (const int shell_index, + const double r, int64_t* grid_start, int n_grid_st, int64_t* grid_size, + int n_grid_si, double* grid_r, int n_grid_r, double* interpolator, + int n_interp, double* normalization, int n_norm, double* const amplitude); + +trexio_exit_code trexio_evaluate_nao_radial_all_py (const int32_t shell_num, + int64_t* nucleus_index, int n_nuc_id, double* nucleus_coords, int n_nuc_co, + int64_t* grid_start, int n_grid_st, int64_t* grid_size, int n_grid_si, + double* grid_r, int n_grid_r, double* interpolator, int n_interp, double* normalization, int n_norm, + const double rx, const double ry, const double rz, double* const amplitudes, int amplitude_cnt); + #+end_src @@ -5615,19 +5954,15 @@ trexio_exit_code trexio_to_bitfield_list (const int32_t* orb_list, bit_list[j] = (bitfield_t) 0; } - uint32_t i; - uint32_t k; - uint32_t iorb; - bitfield_t mask; uint32_t nswaps = 0; for (int32_t pos = 0 ; pos < occupied_num ; pos++) { - iorb = ((uint32_t) (orb_list[pos] + 1)) - TREXIO_ORBITAL_SHIFT; + const uint32_t iorb = ((uint32_t) (orb_list[pos] + 1)) - TREXIO_ORBITAL_SHIFT; // Set the bit of to one - i = (uint32_t) (iorb >> TREXIO_NORB_PER_INT_SHIFT); - k = (uint32_t) (iorb & (TREXIO_NORB_PER_INT - 1) ); - mask = ((bitfield_t) 1) << k; + const uint32_t i = (uint32_t) (iorb >> TREXIO_NORB_PER_INT_SHIFT); + const uint32_t k = (uint32_t) (iorb & (TREXIO_NORB_PER_INT - 1) ); + bitfield_t mask = ((bitfield_t) 1) << k; bit_list[i] |= mask; // Check for phase changes @@ -5658,21 +5993,16 @@ trexio_exit_code trexio_to_orbital_list(const int32_t N_int, if (list == NULL) return TREXIO_INVALID_ARG_3; if (occupied_num == NULL) return TREXIO_INVALID_ARG_4; - bitfield_t tmp; - int32_t shift; - int32_t k; - int32_t pos; - - k = 0; - shift = TREXIO_ORBITAL_SHIFT; + int32_t k = 0; + int32_t shift = TREXIO_ORBITAL_SHIFT; for (int32_t i=0 ; i= grid_size[shell_index]) + return 0; // NAOs vanish at the boundary by definition + + double t = r_log - (double) i_log; + double val_spline = interpolator[i0 + 4*i_log + 0]; + val_spline += t * interpolator[i0 + 4*i_log + 1]; + val_spline += t * t * interpolator[i0 + 4*i_log + 2]; + val_spline += t * t * t * interpolator[i0 + 4*i_log + 3]; + + *amplitude = val_spline * normalization[shell_index] / r; + return TREXIO_SUCCESS; +} + +trexio_exit_code +trexio_evaluate_nao_radial_all (const int32_t shell_num, const int32_t* const nucleus_index, const double* const nucleus_coords, const int32_t* const grid_start, + const int32_t* const grid_size, const double* const grid_r, const double* const interpolator, + const double* const normalization, const double rx, const double ry, const double rz, double* const amplitude) +{ + if (shell_num < 0) return TREXIO_INVALID_ARG_1; + if (nucleus_index == 0) return TREXIO_INVALID_ARG_2; + if (nucleus_coords == 0) return TREXIO_INVALID_ARG_3; + if (grid_start == 0) return TREXIO_INVALID_ARG_4; + if (grid_size == 0) return TREXIO_INVALID_ARG_5; + if (grid_r == NULL) return TREXIO_INVALID_ARG_6; + if (interpolator == 0) return TREXIO_INVALID_ARG_7; + if (normalization == 0) return TREXIO_INVALID_ARG_8; + + trexio_exit_code rc; + + for (int shell_index = 0; shell_index < shell_num; shell_index++) { + const int32_t nuc_index = nucleus_index[shell_index]; + const double dx = nucleus_coords[3*nuc_index + 0] - rx; + const double dy = nucleus_coords[3*nuc_index + 1] - ry; + const double dz = nucleus_coords[3*nuc_index + 2] - rz; + const double r = sqrt(dx*dx + dy*dy + dz*dz); + + // All possibly reported errors have been caught above + rc = trexio_evaluate_nao_radial(shell_index, r, grid_start, + grid_size, grid_r, interpolator, normalization, &litude[shell_index]); + + if (rc != TREXIO_SUCCESS) + return rc; + } + + return TREXIO_SUCCESS; +} + +trexio_exit_code trexio_evaluate_nao_radial_py (const int shell_index, + const double r, int64_t* grid_start, int n_grid_st, + int64_t* grid_size, int n_grid_si, double* grid_r, int n_grid_r, + double* interpolator, int n_interp, double* normalization, int n_norm, double* const amplitude) +{ + // Code needs to be copied because of the use of int64_t mandated by Python + // If a 64-bit version is implemented, this can be avoided + if (shell_index < 0) return TREXIO_INVALID_ARG_1; + if (r < 0) return TREXIO_INVALID_ARG_2; + if (grid_start == 0) return TREXIO_INVALID_ARG_3; + if (grid_size == 0) return TREXIO_INVALID_ARG_4; + if (grid_r == NULL) return TREXIO_INVALID_ARG_5; + if (interpolator == 0) return TREXIO_INVALID_ARG_6; + if (normalization == 0) return TREXIO_INVALID_ARG_7; + + const int32_t i0 = 4*grid_start[shell_index]; + + // Convert radius to logarithmic units + double r_log = 0.0; + trexio_convert_nao_radius_64 (r, grid_r + grid_start[shell_index], &r_log); + int32_t i_log = (int32_t) r_log; + if (i_log < 0) { + *amplitude = interpolator[i0] * normalization[shell_index] / r; + return TREXIO_SUCCESS; + } else if (i_log >= grid_size[shell_index]) { + *amplitude = 0.0; + return TREXIO_SUCCESS; // NAOs vanish at the boundary by definition + } + + double t = r_log - (double) i_log; + double val_spline = interpolator[i0 + 4*i_log + 0]; + val_spline += t * interpolator[i0 + 4*i_log + 1]; + val_spline += t * t * interpolator[i0 + 4*i_log + 2]; + val_spline += t * t * t * interpolator[i0 + 4*i_log + 3]; + + *amplitude = val_spline * normalization[shell_index] / r; + return TREXIO_SUCCESS; +} + +trexio_exit_code trexio_evaluate_nao_radial_all_py (const int32_t shell_num, + int64_t* nucleus_index, int n_nuc_id, double* nucleus_coords, int n_nuc_co, + int64_t* grid_start, int n_grid_st, int64_t* grid_size, int n_grid_si, + double* grid_r, int n_grid_r, double* interpolator, int n_interp, + double* normalization, int n_norm, + const double rx, const double ry, const double rz, double* const amplitudes, int amplitude_cnt) +{ + if (shell_num < 0) return TREXIO_INVALID_ARG_1; + if (nucleus_index == 0) return TREXIO_INVALID_ARG_2; + if (nucleus_coords == 0) return TREXIO_INVALID_ARG_3; + if (grid_start == 0) return TREXIO_INVALID_ARG_4; + if (grid_size == 0) return TREXIO_INVALID_ARG_5; + if (grid_r == NULL) return TREXIO_INVALID_ARG_6; + if (interpolator == 0) return TREXIO_INVALID_ARG_7; + if (normalization == 0) return TREXIO_INVALID_ARG_8; + + trexio_exit_code rc; + + for (int shell_index = 0; shell_index < shell_num; shell_index++) { + const int32_t nuc_index = nucleus_index[shell_index]; + const double dx = nucleus_coords[3*nuc_index + 0] - rx; + const double dy = nucleus_coords[3*nuc_index + 1] - ry; + const double dz = nucleus_coords[3*nuc_index + 2] - rz; + const double r = sqrt(dx*dx + dy*dy + dz*dz); + + // All possibly reported errors have been caught above + rc = trexio_evaluate_nao_radial_py(shell_index, r, grid_start, n_grid_st, + grid_size, n_grid_si, grid_r, n_grid_r, interpolator, n_interp, normalization, n_norm, &litudes[shell_index]); + if (rc != TREXIO_SUCCESS) + return rc; + } + + return TREXIO_SUCCESS; +} + #+end_src + + #+begin_src c :tangle trexio_private.h /* Popcount and trailz */ #if TREXIO_INT_SIZE == 64 @@ -5870,6 +6382,76 @@ interface end interface #+end_src + #+begin_src f90 :tangle prefix_fortran.f90 +interface + integer(trexio_exit_code) function trexio_convert_nao_radius_32(r, grid_r, log_r_out) & + bind(C, name="trexio_convert_nao_radius_32") + use, intrinsic :: iso_c_binding + import + real(c_float), intent(in), value :: r + real(c_float), intent(in) :: grid_r(*) + real(c_float), intent(out) :: log_r_out + end function trexio_convert_nao_radius_32 +end interface + #+end_src + + #+begin_src f90 :tangle prefix_fortran.f90 +interface + integer(trexio_exit_code) function trexio_convert_nao_radius_64(r, grid_r, log_r_out) & + bind(C, name="trexio_convert_nao_radius_64") + use, intrinsic :: iso_c_binding + import + real(c_double), intent(in), value :: r + real(c_double), intent(in) :: grid_r(*) + real(c_double), intent(out) :: log_r_out + end function trexio_convert_nao_radius_64 +end interface + #+end_src + + #+begin_src f90 :tangle prefix_fortran.f90 +interface + integer(trexio_exit_code) function trexio_evaluate_nao_radial (shell_index, r, & + grid_start, grid_size, grid_r, interpolator, normalization, amplitude) & + bind(C, name="trexio_evaluate_nao_radial") + use, intrinsic :: iso_c_binding + import + integer(c_int32_t), intent(in), value :: shell_index + real(c_double), intent(in), value :: r + integer(c_int32_t), intent(in) :: grid_start(*) + integer(c_int32_t), intent(in) :: grid_size(*) + real(c_double), intent(in) :: grid_r(*) + real(c_double), intent(in) :: interpolator(*) + real(c_double), intent(in) :: normalization(*) + real(c_double), intent(out) :: amplitude + end function trexio_evaluate_nao_radial +end interface + #+end_src + + #+begin_src f90 :tangle prefix_fortran.f90 +interface + integer(trexio_exit_code) function trexio_evaluate_nao_radial_all (shell_num, & + nucleus_index, nucleus_coords, & + grid_start, grid_size, grid_r, interpolator, & + normalization, rx, ry, rz, amplitudes) & + bind(C, name="trexio_evaluate_nao_radial_all") + use, intrinsic :: iso_c_binding + import + integer(c_int32_t), intent(in), value :: shell_num + integer(c_int32_t), intent(in) :: nucleus_index(*) + real(c_double), intent(in) :: nucleus_coords(*) + integer(c_int32_t), intent(in) :: grid_start(*) + integer(c_int32_t), intent(in) :: grid_size(*) + real(c_double), intent(in) :: grid_r(*) + real(c_double), intent(in) :: interpolator(*) + real(c_double), intent(in) :: normalization(*) + real(c_double), intent(in), value :: rx + real(c_double), intent(in), value :: ry + real(c_double), intent(in), value :: rz + real(c_double), intent(out) :: amplitudes(*) + end function trexio_evaluate_nao_radial_all +end interface + #+end_src + ** Python #+begin_src python :tangle basic_python.py @@ -5970,6 +6552,99 @@ def to_orbital_list_up_dn(n_int: int, determinant: list) -> tuple: return (orbital_list_up[0:occ_num_up], orbital_list_dn[0:occ_num_dn]) #+end_src + #+begin_src python :tangle basic_python.py +def convert_nao_radius(r: float, grid_r) -> float: + """Converts the radius r as a distance from a nucleus to the shell + s logarithmic grid. + + Input: + ~r~ - the radius to be converted + ~grid_r~ - The radial grid of the shell. Note that this is only the + grid of the shell of interest, not the array of all shells. + + Returns: + Float that gives the radius in the shell's logarithmic units + + 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, r_log = pytr.trexio_convert_nao_radius_py(r, grid_r) + + if rc != TREXIO_SUCCESS: + raise Error(rc) + + return r_log + +def evaluate_nao_radial(shell_index, r, grid_start, grid_size, grid_r, interpolator, normalization) -> float: + """Evaluates the radial function of a given NAO shell at a distance from its center. + + Input: + ~shell_index~ - index of the shell of interest + ~r~ - distance from the shell center + ~grid_start~ - array of starting points of the individual splines + ~grid_size~ - array of number of data points per spline + ~grid_r~ - The radial grid of the shell. Note that this is only the + grid of the shell of interest, not the array of all shells. + ~interpolator~ - Interpolator of the spline. It is assumed to contain a cubic spline. + An interpolator for a kinetic energy spline can also be passed. + ~normalization~ - array of radial function normalization constants. + + Returns: + Value of the spline at the given radius + + Raises: + - Error from AssertionError if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message using trexio_string_of_error. + - Error from some other error (e.g. RuntimeError). + + """ + rc, amplitude = pytr.trexio_evaluate_nao_radial_py(shell_index, r, grid_start, grid_size, grid_r, interpolator.flatten(), normalization) + + if rc != TREXIO_SUCCESS: + raise Error(rc) + + return amplitude + +def evaluate_nao_radial_all(nucleus_index, nucleus_coords, grid_start, + grid_size, grid_r, interpolator, normalization, r) -> float: + """Evaluates the radial functions of all NAO shells at a given position in space. + + Input: + ~nucleus_index~ - array giving the centers of the NAO + ~nucleus_coords~ - array giving the coordinates of the NAO centers + ~grid_start~ - array of starting points of the individual splines + ~grid_size~ - array of number of data points per spline + ~grid_r~ - The radial grid of the shell. Note that this is only the + grid of the shell of interest, not the array of all shells. + ~interpolator~ - Interpolator of the spline. It is assumed to contain a cubic spline. + An interpolator for a kinetic energy spline can also be passed. + ~normalization~ - array of radial function normalization constants. + ~r~ - the position in space at which the functions are evaluated + + Returns: + Array of spline values at ~r~ + + Raises: + - Error if ~r~ is not three dimensional + - Error from AssertionError if TREXIO return code ~rc~ is different from TREXIO_SUCCESS and prints the error message using trexio_string_of_error. + - Error from some other error (e.g. RuntimeError). + + """ + if len(r) != 3: + raise Error(TREXIO_INVALID_ARG7) + shell_cnt = len(nucleus_index) + rc, amplitudes = pytr.trexio_evaluate_nao_radial_all_py(shell_cnt, \ + nucleus_index, nucleus_coords.flatten(), grid_start, grid_size, grid_r, \ + interpolator.flatten(), normalization, r[0], r[1], r[2], shell_cnt) + + if rc != TREXIO_SUCCESS: + raise Error(rc) + + return amplitudes + #+end_src + * Permutations of indices For sparse data structures, there may be values that are the same @@ -6166,7 +6841,6 @@ const int32_t* trexio_4_index_4_perm_anti() { return &(trexio_4_index_4_perm_ant #+end_src :end: - * Fortran helper/wrapper functions The function below adapts the original C-based ~trexio_open~ for Fortran. @@ -6394,6 +7068,11 @@ contains * File suffixes :noexport: #+begin_src c :tangle suffix_front.h + +#ifdef __cplusplus +} +#endif + #endif #+end_src diff --git a/src/templates_hdf5/build.sh b/src/templates_hdf5/build.sh index 88a70a5..ca8894a 100644 --- a/src/templates_hdf5/build.sh +++ b/src/templates_hdf5/build.sh @@ -18,4 +18,5 @@ 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.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 a695d6a..bdfa9bc 100644 --- a/src/templates_hdf5/templator_hdf5.org +++ b/src/templates_hdf5/templator_hdf5.org @@ -38,15 +38,23 @@ #include #include +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif +# +#ifdef HAVE_HDF5 #include "hdf5.h" -#include "hdf5_hl.h" #+end_src #+begin_src c :tangle prefix_hdf5.c :noweb yes <
> #include "trexio_hdf5.h" - +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif +# +#ifdef HAVE_HDF5 #+end_src * Template for HDF5 definitions @@ -380,18 +388,21 @@ trexio_hdf5_read_$group_dset$ (trexio_t* const file, $group_dset_dtype$* const $ } FREE(ddims); + + /* Read dataset */ + herr_t status = H5Dread(dset_id, + H5T_$GROUP_DSET_H5_DTYPE$, + H5S_ALL, H5S_ALL, H5P_DEFAULT, + $group_dset$); + H5Sclose(dspace_id); H5Dclose(dset_id); - /* High-level H5LT API. No need to deal with dataspaces and datatypes */ - herr_t status = H5LTread_dataset(f->$group$_group, - $GROUP_DSET$_NAME, - H5T_$GROUP_DSET_H5_DTYPE$, - $group_dset$); if (status < 0) return TREXIO_FAILURE; return TREXIO_SUCCESS; } + #+end_src #+begin_src c :tangle write_dset_data_hdf5.c @@ -411,7 +422,8 @@ trexio_hdf5_write_$group_dset$ (trexio_t* const file, const $group_dset_dtype$* Consider using HDF5-native h5repack utility after deleting/overwriting big datasets. ,*/ - if (H5LTfind_dataset(f->$group$_group, $GROUP_DSET$_NAME) == 1 && file->mode == 'u') { + + if ((trexio_hdf5_has_$group_dset$(file) == TREXIO_SUCCESS) && (file->mode == 'u')) { herr_t status_del = H5Ldelete(f->$group$_group, $GROUP_DSET$_NAME, H5P_DEFAULT); if (status_del < 0) return TREXIO_FAILURE; } @@ -454,14 +466,13 @@ trexio_hdf5_has_$group_dset$ (trexio_t* const file) 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 */ - if (status == 1){ + htri_t exists = H5Lexists(f->$group$_group, $GROUP_DSET$_NAME, H5P_DEFAULT); + if (exists > 0) { return TREXIO_SUCCESS; - } else if (status == 0) { - return TREXIO_HAS_NOT; - } else { + } else if (exists < 0) { return TREXIO_FAILURE; + } else { + return TREXIO_HAS_NOT; } } @@ -495,7 +506,8 @@ trexio_hdf5_write_$group_dset$ (trexio_t* const file, trexio_hdf5_t* f = (trexio_hdf5_t*) file; hid_t index_dtype; - void* index_p = NULL; + const void* index_p = NULL; + void* index_p_non_const = 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) { @@ -505,6 +517,7 @@ trexio_hdf5_write_$group_dset$ (trexio_t* const file, index[i] = (uint8_t) index_sparse[i]; } index_p = index; + index_p_non_const = index; index_dtype = H5T_NATIVE_UINT8; } else if (size_max < UINT16_MAX) { uint16_t* index = CALLOC(size_ranked, uint16_t); @@ -513,9 +526,10 @@ trexio_hdf5_write_$group_dset$ (trexio_t* const file, index[i] = (uint16_t) index_sparse[i]; } index_p = index; + index_p_non_const = index; index_dtype = H5T_NATIVE_UINT16; } else { - index_p = (int32_t*) index_sparse; + index_p = index_sparse; index_dtype = H5T_NATIVE_INT32; } @@ -534,12 +548,12 @@ trexio_hdf5_write_$group_dset$ (trexio_t* const file, 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_index_name) != 1 ) { + if (trexio_hdf5_has_$group_dset$(file) == TREXIO_HAS_NOT) { /* If the file does not exist -> create it and write */ /* Create chunked dataset with index_dtype datatype and write indices into it */ rc_write = trexio_hdf5_create_write_dset_sparse(f->$group$_group, dset_index_name, index_dtype, chunk_i_dims, index_p); - if (index_p != index_sparse) FREE(index_p); + if (index_p != index_sparse) FREE(index_p_non_const); if (rc_write != TREXIO_SUCCESS) return rc_write; /* Create chunked dataset with value_dtype datatype and write values into it */ @@ -553,7 +567,7 @@ trexio_hdf5_write_$group_dset$ (trexio_t* const file, /* Create chunked dataset with index_dtype datatype and write indices into it */ rc_write = trexio_hdf5_open_write_dset_sparse(f->$group$_group, dset_index_name, index_dtype, chunk_i_dims, offset_i, index_p); - if (index_p != index_sparse) FREE(index_p); + if (index_p != index_sparse) FREE(index_p_non_const); if (rc_write != TREXIO_SUCCESS) return rc_write; /* Create chunked dataset with value_dtype datatype and write values into it */ @@ -657,14 +671,13 @@ trexio_hdf5_has_$group_dset$ (trexio_t* const file) 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 */ - if (status == 1){ + htri_t exists = H5Lexists(f->$group$_group, $GROUP_DSET$_NAME "_values", H5P_DEFAULT); + if (exists > 0) { return TREXIO_SUCCESS; - } else if (status == 0) { - return TREXIO_HAS_NOT; - } else { + } else if (exists < 0) { return TREXIO_FAILURE; + } else { + return TREXIO_HAS_NOT; } } @@ -693,7 +706,7 @@ trexio_exit_code trexio_hdf5_read_$group_dset$(trexio_t* const file, 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 char* dset_name = "$group_dset$"; const trexio_hdf5_t* f = (const trexio_hdf5_t*) file; @@ -717,7 +730,7 @@ trexio_exit_code trexio_hdf5_write_$group_dset$(trexio_t* const file, if (file == NULL) return TREXIO_INVALID_ARG_1; if (dset == NULL) return TREXIO_INVALID_ARG_5; - const char dset_name[256] = "$group_dset$"; + const char* dset_name = "$group_dset$"; trexio_hdf5_t* f = (trexio_hdf5_t*) file; @@ -728,7 +741,7 @@ trexio_exit_code trexio_hdf5_write_$group_dset$(trexio_t* const file, 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 (trexio_hdf5_has_$group_dset$(file) == TREXIO_HAS_NOT) { /* If the file does not exist -> create it and write */ /* Create chunked dataset with dtype datatype and write indices into it */ @@ -755,7 +768,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 char dset_name[256] = "$group_dset$"; + const char* dset_name = "$group_dset$"; const trexio_hdf5_t* f = (const trexio_hdf5_t*) file; @@ -791,16 +804,15 @@ trexio_exit_code trexio_hdf5_has_$group_dset$(trexio_t* const file) 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$"; + const char* dset_name = "$group_dset$"; - herr_t status = H5LTfind_dataset(f->$group$_group, dset_name); - /* H5LTfind_dataset returns 1 if dataset exists, 0 otherwise */ - if (status == 1){ + htri_t exists = H5Lexists(f->$group$_group, dset_name, H5P_DEFAULT); + if (exists > 0) { return TREXIO_SUCCESS; - } else if (status == 0) { - return TREXIO_HAS_NOT; - } else { + } else if (exists < 0) { return TREXIO_FAILURE; + } else { + return TREXIO_HAS_NOT; } } #+end_src @@ -936,7 +948,7 @@ trexio_hdf5_write_$group_dset$ (trexio_t* const file, const char** $group_dset$, Consider using HDF5-provided h5repack utility after deleting/overwriting big datasets. ,*/ - if (H5LTfind_dataset(f->$group$_group, $GROUP_DSET$_NAME) == 1 && file->mode == 'u') { + if ( (trexio_hdf5_has_$group_dset$(file) == TREXIO_SUCCESS) && (file->mode == 'u') ) { herr_t status_del = H5Ldelete(f->$group$_group, $GROUP_DSET$_NAME, H5P_DEFAULT); if (status_del < 0) return TREXIO_FAILURE; } @@ -991,14 +1003,13 @@ trexio_hdf5_has_$group_dset$ (trexio_t* const file) 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 */ - if (status == 1){ + htri_t exists = H5Lexists(f->$group$_group, $GROUP_DSET$_NAME, H5P_DEFAULT); + if (exists > 0) { return TREXIO_SUCCESS; - } else if (status == 0) { - return TREXIO_HAS_NOT; - } else { + } else if (exists < 0) { return TREXIO_FAILURE; + } else { + return TREXIO_HAS_NOT; } } @@ -1231,7 +1242,7 @@ trexio_exit_code trexio_hdf5_write_determinant_list(trexio_t* const file, 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 ( trexio_hdf5_has_determinant_list(file) == TREXIO_HAS_NOT ) { /* If the file does not exist -> create it and write */ /* Create chunked dataset with det_dtype datatype and write indices into it */ @@ -1260,14 +1271,13 @@ trexio_exit_code trexio_hdf5_has_determinant_list(trexio_t* const file) 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){ + htri_t exists = H5Lexists(f->determinant_group, "determinant_list", H5P_DEFAULT); + if (exists > 0) { return TREXIO_SUCCESS; - } else if (status == 0) { - return TREXIO_HAS_NOT; - } else { + } else if (exists < 0) { return TREXIO_FAILURE; + } else { + return TREXIO_HAS_NOT; } } #+end_src @@ -1467,8 +1477,6 @@ trexio_hdf5_open_read_dset_sparse (const hid_t group_id, uint16_t* index = CALLOC(size_ranked, uint16_t); if (index == NULL) return TREXIO_ALLOCATION_FAILED; index_p = index; - } else { - index_p = data_sparse; } } @@ -1476,7 +1484,7 @@ trexio_hdf5_open_read_dset_sparse (const hid_t group_id, if (status < 0) { H5Sclose(fspace_id); H5Dclose(dset_id); - if (index_p != data_sparse) FREE(index_p); + if (index_p != NULL) FREE(index_p); return TREXIO_INVALID_ID; } @@ -1484,15 +1492,22 @@ trexio_hdf5_open_read_dset_sparse (const hid_t group_id, if (memspace_id < 0) { H5Sclose(fspace_id); H5Dclose(dset_id); - if (index_p != data_sparse) FREE(index_p); + if (index_p != NULL) FREE(index_p); return TREXIO_INVALID_ID; } if (is_index == 1) { - status = H5Dread(dset_id, - dtype, - memspace_id, fspace_id, H5P_DEFAULT, - index_p); + if (index_p != NULL) { + status = H5Dread(dset_id, + dtype, + memspace_id, fspace_id, H5P_DEFAULT, + index_p); + } else { + status = H5Dread(dset_id, + dtype, + memspace_id, fspace_id, H5P_DEFAULT, + data_sparse); + } } else { status = H5Dread(dset_id, dtype, @@ -1504,7 +1519,7 @@ trexio_hdf5_open_read_dset_sparse (const hid_t group_id, H5Sclose(memspace_id); H5Dclose(dset_id); if (status < 0) { - if (index_p != data_sparse) FREE(index_p); + if (index_p != NULL) FREE(index_p); return TREXIO_FAILURE; } @@ -1537,5 +1552,10 @@ trexio_exit_code trexio_hdf5_create_write_dset_sparse (const hid_t group_id, con 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 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 +#endif + #+end_src + + #+begin_src c :tangle suffix_hdf5.c :noweb yes #endif #+end_src diff --git a/src/templates_text/templator_text.org b/src/templates_text/templator_text.org index 9ed7858..39874fe 100644 --- a/src/templates_text/templator_text.org +++ b/src/templates_text/templator_text.org @@ -145,10 +145,10 @@ trexio_text_inquire (const char* file_name) if (file_exists) { bool is_a_directory = false; -#ifdef S_IFDIR +#if defined(S_IFDIR) is_a_directory = st.st_mode & S_IFDIR; -#elif S_ISDIR - is_a_directory = S_ISDIR(s.st_mode); +#elif defined(S_ISDIR) + is_a_directory = S_ISDIR(st.st_mode); #else printf("Some important macros are missing for directory handling.\n"); return TREXIO_FAILURE; @@ -162,6 +162,33 @@ trexio_text_inquire (const char* file_name) } #+end_src +On non-POSIX file systems, the function ~mkdtemp~ might is not defined. +In that case, we define an alternate one, which is not as safe as the original one. + + #+begin_src c :tangle basic_text.c +#if /* Since glibc 2.19: */ _DEFAULT_SOURCE \ + || /* Glibc 2.19 and earlier: */ _BSD_SOURCE \ + || /* Since glibc 2.10: */ _POSIX_C_SOURCE >= 200809L + +/* mkdtemp is defined */ +#else + +char* mkdtemp(char* template) { + char* dir = NULL; + dir = tmpnam(dir); + if (dir == NULL) return NULL; + + if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) != 0) { + return NULL; + } + + strcpy(template, dir); + return template; +} + +#endif + #+end_src + #+begin_src c :tangle basic_text.c trexio_exit_code trexio_text_init (trexio_t* const file) diff --git a/tests/delete_group.c b/tests/delete_group.c new file mode 100644 index 0000000..8836fe1 --- /dev/null +++ b/tests/delete_group.c @@ -0,0 +1,85 @@ +#include "trexio.h" +#include +#include +#include + +static int test_write_delete_group (const char* file_name, const back_end_t backend) { + +/* Try to write a dimensioning attribute (num variable) into the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be written + int num = 12; + double coord[36] = { + 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 , + }; + +/*================= START OF TEST ==================*/ + + // open file in 'write' mode + file = trexio_open(file_name, 'w', backend, &rc); + assert (file != NULL); + + // write numerical attribute in an empty file + rc = trexio_write_nucleus_num(file, num); + assert (rc == TREXIO_SUCCESS); + + // write numerical dataset in a file + rc = trexio_write_nucleus_coord(file, coord); + assert (rc == TREXIO_SUCCESS); + + // write numerical attribute ao_cartesian as 0 + rc = trexio_write_ao_cartesian(file, 0); + assert (rc == TREXIO_SUCCESS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + + // open file in 'unsafe' mode + file = trexio_open(file_name, 'u', backend, &rc); + assert (file != NULL); + + // delete a previously written group + rc = trexio_delete_nucleus(file); + assert (rc == TREXIO_SUCCESS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + + +/*================= END OF TEST ==================*/ + + return 0; +} + + +int main(void) { + +/*============== Test launcher ================*/ + + int rc; + rc = system(RM_COMMAND); + assert (rc == 0); + + test_write_delete_group (TREXIO_FILE, TEST_BACKEND); + + rc = system(RM_COMMAND); + assert (rc == 0); + + return 0; +} diff --git a/tests/delete_group_hdf5.c b/tests/delete_group_hdf5.c index 151a73a..db03b5e 100644 --- a/tests/delete_group_hdf5.c +++ b/tests/delete_group_hdf5.c @@ -1,89 +1,4 @@ -#include "trexio.h" -#include -#include -#include - -#define TEST_BACKEND TREXIO_HDF5 -#define TREXIO_FILE "test_del.h5" -#define RM_COMMAND "rm -f -- " TREXIO_FILE - -static int test_write_delete_group (const char* file_name, const back_end_t backend) { - -/* Try to write a dimensioning attribute (num variable) into the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 12; - double coord[36] = { - 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 , - }; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write numerical attribute in an empty file - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_SUCCESS); - - // write numerical dataset in a file - rc = trexio_write_nucleus_coord(file, coord); - assert (rc == TREXIO_SUCCESS); - - // write numerical attribute ao_cartesian as 0 - rc = trexio_write_ao_cartesian(file, 0); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - - // open file in 'unsafe' mode - file = trexio_open(file_name, 'u', backend, &rc); - assert (file != NULL); - - // delete a previously written group - rc = trexio_delete_nucleus(file); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(void) { - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - test_write_delete_group (TREXIO_FILE, TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} +#define TEST_BACKEND_TEXT +#define TREXIO_FILE_PREFIX "delete_group" +#include "test_macros.h" +#include "delete_group.c" diff --git a/tests/delete_group_text.c b/tests/delete_group_text.c index 37f338b..db03b5e 100644 --- a/tests/delete_group_text.c +++ b/tests/delete_group_text.c @@ -1,89 +1,4 @@ -#include "trexio.h" -#include -#include -#include - -#define TEST_BACKEND TREXIO_TEXT -#define TREXIO_FILE "test_del.dir" -#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) { - -/* Try to write a dimensioning attribute (num variable) into the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 12; - double coord[36] = { - 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 , - }; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write numerical attribute in an empty file - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_SUCCESS); - - // write numerical dataset in a file - rc = trexio_write_nucleus_coord(file, coord); - assert (rc == TREXIO_SUCCESS); - - // write numerical attribute ao_cartesian as 0 - rc = trexio_write_ao_cartesian(file, 0); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - - // open file in 'unsafe' mode - file = trexio_open(file_name, 'u', backend, &rc); - assert (file != NULL); - - // delete a previously written group - rc = trexio_delete_nucleus(file); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(void) { - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - test_write_delete_group (TREXIO_FILE, TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} +#define TEST_BACKEND_TEXT +#define TREXIO_FILE_PREFIX "delete_group" +#include "test_macros.h" +#include "delete_group.c" diff --git a/tests/io_determinant.c b/tests/io_determinant.c new file mode 100644 index 0000000..bd861d2 --- /dev/null +++ b/tests/io_determinant.c @@ -0,0 +1,322 @@ +#include "trexio.h" +#include +#include +#include +#include + +#define SIZE 100 +#define N_CHUNKS 5 +#define STATE_TEST 2 + +static int test_write_determinant (const char* file_name, const back_end_t backend, const int64_t offset, const int mo_num) { + +/* 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; + + // 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)); + + int64_t size_list = TREXIO_NORB_PER_INT * int_num; + const int32_t orb_list_up[4] = {0,1,2,3}; + const int32_t orb_list_dn[3] = {0,1,2}; + + + 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_HDF5 +#define TREXIO_FILE_PREFIX "io_determinant" +#include "test_macros.h" +#include "io_determinant.c" -#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_TEXT +#define TREXIO_FILE_PREFIX "io_determinant" +#include "test_macros.h" +#include "io_determinant.c" -#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 +#include +#include + +static int test_write_dset (const char* file_name, const back_end_t backend) { + +/* Try to write a dataset with numerical (floating point) values into the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be written + int num = 12; + double coord[36] = { + 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 , + }; + +/*================= START OF TEST ==================*/ + + // open file in 'write' mode + file = trexio_open(file_name, 'w', backend, &rc); + if (rc != TREXIO_SUCCESS) { + printf("%s\n", trexio_string_of_error(rc)); + } + assert (rc == TREXIO_SUCCESS); + assert (file != NULL); + + // write numerical attribute in an empty file + rc = trexio_write_nucleus_num(file, num); + assert (rc == TREXIO_SUCCESS); + + // write numerical dataset in a file + rc = trexio_write_nucleus_coord(file, coord); + assert (rc == TREXIO_SUCCESS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_has_dset (const char* file_name, const back_end_t backend) { + +/* Try to check the existence of a dataset in the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + +/*================= START OF TEST ==================*/ + + // open file in 'read' mode + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + + // check that the previously written dataset exists + rc = trexio_has_nucleus_coord(file); + assert (rc == TREXIO_SUCCESS); + + // check that another dataset does not exist + rc = trexio_has_mo_coefficient(file); + assert (rc == TREXIO_HAS_NOT); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_read_dset (const char* file_name, const back_end_t backend) { + +/* Try to read a dataset with numerical (floating point) values from the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be read + int num; + double* coord; + +/*================= START OF TEST ==================*/ + + // open file in 'read' mode + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + + // read numerical attribute from the file + rc = trexio_read_nucleus_num(file, &num); + assert (rc == TREXIO_SUCCESS); + assert (num == 12); + + // read numerical (floating point) dataset from the file + coord = (double*) calloc(3*num, sizeof(double)); + rc = trexio_read_nucleus_coord(file, coord); + assert (rc == TREXIO_SUCCESS); + + double x = coord[30] - 2.14171677; + assert( x*x < 1.e-14 ); + free(coord); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +int main(void) { + +/*============== Test launcher ================*/ + + int rc; + rc = system(RM_COMMAND); + assert (rc == 0); + + test_write_dset (TREXIO_FILE, TEST_BACKEND); + test_has_dset (TREXIO_FILE, TEST_BACKEND); + test_read_dset (TREXIO_FILE, TEST_BACKEND); + + rc = system(RM_COMMAND); + assert (rc == 0); + + return 0; +} diff --git a/tests/io_dset_float_hdf5.c b/tests/io_dset_float_hdf5.c index 90174cd..61dd761 100644 --- a/tests/io_dset_float_hdf5.c +++ b/tests/io_dset_float_hdf5.c @@ -1,148 +1,4 @@ -#include "trexio.h" -#include -#include -#include - -#define TEST_BACKEND TREXIO_HDF5 -#define TREXIO_FILE "test_dset_f.h5" -#define RM_COMMAND "rm -rf " TREXIO_FILE - -static int test_write_dset (const char* file_name, const back_end_t backend) { - -/* Try to write a dataset with numerical (floating point) values into the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 12; - double coord[36] = { - 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 , - }; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write numerical attribute in an empty file - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_SUCCESS); - - // write numerical dataset in a file - rc = trexio_write_nucleus_coord(file, coord); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_has_dset (const char* file_name, const back_end_t backend) { - -/* Try to check the existence of a dataset in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // check that the previously written dataset exists - rc = trexio_has_nucleus_coord(file); - assert (rc == TREXIO_SUCCESS); - - // check that another dataset does not exist - rc = trexio_has_mo_coefficient(file); - assert (rc == TREXIO_HAS_NOT); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_read_dset (const char* file_name, const back_end_t backend) { - -/* Try to read a dataset with numerical (floating point) values from the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be read - int num; - double* coord; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // read numerical attribute from the file - rc = trexio_read_nucleus_num(file, &num); - assert (rc == TREXIO_SUCCESS); - assert (num == 12); - - // read numerical (floating point) dataset from the file - coord = (double*) calloc(3*num, sizeof(double)); - rc = trexio_read_nucleus_coord(file, coord); - assert (rc == TREXIO_SUCCESS); - - double x = coord[30] - 2.14171677; - assert( x*x < 1.e-14 ); - free(coord); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(void) { - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - test_write_dset (TREXIO_FILE, TEST_BACKEND); - test_has_dset (TREXIO_FILE, TEST_BACKEND); - test_read_dset (TREXIO_FILE, TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} - - +#define TEST_BACKEND_HDF5 +#define TREXIO_FILE_PREFIX "io_dset_float" +#include "test_macros.h" +#include "io_dset_float.c" diff --git a/tests/io_dset_float_text.c b/tests/io_dset_float_text.c index 3d31185..8e34a13 100644 --- a/tests/io_dset_float_text.c +++ b/tests/io_dset_float_text.c @@ -1,146 +1,4 @@ -#include "trexio.h" -#include -#include -#include - -#define TEST_BACKEND TREXIO_TEXT -#define TREXIO_FILE "test_dset_f.dir" -#define RM_COMMAND "rm -f -- " TREXIO_FILE "/*.txt " TREXIO_FILE "/*.txt.size " TREXIO_FILE "/.lock && rm -fd -- " TREXIO_FILE - -static int test_write_dset (const char* file_name, const back_end_t backend) { - -/* Try to write a dataset with numerical (floating point) values into the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 12; - double coord[36] = { - 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 , - }; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write numerical attribute in an empty file - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_SUCCESS); - - // write numerical dataset in a file - rc = trexio_write_nucleus_coord(file, coord); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_has_dset (const char* file_name, const back_end_t backend) { - -/* Try to check the existence of a dataset in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // check that the previously written dataset exists - rc = trexio_has_nucleus_coord(file); - assert (rc == TREXIO_SUCCESS); - - // check that another dataset does not exist - rc = trexio_has_mo_coefficient(file); - assert (rc == TREXIO_HAS_NOT); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_read_dset (const char* file_name, const back_end_t backend) { - -/* Try to read a dataset with numerical (floating point) values from the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be read - int num; - double* coord; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // read numerical attribute from the file - rc = trexio_read_nucleus_num(file, &num); - assert (rc == TREXIO_SUCCESS); - assert (num == 12); - - // read numerical (floating point) dataset from the file - coord = (double*) calloc(3*num, sizeof(double)); - rc = trexio_read_nucleus_coord(file, coord); - assert (rc == TREXIO_SUCCESS); - - double x = coord[30] - 2.14171677; - assert( x*x < 1.e-14 ); - free(coord); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(void) { - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - test_write_dset (TREXIO_FILE, TEST_BACKEND); - test_has_dset (TREXIO_FILE, TEST_BACKEND); - test_read_dset (TREXIO_FILE, TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} +#define TEST_BACKEND_TEXT +#define TREXIO_FILE_PREFIX "io_dset_float" +#include "test_macros.h" +#include "io_dset_float.c" diff --git a/tests/io_dset_int.c b/tests/io_dset_int.c new file mode 100644 index 0000000..137da06 --- /dev/null +++ b/tests/io_dset_int.c @@ -0,0 +1,147 @@ +#include "trexio.h" +#include +#include +#include + +static int test_write_dset (const char* file_name, const back_end_t backend) { + +/* Try to write a dataset with numerical (int) values into the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be written + int num = 12; + int nucl_index[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + int state_id = 2; + +/*================= START OF TEST ==================*/ + + // open file in 'write' mode + file = trexio_open(file_name, 'w', backend, &rc); + assert (file != NULL); + + // write numerical attribute in an empty file + rc = trexio_write_basis_shell_num(file, num); + assert (rc == TREXIO_SUCCESS); + + // write numerical (integer) dataset in a file + rc = trexio_write_basis_nucleus_index(file, nucl_index); + assert (rc == TREXIO_SUCCESS); + + // write index attribute in a file + rc = trexio_write_state_id(file, state_id); + assert (rc == TREXIO_SUCCESS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_has_dset (const char* file_name, const back_end_t backend) { + +/* Try to check the existence of a dataset in the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + +/*================= START OF TEST ==================*/ + + // open file + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + + // check that the group exists + rc = trexio_has_basis(file); + assert(rc==TREXIO_SUCCESS); + + // check that the group does not exist + rc = trexio_has_mo(file); + assert(rc==TREXIO_HAS_NOT); + + // check that the previously written dataset exists + rc = trexio_has_basis_nucleus_index(file); + assert (rc == TREXIO_SUCCESS); + + // check that another dataset does not exist + rc = trexio_has_mo_coefficient(file); + assert (rc == TREXIO_HAS_NOT); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_read_dset (const char* file_name, const back_end_t backend) { + +/* Try to read a dataset with numericali (int) values from the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be read + int num = 0; + int* nucl_index = NULL; + int state_id = 0; + +/*================= START OF TEST ==================*/ + + // open file in 'read' mode + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + + // read numerical attribute from the file + rc = trexio_read_basis_shell_num(file, &num); + assert (rc == TREXIO_SUCCESS); + assert (num == 12); + + // read index attribute from the file + rc = trexio_read_state_id(file, &state_id); + assert (rc == TREXIO_SUCCESS); + assert (state_id == 2); + + // read numerical dataset from the file + nucl_index = (int*) calloc(num, sizeof(int)); + rc = trexio_read_basis_nucleus_index(file, nucl_index); + assert (rc == TREXIO_SUCCESS); + assert (nucl_index[num-1] == num-1); + + free(nucl_index); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +int main(void) { + +/*============== Test launcher ================*/ + + int rc; + rc = system(RM_COMMAND); + assert (rc == 0); + + test_write_dset (TREXIO_FILE, TEST_BACKEND); + test_has_dset (TREXIO_FILE, TEST_BACKEND); + test_read_dset (TREXIO_FILE, TEST_BACKEND); + + rc = system(RM_COMMAND); + assert (rc == 0); + + return 0; +} diff --git a/tests/io_dset_int_hdf5.c b/tests/io_dset_int_hdf5.c index 42db22b..6ecd731 100644 --- a/tests/io_dset_int_hdf5.c +++ b/tests/io_dset_int_hdf5.c @@ -1,140 +1,4 @@ -#include "trexio.h" -#include -#include -#include - -#define TEST_BACKEND TREXIO_HDF5 -#define TREXIO_FILE "test_dset_i.h5" -#define RM_COMMAND "rm -rf " TREXIO_FILE - -static int test_write_dset (const char* file_name, const back_end_t backend) { - -/* Try to write a dataset with numerical (int) values into the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 12; - int nucl_index[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write numerical attribute in an empty file - rc = trexio_write_basis_shell_num(file, num); - assert (rc == TREXIO_SUCCESS); - - // write numerical (integer) dataset in a file - rc = trexio_write_basis_nucleus_index(file, nucl_index); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_has_dset (const char* file_name, const back_end_t backend) { - -/* Try to check the existence of a dataset in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // check that the group exists - rc = trexio_has_basis(file); - assert(rc==TREXIO_SUCCESS); - - // check that the group does not exist - rc = trexio_has_mo(file); - assert(rc==TREXIO_HAS_NOT); - - // check that the previously written dataset exists - rc = trexio_has_basis_nucleus_index(file); - assert (rc == TREXIO_SUCCESS); - - // check that another dataset does not exist - rc = trexio_has_mo_coefficient(file); - assert (rc == TREXIO_HAS_NOT); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_read_dset (const char* file_name, const back_end_t backend) { - -/* Try to read a dataset with numericali (int) values from the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be read - int num; - int* nucl_index; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // read numerical attribute from the file - rc = trexio_read_basis_shell_num(file, &num); - assert (rc == TREXIO_SUCCESS); - assert (num == 12); - - // read numerical dataset from the file - nucl_index = (int*) calloc(num, sizeof(int)); - rc = trexio_read_basis_nucleus_index(file, nucl_index); - assert (rc == TREXIO_SUCCESS); - assert (nucl_index[num-1] == num-1); - - free(nucl_index); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(void) { - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - test_write_dset (TREXIO_FILE, TEST_BACKEND); - test_has_dset (TREXIO_FILE, TEST_BACKEND); - test_read_dset (TREXIO_FILE, TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} +#define TEST_BACKEND_HDF5 +#define TREXIO_FILE_PREFIX "io_dset_int" +#include "test_macros.h" +#include "io_dset_int.c" diff --git a/tests/io_dset_int_text.c b/tests/io_dset_int_text.c index c1f5a1e..3237d3e 100644 --- a/tests/io_dset_int_text.c +++ b/tests/io_dset_int_text.c @@ -1,140 +1,4 @@ -#include "trexio.h" -#include -#include -#include - -#define TEST_BACKEND TREXIO_TEXT -#define TREXIO_FILE "test_dset_i.dir" -#define RM_COMMAND "rm -f -- " TREXIO_FILE "/*.txt " TREXIO_FILE "/*.txt.size " TREXIO_FILE "/.lock && rm -fd -- " TREXIO_FILE - -static int test_write_dset (const char* file_name, const back_end_t backend) { - -/* Try to write a dataset with numerical (int) values into the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 12; - int nucl_index[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write numerical attribute in an empty file - rc = trexio_write_basis_shell_num(file, num); - assert (rc == TREXIO_SUCCESS); - - // write numerical (integer) dataset in a file - rc = trexio_write_basis_nucleus_index(file, nucl_index); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_has_dset (const char* file_name, const back_end_t backend) { - -/* Try to check the existence of a dataset in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // check that the group exists - rc = trexio_has_basis(file); - assert(rc==TREXIO_SUCCESS); - - // check that the group does not exist - rc = trexio_has_mo(file); - assert(rc==TREXIO_HAS_NOT); - - // check that the previously written dataset exists - rc = trexio_has_basis_nucleus_index(file); - assert (rc == TREXIO_SUCCESS); - - // check that another dataset does not exist - rc = trexio_has_mo_coefficient(file); - assert (rc == TREXIO_HAS_NOT); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_read_dset (const char* file_name, const back_end_t backend) { - -/* Try to read a dataset with numericali (int) values from the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be read - int num; - int* nucl_index; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // read numerical attribute from the file - rc = trexio_read_basis_shell_num(file, &num); - assert (rc == TREXIO_SUCCESS); - assert (num == 12); - - // read numerical dataset from the file - nucl_index = (int*) calloc(num, sizeof(int)); - rc = trexio_read_basis_nucleus_index(file, nucl_index); - assert (rc == TREXIO_SUCCESS); - assert (nucl_index[num-1] == num-1); - - free(nucl_index); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(void) { - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - test_write_dset (TREXIO_FILE, TEST_BACKEND); - test_has_dset (TREXIO_FILE, TEST_BACKEND); - test_read_dset (TREXIO_FILE, TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} +#define TEST_BACKEND_TEXT +#define TREXIO_FILE_PREFIX "io_dset_int" +#include "test_macros.h" +#include "io_dset_int.c" diff --git a/tests/io_dset_sparse.c b/tests/io_dset_sparse.c new file mode 100644 index 0000000..4b19672 --- /dev/null +++ b/tests/io_dset_sparse.c @@ -0,0 +1,268 @@ +#include "trexio.h" +#include +#include +#include +#include + +#define N_CHUNKS 4 + +static int test_write_dset_sparse (const char* file_name, const back_end_t backend, const int64_t offset, const int64_t mo_num) { + +/* 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 + int32_t* index; + double* value; + int64_t size = mo_num/2; + + index = calloc(4L*size, sizeof(int32_t)); + value = calloc(size, sizeof(double)); + + for(int i=0; i 0 ? chunk_size : (uint64_t) size; + int n_chunks = size/chunk_size; + printf("chunk_size = %ld\n", (long) chunk_size); + printf("n_chunks = %d\n", n_chunks); + + uint64_t offset_f = 0UL + offset; + uint64_t offset_d = 0UL; + + // write n_chunks times using write_sparse + while(offset_d < size) { + if (offset_d+chunk_size > size) chunk_size = size-offset_d; + printf("chunk_size = %ld\n", (long) chunk_size); + if (chunk_size == 0L) break; + rc = trexio_write_mo_2e_int_eri(file, offset_f, chunk_size, &index[4*offset_d], &value[offset_d]); + printf("%5d: %s\n", __LINE__, trexio_string_of_error(rc)); + assert(rc == TREXIO_SUCCESS); + offset_d += chunk_size; + offset_f += chunk_size; + } + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + + // free the allocated memeory + free(index); + free(value); + +/*================= END OF TEST ==================*/ + + return 0; +} + +static int test_has_dset_sparse (const char* file_name, const back_end_t backend) { + +/* Try to check the existence of a dataset of sparse data in the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + +/*================= START OF TEST ==================*/ + + // open file + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + assert (rc == TREXIO_SUCCESS); + + // check that the group exists + rc = trexio_has_mo_2e_int(file); + assert(rc==TREXIO_SUCCESS); + + // check that the group does not exist + rc = trexio_has_rdm(file); + assert(rc==TREXIO_HAS_NOT); + + // first check that mo_2e_int_eri_lr (we only write non-lr component in this unit test) + rc = trexio_has_mo_2e_int_eri_lr(file); + assert(rc==TREXIO_HAS_NOT); + + // check that previous call to has_sparse did not create a file/dset + rc = trexio_has_mo_2e_int_eri_lr(file); + assert(rc==TREXIO_HAS_NOT); + + // now check that previously written mo_2e_int_eri exists + rc = trexio_has_mo_2e_int_eri(file); + assert(rc==TREXIO_SUCCESS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + +static int test_read_dset_sparse (const char* file_name, const back_end_t backend, const int64_t offset) { + +/* Try to read one chunk of dataset of sparse data in the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + +/*================= START OF TEST ==================*/ + + // open file + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + assert (rc == TREXIO_SUCCESS); + + int32_t mo_num = 0; + rc = trexio_read_mo_num(file, &mo_num); + assert(rc == TREXIO_SUCCESS); + printf("%5d: mo_num = %d\n", __LINE__, mo_num); + const int64_t size = mo_num/2; + + // define arrays to read into + int32_t* index_read; + double* value_read; + uint64_t size_r = mo_num; + + index_read = (int32_t*) calloc(4L*size_r,sizeof(int32_t)); + value_read = (double*) calloc(size_r,sizeof(double)); + + // specify the read parameters, here: + // 1 chunk of 10 elements using offset of 40 (i.e. lines No. 40--59) into elements of the array starting from 5 + int64_t chunk_read = size/3; + chunk_read = chunk_read < 2 ? 2 : chunk_read; + int64_t offset_file_read = 1; + int64_t read_size_check; + read_size_check = chunk_read; + + if (offset != 0L) offset_file_read += offset; + + // read one chunk using the aforementioned parameters + rc = trexio_read_mo_2e_int_eri(file, offset_file_read, &chunk_read, &index_read[0], &value_read[0]); + printf("%5d: %s\n", __LINE__, trexio_string_of_error(rc)); +/* + for (int i=0 ; i size_max) + int64_t size_max; + rc = trexio_read_mo_2e_int_eri_size(file, &size_max); + assert(rc == TREXIO_SUCCESS); + offset_file_read = size_max-chunk_read+1; + int64_t eof_read_size_check = size_max - offset_file_read; // if offset_file_read=97 => only 3 integrals will be read out of total of 100 + + + // read one chunk that will reach EOF and return TREXIO_END code + rc = trexio_read_mo_2e_int_eri(file, offset_file_read, &chunk_read, &index_read[0], &value_read[0]); + printf("%5d: %s\n", __LINE__, trexio_string_of_error(rc)); + assert(rc == TREXIO_END); + printf("%d %d x\n", (int32_t) index_read[0], (int32_t) (4L*offset_file_read)); + printf("%ld %ld\n", (long) chunk_read, (long) eof_read_size_check); + assert(chunk_read == eof_read_size_check); + printf("%d %d\n", index_read[0] , (int32_t) (offset_file_read - offset)); + assert(index_read[0] == (int32_t) offset_file_read - offset); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + + // free the memory + free(index_read); + free(value_read); + +/*================= END OF TEST ==================*/ + + return 0; +} + +static int test_read_dset_sparse_size (const char* file_name, const back_end_t backend, const int64_t size_check) { + +/* Try to read a size of the dataset of sparse data in the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + +/*================= START OF TEST ==================*/ + + // open file + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + assert (rc == TREXIO_SUCCESS); + + // define the variable to read into + int64_t size_written; + + // read one chunk using the aforementioned parameters + rc = trexio_read_mo_2e_int_eri_size(file, &size_written); + assert(rc == TREXIO_SUCCESS); + printf("%5d: %ld %ld\n", __LINE__, (long) size_written, (long) size_check); + assert(size_written == size_check); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + +int main(){ + +/*============== Test launcher ================*/ + + int rc; + rc = system(RM_COMMAND); + assert (rc == 0); + + int32_t mo_num[8] = {6,12,30,62,252,510,1020,9000}; + + for (int i=0 ; i<8 ; ++i) { + + printf("%5d: mo_num = %d\n", __LINE__, mo_num[i]); + const int64_t size = mo_num[i]/2; + // check the first write attempt (SIZE elements written in N_CHUNKS chunks) + test_write_dset_sparse (TREXIO_FILE, TEST_BACKEND, 0, mo_num[i]); + test_has_dset_sparse (TREXIO_FILE, TEST_BACKEND); + test_read_dset_sparse (TREXIO_FILE, TEST_BACKEND, 0); + test_read_dset_sparse_size(TREXIO_FILE, TEST_BACKEND, size); + + // check the second write attempt (SIZE elements written in N_CHUNKS chunks) + test_write_dset_sparse (TREXIO_FILE, TEST_BACKEND, size, mo_num[i]); + test_read_dset_sparse (TREXIO_FILE, TEST_BACKEND, size); + test_read_dset_sparse_size(TREXIO_FILE, TEST_BACKEND, 2*size); + + rc = system(RM_COMMAND); + assert (rc == 0); + + } + + return 0; +} diff --git a/tests/io_dset_sparse_hdf5.c b/tests/io_dset_sparse_hdf5.c index 7e57ec6..ec691bc 100644 --- a/tests/io_dset_sparse_hdf5.c +++ b/tests/io_dset_sparse_hdf5.c @@ -1,238 +1,4 @@ -#include "trexio.h" -#include -#include -#include -#include - -#define TEST_BACKEND TREXIO_HDF5 -#define TREXIO_FILE "test_dset_sparse.h5" -#define RM_COMMAND "rm -f -- " TREXIO_FILE -#define SIZE 100 -#define N_CHUNKS 5 - -static int test_write_dset_sparse (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 - int32_t* index; - double* value; - - index = calloc(4L*SIZE, sizeof(int32_t)); - value = 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; - - // read one chunk that will reach EOF and return TREXIO_END code - rc = trexio_read_mo_2e_int_eri(file, offset_file_read, &chunk_read, &index_read[4*offset_data_read], &value_read[offset_data_read]); - assert(rc == TREXIO_END); - 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)); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - - // free the memory - free(index_read); - free(value_read); - -/*================= END OF TEST ==================*/ - - return 0; -} - -static int test_read_dset_sparse_size (const char* file_name, const back_end_t backend, const int64_t size_check) { - -/* Try to read a size of the dataset of sparse data in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - assert (rc == TREXIO_SUCCESS); - - // define the variable to read into - int64_t size_written; - - // read one chunk using the aforementioned parameters - rc = trexio_read_mo_2e_int_eri_size(file, &size_written); - assert(rc == TREXIO_SUCCESS); - assert(size_written == size_check); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - -int main(){ - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - // check the first write attempt (SIZE elements written in N_CHUNKS chunks) - test_write_dset_sparse (TREXIO_FILE, TEST_BACKEND, 0); - test_has_dset_sparse (TREXIO_FILE, TEST_BACKEND); - test_read_dset_sparse (TREXIO_FILE, TEST_BACKEND, 0); - test_read_dset_sparse_size(TREXIO_FILE, TEST_BACKEND, SIZE); - - // check the second write attempt (SIZE elements written in N_CHUNKS chunks) - test_write_dset_sparse (TREXIO_FILE, TEST_BACKEND, SIZE); - test_read_dset_sparse (TREXIO_FILE, TEST_BACKEND, SIZE); - test_read_dset_sparse_size(TREXIO_FILE, TEST_BACKEND, SIZE*2); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} +#define TEST_BACKEND_HDF5 +#define TREXIO_FILE_PREFIX "io_dset_sparse" +#include "test_macros.h" +#include "io_dset_sparse.c" diff --git a/tests/io_dset_sparse_text.c b/tests/io_dset_sparse_text.c index caddb9a..4215f96 100644 --- a/tests/io_dset_sparse_text.c +++ b/tests/io_dset_sparse_text.c @@ -1,238 +1,4 @@ -#include "trexio.h" -#include -#include -#include -#include - -#define TEST_BACKEND TREXIO_TEXT -#define TREXIO_FILE "test_dset_sparse.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 - -static int test_write_dset_sparse (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 - int32_t* index; - double* value; - - index = calloc(4L*SIZE, sizeof(int32_t)); - value = 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; - - // read one chunk that will reach EOF and return TREXIO_END code - rc = trexio_read_mo_2e_int_eri(file, offset_file_read, &chunk_read, &index_read[4*offset_data_read], &value_read[offset_data_read]); - assert(rc == TREXIO_END); - 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)); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - - // free the memory - free(index_read); - free(value_read); - -/*================= END OF TEST ==================*/ - - return 0; -} - -static int test_read_dset_sparse_size (const char* file_name, const back_end_t backend, const int64_t size_check) { - -/* Try to read a size of the dataset of sparse data in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - assert (rc == TREXIO_SUCCESS); - - // define the variable to read into - int64_t size_written; - - // read one chunk using the aforementioned parameters - rc = trexio_read_mo_2e_int_eri_size(file, &size_written); - assert(rc == TREXIO_SUCCESS); - assert(size_written == size_check); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - -int main(){ - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - // check the first write attempt (SIZE elements written in N_CHUNKS chunks) - test_write_dset_sparse (TREXIO_FILE, TEST_BACKEND, 0); - test_has_dset_sparse (TREXIO_FILE, TEST_BACKEND); - test_read_dset_sparse (TREXIO_FILE, TEST_BACKEND, 0); - test_read_dset_sparse_size(TREXIO_FILE, TEST_BACKEND, SIZE); - - // check the second write attempt (SIZE elements written in N_CHUNKS chunks) - test_write_dset_sparse (TREXIO_FILE, TEST_BACKEND, SIZE); - test_read_dset_sparse (TREXIO_FILE, TEST_BACKEND, SIZE); - test_read_dset_sparse_size(TREXIO_FILE, TEST_BACKEND, SIZE*2); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} +#define TEST_BACKEND_TEXT +#define TREXIO_FILE_PREFIX "io_dset_sparse" +#include "test_macros.h" +#include "io_dset_sparse.c" diff --git a/tests/io_dset_str.c b/tests/io_dset_str.c new file mode 100644 index 0000000..90735b5 --- /dev/null +++ b/tests/io_dset_str.c @@ -0,0 +1,153 @@ +#include "trexio.h" +#include +#include +#include +#include + +static int test_write_dset_str (const char* file_name, const back_end_t backend) { + +/* Try to write an array of strings into the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be written + int num = 12; + const char* labels[] = {"C" , + "Na FAKE" , + "C" , + "C" , + "C" , + "C" , + "H" , + "H" , + "H" , + "H" , + "H" , + "H FAKE" }; + +/*================= START OF TEST ==================*/ + + // open file in 'write' mode + file = trexio_open(file_name, 'w', backend, &rc); + assert (file != NULL); + + // write numerical attribute in an empty file + rc = trexio_write_nucleus_num(file, num); + assert (rc == TREXIO_SUCCESS); + + // write dataset of string in the file (including FAKE statements) + int max_str_len = 16; + rc = trexio_write_nucleus_label(file, labels, max_str_len); + assert (rc == TREXIO_SUCCESS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_has_dset_str (const char* file_name, const back_end_t backend) { + +/* Try to check the existence of a dataset of strings in the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + +/*================= START OF TEST ==================*/ + + // open file + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + + // check that the previously written dataset of strings exists + rc = trexio_has_nucleus_label(file); + assert (rc == TREXIO_SUCCESS); + + // check that the dataset of strings does not exist + rc = trexio_has_mo_symmetry(file); + assert (rc == TREXIO_HAS_NOT); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_read_dset_str (const char* file_name, const back_end_t backend) { + +/* Try to read a dataset with strings from the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be read + int num; + char** labels; + +/*================= START OF TEST ==================*/ + + // open file in 'read' mode + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + + // read numerical attribute from the file + rc = trexio_read_nucleus_num(file, &num); + assert (rc == TREXIO_SUCCESS); + assert (num == 12); + + // read the arrays of strings truncated to max_str_len=2 symbols + int max_str_len = 2; + + labels = (char**) malloc(num*sizeof(char*)); + for (int i=0; i -#include -#include -#include - -#define TEST_BACKEND TREXIO_HDF5 -#define TREXIO_FILE "test_dset_s.h5" -#define RM_COMMAND "rm -rf " TREXIO_FILE - -static int test_write_dset_str (const char* file_name, const back_end_t backend) { - -/* Try to write an array of strings into the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 12; - const char* labels[] = {"C" , - "Na FAKE" , - "C" , - "C" , - "C" , - "C" , - "H" , - "H" , - "H" , - "H" , - "H" , - "H FAKE" }; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write numerical attribute in an empty file - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_SUCCESS); - - // write dataset of string in the file (including FAKE statements) - int max_str_len = 16; - rc = trexio_write_nucleus_label(file, labels, max_str_len); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_has_dset_str (const char* file_name, const back_end_t backend) { - -/* Try to check the existence of a dataset of strings in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // check that the previously written dataset of strings exists - rc = trexio_has_nucleus_label(file); - assert (rc == TREXIO_SUCCESS); - - // check that the dataset of strings does not exist - rc = trexio_has_mo_symmetry(file); - assert (rc == TREXIO_HAS_NOT); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_read_dset_str (const char* file_name, const back_end_t backend) { - -/* Try to read a dataset with strings from the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be read - int num; - char** labels; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // read numerical attribute from the file - rc = trexio_read_nucleus_num(file, &num); - assert (rc == TREXIO_SUCCESS); - assert (num == 12); - - // read the arrays of strings truncated to max_str_len=2 symbols - int max_str_len = 2; - - labels = (char**) malloc(num*sizeof(char*)); - for (int i=0; i -#include -#include -#include - -#define TEST_BACKEND TREXIO_TEXT -#define TREXIO_FILE "test_dset_s.dir" -#define RM_COMMAND "rm -f -- " TREXIO_FILE "/*.txt " TREXIO_FILE "/*.txt.size " TREXIO_FILE "/.lock && rm -fd -- " TREXIO_FILE - -static int test_write_dset_str (const char* file_name, const back_end_t backend) { - -/* Try to write an array of strings into the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 12; - const char* labels[] = {"C" , - "Na FAKE" , - "C" , - "C" , - "C" , - "C" , - "H" , - "H" , - "H" , - "H" , - "H" , - "H FAKE" }; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write numerical attribute in an empty file - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_SUCCESS); - - // write dataset of string in the file (including FAKE statements) - int max_str_len = 16; - rc = trexio_write_nucleus_label(file, labels, max_str_len); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_has_dset_str (const char* file_name, const back_end_t backend) { - -/* Try to check the existence of a dataset of strings in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // check that the previously written dataset of strings exists - rc = trexio_has_nucleus_label(file); - assert (rc == TREXIO_SUCCESS); - - // check that the dataset of strings does not exist - rc = trexio_has_mo_symmetry(file); - assert (rc == TREXIO_HAS_NOT); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_read_dset_str (const char* file_name, const back_end_t backend) { - -/* Try to read a dataset with strings from the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be read - int num; - char **labels; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // read numerical attribute from the file - rc = trexio_read_nucleus_num(file, &num); - assert (rc == TREXIO_SUCCESS); - assert (num == 12); - - // read the arrays of strings truncated to max_str_len=2 symbols - int max_str_len = 2; - - labels = (char**) malloc(num*sizeof(char*)); - for (int i=0; i +#include +#include +#include +#include + +static int test_write_jastrow (const char* file_name, const back_end_t backend) { + +/* 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); + +#define nucleus_num 3 +#define ee_num 2 +#define en_num 3 +#define een_num 6 + + rc = trexio_write_nucleus_num(file, nucleus_num); + assert (rc == TREXIO_SUCCESS); + + rc = trexio_write_jastrow_type(file, "CHAMP", 6); + assert (rc == TREXIO_SUCCESS); + + rc = trexio_write_jastrow_ee_num(file, ee_num); + assert (rc == TREXIO_SUCCESS); + + rc = trexio_write_jastrow_en_num(file, en_num); + assert (rc == TREXIO_SUCCESS); + + rc = trexio_write_jastrow_een_num(file, een_num); + assert (rc == TREXIO_SUCCESS); + + double ee [2] = { 0.5, 2. }; + rc = trexio_write_jastrow_ee(file, ee); + assert (rc == TREXIO_SUCCESS); + + double en [3] = { 1., 2., 3. }; + rc = trexio_write_jastrow_en(file, en); + assert (rc == TREXIO_SUCCESS); + + double een [6] = { 11., 12., 13., 14., 15., 16. }; + rc = trexio_write_jastrow_een(file, een); + assert (rc == TREXIO_SUCCESS); + + int en_nucleus [3] = { 0, 1, 2 }; + rc = trexio_write_jastrow_en_nucleus(file, en_nucleus); + assert (rc == TREXIO_SUCCESS); + + int een_nucleus [6] = { 0, 0, 1, 1, 2, 2 }; + rc = trexio_write_jastrow_een_nucleus(file, een_nucleus); + assert (rc == TREXIO_SUCCESS); + + double ee_scaling = 1.0; + rc = trexio_write_jastrow_ee_scaling(file, ee_scaling); + assert (rc == TREXIO_SUCCESS); + + double en_scaling[3] = { 0.5, 1.0, 0.5 }; + rc = trexio_write_jastrow_en_scaling(file, en_scaling); + assert (rc == TREXIO_SUCCESS); + +#undef nucleus_num +#undef ee_num +#undef en_num +#undef een_num + + rc = trexio_close(file); +/*================= END OF TEST ==================*/ + + return 0; +} + +static int test_read_jastrow (const char* file_name, const back_end_t backend) { + +/* Try to read one chunk of dataset of sparse data in the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + +/*================= START OF TEST ==================*/ + + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + assert (rc == TREXIO_SUCCESS); + + int nucleus_num = 0; + rc = trexio_read_nucleus_num(file, &nucleus_num); + assert (rc == TREXIO_SUCCESS); + assert (nucleus_num == 3); + + char type[16] = ""; + rc = trexio_read_jastrow_type(file, type, 16); + assert (rc == TREXIO_SUCCESS); + assert (strcmp("CHAMP",type) == 0); + + int ee_num = 0; + rc = trexio_read_jastrow_ee_num(file, &ee_num); + assert (rc == TREXIO_SUCCESS); + assert (ee_num == 2); + + int en_num = 0; + rc = trexio_read_jastrow_en_num(file, &en_num); + assert (rc == TREXIO_SUCCESS); + assert (en_num == nucleus_num); + + int een_num = 0; + rc = trexio_read_jastrow_een_num(file, &een_num); + assert (rc == TREXIO_SUCCESS); + assert (een_num == 2*nucleus_num); + + double ee [2] = { 0., 0. }; + rc = trexio_read_jastrow_ee(file, ee); + assert (rc == TREXIO_SUCCESS); + assert (ee[0] == 0.5); + assert (ee[1] == 2.0); + + double en [3] = { 0., 0., 0. }; + rc = trexio_read_jastrow_en(file, en); + assert (rc == TREXIO_SUCCESS); + assert (en[0] == 1.0); + assert (en[1] == 2.0); + assert (en[2] == 3.0); + + double een [6]; + rc = trexio_read_jastrow_een(file, een); + assert (rc == TREXIO_SUCCESS); + assert (een[0] == 11.0); + assert (een[1] == 12.0); + assert (een[2] == 13.0); + assert (een[3] == 14.0); + assert (een[4] == 15.0); + assert (een[5] == 16.0); + + int en_nucleus [3] = { 0, 0, 0 }; + rc = trexio_read_jastrow_en_nucleus(file, en_nucleus); + assert (rc == TREXIO_SUCCESS); + assert (en_nucleus[0] == 0); + assert (en_nucleus[1] == 1); + assert (en_nucleus[2] == 2); + + int een_nucleus [6] = { 0, 0, 0, 0, 0, 0 }; + rc = trexio_read_jastrow_een_nucleus(file, een_nucleus); + assert (rc == TREXIO_SUCCESS); + assert (een_nucleus[0] == 0); + assert (een_nucleus[1] == 0); + assert (een_nucleus[2] == 1); + assert (een_nucleus[3] == 1); + assert (een_nucleus[4] == 2); + assert (een_nucleus[5] == 2); + + double ee_scaling = 0.0; + rc = trexio_read_jastrow_ee_scaling(file, &ee_scaling); + assert (rc == TREXIO_SUCCESS); + assert (ee_scaling == 1.0); + + double en_scaling[3] = { 0.5, 1.0, 0.5 }; + rc = trexio_read_jastrow_en_scaling(file, en_scaling); + assert (rc == TREXIO_SUCCESS); + assert (en_scaling[0] == 0.5); + assert (en_scaling[1] == 1.0); + assert (en_scaling[2] == 0.5); + + rc = trexio_close(file); +/*================= END OF TEST ==================*/ + + return 0; +} + + +int main(){ + +/*============== Test launcher ================*/ + + int rc; + + rc = system(RM_COMMAND); + assert (rc == 0); + + test_write_jastrow (TREXIO_FILE, TEST_BACKEND); + test_read_jastrow (TREXIO_FILE, TEST_BACKEND); + + rc = system(RM_COMMAND); + assert (rc == 0); + + return 0; +} diff --git a/tests/io_jastrow_hdf5.c b/tests/io_jastrow_hdf5.c index 4dfb9a0..8804096 100644 --- a/tests/io_jastrow_hdf5.c +++ b/tests/io_jastrow_hdf5.c @@ -1,198 +1,5 @@ -#include "trexio.h" -#include -#include -#include -#include -#include +#define TEST_BACKEND_HDF5 +#define TREXIO_FILE_PREFIX "io_jastrow" +#include "test_macros.h" +#include "io_jastrow.c" -#define TEST_BACKEND TREXIO_HDF5 -#define TREXIO_FILE "test_jastrow.h5" -#define RM_COMMAND "rm -f -- " TREXIO_FILE - -static int test_write_jastrow (const char* file_name, const back_end_t backend) { - -/* 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); - -#define nucleus_num 3 -#define ee_num 2 -#define en_num 3 -#define een_num 6 - - rc = trexio_write_nucleus_num(file, nucleus_num); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_jastrow_type(file, "CHAMP", 6); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_jastrow_ee_num(file, ee_num); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_jastrow_en_num(file, en_num); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_jastrow_een_num(file, een_num); - assert (rc == TREXIO_SUCCESS); - - double ee [2] = { 0.5, 2. }; - rc = trexio_write_jastrow_ee(file, ee); - assert (rc == TREXIO_SUCCESS); - - double en [3] = { 1., 2., 3. }; - rc = trexio_write_jastrow_en(file, en); - assert (rc == TREXIO_SUCCESS); - - double een [6] = { 11., 12., 13., 14., 15., 16. }; - rc = trexio_write_jastrow_een(file, een); - assert (rc == TREXIO_SUCCESS); - - int en_nucleus [3] = { 0, 1, 2 }; - rc = trexio_write_jastrow_en_nucleus(file, en_nucleus); - assert (rc == TREXIO_SUCCESS); - - int een_nucleus [6] = { 0, 0, 1, 1, 2, 2 }; - rc = trexio_write_jastrow_een_nucleus(file, een_nucleus); - assert (rc == TREXIO_SUCCESS); - - double ee_scaling = 1.0; - rc = trexio_write_jastrow_ee_scaling(file, ee_scaling); - assert (rc == TREXIO_SUCCESS); - - double en_scaling[3] = { 0.5, 1.0, 0.5 }; - rc = trexio_write_jastrow_en_scaling(file, en_scaling); - assert (rc == TREXIO_SUCCESS); - -#undef nucleus_num -#undef ee_num -#undef en_num -#undef een_num - - rc = trexio_close(file); -/*================= END OF TEST ==================*/ - - return 0; -} - -static int test_read_jastrow (const char* file_name, const back_end_t backend) { - -/* Try to read one chunk of dataset of sparse data in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - assert (rc == TREXIO_SUCCESS); - - int nucleus_num = 0; - rc = trexio_read_nucleus_num(file, &nucleus_num); - assert (rc == TREXIO_SUCCESS); - assert (nucleus_num == 3); - - char type[16] = ""; - rc = trexio_read_jastrow_type(file, type, 16); - assert (rc == TREXIO_SUCCESS); - assert (strcmp("CHAMP",type) == 0); - - int ee_num = 0; - rc = trexio_read_jastrow_ee_num(file, &ee_num); - assert (rc == TREXIO_SUCCESS); - assert (ee_num == 2); - - int en_num = 0; - rc = trexio_read_jastrow_en_num(file, &en_num); - assert (rc == TREXIO_SUCCESS); - assert (en_num == nucleus_num); - - int een_num = 0; - rc = trexio_read_jastrow_een_num(file, &een_num); - assert (rc == TREXIO_SUCCESS); - assert (een_num == 2*nucleus_num); - - double ee [2] = { 0., 0. }; - rc = trexio_read_jastrow_ee(file, ee); - assert (rc == TREXIO_SUCCESS); - assert (ee[0] == 0.5); - assert (ee[1] == 2.0); - - double en [3] = { 0., 0., 0. }; - rc = trexio_read_jastrow_en(file, en); - assert (rc == TREXIO_SUCCESS); - assert (en[0] == 1.0); - assert (en[1] == 2.0); - assert (en[2] == 3.0); - - double een [6]; - rc = trexio_read_jastrow_een(file, een); - assert (rc == TREXIO_SUCCESS); - assert (een[0] == 11.0); - assert (een[1] == 12.0); - assert (een[2] == 13.0); - assert (een[3] == 14.0); - assert (een[4] == 15.0); - assert (een[5] == 16.0); - - int en_nucleus [3] = { 0, 0, 0 }; - rc = trexio_read_jastrow_en_nucleus(file, en_nucleus); - assert (rc == TREXIO_SUCCESS); - assert (en_nucleus[0] == 0); - assert (en_nucleus[1] == 1); - assert (en_nucleus[2] == 2); - - int een_nucleus [6] = { 0, 0, 0, 0, 0, 0 }; - rc = trexio_read_jastrow_een_nucleus(file, een_nucleus); - assert (rc == TREXIO_SUCCESS); - assert (een_nucleus[0] == 0); - assert (een_nucleus[1] == 0); - assert (een_nucleus[2] == 1); - assert (een_nucleus[3] == 1); - assert (een_nucleus[4] == 2); - assert (een_nucleus[5] == 2); - - double ee_scaling = 0.0; - rc = trexio_read_jastrow_ee_scaling(file, &ee_scaling); - assert (rc == TREXIO_SUCCESS); - assert (ee_scaling == 1.0); - - double en_scaling[3] = { 0.5, 1.0, 0.5 }; - rc = trexio_read_jastrow_en_scaling(file, en_scaling); - assert (rc == TREXIO_SUCCESS); - assert (en_scaling[0] == 0.5); - assert (en_scaling[1] == 1.0); - assert (en_scaling[2] == 0.5); - - rc = trexio_close(file); -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(){ - -/*============== Test launcher ================*/ - - int rc; - - rc = system(RM_COMMAND); - assert (rc == 0); - - test_write_jastrow (TREXIO_FILE, TEST_BACKEND); - test_read_jastrow (TREXIO_FILE, TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} diff --git a/tests/io_jastrow_text.c b/tests/io_jastrow_text.c index 80c81ea..40f4b08 100644 --- a/tests/io_jastrow_text.c +++ b/tests/io_jastrow_text.c @@ -1,198 +1,5 @@ -#include "trexio.h" -#include -#include -#include -#include -#include +#define TEST_BACKEND_TEXT +#define TREXIO_FILE_PREFIX "io_jastrow" +#include "test_macros.h" +#include "io_jastrow.c" -#define TEST_BACKEND TREXIO_TEXT -#define TREXIO_FILE "test_jastrow.dir" -#define RM_COMMAND "rm -f -- " TREXIO_FILE "/*.txt " TREXIO_FILE "/*.txt.size " TREXIO_FILE "/.lock && rm -fd -- " TREXIO_FILE - -static int test_write_jastrow (const char* file_name, const back_end_t backend) { - -/* 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); - -#define nucleus_num 3 -#define ee_num 2 -#define en_num 3 -#define een_num 6 - - rc = trexio_write_nucleus_num(file, nucleus_num); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_jastrow_type(file, "CHAMP", 6); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_jastrow_ee_num(file, ee_num); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_jastrow_en_num(file, en_num); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_jastrow_een_num(file, een_num); - assert (rc == TREXIO_SUCCESS); - - double ee [2] = { 0.5, 2. }; - rc = trexio_write_jastrow_ee(file, ee); - assert (rc == TREXIO_SUCCESS); - - double en [3] = { 1., 2., 3. }; - rc = trexio_write_jastrow_en(file, en); - assert (rc == TREXIO_SUCCESS); - - double een [6] = { 11., 12., 13., 14., 15., 16. }; - rc = trexio_write_jastrow_een(file, een); - assert (rc == TREXIO_SUCCESS); - - int en_nucleus [3] = { 0, 1, 2 }; - rc = trexio_write_jastrow_en_nucleus(file, en_nucleus); - assert (rc == TREXIO_SUCCESS); - - int een_nucleus [6] = { 0, 0, 1, 1, 2, 2 }; - rc = trexio_write_jastrow_een_nucleus(file, een_nucleus); - assert (rc == TREXIO_SUCCESS); - - double ee_scaling = 1.0; - rc = trexio_write_jastrow_ee_scaling(file, ee_scaling); - assert (rc == TREXIO_SUCCESS); - - double en_scaling[3] = { 0.5, 1.0, 0.5 }; - rc = trexio_write_jastrow_en_scaling(file, en_scaling); - assert (rc == TREXIO_SUCCESS); - -#undef nucleus_num -#undef ee_num -#undef en_num -#undef een_num - - rc = trexio_close(file); -/*================= END OF TEST ==================*/ - - return 0; -} - -static int test_read_jastrow (const char* file_name, const back_end_t backend) { - -/* Try to read one chunk of dataset of sparse data in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - assert (rc == TREXIO_SUCCESS); - - int nucleus_num = 0; - rc = trexio_read_nucleus_num(file, &nucleus_num); - assert (rc == TREXIO_SUCCESS); - assert (nucleus_num == 3); - - char type[16] = ""; - rc = trexio_read_jastrow_type(file, type, 16); - assert (rc == TREXIO_SUCCESS); - assert (strcmp("CHAMP",type) == 0); - - int ee_num = 0; - rc = trexio_read_jastrow_ee_num(file, &ee_num); - assert (rc == TREXIO_SUCCESS); - assert (ee_num == 2); - - int en_num = 0; - rc = trexio_read_jastrow_en_num(file, &en_num); - assert (rc == TREXIO_SUCCESS); - assert (en_num == nucleus_num); - - int een_num = 0; - rc = trexio_read_jastrow_een_num(file, &een_num); - assert (rc == TREXIO_SUCCESS); - assert (een_num == 2*nucleus_num); - - double ee [2] = { 0., 0. }; - rc = trexio_read_jastrow_ee(file, ee); - assert (rc == TREXIO_SUCCESS); - assert (ee[0] == 0.5); - assert (ee[1] == 2.0); - - double en [3] = { 0., 0., 0. }; - rc = trexio_read_jastrow_en(file, en); - assert (rc == TREXIO_SUCCESS); - assert (en[0] == 1.0); - assert (en[1] == 2.0); - assert (en[2] == 3.0); - - double een [6]; - rc = trexio_read_jastrow_een(file, een); - assert (rc == TREXIO_SUCCESS); - assert (een[0] == 11.0); - assert (een[1] == 12.0); - assert (een[2] == 13.0); - assert (een[3] == 14.0); - assert (een[4] == 15.0); - assert (een[5] == 16.0); - - int en_nucleus [3] = { 0, 0, 0 }; - rc = trexio_read_jastrow_en_nucleus(file, en_nucleus); - assert (rc == TREXIO_SUCCESS); - assert (en_nucleus[0] == 0); - assert (en_nucleus[1] == 1); - assert (en_nucleus[2] == 2); - - int een_nucleus [6] = { 0, 0, 0, 0, 0, 0 }; - rc = trexio_read_jastrow_een_nucleus(file, een_nucleus); - assert (rc == TREXIO_SUCCESS); - assert (een_nucleus[0] == 0); - assert (een_nucleus[1] == 0); - assert (een_nucleus[2] == 1); - assert (een_nucleus[3] == 1); - assert (een_nucleus[4] == 2); - assert (een_nucleus[5] == 2); - - double ee_scaling = 0.0; - rc = trexio_read_jastrow_ee_scaling(file, &ee_scaling); - assert (rc == TREXIO_SUCCESS); - assert (ee_scaling == 1.0); - - double en_scaling[3] = { 0.5, 1.0, 0.5 }; - rc = trexio_read_jastrow_en_scaling(file, en_scaling); - assert (rc == TREXIO_SUCCESS); - assert (en_scaling[0] == 0.5); - assert (en_scaling[1] == 1.0); - assert (en_scaling[2] == 0.5); - - rc = trexio_close(file); -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(){ - -/*============== Test launcher ================*/ - - int rc; - - rc = system(RM_COMMAND); - assert (rc == 0); - - test_write_jastrow (TREXIO_FILE, TEST_BACKEND); - test_read_jastrow (TREXIO_FILE, TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} diff --git a/tests/io_num.c b/tests/io_num.c new file mode 100644 index 0000000..fe55f83 --- /dev/null +++ b/tests/io_num.c @@ -0,0 +1,150 @@ +#include "trexio.h" +#include +#include +#include + +static int test_write_num (const char* file_name, const back_end_t backend) { + +/* Try to write a dimensioning attribute (num variable) into the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be written + int num = 12; + +/*================= START OF TEST ==================*/ + + // open file in 'write' mode + file = trexio_open(file_name, 'w', backend, &rc); + assert (file != NULL); + + // write numerical attribute in an empty file + rc = trexio_write_nucleus_num(file, num); + assert (rc == TREXIO_SUCCESS); + + rc = trexio_write_nucleus_repulsion(file, 2.14171677); + assert (rc == TREXIO_SUCCESS); + + // attempt to write 0 as dimensioning variable in an empty file; should FAIL and return TREXIO_INVALID_ARG_2 + rc = trexio_write_mo_num(file, 0); + assert (rc == TREXIO_INVALID_NUM); + + // write numerical attribute ao_cartesian as 0 + rc = trexio_write_ao_cartesian(file, 0); + assert (rc == TREXIO_SUCCESS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_has_num (const char* file_name, const back_end_t backend) { + +/* Try to check the existence of a dimensioning attribute (num variable) in the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + +/*================= START OF TEST ==================*/ + + // open file + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + + // check that the previously written num variable exists + rc = trexio_has_nucleus_num(file); + assert (rc == TREXIO_SUCCESS); + + rc = trexio_has_nucleus_repulsion(file); + assert (rc == TREXIO_SUCCESS); + + // check that the num variable does not exist + rc = trexio_has_mo_num(file); + assert (rc == TREXIO_HAS_NOT); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_read_num (const char* file_name, const back_end_t backend) { + +/* Try to read a dimensioning attribute (num variable) from the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be read + int num; + int cartesian; + float repulsion_32; + double repulsion_64, d; + +/*================= START OF TEST ==================*/ + + // open file in 'read' mode + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + + // read numerical attribute from the file + rc = trexio_read_nucleus_num(file, &num); + assert (rc == TREXIO_SUCCESS); + assert (num == 12); + + rc = trexio_read_nucleus_repulsion_32(file, &repulsion_32); + assert (rc == TREXIO_SUCCESS); + d = repulsion_32 - 2.14171677; + assert( d*d < 1.e-8 ); + + rc = trexio_read_nucleus_repulsion_64(file, &repulsion_64); + assert (rc == TREXIO_SUCCESS); + d = repulsion_64 - 2.14171677; + assert( d*d < 1.e-14 ); + + // read non-existing numerical attribute from the file + rc = trexio_read_mo_num(file, &num); + assert (rc == TREXIO_ATTR_MISSING); + + // read ao_cartesian (zero) value from the file + rc = trexio_read_ao_cartesian(file, &cartesian); + assert (rc == TREXIO_SUCCESS); + assert (cartesian == 0); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +int main(void) { + +/*============== Test launcher ================*/ + + int rc; + rc = system(RM_COMMAND); + assert (rc == 0); + + test_write_num (TREXIO_FILE, TEST_BACKEND); + test_has_num (TREXIO_FILE, TEST_BACKEND); + test_read_num (TREXIO_FILE, TEST_BACKEND); + + rc = system(RM_COMMAND); + assert (rc == 0); + + return 0; +} diff --git a/tests/io_num_hdf5.c b/tests/io_num_hdf5.c index 32de679..6c6f16b 100644 --- a/tests/io_num_hdf5.c +++ b/tests/io_num_hdf5.c @@ -1,154 +1,5 @@ -#include "trexio.h" -#include -#include -#include +#define TEST_BACKEND_HDF5 +#define TREXIO_FILE_PREFIX "io_num" +#include "test_macros.h" +#include "io_num.c" -#define TEST_BACKEND TREXIO_HDF5 -#define TREXIO_FILE "test_num.h5" -#define RM_COMMAND "rm -rf " TREXIO_FILE - -static int test_write_num (const char* file_name, const back_end_t backend) { - -/* Try to write a dimensioning attribute (num variable) into the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 12; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write numerical attribute in an empty file - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_nucleus_repulsion(file, 2.14171677); - assert (rc == TREXIO_SUCCESS); - - // attempt to write 0 as dimensioning variable in an empty file; should FAIL and return TREXIO_INVALID_ARG_2 - rc = trexio_write_mo_num(file, 0); - assert (rc == TREXIO_INVALID_NUM); - - // write numerical attribute ao_cartesian as 0 - rc = trexio_write_ao_cartesian(file, 0); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_has_num (const char* file_name, const back_end_t backend) { - -/* Try to check the existence of a dimensioning attribute (num variable) in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // check that the previously written num variable exists - rc = trexio_has_nucleus_num(file); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_has_nucleus_repulsion(file); - assert (rc == TREXIO_SUCCESS); - - // check that the num variable does not exist - rc = trexio_has_mo_num(file); - assert (rc == TREXIO_HAS_NOT); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_read_num (const char* file_name, const back_end_t backend) { - -/* Try to read a dimensioning attribute (num variable) from the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be read - int num; - int cartesian; - float repulsion_32; - double repulsion_64, d; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // read numerical attribute from the file - rc = trexio_read_nucleus_num(file, &num); - assert (rc == TREXIO_SUCCESS); - assert (num == 12); - - rc = trexio_read_nucleus_repulsion_32(file, &repulsion_32); - assert (rc == TREXIO_SUCCESS); - d = repulsion_32 - 2.14171677; - assert( d*d < 1.e-8 ); - - rc = trexio_read_nucleus_repulsion_64(file, &repulsion_64); - assert (rc == TREXIO_SUCCESS); - d = repulsion_64 - 2.14171677; - assert( d*d < 1.e-14 ); - - // read non-existing numerical attribute from the file - rc = trexio_read_mo_num(file, &num); - assert (rc == TREXIO_ATTR_MISSING); - - // read ao_cartesian (zero) value from the file - rc = trexio_read_ao_cartesian(file, &cartesian); - assert (rc == TREXIO_SUCCESS); - assert (cartesian == 0); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(void) { - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - test_write_num (TREXIO_FILE, TEST_BACKEND); - test_has_num (TREXIO_FILE, TEST_BACKEND); - test_read_num (TREXIO_FILE, TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} diff --git a/tests/io_num_text.c b/tests/io_num_text.c index 94fd488..3102d6d 100644 --- a/tests/io_num_text.c +++ b/tests/io_num_text.c @@ -1,154 +1,5 @@ -#include "trexio.h" -#include -#include -#include +#define TEST_BACKEND_TEXT +#define TREXIO_FILE_PREFIX "io_num" +#include "test_macros.h" +#include "io_num.c" -#define TEST_BACKEND TREXIO_TEXT -#define TREXIO_FILE "test_num.dir" -#define RM_COMMAND "rm -f -- " TREXIO_FILE "/*.txt " TREXIO_FILE "/*.txt.size " TREXIO_FILE "/.lock && rm -fd -- " TREXIO_FILE - -static int test_write_num (const char* file_name, const back_end_t backend) { - -/* Try to write a dimensioning attribute (num variable) into the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 12; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write numerical attribute in an empty file - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_nucleus_repulsion(file, 2.14171677); - assert (rc == TREXIO_SUCCESS); - - // attempt to write 0 as dimensioning variable in an empty file; should FAIL and return TREXIO_INVALID_ARG_2 - rc = trexio_write_mo_num(file, 0); - assert (rc == TREXIO_INVALID_NUM); - - // write numerical attribute ao_cartesian as 0 - rc = trexio_write_ao_cartesian(file, 0); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_has_num (const char* file_name, const back_end_t backend) { - -/* Try to check the existence of a dimensioning attribute (num variable) in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // check that the previously written num variable exists - rc = trexio_has_nucleus_num(file); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_has_nucleus_repulsion(file); - assert (rc == TREXIO_SUCCESS); - - // check that the num variable does not exist - rc = trexio_has_mo_num(file); - assert (rc == TREXIO_HAS_NOT); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_read_num (const char* file_name, const back_end_t backend) { - -/* Try to read a dimensioning attribute (num variable) from the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be read - int num; - int cartesian; - float repulsion_32; - double repulsion_64, d; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // read numerical attribute from the file - rc = trexio_read_nucleus_num(file, &num); - assert (rc == TREXIO_SUCCESS); - assert (num == 12); - - rc = trexio_read_nucleus_repulsion_32(file, &repulsion_32); - assert (rc == TREXIO_SUCCESS); - d = repulsion_32 - 2.14171677; - assert( d*d < 1.e-8 ); - - rc = trexio_read_nucleus_repulsion_64(file, &repulsion_64); - assert (rc == TREXIO_SUCCESS); - d = repulsion_64 - 2.14171677; - assert( d*d < 1.e-14 ); - - // read non-existing numerical attribute from the file - rc = trexio_read_mo_num(file, &num); - assert (rc == TREXIO_ATTR_MISSING); - - // read ao_cartesian (zero) value from the file - rc = trexio_read_ao_cartesian(file, &cartesian); - assert (rc == TREXIO_SUCCESS); - assert (cartesian == 0); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(void) { - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - test_write_num (TREXIO_FILE, TEST_BACKEND); - test_has_num (TREXIO_FILE, TEST_BACKEND); - test_read_num (TREXIO_FILE, TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} diff --git a/tests/io_safe_dset_float.c b/tests/io_safe_dset_float.c new file mode 100644 index 0000000..c4434b9 --- /dev/null +++ b/tests/io_safe_dset_float.c @@ -0,0 +1,161 @@ +#include "trexio.h" +#include +#include +#include +#include + +static int test_write_dset (const char* file_name, const back_end_t backend) { + +/* Try to write a dataset with floating point values into the TREXIO file using safe API */ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be written + int num = 12; + double coord[36] = { + 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 , + }; + +/*================= START OF TEST ==================*/ + + // open file in 'write' mode + file = trexio_open(file_name, 'w', backend, &rc); + assert (file != NULL); + + // write numerical attribute in an empty file + rc = trexio_write_nucleus_num(file, num); + assert (rc == TREXIO_SUCCESS); + + /* write numerical dataset with an unsafe dimension + * this should return TREXIO_UNSAFE_ARRAY_DIM indicating + * that access beyong allocated memory is likely to occur */ + uint64_t dim_unsafe = num * 12; + rc = trexio_write_safe_nucleus_coord(file, coord, dim_unsafe); + assert (rc == TREXIO_UNSAFE_ARRAY_DIM); + + /* write numerical dataset with a safe dimension + * this should return TREXIO_SUCCESS */ + uint64_t dim_safe = num * 3; + rc = trexio_write_safe_nucleus_coord(file, coord, dim_safe); + assert (rc == TREXIO_SUCCESS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_has_dset (const char* file_name, const back_end_t backend) { + +/* Try to check the existence of a dataset in the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + +/*================= START OF TEST ==================*/ + + // open file in 'read' mode + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + + // check that the previously written dataset exists + rc = trexio_has_nucleus_coord(file); + assert (rc == TREXIO_SUCCESS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_read_dset (const char* file_name, const back_end_t backend) { + +/* Try to read a dataset with floating point values from the TREXIO file using safe API */ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be read + int num; + double* coord; + +/*================= START OF TEST ==================*/ + + // open file in 'read' mode + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + + // read numerical attribute from the file + rc = trexio_read_nucleus_num(file, &num); + assert (rc == TREXIO_SUCCESS); + assert (num == 12); + + // read numerical (floating point) dataset from the file + coord = (double*) calloc(3*num, sizeof(double)); + + /* write numerical dataset with an unsafe dimension + * this should return TREXIO_UNSAFE_ARRAY_DIM indicating + * that access beyong allocated memory is likely to occur */ + uint64_t dim_unsafe = num * 12; + rc = trexio_read_safe_nucleus_coord(file, coord, dim_unsafe); + assert (rc == TREXIO_UNSAFE_ARRAY_DIM); + + /* write numerical dataset with a safe dimension + * this should return TREXIO_SUCCESS */ + uint64_t dim_safe = num * 3; + rc = trexio_read_safe_nucleus_coord(file, coord, dim_safe); + assert (rc == TREXIO_SUCCESS); + + double x = coord[30] - 2.14171677; + assert( x*x < 1.e-14 ); + free(coord); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +int main(void) { + +/*============== Test launcher ================*/ + + int rc; + rc = system(RM_COMMAND); + assert (rc == 0); + + test_write_dset (TREXIO_FILE, TEST_BACKEND); + test_has_dset (TREXIO_FILE, TEST_BACKEND); + test_read_dset (TREXIO_FILE, TEST_BACKEND); + + rc = system(RM_COMMAND); + assert (rc == 0); + + return 0; +} + + diff --git a/tests/io_safe_dset_float_hdf5.c b/tests/io_safe_dset_float_hdf5.c index 318ed4a..da8afe1 100644 --- a/tests/io_safe_dset_float_hdf5.c +++ b/tests/io_safe_dset_float_hdf5.c @@ -1,165 +1,5 @@ -#include "trexio.h" -#include -#include -#include -#include - -#define TEST_BACKEND TREXIO_HDF5 -#define TREXIO_FILE "test_safe_dset_f.h5" -#define RM_COMMAND "rm -rf " TREXIO_FILE - -static int test_write_dset (const char* file_name, const back_end_t backend) { - -/* Try to write a dataset with floating point values into the TREXIO file using safe API */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 12; - double coord[36] = { - 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 , - }; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write numerical attribute in an empty file - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_SUCCESS); - - /* write numerical dataset with an unsafe dimension - * this should return TREXIO_UNSAFE_ARRAY_DIM indicating - * that access beyong allocated memory is likely to occur */ - uint64_t dim_unsafe = num * 12; - rc = trexio_write_safe_nucleus_coord(file, coord, dim_unsafe); - assert (rc == TREXIO_UNSAFE_ARRAY_DIM); - - /* write numerical dataset with a safe dimension - * this should return TREXIO_SUCCESS */ - uint64_t dim_safe = num * 3; - rc = trexio_write_safe_nucleus_coord(file, coord, dim_safe); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_has_dset (const char* file_name, const back_end_t backend) { - -/* Try to check the existence of a dataset in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // check that the previously written dataset exists - rc = trexio_has_nucleus_coord(file); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_read_dset (const char* file_name, const back_end_t backend) { - -/* Try to read a dataset with floating point values from the TREXIO file using safe API */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be read - int num; - double* coord; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // read numerical attribute from the file - rc = trexio_read_nucleus_num(file, &num); - assert (rc == TREXIO_SUCCESS); - assert (num == 12); - - // read numerical (floating point) dataset from the file - coord = (double*) calloc(3*num, sizeof(double)); - - /* write numerical dataset with an unsafe dimension - * this should return TREXIO_UNSAFE_ARRAY_DIM indicating - * that access beyong allocated memory is likely to occur */ - uint64_t dim_unsafe = num * 12; - rc = trexio_read_safe_nucleus_coord(file, coord, dim_unsafe); - assert (rc == TREXIO_UNSAFE_ARRAY_DIM); - - /* write numerical dataset with a safe dimension - * this should return TREXIO_SUCCESS */ - uint64_t dim_safe = num * 3; - rc = trexio_read_safe_nucleus_coord(file, coord, dim_safe); - assert (rc == TREXIO_SUCCESS); - - double x = coord[30] - 2.14171677; - assert( x*x < 1.e-14 ); - free(coord); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(void) { - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - test_write_dset (TREXIO_FILE, TEST_BACKEND); - test_has_dset (TREXIO_FILE, TEST_BACKEND); - test_read_dset (TREXIO_FILE, TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} - +#define TEST_BACKEND_HDF5 +#define TREXIO_FILE_PREFIX "io_safe_dset_float" +#include "test_macros.h" +#include "io_safe_dset_float.c" diff --git a/tests/io_safe_dset_float_text.c b/tests/io_safe_dset_float_text.c index bbd9b6b..7b5cc6e 100644 --- a/tests/io_safe_dset_float_text.c +++ b/tests/io_safe_dset_float_text.c @@ -1,163 +1,5 @@ -#include "trexio.h" -#include -#include -#include -#include +#define TEST_BACKEND_TEXT +#define TREXIO_FILE_PREFIX "io_safe_dset_float" +#include "test_macros.h" +#include "io_safe_dset_float.c" -#define TEST_BACKEND TREXIO_TEXT -#define TREXIO_FILE "test_safe_dset_f.dir" -#define RM_COMMAND "rm -f -- " TREXIO_FILE "/*.txt " TREXIO_FILE "/*.txt.size " TREXIO_FILE "/.lock && rm -fd -- " TREXIO_FILE - -static int test_write_dset (const char* file_name, const back_end_t backend) { - -/* Try to write a dataset with floating point values into the TREXIO file using safe API */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 12; - double coord[36] = { - 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 , - }; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write numerical attribute in an empty file - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_SUCCESS); - - /* write numerical dataset with an unsafe dimension - * this should return TREXIO_UNSAFE_ARRAY_DIM indicating - * that access beyong allocated memory is likely to occur */ - uint64_t dim_unsafe = num * 12; - rc = trexio_write_safe_nucleus_coord(file, coord, dim_unsafe); - assert (rc == TREXIO_UNSAFE_ARRAY_DIM); - - /* write numerical dataset with a safe dimension - * this should return TREXIO_SUCCESS */ - uint64_t dim_safe = num * 3; - rc = trexio_write_safe_nucleus_coord(file, coord, dim_safe); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_has_dset (const char* file_name, const back_end_t backend) { - -/* Try to check the existence of a dataset in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // check that the previously written dataset exists - rc = trexio_has_nucleus_coord(file); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_read_dset (const char* file_name, const back_end_t backend) { - -/* Try to read a dataset with floating point values from the TREXIO file using safe API */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be read - int num; - double* coord; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // read numerical attribute from the file - rc = trexio_read_nucleus_num(file, &num); - assert (rc == TREXIO_SUCCESS); - assert (num == 12); - - // read numerical (floating point) dataset from the file - coord = (double*) calloc(3*num, sizeof(double)); - - /* write numerical dataset with an unsafe dimension - * this should return TREXIO_UNSAFE_ARRAY_DIM indicating - * that access beyong allocated memory is likely to occur */ - uint64_t dim_unsafe = num * 12; - rc = trexio_read_safe_nucleus_coord(file, coord, dim_unsafe); - assert (rc == TREXIO_UNSAFE_ARRAY_DIM); - - /* write numerical dataset with a safe dimension - * this should return TREXIO_SUCCESS */ - uint64_t dim_safe = num * 3; - rc = trexio_read_safe_nucleus_coord(file, coord, dim_safe); - assert (rc == TREXIO_SUCCESS); - - double x = coord[30] - 2.14171677; - assert( x*x < 1.e-14 ); - free(coord); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(void) { - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - test_write_dset (TREXIO_FILE, TEST_BACKEND); - test_has_dset (TREXIO_FILE, TEST_BACKEND); - test_read_dset (TREXIO_FILE, TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} diff --git a/tests/io_str.c b/tests/io_str.c new file mode 100644 index 0000000..a0fdfab --- /dev/null +++ b/tests/io_str.c @@ -0,0 +1,129 @@ +#include "trexio.h" +#include +#include +#include +#include + +static int test_write_str (const char* file_name, const back_end_t backend) { + +/* Try to write a string attribute (single variable-length string) into the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be written + const char* sym = "B3U with some comments"; + +/*================= START OF TEST ==================*/ + + // open file in 'write' mode + file = trexio_open(file_name, 'w', backend, &rc); + assert (file != NULL); + + // write string attribute in an empty file + int max_str_len = 32; + rc = trexio_write_nucleus_point_group(file, sym, max_str_len); + assert (rc == TREXIO_SUCCESS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_has_str (const char* file_name, const back_end_t backend) { + +/* Try to check the existence of a string attribute in the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + +/*================= START OF TEST ==================*/ + + // open file + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + + // check that the previously written string attribute exists + rc = trexio_has_nucleus_point_group(file); + assert (rc == TREXIO_SUCCESS); + + // check that another string attribute does not exist + rc = trexio_has_mo_type(file); + assert (rc == TREXIO_HAS_NOT); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_read_str (const char* file_name, const back_end_t backend) { + +/* Try to read a string attribute from the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be read + char* sym; + +/*================= START OF TEST ==================*/ + + // open file in 'read' mode + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + + // read string attribute from the file + int max_str_len = 32; + sym = (char*) malloc(max_str_len*sizeof(char)); + + rc = trexio_read_nucleus_point_group(file, sym, max_str_len); + assert (rc == TREXIO_SUCCESS); + + char * pch; + pch = strtok(sym, " "); + assert (strcmp(pch, "B3U") == 0); + /* alternative test when 3 symbols are read from the file to sym */ + /*rc = trexio_read_nucleus_point_group(file, sym, 3); + assert (rc == TREXIO_SUCCESS); + assert (strcmp(sym, "B3U") == 0 );*/ + free(sym); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +int main(void) { + +/*============== Test launcher ================*/ + + int rc; + rc = system(RM_COMMAND); + assert (rc == 0); + + test_write_str (TREXIO_FILE, TEST_BACKEND); + test_has_str (TREXIO_FILE, TEST_BACKEND); + test_read_str (TREXIO_FILE, TEST_BACKEND); + + rc = system(RM_COMMAND); + assert (rc == 0); + + return 0; +} + + diff --git a/tests/io_str_hdf5.c b/tests/io_str_hdf5.c index eaafff0..58f0695 100644 --- a/tests/io_str_hdf5.c +++ b/tests/io_str_hdf5.c @@ -1,133 +1,5 @@ -#include "trexio.h" -#include -#include -#include -#include - -#define TEST_BACKEND TREXIO_HDF5 -#define TREXIO_FILE "test_str.h5" -#define RM_COMMAND "rm -rf " TREXIO_FILE - -static int test_write_str (const char* file_name, const back_end_t backend) { - -/* Try to write a string attribute (single variable-length string) into the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - const char* sym = "B3U with some comments"; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write string attribute in an empty file - int max_str_len = 32; - rc = trexio_write_nucleus_point_group(file, sym, max_str_len); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_has_str (const char* file_name, const back_end_t backend) { - -/* Try to check the existence of a string attribute in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // check that the previously written string attribute exists - rc = trexio_has_nucleus_point_group(file); - assert (rc == TREXIO_SUCCESS); - - // check that another string attribute does not exist - rc = trexio_has_mo_type(file); - assert (rc == TREXIO_HAS_NOT); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_read_str (const char* file_name, const back_end_t backend) { - -/* Try to read a string attribute from the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be read - char* sym; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // read string attribute from the file - int max_str_len = 32; - sym = (char*) malloc(max_str_len*sizeof(char)); - - rc = trexio_read_nucleus_point_group(file, sym, max_str_len); - assert (rc == TREXIO_SUCCESS); - - char * pch; - pch = strtok(sym, " "); - assert (strcmp(pch, "B3U") == 0); - /* alternative test when 3 symbols are read from the file to sym */ - /*rc = trexio_read_nucleus_point_group(file, sym, 3); - assert (rc == TREXIO_SUCCESS); - assert (strcmp(sym, "B3U") == 0 );*/ - free(sym); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(void) { - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - test_write_str (TREXIO_FILE, TEST_BACKEND); - test_has_str (TREXIO_FILE, TEST_BACKEND); - test_read_str (TREXIO_FILE, TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} - +#define TEST_BACKEND_HDF5 +#define TREXIO_FILE_PREFIX "io_str" +#include "test_macros.h" +#include "io_str.c" diff --git a/tests/io_str_text.c b/tests/io_str_text.c index 4aad28f..888d35b 100644 --- a/tests/io_str_text.c +++ b/tests/io_str_text.c @@ -1,131 +1,5 @@ -#include "trexio.h" -#include -#include -#include -#include +#define TEST_BACKEND_TEXT +#define TREXIO_FILE_PREFIX "io_str" +#include "test_macros.h" +#include "io_str.c" -#define TEST_BACKEND TREXIO_TEXT -#define TREXIO_FILE "test_str.dir" -#define RM_COMMAND "rm -f -- " TREXIO_FILE "/*.txt " TREXIO_FILE "/*.txt.size " TREXIO_FILE "/.lock && rm -fd -- " TREXIO_FILE - -static int test_write_str (const char* file_name, const back_end_t backend) { - -/* Try to write a string attribute (single variable-length string) into the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - const char* sym = "B3U with some comments"; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write string attribute in an empty file - int max_str_len = 32; - rc = trexio_write_nucleus_point_group(file, sym, max_str_len); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_has_str (const char* file_name, const back_end_t backend) { - -/* Try to check the existence of a string attribute in the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // check that the previously written string attribute exists - rc = trexio_has_nucleus_point_group(file); - assert (rc == TREXIO_SUCCESS); - - // check that another string attribute does not exist - rc = trexio_has_mo_type(file); - assert (rc == TREXIO_HAS_NOT); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_read_str (const char* file_name, const back_end_t backend) { - -/* Try to read a string attribute from the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be read - char* sym; - -/*================= START OF TEST ==================*/ - - // open file in 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // read string attribute from the file - int max_str_len = 32; - sym = (char*) malloc(max_str_len*sizeof(char)); - - rc = trexio_read_nucleus_point_group(file, sym, max_str_len); - assert (rc == TREXIO_SUCCESS); - - char * pch; - pch = strtok(sym, " "); - assert (strcmp(pch, "B3U") == 0); - /* alternative test when 3 symbols are read from the file to sym */ - /*rc = trexio_read_nucleus_point_group(file, sym, 3); - assert (rc == TREXIO_SUCCESS); - assert (strcmp(sym, "B3U") == 0 );*/ - free(sym); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(void) { - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - test_write_str (TREXIO_FILE, TEST_BACKEND); - test_has_str (TREXIO_FILE, TEST_BACKEND); - test_read_str (TREXIO_FILE, TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} diff --git a/tests/open.c b/tests/open.c new file mode 100644 index 0000000..db0bba7 --- /dev/null +++ b/tests/open.c @@ -0,0 +1,160 @@ +#include "trexio.h" +#include +#include +#include + +#define TREXIO_VOID "non_existing_" TREXIO_FILE + + +static int test_open_w (const char* file_name, const back_end_t backend) { + +/* Try to open the TREXIO file in 'write' mode */ + + 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); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_open_r (const char* file_name, const back_end_t backend) { + +/* Try to open the TREXIO file in 'read' mode */ + + trexio_t* file = NULL; + trexio_exit_code rc; + +/*================= START OF TEST ==================*/ + + // open file in 'write' mode + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + assert (rc == TREXIO_SUCCESS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_open_auto (const char* file_name) { + +/* Try to open the TREXIO file in 'read' mode */ + + trexio_t* file = NULL; + trexio_exit_code rc; + +/*================= START OF TEST ==================*/ + + // open file in 'write' mode + file = trexio_open(file_name, 'r', TREXIO_AUTO, &rc); + assert (file != NULL); + assert (rc == TREXIO_SUCCESS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_open_errors (const back_end_t backend) { + +/* Try to call trexio_open with bad arguments */ + + trexio_t* file = NULL; + trexio_exit_code rc; + +/*================= START OF TEST ==================*/ + + // open non-existing file in 'r' (read) mode, should return TREXIO_OPEN_ERROR + file = trexio_open(TREXIO_VOID, 'r', backend, &rc); + assert (file == NULL); + assert (rc == TREXIO_OPEN_ERROR); + fprintf(stderr, "%s \n", trexio_string_of_error(rc)); + + // open file with empty file name, should return TREXIO_INVALID_ARG_1 + file = trexio_open("", 'w', backend, &rc); + assert (file == NULL); + assert (rc == TREXIO_INVALID_ARG_1); + fprintf(stderr, "%s \n", trexio_string_of_error(rc)); + + // open existing file in non-supported I/O mode, should return TREXIO_INVALID_ARG_2 + file = trexio_open(TREXIO_FILE, 'k', backend, &rc); + assert (file == NULL); + assert (rc == TREXIO_INVALID_ARG_2); + fprintf(stderr, "%s \n", trexio_string_of_error(rc)); + + // open existing file with non-supported back end, should return TREXIO_INVALID_ARG_3 + file = trexio_open(TREXIO_FILE, 'w', 666, &rc); + assert (file == NULL); + assert (rc == TREXIO_INVALID_ARG_3); + fprintf(stderr, "%s \n", trexio_string_of_error(rc)); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_inquire (const back_end_t backend) { + +/* Try to call trexio_inquire function */ + + trexio_exit_code rc; + +/*================= START OF TEST ==================*/ + + // inquire non-existing file + rc = trexio_inquire(TREXIO_VOID); + assert (rc == TREXIO_FAILURE); + + // inquire existing file + rc = trexio_inquire(TREXIO_FILE); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +int main(void) { + +/*============== Test launcher ================*/ + + int rc; + rc = system(RM_COMMAND); + assert (rc == 0); + + test_open_w (TREXIO_FILE, TEST_BACKEND); + test_open_r (TREXIO_FILE, TEST_BACKEND); + test_open_auto (TREXIO_FILE); + test_open_errors(TEST_BACKEND); + test_inquire (TEST_BACKEND); + + rc = system(RM_COMMAND); + assert (rc == 0); + + return 0; +} diff --git a/tests/open_hdf5.c b/tests/open_hdf5.c index d0a6581..029347d 100644 --- a/tests/open_hdf5.c +++ b/tests/open_hdf5.c @@ -1,163 +1,5 @@ -#include "trexio.h" -#include -#include -#include +#define TEST_BACKEND_HDF5 +#define TREXIO_FILE_PREFIX "open" +#include "test_macros.h" +#include "open.c" -#define TEST_BACKEND TREXIO_HDF5 -#define TREXIO_FILE "test_open.h5" -#define TREXIO_VOID "non_existing_" TREXIO_FILE -#define RM_COMMAND "rm -rf " TREXIO_FILE - - -static int test_open_w (const char* file_name, const back_end_t backend) { - -/* Try to open the TREXIO file in 'write' mode */ - - 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); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_open_r (const char* file_name, const back_end_t backend) { - -/* Try to open the TREXIO file in 'read' mode */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_open_auto (const char* file_name) { - -/* Try to open the TREXIO file in 'read' mode */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'r', TREXIO_AUTO, &rc); - assert (file != NULL); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_open_errors (const back_end_t backend) { - -/* Try to call trexio_open with bad arguments */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open non-existing file in 'r' (read) mode, should return TREXIO_OPEN_ERROR - file = trexio_open(TREXIO_VOID, 'r', backend, &rc); - assert (file == NULL); - assert (rc == TREXIO_OPEN_ERROR); - fprintf(stderr, "%s \n", trexio_string_of_error(rc)); - - // open file with empty file name, should return TREXIO_INVALID_ARG_1 - file = trexio_open("", 'w', backend, &rc); - assert (file == NULL); - assert (rc == TREXIO_INVALID_ARG_1); - fprintf(stderr, "%s \n", trexio_string_of_error(rc)); - - // open existing file in non-supported I/O mode, should return TREXIO_INVALID_ARG_2 - file = trexio_open(TREXIO_FILE, 'k', backend, &rc); - assert (file == NULL); - assert (rc == TREXIO_INVALID_ARG_2); - fprintf(stderr, "%s \n", trexio_string_of_error(rc)); - - // open existing file with non-supported back end, should return TREXIO_INVALID_ARG_3 - file = trexio_open(TREXIO_FILE, 'w', 666, &rc); - assert (file == NULL); - assert (rc == TREXIO_INVALID_ARG_3); - fprintf(stderr, "%s \n", trexio_string_of_error(rc)); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_inquire (const back_end_t backend) { - -/* Try to call trexio_inquire function */ - - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // inquire non-existing file - rc = trexio_inquire(TREXIO_VOID); - assert (rc == TREXIO_FAILURE); - - // inquire existing file - rc = trexio_inquire(TREXIO_FILE); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(void) { - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - test_open_w (TREXIO_FILE, TEST_BACKEND); - test_open_r (TREXIO_FILE, TEST_BACKEND); - test_open_auto (TREXIO_FILE); - test_open_errors(TEST_BACKEND); - test_inquire (TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} diff --git a/tests/open_text.c b/tests/open_text.c index 4e43501..a4f3cd9 100644 --- a/tests/open_text.c +++ b/tests/open_text.c @@ -1,163 +1,5 @@ -#include "trexio.h" -#include -#include -#include +#define TEST_BACKEND_TEXT +#define TREXIO_FILE_PREFIX "open" +#include "test_macros.h" +#include "open.c" -#define TEST_BACKEND TREXIO_TEXT -#define TREXIO_FILE "test_open.dir" -#define TREXIO_VOID "non_existing_" TREXIO_FILE -#define RM_COMMAND "rm -f -- " TREXIO_FILE "/*.txt " TREXIO_FILE "/*.txt.size " TREXIO_FILE "/.lock && rm -fd -- " TREXIO_FILE - - -static int test_open_w (const char* file_name, const back_end_t backend) { - -/* Try to open the TREXIO file in 'write' mode */ - - 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); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_open_r (const char* file_name, const back_end_t backend) { - -/* Try to open the TREXIO file in 'read' mode */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_open_auto (const char* file_name) { - -/* Try to open the TREXIO file in 'read' mode */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'r', TREXIO_AUTO, &rc); - assert (file != NULL); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_open_errors (const back_end_t backend) { - -/* Try to call trexio_open with bad arguments */ - - trexio_t* file = NULL; - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // open non-existing file in 'r' (read) mode, should return TREXIO_OPEN_ERROR - file = trexio_open(TREXIO_VOID, 'r', backend, &rc); - assert (file == NULL); - assert (rc == TREXIO_OPEN_ERROR); - fprintf(stderr, "%s \n", trexio_string_of_error(rc)); - - // open file with empty file name, should return TREXIO_INVALID_ARG_1 - file = trexio_open("", 'w', backend, &rc); - assert (file == NULL); - assert (rc == TREXIO_INVALID_ARG_1); - fprintf(stderr, "%s \n", trexio_string_of_error(rc)); - - // open existing file in non-supported I/O mode, should return TREXIO_INVALID_ARG_2 - file = trexio_open(TREXIO_FILE, 'k', backend, &rc); - assert (file == NULL); - assert (rc == TREXIO_INVALID_ARG_2); - fprintf(stderr, "%s \n", trexio_string_of_error(rc)); - - // open existing file with non-supported back end, should return TREXIO_INVALID_ARG_3 - file = trexio_open(TREXIO_FILE, 'w', 666, &rc); - assert (file == NULL); - assert (rc == TREXIO_INVALID_ARG_3); - fprintf(stderr, "%s \n", trexio_string_of_error(rc)); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_inquire (const back_end_t backend) { - -/* Try to call trexio_inquire function */ - - trexio_exit_code rc; - -/*================= START OF TEST ==================*/ - - // inquire non-existing file - rc = trexio_inquire(TREXIO_VOID); - assert (rc == TREXIO_FAILURE); - - // inquire existing file - rc = trexio_inquire(TREXIO_FILE); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int main(void) { - -/*============== Test launcher ================*/ - - int rc; - rc = system(RM_COMMAND); - assert (rc == 0); - - test_open_w (TREXIO_FILE, TEST_BACKEND); - test_open_r (TREXIO_FILE, TEST_BACKEND); - test_open_auto (TREXIO_FILE); - test_open_errors(TEST_BACKEND); - test_inquire (TEST_BACKEND); - - rc = system(RM_COMMAND); - assert (rc == 0); - - return 0; -} diff --git a/tests/overwrite_all.c b/tests/overwrite_all.c new file mode 100644 index 0000000..b2236d7 --- /dev/null +++ b/tests/overwrite_all.c @@ -0,0 +1,262 @@ +#include "trexio.h" +#include +#include +#include +#include + +static int test_write (const char* file_name, const back_end_t backend) { + +/* Try to write a full set of data (num+dset_num+str+dset_str) related to benzene molecule into the TREXIO file */ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be written + int num = 12; + double coord[36] = { + 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 , + }; + const char* sym = "D6h"; + const char* labels[] = {"C" , + "C" , + "C" , + "C" , + "C" , + "C" , + "H" , + "H" , + "H" , + "H" , + "H" , + "H" }; + +/*================= START OF TEST ==================*/ + + // open file in 'write' mode + file = trexio_open(file_name, 'w', backend, &rc); + assert (file != NULL); + + // write the data + rc = trexio_write_nucleus_num(file, num); + assert (rc == TREXIO_SUCCESS); + + rc = trexio_write_nucleus_coord(file, coord); + assert (rc == TREXIO_SUCCESS); + + rc = trexio_write_nucleus_point_group(file, sym, 4); + assert (rc == TREXIO_SUCCESS); + + rc = trexio_write_nucleus_label(file, labels, 2); + assert (rc == TREXIO_SUCCESS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_overwrite_unsafe (const char* file_name, const back_end_t backend) { + +/* Try to overwrite the data that already exists in the TREXIO file which is open in UNSAFE mode*/ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be written + int num = 5; + double coord[15] = { + 0.00000000 , 666.666 , 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 + }; + const char* sym = "Unknown"; + const char* labels[] = {"Ru" , + "U" , + "Cl" , + "Na" , + "H" }; + +/*================= START OF TEST ==================*/ + + // open file in 'write' mode + file = trexio_open(file_name, 'u', backend, &rc); + assert (file != NULL); + + // check that the previously written data cannot be overwritten + rc = trexio_write_nucleus_num(file, num); + assert (rc == TREXIO_SUCCESS); + + rc = trexio_write_nucleus_coord(file, coord); + assert (rc == TREXIO_SUCCESS); + + rc = trexio_write_nucleus_point_group(file, sym, 16); + assert (rc == TREXIO_SUCCESS); + + rc = trexio_write_nucleus_label(file, labels, 4); + assert (rc == TREXIO_SUCCESS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +static int test_overwrite_safe (const char* file_name, const back_end_t backend) { + +/* Try to overwrite the data that already exists in the TREXIO file which is open in SAFE mode*/ + + trexio_t* file = NULL; + trexio_exit_code rc; + + // parameters to be written + int num = 24; + double coord[3] = { + 0.00000000 , 666.666, 0.00000000 , + }; + const char* sym = "Unknown"; + const char* labels[] = {"Ru" , + "U" , + "Cl" , + "Na" , + "H" }; + +/*================= START OF TEST ==================*/ + + // open file in 'write' mode + file = trexio_open(file_name, 'w', backend, &rc); + assert (file != NULL); + + // check that the previously written data cannot be overwritten + rc = trexio_write_nucleus_num(file, num); + assert (rc == TREXIO_ATTR_ALREADY_EXISTS); + + rc = trexio_write_nucleus_coord(file, coord); + assert (rc == TREXIO_DSET_ALREADY_EXISTS); + + rc = trexio_write_nucleus_point_group(file, sym, 16); + assert (rc == TREXIO_ATTR_ALREADY_EXISTS); + + rc = trexio_write_nucleus_label(file, labels, 4); + assert (rc == TREXIO_DSET_ALREADY_EXISTS); + + // close current session + rc = trexio_close(file); + assert (rc == TREXIO_SUCCESS); + +/*================= END OF TEST ==================*/ + + return 0; +} + + +int test_read(const char* file_name, const back_end_t backend) { + +/*========= Test read ===========*/ + + trexio_t* file = NULL; + trexio_exit_code rc; + + int num; + double* coord; + char** label; + char* point_group; + +/*================= START OF TEST ==================*/ + + // open existing file on 'read' mode + file = trexio_open(file_name, 'r', backend, &rc); + assert (file != NULL); + + // read nucleus_num + rc = trexio_read_nucleus_num(file,&num); + assert (rc == TREXIO_SUCCESS); + assert (num == 5); + + // read nucleus_coord + coord = (double*) calloc(3*num, sizeof(double)); + rc = trexio_read_nucleus_coord(file,coord); + assert (rc == TREXIO_SUCCESS); + + double x = coord[1] - 666.666; + assert( x*x < 1.e-14); + free(coord); + + // read nucleus_label + label = (char**) malloc(num*sizeof(char*)); + for (int i=0; i -#include -#include -#include +#define TEST_BACKEND_HDF5 +#define TREXIO_FILE_PREFIX "overwrite_all" +#include "test_macros.h" +#include "overwrite_all.c" -#define TEST_BACKEND TREXIO_HDF5 -#define TREXIO_FILE "test_over.h5" -#define RM_COMMAND "rm -f -- " TREXIO_FILE - -static int test_write (const char* file_name, const back_end_t backend) { - -/* Try to write a full set of data (num+dset_num+str+dset_str) related to benzene molecule into the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 12; - double coord[36] = { - 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 , - }; - const char* sym = "D6h"; - const char* labels[] = {"C" , - "C" , - "C" , - "C" , - "C" , - "C" , - "H" , - "H" , - "H" , - "H" , - "H" , - "H" }; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write the data - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_nucleus_coord(file, coord); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_nucleus_point_group(file, sym, 4); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_nucleus_label(file, labels, 2); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_overwrite_unsafe (const char* file_name, const back_end_t backend) { - -/* Try to overwrite the data that already exists in the TREXIO file which is open in UNSAFE mode*/ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 5; - double coord[15] = { - 0.00000000 , 666.666 , 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 - }; - const char* sym = "Unknown"; - const char* labels[] = {"Ru" , - "U" , - "Cl" , - "Na" , - "H" }; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'u', backend, &rc); - assert (file != NULL); - - // check that the previously written data cannot be overwritten - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_nucleus_coord(file, coord); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_nucleus_point_group(file, sym, 16); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_nucleus_label(file, labels, 4); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_overwrite_safe (const char* file_name, const back_end_t backend) { - -/* Try to overwrite the data that already exists in the TREXIO file which is open in SAFE mode*/ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 24; - double coord[3] = { - 0.00000000 , 666.666, 0.00000000 , - }; - const char* sym = "Unknown"; - const char* labels[] = {"Ru" , - "U" , - "Cl" , - "Na" , - "H" }; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // check that the previously written data cannot be overwritten - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_ATTR_ALREADY_EXISTS); - - rc = trexio_write_nucleus_coord(file, coord); - assert (rc == TREXIO_DSET_ALREADY_EXISTS); - - rc = trexio_write_nucleus_point_group(file, sym, 16); - assert (rc == TREXIO_ATTR_ALREADY_EXISTS); - - rc = trexio_write_nucleus_label(file, labels, 4); - assert (rc == TREXIO_DSET_ALREADY_EXISTS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int test_read(const char* file_name, const back_end_t backend) { - -/*========= Test read ===========*/ - - trexio_t* file = NULL; - trexio_exit_code rc; - - int num; - double* coord; - char** label; - char* point_group; - -/*================= START OF TEST ==================*/ - - // open existing file on 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // read nucleus_num - rc = trexio_read_nucleus_num(file,&num); - assert (rc == TREXIO_SUCCESS); - assert (num == 5); - - // read nucleus_coord - coord = (double*) calloc(3*num, sizeof(double)); - rc = trexio_read_nucleus_coord(file,coord); - assert (rc == TREXIO_SUCCESS); - - double x = coord[1] - 666.666; - assert( x*x < 1.e-14); - free(coord); - - // read nucleus_label - label = (char**) malloc(num*sizeof(char*)); - for (int i=0; i -#include -#include -#include +#define TEST_BACKEND_TEXT +#define TREXIO_FILE_PREFIX "overwrite_all" +#include "test_macros.h" +#include "overwrite_all.c" -#define TEST_BACKEND TREXIO_TEXT -#define TREXIO_FILE "test_over.dir" -#define RM_COMMAND "rm -f -- " TREXIO_FILE "/*.txt " TREXIO_FILE "/*.txt.size " TREXIO_FILE "/.lock && rm -fd -- " TREXIO_FILE - -static int test_write (const char* file_name, const back_end_t backend) { - -/* Try to write a full set of data (num+dset_num+str+dset_str) related to benzene molecule into the TREXIO file */ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 12; - double coord[36] = { - 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 , - }; - const char* sym = "D6h"; - const char* labels[] = {"C" , - "C" , - "C" , - "C" , - "C" , - "C" , - "H" , - "H" , - "H" , - "H" , - "H" , - "H" }; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // write the data - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_nucleus_coord(file, coord); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_nucleus_point_group(file, sym, 4); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_nucleus_label(file, labels, 2); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_overwrite_unsafe (const char* file_name, const back_end_t backend) { - -/* Try to overwrite the data that already exists in the TREXIO file which is open in UNSAFE mode*/ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 5; - double coord[15] = { - 0.00000000 , 666.666 , 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 - }; - const char* sym = "Unknown"; - const char* labels[] = {"Ru" , - "U" , - "Cl" , - "Na" , - "H" }; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'u', backend, &rc); - assert (file != NULL); - - // check that the previously written data cannot be overwritten - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_nucleus_coord(file, coord); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_nucleus_point_group(file, sym, 16); - assert (rc == TREXIO_SUCCESS); - - rc = trexio_write_nucleus_label(file, labels, 4); - assert (rc == TREXIO_SUCCESS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -static int test_overwrite_safe (const char* file_name, const back_end_t backend) { - -/* Try to overwrite the data that already exists in the TREXIO file which is open in SAFE mode*/ - - trexio_t* file = NULL; - trexio_exit_code rc; - - // parameters to be written - int num = 24; - double coord[3] = { - 0.00000000 , 666.666, 0.00000000 , - }; - const char* sym = "Unknown"; - const char* labels[] = {"Ru" , - "U" , - "Cl" , - "Na" , - "H" }; - -/*================= START OF TEST ==================*/ - - // open file in 'write' mode - file = trexio_open(file_name, 'w', backend, &rc); - assert (file != NULL); - - // check that the previously written data cannot be overwritten - rc = trexio_write_nucleus_num(file, num); - assert (rc == TREXIO_ATTR_ALREADY_EXISTS); - - rc = trexio_write_nucleus_coord(file, coord); - assert (rc == TREXIO_DSET_ALREADY_EXISTS); - - rc = trexio_write_nucleus_point_group(file, sym, 16); - assert (rc == TREXIO_ATTR_ALREADY_EXISTS); - - rc = trexio_write_nucleus_label(file, labels, 4); - assert (rc == TREXIO_DSET_ALREADY_EXISTS); - - // close current session - rc = trexio_close(file); - assert (rc == TREXIO_SUCCESS); - -/*================= END OF TEST ==================*/ - - return 0; -} - - -int test_read(const char* file_name, const back_end_t backend) { - -/*========= Test read ===========*/ - - trexio_t* file = NULL; - trexio_exit_code rc; - - int num; - double* coord; - char** label; - char* point_group; - -/*================= START OF TEST ==================*/ - - // open existing file on 'read' mode - file = trexio_open(file_name, 'r', backend, &rc); - assert (file != NULL); - - // read nucleus_num - rc = trexio_read_nucleus_num(file,&num); - assert (rc == TREXIO_SUCCESS); - assert (num == 5); - - // read nucleus_coord - coord = (double*) calloc(3*num, sizeof(double)); - rc = trexio_read_nucleus_coord(file,coord); - assert (rc == TREXIO_SUCCESS); - - double x = coord[1] - 666.666; - assert( x*x < 1.e-14); - free(coord); - - // read nucleus_label - label = (char**) malloc(num*sizeof(char*)); - for (int i=0; i +#include +#include +#include + +#ifdef TEST_BACKEND_HDF5 +#define TEST_BACKEND TREXIO_HDF5 +#define TREXIO_FILE TREXIO_FILE_PREFIX ".h5" +#define RM_COMMAND "rm -f -- " TREXIO_FILE +#endif + + +#ifdef TEST_BACKEND_TEXT +#define TEST_BACKEND TREXIO_TEXT +#define TREXIO_FILE TREXIO_FILE_PREFIX ".dir" +#define RM_COMMAND "rm -f -- " TREXIO_FILE "/*.txt " TREXIO_FILE "/*.txt.size " TREXIO_FILE "/.lock && rm -fd -- " TREXIO_FILE +#endif + + diff --git a/tools/build_doc.sh b/tools/build_doc.sh index 413fe09..a3ea25b 100755 --- a/tools/build_doc.sh +++ b/tools/build_doc.sh @@ -81,7 +81,7 @@ function extract_doc() ${org} \ --load ${CONFIG_TANGLE} \ -f org-html-export-to-html &> /dev/null - mv ${local_html} ${DOCS} + mv -f ${local_html} ${DOCS} rm -f "${local_html}~" } @@ -99,7 +99,7 @@ function main() { # Create documentation cd ${SRC} - for dir in ${SRC}/templates_*/ ${TREXIO_ROOT}/ + for dir in ${SRC}/templates_*/ ${TREXIO_ROOT}/ ${TREXIO_ROOT}/docs do dir=${dir%*/} echo ${dir} diff --git a/tools/generator_tools.py b/tools/generator_tools.py index 2cde76f..c42b124 100644 --- a/tools/generator_tools.py +++ b/tools/generator_tools.py @@ -611,8 +611,13 @@ def get_detailed_num_dict (configuration: dict) -> dict: tmp_dict.update(get_dtype_dict(v2[0], 'num')) if v2[0] in ['int', 'dim', 'dim readonly']: tmp_dict['trex_json_int_type'] = v2[0] + tmp_dict['is_index'] = '(false)' + elif v2[0] in ['index']: + tmp_dict['trex_json_int_type'] = v2[0] + tmp_dict['is_index'] = 'file->one_based' else: tmp_dict['trex_json_int_type'] = '' + tmp_dict['is_index'] = '(false)' num_dict[tmp_num] = tmp_dict @@ -716,7 +721,7 @@ def split_dset_dict_detailed (datasets: dict) -> tuple: if 'index' in datatype: tmp_dict['is_index'] = 'file->one_based' else: - tmp_dict['is_index'] = 'false' + tmp_dict['is_index'] = '(false)' # add the list of dimensions tmp_dict['dims'] = [dim.replace('.','_') for dim in v[1]] diff --git a/tools/prepare_python.sh b/tools/prepare_python.sh index 2151378..bf316bf 100755 --- a/tools/prepare_python.sh +++ b/tools/prepare_python.sh @@ -1,11 +1,22 @@ #!/bin/bash +# We want the script to crash on the 1st error: +set -e + # Check that script is executed from tools directory if [[ $(basename $PWD) != "tools" ]] ; then echo "This script should run in the tools directory" exit -1 fi +DO_HDF5=0 +if [[ -z ${1} ]] && [[ "${1}" == "--without-hdf5" ]] ; then + echo "Compiling Python API without the HDF5 back end." + DO_HDF5=1 +else + echo "Compiling Python API with the HDF5 back end." +fi + TREXIO_ROOT=$(dirname "${PWD}../") # First define readonly global variables. @@ -14,9 +25,7 @@ readonly INCLUDIR=${TREXIO_ROOT}/include readonly TOOLS=${TREXIO_ROOT}/tools readonly PYDIR=${TREXIO_ROOT}/python readonly PYTREXIODIR=${PYDIR}/pytrexio - -# We want the script to crash on the 1st error: -set -e +readonly PYDIR_TREXIO_H=${PYDIR}/src/trexio.h # Create src and trexio directories in the python folder if not yet done mkdir -p ${PYDIR}/src @@ -25,22 +34,16 @@ mkdir -p ${PYTREXIODIR} # Copy all the source code and header files in the corresponding python directory cp ${SRC}/pytrexio.py ${PYTREXIODIR}/pytrexio.py cp ${SRC}/trexio.py ${PYDIR}/trexio.py -cp ${SRC}/*.c ${PYDIR}/src -cp ${SRC}/*.h ${PYDIR}/src -cp ${INCLUDIR}/trexio.h ${PYDIR}/src +cp ${SRC}/trexio.c ${SRC}/trexio_s.h ${SRC}/trexio_private.h ${PYDIR}/src +cp ${SRC}/trexio_text.{c,h} ${PYDIR}/src +cp ${SRC}/pytrexio_wrap.c ${PYDIR}/src/pytrexio_wrap.c +cp ${INCLUDIR}/trexio.h ${PYDIR}/src +cp ${INCLUDIR}/config.h ${PYDIR}/src -# fix needed to define HAVE_HDF5 symbol so that Python extension is always compiled with HDF5 (without including config.h) -# add "#define HAVE_HDF5 1" line after "#include stdint.h" using awk and sed -export LINE_NO=$(($(awk '/stdint.h/{print NR}' ${PYDIR}/src/trexio.h) + 1)) -# sed on MacOS is different from GNU sed on Linux and requires special treatment -if [[ "$OSTYPE" == "darwin"* ]]; then - sed -i '' -e "$LINE_NO"'i \ - #define HAVE_HDF5 1' "${PYDIR}/src/trexio.h" -else - sed -i -e "$LINE_NO"'i \ - #define HAVE_HDF5 1' "${PYDIR}/src/trexio.h" + +if [[ ${DO_HDF5} == 0 ]] ; then + cp ${SRC}/trexio_hdf5.{c,h} ${PYDIR}/src fi # Copy additional info cp ${TREXIO_ROOT}/AUTHORS ${TREXIO_ROOT}/LICENSE ${PYDIR} - diff --git a/tools/trexio.scm b/tools/trexio.scm index 72c7f7e..676db89 100644 --- a/tools/trexio.scm +++ b/tools/trexio.scm @@ -60,8 +60,22 @@ "1n9n1gbk5hgvg73am991xrv7ap002rz719a3nvh8m8ff9x10qd76" )))))) +(define-public trexio-2.3 + (package/inherit trexio-2.0 + (version "2.3.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 + "183wljg1avsia2pf2wb59s2i2qw6y19qfw164ffy1g024b6362ii" + )))))) + (define-public trexio ;; Default version of TREXIO. - trexio-2.2) + trexio-2.3) trexio diff --git a/trex.org b/trex.org index 9ef7438..a6f55ee 100644 --- a/trex.org +++ b/trex.org @@ -1,58 +1,17 @@ -#+TITLE: TREX Configuration file +#+TITLE: Data stored in TREXIO #+STARTUP: latexpreview #+SETUPFILE: docs/theme.setup -This page contains information about the general structure of the -TREXIO library. The source code of the library can be automatically -generated based on the contents of the ~trex.json~ configuration file, -which itself is generated from different sections (groups) presented -below. + For simplicity, the singular form is always used for the names of + groups and attributes, and all data are stored in atomic units. + The dimensions of the arrays in the tables below are given in + column-major order (as in Fortran), and the ordering of the dimensions + is reversed in the produced ~trex.json~ configuration file as the + library is written in C. -All quantities are saved in TREXIO files in atomic units. The -dimensions of the arrays in the tables below are given in column-major -order (as in Fortran), and the ordering of the dimensions is reversed -in the produced ~trex.json~ configuration file as the library is -written in C. - -TREXIO currently supports ~int~, ~float~ and ~str~ types for both -single attributes and arrays. Note, that some attributes might have -~dim~ type (e.g. ~num~ of the ~nucleus~ group). This type is treated -exactly in the same way as ~int~ with the only difference that ~dim~ -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 -1-based ~int~ in the Fortran interface and 0-based otherwise. - -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 ~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 Interaction (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. - -Some data may be complex. In that case, the real part should be stored -in the variable, and the imaginary part will be stored in the variable -with the same name suffixed by ~_im~. - - #+begin_src python :tangle trex.json :exports none + #+begin_src python :tangle trex.json :exports none { - #+end_src + #+end_src * Metadata (metadata group) @@ -133,11 +92,15 @@ with the same name suffixed by ~_im~. used in periodic calculations. #+NAME: cell - | Variable | Type | Dimensions | Description | - |----------+---------+------------+-----------------------| - | ~a~ | ~float~ | ~(3)~ | First lattice vector | - | ~b~ | ~float~ | ~(3)~ | Second lattice vector | - | ~c~ | ~float~ | ~(3)~ | Third lattice vector | + | Variable | Type | Dimensions | Description | + |----------+---------+------------+--------------------------------------------------------------------------| + | ~a~ | ~float~ | ~(3)~ | First real space lattice vector | + | ~b~ | ~float~ | ~(3)~ | Second real space lattice vector | + | ~c~ | ~float~ | ~(3)~ | Third real space lattice vector | + | ~G_a~ | ~float~ | ~(3)~ | First reciprocal space lattice vector | + | ~G_b~ | ~float~ | ~(3)~ | Second reciprocal space lattice vector | + | ~G_c~ | ~float~ | ~(3)~ | Third reciprocal space lattice vector | + | ~two_pi~ | ~int~ | | ~0~ or ~1~. If ~two_pi=1~, $2\pi$ is included in the reciprocal vectors. | #+CALL: json(data=cell, title="cell") @@ -145,9 +108,13 @@ with the same name suffixed by ~_im~. :results: #+begin_src python :tangle trex.json "cell": { - "a" : [ "float", [ "3" ] ] - , "b" : [ "float", [ "3" ] ] - , "c" : [ "float", [ "3" ] ] + "a" : [ "float", [ "3" ] ] + , "b" : [ "float", [ "3" ] ] + , "c" : [ "float", [ "3" ] ] + , "G_a" : [ "float", [ "3" ] ] + , "G_b" : [ "float", [ "3" ] ] + , "G_c" : [ "float", [ "3" ] ] + , "two_pi" : [ "int" , [] ] } , #+end_src :end: @@ -177,8 +144,18 @@ with the same name suffixed by ~_im~. ** Electron (electron group) - We consider wave functions expressed in the spin-free formalism, where - the number of \uparrow and \downarrow electrons is fixed. + The chemical system consists of nuclei and electrons, where the + nuclei are considered as fixed point charges with Cartesian + coordinates. The wave function is stored in the spin-free + formalism, and therefore, it is necessary for the user to + explicitly store the number of electrons with spin up + ($N_\uparrow$) and spin down ($N_\downarrow$). These numbers + correspond to the normalization of the spin-up and spin-down + single-particle reduced density matrices. + + We consider wave functions expressed in the spin-free formalism, where + the number of \uparrow and \downarrow electrons is fixed. + #+NAME:electron | Variable | Type | Dimensions | Description | @@ -213,13 +190,14 @@ with the same name suffixed by ~_im~. The ~id~ and ~current_label~ attributes need to be specified for each file. #+NAME: state - | Variable | Type | Dimensions | Description | - |-----------------+-------+---------------+---------------------------------------------------------------------------------------------| - | ~num~ | ~dim~ | | Number of states (including the ground state) | - | ~id~ | ~int~ | | Index of the current state (0 is ground state) | - | ~current_label~ | ~str~ | | Label of the current state | - | ~label~ | ~str~ | ~(state.num)~ | Labels of all states | - | ~file_name~ | ~str~ | ~(state.num)~ | Names of the TREXIO files linked to the current one (i.e. containing data for other states) | + | Variable | Type | Dimensions | Description | + |-----------------+---------+---------------+---------------------------------------------------------------------------------------------| + | ~num~ | ~dim~ | | Number of states (including the ground state) | + | ~id~ | ~index~ | | Index of the current state (0 is ground state) | + | ~energy~ | ~float~ | | Energy of the current state | + | ~current_label~ | ~str~ | | Label of the current state | + | ~label~ | ~str~ | ~(state.num)~ | Labels of all states | + | ~file_name~ | ~str~ | ~(state.num)~ | Names of the TREXIO files linked to the current one (i.e. containing data for other states) | #+CALL: json(data=state, title="state") @@ -227,11 +205,12 @@ with the same name suffixed by ~_im~. :results: #+begin_src python :tangle trex.json "state": { - "num" : [ "dim", [] ] - , "id" : [ "int", [] ] - , "current_label" : [ "str", [] ] - , "label" : [ "str", [ "state.num" ] ] - , "file_name" : [ "str", [ "state.num" ] ] + "num" : [ "dim" , [] ] + , "id" : [ "index", [] ] + , "energy" : [ "float", [] ] + , "current_label" : [ "str" , [] ] + , "label" : [ "str" , [ "state.num" ] ] + , "file_name" : [ "str" , [ "state.num" ] ] } , #+end_src :end: @@ -241,9 +220,9 @@ with the same name suffixed by ~_im~. *** Gaussian and Slater-type orbitals - We consider here basis functions centered on nuclei. Hence, we enable - the possibility to define /dummy atoms/ to place basis functions in - random positions. + We consider here basis functions centered on nuclei. Hence, it is + possibile to define /dummy atoms/ to place basis functions in + arbitrary positions. The atomic basis set is defined as a list of shells. Each shell $s$ is centered on a center $A$, possesses a given angular momentum $l$ and a @@ -277,35 +256,103 @@ with the same name suffixed by ~_im~. All the basis set parameters are stored in one-dimensional arrays. +*** Numerical orbitals + + Trexio supports numerical atom centered orbitals. The implementation is + based on the approach of FHI-aims [Blum, V. et al; Ab initio molecular + simulations with numeric atom-centered orbitals; Computer Physics + Communications 2009]. These orbitals are + defined by the atom they are centered on, their angular momentum and a + radial function $R_s$, which is of the form + \[ + R_s(\mathbf{r}) = \mathcal{N}_s \frac{u_i(\mathbf{r})}{r^{-n_s}}. + \] + Where $u_i(\mathbf{r})$ is numerically tabulated on a dense logarithmic + grid. It is constructed to vanish for any $\mathbf{r}$ + outside of the grid. The reference points are stored in ~nao_grid_r~ + and ~nao_grid_phi~. Additionaly, a separate spline for the first and second + derivative of $u(\mathbf{r})$ can be stored in ~nao_grid_grad~ and ~nao_grid_lap~. + Storing them in this form allows to calculate the actual first and + second derivatives easily as follows: + + \[ + \frac{\partial \phi}{\partial x} = \frac{x}{r^2}\left( u^\prime\left(r\right) - \frac{u\left(r\right)}{r}\right) + \] + \[ + \frac{\partial^2 \phi}{\partial x^2} = \frac{1}{r^3}\left(x^2 u^{\prime\prime}(r) + \left( 3x^2-r^2\right) \left( \frac{u(r)}{r^2} - \frac{u'(r)}{r}\right) \right) + \] + + The index of the first data point for each shell is stored in + ~nao_grid_start~, the number of data points per spline is stored + in ~nao_grid_size~ for convenience. + + What kind of spline is used can be provided in the ~interpolator_kind~ field. + For example, FHI-aims uses a cubic spline, so the ~interpolator_kind~ is + \"Polynomial\" and the ~interp_coeff_cnt~ is $4$. In this case, the first + interpolation coefficient per data point is the absolute term, the second is for + the linear term etc. + The interpolation coefficients for the wave function are given in the + ~interpolator_phi~ array. The ~interpolator_grad~ and ~interpolator_lap~ + arrays provide a spline for the gradient and Laplacian, respectively. + The argument passed to the interpolants is on the logarithmic scale of + the reference points: If the argument is an integer $i$, the interpolant + will return the value of $u(\mathbf{r})$ at the $i$th reference point. + A radius is converted to this scale by (note the zero-indexing) + \[ + i_{\log} = \frac{1}{c} \cdot \log \left( \frac{r}{r_0} \right) + \] + where + \[ + c = \log\left(\frac{r_1}{r_0}\right) + \] + For convenience, this conversion and functions to evaluate the splines + are provided with trexio. Since these implementations are not adapted to + a specific software architecture, a programm using these orbitals should + reimplement them with consideration for its specific needs. + *** Plane waves A plane wave is defined as \[ - \chi_j(r) = \exp \left( -i \mathbf{k}_j \mathbf{r} \right) + \chi_j(\mathbf{r}) = \exp \left( -i \mathbf{G}_j \cdot \mathbf{r} \right) \] The basis set is defined as the array of $k$-points in the - reciprocal space, defined in the ~pbc~ group. The kinetic energy - cutoff ~e_cut~ is the only input data relevant to plane waves. + reciprocal space $\mathbf{G}_j$, defined in the ~pbc~ group. The + kinetic energy cutoff ~e_cut~ is the only input data relevant to + plane waves. *** Data definitions #+NAME: basis - | Variable | Type | Dimensions | Description | - |-----------------+---------+---------------------+-----------------------------------------------------------------| - | ~type~ | ~str~ | | Type of basis set: "Gaussian", "Slater" or "PW" for plane waves | - | ~prim_num~ | ~dim~ | | Total number of primitives | - | ~shell_num~ | ~dim~ | | Total number of shells | - | ~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}$) | - | ~prim_factor~ | ~float~ | ~(basis.prim_num)~ | Normalization coefficients for the primitives ($f_{ks}$) | - | ~e_cut~ | ~float~ | | Energy cut-off for plane-wave calculations | + | Variable | Type | Dimensions | Description | | + |---------------------+---------+-----------------------------------------------+------------------------------------------------------------------------------+---| + | ~type~ | ~str~ | | Type of basis set: "Gaussian", "Slater", "Numerical" or "PW" for plane waves | | + | ~prim_num~ | ~dim~ | | Total number of primitives | | + | ~shell_num~ | ~dim~ | | Total number of shells | | + | ~nao_grid_num~ | ~dim~ | | Total number of grid points for numerical orbitals | | + | ~interp_coeff_cnt~ | ~dim~ | | Number of coefficients for the numerical orbital interpolator | | + | ~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$) | | + | ~nao_grid_start~ | ~index~ | ~(basis.shell_num)~ | Index of the first data point for a given numerical orbital | | + | ~nao_grid_size~ | ~dim~ | ~(basis.shell_num)~ | Number of data points per numerical orbital | | + | ~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}$) | | + | ~prim_factor~ | ~float~ | ~(basis.prim_num)~ | Normalization coefficients for the primitives ($f_{ks}$) | | + | ~e_cut~ | ~float~ | | Energy cut-off for plane-wave calculations | | + | ~nao_grid_radius~ | ~float~ | ~(basis.nao_grid_num)~ | Radii of grid points for numerical orbitals | | + | ~nao_grid_phi~ | ~float~ | ~(basis.nao_grid_num)~ | Wave function values for numerical orbitals | | + | ~nao_grid_grad~ | ~float~ | ~(basis.nao_grid_num)~ | Radial gradient of numerical orbitals | | + | ~nao_grid_lap~ | ~float~ | ~(basis.nao_grid_num)~ | Laplacian of numerical orbitals | | + | ~interpolator_kind~ | ~str~ | | Kind of spline, e.g. "Polynomial" | | + | ~interpolator_phi~ | ~float~ | ~(basis.interp_coeff_cnt,basis.nao_grid_num)~ | Coefficients for numerical orbital interpolation function | | + | ~interpolator_grad~ | ~float~ | ~(basis.interp_coeff_cnt,basis.nao_grid_num)~ | Coefficients for numerical orbital gradient interpolation function | | + | ~interpolator_lap~ | ~float~ | ~(basis.interp_coeff_cnt,basis.nao_grid_num)~ | Coefficients for numerical orbital laplacian interpolation function | | + #+CALL: json(data=basis, title="basis") @@ -313,20 +360,32 @@ with the same name suffixed by ~_im~. #+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" ] ] - , "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" ] ] - , "e_cut" : [ "float", [] ] - } , + "basis": { + "type" : [ "str" , [] ] + , "prim_num" : [ "dim" , [] ] + , "shell_num" : [ "dim" , [] ] + , "nao_grid_num" : [ "dim" , [] ] + , "interp_coeff_cnt" : [ "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" ] ] + , "nao_grid_start" : [ "index", [ "basis.shell_num" ] ] + , "nao_grid_size" : [ "dim" , [ "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" ] ] + , "e_cut" : [ "float", [] ] + , "nao_grid_radius" : [ "float", [ "basis.nao_grid_num" ] ] + , "nao_grid_phi" : [ "float", [ "basis.nao_grid_num" ] ] + , "nao_grid_grad" : [ "float", [ "basis.nao_grid_num" ] ] + , "nao_grid_lap" : [ "float", [ "basis.nao_grid_num" ] ] + , "interpolator_kind" : [ "str" , [] ] + , "interpolator_phi" : [ "float", [ "basis.nao_grid_num", "basis.interp_coeff_cnt" ] ] + , "interpolator_grad" : [ "float", [ "basis.nao_grid_num", "basis.interp_coeff_cnt" ] ] + , "interpolator_lap" : [ "float", [ "basis.nao_grid_num", "basis.interp_coeff_cnt" ] ] + } , #+end_src :end: @@ -390,7 +449,7 @@ exponent = coefficient = [ 0.006068, 0.045308, 0.202822, 0.503903, 0.383421, 1.0, 1.0, 1.0, 1.0, 1.0, 0.006068, 0.045308, 0.202822, 0.503903, 0.383421, 1.0, 1.0, 1.0, 1.0, 1.0 ] -` + prim_factor = [ 1.0006253235944540e+01, 2.4169531573445120e+00, 7.9610924849766440e-01 3.0734305383061117e-01, 1.2929684417481876e-01, 3.0734305383061117e-01, @@ -409,20 +468,21 @@ prim_factor = V_A^{\text{ECP}} = V_{A \ell_{\max}+1} + \sum_{\ell=0}^{\ell_{\max}} - \sum_{m=-\ell}^{\ell} | Y_{\ell m} \rangle \left[ - V_{A \ell} - V_{A \ell_{\max}+1} \right] \langle Y_{\ell m} | + \delta V_{A \ell}\sum_{m=-\ell}^{\ell} | Y_{\ell m} \rangle \langle Y_{\ell m} | \] - The first term in the equation above is sometimes attributed to the local channel, - while the remaining terms correspond to the non-local channel projections. - - The functions $V_{A\ell}$ are parameterized as: - \[ - V_{A \ell}(\mathbf{r}) = - \sum_{q=1}^{N_{q \ell}} - \beta_{A q \ell}\, |\mathbf{r}-\mathbf{R}_{A}|^{n_{A q \ell}}\, - e^{-\alpha_{A q \ell} |\mathbf{r}-\mathbf{R}_{A}|^2 } - \] + The first term in this equation is attributed to the local channel, while + the remaining terms correspond to non-local channel projections. $\ell_{\max}$ + refers to the maximum angular momentum in the non-local component of the ECP. + The functions \(\delta V_{A \ell}\) and \(V_{A \ell_{\max}+1}\) are parameterized as: + \begin{eqnarray} + \delta V_{A \ell}(\mathbf{r}) &=& + \sum_{q=1}^{N_{q \ell}} + \beta_{A q \ell}\, |\mathbf{r}-\mathbf{R}_{A}|^{n_{A q \ell}}\, + e^{-\alpha_{A q \ell} |\mathbf{r}-\mathbf{R}_{A}|^2 } \nonumber\\ + V_{A \ell_{\max}+1}(\mathbf{r}) &=& -\frac{Z_\text{eff}}{|\mathbf{r}-\mathbf{R}_{A}|}+\delta V_{A \ell_{\max}+1}(\mathbf{r}) + \end{eqnarray} + where $Z_\text{eff}$ is the effective nuclear charge of the center. See http://dx.doi.org/10.1063/1.4984046 or https://doi.org/10.1063/1.5121006 for more info. @@ -438,14 +498,13 @@ prim_factor = | ~coefficient~ | ~float~ | ~(ecp.num)~ | $\beta_{A q \ell}$ all ECP coefficients | | ~power~ | ~int~ | ~(ecp.num)~ | $n_{A q \ell}$ all ECP powers | - There might be some confusion in the meaning of the $\ell_{\max}$. It can be attributed to the maximum angular momentum occupied in the core orbitals, which are removed by the ECP. On the other hand, it can be attributed to the maximum angular momentum of the ECP that replaces the core electrons. *Note*, that the latter $\ell_{\max}$ is always higher by 1 than the former. - + *Note for developers*: avoid having variables with similar prefix in their name. The HDF5 back end might cause issues due to the way ~find_dataset~ function works. For example, in the ECP group we @@ -587,58 +646,50 @@ power = [ * Orbitals ** Atomic orbitals (ao group) - Going from the atomic basis set to AOs implies a systematic - construction of all the angular functions of each shell. We - consider two cases for the angular functions: the real-valued - spherical harmonics, and the polynomials in Cartesian coordinates. - In the case of real spherical harmonics, the AOs are ordered as - $0, +1, -1, +2, -2, \dots, +m, -m$ (see [[https://en.wikipedia.org/wiki/Table_of_spherical_harmonics#Real_spherical_harmonics][Wikipedia]]). - In the case of polynomials we - impose the canonical (or alphabetical) ordering), i.e - - \begin{eqnarray} - p & : & p_x, p_y, p_z \nonumber \\ - d & : & d_{xx}, d_{xy}, d_{xz}, d_{yy}, d_{yz}, d_{zz} \nonumber \\ - f & : & f_{xxx}, f_{xxy}, f_{xxz}, f_{xyy}, f_{xyz}, f_{xzz}, f_{yyy}, f_{yyz}, f_{yzz}, …f_{zzz} \nonumber \\ - {\rm etc.} \nonumber - \end{eqnarray} - - Note that there is no exception for $p$ orbitals in spherical - coordinates: the ordering is $0,+1,-1$ which corresponds $p_z, p_x, p_y$. - AOs are defined as \[ - \chi_i (\mathbf{r}) = \mathcal{N}_i\, P_{\eta(i)}(\mathbf{r})\, R_{\theta(i)} (\mathbf{r}) + \chi_i (\mathbf{r}) = \mathcal{N}_i'\, P_{\eta(i)}(\mathbf{r})\, R_{s(i)} (\mathbf{r}) \] - where $i$ is the atomic orbital index, - $P$ encodes for either the - polynomials or the spherical harmonics, $\theta(i)$ returns the - shell on which the AO is expanded, and $\eta(i)$ denotes which - angular function is chosen. - $\mathcal{N}_i$ is a normalization factor that enables the - possibility to have different normalization coefficients within a - shell, as in the GAMESS convention where - $\mathcal{N}_{x^2} \ne \mathcal{N}_{xy}$ because - \[ \left[ \iiint \left(x-X_A \right)^2 R_{\theta(i)} - (\mathbf{r}) dx\, dy\, dz \right]^{-1/2} \ne - \left[ \iiint \left( x-X_A \right) \left( y-Y_A \right) R_{\theta(i)} - (\mathbf{r}) dx\, dy\, dz \right]^{-1/2}. \] + where $i$ is the atomic orbital index, $P$ refers to either + polynomials or spherical harmonics, and $s(i)$ specifies the shell + on which the AO is expanded. + + $\eta(i)$ denotes the chosen angular function. The AOs can be + expressed using real spherical harmonics or polynomials in Cartesian + coordinates. In the case of real spherical harmonics, the AOs are + ordered as $0, +1, -1, +2, -2, \dots, + m, -m$ (see [[https://en.wikipedia.org/wiki/Table_of_spherical_harmonics#Real_spherical_harmonics][Wikipedia]]). In + the case of polynomials, the canonical (or alphabetical) ordering is + used, + + | $p$ | $p_x, p_y, p_z$ | + | $d$ | $d_{xx}, d_{xy}, d_{xz}, d_{yy}, d_{yz}, d_{zz}$ | + | $f$ | $f_{xxx}, f_{xxy}, f_{xxz}, f_{xyy}, f_{xyz}$, | + | | $f_{xzz}, f_{yyy}, f_{yyz}, f_{yzz}, f_{zzz}$ | + | $\vdots$ | | + + Note that for \(p\) orbitals in spherical coordinates, the ordering + is $0,+1,-1$ which corresponds to $p_z, p_x, p_y$. + + $\mathcal{N}_i'$ is a normalization factor that allows for different + normalization coefficients within a single shell, as in the GAMESS + convention where each individual function is unit-normalized. + Using GAMESS convention, the normalization factor of the shell + $\mathcal{N}_d$ in the ~basis~ group is appropriate for instance + for the $d_z^2$ function (i.e. + $\mathcal{N}_{d}\equiv\mathcal{N}_{z^2}$) but not for the $d_{xy}$ + AO, so the correction factor $\mathcal{N}_i'$ for $d_{xy}$ in the + ~ao~ groups is the ratio $\frac{\mathcal{N}_{xy}}{\mathcal{N}_{z^2}}$. - In such a case, one should set the normalization of the shell (in - the [[Basis set (basis group)][Basis set]] section) to $\mathcal{N}_{z^2}$, which is the - normalization factor of the atomic orbitals in spherical coordinates. - The normalization factor of the $xy$ function which should be - introduced here should be $\frac{\mathcal{N}_{xy}}{\mathcal{N}_{z^2}}$. #+NAME: ao - | Variable | Type | Dimensions | Description | - |-----------------+---------+------------+---------------------------------| - | ~cartesian~ | ~int~ | | ~1~: true, ~0~: false | - | ~num~ | ~dim~ | | Total number of atomic orbitals | - | ~shell~ | ~index~ | ~(ao.num)~ | basis set shell for each AO | - | ~normalization~ | ~float~ | ~(ao.num)~ | Normalization factors | + | Variable | Type | Dimensions | Description | + |-----------------+---------+------------+--------------------------------------| + | ~cartesian~ | ~int~ | | ~1~: true, ~0~: false | + | ~num~ | ~dim~ | | Total number of atomic orbitals | + | ~shell~ | ~index~ | ~(ao.num)~ | Basis set shell for each AO | + | ~normalization~ | ~float~ | ~(ao.num)~ | Normalization factor $\mathcal{N}_i$ | #+CALL: json(data=ao, title="ao") @@ -671,18 +722,18 @@ power = [ 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$ | - | ~overlap_im~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert q \rangle$ (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) | + | 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$ | + | ~overlap_im~ | ~float~ | ~(ao.num, ao.num)~ | $\langle p \vert q \rangle$ (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") @@ -711,34 +762,32 @@ power = [ The two-electron integrals for a two-electron operator $\hat{O}$ are \[ \langle p q \vert \hat{O} \vert r s \rangle \] in physicists - notation or \[ ( pr \vert \hat{O} \vert qs ) \] in chemists notation, where $p,q,r,s$ are indices over atomic orbitals. - Functions are provided to get the indices in physicists or chemists - notation. - - # TODO: Physicist / Chemist functions + # TODO: Physicist / Chemist functions + # Functions are provided to get the indices in physicists or chemists + # notation. - \[ \hat{W}_{\text{ee}} = \sum_{i=2}^{N_\text{elec}} \sum_{j=1}^{i-1} \frac{1}{\vert \mathbf{r}_i - \mathbf{r}_j \vert} \] : electron-electron repulsive potential operator. - \[ \hat{W}^{lr}_{\text{ee}} = \sum_{i=2}^{N_\text{elec}} - \sum_{j=1}^{i-1} \frac{\text{erf}(\vert \mathbf{r}_i - + \sum_{j=1}^{i-1} \frac{\text{erf}(\mu\, \vert \mathbf{r}_i - \mathbf{r}_j \vert)}{\vert \mathbf{r}_i - \mathbf{r}_j \vert} \] : electron-electron long range potential The Cholesky decomposition of the integrals can also be stored: \[ - A_{ijkl} = \sum_{\alpha} G_{il\alpha} G_{jl\alpha} + \langle ij | kl \rangle = \sum_{\alpha} G_{ik\alpha} G_{jl\alpha} \] #+NAME: ao_2e_int - | Variable | Type | Dimensions | Description | - |-----------------------+----------------+---------------------------------------------------+-----------------------------------------------| - | ~eri~ | ~float sparse~ | ~(ao.num, ao.num, ao.num, ao.num)~ | Electron repulsion integrals | - | ~eri_lr~ | ~float sparse~ | ~(ao.num, ao.num, ao.num, ao.num)~ | Long-range Electron repulsion integrals | - | ~eri_cholesky_num~ | ~dim~ | | Number of Cholesky vectors for ERI | - | ~eri_cholesky~ | ~float sparse~ | ~(ao.num, ao.num, ao_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~ | ~(ao.num, ao.num, ao_2e_int.eri_lr_cholesky_num)~ | Cholesky decomposition of the long range ERI | + | Variable | Type | Dimensions | Description | + |-----------------------+----------------+---------------------------------------------------+-----------------------------------------------| + | ~eri~ | ~float sparse~ | ~(ao.num, ao.num, ao.num, ao.num)~ | Electron repulsion integrals | + | ~eri_lr~ | ~float sparse~ | ~(ao.num, ao.num, ao.num, ao.num)~ | Long-range electron repulsion integrals | + | ~eri_cholesky_num~ | ~dim~ | | Number of Cholesky vectors for ERI | + | ~eri_cholesky~ | ~float sparse~ | ~(ao.num, ao.num, ao_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~ | ~(ao.num, ao.num, ao_2e_int.eri_lr_cholesky_num)~ | Cholesky decomposition of the long range ERI | #+CALL: json(data=ao_2e_int, title="ao_2e_int") @@ -840,7 +889,7 @@ power = [ | 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_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 | @@ -861,7 +910,7 @@ power = [ } , #+end_src :end: - + * Multi-determinant information ** Slater determinants (determinant group) @@ -959,7 +1008,7 @@ power = [ on a reference wave function $\Psi$, where $\hat{T}_1$ is the single excitation operator, \[ - \hat{T}_1 = \sum_{ia} t_{i}^{a}\, \hat{a}^\dagger_a \hat{a}_i, + \hat{T}_1 = \sum_{ia} t_{i}^{a}\, \hat{a}^\dagger_a \hat{a}_i, \] $\hat{T}_2$ is the double excitation operator, @@ -979,7 +1028,7 @@ power = [ \[ |\Phi\rangle = e^{\hat{T}}| \Psi \rangle \] - The reference wave function is stored using the ~determinant~ and/or + The reference wave function is stored using the ~determinant~ and/or ~csf~ groups, and the amplitudes are stored using the current group. The attributes with the ~exp~ suffix correspond to exponentialized operators. @@ -1036,23 +1085,20 @@ power = [ \gamma_{ij} = \gamma^{\uparrow}_{ij} + \gamma^{\downarrow}_{ij} \] - The $\uparrow \uparrow$, $\downarrow \downarrow$, $\uparrow \downarrow$, $\downarrow \uparrow$ - components of the two-body density matrix are given by + The $\uparrow \uparrow$, $\downarrow \downarrow$, $\uparrow \downarrow$ components of the two-body density matrix are given by \begin{eqnarray*} \Gamma_{ijkl}^{\uparrow \uparrow} &=& \langle \Psi | \hat{a}^{\dagger}_{k\alpha}\, \hat{a}^{\dagger}_{l\alpha} \hat{a}_{j\alpha}\, \hat{a}_{i\alpha} | \Psi \rangle \\ \Gamma_{ijkl}^{\downarrow \downarrow} &=& \langle \Psi | \hat{a}^{\dagger}_{k\beta}\, \hat{a}^{\dagger}_{l\beta} \hat{a}_{j\beta}\, \hat{a}_{i\beta} | \Psi \rangle \\ \Gamma_{ijkl}^{\uparrow \downarrow} &=& - \langle \Psi | \hat{a}^{\dagger}_{k\alpha}\, \hat{a}^{\dagger}_{l\beta} \hat{a}_{j\beta}\, \hat{a}_{i\alpha} | \Psi \rangle \\ - \Gamma_{ijkl}^{\downarrow \uparrow} &=& - \langle \Psi | \hat{a}^{\dagger}_{k\beta}\, \hat{a}^{\dagger}_{l\alpha} \hat{a}_{j\alpha}\, \hat{a}_{i\beta} | \Psi \rangle \\ + \langle \Psi | \hat{a}^{\dagger}_{k\alpha}\, \hat{a}^{\dagger}_{l\beta} \hat{a}_{j\beta}\, \hat{a}_{i\alpha} | \Psi \rangle + + \langle \Psi | \hat{a}^{\dagger}_{l\alpha}\, \hat{a}^{\dagger}_{k\beta} \hat{a}_{i\beta}\, \hat{a}_{j\alpha} | \Psi \rangle \\ \end{eqnarray*} and the spin-summed one-body density matrix is \[ \Gamma_{ijkl} = \Gamma_{ijkl}^{\uparrow \uparrow} + - \Gamma_{ijkl}^{\downarrow \downarrow} + \Gamma_{ijkl}^{\uparrow \downarrow} + - \Gamma_{ijkl}^{\downarrow \uparrow} + \Gamma_{ijkl}^{\downarrow \downarrow} + \Gamma_{ijkl}^{\uparrow \downarrow}. \] The total energy can be computed as: @@ -1078,26 +1124,25 @@ power = [ $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 | - | ~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) | + | 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 | + | ~1e_transition~ | ~float~ | ~(mo.num, mo.num, state.num, state.num) | One-particle transition density matrices | + | ~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_transition~ | ~float sparse~ | ~(mo.num, mo.num, mo.num, mo.num, state.num, state.num) | Two-particle transition density matrices | + | ~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) | #+CALL: json(data=rdm, title="rdm") @@ -1105,24 +1150,23 @@ power = [ :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" ] ] - , "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" ] ] + "1e" : [ "float" , [ "mo.num", "mo.num" ] ] + , "1e_up" : [ "float" , [ "mo.num", "mo.num" ] ] + , "1e_dn" : [ "float" , [ "mo.num", "mo.num" ] ] + , "1e_transition" : [ "float" , [ "state.num", "state.num", "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_transition" : [ "float sparse", [ "state.num", "state.num", "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" ] ] } , #+end_src :end: @@ -1130,12 +1174,12 @@ power = [ * Correlation factors ** Jastrow factor (jastrow group) - The Jastrow factor is an $N$-electron function to which the CI - expansion is multiplied: $\Psi = \Phi \times \exp(J)$, + The Jastrow factor is an $N$-electron function which multiplies the CI + expansion: $\Psi = \Phi \times \exp(J)$, In the following, we use the notations $r_{ij} = |\mathbf{r}_i - \mathbf{r}_j|$ and $R_{i\alpha} = |\mathbf{r}_i - \mathbf{R}_\alpha|$, where indices - $i$ and $j$ correspond to electrons and $\alpha$ to nuclei. + $i$ and $j$ refer to electrons and $\alpha$ to nuclei. Parameters for multiple forms of Jastrow factors can be saved in TREXIO files, and are described in the following sections. These @@ -1143,7 +1187,7 @@ power = [ following: - ~CHAMP~ - ~Mu~ - + *** CHAMP The first form of Jastrow factor is the one used in @@ -1152,75 +1196,95 @@ power = [ \[ J(\mathbf{r},\mathbf{R}) = J_{\text{eN}}(\mathbf{r},\mathbf{R}) + J_{\text{ee}}(\mathbf{r}) + J_{\text{eeN}}(\mathbf{r},\mathbf{R}) \] - - $J_{\text{eN}}$ contains electron-nucleus terms: + + $J_{\text{eN}}$ contains electron-nucleus terms: \[ - J_{\text{eN}}(\mathbf{r},\mathbf{R}) = \sum_{i=1}^{N_\text{elec}} \sum_{\alpha=1}^{N_\text{nucl}} - \frac{a_{1,\alpha}\, g_\alpha(R_{i\alpha})}{1+a_{2,\alpha}\, g_\alpha(R_{i\alpha})} + - \sum_{p=2}^{N_\text{ord}^a} a_{p+1,\alpha}\, [g_\alpha(R_{i\alpha})]^p - J_{eN}^\infty + J_{\text{eN}}(\mathbf{r},\mathbf{R}) = \sum_{i=1}^{N_\text{elec}} \sum_{\alpha=1}^{N_\text{nucl}}\left[ + \frac{a_{1,\alpha}\, f_\alpha(R_{i\alpha})}{1+a_{2,\alpha}\, + f_\alpha(R_{i\alpha})} + \sum_{p=2}^{N_\text{ord}^a} a_{p+1,\alpha}\, [f_\alpha(R_{i\alpha})]^p - J_{\text{eN}}^\infty + \right] \] $J_{\text{ee}}$ contains electron-electron terms: + \[ J_{\text{ee}}(\mathbf{r}) = \sum_{i=1}^{N_\text{elec}} \sum_{j=1}^{i-1} - \frac{b_1\, f(r_{ij})}{1+b_2\, f(r_{ij})} + - \sum_{p=2}^{N_\text{ord}^b} a_{p+1}\, [f(r_{ij})]^p - J_{ee}^\infty + \left[ + \frac{\frac{1}{2}\big(1 + \delta^{\uparrow\downarrow}_{ij}\big)\,b_1\, f_{\text{ee}}(r_{ij})}{1+b_2\, f_{\text{ee}}(r_{ij})} + + \sum_{p=2}^{N_\text{ord}^b} b_{p+1}\, [f_{\text{ee}}(r_{ij})]^p - J_{\text{ee},ij}^\infty + \right] \] + + $\delta^{\uparrow\downarrow}_{ij}$ is zero when the electrons $i$ and + $j$ have the same spin, and one otherwise. - and $J_{\text{eeN}}$ contains electron-electron-Nucleus terms: + $J_{\text{eeN}}$ contains electron-electron-Nucleus terms: \[ - J_{\text{eeN}}(\mathbf{r},\mathbf{R}) = + J_{\text{eeN}}(\mathbf{r},\mathbf{R}) = \sum_{\alpha=1}^{N_{\text{nucl}}} \sum_{i=1}^{N_{\text{elec}}} \sum_{j=1}^{i-1} \sum_{p=2}^{N_{\text{ord}}} \sum_{k=0}^{p-1} \sum_{l=0}^{p-k-2\delta_{k,0}} - c_{lkp\alpha} \left[ f({r}_{ij}) \right]^k - \left[ \left[ g_\alpha({R}_{i\alpha}) \right]^l + \left[ g_\alpha({R}_{j\alpha}) \right]^l \right] - \left[ g_\alpha({R}_{i\,\alpha}) \, g_\alpha({R}_{j\alpha}) \right]^{(p-k-l)/2} + c_{lkp\alpha} \left[ g_{\text{ee}}({r}_{ij}) \right]^k \nonumber \\ + \left[ \left[ g_\alpha({R}_{i\alpha}) \right]^l + \left[ g_\alpha({R}_{j\alpha}) \right]^l \right] + \left[ g_\alpha({R}_{i\,\alpha}) \, + g_\alpha({R}_{j\alpha}) \right]^{(p-k-l)/2} \] - $c_{lkp\alpha}$ are non-zero only when $p-k-l$ is even. - The terms $J_{\text{ee}}^\infty$ and $J_{\text{eN}}^\infty$ are shifts to ensure that - $J_{\text{ee}}$ and $J_{\text{eN}}$ have an asymptotic value of zero. + The terms $J_{\text{ee},ij}^\infty$ and $J_{\text{eN}}^\infty$ are shifts to ensure that + $J_{\text{eN}}$ and $J_{\text{ee}}$ have an asymptotic value of zero: + + \[ + J_{\text{eN}}^{\infty} = + \frac{a_{1,\alpha}\, \kappa_\alpha^{-1}}{1+a_{2,\alpha}\, + \kappa_\alpha^{-1}} + \sum_{p=2}^{N_\text{ord}^a} a_{p+1,\alpha}\, \kappa_\alpha^{-p} + \] + \[ + J_{\text{ee},ij}^{\infty} = + \frac{\frac{1}{2}\big(1 + \delta^{\uparrow\downarrow}_{ij}\big)\,b_1\, + \kappa_{\text{ee}}^{-1}}{1+b_2\, \kappa_{\text{ee}}^{-1}} + + \sum_{p=2}^{N_\text{ord}^b} b_{p+1}\, \kappa_{\text{ee}}^{-p} + \] $f$ and $g$ are scaling function defined as \[ - f(r) = \frac{1-e^{-\kappa\, r}}{\kappa} \text{ and } - g_\alpha(r) = e^{-\kappa_\alpha\, r}. + f_\alpha(r) = \frac{1-e^{-\kappa_\alpha\, r}}{\kappa_\alpha} \text{ and } + g_\alpha(r) = e^{-\kappa_\alpha\, r}, \] + *** Mu [[https://aip.scitation.org/doi/10.1063/5.0044683][Mu-Jastrow]] is based on a one-parameter correlation factor that has been introduced in the context of transcorrelated methods. This - correlation factor imposes the electron-electron cusp and it is + correlation factor imposes the electron-electron cusp, and it is built such that the leading order in $1/r_{12}$ of the effective two-electron potential reproduces the long-range interaction of the range-separated density functional theory. Its analytical - expression reads + expression reads \[ - J(\mathbf{r}, \mathbf{R}) = J_{\text{eeN}}(\mathbf{r}, \mathbf{R}) + + J(\mathbf{r}, \mathbf{R}) = J_{\text{eeN}}(\mathbf{r}, \mathbf{R}) + J_{\text{eN}}(\mathbf{r}, \mathbf{R}) \]. - The electron-electron cusp is incorporated in the three-body term. - + The electron-electron cusp is incorporated in the three-body term + \[ - J_\text{eeN} (\mathbf{r}, \mathbf{R}) = + J_\text{eeN} (\mathbf{r}, \mathbf{R}) = \sum_{i=1}^{N_\text{elec}} \sum_{j=1}^{i-1} \, u\left(\mu, r_{ij}\right) \, - \Pi_{\alpha=1}^{N_{\text{nucl}}} \, E_\alpha({R}_{i\alpha}) \, E_\alpha({R}_{j\alpha}) + \Pi_{\alpha=1}^{N_{\text{nucl}}} \, E_\alpha({R}_{i\alpha}) \, E_\alpha({R}_{j\alpha}), \] - $u$ is an electron-electron function given by the symmetric function + where ww$u$ is an electron-electron function \[ u\left(\mu, r\right) = \frac{r}{2} \, \left[ 1 - \text{erf}(\mu\, r) \right] - \frac{1}{2 \, \mu \, \sqrt{\pi}} \exp \left[ -(\mu \, r)^2 \right]. @@ -1231,24 +1295,24 @@ power = [ electrons. An envelope function has been introduced to cancel out the Jastrow - effects between two-electrons when they are both close to a nucleus + effects between two-electrons when at least one is close to a nucleus (to perform a frozen-core calculation). The envelope function is given by \[ E_\alpha(R) = 1 - \exp\left( - \gamma_{\alpha} \, R^2 \right). \] - + In particular, if the parameters $\gamma_\alpha$ tend to zero, the Mu-Jastrow factor becomes a two-body Jastrow factor: \[ - J_{\text{ee}}(\mathbf{r}) = - \sum_{i=1}^{N_\text{elec}} \sum_{j=1}^{i-1} \, u\left(\mu, r_{ij}\right) + J_{\text{ee}}(\mathbf{r}) = + \sum_{i=1}^{N_\text{elec}} \sum_{j=1}^{i-1} \, u\left(\mu, r_{ij}\right) \] and for large $\gamma_\alpha$ it becomes zero. - + To increase the flexibility of the Jastrow and improve the electron density the following electron-nucleus term is added @@ -1261,36 +1325,36 @@ power = [ The parameter $\mu$ is stored in the ~ee~ array, the parameters $\gamma_\alpha$ are stored in the ~een~ array, and the parameters $a_\alpha$ are stored in the ~en~ array. - + *** Table of values - + #+name: jastrow - | Variable | Type | Dimensions | Description | - |---------------+----------+---------------------+-----------------------------------------------------------------| - | ~type~ | ~string~ | | Type of Jastrow factor: ~CHAMP~ or ~Mu~ | - | ~ee_num~ | ~dim~ | | Number of Electron-electron parameters | - | ~en_num~ | ~dim~ | | Number of Electron-nucleus parameters | - | ~een_num~ | ~dim~ | | Number of Electron-electron-nucleus parameters | - | ~ee~ | ~float~ | ~(jastrow.ee_num)~ | Electron-electron parameters | - | ~en~ | ~float~ | ~(jastrow.en_num)~ | Electron-nucleus parameters | - | ~een~ | ~float~ | ~(jastrow.een_num)~ | Electron-electron-nucleus parameters | - | ~en_nucleus~ | ~index~ | ~(jastrow.en_num)~ | Nucleus relative to the eN parameter | - | ~een_nucleus~ | ~index~ | ~(jastrow.een_num)~ | Nucleus relative to the eeN parameter | - | ~ee_scaling~ | ~float~ | | $\kappa$ value in CHAMP Jastrow for electron-electron distances | - | ~en_scaling~ | ~float~ | ~(nucleus.num)~ | $\kappa$ value in CHAMP Jastrow for electron-nucleus distances | - + | Variable | Type | Dimensions | Description | + |---------------+---------+---------------------+-----------------------------------------------------------------| + | ~type~ | ~str~ | | Type of Jastrow factor: ~CHAMP~ or ~Mu~ | + | ~en_num~ | ~dim~ | | Number of Electron-nucleus parameters | + | ~ee_num~ | ~dim~ | | Number of Electron-electron parameters | + | ~een_num~ | ~dim~ | | Number of Electron-electron-nucleus parameters | + | ~en~ | ~float~ | ~(jastrow.en_num)~ | Electron-nucleus parameters | + | ~ee~ | ~float~ | ~(jastrow.ee_num)~ | Electron-electron parameters | + | ~een~ | ~float~ | ~(jastrow.een_num)~ | Electron-electron-nucleus parameters | + | ~en_nucleus~ | ~index~ | ~(jastrow.en_num)~ | Nucleus relative to the eN parameter | + | ~een_nucleus~ | ~index~ | ~(jastrow.een_num)~ | Nucleus relative to the eeN parameter | + | ~ee_scaling~ | ~float~ | | $\kappa$ value in CHAMP Jastrow for electron-electron distances | + | ~en_scaling~ | ~float~ | ~(nucleus.num)~ | $\kappa$ value in CHAMP Jastrow for electron-nucleus distances | + #+CALL: json(data=jastrow, title="jastrow") #+RESULTS: :results: #+begin_src python :tangle trex.json "jastrow": { - "type" : [ "string", [] ] - , "ee_num" : [ "dim" , [] ] + "type" : [ "str" , [] ] , "en_num" : [ "dim" , [] ] + , "ee_num" : [ "dim" , [] ] , "een_num" : [ "dim" , [] ] - , "ee" : [ "float" , [ "jastrow.ee_num" ] ] , "en" : [ "float" , [ "jastrow.en_num" ] ] + , "ee" : [ "float" , [ "jastrow.ee_num" ] ] , "een" : [ "float" , [ "jastrow.een_num" ] ] , "en_nucleus" : [ "index" , [ "jastrow.en_num" ] ] , "een_nucleus" : [ "index" , [ "jastrow.een_num" ] ] @@ -1331,7 +1395,7 @@ power = [ } #+end_src :end: - + * Appendix :noexport: ** Python script from table to json diff --git a/version_memo.txt b/version_memo.txt new file mode 100644 index 0000000..67fcce7 --- /dev/null +++ b/version_memo.txt @@ -0,0 +1,8 @@ +To update the version, change: + +- configure.ac +- CMakeLists.txt +- ocaml/trexio/trexio.opam +- python/pytrexio/_version.py +- rust/trexio/Cargo.toml +