├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yaml │ └── feature_request.yaml └── workflows │ ├── cmake.yml │ ├── coverage.yml │ ├── fpm.yml │ ├── publish-to-test-pypi.yml │ └── python.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .readthedocs.yaml ├── CITATION.cff ├── CMakeLists.txt ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── MANIFEST.in ├── Placement.tar ├── README.md ├── app ├── inputs.f90 ├── main.f90 ├── mod_read_structures.f90 └── mod_rw_vasprun.f90 ├── cmake └── CodeCoverage.cmake ├── conftest.py ├── docs ├── Makefile ├── make.bat ├── requirements.txt └── source │ ├── RAFFLE_logo.pdf │ ├── RAFFLE_logo_no_background.png │ ├── about.rst │ ├── conf.py │ ├── index.rst │ ├── install.rst │ ├── modules.rst │ ├── raffle.distributions.rst │ ├── raffle.distributions_class.rst │ ├── raffle.generator.rst │ ├── raffle.generator_class.rst │ ├── raffle.generator_module.rst │ ├── raffle.geom.rst │ ├── raffle.geom_module.rst │ ├── raffle.geom_rw_class.rst │ ├── references.bib │ └── tutorials │ ├── Si-Ge_tutorial.rst │ ├── aluminium_tutorial.rst │ ├── databases_tutorial.rst │ ├── diamond_tutorial.rst │ ├── generating_tutorial.rst │ ├── graphite_tutorial.rst │ ├── host_tutorial.rst │ ├── index.rst │ ├── parameters_tutorial.rst │ └── quick_guide.rst ├── example ├── data │ ├── C-MgO.xyz │ ├── C-MgO_hosts │ │ ├── POSCAR_10x10_5.4_separation │ │ ├── POSCAR_10x10_6.0A_separation │ │ ├── POSCAR_1x1_5.4A_separation │ │ ├── POSCAR_1x5_orthorhombic_11.0A_separation │ │ ├── POSCAR_2x2_5.4A_separation │ │ ├── POSCAR_2x5_orthorhombic_11.0A_separation │ │ ├── POSCAR_3x3_11.0A_separation │ │ ├── POSCAR_3x3_5.4A_separation │ │ ├── POSCAR_4x4_11.0A_separation │ │ ├── POSCAR_4x4_14.7A_separation │ │ ├── POSCAR_5x1_5.4A_separation │ │ ├── POSCAR_5x1_6.0A_separation │ │ ├── POSCAR_6x6_5.4A_separation │ │ ├── POSCAR_7x7_8.4A_separation │ │ ├── POSCAR_MgO_HEX │ │ └── POSCAR_orthorhombic_11.1A_separation_Mg_seeded │ ├── ScS2-Li.xyz │ ├── Si-Ge.xyz │ ├── Si-Ge_gpaw.xyz │ ├── aluminium.xyz │ ├── carbon.xyz │ └── diamond.xyz ├── fortran_exe │ ├── param.in │ └── run.sh └── python_pkg │ ├── .gitattributes │ ├── Al_learn │ ├── DRAFFLE │ │ ├── DOutput │ │ │ ├── energies_rlxd_seed0.txt │ │ │ ├── energies_unrlxd_seed0.txt │ │ │ ├── rlxd_structures_seed0.traj │ │ │ └── unrlxd_structures_seed0.traj │ │ ├── learn.py │ │ ├── learn_placement.py │ │ ├── pca.ipynb │ │ ├── pca_placement_boa.ipynb │ │ ├── pca_placement_boa_ratios.ipynb │ │ └── pca_placement_order_ratios.ipynb │ ├── DRSS │ │ ├── DOutput │ │ │ ├── rlxd_structures_seed0.traj │ │ │ └── unrlxd_structures_seed0.traj │ │ ├── pca.ipynb │ │ └── rss.py │ ├── known_phases │ │ ├── mp-1183144.vasp │ │ ├── mp-134.vasp │ │ ├── mp-2647008.vasp │ │ └── mp-998860.vasp │ └── learn.py │ ├── BaTiO3 │ └── run.py │ ├── C-MgO │ └── run.py │ ├── C-MgO_learn │ ├── learn.py │ └── pca.ipynb │ ├── C_learn │ ├── DRAFFLE │ │ ├── DOutput │ │ │ ├── energies_rlxd_seed0.txt │ │ │ ├── energies_unrlxd_seed0.txt │ │ │ ├── rlxd_structures_seed0.traj │ │ │ └── unrlxd_structures_seed0.traj │ │ ├── analyse_structures.py │ │ ├── learn.py │ │ └── pca.ipynb │ ├── DRSS │ │ ├── DOutput │ │ │ ├── rlxd_structures_seed0.traj │ │ │ └── unrlxd_structures_seed0.traj │ │ ├── analyse_structures.py │ │ ├── pca.ipynb │ │ └── rss.py │ ├── Dgraphite_diamond │ │ ├── DOutput │ │ │ ├── energies_rlxd_seed0.txt │ │ │ ├── energies_unrlxd_seed0.txt │ │ │ ├── rlxd_structures_seed0.traj │ │ │ └── unrlxd_structures_seed0.traj │ │ ├── graphite.vasp │ │ ├── learn.py │ │ └── pca.ipynb │ └── plot_structures_vs_energies.ipynb │ ├── MoS2_learn │ ├── DRAFFLE │ │ ├── DOutput │ │ │ ├── energies_rlxd_seed0.txt │ │ │ ├── energies_unrlxd_seed0.txt │ │ │ ├── rlxd_structures_seed0.traj │ │ │ └── unrlxd_structures_seed0.traj │ │ ├── learn.py │ │ └── pca.ipynb │ ├── DRSS │ │ ├── DOutput │ │ │ ├── rlxd_structures_seed0.traj │ │ │ └── unrlxd_structures_seed0.traj │ │ ├── pca.ipynb │ │ └── rss.py │ ├── Mo.poscar │ ├── MoS2_H-phase.poscar │ ├── MoS2_T-phase.poscar │ └── S.poscar │ ├── README.md │ ├── ScS2-Li_learn │ ├── DRAFFLE │ │ ├── DOutput │ │ │ ├── energies_rlxd_seed0.txt │ │ │ ├── energies_unrlxd_seed0.txt │ │ │ ├── rlxd_structures_seed0.traj │ │ │ └── unrlxd_structures_seed0.traj │ │ ├── learn.py │ │ └── pca.ipynb │ └── ScS2.vasp │ ├── Si-Ge_learn │ ├── DRAFFLE │ │ ├── DOutput │ │ │ ├── energies_rlxd_seed0.txt │ │ │ ├── energies_unrlxd_seed0.txt │ │ │ ├── rlxd_structures_seed0.traj │ │ │ └── unrlxd_structures_seed0.traj │ │ ├── learn.py │ │ └── pca.ipynb │ ├── Ge_slab.vasp │ ├── SiGe_abrupt_interface.vasp │ └── Si_slab.vasp │ ├── benchmarks │ ├── create_gdfs.py │ ├── cutoff_max.py │ ├── min_placement.py │ ├── placement_methods.py │ └── plot_benchmarks.ipynb │ ├── diamond │ ├── POSCAR_host │ ├── POSCAR_host_3x3 │ └── run.py │ ├── graphite │ ├── POSCAR_host_graphene │ ├── POSCAR_host_graphite_vacancy │ ├── POSCAR_host_missing_layer │ └── run.py │ ├── perovskites │ ├── database.xyz │ └── run.py │ └── requirements.txt ├── ford.md ├── fpm.toml ├── kind_map ├── pyproject.toml ├── src ├── fortran │ ├── lib │ │ ├── mod_constants.f90 │ │ ├── mod_dist_calcs.f90 │ │ ├── mod_distribs.f90 │ │ ├── mod_distribs_container.f90 │ │ ├── mod_distribs_host.f90 │ │ ├── mod_element_utils.f90 │ │ ├── mod_evaluator.f90 │ │ ├── mod_generator.f90 │ │ ├── mod_geom_extd.f90 │ │ ├── mod_geom_rw.f90 │ │ ├── mod_geom_utils.f90 │ │ ├── mod_io_utils.F90 │ │ ├── mod_misc.f90 │ │ ├── mod_misc_linalg.f90 │ │ ├── mod_misc_maths.f90 │ │ ├── mod_place_methods.f90 │ │ ├── mod_tools_infile.f90 │ │ └── mod_viability.f90 │ └── raffle.f90 ├── raffle │ ├── __init__.py │ └── raffle.py └── wrapper │ ├── f90wrap_mod_distribs_container.f90 │ ├── f90wrap_mod_generator.f90 │ ├── f90wrap_mod_geom_rw.f90 │ └── f90wrap_raffle.f90 ├── test ├── CMakeLists.txt ├── data │ └── POSCAR_Si ├── test_dist_calcs.f90 ├── test_distribs_container.f90 ├── test_element_utils.f90 ├── test_evaluator_BTO.f90 ├── test_evaluator_C.f90 ├── test_generator.f90 ├── test_geom_extd.f90 ├── test_geom_rw.f90 ├── test_geom_utils.f90 ├── test_io_utils.f90 ├── test_misc.f90 ├── test_misc_linalg.f90 ├── test_misc_maths.f90 ├── test_place_methods.f90 ├── test_raffle.py ├── test_tools_infile.f90 └── test_viability.f90 └── tools ├── .gitattributes ├── check_accuracy_Al.py ├── check_accuracy_C-MgO.py ├── check_accuracy_C.py ├── check_accuracy_ScS2-Li.py ├── check_accuracy_Si-Ge.py ├── contour_3D.ipynb ├── contour_3D.py ├── coverage_badge.py ├── database.ipynb ├── database.py ├── descriptors.ipynb ├── heatmap_2Dcut.ipynb ├── isosurface.ipynb ├── version_number.py └── visualise_evaluator.py /.github/ISSUE_TEMPLATE/bug_report.yaml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Something is not working 3 | title: "[BUG]" 4 | labels: [bug] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: Description 10 | placeholder: | 11 | A clear and concise description of what the bug is and what the expected behaviour is. 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: reproduction 16 | attributes: 17 | label: Reproduction steps 18 | description: "How do you trigger this bug? If possible, please provide a minimal reproducible example." 19 | placeholder: | 20 | Does the library compile? Is there an issue with a unit test or example? Or is the bug encountered when calling the library? If possible, provide a step-by-step guide: 21 | 1. 22 | 2. 23 | 3. 24 | validations: 25 | required: true 26 | - type: input 27 | id: version 28 | attributes: 29 | label: Version number 30 | description: "What was the latest version (or branch) of RAFFLE is the bug reproducible in?" 31 | placeholder: 1.0.0 32 | validations: 33 | required: true 34 | - type: input 35 | id: compiler 36 | attributes: 37 | label: Fortran compiler 38 | description: "What Fortran compiler (and version) was used?" 39 | placeholder: gfortran version 14.0 40 | validations: 41 | required: true 42 | - type: input 43 | id: platform 44 | attributes: 45 | label: Platform and Architecture 46 | description: "What architecture and operating system was the bug encountered on?" 47 | placeholder: macOS/ARM 10.14 48 | validations: 49 | required: true 50 | - type: checkboxes 51 | id: build 52 | attributes: 53 | label: Build method 54 | description: "What build methods was this issue encountered with?" 55 | options: 56 | - label: fpm 57 | - label: cmake 58 | - label: pip 59 | - type: textarea 60 | id: additional 61 | attributes: 62 | label: Additional information 63 | placeholder: Any further relevant context, i.e. screenshots, links to other issues, version number of build method. 64 | validations: 65 | required: false -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yaml: -------------------------------------------------------------------------------- 1 | name: Feature Proposal 2 | description: Suggest new functionality for RAFFLE 3 | title: "[PROPOSAL]" 4 | labels: [enhancement] 5 | body: 6 | - type: textarea 7 | id: reasoning 8 | attributes: 9 | label: Reasoning 10 | placeholder: | 11 | Provide clear reasoning why the proposed functionality should be added to the RAFFLE library. 12 | validations: 13 | required: true 14 | - type: textarea 15 | id: prior_art 16 | attributes: 17 | label: Prior Art 18 | placeholder: | 19 | Provide examples of where this has been implemented for machine learning before to help justify its presence in this library. 20 | validations: 21 | required: false 22 | - type: textarea 23 | id: additional 24 | attributes: 25 | label: Additional information 26 | placeholder: | 27 | Add any other context or screenshots about the feature request here. 28 | validations: 29 | required: false -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: run-code-coverage 2 | 3 | on: 4 | push: 5 | branches: 6 | - "main" 7 | paths: 8 | - ".github/workflows/coverage.yml" 9 | - "CMakeLists.txt" 10 | - "**.f90" 11 | - "**.F90" 12 | - "**.cmake" 13 | pull_request: 14 | branches: 15 | - "main" 16 | types: 17 | - opened 18 | - synchronize 19 | paths: 20 | - ".github/workflows/coverage.yml" 21 | - "CMakeLists.txt" 22 | - "**.f90" 23 | - "**.F90" 24 | - "**.cmake" 25 | workflow_dispatch: 26 | 27 | permissions: 28 | contents: read 29 | pages: write 30 | id-token: write 31 | 32 | concurrency: 33 | group: pages 34 | cancel-in-progress: false 35 | 36 | jobs: 37 | run-code-coverage: 38 | # permissions: 39 | # contents: write 40 | environment: 41 | name: github-pages 42 | url: ${{ steps.deployment.outputs.page_url }} 43 | runs-on: ubuntu-latest 44 | strategy: 45 | fail-fast: false 46 | matrix: 47 | compiler: [gcc] 48 | version: [13] 49 | steps: 50 | - name: checkout repo 51 | uses: actions/checkout@v4 52 | 53 | - name: actions-setup-cmake 54 | uses: jwlawson/actions-setup-cmake@v2 55 | with: 56 | cmake-version: '3.24.x' 57 | 58 | - uses: fortran-lang/setup-fortran@v1 59 | id: setup-fortran 60 | with: 61 | compiler: ${{ matrix.compiler }} 62 | version: ${{ matrix.version }} 63 | 64 | - name: Install gcovr 65 | run: | 66 | pip --version 67 | pip install gcovr 68 | 69 | - name: Build project 70 | run: | 71 | sudo apt-get update 72 | sudo apt-get install -y cmake make 73 | cmake --version 74 | mkdir -p build 75 | cd build 76 | cmake -DCMAKE_BUILD_TYPE=Coverage -DBUILD_PYTHON=Off -DBUILD_EXECUTABLE=Off .. 77 | make 78 | 79 | - name: Run coverage tests 80 | run: | 81 | cd build 82 | env CTEST_OUTPUT_ON_FAILURE=1 make coverage 83 | 84 | - name: Get coverage percentage 85 | run: | 86 | pip install bs4 87 | echo "COVERAGE_PERCENTAGE="$(python ./tools/coverage_badge.py) >> $GITHUB_ENV 88 | 89 | - name: Create coverage badge 90 | uses: schneegans/dynamic-badges-action@v1.7.0 91 | with: 92 | auth: ${{ secrets.GIST_SECRET }} 93 | gistID: 48f14ebb5636b54d3813e4b4494903eb 94 | filename: raffle_coverage_${{ github.head_ref || github.ref_name }}.json # Use branch-specific file 95 | label: Coverage 96 | message: ${{ env.COVERAGE_PERCENTAGE }}% 97 | valColorRange: ${{ env.COVERAGE_PERCENTAGE }} 98 | maxColorRange: 100 99 | minColorRange: 0 100 | 101 | - name: upload artifact 102 | uses: actions/upload-pages-artifact@v3 103 | with: 104 | path: './build/coverage/' 105 | 106 | deploy: 107 | environment: 108 | name: github-pages 109 | url: ${{ steps.deployment.outputs.page_url }} 110 | runs-on: ubuntu-latest 111 | needs: run-code-coverage 112 | if: ${{ github.ref == 'refs/heads/main' }} 113 | steps: 114 | - name: deploy to Github Pages (main branch) 115 | id: deployment 116 | uses: actions/deploy-pages@v4 117 | 118 | # - name: deploy to Github Pages (development branch) 119 | # if: ${{ github.ref != 'refs/heads/main' }} 120 | # uses: peaceiris/actions-gh-pages@v4 121 | # with: 122 | # publish_dir: ./build/coverage/ 123 | # github_token: ${{ secrets.GITHUB_TOKEN }} 124 | # destination_dir: development-branch/ -------------------------------------------------------------------------------- /.github/workflows/fpm.yml: -------------------------------------------------------------------------------- 1 | name: run-fpm-build 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | - development 8 | types: 9 | - opened 10 | - synchronize 11 | paths: 12 | - ".github/workflows/fpm.yml" 13 | - "fpm.toml" 14 | - "**.f90" 15 | - "**.F90" 16 | workflow_dispatch: 17 | 18 | permissions: 19 | contents: read 20 | pages: write 21 | id-token: write 22 | 23 | concurrency: 24 | group: fpm 25 | cancel-in-progress: false 26 | 27 | jobs: 28 | build-and-test-fpm-debug: 29 | environment: 30 | name: github-pages 31 | name: Build and test in debug mode 32 | runs-on: ubuntu-latest 33 | strategy: 34 | fail-fast: false 35 | matrix: 36 | os: [ubuntu-latest, macos-latest] 37 | toolchain: 38 | - {compiler: gcc, version: 13} 39 | - {fortran-compiler: gcc, fc-version: 14} 40 | # - {compiler: intel, version: '2024.1'} 41 | # - {compiler: intel-classic, version: '2021.10'} 42 | # exclude: 43 | # - os: macos-latest 44 | # toolchain: {compiler: intel, version: '2024.1'} 45 | # - os: macos-latest 46 | # toolchain: {compiler: intel-classic, version: '2021.10'} 47 | steps: 48 | - name: checkout repo 49 | uses: actions/checkout@v4 50 | 51 | - uses: fortran-lang/setup-fortran@v1 52 | id: setup-fortran 53 | with: 54 | compiler: ${{ matrix.toolchain.compiler }} 55 | version: ${{ matrix.toolchain.version }} 56 | 57 | - uses: fortran-lang/setup-fpm@v5 58 | id: setup-fpm 59 | with: 60 | fpm-version: "v0.10.0" 61 | 62 | - name: Install OpenMP runtime (Linux only) 63 | if: runner.os == 'Linux' 64 | run: sudo apt-get update && sudo apt-get install -y libgomp1 65 | 66 | - name: Compile 67 | run: | 68 | ${{ env.FC }} --version 69 | fpm build --profile debug --compiler ${{ env.FC }} 70 | 71 | - name: Test 72 | run: | 73 | ${{ env.FC }} --version 74 | fpm test --profile debug --compiler ${{ env.FC }} 75 | 76 | build-and-test-fpm-release: 77 | name: Build and test in release mode 78 | environment: 79 | name: github-pages 80 | runs-on: ubuntu-latest 81 | strategy: 82 | fail-fast: false 83 | matrix: 84 | os: [ubuntu-latest, macos-latest] 85 | toolchain: 86 | - {compiler: gcc, version: 13} 87 | # - {compiler: intel, version: '2024.1'} 88 | # - {compiler: intel-classic, version: '2021.10'} 89 | # exclude: 90 | # - os: macos-latest 91 | # toolchain: {compiler: intel, version: '2024.1'} 92 | # - os: macos-latest 93 | # toolchain: {compiler: intel-classic, version: '2021.10'} 94 | 95 | steps: 96 | - name: checkout repo 97 | uses: actions/checkout@v4 98 | 99 | - uses: fortran-lang/setup-fortran@v1 100 | id: setup-fortran 101 | with: 102 | compiler: ${{ matrix.toolchain.compiler }} 103 | version: ${{ matrix.toolchain.version }} 104 | 105 | - uses: fortran-lang/setup-fpm@v5 106 | id: setup-fpm 107 | with: 108 | fpm-version: "v0.10.0" 109 | 110 | - name: Install OpenMP runtime (Linux only) 111 | if: runner.os == 'Linux' 112 | run: sudo apt-get update && sudo apt-get install -y libgomp1 113 | 114 | - name: Compile 115 | run: | 116 | ${{ env.FC }} --version 117 | fpm build --profile release --compiler ${{ env.FC }} 118 | 119 | - name: Test 120 | run: | 121 | ${{ env.FC }} --version 122 | fpm test --profile release --compiler ${{ env.FC }} 123 | -------------------------------------------------------------------------------- /.github/workflows/python.yml: -------------------------------------------------------------------------------- 1 | name: run-python-build 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | - development 8 | types: 9 | - opened 10 | - synchronize 11 | paths: 12 | - ".github/workflows/python.yml" 13 | - "CMakeLists.txt" 14 | - "pyproject.toml" 15 | - "src/*.py" 16 | - "**.f90" 17 | - "**.F90" 18 | workflow_dispatch: 19 | 20 | permissions: 21 | contents: read 22 | pages: write 23 | id-token: write 24 | 25 | concurrency: 26 | group: python 27 | cancel-in-progress: false 28 | 29 | jobs: 30 | build-and-test-python: 31 | environment: 32 | name: github-pages 33 | name: Build and test in debug mode 34 | runs-on: ${{ matrix.os }} 35 | strategy: 36 | fail-fast: false 37 | matrix: 38 | os: [ubuntu-latest, macos-latest] 39 | python-version: [ "3.11", "3.12", "3.13" ] 40 | toolchain: 41 | - {fortran-compiler: gcc, fc-version: 14} 42 | build_type: [Serial, Release] 43 | 44 | steps: 45 | - name: checkout repo 46 | uses: actions/checkout@v4 47 | 48 | - name: actions-setup-python ${{ matrix.python-version }} 49 | uses: actions/setup-python@v5 50 | with: 51 | python-version: ${{ matrix.python-version }} 52 | 53 | - name: actions-setup-cmake 54 | uses: jwlawson/actions-setup-cmake@v2.0.1 55 | with: 56 | cmake-version: '3.24.x' 57 | 58 | - uses: fortran-lang/setup-fortran@v1 59 | id: setup-fortran 60 | with: 61 | compiler: ${{ matrix.toolchain.fortran-compiler }} 62 | version: ${{ matrix.toolchain.fc-version }} 63 | 64 | - name: Install python dependencies 65 | run: | 66 | python --version 67 | python -m pip install pip-tools 68 | python -m pip install pytest 69 | python -m pip install parameterized 70 | python -m piptools compile -o requirements.txt pyproject.toml --all-build-deps 71 | python -m pip install -r requirements.txt 72 | 73 | - name: Install OpenMP runtime (Linux only) 74 | if: runner.os == 'Linux' 75 | run: sudo apt-get update && sudo apt-get install -y libgomp1 76 | 77 | - name: Build and install Python package with CMAKE_BUILD_TYPE=${{ matrix.build_type }} 78 | env: 79 | CMAKE_BUILD_TYPE: ${{ matrix.build_type }} 80 | run: | 81 | cmake --version 82 | echo "Building with CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" 83 | python -m pip install ".[ase]" --config-settings="cmake.define.CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" 84 | 85 | - name: Run tests 86 | run: | 87 | ${{ env.FC }} --version 88 | python -m pytest 89 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | \# 3 | bin/ 4 | obj/ 5 | *.mod 6 | *.smod 7 | *.so 8 | *.txt 9 | DTESTING/ 10 | DTEST/ 11 | build/ 12 | src/*.egg-info 13 | *.egg-info 14 | iteration* 15 | doc/html 16 | docs/html 17 | settings.json 18 | example/**/database*.xyz 19 | **/POSCAR* 20 | iteration/ 21 | *.traj 22 | *.png 23 | *.param 24 | fort.* 25 | *.o 26 | *.out 27 | *.dat 28 | *.err 29 | *.e 30 | *.log 31 | *.agr 32 | *.pdf 33 | *.eps 34 | *.pyc 35 | *.xyz 36 | .coverage 37 | *CAR 38 | *.pckl 39 | .DS_Store 40 | fortranobject.c* 41 | *.db 42 | CHG 43 | EIGENVAL 44 | IBZKPT 45 | KPOINTS 46 | PCDAT 47 | REPORT 48 | vasprun.xml 49 | DVASP_MACE_comparison/ 50 | pca_model*.pkl 51 | .benchmarks/ 52 | .local-pre-commit-config.yaml 53 | *.tgz 54 | .ipynb_checkpoints 55 | *.model 56 | *.vasp -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v5.0.0 # Use the ref you want to point at 4 | hooks: 5 | - id: trailing-whitespace 6 | - id: end-of-file-fixer 7 | - repo: https://github.com/nedtaylor/fortran-format-hooks 8 | rev: e757850a2edabf0c06326ea18acc8125d12054ec 9 | hooks: 10 | - id: check-fortran-indentation 11 | args: [--line-length=80, --ignore-directories 'src/wrapper'] 12 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the OS, Python version and other tools you might need 9 | build: 10 | os: ubuntu-22.04 11 | tools: 12 | python: "3.12" 13 | # You can also specify other tool versions: 14 | # nodejs: "19" 15 | # rust: "1.64" 16 | # golang: "1.19" 17 | 18 | # Build documentation in the "docs/" directory with Sphinx 19 | sphinx: 20 | configuration: docs/source/conf.py 21 | 22 | # Optionally build your docs in additional formats such as PDF and ePub 23 | # formats: 24 | # - pdf 25 | # - epub 26 | 27 | # Optional but recommended, declare the Python requirements required 28 | # to build your documentation 29 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 30 | python: 31 | install: 32 | - requirements: docs/requirements.txt -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | # This CITATION.cff file was generated with cffinit. 2 | # Visit https://bit.ly/cffinit to generate yours today! 3 | 4 | cff-version: 1.2.0 5 | title: >- 6 | RAFFLE: pseudoRandom Approach For Finding Local Energy 7 | minima 8 | message: >- 9 | If you use this software, please cite it using the 10 | metadata from this file and the following paper: 11 | https://link.aps.org/doi/10.1103/PhysRevLett.132.066201 12 | type: software 13 | authors: 14 | - given-names: Ned Thaddeus 15 | family-names: Taylor 16 | orcid: 'https://orcid.org/0000-0002-9134-9712' 17 | affiliation: University of Exeter 18 | - given-names: Joe 19 | family-names: Pitfield 20 | orcid: 'https://orcid.org/0000-0002-9758-5230' 21 | affiliation: Aarhus Universitet 22 | - given-names: Steven Paul 23 | family-names: Hepplestone 24 | orcid: 'https://orcid.org/0000-0002-2528-1270' 25 | affiliation: University of Exeter 26 | repository-code: 'https://github.com/ExeQuantCode/RAFFLE' 27 | keywords: 28 | - materials science 29 | - interfaces 30 | - material interfaces 31 | - structure prediction 32 | - random structure search 33 | license: GPL-3.0 34 | commit: 1a4e7aacf07b4d9623d846df30aa7ac3a5e98e81 35 | version: 1.0.0 36 | date-released: '2025-03-03' 37 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct - RAFFLE 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to make participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to a positive environment for our 15 | community include: 16 | 17 | * Demonstrating empathy and kindness toward other people 18 | * Being respectful of differing opinions, viewpoints, and experiences 19 | * Giving and gracefully accepting constructive feedback 20 | * Accepting responsibility and apologising to those affected by our mistakes, 21 | and learning from the experience 22 | * Focusing on what is best not just for us as individuals, but for the 23 | overall community 24 | 25 | Examples of unacceptable behavior include: 26 | 27 | * The use of sexualised language or imagery, and sexual attention or 28 | advances 29 | * Trolling, insulting or derogatory comments, and personal or political attacks 30 | * Public or private harassment 31 | * Publishing others' private information, such as a physical or email 32 | address, without their explicit permission 33 | * Other conduct which could reasonably be considered inappropriate in a 34 | professional setting 35 | 36 | ## Our Responsibilities 37 | 38 | Project maintainers are responsible for clarifying and enforcing our standards of 39 | acceptable behavior and will take appropriate and fair corrective action in 40 | response to any instances of unacceptable behavior. 41 | 42 | Project maintainers have the right and responsibility to remove, edit, or reject 43 | comments, commits, code, wiki edits, issues, and other contributions that are 44 | not aligned to this Code of Conduct, or to ban 45 | temporarily or permanently any contributor for other behaviors that they deem 46 | inappropriate, threatening, offensive, or harmful. 47 | 48 | ## Scope 49 | 50 | This Code of Conduct applies within all community spaces, and also applies when 51 | an individual is officially representing the community in public spaces. 52 | Examples of representing our community include using an official e-mail address, 53 | posting via an official social media account, or acting as an appointed 54 | representative at an online or offline event. 55 | 56 | ## Enforcement 57 | 58 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 59 | reported to the community leaders responsible for enforcement at . 60 | All complaints will be reviewed and investigated promptly and fairly. 61 | 62 | All community leaders are obligated to respect the privacy and security of the 63 | reporter of any incident. 64 | 65 | ## Attribution 66 | 67 | This Code of Conduct is adapted from the [Contributor Covenant](https://contributor-covenant.org/), version 68 | [1.4](https://www.contributor-covenant.org/version/1/4/code-of-conduct/code_of_conduct.md) and 69 | [2.0](https://www.contributor-covenant.org/version/2/0/code_of_conduct/code_of_conduct.md), 70 | and was generated by [contributing-gen](https://github.com/bttger/contributing-gen). 71 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include src/raffle/*.py 2 | -------------------------------------------------------------------------------- /Placement.tar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/Placement.tar -------------------------------------------------------------------------------- /conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | def pytest_addoption(parser): 4 | parser.addoption( 5 | "--fortran-compiler", 6 | action="store", 7 | default="gfortran", # Default compiler 8 | help="Specify the Fortran compiler to use" 9 | ) 10 | 11 | def pytest_configure(config): 12 | # Make the Fortran compiler available globally during tests 13 | compiler = config.getoption("--fortran-compiler") 14 | os.environ["FORTRAN_COMPILER"] = compiler -------------------------------------------------------------------------------- /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 ?= python -m sphinx 8 | SOURCEDIR = source 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/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx==8.1.3 2 | sphinx-rtd-theme==3.0.2 3 | sphinxcontrib-bibtex==2.6.3 4 | f90wrap==0.2.16 5 | -------------------------------------------------------------------------------- /docs/source/RAFFLE_logo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/docs/source/RAFFLE_logo.pdf -------------------------------------------------------------------------------- /docs/source/RAFFLE_logo_no_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/docs/source/RAFFLE_logo_no_background.png -------------------------------------------------------------------------------- /docs/source/about.rst: -------------------------------------------------------------------------------- 1 | .. _about: 2 | 3 | ===== 4 | About 5 | ===== 6 | 7 | 8 | RAFFLE (pseudoRandom Approach For Finding Local Energetic minima) is a package for structural prediction applied to material interfaces. 9 | RAFFLE can interface with the `Atomic Simulation Environment (ASE) `_. 10 | 11 | RAFFLE is both a Fortran and a Python library, with the option of a Fortran executable. 12 | The code heavily relies on features of Fortran 2018 and above, so there is no backwards compatibility with Fortran95. 13 | 14 | The library enables users to fill a host structure with additional atoms, where placement of those atoms is determined by a set of placement methods. 15 | These methods are meant to bias towards energetically favourable configurations, whilst still providing a thorough search of the configuration space. -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | 3 | # -- Project information 4 | import datetime 5 | import os 6 | import sys 7 | 8 | from unittest.mock import Mock 9 | 10 | MOCK_MODULES = ["raffle._raffle"] # List any other modules if needed 11 | sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES) 12 | 13 | # sys.path.insert(0, os.path.abspath(os.path.join('..', '..', 'src', 'raffle'))) # Sets the base path to find your modules 14 | sys.path.insert(0, os.path.abspath(os.path.join('..', '..', 'src'))) # Sets the base path to find your modules 15 | 16 | project = 'RAFFLE' 17 | copyright = f'{datetime.date.today().year}, RAFFLE-developers' 18 | # release = '1.0' 19 | # version = '1.0.0' 20 | 21 | # -- General configuration 22 | master_doc = 'index' 23 | 24 | extensions = [ 25 | 'sphinx.ext.duration', 26 | 'sphinx.ext.doctest', 27 | 'sphinx.ext.autodoc', 28 | 'sphinx.ext.autosummary', 29 | 'sphinx.ext.intersphinx', 30 | 'sphinxcontrib.bibtex', 31 | 'sphinx.ext.napoleon', 32 | 'sphinx.ext.viewcode', 33 | 'sphinx_rtd_theme', 34 | ] 35 | 36 | intersphinx_mapping = { 37 | 'python': ('https://docs.python.org/3/', None), 38 | 'sphinx': ('https://www.sphinx-doc.org/en/master/', None), 39 | } 40 | intersphinx_disabled_domains = ['std'] 41 | 42 | templates_path = ['_templates'] 43 | 44 | exclude_patterns = ['_build', '.DS_Store', 'build'] 45 | 46 | 47 | # -- Options for HTML output 48 | 49 | html_theme = 'sphinx_rtd_theme' 50 | 51 | # -- Options for EPUB output 52 | epub_show_urls = 'footnote' 53 | 54 | html_logo = "RAFFLE_logo_no_background.png" 55 | # html_favicon = 'favicon.ico' 56 | html_theme_options = { 57 | 'logo_only': False, 58 | 'prev_next_buttons_location': 'bottom', 59 | 'style_external_links': False, 60 | 'vcs_pageview_mode': '', 61 | # 'style_nav_header_background': 'white', 62 | 'flyout_display': 'hidden', 63 | 'version_selector': True, 64 | 'language_selector': True, 65 | # Toc options 66 | 'collapse_navigation': True, 67 | 'sticky_navigation': True, 68 | 'navigation_depth': 4, 69 | 'includehidden': True, 70 | 'titles_only': False, 71 | } 72 | 73 | 74 | html_context = { 75 | "display_github": True, 76 | "github_repo": "RAFFLE", 77 | "github_user": "ExeQuantCode", 78 | "github_version": "main", 79 | "conf_py_path": "/docs/source/", 80 | } 81 | 82 | autoclass_content="both" 83 | 84 | bibtex_bibfiles = ['references.bib'] 85 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | ====== 2 | RAFFLE 3 | ====== 4 | 5 | RAFFLE (pseudoRandom Approach For Finding Local Energetic minima) is a Python and Fortran package for structure prediction applied to interfaces. 6 | RAFFLE can be utilised as a Python package, a Fortran library, or a standalone Fortran executable. 7 | The Python package provides a high-level interface to the Fortran library, which contains the core functionality. 8 | 9 | The Python package interfaces seemlessly with `ASE (Atomic Simulation Environment) `_, allowing for easy reading, writing, and manipulation of atomic structures. 10 | Although the package comes with a built-in atomic structure reader and writer, it is recommended to use ASE due to its greater functionality and wide-reaching support. 11 | 12 | The code is provided freely available under the `GNU General Public License v3.0 `_. 13 | 14 | An example 15 | 16 | .. code-block:: python 17 | 18 | # A simple example of how to use RAFFLE to generate 10 structures of diamond and write them to a single file 19 | from ase import Atoms 20 | from ase.io import write 21 | from ase.calculators.singlepoint import SinglePointCalculator 22 | from raffle.generator import raffle_generator 23 | from mace.calculators import mace_mp 24 | 25 | generator = raffle_generator() 26 | 27 | calc = mace_mp(model="medium", dispersion=False, default_dtype="float32", device='cpu') 28 | 29 | host = Atoms('C', positions=[[0, 0, 0]], cell=[10, 10, 10]) 30 | host.calc = calc 31 | generator.set_host(host) 32 | 33 | generator.distributions.set_element_energies( { 'C': 0.0 } ) 34 | generator.distributions.create(host) 35 | 36 | num_structures_old = 0 37 | for i in range(10): 38 | generator.generate( 39 | num_structures = 2, 40 | stoichiometry = { 'C': 7 } 41 | ) 42 | structures = generator.get_structures(calc) 43 | generator.distributions.update(structures[num_structures_old:]) 44 | num_structures_old = len(structures) 45 | 46 | structures = generator.get_structures(calc) 47 | for structure in structures: 48 | structure.calc = SinglePointCalculator( 49 | structure, 50 | energy=structure.get_potential_energy(), 51 | forces=structure.get_forces() 52 | ) 53 | 54 | write('structures.traj', structures) 55 | 56 | .. toctree:: 57 | :maxdepth: 3 58 | :caption: Contents: 59 | 60 | about 61 | install 62 | tutorials/index 63 | Python API 64 | 65 | .. Indices and tables 66 | .. ================== 67 | 68 | .. * :ref:`genindex` 69 | .. * :ref:`modindex` 70 | .. * :ref:`search` -------------------------------------------------------------------------------- /docs/source/modules.rst: -------------------------------------------------------------------------------- 1 | raffle 2 | ====== 3 | 4 | .. Submodules 5 | .. ---------- 6 | 7 | .. raffle.raffle module 8 | .. -------------------- 9 | 10 | .. .. automodule:: raffle.raffle 11 | .. :members: 12 | .. :undoc-members: 13 | .. :show-inheritance: 14 | 15 | Module contents 16 | --------------- 17 | 18 | RAFFLE is a python package for performing structure prediction at interfaces. 19 | The package provides functionality for generating atomic structures by filling in host structures with additional atoms. 20 | The method involves iteratively generating structures and learning the energetically favourable features of the structures (see https://link.aps.org/doi/10.1103/PhysRevLett.132.066201). 21 | The package is built to accommodate energetic and structure data provided by the Atomic Simulation Environment (ASE) package (https://wiki.fysik.dtu.dk/ase/). 22 | 23 | Submodules 24 | ---------- 25 | 26 | .. toctree:: 27 | :maxdepth: 2 28 | 29 | raffle.generator_module 30 | raffle.geom_module 31 | 32 | Classes 33 | ------- 34 | 35 | These are the main classes of the package (they are only indirectly accessible): 36 | 37 | .. toctree:: 38 | :maxdepth: 2 39 | 40 | raffle.generator_class 41 | raffle.geom_rw_class 42 | raffle.distributions_class 43 | 44 | .. .. automodule:: raffle 45 | .. :members: 46 | .. :undoc-members: 47 | .. :show-inheritance: 48 | -------------------------------------------------------------------------------- /docs/source/raffle.distributions.rst: -------------------------------------------------------------------------------- 1 | raffle.distributions module 2 | =========================== 3 | 4 | .. .. automodule:: raffle.Raffle__Distribs_Container 5 | .. :members: 6 | .. :undoc-members: 7 | .. :show-inheritance: 8 | 9 | .. autoclass:: raffle.Raffle__Distribs_Container 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | -------------------------------------------------------------------------------- /docs/source/raffle.distributions_class.rst: -------------------------------------------------------------------------------- 1 | raffle.distributions Class 2 | =========================== 3 | 4 | .. .. automodule:: raffle.Raffle__Distribs_Container 5 | .. :members: 6 | .. :undoc-members: 7 | .. :show-inheritance: 8 | 9 | .. autoclass:: raffle.raffle.Raffle__Distribs_Container 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | -------------------------------------------------------------------------------- /docs/source/raffle.generator.rst: -------------------------------------------------------------------------------- 1 | raffle.generator module 2 | ======================= 3 | 4 | .. .. automodule:: raffle.Generator 5 | .. :members: 6 | .. :undoc-members: 7 | .. :show-inheritance: 8 | 9 | 10 | .. autoclass:: raffle.Generator 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: -------------------------------------------------------------------------------- /docs/source/raffle.generator_class.rst: -------------------------------------------------------------------------------- 1 | raffle.Generator Class 2 | ======================= 3 | 4 | .. .. automodule:: raffle.Generator 5 | .. :members: 6 | .. :undoc-members: 7 | .. :show-inheritance: 8 | 9 | .. autoclass:: raffle.raffle.Generator 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: -------------------------------------------------------------------------------- /docs/source/raffle.generator_module.rst: -------------------------------------------------------------------------------- 1 | raffle.generator Module 2 | ======================= 3 | 4 | This is a simulated module that holds the following class: 5 | 6 | - :class:`raffle.Generator()` 7 | 8 | This class cannot be directly accessed, but the two user-facing classes within it can be. 9 | Within this class, there exist two directly accessible sub-classes: 10 | 11 | - :class:`raffle.generator.stoichiometry_array()` 12 | - :class:`raffle.generator.raffle_generator()` 13 | 14 | The documentation for these can be found here: :doc:`raffle.generator_class`. 15 | 16 | Finally, the :class:`raffle.generator.raffle_generator()` contains instances of the following classes: 17 | 18 | - :class:`raffle.Raffle__Distribs_Container()` - raffle.generator.raffle_generator().distributions 19 | - :class:`raffle.Geom_Rw().basis()` - raffle.generator.raffle_generator().host 20 | - :class:`raffle.Geom_Rw().basis_arary()` - raffle.generator.raffle_generator().structures 21 | 22 | 23 | 24 | .. automodule:: raffle.generator 25 | :members: 26 | :undoc-members: 27 | :show-inheritance: 28 | -------------------------------------------------------------------------------- /docs/source/raffle.geom.rst: -------------------------------------------------------------------------------- 1 | raffle.geom_rw module 2 | ======================= 3 | 4 | .. .. automodule:: raffle.Geom_Rw 5 | .. :members: 6 | .. :undoc-members: 7 | .. :show-inheritance: 8 | 9 | .. autoclass:: raffle.Geom_Rw 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | -------------------------------------------------------------------------------- /docs/source/raffle.geom_module.rst: -------------------------------------------------------------------------------- 1 | raffle.geom Module 2 | ======================= 3 | 4 | This is a simulated module that holds the following class: 5 | 6 | - :class:`raffle.Geom_Rw()` 7 | 8 | This class cannot be directly accessed, but the two user-facing classes within it can be. 9 | Within this class, there exist two directly accessible sub-classes: 10 | 11 | - :class:`raffle.geom.basis()` 12 | - :class:`raffle.geom.basis_array()` 13 | 14 | These are used to handle the geometry of the system, where the former is a single instance of the geometry and the latter is an array of instances. 15 | The documentation for these can be found here: :doc:`raffle.geom_rw_class`. 16 | 17 | .. automodule:: raffle.geom 18 | :members: 19 | :undoc-members: 20 | :show-inheritance: 21 | -------------------------------------------------------------------------------- /docs/source/raffle.geom_rw_class.rst: -------------------------------------------------------------------------------- 1 | raffle.Geom_Rw Class 2 | ======================= 3 | 4 | .. .. automodule:: raffle.Geom_Rw 5 | .. :members: 6 | .. :undoc-members: 7 | .. :show-inheritance: 8 | 9 | .. autoclass:: raffle.raffle.Geom_Rw 10 | :members: 11 | :undoc-members: 12 | :show-inheritance: 13 | -------------------------------------------------------------------------------- /docs/source/references.bib: -------------------------------------------------------------------------------- 1 | @article{Christiansen2022AtomisticGlobalOptimization, 2 | title = {Atomistic global optimization {X}: {A Python} package for optimization of atomistic structures}, 3 | volume = {157}, 4 | ISSN = {1089-7690}, 5 | url = {http://dx.doi.org/10.1063/5.0094165}, 6 | DOI = {10.1063/5.0094165}, 7 | number = {5}, 8 | journal = {The Journal of Chemical Physics}, 9 | publisher = {AIP Publishing}, 10 | author = {Christiansen, Mads-Peter V. and Rønne, Nikolaj and Hammer, Bjørk}, 11 | year = {2022}, 12 | month = aug 13 | } 14 | -------------------------------------------------------------------------------- /docs/source/tutorials/Si-Ge_tutorial.rst: -------------------------------------------------------------------------------- 1 | .. si-ge: 2 | 3 | ======================== 4 | Si|Ge interface tutorial 5 | ======================== 6 | 7 | This tutorial will guide you through the process of performing RAFFLE-based structure search for an Si|Ge interface. 8 | 9 | The tutorial is designed to show how a RAFFLE generator given no prior knowledge can learn bonding and statistically available interface configurations. 10 | Statistically available configurations are those that are likely to exist due to energetic values close to the ground state, within thermal and entropy conditions. 11 | 12 | The example script can be found in the following directory: 13 | 14 | .. code-block:: bash 15 | 16 | raffle/example/python_pkg/Si-Ge_learn/learn.py 17 | 18 | We recommend reading through the file and running it to understand the process of learning and generating structures. 19 | However, we will provide a brief overview of the script here. 20 | 21 | First, we must import the required packages: 22 | 23 | .. code-block:: python 24 | 25 | from ase import Atoms 26 | from raffle.generator import raffle_generator 27 | from mace.calculators import mace_mp 28 | import numpy as np 29 | 30 | Next, we need to set up the RAFFLE generator and the calculator to calculate the energies of the structures. 31 | In this example, we use the CHGNet calculator: 32 | 33 | .. code-block:: python 34 | 35 | generator = raffle_generator() 36 | 37 | calc = mace_mp(model="mace-mpa-0-medium.model") 38 | 39 | Note, choice of calculator is important. 40 | The calculator should be valid within and near the chemical environment of the structures being generated; in this case, Si and Ge bonding. 41 | If this is the case, it can accurately identify local minima and provide a good representation of the energy landscape. 42 | For this example, we use the [MACE-MPA-0 calculator](https://github.com/ACEsuit/mace-mp/releases/tag/mace_mpa_0), which, from preliminary testing, has been found to be suitable for Si and Ge bonding. 43 | To use the MACE-MPA-0 calculator, you will need to download the model file from the link provided and place it in the same directory as the script (and install the MACE package using `pip install mace-torch`, version 0.3.10 or later). 44 | The CHGNet calculator was not found to be suitable for Si and Ge interface bonding. 45 | 46 | Then, we need to create the host structure. 47 | Here, an abrupt Si|Ge interface is generated. 48 | This is the base structure that will be added to in order to generate the structures. 49 | A vacuum region of 5.54 Å is set up between the Si and Ge regions, in which the atoms will be placed by RAFFLE. 50 | 51 | .. code-block:: python 52 | 53 | Si_bulk = build.bulk("Si", crystalstructure="diamond", a=5.43) 54 | Si_cubic = build.make_supercell(Si_bulk, [[-1, 1, 1], [1, -1, 1], [1, 1, -1]]) 55 | Ge_bulk = build.bulk("Ge", crystalstructure="diamond", a=5.65) 56 | Ge_cubic = build.make_supercell(Ge_bulk, [[-1, 1, 1], [1, -1, 1], [1, 1, -1]]) 57 | 58 | Si_supercell = build.make_supercell(Si_cubic, [[2, 0, 0], [0, 2, 0], [0, 0, 1]]) 59 | Ge_supercell = build.make_supercell(Ge_cubic, [[2, 0, 0], [0, 2, 0], [0, 0, 1]]) 60 | 61 | Si_surface = build.surface(Si_supercell, indices=(0, 0, 1), layers=2) 62 | Ge_surface = build.surface(Ge_supercell, indices=(0, 0, 1), layers=2) 63 | 64 | host = build.stack(Si_surface, Ge_surface, axis=2, distance= 5.43/2 + 5.65/2) 65 | cell[2, 2] -= 3.8865 66 | host.set_cell(cell, scale_atoms=False) 67 | 68 | 69 | The script then sets parameters for the generator and provides an initial database. 70 | Note, this database only contains prior information of Si-Si and Ge-Ge bonding, and no information about Si-Ge bonding. 71 | This is to demonstrate the ability of RAFFLE to learn from scratch. 72 | 73 | .. code-block:: python 74 | 75 | Si_bulk.calc = calc 76 | Ge_bulk.calc = calc 77 | generator.distributions.set_element_energies( 78 | { 79 | 'Si': Si_bulk.get_potential_energy() / len(Si_bulk), 80 | 'Ge': Ge_bulk.get_potential_energy() / len(Ge_bulk), 81 | } 82 | ) 83 | 84 | # set energy scale 85 | generator.distributions.set_kBT(0.2) 86 | 87 | # set the distribution function widths (2-body, 3-body, 4-body) 88 | generator.distributions.set_width([0.04, np.pi/160.0, np.pi/160.0]) 89 | 90 | # set the initial database 91 | initial_database = [Si_bulk, Ge_bulk] 92 | generator.distributions.create(initial_database) 93 | 94 | Finally, the script generates structures using the generator. 95 | The generator is given the host structures. 96 | Finally, the generator is run for each host structure, providing a unique stoichiometry each time and using a custom method ratio. 97 | The 98 | 99 | .. code-block:: python 100 | 101 | generator.set_host(host) 102 | generator.set_bounds([[0, 0, 0.34], [1, 1, 0.52]]) 103 | for iter in range(40): 104 | # generate the structures 105 | structures, exit_code = generator.generate( 106 | num_structures = 5, 107 | stoichiometry = { 'Si': 16, 'Ge': 16 }, 108 | seed = iter, 109 | method_ratio = {"void": 0.1, "rand": 0.01, "walk": 0.25, "grow": 0.25, "min": 1.0}, 110 | verbose = 0, 111 | calc = calc 112 | ) 113 | generator.distributions.update(structures) 114 | 115 | structures = generator.get_structures() 116 | write('structures.traj', structures) 117 | -------------------------------------------------------------------------------- /docs/source/tutorials/aluminium_tutorial.rst: -------------------------------------------------------------------------------- 1 | .. aluminium: 2 | 3 | ================== 4 | Aluminium tutorial 5 | ================== 6 | 7 | This tutorial will guide you through the process of performing RAFFLE-based structure search for the bulk phases of aluminium. 8 | 9 | The tutorial is designed to show how a RAFFLE generator given no prior knowledge can learn bonding and identify known phases. 10 | This is not an expected use-case of RAFFLE due to its application to a bulk system, but still demonstrates the expected workflow and capabilities. 11 | 12 | The example script can be found in the following directory: 13 | 14 | .. code-block:: bash 15 | 16 | raffle/example/python_pkg/Al_learn/learn.py 17 | 18 | We recommend reading through the file and running it to understand the process of learning and generating structures. 19 | However, we will provide a brief overview of the script here. 20 | 21 | First, we must import the required packages: 22 | 23 | .. code-block:: python 24 | 25 | from ase import Atoms 26 | from raffle.generator import raffle_generator 27 | from chgnet.model import CHGNetCalculator 28 | import numpy as np 29 | 30 | Next, we need to set up the RAFFLE generator and the calculator to calculate the energies of the structures. 31 | In this example, we use the CHGNet calculator: 32 | 33 | .. code-block:: python 34 | 35 | generator = raffle_generator() 36 | 37 | calc = CHGNetCalculator() 38 | 39 | Then, we need to create the host structure. 40 | Here, a set of host cells are generated to represent the multiple potential bulk phases of aluminium. 41 | These are then used to generate the structures. 42 | 43 | .. code-block:: python 44 | 45 | crystal_structures = ['orthorhombic', 'hcp'] 46 | hosts = [] 47 | for crystal_structure in crystal_structures: 48 | for a in np.linspace(3.1, 5.4, num=6): 49 | atom = build.bulk( 50 | name = 'Al', 51 | crystalstructure = crystal_structure, 52 | a = a, b = a, c = a, 53 | ) 54 | hosts.append(Atoms( 55 | 'Al', 56 | positions = [(0, 0, 0)], 57 | cell = atom.get_cell(), 58 | pbc = True, 59 | calculator = calc 60 | )) 61 | 62 | The script then sets parameters for the generator and provides an initial database. 63 | Note, this database is effectively empty, as it only contains a single structure, which is an isolated aluminium atom. 64 | 65 | .. code-block:: python 66 | 67 | initial_database = [Atoms('Al', positions=[(0, 0, 0)], cell=[8, 8, 8], pbc=True)] 68 | initial_database[0].calc = calc 69 | generator.distributions.create(initial_database) 70 | 71 | Finally, the script generates structures using the generator. 72 | The generator is given the host structures. 73 | Finally, the generator is run for each host structure, providing a unique stoichiometry each time and using a custom method ratio. 74 | 75 | .. code-block:: python 76 | 77 | for host in hosts: 78 | generator.set_host(host) 79 | generator.generate( 80 | num_structures = 5, 81 | stoichiometry = { 'Al': num_atoms }, 82 | method_ratio = {"void": 0.5, "rand": 0.001, "walk": 0.5, "grow": 0.0, "min": 1.0}, 83 | ) 84 | 85 | structures = generator.get_structures() 86 | write('structures.traj', structures) 87 | -------------------------------------------------------------------------------- /docs/source/tutorials/generating_tutorial.rst: -------------------------------------------------------------------------------- 1 | .. generating_tutorial: 2 | 3 | 4 | ===================== 5 | Generating structures 6 | ===================== 7 | 8 | 9 | This tutorial will arguments associated with the generating procedure of a RAFFLE generator. 10 | 11 | The generating procedure is the process of adding atoms to the host structure to generate new structures. 12 | 13 | .. note:: 14 | The host structure must be set before generating structures. See :doc:`Host tutorial ` for more information. 15 | 16 | 17 | Input arguments 18 | --------------- 19 | 20 | The generating procedure has several arguments that can be set to control the generation of structures. 21 | 22 | The arguments are as follows: 23 | 24 | - ``num_structures``: The number of structures to generate. 25 | - ``stoichiometry``: A dictionary of the stoichiometry of atoms to add. 26 | - ``method_ratio``: A dictionary of the ratio of each method to use. 27 | - ``settings_out_file``: The file to write the settings to. 28 | - ``calc``: The calculator to attach to the generated structures. 29 | - ``seed``: The seed for the random number generator. 30 | - ``verbose``: The verbosity level of the generator. 31 | 32 | 33 | Example 34 | ------- 35 | 36 | The following example demonstrates how to generate structures using the RAFFLE generator. 37 | 38 | .. code-block:: python 39 | 40 | from raffle import Generator 41 | from mace.calculators import mace_mp 42 | 43 | # Set the host structure 44 | generator = Generator() 45 | generator.set_host('host.xyz') 46 | 47 | # Set the generating arguments 48 | generator.set_generating(num_structures=10, 49 | stoichiometry={'Al': 1, 'O': 2}, 50 | method_ratio={ 51 | 'min': 5.0, 52 | 'walk': 3.0, 53 | 'grow': 2.0 54 | 'void': 1.0 55 | 'rand': 0.1 56 | }, 57 | settings_out_file='settings.json', 58 | calc=mace_mp(), 59 | seed=42, 60 | verbose=1) 61 | 62 | # Generate the structures 63 | generator.generate() 64 | 65 | The above example generates 10 structures with a stoichiometry of 1 Al and 2 O atoms. 66 | The five methods are used with the specified ratios, with the values being renormalised to sum to 1 after the input. 67 | 68 | The settings are written to the file ``settings.json`` for future reference to improve reproducibility. 69 | By default, if no file is specified, the settings are not written to a file. 70 | 71 | The calculator is attached to the generated structures to calculate the energies of the structures. 72 | The seed is set to 42 to ensure reproducibility of the random number generator. 73 | 74 | The verbosity level is set to 2 to provide detailed information about the generation process. 75 | Default verbosity is 0, which provides no output. 76 | 77 | 78 | Retrieving generated structures 79 | ------------------------------- 80 | 81 | The generated structures are returned as a list of ASE Atoms objects. 82 | 83 | .. code-block:: python 84 | 85 | structures, status = generator.generate() 86 | 87 | The ``structures`` variable contains the list of generated structures for that iteration 88 | The ``status`` variable contains the status of the generation process, which can be used to check for errors. 89 | A successful generation will return a status of 0, while an error will return a non-zero status. 90 | 91 | Optionally, all structures generated thus far using the generator can be retrieved using the following command: 92 | 93 | .. code-block:: python 94 | 95 | all_structures = generator.get_structures() 96 | -------------------------------------------------------------------------------- /docs/source/tutorials/graphite_tutorial.rst: -------------------------------------------------------------------------------- 1 | .. graphite: 2 | 3 | ================= 4 | Graphite tutorial 5 | ================= 6 | 7 | This tutorial will guide you through the process of reconstructing graphite from a defected graphite cell (one missing layer). 8 | This tutorial follows the same structure as the :doc:`Diamond tutorial `. 9 | 10 | The tutorial is designed to show how RAFFLE learns from a database and uses this information to generate structures. 11 | This is not an expected use-case of RAFFLE, but merely a demonstration of its capabilities to rebuild a structure from a defected cell. 12 | 13 | The example files can be found in the following directory: 14 | 15 | .. code-block:: bash 16 | 17 | raffle/example/python_pkg/graphite 18 | 19 | First, we need to establish an initial database of structures. 20 | This will be used to initialise the generalised distribution functions, which will inform the placement of atoms in the generated structures. 21 | Here, we detail two routes: 1) using an ASE object of bulk graphite and 2) using the Materials Project database. 22 | 23 | Here, we will simply use the ASE object of bulk graphite. 24 | If you wish to use the Materials Project database, please refer to the :doc:`Databases tutorial `. 25 | 26 | First, we must import the required packages: 27 | 28 | .. code-block:: python 29 | 30 | from ase import Atoms 31 | from raffle.generator import raffle_generator 32 | from mace.calculators import mace_mp 33 | import numpy as np 34 | 35 | Next, we need to set up the RAFFLE generator and the calculator to calculate the energies of the structures. 36 | In this example, we use the MACE-MP-0 calculator: 37 | 38 | .. code-block:: python 39 | 40 | generator = raffle_generator() 41 | 42 | calc = mace_mp(model="medium", dispersion=False, default_dtype="float32", device='cpu') 43 | 44 | 45 | Then, we need to create the host structure. 46 | This is the base structure that will be added to in order to generate the structures. 47 | 48 | .. code-block:: python 49 | 50 | host = Atoms( 51 | "C6", 52 | scaled_positions=[ 53 | [0.000000000, 0.000000000, 0.125000000], 54 | [0.000000000, 0.000000000, 0.375000000], 55 | [0.000000000, 0.000000000, 0.875000000], 56 | [0.333333333, 0.666666667, 0.125000000], 57 | [0.666666667, 0.333333333, 0.375000000], 58 | [0.666666667, 0.333333333, 0.875000000], 59 | ], cell=[ 60 | 2.4672912616, 2.4672912616, 15.606146000 61 | ], pbc=True 62 | ) 63 | 64 | host.calc = calc 65 | generator.set_host(host) 66 | 67 | Next, we need to set any variables we want to use for the distributions. 68 | None should be required other than the element energies, which will be used as reference energies to calculate the formation energies of the structures. 69 | However, for completeness, we will set other variables here. 70 | Because there is only one element in this structure, the reference energy is meaningless, so we set it to ``0.0`` here. 71 | This is due to all structures will have the same stoichiometry and thus use the exact same reference energy, so choice of this value is a global shift. 72 | 73 | .. code-block:: python 74 | 75 | generator.distributions.set_element_energies( { 'C': 0.0 } ) 76 | generator.distributions.set_kBT(0.2) 77 | generator.distributions.set_width([0.025, np.pi/200.0, np.pi/200.0]) 78 | generator.distributions.set_radius_distance_tol([1.5, 2.5, 3.0, 6.0]) 79 | 80 | Now we need to generate the database of structures. 81 | We will provide bulk diamond as the only database entry here. 82 | 83 | .. code-block:: python 84 | 85 | database = [] 86 | database.append( 87 | Atoms("C4", 88 | positions=[ 89 | [0.0, 0.0, 1.95076825], 90 | [0.0, 0.0, 5.85230475], 91 | [1.2336456308015413, 0.7122456370278755, 1.95076825], 92 | [1.2336456308015415, -0.7122456370278757, 5.85230475] 93 | ], cell=[ 94 | [1.2336456308015413, -2.1367369110836267, 0.0], 95 | [1.2336456308015413, 2.1367369110836267, 0.0], 96 | [0.0, 0.0, 7.803073] 97 | ], pbc=True 98 | ) 99 | ) 100 | 101 | This database will now be used to initialise the generalised distribution functions in RAFFLE. 102 | 103 | .. code-block:: python 104 | 105 | generator.distributions.create(database) 106 | 107 | Finally, we can set the grid on which atom searches are performed (this grid is applied to the host cell). 108 | By default, the grid is generated using a spacing of 0.1 Å. 109 | 110 | .. code-block:: python 111 | 112 | generator.set_grid(grid_spacing=0.1, grid_offset=[0.0, 0.0, 0.0]) 113 | 114 | We are now ready to generate structures using the database of structures. 115 | 116 | .. code-block:: python 117 | 118 | num_structures_old = 0 119 | structures, status = generator.generate( 120 | num_structures = 1, 121 | stoichiometry = { 'C': 2 }, 122 | method_ratio = {"void":0.0001, "min":1.0}, 123 | calc = calc 124 | ) 125 | 126 | We should now have a structure of layered graphite. 127 | This structure can be visualised using the ASE package. 128 | But this can also be verified energetically. 129 | The generated structure should have double the energy of bulk graphite, found in ```database[0]```. -------------------------------------------------------------------------------- /docs/source/tutorials/host_tutorial.rst: -------------------------------------------------------------------------------- 1 | .. host: 2 | 3 | ====================== 4 | Setting host structure 5 | ====================== 6 | 7 | This tutorial will detail how to set the host structure for RAFFLE and the optional bounding box. 8 | 9 | The host structure is the base structure that will be added to in order to generate the structures. 10 | The bounding box is an optional parameter that can be used to limit the space in which atoms can be placed. 11 | 12 | 13 | It is recommended to set the host after changing parameters such as the Gaussian parameters and cutoffs (see :doc:`Parameters tutorial `). 14 | However, this is not strictly necessary, as the host can be set at any time. 15 | It is recommended that the host be provided with a calculator, as this will enable calculation of the host structure prior to atom placement. 16 | 17 | 18 | Follow the parameter tutorial to see how to initialise the generator. 19 | 20 | .. code-block:: python 21 | 22 | # Initialise RAFFLE generator 23 | from raffle.generator import raffle_generator 24 | 25 | generator = raffle_generator() 26 | 27 | We shall also initialise the calculator. 28 | 29 | .. code-block:: python 30 | 31 | # Set the calculator 32 | from mace.calculators import mace_mp 33 | calc = mace_mp(model="medium", dispersion=False, default_dtype="float32", device='cpu') 34 | 35 | 36 | Defining the host structure 37 | --------------------------- 38 | 39 | Now we shall initialise an atoms object and set it as the host structure. 40 | 41 | .. code-block:: python 42 | 43 | # Set the host structure 44 | host = Atoms(...) 45 | host.calc = calc 46 | generator.set_host(host) 47 | 48 | 49 | Defining the bounding box 50 | -------------------------- 51 | 52 | An optional bounding box can restrict atom placement to a specified region. 53 | The limits are expressed in fractional coordinates relative to the lattice vectors :math:`(\vec{a}, \vec{b}, \vec{c})`. 54 | 55 | .. code-block:: python 56 | 57 | # Set the fractional limits of atom position placement 58 | a_min = 0.0; b_max = 0.0; c_min = 0.3 59 | a_max = 1.0; b_max = 1.0; c_max = 0.8 60 | generator.set_bounds( [ 61 | [a_min, b_min, c_max], 62 | [a_max, b_max, c_max] 63 | ] ) 64 | -------------------------------------------------------------------------------- /docs/source/tutorials/index.rst: -------------------------------------------------------------------------------- 1 | .. tutorials: 2 | 3 | ========= 4 | Tutorials 5 | ========= 6 | 7 | Whilst RAFFLE is a random sturcture search package designed primarlily for interfaces, the tutorials will use bulk systems to demonstrate its functionality. 8 | 9 | .. note:: 10 | If you are looking for bulk random structure search, we recommend using packages such as `AIRSS `_, which are specifically designed for this purpose. 11 | They take advantage of symmetries prevalent in bulk structures to reduce the search space and improve efficiency. 12 | RAFFLE does not account for these symmetries, due to their usual absence in interfaces. 13 | 14 | .. toctree:: 15 | :maxdepth: 2 16 | :caption: Setup and parameters: 17 | 18 | databases_tutorial 19 | parameters_tutorial 20 | host_tutorial 21 | generating_tutorial 22 | quick_guide 23 | 24 | .. toctree:: 25 | :maxdepth: 2 26 | :caption: Static structure prediction: 27 | 28 | diamond_tutorial 29 | graphite_tutorial 30 | 31 | .. toctree:: 32 | :maxdepth: 2 33 | :caption: Iterative structure learning: 34 | 35 | aluminium_tutorial 36 | Si-Ge_tutorial 37 | -------------------------------------------------------------------------------- /docs/source/tutorials/parameters_tutorial.rst: -------------------------------------------------------------------------------- 1 | .. parameters: 2 | 3 | ================== 4 | Setting parameters 5 | ================== 6 | 7 | This tutorial will detail how to change RAFFLE parameters. 8 | These parameters are mainly used in building the RAFFLE descriptors for a database. 9 | For a guide on how to build a database, see the :doc:`Databases tutorial `. 10 | 11 | 12 | 13 | 14 | 15 | Initialisation 16 | -------------- 17 | RAFFLE is initialised by importing the generator object. 18 | This object is the main interface for the user to interact with the RAFFLE package. 19 | 20 | .. code-block:: python 21 | 22 | # Initialise RAFFLE generator 23 | from raffle.generator import raffle_generator 24 | 25 | generator = raffle_generator() 26 | 27 | 28 | It is recommended to use the Atomic Simulation Environment (ASE)~\cite{ase-paper} for handling structure data. 29 | Whilst RAFFLE can handle its own atomic structure object, ASE is more widely used and has a more extensive feature set. 30 | 31 | 32 | Energy references 33 | ----------------- 34 | 35 | Energy references do not have built-in default values, as they depend on specific calculation conditions (e.g. calculator choice, DFT functional choice, pseudopotential selection). 36 | To avoid misleading or inaccurate results, users must define reference energies explicitly: 37 | 38 | .. code-block:: python 39 | 40 | # Set reference energies 41 | generator.distributions.set_element_energies( { 42 | 'Si': -5.31218, # energy per atom of Si bulk 43 | 'Ge': -4.44257 # energy per atom fo Ge bulk 44 | } ) 45 | 46 | 47 | These reference energies are used to calculate the formation energies of the structures generated by RAFFLE. 48 | These are ignored if using the convex hull energies instead, but still need to be set to a value (e.g. 0.0) to avoid errors. 49 | The formation energy is calculated as: 50 | 51 | .. math:: 52 | E_f = \frac{ E_{\text{structure}} - \sum_i n_i E_i }{ \sum_i n_i } 53 | 54 | 55 | where :math:`E_{\text{structure}}` is the energy of the structure, :math:`n_i` is the number of atoms of element :math:`i` in the structure, and :math:`E_i` is the reference energy of element :math:`i`. 56 | 57 | 58 | Gaussian parameters and cutoffs 59 | ------------------------------- 60 | 61 | The distribution functions are built using Gaussian functions. 62 | They are used to determine the probability of placing an atom at a given position. 63 | The distribution functions are scaled by the relative energies of the systems (i.e. formation energy) and combined to form a generalised descriptor. 64 | The user can set the energy scaling, Gaussian smearing, width, and cutoff tolerances. 65 | 66 | .. code-block:: python 67 | 68 | # Set Gaussian parameters 69 | generator.distributions.set_kBT(0.2) 70 | generator.distributions.set_sigma( 71 | [0.1, 0.2, 0.3] 72 | ) 73 | generator.distributions.set_width( 74 | [0.1, 0.2, 0.3] 75 | ) 76 | generator.distributions.cutoff_min( 77 | [0.0, 0.0, 0.0] 78 | ) 79 | generator.distributions.cutoff_max( 80 | [6.0, 3.14159, 3.14159] 81 | ) 82 | generator.distributions.set_radius_distance_tol( 83 | [1.5, 2.5, 3.0, 6.0] 84 | ) 85 | 86 | 87 | The Gaussian width is the standard deviation of the Gaussian function. 88 | The cutoffs are the minimum and maximum values of the Gaussian function. 89 | The radius distance tolerance is a multiple of the element-pair covalent radius, similar to that used in AGOX :footcite:t:`Christiansen2022AtomisticGlobalOptimization`. 90 | 91 | The default value for the element-pair covalent radius is the average of the covalent radii of the two elements. 92 | This can be customised by the user: 93 | 94 | .. code-block:: python 95 | 96 | # Set reference element-pair covalent radii 97 | generator.distributions.set_bond_radii( { 98 | ('Si', 'Ge'): 1.165 # average bond length 99 | } ) 100 | 101 | 102 | Grid settings 103 | ------------- 104 | 105 | The grid settings are used to define the grid on which the generator operates. 106 | This grid is used for the placement of atoms in the host structure, specifically, the void and min methods. 107 | The grid spacing is the distance between grid points. 108 | The grid offset is the displacement of grid points from the cell origin (0,0,0) in fractional coordinates. 109 | 110 | .. code-block:: python 111 | 112 | # Define grid for placement methods 113 | generator.set_grid( 114 | grid_spacing=0.1, 115 | grid_offset=[0.0, 0.0, 0.0] 116 | ) 117 | 118 | 119 | Alternatively, the user can define the number of grid points along the three axes: 120 | 121 | .. code-block:: python 122 | 123 | # Define grid for placement methods 124 | generator.set_grid( 125 | grid=[1, 2, 3], 126 | grid_offset=[0.1, 0.1, 0.1] 127 | ) 128 | 129 | 130 | 131 | .. footbibliography:: 132 | -------------------------------------------------------------------------------- /docs/source/tutorials/quick_guide.rst: -------------------------------------------------------------------------------- 1 | .. quick_guide: 2 | 3 | =========== 4 | Quick guide 5 | =========== 6 | 7 | 8 | The quick guide is designed to give a brief overview of the steps required to run a RAFFLE calculation. 9 | It is assumed that the user has already installed RAFFLE and has a basic understanding of the command line. 10 | For a more detailed explanation of the parameters and options available, please see the :doc:`Main tutorial page ` for individual tutorials detailing each step. 11 | 12 | 13 | RAFFLE is a random structure search package designed primarily for interfaces. 14 | The tutorials will use bulk systems to demonstrate its functionality, but it is recommended to use packages such as `AIRSS `_ for bulk random structure search. 15 | 16 | 17 | Single iteration 18 | ---------------- 19 | 20 | Here is a script to run a single iteration of the RAFFLE generator for structure search. 21 | 22 | .. code-block:: python 23 | 24 | # Single iteration of RAFFLE structure search 25 | from ase.io import read, write 26 | from raffle.generator import raffle_generator 27 | 28 | generator = raffle_generator() 29 | 30 | host = read("host.xyz") 31 | generator.set_host(host) 32 | generator.set_grid(grid_spacing=0.1) 33 | generator.set_bounds([[0, 0, 0.5], [1, 1, 0.75]]) 34 | generator.distributions.set_element_energies( 35 | { 'C': -9.063733 } 36 | ) 37 | 38 | database = read("database.xyz", index=":") 39 | generator.distributions.create(database) 40 | 41 | structures, status = generator.generate( 42 | num_structures = 1, 43 | stoichiometry = { 'C': 2 }, 44 | ) 45 | 46 | write("output.xyz", structures) 47 | 48 | This script will generate a single structure with a stoichiometry of two carbon atoms. 49 | The host structure is read from a file, and the grid spacing and bounds are set. 50 | The element energies are set to the energy of carbon, and the database is read from a file. 51 | The generator is then run, and the structures are written to an output file. 52 | 53 | 54 | Iterative structure search 55 | -------------------------- 56 | 57 | Here is an example of how to run an iterative structure search with RAFFLE. 58 | 59 | .. code-block:: python 60 | 61 | # Iterative RAFFLE structure search 62 | from ase.io import read, write 63 | from ase.optimize import FIRE 64 | from raffle.generator import raffle_generator 65 | from mace.calculators import mace_mp 66 | 67 | generator = raffle_generator() 68 | mace = mace_mp(model="medium", dispersion=False, default_dtype="float32", device='cpu') 69 | 70 | host = read("host.xyz") 71 | generator.set_host(host) 72 | generator.set_grid(grid_spacing=0.1) 73 | generator.set_bounds([[0, 0, 0.5], [1, 1, 0.75]]) 74 | generator.distributions.set_element_energies( 75 | { 'C': -9.063733 } 76 | ) 77 | 78 | database = read("database.xyz", index=":") 79 | generator.distributions.create(database) 80 | 81 | num_structures_old = 0 82 | for i in range(10): 83 | generator.generate( 84 | num_structures = 2, 85 | stoichiometry = { 'C': 2 } 86 | calc = calc 87 | ) 88 | structures, status = generator.get_structures() 89 | for structure in structures: 90 | optimiser = FIRE(structure) 91 | optimiser.run(fmax=0.05) 92 | 93 | generator.update(structures) 94 | num_structures_old = len(structures) 95 | -------------------------------------------------------------------------------- /example/data/C-MgO_hosts/POSCAR_1x1_5.4A_separation: -------------------------------------------------------------------------------- 1 | c1 2 | 1.00000000000000 3 | 2.4639999866000002 0.0000000000000000 0.0000000000000000 4 | -1.2319999933000001 2.1338865833999998 0.0000000000000000 5 | 0.0000000000000000 0.0000000000000000 10.7109999657000001 6 | C 7 | 4 8 | Direct 9 | 0.0000000000000000 0.0000000000000000 0.2500000000000000 10 | 0.0000000000000000 0.0000000000000000 0.7499999819999985 11 | 0.3333333400000029 0.6666666830000025 0.2500000000000000 12 | 0.6666666570000004 0.3333333140000008 0.7499999819999985 13 | 14 | 0.00000000E+00 0.00000000E+00 0.00000000E+00 15 | 0.00000000E+00 0.00000000E+00 0.00000000E+00 16 | 0.00000000E+00 0.00000000E+00 0.00000000E+00 17 | 0.00000000E+00 0.00000000E+00 0.00000000E+00 18 | -------------------------------------------------------------------------------- /example/data/C-MgO_hosts/POSCAR_1x5_orthorhombic_11.0A_separation: -------------------------------------------------------------------------------- 1 | c1+mg1 o1 2 | 1.000000000 3 | 4.267773167 0.000000000 0.000000000 4 | -0.000000000 12.319999933 0.000000000 5 | 0.000000000 0.000000000 14.398580001 6 | C 7 | 40 8 | Direct 9 | 0.000000000 0.000000000 0.000000000 10 | 0.000000000 0.200000000 0.000000000 11 | 0.000000000 0.400000000 0.000000000 12 | 0.000000000 0.600000000 0.000000000 13 | 0.000000000 0.800000000 0.000000000 14 | 0.500000000 0.100000000 0.000000000 15 | 0.500000000 0.300000000 0.000000000 16 | 0.500000000 0.500000000 0.000000000 17 | 0.500000000 0.700000000 0.000000000 18 | 0.500000000 0.900000000 0.000000000 19 | 0.000000000 0.000000000 0.766956196 20 | 0.000000000 0.200000000 0.766956196 21 | 0.000000000 0.400000000 0.766956196 22 | 0.000000000 0.600000000 0.766956196 23 | 0.000000000 0.800000000 0.766956196 24 | 0.500000000 0.100000000 0.766956196 25 | 0.500000000 0.300000000 0.766956196 26 | 0.500000000 0.500000000 0.766956196 27 | 0.500000000 0.700000000 0.766956196 28 | 0.500000000 0.900000000 0.766956196 29 | 0.333333342 1.000000000 0.000000000 30 | 0.333333342 0.200000000 0.000000000 31 | 0.333333342 0.400000000 0.000000000 32 | 0.333333342 0.600000000 0.000000000 33 | 0.333333342 0.800000000 0.000000000 34 | 0.833333342 0.100000000 0.000000000 35 | 0.833333342 0.300000000 0.000000000 36 | 0.833333342 0.500000000 0.000000000 37 | 0.833333342 0.700000000 0.000000000 38 | 0.833333342 0.900000000 0.000000000 39 | 0.166666657 0.100000000 0.766956196 40 | 0.166666657 0.300000000 0.766956196 41 | 0.166666657 0.500000000 0.766956196 42 | 0.166666657 0.700000000 0.766956196 43 | 0.166666657 0.900000000 0.766956196 44 | 0.666666657 0.000000000 0.766956196 45 | 0.666666657 0.200000000 0.766956196 46 | 0.666666657 0.400000000 0.766956196 47 | 0.666666657 0.600000000 0.766956196 48 | 0.666666657 0.800000000 0.766956196 -------------------------------------------------------------------------------- /example/data/C-MgO_hosts/POSCAR_2x2_5.4A_separation: -------------------------------------------------------------------------------- 1 | c1 2 | 1.000000000 3 | 4.927999973 0.000000000 0.000000000 4 | -2.463999987 4.267773167 0.000000000 5 | 0.000000000 0.000000000 10.710999966 6 | C 7 | 16 8 | Direct 9 | 0.000000000 0.000000000 0.250000000 10 | 0.500000000 0.000000000 0.250000000 11 | 0.000000000 0.500000000 0.250000000 12 | 0.500000000 0.500000000 0.250000000 13 | 0.000000000 0.000000000 0.749999982 14 | 0.500000000 0.000000000 0.749999982 15 | 0.000000000 0.500000000 0.749999982 16 | 0.500000000 0.500000000 0.749999982 17 | 0.166666670 0.333333342 0.250000000 18 | 0.666666670 0.333333342 0.250000000 19 | 0.166666670 0.833333342 0.250000000 20 | 0.666666670 0.833333342 0.250000000 21 | 0.333333329 0.166666657 0.749999982 22 | 0.833333329 0.166666657 0.749999982 23 | 0.333333329 0.666666657 0.749999982 24 | 0.833333329 0.666666657 0.749999982 25 | -------------------------------------------------------------------------------- /example/data/C-MgO_hosts/POSCAR_2x5_orthorhombic_11.0A_separation: -------------------------------------------------------------------------------- 1 | c1+mg1 o1 2 | 1.0 3 | 8.5355463028 0.0000000000 0.0000000000 4 | 0.0000000000 12.3199996948 0.0000000000 5 | 0.0000000000 0.0000000000 14.3985795975 6 | C 7 | 80 8 | Direct 9 | 0.000000000 0.000000000 0.000000000 10 | 0.500000000 0.000000000 0.000000000 11 | 0.000000000 0.200000004 0.000000000 12 | 0.500000000 0.200000004 0.000000000 13 | 0.000000000 0.400000008 0.000000000 14 | 0.500000000 0.400000008 0.000000000 15 | 0.000000000 0.600000031 0.000000000 16 | 0.500000000 0.600000031 0.000000000 17 | 0.000000000 0.800000015 0.000000000 18 | 0.500000000 0.800000015 0.000000000 19 | 0.250000000 0.100000002 0.000000000 20 | 0.750000028 0.100000002 0.000000000 21 | 0.250000000 0.300000015 0.000000000 22 | 0.750000028 0.300000015 0.000000000 23 | 0.250000000 0.500000000 0.000000000 24 | 0.750000028 0.500000000 0.000000000 25 | 0.250000000 0.699999985 0.000000000 26 | 0.750000028 0.699999985 0.000000000 27 | 0.250000000 0.899999969 0.000000000 28 | 0.750000028 0.899999969 0.000000000 29 | -0.000000000 -0.000000000 0.766956230 30 | 0.500000000 -0.000000000 0.766956230 31 | -0.000000000 0.200000004 0.766956230 32 | 0.500000000 0.200000004 0.766956230 33 | -0.000000000 0.400000008 0.766956230 34 | 0.500000000 0.400000008 0.766956230 35 | 0.000000000 0.600000031 0.766956230 36 | 0.500000000 0.600000031 0.766956230 37 | 0.000000000 0.800000015 0.766956230 38 | 0.500000000 0.800000015 0.766956230 39 | 0.250000000 0.100000002 0.766956230 40 | 0.750000028 0.100000002 0.766956230 41 | 0.250000000 0.300000015 0.766956230 42 | 0.750000028 0.300000015 0.766956230 43 | 0.250000000 0.500000000 0.766956230 44 | 0.750000028 0.500000000 0.766956230 45 | 0.250000000 0.699999985 0.766956230 46 | 0.750000028 0.699999985 0.766956230 47 | 0.250000000 0.899999969 0.766956230 48 | 0.750000028 0.899999969 0.766956230 49 | 0.166666671 0.000000000 0.000000000 50 | 0.666666685 0.000000000 0.000000000 51 | 0.166666671 0.200000004 0.000000000 52 | 0.666666685 0.200000004 0.000000000 53 | 0.166666671 0.400000008 0.000000000 54 | 0.666666685 0.400000008 0.000000000 55 | 0.166666671 0.600000031 0.000000000 56 | 0.666666685 0.600000031 0.000000000 57 | 0.166666671 0.800000015 0.000000000 58 | 0.666666685 0.800000015 0.000000000 59 | 0.416666657 0.100000002 0.000000000 60 | 0.916666601 0.100000002 0.000000000 61 | 0.416666657 0.300000015 0.000000000 62 | 0.916666601 0.300000015 0.000000000 63 | 0.416666657 0.500000000 0.000000000 64 | 0.916666601 0.500000000 0.000000000 65 | 0.416666657 0.699999985 0.000000000 66 | 0.916666601 0.699999985 0.000000000 67 | 0.416666657 0.899999969 0.000000000 68 | 0.916666601 0.899999969 0.000000000 69 | 0.083333329 0.100000002 0.766956230 70 | 0.583333287 0.100000002 0.766956230 71 | 0.083333329 0.300000015 0.766956230 72 | 0.583333287 0.300000015 0.766956230 73 | 0.083333329 0.500000000 0.766956230 74 | 0.583333287 0.500000000 0.766956230 75 | 0.083333329 0.699999985 0.766956230 76 | 0.583333287 0.699999985 0.766956230 77 | 0.083333329 0.899999969 0.766956230 78 | 0.583333287 0.899999969 0.766956230 79 | 0.333333343 -0.000000000 0.766956230 80 | 0.833333371 -0.000000000 0.766956230 81 | 0.333333343 0.200000004 0.766956230 82 | 0.833333371 0.200000004 0.766956230 83 | 0.333333343 0.400000008 0.766956230 84 | 0.833333371 0.400000008 0.766956230 85 | 0.333333343 0.600000031 0.766956230 86 | 0.833333371 0.600000031 0.766956230 87 | 0.333333343 0.800000015 0.766956230 88 | 0.833333371 0.800000015 0.766956230 89 | -------------------------------------------------------------------------------- /example/data/C-MgO_hosts/POSCAR_3x3_11.0A_separation: -------------------------------------------------------------------------------- 1 | c1 2 | 1.000000000 3 | 7.391999960 0.000000000 0.000000000 4 | -3.695999980 6.401659750 0.000000000 5 | 0.000000000 0.000000000 14.710999966 6 | C 7 | 36 8 | Direct 9 | 0.000000000 0.000000000 0.000000000 10 | 0.333333333 0.000000000 0.000000000 11 | 0.666666667 0.000000000 0.000000000 12 | 0.000000000 0.333333333 0.000000000 13 | 0.333333333 0.333333333 0.000000000 14 | 0.666666667 0.333333333 0.000000000 15 | 0.000000000 0.666666667 0.000000000 16 | 0.333333333 0.666666667 0.000000000 17 | 0.666666667 0.666666667 0.000000000 18 | 0.000000000 0.000000000 0.749999982 19 | 0.333333333 0.000000000 0.749999982 20 | 0.666666667 0.000000000 0.749999982 21 | 0.000000000 0.333333333 0.749999982 22 | 0.333333333 0.333333333 0.749999982 23 | 0.666666667 0.333333333 0.749999982 24 | 0.000000000 0.666666667 0.749999982 25 | 0.333333333 0.666666667 0.749999982 26 | 0.666666667 0.666666667 0.749999982 27 | 0.111111113 0.222222228 0.000000000 28 | 0.444444447 0.222222228 0.000000000 29 | 0.777777780 0.222222228 0.000000000 30 | 0.111111113 0.555555561 0.000000000 31 | 0.444444447 0.555555561 0.000000000 32 | 0.777777780 0.555555561 0.000000000 33 | 0.111111113 0.888888894 0.000000000 34 | 0.444444447 0.888888894 0.000000000 35 | 0.777777780 0.888888894 0.000000000 36 | 0.222222219 0.111111105 0.749999982 37 | 0.555555552 0.111111105 0.749999982 38 | 0.888888886 0.111111105 0.749999982 39 | 0.222222219 0.444444438 0.749999982 40 | 0.555555552 0.444444438 0.749999982 41 | 0.888888886 0.444444438 0.749999982 42 | 0.222222219 0.777777771 0.749999982 43 | 0.555555552 0.777777771 0.749999982 44 | 0.888888886 0.777777771 0.749999982 45 | -------------------------------------------------------------------------------- /example/data/C-MgO_hosts/POSCAR_3x3_5.4A_separation: -------------------------------------------------------------------------------- 1 | c1 2 | 1.000000000 3 | 7.391999960 0.000000000 0.000000000 4 | -3.695999980 6.401659750 0.000000000 5 | 0.000000000 0.000000000 10.710999966 6 | C 7 | 36 8 | Direct 9 | 0.000000000 0.000000000 0.250000000 10 | 0.333333333 0.000000000 0.250000000 11 | 0.666666667 0.000000000 0.250000000 12 | 0.000000000 0.333333333 0.250000000 13 | 0.333333333 0.333333333 0.250000000 14 | 0.666666667 0.333333333 0.250000000 15 | 0.000000000 0.666666667 0.250000000 16 | 0.333333333 0.666666667 0.250000000 17 | 0.666666667 0.666666667 0.250000000 18 | 0.000000000 0.000000000 0.749999982 19 | 0.333333333 0.000000000 0.749999982 20 | 0.666666667 0.000000000 0.749999982 21 | 0.000000000 0.333333333 0.749999982 22 | 0.333333333 0.333333333 0.749999982 23 | 0.666666667 0.333333333 0.749999982 24 | 0.000000000 0.666666667 0.749999982 25 | 0.333333333 0.666666667 0.749999982 26 | 0.666666667 0.666666667 0.749999982 27 | 0.111111113 0.222222228 0.250000000 28 | 0.444444447 0.222222228 0.250000000 29 | 0.777777780 0.222222228 0.250000000 30 | 0.111111113 0.555555561 0.250000000 31 | 0.444444447 0.555555561 0.250000000 32 | 0.777777780 0.555555561 0.250000000 33 | 0.111111113 0.888888894 0.250000000 34 | 0.444444447 0.888888894 0.250000000 35 | 0.777777780 0.888888894 0.250000000 36 | 0.222222219 0.111111105 0.749999982 37 | 0.555555552 0.111111105 0.749999982 38 | 0.888888886 0.111111105 0.749999982 39 | 0.222222219 0.444444438 0.749999982 40 | 0.555555552 0.444444438 0.749999982 41 | 0.888888886 0.444444438 0.749999982 42 | 0.222222219 0.777777771 0.749999982 43 | 0.555555552 0.777777771 0.749999982 44 | 0.888888886 0.777777771 0.749999982 45 | -------------------------------------------------------------------------------- /example/data/C-MgO_hosts/POSCAR_4x4_11.0A_separation: -------------------------------------------------------------------------------- 1 | c1 2 | 1.000000000 3 | 9.855999947 0.000000000 0.000000000 4 | -4.927999973 8.535546333 0.000000000 5 | 0.000000000 0.000000000 14.710999966 6 | C 7 | 64 8 | Direct 9 | 0.000000000 0.000000000 0.000000000 10 | 0.750000000 0.000000000 0.000000000 11 | 0.000000000 0.750000000 0.000000000 12 | 0.750000000 0.750000000 0.000000000 13 | 0.250000000 0.000000000 0.000000000 14 | 0.250000000 0.750000000 0.000000000 15 | 0.500000000 0.000000000 0.000000000 16 | 0.500000000 0.750000000 0.000000000 17 | 0.000000000 0.250000000 0.000000000 18 | 0.750000000 0.250000000 0.000000000 19 | 0.250000000 0.250000000 0.000000000 20 | 0.500000000 0.250000000 0.000000000 21 | 0.000000000 0.500000000 0.000000000 22 | 0.750000000 0.500000000 0.000000000 23 | 0.250000000 0.500000000 0.000000000 24 | 0.500000000 0.500000000 0.000000000 25 | 0.000000000 0.000000000 0.749999982 26 | 0.750000000 0.000000000 0.749999982 27 | 0.000000000 0.750000000 0.749999982 28 | 0.750000000 0.750000000 0.749999982 29 | 0.250000000 0.000000000 0.749999982 30 | 0.250000000 0.750000000 0.749999982 31 | 0.500000000 0.000000000 0.749999982 32 | 0.500000000 0.750000000 0.749999982 33 | 0.000000000 0.250000000 0.749999982 34 | 0.750000000 0.250000000 0.749999982 35 | 0.250000000 0.250000000 0.749999982 36 | 0.500000000 0.250000000 0.749999982 37 | 0.000000000 0.500000000 0.749999982 38 | 0.750000000 0.500000000 0.749999982 39 | 0.250000000 0.500000000 0.749999982 40 | 0.500000000 0.500000000 0.749999982 41 | 0.083333335 0.166666671 0.000000000 42 | 0.833333335 0.166666671 0.000000000 43 | 0.083333335 0.916666671 0.000000000 44 | 0.833333335 0.916666671 0.000000000 45 | 0.333333335 0.166666671 0.000000000 46 | 0.333333335 0.916666671 0.000000000 47 | 0.583333335 0.166666671 0.000000000 48 | 0.583333335 0.916666671 0.000000000 49 | 0.083333335 0.416666671 0.000000000 50 | 0.833333335 0.416666671 0.000000000 51 | 0.333333335 0.416666671 0.000000000 52 | 0.583333335 0.416666671 0.000000000 53 | 0.083333335 0.666666671 0.000000000 54 | 0.833333335 0.666666671 0.000000000 55 | 0.333333335 0.666666671 0.000000000 56 | 0.583333335 0.666666671 0.000000000 57 | 0.166666664 0.083333329 0.749999982 58 | 0.916666664 0.083333329 0.749999982 59 | 0.166666664 0.833333329 0.749999982 60 | 0.916666664 0.833333329 0.749999982 61 | 0.416666664 0.083333329 0.749999982 62 | 0.416666664 0.833333329 0.749999982 63 | 0.666666665 0.083333329 0.749999982 64 | 0.666666665 0.833333329 0.749999982 65 | 0.166666664 0.333333329 0.749999982 66 | 0.916666664 0.333333329 0.749999982 67 | 0.416666664 0.333333329 0.749999982 68 | 0.666666665 0.333333329 0.749999982 69 | 0.166666664 0.583333328 0.749999982 70 | 0.916666664 0.583333328 0.749999982 71 | 0.416666664 0.583333328 0.749999982 72 | 0.666666665 0.583333328 0.749999982 73 | -------------------------------------------------------------------------------- /example/data/C-MgO_hosts/POSCAR_4x4_14.7A_separation: -------------------------------------------------------------------------------- 1 | c1 2 | 1.000000000 3 | 9.855999947 0.000000000 0.000000000 4 | -4.927999973 8.535546333 0.000000000 5 | 0.000000000 0.000000000 18.388833288 6 | C 7 | 64 8 | Direct 9 | 0.000000000 0.000000000 0.000000000 10 | 0.750000000 0.000000000 0.000000000 11 | 0.000000000 0.750000000 0.000000000 12 | 0.750000000 0.750000000 0.000000000 13 | 0.250000000 0.000000000 0.000000000 14 | 0.250000000 0.750000000 0.000000000 15 | 0.500000000 0.000000000 0.000000000 16 | 0.500000000 0.750000000 0.000000000 17 | 0.000000000 0.250000000 0.000000000 18 | 0.750000000 0.250000000 0.000000000 19 | 0.250000000 0.250000000 0.000000000 20 | 0.500000000 0.250000000 0.000000000 21 | 0.000000000 0.500000000 0.000000000 22 | 0.750000000 0.500000000 0.000000000 23 | 0.250000000 0.500000000 0.000000000 24 | 0.500000000 0.500000000 0.000000000 25 | 0.000000000 0.000000000 0.800000892 26 | 0.750000000 0.000000000 0.800000892 27 | 0.000000000 0.750000000 0.800000892 28 | 0.750000000 0.750000000 0.800000892 29 | 0.250000000 0.000000000 0.800000892 30 | 0.250000000 0.750000000 0.800000892 31 | 0.500000000 0.000000000 0.800000892 32 | 0.500000000 0.750000000 0.800000892 33 | 0.000000000 0.250000000 0.800000892 34 | 0.750000000 0.250000000 0.800000892 35 | 0.250000000 0.250000000 0.800000892 36 | 0.500000000 0.250000000 0.800000892 37 | 0.000000000 0.500000000 0.800000892 38 | 0.750000000 0.500000000 0.800000892 39 | 0.250000000 0.500000000 0.800000892 40 | 0.500000000 0.500000000 0.800000892 41 | 0.083333335 0.166666671 0.000000000 42 | 0.833333335 0.166666671 0.000000000 43 | 0.083333335 0.916666671 0.000000000 44 | 0.833333335 0.916666671 0.000000000 45 | 0.333333335 0.166666671 0.000000000 46 | 0.333333335 0.916666671 0.000000000 47 | 0.583333335 0.166666671 0.000000000 48 | 0.583333335 0.916666671 0.000000000 49 | 0.083333335 0.416666671 0.000000000 50 | 0.833333335 0.416666671 0.000000000 51 | 0.333333335 0.416666671 0.000000000 52 | 0.583333335 0.416666671 0.000000000 53 | 0.083333335 0.666666671 0.000000000 54 | 0.833333335 0.666666671 0.000000000 55 | 0.333333335 0.666666671 0.000000000 56 | 0.583333335 0.666666671 0.000000000 57 | 0.166666664 0.083333329 0.800000892 58 | 0.916666664 0.083333329 0.800000892 59 | 0.166666664 0.833333329 0.800000892 60 | 0.916666664 0.833333329 0.800000892 61 | 0.416666664 0.083333329 0.800000892 62 | 0.416666664 0.833333329 0.800000892 63 | 0.666666665 0.083333329 0.800000892 64 | 0.666666665 0.833333329 0.800000892 65 | 0.166666664 0.333333329 0.800000892 66 | 0.916666664 0.333333329 0.800000892 67 | 0.416666664 0.333333329 0.800000892 68 | 0.666666665 0.333333329 0.800000892 69 | 0.166666664 0.583333328 0.800000892 70 | 0.916666664 0.583333328 0.800000892 71 | 0.416666664 0.583333328 0.800000892 72 | 0.666666665 0.583333328 0.800000892 73 | -------------------------------------------------------------------------------- /example/data/C-MgO_hosts/POSCAR_5x1_5.4A_separation: -------------------------------------------------------------------------------- 1 | c1 2 | 1.000000000 3 | 12.319999933 0.000000000 0.000000000 4 | -1.231999993 2.133886583 0.000000000 5 | 0.000000000 0.000000000 10.710999966 6 | C 7 | 20 8 | Direct 9 | 0.000000000 0.000000000 0.250000000 10 | 0.200000000 0.000000000 0.250000000 11 | 0.400000000 0.000000000 0.250000000 12 | 0.600000000 0.000000000 0.250000000 13 | 0.800000000 0.000000000 0.250000000 14 | 0.000000000 0.000000000 0.749999982 15 | 0.200000000 0.000000000 0.749999982 16 | 0.400000000 0.000000000 0.749999982 17 | 0.600000000 0.000000000 0.749999982 18 | 0.800000000 0.000000000 0.749999982 19 | 0.066666668 0.666666683 0.250000000 20 | 0.266666668 0.666666683 0.250000000 21 | 0.466666668 0.666666683 0.250000000 22 | 0.666666668 0.666666683 0.250000000 23 | 0.866666668 0.666666683 0.250000000 24 | 0.133333331 0.333333314 0.749999982 25 | 0.333333331 0.333333314 0.749999982 26 | 0.533333331 0.333333314 0.749999982 27 | 0.733333331 0.333333314 0.749999982 28 | 0.933333331 0.333333314 0.749999982 29 | -------------------------------------------------------------------------------- /example/data/C-MgO_hosts/POSCAR_5x1_6.0A_separation: -------------------------------------------------------------------------------- 1 | c1 2 | 1.000000000 3 | 12.319999933 0.000000000 0.000000000 4 | -6.159999967 10.669432917 0.000000000 5 | 0.000000000 0.000000000 12.029835 6 | C 7 | 100 8 | Direct 9 | 0.000000000 0.000000000 0.250000000 10 | 0.200000000 0.000000000 0.250000000 11 | 0.400000000 0.000000000 0.250000000 12 | 0.600000000 0.000000000 0.250000000 13 | 0.800000000 0.000000000 0.250000000 14 | 0.000000000 0.200000000 0.250000000 15 | 0.200000000 0.200000000 0.250000000 16 | 0.400000000 0.200000000 0.250000000 17 | 0.600000000 0.200000000 0.250000000 18 | 0.800000000 0.200000000 0.250000000 19 | 0.000000000 0.400000000 0.250000000 20 | 0.200000000 0.400000000 0.250000000 21 | 0.400000000 0.400000000 0.250000000 22 | 0.600000000 0.400000000 0.250000000 23 | 0.800000000 0.400000000 0.250000000 24 | 0.000000000 0.600000000 0.250000000 25 | 0.200000000 0.600000000 0.250000000 26 | 0.400000000 0.600000000 0.250000000 27 | 0.600000000 0.600000000 0.250000000 28 | 0.800000000 0.600000000 0.250000000 29 | 0.000000000 0.800000000 0.250000000 30 | 0.200000000 0.800000000 0.250000000 31 | 0.400000000 0.800000000 0.250000000 32 | 0.600000000 0.800000000 0.250000000 33 | 0.800000000 0.800000000 0.250000000 34 | 0.000000000 0.000000000 0.749999982 35 | 0.200000000 0.000000000 0.749999982 36 | 0.400000000 0.000000000 0.749999982 37 | 0.600000000 0.000000000 0.749999982 38 | 0.800000000 0.000000000 0.749999982 39 | 0.000000000 0.200000000 0.749999982 40 | 0.200000000 0.200000000 0.749999982 41 | 0.400000000 0.200000000 0.749999982 42 | 0.600000000 0.200000000 0.749999982 43 | 0.800000000 0.200000000 0.749999982 44 | 0.000000000 0.400000000 0.749999982 45 | 0.200000000 0.400000000 0.749999982 46 | 0.400000000 0.400000000 0.749999982 47 | 0.600000000 0.400000000 0.749999982 48 | 0.800000000 0.400000000 0.749999982 49 | 0.000000000 0.600000000 0.749999982 50 | 0.200000000 0.600000000 0.749999982 51 | 0.400000000 0.600000000 0.749999982 52 | 0.600000000 0.600000000 0.749999982 53 | 0.800000000 0.600000000 0.749999982 54 | 0.000000000 0.800000000 0.749999982 55 | 0.200000000 0.800000000 0.749999982 56 | 0.400000000 0.800000000 0.749999982 57 | 0.600000000 0.800000000 0.749999982 58 | 0.800000000 0.800000000 0.749999982 59 | 0.066666668 0.133333337 0.250000000 60 | 0.266666668 0.133333337 0.250000000 61 | 0.466666668 0.133333337 0.250000000 62 | 0.666666668 0.133333337 0.250000000 63 | 0.866666668 0.133333337 0.250000000 64 | 0.066666668 0.333333337 0.250000000 65 | 0.266666668 0.333333337 0.250000000 66 | 0.466666668 0.333333337 0.250000000 67 | 0.666666668 0.333333337 0.250000000 68 | 0.866666668 0.333333337 0.250000000 69 | 0.066666668 0.533333337 0.250000000 70 | 0.266666668 0.533333337 0.250000000 71 | 0.466666668 0.533333337 0.250000000 72 | 0.666666668 0.533333337 0.250000000 73 | 0.866666668 0.533333337 0.250000000 74 | 0.066666668 0.733333337 0.250000000 75 | 0.266666668 0.733333337 0.250000000 76 | 0.466666668 0.733333337 0.250000000 77 | 0.666666668 0.733333337 0.250000000 78 | 0.866666668 0.733333337 0.250000000 79 | 0.066666668 0.933333337 0.250000000 80 | 0.266666668 0.933333337 0.250000000 81 | 0.466666668 0.933333337 0.250000000 82 | 0.666666668 0.933333337 0.250000000 83 | 0.866666668 0.933333337 0.250000000 84 | 0.133333331 0.066666663 0.749999982 85 | 0.333333331 0.066666663 0.749999982 86 | 0.533333331 0.066666663 0.749999982 87 | 0.733333331 0.066666663 0.749999982 88 | 0.933333331 0.066666663 0.749999982 89 | 0.133333331 0.266666663 0.749999982 90 | 0.333333331 0.266666663 0.749999982 91 | 0.533333331 0.266666663 0.749999982 92 | 0.733333331 0.266666663 0.749999982 93 | 0.933333331 0.266666663 0.749999982 94 | 0.133333331 0.466666663 0.749999982 95 | 0.333333331 0.466666663 0.749999982 96 | 0.533333331 0.466666663 0.749999982 97 | 0.733333331 0.466666663 0.749999982 98 | 0.933333331 0.466666663 0.749999982 99 | 0.133333331 0.666666663 0.749999982 100 | 0.333333331 0.666666663 0.749999982 101 | 0.533333331 0.666666663 0.749999982 102 | 0.733333331 0.666666663 0.749999982 103 | 0.933333331 0.666666663 0.749999982 104 | 0.133333331 0.866666663 0.749999982 105 | 0.333333331 0.866666663 0.749999982 106 | 0.533333331 0.866666663 0.749999982 107 | 0.733333331 0.866666663 0.749999982 108 | 0.933333331 0.866666663 0.749999982 109 | -------------------------------------------------------------------------------- /example/data/C-MgO_hosts/POSCAR_orthorhombic_11.1A_separation_Mg_seeded: -------------------------------------------------------------------------------- 1 | c1+mg1 o1 2 | 1.000000000 3 | 4.267773167 0.000000000 0.000000000 4 | -0.000000000 12.319999933 0.000000000 5 | 0.000000000 0.000000000 14.398580001 6 | C Mg 7 | 40 2 8 | Direct 9 | 0.000000000 0.000000000 0.000000000 10 | 0.000000000 0.200000000 0.000000000 11 | 0.000000000 0.400000000 0.000000000 12 | 0.000000000 0.600000000 0.000000000 13 | 0.000000000 0.800000000 0.000000000 14 | 0.500000000 0.100000000 0.000000000 15 | 0.500000000 0.300000000 0.000000000 16 | 0.500000000 0.500000000 0.000000000 17 | 0.500000000 0.700000000 0.000000000 18 | 0.500000000 0.900000000 0.000000000 19 | 0.000000000 0.000000000 0.766956196 20 | 0.000000000 0.200000000 0.766956196 21 | 0.000000000 0.400000000 0.766956196 22 | 0.000000000 0.600000000 0.766956196 23 | 0.000000000 0.800000000 0.766956196 24 | 0.500000000 0.100000000 0.766956196 25 | 0.500000000 0.300000000 0.766956196 26 | 0.500000000 0.500000000 0.766956196 27 | 0.500000000 0.700000000 0.766956196 28 | 0.500000000 0.900000000 0.766956196 29 | 0.333333342 1.000000000 0.000000000 30 | 0.333333342 0.200000000 0.000000000 31 | 0.333333342 0.400000000 0.000000000 32 | 0.333333342 0.600000000 0.000000000 33 | 0.333333342 0.800000000 0.000000000 34 | 0.833333342 0.100000000 0.000000000 35 | 0.833333342 0.300000000 0.000000000 36 | 0.833333342 0.500000000 0.000000000 37 | 0.833333342 0.700000000 0.000000000 38 | 0.833333342 0.900000000 0.000000000 39 | 0.166666657 0.100000000 0.766956196 40 | 0.166666657 0.300000000 0.766956196 41 | 0.166666657 0.500000000 0.766956196 42 | 0.166666657 0.700000000 0.766956196 43 | 0.166666657 0.900000000 0.766956196 44 | 0.666666657 0.000000000 0.766956196 45 | 0.666666657 0.200000000 0.766956196 46 | 0.666666657 0.400000000 0.766956196 47 | 0.666666657 0.600000000 0.766956196 48 | 0.666666657 0.800000000 0.766956196 49 | 0.500000000 0.500000000 0.384000000 50 | 0.500000000 0.250000000 0.192000000 -------------------------------------------------------------------------------- /example/fortran_exe/param.in: -------------------------------------------------------------------------------- 1 | &setup 2 | task = 0, 3 | filename_host = "../data/C-MgO_hosts/POSCAR_MgO_HEX", 4 | database_format = "xyz" 5 | database = "./", 6 | seed = 1, 7 | grid_spacing = 0.05, 8 | verbose = 0, 9 | output_dir = "iteration1" 10 | / 11 | 12 | &placement_method 13 | void = 1.0, 14 | rand = 1.0, 15 | walk = 1.0, 16 | grow = 1.0, 17 | min = 1.0 18 | / 19 | 20 | &structure 21 | num_structures=10, 22 | stoichiometry="{Mg:8, O:8}", 23 | / 24 | 25 | &volume 26 | vdW=10, 27 | volvar=10 28 | / 29 | 30 | &distribution 31 | cutoff_min = 0.5 0.0 0.0, 32 | cutoff_max = 6.0 "pi" "pi", 33 | sigma = 0.5 0.1 0.1 34 | / 35 | 36 | &element_info 37 | energies = "{ 38 | C: -9.0266865, 39 | Mg: -1.5478236, 40 | O: -4.3707458 41 | }" 42 | bond_radii = "{ 43 | C-C: 1.54461, 44 | C-Mg: 2.3 45 | } 46 | / 47 | -------------------------------------------------------------------------------- /example/fortran_exe/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | $HOME/.local/raffle/bin/raffle_executable -f param.in 4 | -------------------------------------------------------------------------------- /example/python_pkg/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto-remove output from Jupyter notebooks 2 | # Follow the guide from this link to set up the filter: 3 | # https://gist.github.com/33eyes/431e3d432f73371509d176d0dfb95b6e 4 | *.ipynb filter=strip-notebook-output -------------------------------------------------------------------------------- /example/python_pkg/Al_learn/DRAFFLE/DOutput/rlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/Al_learn/DRAFFLE/DOutput/rlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/Al_learn/DRAFFLE/DOutput/unrlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/Al_learn/DRAFFLE/DOutput/unrlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/Al_learn/DRSS/DOutput/rlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/Al_learn/DRSS/DOutput/rlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/Al_learn/DRSS/DOutput/unrlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/Al_learn/DRSS/DOutput/unrlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/Al_learn/known_phases/mp-1183144.vasp: -------------------------------------------------------------------------------- 1 | Al mp-1183144 2 | 1.0 3 | 1.413539 -2.448321 0.000000 4 | 1.413539 2.448321 0.000000 5 | 0.000000 0.000000 9.185993 6 | Al 7 | 4 8 | direct 9 | 0.0000000 0.0000000 0.00 10 | 0.3333333 0.6666666 0.25 11 | 0.0000000 0.0000000 0.50 12 | 0.6666666 0.3333333 0.75 13 | -------------------------------------------------------------------------------- /example/python_pkg/Al_learn/known_phases/mp-134.vasp: -------------------------------------------------------------------------------- 1 | Al mp-134 2 | 1.0 3 | 4.03893 0.00000 0.00000 4 | 0.00000 4.03893 0.00000 5 | 0.00000 0.00000 4.03893 6 | Al 7 | 4 8 | direct 9 | 0.0 0.0 0.0 10 | 0.0 0.5 0.5 11 | 0.5 0.0 0.5 12 | 0.5 0.5 0.0 13 | -------------------------------------------------------------------------------- /example/python_pkg/Al_learn/known_phases/mp-2647008.vasp: -------------------------------------------------------------------------------- 1 | Al mp-2647008 2 | 1.0 3 | 1.4062277 -2.4356578 0.00000 4 | 1.4062277 2.4356578 0.00000 5 | 0.0000000 0.0000000 4.86685 6 | Al 7 | 2 8 | direct 9 | 0.6666667 0.3333333 0.75 10 | 0.3333333 0.6666667 0.25 11 | -------------------------------------------------------------------------------- /example/python_pkg/Al_learn/known_phases/mp-998860.vasp: -------------------------------------------------------------------------------- 1 | Al mp-998860 2 | 1.0 3 | 3.182437 0.000000 0.000000 4 | -0.000000 3.182437 0.000000 5 | 0.000000 0.000000 3.182437 6 | Al 7 | 2 8 | direct 9 | 0.0 0.0 0.0 10 | 0.5 0.5 0.5 11 | -------------------------------------------------------------------------------- /example/python_pkg/C_learn/DRAFFLE/DOutput/rlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/C_learn/DRAFFLE/DOutput/rlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/C_learn/DRAFFLE/DOutput/unrlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/C_learn/DRAFFLE/DOutput/unrlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/C_learn/DRSS/DOutput/rlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/C_learn/DRSS/DOutput/rlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/C_learn/DRSS/DOutput/unrlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/C_learn/DRSS/DOutput/unrlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/C_learn/DRSS/analyse_structures.py: -------------------------------------------------------------------------------- 1 | # %% 2 | import matplotlib 3 | # %matplotlib inline 4 | # print("BACKEND: ", matplotlib.get_backend()) 5 | # if matplotlib.get_backend() != "macosx": 6 | # print("Changing backend to macosx") 7 | # matplotlib.use('macosx') 8 | 9 | # %% 10 | import matplotlib.pyplot as plt 11 | # %matplotlib inline 12 | 13 | # matplotlib.use("Agg") 14 | 15 | from ase.visualize import view 16 | 17 | from ase import Atoms 18 | from ase.build import bulk 19 | from ase.io import read, write 20 | from agox.databases import Database 21 | from agox.environments import Environment 22 | from agox.utils.graph_sorting import Analysis 23 | 24 | import pickle 25 | from sklearn.decomposition import PCA 26 | 27 | # %% 28 | from agox.models.descriptors.fingerprint import Fingerprint 29 | from agox.models.descriptors import Voronoi 30 | import numpy as np 31 | 32 | template = Atoms("", cell=np.eye(3) * 3.567, pbc=True) 33 | diamond = bulk("C", "diamond", a=3.567) # Lattice constant for diamond cubic carbon 34 | confinement_cell = template.cell.copy() 35 | confinement_corner = np.array([0, 0, 0]) 36 | environment = Environment( 37 | template=template, 38 | symbols="C8", 39 | confinement_cell=confinement_cell, 40 | confinement_corner=confinement_corner, 41 | box_constraint_pbc=[True, True, True], # Confinement is periodic in all directions. 42 | ) 43 | descriptor = Fingerprint(environment=environment) 44 | graph_descriptor = Voronoi( 45 | covalent_bond_scale_factor=1.3, n_points=8, angle_from_central_atom=20, environment=environment 46 | ) 47 | 48 | 49 | # %% 50 | from chgnet.model import CHGNetCalculator 51 | calc = CHGNetCalculator() 52 | 53 | # %% 54 | seed = 0 55 | rlxd_string = "unrlxd" 56 | bin_width = 0.1 57 | target_energy = -9.064090728759766 58 | 59 | # %% 60 | for seed in range(1): 61 | for rlxd_string in ["unrlxd", "rlxd"]: 62 | structures = read("DOutput/"+rlxd_string+"_structures_seed"+str(seed)+".traj", index=":") 63 | for structure in structures: 64 | structure.calc = calc 65 | 66 | # %% 67 | graph_sorting = Analysis(descriptor=graph_descriptor, directories=["."], sample_size=min(1000, len(structures))) 68 | # %% 69 | unique, count = graph_sorting.sort_structures(structures=structures) 70 | print("Repeats of unique structures: ", count) 71 | 72 | # %% 73 | # Calculate energies per atom for each unique structure 74 | energies_per_atom = [structure.get_potential_energy() / len(structure) for structure in unique] 75 | delta_en_per_atom = np.array(energies_per_atom) - target_energy 76 | 77 | 78 | # %% 79 | if abs( np.min(energies_per_atom) + 9.064090728759766 ) > 1e-4: 80 | print("Minimum energy per atom is not zero. Check the energy calculation.") 81 | if ( rlxd_string == "rlxd" ): 82 | exit() 83 | 84 | # %% 85 | # further reduce the delta_en_per_atom and count by the bin width 86 | delta_en_per_atom_rounded = np.round(delta_en_per_atom / bin_width) * bin_width 87 | delta_en_per_atom_binned = np.unique(delta_en_per_atom_rounded) 88 | count_binned = np.zeros_like(delta_en_per_atom_binned) 89 | for i, de in enumerate(delta_en_per_atom_binned): 90 | for j, de2 in enumerate(delta_en_per_atom_rounded): 91 | if abs(de - de2) < 1e-4: 92 | count_binned[i] += count[j] 93 | 94 | # %% 95 | # Plot the number of unique structures vs the energies per atom 96 | plt.figure(figsize=(10, 6)) 97 | plt.bar(delta_en_per_atom_binned, count_binned, width=0.1) 98 | plt.xlabel('Energy per Atom (eV/atom)') 99 | plt.ylabel('Number of structures') 100 | plt.title('Number of Unique Structures vs Energies per Atom ('+rlxd_string+' seed '+str(seed)+')') 101 | # plt.show() 102 | plt.savefig("RSS_unique_structures_vs_energies_per_atom_"+rlxd_string+"_seed"+str(seed)+".png") 103 | 104 | # %% 105 | pca = PCA(n_components=2) 106 | 107 | # %% 108 | # graph_descriptor.get_features(unique[0]) 109 | if rlxd_string == "unrlxd" and seed == 0: 110 | pca.fit(np.squeeze([arr for arr in descriptor.get_features(unique)])) 111 | 112 | # %% 113 | # save pca model 114 | if False: #rlxd_string == "unrlxd" and seed == 0: 115 | with open("pca_model_"+rlxd_string+"_"+str(seed)+".pkl", "wb") as f: 116 | pickle.dump(pca, f) 117 | 118 | # load pca model 119 | with open("../DRAFFLE/pca_model_all_unrlxd_0.pkl", "rb") as f: 120 | pca = pickle.load(f) 121 | 122 | 123 | # %% 124 | X_reduced = pca.transform(np.squeeze([arr for arr in descriptor.get_features(structures)])) 125 | energies_per_atom_pca = [structure.get_potential_energy() / len(structure) for structure in structures] 126 | delta_en_per_atom_pca = np.array(energies_per_atom_pca) - target_energy 127 | 128 | # %% 129 | plt.figure(1, figsize=(8, 6)) 130 | 131 | # %% 132 | plt.figure(figsize=(10, 6)) 133 | plt.scatter(X_reduced[:, 0], X_reduced[:, 1], c=delta_en_per_atom_pca, cmap="viridis") 134 | plt.xlabel('Principal component 1') 135 | plt.ylabel('Principal component 2') 136 | plt.title('PCA of Unique Structures ('+rlxd_string+', seed'+str(seed)+')') 137 | plt.xlim(-6, 10) 138 | plt.ylim(-6, 10) 139 | plt.colorbar(label='Energy above diamond (eV/atom)') 140 | plt.savefig('RSS_pca_unique_structures_'+rlxd_string+'_seed'+str(seed)+'.png') 141 | -------------------------------------------------------------------------------- /example/python_pkg/C_learn/DRSS/rss.py: -------------------------------------------------------------------------------- 1 | # https://agox.gitlab.io/agox/command_line_tools/command_line.html 2 | 3 | import matplotlib 4 | 5 | matplotlib.use("Agg") 6 | 7 | 8 | import numpy as np 9 | from ase import Atoms 10 | from ase.io import write 11 | 12 | from agox import AGOX 13 | from agox.databases import Database 14 | from agox.environments import Environment 15 | from agox.evaluators import LocalOptimizationEvaluator 16 | from agox.generators import RandomGenerator 17 | from agox.postprocessors import MinimumDistPostProcess 18 | 19 | 20 | database_index = 0 21 | iteration_directory = "iteration" 22 | 23 | ############################################################################## 24 | # Calculator 25 | ############################################################################## 26 | 27 | # from mace.calculators import mace_mp 28 | from chgnet.model import CHGNetCalculator 29 | from ase.build import bulk 30 | import os 31 | 32 | # calc = mace_mp() 33 | calc = CHGNetCalculator() 34 | 35 | ############################################################################## 36 | # System & general settings: 37 | ############################################################################## 38 | 39 | 40 | diamond = bulk("C", "diamond", a=3.567) # Lattice constant for diamond cubic carbon 41 | diamond.write("diamond.traj") 42 | post1 = MinimumDistPostProcess(order=1.5, c1=0.75) 43 | post2 = MinimumDistPostProcess(order=2.5, c1=0.75) 44 | 45 | # Make an empty template with a cubic cell of size 6x6x6 with periodic boundary conditions 46 | # in all directions 47 | a = 3.567 48 | iteration = 0 49 | template = Atoms("", cell=np.eye(3) * a, pbc=True) 50 | 51 | 52 | # Confinement cell matches the template cell in all dimensions and is placed at 53 | # the origin of the template cell. 54 | confinement_cell = template.cell.copy() 55 | confinement_corner = np.array([0, 0, 0]) 56 | 57 | environment = Environment( 58 | template=template, 59 | symbols="C8", 60 | confinement_cell=confinement_cell, 61 | confinement_corner=confinement_corner, 62 | box_constraint_pbc=[True, True, True], # Confinement is periodic in all directions. 63 | ) 64 | 65 | # Database 66 | db_directory = iteration_directory+"{}".format(iteration)+"/" 67 | if not os.path.exists(db_directory): 68 | os.makedirs(db_directory) 69 | db_path = db_directory+"db{}.db".format(database_index) # From input argument! 70 | 71 | for seed in range(20): 72 | database = Database(filename=db_path, order=3, initialize=True) 73 | 74 | ############################################################################## 75 | # Search Settings: 76 | ############################################################################## 77 | 78 | random_generator = RandomGenerator(**environment.get_confinement(), environment=environment, order=1) 79 | 80 | # Wont relax fully with steps:5 - more realistic setting would be 100+. 81 | evaluator = LocalOptimizationEvaluator( 82 | calc, 83 | gets={"get_key": "candidates"}, 84 | optimizer_run_kwargs={"fmax": 0.05, "steps": 100}, 85 | store_trajectory=True, 86 | order=2, 87 | constraints=environment.get_constraints(), 88 | ) 89 | 90 | ############################################################################## 91 | # Let get the show running! 92 | ############################################################################## 93 | 94 | agox = AGOX(random_generator, database, evaluator, seed=seed) 95 | 96 | agox.run(N_iterations=1000) 97 | 98 | structure_data = database.get_all_structures_data() 99 | # check iteration number has changed 100 | iteration_check = -1 101 | unrlxd_structures = [] 102 | rlxd_structures = [] 103 | for idx, structure in enumerate(structure_data): 104 | if structure["iteration"] != iteration_check: 105 | iteration_check = structure["iteration"] 106 | unrlxd_structures.append(database.db_to_atoms(structure)) 107 | if idx != 0: 108 | rlxd_structures.append(database.db_to_atoms(structure_data[idx-1])) 109 | if len(rlxd_structures) != len(unrlxd_structures): 110 | rlxd_structures.append(database.db_to_atoms(structure_data[-1])) 111 | 112 | print("Unrelaxed structures", len(unrlxd_structures)) 113 | print("Relaxed structures", len(rlxd_structures)) 114 | write(f"unrlxd_structures_seed{seed}.traj", unrlxd_structures) 115 | write(f"rlxd_structures_seed{seed}.traj", rlxd_structures) 116 | 117 | # database.restore_to_memory() 118 | # structures = database.get_all_candidates() # this is an Atoms object with some more stuff 119 | -------------------------------------------------------------------------------- /example/python_pkg/C_learn/Dgraphite_diamond/DOutput/rlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/C_learn/Dgraphite_diamond/DOutput/rlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/C_learn/Dgraphite_diamond/DOutput/unrlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/C_learn/Dgraphite_diamond/DOutput/unrlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/C_learn/Dgraphite_diamond/graphite.vasp: -------------------------------------------------------------------------------- 1 | C4 2 | 1.0 3 | 0.0000000000000000 4.2546406144450799 0.0000000000000000 4 | 2.4565648800000002 0.0000000000000000 0.0000000000000000 5 | 0.0000000000000000 -1.3790696309310659 -3.5028300786042923 6 | C 7 | 4 8 | direct 9 | 0.1666444699999990 0.0000000000000000 0.9999069600000000 C0+ 10 | 0.8333555300000001 0.0000000000000000 0.0000930400000000 C0+ 11 | 0.6666444699999990 0.5000000000000000 0.9999069600000000 C0+ 12 | 0.3333555300000000 0.5000000000000000 0.0000930400000000 C0+ 13 | -------------------------------------------------------------------------------- /example/python_pkg/C_learn/plot_structures_vs_energies.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import matplotlib.pyplot as plt\n", 10 | "%matplotlib inline\n", 11 | "\n", 12 | "import numpy as np\n", 13 | "from ase.io import read\n", 14 | "from matplotlib.ticker import AutoMinorLocator" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "## Set up the plotting environment\n", 24 | "# # matplotlib.rcParams.update(matplotlib.rcParamsDefault)\n", 25 | "plt.rc('text', usetex=True)\n", 26 | "plt.rc('font', family='cmr10', size=12)\n", 27 | "plt.rcParams[\"axes.formatter.use_mathtext\"] = True" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "metadata": {}, 34 | "outputs": [], 35 | "source": [ 36 | "## Set the plotting parameters\n", 37 | "method = \"RSS\"\n", 38 | "identifier = \"_seed_test\"\n", 39 | "bin_width = 0.1\n", 40 | "rlxd_string = \"rlxd\"\n", 41 | "seed = 0" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "## Load the data\n", 51 | "energies = []\n", 52 | "if method == \"RAFFLE\":\n", 53 | " filename = \"D\"+method+\"/DOutput\"+identifier+\"/energies_\"+rlxd_string+\"_seed\"+str(seed)+\".txt\"\n", 54 | " with open(filename) as f:\n", 55 | " for line in f:\n", 56 | " index, energy = line.split()\n", 57 | " index = int(index)\n", 58 | " energy = float(energy)\n", 59 | " energies.append(energy)\n", 60 | "else:\n", 61 | " filename = \"D\"+method+\"/DOutput\"+identifier+\"/\"+rlxd_string+\"_structures_seed\"+str(seed)+\".traj\"\n", 62 | " traj = read(filename, \":\")\n", 63 | " for atoms in traj:\n", 64 | " energies.append(atoms.get_potential_energy() / len(atoms))" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": {}, 71 | "outputs": [], 72 | "source": [ 73 | "## Get the delta energies and bin them\n", 74 | "en_per_atom = np.array(energies)\n", 75 | "delta_en_per_atom = en_per_atom - np.min(en_per_atom)\n", 76 | "\n", 77 | "# further reduce the delta_en_per_atom and count by the bin width\n", 78 | "delta_en_per_atom_rounded = np.round(delta_en_per_atom / bin_width) * bin_width\n", 79 | "delta_en_per_atom_binned = np.unique(delta_en_per_atom_rounded)\n", 80 | "\n", 81 | "counts = np.zeros(len(delta_en_per_atom_binned))\n", 82 | "for i, en in enumerate(delta_en_per_atom_rounded):\n", 83 | " counts[np.where(delta_en_per_atom_binned == en)] += 1" 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": null, 89 | "metadata": {}, 90 | "outputs": [], 91 | "source": [ 92 | "## Plot the number structures vs the energies per atom\n", 93 | "fig = plt.figure(figsize=(6, 6))\n", 94 | "ax = fig.add_subplot(111)\n", 95 | "plt.bar(delta_en_per_atom_binned, counts, width=0.1)\n", 96 | "plt.xlabel('Energy per atom (eV/atom)', fontsize=25)\n", 97 | "plt.ylabel('Number of structures', fontsize=25)\n", 98 | "ax.tick_params(axis='x', which='minor', length=3)\n", 99 | "ax.tick_params(axis='x', which='major', length=6, labelsize=20)\n", 100 | "ax.tick_params(axis='x', which='both', labelbottom=True, top=True, direction='in')\n", 101 | "ax.tick_params(axis='y', which='both', labelbottom=True, right=True, direction='in', labelsize=20, length=6)\n", 102 | "plt.bar(delta_en_per_atom_binned, counts, width=0.1, color='lightgrey', edgecolor='black')\n", 103 | "\n", 104 | "ax.set_xticks(np.arange(0, max(2.0,max(delta_en_per_atom_binned)) + 0.5, 0.5))\n", 105 | "ax.xaxis.set_minor_locator(AutoMinorLocator(2))\n", 106 | "ax.set_ylim(0, 500)\n", 107 | "\n", 108 | "## Save the plot\n", 109 | "plt.savefig(\"C_\"+method+identifier+\"_structures_vs_deltaE_\"+rlxd_string+\"_seed\"+str(seed)+\".pdf\", bbox_inches='tight', pad_inches=0, facecolor=fig.get_facecolor(), edgecolor='none')\n" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": null, 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [] 118 | } 119 | ], 120 | "metadata": { 121 | "kernelspec": { 122 | "display_name": "raffle_env", 123 | "language": "python", 124 | "name": "python3" 125 | }, 126 | "language_info": { 127 | "codemirror_mode": { 128 | "name": "ipython", 129 | "version": 3 130 | }, 131 | "file_extension": ".py", 132 | "mimetype": "text/x-python", 133 | "name": "python", 134 | "nbconvert_exporter": "python", 135 | "pygments_lexer": "ipython3", 136 | "version": "3.12.8" 137 | } 138 | }, 139 | "nbformat": 4, 140 | "nbformat_minor": 2 141 | } 142 | -------------------------------------------------------------------------------- /example/python_pkg/MoS2_learn/DRAFFLE/DOutput/rlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/MoS2_learn/DRAFFLE/DOutput/rlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/MoS2_learn/DRAFFLE/DOutput/unrlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/MoS2_learn/DRAFFLE/DOutput/unrlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/MoS2_learn/DRSS/DOutput/rlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/MoS2_learn/DRSS/DOutput/rlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/MoS2_learn/DRSS/DOutput/unrlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/MoS2_learn/DRSS/DOutput/unrlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/MoS2_learn/DRSS/rss.py: -------------------------------------------------------------------------------- 1 | # https://agox.gitlab.io/agox/command_line_tools/command_line.html 2 | 3 | import matplotlib 4 | 5 | matplotlib.use("Agg") 6 | 7 | 8 | import numpy as np 9 | from ase import Atoms 10 | from ase.io import write 11 | 12 | from agox import AGOX 13 | from agox.databases import Database 14 | from agox.environments import Environment 15 | from agox.evaluators import LocalOptimizationEvaluator 16 | from agox.generators import RandomGenerator 17 | from agox.postprocessors import MinimumDistPostProcess 18 | 19 | 20 | database_index = 0 21 | iteration_directory = "iteration" 22 | 23 | ############################################################################## 24 | # Calculator 25 | ############################################################################## 26 | 27 | # from mace.calculators import mace_mp 28 | from chgnet.model import CHGNetCalculator 29 | from ase.build import bulk 30 | import os 31 | 32 | # calc = mace_mp() 33 | calc = CHGNetCalculator() 34 | 35 | ############################################################################## 36 | # System & general settings: 37 | ############################################################################## 38 | 39 | 40 | post1 = MinimumDistPostProcess(order=1.5, c1=0.75) 41 | post2 = MinimumDistPostProcess(order=2.5, c1=0.75) 42 | 43 | a = 3.19 44 | MoS2 = Atoms('Mo', positions=[(0, 0, 0)], cell=[ 45 | [a * 0.5, a * -np.sqrt(3.0)/2.0, 0.0], 46 | [a * 0.5, a * np.sqrt(3.0)/2.0, 0.0], 47 | [0.0, 0.0, 13.1] 48 | ], pbc=True, calculator=calc) 49 | 50 | # Make an empty template with a cubic cell of size 6x6x6 with periodic boundary conditions 51 | # in all directions 52 | iteration = 0 53 | template = Atoms("", 54 | cell=[ 55 | [a * 0.5, a * -np.sqrt(3.0)/2.0, 0.0], 56 | [a * 0.5, a * np.sqrt(3.0)/2.0, 0.0], 57 | [0.0, 0.0, 13.1] 58 | ], 59 | pbc=True) 60 | 61 | 62 | # Confinement cell matches the template cell in all dimensions and is placed at 63 | # the origin of the template cell. 64 | confinement_cell = template.cell.copy() 65 | confinement_corner = np.array([0, 0, 0]) 66 | 67 | environment = Environment( 68 | template=template, 69 | symbols="Mo2S4", 70 | confinement_cell=confinement_cell, 71 | confinement_corner=confinement_corner, 72 | box_constraint_pbc=[True, True, True], # Confinement is periodic in all directions. 73 | ) 74 | 75 | # Database 76 | db_directory = iteration_directory+"{}".format(iteration)+"/" 77 | if not os.path.exists(db_directory): 78 | os.makedirs(db_directory) 79 | db_path = db_directory+"db{}.db".format(database_index) # From input argument! 80 | 81 | for seed in range(1): 82 | database = Database(filename=db_path, order=3, initialize=True) 83 | 84 | ############################################################################## 85 | # Search Settings: 86 | ############################################################################## 87 | 88 | random_generator = RandomGenerator(**environment.get_confinement(), environment=environment, order=1) 89 | 90 | # Wont relax fully with steps:5 - more realistic setting would be 100+. 91 | evaluator = LocalOptimizationEvaluator( 92 | calc, 93 | gets={"get_key": "candidates"}, 94 | optimizer_run_kwargs={"fmax": 0.05, "steps": 100}, 95 | store_trajectory=True, 96 | order=2, 97 | constraints=environment.get_constraints(), 98 | ) 99 | 100 | ############################################################################## 101 | # Let get the show running! 102 | ############################################################################## 103 | 104 | agox = AGOX(random_generator, database, evaluator, seed=seed) 105 | 106 | agox.run(N_iterations=1000) 107 | 108 | database.restore_to_memory() 109 | structure_data = database.get_all_structures_data() 110 | # check iteration number has changed 111 | iteration_check = -1 112 | unrlxd_structures = [] 113 | rlxd_structures = [] 114 | for idx, structure in enumerate(structure_data): 115 | if structure["iteration"] != iteration_check: 116 | iteration_check = structure["iteration"] 117 | unrlxd_structures.append(database.db_to_atoms(structure)) 118 | if idx != 0: 119 | rlxd_structures.append(database.db_to_atoms(structure_data[idx-1])) 120 | if len(rlxd_structures) != len(unrlxd_structures): 121 | rlxd_structures.append(database.db_to_atoms(structure_data[-1])) 122 | 123 | for structure in unrlxd_structures: 124 | structure.calc = None 125 | for structure in rlxd_structures: 126 | structure.calc = None 127 | print("Unrelaxed structures", len(unrlxd_structures)) 128 | print("Relaxed structures", len(rlxd_structures)) 129 | write(f"unrlxd_structures_seed{seed}.traj", unrlxd_structures) 130 | write(f"rlxd_structures_seed{seed}.traj", rlxd_structures) 131 | 132 | # database.restore_to_memory() 133 | # structures = database.get_all_candidates() # this is an Atoms object with some more stuff 134 | -------------------------------------------------------------------------------- /example/python_pkg/MoS2_learn/Mo.poscar: -------------------------------------------------------------------------------- 1 | Mo2 2 | 1.00000000000000 3 | 3.1229640216873942 -0.0000000000000000 -0.0000000000000000 4 | 0.0000000000000000 3.1229640216873942 -0.0000000000000000 5 | 0.0000000000000000 0.0000000000000000 3.1229640216873942 6 | Mo 7 | 2 8 | Direct 9 | 0.0000000000000000 0.0000000000000000 0.0000000000000000 10 | 0.5000000000000000 0.5000000000000000 0.5000000000000000 11 | -------------------------------------------------------------------------------- /example/python_pkg/MoS2_learn/MoS2_H-phase.poscar: -------------------------------------------------------------------------------- 1 | MoS2 H-phase 2 | 1.0 3 | 1.592716 -2.758665 0.000000 4 | 1.592716 2.758665 0.000000 5 | 0.000000 0.000000 13.178390 6 | Mo S 7 | 2 4 8 | direct 9 | 0.000000 0.000000 0.250000 10 | 0.000000 0.000000 0.750000 11 | 0.333333 0.666666 0.367743 12 | 0.666666 0.333333 0.632256 13 | 0.666666 0.333333 0.867743 14 | 0.333333 0.666666 0.132256 -------------------------------------------------------------------------------- /example/python_pkg/MoS2_learn/MoS2_T-phase.poscar: -------------------------------------------------------------------------------- 1 | MoS2 T-phase 2 | 1.0 3 | 1.592716 -2.758665 0.000000 4 | 1.592716 2.758665 0.000000 5 | 0.000000 0.000000 12.62495 6 | Mo S 7 | 2 4 8 | direct 9 | 0.000000 0.000000 0.250000 10 | 0.000000 0.000000 0.750000 11 | 0.333333 0.666666 0.127659 12 | 0.666666 0.333333 0.372341 13 | 0.333333 0.666666 0.627659 14 | 0.666666 0.333333 0.872341 -------------------------------------------------------------------------------- /example/python_pkg/README.md: -------------------------------------------------------------------------------- 1 | # Python Package Example 2 | 3 | This directory contains example Python files demonstrating how to use the raffle package. 4 | 5 | ## Directory Structure 6 | 7 | ``` 8 | python_pkg/ 9 | ├── # Example with dataset containing global minimum from which to learn RAFFLE descriptors 10 | └── run.py # Script to test placement methods 11 | └── # Example with no prior database, i.e. RAFFLE starts with no prior knowledge 12 | ├── DRAFFLE # Directory containing example RAFFLE learning script 13 | ├── learn.py # Script to run RSS generating and learning 14 | └── pca.ipynb # Notebook to plot principal component analysis of RAFFLE results 15 | └── DRSS # Directory containing example random structure search script using AGOX 16 | ├── rss.py # Script to run RSS 17 | └── pca.ipynb # Notebook to plot principal component analysis of RSS results 18 | ``` 19 | 20 | ## File Descriptions 21 | 22 | - `run.py`: Example script highlighting placement method capabilities 23 | - `learn.py`: Example script highlighting learning capabilties of RAFFLE 24 | - `pca.ipynb`: Notebook to generate principal component analysis of generated structures 25 | 26 | ## Execution Order 27 | 28 | To run a RAFFLE example and analyse the results, the following order must be performed. 29 | 1. Move to the desired `SYSTEM_learn/DRAFFLE` directory and create a directory to work in: 30 | ```bash 31 | cd SYSTEM_learn 32 | mkdir DOutput 33 | cd DOutput 34 | ``` 35 | 36 | 2. Run the `learn.py` script: 37 | ```bash 38 | python ../learn.py 39 | ``` 40 | 41 | 3. Go to parent directory and open the notebook `pca.ipynb`, run all the cells. 42 | 43 | NOTE: for the `C_learn/DRSS/` example, the `pca.ipynb` notebook expects that the `C_learn/DRAFFLE/` example script and notebook have been fully run first. 44 | This is because it attempts to use the PCA fit to the RAFFLE results to transform its data. 45 | Doing so enables the two techniques to be properly compared. 46 | 47 | The `[un]rlxd_structures_seed0.traj` files are provided (as are the `energies_[un]rlxd+seed0.txt`) as the key outputs from the `learn.py` runs. 48 | For the `rss.py` scripts, the `[un]rlxd_structures_seed0.traj` files are provided. 49 | Whilst other output files are generated during the RAFFLE runs, these are optional files with mostly redundant data. 50 | 51 | ## Prerequisites 52 | 53 | - Python 3.11 or higher 54 | - raffle package installed (`pip install .`) 55 | - `ase` for handling atomic structure data 56 | - `CHGNet`, `MACE-0`, `VASP`, or some other `ase`-compatible calculator 57 | -------------------------------------------------------------------------------- /example/python_pkg/ScS2-Li_learn/DRAFFLE/DOutput/rlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/ScS2-Li_learn/DRAFFLE/DOutput/rlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/ScS2-Li_learn/DRAFFLE/DOutput/unrlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/ScS2-Li_learn/DRAFFLE/DOutput/unrlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/ScS2-Li_learn/ScS2.vasp: -------------------------------------------------------------------------------- 1 | ScS2 2 | 1.00000000000000 3 | 3.4373550228202143 1.2722491953399284 -0.0985749251780342 4 | 0.6164998078516010 3.5730165704323316 -0.5636062457623744 5 | -0.1941735091202983 0.9816038800609169 6.1273390509283345 6 | Sc S 7 | 1 2 8 | Direct 9 | 0.6762039103400640 0.1332178797064758 0.9103732174536018 10 | 0.0097462202190008 0.4656228504900874 0.6731159326278954 11 | 0.3427267534832620 0.8007351821914250 0.1476299218798714 12 | 13 | -------------------------------------------------------------------------------- /example/python_pkg/Si-Ge_learn/DRAFFLE/DOutput/rlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/Si-Ge_learn/DRAFFLE/DOutput/rlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/Si-Ge_learn/DRAFFLE/DOutput/unrlxd_structures_seed0.traj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ExeQuantCode/RAFFLE/d32a89c832193dda485543891d16f304eaaa2cb7/example/python_pkg/Si-Ge_learn/DRAFFLE/DOutput/unrlxd_structures_seed0.traj -------------------------------------------------------------------------------- /example/python_pkg/Si-Ge_learn/Ge_slab.vasp: -------------------------------------------------------------------------------- 1 | Ge 2 | 1.000000000 3 | 11.300000000 0.000000000 0.000000000 4 | 0.000000000 11.300000000 0.000000000 5 | 0.000000000 0.000000000 25.299999996 6 | Ge 7 | 80 8 | Direct 9 | 0.750000000 0.000000000 0.000000000 10 | 0.750000000 0.000000000 0.223320158 11 | 0.750000000 0.000000000 0.446640316 12 | 0.875000000 0.125000000 0.055830039 13 | 0.875000000 0.125000000 0.279150198 14 | 0.875000000 0.125000000 0.502470356 15 | 0.000000000 0.250000000 0.000000000 16 | 0.000000000 0.250000000 0.223320158 17 | 0.000000000 0.250000000 0.446640316 18 | 0.125000000 0.375000000 0.055830039 19 | 0.125000000 0.375000000 0.279150198 20 | 0.125000000 0.375000000 0.502470356 21 | 0.000000000 0.000000000 0.111660079 22 | 0.000000000 0.000000000 0.334980237 23 | 0.125000000 0.125000000 0.167490118 24 | 0.125000000 0.125000000 0.390810277 25 | 0.750000000 0.250000000 0.111660079 26 | 0.750000000 0.250000000 0.334980237 27 | 0.875000000 0.375000000 0.167490118 28 | 0.875000000 0.375000000 0.390810277 29 | 0.750000000 0.500000000 0.000000000 30 | 0.750000000 0.500000000 0.223320158 31 | 0.750000000 0.500000000 0.446640316 32 | 0.875000000 0.625000000 0.055830039 33 | 0.875000000 0.625000000 0.279150198 34 | 0.875000000 0.625000000 0.502470356 35 | 0.000000000 0.750000000 0.000000000 36 | 0.000000000 0.750000000 0.223320158 37 | 0.000000000 0.750000000 0.446640316 38 | 0.125000000 0.875000000 0.055830039 39 | 0.125000000 0.875000000 0.279150198 40 | 0.125000000 0.875000000 0.502470356 41 | 0.000000000 0.500000000 0.111660079 42 | 0.000000000 0.500000000 0.334980237 43 | 0.125000000 0.625000000 0.167490118 44 | 0.125000000 0.625000000 0.390810277 45 | 0.750000000 0.750000000 0.111660079 46 | 0.750000000 0.750000000 0.334980237 47 | 0.875000000 0.875000000 0.167490118 48 | 0.875000000 0.875000000 0.390810277 49 | 0.250000000 0.000000000 0.000000000 50 | 0.250000000 0.000000000 0.223320158 51 | 0.250000000 0.000000000 0.446640316 52 | 0.375000000 0.125000000 0.055830039 53 | 0.375000000 0.125000000 0.279150198 54 | 0.375000000 0.125000000 0.502470356 55 | 0.500000000 0.250000000 0.000000000 56 | 0.500000000 0.250000000 0.223320158 57 | 0.500000000 0.250000000 0.446640316 58 | 0.625000000 0.375000000 0.055830039 59 | 0.625000000 0.375000000 0.279150198 60 | 0.625000000 0.375000000 0.502470356 61 | 0.500000000 0.000000000 0.111660079 62 | 0.500000000 0.000000000 0.334980237 63 | 0.625000000 0.125000000 0.167490118 64 | 0.625000000 0.125000000 0.390810277 65 | 0.250000000 0.250000000 0.111660079 66 | 0.250000000 0.250000000 0.334980237 67 | 0.375000000 0.375000000 0.167490118 68 | 0.375000000 0.375000000 0.390810277 69 | 0.250000000 0.500000000 0.000000000 70 | 0.250000000 0.500000000 0.223320158 71 | 0.250000000 0.500000000 0.446640316 72 | 0.375000000 0.625000000 0.055830039 73 | 0.375000000 0.625000000 0.279150198 74 | 0.375000000 0.625000000 0.502470356 75 | 0.500000000 0.750000000 0.000000000 76 | 0.500000000 0.750000000 0.223320158 77 | 0.500000000 0.750000000 0.446640316 78 | 0.625000000 0.875000000 0.055830039 79 | 0.625000000 0.875000000 0.279150198 80 | 0.625000000 0.875000000 0.502470356 81 | 0.500000000 0.500000000 0.111660079 82 | 0.500000000 0.500000000 0.334980237 83 | 0.625000000 0.625000000 0.167490118 84 | 0.625000000 0.625000000 0.390810277 85 | 0.250000000 0.750000000 0.111660079 86 | 0.250000000 0.750000000 0.334980237 87 | 0.375000000 0.875000000 0.167490118 88 | 0.375000000 0.875000000 0.390810277 89 | -------------------------------------------------------------------------------- /example/python_pkg/Si-Ge_learn/Si_slab.vasp: -------------------------------------------------------------------------------- 1 | Si 2 | 1.000000000 3 | 10.860000000 0.000000000 0.000000000 4 | 0.000000000 10.860000000 0.000000000 5 | 0.000000000 0.000000000 24.859999996 6 | Si 7 | 80 8 | Direct 9 | 0.000000000 0.000000000 0.000000000 10 | 0.000000000 0.000000000 0.218423170 11 | 0.000000000 0.000000000 0.436846339 12 | 0.125000000 0.125000000 0.054605792 13 | 0.125000000 0.125000000 0.273028962 14 | 0.125000000 0.125000000 0.491452132 15 | 0.250000000 0.250000000 0.000000000 16 | 0.250000000 0.250000000 0.218423170 17 | 0.250000000 0.250000000 0.436846339 18 | 0.375000000 0.375000000 0.054605792 19 | 0.375000000 0.375000000 0.273028962 20 | 0.375000000 0.375000000 0.491452132 21 | 0.250000000 0.000000000 0.109211585 22 | 0.250000000 0.000000000 0.327634755 23 | 0.375000000 0.125000000 0.163817377 24 | 0.375000000 0.125000000 0.382240547 25 | 0.000000000 0.250000000 0.109211585 26 | 0.000000000 0.250000000 0.327634755 27 | 0.125000000 0.375000000 0.163817377 28 | 0.125000000 0.375000000 0.382240547 29 | 0.000000000 0.500000000 0.000000000 30 | 0.000000000 0.500000000 0.218423170 31 | 0.000000000 0.500000000 0.436846339 32 | 0.125000000 0.625000000 0.054605792 33 | 0.125000000 0.625000000 0.273028962 34 | 0.125000000 0.625000000 0.491452132 35 | 0.250000000 0.750000000 0.000000000 36 | 0.250000000 0.750000000 0.218423170 37 | 0.250000000 0.750000000 0.436846339 38 | 0.375000000 0.875000000 0.054605792 39 | 0.375000000 0.875000000 0.273028962 40 | 0.375000000 0.875000000 0.491452132 41 | 0.250000000 0.500000000 0.109211585 42 | 0.250000000 0.500000000 0.327634755 43 | 0.375000000 0.625000000 0.163817377 44 | 0.375000000 0.625000000 0.382240547 45 | 0.000000000 0.750000000 0.109211585 46 | 0.000000000 0.750000000 0.327634755 47 | 0.125000000 0.875000000 0.163817377 48 | 0.125000000 0.875000000 0.382240547 49 | 0.500000000 0.000000000 0.000000000 50 | 0.500000000 0.000000000 0.218423170 51 | 0.500000000 0.000000000 0.436846339 52 | 0.625000000 0.125000000 0.054605792 53 | 0.625000000 0.125000000 0.273028962 54 | 0.625000000 0.125000000 0.491452132 55 | 0.750000000 0.250000000 0.000000000 56 | 0.750000000 0.250000000 0.218423170 57 | 0.750000000 0.250000000 0.436846339 58 | 0.875000000 0.375000000 0.054605792 59 | 0.875000000 0.375000000 0.273028962 60 | 0.875000000 0.375000000 0.491452132 61 | 0.750000000 0.000000000 0.109211585 62 | 0.750000000 0.000000000 0.327634755 63 | 0.875000000 0.125000000 0.163817377 64 | 0.875000000 0.125000000 0.382240547 65 | 0.500000000 0.250000000 0.109211585 66 | 0.500000000 0.250000000 0.327634755 67 | 0.625000000 0.375000000 0.163817377 68 | 0.625000000 0.375000000 0.382240547 69 | 0.500000000 0.500000000 0.000000000 70 | 0.500000000 0.500000000 0.218423170 71 | 0.500000000 0.500000000 0.436846339 72 | 0.625000000 0.625000000 0.054605792 73 | 0.625000000 0.625000000 0.273028962 74 | 0.625000000 0.625000000 0.491452132 75 | 0.750000000 0.750000000 0.000000000 76 | 0.750000000 0.750000000 0.218423170 77 | 0.750000000 0.750000000 0.436846339 78 | 0.875000000 0.875000000 0.054605792 79 | 0.875000000 0.875000000 0.273028962 80 | 0.875000000 0.875000000 0.491452132 81 | 0.750000000 0.500000000 0.109211585 82 | 0.750000000 0.500000000 0.327634755 83 | 0.875000000 0.625000000 0.163817377 84 | 0.875000000 0.625000000 0.382240547 85 | 0.500000000 0.750000000 0.109211585 86 | 0.500000000 0.750000000 0.327634755 87 | 0.625000000 0.875000000 0.163817377 88 | 0.625000000 0.875000000 0.382240547 89 | -------------------------------------------------------------------------------- /example/python_pkg/benchmarks/create_gdfs.py: -------------------------------------------------------------------------------- 1 | import os 2 | import glob 3 | from raffle.generator import raffle_generator 4 | import pytest 5 | from ase.io import read 6 | import time 7 | import numpy as np 8 | 9 | 10 | def get_xyz_files(): 11 | """Get all .xyz files from the ../../data directory""" 12 | current_dir = os.path.dirname(os.path.abspath(__file__)) 13 | data_dir = os.path.join(current_dir, '..', '..', '..', 'example', 'data') 14 | print("Data directory:", data_dir) 15 | return glob.glob(os.path.join(data_dir, '*.xyz')) 16 | 17 | 18 | @pytest.mark.parametrize("xyz_file", get_xyz_files()) 19 | @pytest.mark.parametrize("kBT", [0.2, 0.4, 0.6]) 20 | @pytest.mark.parametrize("width", [ 21 | [0.025, np.pi/200.0, np.pi/200.0], 22 | [0.05, np.pi/100.0, np.pi/100.0], 23 | [0.1, np.pi/50.0, np.pi/50.0] 24 | ]) 25 | @pytest.mark.benchmark( 26 | group="distributions", 27 | min_rounds=5, 28 | timer=time.time, 29 | disable_gc=True, 30 | warmup=False 31 | ) 32 | def test_distributions_create(benchmark, xyz_file, kBT, width): 33 | atoms = read(xyz_file, index=":") 34 | 35 | # Initialize generator 36 | generator = raffle_generator() 37 | 38 | # get list of elements in list of atoms 39 | elements = [] 40 | for atom in atoms: 41 | elements += atom.get_chemical_symbols() 42 | elements = list(set(elements)) 43 | energies = {element: 0.0 for element in elements} 44 | generator.distributions.set_element_energies(energies) 45 | 46 | avg_num_atoms = 0 47 | for atom in atoms: 48 | avg_num_atoms += len(atom) 49 | avg_num_atoms = round(avg_num_atoms / len(atoms)) 50 | 51 | benchmark.extra_info = { 52 | 'file': os.path.basename(xyz_file), 53 | 'num_structures': len(atoms), 54 | 'num_species': len(elements), 55 | "avg_num_atoms": avg_num_atoms, 56 | "kBT": kBT, 57 | "width": width 58 | } 59 | 60 | # set energy scale 61 | generator.distributions.set_kBT(kBT) 62 | 63 | # set the distribution function widths (2-body, 3-body, 4-body) 64 | generator.distributions.set_width(width) 65 | 66 | # Measure time for distributions.create() 67 | result = benchmark(generator.distributions.create, atoms) 68 | 69 | 70 | return { 71 | 'file': os.path.basename(xyz_file), 72 | 'time': result, 73 | 'num_structures': len(atoms), 74 | 'num_species': len(elements), 75 | "avg_num_atoms": avg_num_atoms 76 | } 77 | 78 | @pytest.fixture 79 | def make_customer_record(): 80 | def _make_customer_record(name): 81 | return {"name": name, "orders": []} 82 | 83 | return _make_customer_record 84 | 85 | if __name__ == '__main__': 86 | xyz_files = get_xyz_files() 87 | results = [] 88 | 89 | result = test_distributions_create(lambda x: x) 90 | # for xyz_file in xyz_files: 91 | # # for _ in range(5): # Run the benchmark 5 times for each file 92 | # result = test_distributions_create(lambda x: x, xyz_file) 93 | # results.append(result) 94 | 95 | # Print results 96 | print("\nBenchmark Results:") 97 | print("-" * 60) 98 | print(f"{'File':<20} {'Time (s)':<10} {'Num Structures':<10} {'Num Species':<10} {'Avg Num Atoms':<10}") 99 | print("-" * 60) 100 | for result in results: 101 | print(f"{result['file']:<20} {result['time']:<10.4f} {result['num_structures']:<10} {result['num_species']:<10} {result['avg_num_atoms']:<10}") -------------------------------------------------------------------------------- /example/python_pkg/benchmarks/min_placement.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import time 3 | import numpy as np 4 | from ase import Atoms 5 | from chgnet.model import CHGNetCalculator 6 | from raffle.generator import raffle_generator 7 | 8 | 9 | @pytest.mark.parametrize("kBT", [0.4]) 10 | @pytest.mark.parametrize("width", [ 11 | [0.025, np.pi/200.0, np.pi/200.0] 12 | ]) 13 | @pytest.mark.parametrize("grid_spacing", [0.5, 0.25, 0.1, 0.075, 0.05]) 14 | @pytest.mark.benchmark( 15 | group="min_placement", 16 | min_rounds=5, 17 | timer=time.time, 18 | disable_gc=True, 19 | warmup=False 20 | ) 21 | def test_min_placement(benchmark, grid_spacing, kBT, width): 22 | 23 | calc = CHGNetCalculator() 24 | host = Atoms('C', positions=[(0, 0, 0)], cell=[3.567, 3.567, 3.567], pbc=True, calculator=calc) 25 | 26 | # Initialize generator 27 | generator = raffle_generator() 28 | 29 | # set energy scale 30 | generator.distributions.set_kBT(kBT) 31 | 32 | # set the distribution function widths (2-body, 3-body, 4-body) 33 | generator.distributions.set_width(width) 34 | 35 | energies = {element: 0.0 for element in ['C']} 36 | generator.distributions.set_element_energies(energies) 37 | 38 | generator.set_grid(grid_spacing=grid_spacing) 39 | generator.set_host(host) 40 | 41 | initial_database = [Atoms('C', positions=[(0, 0, 0)], cell=[8, 8, 8], pbc=True, calculator=calc)] 42 | 43 | generator.distributions.create(initial_database) 44 | 45 | benchmark.extra_info = { 46 | "kBT": kBT, 47 | "width": width, 48 | "grid_spacing": grid_spacing 49 | } 50 | 51 | 52 | # Measure time for distributions.create() 53 | result = benchmark(generator.generate, 54 | num_structures = 1, 55 | stoichiometry = {'C': 1}, 56 | seed = 0, 57 | method_ratio = { 58 | 'void': 0.0, 59 | 'rand': 0.0, 60 | 'walk': 0.0, 61 | 'grow': 0.0, 62 | 'min': 1.0 63 | 64 | }, 65 | verbose = 0 66 | ) 67 | 68 | return result 69 | 70 | if __name__ == '__main__': 71 | grid_spacings = [0.5, 0.25, 0.1, 0.075, 0.05] 72 | results = [] 73 | 74 | for grid_spacing in grid_spacings: 75 | for _ in range(5): # Run the benchmark 5 times for each grid size 76 | result = test_min_placement(lambda x: x, grid_spacing, 0.4, [0.025, np.pi/200.0, np.pi/200.0]) 77 | results.append({ 78 | 'grid_spacing': grid_spacing, 79 | 'time': result 80 | }) 81 | 82 | # Print results 83 | print("\nBenchmark Results:") 84 | print("-" * 40) 85 | print(f"{'Grid Size':<10} {'Time (s)':<10}") 86 | print("-" * 40) 87 | for result in results: 88 | print(f"{result['grid_spacing']:<10} {result['time']:<10.4f}") 89 | -------------------------------------------------------------------------------- /example/python_pkg/benchmarks/placement_methods.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import time 3 | import numpy as np 4 | from ase import Atoms 5 | from chgnet.model import CHGNetCalculator 6 | from raffle.generator import raffle_generator 7 | 8 | 9 | @pytest.mark.parametrize("kBT", [0.4]) 10 | @pytest.mark.parametrize("width", [ 11 | [0.025, np.pi/200.0, np.pi/200.0] 12 | ]) 13 | @pytest.mark.parametrize("grid_spacing", [0.5, 0.25, 0.1, 0.075, 0.05]) 14 | @pytest.mark.parametrize("method_ratio", [ 15 | {'void': 0.0, 'rand': 0.0, 'walk': 0.0, 'grow': 0.0, 'min': 1.0}, 16 | {'void': 0.0, 'rand': 0.0, 'walk': 0.0, 'grow': 1.0, 'min': 0.0}, 17 | {'void': 0.0, 'rand': 0.0, 'walk': 1.0, 'grow': 0.0, 'min': 0.0}, 18 | {'void': 0.0, 'rand': 1.0, 'walk': 0.0, 'grow': 0.0, 'min': 0.0}, 19 | {'void': 1.0, 'rand': 0.0, 'walk': 0.0, 'grow': 0.0, 'min': 0.0} 20 | ]) 21 | @pytest.mark.benchmark( 22 | group="placement_methods", 23 | min_rounds=5, 24 | timer=time.time, 25 | disable_gc=True, 26 | warmup=False 27 | ) 28 | def test_placement_methods(benchmark, grid_spacing, kBT, width, method_ratio): 29 | 30 | calc = CHGNetCalculator() 31 | host = Atoms('C', positions=[(0, 0, 0)], cell=[3.567, 3.567, 3.567], pbc=True, calculator=calc) 32 | 33 | # Initialize generator 34 | generator = raffle_generator() 35 | 36 | # set energy scale 37 | generator.distributions.set_kBT(kBT) 38 | 39 | # set the distribution function widths (2-body, 3-body, 4-body) 40 | generator.distributions.set_width(width) 41 | 42 | energies = {element: 0.0 for element in ['C']} 43 | generator.distributions.set_element_energies(energies) 44 | 45 | generator.set_grid(grid_spacing=grid_spacing) 46 | generator.set_host(host) 47 | 48 | initial_database = [Atoms('C', positions=[(0, 0, 0)], cell=[8, 8, 8], pbc=True, calculator=calc)] 49 | 50 | generator.distributions.create(initial_database) 51 | 52 | benchmark.extra_info = { 53 | "kBT": kBT, 54 | "width": width, 55 | "grid_spacing": grid_spacing, 56 | "method_ratio": method_ratio 57 | } 58 | 59 | # Measure time for distributions.create() 60 | result = benchmark(generator.generate, 61 | num_structures = 1, 62 | stoichiometry = {'C': 1}, 63 | seed = 0, 64 | method_ratio = method_ratio, 65 | verbose = 0 66 | ) 67 | 68 | return result 69 | 70 | if __name__ == '__main__': 71 | grid_spacings = [0.5, 0.25, 0.1, 0.075, 0.05] 72 | results = [] 73 | 74 | for grid_spacing in grid_spacings: 75 | for _ in range(5): # Run the benchmark 5 times for each grid size 76 | result = test_placement_methods(lambda x: x, grid_spacing, 0.4, [0.025, np.pi/200.0, np.pi/200.0]) 77 | results.append({ 78 | 'grid_spacing': grid_spacing, 79 | 'time': result 80 | }) 81 | 82 | # Print results 83 | print("\nBenchmark Results:") 84 | print("-" * 40) 85 | print(f"{'Grid Size':<10} {'Time (s)':<10}") 86 | print("-" * 40) 87 | for result in results: 88 | print(f"{result['grid_spacing']:<10} {result['time']:<10.4f}") 89 | -------------------------------------------------------------------------------- /example/python_pkg/diamond/POSCAR_host: -------------------------------------------------------------------------------- 1 | C8 2 | 1.000000000 3 | 3.560745109 0.000000000 0.000000000 4 | 0.000000000 3.560745109 0.000000000 5 | 0.000000000 0.000000000 7.121490218 6 | C 7 | 8 8 | Direct 9 | 0.000000000 0.000000000 0.000000000 10 | 0.500000000 0.500000000 0.000000000 11 | 0.500000000 0.000000000 0.250000000 12 | 0.000000000 0.500000000 0.250000000 13 | 0.250000000 0.250000000 0.125000000 14 | 0.750000000 0.750000000 0.125000000 15 | 0.750000000 0.250000000 0.375000000 16 | 0.250000000 0.750000000 0.375000000 17 | -------------------------------------------------------------------------------- /example/python_pkg/diamond/POSCAR_host_3x3: -------------------------------------------------------------------------------- 1 | C8 2 | 1.000000000 3 | 14.242980436 0.000000000 0.000000000 4 | 0.000000000 14.242980436 0.000000000 5 | 0.000000000 0.000000000 7.121490218 6 | C 7 | 72 8 | Direct 9 | 0.000000000 0.000000000 0.000000000 10 | 0.333333333 0.000000000 0.000000000 11 | 0.666666667 0.000000000 0.000000000 12 | 0.000000000 0.333333333 0.000000000 13 | 0.333333333 0.333333333 0.000000000 14 | 0.666666667 0.333333333 0.000000000 15 | 0.000000000 0.666666667 0.000000000 16 | 0.333333333 0.666666667 0.000000000 17 | 0.666666667 0.666666667 0.000000000 18 | 0.166666667 0.166666667 0.000000000 19 | 0.500000000 0.166666667 0.000000000 20 | 0.833333333 0.166666667 0.000000000 21 | 0.166666667 0.500000000 0.000000000 22 | 0.500000000 0.500000000 0.000000000 23 | 0.833333333 0.500000000 0.000000000 24 | 0.166666667 0.833333333 0.000000000 25 | 0.500000000 0.833333333 0.000000000 26 | 0.833333333 0.833333333 0.000000000 27 | 0.166666667 0.000000000 0.250000000 28 | 0.500000000 0.000000000 0.250000000 29 | 0.833333333 0.000000000 0.250000000 30 | 0.166666667 0.333333333 0.250000000 31 | 0.500000000 0.333333333 0.250000000 32 | 0.833333333 0.333333333 0.250000000 33 | 0.166666667 0.666666667 0.250000000 34 | 0.500000000 0.666666667 0.250000000 35 | 0.833333333 0.666666667 0.250000000 36 | 0.000000000 0.166666667 0.250000000 37 | 0.333333333 0.166666667 0.250000000 38 | 0.666666667 0.166666667 0.250000000 39 | 0.000000000 0.500000000 0.250000000 40 | 0.333333333 0.500000000 0.250000000 41 | 0.666666667 0.500000000 0.250000000 42 | 0.000000000 0.833333333 0.250000000 43 | 0.333333333 0.833333333 0.250000000 44 | 0.666666667 0.833333333 0.250000000 45 | 0.083333333 0.083333333 0.125000000 46 | 0.416666667 0.083333333 0.125000000 47 | 0.750000000 0.083333333 0.125000000 48 | 0.083333333 0.416666667 0.125000000 49 | 0.416666667 0.416666667 0.125000000 50 | 0.750000000 0.416666667 0.125000000 51 | 0.083333333 0.750000000 0.125000000 52 | 0.416666667 0.750000000 0.125000000 53 | 0.750000000 0.750000000 0.125000000 54 | 0.250000000 0.250000000 0.125000000 55 | 0.583333333 0.250000000 0.125000000 56 | 0.916666667 0.250000000 0.125000000 57 | 0.250000000 0.583333333 0.125000000 58 | 0.583333333 0.583333333 0.125000000 59 | 0.916666667 0.583333333 0.125000000 60 | 0.250000000 0.916666667 0.125000000 61 | 0.583333333 0.916666667 0.125000000 62 | 0.916666667 0.916666667 0.125000000 63 | 0.250000000 0.083333333 0.375000000 64 | 0.583333333 0.083333333 0.375000000 65 | 0.916666667 0.083333333 0.375000000 66 | 0.250000000 0.416666667 0.375000000 67 | 0.583333333 0.416666667 0.375000000 68 | 0.916666667 0.416666667 0.375000000 69 | 0.250000000 0.750000000 0.375000000 70 | 0.583333333 0.750000000 0.375000000 71 | 0.916666667 0.750000000 0.375000000 72 | 0.083333333 0.250000000 0.375000000 73 | 0.416666667 0.250000000 0.375000000 74 | 0.750000000 0.250000000 0.375000000 75 | 0.083333333 0.583333333 0.375000000 76 | 0.416666667 0.583333333 0.375000000 77 | 0.750000000 0.583333333 0.375000000 78 | 0.083333333 0.916666667 0.375000000 79 | 0.416666667 0.916666667 0.375000000 80 | 0.750000000 0.916666667 0.375000000 81 | -------------------------------------------------------------------------------- /example/python_pkg/graphite/POSCAR_host_graphene: -------------------------------------------------------------------------------- 1 | C4 2 | 1.000000000 3 | 3.700936892 -6.410210733 0.000000000 4 | 3.700936892 6.410210733 0.000000000 5 | 0.000000000 0.000000000 7.803073000 6 | C 7 | 18 8 | Direct 9 | 0.000000000 0.000000000 0.250000000 10 | 0.333333333 0.000000000 0.250000000 11 | 0.666666667 0.000000000 0.250000000 12 | 0.000000000 0.333333333 0.250000000 13 | 0.333333333 0.333333333 0.250000000 14 | 0.666666667 0.333333333 0.250000000 15 | 0.000000000 0.666666667 0.250000000 16 | 0.333333333 0.666666667 0.250000000 17 | 0.666666667 0.666666667 0.250000000 18 | 0.111111111 0.222222222 0.250000000 19 | 0.444444444 0.222222222 0.250000000 20 | 0.777777778 0.222222222 0.250000000 21 | 0.111111111 0.555555556 0.250000000 22 | 0.444444444 0.555555556 0.250000000 23 | 0.777777778 0.555555556 0.250000000 24 | 0.111111111 0.888888889 0.250000000 25 | 0.444444444 0.888888889 0.250000000 26 | 0.777777778 0.888888889 0.250000000 -------------------------------------------------------------------------------- /example/python_pkg/graphite/POSCAR_host_graphite_vacancy: -------------------------------------------------------------------------------- 1 | C4 2 | 1.000000000 3 | 3.700936892 -6.410210733 0.000000000 4 | 3.700936892 6.410210733 0.000000000 5 | 0.000000000 0.000000000 7.803073000 6 | C 7 | 35 8 | Direct 9 | 0.000000000 0.000000000 0.250000000 10 | 0.333333333 0.000000000 0.250000000 11 | 0.666666667 0.000000000 0.250000000 12 | 0.000000000 0.333333333 0.250000000 13 | 0.333333333 0.333333333 0.250000000 14 | 0.666666667 0.333333333 0.250000000 15 | 0.000000000 0.666666667 0.250000000 16 | 0.333333333 0.666666667 0.250000000 17 | 0.666666667 0.666666667 0.250000000 18 | 0.000000000 0.000000000 0.750000000 19 | 0.333333333 0.000000000 0.750000000 20 | 0.666666667 0.000000000 0.750000000 21 | 0.000000000 0.333333333 0.750000000 22 | 0.333333333 0.333333333 0.750000000 23 | 0.666666667 0.333333333 0.750000000 24 | 0.000000000 0.666666667 0.750000000 25 | 0.333333333 0.666666667 0.750000000 26 | 0.666666667 0.666666667 0.750000000 27 | 0.111111111 0.222222222 0.250000000 28 | 0.444444444 0.222222222 0.250000000 29 | 0.777777778 0.222222222 0.250000000 30 | 0.111111111 0.555555556 0.250000000 31 | 0.444444444 0.555555556 0.250000000 32 | 0.777777778 0.555555556 0.250000000 33 | 0.111111111 0.888888889 0.250000000 34 | 0.444444444 0.888888889 0.250000000 35 | 0.777777778 0.888888889 0.250000000 36 | 0.222222222 0.111111111 0.750000000 37 | 0.555555556 0.111111111 0.750000000 38 | 0.888888889 0.111111111 0.750000000 39 | 0.222222222 0.444444444 0.750000000 40 | 0.555555556 0.444444444 0.750000000 41 | 0.888888889 0.444444444 0.750000000 42 | 0.222222222 0.777777778 0.750000000 43 | 0.555555556 0.777777778 0.750000000 44 | 45 | -------------------------------------------------------------------------------- /example/python_pkg/graphite/POSCAR_host_missing_layer: -------------------------------------------------------------------------------- 1 | C 2 | 1.000000000 3 | 1.233645631 -2.136736911 0.000000000 4 | 1.233645631 2.136736911 0.000000000 5 | 0.000000000 0.000000000 15.606146000 6 | C 7 | 6 8 | Direct 9 | 0.000000000 0.000000000 0.125000000 10 | 0.000000000 0.000000000 0.375000000 11 | 0.000000000 0.000000000 0.875000000 12 | 0.333333333 0.666666667 0.125000000 13 | 0.666666667 0.333333333 0.375000000 14 | 0.666666667 0.333333333 0.875000000 15 | 16 | -------------------------------------------------------------------------------- /example/python_pkg/perovskites/database.xyz: -------------------------------------------------------------------------------- 1 | 5 2 | Lattice="3.93796462 0.0 0.0 0.0 3.93796462 0.0 0.0 0.0 3.93891698" Properties=species:S:1:pos:R:3:forces:R:3 energy=-40.12032428 stress="-0.0008424844130642804 -0.0 -0.0 -0.0 -0.0008424844130642804 0.0 -0.0 0.0 -0.000512511616596921" free_energy=-40.12032428 pbc="T T T" 3 | Sr 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 4 | Ti 1.96898231 1.96898231 1.96945849 0.00000000 0.00000000 0.00000000 5 | O 0.00000000 1.96898231 1.96945849 0.00000000 0.00000000 0.00000000 6 | O 1.96898231 0.00000000 1.96945849 0.00000000 0.00000000 0.00000000 7 | O 1.96898231 1.96898231 0.00000000 0.00000000 0.00000000 0.00000000 8 | 5 9 | Lattice="4.03084376 0.0 0.0 0.0 4.03084376 0.0 0.0 0.0 4.03254345" Properties=species:S:1:pos:R:3:forces:R:3 energy=-40.00295673 stress="-0.0002488092354018701 -0.0 -0.0 -0.0 -0.0002488092354018701 0.0 -0.0 0.0 0.0002890913610814811" free_energy=-40.00295673 pbc="T T T" 10 | Ba 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 0.00000000 11 | Ti 2.01542188 2.01542188 2.01627173 0.00000000 0.00000000 0.00000000 12 | O 2.01542188 0.00000000 2.01627173 0.00000000 0.00000000 0.00000000 13 | O 0.00000000 2.01542188 2.01627173 0.00000000 0.00000000 0.00000000 14 | O 2.01542188 2.01542188 0.00000000 0.00000000 0.00000000 0.00000000 15 | -------------------------------------------------------------------------------- /example/python_pkg/perovskites/run.py: -------------------------------------------------------------------------------- 1 | # This script demonstrates how to use the raffle generator to generate perovskite supperlattice structures 2 | 3 | # The script reads a host structure from a POSCAR file, and sets it as the host structure for the generator. 4 | 5 | # import standard libraries 6 | import os 7 | import numpy as np 8 | 9 | # import raffle library 10 | from raffle.generator import raffle_generator 11 | 12 | # import ASE (Atomic Simulation Environment) modules 13 | from ase import Atoms 14 | from ase.io import read, write 15 | from ase.optimize import BFGS 16 | 17 | # import CHGNet calculator (for MLP energy evaluation) 18 | from chgnet.model.dynamics import CHGNetCalculator 19 | 20 | # load CHGNet calculator 21 | print("Initialising CHGNet calculator") 22 | calculator = CHGNetCalculator(model=None) 23 | 24 | # set up an instance of the raffle generator 25 | print("Initialising raffle generator") 26 | generator = raffle_generator() 27 | 28 | # read the host structure from a POSCAR file 29 | print("Reading host") 30 | host = read("POSCAR_host") 31 | generator.set_host(host) 32 | print("Host read") 33 | 34 | host.calc = calculator 35 | print("host energy: ", host.get_potential_energy()) 36 | 37 | # set the element reference energies 38 | print("Setting element energies") 39 | generator.distributions.set_element_energies( 40 | { 41 | 'Ba': -1.9030744, 42 | 'Sr': -1.5478236, 43 | 'Ti': -7.842818, 44 | 'O': -4.3707458 45 | } 46 | ) 47 | 48 | # set the distribution function widths (2-body, 3-body, 4-body) 49 | print("Reading database") 50 | database = read("database.xyz", index=":") 51 | 52 | 53 | # create the distribution functions 54 | print("Setting database") 55 | generator.distributions.create(database, deallocate_systems=False) 56 | print("Database set") 57 | 58 | # print the distribution functions to a file 59 | print("Printing distributions") 60 | generator.distributions.write("distributions.txt") 61 | generator.distributions.write_2body("df2.txt") 62 | generator.distributions.write_3body("df3.txt") 63 | generator.distributions.write_4body("df4.txt") 64 | 65 | # check the element energies and bond radii 66 | print("Checking element energies") 67 | print(generator.distributions.get_element_energies()) 68 | print("Checking bond radii") 69 | print(generator.distributions.get_bond_radii()) 70 | 71 | # set the grid for the host cell 72 | print("Setting bins (discretisation of host cell)") 73 | generator.set_grid(grid=[8,8,128], grid_offset=[0.0, 0.0, 0.0]) 74 | print(generator.grid) 75 | 76 | # set the stoichiometry for the structures to be generated 77 | print("Setting stoichiometry to insert") 78 | stoich_dict = { 'Ba': 4, 'Sr': 4, 'Ti': 8, 'O': 24 } 79 | 80 | # generate structures 81 | num_structures_old = 0 82 | optimise_structure = True 83 | for iter in range(20): 84 | print(f"Iteration {iter}") 85 | print("Generating...") 86 | # this is the main function to generate structures 87 | generator.generate(num_structures=1, stoichiometry=stoich_dict, seed=0+iter, verbose=0, method_ratio={"void":0.001, "walk":0.0, "min":1.0}) 88 | print("Generated") 89 | 90 | print("Getting structures") 91 | print("number of structures supposed to be generated: ", generator.num_structures) 92 | generated_structures = generator.get_structures() 93 | print("actual number allocated: ",len(generated_structures)) 94 | print("Got structures") 95 | 96 | # check if directory iteration[iter] exists, if not create it 97 | iterdir = f"iteration{iter}/" 98 | if not os.path.exists(iterdir): 99 | os.makedirs(iterdir) 100 | 101 | # get energies using MLPs and optimise the structures 102 | num_structures_new = len(generated_structures) 103 | for i, atoms in enumerate(generated_structures): 104 | if(i < num_structures_old): 105 | continue 106 | inew = i - num_structures_old 107 | atoms.calc = calculator 108 | if optimise_structure: 109 | optimizer = BFGS(atoms, trajectory = "traje.traj") 110 | optimizer.run(fmax=0.05) 111 | print(f"Structure {inew} optimised") 112 | atoms.get_potential_energy() 113 | print(f"Structure {inew} energy: {atoms.get_potential_energy()}") 114 | write(iterdir+f"POSCAR_{inew}", atoms) 115 | 116 | # update the distribution functions 117 | print("Updating distributions") 118 | generator.distributions.update(generated_structures[num_structures_old:], deallocate_systems=False) 119 | 120 | # print the new distribution functions to a file 121 | print("Printing distributions") 122 | generator.distributions.write(iterdir+"distributions.txt") 123 | generator.distributions.write_2body(iterdir+"df2.txt") 124 | generator.distributions.write_3body(iterdir+"df3.txt") 125 | generator.distributions.write_4body(iterdir+"df4.txt") 126 | 127 | # update the number of structures generated 128 | num_structures_old = num_structures_new 129 | -------------------------------------------------------------------------------- /example/python_pkg/requirements.txt: -------------------------------------------------------------------------------- 1 | mace-torch==0.3.12 2 | chgnet==0.4.0 3 | joblib==1.4.2 4 | ase>=3.23.0 5 | -------------------------------------------------------------------------------- /ford.md: -------------------------------------------------------------------------------- 1 | project: 2 | summary: A Fortran library and executable for structure prediction at material interfaces 3 | src_dir: ./src/fortran 4 | ./app 5 | exclude: **/f90wrap_*.f90 6 | output_dir: docs/html 7 | preprocess: false 8 | predocmark: !! 9 | fpp_extensions: f90 10 | F90 11 | display: public 12 | protected 13 | private 14 | source: true 15 | graph: true 16 | md_extensions: markdown.extensions.toc 17 | coloured_edges: true 18 | sort: permission-alpha 19 | author: RAFFLE developers 20 | github: https://github.com/ExeQuantCode 21 | print_creation_date: true 22 | creation_date: %Y-%m-%d %H:%M %z 23 | project_github: https://github.com/ExeQuantCode/raffle 24 | project_download: https://github.com/ExeQuantCode/raffle/releases 25 | github: https://github.com/ExeQuantCode 26 | 27 | {!README.md!} -------------------------------------------------------------------------------- /fpm.toml: -------------------------------------------------------------------------------- 1 | name = "raffle" 2 | version = "1.0.1" 3 | author = "Ned Thaddeus Taylor" 4 | maintainer = "n.t.taylor@exeter.ac.uk" 5 | description = "A Fortran library and executable for structure prediction at material interfaces" 6 | 7 | [preprocess] 8 | [preprocess.cpp] 9 | suffixes = ["F90", "f90"] 10 | 11 | [library] 12 | source-dir="src/fortran" 13 | 14 | [dependencies] 15 | openmp = "*" 16 | 17 | [fortran] 18 | implicit-typing = false 19 | implicit-external = false 20 | source-form = "free" 21 | 22 | [[executable]] 23 | name="raffle_executable" 24 | source-dir="app" 25 | main="main.f90" 26 | -------------------------------------------------------------------------------- /kind_map: -------------------------------------------------------------------------------- 1 | { 2 | 'real': {'': 'float', 3 | '4': 'float', 4 | '8': 'double', 5 | 'dp': 'double', 6 | 'idp':'double', 7 | 'real32': 'float'}, 8 | 'complex' : {'': 'complex_float', 9 | '8' : 'complex_double', 10 | '16': 'complex_long_double', 11 | 'dp': 'complex_double', 12 | 'real32': 'complex_float'}, 13 | 'integer' : {'' : 'int', 14 | '4': 'int', 15 | '8': 'long_long', 16 | 'dp': 'long_long', 17 | 'quadint_k': 'long_long'} 18 | } -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "f90wrap>=0.2.14,<=0.2.16", 4 | "numpy>=1.26.4,<=2.2", 5 | "meson~=1.6.0", 6 | "cython~=3.0.11", 7 | "scikit-build-core", 8 | ] 9 | build-backend = "scikit_build_core.build" 10 | 11 | [tool.scikit-build] 12 | cmake.version = "CMakeLists.txt" 13 | ninja.version = ">=1.10" 14 | cmake.build-type = "Release" 15 | cmake.source-dir = "." 16 | cmake.args = [ 17 | "-DBUILD_PYTHON=On", 18 | "-DBUILD_EXECUTABLE=Off", 19 | "-DREMAKE_F90WRAP=Off", 20 | ] 21 | sdist.cmake = true 22 | wheel.cmake = true 23 | build-dir="build/{wheel_tag}" 24 | wheel.expand-macos-universal-tags = true 25 | ninja.make-fallback = true 26 | sdist.reproducible = true 27 | # dev purposes only 28 | build.verbose = false 29 | 30 | [project] 31 | name = "raffle" 32 | dynamic = ["version"] 33 | dependencies = [ 34 | "numpy>=1.26.4,<=2.2", 35 | "f90wrap>=0.2.14,<=0.2.16", 36 | ] 37 | requires-python = ">=3.11,<3.14" 38 | authors = [ 39 | { name = "Ned Thaddeus Taylor", email = "n.t.taylor@exeter.ac.uk" }, 40 | { name = "Joe Pitfield", email = "joepitfield@gmail.com" }, 41 | { name = "Steven Paul Hepplestone", email = "s.p.hepplestone@exeter.ac.uk" }, 42 | ] 43 | description = "A material interface structure prediction package" 44 | readme = "README.md" 45 | license = { text = 'GNU General Public License v3.0 or later'} 46 | classifiers = [ 47 | "Development Status :: 4 - Beta", 48 | "Intended Audience :: Science/Research", 49 | "Programming Language :: Python :: 3.11", 50 | "Programming Language :: Python :: 3.12", 51 | "Programming Language :: Python :: 3.13", 52 | "Programming Language :: Fortran", 53 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", 54 | "Operating System :: OS Independent", 55 | ] 56 | 57 | [project.urls] 58 | Homepage = "https://github.com/ExeQuantCode/raffle" 59 | Documentation = "https://raffle-fortran.readthedocs.io/" 60 | Repository = "https://github.com/ExeQuantCode/raffle" 61 | Issues = "https://github.com/ExeQuantCode/raffle/issues" 62 | 63 | [project.optional-dependencies] 64 | ase = ["ase>=3.23.0"] 65 | no-ase = [] 66 | tests = [ 67 | "pytest", 68 | "pytest-cov", 69 | "parameterized", 70 | "unittest", 71 | ] 72 | 73 | [tool.scikit-build.metadata.version] 74 | provider = "scikit_build_core.metadata.regex" 75 | input = "fpm.toml" 76 | regex = '(?i)^version *= \"(?P.+?)\"' 77 | -------------------------------------------------------------------------------- /src/fortran/lib/mod_constants.f90: -------------------------------------------------------------------------------- 1 | module raffle__constants 2 | !! Module with global constants 3 | !! 4 | !! This module contains global constants that may be used throughout the 5 | !! library. 6 | implicit none 7 | integer, parameter, public :: real32 = Selected_real_kind(6,37)!(15,307) 8 | real(real32), parameter, public :: pi = 4._real32 * atan(1._real32) 9 | real(real32), parameter, public :: c = 0.26246582250210965422_real32 10 | real(real32), parameter, public :: c_vasp = 0.262465831_real32 11 | real(real32), parameter, public :: INF = huge(0._real32) 12 | complex(real32), parameter, public :: imag=(0._real32, 1._real32) 13 | end module raffle__constants 14 | -------------------------------------------------------------------------------- /src/fortran/lib/mod_geom_utils.f90: -------------------------------------------------------------------------------- 1 | module raffle__geom_utils 2 | !! Module to contain all geometry-manipulation related procedures 3 | !! 4 | !! This module contains procedures that are used to manipulate the geometry 5 | !! of the system. The geometry type used is defined in the geom_rw module. 6 | use raffle__constants, only: pi,real32 7 | use raffle__geom_rw, only: basis_type 8 | use raffle__misc_linalg, only: modu, get_angle 9 | implicit none 10 | 11 | 12 | private 13 | 14 | public :: basis_merge 15 | 16 | 17 | contains 18 | 19 | !############################################################################### 20 | function basis_merge(basis1,basis2,length,map1,map2) result(output) 21 | !! Merge two supplied bases 22 | !! 23 | !! Merge two bases assuming that the lattice is the same 24 | implicit none 25 | 26 | ! Arguments 27 | type(basis_type) :: output 28 | !! Output merged basis. 29 | class(basis_type), intent(in) :: basis1, basis2 30 | !! Input bases to merge. 31 | integer, intent(in), optional :: length 32 | !! Number of dimensions for atomic positions (default 3). 33 | integer, allocatable, dimension(:,:,:), optional, intent(inout) :: map1,map2 34 | !! Maps for atoms in the two bases. 35 | 36 | ! Local variables 37 | integer :: i, j, k, itmp, dim 38 | !! Loop counters. 39 | logical :: lmap 40 | !! Boolean for map presence. 41 | integer, allocatable, dimension(:) :: match 42 | !! Array to match species. 43 | integer, allocatable, dimension(:,:,:) :: new_map 44 | !! New map for merged basis. 45 | 46 | 47 | 48 | !--------------------------------------------------------------------------- 49 | ! set up number of species 50 | !--------------------------------------------------------------------------- 51 | dim=3 52 | if(present(length)) dim=length 53 | 54 | allocate(match(basis2%nspec)) 55 | match=0 56 | output%nspec=basis1%nspec 57 | do i = 1, basis2%nspec 58 | if(.not.any(basis2%spec(i)%name.eq.basis1%spec(:)%name))then 59 | output%nspec=output%nspec+1 60 | end if 61 | end do 62 | allocate(output%spec(output%nspec)) 63 | output%spec(:basis1%nspec)%num=basis1%spec(:)%num 64 | output%spec(:basis1%nspec)%name=basis1%spec(:)%name 65 | 66 | 67 | write(output%sysname,'(A,"+",A)') & 68 | trim(basis1%sysname),trim(basis2%sysname) 69 | k=basis1%nspec 70 | spec1check: do i = 1, basis2%nspec 71 | do j = 1, basis1%nspec 72 | if(basis2%spec(i)%name.eq.basis1%spec(j)%name)then 73 | output%spec(j)%num=output%spec(j)%num+basis2%spec(i)%num 74 | match(i)=j 75 | cycle spec1check 76 | end if 77 | end do 78 | k=k+1 79 | match(i)=k 80 | output%spec(k)%num=basis2%spec(i)%num 81 | output%spec(k)%name=basis2%spec(i)%name 82 | end do spec1check 83 | 84 | 85 | !--------------------------------------------------------------------------- 86 | ! if map is present, sets up new map 87 | !--------------------------------------------------------------------------- 88 | lmap = .false. 89 | if_map: if(present(map1).and.present(map2))then 90 | if(all(map1.eq.-1)) exit if_map 91 | lmap = .true. 92 | allocate(new_map(& 93 | output%nspec,& 94 | maxval(output%spec(:)%num,dim=1),2)) 95 | new_map = 0 96 | end if if_map 97 | 98 | 99 | !--------------------------------------------------------------------------- 100 | ! set up atoms in merged basis 101 | !--------------------------------------------------------------------------- 102 | do i = 1, basis1%nspec 103 | allocate(output%spec(i)%atom(output%spec(i)%num,dim)) 104 | output%spec(i)%atom(:,:)=0._real32 105 | output%spec(i)%atom(1:basis1%spec(i)%num,:3)=basis1%spec(i)%atom(:,:3) 106 | if(lmap) new_map(i,:basis1%spec(i)%num,:)=map1(i,:basis1%spec(i)%num,:) 107 | end do 108 | do i = 1, basis2%nspec 109 | if(match(i).gt.basis1%nspec)then 110 | allocate(output%spec(match(i))%atom(output%spec(match(i))%num,dim)) 111 | output%spec(match(i))%atom(:,:)=0._real32 112 | output%spec(match(i))%atom(:,:3)=basis2%spec(i)%atom(:,:3) 113 | if(lmap) new_map(match(i),:basis2%spec(i)%num,:) = & 114 | map2(i,:basis2%spec(i)%num,:) 115 | else 116 | itmp=basis1%spec(match(i))%num 117 | output%spec(match(i))%atom(itmp+1:basis2%spec(i)%num+itmp,:3) = & 118 | basis2%spec(i)%atom(:,:3) 119 | if(lmap) new_map(match(i),itmp+1:basis2%spec(i)%num+itmp,:) = & 120 | map2(i,:basis2%spec(i)%num,:) 121 | end if 122 | end do 123 | output%natom=sum(output%spec(:)%num) 124 | 125 | 126 | if(lmap) call move_alloc(new_map,map1) 127 | 128 | return 129 | end function basis_merge 130 | !############################################################################### 131 | 132 | end module raffle__geom_utils 133 | -------------------------------------------------------------------------------- /src/fortran/lib/mod_io_utils.F90: -------------------------------------------------------------------------------- 1 | module raffle__io_utils 2 | !! Module for handling errors and io calls in the program. 3 | !! 4 | !! This module provides the expected procedure for stopping a program. 5 | !! If in testing mode, the stop can be suppressed. 6 | implicit none 7 | logical :: test_error_handling = .false. 8 | 9 | logical :: suppress_warnings = .false. 10 | character(len=*), parameter :: raffle__version__ = "1.0.1" 11 | 12 | private 13 | 14 | public :: raffle__version__ 15 | public :: test_error_handling, suppress_warnings 16 | public :: stop_program, print_warning 17 | public :: print_version, print_build_info 18 | 19 | 20 | contains 21 | 22 | !############################################################################### 23 | subroutine stop_program(message, exit_code, block_stop) 24 | !! Stop the program and print an error message. 25 | implicit none 26 | character(len=*), intent(in) :: message 27 | integer, intent(in), optional :: exit_code 28 | logical, intent(in), optional :: block_stop 29 | 30 | integer :: exit_code_ 31 | logical :: block_stop_ 32 | 33 | if(present(exit_code)) then 34 | exit_code_ = exit_code 35 | else 36 | exit_code_ = 1 37 | end if 38 | if(present(block_stop)) then 39 | block_stop_ = block_stop 40 | else 41 | block_stop_ = .false. 42 | end if 43 | 44 | write(0,*) 'ERROR: ', trim(message) 45 | if(.not.block_stop_)then 46 | if(.not.test_error_handling) then 47 | stop exit_code_ 48 | end if 49 | end if 50 | end subroutine stop_program 51 | !############################################################################### 52 | 53 | 54 | !############################################################################### 55 | subroutine print_warning(message) 56 | !! Print a warning message 57 | implicit none 58 | character(len=*), intent(in) :: message 59 | 60 | if(.not.suppress_warnings) then 61 | write(0,*) 'WARNING: ', trim(message) 62 | end if 63 | end subroutine print_warning 64 | !############################################################################### 65 | 66 | 67 | !############################################################################### 68 | subroutine print_version() 69 | !! Print the version number of the program. 70 | implicit none 71 | 72 | write(*,'("version: ",A)') raffle__version__ 73 | end subroutine print_version 74 | !############################################################################### 75 | 76 | 77 | !############################################################################### 78 | subroutine print_build_info() 79 | !! Print the build information of the program. 80 | implicit none 81 | 82 | write(*,'("RAFFLE: pseudoRandom Approach For Finding Local Energy minima")') 83 | call print_version() 84 | write(*,'(" (build ",A,1X,A,")")') __DATE__, __TIME__ 85 | 86 | end subroutine print_build_info 87 | !############################################################################### 88 | 89 | end module raffle__io_utils 90 | -------------------------------------------------------------------------------- /src/fortran/lib/mod_misc_maths.f90: -------------------------------------------------------------------------------- 1 | module raffle__misc_maths 2 | !! Module for miscellaneous mathematical functions. 3 | use raffle__io_utils, only: stop_program 4 | use raffle__constants, only: real32 5 | implicit none 6 | 7 | 8 | private 9 | 10 | public :: lnsum, triangular_number, set_difference 11 | 12 | 13 | 14 | contains 15 | 16 | !############################################################################### 17 | function lnsum(n) 18 | !! Return the sum of the logs of the integers from 1 to n. 19 | implicit none 20 | 21 | ! Arguments 22 | integer :: n 23 | !! The upper limit of the range. 24 | real(real32) :: lnsum 25 | !! The sum of the logs of the integers from 1 to n. 26 | 27 | ! Local variables 28 | integer :: i 29 | !! Loop index. 30 | 31 | lnsum = 0._real32 32 | do i = 1, n 33 | lnsum = lnsum + log( real(i, real32) ) 34 | end do 35 | 36 | return 37 | end function lnsum 38 | !############################################################################### 39 | 40 | 41 | !############################################################################### 42 | integer function triangular_number(n) 43 | !! Return the nth triangular number. 44 | implicit none 45 | 46 | ! Arguments 47 | integer :: n 48 | !! The index of the triangular number to return. 49 | triangular_number = n * ( n + 1 ) / 2 50 | end function triangular_number 51 | !############################################################################### 52 | 53 | 54 | !############################################################################### 55 | function set_difference(a, b, set_min_zero) 56 | !! Return the set difference of two arrays. 57 | implicit none 58 | 59 | ! Arguments 60 | real(real32), dimension(:), intent(in) :: a 61 | !! The first array. 62 | real(real32), dimension(:), intent(in) :: b 63 | !! The second array. 64 | logical, optional :: set_min_zero 65 | !! Boolean to set the maximum value of the output array to zero. 66 | real(real32), dimension(size(a)) :: set_difference 67 | !! The set difference of the two arrays. 68 | 69 | ! Local variables 70 | integer :: i 71 | !! Loop indices. 72 | logical :: set_min_zero_ 73 | !! Boolean to set all values below zero to zero. 74 | 75 | 76 | if(present(set_min_zero)) then 77 | set_min_zero_ = set_min_zero 78 | else 79 | set_min_zero_ = .false. 80 | end if 81 | 82 | if(size(a,1) .ne. size(b,1)) then 83 | call stop_program('Arrays must be the same size.') 84 | return 85 | end if 86 | 87 | if(set_min_zero_)then 88 | do i = 1, size(a,1) 89 | set_difference(i) = max(0.0_real32, a(i) - b(i)) 90 | end do 91 | else 92 | set_difference = a - b 93 | end if 94 | 95 | end function set_difference 96 | !############################################################################### 97 | 98 | end module raffle__misc_maths 99 | -------------------------------------------------------------------------------- /src/fortran/raffle.f90: -------------------------------------------------------------------------------- 1 | module raffle 2 | use raffle__constants, only: real32 3 | use raffle__io_utils, only: raffle__version__ 4 | use raffle__generator, only: raffle_generator_type 5 | use raffle__distribs_container, only: distribs_container_type 6 | implicit none 7 | 8 | 9 | private 10 | public :: real32 11 | public :: distribs_container_type 12 | public :: raffle_generator_type 13 | 14 | 15 | end module raffle -------------------------------------------------------------------------------- /src/raffle/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | raffle package 3 | 4 | This package provides functionality to interface with a Fortran library, 5 | including a Python wrapper around the Fortran code. 6 | """ 7 | 8 | from importlib.metadata import PackageNotFoundError, version 9 | try: 10 | __version__ = version(__name__) 11 | except PackageNotFoundError: 12 | __version__ = "unknown" 13 | 14 | from .raffle import generator as _generator_class 15 | from .raffle import geom_rw as _geom_rw_class 16 | # from .raffle import generator 17 | 18 | 19 | # Use the 'types' module to create simulated 'generator' and 'geom submodules 20 | import types 21 | generator = types.ModuleType('generator') 22 | geom = types.ModuleType('geom') 23 | 24 | # Assign the respective class to the simulated 'generator' and 'geom' modules 25 | generator.raffle_generator = _generator_class.raffle_generator 26 | generator.stoichiometry_array = _generator_class.stoichiometry_array 27 | 28 | # Assign the class to the simulated 'geom' module 29 | geom.basis_array = _geom_rw_class.basis_array 30 | geom.basis = _geom_rw_class.basis 31 | 32 | 33 | # Add the simulated 'generator' and 'geom' module to the current package 34 | import sys 35 | sys.modules['raffle.generator'] = generator 36 | sys.modules['raffle.geom'] = geom 37 | 38 | # Clean up internal imports (remove access to the direct classes) 39 | del _generator_class 40 | del _geom_rw_class 41 | del PackageNotFoundError 42 | del version 43 | del sys 44 | del types 45 | del raffle 46 | 47 | __all__ = ['__version__', 'generator', 'geom'] 48 | 49 | def __getattr__(name): 50 | if name == "generator": 51 | return generator 52 | elif name == "geom": 53 | return geom 54 | raise AttributeError(f"module {__name__} has no attribute {name}") -------------------------------------------------------------------------------- /src/wrapper/f90wrap_raffle.f90: -------------------------------------------------------------------------------- 1 | ! Module raffle defined in file ../raffle.f90 2 | 3 | ! End of module raffle defined in file ../raffle.f90 4 | 5 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | message(STATUS "Building tests") 2 | foreach(execid 3 | misc 4 | misc_maths 5 | misc_linalg 6 | element_utils 7 | geom_rw 8 | geom_utils 9 | geom_extd 10 | dist_calcs 11 | place_methods 12 | viability 13 | distribs_container 14 | evaluator_C 15 | evaluator_BTO 16 | generator 17 | io_utils 18 | tools_infile 19 | ) 20 | add_executable(test_${execid} test_${execid}.f90) 21 | # Specify the include directories 22 | target_include_directories(test_${execid} PRIVATE "${CMAKE_BUILD_DIR}" "${CMAKE_BUILD_DIR}/mod") 23 | 24 | target_link_libraries(test_${execid} PRIVATE ${PROJECT_NAME}) 25 | 26 | # Link against OpenMP if the build type is Parallel 27 | if (CMAKE_BUILD_TYPE MATCHES "Parallel*") 28 | target_link_libraries(test_${execid} PRIVATE ${PROJECT_NAME} OpenMP::OpenMP_Fortran) 29 | endif() 30 | 31 | add_test(NAME test_${execid} COMMAND test_${execid}) 32 | endforeach() -------------------------------------------------------------------------------- /test/data/POSCAR_Si: -------------------------------------------------------------------------------- 1 | Si 2 | 5.44 3 | 1.00 0.00 0.00 4 | 0.00 1.00 0.00 5 | 0.00 0.00 1.00 6 | Si 7 | 8 8 | direct 9 | 0.75 0.75 0.25 10 | 0.00 0.50 0.50 11 | 0.75 0.25 0.75 12 | 0.00 0.00 0.00 13 | 0.25 0.75 0.75 14 | 0.50 0.50 0.00 15 | 0.25 0.25 0.25 16 | 0.50 0.00 0.50 17 | -------------------------------------------------------------------------------- /test/test_element_utils.f90: -------------------------------------------------------------------------------- 1 | program test_mod_element_utils 2 | use raffle__element_utils 3 | use raffle__geom_rw, only: get_element_properties 4 | use raffle__constants, only: real32 5 | implicit none 6 | 7 | ! Local variables 8 | class(element_type), allocatable :: element 9 | class(element_bond_type), allocatable :: bond 10 | 11 | integer :: i 12 | logical :: in_database 13 | character(len=3), dimension(:), allocatable :: element_list 14 | 15 | logical :: success = .true. 16 | 17 | ! Initialise the element database 18 | allocate(element_list(118)) 19 | element_list = [ & 20 | 'H ', 'He ', 'Li ', 'Be ', 'B ', 'C ', 'N ', 'O ', 'F ', 'Ne ', & 21 | 'Na ', 'Mg ', 'Al ', 'Si ', 'P ', 'S ', 'Cl ', 'Ar ', 'K ', 'Ca ', & 22 | 'Sc ', 'Ti ', 'V ', 'Cr ', 'Mn ', 'Fe ', 'Co ', 'Ni ', 'Cu ', 'Zn ', & 23 | 'Ga ', 'Ge ', 'As ', 'Se ', 'Br ', 'Kr ', 'Rb ', 'Sr ', 'Y ', 'Zr ', & 24 | 'Nb ', 'Mo ', 'Tc ', 'Ru ', 'Rh ', 'Pd ', 'Ag ', 'Cd ', 'In ', 'Sn ', & 25 | 'Sb ', 'Te ', 'I ', 'Xe ', 'Cs ', 'Ba ', 'La ', 'Ce ', 'Pr ', 'Nd ', & 26 | 'Pm ', 'Sm ', 'Eu ', 'Gd ', 'Tb ', 'Dy ', 'Ho ', 'Er ', 'Tm ', 'Yb ', & 27 | 'Lu ', 'Hf ', 'Ta ', 'W ', 'Re ', 'Os ', 'Ir ', 'Pt ', 'Au ', 'Hg ', & 28 | 'Tl ', 'Pb ', 'Bi ', 'Po ', 'At ', 'Rn ', 'Fr ', 'Ra ', 'Ac ', 'Th ', & 29 | 'Pa ', 'U ', 'Np ', 'Pu ', 'Am ', 'Cm ', 'Bk ', 'Cf ', 'Es ', 'Fm ', & 30 | 'Md ', 'No ', 'Lr ', 'Rf ', 'Db ', 'Sg ', 'Bh ', 'Hs ', 'Mt ', 'Ds ', & 31 | 'Rg ', 'Cn ', 'Nh ', 'Fl ', 'Mc ', 'Lv ', 'Ts ', 'Og ' & 32 | ] 33 | 34 | allocate(element_database(size(element_list))) 35 | do i = 1, size(element_list) 36 | element_database(i)%name = element_list(i) 37 | call get_element_properties( & 38 | element_list(i), & 39 | mass = element_database(i)%mass, & 40 | charge = element_database(i)%charge, & 41 | radius = element_database(i)%radius & 42 | ) 43 | end do 44 | 45 | 46 | ! Test element initialization 47 | element = element_type( & 48 | name='H ', & 49 | mass=1.008_real32, & 50 | charge=0.0_real32, & 51 | energy=13.6_real32 & 52 | ) 53 | call assert( & 54 | trim(element%name) .eq. "H", & 55 | "Element name initialisation failed", & 56 | success & 57 | ) 58 | call assert( & 59 | abs(element%mass - 1.008_real32) .lt. 1.E-6, & 60 | "Element mass initialisation failed", & 61 | success & 62 | ) 63 | call assert( & 64 | abs(element%charge) .lt. 1.E-6, & 65 | "Element charge initialisation failed", & 66 | success & 67 | ) 68 | call assert( & 69 | abs(element%energy - 13.6_real32) .lt. 1.E-6, & 70 | "Element energy initialisation failed", & 71 | success & 72 | ) 73 | 74 | ! Test setting element properties 75 | call element%set('C ', in_database) 76 | call assert( & 77 | trim(element%name) .eq. "C", & 78 | "Element name setting failed", & 79 | success & 80 | ) 81 | call assert( & 82 | abs(element%mass - 12.011_real32) .lt. 1.E-6, & 83 | "Element mass setting failed", & 84 | success & 85 | ) 86 | call assert( & 87 | abs(element%charge - 6._real32) .lt. 1.E-6, & 88 | "Element charge setting failed", & 89 | success & 90 | ) 91 | call assert( & 92 | abs(element%radius - 0.76_real32) .lt. 1.E-6, & 93 | "Element radius setting failed", & 94 | success & 95 | ) 96 | call assert( & 97 | in_database, & 98 | "Element in_database setting failed", & 99 | success & 100 | ) 101 | 102 | ! Test bond initialisation 103 | bond = element_bond_type(elements=['H ', 'O '], radius=0.96_real32) 104 | 105 | ! Test setting bond properties 106 | call bond%set('C ', 'O ', in_database) 107 | 108 | 109 | !----------------------------------------------------------------------------- 110 | ! check for any failed tests 111 | !----------------------------------------------------------------------------- 112 | write(*,*) "----------------------------------------" 113 | if(success)then 114 | write(*,*) 'test_elements passed all tests' 115 | else 116 | write(0,*) 'test_elements failed one or more tests' 117 | stop 1 118 | end if 119 | 120 | contains 121 | 122 | !############################################################################### 123 | 124 | subroutine assert(condition, message, success) 125 | implicit none 126 | logical, intent(in) :: condition 127 | character(len=*), intent(in) :: message 128 | logical, intent(inout) :: success 129 | if (.not. condition) then 130 | write(0,*) "Test failed: ", message 131 | success = .false. 132 | end if 133 | end subroutine assert 134 | 135 | end program test_mod_element_utils -------------------------------------------------------------------------------- /test/test_geom_utils.f90: -------------------------------------------------------------------------------- 1 | program test_geom_utils 2 | !! Test program for the module edit_geom. 3 | use raffle__constants, only: real32 4 | use raffle__geom_rw, only: basis_type 5 | use raffle__misc_linalg, only: modu 6 | use raffle__geom_utils, only: basis_merge 7 | 8 | implicit none 9 | 10 | type(basis_type) :: bas, bas2, basis_merged 11 | 12 | logical :: success = .true. 13 | 14 | 15 | ! Initialise silicon basis 16 | bas%sysname = "Silicon" 17 | bas%nspec = 1 18 | bas%natom = 2 19 | allocate(bas%spec(bas%nspec)) 20 | bas%spec(1)%num = 2 21 | bas%spec(1)%name = 'Si' 22 | allocate(bas%spec(1)%atom(bas%spec(1)%num, 3)) 23 | bas%spec(1)%atom(1, :) = [0.0, 0.0, 0.0] 24 | bas%spec(1)%atom(2, :) = [0.25, 0.25, 0.25] 25 | 26 | ! Initialise silicon lattice 27 | bas%lat(1,:) = [0.0, 2.14, 2.14] 28 | bas%lat(2,:) = [2.14, 0.0, 2.14] 29 | bas%lat(3,:) = [2.14, 2.14, 0.0] 30 | 31 | 32 | !----------------------------------------------------------------------------- 33 | ! Test basis_merge 34 | !----------------------------------------------------------------------------- 35 | 36 | ! Initialise second basis 37 | bas2%sysname = "SiO2" 38 | bas2%nspec = 2 39 | bas2%natom = 3 40 | allocate(bas2%spec(bas2%nspec)) 41 | bas2%spec(1)%num = 2 42 | bas2%spec(1)%name = 'Si' 43 | allocate(bas2%spec(1)%atom(bas2%spec(1)%num, 3)) 44 | bas2%spec(1)%atom(1, :) = [0.5, 0.5, 0.5] 45 | bas2%spec(1)%atom(2, :) = [0.5, 0.0, 0.0] 46 | bas2%spec(2)%num = 1 47 | bas2%spec(2)%name = 'O' 48 | allocate(bas2%spec(2)%atom(bas2%spec(2)%num, 3)) 49 | bas2%spec(2)%atom(1, :) = [0.0, 0.7, 0.0] 50 | 51 | ! Initialise second lattice 52 | bas2%lat(1,:) = [0.0, 2.14, 2.14] 53 | bas2%lat(2,:) = [2.14, 0.0, 2.14] 54 | bas2%lat(3,:) = [2.14, 2.14, 0.0] 55 | 56 | 57 | basis_merged = basis_merge(bas, bas2) 58 | 59 | if ( basis_merged%nspec .ne. 2 ) then 60 | write(0,*) & 61 | 'basis_merge failed, number of species not equal to 2: ', & 62 | basis_merged%nspec 63 | success = .false. 64 | end if 65 | if ( basis_merged%natom .ne. 5 ) then 66 | write(0,*) & 67 | 'basis_merge failed, number of atoms not equal to 5: ', & 68 | basis_merged%natom 69 | success = .false. 70 | end if 71 | if ( basis_merged%spec(1)%num .ne. 4 ) then 72 | write(0,*) & 73 | 'basis_merge failed, number of atoms for species 1 not equal to 4: ', & 74 | basis_merged%spec(1)%num 75 | success = .false. 76 | end if 77 | if ( basis_merged%spec(2)%num .ne. 1 ) then 78 | write(0,*) & 79 | 'basis_merge failed, number of atoms for species 2 not equal to 1: ', & 80 | basis_merged%spec(2)%num 81 | success = .false. 82 | end if 83 | if( basis_merged%spec(1)%name .ne. 'Si' ) then 84 | write(0,*) & 85 | 'basis_merge failed, name of species 1 not equal to Si: ', & 86 | basis_merged%spec(1)%name 87 | success = .false. 88 | end if 89 | if( basis_merged%spec(2)%name .ne. 'O' ) then 90 | write(0,*) & 91 | 'basis_merge failed, name of species 2 not equal to O: ', & 92 | basis_merged%spec(2)%name 93 | success = .false. 94 | end if 95 | 96 | 97 | !----------------------------------------------------------------------------- 98 | ! check for any failed tests 99 | !----------------------------------------------------------------------------- 100 | write(*,*) "----------------------------------------" 101 | if(success)then 102 | write(*,*) 'test_geom_utils passed all tests' 103 | else 104 | write(0,*) 'test_geom_utils failed one or more tests' 105 | stop 1 106 | end if 107 | 108 | end program test_geom_utils -------------------------------------------------------------------------------- /test/test_io_utils.f90: -------------------------------------------------------------------------------- 1 | program test_io_utils 2 | use raffle__io_utils 3 | implicit none 4 | 5 | ! Test variables 6 | logical :: success = .true. 7 | character(100) :: message 8 | 9 | ! Test stop_program subroutine 10 | test_error_handling = .true. 11 | message = "Test error message" 12 | call stop_program(message) 13 | 14 | ! Test print_warning subroutine 15 | call print_warning("This is a test warning message") 16 | 17 | ! Test print_version subroutine 18 | call print_version() 19 | 20 | ! Test print_build_info subroutine 21 | call print_build_info() 22 | 23 | !----------------------------------------------------------------------------- 24 | ! check for any failed tests 25 | !----------------------------------------------------------------------------- 26 | write(*,*) "----------------------------------------" 27 | if(success)then 28 | write(*,*) 'test_misc_linalg passed all tests' 29 | else 30 | write(0,*) 'test_misc_linalg failed one or more tests' 31 | stop 1 32 | end if 33 | 34 | end program test_io_utils -------------------------------------------------------------------------------- /test/test_misc_maths.f90: -------------------------------------------------------------------------------- 1 | program test_misc_maths 2 | use raffle__io_utils, only: test_error_handling 3 | use raffle__misc_maths 4 | use raffle__constants, only: real32 5 | implicit none 6 | 7 | logical :: success = .true. 8 | 9 | test_error_handling = .true. 10 | 11 | 12 | call test_lnsum(success) 13 | call test_triangular_number(success) 14 | call test_set_difference(success) 15 | 16 | 17 | !----------------------------------------------------------------------------- 18 | ! check for any failed tests 19 | !----------------------------------------------------------------------------- 20 | write(*,*) "----------------------------------------" 21 | if(success)then 22 | write(*,*) 'test_misc_maths passed all tests' 23 | else 24 | write(0,*) 'test_misc_maths failed one or more tests' 25 | stop 1 26 | end if 27 | 28 | contains 29 | 30 | subroutine test_lnsum(success) 31 | implicit none 32 | logical, intent(inout) :: success 33 | integer :: n 34 | real(real32) :: result 35 | 36 | n = 5 37 | result = lnsum(n) 38 | call assert( & 39 | abs( & 40 | result - & 41 | ( & 42 | log(1.0_real32) + & 43 | log(2.0_real32) + & 44 | log(3.0_real32) + & 45 | log(4.0_real32) + & 46 | log(5.0_real32) & 47 | ) & 48 | ) .lt. 1.E-6_real32, & 49 | 'lnsum failed', & 50 | success & 51 | ) 52 | end subroutine test_lnsum 53 | 54 | subroutine test_triangular_number(success) 55 | implicit none 56 | logical, intent(inout) :: success 57 | integer :: n, result 58 | 59 | n = 5 60 | result = triangular_number(n) 61 | call assert( & 62 | result .eq. 15, & 63 | 'Triangular number failed', & 64 | success & 65 | ) 66 | end subroutine test_triangular_number 67 | 68 | subroutine test_set_difference(success) 69 | implicit none 70 | logical, intent(inout) :: success 71 | real(real32), dimension(3) :: a, b, result, expected 72 | real(real32), dimension(4) :: c 73 | 74 | a = [1.0_real32, 2.0_real32, 3.0_real32] 75 | b = [1.0_real32, 1.0_real32, 1.0_real32] 76 | expected = [0.0_real32, 1.0_real32, 2.0_real32] 77 | result = set_difference(a, b) 78 | 79 | call assert( & 80 | all( abs(result - expected) .lt. 1.E-6_real32 ), & 81 | 'Set difference failed', & 82 | success & 83 | ) 84 | 85 | b = [0.0_real32, 1.0_real32, 4.0_real32] 86 | expected = [1.0_real32, 1.0_real32, 0.0_real32] 87 | result = set_difference(a, b, set_min_zero=.true.) 88 | 89 | call assert( & 90 | all( abs(result - expected) .lt. 1.E-6_real32 ), & 91 | 'Set difference min zero failed', & 92 | success & 93 | ) 94 | 95 | c = [1.0_real32, 2.0_real32, 3.0_real32, 4.0_real32] 96 | write(*,*) "Testing set_difference error handling" 97 | result = set_difference(a, c) 98 | write(*,*) "Handled error: set difference of arrays of different lengths" 99 | 100 | 101 | end subroutine test_set_difference 102 | 103 | !############################################################################### 104 | 105 | subroutine assert(condition, message, success) 106 | implicit none 107 | logical, intent(in) :: condition 108 | character(len=*), intent(in) :: message 109 | logical, intent(inout) :: success 110 | if (.not. condition) then 111 | write(0,*) "Test failed: ", message 112 | success = .false. 113 | end if 114 | end subroutine assert 115 | 116 | end program test_misc_maths -------------------------------------------------------------------------------- /test/test_tools_infile.f90: -------------------------------------------------------------------------------- 1 | program test_tools_infile 2 | use raffle__constants, only: real32 3 | use raffle__tools_infile 4 | implicit none 5 | 6 | 7 | integer :: ival = 0 8 | logical :: ltmp1 9 | real(real32) :: rtmp1 10 | character(256) :: stmp1 11 | character(256) :: line 12 | 13 | logical :: success = .true. 14 | 15 | 16 | line = "APPLES = string" 17 | call assign_val(line, stmp1, ival, keyword="APPLES") 18 | if( trim(stmp1) .ne. "string" .or. ival .ne. 1 )then 19 | write(0,*) "assign_val failed for string" 20 | success = .false. 21 | end if 22 | 23 | line = "ORANGES = 1" 24 | call assign_val(line, ltmp1, ival, keyword="ORANGES") 25 | if( .not. ltmp1 .or. ival .ne. 2 )then 26 | write(0,*) "assign_val failed for logical" 27 | success = .false. 28 | end if 29 | line = "ORANGES = 0" 30 | call assign_val(line, ltmp1, ival, keyword="ORANGES") 31 | if( ltmp1 .or. ival .ne. 3 )then 32 | write(0,*) "assign_val failed for logical" 33 | success = .false. 34 | end if 35 | line = "ORANGES = T" 36 | call assign_val(line, ltmp1, ival, keyword="ORANGES") 37 | if( .not. ltmp1 .or. ival .ne. 4 )then 38 | write(0,*) "assign_val failed for logical" 39 | success = .false. 40 | end if 41 | line = "ORANGES = F" 42 | call assign_val(line, ltmp1, ival, keyword="ORANGES") 43 | if( ltmp1 .or. ival .ne. 5 )then 44 | write(0,*) "assign_val failed for logical" 45 | success = .false. 46 | end if 47 | line = "ORANGES = t" 48 | call assign_val(line, ltmp1, ival, keyword="ORANGES") 49 | if( .not. ltmp1 .or. ival .ne. 6 )then 50 | write(0,*) "assign_val failed for logical" 51 | success = .false. 52 | end if 53 | line = "ORANGES = f" 54 | call assign_val(line, ltmp1, ival, keyword="ORANGES") 55 | if( ltmp1 .or. ival .ne. 7 )then 56 | write(0,*) "assign_val failed for logical" 57 | success = .false. 58 | end if 59 | 60 | line = "BANANAS = 1.0 # comment" 61 | ! ival = line number here 62 | call rm_comments(line, ival) 63 | if( trim(line) .ne. "BANANAS = 1.0")then 64 | write(0,*) "rm_comments failed" 65 | write(0,'("\",A,"\")') trim(line) 66 | success = .false. 67 | end if 68 | 69 | 70 | !----------------------------------------------------------------------------- 71 | ! check for any failed tests 72 | !----------------------------------------------------------------------------- 73 | write(*,*) "----------------------------------------" 74 | if(success)then 75 | write(*,*) 'test_tools_infile passed all tests' 76 | else 77 | write(0,*) 'test_tools_infile failed one or more tests' 78 | stop 1 79 | end if 80 | 81 | 82 | 83 | end program test_tools_infile -------------------------------------------------------------------------------- /tools/.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto-remove output from Jupyter notebooks 2 | # Follow the guide from this link to set up the filter: 3 | # https://gist.github.com/33eyes/431e3d432f73371509d176d0dfb95b6e 4 | *.ipynb filter=strip-notebook-output -------------------------------------------------------------------------------- /tools/check_accuracy_Al.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | 4 | ## import ASE (Atomic Simulation Environment) modules 5 | from ase import Atoms 6 | from ase.io import read, write 7 | 8 | 9 | ## load calculator 10 | calculator = "CHGNet" 11 | match calculator: 12 | case "CHGNet": 13 | from chgnet.model.dynamics import CHGNetCalculator 14 | print("Initialising CHGNet calculator") 15 | calc = CHGNetCalculator() 16 | label = "CHGNet" 17 | case "MACE": 18 | from mace.calculators import mace_mp 19 | print("Initialising MACE calculator") 20 | calc = mace_mp(model="medium", dispersion=False, default_dtype="float32", device='cpu') 21 | label = "MACE" 22 | 23 | ## Read the database 24 | print("Reading database") 25 | database = read("../example/data/aluminium.xyz", index=":") 26 | 27 | ## Compare energy of isolated Al atom (MLPs should not do well with this test) 28 | Al_reference = Atoms('Al', positions=[(0, 0, 0)], cell=[12,12,12], pbc=False) 29 | Al_reference.calc = calc 30 | Al_reference_energy_mlp = Al_reference.get_potential_energy() / len(Al_reference) 31 | 32 | Al_reference_energy_dft = -0.19810165 33 | print("Al_reference_energy_mace: ", Al_reference_energy_mlp) 34 | print("Al_reference_energy_dft: ", Al_reference_energy_dft) 35 | 36 | ## Calculate the energies 37 | energies_dft = [] 38 | energies_mlp = [] 39 | for i, atoms in enumerate(database): 40 | if atoms.calc is None: 41 | database.remove(atoms) 42 | continue 43 | energies_dft.append(atoms.get_potential_energy()/len(atoms)) 44 | atoms.calc = calc 45 | energies_mlp.append(atoms.get_potential_energy()/len(atoms)) 46 | 47 | 48 | import matplotlib.pyplot as plt 49 | 50 | ## Write energies to a file 51 | with open("energies_comparison.txt", "w") as f: 52 | f.write("# DFT_Energy_per_atom "+label+"_Energy_per_atom\n") 53 | for dft_energy, mace_energy in zip(energies_dft, energies_mlp): 54 | f.write(f"{dft_energy} {mace_energy}\n") 55 | 56 | ## Plotting the energies 57 | plt.figure(figsize=(10, 6)) 58 | plt.scatter(energies_dft, energies_mlp, c='blue', marker='o', label=label+' vs DFT') 59 | plt.show() -------------------------------------------------------------------------------- /tools/check_accuracy_C-MgO.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | 4 | # import ASE (Atomic Simulation Environment) modules 5 | from ase import Atoms 6 | from ase.io import read, write 7 | 8 | 9 | ## load calculator 10 | calculator = "CHGNet" 11 | match calculator: 12 | case "CHGNet": 13 | from chgnet.model.dynamics import CHGNetCalculator 14 | print("Initialising CHGNet calculator") 15 | calc = CHGNetCalculator() 16 | label = "CHGNet" 17 | case "MACE": 18 | from mace.calculators import mace_mp 19 | print("Initialising MACE calculator") 20 | calc = mace_mp(model="medium", dispersion=False, default_dtype="float32", device='cpu') 21 | label = "MACE" 22 | 23 | ## Read the database 24 | print("Reading database") 25 | database = read("../example/data/C-MgO.xyz", index=":") 26 | 27 | ## Calculate the energies 28 | energies_dft = [] 29 | energies_mlp = [] 30 | for i, atoms in enumerate(database): 31 | if atoms.calc is None: 32 | database.remove(atoms) 33 | continue 34 | energies_dft.append(atoms.get_potential_energy()/len(atoms)) 35 | atoms.calc = calc 36 | energies_mlp.append(atoms.get_potential_energy()/len(atoms)) 37 | # if energies_mlp[-1] - energies_dft[-1] > 3e-1 and energies_mlp[-1] < -7.9: 38 | # print(f"Energy difference for structure {i} is {energies_mlp[-1] - energies_dft[-1]}, energy_mace: {energies_mlp[-1]}") 39 | # view(atoms) 40 | 41 | 42 | import matplotlib.pyplot as plt 43 | 44 | ## Write energies to a file 45 | with open("C-MgO_energies_comparison.txt", "w") as f: 46 | f.write("# DFT_Energy_per_atom "+label+"_Energy_per_atom\n") 47 | for dft_energy, mace_energy in zip(energies_dft, energies_mlp): 48 | f.write(f"{dft_energy} {mace_energy}\n") 49 | 50 | # Plotting the energies 51 | plt.figure(figsize=(10, 6)) 52 | plt.scatter(energies_dft, energies_mlp, c='blue', marker='o', label=label+' vs DFT') 53 | plt.show() -------------------------------------------------------------------------------- /tools/check_accuracy_C.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | 4 | ## import ASE (Atomic Simulation Environment) modules 5 | from ase import Atoms 6 | from ase.io import read, write 7 | 8 | 9 | ## load calculator 10 | calculator = "CHGNet" 11 | match calculator: 12 | case "CHGNet": 13 | from chgnet.model.dynamics import CHGNetCalculator 14 | print("Initialising CHGNet calculator") 15 | calc = CHGNetCalculator() 16 | label = "CHGNet" 17 | case "MACE": 18 | from mace.calculators import mace_mp 19 | print("Initialising MACE calculator") 20 | calc = mace_mp(model="medium", dispersion=False, default_dtype="float32", device='cpu') 21 | label = "MACE" 22 | 23 | ## Read the database 24 | print("Reading database") 25 | database = read("../example/data/carbon.xyz", index=":") 26 | 27 | ## Calculate the energies 28 | energies_dft = [] 29 | energies_mlp = [] 30 | for i, atoms in enumerate(database): 31 | if atoms.calc is None: 32 | database.remove(atoms) 33 | continue 34 | energies_dft.append(atoms.get_potential_energy()/len(atoms)) 35 | atoms.calc = calc 36 | energies_mlp.append(atoms.get_potential_energy()/len(atoms)) 37 | # if energies_mlp[-1] - energies_dft[-1] > 3e-1 and energies_mlp[-1] < -7.9: 38 | # print(f"Energy difference for structure {i} is {energies_mlp[-1] - energies_dft[-1]}, energy_mace: {energies_mlp[-1]}") 39 | # view(atoms) 40 | 41 | 42 | import matplotlib.pyplot as plt 43 | 44 | ## Write energies to a file 45 | with open("C_energies_comparison.txt", "w") as f: 46 | f.write("# DFT_Energy_per_atom "+label+"_Energy_per_atom\n") 47 | for dft_energy, mace_energy in zip(energies_dft, energies_mlp): 48 | f.write(f"{dft_energy} {mace_energy}\n") 49 | 50 | ## Plot the energies 51 | plt.figure(figsize=(10, 6)) 52 | plt.scatter(energies_dft, energies_mlp, c='blue', marker='o', label=label+' vs DFT') 53 | plt.show() -------------------------------------------------------------------------------- /tools/check_accuracy_ScS2-Li.py: -------------------------------------------------------------------------------- 1 | import os 2 | import numpy as np 3 | 4 | ## import ASE (Atomic Simulation Environment) modules 5 | from ase import Atoms 6 | from ase.io import read, write 7 | from ase.calculators.singlepoint import SinglePointCalculator 8 | 9 | 10 | ## load calculator 11 | calculator = "CHGNet" 12 | match calculator: 13 | case "CHGNet": 14 | from chgnet.model.dynamics import CHGNetCalculator 15 | print("Initialising CHGNet calculator") 16 | calc = CHGNetCalculator() 17 | label = "CHGNet" 18 | case "MACE": 19 | from mace.calculators import mace_mp 20 | print("Initialising MACE calculator") 21 | calc = mace_mp(model="medium", dispersion=False, default_dtype="float32", device='cpu') 22 | label = "MACE" 23 | 24 | ## Read the database 25 | print("Reading database") 26 | database = read("../example/data/ScS2-Li.xyz", index=":") 27 | 28 | ## Calculate the energies 29 | energies_dft = [] 30 | energies_mlp = [] 31 | output_atoms = [] 32 | for i, atoms in enumerate(database): 33 | if atoms.calc is None: 34 | database.remove(atoms) 35 | continue 36 | 37 | energies_dft.append(atoms.get_potential_energy()/len(atoms)) 38 | atoms.calc = calc 39 | energies_mlp.append(atoms.get_potential_energy()/len(atoms)) 40 | # if energies_mlp[-1] - energies_dft[-1] > 3e-1 and energies_mlp[-1] < -7.9: 41 | # print(f"Energy difference for structure {i} is {energies_mlp[-1] - energies_dft[-1]}, energy_mace: {energies_mlp[-1]}") 42 | # view(atoms) 43 | output_atoms.append(atoms) 44 | output_atoms[-1].calc = SinglePointCalculator( 45 | atoms, 46 | energy=atoms.get_potential_energy(), 47 | forces=atoms.get_forces() 48 | ) 49 | 50 | 51 | import matplotlib.pyplot as plt 52 | 53 | ## Write energies to a file 54 | with open("ScS2-Li_energies_comparison.txt", "w") as f: 55 | f.write("# DFT_Energy_per_atom "+label+"_Energy_per_atom\n") 56 | for dft_energy, mace_energy in zip(energies_dft, energies_mlp): 57 | f.write(f"{dft_energy} {mace_energy}\n") 58 | 59 | ## Plot the energies 60 | plt.figure(figsize=(10, 6)) 61 | plt.scatter(energies_dft, energies_mlp, c='blue', marker='o', label=label+' vs DFT') 62 | plt.show() 63 | -------------------------------------------------------------------------------- /tools/coverage_badge.py: -------------------------------------------------------------------------------- 1 | from bs4 import BeautifulSoup 2 | 3 | html_file = "./build/coverage/index.html" 4 | 5 | colour_dict = {'coverage-low':"red", 'coverage-medium':"yellow", 'coverage-high':"brightgreen"} 6 | 7 | with open(html_file, 'r') as file: 8 | soup = BeautifulSoup(file, 'html.parser') 9 | 10 | # Find the "coverage" table 11 | coverage_table = soup.find('table', {'class': 'coverage'}) 12 | 13 | # Find the second row of the "coverage" table 14 | second_row = coverage_table.find_all('tr')[1] 15 | 16 | # Find the third column of the second row 17 | third_column = second_row.find_all('td')[2] 18 | 19 | percentage = third_column.get_text() 20 | 21 | # Get the class of the element 22 | td_class = third_column.get('class')[0] 23 | 24 | print(int(float(percentage.replace("%", "")))) -------------------------------------------------------------------------------- /tools/database.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "#Imports MPRester\n", 10 | "# from mp_api.client import MPRester\n", 11 | "from ase import Atoms\n", 12 | "from ase.io import write, read\n", 13 | "from pymatgen.io.ase import AseAtomsAdaptor\n", 14 | "from pymatgen.ext.matproj import MPRester" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": {}, 21 | "outputs": [], 22 | "source": [ 23 | "# Personal api key for accessing materials project api\n", 24 | "# This is unique to each user\n", 25 | "# api_key = \"\"" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": null, 31 | "metadata": {}, 32 | "outputs": [], 33 | "source": [ 34 | "# Get the ID of materials from the materials project\n", 35 | "mpr = MPRester() # MPRester(api_key)\n", 36 | "materials = []\n", 37 | "\n", 38 | "materials.append(mpr.materials.summary.search(chemsys=\"C\", \n", 39 | " fields=[\"material_id\",\"structure\", \"energy_per_atom\", \"nsites\"]))\n", 40 | "materials.append(mpr.materials.summary.search(chemsys=\"Mg\", \n", 41 | " fields=[\"material_id\",\"structure\", \"energy_per_atom\", \"nsites\"]))\n", 42 | "materials.append(mpr.materials.summary.search(chemsys=\"O\", \n", 43 | " fields=[\"material_id\",\"structure\", \"energy_per_atom\", \"nsites\"]))\n", 44 | "materials.append(mpr.materials.summary.search(chemsys=\"C-Mg\", \n", 45 | " fields=[\"material_id\",\"structure\", \"energy_per_atom\", \"nsites\"]))\n", 46 | "materials.append(mpr.materials.summary.search(chemsys=\"C-O\", \n", 47 | " fields=[\"material_id\",\"structure\", \"energy_per_atom\", \"nsites\"]))\n", 48 | "materials.append(mpr.materials.summary.search(chemsys=\"Mg-O\", \n", 49 | " fields=[\"material_id\",\"structure\", \"energy_per_atom\", \"nsites\"]))" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "# Get the structures, energies, and number of sites for each material from the materials project\n", 59 | "structures = []\n", 60 | "energies = []\n", 61 | "nsites = []\n", 62 | "for material_set in materials:\n", 63 | " for material in material_set:\n", 64 | " material_id = material.material_id\n", 65 | " structures.append(mpr.get_structure_by_material_id(material_id))\n", 66 | " energies.append(material.energy_per_atom)\n", 67 | " nsites.append(material.nsites)" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": null, 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [ 76 | "# Convert the structures to atoms and write them to a single extended xyz file\n", 77 | "all_atoms = []\n", 78 | "for structure, energy, nsite in zip(structures, energies, nsites):\n", 79 | " atom = AseAtomsAdaptor.get_atoms(structure)\n", 80 | " atom.info['free_energy'] = energy * nsite\n", 81 | " atom.info['energy'] = energy * nsite\n", 82 | " all_atoms.append(atom)\n", 83 | "write(\"database.xyz\", all_atoms, format='extxyz')" 84 | ] 85 | } 86 | ], 87 | "metadata": { 88 | "kernelspec": { 89 | "display_name": "py3.11", 90 | "language": "python", 91 | "name": "python3" 92 | }, 93 | "language_info": { 94 | "codemirror_mode": { 95 | "name": "ipython", 96 | "version": 3 97 | }, 98 | "file_extension": ".py", 99 | "mimetype": "text/x-python", 100 | "name": "python", 101 | "nbconvert_exporter": "python", 102 | "pygments_lexer": "ipython3", 103 | "version": "3.11.8" 104 | } 105 | }, 106 | "nbformat": 4, 107 | "nbformat_minor": 2 108 | } 109 | -------------------------------------------------------------------------------- /tools/database.py: -------------------------------------------------------------------------------- 1 | # %% 2 | #Imports MPRester 3 | # from mp_api.client import MPRester 4 | from ase import Atoms 5 | from ase.io import write, read 6 | from pymatgen.io.ase import AseAtomsAdaptor 7 | from mp_api.client import MPRester 8 | 9 | 10 | # %% 11 | # Personal api key for accessing materials project api 12 | # This is unique to each user 13 | # api_key = "" 14 | 15 | # %% 16 | #Gets the ID of materials we want. Ba is all structures with only Ba. Ba-O is all structures with only Ba and O, not only BaO. 17 | 18 | mpr = MPRester() # MPRester(api_key) 19 | materials = [] 20 | 21 | materials.append(mpr.materials.summary.search(chemsys="C", 22 | fields=["material_id","structure", "energy_per_atom", "nsites"])) 23 | materials.append(mpr.materials.summary.search(chemsys="Mg", 24 | fields=["material_id","structure", "energy_per_atom", "nsites"])) 25 | materials.append(mpr.materials.summary.search(chemsys="O", 26 | fields=["material_id","structure", "energy_per_atom", "nsites"])) 27 | materials.append(mpr.materials.summary.search(chemsys="C-Mg", 28 | fields=["material_id","structure", "energy_per_atom", "nsites"])) 29 | materials.append(mpr.materials.summary.search(chemsys="C-O", 30 | fields=["material_id","structure", "energy_per_atom", "nsites"])) 31 | materials.append(mpr.materials.summary.search(chemsys="Mg-O", 32 | fields=["material_id","structure", "energy_per_atom", "nsites"])) 33 | 34 | 35 | # %% 36 | structures = [] 37 | energies = [] 38 | nsites = [] 39 | for material_set in materials: 40 | for material in material_set: 41 | material_id = material.material_id 42 | structures.append(mpr.get_structure_by_material_id(material_id)) 43 | energies.append(material.energy_per_atom) 44 | nsites.append(material.nsites) 45 | 46 | # %% 47 | all_atoms = [] 48 | for structure, energy, nsite in zip(structures, energies, nsites): 49 | atom = AseAtomsAdaptor.get_atoms(structure) 50 | atom.info['free_energy'] = energy * nsite 51 | atom.info['energy'] = energy * nsite 52 | all_atoms.append(atom) 53 | write("database.xyz", all_atoms, format='extxyz') 54 | 55 | # %% 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /tools/descriptors.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import numpy as np\n", 10 | "from copy import deepcopy\n", 11 | "from ase import Atoms\n", 12 | "from ase.io import read\n", 13 | "from ase.build import bulk\n", 14 | "from raffle.generator import raffle_generator\n", 15 | "from chgnet.model import CHGNetCalculator" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": null, 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "calc = CHGNetCalculator()" 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "diamond = bulk('C', 'diamond', a=3.567)\n", 34 | "diamond.calc = calc\n", 35 | "\n", 36 | "graphite = Atoms(\n", 37 | " 'C4',\n", 38 | " cell = [\n", 39 | " [0.0, 4.25464061444508, 0.0], \n", 40 | " [2.45656488, 0.0, 0.0], \n", 41 | " [0.0, -1.379069630931066, -3.5028300786042923]\n", 42 | " ],\n", 43 | " positions = [\n", 44 | " [ 0.00000000e+00, -6.69928992e-01, -3.50250418e+00],\n", 45 | " [ 0.00000000e+00, 3.54549998e+00, -3.25903311e-04],\n", 46 | " [ 1.22828244e+00, 1.45739132e+00, -3.50250418e+00],\n", 47 | " [ 1.22828244e+00, 1.41817967e+00, -3.25903311e-04]\n", 48 | " ],\n", 49 | " pbc = True,\n", 50 | " calculator = calc\n", 51 | ")" 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": null, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "print(\"Diamond energy per atom: \", diamond.get_potential_energy() / len(diamond))\n", 61 | "print(\"Graphite energy per atom: \", graphite.get_potential_energy() / len(graphite))\n", 62 | "print(\"Difference in energies per atom: \", graphite.get_potential_energy()/ len(graphite) - diamond.get_potential_energy() / len(diamond))" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": null, 68 | "metadata": {}, 69 | "outputs": [], 70 | "source": [ 71 | "generator = raffle_generator()\n", 72 | "generator.distributions.set_element_energies({'C': 0.0})\n", 73 | "generator.distributions.set_kBT(0.4)\n", 74 | "generator.distributions.set_width([0.025, np.pi/200.0, np.pi/200.0])" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "diamond_generator = raffle_generator()\n", 84 | "diamond_generator.distributions.set_element_energies({'C': 0.0})\n", 85 | "diamond_generator.distributions.set_kBT(0.4)\n", 86 | "diamond_generator.distributions.set_width([0.025, np.pi/200.0, np.pi/200.0])" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "metadata": {}, 93 | "outputs": [], 94 | "source": [ 95 | "graphite_generator = raffle_generator()\n", 96 | "graphite_generator.distributions.set_element_energies({'C': 0.0})\n", 97 | "graphite_generator.distributions.set_kBT(0.4)\n", 98 | "graphite_generator.distributions.set_width([0.025, np.pi/200.0, np.pi/200.0])" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": null, 104 | "metadata": {}, 105 | "outputs": [], 106 | "source": [ 107 | "diamond_generator.distributions.create([diamond])\n", 108 | "graphite_generator.distributions.create([graphite])\n", 109 | "generator.distributions.create([diamond, graphite])" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": null, 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [ 118 | "diamond_generator.distributions.write_gdfs(file='diamond_gdfs.dat')\n", 119 | "graphite_generator.distributions.write_gdfs(file='graphite_gdfs.dat')\n", 120 | "generator.distributions.write_gdfs(file='combined_gdfs.dat')" 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": null, 126 | "metadata": {}, 127 | "outputs": [], 128 | "source": [] 129 | } 130 | ], 131 | "metadata": { 132 | "kernelspec": { 133 | "display_name": "raffle_env", 134 | "language": "python", 135 | "name": "python3" 136 | }, 137 | "language_info": { 138 | "codemirror_mode": { 139 | "name": "ipython", 140 | "version": 3 141 | }, 142 | "file_extension": ".py", 143 | "mimetype": "text/x-python", 144 | "name": "python", 145 | "nbconvert_exporter": "python", 146 | "pygments_lexer": "ipython3", 147 | "version": "3.12.8" 148 | } 149 | }, 150 | "nbformat": 4, 151 | "nbformat_minor": 2 152 | } 153 | -------------------------------------------------------------------------------- /tools/version_number.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | def update_version(new_version): 4 | # Update fpm.toml 5 | with open('fpm.toml', 'r') as file: 6 | content = file.read() 7 | content = re.sub(r'version = "\d+\.\d+\.\d+.*"', f'version = "{new_version}"', content) 8 | with open('fpm.toml', 'w') as file: 9 | file.write(content) 10 | 11 | # Update Fortran module 12 | with open('src/fortran/lib/mod_io_utils.F90', 'r') as file: 13 | content = file.read() 14 | content = re.sub(r'character\(len=\*\), parameter :: raffle__version__ = "\d+\.\d+\.\d+.*"', f'character(len=*), parameter :: raffle__version__ = "{new_version}"', content) 15 | with open('src/fortran/lib/mod_io_utils.F90', 'w') as file: 16 | file.write(content) 17 | 18 | def get_version(): 19 | # get the version number from fpm.toml 20 | with open('fpm.toml', 'r') as file: 21 | content = file.read() 22 | match = re.search(r'version = "(\d+\.\d+\.\d+.*)"', content) 23 | print(match.group(1)) 24 | if match: 25 | return match.group(1) 26 | 27 | if __name__ == '__main__': 28 | update_version(get_version()) 29 | -------------------------------------------------------------------------------- /tools/visualise_evaluator.py: -------------------------------------------------------------------------------- 1 | from mpl_toolkits.mplot3d import Axes3D 2 | from mpl_toolkits.mplot3d import proj3d 3 | import numpy as np 4 | 5 | import matplotlib.pyplot as plt 6 | 7 | # Read the data from the file 8 | data = [] 9 | atoms = [] 10 | with open('viability.dat', 'r') as file: 11 | for line in file: 12 | values = line.strip().split() 13 | if len(values) == 3: 14 | atoms.append([float(values[0]), float(values[1]), float(values[2])]) 15 | 16 | if len(values) == 4: 17 | data.append([float(values[0]), float(values[1]), float(values[2]), float(values[3])]) 18 | 19 | # Drop all rows with row[3] less than 0.2 20 | # data = [row for row in data if row[3] > 0.4] # for 4-body only 21 | max_val = max([row[3] for row in data]) 22 | avg_val = sum([row[3] for row in data])/len(data) 23 | print(f"Max value: {max_val}") 24 | print(f"Avg value: {avg_val}") 25 | 26 | # Extract the coordinates and values 27 | x = [row[0] for row in data] 28 | y = [row[1] for row in data] 29 | z = [row[2] for row in data] 30 | # alpha = [row[3] for row in data] 31 | alpha = [(row[3]*100)*2 for row in data] 32 | alpha = [val/max(alpha) for val in alpha] 33 | # size = [(row[3]*10)**3 for row in data] # for 2-body only 34 | # size = [(row[3]*100)*2 for row in data] # for 2-body and 3-body 35 | # size = [row[3] for row in data] # for 4-body only 36 | # size = [(row[3]*2000) for row in data] # for all 37 | size = [(row[3]*1000) for row in data] # for all 38 | 39 | # Extract the atom coordinates 40 | atoms_x = [row[0] for row in atoms] 41 | atoms_y = [row[1] for row in atoms] 42 | atoms_z = [row[2] for row in atoms] 43 | 44 | # Plot the data on a 3D graph 45 | fig = plt.figure() 46 | ax = fig.add_subplot(111, projection='3d') 47 | 48 | x_scale=max(x)-min(x) 49 | y_scale=max(y)-min(y) 50 | z_scale=max(z)-min(z) 51 | 52 | scale=np.diag([x_scale, y_scale, z_scale, 1.0]) 53 | scale=scale*(1.0/scale.max()) 54 | scale[3,3]=1.0 55 | 56 | def short_proj(): 57 | return np.dot(Axes3D.get_proj(ax), scale) 58 | 59 | ax.get_proj=short_proj 60 | ax.mouse_init() 61 | 62 | 63 | ax.scatter(atoms_x, atoms_y, atoms_z, c='red', alpha=1.0, s=200) 64 | 65 | # ax.scatter(x, y, z, alpha=alpha, c='black', s=size) 66 | ax.scatter(x, y, z, c=alpha, cmap='viridis', s=size) 67 | ax.set_xlabel('X') 68 | ax.set_ylabel('Y') 69 | ax.set_zlabel('Z') 70 | plt.show() 71 | --------------------------------------------------------------------------------