├── .clang-format ├── .flake8 ├── .github └── workflows │ ├── apt_deps.sh │ ├── basic_tests.yml │ ├── build_docs.yml │ ├── cmake_script.sh │ ├── get_base.py │ ├── gpaw_blas_siteconfig.py │ ├── gpaw_siteconfig.py │ ├── gpaw_tests.yml │ ├── lint.yaml │ ├── load_conda.sh │ ├── mm_install_mpi.sh │ ├── mm_install_torch.sh │ ├── mpi_apt_deps.sh │ ├── mpi_tests.yml │ ├── mpi_testsv2.yml │ ├── nodef_condarc │ ├── nompi_siteconfig.py │ ├── publish.yml │ ├── run_core_ci.sh │ ├── run_gpaw_ci.sh │ ├── run_gpaw_mpi_ci.sh │ ├── run_gpaw_tests.sh │ ├── run_local_pip.sh │ ├── run_mpi_tests.sh │ ├── run_tests.sh │ ├── setup_gpaw.sh │ ├── setup_gpaw_nompi.sh │ └── tests.yml ├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── MANIFEST.in ├── NOTICE ├── README.md ├── ciderpress ├── __init__.py ├── data │ ├── __init__.py │ ├── expnt_maxs.npy │ └── expnt_mins.npy ├── dft │ ├── __init__.py │ ├── baselines.py │ ├── debug_numint.py │ ├── density_util.py │ ├── feat_normalizer.py │ ├── grids_indexer.py │ ├── lcao_convolutions.py │ ├── lcao_interpolation.py │ ├── lcao_nldf_generator.py │ ├── model_utils.py │ ├── plans.py │ ├── pwutil.py │ ├── settings.py │ ├── sph_harm_coeff.py │ ├── tests │ │ ├── __init__.py │ │ ├── debug_normalizers.py │ │ ├── test_baselines.py │ │ ├── test_convolutions.py │ │ ├── test_feat_normalizer.py │ │ ├── test_grids_indexer.py │ │ ├── test_interpolation.py │ │ ├── test_plans.py │ │ ├── test_sph_harm_coeff.py │ │ ├── test_transform_data.py │ │ └── test_ueg.py │ ├── transform_data.py │ ├── xc_evaluator.py │ ├── xc_evaluator2.py │ └── xc_torch.py ├── external │ ├── __init__.py │ └── sgx_tools.py ├── gpaw │ ├── __init__.py │ ├── atom_descriptor_utils.py │ ├── atom_utils.py │ ├── calculator.py │ ├── cider_fft.py │ ├── cider_kernel.py │ ├── cider_paw.py │ ├── cider_sl.py │ ├── config.py │ ├── descriptors.py │ ├── fit_paw_gauss_pot.py │ ├── gpaw_grids.py │ ├── interp_paw.py │ ├── nldf_interface.py │ ├── tests │ │ ├── __init__.py │ │ ├── test_basic_calc.py │ │ ├── test_descriptors.py │ │ ├── test_fe_force.py │ │ ├── test_fe_stress.py │ │ ├── test_gpaw_grids.py │ │ ├── test_nldf_interface.py │ │ ├── test_pp_force.py │ │ ├── test_read_write.py │ │ ├── test_si_force.py │ │ └── test_si_stress.py │ └── xc_tools.py ├── lib │ ├── CMakeLists.txt │ ├── __init__.py │ ├── fft_plan.py │ ├── fft_wrapper │ │ ├── CMakeLists.txt │ │ ├── cider_fft.c │ │ ├── cider_fft.h │ │ ├── cider_mpi_fft.c │ │ ├── cider_mpi_fft.h │ │ └── config.h.in │ ├── load.py │ ├── mod_cider │ │ ├── CMakeLists.txt │ │ ├── cider_coefs.c │ │ ├── cider_grids.c │ │ ├── conv_interpolation.c │ │ ├── conv_interpolation.h │ │ ├── convolutions.c │ │ ├── convolutions.h │ │ ├── debug_numint.c │ │ ├── fast_sdmx.c │ │ ├── fast_sdmx.h │ │ ├── fblas.h │ │ ├── frac_lapl.c │ │ ├── model_utils.c │ │ ├── pbc_tools.c │ │ ├── pyscf_gto.h │ │ ├── sph_harm.c │ │ ├── sph_harm.h │ │ ├── spline.c │ │ └── spline.h │ ├── mpi_fft_plan.py │ ├── numint_cider │ │ ├── CMakeLists.txt │ │ └── nr_numint.c │ ├── pwutil │ │ ├── CMakeLists.txt │ │ ├── config.h.in │ │ ├── gpaw_interface.c │ │ ├── gpaw_interface.h │ │ ├── grid_util.c │ │ ├── nldf_fft_core.c │ │ ├── nldf_fft_core.h │ │ ├── nldf_fft_mpi.c │ │ ├── nldf_fft_mpi.h │ │ ├── nldf_fft_serial.c │ │ └── nldf_fft_serial.h │ ├── sbt │ │ ├── CMakeLists.txt │ │ ├── sbt.c │ │ └── sbt.h │ ├── tests │ │ ├── __init__.py │ │ ├── tests_fft_plan.py │ │ └── tests_mpi_fft_plan.py │ └── xc_utils │ │ ├── CMakeLists.txt │ │ └── libxc_baselines.c ├── models │ ├── __init__.py │ ├── dft_kernel.py │ ├── kernel_plans │ │ ├── __init__.py │ │ ├── arbf_exchange.py │ │ ├── kernel_tools.py │ │ ├── map_tools.py │ │ ├── plan_template.py │ │ └── settings_example.yaml │ ├── kernels.py │ ├── tests │ │ └── test_kernels.py │ └── train.py └── pyscf │ ├── __init__.py │ ├── analyzers.py │ ├── debug_numint.py │ ├── descriptors.py │ ├── dft.py │ ├── frac_lapl.py │ ├── gen_cider_grid.py │ ├── nldf_convolutions.py │ ├── numint.py │ ├── pbc │ ├── __init__.py │ ├── dft.py │ ├── numint.py │ ├── sdmx_fft.py │ ├── tests │ │ ├── test_fft.py │ │ ├── test_sdmx_fft.py │ │ └── test_util.py │ └── util.py │ ├── rks_grad.py │ ├── sdmx.py │ ├── sdmx_slow.py │ ├── tests │ ├── __init__.py │ ├── old_test_nldf.py │ ├── test_frac_lapl.py │ ├── test_functionals.py │ ├── test_nldf.py │ ├── test_rks_grad.py │ ├── test_sdmx.py │ ├── test_sdmx_slow.py │ ├── test_sl.py │ ├── test_uks_grad.py │ └── utils_for_test.py │ └── uks_grad.py ├── docs ├── Doxyfile.in ├── Makefile ├── _templates │ └── layout.html ├── c_extensions │ ├── c_extensions.rst │ └── pwutil.rst ├── ciderpress │ ├── dft │ │ ├── dft.rst │ │ ├── feat_normalizer.rst │ │ ├── plans.rst │ │ ├── settings.rst │ │ ├── transform_data.rst │ │ └── xc_evaluator.rst │ ├── gpaw │ │ ├── calculator.rst │ │ └── gpaw.rst │ ├── models │ │ ├── dft_kernel.rst │ │ ├── kernel_tools.rst │ │ ├── kernels.rst │ │ ├── models.rst │ │ └── train.rst │ └── pyscf │ │ ├── analyzers.rst │ │ ├── descriptors.rst │ │ ├── dft.rst │ │ ├── pbc │ │ └── dft.rst │ │ └── pyscf.rst ├── conf.py ├── features │ ├── features.rst │ ├── nldf.rst │ ├── nlof.rst │ ├── sdmx.rst │ └── sl.rst ├── index.rst ├── installation │ └── installation.rst ├── logos │ ├── cider_logo.svg │ ├── cider_logo_and_name.png │ └── cider_logo_and_name.svg ├── refs │ ├── cider_refs.bib │ └── refs.bib ├── theory │ ├── gp.rst │ ├── nldf_numerical.rst │ ├── theory.rst │ └── uniform_scaling.rst └── tools │ └── extensions │ └── ciderdocext.py ├── examples ├── gpaw │ ├── pp_calc.py │ └── simple_calc.py └── pyscf │ ├── compute_ae.py │ ├── simple_calc.py │ └── simple_sdmx.py ├── pyproject.toml ├── pytest.ini ├── pytest_mpi.ini ├── scripts ├── download_functionals.py └── generate_etb.py └── setup.py /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: llvm 2 | IndentWidth: 4 3 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = E226, E501, E741, E743, C901, W503, E203 3 | max-line-length = 88 4 | exclude = .git,__pycache__,docs/tools/extensions,docs/conf.py,old,build,dist,examples,tmp,.github 5 | -------------------------------------------------------------------------------- /.github/workflows/apt_deps.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ "$RUNNER_OS" == "Linux" ] 4 | then 5 | sudo apt-get -qq install \ 6 | gcc \ 7 | libblas-dev \ 8 | liblapack-dev \ 9 | cmake \ 10 | curl 11 | elif [ "$RUNNER_OS" == "macOS" ] 12 | then 13 | brew install \ 14 | gcc@14 \ 15 | libomp \ 16 | openblas \ 17 | lapack \ 18 | cmake \ 19 | curl \ 20 | libxc \ 21 | fftw \ 22 | wget 23 | else 24 | echo "$RUNNER_OS not supported" 25 | exit 1 26 | fi 27 | -------------------------------------------------------------------------------- /.github/workflows/basic_tests.yml: -------------------------------------------------------------------------------- 1 | name: Run Tests with BLAS 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | core-build: 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | os: [ubuntu-latest, macos-latest] 19 | python-version: ["3.12"] 20 | steps: 21 | - uses: actions/checkout@v3 22 | - name: Set up Python ${{ matrix.python-version }} 23 | uses: actions/setup-python@v4 24 | with: 25 | python-version: ${{ matrix.python-version }} 26 | - name: Install and Test 27 | run: ./.github/workflows/run_core_ci.sh 28 | 29 | gpaw-build: 30 | runs-on: ${{ matrix.os }} 31 | strategy: 32 | fail-fast: false 33 | matrix: 34 | os: [ubuntu-latest, macos-latest] 35 | python-version: ["3.12"] 36 | steps: 37 | - uses: actions/checkout@v3 38 | - name: Set up Python ${{ matrix.python-version }} 39 | uses: actions/setup-python@v4 40 | with: 41 | python-version: ${{ matrix.python-version }} 42 | - name: Install and Test 43 | run: ./.github/workflows/run_gpaw_ci.sh 44 | -------------------------------------------------------------------------------- /.github/workflows/build_docs.yml: -------------------------------------------------------------------------------- 1 | name: Build docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | python-version: ['3.12'] 16 | defaults: 17 | run: 18 | shell: bash -el {0} 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Setup conda environment 22 | uses: mamba-org/setup-micromamba@v1 23 | with: 24 | micromamba-version: '1.5.6-0' # any version from https://github.com/mamba-org/micromamba-releases 25 | environment-name: run_tests 26 | init-shell: >- 27 | bash 28 | powershell 29 | cache-environment: false 30 | post-cleanup: 'all' 31 | create-args: >- 32 | python=${{ matrix.python-version }} 33 | env: 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | - name: Install dependencies and build 36 | run: | 37 | sudo apt-get -qq install gcc cmake 38 | - name: Build things 39 | run: | 40 | source .github/workflows/load_conda.sh 41 | source .github/workflows/mm_install_torch.sh 42 | pip install gpaw 43 | ./.github/workflows/run_local_pip.sh 44 | - name: Build documentation 45 | run: | 46 | source .github/workflows/load_conda.sh 47 | sudo apt-get -qq install doxygen 48 | pip install sphinx breathe sphinx_rtd_theme sphinxcontrib-bibtex 49 | cd docs 50 | doxygen Doxyfile.in 51 | sphinx-build ./ _build 52 | make html 53 | cd .. 54 | - name: Deploy to GitHub Pages 55 | uses: peaceiris/actions-gh-pages@v3 56 | if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} 57 | with: 58 | publish_branch: gh-pages 59 | github_token: ${{ secrets.GITHUB_TOKEN }} 60 | publish_dir: ./docs/_build/html 61 | force_orphan: true 62 | -------------------------------------------------------------------------------- /.github/workflows/cmake_script.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export MY_PYTHON_LIBDIR=$(python -c 'import sysconfig; print(sysconfig.get_config_var("LIBDIR"))') 4 | export MY_PYTHON_INCDIR=$(python -c 'import sysconfig; print(sysconfig.get_config_var("INCLUDEPY"))') 5 | 6 | echo $MY_PYTHON_LIBDIR $MY_PYTHON_INCDIR 7 | 8 | cmake -DCMAKE_PYTHON_LIBRARY_PATH=$MY_PYTHON_LIBDIR \ 9 | -DCMAKE_PYTHON_INCLUDE_PATH=$MY_PYTHON_INCDIR \ 10 | -DCMAKE_BUILD_TYPE=Release \ 11 | -DBLA_VENDOR=Intel10_64lp_seq -DBUILD_FFTW=1 .. 12 | make 13 | -------------------------------------------------------------------------------- /.github/workflows/get_base.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | print(sys.base_prefix) 4 | -------------------------------------------------------------------------------- /.github/workflows/gpaw_blas_siteconfig.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | 22 | scalapack = True 23 | mpi = True 24 | fftw = True 25 | compiler = "mpicc" 26 | 27 | libraries = [ 28 | "fftw3", 29 | "fftw3_omp", 30 | "xc", 31 | "mpi", 32 | "blas", 33 | "lapack", 34 | "scalapack-openmpi", 35 | "gomp", 36 | "pthread", 37 | ] 38 | 39 | extra_compile_args += ["-O3", "-std=c99", "-w", "-m64"] 40 | -------------------------------------------------------------------------------- /.github/workflows/gpaw_siteconfig.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import os 22 | 23 | scalapack = True 24 | mklpath = os.environ["CONDA_PREFIX"] 25 | omppath = os.environ["CONDA_PREFIX"] 26 | 27 | mpi = True 28 | fftw = True 29 | compiler = "mpicc" 30 | 31 | libraries = [ 32 | "fftw3", 33 | "fftw3_omp", 34 | "xc", 35 | "mpi", 36 | "mkl_blacs_openmpi_lp64", 37 | "mkl_scalapack_lp64", 38 | "mkl_intel_lp64", 39 | "mkl_intel_thread", 40 | "mkl_core", 41 | "iomp5", 42 | "pthread", 43 | ] 44 | library_dirs += [f"{omppath}/lib", f"{mklpath}/lib", f"{mklpath}/lib/intel64"] 45 | include_dirs += [f"{omppath}/include", f"{mklpath}/include"] 46 | # might need to include /usr/include if your compilers are not from conda 47 | # include_dirs += ['/usr/include', f'{omppath}/include', f'{mklpath}/include'] 48 | 49 | extra_compile_args += ["-O3", "-std=c99", "-w", "-m64"] 50 | 51 | define_macros += [ 52 | ("GPAW_NO_UNDERSCORE_CBLACS", "1"), 53 | ("GPAW_NO_UNDERSCORE_CSCALAPACK", "1"), 54 | ("GPAW_NO_UNDERSCORE_SCALAPACK", "1"), 55 | ] 56 | -------------------------------------------------------------------------------- /.github/workflows/gpaw_tests.yml: -------------------------------------------------------------------------------- 1 | name: Run Serial GPAW Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: ['3.12'] 20 | defaults: 21 | run: 22 | shell: bash -el {0} 23 | steps: 24 | - uses: actions/checkout@v4 25 | - name: Setup conda environment 26 | uses: mamba-org/setup-micromamba@v1 27 | with: 28 | micromamba-version: '1.5.6-0' # any version from https://github.com/mamba-org/micromamba-releases 29 | environment-name: run_tests 30 | init-shell: >- 31 | bash 32 | powershell 33 | cache-environment: false 34 | post-cleanup: 'all' 35 | create-args: >- 36 | python=${{ matrix.python-version }} 37 | env: 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 39 | - name: Install dependencies and build 40 | run: | 41 | sudo apt-get -qq install gcc cmake 42 | - name: Build things 43 | run: | 44 | source .github/workflows/load_conda.sh 45 | source .github/workflows/mm_install_torch.sh 46 | export CMAKE_CONFIGURE_ARGS="-DBUILD_WITH_MKL=ON -DBUILD_LIBXC=OFF" 47 | ./.github/workflows/run_local_pip.sh 48 | python scripts/download_functionals.py 49 | - name: Test with unittest 50 | run: | 51 | source .github/workflows/load_conda.sh 52 | ./.github/workflows/setup_gpaw_nompi.sh 53 | ./.github/workflows/run_gpaw_tests.sh 54 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: Check coding style 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | flake8: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v2 16 | - uses: actions/setup-python@v2 17 | with: 18 | python-version: '3.x' 19 | - name: Install flake8 20 | run: | 21 | pip install flake8 22 | - name: run flake8 23 | run: | 24 | flake8 . --count --show-source --statistics 25 | -------------------------------------------------------------------------------- /.github/workflows/load_conda.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # micromamba init 4 | micromamba activate run_tests 5 | export LD_LIBRARY_PATH=$(python .github/workflows/get_base.py)/lib:$LD_LIBRARY_PATH 6 | -------------------------------------------------------------------------------- /.github/workflows/mm_install_mpi.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cp .github/workflows/nodef_condarc ~/.condarc 4 | micromamba install mkl"<=2024.0" mkl-devel"<=2024.0" mkl-service"<=2024.0" mkl_fft mkl_random 5 | micromamba install openmpi openmpi-mpicc 6 | micromamba install libxc conda-forge::fftw 7 | -------------------------------------------------------------------------------- /.github/workflows/mm_install_torch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | cp .github/workflows/nodef_condarc ~/.condarc 4 | micromamba install mkl"<=2024.0" mkl-devel"<=2024.0" mkl-service"<=2024.0" mkl_fft mkl_random 5 | micromamba install libxc conda-forge::fftw 6 | if [ "$RUNNER_OS" == "Linux" ] 7 | then 8 | pip3 install torch --index-url https://download.pytorch.org/whl/cu118 9 | elif [ "$RUNNER_OS" == "macOS" ] 10 | then 11 | pip3 install torch 12 | else 13 | echo "$RUNNER_OS not supported" 14 | exit 1 15 | fi 16 | -------------------------------------------------------------------------------- /.github/workflows/mpi_apt_deps.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ "$RUNNER_OS" == "Linux" ]; then 4 | sudo apt-get -qq install openmpi-bin openmpi-common libopenmpi-dev 5 | sudo apt-get -qq install libscalapack-openmpi-dev 6 | elif [ "$RUNNER_OS" == "macOS" ]; then 7 | brew install open-mpi scalapack 8 | else 9 | echo "$RUNNER_OS not supported" 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /.github/workflows/mpi_tests.yml: -------------------------------------------------------------------------------- 1 | name: Run MPI Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: ['3.12'] 20 | defaults: 21 | run: 22 | shell: bash -el {0} 23 | steps: 24 | - uses: actions/checkout@v4 25 | - name: Setup conda environment 26 | uses: mamba-org/setup-micromamba@v1 27 | with: 28 | micromamba-version: '1.5.6-0' # any version from https://github.com/mamba-org/micromamba-releases 29 | environment-name: run_tests 30 | init-shell: >- 31 | bash 32 | powershell 33 | cache-environment: false 34 | post-cleanup: 'all' 35 | create-args: >- 36 | python=${{ matrix.python-version }} 37 | env: 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 39 | - name: Install dependencies and build 40 | run: | 41 | sudo apt-get -qq install gcc cmake 42 | - name: Build things 43 | run: | 44 | source .github/workflows/load_conda.sh 45 | source .github/workflows/mm_install_mpi.sh 46 | export CMAKE_CONFIGURE_ARGS="-DBUILD_WITH_MKL=ON -DBUILD_LIBXC=OFF" 47 | ./.github/workflows/run_local_pip.sh 48 | python scripts/download_functionals.py 49 | - name: Test with unittest 50 | run: | 51 | source .github/workflows/load_conda.sh 52 | ./.github/workflows/setup_gpaw.sh 53 | ./.github/workflows/run_gpaw_tests.sh 54 | - name: Run MPI tests 55 | run: | 56 | source .github/workflows/load_conda.sh 57 | ./.github/workflows/run_mpi_tests.sh 58 | -------------------------------------------------------------------------------- /.github/workflows/mpi_testsv2.yml: -------------------------------------------------------------------------------- 1 | name: Run MPI Tests BLAS 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | build: 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | os: [ubuntu-latest] 19 | python-version: ["3.12"] 20 | steps: 21 | - uses: actions/checkout@v3 22 | - name: Set up Python ${{ matrix.python-version }} 23 | uses: actions/setup-python@v4 24 | with: 25 | python-version: ${{ matrix.python-version }} 26 | - name: Install and Test 27 | run: ./.github/workflows/run_gpaw_mpi_ci.sh 28 | - name: Run MPI tests 29 | run: | 30 | # Slightly hacky, link gpaw to our internal libxc 31 | export CIDER_DEPS=$(python -c "import ciderpress, os; print(os.path.dirname(ciderpress.__file__))")/lib/deps 32 | export LIBRARY_PATH=$LIBRARY_PATH:$CIDER_DEPS/lib 33 | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CIDER_DEPS/lib 34 | export C_INCLUDE_PATH=$C_INCLUDE_PATH:$CIDER_DEPS/include 35 | ./.github/workflows/run_mpi_tests.sh 36 | -------------------------------------------------------------------------------- /.github/workflows/nodef_condarc: -------------------------------------------------------------------------------- 1 | channels: 2 | - conda-forge 3 | - nodefaults 4 | channel_priority: strict 5 | -------------------------------------------------------------------------------- /.github/workflows/nompi_siteconfig.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import os 22 | 23 | scalapack = False 24 | mklpath = os.environ["CONDA_PREFIX"] 25 | omppath = os.environ["CONDA_PREFIX"] 26 | 27 | mpi = False 28 | fftw = True 29 | compiler = "gcc" 30 | 31 | libraries = [ 32 | "fftw3", 33 | "fftw3_omp", 34 | "xc", 35 | "mkl_intel_lp64", 36 | "mkl_intel_thread", 37 | "mkl_core", 38 | "iomp5", 39 | "pthread", 40 | ] 41 | library_dirs += [f"{omppath}/lib", f"{mklpath}/lib", f"{mklpath}/lib/intel64"] 42 | include_dirs += [f"{omppath}/include", f"{mklpath}/include"] 43 | 44 | extra_compile_args += ["-O3", "-std=c99", "-w", "-m64"] 45 | 46 | define_macros += [ 47 | ("GPAW_NO_UNDERSCORE_CBLACS", "1"), 48 | ("GPAW_NO_UNDERSCORE_CSCALAPACK", "1"), 49 | ("GPAW_NO_UNDERSCORE_SCALAPACK", "1"), 50 | ] 51 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | release: 5 | types: 6 | - released 7 | workflow_dispatch: 8 | 9 | jobs: 10 | release-pypi-sdist: 11 | runs-on: ubuntu-latest 12 | environment: 13 | name: pypi 14 | url: https://pypi.org/p/ciderpress 15 | permissions: 16 | id-token: write 17 | steps: 18 | - uses: actions/checkout@v4 19 | - name: Set up Python 3.12 20 | uses: actions/setup-python@v4 21 | with: 22 | python-version: 3.12 23 | - name: Build sdist 24 | run: | 25 | pip install build 26 | python3 -m build -s 27 | - name: List available sdist 28 | run: | 29 | ls ${{ github.workspace }}/dist 30 | - name: Publish package distributions to PyPI 31 | uses: pypa/gh-action-pypi-publish@release/v1 32 | -------------------------------------------------------------------------------- /.github/workflows/run_core_ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ./.github/workflows/apt_deps.sh 3 | pip install pytest 4 | if [ "$RUNNER_OS" == "Linux" ] 5 | then 6 | pip3 install torch --index-url https://download.pytorch.org/whl/cu118 7 | elif [ "$RUNNER_OS" == "macOS" ] 8 | then 9 | pip3 install torch 10 | else 11 | echo "$RUNNER_OS not supported" 12 | exit 1 13 | fi 14 | if [ "$RUNNER_OS" == "macOS" ]; then 15 | export CC=gcc-14 16 | export CXX=g++-14 17 | export C_INCLUDE_PATH=$(brew --prefix)/include 18 | export LIBRARY_PATH=$(brew --prefix)/lib 19 | export LD_LIBRARY_PATH=$(brew --prefix)/lib 20 | fi 21 | export CMAKE_CONFIGURE_ARGS="-DBUILD_LIBXC=1 -DBUILD_FFTW=1 -DBUILD_WITH_MKL=0 -DBUILD_WITH_MPI=0 -DBUILD_MARCH_NATIVE=0" 22 | pip install . 23 | python scripts/download_functionals.py 24 | ./.github/workflows/run_tests.sh 25 | -------------------------------------------------------------------------------- /.github/workflows/run_gpaw_ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ./.github/workflows/apt_deps.sh 3 | pip install pytest 4 | if [ "$RUNNER_OS" == "macOS" ]; then 5 | export CC=gcc-14 6 | export CXX=g++-14 7 | export C_INCLUDE_PATH=$(brew --prefix)/include 8 | export LIBRARY_PATH=$(brew --prefix)/lib 9 | export LD_LIBRARY_PATH=$(brew --prefix)/lib 10 | fi 11 | export CMAKE_CONFIGURE_ARGS="-DBUILD_LIBXC=1 -DBUILD_FFTW=1 -DBUILD_WITH_MKL=0 -DBUILD_WITH_MPI=0 -DBUILD_MARCH_NATIVE=0" 12 | pip install . 13 | python scripts/download_functionals.py 14 | 15 | # Slightly hacky, link gpaw to our internal libxc 16 | export CIDER_DEPS=$(python -c "import ciderpress, os; print(os.path.dirname(ciderpress.__file__))")/lib/deps 17 | export LIBRARY_PATH=$LIBRARY_PATH:$CIDER_DEPS/lib 18 | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CIDER_DEPS/lib 19 | export C_INCLUDE_PATH=$C_INCLUDE_PATH:$CIDER_DEPS/include 20 | pip install gpaw 21 | gpaw install-data --sg15 --register $PWD 22 | gpaw install-data --register $PWD 23 | 24 | ./.github/workflows/run_gpaw_tests.sh 25 | -------------------------------------------------------------------------------- /.github/workflows/run_gpaw_mpi_ci.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ./.github/workflows/apt_deps.sh 3 | ./.github/workflows/mpi_apt_deps.sh 4 | 5 | if [ "$RUNNER_OS" == "macOS" ]; then 6 | export CC=gcc-14 7 | export CXX=g++-14 8 | fi 9 | 10 | CMAKE_CONFIGURE_ARGS="-DBUILD_LIBXC=on" pip install . 11 | python scripts/download_functionals.py 12 | 13 | # Slightly hacky, link gpaw to our internal libxc 14 | export CIDER_DEPS=$(python -c "import ciderpress, os; print(os.path.dirname(ciderpress.__file__))")/lib/deps 15 | export LIBRARY_PATH=$LIBRARY_PATH:$CIDER_DEPS/lib 16 | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CIDER_DEPS/lib 17 | export C_INCLUDE_PATH=$C_INCLUDE_PATH:$CIDER_DEPS/include 18 | export CIDERDIR=$PWD 19 | cd .. 20 | git clone https://gitlab.com/gpaw/gpaw.git 21 | cd gpaw 22 | cp $CIDERDIR/.github/workflows/gpaw_blas_siteconfig.py siteconfig.py 23 | pip install . 24 | cd .. 25 | gpaw install-data --sg15 --register $PWD 26 | gpaw install-data --register $PWD 27 | cd $CIDERDIR 28 | 29 | ./.github/workflows/run_gpaw_tests.sh 30 | -------------------------------------------------------------------------------- /.github/workflows/run_gpaw_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | export OMP_NUM_THREADS=1 3 | export PYTHONPATH=$(pwd):$PYTHONPATH 4 | ulimit -s 20000 5 | 6 | version=$(python -c 'import sys; print("{0}.{1}".format(*sys.version_info[:2]))') 7 | pytest ciderpress/gpaw -s -c pytest_mpi.ini ciderpress 8 | -------------------------------------------------------------------------------- /.github/workflows/run_local_pip.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | export LIBRARY_PATH=$CONDA_PREFIX/lib:$LIBRARY_PATH 3 | export C_INCLUDE_PATH=$CONDA_PREFIX/include:$C_INCLUDE_PATH 4 | pip install . 5 | -------------------------------------------------------------------------------- /.github/workflows/run_mpi_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | export OMP_NUM_THREADS=1 3 | export PYTHONPATH=$(pwd):$PYTHONPATH 4 | ulimit -s 20000 5 | 6 | version=$(python -c 'import sys; print("{0}.{1}".format(*sys.version_info[:2]))') 7 | mpirun -np 2 --oversubscribe gpaw python -m unittest ciderpress.gpaw.tests.test_basic_calc 8 | mpirun -np 2 --oversubscribe gpaw python -m unittest ciderpress.gpaw.tests.test_si_force 9 | mpirun -np 2 --oversubscribe gpaw python -m unittest ciderpress.gpaw.tests.test_si_stress 10 | -------------------------------------------------------------------------------- /.github/workflows/run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | export OMP_NUM_THREADS=2 3 | export PYTHONPATH=$(pwd):$PYTHONPATH 4 | ulimit -s 20000 5 | 6 | # See https://github.com/pytest-dev/pytest/issues/1075 7 | version=$(python -c 'import sys; print("{0}.{1}".format(*sys.version_info[:2]))') 8 | PYTHONHASHSEED=0 pytest ciderpress/ -s -c pytest.ini ciderpress 9 | -------------------------------------------------------------------------------- /.github/workflows/setup_gpaw.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | export CIDERDIR=$PWD 3 | cd .. 4 | git clone https://gitlab.com/gpaw/gpaw.git 5 | cd gpaw 6 | cp $CIDERDIR/.github/workflows/gpaw_siteconfig.py siteconfig.py 7 | pip install . 8 | cd .. 9 | gpaw install-data --sg15 --register $PWD 10 | gpaw install-data --register $PWD 11 | cd $CIDERDIR 12 | -------------------------------------------------------------------------------- /.github/workflows/setup_gpaw_nompi.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | export CIDERDIR=$PWD 3 | cd .. 4 | git clone https://gitlab.com/gpaw/gpaw.git 5 | cd gpaw 6 | cp $CIDERDIR/.github/workflows/nompi_siteconfig.py siteconfig.py 7 | pip install . 8 | cd .. 9 | gpaw install-data --sg15 --register $PWD 10 | gpaw install-data --register $PWD 11 | cd $CIDERDIR 12 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Run PySCF Tests 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | pull_request: 9 | branches: 10 | - main 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: ['3.12'] 20 | defaults: 21 | run: 22 | shell: bash -el {0} 23 | steps: 24 | - uses: actions/checkout@v4 25 | - name: Setup conda environment 26 | uses: mamba-org/setup-micromamba@v1 27 | with: 28 | micromamba-version: '1.5.6-0' # any version from https://github.com/mamba-org/micromamba-releases 29 | environment-name: run_tests 30 | init-shell: >- 31 | bash 32 | powershell 33 | cache-environment: false 34 | post-cleanup: 'all' 35 | create-args: >- 36 | python=${{ matrix.python-version }} 37 | env: 38 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 39 | - name: Install dependencies and build 40 | run: | 41 | sudo apt-get -qq install gcc cmake 42 | - name: Build things 43 | run: | 44 | source .github/workflows/load_conda.sh 45 | source .github/workflows/mm_install_torch.sh 46 | export CMAKE_CONFIGURE_ARGS="-DBUILD_WITH_MKL=ON -DBUILD_LIBXC=OFF" 47 | ./.github/workflows/run_local_pip.sh 48 | python scripts/download_functionals.py 49 | - name: Test with unittest 50 | run: | 51 | source .github/workflows/load_conda.sh 52 | ./.github/workflows/run_tests.sh 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | build/ 4 | ciderpress/lib/deps/ 5 | ciderpress/lib/pwutil/config.h 6 | ciderpress/lib/fft_wrapper/cider_fft_config.h 7 | dist/ 8 | docs/_build 9 | docs/_static 10 | docs/xml 11 | functionals/ 12 | ***pycache*** 13 | *.egg-info* 14 | *.out 15 | *.err 16 | *.npy 17 | *.npz 18 | *.hdf5 19 | *.html 20 | *.pth 21 | *.dylib 22 | *.so 23 | *.o 24 | *.pyc 25 | *.png 26 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/PyCQA/autoflake 3 | rev: v2.3.1 4 | hooks: 5 | - id: autoflake 6 | args: [--in-place, --remove-all-unused-imports, --remove-unused-variable, --ignore-init-module-imports] 7 | - repo: https://github.com/psf/black 8 | rev: 22.3.0 9 | hooks: 10 | - id: black 11 | - repo: https://github.com/pre-commit/pre-commit-hooks 12 | rev: v4.0.1 13 | hooks: 14 | - id: check-yaml 15 | - id: end-of-file-fixer 16 | - id: trailing-whitespace 17 | - id: mixed-line-ending 18 | args: [--fix=lf] 19 | exclude: '\.bat$' 20 | - repo: https://github.com/pycqa/isort 21 | rev: 5.12.0 22 | hooks: 23 | - id: isort 24 | name: isort (python) 25 | args: [--profile=black] 26 | - repo: https://github.com/pre-commit/mirrors-clang-format 27 | rev: 79dadb849d5247ae54fa1f13f838fde95d91b2e9 28 | hooks: 29 | - id: clang-format 30 | args: ['-style=file'] 31 | exclude: ^docs/ 32 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include MANIFEST.in 2 | include README.md setup.py LICENSE NOTICE 3 | 4 | include ciderpress/data/*.npy 5 | 6 | prune pyscf/lib/build 7 | include ciderpress/lib/*.so 8 | include ciderpress/lib/*.so* 9 | recursive-include ciderpress/lib/deps *.so 10 | recursive-include ciderpress/lib/deps *.so.* 11 | 12 | # macos dynamic libraries 13 | include ciderpress/lib/*.dylib 14 | include ciderpress/lib/*.dylib* 15 | recursive-include ciderpress/lib/deps *.dylib 16 | recursive-include ciderpress/lib/deps *.dylib.* 17 | 18 | # source code 19 | recursive-include ciderpress/lib *.c *.h *.h.in CMakeLists.txt 20 | recursive-exclude ciderpress/lib *.cl 21 | 22 | global-exclude *.py[cod] 23 | prune ciderpress/lib/build 24 | 25 | # docs 26 | recursive-exclude docs/ 27 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | CiderPress: Machine-learning based density functional theory calculations 2 | Copyright (C) 2024 The President and Fellows of Harvard College 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program. If not, see 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | CiderPress: Machine Learned Exchange-Correlation Functionals 6 | ------------------------------------------------------------ 7 | ![Build Status](https://github.com/mir-group/CiderPress/actions/workflows/basic_tests.yml/badge.svg) 8 | 9 | CiderPress provides tools for training and evaluating CIDER functionals for use in Density Functional Theory calculations. Interfaces to the GPAW and PySCF codes are included. 10 | 11 | Please see the [CiderPress website](https://mir-group.github.io/CiderPress/) for installation instructions and documentation. 12 | 13 | ## Questions and Comments 14 | 15 | Find a bug? Areas of code unclearly documented? Other questions? Feel free to contact 16 | Kyle Bystrom at kylebystrom@gmail.com AND/OR create an issue on the [Github page](https://github.com/mir-group/CiderPress/). 17 | 18 | ## Citing 19 | 20 | If you find CiderPress or CIDER functionals useful in your research, please cite the following article 21 | ``` 22 | @article{PhysRevB.110.075130, 23 | title = {Nonlocal machine-learned exchange functional for molecules and solids}, 24 | author = {Bystrom, Kyle and Kozinsky, Boris}, 25 | journal = {Phys. Rev. B}, 26 | volume = {110}, 27 | issue = {7}, 28 | pages = {075130}, 29 | numpages = {30}, 30 | year = {2024}, 31 | month = {Aug}, 32 | publisher = {American Physical Society}, 33 | doi = {10.1103/PhysRevB.110.075130}, 34 | url = {https://link.aps.org/doi/10.1103/PhysRevB.110.075130} 35 | } 36 | ``` 37 | The above article introduces the CIDER23X functionals and much of the algorithms in CiderPress. If you use the CIDER24X functionals, please also cite 38 | ``` 39 | @article{doi:10.1021/acs.jctc.4c00999, 40 | author = {Bystrom, Kyle and Falletta, Stefano and Kozinsky, Boris}, 41 | title = {Training Machine-Learned Density Functionals on Band Gaps}, 42 | journal = {Journal of Chemical Theory and Computation}, 43 | volume = {20}, 44 | number = {17}, 45 | pages = {7516-7532}, 46 | year = {2024}, 47 | doi = {10.1021/acs.jctc.4c00999}, 48 | note ={PMID: 39178337}, 49 | URL = {https://doi.org/10.1021/acs.jctc.4c00999}, 50 | eprint = {https://doi.org/10.1021/acs.jctc.4c00999} 51 | } 52 | ``` 53 | -------------------------------------------------------------------------------- /ciderpress/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.4.0" 2 | -------------------------------------------------------------------------------- /ciderpress/data/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import os 22 | 23 | import numpy as np 24 | 25 | DATA_PATH = os.path.dirname(os.path.abspath(__file__)) 26 | 27 | 28 | def get_hgbs_min_exps(Z): 29 | dpath = os.path.join(DATA_PATH, "expnt_mins.npy") 30 | return np.load(dpath)[int(Z)] 31 | 32 | 33 | def get_hgbs_max_exps(Z): 34 | dpath = os.path.join(DATA_PATH, "expnt_maxs.npy") 35 | return np.load(dpath)[int(Z)] 36 | -------------------------------------------------------------------------------- /ciderpress/data/expnt_maxs.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/data/expnt_maxs.npy -------------------------------------------------------------------------------- /ciderpress/data/expnt_mins.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/data/expnt_mins.npy -------------------------------------------------------------------------------- /ciderpress/dft/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/dft/__init__.py -------------------------------------------------------------------------------- /ciderpress/dft/debug_numint.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import ctypes 22 | 23 | import numpy as np 24 | 25 | from ciderpress.dft.plans import get_cider_exponent 26 | from ciderpress.lib import load_library as load_cider_library 27 | 28 | libcider = load_cider_library("libmcider") 29 | 30 | 31 | def get_get_exponent(gg_kwargs): 32 | def _get_exponent(rho_data): 33 | rho = rho_data[0] 34 | sigma = np.einsum("xg,xg->g", rho_data[1:4], rho_data[1:4]) 35 | tau = rho_data[4] 36 | return get_cider_exponent( 37 | rho, 38 | sigma, 39 | tau, 40 | a0=gg_kwargs["a0"], 41 | grad_mul=0, 42 | tau_mul=gg_kwargs["fac_mul"], 43 | nspin=1, 44 | )[0] 45 | 46 | return _get_exponent 47 | 48 | 49 | def get_nonlocal_features( 50 | rho, coords, vvrho, vvweight, vvcoords, get_exponent_r, get_exponent_rp, version="i" 51 | ): 52 | thresh = 1e-8 53 | nfeat = 12 if version == "i" else 4 54 | feat = np.zeros((rho[0].size, nfeat)) 55 | 56 | threshind = rho[0] >= thresh 57 | coords = coords[threshind] 58 | expnt_data = get_exponent_r(rho[:, threshind]) 59 | 60 | innerthreshind = vvrho[0] >= thresh 61 | vvcoords = vvcoords[innerthreshind] 62 | vvweight = vvweight[innerthreshind] 63 | vvexpnt_data = get_exponent_rp(vvrho[:, innerthreshind]) 64 | 65 | vvf = vvrho[0, innerthreshind] * vvweight 66 | 67 | vvcoords = np.asarray(vvcoords, order="C") 68 | coords = np.asarray(coords, order="C") 69 | _feat = np.empty((expnt_data.shape[0], nfeat)) 70 | 71 | if version == "i": 72 | libcider.debug_numint_vi( 73 | _feat.ctypes.data_as(ctypes.c_void_p), 74 | vvexpnt_data.ctypes.data_as(ctypes.c_void_p), 75 | vvf.ctypes.data_as(ctypes.c_void_p), 76 | vvcoords.ctypes.data_as(ctypes.c_void_p), 77 | coords.ctypes.data_as(ctypes.c_void_p), 78 | ctypes.c_int(vvcoords.shape[0]), 79 | ctypes.c_int(coords.shape[0]), 80 | ) 81 | else: 82 | if version == "j": 83 | fn = libcider.debug_numint_vj 84 | elif version == "k": 85 | fn = libcider.debug_numint_vk 86 | else: 87 | raise ValueError("Version must be i, j, or k") 88 | fn( 89 | _feat.ctypes.data_as(ctypes.c_void_p), 90 | vvexpnt_data.ctypes.data_as(ctypes.c_void_p), 91 | expnt_data.ctypes.data_as(ctypes.c_void_p), 92 | vvf.ctypes.data_as(ctypes.c_void_p), 93 | vvcoords.ctypes.data_as(ctypes.c_void_p), 94 | coords.ctypes.data_as(ctypes.c_void_p), 95 | ctypes.c_int(vvcoords.shape[0]), 96 | ctypes.c_int(coords.shape[0]), 97 | ctypes.c_double(2.0), 98 | ) 99 | feat[threshind, :] = _feat 100 | return feat 101 | -------------------------------------------------------------------------------- /ciderpress/dft/density_util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import numpy as np 22 | 23 | 24 | def get_sigma(grad_svg): 25 | nspin = grad_svg.shape[0] 26 | shape = grad_svg.shape[2:] 27 | if nspin not in [1, 2]: 28 | raise ValueError("Only 1 or 2 spins supported") 29 | sigma_xg = np.empty((2 * nspin - 1,) + shape) 30 | sigma_xg[::2] = np.einsum("sv...,sv...->s...", grad_svg, grad_svg) 31 | if nspin == 2: 32 | sigma_xg[1] = np.einsum("v...,v...->...", grad_svg[0], grad_svg[1]) 33 | return sigma_xg 34 | 35 | 36 | def get_dsigmadf(grad_svg, dgraddf_ovg, spins): 37 | norb = len(spins) 38 | assert dgraddf_ovg.shape[0] == norb 39 | shape = grad_svg.shape[2:] 40 | dsigmadf_og = np.empty((norb,) + shape) 41 | for o, s in enumerate(spins): 42 | dsigmadf_og[o] = 2 * np.einsum("vg,vg->g", grad_svg[s], dgraddf_ovg[o]) 43 | return dsigmadf_og 44 | -------------------------------------------------------------------------------- /ciderpress/dft/model_utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import joblib 22 | import yaml 23 | 24 | from ciderpress.dft.xc_evaluator import MappedXC 25 | from ciderpress.dft.xc_evaluator2 import MappedXC2 26 | 27 | 28 | def load_cider_model(mlfunc, mlfunc_format): 29 | if isinstance(mlfunc, str): 30 | if mlfunc_format is None: 31 | if mlfunc.endswith(".yaml"): 32 | mlfunc_format = "yaml" 33 | elif mlfunc.endswith(".joblib"): 34 | mlfunc_format = "joblib" 35 | else: 36 | raise ValueError("Unsupported file format") 37 | if mlfunc_format == "yaml": 38 | with open(mlfunc, "r") as f: 39 | mlfunc = yaml.load(f, Loader=yaml.CLoader) 40 | elif mlfunc_format == "joblib": 41 | mlfunc = joblib.load(mlfunc) 42 | else: 43 | raise ValueError("Unsupported file format") 44 | if not isinstance(mlfunc, (MappedXC, MappedXC2)): 45 | raise ValueError("mlfunc must be MappedXC") 46 | return mlfunc 47 | 48 | 49 | def get_slxc_settings(xc, xkernel, ckernel, xmix): 50 | if xc is None: 51 | # xc is another way to specify non-mixed part of kernel 52 | xc = "" 53 | if ckernel is not None: 54 | xc = ckernel + " + " + xc 55 | if xkernel is not None: 56 | xc = "{} * {} + {}".format(1 - xmix, xkernel, xc) 57 | if xc.endswith(" + "): 58 | xc = xc[:-3] 59 | return xc 60 | -------------------------------------------------------------------------------- /ciderpress/dft/sph_harm_coeff.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import numpy as np 22 | from sympy.physics.wigner import clebsch_gordan 23 | 24 | from ciderpress.lib import load_library as load_cider_library 25 | 26 | libcider = load_cider_library("libmcider") 27 | 28 | 29 | def change_basis_real_to_complex(l: int) -> np.ndarray: 30 | # https://en.wikipedia.org/wiki/Spherical_harmonics#Real_form 31 | q = np.zeros((2 * l + 1, 2 * l + 1), dtype=np.complex128) 32 | for m in range(-l, 0): 33 | q[l + m, l + abs(m)] = 1 / np.sqrt(2) 34 | q[l + m, l - abs(m)] = -1j / np.sqrt(2) 35 | q[l, l] = 1 36 | for m in range(1, l + 1): 37 | q[l + m, l + abs(m)] = (-1) ** m / np.sqrt(2) 38 | q[l + m, l - abs(m)] = 1j * (-1) ** m / np.sqrt(2) 39 | # Added factor of 1j**l to make the Clebsch-Gordan coefficients real 40 | return (-1j) ** l * q 41 | 42 | 43 | def su2_clebsch_gordan(l1, l2, l3): 44 | mat = np.zeros( 45 | [ 46 | 2 * l1 + 1, 47 | 2 * l2 + 1, 48 | 2 * l3 + 1, 49 | ] 50 | ) 51 | for m1 in range(2 * l1 + 1): 52 | for m2 in range(2 * l2 + 1): 53 | for m3 in range(2 * l3 + 1): 54 | mat[m1, m2, m3] = clebsch_gordan(l1, l2, l3, m1 - l1, m2 - l2, m3 - l3) 55 | return mat 56 | 57 | 58 | def clebsch_gordan_e3nn(l1: int, l2: int, l3: int) -> np.ndarray: 59 | r""" 60 | The Clebsch-Gordan coefficients of the real irreducible representations of :math:`SO(3)`. 61 | This function taken from https://github.com/e3nn/e3nn 62 | 63 | Args: 64 | l1 (int): the representation order of the first irrep 65 | l2 (int): the representation order of the second irrep 66 | l3 (int): the representation order of the third irrep 67 | 68 | Returns: 69 | np.ndarray: the Clebsch-Gordan coefficients 70 | """ 71 | C = su2_clebsch_gordan(l1, l2, l3) 72 | Q1 = change_basis_real_to_complex(l1) 73 | Q2 = change_basis_real_to_complex(l2) 74 | Q3 = change_basis_real_to_complex(l3) 75 | C = np.einsum("ij,kl,mn,ikn->jlm", Q1, Q2, np.conj(Q3.T), C) 76 | 77 | assert np.all(np.abs(np.imag(C)) < 1e-5) 78 | return np.real(C) 79 | 80 | 81 | def get_deriv_ylm_coeff(lmax): 82 | nlm = (lmax + 1) * (lmax + 1) 83 | gaunt_coeff = np.zeros((5, nlm)) 84 | for l in range(lmax + 1): 85 | fe = clebsch_gordan_e3nn(l, 1, l + 1) 86 | for im in range(2 * l + 1): 87 | lm = l * l + im 88 | m = abs(im - l) 89 | l1m = l + 1 - m 90 | fac = ((2 * l + 3) * (l + 1)) ** 0.5 91 | gaunt_coeff[0, lm] = fac * fe[im, 2, im] 92 | gaunt_coeff[1, lm] = fac * fe[im, 2, im + 2] 93 | gaunt_coeff[2, lm] = fac * fe[im, 0, 2 * l - im] 94 | gaunt_coeff[3, lm] = fac * fe[im, 0, 2 * l - im + 2] 95 | gaunt_coeff[4, lm] = np.sqrt( 96 | ((2.0 * l + 3) * l1m * (l + 1 + m) / (2 * l + 1)) 97 | ) 98 | return gaunt_coeff 99 | -------------------------------------------------------------------------------- /ciderpress/dft/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/dft/tests/__init__.py -------------------------------------------------------------------------------- /ciderpress/dft/tests/test_grids_indexer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import ctypes 22 | import unittest 23 | 24 | import numpy as np 25 | from numpy.testing import assert_almost_equal 26 | from pyscf import gto 27 | from pyscf.dft.gen_grid import libdft 28 | 29 | from ciderpress.pyscf.gen_cider_grid import CiderGrids 30 | 31 | 32 | class TestAtomicGridsIndexer(unittest.TestCase): 33 | def test_a2y(self): 34 | mol = gto.M(atom="H 0 0 0; F 0 0 0.9", basis="def2-tzvp") 35 | grids = CiderGrids(mol) 36 | n = 194 37 | grids.atom_grid = {"H": (30, n), "F": (50, n)} 38 | grids.prune = None 39 | grids.build() 40 | grid = np.empty((n, 4)) 41 | libdft.MakeAngularGrid(grid.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(n)) 42 | ang_wt = np.ascontiguousarray(grid[:, 3]) 43 | indexer = grids.grids_indexer 44 | nalpha = 10 45 | theta_rlmq = indexer.empty_rlmq(nalpha) 46 | theta_new_rlmq = indexer.empty_rlmq(nalpha) 47 | theta_gq = indexer.empty_gq(nalpha) 48 | np.random.seed(89) 49 | theta_rlmq[:] = np.random.normal(size=theta_rlmq.shape) 50 | indexer.reduce_angc_ylm_(theta_rlmq, theta_gq, a2y=False) 51 | shape = theta_gq.shape 52 | theta_gq.shape = (-1, n, nalpha) 53 | theta_gq *= ang_wt[None, :, None] * 4 * np.pi 54 | theta_gq.shape = shape 55 | indexer.reduce_angc_ylm_(theta_new_rlmq, theta_gq, a2y=True) 56 | assert_almost_equal(theta_new_rlmq, theta_rlmq) 57 | 58 | theta_big_gq = np.zeros((theta_gq.shape[0], nalpha + 7)) 59 | indexer.reduce_angc_ylm_(theta_rlmq, theta_gq, a2y=False) 60 | indexer.reduce_angc_ylm_(theta_rlmq, theta_big_gq, a2y=False, offset=3) 61 | assert (theta_big_gq[:, :3] == 0).all() 62 | assert (theta_big_gq[:, -4:] == 0).all() 63 | assert_almost_equal(theta_big_gq[:, 3:-4], theta_gq, 14) 64 | theta_big_gq[:, :3] = np.random.normal(size=theta_big_gq[:, :3].shape) 65 | theta_big_gq[:, -4:] = np.random.normal(size=theta_big_gq[:, -4:].shape) 66 | theta_new2_rlmq = np.empty_like(theta_new_rlmq) 67 | indexer.reduce_angc_ylm_(theta_new_rlmq, theta_gq, a2y=True, offset=0) 68 | indexer.reduce_angc_ylm_(theta_new2_rlmq, theta_big_gq, a2y=True, offset=3) 69 | # NOTE this test is fine on laptop with 14 digits but fails on Github CI 70 | assert_almost_equal(theta_new2_rlmq, theta_new_rlmq, 13) 71 | 72 | 73 | if __name__ == "__main__": 74 | unittest.main() 75 | -------------------------------------------------------------------------------- /ciderpress/external/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/external/__init__.py -------------------------------------------------------------------------------- /ciderpress/external/sgx_tools.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright 2014-2020 The PySCF Developers. All Rights Reserved. 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | # Author: Qiming Sun 17 | # Edits by Kyle Bystrom 18 | # 19 | 20 | import time 21 | 22 | import numpy 23 | from pyscf.sgx.sgx_jk import _gen_batch_nuc, _gen_jk_direct, lib, logger 24 | 25 | 26 | def get_jk_densities(sgx, dm, hermi=1, direct_scf_tol=1e-13): 27 | t0 = time.monotonic(), time.time() 28 | mol = sgx.mol 29 | grids = sgx.grids 30 | gthrd = sgx.grids_thrd 31 | 32 | dms = numpy.asarray(dm) 33 | dm_shape = dms.shape 34 | nao = dm_shape[-1] 35 | dms = dms.reshape(-1, nao, nao) 36 | nset = dms.shape[0] 37 | 38 | if sgx.debug: 39 | batch_nuc = _gen_batch_nuc(mol) 40 | else: 41 | batch_jk = _gen_jk_direct( 42 | mol, "s2", True, True, direct_scf_tol, sgx._opt, pjs=False 43 | ) 44 | logger.timer_debug1(mol, "sgX initialziation", *t0) 45 | 46 | ngrids = grids.coords.shape[0] 47 | max_memory = sgx.max_memory - lib.current_memory()[0] 48 | sblk = sgx.blockdim 49 | blksize = min(ngrids, max(4, int(min(sblk, max_memory * 1e6 / 8 / nao**2)))) 50 | tnuc = 0, 0 51 | ej, ek = numpy.zeros((nset, ngrids)), numpy.zeros((nset, ngrids)) 52 | for i0, i1 in lib.prange(0, ngrids, blksize): 53 | coords = grids.coords[i0:i1] 54 | ao = mol.eval_gto("GTOval", coords) 55 | wao = ao * grids.weights[i0:i1, None] 56 | 57 | fg = lib.einsum("gi,xij->xgj", wao, dms) 58 | fgnw = lib.einsum("gi,xij->xgj", ao, dms) 59 | mask = numpy.zeros(i1 - i0, dtype=bool) 60 | for i in range(nset): 61 | mask |= numpy.any(fg[i] > gthrd, axis=1) 62 | mask |= numpy.any(fg[i] < -gthrd, axis=1) 63 | 64 | inds = numpy.arange(i0, i1) 65 | 66 | numpy.einsum("xgu,gu->xg", fg, ao) 67 | rho = numpy.einsum("xgu,gu->xg", fgnw, ao) 68 | 69 | if sgx.debug: 70 | tnuc = tnuc[0] - time.monotonic(), tnuc[1] - time.time() 71 | gbn = batch_nuc(mol, coords) 72 | tnuc = tnuc[0] + time.monotonic(), tnuc[1] + time.time() 73 | jg = numpy.einsum("gij,xij->xg", gbn, dms) 74 | gv = lib.einsum("gvt,xgt->xgv", gbn, fgnw) 75 | gbn = None 76 | else: 77 | tnuc = tnuc[0] - time.monotonic(), tnuc[1] - time.time() 78 | jg, gv = batch_jk(mol, coords, dms, fgnw.copy(), None) 79 | tnuc = tnuc[0] + time.monotonic(), tnuc[1] + time.time() 80 | 81 | jg = numpy.sum(jg, axis=0) 82 | ej[:, inds] = jg * rho / 2.0 83 | for i in range(nset): 84 | ek[i, inds] = lib.einsum("gu,gu->g", fgnw[i], gv[i]) 85 | 86 | jg = gv = None 87 | 88 | ek *= -0.5 89 | return ej, ek 90 | -------------------------------------------------------------------------------- /ciderpress/gpaw/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/gpaw/__init__.py -------------------------------------------------------------------------------- /ciderpress/gpaw/cider_sl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import numpy as np 22 | import yaml 23 | 24 | from ciderpress.gpaw.cider_kernel import CiderGGAHybridKernel, CiderMGGAHybridKernel 25 | from ciderpress.gpaw.interp_paw import DiffGGA, DiffMGGA 26 | 27 | 28 | class SLCiderGGAHybridWrapper(CiderGGAHybridKernel): 29 | def calculate(self, e_g, n_sg, v_sg, sigma_xg, dedsigma_xg): 30 | super(SLCiderGGAHybridWrapper, self).calculate( 31 | e_g, 32 | n_sg, 33 | v_sg, 34 | sigma_xg, 35 | dedsigma_xg, 36 | np.zeros( 37 | ( 38 | n_sg.shape[0], 39 | 3, 40 | ) 41 | + e_g.shape, 42 | dtype=e_g.dtype, 43 | ), 44 | ) 45 | 46 | 47 | class SLCiderMGGAHybridWrapper(CiderMGGAHybridKernel): 48 | def calculate(self, e_g, n_sg, v_sg, sigma_xg, dedsigma_xg, tau_sg, dedtau_sg): 49 | super(SLCiderMGGAHybridWrapper, self).calculate( 50 | e_g, 51 | n_sg, 52 | v_sg, 53 | sigma_xg, 54 | dedsigma_xg, 55 | tau_sg, 56 | dedtau_sg, 57 | np.zeros( 58 | ( 59 | n_sg.shape[0], 60 | 3, 61 | ) 62 | + e_g.shape, 63 | dtype=e_g.dtype, 64 | ), 65 | ) 66 | 67 | 68 | class _SLCiderBase: 69 | def get_setup_name(self): 70 | return "PBE" 71 | 72 | def todict(self): 73 | kparams = self.kernel.todict() 74 | return { 75 | "kernel_params": kparams, 76 | } 77 | 78 | def get_mlfunc_data(self): 79 | return yaml.dump(self.kernel.mlfunc, Dumper=yaml.CDumper) 80 | 81 | 82 | class SLCiderGGA(_SLCiderBase, DiffGGA): 83 | def todict(self): 84 | d = super(SLCiderGGA, self).todict() 85 | d["_cider_type"] = "SLCiderGGA" 86 | return d 87 | 88 | 89 | class SLCiderMGGA(_SLCiderBase, DiffMGGA): 90 | def todict(self): 91 | d = super(SLCiderMGGA, self).todict() 92 | d["_cider_type"] = "SLCiderMGGA" 93 | return d 94 | -------------------------------------------------------------------------------- /ciderpress/gpaw/config.py: -------------------------------------------------------------------------------- 1 | GPAW_USE_NEW_PLANS = True 2 | GPAW_DEFAULT_RHO_TOL = 1e-8 3 | -------------------------------------------------------------------------------- /ciderpress/gpaw/tests/__init__.py: -------------------------------------------------------------------------------- 1 | from numpy.testing import assert_allclose 2 | 3 | 4 | def equal(x, y, t): 5 | assert_allclose(x, y, atol=t) 6 | -------------------------------------------------------------------------------- /ciderpress/gpaw/tests/test_basic_calc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import unittest 22 | 23 | import numpy as np 24 | from ase.build import bulk 25 | from gpaw import PW 26 | from numpy.testing import assert_almost_equal 27 | 28 | from ciderpress.gpaw.calculator import CiderGPAW, get_cider_functional 29 | 30 | NKPT = 4 31 | REFERENCE_ENERGIES = { 32 | "CIDER23X_SL_GGA": -12.866290987790224, 33 | "CIDER23X_NL_GGA": -13.046146980191777, 34 | "CIDER23X_SL_MGGA": -12.265893307629582, 35 | "CIDER23X_NL_MGGA_DTR": -12.53022643638701, 36 | } 37 | USE_AUGMENT_GRIDS = True 38 | 39 | 40 | def run_calc(xc, spinpol, setups="paw"): 41 | atoms = bulk("Si") 42 | mlfunc = "functionals/{}.yaml".format(xc) 43 | xc = get_cider_functional( 44 | mlfunc, 45 | xmix=0.25, 46 | qmax=300, 47 | lambd=1.8, 48 | pasdw_store_funcs=True, 49 | pasdw_ovlp_fit=True, # not USE_FAST_GPAW, 50 | use_paw=False if setups == "sg15" else True, 51 | ) 52 | 53 | atoms.calc = CiderGPAW( 54 | h=0.18, # use a reasonably small grid spacing 55 | xc=xc, # assign the CIDER functional to xc 56 | mode=PW(520), # plane-wave mode with 520 eV cutoff. 57 | txt="-", # output file, '-' for stdout 58 | occupations={"name": "fermi-dirac", "width": 0.01}, 59 | kpts={"size": (NKPT, NKPT, NKPT), "gamma": False}, # kpt mesh parameters 60 | convergence={"energy": 1e-7}, # convergence energy in eV/electron 61 | spinpol=spinpol, 62 | setups=setups, 63 | parallel={"augment_grids": USE_AUGMENT_GRIDS}, 64 | ) 65 | etot = atoms.get_potential_energy() # run the calculation 66 | return etot 67 | 68 | 69 | def generate_test(xcname): 70 | e_ref = REFERENCE_ENERGIES[xcname] 71 | 72 | def run_test(self): 73 | with np.errstate(all="ignore"): 74 | e_rks = run_calc(xcname, False) 75 | e_uks = run_calc(xcname, True) 76 | assert_almost_equal(e_rks, e_ref, 6) 77 | assert_almost_equal(e_uks, e_ref, 6) 78 | 79 | return run_test 80 | 81 | 82 | class TestEnergy(unittest.TestCase): 83 | 84 | test_sl_gga = generate_test("CIDER23X_SL_GGA") 85 | 86 | test_nl_gga = generate_test("CIDER23X_NL_GGA") 87 | 88 | test_sl_mgga = generate_test("CIDER23X_SL_MGGA") 89 | 90 | test_nl_mgga = generate_test("CIDER23X_NL_MGGA_DTR") 91 | 92 | 93 | if __name__ == "__main__": 94 | unittest.main() 95 | -------------------------------------------------------------------------------- /ciderpress/gpaw/tests/test_fe_force.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import unittest 22 | 23 | import numpy as np 24 | from ase.build import bulk 25 | from gpaw import GPAW, PW, FermiDirac 26 | from gpaw.mpi import world 27 | 28 | from ciderpress.gpaw.calculator import get_cider_functional 29 | from ciderpress.gpaw.tests import equal 30 | 31 | 32 | def numeric_force(atoms, a, i, d=0.001, get_xc=None): 33 | """Compute numeric force on atom with index a, Cartesian component i, 34 | with finite step of size d 35 | """ 36 | p0 = atoms.get_positions() 37 | p = p0.copy() 38 | p[a, i] += d 39 | atoms.set_positions(p, apply_constraint=False) 40 | eplus = atoms.get_potential_energy() 41 | p[a, i] -= 2 * d 42 | atoms.set_positions(p, apply_constraint=False) 43 | eminus = atoms.get_potential_energy() 44 | atoms.set_positions(p0, apply_constraint=False) 45 | return (eminus - eplus) / (2 * d) 46 | 47 | 48 | def _run_cider_forces(functional, get_xc=None): 49 | m = [2.2, 2.2] 50 | fe = bulk("Fe", crystalstructure="bcc") 51 | fe = fe * [2, 1, 1] 52 | fe.set_initial_magnetic_moments(m) 53 | if get_xc is not None: 54 | functional = get_xc() 55 | fe.calc = GPAW( 56 | mode=PW(500), 57 | h=0.2, 58 | occupations=FermiDirac(width=0.1), 59 | xc=functional, 60 | kpts=(2, 4, 4), 61 | convergence={"energy": 1e-8}, 62 | parallel={"domain": min(2, world.size), "augment_grids": True}, 63 | symmetry="off", 64 | txt="fe.txt", 65 | ) 66 | pos = fe.get_positions() 67 | pos[0, 1] += 0.08 68 | fe.set_positions(pos) 69 | fe.get_potential_energy() 70 | f1 = fe.get_forces()[0, 2] 71 | 72 | f2 = numeric_force(fe, 0, 2, 0.001, get_xc=get_xc) 73 | print((f1, f2, f1 - f2)) 74 | # This is a really loose bound but same order as with PBE 75 | # Just to make things things aren't totally broken 76 | equal(f1, f2, 0.02) 77 | 78 | 79 | def run_cider_forces(functional, get_xc=None): 80 | with np.errstate(all="ignore"): 81 | _run_cider_forces(functional, get_xc=get_xc) 82 | 83 | 84 | class TestForce(unittest.TestCase): 85 | def test_nl_mgga(self): 86 | def get_xc(): 87 | return get_cider_functional( 88 | "functionals/CIDER23X_NL_MGGA_DTR.yaml", 89 | qmax=300, 90 | lambd=1.8, 91 | xmix=0.25, 92 | pasdw_ovlp_fit=False, 93 | pasdw_store_funcs=False, 94 | ) 95 | 96 | run_cider_forces(get_xc()) 97 | 98 | 99 | if __name__ == "__main__": 100 | unittest.main() 101 | -------------------------------------------------------------------------------- /ciderpress/gpaw/tests/test_fe_stress.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import unittest 22 | 23 | import numpy as np 24 | from ase.build import bulk 25 | from ase.parallel import parprint 26 | from gpaw import GPAW, PW, FermiDirac 27 | from gpaw.mpi import world 28 | 29 | from ciderpress.gpaw.calculator import get_cider_functional 30 | 31 | USE_STORED_REF = True 32 | 33 | 34 | def _run_pw_si_stress(xc, use_pp=False, s_numerical=None): 35 | # This is based on a test from GPAW 36 | k = 3 37 | m = [2.2] 38 | si = bulk("Fe") 39 | si.set_initial_magnetic_moments(m) 40 | si.calc = GPAW( 41 | mode=PW(800), 42 | h=0.15, 43 | occupations=FermiDirac(width=0.1), 44 | xc=xc, 45 | kpts=(k, k, k), 46 | convergence={"energy": 1e-8}, 47 | parallel={"domain": min(2, world.size), "augment_grids": True}, 48 | txt="fe.txt", 49 | ) 50 | 51 | si.set_cell( 52 | np.dot(si.cell, [[1.02, 0, 0.03], [0, 0.99, -0.02], [0.2, -0.01, 1.03]]), 53 | scale_atoms=True, 54 | ) 55 | si.get_potential_energy() 56 | 57 | # Trigger nasty bug (fixed in !486): 58 | si.calc.wfs.pt.blocksize = si.calc.wfs.pd.maxmyng - 1 59 | s_analytical = si.get_stress() 60 | if s_numerical is None: 61 | s_numerical = si.calc.calculate_numerical_stress(si, 1e-5) 62 | s_err = s_numerical - s_analytical 63 | 64 | parprint("Analytical stress:\n", s_analytical) 65 | parprint("Numerical stress:\n", s_numerical) 66 | parprint("Error in stress:\n", s_err) 67 | assert np.all(abs(s_err) < 1e-4) 68 | 69 | 70 | def run_pw_si_stress(xc, use_pp=False, s_numerical=None): 71 | with np.errstate(all="ignore"): 72 | _run_pw_si_stress(xc, use_pp=use_pp, s_numerical=s_numerical) 73 | 74 | 75 | def get_xc(fname, use_paw=True): 76 | return get_cider_functional(fname, xmix=0.25, pasdw_ovlp_fit=False, use_paw=use_paw) 77 | 78 | 79 | class TestStress(unittest.TestCase): 80 | def test_nl_mgga(self): 81 | xc = get_xc("functionals/CIDER23X_NL_MGGA_DTR.yaml") 82 | if USE_STORED_REF: 83 | s_numerical = np.array( 84 | [ 85 | -0.03445521, 86 | -0.1184332, 87 | -0.09615671, 88 | -0.03262395, 89 | 0.2034452, 90 | 0.01842121, 91 | ] 92 | ) 93 | run_pw_si_stress(xc, s_numerical=s_numerical) 94 | else: 95 | run_pw_si_stress(xc, s_numerical=None) 96 | 97 | 98 | if __name__ == "__main__": 99 | unittest.main() 100 | -------------------------------------------------------------------------------- /ciderpress/gpaw/tests/test_gpaw_grids.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | import numpy as np 4 | from numpy.testing import assert_allclose 5 | 6 | from ciderpress.gpaw.gpaw_grids import SBTFullGridDescriptor 7 | 8 | LMAX = 6 9 | 10 | 11 | def gaussian(l, alpha, r): 12 | return r**l * np.exp(-alpha * r * r) 13 | 14 | 15 | def gaussian_ft(l, alpha, k): 16 | const = np.pi**1.5 / 2**l / alpha ** (1.5 + l) 17 | return const * k**l * np.exp((-0.25 / alpha) * k * k) 18 | 19 | 20 | class TestSBT(unittest.TestCase): 21 | def test_sbt_gaussian(self): 22 | sbtgd = SBTFullGridDescriptor(0.001, 1e12, 0.02, N=1024, lmax=LMAX) 23 | for l in range(LMAX + 1): 24 | for alpha in [0.01, 0.1, 1.0, 10.0, 100.0]: 25 | scale = alpha ** (1.5 + 0.5 * l) 26 | f_g = scale * gaussian(l, alpha, sbtgd.r_g) 27 | fref_k = scale * gaussian_ft(l, alpha, sbtgd.k_g) 28 | ftest_k = 4 * np.pi * sbtgd.transform_single_fwd(f_g, l) 29 | print("MINMAX", np.min(sbtgd.k_g), np.max(sbtgd.k_g)) 30 | print( 31 | np.linalg.norm(ftest_k - fref_k), 32 | np.linalg.norm(fref_k), 33 | np.linalg.norm(ftest_k), 34 | ) 35 | print(np.max(np.abs(ftest_k - fref_k))) 36 | assert_allclose(ftest_k, fref_k, atol=1e-4, rtol=0) 37 | ftest_g = (0.25 / np.pi) * sbtgd.transform_single_bwd(ftest_k, l) 38 | assert_allclose(ftest_g, f_g, atol=1e-4, rtol=0) 39 | 40 | 41 | if __name__ == "__main__": 42 | unittest.main() 43 | -------------------------------------------------------------------------------- /ciderpress/gpaw/tests/test_nldf_interface.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import unittest 22 | 23 | import numpy as np 24 | from gpaw.mpi import MPIComm, world 25 | from gpaw.pw.descriptor import PWDescriptor 26 | from numpy.testing import assert_allclose 27 | 28 | from ciderpress.gpaw.nldf_interface import GridDescriptor, LibCiderPW, wrap_fft_mpi 29 | 30 | 31 | class TestLibCiderPW(unittest.TestCase): 32 | def test_pwutil(self): 33 | np.random.seed(98) 34 | comm = MPIComm(world) 35 | N_c = [100, 80, 110] 36 | cell_cv = np.diag(np.ones(3)) 37 | ciderpw = LibCiderPW(N_c, cell_cv, comm) 38 | ciderpw.initialize_backend() 39 | gd = GridDescriptor(N_c, cell_cv, comm=MPIComm(world)) 40 | pd = PWDescriptor(180, gd, dtype=float) 41 | wrapper = wrap_fft_mpi(pd) 42 | input = np.random.normal(size=N_c)[None, :, :, :] 43 | input = gd.distribute(input) 44 | output_ref = pd.fft(input) 45 | sum = np.abs(output_ref).sum() 46 | sum = pd.gd.comm.sum_scalar(sum) 47 | for i in range(20): 48 | output_test = wrapper.fft(input) 49 | input_test = wrapper.ifft(output_test) 50 | input_ref = pd.ifft(output_ref) 51 | assert_allclose(output_test[0], output_ref) 52 | assert_allclose(input_test[0], input_ref) 53 | 54 | 55 | if __name__ == "__main__": 56 | unittest.main() 57 | -------------------------------------------------------------------------------- /ciderpress/gpaw/tests/test_pp_force.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import unittest 22 | 23 | import numpy as np 24 | from ase import Atoms 25 | from gpaw import GPAW, PW, FermiDirac, Mixer 26 | 27 | from ciderpress.gpaw.calculator import get_cider_functional 28 | from ciderpress.gpaw.tests import equal 29 | 30 | 31 | def numeric_force(atoms, a, i, d=0.001, get_xc=None): 32 | """Compute numeric force on atom with index a, Cartesian component i, 33 | with finite step of size d 34 | """ 35 | p0 = atoms.get_positions() 36 | p = p0.copy() 37 | p[a, i] += d 38 | atoms.set_positions(p, apply_constraint=False) 39 | eplus = atoms.get_potential_energy() 40 | p[a, i] -= 2 * d 41 | atoms.set_positions(p, apply_constraint=False) 42 | eminus = atoms.get_potential_energy() 43 | atoms.set_positions(p0, apply_constraint=False) 44 | return (eminus - eplus) / (2 * d) 45 | 46 | 47 | def _run_cider_forces(functional, get_xc=None): 48 | a = 5.45 49 | bulk = Atoms( 50 | symbols="Si8", 51 | positions=[ 52 | (0, 0, 0.1 / a), 53 | (0, 0.5, 0.5), 54 | (0.5, 0, 0.5), 55 | (0.5, 0.5, 0), 56 | (0.25, 0.25, 0.25), 57 | (0.25, 0.75, 0.75), 58 | (0.75, 0.25, 0.75), 59 | (0.75, 0.75, 0.25), 60 | ], 61 | pbc=True, 62 | ) 63 | bulk.set_cell((a, a, a), scale_atoms=True) 64 | if get_xc is not None: 65 | functional = get_xc() 66 | calc = GPAW( 67 | h=0.20, 68 | mode=PW(350), 69 | xc=functional, 70 | nbands="150%", 71 | occupations=FermiDirac(width=0.01), 72 | kpts=(3, 3, 3), 73 | convergence={"energy": 1e-7}, 74 | mixer=Mixer(0.7, 8, 50), 75 | setups="sg15", 76 | parallel={"augment_grids": True}, 77 | ) 78 | bulk.calc = calc 79 | f1 = bulk.get_forces()[0, 2] 80 | bulk.get_potential_energy() 81 | 82 | f2 = numeric_force(bulk, 0, 2, 0.001, get_xc=get_xc) 83 | print((f1, f2, f1 - f2)) 84 | equal(f1, f2, 0.0005) 85 | 86 | 87 | def run_cider_forces(functional, get_xc=None): 88 | with np.errstate(all="ignore"): 89 | _run_cider_forces(functional, get_xc=get_xc) 90 | 91 | 92 | class TestForce(unittest.TestCase): 93 | def test_sl_gga(self): 94 | run_cider_forces(get_cider_functional("functionals/CIDER23X_SL_GGA.yaml")) 95 | 96 | @unittest.expectedFailure 97 | def test_sl_mgga(self): 98 | run_cider_forces(get_cider_functional("functionals/CIDER23X_SL_MGGA.yaml")) 99 | 100 | def test_nl_gga(self): 101 | def get_xc(): 102 | return get_cider_functional( 103 | "functionals/CIDER23X_NL_GGA.yaml", 104 | qmax=300, 105 | lambd=1.8, 106 | xmix=0.25, 107 | pasdw_ovlp_fit=True, 108 | pasdw_store_funcs=True, 109 | use_paw=False, 110 | ) 111 | 112 | run_cider_forces(get_xc()) 113 | 114 | @unittest.expectedFailure 115 | def test_nl_mgga(self): 116 | def get_xc(): 117 | return get_cider_functional( 118 | "functionals/CIDER23X_NL_MGGA_DTR.yaml", 119 | qmax=300, 120 | lambd=1.8, 121 | xmix=0.25, 122 | pasdw_ovlp_fit=True, 123 | pasdw_store_funcs=False, 124 | use_paw=False, 125 | ) 126 | 127 | run_cider_forces(get_xc()) 128 | 129 | 130 | if __name__ == "__main__": 131 | unittest.main() 132 | -------------------------------------------------------------------------------- /ciderpress/gpaw/tests/test_si_force.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import unittest 22 | 23 | import numpy as np 24 | from ase import Atoms 25 | from gpaw import GPAW, PW, FermiDirac, Mixer 26 | 27 | from ciderpress.gpaw.calculator import get_cider_functional 28 | from ciderpress.gpaw.tests import equal 29 | 30 | USE_AUGMENT_GRIDS = True 31 | 32 | 33 | def numeric_force(atoms, a, i, d=0.001, get_xc=None): 34 | """Compute numeric force on atom with index a, Cartesian component i, 35 | with finite step of size d 36 | """ 37 | p0 = atoms.get_positions() 38 | p = p0.copy() 39 | p[a, i] += d 40 | atoms.set_positions(p, apply_constraint=False) 41 | eplus = atoms.get_potential_energy() 42 | p[a, i] -= 2 * d 43 | atoms.set_positions(p, apply_constraint=False) 44 | eminus = atoms.get_potential_energy() 45 | atoms.set_positions(p0, apply_constraint=False) 46 | return (eminus - eplus) / (2 * d) 47 | 48 | 49 | def _run_cider_forces(functional, get_xc=None): 50 | a = 5.45 51 | bulk = Atoms( 52 | symbols="Si8", 53 | positions=[ 54 | (0, 0, 0.1 / a), 55 | (0, 0.5, 0.5), 56 | (0.5, 0, 0.5), 57 | (0.5, 0.5, 0), 58 | (0.25, 0.25, 0.25), 59 | (0.25, 0.75, 0.75), 60 | (0.75, 0.25, 0.75), 61 | (0.75, 0.75, 0.25), 62 | ], 63 | pbc=True, 64 | ) 65 | bulk.set_cell((a, a, a), scale_atoms=True) 66 | if get_xc is not None: 67 | functional = get_xc() 68 | calc = GPAW( 69 | h=0.20, 70 | mode=PW(350), 71 | xc=functional, 72 | nbands="150%", 73 | occupations=FermiDirac(width=0.01), 74 | kpts=(3, 3, 3), 75 | convergence={"energy": 1e-8}, 76 | mixer=Mixer(0.7, 8, 50), 77 | parallel={"augment_grids": USE_AUGMENT_GRIDS}, 78 | ) 79 | bulk.calc = calc 80 | f1 = bulk.get_forces()[0, 2] 81 | bulk.get_potential_energy() 82 | 83 | f2 = numeric_force(bulk, 0, 2, 0.001, get_xc=get_xc) 84 | print((f1, f2, f1 - f2)) 85 | equal(f1, f2, 0.001) 86 | 87 | 88 | def run_cider_forces(functional, get_xc=None): 89 | with np.errstate(all="ignore"): 90 | _run_cider_forces(functional, get_xc=get_xc) 91 | 92 | 93 | class TestForce(unittest.TestCase): 94 | def test_sl_gga(self): 95 | run_cider_forces(get_cider_functional("functionals/CIDER23X_SL_GGA.yaml")) 96 | 97 | def test_sl_mgga(self): 98 | run_cider_forces(get_cider_functional("functionals/CIDER23X_SL_MGGA.yaml")) 99 | 100 | def test_nl_gga(self): 101 | def get_xc(): 102 | return get_cider_functional( 103 | "functionals/CIDER23X_NL_GGA.yaml", 104 | qmax=300, 105 | lambd=1.8, 106 | xmix=0.25, 107 | pasdw_ovlp_fit=True, 108 | pasdw_store_funcs=True, 109 | ) 110 | 111 | run_cider_forces(get_xc()) 112 | 113 | def test_nl_mgga(self): 114 | def get_xc(): 115 | return get_cider_functional( 116 | "functionals/CIDER23X_NL_MGGA_DTR.yaml", 117 | qmax=300, 118 | lambd=1.8, 119 | xmix=0.25, 120 | pasdw_ovlp_fit=True, 121 | pasdw_store_funcs=False, 122 | ) 123 | 124 | run_cider_forces(get_xc()) 125 | 126 | 127 | if __name__ == "__main__": 128 | unittest.main() 129 | -------------------------------------------------------------------------------- /ciderpress/lib/__init__.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | 3 | from ciderpress.lib.load import load_library 4 | 5 | __all__ = ["load_library", "c_double_p", "c_int_p", "c_null_ptr"] 6 | 7 | c_double_p = ctypes.POINTER(ctypes.c_double) 8 | c_int_p = ctypes.POINTER(ctypes.c_int) 9 | c_null_ptr = ctypes.POINTER(ctypes.c_void_p) 10 | -------------------------------------------------------------------------------- /ciderpress/lib/fft_plan.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | 3 | import numpy as np 4 | 5 | from ciderpress.lib import load_library 6 | 7 | libfft = load_library("libfft_wrapper") 8 | 9 | libfft.allocate_fftnd_plan.restype = ctypes.c_void_p 10 | libfft.malloc_fft_plan_in_array.restype = ctypes.c_void_p 11 | libfft.malloc_fft_plan_out_array.restype = ctypes.c_void_p 12 | libfft.get_fft_plan_in_array.restype = ctypes.c_void_p 13 | libfft.get_fft_plan_out_array.restype = ctypes.c_void_p 14 | libfft.get_fft_input_size.restype = ctypes.c_int 15 | libfft.get_fft_output_size.restype = ctypes.c_int 16 | 17 | 18 | class FFTWrapper: 19 | def __init__( 20 | self, dims, ntransform=1, fwd=True, r2c=False, inplace=False, batch_first=True 21 | ): 22 | self._dims = dims 23 | self._ntransform = ntransform 24 | self._fwd = fwd 25 | self._r2c = r2c 26 | self._inplace = inplace 27 | self._batch_first = batch_first 28 | rshape = [d for d in dims] 29 | if r2c: 30 | kshape = [d for d in dims[:-1]] + [dims[-1] // 2 + 1] 31 | else: 32 | kshape = [d for d in dims] 33 | if batch_first: 34 | rshape.insert(0, self._ntransform) 35 | kshape.insert(0, self._ntransform) 36 | else: 37 | rshape.append(self._ntransform) 38 | kshape.append(self._ntransform) 39 | if fwd: 40 | self._inshape = tuple(rshape) 41 | self._outshape = tuple(kshape) 42 | else: 43 | self._inshape = tuple(kshape) 44 | self._outshape = tuple(rshape) 45 | dims = np.asarray(dims, dtype=np.int32) 46 | self._ptr = ctypes.c_void_p( 47 | libfft.allocate_fftnd_plan( 48 | ctypes.c_int(len(dims)), 49 | dims.ctypes.data_as(ctypes.c_void_p), 50 | ctypes.c_int(1 if fwd else 0), 51 | ctypes.c_int(1 if r2c else 0), 52 | ctypes.c_int(self._ntransform), 53 | ctypes.c_int(1 if inplace else 0), 54 | ctypes.c_int(1 if batch_first else 0), 55 | ) 56 | ) 57 | self._in = ctypes.c_void_p(libfft.malloc_fft_plan_in_array(self._ptr)) 58 | if self._inplace: 59 | self._out = None 60 | else: 61 | self._out = ctypes.c_void_p(libfft.malloc_fft_plan_out_array(self._ptr)) 62 | libfft.initialize_fft_plan( 63 | self._ptr, 64 | self._in, 65 | self._out, 66 | ) 67 | 68 | def __del__(self): 69 | libfft.free_fft_plan(self._ptr) 70 | libfft.free_fft_array(self._in) 71 | if not self._inplace: 72 | libfft.free_fft_array(self._out) 73 | 74 | @property 75 | def input_shape(self): 76 | return self._inshape 77 | 78 | @property 79 | def output_shape(self): 80 | return self._outshape 81 | 82 | def call(self, x): 83 | if x.shape != self._inshape: 84 | raise ValueError(f"Expected input of shape {self._inshape}, got {x.shape}") 85 | dtype = np.float64 if (self._r2c and not self._fwd) else np.complex128 86 | out = np.empty(self._outshape, dtype=dtype) 87 | libfft.write_fft_input(self._ptr, x.ctypes.data_as(ctypes.c_void_p)) 88 | libfft.execute_fft_plan(self._ptr) 89 | libfft.read_fft_output(self._ptr, out.ctypes.data_as(ctypes.c_void_p)) 90 | return out 91 | -------------------------------------------------------------------------------- /ciderpress/lib/fft_wrapper/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | if (HAVE_MPI) 3 | add_library(fft_wrapper SHARED 4 | cider_fft.c 5 | cider_mpi_fft.c 6 | ) 7 | else() 8 | add_library(fft_wrapper SHARED 9 | cider_fft.c 10 | ) 11 | endif() 12 | 13 | set_target_properties(fft_wrapper PROPERTIES 14 | LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR} 15 | COMPILE_FLAGS ${OpenMP_C_FLAGS} 16 | LINK_FLAGS ${OpenMP_C_FLAGS}) 17 | 18 | configure_file( 19 | ${PROJECT_SOURCE_DIR}/fft_wrapper/config.h.in 20 | ${PROJECT_SOURCE_DIR}/fft_wrapper/cider_fft_config.h 21 | NEWLINE_STYLE UNIX 22 | ) 23 | 24 | if (HAVE_MPI) 25 | target_link_libraries(fft_wrapper PUBLIC MPI::MPI_C) 26 | endif() 27 | 28 | if (FFT_BACKEND EQUAL 1) # MKL 29 | target_include_directories(fft_wrapper PUBLIC ${MKL_INCLUDE_DIR}) 30 | target_link_libraries(fft_wrapper PUBLIC MKL::MKL) 31 | if (HAVE_MPI) 32 | target_link_libraries(fft_wrapper PUBLIC MKL::mkl_cdft_core) 33 | endif() 34 | else() # FFTW 35 | target_link_libraries(fft_wrapper PRIVATE fftw3) 36 | target_link_libraries(fft_wrapper PRIVATE fftw3_omp) 37 | if (HAVE_MPI) 38 | target_link_libraries(fft_wrapper PRIVATE fftw3_mpi) 39 | endif() 40 | endif() 41 | -------------------------------------------------------------------------------- /ciderpress/lib/fft_wrapper/cider_fft.h: -------------------------------------------------------------------------------- 1 | #ifndef _CIDER_FFT_H 2 | #define _CIDER_FFT_H 3 | 4 | #include "cider_fft_config.h" 5 | 6 | #if FFT_BACKEND == FFT_MKL_BACKEND 7 | #include 8 | #include 9 | #include 10 | #else // FFTW 11 | #include 12 | #include 13 | #endif 14 | #if HAVE_MPI 15 | #include 16 | #endif 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | typedef struct fft_plan { 24 | int is_initialized; 25 | int ndim; 26 | int *dims; 27 | int r2c; 28 | int ntransform; 29 | size_t fft_in_size; 30 | size_t fft_out_size; 31 | int fwd; 32 | int batch_first; 33 | int inplace; 34 | int stride; 35 | int idist; 36 | int odist; 37 | void *in; 38 | void *out; 39 | #if FFT_BACKEND == FFT_MKL_BACKEND 40 | DFTI_DESCRIPTOR_HANDLE handle; 41 | DFTI_DESCRIPTOR_HANDLE xhandle; 42 | DFTI_DESCRIPTOR_HANDLE yhandle; 43 | DFTI_DESCRIPTOR_HANDLE zhandle; 44 | #else // FFTW 45 | fftw_plan plan; 46 | #endif 47 | } fft_plan_t; 48 | 49 | int cider_fft_is_initialized(); 50 | 51 | int cider_fft_is_threaded(); 52 | 53 | #if FFT_BACKEND == FFT_MKL_BACKEND 54 | int cider_fft_get_num_mkl_threads(); 55 | #endif 56 | 57 | void cider_fft_initialize(); 58 | 59 | void cider_fft_set_nthread(int nthread); 60 | 61 | #if FFT_BACKEND == FFT_MKL_BACKEND 62 | void cider_fft_init_fft3d_1d_parts(const int ntransform, const int nx, 63 | const int ny, const int nz, const int r2c, 64 | const int transpose, const int inplace, 65 | DFTI_DESCRIPTOR_HANDLE *xhandlep, 66 | DFTI_DESCRIPTOR_HANDLE *yhandlep, 67 | DFTI_DESCRIPTOR_HANDLE *zhandlep); 68 | #endif 69 | 70 | fft_plan_t *allocate_fftnd_plan(int ndim, int *dims, int fwd, int r2c, 71 | int ntransform, int inplace, int batch_first); 72 | 73 | int initialize_fft_plan(fft_plan_t *plan, void *in_array, void *out_array); 74 | 75 | void execute_fft_plan(fft_plan_t *plan); 76 | 77 | void free_fft_plan(fft_plan_t *plan); 78 | 79 | void *malloc_fft_plan_in_array(fft_plan_t *plan); 80 | 81 | void *malloc_fft_plan_out_array(fft_plan_t *plan); 82 | 83 | void *alloc_fft_array(size_t objsize); 84 | 85 | void free_fft_array(void *arr); 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /ciderpress/lib/fft_wrapper/cider_mpi_fft.h: -------------------------------------------------------------------------------- 1 | #ifndef _CIDER_MPI_FFT_H 2 | #define _CIDER_MPI_FFT_H 3 | #if 1 4 | 5 | #include "cider_fft_config.h" 6 | 7 | #if FFT_BACKEND == FFT_MKL_BACKEND 8 | #include 9 | #include 10 | #include 11 | #include 12 | #else // FFTW 13 | #include 14 | #include 15 | #include 16 | #endif 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | typedef struct mpi_fft3d_plan { 25 | MPI_Comm comm; 26 | int r_offset[3]; 27 | int r_Nlocal[3]; 28 | int r_Nglobal[3]; 29 | int k_offset[3]; 30 | int k_Nlocal[3]; 31 | int k_Nglobal[3]; 32 | int xpp; 33 | int ypp; 34 | int r2c; 35 | int ntransform; 36 | size_t fft_in_size; 37 | size_t fft_out_size; 38 | size_t work_array_size; 39 | int fwd; 40 | int inplace; 41 | void *work; 42 | #if FFT_BACKEND == FFT_MKL_BACKEND 43 | DFTI_DESCRIPTOR_HANDLE xhandle; 44 | DFTI_DESCRIPTOR_HANDLE yhandle; 45 | DFTI_DESCRIPTOR_HANDLE zhandle; 46 | #else // FFTW 47 | fftw_plan fwd_plan; 48 | fftw_plan bwd_plan; 49 | #endif 50 | } mpi_fft3d_plan_t; 51 | 52 | mpi_fft3d_plan_t *allocate_mpi_fft3d_plan(MPI_Comm comm, const int *dims, 53 | int r2c, int ntransform); 54 | 55 | void execute_mpi_fft3d_fwd(mpi_fft3d_plan_t *plan); 56 | 57 | void execute_mpi_fft3d_bwd(mpi_fft3d_plan_t *plan); 58 | 59 | void free_mpi_fft3d_plan(mpi_fft3d_plan_t *plan); 60 | 61 | #endif 62 | #endif 63 | -------------------------------------------------------------------------------- /ciderpress/lib/fft_wrapper/config.h.in: -------------------------------------------------------------------------------- 1 | #ifndef _CIDER_FFT_CONFIG_H 2 | #define _CIDER_FFT_CONFIG_H 3 | 4 | #define FFT_MKL_BACKEND 1 5 | #define FFT_FFTW_BACKEND 2 6 | 7 | #cmakedefine01 HAVE_MPI 8 | #cmakedefine FFT_BACKEND @FFT_BACKEND@ 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /ciderpress/lib/load.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import numpy 4 | 5 | 6 | def load_library(libname): 7 | _loaderpath = os.path.dirname(__file__) 8 | return numpy.ctypeslib.load_library(libname, _loaderpath) 9 | -------------------------------------------------------------------------------- /ciderpress/lib/mod_cider/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_library(mcider SHARED 3 | frac_lapl.c cider_coefs.c cider_grids.c spline.c sph_harm.c 4 | conv_interpolation.c convolutions.c fast_sdmx.c pbc_tools.c debug_numint.c 5 | model_utils.c 6 | ) 7 | 8 | set_target_properties(mcider PROPERTIES 9 | LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR} 10 | COMPILE_FLAGS ${OpenMP_C_FLAGS} 11 | LINK_FLAGS ${OpenMP_C_FLAGS}) 12 | 13 | if (HAVE_MPI) 14 | target_link_libraries(mcider PRIVATE MPI::MPI_C) 15 | endif() 16 | if (BUILD_WITH_MKL) 17 | target_link_libraries(mcider PRIVATE MKL::MKL) 18 | target_include_directories(mcider PRIVATE ${MKL_INCLUDE_DIR}) 19 | else() 20 | target_link_libraries(mcider PRIVATE ${BLAS_LIBRARIES}) 21 | target_link_libraries(mcider PRIVATE ${LAPACK_LIBRARIES}) 22 | endif() 23 | target_include_directories(mcider PRIVATE ../fft_wrapper) 24 | target_link_libraries(mcider PRIVATE fft_wrapper) 25 | -------------------------------------------------------------------------------- /ciderpress/lib/mod_cider/cider_grids.c: -------------------------------------------------------------------------------- 1 | // CiderPress: Machine-learning based density functional theory calculations 2 | // Copyright (C) 2024 The President and Fellows of Harvard College 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see 16 | // 17 | // Author: Kyle Bystrom 18 | // 19 | 20 | #include "fblas.h" 21 | #include 22 | #include 23 | 24 | void reduce_angc_to_ylm(double *theta_rlmq, double *y_glm, double *theta_gq, 25 | int *rad_loc, int *ylm_loc, int nalpha, int nrad, 26 | int ngrids, int nlm, int stride, int offset) { 27 | theta_gq = theta_gq + offset; 28 | #pragma omp parallel 29 | { 30 | double ALPHA = 1.0; 31 | double BETA = 0.0; 32 | char NTRANS = 'N'; 33 | char TRANS = 'T'; 34 | int r, nw; 35 | double *y_wlm, *theta_lmq, *theta_wq; 36 | #pragma omp for schedule(dynamic, 4) 37 | for (r = 0; r < nrad; r++) { 38 | y_wlm = y_glm + ylm_loc[r] * nlm; 39 | nw = rad_loc[r + 1] - rad_loc[r]; 40 | theta_lmq = theta_rlmq + r * nlm * nalpha; 41 | theta_wq = theta_gq + rad_loc[r] * stride; 42 | dgemm_(&NTRANS, &TRANS, &nalpha, &nlm, &nw, &ALPHA, theta_wq, 43 | &stride, y_wlm, &nlm, &BETA, theta_lmq, &nalpha); 44 | } 45 | } 46 | } 47 | 48 | void reduce_ylm_to_angc(double *theta_rlmq, double *y_glm, double *theta_gq, 49 | int *rad_loc, int *ylm_loc, int nalpha, int nrad, 50 | int ngrids, int nlm, int stride, int offset) { 51 | theta_gq = theta_gq + offset; 52 | #pragma omp parallel 53 | { 54 | double ALPHA = 1.0; 55 | double BETA = 0.0; 56 | char NTRANS = 'N'; 57 | char TRANS = 'T'; 58 | int r, nw; 59 | double *y_wlm, *theta_lmq, *theta_wq; 60 | #pragma omp for schedule(dynamic, 4) 61 | for (r = 0; r < nrad; r++) { 62 | y_wlm = y_glm + ylm_loc[r] * nlm; 63 | nw = rad_loc[r + 1] - rad_loc[r]; 64 | theta_lmq = theta_rlmq + r * nlm * nalpha; 65 | theta_wq = theta_gq + rad_loc[r] * stride; 66 | dgemm_(&NTRANS, &NTRANS, &nalpha, &nw, &nlm, &ALPHA, theta_lmq, 67 | &nalpha, y_wlm, &nlm, &BETA, theta_wq, &stride); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /ciderpress/lib/mod_cider/conv_interpolation.h: -------------------------------------------------------------------------------- 1 | // CiderPress: Machine-learning based density functional theory calculations 2 | // Copyright (C) 2024 The President and Fellows of Harvard College 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see 16 | // 17 | // Author: Kyle Bystrom 18 | // 19 | 20 | #ifndef _CONV_INTERPOLATION_H 21 | #define _CONV_INTERPOLATION_H 22 | 23 | typedef struct { 24 | int *loc_i; 25 | int *num_i; 26 | double *rel_ord_coords; 27 | int *ind_ord_fwd; 28 | int *ind_ord_bwd; 29 | int nrad; 30 | double aparam; 31 | double dparam; 32 | int ngrids; 33 | int buffer_size; 34 | } spline_locator; 35 | 36 | typedef struct { 37 | spline_locator *sloc_list; 38 | int natm; 39 | } spline_loc_list; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /ciderpress/lib/mod_cider/fast_sdmx.h: -------------------------------------------------------------------------------- 1 | // CiderPress: Machine-learning based density functional theory calculations 2 | // Copyright (C) 2024 The President and Fellows of Harvard College 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see 16 | // 17 | // Author: Kyle Bystrom 18 | // 19 | 20 | #ifndef FAST_SDMX_H 21 | #define FAST_SDMX_H 22 | #include "pyscf_gto.h" 23 | #include 24 | #include 25 | 26 | void SDMXeval_rad_iter(FPtr_eval_sdmx_rad feval, FPtr_exp_sdmx fexp, double fac, 27 | size_t nao, size_t ngrids, size_t bgrids, int param[], 28 | int *shls_slice, int *rf_loc, double *buf, double *vbas, 29 | double *coord, uint8_t *non0table, int *atm, int natm, 30 | int *bas, int nbas, double *env, double *alphas, 31 | double *alpha_norms, int nalpha); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /ciderpress/lib/mod_cider/fblas.h: -------------------------------------------------------------------------------- 1 | // CiderPress: Machine-learning based density functional theory calculations 2 | // Copyright (C) 2024 The President and Fellows of Harvard College 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see 16 | // 17 | // Author: Kyle Bystrom 18 | // 19 | 20 | #ifndef _CIDER_FBLAS_H 21 | #define _CIDER_FBLAS_H 22 | 23 | #if defined __cplusplus 24 | extern "C" { 25 | #endif 26 | #include 27 | 28 | double ddot_(const int *, const double *, const int *, const double *, 29 | const int *); 30 | 31 | void dgemv_(const char *, const int *, const int *, const double *, 32 | const double *, const int *, const double *, const int *, 33 | const double *, const double *, const int *); 34 | 35 | void dtrtri_(const char *, const char *, const int *, const double *, 36 | const int *, const int *); 37 | 38 | void dtrmv_(const char *, const char *, const char *, const int *, 39 | const double *, const int *, const double *, const int *); 40 | 41 | void dgemm_(const char *, const char *, const int *, const int *, const int *, 42 | const double *, const double *, const int *, const double *, 43 | const int *, const double *, double *, const int *); 44 | 45 | void dpotrs_(const char *, const int *, const int *, const double *, 46 | const int *, const double *, const int *, const int *); 47 | 48 | void dpotrf_(const char *, const int *, const double *, const int *, 49 | const int *); 50 | 51 | #if defined __cplusplus 52 | } // end extern "C" 53 | #endif 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /ciderpress/lib/mod_cider/pyscf_gto.h: -------------------------------------------------------------------------------- 1 | // CiderPress: Machine-learning based density functional theory calculations 2 | // Copyright (C) 2024 The President and Fellows of Harvard College 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see 16 | // 17 | // Author: Kyle Bystrom 18 | // 19 | 20 | #include 21 | #ifndef PYSCF_GTO_H_ 22 | #define PYSCF_GTO_H_ 23 | 24 | #define CHARGE_OF 0 25 | #define PTR_COORD 1 26 | #define NUC_MOD_OF 2 27 | #define PTR_ZETA 3 28 | #define PTR_FRAC_CHARGE 4 29 | #define RESERVE_ATMSLOT 5 30 | #define ATM_SLOTS 6 31 | 32 | #define ATOM_OF 0 33 | #define ANG_OF 1 34 | #define NPRIM_OF 2 35 | #define NCTR_OF 3 36 | #define KAPPA_OF 4 37 | #define PTR_EXP 5 38 | #define PTR_COEFF 6 39 | #define RESERVE_BASLOT 7 40 | #define BAS_SLOTS 8 41 | 42 | #define POS_E1 0 43 | #define TENSOR 1 44 | 45 | #define LMAX ANG_MAX 46 | #define SIMDD 8 47 | #define NCTR_CART 128 48 | #define BLKSIZE 56 49 | #define NPRIMAX 40 50 | #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) 51 | #define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) 52 | 53 | #define ALIGN8_UP(buf) (void *)(((uintptr_t)buf + 7) & (-(uintptr_t)8)) 54 | 55 | typedef int (*FPtr_exp)(double *ectr, double *coord, double *alpha, 56 | double *coeff, int l, int nprim, int nctr, 57 | size_t ngrids, double fac); 58 | typedef void (*FPtr_eval)(double *gto, double *ri, double *exps, double *coord, 59 | double *alpha, double *coeff, double *env, int l, 60 | int np, int nc, size_t nao, size_t ngrids, 61 | size_t blksize); 62 | typedef int (*FPtr_exp_sdmx)(double *ectr, double *coord, double *alpha, 63 | double *coeff, int l, int nprim, int nctr, 64 | size_t ngrids, double fac, double conv_alpha, 65 | double conv_alpha_coeff); 66 | typedef void (*FPtr_eval_sdmx)(double *gto, double *ri, double *exps, 67 | double *coord, double *alpha, double *coeff, 68 | double *env, int l, int np, int nc, size_t nao, 69 | size_t ngrids, size_t blksize, double *ylm_vmg, 70 | int mg_stride); 71 | typedef void (*FPtr_eval_sdmx_rad)(double *vbas, double *exps, int nc, 72 | size_t nao, size_t ngrids, size_t blksize, 73 | int stride); 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /ciderpress/lib/mod_cider/sph_harm.h: -------------------------------------------------------------------------------- 1 | // CiderPress: Machine-learning based density functional theory calculations 2 | // Copyright (C) 2024 The President and Fellows of Harvard College 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see 16 | // 17 | // Author: Kyle Bystrom 18 | // 19 | 20 | #ifndef _SPH_HARM_CIDER 21 | #define _SPH_HARM_CIDER 22 | 23 | #include 24 | 25 | #define SQRT2 1.4142135623730950488 26 | #define SQRT3 1.7320508075688772936 27 | #define SPHF0 0.28209479177387814346 28 | 29 | typedef struct { 30 | int nlm; // (lmax+1) * (lmax+1) 31 | int lmax; 32 | int lp1; // (lmax+1) 33 | double *coef0; // size nlm, indexed as l, m 34 | double *coef1; // size nlm, indexed as l, m 35 | double *c0; // size lp1, indexed as l 36 | double *c1; // size lp1, indexed as l 37 | double complex *ylm; // size nlm, indexed as l, m 38 | double complex *dylm; // size nlm, indexed as l, m 39 | } sphbuf; 40 | 41 | sphbuf setup_sph_harm_buffer(int nlm); 42 | 43 | void free_sph_harm_buffer(sphbuf buf); 44 | 45 | void recursive_sph_harm(sphbuf buf, double *r, double *res); 46 | 47 | void recursive_sph_harm_deriv(sphbuf buf, double *r, double *res, double *dres); 48 | 49 | void remove_radial_grad(sphbuf buf, double *r, double *dres); 50 | 51 | void recursive_sph_harm_vec(int nlm, int n, double *r, double *res); 52 | 53 | void recursive_sph_harm_deriv_vec(int nlm, int n, double *r, double *res, 54 | double *dres); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /ciderpress/lib/mod_cider/spline.c: -------------------------------------------------------------------------------- 1 | // CiderPress: Machine-learning based density functional theory calculations 2 | // Copyright (C) 2024 The President and Fellows of Harvard College 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see 16 | // 17 | // Author: Kyle Bystrom 18 | // 19 | 20 | #include "spline.h" 21 | #include 22 | #include 23 | 24 | void get_cubic_spline_coeff(double *x, double *y, double *spline, int N) { 25 | double **coeff = (double **)malloc(3 * sizeof(double *)); 26 | coeff[0] = spline + 2 * N; 27 | coeff[1] = spline + 3 * N; 28 | coeff[2] = spline + 4 * N; 29 | 30 | int i; 31 | for (i = 0; i < N; i++) { 32 | spline[i] = x[i]; 33 | spline[N + i] = y[i]; 34 | } 35 | 36 | double d1p1 = (y[1] - y[0]) / (x[1] - x[0]); 37 | if (d1p1 > 0.99E30) { 38 | coeff[1][0] = 0; 39 | coeff[0][0] = 0; 40 | } else { 41 | coeff[1][0] = -0.5; 42 | coeff[0][0] = 43 | (3 / (x[1] - x[0])) * ((y[1] - y[0]) / (x[1] - x[0]) - d1p1); 44 | } 45 | 46 | double s = 0, r = 0; 47 | 48 | for (i = 1; i < N - 1; i++) { 49 | s = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]); 50 | r = s * coeff[1][i - 1] + 2; 51 | coeff[1][i] = (s - 1) / r; 52 | coeff[0][i] = (6 * 53 | ((y[i + 1] - y[i]) / (x[i + 1] - x[i]) - 54 | (y[i] - y[i - 1]) / (x[i] - x[i - 1])) / 55 | (x[i + 1] - x[i - 1]) - 56 | s * coeff[0][i - 1]) / 57 | r; 58 | } 59 | 60 | coeff[0][N - 1] = 0; 61 | coeff[1][N - 1] = 0; 62 | coeff[2][N - 1] = 0; 63 | 64 | for (i = N - 2; i >= 0; i--) { 65 | coeff[1][i] = coeff[1][i] * coeff[1][i + 1] + coeff[0][i]; 66 | } 67 | 68 | for (i = 0; i < N - 1; i++) { 69 | s = x[i + 1] - x[i]; 70 | r = (coeff[1][i + 1] - coeff[1][i]) / 6; 71 | coeff[2][i] = r / s; 72 | coeff[1][i] = coeff[1][i] / 2; 73 | coeff[0][i] = (y[i + 1] - y[i]) / s - (coeff[1][i] + r) * s; 74 | } 75 | 76 | free(coeff); 77 | } 78 | 79 | double spline_integral(double *spline, int N) { 80 | double *x = spline; 81 | double *a = spline + N; 82 | double *b = spline + 2 * N; 83 | double *c = spline + 3 * N; 84 | double *d = spline + 4 * N; 85 | double dx = 0; 86 | double integral = 0; 87 | int i; 88 | for (i = 0; i < N - 1; i++) { 89 | dx = x[i + 1] - x[i]; 90 | integral += 91 | dx * (a[i] + dx * (b[i] / 2 + dx * (c[i] / 3 + d[i] * dx / 4))); 92 | } 93 | 94 | return integral; 95 | } 96 | -------------------------------------------------------------------------------- /ciderpress/lib/mod_cider/spline.h: -------------------------------------------------------------------------------- 1 | // CiderPress: Machine-learning based density functional theory calculations 2 | // Copyright (C) 2024 The President and Fellows of Harvard College 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see 16 | // 17 | // Author: Kyle Bystrom 18 | // 19 | 20 | #ifndef CIDER_SPLINE_H 21 | #define CIDER_SPLINE_H 22 | 23 | void get_cubic_spline_coeff(double *x, double *y, double *spline, int N); 24 | double spline_integral(double *spline, int N); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /ciderpress/lib/mpi_fft_plan.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | 3 | import numpy as np 4 | 5 | from ciderpress.lib import load_library 6 | 7 | libfft = load_library("libfft_wrapper") 8 | 9 | libfft.allocate_mpi_fft3d_plan_world.restype = ctypes.c_void_p 10 | libfft.malloc_fft_plan_in_array.restype = ctypes.c_void_p 11 | libfft.malloc_fft_plan_out_array.restype = ctypes.c_void_p 12 | libfft.get_fft_plan_in_array.restype = ctypes.c_void_p 13 | libfft.get_fft_plan_out_array.restype = ctypes.c_void_p 14 | libfft.get_fft_input_size.restype = ctypes.c_int 15 | libfft.get_fft_output_size.restype = ctypes.c_int 16 | 17 | 18 | class MPIFFTWrapper: 19 | def __init__(self, dims, ntransform=1, r2c=False): 20 | self._dims = dims 21 | self._ntransform = ntransform 22 | self._r2c = r2c 23 | rshape = [d for d in dims] 24 | if r2c: 25 | kshape = [d for d in dims[:-1]] + [dims[-1] // 2 + 1] 26 | else: 27 | kshape = [d for d in dims] 28 | rshape.append(self._ntransform) 29 | kshape.append(self._ntransform) 30 | dims = np.asarray(dims, dtype=np.int32, order="C") 31 | self._ptr = ctypes.c_void_p( 32 | libfft.allocate_mpi_fft3d_plan_world( 33 | dims.ctypes.data_as(ctypes.c_void_p), 34 | ctypes.c_int(1 if r2c else 0), 35 | ctypes.c_int(self._ntransform), 36 | ) 37 | ) 38 | nproc = ctypes.c_int(0) 39 | rank = ctypes.c_int(0) 40 | libfft.cider_fft_world_size_and_rank( 41 | ctypes.byref(nproc), 42 | ctypes.byref(rank), 43 | ) 44 | nproc = nproc.value 45 | rank = rank.value 46 | nx, ny, nz = dims 47 | xpp = -(-nx // nproc) 48 | ypp = -(-ny // nproc) 49 | my_ox = min(xpp * rank, nx) 50 | my_nx = min(xpp * (rank + 1), nx) - my_ox 51 | my_oy = min(ypp * rank, ny) 52 | my_ny = min(ypp * (rank + 1), ny) - my_oy 53 | self._nproc = nproc 54 | self._rank = rank 55 | self._xpp = xpp 56 | self._ypp = ypp 57 | self._my_ox = my_ox 58 | self._my_nx = my_nx 59 | self._my_oy = my_oy 60 | self._my_ny = my_ny 61 | self._rshape = (self._my_nx, self._dims[1], self._dims[2], self._ntransform) 62 | if r2c: 63 | self._kshape = [self._dims[0], self._dims[1], self._dims[2] // 2 + 1] 64 | else: 65 | self._kshape = self._dims 66 | self._kshape = (self._my_ny, self._kshape[0], self._kshape[2], self._ntransform) 67 | 68 | def __del__(self): 69 | libfft.free_mpi_fft3d_plan(self._ptr) 70 | 71 | def _execute_fwd(self): 72 | libfft.execute_mpi_fft3d_fwd(self._ptr) 73 | 74 | def _execute_bwd(self): 75 | libfft.execute_mpi_fft3d_bwd(self._ptr) 76 | 77 | def call(self, x, fwd=True): 78 | if fwd: 79 | if self._r2c: 80 | assert x.dtype == np.float64 81 | else: 82 | assert x.dtype == np.complex128 83 | assert x.shape == self._rshape, "{} {}".format(x.shape, self._rshape) 84 | else: 85 | assert x.dtype == np.complex128 86 | assert x.shape == self._kshape, "{} {}".format(x.shape, self._kshape) 87 | dtype = np.float64 if (self._r2c and not fwd) else np.complex128 88 | out = np.empty(self._kshape if fwd else self._rshape, dtype=dtype) 89 | libfft.write_mpi_fft3d_input( 90 | self._ptr, 91 | x.ctypes.data_as(ctypes.c_void_p), 92 | ctypes.c_int(1 if fwd else 0), 93 | ) 94 | if fwd: 95 | self._execute_fwd() 96 | else: 97 | self._execute_bwd() 98 | libfft.read_mpi_fft3d_output( 99 | self._ptr, 100 | out.ctypes.data_as(ctypes.c_void_p), 101 | ctypes.c_int(1 if fwd else 0), 102 | ) 103 | return out 104 | -------------------------------------------------------------------------------- /ciderpress/lib/numint_cider/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_library(numint SHARED 3 | nr_numint.c 4 | ) 5 | 6 | set_target_properties(numint PROPERTIES 7 | LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR} 8 | COMPILE_FLAGS ${OpenMP_C_FLAGS} 9 | LINK_FLAGS ${OpenMP_C_FLAGS}) 10 | 11 | if (HAVE_MPI) 12 | target_link_libraries(numint PRIVATE MPI::MPI_C) 13 | endif() 14 | if (BUILD_WITH_MKL) 15 | target_link_libraries(numint PRIVATE MKL::MKL) 16 | target_include_directories(numint PRIVATE ${MKL_INCLUDE_DIR}) 17 | else() 18 | target_link_libraries(numint PRIVATE ${BLAS_LIBRARIES}) 19 | endif() 20 | -------------------------------------------------------------------------------- /ciderpress/lib/pwutil/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | python_add_library(pwutil SHARED 2 | grid_util.c nldf_fft_core.c ../mod_cider/sph_harm.c 3 | ) 4 | 5 | set_target_properties(pwutil PROPERTIES 6 | LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR} 7 | COMPILE_FLAGS ${OpenMP_C_FLAGS} 8 | LINK_FLAGS ${OpenMP_C_FLAGS} 9 | ) 10 | 11 | configure_file( 12 | ${PROJECT_SOURCE_DIR}/pwutil/config.h.in 13 | ${PROJECT_SOURCE_DIR}/pwutil/config.h 14 | NEWLINE_STYLE UNIX 15 | ) 16 | 17 | if (HAVE_MPI) 18 | target_link_libraries(pwutil PRIVATE MPI::MPI_C) 19 | target_sources(pwutil PRIVATE nldf_fft_mpi.c gpaw_interface.c) 20 | else() 21 | target_sources(pwutil PRIVATE nldf_fft_serial.c) 22 | endif() 23 | 24 | target_include_directories(pwutil PRIVATE ../mod_cider/) 25 | target_include_directories(pwutil PRIVATE ${PROJECT_SOURCE_DIR}/pwutil) 26 | target_include_directories(pwutil PRIVATE ../fft_wrapper) 27 | target_link_libraries(pwutil PRIVATE fft_wrapper) 28 | -------------------------------------------------------------------------------- /ciderpress/lib/pwutil/config.h.in: -------------------------------------------------------------------------------- 1 | #ifndef CIDERPW_CONFIG_H 2 | #define CIDERPW_CONFIG_H 3 | 4 | #cmakedefine01 HAVE_MPI 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /ciderpress/lib/pwutil/gpaw_interface.c: -------------------------------------------------------------------------------- 1 | // CiderPress: Machine-learning based density functional theory calculations 2 | // Copyright (C) 2024 The President and Fellows of Harvard College 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see 16 | // 17 | // Author: Kyle Bystrom 18 | // 19 | 20 | #include "gpaw_interface.h" 21 | #include 22 | #include 23 | #include 24 | 25 | MPI_Comm unpack_gpaw_comm(PyObject *gpaw_mpi_obj) { 26 | MPIObject *gpaw_comm = (MPIObject *)gpaw_mpi_obj; 27 | return gpaw_comm->comm; 28 | } 29 | 30 | static void mpi_ensure_finalized(void) { 31 | int already_finalized = 1; 32 | int ierr = MPI_SUCCESS; 33 | 34 | MPI_Finalized(&already_finalized); 35 | if (!already_finalized) { 36 | ierr = MPI_Finalize(); 37 | } 38 | if (ierr != MPI_SUCCESS) 39 | PyErr_SetString(PyExc_RuntimeError, "MPI_Finalize error occurred"); 40 | } 41 | 42 | // MPI initialization 43 | void mpi_ensure_initialized(void) { 44 | int already_initialized = 1; 45 | int ierr = MPI_SUCCESS; 46 | 47 | // Check whether MPI is already initialized 48 | MPI_Initialized(&already_initialized); 49 | if (!already_initialized) { 50 | // if not, let's initialize it 51 | int use_threads = 0; 52 | // GPAW turns on threading for GPUs, but we don't have GPU support yet. 53 | // #ifdef GPAW_GPU 54 | // use_threads = 1; 55 | // #endif 56 | #ifdef _OPENMP 57 | use_threads = 1; 58 | #endif 59 | if (!use_threads) { 60 | ierr = MPI_Init(NULL, NULL); 61 | if (ierr == MPI_SUCCESS) { 62 | // No problem: register finalization when at Python exit 63 | Py_AtExit(*mpi_ensure_finalized); 64 | } else { 65 | // We have a problem: raise an exception 66 | char err[MPI_MAX_ERROR_STRING]; 67 | int resultlen; 68 | MPI_Error_string(ierr, err, &resultlen); 69 | PyErr_SetString(PyExc_RuntimeError, err); 70 | } 71 | } else { 72 | int granted; 73 | ierr = MPI_Init_thread(NULL, NULL, MPI_THREAD_MULTIPLE, &granted); 74 | if (ierr == MPI_SUCCESS && granted == MPI_THREAD_MULTIPLE) { 75 | // No problem: register finalization when at Python exit 76 | Py_AtExit(*mpi_ensure_finalized); 77 | } else if (granted != MPI_THREAD_MULTIPLE) { 78 | // We have a problem: raise an exception 79 | char err[MPI_MAX_ERROR_STRING] = 80 | "MPI_THREAD_MULTIPLE is not supported"; 81 | PyErr_SetString(PyExc_RuntimeError, err); 82 | } else { 83 | // We have a problem: raise an exception 84 | char err[MPI_MAX_ERROR_STRING]; 85 | int resultlen; 86 | MPI_Error_string(ierr, err, &resultlen); 87 | PyErr_SetString(PyExc_RuntimeError, err); 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /ciderpress/lib/pwutil/gpaw_interface.h: -------------------------------------------------------------------------------- 1 | // CiderPress: Machine-learning based density functional theory calculations 2 | // Copyright (C) 2024 The President and Fellows of Harvard College 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see 16 | // 17 | // Author: Kyle Bystrom 18 | // 19 | 20 | #ifndef GPAW_INTERFACE_H 21 | #define GPAW_INTERFACE_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | typedef struct { 28 | PyObject_HEAD int size; 29 | int rank; 30 | MPI_Comm comm; 31 | PyObject *parent; 32 | int *members; 33 | } MPIObject; 34 | 35 | MPI_Comm unpack_gpaw_comm(PyObject *gpaw_mpi_obj); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /ciderpress/lib/pwutil/nldf_fft_mpi.h: -------------------------------------------------------------------------------- 1 | // CiderPress: Machine-learning based density functional theory calculations 2 | // Copyright (C) 2024 The President and Fellows of Harvard College 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see 16 | // 17 | // Author: Kyle Bystrom 18 | // 19 | 20 | #ifndef NLDF_FFT_MPI_H 21 | #define NLDF_FFT_MPI_H 22 | #include "nldf_fft_core.h" 23 | 24 | void ciderpw_setup_reciprocal_vectors(ciderpw_data data); 25 | 26 | void ciderpw_g2k_mpi(ciderpw_data data); 27 | 28 | void ciderpw_k2g_mpi(ciderpw_data data); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /ciderpress/lib/pwutil/nldf_fft_serial.h: -------------------------------------------------------------------------------- 1 | // CiderPress: Machine-learning based density functional theory calculations 2 | // Copyright (C) 2024 The President and Fellows of Harvard College 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see 16 | // 17 | // Author: Kyle Bystrom 18 | // 19 | 20 | #ifndef NLDF_FFT_SERIAL_H 21 | #define NLDF_FFT_SERIAL_H 22 | #include "nldf_fft_core.h" 23 | 24 | void ciderpw_setup_reciprocal_vectors(ciderpw_data data); 25 | 26 | void ciderpw_g2k_serial(ciderpw_data data); 27 | 28 | void ciderpw_k2g_serial(ciderpw_data data); 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /ciderpress/lib/sbt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_library(sbt SHARED 3 | sbt.c 4 | ) 5 | 6 | set_target_properties(sbt PROPERTIES 7 | LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR} 8 | COMPILE_FLAGS ${OpenMP_C_FLAGS} 9 | LINK_FLAGS ${OpenMP_C_FLAGS}) 10 | 11 | # target_link_libraries(sbt ${BLAS_LIBRARIES}) 12 | target_include_directories(sbt PRIVATE ../fft_wrapper) 13 | target_link_libraries(sbt PRIVATE fft_wrapper) 14 | 15 | if (HAVE_MPI) 16 | target_link_libraries(sbt PRIVATE MPI::MPI_C) 17 | endif() 18 | if (BUILD_WITH_MKL) 19 | target_link_libraries(sbt PRIVATE MKL::MKL) 20 | target_include_directories(sbt PRIVATE ${MKL_INCLUDE_DIR}) 21 | else() 22 | target_link_libraries(sbt PRIVATE ${BLAS_LIBRARIES}) 23 | endif() 24 | -------------------------------------------------------------------------------- /ciderpress/lib/sbt/sbt.h: -------------------------------------------------------------------------------- 1 | // CiderPress: Machine-learning based density functional theory calculations 2 | // Copyright (C) 2024 The President and Fellows of Harvard College 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see 16 | // 17 | // Author: Kyle Bystrom 18 | // 19 | 20 | // The following routines are based on the Fortran program NumSBT written by 21 | // J. Talman. The algorithm performs a spherical Bessel transform in O(NlnN) 22 | // time. If you adapt this code for any purpose, please cite: Talman, 23 | // J. Computer Physics Communications 2009, 180, 332-338. The original NumSBT 24 | // code is distributed under the Standard CPC license. 25 | 26 | #ifndef SBT_H 27 | #define SBT_H 28 | // #include "config.h" 29 | #include "cider_fft.h" 30 | #include 31 | 32 | /** 33 | Contains the parameters for a fast spherical Bessel transform. 34 | */ 35 | typedef struct sbt_descriptor { 36 | double kmin; ///< Minimum reciprocal space value 37 | double kappamin; ///< ln(kmin) 38 | double rmin; ///< Minimum real space value 39 | double rhomin; ///< ln(rmin) 40 | double drho; ///< linear increment of rho = ln(r), drho == dkappa 41 | double dt; ///< increment of the multiplication table 42 | int N; ///< number of values of r and k 43 | double complex **mult_table; ///< M_l(t) for l up to lmax 44 | double *ks; ///< Reciprocal space grid 45 | double *rs; ///< Real space grid 46 | double *k32; ///< (Recip space grid)^1.5 47 | double *r32; ///< (Real space grid)^1.5 48 | int lmax; 49 | double complex *buffer; 50 | fft_plan_t *plan; 51 | } sbt_descriptor_t; 52 | 53 | /** 54 | Creates an sbt_descriptor_t object from the real space and k-space grids. 55 | Extrapolates the radial grid to have N values lower than the initial rmin, 56 | and the reciprocal grid to have N values higher than the initial kmin. 57 | encut+enbuf is the maximum value of k BEFORE extrapolation. 58 | lmax is the maximum l-value used to construct the the mult_table. 59 | N is the size of the grid BEFORE exprapolation (i.e. length of r and ks). 60 | */ 61 | sbt_descriptor_t *spherical_bessel_transform_setup(double encut, int lmax, 62 | int N, double *r, 63 | double *ks); 64 | 65 | /** 66 | Returns the values of radially defined function f 67 | in reciprocal space in a spherical bessel basis. 68 | f is defined on the grid corresponding to the r 69 | passed into spherical_bessesl_transform_setup. 70 | */ 71 | void wave_spherical_bessel_transform(sbt_descriptor_t *d, double *f, int l, 72 | double *vals, int l_add); 73 | 74 | /** 75 | Performs the inverse transform of f. Calling this function on the output 76 | of wave_spherical_bessel_transform gives the initial input to 77 | wave_spherical_bessel_transform on the initial radial grid passed to 78 | spherical_bessel_transform_setup 79 | */ 80 | void inverse_wave_spherical_bessel_transform(sbt_descriptor_t *d, double *f, 81 | int l, double *vals); 82 | 83 | /** 84 | Free all the memory associated with an sbt descriptor. 85 | */ 86 | void free_sbt_descriptor(sbt_descriptor_t *d); 87 | 88 | /** Check whether an array was allocated. If not, exit. */ 89 | void sbt_check_allocation(void *ptr); 90 | void sbt_allocation_failed(void); 91 | 92 | #endif 93 | -------------------------------------------------------------------------------- /ciderpress/lib/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/lib/tests/__init__.py -------------------------------------------------------------------------------- /ciderpress/lib/tests/tests_fft_plan.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import itertools 3 | import unittest 4 | 5 | import numpy as np 6 | from numpy.testing import assert_allclose 7 | 8 | from ciderpress.lib.fft_plan import FFTWrapper, libfft 9 | 10 | # libfft.cider_fft_set_nthread(ctypes.c_int(-1)) 11 | 12 | SEED = 1684 13 | 14 | ALL_DIMS = [ 15 | [13], 16 | [16], 17 | [13, 9], 18 | [13, 8], 19 | [16, 18], 20 | [13, 9, 17], 21 | [13, 9, 8], 22 | [16, 18, 12], 23 | [4, 4, 4, 4], 24 | ] 25 | 26 | 27 | class TestFFT(unittest.TestCase): 28 | def run_single_test(self, dims, ntrans, fwd, r2c, inplace, batch_first): 29 | np.random.seed(SEED) 30 | ishape = [ntrans] + dims if batch_first else dims + [ntrans] 31 | axes = [i for i in range(len(dims))] 32 | if batch_first: 33 | for i in range(len(axes)): 34 | axes[i] += 1 35 | if r2c: 36 | input_arr = np.empty(shape=ishape, dtype=np.float64) 37 | input_arr[:] = np.random.normal(size=ishape) 38 | else: 39 | input_arr = np.empty(shape=ishape, dtype=np.complex128) 40 | input_arr.real[:] = np.random.normal(size=ishape) 41 | input_arr.imag[:] = np.random.normal(size=ishape) 42 | if not fwd: 43 | if r2c: 44 | input_arr = np.fft.rfftn(input_arr, axes=axes) 45 | else: 46 | input_arr = np.fft.fftn(input_arr, axes=axes) 47 | if fwd and r2c: 48 | ref_output_arr = np.fft.rfftn(input_arr, axes=axes) 49 | elif fwd: 50 | ref_output_arr = np.fft.fftn(input_arr, axes=axes) 51 | elif r2c: 52 | ref_output_arr = np.fft.irfftn(input_arr, axes=axes, s=dims) 53 | else: 54 | ref_output_arr = np.fft.ifftn(input_arr, axes=axes) 55 | wrapper = FFTWrapper( 56 | dims, 57 | ntransform=ntrans, 58 | r2c=r2c, 59 | fwd=fwd, 60 | inplace=inplace, 61 | batch_first=batch_first, 62 | ) 63 | input_arr.shape = wrapper.input_shape 64 | ref_output_arr.shape = wrapper.output_shape 65 | test_output_arr = wrapper.call(input_arr) 66 | if not fwd: 67 | test_output_arr /= np.prod(dims) 68 | test_output_arr = test_output_arr.reshape(ref_output_arr.shape) 69 | tol = 1e-15 * 10 ** len(dims) 70 | assert_allclose(test_output_arr, ref_output_arr, atol=tol, rtol=0) 71 | 72 | def test_cider_fft(self): 73 | tf = [True, False] 74 | nts = [1, 5] 75 | settings_gen = itertools.product(ALL_DIMS, nts, tf, tf, tf, tf) 76 | for dims, nt, fwd, r2c, inplace, batch_first in settings_gen: 77 | self.run_single_test(dims, nt, fwd, r2c, inplace, batch_first) 78 | 79 | def test_time(self): 80 | libfft.cider_fft_set_nthread(ctypes.c_int(-1)) 81 | import time 82 | 83 | dims = [105, 128, 121] 84 | nt = 10 85 | batch_first = False 86 | if batch_first: 87 | array_size = [nt] + dims 88 | else: 89 | array_size = dims + [nt] 90 | np.random.seed(SEED) 91 | r2c = True 92 | dtype = np.float64 if r2c else np.complex128 93 | matrix = np.random.normal(size=array_size).astype(dtype) 94 | my_matrix = matrix.copy(order="C") 95 | t0 = time.monotonic() 96 | fwr = FFTWrapper( 97 | dims, 98 | ntransform=nt, 99 | fwd=True, 100 | r2c=r2c, 101 | batch_first=batch_first, 102 | inplace=True, 103 | ) 104 | bwr = FFTWrapper( 105 | dims, 106 | ntransform=nt, 107 | fwd=False, 108 | r2c=r2c, 109 | batch_first=batch_first, 110 | inplace=True, 111 | ) 112 | my_test_kmatrix = fwr.call(my_matrix) 113 | my_test_matrix = bwr.call(my_test_kmatrix) 114 | t1 = time.monotonic() 115 | print("TIME", t1 - t0) 116 | print(my_test_kmatrix.sum()) 117 | print(my_test_matrix.sum()) 118 | 119 | 120 | if __name__ == "__main__": 121 | unittest.main() 122 | -------------------------------------------------------------------------------- /ciderpress/lib/xc_utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_library(xc_utils SHARED 3 | libxc_baselines.c 4 | ) 5 | 6 | set_target_properties(xc_utils PROPERTIES 7 | LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR} 8 | COMPILE_FLAGS ${OpenMP_C_FLAGS} 9 | LINK_FLAGS ${OpenMP_C_FLAGS}) 10 | 11 | if (HAVE_MPI) 12 | target_link_libraries(xc_utils PRIVATE MPI::MPI_C) 13 | endif() 14 | if (BUILD_WITH_MKL) 15 | target_link_libraries(xc_utils PRIVATE MKL::MKL) 16 | target_include_directories(xc_utils PRIVATE ${MKL_INCLUDE_DIR}) 17 | else() 18 | target_link_libraries(xc_utils PRIVATE ${BLAS_LIBRARIES}) 19 | endif() 20 | if(BUILD_LIBXC) 21 | target_link_libraries(xc_utils PRIVATE xc) 22 | else() 23 | target_link_libraries(xc_utils PRIVATE Libxc::xc) 24 | endif() 25 | -------------------------------------------------------------------------------- /ciderpress/lib/xc_utils/libxc_baselines.c: -------------------------------------------------------------------------------- 1 | // CiderPress: Machine-learning based density functional theory calculations 2 | // Copyright (C) 2024 The President and Fellows of Harvard College 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU General Public License as published by 6 | // the Free Software Foundation, either version 3 of the License, or 7 | // (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU General Public License 15 | // along with this program. If not, see 16 | // 17 | // Author: Kyle Bystrom 18 | // 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | void get_lda_baseline(int fn_id, int nspin, int size, double *rho, double *exc, 25 | double *vrho, double dens_threshold) { 26 | xc_func_type func; 27 | xc_func_init(&func, fn_id, nspin); 28 | xc_func_set_dens_threshold(&func, dens_threshold); 29 | xc_lda_exc_vxc(&func, size, rho, exc, vrho); 30 | } 31 | 32 | void get_gga_baseline(int fn_id, int nspin, int size, double *rho, 33 | double *sigma, double *exc, double *vrho, double *vsigma, 34 | double dens_threshold) { 35 | xc_func_type func; 36 | xc_func_init(&func, fn_id, nspin); 37 | xc_func_set_dens_threshold(&func, dens_threshold); 38 | xc_gga_exc_vxc(&func, size, rho, sigma, exc, vrho, vsigma); 39 | } 40 | 41 | void get_mgga_baseline(int fn_id, int nspin, int size, double *rho, 42 | double *sigma, double *tau, double *exc, double *vrho, 43 | double *vsigma, double *vtau, double dens_threshold) { 44 | xc_func_type func; 45 | xc_func_init(&func, fn_id, nspin); 46 | xc_func_set_dens_threshold(&func, dens_threshold); 47 | xc_mgga_exc_vxc(&func, size, rho, sigma, rho, tau, exc, vrho, vsigma, NULL, 48 | vtau); 49 | } 50 | -------------------------------------------------------------------------------- /ciderpress/models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/models/__init__.py -------------------------------------------------------------------------------- /ciderpress/models/kernel_plans/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/models/kernel_plans/__init__.py -------------------------------------------------------------------------------- /ciderpress/models/kernel_plans/arbf_exchange.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | from ciderpress.dft.xc_evaluator import SplineSetEvaluator 22 | from ciderpress.models.kernel_plans.kernel_tools import get_agpr_kernel 23 | from ciderpress.models.kernel_plans.map_tools import get_mapped_gp_evaluator_additive 24 | 25 | 26 | def get_kernel( 27 | natural_scale=None, 28 | natural_lscale=None, 29 | scale_factor=None, 30 | lscale_factor=None, 31 | **kwargs, 32 | ): 33 | # leave out density from feature vector 34 | slice(1, None, None) 35 | print(lscale_factor, natural_lscale) 36 | print(scale_factor, natural_scale) 37 | return get_agpr_kernel( 38 | slice(0, 1, None), 39 | slice(1, None, None), 40 | lscale_factor * natural_lscale, 41 | scale=[1e-5, 1e-5, scale_factor * natural_scale], 42 | order=2, 43 | nsingle=1, 44 | ) 45 | 46 | 47 | def mapping_plan(dft_kernel): 48 | scale, ind_sets, spline_grids, coeff_sets = get_mapped_gp_evaluator_additive( 49 | dft_kernel.kernel, 50 | dft_kernel.X1ctrl, 51 | dft_kernel.alpha, 52 | dft_kernel.feature_list, 53 | ) 54 | # TODO this needs to get converted into a class 55 | # that evaluates a specific kernel's contribution to the 56 | # XC energy. This function should then be a component 57 | # called by DFTKernel.map(). 58 | # Then these mapping plans need to be combined within some 59 | # overarching evaluator class, which should be created 60 | # by a function like MOLGP.map(). 61 | return SplineSetEvaluator(scale, ind_sets, spline_grids, coeff_sets) 62 | -------------------------------------------------------------------------------- /ciderpress/models/kernel_plans/kernel_tools.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import numpy as np 22 | 23 | from ciderpress.models.kernels import ( 24 | DiffAntisymRBF, 25 | DiffConstantKernel, 26 | SubsetARBF, 27 | SubsetRBF, 28 | ) 29 | 30 | 31 | def get_rbf_kernel( 32 | indexes, length_scale, scale=1.0, opt_hparams=False, min_lscale=None 33 | ): 34 | if min_lscale is None: 35 | min_lscale = 0.01 36 | length_scale_bounds = (min_lscale, 10) if opt_hparams else "fixed" 37 | scale_bounds = (1e-5, 1e3) if opt_hparams else "fixed" 38 | return DiffConstantKernel(scale, constant_value_bounds=scale_bounds) * SubsetRBF( 39 | indexes, 40 | length_scale=length_scale[indexes], 41 | length_scale_bounds=length_scale_bounds, 42 | ) 43 | 44 | 45 | def get_antisym_rbf_kernel(length_scale, scale=1.0, opt_hparams=False, min_lscale=None): 46 | if min_lscale is None: 47 | min_lscale = 0.01 48 | length_scale_bounds = (min_lscale, 10) if opt_hparams else "fixed" 49 | scale_bounds = (1e-5, 1e3) if opt_hparams else "fixed" 50 | length_scale = np.append( 51 | 0.5 * (length_scale[0] + length_scale[1]), length_scale[2:] 52 | ) 53 | return DiffConstantKernel( 54 | scale, constant_value_bounds=scale_bounds 55 | ) * DiffAntisymRBF( 56 | length_scale=length_scale, 57 | length_scale_bounds=length_scale_bounds, 58 | ) 59 | 60 | 61 | def get_agpr_kernel( 62 | sinds, 63 | ainds, 64 | length_scale, 65 | scale=None, 66 | order=2, 67 | nsingle=1, 68 | opt_hparams=False, 69 | min_lscale=None, 70 | ): 71 | print(sinds, ainds, length_scale[sinds], length_scale[ainds]) 72 | if min_lscale is None: 73 | min_lscale = 0.01 74 | length_scale_bounds = (min_lscale, 10) if opt_hparams else "fixed" 75 | scale_bounds = (1e-5, 1e5) if opt_hparams else "fixed" 76 | if scale is None: 77 | scale = [1.0] * (order + 1) 78 | if nsingle == 0: 79 | singles = None 80 | else: 81 | singles = SubsetRBF( 82 | sinds, 83 | length_scale=length_scale[sinds], 84 | length_scale_bounds=length_scale_bounds, 85 | ) 86 | cov_kernel = SubsetARBF( 87 | ainds, 88 | order=order, 89 | length_scale=length_scale[ainds], 90 | scale=scale, 91 | length_scale_bounds=length_scale_bounds, 92 | scale_bounds=scale_bounds, 93 | ) 94 | if singles is None: 95 | return cov_kernel 96 | else: 97 | return singles * cov_kernel 98 | -------------------------------------------------------------------------------- /ciderpress/models/kernel_plans/plan_template.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | 22 | def get_kernel( 23 | natural_scale=None, 24 | natural_lscale=None, 25 | scale_factor=None, 26 | lscale_factor=None, 27 | ): 28 | """ 29 | Args: 30 | natural_scale (float, None): Natural scale for covariance, 31 | typically set based on variance of target over training data. 32 | natural_lscale (array, None): Natural length scale for features, 33 | typically set based on variance of features over the 34 | training data. 35 | scale_factor (float, None): Multiplicative factor to tune 36 | covariance scale 37 | lscale_factor (float or array, None): Multiplicative factor 38 | to tune length scale. 39 | 40 | Returns: 41 | An sklearn kernel 42 | """ 43 | 44 | 45 | def mapping_plan(model): 46 | """ 47 | A function that maps a model based on the kernel above to 'fast' 48 | functions like splines and polynomial evaluations, then returns 49 | an Evaluator object based on the mapping. 50 | 51 | Args: 52 | model: 53 | 54 | Returns: 55 | 56 | """ 57 | -------------------------------------------------------------------------------- /ciderpress/models/kernel_plans/settings_example.yaml: -------------------------------------------------------------------------------- 1 | # init_file: Path to Python file containing two functions, 2 | # `get_kernel` and (optionally) `mapping_plan`, 3 | # as documented in plan_template.py 4 | # feature_list: Serialized feature list or path to yaml file 5 | # containing serialized feature list. 6 | # mode: See DFTKernel documentation. Corresponds to how spin- 7 | # polarization is handled by the kernel. 8 | # multiplicative_baseline: str name (or serialized function) 9 | # for multiplicative baseline used by kernel. 10 | # additive_baseline: Same as above, but for additive baseline 11 | # ctrl_tol: See DFTKernel docs 12 | # ctrl_nmax: See DFTKernel docs 13 | - plan_file: path/to/plan_file1.py 14 | feature_list: path/to/feature_list1.yaml 15 | mode: SEP 16 | multiplicative_baseline: LDA_X 17 | additive_baseline: GGA_X_PBE 18 | ctrl_tol: 1e-5 # optional 19 | ctrl_nmax: null # optional 20 | - plan_file: path/to/plan_file2.py 21 | feature_list: 22 | mode: OSPOL 23 | multiplicative_baseline: RHO 24 | additive_baseline: null 25 | ctrl_nmax: 100 26 | -------------------------------------------------------------------------------- /ciderpress/pyscf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/pyscf/__init__.py -------------------------------------------------------------------------------- /ciderpress/pyscf/debug_numint.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import numpy as np 22 | from pyscf.dft.gen_grid import Grids 23 | from pyscf.dft.numint import NumInt 24 | 25 | from ciderpress.dft.debug_numint import get_get_exponent, get_nonlocal_features 26 | 27 | 28 | def get_nldf_numint( 29 | mol, grids, dms, gg_kwargs, vv_gg_kwargs, version="i", inner_grids_level=3 30 | ): 31 | if dms.ndim == 2: 32 | return _get_nldf_numint( 33 | mol, 34 | grids, 35 | dms, 36 | gg_kwargs, 37 | vv_gg_kwargs, 38 | version=version, 39 | inner_grids_level=inner_grids_level, 40 | )[None, :] 41 | else: 42 | assert dms.shape[0] == 2 43 | dms = dms * 2 44 | res0 = _get_nldf_numint( 45 | mol, 46 | grids, 47 | dms[0], 48 | gg_kwargs, 49 | vv_gg_kwargs, 50 | version=version, 51 | inner_grids_level=inner_grids_level, 52 | ) 53 | res1 = _get_nldf_numint( 54 | mol, 55 | grids, 56 | dms[1], 57 | gg_kwargs, 58 | vv_gg_kwargs, 59 | version=version, 60 | inner_grids_level=inner_grids_level, 61 | ) 62 | return np.stack([res0, res1]) 63 | 64 | 65 | def _get_nldf_numint( 66 | mol, grids, dms, gg_kwargs, vv_gg_kwargs, version="i", inner_grids_level=3 67 | ): 68 | ni = NumInt() 69 | make_rho, nset, nao = ni._gen_rho_evaluator(mol, dms, 1, False) 70 | max_memory = 2000 71 | assert nset == 1 72 | 73 | get_exponent_r = get_get_exponent(gg_kwargs) 74 | get_exponent_rp = get_get_exponent(vv_gg_kwargs) 75 | 76 | assert nset == 1 77 | smgrids = Grids(mol) 78 | smgrids.level = inner_grids_level 79 | smgrids.prune = None 80 | smgrids.build() 81 | 82 | nfeat = 12 if version == "i" else 4 83 | desc = np.empty((0, nfeat)) 84 | ao_deriv = 1 85 | vvrho = np.empty([nset, 5, 0]) 86 | vvweight = np.empty([nset, 0]) 87 | vvcoords = np.empty([nset, 0, 3]) 88 | for ao, mask, weight, coords in ni.block_loop( 89 | mol, smgrids, nao, ao_deriv, max_memory 90 | ): 91 | rhotmp = np.empty([0, 5, weight.size]) 92 | weighttmp = np.empty([0, weight.size]) 93 | coordstmp = np.empty([0, weight.size, 3]) 94 | for idm in range(nset): 95 | rho = make_rho(idm, ao, mask, "MGGA") 96 | rho = np.expand_dims(rho, axis=0) 97 | rhotmp = np.concatenate((rhotmp, rho), axis=0) 98 | weighttmp = np.concatenate( 99 | (weighttmp, np.expand_dims(weight, axis=0)), 100 | axis=0, 101 | ) 102 | coordstmp = np.concatenate( 103 | (coordstmp, np.expand_dims(coords, axis=0)), 104 | axis=0, 105 | ) 106 | vvrho = np.concatenate((vvrho, rhotmp), axis=2) 107 | vvweight = np.concatenate((vvweight, weighttmp), axis=1) 108 | vvcoords = np.concatenate((vvcoords, coordstmp), axis=1) 109 | aow = None 110 | for ao, mask, weight, coords in ni.block_loop( 111 | mol, grids, nao, ao_deriv, max_memory 112 | ): 113 | aow = np.ndarray(ao[0].shape, order="F", buffer=aow) 114 | for idm in range(nset): 115 | rho = make_rho(idm, ao, mask, "MGGA") 116 | feat = get_nonlocal_features( 117 | rho, 118 | coords, 119 | vvrho[idm], 120 | vvweight[idm], 121 | vvcoords[idm], 122 | get_exponent_r, 123 | get_exponent_rp, 124 | version=version, 125 | ) 126 | desc = np.append(desc, feat, axis=0) 127 | return desc 128 | -------------------------------------------------------------------------------- /ciderpress/pyscf/pbc/__init__.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | 3 | warnings.warn( 4 | "WARNING: The ciderpress.pyscf.pbc module is highly experimental. " 5 | "Only the SDMX nonlocal features are supported, and the memory " 6 | "requirements are high. It is provided for the sole purpose " 7 | "of reproducing past results. A more robust and fully-featured " 8 | "version is planned for future development." 9 | ) 10 | -------------------------------------------------------------------------------- /ciderpress/pyscf/pbc/dft.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | from pyscf import lib 22 | 23 | from ciderpress.pyscf.dft import _CiderKS as _MolCiderKS 24 | from ciderpress.pyscf.dft import get_slxc_settings, load_cider_model 25 | from ciderpress.pyscf.pbc.numint import CiderKNumInt, CiderNumInt, numint 26 | from ciderpress.pyscf.pbc.sdmx_fft import PySCFSDMXInitializer 27 | 28 | 29 | def make_cider_calc( 30 | ks, 31 | mlfunc, 32 | xmix=1.0, 33 | xc=None, 34 | xkernel=None, 35 | ckernel=None, 36 | mlfunc_format=None, 37 | nlc_coeff=None, 38 | nldf_init=None, 39 | sdmx_init=None, 40 | dense_mesh=None, 41 | rhocut=None, 42 | ): 43 | """ 44 | Same as :func:`ciderpress.pyscf.dft.make_cider_calc`, but 45 | for periodic systems. Note that only semilocal and SDMX 46 | features are supported. The ks object must use a uniform XC 47 | integration grid and pseudopotentials. 48 | """ 49 | mlfunc = load_cider_model(mlfunc, mlfunc_format) 50 | ks._xc = get_slxc_settings(xc, xkernel, ckernel, xmix) 51 | # Assign the PySCF-facing functional to be a simple SL 52 | # functional to avoid hybrid DFT being called. 53 | # NOTE this might need to be changed to some nicer 54 | # approach later. 55 | if mlfunc.settings.sl_settings.level == "MGGA": 56 | ks.xc = "R2SCAN" 57 | else: 58 | ks.xc = "PBE" 59 | new_ks = _CiderKS( 60 | ks, 61 | mlfunc, 62 | xmix=xmix, 63 | nldf_init=nldf_init, 64 | sdmx_init=sdmx_init, 65 | rhocut=rhocut, 66 | nlc_coeff=nlc_coeff, 67 | dense_mesh=dense_mesh, 68 | ) 69 | return lib.set_class(new_ks, (_CiderKS, ks.__class__)) 70 | 71 | 72 | class _CiderKS(_MolCiderKS): 73 | def __init__( 74 | self, 75 | mf, 76 | mlxc, 77 | xmix=1.0, 78 | nldf_init=None, 79 | sdmx_init=None, 80 | rhocut=None, 81 | nlc_coeff=None, 82 | dense_mesh=None, 83 | ): 84 | self.dense_mesh = dense_mesh 85 | super().__init__(mf, mlxc, xmix, nldf_init, sdmx_init, rhocut, nlc_coeff) 86 | 87 | def set_mlxc( 88 | self, 89 | mlxc, 90 | xmix=1.0, 91 | nldf_init=None, 92 | sdmx_init=None, 93 | rhocut=None, 94 | nlc_coeff=None, 95 | ): 96 | if nldf_init is None and mlxc.settings.has_nldf: 97 | raise NotImplementedError 98 | if sdmx_init is None and mlxc.settings.has_sdmx: 99 | sdmx_init = PySCFSDMXInitializer(mlxc.settings.sdmx_settings, lowmem=False) 100 | old_grids = self.grids 101 | changed = False 102 | if mlxc.settings.has_nldf: 103 | raise NotImplementedError 104 | if changed: 105 | for key in ( 106 | "atom_grid", 107 | "atomic_radii", 108 | "radii_adjust", 109 | "radi_method", 110 | "becke_scheme", 111 | "prune", 112 | "level", 113 | ): 114 | self.grids.__setattr__(key, old_grids.__getattribute__(key)) 115 | settings = mlxc.settings 116 | has_nldf = not settings.nldf_settings.is_empty 117 | has_nlof = not settings.nlof_settings.is_empty 118 | has_kpts = isinstance(self._numint, numint.KNumInt) 119 | if has_nldf and has_nlof: 120 | raise NotImplementedError 121 | elif has_nldf: 122 | raise NotImplementedError 123 | elif has_nlof: 124 | raise NotImplementedError 125 | else: 126 | if has_kpts: 127 | cls = CiderKNumInt 128 | else: 129 | cls = CiderNumInt 130 | self._numint = cls( 131 | mlxc, 132 | self._xc, 133 | nldf_init, 134 | sdmx_init, 135 | xmix=xmix, 136 | rhocut=rhocut, 137 | nlc_coeff=nlc_coeff, 138 | dense_mesh=self.dense_mesh, 139 | ) 140 | -------------------------------------------------------------------------------- /ciderpress/pyscf/pbc/tests/test_fft.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import ctypes 22 | import unittest 23 | 24 | import numpy as np 25 | from numpy.fft import fftn, ifftn, irfftn, rfftn 26 | from numpy.testing import assert_allclose 27 | 28 | from ciderpress.pyscf.pbc.sdmx_fft import libcider 29 | 30 | 31 | def _call_mkl_test(x, fwd, mesh): 32 | nx, ny, nz = mesh 33 | nzc = nz // 2 + 1 34 | if fwd: 35 | xr = x 36 | xk = np.empty((nx, ny, nzc), order="C", dtype=np.complex128) 37 | else: 38 | xk = x 39 | xr = np.empty((nx, ny, nz), order="C", dtype=np.float64) 40 | assert xr.shape == (nx, ny, nz) 41 | assert xk.shape == (nx, ny, nzc) 42 | libcider.test_fft3d( 43 | xr.ctypes.data_as(ctypes.c_void_p), 44 | xk.ctypes.data_as(ctypes.c_void_p), 45 | ctypes.c_int(nx), 46 | ctypes.c_int(ny), 47 | ctypes.c_int(nz), 48 | ctypes.c_int(1 if fwd else 0), 49 | ) 50 | if fwd: 51 | return xk 52 | else: 53 | return xr 54 | 55 | 56 | class TestFFT(unittest.TestCase): 57 | def test_fft(self): 58 | np.random.seed(34) 59 | meshes = [ 60 | [32, 100, 19], 61 | [32, 100, 20], 62 | [31, 99, 19], 63 | [2, 2, 4], 64 | [81, 81, 81], 65 | [80, 80, 80], 66 | ] 67 | 68 | for mesh in meshes: 69 | kmesh = [mesh[0], mesh[1], mesh[2] // 2 + 1] 70 | xrin = np.random.normal(size=mesh).astype(np.float64) 71 | xkin1 = np.random.normal(size=kmesh) 72 | xkin2 = np.random.normal(size=kmesh) 73 | xkin = np.empty(kmesh, dtype=np.complex128) 74 | xkin.real = xkin1 75 | xkin.imag = xkin2 76 | xkin[:] = rfftn(xrin, norm="backward") 77 | xkc = fftn(xrin.astype(np.complex128), norm="backward") 78 | xkin2 = xkin.copy() 79 | if mesh[2] % 2 == 0: 80 | xkin2[0, 0, 0] = xkin2.real[0, 0, 0] 81 | xkin2[0, 0, -1] = xkin2.real[0, 0, -1] 82 | for ind in [0, -1]: 83 | for i in range(xkin2.shape[-3]): 84 | for j in range(xkin2.shape[-2]): 85 | tmp1 = xkin2[i, j, ind] 86 | tmp2 = xkin2[-i, -j, ind] 87 | xkin2[i, j, ind] = 0.5 * (tmp1 + tmp2.conj()) 88 | xkin2[-i, -j, ind] = 0.5 * (tmp1.conj() + tmp2) 89 | 90 | xk_np = rfftn(xrin) 91 | xk_mkl = _call_mkl_test(xrin, True, mesh) 92 | assert (xk_np.shape == np.array(kmesh)).all() 93 | assert (xk_mkl.shape == np.array(kmesh)).all() 94 | 95 | xr2_np = ifftn(xkc.copy(), s=mesh, norm="forward") 96 | xr_np = irfftn(xkin.copy(), s=mesh, norm="forward") 97 | xr3_np = irfftn(xkin2.copy(), s=mesh, norm="forward") 98 | xr_mkl = _call_mkl_test(xkin, False, mesh) 99 | xr2_mkl = _call_mkl_test(xkin2, False, mesh) 100 | assert (xr_np.shape == np.array(mesh)).all() 101 | assert (xr_mkl.shape == np.array(mesh)).all() 102 | assert_allclose(xr2_np.imag, 0, atol=1e-9) 103 | assert_allclose(xr2_np, xr3_np, atol=1e-9) 104 | assert_allclose(xr2_mkl, xr3_np, atol=1e-9) 105 | assert_allclose(xr_mkl, xr_np, atol=1e-9) 106 | 107 | 108 | if __name__ == "__main__": 109 | unittest.main() 110 | -------------------------------------------------------------------------------- /ciderpress/pyscf/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/ciderpress/pyscf/tests/__init__.py -------------------------------------------------------------------------------- /ciderpress/pyscf/tests/test_functionals.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import unittest 22 | 23 | import pyscf.dft.radi 24 | from numpy.testing import assert_almost_equal 25 | from pyscf import dft, gto 26 | 27 | from ciderpress.pyscf.dft import make_cider_calc 28 | 29 | """ 30 | This is a high-level test to make sure RKS SCF energies are consistent between 31 | commits. It also checks that the functionals are not accidentally changed. 32 | """ 33 | 34 | # This is for backward consistency 35 | pyscf.dft.radi.ATOM_SPECIFIC_TREUTLER_GRIDS = False 36 | 37 | 38 | XCVALS = { 39 | "CIDER23X_SL_GGA": -199.442504774708, 40 | "CIDER23X_NL_GGA": -199.410917905451, 41 | "CIDER23X_SL_MGGA": -199.41699396454, 42 | "CIDER23X_NL_MGGA": -199.422085280523, 43 | "CIDER23X_NL_MGGA_PBE": -199.421990307797, 44 | "CIDER23X_NL_MGGA_DTR": -199.423911593205, 45 | "CIDER24Xne": -199.4190650929805, 46 | "CIDER24Xe": -199.4241297851031, 47 | } 48 | 49 | 50 | def run_functional(xcname): 51 | mol = gto.M( 52 | atom="F 0 0 0; F 0 0 1.420608", 53 | basis="def2-qzvppd", 54 | verbose=4, 55 | output="/dev/null", 56 | ) 57 | ks = dft.RKS(mol) 58 | ks.xc = "PBE" 59 | ks.grids.level = 3 60 | 61 | xcfile = "functionals/{}.yaml".format(xcname) 62 | ks = make_cider_calc( 63 | ks, xcfile, xmix=0.25, xkernel="GGA_X_PBE", ckernel="GGA_C_PBE" 64 | ) 65 | ks = ks.density_fit(auxbasis="def2-universal-jfit") 66 | etot = ks.kernel() 67 | mol.stdout.close() 68 | assert_almost_equal(etot, XCVALS[xcname], 5) 69 | 70 | 71 | class TestFunctionals(unittest.TestCase): 72 | def test_semilocal_gga(self): 73 | run_functional("CIDER23X_SL_GGA") 74 | 75 | def test_nonlocal_gga(self): 76 | run_functional("CIDER23X_NL_GGA") 77 | 78 | def test_semilocal_mgga(self): 79 | run_functional("CIDER23X_SL_MGGA") 80 | 81 | def test_nonlocal_mgga(self): 82 | run_functional("CIDER23X_NL_MGGA") 83 | 84 | def test_nonlocal_mgga_pbe(self): 85 | run_functional("CIDER23X_NL_MGGA_PBE") 86 | 87 | def test_nonlocal_mgga_dtr(self): 88 | run_functional("CIDER23X_NL_MGGA_DTR") 89 | 90 | def test_cider24ne(self): 91 | run_functional("CIDER24Xne") 92 | 93 | def test_cider24e(self): 94 | run_functional("CIDER24Xe") 95 | 96 | 97 | if __name__ == "__main__": 98 | unittest.main() 99 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | {% block footer %} {{ super() }} 3 | 4 | 14 | {% endblock %} 15 | -------------------------------------------------------------------------------- /docs/c_extensions/c_extensions.rst: -------------------------------------------------------------------------------- 1 | C Extension Libraries 2 | ===================== 3 | 4 | .. toctree:: 5 | :maxdepth: 3 6 | 7 | pwutil 8 | -------------------------------------------------------------------------------- /docs/c_extensions/pwutil.rst: -------------------------------------------------------------------------------- 1 | Plane-wave Utilities (pwutil) 2 | ============================= 3 | 4 | .. doxygenfile:: nldf_fft_core.h 5 | :project: CiderPress 6 | -------------------------------------------------------------------------------- /docs/ciderpress/dft/dft.rst: -------------------------------------------------------------------------------- 1 | DFT Module 2 | ========== 3 | 4 | The :py:mod:`ciderpress.dft` module contains many of the core utilities 5 | of the CiderPress code. The most important of these are: 6 | 7 | * The :py:mod:`ciderpress.dft.settings` module, which consists of a set 8 | of classes for specifying the types of features to be computed 9 | for an ML model along with the parametrizations of those features. 10 | * The :py:mod:`ciderpress.dft.plans` module, which provides classes 11 | that specify *how* a given set of features is to be computed. 12 | For example, an instance of :py:class:`NLDFSettingsVJ` from the 13 | :py:mod:`settings` module specifies that version-j :ref:`NLDF ` 14 | features are to be computed, and an instance :py:class:`NLDFSplinePlan` 15 | from :py:mod:`plans` instructs CiderPress how to compute these 16 | features using cubic spline interpolation (see 17 | :ref:`NLDF Numerical Evaluation `). 18 | * The :py:mod:`ciderpress.dft.feat_normalizer` module, which provides 19 | utilities to transform "raw" features (which might not be scale-invariant) 20 | to scale-invariant "normalized features". Note it is not necessary to make 21 | every feature scale-invariant unless you want to enforce the uniform 22 | scaling rule for exchange. 23 | * The :py:mod:`ciderpress.dft.transform_data` module, which provides 24 | utilities to transform "normalized" features (which do not necessarily fall 25 | in a finite interval, making them unwieldy for ML models) into 26 | "transformed" features suitable for direct input into Gaussian process 27 | regression. 28 | * The :py:mod:`ciderpress.dft.xc_evaluator` and :py:mod:`ciderpress.dft.xc_evaluator2` 29 | modules, which provide tools to efficiently evaluate trained CIDER models. 30 | 31 | The APIs of these modules are documentation in the subsections below. 32 | 33 | .. toctree:: 34 | :maxdepth: 1 35 | 36 | settings 37 | plans 38 | feat_normalizer 39 | transform_data 40 | xc_evaluator 41 | -------------------------------------------------------------------------------- /docs/ciderpress/dft/feat_normalizer.rst: -------------------------------------------------------------------------------- 1 | .. _feat_normalizer_module: 2 | 3 | The Feature Normalizer Module 4 | ============================= 5 | 6 | .. automodule:: ciderpress.dft.feat_normalizer 7 | :members: 8 | -------------------------------------------------------------------------------- /docs/ciderpress/dft/plans.rst: -------------------------------------------------------------------------------- 1 | .. _plans_module: 2 | 3 | The Plans Module 4 | ================ 5 | 6 | .. automodule:: ciderpress.dft.plans 7 | :members: 8 | -------------------------------------------------------------------------------- /docs/ciderpress/dft/settings.rst: -------------------------------------------------------------------------------- 1 | .. _settings_module: 2 | 3 | The Settings Module 4 | =================== 5 | 6 | .. automodule:: ciderpress.dft.settings 7 | :members: 8 | -------------------------------------------------------------------------------- /docs/ciderpress/dft/transform_data.rst: -------------------------------------------------------------------------------- 1 | .. _transform_data_module: 2 | 3 | The Transform Data Module 4 | ========================= 5 | 6 | .. automodule:: ciderpress.dft.transform_data 7 | :members: 8 | -------------------------------------------------------------------------------- /docs/ciderpress/dft/xc_evaluator.rst: -------------------------------------------------------------------------------- 1 | .. _xc_evaluator_module: 2 | 3 | The XC Evaluator Modules 4 | ======================== 5 | 6 | .. automodule:: ciderpress.dft.xc_evaluator 7 | :members: 8 | 9 | .. automodule:: ciderpress.dft.xc_evaluator2 10 | :members: 11 | -------------------------------------------------------------------------------- /docs/ciderpress/gpaw/calculator.rst: -------------------------------------------------------------------------------- 1 | .. _GPAW Calculator Interface: 2 | 3 | GPAW Calculator Interface 4 | ========================= 5 | 6 | The GPAW calculator interfaces modifies GPAW to be 7 | compatible with CIDER functionals. There are two 8 | key components. The first is the function 9 | :func:`ciderpress.gpaw.calculator.get_cider_functional`, 10 | which generates a CIDER functional for use in GPAW. 11 | The second is the :func:`ciderpress.gpaw.calculator.CiderGPAW` 12 | class, which modifies the ``GPAW`` calculator object 13 | to be able to read and write calculations that use CIDER 14 | functionals. :: 15 | 16 | xc = get_cider_functional(...) 17 | atoms.calc = CiderGPAW(xc=xc, ...) 18 | atoms.get_potential_energy() 19 | 20 | For a full example, see :source:`examples/gpaw/simple_calc.py` 21 | and the other examples in :source:`examples/gpaw` 22 | 23 | .. automodule:: ciderpress.gpaw.calculator 24 | :members: 25 | -------------------------------------------------------------------------------- /docs/ciderpress/gpaw/gpaw.rst: -------------------------------------------------------------------------------- 1 | GPAW Interface 2 | ============== 3 | 4 | The GPAW interface allows CIDER functionals to be used in the GPAW code. 5 | CIDER has only been tested with the plane-wave mode of GPAW. It is 6 | recommended to use PAW setups (not pseudopotentials) because accurately 7 | computing the CIDER features requires an all-electron formalism. 8 | It is possible to run CIDER functionals with norm-conserving pseudopotentials 9 | (except for semilocal meta-GGA models), but it is not recommended. 10 | 11 | This documentation assumes that you are familiar with the GPAW code and 12 | have a working installation of the software. For GPAW documentation, 13 | see the `GPAW website `_. 14 | 15 | The key user-facing component of the GPAW interface is the 16 | :ref:`calculator` module, which provides tools 17 | to initialize a CIDER functional object that can be used in GPAW. 18 | It also provides a subclass of the ``GPAW`` calculator object. 19 | See the :ref:`calculator` module documentation 20 | for examples and API documentation. 21 | 22 | Note that CIDER does not support ``gpaw.new`` yet. 23 | 24 | .. toctree:: 25 | :maxdepth: 1 26 | :caption: Contents: 27 | 28 | calculator 29 | 30 | -------------------------------------------------------------------------------- /docs/ciderpress/models/dft_kernel.rst: -------------------------------------------------------------------------------- 1 | .. _dftkernel: 2 | 3 | ciderpress.models.dft_kernel 4 | ============================ 5 | 6 | The DFTKernel 7 | 8 | .. automodule:: ciderpress.models.dft_kernel 9 | :members: 10 | 11 | -------------------------------------------------------------------------------- /docs/ciderpress/models/kernel_tools.rst: -------------------------------------------------------------------------------- 1 | Kernel Tools 2 | ============ 3 | 4 | .. automodule:: ciderpress.models.kernel_plans.kernel_tools 5 | :members: 6 | 7 | -------------------------------------------------------------------------------- /docs/ciderpress/models/kernels.rst: -------------------------------------------------------------------------------- 1 | ciderpress.models.kernels 2 | ========================= 3 | 4 | .. automodule:: ciderpress.models.kernels 5 | :members: 6 | 7 | -------------------------------------------------------------------------------- /docs/ciderpress/models/models.rst: -------------------------------------------------------------------------------- 1 | .. _models_module: 2 | 3 | The Models Module 4 | ================= 5 | 6 | The :py:mod:`ciderpress.models` module is the workhorse for training 7 | Cider exchange-correlation functionals and mapping them to efficient 8 | models for evaluation in DFT codes. The :py:mod:`train` module 9 | contains the :py:class:`MOLGP` and :py:class:`MOLGP2` classes, 10 | which are used to construct Gaussian process models for the exchange 11 | and correlation energies. While these Gaussian process classes 12 | are custom to CiderPress, the kernel functions used to construct 13 | the covariance matrix are built on top of those in the scikit-learn 14 | package. 15 | 16 | .. toctree:: 17 | :maxdepth: 1 18 | :caption: Contents: 19 | 20 | train 21 | dft_kernel 22 | kernels 23 | kernel_tools 24 | 25 | -------------------------------------------------------------------------------- /docs/ciderpress/models/train.rst: -------------------------------------------------------------------------------- 1 | ciderpress.models.train 2 | ======================= 3 | 4 | .. automodule:: ciderpress.models.train 5 | :members: 6 | 7 | -------------------------------------------------------------------------------- /docs/ciderpress/pyscf/analyzers.rst: -------------------------------------------------------------------------------- 1 | analyzers 2 | ========= 3 | 4 | The :py:mod:`ciderpress.pyscf.analyzers` module provides 5 | post-processing tools for analyzing PySCF DFT calculations. 6 | In particular, sub-classes of :py:class:`ciderpress.pyscf.analyzers.ElectronAnalyzer` 7 | can generate densities, kinetic energy densities, 8 | exchange energy densities, etc. on a real-space grid. 9 | 10 | .. automodule:: ciderpress.pyscf.analyzers 11 | :members: 12 | -------------------------------------------------------------------------------- /docs/ciderpress/pyscf/descriptors.rst: -------------------------------------------------------------------------------- 1 | descriptors 2 | =========== 3 | 4 | The :py:mod:`ciderpress.pyscf.descriptors` module provides the 5 | function :py:func:`get_descriptors`, which computes a 6 | set of requested CIDER features from a completed PySCF calculation. 7 | This is the utility used to generate the features 8 | for training CIDER models 9 | 10 | .. automodule:: ciderpress.pyscf.descriptors 11 | :members: 12 | -------------------------------------------------------------------------------- /docs/ciderpress/pyscf/dft.rst: -------------------------------------------------------------------------------- 1 | dft 2 | === 3 | 4 | The :py:mod:`ciderpress.pyscf.dft` module provides the 5 | function :py:func:`make_cider_calc`, which takes 6 | a Pyscf :py:class:`KohnShamDFT` object and a CIDER 7 | functional object (:py:class:`MappedXC` or :py:class:`MappedXC2`) 8 | and returns an instance of a :py:class:`KohnShamDFT` 9 | subclass that uses the CIDER functional. The function 10 | is similar to native PySCF routines like :py:func:`density_fit`, 11 | in which the input SCF object is "decorated" with the 12 | necessary routines to evaluate the CIDER functional. 13 | 14 | The basic use case is:: 15 | 16 | from pyscf.dft import RKS 17 | from pyscf import gto 18 | mol = gto.M(...) 19 | ks = dft.RKS(mol) 20 | ks = make_cider_calc(ks, mlfunc, ...) 21 | etot = ks.kernel() 22 | 23 | For a complete example, please see :source:`examples/pyscf/simple_calc.py` 24 | and the other examples in :source:`examples/pyscf`. 25 | 26 | .. automodule:: ciderpress.pyscf.dft 27 | :members: 28 | -------------------------------------------------------------------------------- /docs/ciderpress/pyscf/pbc/dft.rst: -------------------------------------------------------------------------------- 1 | pbc.dft 2 | ======= 3 | 4 | The :py:mod:`ciderpress.pyscf.pbc.dft` module serves the same 5 | purpose as :py:mod:`ciderpress.pyscf.dft` but for periodic 6 | systems. This module's version of :py:func:`make_cider_calc` 7 | modifies a :py:mod:`pbc` Kohn Sham DFT object from PySCF 8 | to evaluate a CIDER functional. Currently only semilocal 9 | and SDMX features are supported. 10 | 11 | **NOTE**: This module is particularly experimental. It is 12 | provided for the purpose of reproducing previous work that 13 | used this module (i.e. :footcite:t:`CIDER24X`) and is not as 14 | close to production readiness as other parts of the code. 15 | 16 | .. automodule:: ciderpress.pyscf.pbc.dft 17 | :members: 18 | 19 | .. footbibliography:: 20 | -------------------------------------------------------------------------------- /docs/ciderpress/pyscf/pyscf.rst: -------------------------------------------------------------------------------- 1 | PySCF Interface 2 | =============== 3 | 4 | The PySCF interface allows CIDER functionals to be used in the PySCF 5 | software package. Most CIDER models are only availabe in the 6 | non-periodic version of PySCF, but SDMX functionals can be performed 7 | with periodic boundary conditions if pseudopotentials and a 8 | uniform XC integration grid are used. We note that the latter 9 | feature is particularly experimental. 10 | 11 | This documentation assumes you are familiar with the PySCF code and 12 | have a working installation of the software. 13 | For PySCF documentation, please see the `PySCF `_ 14 | website. 15 | 16 | The main module CiderPress users need to be familiar with is 17 | :py:mod:`ciderpress.pyscf.dft`, which contains tools to 18 | turn a standard Kohn-Sham DFT calculation into one that uses 19 | a CIDER functional. See the module documentation for details. 20 | 21 | For those interested in the experimental periodic boundary 22 | condition feature for SDMX functionals, please see the 23 | :py:mod:`ciderpress.pyscf.pbc.dft` module documentation. 24 | 25 | .. toctree:: 26 | :maxdepth: 2 27 | 28 | dft 29 | pbc/dft 30 | analyzers 31 | descriptors 32 | 33 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # For the full list of built-in configuration values, see the documentation: 4 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 5 | 6 | import sys 7 | from pathlib import Path 8 | from datetime import datetime 9 | from ciderpress import __version__ 10 | 11 | # sys.path.insert(0, str(Path('..').resolve())) 12 | sys.path.append("./tools/extensions") 13 | 14 | # -- Project information ----------------------------------------------------- 15 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information 16 | 17 | project = 'CiderPress' 18 | author = 'Kyle Bystrom' 19 | year = datetime.now().year 20 | copyright = f"{year}, Kyle Bystrom" 21 | # The short X.Y version. 22 | v,sv = __version__.split('.')[:2] 23 | version = "%s.%s"%(v,sv) 24 | # The full version, including alpha/beta/rc tags. 25 | release = __version__ 26 | 27 | # -- General configuration --------------------------------------------------- 28 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration 29 | 30 | extensions = [ 31 | 'sphinx.ext.autodoc', 32 | 'sphinx_rtd_theme', 33 | 'sphinx.ext.mathjax', 34 | 'sphinx.ext.napoleon', 35 | 'sphinxcontrib.bibtex', 36 | 'ciderdocext', 37 | 'breathe', 38 | ] 39 | bibtex_bibfiles = ['refs/refs.bib', 'refs/cider_refs.bib'] 40 | 41 | templates_path = ['_templates'] 42 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 43 | 44 | autoclass_content = 'both' 45 | 46 | breathe_projects = {"CiderPress": "xml"} 47 | breathe_default_project = "CiderPress" 48 | breathe_default_members = ("members", "undoc-members") 49 | breathe_domain_by_extension = { 50 | "h" : "c", 51 | } 52 | 53 | napoleon_google_docstring = True 54 | # napoleon_numpy_docstring = True 55 | napoleon_use_param = False 56 | 57 | # -- Options for HTML output ------------------------------------------------- 58 | # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output 59 | 60 | html_theme = 'sphinx_rtd_theme' 61 | html_static_path = ['_static'] 62 | html_logo = "logos/cider_logo_and_name.png" 63 | html_theme_options = {'logo_only': True} 64 | 65 | -------------------------------------------------------------------------------- /docs/features/features.rst: -------------------------------------------------------------------------------- 1 | Density and Orbital Features in CiderPress 2 | ========================================== 3 | 4 | To predict the exchange-correlation energy :math:`E_{\text{xc}}`, we need 5 | to train a machine learning model :math:`e_{\text{xc}}(\mathbf{x})` such that 6 | 7 | .. math:: E_{\text{xc}} = \int \text{d}^3\mathbf{r}\, e_\text{xc}(\mathbf{x}[n_1](\mathbf{r})) 8 | 9 | where :math:`\mathbf{x}[n_1](\mathbf{r})` is a position-dependent feature vector that is 10 | a functional of the density :math:`n(\mathbf{r})` in "pure" Kohn-Sham DFT and a 11 | functional of the density matrix :math:`n_1(\mathbf{r}, \mathbf{r}')` in the case of 12 | "generalized" Kohn-Sham DFT. Cider provides several types of feature that can 13 | be used as input to the ML model. These features 14 | can be divided into four categories: 15 | 16 | * :ref:`Semilocal Features (SL) `: Same features as in conventional GGA/meta-GGA functionals (i.e. :math:`n`, :math:`\nabla n`, :math:`\tau`). 17 | NOTE: All Cider models must include semilocal features. 18 | They need not be used explicitly in the model, but evaluating 19 | them is required to evalute baseline functionals and other quantities in the code. 20 | * :ref:`Nonlocal Density Features (NLDF) `: These features are constructed by integrating the density 21 | over a real-space kernel function to characterize the shape of the density around a point :math:`\mathbf{r}`. 22 | * :ref:`Nonlocal Orbital Features (NLOF) `: EXPERIMENTAL, NOT TESTED, NOT RECOMMENDED FOR USE. 23 | One coordinate of the density matrix is operated on by a fractional Laplacian. 24 | * :ref:`Smooth Density Matrix Exchange (SDMX) `: 25 | One coordinate of the density matrix is convolved at different length scales. Then these convolutions 26 | are contracted to approximately characterize the shape of the density matrix around a point :math:`\mathbf{r}`. 27 | 28 | The set of features to be used in a model is specified using the :class:`FeatureSettings` object. To see 29 | the code API for setting up feature settings, see the :ref:`Settings module ` section. To see 30 | mathematical descriptions and physical intuition for the different types of features, see 31 | the subsections below. 32 | 33 | .. toctree:: 34 | :maxdepth: 1 35 | 36 | sl 37 | nldf 38 | nlof 39 | sdmx 40 | 41 | -------------------------------------------------------------------------------- /docs/features/nlof.rst: -------------------------------------------------------------------------------- 1 | .. _nlof_feat: 2 | 3 | Nonlocal Orbital Features (NLOF) 4 | ================================ 5 | 6 | **The nonlocal orbital features are still highly experimental. We note here 7 | that they are implemented in the code so that their presence does not cause 8 | confusion, but their use is not encouraged, and they might be removed at a 9 | later date.** 10 | 11 | -------------------------------------------------------------------------------- /docs/features/sl.rst: -------------------------------------------------------------------------------- 1 | .. _sl_feat: 2 | 3 | Semilocal Features (SL) 4 | ======================= 5 | 6 | Semilocal features are the ingredient commonly used in semilocal DFT. 7 | They most basic ingredient is the electron density :math:`n(\mathbf{r})`, 8 | which is defined as 9 | 10 | .. math:: n(\mathbf{r}) = \sum_i f_i |\phi_i(\mathbf{r})|^2 11 | 12 | with :math:`\phi_i(\mathbf{r})` being the Kohn-Sham orbitals. A functional 13 | constructed from :math:`n(\mathbf{r})` only is called a local density 14 | approximation (LDA). The gradient of the density :math:`\nabla n(\mathbf{r})` 15 | is also commonly used and results in a generalized-gradient approximation (GGA). 16 | Lastly, the kinetic energy density 17 | 18 | .. math:: \tau(\mathbf{r}) = \frac{1}{2} \sum_i f_i |\nabla\phi_i(\mathbf{r})|^2 19 | 20 | can be used, resulting in a meta-generalized gradient approximation (meta-GGA or MGGA). 21 | To help enforce physical constraints such as uniform scaling, regularized 22 | features are often introduced, including the reduced gradient\ :footcite:p:`Perdew1996` 23 | 24 | .. math:: p = \frac{|\nabla n|^2}{2(3\pi^2)^{1/3}n^{4/3}} 25 | 26 | and the iso-orbital indicator\ :footcite:p:`Sun2013` 27 | 28 | .. math:: \alpha = \frac{\tau - \tau_W}{\tau_0} 29 | 30 | where :math:`\tau_W=|\nabla n|^2/8n` is the single-electron kinetic energy, 31 | and :math:`\tau_0=\frac{3}{10}(3\pi^2)^{2/3}n^{5/3}` is the kinetic energy 32 | density of the uniform electron gas. 33 | 34 | Note that for simplicity, all of these definitions are provided for the 35 | non-spin-polarized case, where the orbital occupations :math:`f_i\in [0,2]` 36 | 37 | In Cider, the choice of semilocal features is specified using the class:`SemilocalSettings` 38 | class in :py:mod:`ciderpress.dft.settings`. There is only one argument to this 39 | class, :py:obj:`mode`, which specifies which features to compute. There are four choices: 40 | 41 | * ``ns``: :math:`\mathbf{x}_\text{sl} = [n, |\nabla n|^2]` 42 | * ``np``: :math:`\mathbf{x}_\text{sl} = [n, p]` 43 | * ``nst``: :math:`\mathbf{x}_\text{sl} = [n, |\nabla n|^2, \tau]` 44 | * ``npa``: :math:`\mathbf{x}_\text{sl} = [n, p, \alpha]` 45 | 46 | **IMPORTANT NOTE 1**: If the mode is ``ns`` or ``np``, the kinetic energy density :math:`\tau` 47 | is not computed, so it cannot be used at any point in the calculation. This means 48 | that :ref:`Nonlocal Density Features ` must be instantiated with 49 | ``sl_level="GGA"``. If desired, orbital-dependent features can still be incorporated 50 | via :ref:`Smooth Density Matrix Exchange `. If the mode is ``nst`` or ``npa``, 51 | :math:`\tau` is always computed. 52 | 53 | **IMPORTANT NOTE 2**: The regularized features :math:`p` and :math:`\alpha` are 54 | scale-invariant, meaning that 55 | an exchange functional trained with these features and 56 | a proper exchange functional baseline will obey the 57 | uniform scaling rule (see :ref:`Uniform Scaling Constraints `). 58 | The raw features :math:`n`, :math:`|\nabla n|^2`, and :math:`\tau` are not 59 | scale-invariant, and CiderPress does not automatically regularize these features 60 | as it does with nonlocal features. Therefore, these features must be regularized in 61 | the :py:mod:`ciderpress.dft.transform_data` module to enforce the uniform scaling 62 | constraint in trained models. (TODO need to elaborate on this). 63 | 64 | See the :class:`SemilocalSettings` class in the :ref:`Feature Settings ` 65 | documentation for more details on the API for setting up these features. 66 | 67 | .. footbibliography:: 68 | 69 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. CiderPress documentation master file, created by 2 | sphinx-quickstart on Sat Oct 12 11:17:44 2024. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | CiderPress: Machine Learning Exchange-Correlation Functionals 7 | ============================================================= 8 | 9 | Welcome to the CiderPress documentation! CiderPress is a Python package built 10 | for running machine-learned exchange-correlation functionals within the CIDER 11 | framework. This documentation is currently under construction. In the meantime, 12 | please feel free to post a Github issue or reach out the developers at 13 | kylebystrom@gmail.com. 14 | 15 | 16 | .. toctree:: 17 | :maxdepth: 2 18 | :caption: Contents: 19 | 20 | installation/installation 21 | theory/theory 22 | features/features 23 | ciderpress/dft/dft 24 | ciderpress/models/models 25 | ciderpress/pyscf/pyscf 26 | ciderpress/gpaw/gpaw 27 | c_extensions/c_extensions 28 | 29 | -------------------------------------------------------------------------------- /docs/logos/cider_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /docs/logos/cider_logo_and_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mir-group/CiderPress/c6daba191d74dabb4ec605a2ce8e1b33ed9bfb97/docs/logos/cider_logo_and_name.png -------------------------------------------------------------------------------- /docs/logos/cider_logo_and_name.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | 24 | 25 | 26 | 27 | 28 | CIDER 29 | PRESS 30 | -------------------------------------------------------------------------------- /docs/refs/cider_refs.bib: -------------------------------------------------------------------------------- 1 | @article{CIDER22X, 2 | title = {{{CIDER}}: {{An Expressive}}, {{Nonlocal Feature Set}} for {{Machine Learning Density Functionals}} with {{Exact Constraints}}}, 3 | author = {Bystrom, Kyle and Kozinsky, Boris}, 4 | year = {2022}, 5 | month = apr, 6 | journal = {J. Chem. Theory Comput.}, 7 | volume = {18}, 8 | number = {4}, 9 | pages = {2180--2192}, 10 | issn = {1549-9618}, 11 | doi = {10.1021/acs.jctc.1c00904} 12 | } 13 | 14 | @article{CIDER23X, 15 | title = {Nonlocal machine-learned exchange functional for molecules and solids}, 16 | author = {Bystrom, Kyle and Kozinsky, Boris}, 17 | journal = {Phys. Rev. B}, 18 | volume = {110}, 19 | issue = {7}, 20 | pages = {075130}, 21 | year = {2024}, 22 | month = {Aug}, 23 | publisher = {American Physical Society}, 24 | doi = {10.1103/PhysRevB.110.075130}, 25 | url = {https://link.aps.org/doi/10.1103/PhysRevB.110.075130} 26 | } 27 | 28 | @article{CIDER24X, 29 | author = {Bystrom, Kyle and Falletta, Stefano and Kozinsky, Boris}, 30 | title = {Training Machine-Learned Density Functionals on Band Gaps}, 31 | journal = {Journal of Chemical Theory and Computation}, 32 | volume = {20}, 33 | number = {17}, 34 | pages = {7516-7532}, 35 | year = {2024}, 36 | doi = {10.1021/acs.jctc.4c00999}, 37 | note ={PMID: 39178337}, 38 | URL = {https://doi.org/10.1021/acs.jctc.4c00999}, 39 | eprint = {https://doi.org/10.1021/acs.jctc.4c00999} 40 | } 41 | 42 | -------------------------------------------------------------------------------- /docs/theory/nldf_numerical.rst: -------------------------------------------------------------------------------- 1 | .. _nldf_numerical: 2 | 3 | Numerical Evaluation of NLDF Features 4 | ===================================== 5 | 6 | Computing :ref:`Nonlocal Density Features ` (NLDFs) using simple 7 | numerical integration can be unwieldy and computationally costly, so in 8 | practical calculations, the feature integrals are expanded as a sum 9 | of convolutions. The expansion is slightly different for each 10 | feature version. 11 | 12 | For version j, the general form of the feature is 13 | 14 | .. math:: 15 | 16 | G_i[n](\mathbf{r}) = \int \text{d}^3\mathbf{r} k(a_0[n](\mathbf{r}'), a_i(\mathbf{r}), |\mathbf{r}-\mathbf{r}'|) n(\mathbf{r}') 17 | 18 | In the context of implementing a nonlocal van der Waals density functional, :footcite:t:`Roman-Perez2009` 19 | found that the kernel :math:`k(a_0[n](\mathbf{r}'), a_i(\mathbf{r}), |\mathbf{r}-\mathbf{r}'|)` 20 | can be approximated as 21 | 22 | .. math:: 23 | 24 | k(a, b, r) \approx \sum_\alpha \sum_\beta k(\alpha, \beta, r) p_\alpha(a) p_\beta(b) 25 | 26 | where :math:`\alpha` and :math:`\beta` are a set of interpolating points that span the range 27 | of values taken by :math:`a_0` and :math:`a_i` over the density distribution, 28 | and :math:`p_\alpha(a)` is a cubic spline that is :math:`1` when :math:`a=\alpha` and :math:`0` 29 | when :math:`a=\beta` (with :math:`\beta` being another interpolation point not equal to :math:`\alpha`). 30 | Because the interpolation points are constants independent of the density, the above approximation 31 | converts the feature integral into a sum over convolutions. 32 | 33 | The :py:class:`ciderpress.dft.plans.NLDFSplinePlan` class implements this interpolation 34 | approach. 35 | 36 | The version j integration kernel :math:`k(a, b, r)` is separable in :math:`a` and :math:`b`: 37 | 38 | .. math:: k(a, b, r) = \exp(-(a+b)r^2) = \exp(-a r^2) \exp(-b r^2) 39 | 40 | Because of this, the interpolations can also be performed by expanding :math:`\exp(-a r^2)` 41 | as a linear combination of the interpolation functions :math:`\exp(-\alpha r^2)`. This 42 | modified approach is implemented by the :py:class:`ciderpress.dft.plans.NLDFGaussianPlan` class. 43 | 44 | The details of how this interpolation approximation is used to compute the NLDFs 45 | is dependent on the periodicity, type of grid, and type of basis set used in a DFT 46 | calculation. For details on the implementation of this approach for isolated Gaussian-type 47 | orbital calculations and periodic plane-wave DFT calculations, see :footcite:t:`CIDER23X`. 48 | 49 | The other features versions (i and k) require slightly modified version of this approach, 50 | but the basic idea is the same and the implementation quite similar. 51 | 52 | -------------------------------------------------------------------------------- /docs/theory/theory.rst: -------------------------------------------------------------------------------- 1 | Theory Overview 2 | =============== 3 | 4 | The theory section provides an overview of some of the important concepts 5 | involved in designing exchange-correlation functionals for DFT, 6 | particularly machine learning-based functionals. 7 | 8 | .. toctree:: 9 | :maxdepth: 1 10 | :caption: Contents: 11 | 12 | uniform_scaling 13 | gp 14 | nldf_numerical 15 | 16 | -------------------------------------------------------------------------------- /docs/theory/uniform_scaling.rst: -------------------------------------------------------------------------------- 1 | .. _unif_scaling: 2 | 3 | Uniform Scaling 4 | =============== 5 | 6 | Uniform scaling is a critical concept for understanding density functional 7 | design. Consider a given electron density distribution :math:`n(\mathbf{r})`. 8 | We can consider a transformed density of the form 9 | 10 | .. math:: n_\lambda(\mathbf{r}) = \lambda^3 n(\lambda \mathbf{r}) 11 | 12 | This transformation is called *uniform coordinate scaling*,\ :footcite:p:`Martin2004` 13 | because it essentially involves redefining 14 | :math:`\mathbf{r}\leftarrow\lambda\mathbf{r}`, which squishes 15 | (:math:`\lambda>0`) or expands (:math:`\lambda<0`) the 16 | density while maintaining its relative shape. The :math:`\lambda^3` 17 | prefactor ensures that the particle number is conserved, i.e. 18 | 19 | .. math:: \int \text{d}^3\mathbf{r} n_\lambda(\mathbf{r}) = \int \text{d}^3\mathbf{r} n(\mathbf{r}) 20 | 21 | One can also consider uniform scaling of the density *matrix*: 22 | 23 | .. math:: n_1^\lambda(\mathbf{r}, \mathbf{r}') = \lambda^3 n_1(\lambda \mathbf{r}, \lambda \mathbf{r}') 24 | 25 | NOTE: For orbital-dependent functionals, scaling the density and scaling the density matrix are 26 | not precisely equivalent, because there is a distribution of possible density 27 | matrices that can yield a given density. If the orbital-dependent potential 28 | causes the orbitals to rearrange themselves when uniform scaling occurs, the 29 | lowest-energy density matrix for a density :math:`n_\lambda` will not necessarily 30 | be :math:`n_1^\lambda`, i.e. the scaled density matrix obtained 31 | from the lowest-energy density matrix with density :math:`n`. This is a very 32 | subtle point, however, and does not usually make a big impact, so in most 33 | cases we will always refer to scaling the density :math:`n_\lambda` for 34 | simplicity, even when orbital-dependent quantities are involved. 35 | For more details, see :footcite:t:`Gorling1995`. 36 | 37 | The exact exchange functional :math:`E_\text{x}[n]` has a simple, 38 | exact behavior under uniform scaling:\ :footcite:p:`Levy1985` 39 | 40 | .. math:: E_\text{x}[n_\lambda] = \lambda E_\text{x}[n] 41 | 42 | The correlation functional :math:`E_\text{c}[n]` does not have such simple 43 | behavior under uniform scaling, but it does obey the limits\ :footcite:p:`Kaplan2023` 44 | 45 | .. math:: 46 | 47 | \lim_{\lambda\rightarrow 0} E_\text{c}[n_\lambda] &= \lambda C_0[n] \\ 48 | \lim_{\lambda\rightarrow \infty} E_\text{c}[n_\lambda] &> -\infty 49 | 50 | Therefore, it can be helpful to design features with simple, well-understood 51 | behavior under uniform scaling. In particular, if the feature vector :math:`\mathbf{x}` 52 | for the ML model is *scale-invariant*, i.e. if 53 | 54 | .. math:: \mathbf{x}[n_\lambda](\mathbf{r}) = \mathbf{x}[n](\lambda \mathbf{r}) 55 | 56 | then an exchange functional of the form 57 | 58 | .. math:: E_\text{x}[n] = \int \text{d}^3\mathbf{r} e_\text{x}^\text{ML}(\mathbf{x}(\mathbf{r}) 59 | 60 | obeys the uniform scaling rule for exchange (:math:`E_\text{x}[n_\lambda] = \lambda E_\text{x}[n]`). 61 | Similar, scale-invariant features can also be useful for correlation functionals because 62 | their behavior under uniform scaling will be the same as the behavior of the multiplicative 63 | baseline functional used for training. If the baseline model has reasonable behavior under 64 | uniform scaling (such as PBE/SCAN), this could help make more physically realistic models. 65 | (However, it could also needlessly restrict the model's flexibility, so there are trade-offs involved). 66 | 67 | .. footbibliography:: 68 | 69 | -------------------------------------------------------------------------------- /docs/tools/extensions/ciderdocext.py: -------------------------------------------------------------------------------- 1 | from sphinx.util.nodes import split_explicit_title 2 | from docutils import nodes, utils 3 | 4 | SOURCE_URI = 'https://github.com/mir-group/CiderPress/tree/main/%s' 5 | 6 | def source_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): 7 | has_title, title, target = split_explicit_title(text) 8 | title = utils.unescape(title) 9 | target = utils.unescape(target) 10 | refnode = nodes.reference(title, title, refuri=SOURCE_URI % target) 11 | return [refnode], [] 12 | 13 | def setup(app): 14 | app.add_role('source', source_role) 15 | return {'version': '0.1', 'parallel_read_safe': True} 16 | -------------------------------------------------------------------------------- /examples/gpaw/pp_calc.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from ase.build import bulk 4 | from gpaw import PW 5 | 6 | from ciderpress.gpaw.calculator import CiderGPAW, get_cider_functional 7 | 8 | # NOTE: Run this script as follows: 9 | # mpirun -np python simple_calc.py 10 | 11 | atoms = bulk("Si") 12 | 13 | mlfunc = "functionals/{}.yaml".format(sys.argv[1]) 14 | 15 | # This is the initializer for CIDER functionals for GPAW 16 | xc = get_cider_functional( 17 | # IMPORTANT: NormGPFunctional object or a path to a joblib or yaml file 18 | # containing a CIDER functional. 19 | mlfunc, 20 | # IMPORTANT: xmix is the mixing parameter for exact exchange. Default=0.25 21 | # gives the PBE0/CIDER surrogate hybrid. 22 | xmix=0.25, 23 | # largest q for interpolating feature expansion, default=300 is usually fine 24 | qmax=300, 25 | # lambda parameter for interpolating features. default=1.8 is usually fine. 26 | # Lower lambd is more precise 27 | lambd=1.8, 28 | # pasdw_store_funcs=False (default) saves memory. True reduces cost 29 | pasdw_store_funcs=False, 30 | # pasdw_ovlp_fit=True (default) uses overlap fitting to improve precision 31 | # of PAW correction terms of features. 32 | pasdw_ovlp_fit=True, 33 | use_paw=False, 34 | ) 35 | 36 | # Using CiderGPAW instead of the default GPAW calculator allows calculations 37 | # to be restarted. GPAW calculations will run with CIDER functionals but 38 | # cannot be saved and loaded properly. 39 | atoms.calc = CiderGPAW( 40 | h=0.13, # use a reasonably small grid spacing 41 | xc=xc, # assign the CIDER functional to xc 42 | mode=PW(520), # plane-wave mode with 520 eV cutoff. 43 | txt="-", # output file, '-' for stdout 44 | occupations={"name": "fermi-dirac", "width": 0.01}, 45 | # ^ Fermi smearing with 0.01 eV width 46 | kpts={"size": (12, 12, 12), "gamma": False}, # kpt mesh parameters 47 | convergence={"energy": 1e-5}, # convergence energy in eV/electron 48 | # Set augments_grids=True for CIDER functionals to parallelize 49 | # XC energy and potential evaluation more effectively 50 | parallel={"augment_grids": True}, 51 | setups="sg15", 52 | ) 53 | etot = atoms.get_potential_energy() # run the calculation 54 | -------------------------------------------------------------------------------- /examples/gpaw/simple_calc.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import numpy as np 4 | from ase.build import bulk 5 | from gpaw import PW, Mixer 6 | 7 | from ciderpress.gpaw.calculator import CiderGPAW, get_cider_functional 8 | 9 | # NOTE: Run this script as follows: 10 | # mpirun -np gpaw python simple_calc.py 11 | 12 | MODIFY_CELL = True 13 | 14 | atoms = bulk("Si") 15 | 16 | mlfunc = "functionals/{}.yaml".format(sys.argv[1]) 17 | 18 | # This is the initializer for CIDER functionals for GPAW 19 | xc = get_cider_functional( 20 | # IMPORTANT: Path to a joblib or yaml file containing a CIDER functional. 21 | # Object stored in yaml/joblib must be MappedXC or MappedXC2. 22 | # Can also pass the object itself rather than a file name. 23 | mlfunc, 24 | # IMPORTANT: xmix is the mixing parameter for exact exchange. Default=0.25 25 | # gives the PBE0/CIDER surrogate hybrid. 26 | xmix=0.25, 27 | # largest q for interpolating feature expansion, default=300 is usually fine 28 | qmax=300, 29 | # lambda parameter for interpolating features. default=1.8 is usually fine. 30 | # Lower lambd is more precise 31 | lambd=1.8, 32 | # pasdw_store_funcs=False (default) saves memory. True reduces cost 33 | pasdw_store_funcs=False, 34 | # pasdw_ovlp_fit=True (default) uses overlap fitting to improve precision 35 | # of PAW correction terms of features. Usually not needed. 36 | pasdw_ovlp_fit=False, 37 | ) 38 | 39 | # Using CiderGPAW instead of the default GPAW calculator allows calculations 40 | # to be restarted. Calculations using GPAW (rather than CiderGPAW) 41 | # will run with CIDER functionals but cannot be saved and loaded properly. 42 | atoms.calc = CiderGPAW( 43 | # use a reasonably small grid spacing 44 | h=0.18, 45 | # assign the CIDER functional to xc 46 | xc=xc, 47 | # plane-wave mode with 520 eV cutoff 48 | mode=PW(520), 49 | # output file, '-' for stdout 50 | txt="-", 51 | # Fermi smearing with 0.01 eV width 52 | occupations={"name": "fermi-dirac", "width": 0.01}, 53 | # kpt mesh parameters 54 | kpts={"size": (4, 4, 4), "gamma": False}, 55 | # convergence energy in eV/electron 56 | convergence={"energy": 1e-5}, 57 | # Set augments_grids=True for CIDER functionals to parallelize 58 | # XC energy and potential evaluation more effectively 59 | parallel={"augment_grids": True}, 60 | # Customize the mixer object if desired. 61 | mixer=Mixer(0.7, 8, 50), 62 | # Turn spin polarization on or off. 63 | spinpol=False, 64 | ) 65 | 66 | # If desired, make a low-symmetry cell for testing purposes. 67 | if MODIFY_CELL: 68 | atoms.set_cell( 69 | np.dot(atoms.cell, [[1.02, 0, 0.03], [0, 0.99, -0.02], [0.2, -0.01, 1.03]]), 70 | scale_atoms=True, 71 | ) 72 | 73 | # run the calculation 74 | etot = atoms.get_potential_energy() 75 | -------------------------------------------------------------------------------- /examples/pyscf/compute_ae.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from collections import Counter 3 | 4 | import ase 5 | from ase import Atoms 6 | from ase.data import chemical_symbols, ground_state_magnetic_moments 7 | from pyscf import dft, gto, scf 8 | from pyscf.pbc.tools.pyscf_ase import atoms_from_ase 9 | 10 | from ciderpress.pyscf.dft import make_cider_calc 11 | 12 | """ 13 | This script demonstrates running a CIDER calculation with accelerated 14 | nonlocal feature evaluation. Example commands: 15 | 16 | python examples/pyscf/fast_cider.py 17 | python examples/pyscf/fast_cider.py H2 0 0 PBE 18 | python examples/pyscf/fast_cider.py O2 0 2 CIDER_NL_MGGA 19 | 20 | is a chemical formula string like CH4, H2, etc. It must be included 21 | in the list of molecules supported by ase.build.molecule() 22 | 23 | is the integer charge of the system. 24 | 25 | is the integer spin of the system 2S. 26 | 27 | is the functional name. It can be the name of a libxc functional, 28 | or it can be the name of a functional in the functionals/ directory, in which case 29 | the corresponding example CIDER functional is run with the PBE0/CIDER 30 | surrogate hybrid functional form. If a path to a joblib file is given, that 31 | file will be read assuming it is a CIDER functional. 32 | 33 | At the end, prints out the total energy of the molecule and its atomization energy 34 | in Ha and eV, then saves the atomization energy in eV to aeresult.txt. 35 | """ 36 | 37 | name, charge, spin, functional = sys.argv[1:5] 38 | charge = int(charge) 39 | spin = int(spin) 40 | 41 | spinpol = True if spin > 0 else False 42 | BAS = "def2-qzvppd" 43 | if name == "HF_stretch": 44 | BAS = "def2-svp" 45 | atoms = Atoms(symbols=["H", "F"], positions=[[0, 0, 0], [0, 0, 1.1]]) 46 | elif name.startswith("el-"): 47 | el = name[3:] 48 | atoms = Atoms(el) 49 | elif name.endswith(".xyz"): 50 | ismol = True 51 | atoms = ase.io.read(name) 52 | atoms.center(vacuum=4) 53 | else: 54 | ismol = True 55 | from ase.build import molecule 56 | 57 | atoms = molecule(name) 58 | atoms.center(vacuum=4) 59 | 60 | if functional.startswith("CIDER"): 61 | functional = "functionals/{}.yaml".format(functional) 62 | is_cider = True 63 | mlfunc = functional 64 | elif functional.endswith(".joblib"): 65 | is_cider = True 66 | mlfunc = functional 67 | else: 68 | is_cider = False 69 | formula = Counter(atoms.get_atomic_numbers()) 70 | 71 | mol = gto.M( 72 | atom=atoms_from_ase(atoms), basis=BAS, ecp=BAS, spin=spin, charge=charge, verbose=4 73 | ) 74 | 75 | 76 | def run_calc(mol, spinpol): 77 | if spinpol: 78 | ks = dft.UKS(mol) 79 | else: 80 | ks = dft.RKS(mol) 81 | ks = ks.density_fit() 82 | ks.with_df.auxbasis = "def2-universal-jfit" 83 | ks = ks.apply(scf.addons.remove_linear_dep_) 84 | if is_cider: 85 | ks = make_cider_calc( 86 | ks, 87 | functional, 88 | xmix=0.25, 89 | xkernel="GGA_X_PBE", 90 | ckernel="GGA_C_PBE", 91 | ) 92 | else: 93 | ks.xc = functional 94 | ks.grids.level = 3 95 | ks = ks.apply(scf.addons.remove_linear_dep_) 96 | etot = ks.kernel() 97 | return etot 98 | 99 | 100 | if spin == 0: 101 | spinpol = False 102 | else: 103 | spinpol = True 104 | 105 | etot_mol = run_calc(mol, spinpol) 106 | etot_ae = -1 * etot_mol 107 | 108 | for Z, count in formula.items(): 109 | atom = gto.M( 110 | atom=chemical_symbols[Z], 111 | basis=BAS, 112 | ecp=BAS, 113 | spin=int(ground_state_magnetic_moments[Z]), 114 | verbose=4, 115 | ) 116 | etot_atom = run_calc(atom, True) 117 | etot_ae += count * etot_atom 118 | 119 | print("Total and Atomization Energies, Ha") 120 | print(etot_mol, etot_ae) 121 | eh2ev = 27.211399 122 | print("Total and Atomization Energies, eV") 123 | print(etot_mol * eh2ev, etot_ae * eh2ev) 124 | with open("aeresult.txt", "w") as f: 125 | f.write(str(etot_ae * eh2ev)) 126 | -------------------------------------------------------------------------------- /examples/pyscf/simple_calc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import sys 22 | 23 | from pyscf import dft, gto 24 | 25 | from ciderpress.pyscf.dft import make_cider_calc 26 | 27 | # This is a simple example for running a PySCF calculation with 28 | # a CIDER functional. 29 | # This example runs a "surrogate" PBE0 calculation, where a CIDER exchange 30 | # functional is used in place of exact exchange. 31 | # It takes one command line argument, which is the functional to use. 32 | # For example, you could use "CIDER23X_NL_MGGA_DTR" or "CIDER23X_SL_GGA". 33 | 34 | mlfunc = "functionals/{}.yaml".format(sys.argv[1]) 35 | 36 | mol = gto.M( 37 | atom="F 0.0 0.0 0.0; F 0.0 0.0 1.42", 38 | basis="def2-tzvp", 39 | ) 40 | 41 | ks = dft.RKS(mol) 42 | ks = make_cider_calc( 43 | # KohnShamDFT object 44 | ks, 45 | # MappedXC, MappedXC2, or path to yaml/joblib file with one of these classes 46 | mlfunc, 47 | # Semi-local exchange and correlation parts 48 | xkernel="GGA_X_PBE", 49 | ckernel="GGA_C_PBE", 50 | # exact exchange mixing parameter 51 | xmix=0.25, 52 | ) 53 | ks = ks.density_fit() 54 | ks.with_df.auxbasis = "def2-universal-jfit" 55 | ks.kernel() 56 | -------------------------------------------------------------------------------- /examples/pyscf/simple_sdmx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | 22 | from pyscf import dft, gto 23 | 24 | from ciderpress.pyscf.dft import make_cider_calc 25 | 26 | # This is a simple example for running a PySCF calculation with 27 | # a CIDER functional. 28 | # This is the same as the other example but runs the CIDER24Xe 29 | # exchange functional, which is fit to HOMO-LUMO gaps as well as energetic 30 | # data. 31 | 32 | mlfunc = "functionals/CIDER24Xe.yaml" 33 | 34 | mol = gto.M( 35 | atom="Cl 0.0 0.0 0.0; Cl 0.0 0.0 1.6", 36 | basis="def2-tzvp", 37 | ) 38 | 39 | ks = dft.RKS(mol) 40 | ks = make_cider_calc( 41 | # KohnShamDFT object 42 | ks, 43 | # MappedXC, MappedXC2, or path to yaml/joblib file with one of these classes 44 | mlfunc, 45 | # Semi-local exchange and correlation parts 46 | xkernel="GGA_X_PBE", 47 | ckernel="GGA_C_PBE", 48 | # exact exchange mixing parameter 49 | xmix=0.25, 50 | ) 51 | ks = ks.density_fit() 52 | ks.with_df.auxbasis = "def2-universal-jfit" 53 | ks.kernel() 54 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools >= 61.0", "wheel", "cmake<3.31"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | ["project"] 6 | name = "ciderpress" 7 | dynamic = ["version"] 8 | description = "CiderPress: DFT Calculations with Machine-Learned XC Functionals" 9 | readme = "README.md" 10 | classifiers = [ 11 | "Development Status :: 3 - Alpha", 12 | 'Intended Audience :: Science/Research', 13 | 'Intended Audience :: Developers', 14 | 'Programming Language :: C', 15 | 'Programming Language :: Python', 16 | 'Topic :: Scientific/Engineering', 17 | 'Operating System :: POSIX', 18 | 'Operating System :: Unix', 19 | ] 20 | 21 | maintainers = [{ name = "Kyle Bystrom", email = "kylebystrom@gmail.com" }] 22 | 23 | authors = [{ name = "Kyle Bystrom", email = "kylebystrom@gmail.com" }] 24 | 25 | dependencies = [ 26 | "ase>=3.22.0", 27 | "h5py>=3.6.0", 28 | "interpolation>=2.2.7", 29 | "numba>=0.60", 30 | "numpy>=1.20", 31 | "pyscf>=2.6", 32 | "pytest", 33 | "pyyaml", 34 | "scikit-learn>=1.0.1", 35 | "scipy>=1.12", 36 | "sympy", 37 | ] 38 | 39 | [project.urls] 40 | Repository = "https://github.com/mir-group/CiderPress" 41 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | addopts = --import-mode=importlib 3 | -k "not _high_cost and not _skip" 4 | --ignore=examples 5 | --ignore-glob="*_slow*.py" 6 | --ignore-glob="*gpaw/*.py" 7 | -------------------------------------------------------------------------------- /pytest_mpi.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | addopts = --import-mode=importlib 3 | -k "not _high_cost and not _skip" 4 | --ignore=examples 5 | --ignore-glob="*_slow*.py" 6 | -------------------------------------------------------------------------------- /scripts/download_functionals.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # CiderPress: Machine-learning based density functional theory calculations 3 | # Copyright (C) 2024 The President and Fellows of Harvard College 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with this program. If not, see 17 | # 18 | # Author: Kyle Bystrom 19 | # 20 | 21 | import os 22 | import subprocess 23 | 24 | basedir = __file__ 25 | savedir = os.path.basename(os.path.join(basedir, "../functionals")) 26 | 27 | os.makedirs(savedir, exist_ok=True) 28 | 29 | os.chdir(savedir) 30 | cmd = "wget 'https://zenodo.org/api/records/13336814/files-archive' -O cider_functionals.zip" 31 | unzip = "unzip cider_functionals.zip" 32 | rm = "rm -r cider_functionals.zip" 33 | subprocess.call(cmd, shell=True) 34 | subprocess.call(unzip, shell=True) 35 | subprocess.call(rm, shell=True) 36 | -------------------------------------------------------------------------------- /scripts/generate_etb.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from pyscf.data.elements import ELEMENTS 3 | from pyscf.gto.basis import load 4 | 5 | ZMAX = 118 6 | LMAX = 3 7 | min_data = np.zeros((ZMAX + 1, LMAX + 1), dtype=np.float64) 8 | max_data = np.zeros((ZMAX + 1, LMAX + 1), dtype=np.float64) 9 | for Z in range(1, ZMAX + 1): 10 | symb = ELEMENTS[Z] 11 | print(symb) 12 | # want at least up to d shells 13 | if Z == 1: 14 | basis = "HGBSP2-5" 15 | else: 16 | basis = "HGBSP2-5" 17 | # basis = 'ANO-RCC' 18 | try: 19 | basis = load(basis, symb) 20 | except Exception: 21 | basis = "HGBSP2-5" 22 | basis = load(basis, symb) 23 | try: 24 | basis = basis[symb] 25 | except TypeError: 26 | pass 27 | for lst in basis: 28 | l = lst[0] 29 | if l > 3: 30 | continue 31 | lists = lst[1:] 32 | expnts = [] 33 | for lst in lists: 34 | expnts.append(lst[0]) 35 | min_data[Z, l] = np.min(expnts) 36 | max_data[Z, l] = np.max(expnts) 37 | 38 | np.save("ciderpress/data/expnt_mins.npy", min_data) 39 | np.save("ciderpress/data/expnt_maxs.npy", max_data) 40 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from setuptools import find_packages, setup 5 | from setuptools.command.build_py import build_py 6 | 7 | # TODO not using wheel yet, but plan to do so eventually 8 | from wheel.bdist_wheel import bdist_wheel 9 | 10 | 11 | def get_version(): 12 | topdir = os.path.abspath(os.path.join(__file__, "..")) 13 | with open(os.path.join(topdir, "ciderpress", "__init__.py"), "r") as f: 14 | for line in f.readlines(): 15 | if line.startswith("__version__"): 16 | delim = '"' if '"' in line else "'" 17 | return line.split(delim)[1] 18 | raise ValueError("Version string not found") 19 | 20 | 21 | VERSION = get_version() 22 | 23 | 24 | def get_platform(): 25 | from sysconfig import get_platform 26 | 27 | platform = get_platform() 28 | # TODO might want to add darwin OSX support like PySCF 29 | # but only after officially adding OSX support 30 | return platform 31 | 32 | 33 | class CMakeBuildPy(build_py): 34 | def run(self): 35 | self.plat_name = get_platform() 36 | self.build_base = "build" 37 | self.build_lib = os.path.join(self.build_base, "lib") 38 | self.build_temp = os.path.join(self.build_base, f"temp.{self.plat_name}") 39 | 40 | self.announce("Configuring extensions", level=3) 41 | src_dir = os.path.abspath(os.path.join(__file__, "..", "ciderpress", "lib")) 42 | cmd = [ 43 | "cmake", 44 | f"-S{src_dir}", 45 | f"-B{self.build_temp}", 46 | "-DCMAKE_PREFIX_PATH={}".format(sys.base_prefix), 47 | "-DCMAKE_BUILD_TYPE=Release", 48 | ] 49 | configure_args = os.getenv("CMAKE_CONFIGURE_ARGS") 50 | if configure_args: 51 | cmd.extend(configure_args.split(" ")) 52 | self.spawn(cmd) 53 | 54 | self.announce("Building binaries", level=3) 55 | cmd = ["cmake", "--build", self.build_temp, "-j2"] 56 | build_args = os.getenv("CMAKE_BUILD_ARGS") 57 | if build_args: 58 | cmd.extend(build_args.split(" ")) 59 | if self.dry_run: 60 | self.announce(" ".join(cmd)) 61 | else: 62 | self.spawn(cmd) 63 | self.editable_mode = False 64 | super().run() 65 | 66 | 67 | # NOTE note trying to support wheal yet, but including 68 | # these code block from PySCF setup.py for future. 69 | initialize_options_1 = bdist_wheel.initialize_options 70 | 71 | 72 | def initialize_with_default_plat_name(self): 73 | initialize_options_1(self) 74 | self.plat_name = get_platform() 75 | self.plat_name_supplied = True 76 | 77 | 78 | bdist_wheel.initialize_options = initialize_with_default_plat_name 79 | 80 | # from PySCF setup.py 81 | try: 82 | from setuptools.command.bdist_wheel import bdist_wheel 83 | 84 | initialize_options_2 = bdist_wheel.initialize_options 85 | 86 | def initialize_with_default_plat_name(self): 87 | initialize_options_2(self) 88 | self.plat_name = get_platform() 89 | self.plat_name_supplied = True 90 | 91 | bdist_wheel.initialize_options = initialize_with_default_plat_name 92 | except ImportError: 93 | pass 94 | 95 | setup( 96 | version=VERSION, 97 | include_package_data=True, 98 | packages=find_packages(exclude=["*test*", "*examples*"]), 99 | cmdclass={"build_py": CMakeBuildPy}, 100 | ) 101 | --------------------------------------------------------------------------------