From de5ccf7482ccbe02a909e7467eb76940f393ad59 Mon Sep 17 00:00:00 2001 From: Sebastian Ehlert Date: Tue, 18 Nov 2025 11:49:53 +0100 Subject: [PATCH 01/12] Add documentation to build GauXC --- docs/gauxc/index.rst | 11 ++++ docs/gauxc/installation.rst | 100 ++++++++++++++++++++++++++++++++++++ docs/index.rst | 1 + 3 files changed, 112 insertions(+) create mode 100644 docs/gauxc/index.rst create mode 100644 docs/gauxc/installation.rst diff --git a/docs/gauxc/index.rst b/docs/gauxc/index.rst new file mode 100644 index 0000000..56304ce --- /dev/null +++ b/docs/gauxc/index.rst @@ -0,0 +1,11 @@ +Integrating Skala in Electronic Structure Packages via GauXC +============================================================ + +The `GauXC `__ library provides an implementation for evaluating exchange-correlation functionals from an input density matrix. +We provide Skala as an extension to the GauXC library, allowing users to easily integrate Skala into electronic structure packages that already interface with GauXC. +The following sections provide instructions on how to install GauXC with Skala support and how to use Skala in your own electronic structure package via GauXC. + + +.. toctree:: + + installation diff --git a/docs/gauxc/installation.rst b/docs/gauxc/installation.rst new file mode 100644 index 0000000..9e82198 --- /dev/null +++ b/docs/gauxc/installation.rst @@ -0,0 +1,100 @@ +Installing GauXC +================ + +In this section, we will provide instructions on how to install GauXC with Skala support based on the conda-forge ecosystem. +For this tutorial, we will use the `mamba `__ package manager for setting up the environment and installing dependencies. +If you do not have mamba installed, you can download the `miniforge `__ installer. + +First, we will create a new environment with all the required dependencies for building GauXC with Skala support. +For this, create a file named `environment.yml` with the following content: + +.. code-block:: yaml + :caption: environment.yml + + name: gauxc-dev + channels: + - conda-forge + dependencies: + # build requirements + - c-compiler + - cxx-compiler + - cmake + - ninja + - nlohmann_json + # host requirements + - exchcxx >=1.0 + - gau2grid >=2.0.6 + - hdf5 + - pytorch * cpu_* + - libblas + +Then, run the following commands to create and activate the new environment: + +.. code-block:: none + + mamba env create -n gauxc-dev -f environment.yml + mamba activate gauxc-dev + +Next, we will download the GauXC source code with Skala support and setup the build using CMake: + +.. code-block:: none + + curl -JL https://github.com/microsoft/skala/releases/download/v1.0.0/gauxc-skala.tar.gz > gauxc-skala.tar.gz | tar xzv + cmake -B _build -S gauxc -G Ninja -DGAUXC_ENABLE_MPI=no -DGAUXC_ENABLE_OPENMP=yes -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} + cmake --build _build + +We can check the Skala implementation by evaluating a traditional density functional via the Skala driver. +In the GauXC test directory we have checkpoints for the PBE and TPSS functionals that can be used for testing. +To run the test via the standalone driver of GauXC, we can use the following command: + +.. code-block:: none + + cd gauxc/tests/ref_data + ../../../_build/tests/standalone_driver onedft_input.inp + +This will evaluate the TPSS exchange-correlation functional via the Skala driver on a provided density matrix. + +To use GauXC in your project install the built library into your conda environment: + +.. code-block:: none + + cmake --install _build + +Finally, you can link against the GauXC library in your own electronic structure package to use Skala as an exchange-correlation functional. +This can be done by linking against the `gauxc` target in your CMake build system. + +.. code-block:: cmake + + find_package(gauxc REQUIRED) + target_link_libraries(${PROJECT_NAME} PRIVATE gauxc::gauxc) + +To build GauXC as part of your own CMake project, you can use the following snippet to include it via FetchContent. + +.. code-block:: cmake + + set(Skala_GauXC_URL "https://github.com/microsoft/skala/releases/download/v1.0.0/gauxc-skala.tar.gz") + set(Skala_GauXC_SHA "3368a4f8c968a295ad03363c5ccbee787f24f703df42c7b929a40e76f48bd324") + + find_package(gauxc QUIET) + if(NOT gauxc_FOUND) + include(FetchContent) + + message(STATUS "Could not find GauXC... Building GauXC from source") + message(STATUS "GAUXC URL: ${Skala_GauXC_URL}") + + set(GAUXC_ENABLE_ONEDFT ON CACHE BOOL "" FORCE) + set(GAUXC_ENABLE_TESTS OFF CACHE BOOL "" FORCE) + + FetchContent_Declare( + gauxc + URL ${Skala_GauXC_URL} + URL_HASH SHA256=${Skala_GauXC_SHA} + DOWNLOAD_EXTRACT_TIMESTAMP ON + ) + FetchContent_MakeAvailable(gauxc) + + else() + if(NOT ${GAUXC_HAS_ONEDFT}) + message(FATAL_ERROR "GauXC Found but without OneDFT Support Enabled") + endif() + endif() \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 4cfc352..0d8d846 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -27,6 +27,7 @@ Please stay tuned for updates and new releases. pyscf/scf_settings ase foundry + gauxc/index .. toctree:: :maxdepth: 1 From 38a007f97eab47b637d2c526ac5f2af8405475e1 Mon Sep 17 00:00:00 2001 From: Sebastian Ehlert Date: Tue, 18 Nov 2025 13:26:57 +0100 Subject: [PATCH 02/12] Add installation instructions for MPI and Cuda support --- docs/conf.py | 1 + docs/gauxc/installation.rst | 141 ++++++++++++++++++++++++++++++------ pyproject.toml | 1 + 3 files changed, 120 insertions(+), 23 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index b871475..8e556dd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -7,6 +7,7 @@ extensions = [ "myst_nb", "sphinx_book_theme", + "sphinx_design", "sphinx.ext.autodoc", ] diff --git a/docs/gauxc/installation.rst b/docs/gauxc/installation.rst index 9e82198..9b140e8 100644 --- a/docs/gauxc/installation.rst +++ b/docs/gauxc/installation.rst @@ -8,25 +8,75 @@ If you do not have mamba installed, you can download the `miniforge =1.0 - - gau2grid >=2.0.6 - - hdf5 - - pytorch * cpu_* - - libblas +.. tab-set:: + :sync-group: config + + .. tab-item:: OpenMP + + .. code-block:: yaml + :caption: environment.yml + + name: gauxc-dev + channels: + - conda-forge + dependencies: + # build requirements + - c-compiler + - cxx-compiler + - cmake + - ninja + - nlohmann_json + # host requirements + - exchcxx >=1.0 + - gau2grid >=2.0.6 + - hdf5 + - libblas + - pytorch * cpu* + + .. tab-item:: MPI + + .. code-block:: yaml + :caption: environment.yml + + name: gauxc-dev + channels: + - conda-forge + dependencies: + # build requirements + - c-compiler + - cxx-compiler + - cmake + - ninja + - nlohmann_json + # host requirements + - openmpi # or mpich + - exchcxx >=1.0 + - gau2grid >=2.0.6 + - hdf5 * mpi_* + - libblas + - pytorch * cpu* + + .. tab-item:: CUDA + + .. code-block:: yaml + :caption: environment.yml + + name: gauxc-dev + channels: + - conda-forge + dependencies: + # build requirements + - c-compiler + - cxx-compiler + - cuda-compiler + - cmake + - ninja + - nlohmann_json + # host requirements + - gau2grid >=2.0.6 + - hdf5 + - libblas + - pytorch * cuda* Then, run the following commands to create and activate the new environment: @@ -35,13 +85,40 @@ Then, run the following commands to create and activate the new environment: mamba env create -n gauxc-dev -f environment.yml mamba activate gauxc-dev -Next, we will download the GauXC source code with Skala support and setup the build using CMake: +Next, we will download the GauXC source code with Skala support. +We provide a pre-packaged version of GauXC with Skala integration that can be downloaded from the Skala releases page. +Run the following command to download and extract the source code: .. code-block:: none curl -JL https://github.com/microsoft/skala/releases/download/v1.0.0/gauxc-skala.tar.gz > gauxc-skala.tar.gz | tar xzv - cmake -B _build -S gauxc -G Ninja -DGAUXC_ENABLE_MPI=no -DGAUXC_ENABLE_OPENMP=yes -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} - cmake --build _build + +Now we can build GauXC with Skala support using CMake and Ninja. +Create a build directory and run the following commands to configure and build the library: + +.. tab-set:: + :sync-group: config + + .. tab-item:: OpenMP + + .. code-block:: none + + cmake -B _build -S gauxc -G Ninja -DGAUXC_ENABLE_MPI=no -DGAUXC_ENABLE_OPENMP=yes -DGAUXC_ENABLE_CUDA=no -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} + cmake --build _build + + .. tab-item:: MPI + + .. code-block:: none + + cmake -B _build -S gauxc -G Ninja -DGAUXC_ENABLE_MPI=yes -DGAUXC_ENABLE_OPENMP=yes -DGAUXC_ENABLE_CUDA=no -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} + cmake --build _build + + .. tab-item:: CUDA + + .. code-block:: none + + cmake -B _build -S gauxc -G Ninja -DGAUXC_ENABLE_MPI=no -DGAUXC_ENABLE_OPENMP=yes -DGAUXC_ENABLE_CUDA=yes -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} + cmake --build _build We can check the Skala implementation by evaluating a traditional density functional via the Skala driver. In the GauXC test directory we have checkpoints for the PBE and TPSS functionals that can be used for testing. @@ -66,6 +143,9 @@ This can be done by linking against the `gauxc` target in your CMake build syste .. code-block:: cmake find_package(gauxc REQUIRED) + if(NOT ${GAUXC_HAS_ONEDFT}) + message(FATAL_ERROR "GauXC found but without Skala support enabled") + endif() target_link_libraries(${PROJECT_NAME} PRIVATE gauxc::gauxc) To build GauXC as part of your own CMake project, you can use the following snippet to include it via FetchContent. @@ -74,6 +154,9 @@ To build GauXC as part of your own CMake project, you can use the following snip set(Skala_GauXC_URL "https://github.com/microsoft/skala/releases/download/v1.0.0/gauxc-skala.tar.gz") set(Skala_GauXC_SHA "3368a4f8c968a295ad03363c5ccbee787f24f703df42c7b929a40e76f48bd324") + option(Skala_GauXC_ENABLE_OPENMP "Enable OpenMP support in GauXC" ON) + option(Skala_GauXC_ENABLE_MPI "Enable MPI support in GauXC" OFF) + option(Skala_GauXC_ENABLE_CUDA "Enable CUDA support in GauXC" OFF) find_package(gauxc QUIET) if(NOT gauxc_FOUND) @@ -84,6 +167,9 @@ To build GauXC as part of your own CMake project, you can use the following snip set(GAUXC_ENABLE_ONEDFT ON CACHE BOOL "" FORCE) set(GAUXC_ENABLE_TESTS OFF CACHE BOOL "" FORCE) + set(GAUXC_ENABLE_OPENMP ${Skala_GauXC_ENABLE_OPENMP} CACHE BOOL "" FORCE) + set(GAUXC_ENABLE_MPI ${Skala_GauXC_ENABLE_MPI} CACHE BOOL "" FORCE) + set(GAUXC_ENABLE_CUDA ${Skala_GauXC_ENABLE_CUDA} CACHE BOOL "" FORCE) FetchContent_Declare( gauxc @@ -95,6 +181,15 @@ To build GauXC as part of your own CMake project, you can use the following snip else() if(NOT ${GAUXC_HAS_ONEDFT}) - message(FATAL_ERROR "GauXC Found but without OneDFT Support Enabled") + message(FATAL_ERROR "GauXC found but without Skala support enabled") + endif() + if(${Skala_GauXC_ENABLE_OPENMP} AND NOT ${GAUXC_HAS_OPENMP}) + message(WARNING "GauXC Found with OpenMP support but Skala_GauXC_ENABLE_OPENMP is OFF") + endif() + if(${Skala_GauXC_ENABLE_MPI} AND NOT ${GAUXC_HAS_MPI}) + message(WARNING "GauXC Found with MPI support but Skala_GauXC_ENABLE_MPI is OFF") + endif() + if(${Skala_GauXC_ENABLE_CUDA} AND NOT ${GAUXC_HAS_CUDA}) + message(WARNING "GauXC Found with CUDA support but Skala_GauXC_ENABLE_CUDA is OFF") endif() endif() \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index e4e65d0..827b7ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ optional-dependencies.doc = [ "myst-nb", "sphinx", "sphinx-book-theme", + "sphinx-design", ] urls.repository = "https://github.com/microsoft/skala" From 759096108a965c0a2458cfe8f9060375c97de3c1 Mon Sep 17 00:00:00 2001 From: Sebastian Ehlert Date: Tue, 18 Nov 2025 13:46:37 +0100 Subject: [PATCH 03/12] Add list of dependencies to installation guide --- docs/gauxc/installation.rst | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/docs/gauxc/installation.rst b/docs/gauxc/installation.rst index 9b140e8..07cc168 100644 --- a/docs/gauxc/installation.rst +++ b/docs/gauxc/installation.rst @@ -6,6 +6,44 @@ For this tutorial, we will use the `mamba `__ installer. First, we will create a new environment with all the required dependencies for building GauXC with Skala support. +We provide three different configurations depending on whether you want to build GauXC with OpenMP, MPI, or CUDA support. + +.. dropdown:: GauXC dependencies + + The following dependencies are required for building GauXC with Skala support: + + - C/C++ compiler (with C++17 support) + - CMake (version 3.15 or higher) + - `exchcxx `__* (version 1 or higher) + - `libxc `__* (version 7 or higher) + - `integratorxx `__* (version 1 or higher) + - `gau2grid `__* (version 2.0.6 or higher) + - `libtorch `__ (CPU or CUDA version depending on your configuration) + - `nlohmann_json `__* (version 3.9.1 or higher) + - BLAS library (like OpenBLAS, MKL, etc.) + + When building with MPI support via ``-DGAUXC_ENABLE_MPI=on`` (default ``off``), + the following dependencies are also required: + + - MPI implementation (like OpenMPI, MPICH, etc.) + + When building with Cuda support via ``-DGAUXC_ENABLE_CUDA=on`` (default ``off``), + the following dependencies are also required: + + - CUDA toolkit + - `cuBLAS library `__ + - `Cutlass library `__* + - `CUB library `__* + + When building with HDF5 support via ``-DGAUXC_ENABLE_HDF5=on`` (default ``on``), + the following dependencies are also required: + + - `HDF5 `__ + - `HighFive `__* (version 2.4.0 or higher) + + All libraries marked with a * can be automatically fetched by the GauXC build system + and do not need to be installed manually. + For this, create a file named `environment.yml` with the following content: .. tab-set:: From 2867373480fc668cb4a7263516db4079e4e4be7b Mon Sep 17 00:00:00 2001 From: Sebastian Ehlert Date: Wed, 19 Nov 2025 09:12:59 +0100 Subject: [PATCH 04/12] Rework installation guide --- docs/gauxc/installation.rst | 276 +++++++++++++++++++++++++----------- 1 file changed, 194 insertions(+), 82 deletions(-) diff --git a/docs/gauxc/installation.rst b/docs/gauxc/installation.rst index 07cc168..0e410e4 100644 --- a/docs/gauxc/installation.rst +++ b/docs/gauxc/installation.rst @@ -2,6 +2,18 @@ Installing GauXC ================ In this section, we will provide instructions on how to install GauXC with Skala support based on the conda-forge ecosystem. +As part of this tutorial we will be + +* installing dependencies for building GauXC +* configuring GauXC with different options +* testing our the Skala implementation in GauXC +* installing the GauXC library +* reusing GauXC from the CMake build system + + +Prerequisites +------------- + For this tutorial, we will use the `mamba `__ package manager for setting up the environment and installing dependencies. If you do not have mamba installed, you can download the `miniforge `__ installer. @@ -14,12 +26,12 @@ We provide three different configurations depending on whether you want to build - C/C++ compiler (with C++17 support) - CMake (version 3.15 or higher) - - `exchcxx `__* (version 1 or higher) - - `libxc `__* (version 7 or higher) - - `integratorxx `__* (version 1 or higher) - - `gau2grid `__* (version 2.0.6 or higher) + - `exchcxx `__\ * (version 1 or higher) + - `libxc `__\ * (version 7 or higher) + - `integratorxx `__\ * (version 1 or higher) + - `gau2grid `__\ * (version 2.0.6 or higher) - `libtorch `__ (CPU or CUDA version depending on your configuration) - - `nlohmann_json `__* (version 3.9.1 or higher) + - `nlohmann_json `__\ * (version 3.9.1 or higher) - BLAS library (like OpenBLAS, MKL, etc.) When building with MPI support via ``-DGAUXC_ENABLE_MPI=on`` (default ``off``), @@ -32,14 +44,14 @@ We provide three different configurations depending on whether you want to build - CUDA toolkit - `cuBLAS library `__ - - `Cutlass library `__* - - `CUB library `__* + - `Cutlass library `__\ * + - `CUB library `__\ * When building with HDF5 support via ``-DGAUXC_ENABLE_HDF5=on`` (default ``on``), the following dependencies are also required: - `HDF5 `__ - - `HighFive `__* (version 2.4.0 or higher) + - `HighFive `__\ * (version 2.4.0 or higher) All libraries marked with a * can be automatically fetched by the GauXC build system and do not need to be installed manually. @@ -56,20 +68,20 @@ For this, create a file named `environment.yml` with the following content: name: gauxc-dev channels: - - conda-forge + - conda-forge dependencies: - # build requirements - - c-compiler - - cxx-compiler - - cmake - - ninja - - nlohmann_json - # host requirements - - exchcxx >=1.0 - - gau2grid >=2.0.6 - - hdf5 - - libblas - - pytorch * cpu* + # build requirements + - c-compiler + - cxx-compiler + - cmake >=3.15,<4 + - ninja + - nlohmann_json >=3.9 + # host/runtime requirements + - exchcxx >=1.0 + - gau2grid >=2.0.6 + - hdf5 + - libblas + - pytorch >=2.0 cpu_* .. tab-item:: MPI @@ -78,21 +90,21 @@ For this, create a file named `environment.yml` with the following content: name: gauxc-dev channels: - - conda-forge + - conda-forge dependencies: - # build requirements - - c-compiler - - cxx-compiler - - cmake - - ninja - - nlohmann_json - # host requirements - - openmpi # or mpich - - exchcxx >=1.0 - - gau2grid >=2.0.6 - - hdf5 * mpi_* - - libblas - - pytorch * cpu* + # build requirements + - c-compiler + - cxx-compiler + - cmake >=3.15,<4 + - ninja + - nlohmann_json >=3.9 + # host/runtime requirements + - openmpi # pick mpich if that matches your stack + - exchcxx >=1.0 + - gau2grid >=2.0.6 + - hdf5 * mpi_* + - libblas + - pytorch >=2.0 cpu_* .. tab-item:: CUDA @@ -101,38 +113,62 @@ For this, create a file named `environment.yml` with the following content: name: gauxc-dev channels: - - conda-forge + - conda-forge dependencies: - # build requirements - - c-compiler - - cxx-compiler - - cuda-compiler - - cmake - - ninja - - nlohmann_json - # host requirements - - gau2grid >=2.0.6 - - hdf5 - - libblas - - pytorch * cuda* - -Then, run the following commands to create and activate the new environment: + # build requirements + - c-compiler + - cxx-compiler + - cuda-compiler + - cmake >=3.15,<4 + - ninja + - nlohmann_json >=3.9 + # host/runtime requirements + - gau2grid >=2.0.6 + - hdf5 + - libblas + - pytorch >=2.0 cuda* + +Create and activate the environment: .. code-block:: none mamba env create -n gauxc-dev -f environment.yml mamba activate gauxc-dev -Next, we will download the GauXC source code with Skala support. -We provide a pre-packaged version of GauXC with Skala integration that can be downloaded from the Skala releases page. -Run the following command to download and extract the source code: +Verify that the toolchain is visible: + +.. code-block:: bash + + cmake --version + python -c "import torch; print(torch.__version__)" + + +Obtain GauXC with Skala +----------------------- + +Download the pre-packaged source bundle from the Skala release page: .. code-block:: none - curl -JL https://github.com/microsoft/skala/releases/download/v1.0.0/gauxc-skala.tar.gz > gauxc-skala.tar.gz | tar xzv + curl -L https://github.com/microsoft/skala/releases/download/v1.0.0/gauxc-skala.tar.gz | tar xzv + +.. tip:: + + To verify the downloaded tarball you can obtain a checksum -Now we can build GauXC with Skala support using CMake and Ninja. -Create a build directory and run the following commands to configure and build the library: + .. code-block:: none + + curl -L https://github.com/microsoft/skala/releases/download/v1.0.0/gauxc-skala.tar.gz > gauxc-skala.tar.gz + curl -L https://github.com/microsoft/skala/releases/download/v1.0.0/gauxc-skala.tar.gz.sha256 | sha256sum -c + tar xzvf gauxc-skala.tar.gz + +The archive expands into a ``gauxc`` directory that already contains the Skala patches. + + +Configure and build +------------------- + +Create an out-of-tree build directory and pick the configuration that matches your backend. .. tab-set:: :sync-group: config @@ -141,62 +177,115 @@ Create a build directory and run the following commands to configure and build t .. code-block:: none - cmake -B _build -S gauxc -G Ninja -DGAUXC_ENABLE_MPI=no -DGAUXC_ENABLE_OPENMP=yes -DGAUXC_ENABLE_CUDA=no -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} - cmake --build _build + cmake -B build -S gauxc -G Ninja \ + -DGAUXC_ENABLE_OPENMP=on \ + -DGAUXC_ENABLE_MPI=off \ + -DGAUXC_ENABLE_CUDA=off \ + -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} + cmake --build build .. tab-item:: MPI .. code-block:: none - cmake -B _build -S gauxc -G Ninja -DGAUXC_ENABLE_MPI=yes -DGAUXC_ENABLE_OPENMP=yes -DGAUXC_ENABLE_CUDA=no -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} - cmake --build _build + cmake -B build -S gauxc -G Ninja \ + -DGAUXC_ENABLE_OPENMP=on \ + -DGAUXC_ENABLE_MPI=on \ + -DGAUXC_ENABLE_CUDA=off \ + -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} + cmake --build build .. tab-item:: CUDA .. code-block:: none - cmake -B _build -S gauxc -G Ninja -DGAUXC_ENABLE_MPI=no -DGAUXC_ENABLE_OPENMP=yes -DGAUXC_ENABLE_CUDA=yes -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} - cmake --build _build + cmake -B build -S gauxc -G Ninja \ + -DGAUXC_ENABLE_OPENMP=on \ + -DGAUXC_ENABLE_MPI=off \ + -DGAUXC_ENABLE_CUDA=on \ + -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} + cmake --build build -We can check the Skala implementation by evaluating a traditional density functional via the Skala driver. -In the GauXC test directory we have checkpoints for the PBE and TPSS functionals that can be used for testing. -To run the test via the standalone driver of GauXC, we can use the following command: +.. tip:: -.. code-block:: none + If CMake cannot find libtorch, the ``Torch_DIR`` variable can be set to help discover the package. + For conda-forge installed pytorch this should be set as ``-DTorch_DIR=${CONDA_PREFIX}/share/cmake/Torch`` + and for pip installed pytorch the CMake config file will be in ``${CONDA_PREFIX}/lib/python3.11/site-packages/torch/share/cmake/Torch`` + where the Python version should be adjusted accordingly to the environment. + + +Quick verification +------------------ + +After the build finishes, run the bundled regression test to confirm that Skala-enabled functionals +are working correctly. The Skala implementation can run different traditional functionals, like PBE and TPSS, +which can be compared against other libraries. + +.. code-block:: bash cd gauxc/tests/ref_data - ../../../_build/tests/standalone_driver onedft_input.inp + ../../../build/tests/standalone_driver onedft_input.inp -This will evaluate the TPSS exchange-correlation functional via the Skala driver on a provided density matrix. +Expected output includes the total TPSS energy computed using a checkpoint compatible for the Skala implementation +for the reference density matrix. -To use GauXC in your project install the built library into your conda environment: +.. tip:: + + If the executable cannot locate libtorch or other shared libraries, double-check + that ``LD_LIBRARY_PATH`` includes ``${CONDA_PREFIX}/lib`` + (activating the environment usually handles this). -.. code-block:: none - cmake --install _build +Install the library +------------------- + +Install into the active conda environment so downstream projects can pick up the CMake config files. + +.. code-block:: bash + + cmake --install build + +This installs headers, libraries, and CMake config. + -Finally, you can link against the GauXC library in your own electronic structure package to use Skala as an exchange-correlation functional. -This can be done by linking against the `gauxc` target in your CMake build system. +Integrate with your codebase +---------------------------- + +Using an installed GauXC +~~~~~~~~~~~~~~~~~~~~~~~~ + +Add the following to your CMake project, ensuring that ``CMAKE_PREFIX_PATH`` contains +``${CONDA_PREFIX}`` (activation scripts typically set this). .. code-block:: cmake - find_package(gauxc REQUIRED) - if(NOT ${GAUXC_HAS_ONEDFT}) - message(FATAL_ERROR "GauXC found but without Skala support enabled") + find_package(gauxc CONFIG REQUIRED) + + if(NOT gauxc_HAS_ONEDFT) + message(FATAL_ERROR "GauXC found but Skala/OneDFT was not enabled during the build") endif() - target_link_libraries(${PROJECT_NAME} PRIVATE gauxc::gauxc) -To build GauXC as part of your own CMake project, you can use the following snippet to include it via FetchContent. + target_link_libraries(my_dft_driver PRIVATE gauxc::gauxc) + +The imported target propagates include directories, compile definitions, and linkage against BLAS, +Torch, and optional MPI/CUDA components. + +Embedding GauXC via FetchContent +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you need to vend GauXC directly from your build, use ``FetchContent`` while mirroring the +options chosen above. .. code-block:: cmake set(Skala_GauXC_URL "https://github.com/microsoft/skala/releases/download/v1.0.0/gauxc-skala.tar.gz") - set(Skala_GauXC_SHA "3368a4f8c968a295ad03363c5ccbee787f24f703df42c7b929a40e76f48bd324") + set(Skala_GauXC_SHA256 "3368a4f8c968a295ad03363c5ccbee787f24f703df42c7b929a40e76f48bd324") + option(Skala_GauXC_ENABLE_OPENMP "Enable OpenMP support in GauXC" ON) option(Skala_GauXC_ENABLE_MPI "Enable MPI support in GauXC" OFF) option(Skala_GauXC_ENABLE_CUDA "Enable CUDA support in GauXC" OFF) - find_package(gauxc QUIET) + find_package(gauxc QUIET CONFIG) if(NOT gauxc_FOUND) include(FetchContent) @@ -212,7 +301,7 @@ To build GauXC as part of your own CMake project, you can use the following snip FetchContent_Declare( gauxc URL ${Skala_GauXC_URL} - URL_HASH SHA256=${Skala_GauXC_SHA} + URL_HASH SHA256=${Skala_GauXC_SHA256} DOWNLOAD_EXTRACT_TIMESTAMP ON ) FetchContent_MakeAvailable(gauxc) @@ -230,4 +319,27 @@ To build GauXC as part of your own CMake project, you can use the following snip if(${Skala_GauXC_ENABLE_CUDA} AND NOT ${GAUXC_HAS_CUDA}) message(WARNING "GauXC Found with CUDA support but Skala_GauXC_ENABLE_CUDA is OFF") endif() - endif() \ No newline at end of file + endif() + +Troubleshooting +--------------- + +Torch not found + ensure ``Torch_DIR`` points to the libtorch CMake package inside the active environment, + or export ``Torch_DIR`` before running CMake. + +CUDA mismatch + the CUDA toolkit selected by conda must match the version baked into the + ``pytorch`` build; reinstall ``pytorch`` if necessary (e.g., ``pytorch ==2.3.* cuda118*``). + +Linker errors for BLAS/MPI + verify that the conda environment stayed active during the build and that ``cmake`` picked + the toolchain from ``${CONDA_PREFIX}`` via ``CMAKE_PREFIX_PATH``. + +Standalone driver cannot find densities + run it from ``gauxc/tests/ref_data`` since paths in density files are specified relative to the + current directory. + +.. note:: + + Need help? Open an issue on the `Skala repository `__. \ No newline at end of file From c9d4f618a889269c04ca7adc00cc67554b5f768c Mon Sep 17 00:00:00 2001 From: Sebastian Ehlert Date: Tue, 9 Dec 2025 13:34:42 +0000 Subject: [PATCH 05/12] Reformat --- src/skala/gauxc/__init__.py | 0 src/skala/gauxc/export.py | 131 ++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 src/skala/gauxc/__init__.py create mode 100644 src/skala/gauxc/export.py diff --git a/src/skala/gauxc/__init__.py b/src/skala/gauxc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/skala/gauxc/export.py b/src/skala/gauxc/export.py new file mode 100644 index 0000000..9fafbe8 --- /dev/null +++ b/src/skala/gauxc/export.py @@ -0,0 +1,131 @@ +import h5py +import numpy as np + +from pyscf import gto + +MOLECULE_DTYPE = { + "names": ["Atomic Number", "X Coordinate", "Y Coordinate", "Z Coordinate"], + "formats": [" None: + data = pyscf_to_gauxc_h5(mol, dm) + with h5py.File(filename, "w") as fd: + for key, value in data.items(): + fd.create_dataset(key, data=value) + + +def pyscf_to_gauxc_h5(mol: gto.Mole, dm: np.ndarray) -> dict[str, np.ndarray]: + molecule = np.array( + [ + (number, *coords) + for number, coords in zip(mol.atom_charges(), mol.atom_coords(unit="Bohr"), strict=True) + ], + dtype=MOLECULE_DTYPE, + ) + basis = np.array( + [ + format_basis( + func[0], + mol.cart, + [pair[0] for pair in func[1:]], + [pair[prim] for pair in func[1:]], + coord, + ) + for atom, coord in mol._atom + for func in mol._basis[atom] + for prim in range(1, len(func[1])) + ], + dtype=BASIS_DTYPE, + ) + dm_scalar = dm if dm.ndim == 2 else dm[0] + dm[1] + dm_z = np.zeros_like(dm) if dm.ndim == 2 else dm[0] - dm[1] + + return { + "MOLECULE": molecule, + "BASIS": basis, + "DENSITY_SCALAR": dm_scalar, + "DENSITY_Z": dm_z, + } + + +def norm(coeff: list[float], alpha: list[float], l: int) -> list[float]: + """ + Normalize contraction coefficients for a given angular momentum and exponents + using libint normalization conventions. + """ + alpha = np.asarray(alpha) + two_alpha = 2 * alpha + two_alpha_to_am32 = two_alpha ** (l + 1) * np.sqrt(two_alpha) + normalization_factor = np.sqrt(2**l * two_alpha_to_am32 / (SQRT_PI_CUBED * K_MINUS_1[2 * l])) + gamma = alpha[:, np.newaxis] + alpha[np.newaxis, :] + aa = K_MINUS_1[2 * l] * SQRT_PI_CUBED / (2**l * gamma ** (l + 1) * np.sqrt(gamma)) + coeff = coeff * normalization_factor + normalization_factor = 1.0 / np.sqrt(np.einsum("i,j,ij->", coeff, coeff, aa)) + return (coeff * normalization_factor).tolist() + + +def format_basis( + l: int, + cart: bool, + alpha: list[float], + coeff: list[float], + coord: list[float], + padv: float = 0.0, + padl: int = 16, +) -> tuple[int, int, int, list[float], list[float], list[float]]: + return ( + len(alpha), + l, + 0 if cart or l == 1 else 1, + alpha + [padv] * (padl - len(alpha)), + norm(coeff, alpha, l) + [padv] * (padl - len(coeff)), + coord, + ) From c2e64af4e2a5c2480f85171aa5e09237a0acd50e Mon Sep 17 00:00:00 2001 From: Sebastian Ehlert Date: Sat, 3 Jan 2026 15:14:19 +0100 Subject: [PATCH 06/12] Update installation with newer GauXC source --- docs/gauxc/installation.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/gauxc/installation.rst b/docs/gauxc/installation.rst index 0e410e4..6c4f087 100644 --- a/docs/gauxc/installation.rst +++ b/docs/gauxc/installation.rst @@ -123,6 +123,7 @@ For this, create a file named `environment.yml` with the following content: - ninja - nlohmann_json >=3.9 # host/runtime requirements + - libxc >=7,<8 - gau2grid >=2.0.6 - hdf5 - libblas @@ -150,7 +151,7 @@ Download the pre-packaged source bundle from the Skala release page: .. code-block:: none - curl -L https://github.com/microsoft/skala/releases/download/v1.0.0/gauxc-skala.tar.gz | tar xzv + curl -L https://github.com/microsoft/skala/releases/download/v1.1.0/gauxc-skala.tar.gz | tar xzv .. tip:: @@ -158,8 +159,8 @@ Download the pre-packaged source bundle from the Skala release page: .. code-block:: none - curl -L https://github.com/microsoft/skala/releases/download/v1.0.0/gauxc-skala.tar.gz > gauxc-skala.tar.gz - curl -L https://github.com/microsoft/skala/releases/download/v1.0.0/gauxc-skala.tar.gz.sha256 | sha256sum -c + curl -L https://github.com/microsoft/skala/releases/download/v1.1.0/gauxc-skala.tar.gz > gauxc-skala.tar.gz + curl -L https://github.com/microsoft/skala/releases/download/v1.1.0/gauxc-skala.tar.gz.sha256 | sha256sum -c tar xzvf gauxc-skala.tar.gz The archive expands into a ``gauxc`` directory that already contains the Skala patches. @@ -278,8 +279,8 @@ options chosen above. .. code-block:: cmake - set(Skala_GauXC_URL "https://github.com/microsoft/skala/releases/download/v1.0.0/gauxc-skala.tar.gz") - set(Skala_GauXC_SHA256 "3368a4f8c968a295ad03363c5ccbee787f24f703df42c7b929a40e76f48bd324") + set(Skala_GauXC_URL "https://github.com/microsoft/skala/releases/download/v1.1.0/gauxc-skala.tar.gz") + set(Skala_GauXC_SHA256 "ed3102485f6d838c8076a03162b11a1d7c3fd52b212ba6a048db2e9089c98f3c") option(Skala_GauXC_ENABLE_OPENMP "Enable OpenMP support in GauXC" ON) option(Skala_GauXC_ENABLE_MPI "Enable MPI support in GauXC" OFF) From e42c4c9b857131e371d4796db93136484c7a7875 Mon Sep 17 00:00:00 2001 From: Sebastian Ehlert Date: Sat, 3 Jan 2026 15:34:32 +0100 Subject: [PATCH 07/12] Add tests for gauxc export --- environment-cpu.yml | 1 + environment-gpu.yml | 1 + tests/test_gauxc_export.py | 52 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 tests/test_gauxc_export.py diff --git a/environment-cpu.yml b/environment-cpu.yml index f52912e..ebbf414 100644 --- a/environment-cpu.yml +++ b/environment-cpu.yml @@ -7,6 +7,7 @@ dependencies: - azure-identity - dftd3-python - e3nn + - h5py - numpy - opt_einsum_fx - pyscf<2.10.0 diff --git a/environment-gpu.yml b/environment-gpu.yml index 7d987ed..e22effb 100644 --- a/environment-gpu.yml +++ b/environment-gpu.yml @@ -7,6 +7,7 @@ dependencies: - azure-identity - dftd3-python - e3nn + - h5py - numpy - opt_einsum_fx - pyscf<2.10.0 diff --git a/tests/test_gauxc_export.py b/tests/test_gauxc_export.py new file mode 100644 index 0000000..c310440 --- /dev/null +++ b/tests/test_gauxc_export.py @@ -0,0 +1,52 @@ +from tempfile import NamedTemporaryFile + +import h5py +import numpy as np +import pytest + +from pyscf import dft, gto +from skala.gauxc.export import write_gauxc_h5_from_pyscf + + +@pytest.fixture(params=["He", "Li"]) +def mol_name(request) -> str: + return request.param + + +@pytest.fixture +def basis() -> str: + return "def2-svp" + + +@pytest.fixture(params=["cart", "sph"]) +def cartesian(request) -> bool: + return request.param == "cart" + + +@pytest.fixture +def mol(mol_name: str, basis: str, cartesian: bool) -> gto.Mole: + match mol_name: + case "He": + return gto.M(atom="He 0 0 0", basis=basis, cart=cartesian, unit="Bohr", spin=0) + case "Li": + return gto.M(atom="Li 0 0 0", basis=basis, cart=cartesian, unit="Bohr", spin=1) + case _: + raise ValueError(f"Unknown molecule name: {mol_name}") + + +@pytest.fixture +def dm(mol: gto.Mole) -> np.ndarray: + ks = dft.KS(mol, xc="pbe") + ks.kernel() + return ks.make_rdm1() + + +def test_write_pyscf(mol: gto.Mole, dm: np.ndarray) -> None: + with NamedTemporaryFile(suffix=".h5") as tmp: + write_gauxc_h5_from_pyscf(tmp.name, mol, dm) + + with h5py.File(tmp.name, "r") as h5: + assert "MOLECULE" in h5 + assert "BASIS" in h5 + assert "DENSITY_SCALAR" in h5 + assert "DENSITY_Z" in h5 \ No newline at end of file From fb69900d93859e9b9edc971a71c0ae8a6417a188 Mon Sep 17 00:00:00 2001 From: Sebastian Ehlert Date: Mon, 5 Jan 2026 15:20:40 +0100 Subject: [PATCH 08/12] Also export exc and vxc in h5 file if provided --- src/skala/gauxc/export.py | 18 ++++++++++++++---- tests/test_gauxc_export.py | 35 ++++++++++++++++++++++++++++------- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/skala/gauxc/export.py b/src/skala/gauxc/export.py index 9fafbe8..227b2eb 100644 --- a/src/skala/gauxc/export.py +++ b/src/skala/gauxc/export.py @@ -55,14 +55,14 @@ ] -def write_gauxc_h5_from_pyscf(filename: str, mol: gto.Mole, dm: np.ndarray) -> None: - data = pyscf_to_gauxc_h5(mol, dm) +def write_gauxc_h5_from_pyscf(filename: str, mol: gto.Mole, dm: np.ndarray, exc: float | None = None, vxc: np.ndarray | None = None) -> None: + data = pyscf_to_gauxc_h5(mol, dm, exc, vxc) with h5py.File(filename, "w") as fd: for key, value in data.items(): fd.create_dataset(key, data=value) -def pyscf_to_gauxc_h5(mol: gto.Mole, dm: np.ndarray) -> dict[str, np.ndarray]: +def pyscf_to_gauxc_h5(mol: gto.Mole, dm: np.ndarray, exc: float | None = None, vxc: np.ndarray | None = None) -> dict[str, np.ndarray]: molecule = np.array( [ (number, *coords) @@ -88,13 +88,23 @@ def pyscf_to_gauxc_h5(mol: gto.Mole, dm: np.ndarray) -> dict[str, np.ndarray]: dm_scalar = dm if dm.ndim == 2 else dm[0] + dm[1] dm_z = np.zeros_like(dm) if dm.ndim == 2 else dm[0] - dm[1] - return { + data = { "MOLECULE": molecule, "BASIS": basis, "DENSITY_SCALAR": dm_scalar, "DENSITY_Z": dm_z, } + if exc is not None: + data["EXC"] = exc + if vxc is not None: + vxc_scalar = vxc if vxc.ndim == 2 else vxc[0] + vxc[1] + vxc_z = np.zeros_like(vxc) if vxc.ndim == 2 else vxc[0] - vxc[1] + data["VXC_SCALAR"] = vxc_scalar + data["VXC_Z"] = vxc_z + + return data + def norm(coeff: list[float], alpha: list[float], l: int) -> list[float]: """ diff --git a/tests/test_gauxc_export.py b/tests/test_gauxc_export.py index c310440..4069614 100644 --- a/tests/test_gauxc_export.py +++ b/tests/test_gauxc_export.py @@ -35,18 +35,39 @@ def mol(mol_name: str, basis: str, cartesian: bool) -> gto.Mole: @pytest.fixture -def dm(mol: gto.Mole) -> np.ndarray: +def ks(mol: gto.Mole) -> dft.rks.RKS: ks = dft.KS(mol, xc="pbe") ks.kernel() + return ks + +@pytest.fixture +def dm(ks: dft.rks.RKS) -> np.ndarray: return ks.make_rdm1() +@pytest.fixture +def exc(ks: dft.rks.RKS) -> float: + return ks.scf_summary["exc"] + + +@pytest.fixture +def vxc(ks: dft.rks.RKS, dm: np.ndarray) -> np.ndarray: + if dm.ndim == 2: + _, _, vxc = ks._numint.nr_rks(ks.mol, ks.grids, ks.xc, dm) + else: + _, _, vxc = ks._numint.nr_uks(ks.mol, ks.grids, ks.xc, dm) + return vxc + + -def test_write_pyscf(mol: gto.Mole, dm: np.ndarray) -> None: +def test_write_pyscf(mol: gto.Mole, dm: np.ndarray, mol_name, basis, exc, vxc) -> None: with NamedTemporaryFile(suffix=".h5") as tmp: - write_gauxc_h5_from_pyscf(tmp.name, mol, dm) + write_gauxc_h5_from_pyscf(tmp.name, mol, dm, exc, vxc) with h5py.File(tmp.name, "r") as h5: - assert "MOLECULE" in h5 - assert "BASIS" in h5 - assert "DENSITY_SCALAR" in h5 - assert "DENSITY_Z" in h5 \ No newline at end of file + assert "MOLECULE" in h5, "Molecule is missing in h5 export" + assert "BASIS" in h5, "Basis is missing in h5 export" + assert "DENSITY_SCALAR" in h5, "Density (a+b) is missing in h5 export" + assert "DENSITY_Z" in h5, "Density (a-b) is missing in h5 export" + assert "EXC" in h5, "Exchange-correlation energy is missing in h5 export" + assert "VXC_SCALAR" in h5, "Exchange-correlation potential (a+b) is missing in h5 export" + assert "VXC_Z" in h5, "Exchange-correlation potential (a-b) is missing in h5 export" \ No newline at end of file From 5f933552535a54417c1203e0e0b4270274817f52 Mon Sep 17 00:00:00 2001 From: Sebastian Ehlert Date: Tue, 6 Jan 2026 11:16:09 +0100 Subject: [PATCH 09/12] Add guide on standalone driver --- docs/gauxc/index.rst | 1 + docs/gauxc/installation.rst | 2 + docs/gauxc/standalone.rst | 227 ++++++++++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 docs/gauxc/standalone.rst diff --git a/docs/gauxc/index.rst b/docs/gauxc/index.rst index 56304ce..1e2b55f 100644 --- a/docs/gauxc/index.rst +++ b/docs/gauxc/index.rst @@ -9,3 +9,4 @@ The following sections provide instructions on how to install GauXC with Skala s .. toctree:: installation + standalone diff --git a/docs/gauxc/installation.rst b/docs/gauxc/installation.rst index 6c4f087..effbfa0 100644 --- a/docs/gauxc/installation.rst +++ b/docs/gauxc/installation.rst @@ -1,3 +1,5 @@ +.. _gauxc_install: + Installing GauXC ================ diff --git a/docs/gauxc/standalone.rst b/docs/gauxc/standalone.rst new file mode 100644 index 0000000..794e2be --- /dev/null +++ b/docs/gauxc/standalone.rst @@ -0,0 +1,227 @@ +GauXC standalone usage +====================== + +The GauXC package comes with a standalone driver for testing the evaluation of the exchange-correlation energy with different functionals. +In this tutorial we will use the standalone driver to evaluate Skala based on density matrices computed with different packages. + +.. note:: + + For building GauXC and running the standalone driver checkout :ref:`install_gauxc`. + +Create GauXC compatible input +----------------------------- + +We will use the ``skala`` package to write a GauXC compatible input for our calculation. +For this we will run a PySCF calculation and write the molecule, basis set and density matrix in the format expected by GauXC. +In this example we will use a single one atom system in a small basis set. + +.. note:: + + We will write the input data as HDF5 file since GauXC can read its objects directly from HDF5 datasets. + The format in the HDF5 file does correpond to the internal structure of GauXC objects and therefore allows us to conveniently inspect the data. + +.. code-block:: python + + from pyscf import gto + + from skala.gauxc.export import write_gauxc_h5_from_pyscf + from skala.pyscf import SkalaRKS + + mol = gto.M(atom="He 0 0 0", basis="def2-svp", unit="Bohr", spin=0) + ks = SkalaRKS(xc="pbe") + ks.kernel() + + dm = ks.make_rdm1() + exc = ks.scf_summary["exc"] + _, _, vxc = ks._numint.nr_rks(ks.mol, ks.grids, ks.xc, dm) + + write_gauxc_h5_from_pyscf("He_def2svp.h5", mol, dm=dm, exc=exc, vxc=vxc) + +Additionally to the inputs (molecule, basis set, and density matrix) we provide the exchange-correlation energy and potential to allow the standalone driver to compare against our reference calculation. + +Running the GauXC standalone driver +----------------------------------- + +The GauXC standalone driver takes a single input file, where we need to specify the path of our HDF5 file with the input data. +In the input file we specify the ``ONEDFT_MODEL`` as PBE since we used it for our input calculation as well. +Furthermore, we have parameters like ``grid``, ``pruning_scheme``, etc. which define the integration grid settings in GauXC, here we go with a fine grid, Mura-Knowles radial integration scheme and the robust pruning scheme of Psi4. + +.. code-block:: ini + :caption: gauxc_input.inp + + [GAUXC] + ref_file = He_def2svp.h5 + ONEDFT_MODEL = PBE + grid = Fine + pruning_scheme = Robust + RAD_QUAD = MuraKnowles + batch_size = 512 + basis_tol = 2.22e-16 + LB_EXEC_SPACE = Device + INT_EXEC_SPACE = Device + REDUCTION_KERNEL = Default + MEMORY_SIZE = 0.1 + +.. note:: + + Make sure the HDF5 file ``He_def2svp.h5`` is in the same directory as the one where we start the standalone driver. + +To run the standalone driver with this input we run it from the build directory with our input file: + +.. code-block:: text + + ./build/tests/standalone_driver gauxc_input.inp + +For a successful run we will see the following output + +.. code-block:: text + + DRIVER SETTINGS: + REF_FILE = He_def2svp.h5 + GRID = FINE + RAD_QUAD = MURAKNOWLES + PRUNING_SCHEME = ROBUST + BATCH_SIZE = 512 + BASIS_TOL = 2.22e-16 + FUNCTIONAL = PBE0 + LB_EXEC_SPACE = DEVICE + INT_EXEC_SPACE = DEVICE + INTEGRATOR_KERNEL = DEFAULT + LWD_KERNEL = DEFAULT + REDUCTION_KERNEL = DEFAULT + DEN (?) = false + VXC (?) = true + EXX (?) = false + EXC_GRAD (?) = false + DD_PSI (?) = false + DD_PSI_POTENTIAL (?) = false + ONEDFT_MODEL = PBE + FXC_CONTRACTION (?) = false + MEMORY_SIZE = 0.1 + + EXC: -1.054031868349e+00 + EXC = -1.054031868349e+00 + + Load Balancer Timings + LoadBalancer.CreateTasks: 1.50510e+01 ms + MolecularWeights Timings + MolecularWeights: 2.98569e+01 ms + Integrator Timings + XCIntegrator.Allreduce: 4.11500e-03 ms + XCIntegrator.LocalWork: 2.35691e+01 ms + XCIntegrator.LocalWork2: 9.11679e+00 ms + XC Int Duration = 3.35111170000000e-01 s + EXC (ref) = -1.05403142675144e+00 + EXC (calc) = -1.05403186834886e+00 + EXC Diff = -4.18960391377858e-07 + | VXC (ref) |_F = 1.45598265614311e+00 + | VXC (calc) |_F = 1.45598296606474e+00 + RMS VXC Diff = 7.43706533247358e-08 + | VXCz (ref) |_F = 0.00000000000000e+00 + | VXCz (calc) |_F = 0.00000000000000e+00 + RMS VXCz Diff = 0.00000000000000e+00 + +We find a reasonable difference between PySCF and GauXC computed exchange-correlation energy and potential. + +.. note:: + + We can converge this value further by choosing finer grid settings both in PySCF and GauXC. + +Inspecting the GauXC input data +------------------------------- + +Now that we verified that GauXC can evaluate based on our PySCF produced input data, we will have a closer look of what we sent to GauXC. +For this we will inspect our HDF5 input data more closely. + +.. code-block:: ipython + + In [1]: import h5py + ...: import numpy as np + + In [2]: with h5py.File("He_def2-svp.h5") as h5: + ...: molecule = np.asarray(h5["MOLECULE"]) + ...: basis = np.asarray(h5["BASIS"]) + ...: dm_scalar = np.asarray(h5["DENSITY_SCALAR"]) + ...: dm_z = np.asarray(h5["DENSITY_Z"]) + ...: + +First, we inspect the molecule format which represents follows an array of structs format, combining the atomic number together with the cartesian coordinates in Bohr. +For our Helium example we expect a single entry centered at the origin: + +.. code-block:: ipython + + In [3]: molecule.shape + Out[3]: (1,) + + In [4]: molecule.dtype + Out[4]: dtype({'names': ['Atomic Number', 'X Coordinate', 'Y Coordinate', 'Z Coordinate'], 'formats': [' Date: Thu, 8 Jan 2026 08:52:07 +0100 Subject: [PATCH 10/12] Update standalone guide --- docs/gauxc/standalone.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/gauxc/standalone.rst b/docs/gauxc/standalone.rst index 794e2be..ee4567e 100644 --- a/docs/gauxc/standalone.rst +++ b/docs/gauxc/standalone.rst @@ -4,9 +4,9 @@ GauXC standalone usage The GauXC package comes with a standalone driver for testing the evaluation of the exchange-correlation energy with different functionals. In this tutorial we will use the standalone driver to evaluate Skala based on density matrices computed with different packages. -.. note:: +.. tip:: - For building GauXC and running the standalone driver checkout :ref:`install_gauxc`. + For building GauXC and running the standalone driver checkout :ref:`gauxc_install`. Create GauXC compatible input ----------------------------- @@ -28,7 +28,7 @@ In this example we will use a single one atom system in a small basis set. from skala.pyscf import SkalaRKS mol = gto.M(atom="He 0 0 0", basis="def2-svp", unit="Bohr", spin=0) - ks = SkalaRKS(xc="pbe") + ks = SkalaRKS(mol, xc="pbe") ks.kernel() dm = ks.make_rdm1() @@ -62,7 +62,7 @@ Furthermore, we have parameters like ``grid``, ``pruning_scheme``, etc. which de REDUCTION_KERNEL = Default MEMORY_SIZE = 0.1 -.. note:: +.. tip:: Make sure the HDF5 file ``He_def2svp.h5`` is in the same directory as the one where we start the standalone driver. @@ -123,7 +123,7 @@ For a successful run we will see the following output We find a reasonable difference between PySCF and GauXC computed exchange-correlation energy and potential. -.. note:: +.. tip:: We can converge this value further by choosing finer grid settings both in PySCF and GauXC. @@ -160,7 +160,7 @@ For our Helium example we expect a single entry centered at the origin: Out[5]: np.void((2, 0.0, 0.0, 0.0), dtype={'names': ['Atomic Number', 'X Coordinate', 'Y Coordinate', 'Z Coordinate'], 'formats': [' Date: Thu, 8 Jan 2026 13:17:05 +0100 Subject: [PATCH 11/12] Cleanup export, formatting, update file name --- docs/gauxc/standalone.rst | 8 ++++---- src/skala/gauxc/export.py | 30 +++++++++++++++++++++++------- tests/test_gauxc_export.py | 23 ++++++++++++++++------- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/docs/gauxc/standalone.rst b/docs/gauxc/standalone.rst index ee4567e..9cc1f05 100644 --- a/docs/gauxc/standalone.rst +++ b/docs/gauxc/standalone.rst @@ -35,7 +35,7 @@ In this example we will use a single one atom system in a small basis set. exc = ks.scf_summary["exc"] _, _, vxc = ks._numint.nr_rks(ks.mol, ks.grids, ks.xc, dm) - write_gauxc_h5_from_pyscf("He_def2svp.h5", mol, dm=dm, exc=exc, vxc=vxc) + write_gauxc_h5_from_pyscf("He_def2-svp.h5", mol, dm=dm, exc=exc, vxc=vxc) Additionally to the inputs (molecule, basis set, and density matrix) we provide the exchange-correlation energy and potential to allow the standalone driver to compare against our reference calculation. @@ -50,7 +50,7 @@ Furthermore, we have parameters like ``grid``, ``pruning_scheme``, etc. which de :caption: gauxc_input.inp [GAUXC] - ref_file = He_def2svp.h5 + ref_file = He_def2-svp.h5 ONEDFT_MODEL = PBE grid = Fine pruning_scheme = Robust @@ -64,7 +64,7 @@ Furthermore, we have parameters like ``grid``, ``pruning_scheme``, etc. which de .. tip:: - Make sure the HDF5 file ``He_def2svp.h5`` is in the same directory as the one where we start the standalone driver. + Make sure the HDF5 file ``He_def2-svp.h5`` is in the same directory as the one where we start the standalone driver. To run the standalone driver with this input we run it from the build directory with our input file: @@ -77,7 +77,7 @@ For a successful run we will see the following output .. code-block:: text DRIVER SETTINGS: - REF_FILE = He_def2svp.h5 + REF_FILE = He_def2-svp.h5 GRID = FINE RAD_QUAD = MURAKNOWLES PRUNING_SCHEME = ROBUST diff --git a/src/skala/gauxc/export.py b/src/skala/gauxc/export.py index 227b2eb..c252fc6 100644 --- a/src/skala/gauxc/export.py +++ b/src/skala/gauxc/export.py @@ -1,6 +1,5 @@ import h5py import numpy as np - from pyscf import gto MOLECULE_DTYPE = { @@ -55,18 +54,31 @@ ] -def write_gauxc_h5_from_pyscf(filename: str, mol: gto.Mole, dm: np.ndarray, exc: float | None = None, vxc: np.ndarray | None = None) -> None: +def write_gauxc_h5_from_pyscf( + filename: str, + mol: gto.Mole, + dm: np.ndarray, + exc: float | None = None, + vxc: np.ndarray | None = None, +) -> None: data = pyscf_to_gauxc_h5(mol, dm, exc, vxc) with h5py.File(filename, "w") as fd: for key, value in data.items(): fd.create_dataset(key, data=value) -def pyscf_to_gauxc_h5(mol: gto.Mole, dm: np.ndarray, exc: float | None = None, vxc: np.ndarray | None = None) -> dict[str, np.ndarray]: +def pyscf_to_gauxc_h5( + mol: gto.Mole, + dm: np.ndarray, + exc: float | None = None, + vxc: np.ndarray | None = None, +) -> dict[str, np.ndarray]: molecule = np.array( [ (number, *coords) - for number, coords in zip(mol.atom_charges(), mol.atom_coords(unit="Bohr"), strict=True) + for number, coords in zip( + mol.atom_charges(), mol.atom_coords(unit="Bohr"), strict=True + ) ], dtype=MOLECULE_DTYPE, ) @@ -106,7 +118,9 @@ def pyscf_to_gauxc_h5(mol: gto.Mole, dm: np.ndarray, exc: float | None = None, v return data -def norm(coeff: list[float], alpha: list[float], l: int) -> list[float]: +def norm( + coeff: list[float] | np.ndarray, alpha: list[float] | np.ndarray, l: int +) -> list[float]: """ Normalize contraction coefficients for a given angular momentum and exponents using libint normalization conventions. @@ -114,10 +128,12 @@ def norm(coeff: list[float], alpha: list[float], l: int) -> list[float]: alpha = np.asarray(alpha) two_alpha = 2 * alpha two_alpha_to_am32 = two_alpha ** (l + 1) * np.sqrt(two_alpha) - normalization_factor = np.sqrt(2**l * two_alpha_to_am32 / (SQRT_PI_CUBED * K_MINUS_1[2 * l])) + normalization_factor = np.sqrt( + 2**l * two_alpha_to_am32 / (SQRT_PI_CUBED * K_MINUS_1[2 * l]) + ) gamma = alpha[:, np.newaxis] + alpha[np.newaxis, :] aa = K_MINUS_1[2 * l] * SQRT_PI_CUBED / (2**l * gamma ** (l + 1) * np.sqrt(gamma)) - coeff = coeff * normalization_factor + coeff = np.asarray(coeff) * normalization_factor normalization_factor = 1.0 / np.sqrt(np.einsum("i,j,ij->", coeff, coeff, aa)) return (coeff * normalization_factor).tolist() diff --git a/tests/test_gauxc_export.py b/tests/test_gauxc_export.py index 4069614..87d56ff 100644 --- a/tests/test_gauxc_export.py +++ b/tests/test_gauxc_export.py @@ -3,8 +3,8 @@ import h5py import numpy as np import pytest - from pyscf import dft, gto + from skala.gauxc.export import write_gauxc_h5_from_pyscf @@ -27,9 +27,13 @@ def cartesian(request) -> bool: def mol(mol_name: str, basis: str, cartesian: bool) -> gto.Mole: match mol_name: case "He": - return gto.M(atom="He 0 0 0", basis=basis, cart=cartesian, unit="Bohr", spin=0) + return gto.M( + atom="He 0 0 0", basis=basis, cart=cartesian, unit="Bohr", spin=0 + ) case "Li": - return gto.M(atom="Li 0 0 0", basis=basis, cart=cartesian, unit="Bohr", spin=1) + return gto.M( + atom="Li 0 0 0", basis=basis, cart=cartesian, unit="Bohr", spin=1 + ) case _: raise ValueError(f"Unknown molecule name: {mol_name}") @@ -40,10 +44,12 @@ def ks(mol: gto.Mole) -> dft.rks.RKS: ks.kernel() return ks + @pytest.fixture def dm(ks: dft.rks.RKS) -> np.ndarray: return ks.make_rdm1() + @pytest.fixture def exc(ks: dft.rks.RKS) -> float: return ks.scf_summary["exc"] @@ -58,8 +64,7 @@ def vxc(ks: dft.rks.RKS, dm: np.ndarray) -> np.ndarray: return vxc - -def test_write_pyscf(mol: gto.Mole, dm: np.ndarray, mol_name, basis, exc, vxc) -> None: +def test_write_pyscf(mol: gto.Mole, dm: np.ndarray, exc, vxc) -> None: with NamedTemporaryFile(suffix=".h5") as tmp: write_gauxc_h5_from_pyscf(tmp.name, mol, dm, exc, vxc) @@ -69,5 +74,9 @@ def test_write_pyscf(mol: gto.Mole, dm: np.ndarray, mol_name, basis, exc, vxc) - assert "DENSITY_SCALAR" in h5, "Density (a+b) is missing in h5 export" assert "DENSITY_Z" in h5, "Density (a-b) is missing in h5 export" assert "EXC" in h5, "Exchange-correlation energy is missing in h5 export" - assert "VXC_SCALAR" in h5, "Exchange-correlation potential (a+b) is missing in h5 export" - assert "VXC_Z" in h5, "Exchange-correlation potential (a-b) is missing in h5 export" \ No newline at end of file + assert ( + "VXC_SCALAR" in h5 + ), "Exchange-correlation potential (a+b) is missing in h5 export" + assert ( + "VXC_Z" in h5 + ), "Exchange-correlation potential (a-b) is missing in h5 export" From b2c121cc16e6850eb6e67f67eee4d17c8c3ebc70 Mon Sep 17 00:00:00 2001 From: Sebastian Ehlert Date: Thu, 8 Jan 2026 16:47:59 +0100 Subject: [PATCH 12/12] Add guide on building C++ driver for GauXC --- docs/gauxc/cpp-library.rst | 443 ++++++++++++++++++ docs/gauxc/index.rst | 1 + docs/gauxc/scripts/export-h5.py | 14 + docs/gauxc/standalone.rst | 18 +- examples/cpp/gauxc_integration/.gitignore | 3 + examples/cpp/gauxc_integration/CMakeLists.txt | 38 ++ examples/cpp/gauxc_integration/app/main.cxx | 248 ++++++++++ .../gauxc_integration/cmake/skala-cli11.cmake | 25 + .../cmake/skala-dep-versions.cmake | 8 + .../cmake/skala-eigen3.cmake | 28 ++ .../gauxc_integration/cmake/skala-gauxc.cmake | 38 ++ third_party/gauxc/tests/standalone_driver.cxx | 6 +- 12 files changed, 851 insertions(+), 19 deletions(-) create mode 100644 docs/gauxc/cpp-library.rst create mode 100644 docs/gauxc/scripts/export-h5.py create mode 100644 examples/cpp/gauxc_integration/.gitignore create mode 100644 examples/cpp/gauxc_integration/CMakeLists.txt create mode 100644 examples/cpp/gauxc_integration/app/main.cxx create mode 100644 examples/cpp/gauxc_integration/cmake/skala-cli11.cmake create mode 100644 examples/cpp/gauxc_integration/cmake/skala-dep-versions.cmake create mode 100644 examples/cpp/gauxc_integration/cmake/skala-eigen3.cmake create mode 100644 examples/cpp/gauxc_integration/cmake/skala-gauxc.cmake diff --git a/docs/gauxc/cpp-library.rst b/docs/gauxc/cpp-library.rst new file mode 100644 index 0000000..d0bf320 --- /dev/null +++ b/docs/gauxc/cpp-library.rst @@ -0,0 +1,443 @@ +GauXC in C++ +============ + +In this guide we will cover how to use the GauXC library in C++. +We will cover + +* setting up a CMake project including GauXC as dependency +* initializing the GauXC runtime environment +* reading molecule, basis set, and density matrix from an HDF5 input file +* setting up the integration grid, load balancer, and exchange-correlation integrator +* performing the exchange-correlation evaluation and outputting the results + +.. tip:: + + For building GauXC and installing in the conda environment checkout :ref:`gauxc_install`. + +Setting up CMake +---------------- + +GauXC can be most conveniently used via CMake, therefore we will setup a minimal CMake project for a command line driver to use GauXC. +Next to GauXC we will use other dependencies as needed. + +The directory structure for the project will be + +.. code-block:: text + + ├── CMakeLists.txt + ├── app + │ └── main.cxx + └── cmake + ├── skala-cli11.cmake + ├── skala-dep-versions.cmake + ├── skala-eigen3.cmake + └── skala-gauxc.cmake + +First we create the main ``CMakeLists.txt`` to define our project, include our dependencies, and declare our executable. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/CMakeLists.txt + :language: cmake + :caption: CMakeLists.txt + +For handling the dependencies, we create a separate file in the ``cmake/`` subdirectory to include the path and checksums for all our dependencies. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/cmake/skala-dep-versions.cmake + :language: cmake + :caption: cmake/skala-dep-versions.cmake + +For each dependency we will create a separate CMake include file for finding and making it available. +First, we define how we will include GauXC our main dependency. +For this we can rely in most cases to discover the GauXC config file, however we also provide a fallback to download and build GauXC in case it is not available in the environment. +The options we defined in the main CMake file will be passed through to GauXC to ensure the library provides the requested features. +Furthermore, after having GauXC available, we double check whether our requirements for GauXC are satisfied, this is especially necessary for the Skala implementation, which requires the ``GAUXC_HAS_ONEDFT`` feature flag. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/cmake/skala-gauxc.cmake + :language: cmake + :caption: cmake/skala-gauxc.cmake + +While GauXC provides the implementation to evaluate the exchange-correlation functional, it is independent to the library used for storing matrices. +For our example here we will be using Eigen3. +Similar to GauXC we will attempt to find Eigen3 via its config file and fallback to downloading it. +Since Eigen3 is a header-only library, we just need to reexport the include directory of the project. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/cmake/skala-eigen3.cmake + :language: cmake + :caption: cmake/skala-eigen3.cmake + +For our command line driver, we will be using CLI11 to create the command line interface without. +Similar to Eigen3, CLI11 is a header-only library and we will use the same approach for including its headers if the dependency can not be found in the environment. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/cmake/skala-cli11.cmake + :language: cmake + :caption: cmake/skala-cli11.cmake + +With this we have the full CMake setup we need for creating our command line driver. + +Initializing GauXC +------------------ + +For the main program we start with including the relevant headers for GauXC. +In our case those come from GauXC for the main functionality of the library, HighFive for access to HDF5 files, Eigen3 for matrix types, and CLI11 for creating the command line interface. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (headers) + :lines: 1-20 + +We start defining our main program with a set of default variables. +In this tutorial we will be using + +``input_file`` + an HDF5 input file to provide the molecule, basis and density matrix + +``model`` + the model checkpoint we want to evaluate + +``grid_spec`` + the grid size specification which defines the number of angular and radial integration points + +``rad_quad_spec`` + the radial quadrature scheme which defines the spacing of radial integration points + +``prune_spec`` + the pruning scheme for combining the atomic grids to a molecular one + +Furthermore, we have the variables which define where GauXC is executing (host or device) and ``batch_size`` and ``basis_tol`` for the numerical settings of the evaluation. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (initialization) + :lines: 118-133 + +Command line interface +---------------------- + +Next we will create a command line interface based on the CLI11 library. +Each of the default options we specified will be included there. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (command-line) + :lines: 134-152 + +Before adding any further implementation, we can add the finalization to our main and create a first build of the project. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (finalization) + :lines: 244-248 + +To configure the CMake build run + +.. code-block:: shell + + cmake -B build -G Ninja -S . + cmake --build build + +After we build our project successfully, we can run our driver directly from the build directory with + +.. code-block:: shell + + ./build/Skala --help + +As output you should see the help page generated by our command-line interface + +.. code-block:: text + + Skala GauXC driver + + + ./build/Skala [OPTIONS] input + + + POSITIONALS: + input TEXT:FILE REQUIRED Input file in HDF5 format + + OPTIONS: + -h, --help Print this help message and exit + --model TEXT Model checkpoint to evaluate + --grid-size TEXT [fine] + Grid specification (fine|ultrafine|superfine|gm3|gm5) + --radial-quad TEXT [muraknowles] + Radial quadrature specification + (becke|muraknowles|treutlerahlrichs|murrayhandylaming) + --prune-scheme TEXT [robust] + Pruning scheme (unpruned|robust|treutler) + --lb-exec-space TEXT [host] + Load balancing execution space + --int-exec-space TEXT [host] + Integration execution space + --batch-size INT [512] + --basis-tol FLOAT [1e-10] + +Now that we are able to change our program variables conveniently from the command-line, we will initialize the GauXC runtime. +For this we are defining a new function to handle different cases, like having access to a device (GPU) or running MPI parallel. +GauXC provides preprocessor guards like ``GAUXC_HAS_DEVICE`` and ``GAUXC_HAS_MPI`` or convenience macros like ``GAUXC_MPI_CODE`` for defining conditional code paths. +When creating the runtime environment, we will provide it with the MPI world communicator if available and if we have a device preallocate memory on the device. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (get_runtime) + :lines: 22-41 + +We return the runtime environment in the main program. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (runtime setup) + :lines: 153-156 + +The ``world_size`` and ``world_rank`` variables describe our MPI environment and contain dummy values if we do not use MPI. + +Before we continue with setting up GauXC, we include an output of our program variables. +Here we can use ``world_rank`` provided by the runtime environment to ensure only the root rank outputs the information. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (inputs) + :lines: 158-167 + +Molecule data +------------- + +For reading the molecule we will use GauXC's built-in functionality to read from an HDF5 dataset. + +.. note:: + + The ``GauXC::Molecule`` stores the information about the atomic numbers and their coordinates as an array of structs. + + .. code-block:: c++ + + struct GauXC::Atom { + int64_t Z; ///< Atomic number + double x; ///< X coordinate (bohr) + double y; ///< Y coordinate (bohr) + double z; ///< Z coordinate (bohr) + }; + class GauXC::Molecule : public std::vector { + ... + }; + + This allows to directly map the object's representation to an HDF5 dataset. + +We use ``GauXC::read_hdf5_record`` function which implements the reading of the molecule data. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (read_molecule) + :lines: 43-50 + +In the main program we will just use our small wrapper function to obtain the molecule. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (molecule) + :lines: 169-170 + +Basis set data +-------------- + +For the basis set we will use the same approach as for the molecule and use GauXC's built-in HDF5 reading functionality. + +.. note:: + + Similar to the molecule the ``GauXC::BasisSet`` object is built as an array of ``GauXC::Shell`` objects. + The ``GauXC::Shell`` object contains the information about the primitives, contraction coefficients, angular momentum, and center of the shell. + + .. code-block:: c++ + + template + class alignas(256) GauXC::Shell { + std::array alpha; + std::array coeff; + std::array O; + int32_t nprim; + int32_t l; + int32_t pure; + }; + + template + struct GauXC::BasisSet : public std::vector> { + ... + }; + + Again, this allows to directly map the object's representation to an HDF5 dataset. + +With GauXC's ``GauXC::read_hdf5_record`` function we can read the basis set data conveniently from the HDF5 file. +Additionally, we are setting the basis set tolerance on the loaded basis set data, which will be taken from our input variables. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (read_basis) + :lines: 52-62 + +In the main program we can use our wrapper function to load the basis set. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (basis) + :lines: 172-173 + +Integration grid +---------------- + +To setup the integration grid, which is the part of the input to GauXC for computing the exchange-correlation functional, we create a molecular grid. +We have three main input parameters here, the grid size which defines the density of angular and radial points, the radial quadrature scheme which defines the spacing of the radial points, and the pruning scheme which defines how atomic grids are combined to a molecular grid. +In GauXC these are defined as enumerators and we add a number of helper functions for turning the input strings from the command-line to the respective enumerator values. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (grid setting) + :lines: 64-98 + +For the main program we can now create the molecular grid based on our input parameters. +We also have to define the batch size for the grid, the default is 512 points per batch, however larger values up around 10000 are recommended for better performance. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (grid) + :lines: 175-181 + +Exchange-correlation integrator +------------------------------- + +To distribute the work of evaluating the exchange-correlation functional on the grid points, we create a load balancer. +The load balancer will take care of distributing the grid points to the available resources, either host or device, based on the execuation space we provide. +Note that the load balancer will provide access to the molecule, basis and grid data for all further usage in GauXC. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (load balancer) + :lines: 183-205 + +Finally, we can create the main GauXC integrator, for this we setup the exchange-correlation integrator factory for producing an instance of the integrator. +To configure the integrator we create an additional settings object which holds the model checkpoint we want to evaluate. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (integrator) + :lines: 207-214 + +Density matrix +-------------- + +The final input we need to provide to GauXC is the density matrix. +Similar to the molecule and basis set we will read it from our HDF5 input file using the HighFive library directly. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (load_density_matrix) + :lines: 100-116 + +For the model checkpoint we always use two spin channels and therefore have the scalar density matrix (alpha + beta spin channel) and the polarization density matrix (alpha - beta spin channel). + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (density matrix) + :lines: 216-218 + +Exchange-correlation evaluation +------------------------------- + +With all inputs provided we can now perform the exchange-correlation evaluation. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (exchange-correlation) + :lines: 225-228 + +.. tip:: + + For timing the execution we can add an optional timer around the evaluation and synchronize the MPI processes before and after the evaluation to get accurate timings. + + .. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (timer) + :lines: 220-234 + +After the evaluation we can output the computed exchange-correlation energy and potential. + +.. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx (output) + :lines: 236-243 + +Now we can rebuild our project with + +.. code-block:: shell + + cmake --build build + +After we build our project successfully, we run the driver again from the build directory + +.. code-block:: shell + + ./build/Skala He_def2-svp.h5 --model PBE + +.. note:: + + The ``He_def2-svp.h5`` input file can be created with the ``skala`` package. + + .. literalinclude:: scripts/export-h5.py + :language: python + +As output we can see the results for the PBE functional + +.. code-block:: text + + Configuration + -> Input file : He_def2-svp.h5 + -> Model : PBE + -> Grid : fine + -> Radial quadrature : muraknowles + -> Pruning scheme : robust + + EXC = -1.054031868349e+00 Eh + |VXC(a+b)|_F = 1.455982966065e+00 + |VXC(a-b)|_F = 0.000000000000e+00 + Runtime XC = 4.382018760000e-01 s + +Download checkpoint from HuggingFace +------------------------------------ + +To evaluate Skala we first need to download the model checkpoint from HuggingFace. +For this we can use the ``hf`` command line tool from the ``huggingface_hub`` Python package. +After downloading the model checkpoint we can run our driver again with the new model + +.. code-block:: shell + + hf download microsoft/skala skala-1.0.fun --local-dir . + ./build/Skala He_def2-svp.h5 --model ./skala-1.0.fun + +In the output we can see the results for the Skala functional + +.. code-block:: text + + Configuration + -> Input file : He_def2-svp.h5 + -> Model : ./skala-v1.0.fun + -> Grid : fine + -> Radial quadrature : muraknowles + -> Pruning scheme : robust + + EXC = -1.071256087389e+00 Eh + |VXC(a+b)|_F = 1.500299750739e+00 + |VXC(a-b)|_F = 0.000000000000e+00 + Runtime XC = 1.792662281000e+00 s + +Full source code +---------------- + +.. dropdown:: Full source code of the main driver + + .. literalinclude:: ../../examples/cpp/gauxc_integration/app/main.cxx + :language: c++ + :caption: app/main.cxx + +Summary +------- + +In this guide we covered how to use the GauXC library in C++. +We created a minimal CMake project to setup the build environment and included GauXC. +We created a command line driver which reads the molecule, basis set, and density matrix from an HDF5 input file and sets up the integration grid, load balancer, and exchange-correlation integrator. +Finally, we performed the exchange-correlation evaluation and output the results. \ No newline at end of file diff --git a/docs/gauxc/index.rst b/docs/gauxc/index.rst index 1e2b55f..91b0596 100644 --- a/docs/gauxc/index.rst +++ b/docs/gauxc/index.rst @@ -10,3 +10,4 @@ The following sections provide instructions on how to install GauXC with Skala s installation standalone + cpp-library \ No newline at end of file diff --git a/docs/gauxc/scripts/export-h5.py b/docs/gauxc/scripts/export-h5.py new file mode 100644 index 0000000..a5df3c4 --- /dev/null +++ b/docs/gauxc/scripts/export-h5.py @@ -0,0 +1,14 @@ +from pyscf import gto + +from skala.gauxc.export import write_gauxc_h5_from_pyscf +from skala.pyscf import SkalaRKS + +mol = gto.M(atom="He 0 0 0", basis="def2-svp", unit="Bohr", spin=0) +ks = SkalaRKS(mol, xc="pbe") +ks.kernel() + +dm = ks.make_rdm1() +exc = ks.scf_summary["exc"] +_, _, vxc = ks._numint.nr_rks(ks.mol, ks.grids, ks.xc, dm) + +write_gauxc_h5_from_pyscf("He_def2-svp.h5", mol, dm=dm, exc=exc, vxc=vxc) \ No newline at end of file diff --git a/docs/gauxc/standalone.rst b/docs/gauxc/standalone.rst index 9cc1f05..35af428 100644 --- a/docs/gauxc/standalone.rst +++ b/docs/gauxc/standalone.rst @@ -20,22 +20,8 @@ In this example we will use a single one atom system in a small basis set. We will write the input data as HDF5 file since GauXC can read its objects directly from HDF5 datasets. The format in the HDF5 file does correpond to the internal structure of GauXC objects and therefore allows us to conveniently inspect the data. -.. code-block:: python - - from pyscf import gto - - from skala.gauxc.export import write_gauxc_h5_from_pyscf - from skala.pyscf import SkalaRKS - - mol = gto.M(atom="He 0 0 0", basis="def2-svp", unit="Bohr", spin=0) - ks = SkalaRKS(mol, xc="pbe") - ks.kernel() - - dm = ks.make_rdm1() - exc = ks.scf_summary["exc"] - _, _, vxc = ks._numint.nr_rks(ks.mol, ks.grids, ks.xc, dm) - - write_gauxc_h5_from_pyscf("He_def2-svp.h5", mol, dm=dm, exc=exc, vxc=vxc) +.. literalinclude:: scripts/export-h5.py + :language: python Additionally to the inputs (molecule, basis set, and density matrix) we provide the exchange-correlation energy and potential to allow the standalone driver to compare against our reference calculation. diff --git a/examples/cpp/gauxc_integration/.gitignore b/examples/cpp/gauxc_integration/.gitignore new file mode 100644 index 0000000..07b9832 --- /dev/null +++ b/examples/cpp/gauxc_integration/.gitignore @@ -0,0 +1,3 @@ +*build/ +*.tar.gz +*.fun diff --git a/examples/cpp/gauxc_integration/CMakeLists.txt b/examples/cpp/gauxc_integration/CMakeLists.txt new file mode 100644 index 0000000..11a3a99 --- /dev/null +++ b/examples/cpp/gauxc_integration/CMakeLists.txt @@ -0,0 +1,38 @@ +cmake_minimum_required(VERSION 3.20 FATAL_ERROR) + +project("Skala" LANGUAGES CXX) + +include(GNUInstallDirs) +include(FetchContent) +set(FETCHCONTENT_UPDATES_DISCONNECTED ON CACHE BOOL "Disable FC Updates") + +list(PREPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) + +option(Skala_GauXC_ENABLE_OPENMP "Enable OpenMP support in GauXC" ON) +option(Skala_GauXC_ENABLE_MPI "Enable MPI support in GauXC" OFF) +option(Skala_GauXC_ENABLE_CUDA "Enable CUDA support in GauXC" OFF) + +include(skala-dep-versions) +include(skala-gauxc) +include(skala-cli11) +include(skala-eigen3) + +add_executable( + "${PROJECT_NAME}" + "app/main.cxx" +) +target_link_libraries( + "${PROJECT_NAME}" + PRIVATE + gauxc::gauxc + CLI11::CLI11 + Eigen3::Eigen +) +install( + TARGETS + "${PROJECT_NAME}" + DESTINATION + "${CMAKE_INSTALL_BINDIR}" +) + +list(REMOVE_AT CMAKE_MODULE_PATH 0) \ No newline at end of file diff --git a/examples/cpp/gauxc_integration/app/main.cxx b/examples/cpp/gauxc_integration/app/main.cxx new file mode 100644 index 0000000..7c1ad69 --- /dev/null +++ b/examples/cpp/gauxc_integration/app/main.cxx @@ -0,0 +1,248 @@ +#include +#include +#include +#include +#include +#include + +// For loading data from HDF5 files +#include +#include + +// For providing matrix implementation +#define EIGEN_DONT_VECTORIZE +#define EIGEN_NO_CUDA +#include + +// For command line interface +#include + +using matrix = Eigen::MatrixXd; + +GauXC::RuntimeEnvironment +get_runtime() +{ +#ifdef GAUXC_HAS_DEVICE + auto rt = GauXC::DeviceRuntimeEnvironment( GAUXC_MPI_CODE(MPI_COMM_WORLD,) 0.9 ); + // Caluclate GauXC Device buffer size + size_t available_mem, total_mem; + cudaMemGetInfo(&available_mem, &total_mem); + int device_id; + cudaGetDevice(&device_id); + size_t sz = mem_sz * available_mem; + void* p; + cudaMallocAsync(&p, sz, 0); + cudaStreamSynchronize(0); + rt.set_buffer(p, sz); +#else + auto rt = GauXC::RuntimeEnvironment(GAUXC_MPI_CODE(MPI_COMM_WORLD)); +#endif + return rt; +} + +// Load molecule from HDF5 dataset +GauXC::Molecule +read_molecule(std::string ref_file) +{ + GauXC::Molecule mol; + GauXC::read_hdf5_record(mol, ref_file, "/MOLECULE"); + return mol; +} + +// Load basis from HDF5 dataset +GauXC::BasisSet +read_basis(std::string ref_file, double basis_tol) +{ + GauXC::BasisSet basis; + GauXC::read_hdf5_record(basis, ref_file, "/BASIS"); + for(auto& shell : basis){ + shell.set_shell_tolerance(basis_tol); + } + return basis; +} + +GauXC::AtomicGridSizeDefault +read_atomic_grid_size(std::string spec) +{ + std::map mg_map = { + {"fine", GauXC::AtomicGridSizeDefault::FineGrid}, + {"ultrafine", GauXC::AtomicGridSizeDefault::UltraFineGrid}, + {"superfine", GauXC::AtomicGridSizeDefault::SuperFineGrid}, + {"gm3", GauXC::AtomicGridSizeDefault::GM3}, + {"gm5", GauXC::AtomicGridSizeDefault::GM5} + }; + return mg_map.at(spec); +} + +GauXC::PruningScheme +read_pruning_scheme(std::string spec) +{ + std::map prune_map = { + {"unpruned", GauXC::PruningScheme::Unpruned}, + {"robust", GauXC::PruningScheme::Robust}, + {"treutler", GauXC::PruningScheme::Treutler} + }; + return prune_map.at(spec); +} + +GauXC::RadialQuad +read_radial_quad(std::string spec) +{ + std::map rad_quad_map = { + {"becke", GauXC::RadialQuad::Becke}, + {"muraknowles", GauXC::RadialQuad::MuraKnowles}, + {"treutlerahlrichs", GauXC::RadialQuad::TreutlerAhlrichs}, + {"murrayhandylaming", GauXC::RadialQuad::MurrayHandyLaming}, + }; + return rad_quad_map.at(spec); +} + +std::pair +read_density_matrix(std::string ref_file) +{ + HighFive::File h5file(ref_file, HighFive::File::ReadOnly); + + auto dset = h5file.getDataSet("/DENSITY_SCALAR"); + auto dims = dset.getDimensions(); + auto P_s = matrix(dims[0], dims[1]); + auto P_z = matrix(dims[0], dims[1]); + + dset.read(P_s.data()); + + dset = h5file.getDataSet("/DENSITY_Z"); + dset.read(P_z.data()); + + return std::make_pair(P_s, P_z); +} + +int +main(int argc, char** argv) +{ +#ifdef GAUXC_HAS_MPI + MPI_Init(NULL, NULL); +#endif + { + std::string input_file; + std::string model; + std::string grid_spec = "fine"; + std::string rad_quad_spec = "muraknowles"; + std::string prune_spec = "robust"; + std::string lb_exec_space_str = "host"; + std::string int_exec_space_str = "host"; + int batch_size = 512; + double basis_tol = 1e-10; + { + auto string_to_lower = CLI::Validator( + [](auto& str){ + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + return ""; + }, std::string(""), std::string("argument is case-insensitive")); + CLI::App app{"Skala GauXC driver"}; + app.option_defaults()->always_capture_default(); + app.add_option("input", input_file, "Input file in HDF5 format")->required()->check(CLI::ExistingFile); + app.add_option("--model", model, "Model checkpoint to evaluate")->required(); + app.add_option("--grid-size", grid_spec, "Grid specification (fine|ultrafine|superfine|gm3|gm5)")->transform(string_to_lower); + app.add_option("--radial-quad", rad_quad_spec, "Radial quadrature specification (becke|muraknowles|treutlerahlrichs|murrayhandylaming)")->transform(string_to_lower); + app.add_option("--prune-scheme", prune_spec, "Pruning scheme (unpruned|robust|treutler)")->transform(string_to_lower); + app.add_option("--lb-exec-space", lb_exec_space_str, "Load balancing execution space")->transform(string_to_lower); + app.add_option("--int-exec-space", int_exec_space_str, "Integration execution space")->transform(string_to_lower); + app.add_option("--batch-size", batch_size, ""); + app.add_option("--basis-tol", basis_tol, ""); + CLI11_PARSE(app, argc, argv); + } + // Create runtime + auto rt = get_runtime(); + auto world_rank = rt.comm_rank(); + auto world_size = rt.comm_size(); + + if (!world_rank) { + std::cout << std::boolalpha; + std::cout << "Configuration" << std::endl + << "-> Input file : " << input_file << std::endl + << "-> Model : " << model << std::endl + << "-> Grid : " << grid_spec << std::endl + << "-> Radial quadrature : " << rad_quad_spec << std::endl + << "-> Pruning scheme : " << prune_spec << std::endl + << std::endl; + } + + // Get molecule (atomic numbers and cartesian coordinates) + auto mol = read_molecule(input_file); + + // Get basis set + auto basis = read_basis(input_file, basis_tol); + + // Define molecular grid from grid size, radial quadrature and pruning scheme + auto grid = GauXC::MolGridFactory::create_default_molgrid( + mol, + read_pruning_scheme(prune_spec), + GauXC::BatchSize(batch_size), + read_radial_quad(rad_quad_spec), + read_atomic_grid_size(grid_spec)); + + // Choose whether we run on host or device + #ifdef GAUXC_HAS_DEVICE + std::map exec_space_map = { + { "host", GauXC::ExecutionSpace::Host }, + { "device", GauXC::ExecutionSpace::Device } + }; + + auto lb_exec_space = exec_space_map.at(lb_exec_space_str); + auto int_exec_space = exec_space_map.at(int_exec_space_str); + #else + auto lb_exec_space = GauXC::ExecutionSpace::Host; + auto int_exec_space = GauXC::ExecutionSpace::Host; + #endif + + // Setup load balancer based on molecule, grid and basis set + GauXC::LoadBalancerFactory lb_factory(lb_exec_space, "Replicated"); + auto lb = lb_factory.get_shared_instance(rt, mol, grid, basis); + + // Apply partitioning weights to the molecule grid + GauXC::MolecularWeightsFactory mw_factory(int_exec_space, "Default", + GauXC::MolecularWeightsSettings{} ); + auto mw = mw_factory.get_instance(); + mw.modify_weights(*lb); + + // Setup exchange-correlation integrator + GauXC::functional_type func; + GauXC::XCIntegratorFactory integrator_factory(int_exec_space, "Replicated", "Default", "Default", "Default"); + auto integrator = integrator_factory.get_instance(func, lb); + + // Configure model checkpoint + GauXC::OneDFTSettings onedft_settings; + onedft_settings.model = model; + + // Load density matrix from input + matrix P_s, P_z; + std::tie(P_s, P_z) = read_density_matrix(input_file); + +#ifdef GAUXC_HAS_MPI + MPI_Barrier(MPI_COMM_WORLD); +#endif + auto xc_int_start = std::chrono::high_resolution_clock::now(); + + // Integrate exchange correlation energy + double EXC; + matrix VXC_s, VXC_z; + std::tie(EXC, VXC_s, VXC_z) = integrator.eval_exc_vxc_onedft(P_s, P_z, onedft_settings); + +#ifdef GAUXC_HAS_MPI + MPI_Barrier(MPI_COMM_WORLD); +#endif + auto xc_int_end = std::chrono::high_resolution_clock::now(); + double xc_int_dur = std::chrono::duration(xc_int_end - xc_int_start).count(); + + std::cout << std::scientific << std::setprecision(12); + if(!world_rank) { + std::cout << "EXC = " << EXC << " Eh" << std::endl + << "|VXC(a+b)|_F = " << VXC_s.norm() << std::endl + << "|VXC(a-b)|_F = " << VXC_z.norm() << std::endl + << "Runtime XC = " << xc_int_dur << " s" << std::endl + << std::endl; + } + } +#ifdef GAUXC_HAS_MPI + MPI_Finalize(); +#endif +} \ No newline at end of file diff --git a/examples/cpp/gauxc_integration/cmake/skala-cli11.cmake b/examples/cpp/gauxc_integration/cmake/skala-cli11.cmake new file mode 100644 index 0000000..0292170 --- /dev/null +++ b/examples/cpp/gauxc_integration/cmake/skala-cli11.cmake @@ -0,0 +1,25 @@ +if(NOT ${Skala_CLI11_URL}) + include(skala-dep-versions) +endif() +find_package(CLI11 QUIET CONFIG) +if(NOT CLI11_FOUND) + message(STATUS "Could not find CLI11... Building CLI11 from source") + message(STATUS "CLI11 URL: ${Skala_CLI11_URL}") + + FetchContent_Declare( + cli11 + URL ${Skala_CLI11_URL} + URL_HASH SHA256=${Skala_CLI11_SHA256} + DOWNLOAD_EXTRACT_TIMESTAMP ON + ) + + FetchContent_GetProperties(cli11) + if(NOT cli11_POPULATED) + FetchContent_Populate(cli11) + endif() + + add_library( CLI11::CLI11 INTERFACE IMPORTED ) + set_target_properties( CLI11::CLI11 PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${cli11_SOURCE_DIR}/include + ) +endif() \ No newline at end of file diff --git a/examples/cpp/gauxc_integration/cmake/skala-dep-versions.cmake b/examples/cpp/gauxc_integration/cmake/skala-dep-versions.cmake new file mode 100644 index 0000000..2e85d1c --- /dev/null +++ b/examples/cpp/gauxc_integration/cmake/skala-dep-versions.cmake @@ -0,0 +1,8 @@ +set(Skala_GauXC_URL "https://github.com/microsoft/skala/releases/download/v1.1.0/gauxc-skala.tar.gz") +set(Skala_GauXC_SHA256 "ed3102485f6d838c8076a03162b11a1d7c3fd52b212ba6a048db2e9089c98f3c") + +set(Skala_CLI11_URL "https://github.com/CLIUtils/CLI11/archive/refs/tags/v2.6.1.tar.gz") +set(Skala_CLI11_SHA256 "377691f3fac2b340f12a2f79f523c780564578ba3d6eaf5238e9f35895d5ba95") + +set(Skala_Eigen3_URL "https://gitlab.com/libeigen/eigen/-/archive/3.4.0/eigen-3.4.0.tar.gz") +set(Skala_Eigen3_SHA256 "8586084f71f9bde545ee7fa6d00288b264a2b7ac3607b974e54d13e7162c1c72") \ No newline at end of file diff --git a/examples/cpp/gauxc_integration/cmake/skala-eigen3.cmake b/examples/cpp/gauxc_integration/cmake/skala-eigen3.cmake new file mode 100644 index 0000000..14c6a3c --- /dev/null +++ b/examples/cpp/gauxc_integration/cmake/skala-eigen3.cmake @@ -0,0 +1,28 @@ +if(NOT ${Skala_Eigen3_URL}) + include(skala-dep-versions) +endif() +find_package(Eigen3 CONFIG HINTS ${EIGEN3_ROOT_DIR}) +if(NOT Eigen3_FOUND) + message(STATUS "Could Not Find Eigen3... Building Eigen3 from source") + message(STATUS "EIGEN3 REPO = ${Skala_Eigen3_URL}") + + FetchContent_Declare( + eigen3 + URL ${Skala_Eigen3_URL} + URL_HASH SHA256=${Skala_Eigen3_SHA256} + DOWNLOAD_EXTRACT_TIMESTAMP ON + ) + + FetchContent_GetProperties(eigen3) + if(NOT eigen3_POPULATED) + FetchContent_Populate(eigen3) + endif() + + add_library(Eigen3::Eigen INTERFACE IMPORTED) + set_target_properties( + Eigen3::Eigen + PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${eigen3_SOURCE_DIR} + ) +endif() + diff --git a/examples/cpp/gauxc_integration/cmake/skala-gauxc.cmake b/examples/cpp/gauxc_integration/cmake/skala-gauxc.cmake new file mode 100644 index 0000000..545608a --- /dev/null +++ b/examples/cpp/gauxc_integration/cmake/skala-gauxc.cmake @@ -0,0 +1,38 @@ +if(NOT ${Skala_GauXC_URL}) + include(skala-dep-versions) +endif() +find_package(gauxc QUIET CONFIG) +if(NOT gauxc_FOUND) + include(FetchContent) + + message(STATUS "Could not find GauXC... Building GauXC from source") + message(STATUS "GAUXC URL: ${Skala_GauXC_URL}") + + set(GAUXC_ENABLE_ONEDFT ON CACHE BOOL "" FORCE) + set(GAUXC_ENABLE_TESTS OFF CACHE BOOL "" FORCE) + set(GAUXC_ENABLE_OPENMP ${Skala_GauXC_ENABLE_OPENMP} CACHE BOOL "" FORCE) + set(GAUXC_ENABLE_MPI ${Skala_GauXC_ENABLE_MPI} CACHE BOOL "" FORCE) + set(GAUXC_ENABLE_CUDA ${Skala_GauXC_ENABLE_CUDA} CACHE BOOL "" FORCE) + + FetchContent_Declare( + gauxc + URL ${Skala_GauXC_URL} + URL_HASH SHA256=${Skala_GauXC_SHA256} + DOWNLOAD_EXTRACT_TIMESTAMP ON + ) + FetchContent_MakeAvailable(gauxc) + +else() + if(NOT ${GAUXC_HAS_ONEDFT}) + message(FATAL_ERROR "GauXC found but without Skala support enabled") + endif() + if(${Skala_GauXC_ENABLE_OPENMP} AND NOT ${GAUXC_HAS_OPENMP}) + message(FATAL_ERROR "GauXC Found with OpenMP support but Skala_GauXC_ENABLE_OPENMP is OFF") + endif() + if(${Skala_GauXC_ENABLE_MPI} AND NOT ${GAUXC_HAS_MPI}) + message(FATAL_ERROR "GauXC Found with MPI support but Skala_GauXC_ENABLE_MPI is OFF") + endif() + if(${Skala_GauXC_ENABLE_CUDA} AND NOT ${GAUXC_HAS_CUDA}) + message(FATAL_ERROR "GauXC Found with CUDA support but Skala_GauXC_ENABLE_CUDA is OFF") + endif() +endif() \ No newline at end of file diff --git a/third_party/gauxc/tests/standalone_driver.cxx b/third_party/gauxc/tests/standalone_driver.cxx index 08e48fd..bddc710 100644 --- a/third_party/gauxc/tests/standalone_driver.cxx +++ b/third_party/gauxc/tests/standalone_driver.cxx @@ -50,9 +50,9 @@ int main(int argc, char** argv) { std::string prune_spec = "UNPRUNED"; std::string lb_exec_space_str = "Host"; std::string int_exec_space_str = "Host"; - std::string integrator_kernel = "Default"; - std::string lwd_kernel = "Default"; - std::string reduction_kernel = "Default"; + std::string integrator_kernel = "default"; + std::string lwd_kernel = "default"; + std::string reduction_kernel = "default"; size_t batch_size = 512; double basis_tol = 1e-10;