├── .coveragerc ├── .docker ├── cp2k-code.yml ├── init │ └── add-codes.sh ├── s6-rc.d │ └── cp2k-code-setup │ │ ├── dependencies.d │ │ └── aiida-prepare │ │ ├── timeout-up │ │ ├── type │ │ └── up └── user │ └── cp2k-code-setup ├── .flake8 ├── .github └── workflows │ ├── ci.yml │ └── publish.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .readthedocs.yml ├── Dockerfile ├── LICENSE.txt ├── README.md ├── aiida-cp2k_logo.svg ├── aiida_cp2k ├── __init__.py ├── calculations │ └── __init__.py ├── parsers │ └── __init__.py ├── utils │ ├── __init__.py │ ├── datatype_helpers.py │ ├── input_generator.py │ ├── parser.py │ └── workchains.py └── workchains │ ├── __init__.py │ └── base.py ├── conftest.py ├── docs ├── .gitignore ├── Makefile └── source │ ├── _static │ └── style.css │ ├── _templates │ └── layout.html │ ├── apidoc │ └── .gitignore │ ├── conf.py │ ├── examples.rst │ ├── features.rst │ ├── images │ └── AiiDA_transparent_logo.png │ ├── index.rst │ └── workflows.rst ├── examples ├── files │ ├── BASIS_MOLOPT │ ├── GTH_POTENTIALS │ ├── h2.xyz │ ├── h2o.xyz │ └── si.xyz ├── gaussian_datatypes │ ├── example_automatic.py │ ├── example_explicit.py │ └── gdt_data.py ├── single_calculations │ ├── example_bands.py │ ├── example_dft.py │ ├── example_dft_atomic_kinds.py │ ├── example_failure.py │ ├── example_geopt.py │ ├── example_geopt_advanced_parser.py │ ├── example_max_error.py │ ├── example_mm.py │ ├── example_mm_md.py │ ├── example_multiple_force_eval.py │ ├── example_no_struct.py │ ├── example_precision.py │ ├── example_restart.py │ ├── example_sirius.py │ └── example_structure_through_file.py └── workchains │ ├── example_base_energy_restart.py │ ├── example_base_failed_restart.py │ ├── example_base_geo_opt_ignore_converge_restart.py │ ├── example_base_geoopt_restart.py │ ├── example_base_md_restart.py │ └── fixme_example_base_md_reftraj_restart.py ├── miscellaneous └── logos │ ├── MARVEL.png │ ├── MaX.png │ └── swissuniversities.png ├── pyproject.toml └── test ├── outputs ├── BANDS_output_v5.1.out ├── BANDS_output_v8.1.out ├── BSSE_output_v5.1_.out ├── GEO_OPT_v2024.3.out ├── GEO_OPT_v9.1.out ├── OT_v9.1.out ├── PBC_output_none.restart ├── PBC_output_xyz.restart ├── PBC_output_xz.restart ├── cdft_dos_cp2k_6.0.out └── tddft_cp2k_6.0.out ├── test_datatype_helpers.py ├── test_gaussian_datatypes.py ├── test_input_generator.py ├── test_parser.py └── test_xyz.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | parallel=True 3 | -------------------------------------------------------------------------------- /.docker/cp2k-code.yml: -------------------------------------------------------------------------------- 1 | label: cp2k 2 | computer: localhost 3 | description: 4 | default_calc_job_plugin: cp2k 5 | filepath_executable: /opt/conda/envs/cp2k/bin/cp2k.psmp 6 | append_text: 7 | prepend_text: | 8 | eval "$(command conda shell.bash hook 2> /dev/null)" 9 | conda activate cp2k 10 | -------------------------------------------------------------------------------- /.docker/init/add-codes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Debugging 4 | set -x 5 | 6 | # Environment 7 | export SHELL=/bin/bash 8 | 9 | # Install cp2k code. 10 | verdi code show cp2k@localhost || verdi code create core.code.installed --config /home/aiida/aiida-cp2k/.docker/cp2k-code.yml --non-interactive 11 | -------------------------------------------------------------------------------- /.docker/s6-rc.d/cp2k-code-setup/dependencies.d/aiida-prepare: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aiidateam/aiida-cp2k/c6b973e774c327066037544cff2e07f80a5fb4a4/.docker/s6-rc.d/cp2k-code-setup/dependencies.d/aiida-prepare -------------------------------------------------------------------------------- /.docker/s6-rc.d/cp2k-code-setup/timeout-up: -------------------------------------------------------------------------------- 1 | 0 2 | -------------------------------------------------------------------------------- /.docker/s6-rc.d/cp2k-code-setup/type: -------------------------------------------------------------------------------- 1 | oneshot 2 | -------------------------------------------------------------------------------- /.docker/s6-rc.d/cp2k-code-setup/up: -------------------------------------------------------------------------------- 1 | #!/command/execlineb -S0 2 | 3 | with-contenv 4 | 5 | foreground { s6-echo "Setting up CP2K code" } 6 | 7 | /etc/init/add-codes.sh 8 | -------------------------------------------------------------------------------- /.docker/user/cp2k-code-setup: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aiidateam/aiida-cp2k/c6b973e774c327066037544cff2e07f80a5fb4a4/.docker/user/cp2k-code-setup -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 88 3 | extend-ignore = 4 | E501 5 | W503 6 | E203 7 | exclude = 8 | docs/source/conf.py 9 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | 11 | test-plugin: 12 | 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | aiida-version: 17 | - '2.4.3' 18 | - '2.5.1' 19 | 20 | timeout-minutes: 30 21 | 22 | steps: 23 | 24 | - uses: actions/checkout@v2 25 | 26 | - name: Set up Docker Buildx 27 | uses: docker/setup-buildx-action@v1 28 | 29 | # see https://github.com/docker/build-push-action/blob/master/docs/advanced/cache.md#github-cache 30 | - name: Cache Docker layers 31 | uses: actions/cache@v2 32 | with: 33 | path: /tmp/.buildx-cache 34 | key: ${{ runner.os }}-buildx-${{ github.sha }} 35 | restore-keys: | 36 | ${{ runner.os }}-buildx- 37 | 38 | - name: Build 39 | uses: docker/build-push-action@v2 40 | with: 41 | context: . 42 | push: false 43 | load: true 44 | tags: aiida_cp2k_test 45 | cache-from: type=local,src=/tmp/.buildx-cache 46 | cache-to: type=local,dest=/tmp/.buildx-cache-new 47 | build-args: | 48 | AIIDA_VERSION=${{ matrix.aiida-version }} 49 | 50 | # Temp fix 51 | # https://github.com/docker/build-push-action/issues/252 52 | # https://github.com/moby/buildkit/issues/1896 53 | - name: Move cache 54 | run: | 55 | rm -rf /tmp/.buildx-cache 56 | mv /tmp/.buildx-cache-new /tmp/.buildx-cache 57 | 58 | - name: Create container from aiida_cp2k_test image and test the plugin inside 59 | run: | 60 | export DOCKERID=`docker run -d aiida_cp2k_test` 61 | sleep 5 62 | docker logs $DOCKERID 63 | docker exec --tty --user aiida $DOCKERID /bin/bash -l -c 'cd /home/aiida/aiida-cp2k/ && py.test --cov aiida_cp2k --cov-append .' 64 | 65 | 66 | docs: 67 | runs-on: ubuntu-latest 68 | timeout-minutes: 10 69 | strategy: 70 | matrix: 71 | python-version: [3.11] 72 | steps: 73 | - uses: actions/checkout@v2 74 | - name: Set up Python ${{ matrix.python-version }} 75 | uses: actions/setup-python@v2 76 | with: 77 | python-version: ${{ matrix.python-version }} 78 | - name: Install python dependencies 79 | run: | 80 | pip install --upgrade pip 81 | pip install -e .[docs,dev] 82 | 83 | - name: Build docs 84 | run: cd docs && make 85 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Publish on PyPI 3 | 4 | on: 5 | push: 6 | tags: 7 | # After vMajor.Minor.Patch _anything_ is allowed (without "/") ! 8 | - v[0-9]+.[0-9]+.[0-9]+* 9 | 10 | jobs: 11 | publish: 12 | runs-on: ubuntu-latest 13 | if: github.repository == 'aiidateam/aiida-cp2k' 14 | 15 | steps: 16 | - name: Checkout source 17 | uses: actions/checkout@v2 18 | - name: Set up Python 3.8 19 | uses: actions/setup-python@v2 20 | with: 21 | python-version: '3.8' 22 | - name: Install flit 23 | run: pip install flit~=3.4 24 | - name: Build and publish 25 | run: flit publish 26 | env: 27 | FLIT_USERNAME: __token__ 28 | FLIT_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} 29 | - uses: softprops/action-gh-release@v0.1.14 30 | name: Create release 31 | with: 32 | files: | 33 | dist/* 34 | generate_release_notes: true 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/vim,linux,macos,python,pycharm 3 | # Edit at https://www.gitignore.io/?templates=vim,linux,macos,python,pycharm 4 | 5 | ### Linux ### 6 | *~ 7 | 8 | # temporary files which can be created if a process still has a handle open of a deleted file 9 | .fuse_hidden* 10 | 11 | # KDE directory preferences 12 | .directory 13 | 14 | # Linux trash folder which might appear on any partition or disk 15 | .Trash-* 16 | 17 | # .nfs files are created when an open file is removed but is still being accessed 18 | .nfs* 19 | 20 | ### macOS ### 21 | # General 22 | .DS_Store 23 | .AppleDouble 24 | .LSOverride 25 | 26 | # Icon must end with two \r 27 | Icon 28 | 29 | # Thumbnails 30 | ._* 31 | 32 | # Files that might appear in the root of a volume 33 | .DocumentRevisions-V100 34 | .fseventsd 35 | .Spotlight-V100 36 | .TemporaryItems 37 | .Trashes 38 | .VolumeIcon.icns 39 | .com.apple.timemachine.donotpresent 40 | 41 | # Directories potentially created on remote AFP share 42 | .AppleDB 43 | .AppleDesktop 44 | Network Trash Folder 45 | Temporary Items 46 | .apdisk 47 | 48 | ### PyCharm ### 49 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 50 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 51 | 52 | # User-specific stuff 53 | .idea/**/workspace.xml 54 | .idea/**/tasks.xml 55 | .idea/**/usage.statistics.xml 56 | .idea/**/dictionaries 57 | .idea/**/shelf 58 | 59 | # Generated files 60 | .idea/**/contentModel.xml 61 | 62 | # Sensitive or high-churn files 63 | .idea/**/dataSources/ 64 | .idea/**/dataSources.ids 65 | .idea/**/dataSources.local.xml 66 | .idea/**/sqlDataSources.xml 67 | .idea/**/dynamic.xml 68 | .idea/**/uiDesigner.xml 69 | .idea/**/dbnavigator.xml 70 | 71 | # Gradle 72 | .idea/**/gradle.xml 73 | .idea/**/libraries 74 | 75 | # Gradle and Maven with auto-import 76 | # When using Gradle or Maven with auto-import, you should exclude module files, 77 | # since they will be recreated, and may cause churn. Uncomment if using 78 | # auto-import. 79 | # .idea/modules.xml 80 | # .idea/*.iml 81 | # .idea/modules 82 | # *.iml 83 | # *.ipr 84 | 85 | # CMake 86 | cmake-build-*/ 87 | 88 | # Mongo Explorer plugin 89 | .idea/**/mongoSettings.xml 90 | 91 | # File-based project format 92 | *.iws 93 | 94 | # IntelliJ 95 | out/ 96 | 97 | # mpeltonen/sbt-idea plugin 98 | .idea_modules/ 99 | 100 | # JIRA plugin 101 | atlassian-ide-plugin.xml 102 | 103 | # Cursive Clojure plugin 104 | .idea/replstate.xml 105 | 106 | # Crashlytics plugin (for Android Studio and IntelliJ) 107 | com_crashlytics_export_strings.xml 108 | crashlytics.properties 109 | crashlytics-build.properties 110 | fabric.properties 111 | 112 | # Editor-based Rest Client 113 | .idea/httpRequests 114 | 115 | # Android studio 3.1+ serialized cache file 116 | .idea/caches/build_file_checksums.ser 117 | 118 | ### PyCharm Patch ### 119 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 120 | 121 | # *.iml 122 | # modules.xml 123 | # .idea/misc.xml 124 | # *.ipr 125 | 126 | # Sonarlint plugin 127 | .idea/sonarlint 128 | 129 | ### Python ### 130 | # Byte-compiled / optimized / DLL files 131 | __pycache__/ 132 | *.py[cod] 133 | *$py.class 134 | 135 | # C extensions 136 | *.so 137 | 138 | # Distribution / packaging 139 | .Python 140 | build/ 141 | develop-eggs/ 142 | dist/ 143 | downloads/ 144 | eggs/ 145 | .eggs/ 146 | lib/ 147 | lib64/ 148 | parts/ 149 | sdist/ 150 | var/ 151 | wheels/ 152 | pip-wheel-metadata/ 153 | share/python-wheels/ 154 | *.egg-info/ 155 | .installed.cfg 156 | *.egg 157 | MANIFEST 158 | 159 | # PyInstaller 160 | # Usually these files are written by a python script from a template 161 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 162 | *.manifest 163 | *.spec 164 | 165 | # Installer logs 166 | pip-log.txt 167 | pip-delete-this-directory.txt 168 | 169 | # Unit test / coverage reports 170 | htmlcov/ 171 | .tox/ 172 | .nox/ 173 | .coverage 174 | .coverage.* 175 | .cache 176 | nosetests.xml 177 | coverage.xml 178 | *.cover 179 | .hypothesis/ 180 | .pytest_cache/ 181 | 182 | # Translations 183 | *.mo 184 | *.pot 185 | 186 | # Django stuff: 187 | *.log 188 | local_settings.py 189 | db.sqlite3 190 | db.sqlite3-journal 191 | 192 | # Flask stuff: 193 | instance/ 194 | .webassets-cache 195 | 196 | # Scrapy stuff: 197 | .scrapy 198 | 199 | # Sphinx documentation 200 | docs/_build/ 201 | 202 | # PyBuilder 203 | target/ 204 | 205 | # Jupyter Notebook 206 | .ipynb_checkpoints 207 | 208 | # IPython 209 | profile_default/ 210 | ipython_config.py 211 | 212 | # pyenv 213 | .python-version 214 | 215 | # pipenv 216 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 217 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 218 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 219 | # install all needed dependencies. 220 | #Pipfile.lock 221 | 222 | # celery beat schedule file 223 | celerybeat-schedule 224 | 225 | # SageMath parsed files 226 | *.sage.py 227 | 228 | # Environments 229 | .env 230 | .venv 231 | env/ 232 | venv/ 233 | ENV/ 234 | env.bak/ 235 | venv.bak/ 236 | 237 | # Spyder project settings 238 | .spyderproject 239 | .spyproject 240 | 241 | # Rope project settings 242 | .ropeproject 243 | 244 | # mkdocs documentation 245 | /site 246 | 247 | # mypy 248 | .mypy_cache/ 249 | .dmypy.json 250 | dmypy.json 251 | 252 | # Pyre type checker 253 | .pyre/ 254 | 255 | ### Vim ### 256 | # Swap 257 | [._]*.s[a-v][a-z] 258 | [._]*.sw[a-p] 259 | [._]s[a-rt-v][a-z] 260 | [._]ss[a-gi-z] 261 | [._]sw[a-p] 262 | 263 | # Session 264 | Session.vim 265 | Sessionx.vim 266 | 267 | # Temporary 268 | .netrwhist 269 | # Auto-generated tag files 270 | tags 271 | # Persistent undo 272 | [._]*.un~ 273 | 274 | # End of https://www.gitignore.io/api/vim,linux,macos,python,pycharm 275 | 276 | submit_test 277 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | ci: 3 | autoupdate_schedule: quarterly 4 | 5 | repos: 6 | - repo: https://github.com/pre-commit/pre-commit-hooks 7 | rev: v5.0.0 8 | hooks: 9 | 10 | - id: check-json 11 | - id: check-yaml 12 | - id: end-of-file-fixer 13 | exclude: &exclude_pre_commit_hooks > 14 | (?x)^( 15 | test/.*(? 97 | MaX 98 | swissuniversities 99 | -------------------------------------------------------------------------------- /aiida_cp2k/__init__.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """The official AiiDA plugin for CP2K.""" 8 | 9 | __version__ = "2.1.1" 10 | 11 | # EOF 12 | -------------------------------------------------------------------------------- /aiida_cp2k/utils/__init__.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """AiiDA-CP2K utils""" 8 | 9 | from .datatype_helpers import ( 10 | merge_trajectory_data_non_unique, 11 | merge_trajectory_data_unique, 12 | ) 13 | from .input_generator import ( 14 | Cp2kInput, 15 | add_ext_restart_section, 16 | add_first_snapshot_in_reftraj_section, 17 | add_ignore_convergence_failure, 18 | add_wfn_restart_section, 19 | increase_geo_opt_max_iter_by_factor, 20 | ) 21 | from .parser import parse_cp2k_output, parse_cp2k_output_advanced, parse_cp2k_trajectory 22 | from .workchains import ( 23 | HARTREE2EV, 24 | HARTREE2KJMOL, 25 | check_resize_unit_cell, 26 | get_input_multiplicity, 27 | get_kinds_section, 28 | get_last_convergence_value, 29 | merge_dict, 30 | merge_Dict, 31 | ot_has_small_bandgap, 32 | resize_unit_cell, 33 | ) 34 | 35 | __all__ = [ 36 | "Cp2kInput", 37 | "add_ext_restart_section", 38 | "add_ignore_convergence_failure", 39 | "add_first_snapshot_in_reftraj_section", 40 | "add_wfn_restart_section", 41 | "check_resize_unit_cell", 42 | "get_input_multiplicity", 43 | "get_kinds_section", 44 | "get_last_convergence_value", 45 | "HARTREE2EV", 46 | "HARTREE2KJMOL", 47 | "increase_geo_opt_max_iter_by_factor", 48 | "merge_dict", 49 | "merge_Dict", 50 | "merge_trajectory_data_unique", 51 | "merge_trajectory_data_non_unique", 52 | "ot_has_small_bandgap", 53 | "parse_cp2k_output", 54 | "parse_cp2k_output_advanced", 55 | "parse_cp2k_trajectory", 56 | "resize_unit_cell", 57 | ] 58 | -------------------------------------------------------------------------------- /aiida_cp2k/utils/input_generator.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """AiiDA-CP2K input generator.""" 8 | 9 | from collections.abc import Mapping, MutableMapping, MutableSequence, Sequence 10 | from copy import deepcopy 11 | 12 | from aiida.engine import calcfunction 13 | from aiida.orm import Dict 14 | 15 | from .workchains import merge_dict 16 | 17 | 18 | class Cp2kInput: 19 | """Transforms dictionary into CP2K input""" 20 | 21 | DISCLAIMER = "!!! Generated by AiiDA !!!" 22 | 23 | def __init__(self, params=None): 24 | """Initializing Cp2kInput object""" 25 | if not params: 26 | self._params = {} 27 | else: 28 | # always make a full copy to avoid that add_keyword() changes the 29 | # passed-in dictionary 30 | self._params = deepcopy(params) 31 | 32 | def __getitem__(self, key): 33 | return self._params[key] 34 | 35 | def add_keyword(self, kwpath, value, override=True, conflicting_keys=None): 36 | """ 37 | Add a value for the given keyword. 38 | 39 | Args: 40 | 41 | kwpath: Can be a single keyword, a path with `/` as divider for sections & key, 42 | or a sequence with sections and key. 43 | 44 | value: the value to set the given key to 45 | 46 | override: whether to override the key if it is already present in the self._params 47 | 48 | conflicting_keys: list of keys that cannot live together with the provided key 49 | (SOMETHING1/[..]/SOMETHING2/KEY). In case override is True, all conflicting keys will 50 | be removed, if override is False and conflicting_keys are present the new key won't be 51 | added. 52 | """ 53 | 54 | if isinstance(kwpath, str): 55 | kwpath = kwpath.split("/") 56 | 57 | Cp2kInput._add_keyword( 58 | kwpath, value, self._params, ovrd=override, cfct=conflicting_keys 59 | ) 60 | 61 | def render(self): 62 | output = [self.DISCLAIMER] 63 | self._render_section(output, deepcopy(self._params)) 64 | return "\n".join(output) 65 | 66 | def param_iter(self, sections=True): 67 | """Iterator yielding ((section,section,...,section/keyword), value) tuples""" 68 | stack = [((k,), v) for k, v in self._params.items()] 69 | 70 | while stack: 71 | key, value = stack.pop(0) 72 | if isinstance(value, Mapping): 73 | if sections: 74 | yield (key, value) 75 | stack += [(key + (k,), v) for k, v in value.items()] 76 | elif isinstance( 77 | value, MutableSequence 78 | ): # not just 'Sequence' to avoid matching strings 79 | for entry in value: 80 | stack += [(key, entry)] 81 | else: 82 | yield (key, value) 83 | 84 | @staticmethod 85 | def _add_keyword(kwpath, value, params, ovrd, cfct): 86 | """Add keyword into the given nested dictionary""" 87 | conflicting_keys_present = [] 88 | # key/value for the deepest level 89 | if len(kwpath) == 1: 90 | if cfct: 91 | conflicting_keys_present = [key for key in cfct if key in params] 92 | if ( 93 | ovrd 94 | ): # if ovrd is True, set the new element's value and remove the conflicting keys 95 | params[kwpath[0]] = value 96 | for key in conflicting_keys_present: 97 | params.pop(key) 98 | # if ovrd is False, I only add the new key if (1) it wasn't present beforeAND (2) it does not conflict 99 | # with any key that is currently present 100 | elif not conflicting_keys_present and kwpath[0] not in params: 101 | params[kwpath[0]] = value 102 | 103 | # the key was not present in the dictionary, and we are not yet at the deepest level, 104 | # therefore a subdictionary should be added 105 | elif kwpath[0] not in params: 106 | params[kwpath[0]] = {} 107 | Cp2kInput._add_keyword(kwpath[1:], value, params[kwpath[0]], ovrd, cfct) 108 | 109 | # if it is a list, loop over its elements 110 | elif isinstance(params[kwpath[0]], Sequence) and not isinstance( 111 | params[kwpath[0]], str 112 | ): 113 | for element in params[kwpath[0]]: 114 | Cp2kInput._add_keyword(kwpath[1:], value, element, ovrd, cfct) 115 | 116 | # if the key does NOT point to a dictionary and we are not yet at the deepest level, 117 | # therefore, the element should be replaced with an empty dictionary unless ovrd is False 118 | elif not isinstance(params[kwpath[0]], Mapping): 119 | if ovrd: 120 | params[kwpath[0]] = {} 121 | Cp2kInput._add_keyword(kwpath[1:], value, params[kwpath[0]], ovrd, cfct) 122 | # if params[kwpath[0]] points to a sub-dictionary, enter into it 123 | else: 124 | Cp2kInput._add_keyword(kwpath[1:], value, params[kwpath[0]], ovrd, cfct) 125 | 126 | @staticmethod 127 | def _render_section(output, params, indent=0): 128 | """It takes a dictionary and recurses through. 129 | 130 | For key-value pair it checks whether the value is a dictionary and prepends the key with & (CP2K section). 131 | It passes the valued to the same function, increasing the indentation. If the value is a list, I assume 132 | that this is something the user wants to store repetitively 133 | eg: 134 | .. highlight:: 135 | 136 | dict['KEY'] = ['val1', 'val2'] 137 | ===> 138 | KEY val1 139 | KEY val2 140 | 141 | or 142 | 143 | dict['KIND'] = [{'_': 'Ba', 'ELEMENT':'Ba'}, 144 | {'_': 'Ti', 'ELEMENT':'Ti'}, 145 | {'_': 'O', 'ELEMENT':'O'}] 146 | ====> 147 | &KIND Ba 148 | ELEMENT Ba 149 | &END KIND 150 | &KIND Ti 151 | ELEMENT Ti 152 | &END KIND 153 | &KIND O 154 | ELEMENT O 155 | &END KIND 156 | """ 157 | 158 | for key, val in sorted(params.items()): 159 | # keys are not case-insensitive, ensure that they follow the current scheme 160 | if key.upper() != key: 161 | raise ValueError(f"keyword '{key}' not upper case.") 162 | 163 | if key.startswith(("@", "$")): 164 | raise ValueError("CP2K preprocessor directives not supported.") 165 | 166 | if isinstance(val, MutableMapping): 167 | line = f"{' ' * indent}&{key}" 168 | if "_" in val: # if there is a section parameter, add it 169 | line += f" {val.pop('_')}" 170 | output.append(line) 171 | Cp2kInput._render_section(output, val, indent + 3) 172 | output.append(f"{' ' * indent}&END {key}") 173 | 174 | elif isinstance(val, Sequence) and not isinstance(val, str): 175 | for listitem in val: 176 | Cp2kInput._render_section(output, {key: listitem}, indent) 177 | 178 | elif isinstance(val, bool): 179 | val_str = ".TRUE." if val else ".FALSE." 180 | output.append(f"{' ' * indent}{key} {val_str}") 181 | 182 | else: 183 | output.append(f"{' ' * indent}{key} {val}") 184 | 185 | 186 | @calcfunction 187 | def add_wfn_restart_section(input_dict, is_kpoints): 188 | """Add wavefunction restart section to the input dictionary.""" 189 | params = input_dict.get_dict() 190 | fname = ( 191 | "./parent_calc/aiida-RESTART.kp" 192 | if is_kpoints 193 | else "./parent_calc/aiida-RESTART.wfn" 194 | ) 195 | restart_wfn_dict = { 196 | "FORCE_EVAL": { 197 | "DFT": { 198 | "RESTART_FILE_NAME": fname, 199 | "SCF": { 200 | "SCF_GUESS": "RESTART", 201 | }, 202 | }, 203 | }, 204 | } 205 | merge_dict(params, restart_wfn_dict) 206 | return Dict(params) 207 | 208 | 209 | @calcfunction 210 | def add_ext_restart_section(input_dict): 211 | """Add external restart section to the input dictionary.""" 212 | params = input_dict.get_dict() 213 | # overwrite the complete EXT_RESTART section if present 214 | params["EXT_RESTART"] = { 215 | "RESTART_FILE_NAME": "./parent_calc/aiida-1.restart", 216 | "RESTART_DEFAULT": ".TRUE.", 217 | "RESTART_COUNTERS": ".TRUE.", 218 | "RESTART_POS": ".TRUE.", 219 | "RESTART_VEL": ".TRUE.", 220 | "RESTART_CELL": ".TRUE.", 221 | "RESTART_THERMOSTAT": ".TRUE.", 222 | "RESTART_CONSTRAINT": ".FALSE.", 223 | } 224 | return Dict(params) 225 | 226 | 227 | @calcfunction 228 | def add_first_snapshot_in_reftraj_section(input_dict, first_snapshot): 229 | """Add first_snapshot in REFTRAJ section to the input dictionary.""" 230 | params = input_dict.get_dict() 231 | params["MOTION"]["MD"]["REFTRAJ"]["FIRST_SNAPSHOT"] = first_snapshot 232 | return Dict(params) 233 | 234 | 235 | @calcfunction 236 | def increase_geo_opt_max_iter_by_factor(input_dict, factor): 237 | """Increase the MAX_ITER in GEO_OPT section by a factor.""" 238 | params = input_dict.get_dict() 239 | params.setdefault("MOTION", {}).setdefault("GEO_OPT", {})["MAX_ITER"] = int( 240 | factor * params.get("MOTION", {}).get("GEO_OPT", {}).get("MAX_ITER", 100) 241 | ) 242 | return Dict(params) 243 | 244 | 245 | @calcfunction 246 | def add_ignore_convergence_failure(input_dict): 247 | """Add IGNORE_CONVERGENCE_FAILURE for non converged SCF runs.""" 248 | params = input_dict.get_dict() 249 | params.setdefault("FORCE_EVAL", {}).setdefault("DFT", {}).setdefault("SCF", {})[ 250 | "IGNORE_CONVERGENCE_FAILURE" 251 | ] = ".TRUE." 252 | return Dict(params) 253 | -------------------------------------------------------------------------------- /aiida_cp2k/utils/workchains.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """AiiDA-CP2K utilities for workchains""" 8 | 9 | import re 10 | 11 | from aiida.engine import calcfunction 12 | from aiida.orm import Dict 13 | from aiida.plugins import DataFactory 14 | 15 | StructureData = DataFactory("core.structure") 16 | 17 | HARTREE2EV = 27.211399 18 | HARTREE2KJMOL = 2625.500 19 | 20 | 21 | def merge_dict(dct, merge_dct): 22 | """Taken from https://gist.github.com/angstwad/bf22d1822c38a92ec0a9 23 | Recursive dict merge. Inspired by :meth:``dict.update()``, instead of 24 | updating only top-level keys, merge_dict recurses down into dicts nested 25 | to an arbitrary depth, updating keys. The ``merge_dct`` is merged into 26 | ``dct``. 27 | :param dct: dict onto which the merge is executed 28 | :param merge_dct: dct merged into dct (overwrites dct data if in both) 29 | :return: None 30 | """ 31 | from collections.abc import Mapping 32 | 33 | for k, _ in merge_dct.items(): # it was .iteritems() in python2 34 | if k in dct and isinstance(dct[k], dict) and isinstance(merge_dct[k], Mapping): 35 | merge_dict(dct[k], merge_dct[k]) 36 | else: 37 | dct[k] = merge_dct[k] 38 | 39 | 40 | @calcfunction 41 | def merge_Dict(d1, d2): 42 | """Make all the data in the second Dict overwrite the corrisponding data in the first Dict""" 43 | d1_dict = d1.get_dict() 44 | d2_dict = d2.get_dict() 45 | merge_dict(d1_dict, d2_dict) 46 | return Dict(d1_dict) 47 | 48 | 49 | def get_kinds_section(structure, protocol_settings): 50 | """Write the &KIND sections given the structure and the settings_dict""" 51 | kinds = [] 52 | all_atoms = set(structure.get_ase().get_chemical_symbols()) 53 | for atom in all_atoms: 54 | kinds.append( 55 | { 56 | "_": atom, 57 | "BASIS_SET": protocol_settings["basis_set"][atom], 58 | "POTENTIAL": protocol_settings["pseudopotential"][atom], 59 | "MAGNETIZATION": protocol_settings["initial_magnetization"][atom], 60 | } 61 | ) 62 | return {"FORCE_EVAL": {"SUBSYS": {"KIND": kinds}}} 63 | 64 | 65 | def get_input_multiplicity(structure, protocol_settings): 66 | """Compute the total multiplicity of the structure, 67 | by summing the atomic magnetizations: 68 | multiplicity = 1 + sum_i ( natoms_i * magnetization_i ), for each atom_type i 69 | """ 70 | multiplicity = 1 71 | all_atoms = structure.get_ase().get_chemical_symbols() 72 | for key, value in protocol_settings["initial_magnetization"].items(): 73 | multiplicity += all_atoms.count(key) * value 74 | multiplicity = int(round(multiplicity)) 75 | multiplicity_dict = {"FORCE_EVAL": {"DFT": {"MULTIPLICITY": multiplicity}}} 76 | if multiplicity != 1: 77 | multiplicity_dict["FORCE_EVAL"]["DFT"]["UKS"] = True 78 | return multiplicity_dict 79 | 80 | 81 | def ot_has_small_bandgap(cp2k_input, cp2k_output, bandgap_thr_ev): 82 | """Returns True if the calculation used OT and had a smaller bandgap then the guess needed for the OT. 83 | (NOTE: It has been observed also negative bandgap with OT in CP2K!) 84 | cp2k_input: dict 85 | cp2k_output: dict 86 | bandgap_thr_ev: float [eV] 87 | """ 88 | list_true = [True, "T", "t", ".TRUE.", "True", "true"] # add more? 89 | try: 90 | ot_settings = cp2k_input["FORCE_EVAL"]["DFT"]["SCF"]["OT"] 91 | if "_" not in ot_settings.keys() or ot_settings["_"] in list_true: 92 | using_ot = True 93 | else: 94 | using_ot = False 95 | except KeyError: 96 | using_ot = False 97 | min_bandgap_ev = ( 98 | min(cp2k_output["bandgap_spin1_au"], cp2k_output["bandgap_spin2_au"]) 99 | * HARTREE2EV 100 | ) 101 | is_bandgap_small = min_bandgap_ev < bandgap_thr_ev 102 | return using_ot and is_bandgap_small 103 | 104 | 105 | def get_last_convergence_value(input_string): 106 | """Search for last "OT CG" and returns the SCF gradient. 107 | 108 | If no "OT CG", searches for last "DIIS/Diag" and returns the gradient. 109 | 110 | Args: 111 | input_string (str): the cp2k output string. 112 | 113 | Returns: 114 | float or None: the SCF gradient or None if not found. 115 | """ 116 | # Search all "OT CG" lines and gets the 6th column. 117 | ot_cg_pattern = r"OT CG\s+\S+\s+\S+\s+\S+\s+\S+\s+([\d.E+-]+)" 118 | ot_cg_matches = re.findall(ot_cg_pattern, input_string) 119 | 120 | if ot_cg_matches: 121 | return float(ot_cg_matches[-1]) # Last value found for "OT CG". 122 | 123 | # Search for "DIIS/Diag" lines and returns the 5th column. 124 | diis_diag_pattern = r"DIIS/Diag\.\s+\S+\s+\S+\s+\S+\s+([\d.E+-]+)" 125 | diis_diag_matches = re.findall(diis_diag_pattern, input_string) 126 | 127 | if diis_diag_matches: 128 | return float(diis_diag_matches[-1]) # Last value found for "DIIS/Diag". 129 | 130 | return None # No value found. 131 | 132 | 133 | @calcfunction 134 | def check_resize_unit_cell(struct, threshold): 135 | """Returns the multiplication factors for the cell vectors to respect, in every direction: 136 | min(perpendicular_width) > threshold. 137 | """ 138 | from math import ceil, cos, fabs, sin, sqrt 139 | 140 | import numpy as np 141 | 142 | # Parsing structure's cell 143 | def angle(vect1, vect2): 144 | return np.arccos( 145 | np.dot(vect1, vect2) / (np.linalg.norm(vect1) * np.linalg.norm(vect2)) 146 | ) 147 | 148 | a_len = np.linalg.norm(struct.cell[0]) 149 | b_len = np.linalg.norm(struct.cell[1]) 150 | c_len = np.linalg.norm(struct.cell[2]) 151 | 152 | alpha = angle(struct.cell[1], struct.cell[2]) 153 | beta = angle(struct.cell[0], struct.cell[2]) 154 | gamma = angle(struct.cell[0], struct.cell[1]) 155 | 156 | # Computing triangular cell matrix 157 | vol = np.sqrt( 158 | 1 159 | - cos(alpha) ** 2 160 | - cos(beta) ** 2 161 | - cos(gamma) ** 2 162 | + 2 * cos(alpha) * cos(beta) * cos(gamma) 163 | ) 164 | cell = np.zeros((3, 3)) 165 | cell[0, :] = [a_len, 0, 0] 166 | cell[1, :] = [b_len * cos(gamma), b_len * sin(gamma), 0] 167 | cell[2, :] = [ 168 | c_len * cos(beta), 169 | c_len * (cos(alpha) - cos(beta) * cos(gamma)) / (sin(gamma)), 170 | c_len * vol / sin(gamma), 171 | ] 172 | cell = np.array(cell) 173 | 174 | # Computing perpendicular widths, as implemented in Raspa 175 | # for the check (simplified for triangular cell matrix) 176 | axc1 = cell[0, 0] * cell[2, 2] 177 | axc2 = -cell[0, 0] * cell[2, 1] 178 | bxc1 = cell[1, 1] * cell[2, 2] 179 | bxc2 = -cell[1, 0] * cell[2, 2] 180 | bxc3 = cell[1, 0] * cell[2, 1] - cell[1, 1] * cell[2, 0] 181 | det = fabs(cell[0, 0] * cell[1, 1] * cell[2, 2]) 182 | perpwidth = np.zeros(3) 183 | perpwidth[0] = det / sqrt(bxc1**2 + bxc2**2 + bxc3**2) 184 | perpwidth[1] = det / sqrt(axc1**2 + axc2**2) 185 | perpwidth[2] = cell[2, 2] 186 | 187 | # prevent from crashing if threshold.value is zero 188 | if threshold.value == 0: 189 | thr = 0.1 190 | else: 191 | thr = threshold.value 192 | 193 | resize = { 194 | "nx": int(ceil(thr / perpwidth[0])), 195 | "ny": int(ceil(thr / perpwidth[1])), 196 | "nz": int(ceil(thr / perpwidth[2])), 197 | } 198 | return Dict(resize) 199 | 200 | 201 | @calcfunction 202 | def resize_unit_cell(struct, resize): 203 | """Resize the StructureData according to the resize Dict""" 204 | resize_tuple = tuple(resize[x] for x in ["nx", "ny", "nz"]) 205 | return StructureData(ase=struct.get_ase().repeat(resize_tuple)) 206 | -------------------------------------------------------------------------------- /aiida_cp2k/workchains/__init__.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/cp2k/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """AiiDA-CP2K workchains""" 8 | 9 | from .base import Cp2kBaseWorkChain 10 | 11 | __all__ = ["Cp2kBaseWorkChain"] 12 | -------------------------------------------------------------------------------- /aiida_cp2k/workchains/base.py: -------------------------------------------------------------------------------- 1 | """Base work chain to run a CP2K calculation.""" 2 | 3 | import re 4 | 5 | from aiida import common, engine, orm, plugins 6 | 7 | from .. import utils 8 | 9 | Cp2kCalculation = plugins.CalculationFactory('cp2k') 10 | 11 | 12 | class Cp2kBaseWorkChain(engine.BaseRestartWorkChain): 13 | """Workchain to run a CP2K calculation with automated error handling and restarts.""" 14 | 15 | _process_class = Cp2kCalculation 16 | 17 | @classmethod 18 | def define(cls, spec): 19 | # yapf: disable 20 | super().define(spec) 21 | spec.expose_inputs(Cp2kCalculation, namespace='cp2k') 22 | 23 | spec.outline( 24 | cls.setup, 25 | engine.while_(cls.should_run_process)( 26 | cls.run_process, 27 | cls.inspect_process, 28 | cls.overwrite_input_structure, 29 | ), 30 | cls.results, 31 | ) 32 | 33 | spec.expose_outputs(Cp2kCalculation) 34 | spec.output('final_input_parameters', valid_type=orm.Dict, required=False, 35 | help='The input parameters used for the final calculation.') 36 | spec.exit_code(400, 'NO_RESTART_DATA', message="The calculation didn't produce any data to restart from.") 37 | spec.exit_code(300, 'ERROR_UNRECOVERABLE_FAILURE', 38 | message='The calculation failed with an unidentified unrecoverable error.') 39 | spec.exit_code(310, 'ERROR_KNOWN_UNRECOVERABLE_FAILURE', 40 | message='The calculation failed with a known unrecoverable error.') 41 | 42 | def setup(self): 43 | """Call the `setup` of the `BaseRestartWorkChain` and then create the inputs dictionary in `self.ctx.inputs`. 44 | 45 | This `self.ctx.inputs` dictionary will be used by the `BaseRestartWorkChain` to submit the calculations in the 46 | internal loop. 47 | """ 48 | super().setup() 49 | self.ctx.inputs = common.AttributeDict(self.exposed_inputs(Cp2kCalculation, 'cp2k')) 50 | 51 | def _collect_all_trajetories(self): 52 | """Collect all trajectories from the children calculations.""" 53 | trajectories = [] 54 | for called in self.ctx.children: 55 | if isinstance(called, orm.CalcJobNode): 56 | try: 57 | trajectories.append(called.outputs.output_trajectory) 58 | except AttributeError: 59 | pass 60 | return trajectories 61 | 62 | def results(self): 63 | super().results() 64 | if self.inputs.cp2k.parameters != self.ctx.inputs.parameters: 65 | self.out('final_input_parameters', self.ctx.inputs.parameters) 66 | 67 | trajectories = self._collect_all_trajetories() 68 | if trajectories: 69 | self.report("Work chain completed successfully, collecting all trajectories") 70 | if self.ctx.inputs.parameters.get_dict().get("GLOBAL", {}).get("RUN_TYPE") == "GEO_OPT": 71 | output_trajectory = utils.merge_trajectory_data_non_unique(*trajectories) 72 | else: 73 | output_trajectory = utils.merge_trajectory_data_unique(*trajectories) 74 | self.out("output_trajectory", output_trajectory) 75 | 76 | def overwrite_input_structure(self): 77 | if "output_structure" in self.ctx.children[self.ctx.iteration-1].outputs: 78 | self.ctx.inputs.structure = self.ctx.children[self.ctx.iteration-1].outputs.output_structure 79 | 80 | @engine.process_handler(priority=401, exit_codes=[ 81 | Cp2kCalculation.exit_codes.ERROR_OUT_OF_WALLTIME, 82 | Cp2kCalculation.exit_codes.ERROR_OUTPUT_INCOMPLETE, 83 | Cp2kCalculation.exit_codes.ERROR_SCF_NOT_CONVERGED, 84 | Cp2kCalculation.exit_codes.ERROR_MAXIMUM_NUMBER_OPTIMIZATION_STEPS_REACHED, 85 | ], enabled=False) 86 | def restart_incomplete_calculation(self, calc): 87 | """This handler restarts incomplete calculations.""" 88 | content_string = calc.outputs.retrieved.base.repository.get_object_content(calc.base.attributes.get('output_filename')) 89 | 90 | # CP2K was updating geometry. 91 | possible_geometry_restart = re.search(r"Max. gradient\s+=", content_string) or re.search(r"OPT\| Maximum gradient\s*[-+]?\d*\.?\d+", content_string) or "MD| Step number" in content_string 92 | 93 | # CP2K wrote a wavefunction restart file. 94 | possible_scf_restart = "Total energy: " in content_string 95 | 96 | # External restart file was written. 97 | possible_ext_restart = "Writing RESTART" in content_string 98 | 99 | # Check if calculation aborted due to SCF convergence failure. 100 | scf_didnt_converge_and_aborted = "SCF run NOT converged. To continue the calculation regardless" in content_string 101 | good_scf_gradient = None 102 | if scf_didnt_converge_and_aborted: 103 | scf_gradient = utils.get_last_convergence_value(content_string) 104 | scf_restart_thr = 1e-5 # if ABORT for not SCF convergence, but SCF gradient is small, continue 105 | good_scf_gradient = (scf_gradient is not None) and (scf_gradient < scf_restart_thr) 106 | 107 | # Condition for allowing restart. 108 | restart_possible = any([possible_geometry_restart, possible_scf_restart, possible_ext_restart]) and good_scf_gradient is not False 109 | if not restart_possible: # The message is written in the log file when the CP2K input parameter `LOG_PRINT_KEY` is set to True. 110 | self.report("It seems that the restart of CP2K calculation wouldn't be able to fix the problem as the " 111 | "previous calculation didn't produce any output to restart from. " 112 | "Sending a signal to stop the Base work chain.") 113 | 114 | # Signaling to the base work chain that the problem could not be recovered. 115 | return engine.ProcessHandlerReport(True, self.exit_codes.NO_RESTART_DATA) 116 | 117 | self.ctx.inputs.parent_calc_folder = calc.outputs.remote_folder 118 | params = self.ctx.inputs.parameters 119 | 120 | params = utils.add_wfn_restart_section(params, orm.Bool('kpoints' in self.ctx.inputs)) 121 | 122 | if possible_geometry_restart: 123 | # Check if we need to fix restart snapshot in REFTRAJ MD 124 | first_snapshot = None 125 | try: 126 | first_snapshot = int(params['MOTION']['MD']['REFTRAJ']['FIRST_SNAPSHOT']) + calc.outputs.output_trajectory.get_shape('positions')[0] 127 | self.report(f"First snapshot changed from {int(params['MOTION']['MD']['REFTRAJ']['FIRST_SNAPSHOT'])} to {first_snapshot}") 128 | if first_snapshot: 129 | params = utils.add_first_snapshot_in_reftraj_section(params, first_snapshot) 130 | except KeyError: 131 | pass 132 | params = utils.add_ext_restart_section(params) 133 | 134 | is_geo_opt = params.get_dict().get("GLOBAL", {}).get("RUN_TYPE") in ["GEO_OPT", "CELL_OPT"] 135 | if is_geo_opt and good_scf_gradient: 136 | self.report("The SCF was not converged, but the SCF gradient is small and we are optimising geometry. Enabling IGNORE_CONVERGENCE_FAILURE.") 137 | params = utils.add_ignore_convergence_failure(params) 138 | 139 | if calc.exit_code == Cp2kCalculation.exit_codes.ERROR_MAXIMUM_NUMBER_OPTIMIZATION_STEPS_REACHED: 140 | # If the maximum number of optimization steps is reached, we increase the number of steps by 40%. 141 | params = utils.increase_geo_opt_max_iter_by_factor(params, 1.4) 142 | 143 | self.ctx.inputs.parameters = params # params (new or old ones) that include the necessary restart information. 144 | self.report( 145 | "The CP2K calculation wasn't completed. The restart of the calculation might be able to " 146 | "fix the problem.") 147 | return engine.ProcessHandlerReport(False) 148 | -------------------------------------------------------------------------------- /conftest.py: -------------------------------------------------------------------------------- 1 | """For pytest initialise a test database and profile.""" 2 | 3 | import subprocess 4 | 5 | import pytest 6 | 7 | pytest_plugins = ["aiida.manage.tests.pytest_fixtures"] 8 | 9 | 10 | @pytest.fixture(scope="function") 11 | def cp2k_code(aiida_local_code_factory): 12 | return aiida_local_code_factory( 13 | entry_point="cp2k", 14 | executable="/opt/conda/envs/cp2k/bin/cp2k.psmp", 15 | prepend_text='eval "$(command conda shell.bash hook 2> /dev/null)"\nconda activate cp2k\n', 16 | ) 17 | 18 | 19 | # from https://stackoverflow.com/a/25188424 20 | # required for examples for optional features to show appropriate error messages 21 | def pytest_configure(config): 22 | import sys 23 | 24 | sys._called_from_test = True 25 | 26 | 27 | def pytest_unconfigure(config): 28 | import sys 29 | 30 | del sys._called_from_test 31 | 32 | 33 | @pytest.fixture(scope="session", autouse=True) 34 | def setup_sssp_pseudos(aiida_profile): 35 | """Create an SSSP pseudo potential family from scratch.""" 36 | subprocess.run( 37 | [ 38 | "aiida-pseudo", 39 | "install", 40 | "sssp", 41 | "-p", 42 | "efficiency", 43 | "-x", 44 | "PBE", 45 | "-v", 46 | "1.3", 47 | ] 48 | ) 49 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -n -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 21 | 22 | .PHONY: all help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext customdefault 23 | 24 | ## Runs with nitty-pick and converting warnings into errors to 25 | ## make sure the documentation is properly written 26 | customdefault: 27 | $(SPHINXBUILD) -b html -nW $(ALLSPHINXOPTS) $(BUILDDIR)/html 28 | 29 | all: html 30 | 31 | clean: 32 | rm -r $(BUILDDIR) 33 | 34 | html: 35 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 36 | @echo 37 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 38 | 39 | 40 | view: 41 | xdg-open $(BUILDDIR)/html/index.html 42 | -------------------------------------------------------------------------------- /docs/source/_static/style.css: -------------------------------------------------------------------------------- 1 | .wy-nav-content { 2 | max-width: 800px !important; 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | {% block extrahead %} 3 | 4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /docs/source/apidoc/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /docs/source/examples.rst: -------------------------------------------------------------------------------- 1 | Examples 2 | -------- 3 | 4 | See `examples` folder for complete examples of setting up a calculation or a work chain. 5 | 6 | 7 | Simple calculation 8 | ================== 9 | 10 | .. code-block:: bash 11 | 12 | cd examples/single_calculations 13 | verdi run example_dft.py # Submit example calculation. 14 | verdi process list -a -p1 # Check status of calculation. 15 | 16 | 17 | Work chain 18 | ========== 19 | 20 | .. code-block:: bash 21 | 22 | cd examples/workchains 23 | verdi run example_base.py # Submit test calculation. 24 | verdi process list -a -p1 # Check status of the work chain. 25 | -------------------------------------------------------------------------------- /docs/source/features.rst: -------------------------------------------------------------------------------- 1 | Features 2 | -------- 3 | 4 | Following the philosophy to ''enable without getting in the way'', this plugin provides access to all of CP2K's capabilities through a small set of well-tested features: 5 | 6 | A full `CP2K input `__ has to be provided as a nested Python dictionary `example `__: 7 | 8 | .. code-block:: python 9 | 10 | params = {'FORCE_EVAL': {'METHOD': 'Quickstep', 'DFT': { ... }}} 11 | builder.parameters = Dict(dict=params) 12 | 13 | 14 | Section parameters are stored as key `_` in the dictionary: 15 | 16 | .. code-block:: python 17 | 18 | xc_section = {'XC_FUNCTIONAL': {'_': 'LDA'}} 19 | 20 | Repeated sections are stored as a list: 21 | 22 | .. code-block:: python 23 | 24 | kind_section = [{'_': 'H', 'BASIS_SET': 'DZVP-MOLOPT-GTH', 'POTENTIAL': 'GTH-LDA'}, 25 | {'_': 'O', 'BASIS_SET': 'DZVP-MOLOPT-GTH', 'POTENTIAL': 'GTH-LDA'}] 26 | 27 | Most data files (basis sets, pseudo potentials, VdW, etc.) are auto-discovered from CP2K's `data directory `__. 28 | 29 | .. code-block:: python 30 | 31 | dft_section = {'BASIS_SET_FILE_NAME': 'BASIS_MOLOPT', ...} 32 | 33 | 34 | Additional data files can be added as AiiDA SinglefileData (`example `__): 35 | 36 | .. code-block:: python 37 | 38 | water_pot = SinglefileData(file=os.path.join("/tmp", "water.pot")) 39 | builder.file = {"water_pot": water_pot} 40 | 41 | The start geometry can be provided as AiiDA StructureData (`example `__): 42 | 43 | .. code-block:: python 44 | 45 | structure = StructureData(ase=ase.io.read(os.path.join(thisdir, '..', "files", 'h2o.xyz'))) 46 | 47 | Alternatively the start geometry can be contained in the CP2K input (`example `_): 48 | 49 | .. code-block:: python 50 | 51 | 'COORD': {' ': ['H 2.0 2.0 2.737166', 'H 2.0 2.0 2.000000']} 52 | 53 | For restarting a calculation a parent folder can be attached (`example `__): 54 | 55 | .. code-block:: python 56 | 57 | builder.parent_calc_folder = calc1['remote_folder'] 58 | 59 | By default only the output and restart file (if present) are retrieved. Additional files are retrieved upon request (`example `__): 60 | 61 | .. code-block:: python 62 | 63 | settings = Dict(dict={'additional_retrieve_list': ["runtime.callgraph"]}) 64 | builder.settings = settings 65 | 66 | The final geometry is extracted from the restart file (if present) and stored in AiiDA (`example `__): 67 | 68 | .. code-block:: python 69 | 70 | dist = calc['output_structure'].get_ase().get_distance(0, 1) 71 | 72 | 73 | The conversion of geometries between AiiDA and CP2K has a precision of at least 1e-10 Ångström (`example `__). 74 | -------------------------------------------------------------------------------- /docs/source/images/AiiDA_transparent_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aiidateam/aiida-cp2k/c6b973e774c327066037544cff2e07f80a5fb4a4/docs/source/images/AiiDA_transparent_logo.png -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. figure:: images/AiiDA_transparent_logo.png 2 | :width: 250px 3 | :align: center 4 | 5 | The aiida-cp2k plugin for `AiiDA`_ 6 | ===================================================== 7 | 8 | ``aiida-cp2k`` is available at https://github.com/aiidateam/aiida-cp2k 9 | 10 | 11 | .. toctree:: 12 | :maxdepth: 1 13 | 14 | features 15 | examples 16 | workflows 17 | 18 | 19 | API documentation 20 | 21 | 22 | If you use AiiDA for your research, please cite the following work: 23 | 24 | .. highlights:: Giovanni Pizzi, Andrea Cepellotti, Riccardo Sabatini, Nicola Marzari, 25 | and Boris Kozinsky, *AiiDA: automated interactive infrastructure and database 26 | for computational science*, Comp. Mat. Sci 111, 218-230 (2016); 27 | https://doi.org/10.1016/j.commatsci.2015.09.013; http://www.aiida.net. 28 | 29 | ``aiida-cp2k`` is released under the MIT license. 30 | 31 | 32 | 33 | 34 | Indices and tables 35 | ================== 36 | 37 | * :ref:`genindex` 38 | * :ref:`modindex` 39 | * :ref:`search` 40 | 41 | .. _AiiDA: http://www.aiida.net 42 | -------------------------------------------------------------------------------- /docs/source/workflows.rst: -------------------------------------------------------------------------------- 1 | Workflows 2 | --------- 3 | 4 | .. aiida-workchain:: Cp2kBaseWorkChain 5 | :module: aiida_cp2k.workchains.base 6 | -------------------------------------------------------------------------------- /examples/files/GTH_POTENTIALS: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # 3 | # Potential data base file for CP2K (Quickstep) 4 | # 5 | ################################################################################ 6 | # 7 | # Pseudopotentials of Goedecker, Teter and Hutter (GTH) 8 | # ----------------------------------------------------- 9 | # 10 | # History: - Creation (12.12.1999, Matthias Krack) 11 | # - Electronic configurations added (11.05.2000,MK) 12 | # - GTH-PP for first-row transition metal added (18.03.2003,MK) 13 | # - Automatic update (16.12.2003,MK) 14 | # - PBE GTH-PPs for the Lanthanides added (30.11.2012,MK) 15 | # - Set default GTH PPs (12.08.2016,MK) 16 | # - Last update (21.10.2016,MK) 17 | # 18 | # Literature: - S. Goedecker, M. Teter, and J. Hutter, 19 | # Phys. Rev. B 54, 1703 (1996) 20 | # - C. Hartwigsen, S. Goedecker, and J. Hutter, 21 | # Phys. Rev. B 58, 3641 (1998) 22 | # - M. Krack, 23 | # Theor. Chem. Acc. 114, 145 (2005) 24 | # 25 | # GTH-potential format: 26 | # 27 | # Element symbol Name of the potential Alias names 28 | # n_elec(s) n_elec(p) n_elec(d) ... 29 | # r_loc nexp_ppl cexp_ppl(1) ... cexp_ppl(nexp_ppl) 30 | # nprj 31 | # r(1) nprj_ppnl(1) ((hprj_ppnl(1,i,j),j=i,nprj_ppnl(1)),i=1,nprj_ppnl(1)) 32 | # r(2) nprj_ppnl(2) ((hprj_ppnl(2,i,j),j=i,nprj_ppnl(2)),i=1,nprj_ppnl(2)) 33 | # . . . 34 | # . . . 35 | # . . . 36 | # r(nprj) nprj_ppnl(nprj) ((hprj_ppnl(nprj,i,j),j=i,nprj_ppnl(nprj)), 37 | # i=1,nprj_ppnl(nprj)) 38 | # 39 | # n_elec : Number of electrons for each angular momentum quantum number 40 | # (electronic configuration -> s p d ...) 41 | # r_loc : Radius for the local part defined by the Gaussian function 42 | # exponent alpha_erf 43 | # nexp_ppl : Number of the local pseudopotential functions 44 | # cexp_ppl : Coefficients of the local pseudopotential functions 45 | # nprj : Number of the non-local projectors => nprj = SIZE(nprj_ppnl(:)) 46 | # r : Radius of the non-local part for angular momentum quantum number l 47 | # defined by the Gaussian function exponents alpha_prj_ppnl 48 | # nprj_ppnl: Number of the non-local projectors for the angular momentum 49 | # quantum number l 50 | # hprj_ppnl: Coefficients of the non-local projector functions 51 | # 52 | ################################################################################ 53 | # 54 | # PADE functional 55 | # 56 | ################################################################################ 57 | # 58 | H GTH-PADE-q1 GTH-LDA-q1 GTH-PADE GTH-LDA 59 | 1 60 | 0.20000000 2 -4.18023680 0.72507482 61 | 0 62 | # 63 | He GTH-PADE-q2 GTH-LDA-q2 GTH-PADE GTH-LDA 64 | 2 65 | 0.20000000 2 -9.11202340 1.69836797 66 | 0 67 | # 68 | Li GTH-PADE-q1 GTH-LDA-q1 69 | 1 70 | 0.78755305 2 -1.89261247 0.28605968 71 | 2 72 | 0.66637518 1 1.85881111 73 | 1.07930561 1 -0.00589504 74 | # 75 | Be GTH-PADE-q2 GTH-LDA-q2 76 | 2 77 | 0.73900865 2 -2.59295078 0.35483893 78 | 2 79 | 0.52879656 1 3.06166591 80 | 0.65815348 1 0.09246196 81 | # 82 | B GTH-PADE-q3 GTH-LDA-q3 GTH-PADE GTH-LDA 83 | 2 1 84 | 0.43392956 2 -5.57864173 0.80425145 85 | 2 86 | 0.37384326 1 6.23392822 87 | 0.36039317 0 88 | # 89 | C GTH-PADE-q4 GTH-LDA-q4 GTH-PADE GTH-LDA 90 | 2 2 91 | 0.34883045 2 -8.51377110 1.22843203 92 | 2 93 | 0.30455321 1 9.52284179 94 | 0.23267730 0 95 | # 96 | N GTH-PADE-q5 GTH-LDA-q5 GTH-PADE GTH-LDA 97 | 2 3 98 | 0.28917923 2 -12.23481988 1.76640728 99 | 2 100 | 0.25660487 1 13.55224272 101 | 0.27013369 0 102 | # 103 | O GTH-PADE-q6 GTH-LDA-q6 GTH-PADE GTH-LDA 104 | 2 4 105 | 0.24762086 2 -16.58031797 2.39570092 106 | 2 107 | 0.22178614 1 18.26691718 108 | 0.25682890 0 109 | # 110 | F GTH-PADE-q7 GTH-LDA-q7 GTH-PADE GTH-LDA 111 | 2 5 112 | 0.21852465 2 -21.30736112 3.07286942 113 | 2 114 | 0.19556721 1 23.58494211 115 | 0.17426832 0 116 | # 117 | Ne GTH-PADE-q8 GTH-LDA-q8 GTH-PADE GTH-LDA 118 | 2 6 119 | 0.19000000 2 -27.69285182 4.00590585 120 | 2 121 | 0.17948804 2 28.50609828 0.41682800 122 | -1.07624528 123 | 0.21491271 1 -0.00008991 124 | # 125 | Na GTH-PADE-q1 GTH-LDA-q1 126 | 1 127 | 0.88550938 1 -1.23886713 128 | 2 129 | 0.66110390 2 1.84727135 -0.22540903 130 | 0.58200362 131 | 0.85711928 1 0.47113258 132 | # 133 | Na GTH-PADE-q9 GTH-LDA-q9 GTH-PADE GTH-LDA 134 | 3 6 135 | 0.24631780 2 -7.54559253 1.12599671 136 | 2 137 | 0.14125125 1 36.55698653 138 | 0.13966840 1 -10.39208332 139 | # 140 | Mg GTH-PADE-q10 GTH-LDA-q10 GTH-PADE GTH-LDA 141 | 4 6 142 | 0.21094954 2 -19.41900751 2.87133099 143 | 2 144 | 0.14154696 1 40.31662629 145 | 0.10546902 1 -10.89111329 146 | # 147 | Mg GTH-PADE-q2 GTH-LDA-q2 148 | 2 149 | 0.65181169 1 -2.86429746 150 | 2 151 | 0.55647814 2 2.97095712 -0.51508390 152 | 1.32994091 153 | 0.67756881 1 1.04988101 154 | # 155 | Al GTH-PADE-q3 GTH-LDA-q3 GTH-PADE GTH-LDA 156 | 2 1 157 | 0.45000000 1 -8.49135116 158 | 2 159 | 0.46010427 2 5.08833953 -1.03784325 160 | 2.67969975 161 | 0.53674439 1 2.19343827 162 | # 163 | Si GTH-PADE-q4 GTH-LDA-q4 GTH-PADE GTH-LDA 164 | 2 2 165 | 0.44000000 1 -7.33610297 166 | 2 167 | 0.42273813 2 5.90692831 -1.26189397 168 | 3.25819622 169 | 0.48427842 1 2.72701346 170 | # 171 | P GTH-PADE-q5 GTH-LDA-q5 GTH-PADE GTH-LDA 172 | 2 3 173 | 0.43000000 1 -6.65421981 174 | 2 175 | 0.38980284 2 6.84213556 -1.49369090 176 | 3.85669332 177 | 0.44079585 1 3.28260592 178 | # 179 | S GTH-PADE-q6 GTH-LDA-q6 GTH-PADE GTH-LDA 180 | 2 4 181 | 0.42000000 1 -6.55449184 182 | 2 183 | 0.36175665 2 7.90530250 -1.73188130 184 | 4.47169830 185 | 0.40528502 1 3.86657900 186 | # 187 | Cl GTH-PADE-q7 GTH-LDA-q7 GTH-PADE GTH-LDA 188 | 2 5 189 | 0.41000000 1 -6.86475431 190 | 2 191 | 0.33820832 2 9.06223968 -1.96193036 192 | 5.06568240 193 | 0.37613709 1 4.46587640 194 | # 195 | Ar GTH-PADE-q8 GTH-LDA-q8 GTH-PADE GTH-LDA 196 | 2 6 197 | 0.40000000 1 -7.10000000 198 | 2 199 | 0.31738081 2 10.24948699 -2.16984522 200 | 5.60251627 201 | 0.35161921 1 4.97880101 202 | # 203 | ################################################################################ 204 | # 205 | # PBE functional 206 | # 207 | ################################################################################ 208 | # 209 | H GTH-PBE-q1 GTH-PBE 210 | 1 211 | 0.20000000 2 -4.17890044 0.72446331 212 | 0 213 | # 214 | He GTH-PBE-q2 GTH-PBE 215 | 2 216 | 0.20000000 2 -9.12214383 1.70270770 217 | 0 218 | # 219 | Li GTH-PBE-q3 GTH-PBE 220 | 3 221 | 0.40000000 4 -14.08115455 9.62621962 -1.78361605 0.08515207 222 | 0 223 | # 224 | Be GTH-PBE-q4 GTH-PBE 225 | 4 226 | 0.32500000 4 -24.06746684 17.27902186 -3.33910629 0.16554912 227 | 0 228 | # 229 | B GTH-PBE-q3 GTH-PBE 230 | 2 1 231 | 0.41899145 2 -5.85946171 0.90375643 232 | 2 233 | 0.37132046 1 6.29728018 234 | 0.36456308 0 235 | # 236 | C GTH-PBE-q4 GTH-PBE 237 | 2 2 238 | 0.33847124 2 -8.80367398 1.33921085 239 | 2 240 | 0.30257575 1 9.62248665 241 | 0.29150694 0 242 | # 243 | N GTH-PBE-q5 GTH-PBE 244 | 2 3 245 | 0.28379051 2 -12.41522559 1.86809592 246 | 2 247 | 0.25540500 1 13.63026257 248 | 0.24549453 0 249 | # 250 | O GTH-PBE-q6 GTH-PBE 251 | 2 4 252 | 0.24455430 2 -16.66721480 2.48731132 253 | 2 254 | 0.22095592 1 18.33745811 255 | 0.21133247 0 256 | # 257 | F GTH-PBE-q7 GTH-PBE 258 | 2 5 259 | 0.21492959 2 -21.57302836 3.19977615 260 | 2 261 | 0.19468402 1 23.74354045 262 | 0.18615608 0 263 | # 264 | Ne GTH-PBE-q8 GTH-PBE 265 | 2 6 266 | 0.19000000 2 -27.12015973 4.36044962 267 | 2 268 | 0.17605938 2 28.17737082 0.83365601 269 | -1.07624528 270 | 0.19547452 1 -0.23629360 271 | # 272 | Na GTH-PBE-q9 GTH-PBE 273 | 3 6 274 | 0.23652322 2 0.29510499 -0.91388488 275 | 2 276 | 0.14356046 1 34.60149228 277 | 0.12993224 1 -14.27746168 278 | # 279 | Mg GTH-PBE-q10 GTH-PBE 280 | 4 6 281 | 0.19275787 2 -20.57539077 3.04016732 282 | 2 283 | 0.14140682 1 41.04729209 284 | 0.10293187 1 -9.98562566 285 | # 286 | Mg GTH-PBE-q2 287 | 2 288 | 0.57696017 1 -2.69040744 289 | 2 290 | 0.59392350 2 3.50321099 -0.71677167 291 | 0.92534825 292 | 0.70715728 1 0.83115848 293 | # 294 | Al GTH-PBE-q3 GTH-PBE 295 | 2 1 296 | 0.45000000 1 -7.55476126 297 | 2 298 | 0.48743529 2 6.95993832 -1.88883584 299 | 2.43847659 300 | 0.56218949 1 1.86529857 301 | # 302 | Si GTH-PBE-q4 GTH-PBE 303 | 2 2 304 | 0.44000000 1 -6.26928833 305 | 2 306 | 0.43563383 2 8.95174150 -2.70627082 307 | 3.49378060 308 | 0.49794218 1 2.43127673 309 | # 310 | P GTH-PBE-q5 GTH-PBE 311 | 2 3 312 | 0.43000000 1 -5.87594327 313 | 2 314 | 0.39637742 2 11.00886207 -3.47035607 315 | 4.48021042 316 | 0.44829838 1 3.05606416 317 | # 318 | S GTH-PBE-q6 GTH-PBE 319 | 2 4 320 | 0.42000000 1 -5.98626038 321 | 2 322 | 0.36482035 2 13.14354448 -4.24183045 323 | 5.47617957 324 | 0.40948048 1 3.70089057 325 | # 326 | Cl GTH-PBE-q7 GTH-PBE 327 | 2 5 328 | 0.41000000 1 -6.39208181 329 | 2 330 | 0.33953864 2 15.21898983 -4.93452321 331 | 6.37044208 332 | 0.37847416 1 4.33877527 333 | # 334 | Ar GTH-PBE-q8 GTH-PBE 335 | 2 6 336 | 0.40000000 1 -7.10000000 337 | 2 338 | 0.31881468 2 17.25203807 -5.58548836 339 | 7.21083447 340 | 0.35337019 1 4.97421551 341 | # 342 | -------------------------------------------------------------------------------- /examples/files/h2.xyz: -------------------------------------------------------------------------------- 1 | 2 2 | Lattice="4.0 0.0 0.0 0.0 4.0 0.0 0.0 0.0 4.737166" Properties=species:S:1:pos:R:3 pbc="F F F" 3 | H 2.00000000 2.00000000 2.73716600 4 | H 2.00000000 2.00000000 2.00000000 5 | -------------------------------------------------------------------------------- /examples/files/h2o.xyz: -------------------------------------------------------------------------------- 1 | 3 2 | Lattice="10.0 0.0 0.0 0.0 10.0 0.0 0.0 0.0 10.0" Properties=species:S:1:pos:R:3 pbc="F F F" 3 | O 5.0 5.763239 5.596309 4 | H 5.0 6.526478 5.000000 5 | H 5.0 5.000000 5.000000 6 | -------------------------------------------------------------------------------- /examples/files/si.xyz: -------------------------------------------------------------------------------- 1 | 2 2 | Lattice="3.81196 0.0 0.0 1.9059800000000005 3.3012541982101284 0.0 1.9059800000000005 1.100418066070043 3.112452306633254" Properties=species:S:1:pos:R:3:_aiidalab_viewer_representation_default:I:1 spacegroup="P 1" unit_cell=conventional pbc="T T T" 3 | Si 0.00000000 0.00000000 0.00000000 0 4 | Si 1.90598000 1.10041807 0.77811308 0 5 | -------------------------------------------------------------------------------- /examples/gaussian_datatypes/example_automatic.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Simple DFT calculations with Gaussian Datatypes examples""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run 16 | from aiida.orm import Code, Dict 17 | from aiida.plugins import DataFactory 18 | from gdt_data import load_data 19 | 20 | StructureData = DataFactory("core.structure") 21 | 22 | 23 | def example_gdt(cp2k_code): 24 | """ 25 | Testing CP2K with the Basis Set and Pseudopotential stored in gaussian.basisset/pseudo. 26 | In this example the KIND section is omitted completely and the aiida-cp2k plugin will 27 | automatically assign basissets and pseudopotential data based on the different kinds of 28 | the structure. This only works if the assignment can be done unambiguously, hence the 29 | need to give a list of basissets and pseudos to be used. You can also not give more 30 | basissets or pseudos than actually required to avoid false links in the provenance graph. 31 | """ 32 | 33 | thisdir = os.path.dirname(os.path.realpath(__file__)) 34 | 35 | # Structure. 36 | structure = StructureData( 37 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "h2o.xyz")) 38 | ) 39 | 40 | bsets, pseudos = load_data(prefix="MY-AUTO-") 41 | # in your code you will probably use something like: 42 | # bsets = [ 43 | # BasisSet.get(element="H", name="DZVP-MOLOPT-GTH") 44 | # BasisSet.get(element="O", name="DZVP-MOLOPT-SR-GTH") 45 | # ] 46 | # ... 47 | 48 | # parameters 49 | parameters = Dict( 50 | { 51 | "FORCE_EVAL": { 52 | "METHOD": "Quickstep", 53 | "DFT": { 54 | "QS": { 55 | "EPS_DEFAULT": 1.0e-12, 56 | "WF_INTERPOLATION": "ps", 57 | "EXTRAPOLATION_ORDER": 3, 58 | }, 59 | "MGRID": {"NGRIDS": 4, "CUTOFF": 280, "REL_CUTOFF": 30}, 60 | "XC": {"XC_FUNCTIONAL": {"_": "LDA"}}, 61 | "POISSON": {"PERIODIC": "none", "PSOLVER": "MT"}, 62 | }, 63 | } 64 | } 65 | ) 66 | 67 | # Construct process builder. 68 | builder = cp2k_code.get_builder() 69 | builder.structure = structure 70 | builder.parameters = parameters 71 | builder.code = cp2k_code 72 | builder.metadata.options.resources = { 73 | "num_machines": 1, 74 | "num_mpiprocs_per_machine": 1, 75 | } 76 | builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60 77 | builder.basissets = bsets 78 | builder.pseudos = pseudos 79 | 80 | print("Submitted calculation...") 81 | run(builder) 82 | 83 | 84 | @click.command("cli") 85 | @click.argument("codelabel") 86 | def cli(codelabel): 87 | """Click interface.""" 88 | try: 89 | code = Code.get_from_string(codelabel) 90 | except NotExistent: 91 | print(f"The code '{codelabel}' does not exist.") 92 | sys.exit(1) 93 | example_gdt(code) 94 | 95 | 96 | if __name__ == "__main__": 97 | cli() 98 | -------------------------------------------------------------------------------- /examples/gaussian_datatypes/example_explicit.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Simple DFT calculations with Gaussian Datatypes examples""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run 16 | from aiida.orm import Code, Dict 17 | from aiida.plugins import DataFactory 18 | from gdt_data import load_data 19 | 20 | StructureData = DataFactory("core.structure") 21 | 22 | 23 | def example_gdt(cp2k_code): 24 | """ 25 | Testing CP2K with the Basis Set and Pseudopotential stored in gaussian.basisset/pseudo. 26 | In this example the names of the basissets and pseudopotentials are still explicitly named 27 | in the CP2K input section. The plugin will then validate the names against the data objects 28 | passed to ensure consistency, and alter the generated CP2K input file to include the parameters 29 | contained in the specified basisset and pseudopotential objects, rather than relying on the 30 | data being present on the target node. 31 | Use this mode if you are migrating from implicitly tracked basissets and pseudos or if you 32 | you have more complicated setups (e.g. having different basissets for the same kind on different sites). 33 | """ 34 | 35 | thisdir = os.path.dirname(os.path.realpath(__file__)) 36 | 37 | # Structure. 38 | structure = StructureData( 39 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "h2o.xyz")) 40 | ) 41 | 42 | # in your actual code you may want to get the basisset and pseudopotential 43 | # with a lookup in the database, here we can simply call load_data() 44 | bsets, pseudos = load_data(prefix="MY-EXPLICIT-") 45 | # in your code you will probably use something like: 46 | # bsets = [ 47 | # BasisSet.get(element="H", name="DZVP-MOLOPT-GTH") 48 | # BasisSet.get(element="O", name="DZVP-MOLOPT-SR-GTH") 49 | # ] 50 | # ... 51 | 52 | # parameters 53 | parameters = Dict( 54 | { 55 | "FORCE_EVAL": { 56 | "METHOD": "Quickstep", 57 | "DFT": { 58 | "QS": { 59 | "EPS_DEFAULT": 1.0e-12, 60 | "WF_INTERPOLATION": "ps", 61 | "EXTRAPOLATION_ORDER": 3, 62 | }, 63 | "MGRID": {"NGRIDS": 4, "CUTOFF": 280, "REL_CUTOFF": 30}, 64 | "XC": {"XC_FUNCTIONAL": {"_": "LDA"}}, 65 | "POISSON": {"PERIODIC": "none", "PSOLVER": "MT"}, 66 | }, 67 | "SUBSYS": { 68 | "KIND": [ 69 | { 70 | "_": "O", 71 | "POTENTIAL": "GTH {p.name}".format(p=pseudos["O"]), 72 | "BASIS_SET": "ORB {b.name}".format(b=bsets["O"]), 73 | }, 74 | { 75 | "_": "H", 76 | "POTENTIAL": "GTH {p.name}".format(p=pseudos["H"]), 77 | "BASIS_SET": "ORB {b.name}".format(b=bsets["H"]), 78 | }, 79 | ] 80 | }, 81 | } 82 | } 83 | ) 84 | 85 | # Construct process builder. 86 | builder = cp2k_code.get_builder() 87 | builder.structure = structure 88 | builder.parameters = parameters 89 | builder.code = cp2k_code 90 | builder.metadata.options.resources = { 91 | "num_machines": 1, 92 | "num_mpiprocs_per_machine": 1, 93 | } 94 | builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60 95 | builder.basissets = bsets 96 | builder.pseudos = pseudos 97 | 98 | print("Submitted calculation...") 99 | run(builder) 100 | 101 | 102 | @click.command("cli") 103 | @click.argument("codelabel") 104 | def cli(codelabel): 105 | """Click interface.""" 106 | try: 107 | code = Code.get_from_string(codelabel) 108 | except NotExistent: 109 | print(f"The code '{codelabel}' does not exist.") 110 | sys.exit(1) 111 | example_gdt(code) 112 | 113 | 114 | if __name__ == "__main__": 115 | cli() 116 | -------------------------------------------------------------------------------- /examples/gaussian_datatypes/gdt_data.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Create Gaussian basisset and pseudopotential data in the database""" 8 | 9 | from io import StringIO 10 | 11 | from aiida.common.exceptions import UniquenessError 12 | from aiida.plugins import DataFactory 13 | 14 | 15 | def load_data(prefix="MY-"): 16 | """ 17 | This is something the user will usually do only ONCE and most likely by 18 | using the CLI of the aiida-gaussian-datatypes. 19 | """ 20 | 21 | # Note: the basissets and pseudos deliberately have a prefix to avoid matching 22 | # any CP2K provided entries which may creep in via the DATA_DIR 23 | 24 | bset_input = f"""\ 25 | H {prefix}AUTO-DZVP-MOLOPT-GTH {prefix}AUTO-DZVP-MOLOPT-GTH-q1 26 | 1 27 | 2 0 1 7 2 1 28 | 11.478000339908 0.024916243200 -0.012512421400 0.024510918200 29 | 3.700758562763 0.079825490000 -0.056449071100 0.058140794100 30 | 1.446884268432 0.128862675300 0.011242684700 0.444709498500 31 | 0.716814589696 0.379448894600 -0.418587548300 0.646207973100 32 | 0.247918564176 0.324552432600 0.590363216700 0.803385018200 33 | 0.066918004004 0.037148121400 0.438703133000 0.892971208700 34 | 0.021708243634 -0.001125195500 -0.059693171300 0.120101316500 35 | 36 | O {prefix}AUTO-DZVP-MOLOPT-SR-GTH {prefix}AUTO-DZVP-MOLOPT-SR-GTH-q6 37 | 1 38 | 2 0 2 5 2 2 1 39 | 10.389228018317 0.126240722900 0.069215797900 -0.061302037200 -0.026862701100 0.029845227500 40 | 3.849621072005 0.139933704300 0.115634538900 -0.190087511700 -0.006283021000 0.060939733900 41 | 1.388401188741 -0.434348231700 -0.322839719400 -0.377726982800 -0.224839187800 0.732321580100 42 | 0.496955043655 -0.852791790900 -0.095944016600 -0.454266086000 0.380324658600 0.893564918400 43 | 0.162491615040 -0.242351537800 1.102830348700 -0.257388983000 1.054102919900 0.152954188700 44 | """ 45 | 46 | pseudo_input = f"""\ 47 | # 48 | H {prefix}AUTO-GTH-PADE-q1 {prefix}AUTO-GTH-LDA-q1 {prefix}AUTO-GTH-PADE {prefix}AUTO-GTH-LDA 49 | 1 50 | 0.20000000 2 -4.18023680 0.72507482 51 | 0 52 | 53 | O {prefix}AUTO-GTH-PADE-q6 {prefix}AUTO-GTH-LDA-q6 {prefix}AUTO-GTH-PADE {prefix}AUTO-GTH-LDA 54 | 2 4 55 | 0.24762086 2 -16.58031797 2.39570092 56 | 2 57 | 0.22178614 1 18.26691718 58 | 0.25682890 0 59 | """ 60 | 61 | BasisSet = DataFactory("gaussian.basisset") 62 | Pseudo = DataFactory("gaussian.pseudo") 63 | 64 | fhandle_bset = StringIO(bset_input) 65 | fhandle_pseudo = StringIO(pseudo_input) 66 | 67 | try: 68 | bsets = { 69 | b.element: b 70 | for b in BasisSet.from_cp2k(fhandle_bset, duplicate_handling="error") 71 | } 72 | pseudos = { 73 | p.element: p 74 | for p in Pseudo.from_cp2k(fhandle_pseudo, duplicate_handling="error") 75 | } 76 | except ( 77 | UniquenessError 78 | ): # if the user already ran the script, fetch the data from the db instead 79 | bsets = { 80 | "H": BasisSet.get("H", f"{prefix}AUTO-DZVP-MOLOPT-GTH"), 81 | "O": BasisSet.get("O", f"{prefix}AUTO-DZVP-MOLOPT-SR-GTH"), 82 | } 83 | pseudos = { 84 | "H": Pseudo.get("H", f"{prefix}AUTO-GTH-PADE-q1"), 85 | "O": Pseudo.get("O", f"{prefix}AUTO-GTH-PADE-q6"), 86 | } 87 | 88 | return bsets, pseudos 89 | -------------------------------------------------------------------------------- /examples/single_calculations/example_bands.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/cp2k/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Run simple Band Structure calculation""" 8 | 9 | import os 10 | import sys 11 | 12 | import click 13 | import numpy as np 14 | from aiida.common import NotExistent 15 | from aiida.engine import run 16 | from aiida.orm import Dict, SinglefileData, load_code 17 | from aiida.plugins import DataFactory 18 | from ase.atoms import Atoms 19 | 20 | StructureData = DataFactory("core.structure") 21 | KpointsData = DataFactory("core.array.kpoints") 22 | 23 | 24 | def example_bands(cp2k_code): 25 | """Run simple Band Structure calculation""" 26 | 27 | print("Computing Band Structure of Si...") 28 | 29 | thisdir = os.path.dirname(os.path.realpath(__file__)) 30 | 31 | # structure 32 | positions = [ 33 | [0.0000000000, 0.0000000000, 2.6954627656], 34 | [4.0431941484, 4.0431941484, 4.0431941484], 35 | ] 36 | cell = [ 37 | [0.0, 2.69546276561, 2.69546276561], 38 | [2.69546276561, 0.0, 2.69546276561], 39 | [2.69546276561, 2.69546276561, 0.0], 40 | ] 41 | atoms = Atoms("Si2", positions=positions, cell=cell) 42 | structure = StructureData(ase=atoms) 43 | 44 | # kpoints 45 | kpoints_mesh = KpointsData() 46 | kpoints_mesh.set_cell(cell) 47 | kpoints_mesh.set_kpoints_mesh_from_density(distance=0.5) 48 | 49 | # basis set 50 | basis_file = SinglefileData( 51 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 52 | ) 53 | 54 | # pseudopotentials 55 | pseudo_file = SinglefileData( 56 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 57 | ) 58 | 59 | # parameters 60 | parameters = Dict( 61 | { 62 | "FORCE_EVAL": { 63 | "METHOD": "Quickstep", 64 | "DFT": { 65 | "CHARGE": 0, 66 | "MGRID": { 67 | "CUTOFF": 600, 68 | "NGRIDS": 4, 69 | "REL_CUTOFF": 50, 70 | }, 71 | "UKS": False, 72 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 73 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 74 | "QS": {"METHOD": "GPW", "EXTRAPOLATION": "USE_GUESS"}, 75 | "POISSON": { 76 | "PERIODIC": "XYZ", 77 | }, 78 | "SCF": { 79 | "EPS_SCF": 1.0e-4, 80 | "ADDED_MOS": 1, 81 | "SMEAR": { 82 | "METHOD": "FERMI_DIRAC", 83 | "ELECTRONIC_TEMPERATURE": 300, 84 | }, 85 | "DIAGONALIZATION": {"ALGORITHM": "STANDARD", "EPS_ADAPT": 0.01}, 86 | "MIXING": { 87 | "METHOD": "BROYDEN_MIXING", 88 | "ALPHA": 0.2, 89 | "BETA": 1.5, 90 | "NBROYDEN": 8, 91 | }, 92 | }, 93 | "XC": { 94 | "XC_FUNCTIONAL": { 95 | "_": "PBE", 96 | }, 97 | }, 98 | "PRINT": { 99 | "MO_CUBES": { # this is to print the band gap 100 | "STRIDE": "1 1 1", 101 | "WRITE_CUBE": "F", 102 | "NLUMO": 1, 103 | "NHOMO": 1, 104 | }, 105 | "BAND_STRUCTURE": { 106 | "KPOINT_SET": [ 107 | { 108 | "NPOINTS": 10, 109 | "SPECIAL_POINT": [ 110 | "GAMMA 0.0 0.0 0.0", 111 | "X 0.5 0.0 0.5", 112 | ], 113 | "UNITS": "B_VECTOR", 114 | }, 115 | { 116 | "NPOINTS": 10, 117 | "SPECIAL_POINT": [ 118 | "X 0.5 0.0 0.5", 119 | "U 0.625 0.25 0.625", 120 | ], 121 | "UNITS": "B_VECTOR", 122 | }, 123 | { 124 | "NPOINTS": 10, 125 | "SPECIAL_POINT": [ 126 | "K 0.375 0.375 0.75", 127 | "GAMMA 0.0 0.0 0.0", 128 | ], 129 | "UNITS": "B_VECTOR", 130 | }, 131 | { 132 | "NPOINTS": 10, 133 | "SPECIAL_POINT": [ 134 | "GAMMA 0.0 0.0 0.0", 135 | "L 0.5 0.5 0.5", 136 | ], 137 | "UNITS": "B_VECTOR", 138 | }, 139 | { 140 | "NPOINTS": 10, 141 | "SPECIAL_POINT": [ 142 | "L 0.5 0.5 0.5", 143 | "W 0.5 0.25 0.75", 144 | ], 145 | "UNITS": "B_VECTOR", 146 | }, 147 | { 148 | "NPOINTS": 10, 149 | "SPECIAL_POINT": [ 150 | "W 0.5 0.25 0.75", 151 | "X 0.5 0.0 0.5", 152 | ], 153 | "UNITS": "B_VECTOR", 154 | }, 155 | ] 156 | }, 157 | }, 158 | }, 159 | "SUBSYS": { 160 | "KIND": [ 161 | { 162 | "_": "Si", 163 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 164 | "POTENTIAL": "GTH-LDA-q4", 165 | }, 166 | ] 167 | }, 168 | "PRINT": { # this is to print forces (may be necessary for problems 169 | # detection) 170 | "FORCES": { 171 | "_": "ON", 172 | } 173 | }, 174 | }, 175 | "GLOBAL": { 176 | "EXTENDED_FFT_LENGTHS": True, # Needed for large systems 177 | }, 178 | } 179 | ) 180 | 181 | # Construct process builder 182 | builder = cp2k_code.get_builder() 183 | builder.structure = structure 184 | builder.parameters = parameters 185 | builder.kpoints = kpoints_mesh 186 | builder.code = cp2k_code 187 | builder.file = { 188 | "basis": basis_file, 189 | "pseudo": pseudo_file, 190 | } 191 | builder.metadata.options.resources = { 192 | "num_machines": 1, 193 | "num_mpiprocs_per_machine": 1, 194 | } 195 | builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60 196 | 197 | builder.metadata.options.parser_name = "cp2k_advanced_parser" 198 | 199 | print("submitted calculation...") 200 | calc = run(builder) 201 | 202 | bands = calc["output_bands"] 203 | 204 | # check bands 205 | expected_gamma_kpoint = np.array( 206 | [-6.84282475, 5.23143741, 5.23143741, 5.23143741, 7.89232311] 207 | ) 208 | 209 | if bands.get_kpoints().shape == (62, 3): 210 | print("OK, got expected kpoints set size.") 211 | else: 212 | print("Got unexpected kpoints set.") 213 | sys.exit(3) 214 | 215 | if bands.get_bands().shape == (62, 5): 216 | print("OK, got expected bands set size.") 217 | else: 218 | print("Got unexpected bands set.") 219 | sys.exit(3) 220 | 221 | if abs(max(bands.get_bands()[0] - expected_gamma_kpoint)) < 1e-7: 222 | print("Ok, got expected energy levels at GAMMA point.") 223 | else: 224 | print("Got unexpected energy levels at GAMMA point.") 225 | print(bands.get_bands()[0]) 226 | print(expected_gamma_kpoint) 227 | sys.exit(3) 228 | 229 | 230 | @click.command("cli") 231 | @click.argument("codelabel") 232 | def cli(codelabel): 233 | """Click interface""" 234 | try: 235 | code = load_code(codelabel) 236 | except NotExistent: 237 | print("The code '{codelabel}' does not exist.") 238 | sys.exit(1) 239 | example_bands(code) 240 | 241 | 242 | if __name__ == "__main__": 243 | cli() 244 | -------------------------------------------------------------------------------- /examples/single_calculations/example_dft.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Run simple DFT calculation.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run 16 | from aiida.orm import Dict, SinglefileData, load_code 17 | from aiida.plugins import DataFactory 18 | 19 | StructureData = DataFactory("core.structure") 20 | 21 | 22 | def example_dft(cp2k_code): 23 | """Run simple DFT calculation.""" 24 | 25 | print("Testing CP2K ENERGY on H2O (DFT)...") 26 | 27 | thisdir = os.path.dirname(os.path.realpath(__file__)) 28 | 29 | # Structure. 30 | structure = StructureData( 31 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "h2o.xyz")) 32 | ) 33 | 34 | # Basis set. 35 | basis_file = SinglefileData( 36 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 37 | ) 38 | 39 | # Pseudopotentials. 40 | pseudo_file = SinglefileData( 41 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 42 | ) 43 | 44 | # Parameters. 45 | parameters = Dict( 46 | { 47 | "FORCE_EVAL": { 48 | "METHOD": "Quickstep", 49 | "DFT": { 50 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 51 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 52 | "QS": { 53 | "EPS_DEFAULT": 1.0e-12, 54 | "WF_INTERPOLATION": "ps", 55 | "EXTRAPOLATION_ORDER": 3, 56 | }, 57 | "MGRID": { 58 | "NGRIDS": 4, 59 | "CUTOFF": 280, 60 | "REL_CUTOFF": 30, 61 | }, 62 | "XC": { 63 | "XC_FUNCTIONAL": { 64 | "_": "LDA", 65 | }, 66 | }, 67 | "POISSON": { 68 | "PERIODIC": "none", 69 | "PSOLVER": "MT", 70 | }, 71 | }, 72 | "SUBSYS": { 73 | "KIND": [ 74 | { 75 | "_": "O", 76 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 77 | "POTENTIAL": "GTH-LDA-q6", 78 | }, 79 | { 80 | "_": "H", 81 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 82 | "POTENTIAL": "GTH-LDA-q1", 83 | }, 84 | ], 85 | }, 86 | } 87 | } 88 | ) 89 | 90 | # Construct process builder. 91 | builder = cp2k_code.get_builder() 92 | builder.structure = structure 93 | builder.parameters = parameters 94 | builder.code = cp2k_code 95 | builder.file = { 96 | "basis": basis_file, 97 | "pseudo": pseudo_file, 98 | } 99 | builder.metadata.options.resources = { 100 | "num_machines": 1, 101 | "num_mpiprocs_per_machine": 1, 102 | } 103 | builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60 104 | 105 | print("Submitted calculation...") 106 | run(builder) 107 | 108 | 109 | @click.command("cli") 110 | @click.argument("codelabel") 111 | def cli(codelabel): 112 | """Click interface.""" 113 | try: 114 | code = load_code(codelabel) 115 | except NotExistent: 116 | print(f"The code '{codelabel}' does not exist.") 117 | sys.exit(1) 118 | example_dft(code) 119 | 120 | 121 | if __name__ == "__main__": 122 | cli() 123 | -------------------------------------------------------------------------------- /examples/single_calculations/example_dft_atomic_kinds.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Run DFT calculation with different atomic kinds.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run 16 | from aiida.orm import Dict, SinglefileData, load_code 17 | from aiida.plugins import DataFactory 18 | 19 | StructureData = DataFactory("core.structure") 20 | 21 | 22 | def example_dft_atomic_kinds(cp2k_code): 23 | """Run DFT calculation with different atomic kinds.""" 24 | 25 | print("Testing CP2K GEOP_OPT on Si with different atomic kinds (DFT)...") 26 | 27 | thisdir = os.path.dirname(os.path.realpath(__file__)) 28 | 29 | # Structure. 30 | pos = [[0.0, 0.0, 0.0], [1.90598, 1.10041807, 0.77811308]] 31 | cell = [ 32 | [3.81196, 0.0, 0.0], 33 | [1.90598, 3.3012541982101, 0.0], 34 | [1.90598, 1.10041806607, 3.1124523066333], 35 | ] 36 | tags = [0, 1] 37 | atoms = ase.Atoms(symbols="Si2", pbc=True, cell=cell, positions=pos, tags=tags) 38 | structure = StructureData(ase=atoms) 39 | 40 | # Basis set. 41 | basis_file = SinglefileData( 42 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 43 | ) 44 | 45 | # Pseudopotentials. 46 | pseudo_file = SinglefileData( 47 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 48 | ) 49 | 50 | # Parameters. 51 | parameters = Dict( 52 | { 53 | "FORCE_EVAL": { 54 | "METHOD": "Quickstep", 55 | "DFT": { 56 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 57 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 58 | "QS": { 59 | "EPS_DEFAULT": 1.0e-12, 60 | "WF_INTERPOLATION": "ps", 61 | "EXTRAPOLATION_ORDER": 3, 62 | }, 63 | "MGRID": { 64 | "NGRIDS": 4, 65 | "CUTOFF": 280, 66 | "REL_CUTOFF": 30, 67 | }, 68 | "XC": { 69 | "XC_FUNCTIONAL": { 70 | "_": "LDA", 71 | }, 72 | }, 73 | "POISSON": { 74 | "PERIODIC": "none", 75 | "PSOLVER": "MT", 76 | }, 77 | }, 78 | "SUBSYS": { 79 | "KIND": [ 80 | { 81 | "_": "Si", 82 | "ELEMENT": "Si", 83 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 84 | "POTENTIAL": "GTH-LDA-q4", 85 | }, 86 | { 87 | "_": "Si1", 88 | "ELEMENT": "Si", 89 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 90 | "POTENTIAL": "GTH-LDA-q4", 91 | }, 92 | ], 93 | }, 94 | }, 95 | "MOTION": { 96 | "GEO_OPT": { 97 | "MAX_FORCE": 1e-4, 98 | "MAX_ITER": "3", 99 | "OPTIMIZER": "BFGS", 100 | "BFGS": { 101 | "TRUST_RADIUS": "[bohr] 0.1", 102 | }, 103 | }, 104 | }, 105 | "GLOBAL": { 106 | "RUN_TYPE": "GEO_OPT", 107 | }, 108 | } 109 | ) 110 | 111 | # Construct process builder. 112 | builder = cp2k_code.get_builder() 113 | builder.structure = structure 114 | builder.parameters = parameters 115 | builder.code = cp2k_code 116 | builder.file = { 117 | "basis": basis_file, 118 | "pseudo": pseudo_file, 119 | } 120 | builder.metadata.options.resources = { 121 | "num_machines": 1, 122 | "num_mpiprocs_per_machine": 1, 123 | } 124 | builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60 125 | 126 | print("Submitted calculation...") 127 | run(builder) 128 | 129 | 130 | @click.command("cli") 131 | @click.argument("codelabel") 132 | def cli(codelabel): 133 | """Click interface.""" 134 | try: 135 | code = load_code(codelabel) 136 | except NotExistent: 137 | print(f"The code '{codelabel}' does not exist.") 138 | sys.exit(1) 139 | example_dft_atomic_kinds(code) 140 | 141 | 142 | if __name__ == "__main__": 143 | cli() 144 | -------------------------------------------------------------------------------- /examples/single_calculations/example_failure.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Run failing calculation.""" 8 | 9 | import sys 10 | 11 | import click 12 | from aiida.common import NotExistent 13 | from aiida.engine import run_get_node 14 | from aiida.orm import Dict, load_code 15 | 16 | 17 | def example_failure(cp2k_code): 18 | """Run failing calculation.""" 19 | 20 | print("Testing CP2K failure...") 21 | 22 | # a broken CP2K input 23 | parameters = Dict({"GLOBAL": {"FOO_BAR_QUUX": 42}}) 24 | 25 | print("Submitted calculation...") 26 | 27 | # Construct process builder 28 | builder = cp2k_code.get_builder() 29 | builder.parameters = parameters 30 | builder.code = cp2k_code 31 | builder.metadata.options.resources = { 32 | "num_machines": 1, 33 | "num_mpiprocs_per_machine": 1, 34 | } 35 | builder.metadata.options.max_wallclock_seconds = 1 * 2 * 60 36 | 37 | _, calc_node = run_get_node(builder) 38 | 39 | if calc_node.exit_status == 304: 40 | print("CP2K failure correctly recognized.") 41 | else: 42 | print("ERROR!") 43 | print("CP2K failure was not recognized.") 44 | sys.exit(3) 45 | 46 | 47 | @click.command("cli") 48 | @click.argument("codelabel") 49 | def cli(codelabel): 50 | """Click interface.""" 51 | try: 52 | code = load_code(codelabel) 53 | except NotExistent: 54 | print(f"The code '{codelabel}' does not exist.") 55 | sys.exit(1) 56 | example_failure(code) 57 | 58 | 59 | if __name__ == "__main__": 60 | cli() 61 | -------------------------------------------------------------------------------- /examples/single_calculations/example_geopt.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Run DFT geometry optimization.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run 16 | from aiida.orm import Dict, SinglefileData, load_code 17 | from aiida.plugins import DataFactory 18 | 19 | StructureData = DataFactory("core.structure") 20 | 21 | 22 | def example_geopt(cp2k_code): 23 | """Run DFT geometry optimization.""" 24 | 25 | print("Testing CP2K GEO_OPT on H2O (DFT)...") 26 | 27 | thisdir = os.path.dirname(os.path.realpath(__file__)) 28 | 29 | # Structure. 30 | structure = StructureData( 31 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "h2.xyz")) 32 | ) 33 | 34 | # Basis set. 35 | basis_file = SinglefileData( 36 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 37 | ) 38 | 39 | # Pseudopotentials. 40 | pseudo_file = SinglefileData( 41 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 42 | ) 43 | 44 | # Parameters. 45 | parameters = Dict( 46 | { 47 | "GLOBAL": { 48 | "RUN_TYPE": "GEO_OPT", 49 | }, 50 | "FORCE_EVAL": { 51 | "METHOD": "Quickstep", 52 | "DFT": { 53 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 54 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 55 | "QS": { 56 | "EPS_DEFAULT": 1.0e-12, 57 | "WF_INTERPOLATION": "ps", 58 | "EXTRAPOLATION_ORDER": 3, 59 | }, 60 | "MGRID": { 61 | "NGRIDS": 4, 62 | "CUTOFF": 280, 63 | "REL_CUTOFF": 30, 64 | }, 65 | "XC": { 66 | "XC_FUNCTIONAL": { 67 | "_": "PBE", 68 | }, 69 | }, 70 | "POISSON": { 71 | "PERIODIC": "none", 72 | "PSOLVER": "MT", 73 | }, 74 | }, 75 | "SUBSYS": { 76 | "KIND": [ 77 | { 78 | "_": "O", 79 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 80 | "POTENTIAL": "GTH-PBE-q6", 81 | }, 82 | { 83 | "_": "H", 84 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 85 | "POTENTIAL": "GTH-PBE-q1", 86 | }, 87 | ], 88 | }, 89 | }, 90 | } 91 | ) 92 | 93 | # Construct process builder. 94 | builder = cp2k_code.get_builder() 95 | builder.structure = structure 96 | builder.parameters = parameters 97 | builder.code = cp2k_code 98 | builder.file = { 99 | "basis": basis_file, 100 | "pseudo": pseudo_file, 101 | } 102 | builder.metadata.options.resources = { 103 | "num_machines": 1, 104 | "num_mpiprocs_per_machine": 1, 105 | } 106 | builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60 107 | 108 | print("Submitted calculation...") 109 | calc = run(builder) 110 | 111 | # Check walltime not exceeded. 112 | assert calc["output_parameters"]["exceeded_walltime"] is False 113 | 114 | # Check energy. 115 | expected_energy = -1.17212345935 116 | if abs(calc["output_parameters"]["energy"] - expected_energy) < 1e-10: 117 | print("OK, energy has the expected value.") 118 | else: 119 | print("ERROR!") 120 | print(f"Expected energy value: {expected_energy}") 121 | print(f"Actual energy value: {calc['output_parameters']['energy']}") 122 | sys.exit(3) 123 | 124 | # Check geometry. 125 | expected_dist = 0.732594809575 126 | dist = calc["output_structure"].get_ase().get_distance(0, 1) 127 | if abs(dist - expected_dist) < 1e-7: 128 | print("OK, H-H distance has the expected value.") 129 | else: 130 | print("ERROR!") 131 | print(f"Expected dist value: {expected_dist}") 132 | print(f"Actual dist value: {dist}") 133 | sys.exit(3) 134 | 135 | 136 | @click.command("cli") 137 | @click.argument("codelabel") 138 | def cli(codelabel): 139 | """Click interface.""" 140 | try: 141 | code = load_code(codelabel) 142 | except NotExistent: 143 | print(f"The code '{codelabel}' does not exist.") 144 | sys.exit(1) 145 | example_geopt(code) 146 | 147 | 148 | if __name__ == "__main__": 149 | cli() 150 | -------------------------------------------------------------------------------- /examples/single_calculations/example_geopt_advanced_parser.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Run DFT geometry optimization.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run 16 | from aiida.orm import Dict, SinglefileData, load_code 17 | from aiida.plugins import DataFactory 18 | 19 | StructureData = DataFactory("core.structure") 20 | 21 | 22 | def example_geopt(cp2k_code): 23 | """Run DFT geometry optimization.""" 24 | 25 | print("Testing CP2K GEO_OPT on H2O (DFT)...") 26 | 27 | thisdir = os.path.dirname(os.path.realpath(__file__)) 28 | 29 | # Structure. 30 | structure = StructureData( 31 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "h2.xyz")) 32 | ) 33 | 34 | # Basis set. 35 | basis_file = SinglefileData( 36 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 37 | ) 38 | 39 | # Pseudopotentials. 40 | pseudo_file = SinglefileData( 41 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 42 | ) 43 | 44 | # Parameters. 45 | parameters = Dict( 46 | { 47 | "GLOBAL": { 48 | "RUN_TYPE": "GEO_OPT", 49 | }, 50 | "FORCE_EVAL": { 51 | "METHOD": "Quickstep", 52 | "DFT": { 53 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 54 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 55 | "QS": { 56 | "EPS_DEFAULT": 1.0e-12, 57 | "WF_INTERPOLATION": "ps", 58 | "EXTRAPOLATION_ORDER": 3, 59 | }, 60 | "MGRID": { 61 | "NGRIDS": 4, 62 | "CUTOFF": 280, 63 | "REL_CUTOFF": 30, 64 | }, 65 | "XC": { 66 | "XC_FUNCTIONAL": { 67 | "_": "PBE", 68 | }, 69 | }, 70 | "POISSON": { 71 | "PERIODIC": "none", 72 | "PSOLVER": "MT", 73 | }, 74 | }, 75 | "SUBSYS": { 76 | "KIND": [ 77 | { 78 | "_": "O", 79 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 80 | "POTENTIAL": "GTH-PBE-q6", 81 | }, 82 | { 83 | "_": "H", 84 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 85 | "POTENTIAL": "GTH-PBE-q1", 86 | }, 87 | ], 88 | }, 89 | }, 90 | } 91 | ) 92 | 93 | # Construct process builder. 94 | builder = cp2k_code.get_builder() 95 | builder.structure = structure 96 | builder.parameters = parameters 97 | builder.code = cp2k_code 98 | builder.file = { 99 | "basis": basis_file, 100 | "pseudo": pseudo_file, 101 | } 102 | builder.metadata.options.resources = { 103 | "num_machines": 1, 104 | "num_mpiprocs_per_machine": 1, 105 | } 106 | builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60 107 | builder.metadata.options.parser_name = "cp2k_advanced_parser" 108 | 109 | print("Submitted calculation...") 110 | calc = run(builder) 111 | 112 | # Check walltime not exceeded. 113 | assert calc["output_parameters"]["exceeded_walltime"] is False 114 | 115 | # Check energy. 116 | expected_energy = -1.17212345935 117 | if abs(calc["output_parameters"]["energy"] - expected_energy) < 1e-10: 118 | print("OK, energy has the expected value.") 119 | else: 120 | print("ERROR!") 121 | print(f"Expected energy value: {expected_energy}") 122 | print(f"Actual energy value: {calc['output_parameters']['energy']}") 123 | sys.exit(3) 124 | 125 | # Check geometry. 126 | expected_dist = 0.732594809575 127 | dist = calc["output_structure"].get_ase().get_distance(0, 1) 128 | if abs(dist - expected_dist) < 1e-7: 129 | print("OK, H-H distance has the expected value.") 130 | else: 131 | print("ERROR!") 132 | print(f"Expected dist value: {expected_dist}") 133 | print(f"Actual dist value: {dist}") 134 | sys.exit(3) 135 | 136 | # Check motion step information. 137 | assert calc["output_parameters"]["motion_step_info"]["step"] == [ 138 | 0, 139 | 1, 140 | 2, 141 | ], "ERROR: motion step info is incorrect" 142 | assert calc["output_parameters"]["motion_step_info"]["cell_a_angs"] == [ 143 | 4.0, 144 | 4.0, 145 | 4.0, 146 | ], "ERROR: motion step info is incorrect" 147 | 148 | 149 | @click.command("cli") 150 | @click.argument("codelabel") 151 | def cli(codelabel): 152 | """Click interface.""" 153 | try: 154 | code = load_code(codelabel) 155 | except NotExistent: 156 | print(f"The code '{codelabel}' does not exist.") 157 | sys.exit(1) 158 | example_geopt(code) 159 | 160 | 161 | if __name__ == "__main__": 162 | cli() 163 | -------------------------------------------------------------------------------- /examples/single_calculations/example_max_error.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Run simple DFT calculation.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run_get_node 16 | from aiida.orm import Dict, SinglefileData, load_code 17 | from aiida.plugins import CalculationFactory, DataFactory 18 | 19 | StructureData = DataFactory("core.structure") 20 | Cp2kCalculation = CalculationFactory("cp2k") 21 | 22 | 23 | def example_dft(cp2k_code): 24 | """Run simple DFT calculation.""" 25 | 26 | print("Testing CP2K GEO_OPT ERROR MAX on H2O (DFT)...") 27 | 28 | thisdir = os.path.dirname(os.path.realpath(__file__)) 29 | 30 | # Structure. 31 | structure = StructureData( 32 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "h2o.xyz")) 33 | ) 34 | 35 | # Basis set. 36 | basis_file = SinglefileData( 37 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 38 | ) 39 | 40 | # Pseudopotentials. 41 | pseudo_file = SinglefileData( 42 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 43 | ) 44 | 45 | # Parameters. 46 | parameters = Dict( 47 | { 48 | "GLOBAL": { 49 | "RUN_TYPE": "GEO_OPT", 50 | }, 51 | "MOTION": { 52 | "GEO_OPT": { 53 | "OPTIMIZER": "BFGS", 54 | "MAX_ITER": "2", 55 | "MAX_DR": 0.0001, 56 | "RMS_DR": 0.00005, 57 | "MAX_FORCE": 0.000015, 58 | "RMS_FORCE": 0.00001, 59 | }, 60 | }, 61 | "FORCE_EVAL": { 62 | "METHOD": "Quickstep", 63 | "DFT": { 64 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 65 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 66 | "QS": {"EPS_DEFAULT": 1.0e-8, "EXTRAPOLATION": "use_prev_p"}, 67 | "MGRID": { 68 | "NGRIDS": 4, 69 | "CUTOFF": 200, 70 | "REL_CUTOFF": 30, 71 | }, 72 | "XC": { 73 | "XC_FUNCTIONAL": { 74 | "_": "LDA", 75 | }, 76 | }, 77 | "POISSON": { 78 | "PERIODIC": "none", 79 | "PSOLVER": "MT", 80 | }, 81 | }, 82 | "SUBSYS": { 83 | "KIND": [ 84 | { 85 | "_": "O", 86 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 87 | "POTENTIAL": "GTH-LDA-q6", 88 | }, 89 | { 90 | "_": "H", 91 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 92 | "POTENTIAL": "GTH-LDA-q1", 93 | }, 94 | ], 95 | }, 96 | }, 97 | } 98 | ) 99 | 100 | # Construct process builder. 101 | builder = cp2k_code.get_builder() 102 | builder.structure = structure 103 | builder.parameters = parameters 104 | builder.code = cp2k_code 105 | builder.file = { 106 | "basis": basis_file, 107 | "pseudo": pseudo_file, 108 | } 109 | builder.metadata.options.resources = { 110 | "num_machines": 1, 111 | "num_mpiprocs_per_machine": 1, 112 | } 113 | builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60 114 | 115 | print("Submitted calculation...") 116 | calc = run_get_node(builder) 117 | assert ( 118 | calc[1].exit_status 119 | == Cp2kCalculation.exit_codes.ERROR_MAXIMUM_NUMBER_OPTIMIZATION_STEPS_REACHED.status 120 | ) 121 | 122 | 123 | @click.command("cli") 124 | @click.argument("codelabel") 125 | def cli(codelabel): 126 | """Click interface.""" 127 | try: 128 | code = load_code(codelabel) 129 | except NotExistent: 130 | print(f"The code '{codelabel}' does not exist.") 131 | sys.exit(1) 132 | example_dft(code) 133 | 134 | 135 | if __name__ == "__main__": 136 | cli() 137 | -------------------------------------------------------------------------------- /examples/single_calculations/example_mm.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Run molecular mechanics calculation.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run 16 | from aiida.orm import Dict, SinglefileData, load_code 17 | 18 | 19 | def example_mm(cp2k_code): 20 | """Run molecular mechanics calculation.""" 21 | 22 | print("Testing CP2K ENERGY on H2O (MM) ...") 23 | 24 | # Force field. 25 | with open(os.path.join("/tmp", "water.pot"), "w") as f: 26 | f.write( 27 | """BONDS 28 | H H 0.000 1.5139 29 | O H 450.000 0.9572 30 | 31 | ANGLES 32 | H O H 55.000 104.5200 33 | 34 | DIHEDRALS 35 | 36 | IMPROPER 37 | 38 | NONBONDED 39 | H 0.000000 -0.046000 0.224500 40 | O 0.000000 -0.152100 1.768200 41 | 42 | HBOND CUTHB 0.5 43 | 44 | END""" 45 | ) 46 | 47 | water_pot = SinglefileData(file=os.path.join("/tmp", "water.pot")) 48 | 49 | thisdir = os.path.dirname(os.path.realpath(__file__)) 50 | 51 | # structure using pdb format, because it also carries topology information 52 | atoms = ase.io.read(os.path.join(thisdir, "..", "files", "h2o.xyz")) 53 | atoms.center(vacuum=10.0) 54 | atoms.write(os.path.join("/tmp", "coords.pdb"), format="proteindatabank") 55 | coords_pdb = SinglefileData(file=os.path.join("/tmp", "coords.pdb")) 56 | 57 | # Parameters. 58 | # Based on cp2k/tests/Fist/regtest-1-1/water_1.inp 59 | parameters = Dict( 60 | { 61 | "FORCE_EVAL": { 62 | "METHOD": "fist", 63 | "MM": { 64 | "FORCEFIELD": { 65 | "PARM_FILE_NAME": "water.pot", 66 | "PARMTYPE": "CHM", 67 | "CHARGE": [ 68 | {"ATOM": "O", "CHARGE": -0.8476}, 69 | {"ATOM": "H", "CHARGE": 0.4238}, 70 | ], 71 | }, 72 | "POISSON": { 73 | "EWALD": { 74 | "EWALD_TYPE": "spme", 75 | "ALPHA": 0.44, 76 | "GMAX": 24, 77 | "O_SPLINE": 6, 78 | } 79 | }, 80 | }, 81 | "SUBSYS": { 82 | "CELL": { 83 | "ABC": "%f %f %f" % tuple(atoms.cell.diagonal()), 84 | }, 85 | "TOPOLOGY": { 86 | "COORD_FILE_NAME": "coords.pdb", 87 | "COORD_FILE_FORMAT": "PDB", 88 | }, 89 | }, 90 | }, 91 | "GLOBAL": {"CALLGRAPH": "master", "CALLGRAPH_FILE_NAME": "runtime"}, 92 | } 93 | ) 94 | 95 | # Settings. 96 | settings = Dict({"additional_retrieve_list": ["runtime.callgraph"]}) 97 | 98 | # Construct process builder. 99 | builder = cp2k_code.get_builder() 100 | builder.parameters = parameters 101 | builder.settings = settings 102 | builder.code = cp2k_code 103 | builder.file = { 104 | "water_pot": water_pot, 105 | "coords_pdb": coords_pdb, 106 | } 107 | builder.metadata.options.resources = { 108 | "num_machines": 1, 109 | "num_mpiprocs_per_machine": 1, 110 | } 111 | builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60 112 | 113 | print("Submitted calculation...") 114 | calc = run(builder) 115 | 116 | # Check energy. 117 | expected_energy = 0.146927412614e-3 118 | if abs(calc["output_parameters"]["energy"] - expected_energy) < 1e-10: 119 | print("OK, energy has the expected value.") 120 | else: 121 | print("ERROR!") 122 | print(f"Expected energy value: {expected_energy}") 123 | print(f"Actual energy value: {calc['output_parameters']['energy']}") 124 | sys.exit(3) 125 | 126 | # Check if callgraph is there. 127 | if "runtime.callgraph" in calc["retrieved"].base.repository.list_object_names(): 128 | print("OK, callgraph file was retrived.") 129 | else: 130 | print("ERROR!") 131 | print("Callgraph file was not retrieved.") 132 | sys.exit(3) 133 | 134 | 135 | @click.command("cli") 136 | @click.argument("codelabel") 137 | def cli(codelabel): 138 | """Click interface.""" 139 | try: 140 | code = load_code(codelabel) 141 | except NotExistent: 142 | print(f"The code '{codelabel}' does not exist.") 143 | sys.exit(1) 144 | example_mm(code) 145 | 146 | 147 | if __name__ == "__main__": 148 | cli() 149 | -------------------------------------------------------------------------------- /examples/single_calculations/example_mm_md.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Run molecular dynamics calculation.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida import common, engine, orm 15 | 16 | 17 | def example_mm(cp2k_code): 18 | """Run molecular mechanics calculation.""" 19 | 20 | print("Testing CP2K ENERGY on H2O (MM) ...") 21 | 22 | # Force field. 23 | with open(os.path.join("/tmp", "water.pot"), "w") as f: 24 | f.write( 25 | """BONDS 26 | H H 0.000 1.5139 27 | O H 450.000 0.9572 28 | 29 | ANGLES 30 | H O H 55.000 104.5200 31 | 32 | DIHEDRALS 33 | 34 | IMPROPER 35 | 36 | NONBONDED 37 | H 0.000000 -0.046000 0.224500 38 | O 0.000000 -0.152100 1.768200 39 | 40 | HBOND CUTHB 0.5 41 | 42 | END""" 43 | ) 44 | 45 | water_pot = orm.SinglefileData(file=os.path.join("/tmp", "water.pot")) 46 | 47 | thisdir = os.path.dirname(os.path.realpath(__file__)) 48 | 49 | # structure using pdb format, because it also carries topology information 50 | atoms = ase.io.read(os.path.join(thisdir, "..", "files", "h2o.xyz")) 51 | atoms.center(vacuum=10.0) 52 | atoms.write(os.path.join("/tmp", "coords.pdb"), format="proteindatabank") 53 | coords_pdb = orm.SinglefileData(file=os.path.join("/tmp", "coords.pdb")) 54 | 55 | # Parameters. 56 | # Based on cp2k/tests/Fist/regtest-1-1/water_1.inp 57 | parameters = orm.Dict( 58 | { 59 | "FORCE_EVAL": { 60 | "METHOD": "fist", 61 | "STRESS_TENSOR": "analytical", 62 | "MM": { 63 | "FORCEFIELD": { 64 | "PARM_FILE_NAME": "water.pot", 65 | "PARMTYPE": "CHM", 66 | "CHARGE": [ 67 | {"ATOM": "O", "CHARGE": -0.8476}, 68 | {"ATOM": "H", "CHARGE": 0.4238}, 69 | ], 70 | }, 71 | "POISSON": { 72 | "EWALD": { 73 | "EWALD_TYPE": "spme", 74 | "ALPHA": 0.44, 75 | "GMAX": 24, 76 | "O_SPLINE": 6, 77 | } 78 | }, 79 | }, 80 | "SUBSYS": { 81 | "CELL": { 82 | "ABC": "%f %f %f" % tuple(atoms.cell.diagonal()), 83 | }, 84 | "TOPOLOGY": { 85 | "COORD_FILE_NAME": "coords.pdb", 86 | "COORD_FILE_FORMAT": "PDB", 87 | }, 88 | }, 89 | }, 90 | "MOTION": { 91 | "CONSTRAINT": {}, 92 | "MD": { 93 | "THERMOSTAT": {"CSVR": {}, "TYPE": "csvr"}, 94 | "BAROSTAT": {}, 95 | "STEPS": 1000, 96 | "ENSEMBLE": "npt_f", 97 | "TEMPERATURE": 300.0, 98 | }, 99 | "PRINT": { 100 | "TRAJECTORY": {"EACH": {"MD": 5}}, 101 | "RESTART": {"EACH": {"MD": 5}}, 102 | "RESTART_HISTORY": {"_": "OFF"}, 103 | "CELL": {"EACH": {"MD": 5}}, 104 | "FORCES": {"EACH": {"MD": 5}, "FORMAT": "XYZ"}, 105 | }, 106 | }, 107 | "GLOBAL": { 108 | "CALLGRAPH": "master", 109 | "CALLGRAPH_FILE_NAME": "runtime", 110 | "PRINT_LEVEL": "medium", 111 | "RUN_TYPE": "MD", 112 | }, 113 | } 114 | ) 115 | 116 | # Construct process builder. 117 | builder = cp2k_code.get_builder() 118 | builder.parameters = parameters 119 | builder.code = cp2k_code 120 | builder.file = { 121 | "water_pot": water_pot, 122 | "coords_pdb": coords_pdb, 123 | } 124 | builder.metadata.options.resources = { 125 | "num_machines": 1, 126 | "num_mpiprocs_per_machine": 1, 127 | } 128 | builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60 129 | 130 | print("Submitted calculation...") 131 | results = engine.run(builder) 132 | assert "output_trajectory" in results, "Output trajectory not found among results." 133 | traj = results["output_trajectory"] 134 | 135 | assert traj.get_cells().shape == (201, 3, 3), "Unexpected shape of cells." 136 | assert traj.get_positions().shape == (201, 3, 3), "Unexpected shape of positions." 137 | assert traj.get_array("forces").shape == (201, 3, 3), "Unexpected shape of forces." 138 | 139 | 140 | @click.command("cli") 141 | @click.argument("codelabel") 142 | def cli(codelabel): 143 | """Click interface.""" 144 | try: 145 | code = orm.load_code(codelabel) 146 | except common.NotExistent: 147 | print(f"The code '{codelabel}' does not exist.") 148 | sys.exit(1) 149 | example_mm(code) 150 | 151 | 152 | if __name__ == "__main__": 153 | cli() 154 | -------------------------------------------------------------------------------- /examples/single_calculations/example_multiple_force_eval.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Run DFT calculation with multiple force eval sections.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run 16 | from aiida.orm import Dict, SinglefileData, load_code 17 | from aiida.plugins import DataFactory 18 | 19 | StructureData = DataFactory("core.structure") 20 | 21 | 22 | def example_multiple_force_eval(cp2k_code): 23 | """Run DFT calculation with multiple force eval sections.""" 24 | 25 | print("Testing CP2K ENERGY on H2O dimer (Mixed: DFT+MM)...") 26 | 27 | thisdir = os.path.dirname(os.path.realpath(__file__)) 28 | 29 | # structure 30 | pos = [ 31 | [0.934, 2.445, 1.844], 32 | [1.882, 2.227, 1.982], 33 | [0.81, 3.165, 2.479], 34 | [3.59, 2.048, 2.436], 35 | [4.352, 2.339, 1.906], 36 | [3.953, 1.304, 2.946], 37 | ] 38 | atoms = ase.Atoms(symbols="OH2OH2", pbc=True, cell=[5.0, 5.0, 5.0]) 39 | atoms.set_positions(pos) 40 | structure = StructureData(ase=atoms) 41 | 42 | # Basis set. 43 | basis_file = SinglefileData( 44 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 45 | ) 46 | 47 | # Pseudopotentials. 48 | pseudo_file = SinglefileData( 49 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 50 | ) 51 | 52 | # Parameters. 53 | parameters = Dict( 54 | { 55 | "MULTIPLE_FORCE_EVALS": { 56 | "FORCE_EVAL_ORDER": "2 3", 57 | "MULTIPLE_SUBSYS": "T", 58 | }, 59 | "FORCE_EVAL": [ 60 | { 61 | "METHOD": "MIXED", 62 | "MIXED": { 63 | "MIXING_TYPE": "GENMIX", 64 | "GENERIC": { 65 | "ERROR_LIMIT": 1.0e-10, 66 | "MIXING_FUNCTION": "E1+E2", 67 | "VARIABLES": "E1 E2", 68 | }, 69 | "MAPPING": { 70 | "FORCE_EVAL_MIXED": { 71 | "FRAGMENT": [ 72 | {"_": 1, "1": "3"}, 73 | {"_": 2, "4": "6"}, 74 | ], 75 | }, 76 | "FORCE_EVAL": [ 77 | { 78 | "_": 1, 79 | "DEFINE_FRAGMENTS": "1 2", 80 | }, 81 | { 82 | "_": 2, 83 | "DEFINE_FRAGMENTS": "1 2", 84 | }, 85 | ], 86 | }, 87 | }, 88 | }, 89 | { 90 | "METHOD": "FIST", 91 | "MM": { 92 | "FORCEFIELD": { 93 | "SPLINE": { 94 | "EPS_SPLINE": 1.30e-5, 95 | "EMAX_SPLINE": 0.8, 96 | }, 97 | "CHARGE": [ 98 | { 99 | "ATOM": "H", 100 | "CHARGE": 0.0, 101 | }, 102 | { 103 | "ATOM": "O", 104 | "CHARGE": 0.0, 105 | }, 106 | ], 107 | "BOND": { 108 | "ATOMS": "H O", 109 | "K": 0.0, 110 | "R0": 2.0, 111 | }, 112 | "BEND": { 113 | "ATOMS": "H O H", 114 | "K": 0.0, 115 | "THETA0": 2.0, 116 | }, 117 | "NONBONDED": { 118 | "LENNARD-JONES": [ 119 | { 120 | "ATOMS": "H H", 121 | "EPSILON": 0.2, 122 | "SIGMA": 2.4, 123 | }, 124 | { 125 | "ATOMS": "H O", 126 | "EPSILON": 0.4, 127 | "SIGMA": 3.0, 128 | }, 129 | { 130 | "ATOMS": "O O", 131 | "EPSILON": 0.8, 132 | "SIGMA": 3.6, 133 | }, 134 | ] 135 | }, 136 | }, 137 | "POISSON": { 138 | "EWALD": { 139 | "EWALD_TYPE": "none", 140 | } 141 | }, 142 | }, 143 | "SUBSYS": { 144 | "TOPOLOGY": { 145 | "CONNECTIVITY": "GENERATE", 146 | "GENERATE": { 147 | "CREATE_MOLECULES": True, 148 | }, 149 | } 150 | }, 151 | }, 152 | { 153 | "METHOD": "Quickstep", 154 | "DFT": { 155 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 156 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 157 | "QS": { 158 | "EPS_DEFAULT": 1.0e-12, 159 | "WF_INTERPOLATION": "ps", 160 | "EXTRAPOLATION_ORDER": 3, 161 | }, 162 | "MGRID": { 163 | "NGRIDS": 4, 164 | "CUTOFF": 280, 165 | "REL_CUTOFF": 30, 166 | }, 167 | "XC": { 168 | "XC_FUNCTIONAL": { 169 | "_": "LDA", 170 | }, 171 | }, 172 | "POISSON": { 173 | "PERIODIC": "none", 174 | "PSOLVER": "MT", 175 | }, 176 | }, 177 | "SUBSYS": { 178 | "KIND": [ 179 | { 180 | "_": "O", 181 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 182 | "POTENTIAL": "GTH-LDA-q6", 183 | }, 184 | { 185 | "_": "H", 186 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 187 | "POTENTIAL": "GTH-LDA-q1", 188 | }, 189 | ], 190 | }, 191 | }, 192 | ], 193 | } 194 | ) 195 | 196 | # Construct process builder. 197 | builder = cp2k_code.get_builder() 198 | builder.structure = structure 199 | builder.parameters = parameters 200 | builder.code = cp2k_code 201 | builder.file = { 202 | "basis": basis_file, 203 | "pseudo": pseudo_file, 204 | } 205 | builder.metadata.options.resources = { 206 | "num_machines": 1, 207 | "num_mpiprocs_per_machine": 1, 208 | } 209 | builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60 210 | 211 | print("Submitted calculation...") 212 | run(builder) 213 | 214 | 215 | @click.command("cli") 216 | @click.argument("codelabel") 217 | def cli(codelabel): 218 | """Click interface.""" 219 | try: 220 | code = load_code(codelabel) 221 | except NotExistent: 222 | print(f"The code '{codelabel}' does not exist.") 223 | sys.exit(1) 224 | example_multiple_force_eval(code) 225 | 226 | 227 | if __name__ == "__main__": 228 | cli() 229 | -------------------------------------------------------------------------------- /examples/single_calculations/example_no_struct.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Run DFT calculation with structure specified in the input file.""" 8 | 9 | import os 10 | import sys 11 | 12 | import click 13 | from aiida.common import NotExistent 14 | from aiida.engine import run 15 | from aiida.orm import Dict, SinglefileData, load_code 16 | 17 | 18 | def example_no_struct(cp2k_code): 19 | """Run DFT calculation with structure specified in the input file.""" 20 | 21 | print("Testing CP2K ENERGY on H2 (DFT) without StructureData...") 22 | 23 | thisdir = os.path.dirname(os.path.realpath(__file__)) 24 | 25 | # Basis set. 26 | basis_file = SinglefileData( 27 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 28 | ) 29 | 30 | # Pseudopotentials. 31 | pseudo_file = SinglefileData( 32 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 33 | ) 34 | 35 | # Parameters. 36 | parameters = Dict( 37 | { 38 | "FORCE_EVAL": { 39 | "METHOD": "Quickstep", 40 | "DFT": { 41 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 42 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 43 | "QS": { 44 | "EPS_DEFAULT": 1.0e-12, 45 | "WF_INTERPOLATION": "ps", 46 | "EXTRAPOLATION_ORDER": 3, 47 | }, 48 | "MGRID": { 49 | "NGRIDS": 4, 50 | "CUTOFF": 280, 51 | "REL_CUTOFF": 30, 52 | }, 53 | "XC": { 54 | "XC_FUNCTIONAL": { 55 | "_": "LDA", 56 | }, 57 | }, 58 | "POISSON": { 59 | "PERIODIC": "none", 60 | "PSOLVER": "MT", 61 | }, 62 | }, 63 | "SUBSYS": { 64 | # structure directly included in parameters 65 | "CELL": {"ABC": "4.0 4.0 4.75"}, 66 | "COORD": { 67 | " ": ["H 2.0 2.0 2.737166", "H 2.0 2.0 2.000000"] 68 | }, 69 | "KIND": [ 70 | { 71 | "_": "O", 72 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 73 | "POTENTIAL": "GTH-LDA-q6", 74 | }, 75 | { 76 | "_": "H", 77 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 78 | "POTENTIAL": "GTH-LDA-q1", 79 | }, 80 | ], 81 | }, 82 | } 83 | } 84 | ) 85 | 86 | # Construct process builder. 87 | builder = cp2k_code.get_builder() 88 | builder.parameters = parameters 89 | builder.code = cp2k_code 90 | builder.file = { 91 | "basis": basis_file, 92 | "pseudo": pseudo_file, 93 | } 94 | builder.metadata.options.resources = { 95 | "num_machines": 1, 96 | "num_mpiprocs_per_machine": 1, 97 | } 98 | builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60 99 | 100 | print("Submitted calculation...") 101 | calc = run(builder) 102 | 103 | # Check energy. 104 | expected_energy = -1.14005678487 105 | if abs(calc["output_parameters"]["energy"] - expected_energy) < 1e-10: 106 | print("OK, energy has the expected value.") 107 | else: 108 | print("ERROR!") 109 | print(f"Expected energy value: {expected_energy}") 110 | print(f"Actual energy value: {calc['output_parameters']['energy']}") 111 | sys.exit(3) 112 | 113 | 114 | @click.command("cli") 115 | @click.argument("codelabel") 116 | def cli(codelabel): 117 | """Click interface.""" 118 | try: 119 | code = load_code(codelabel) 120 | except NotExistent: 121 | print(f"The code '{codelabel}' does not exist.") 122 | sys.exit(1) 123 | example_no_struct(code) 124 | 125 | 126 | if __name__ == "__main__": 127 | cli() 128 | -------------------------------------------------------------------------------- /examples/single_calculations/example_precision.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Test structure roundtrip precision ase->aiida->cp2k->aiida->ase.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase 13 | import click 14 | import numpy as np 15 | from aiida.common import NotExistent 16 | from aiida.engine import run 17 | from aiida.orm import Dict, SinglefileData, load_code 18 | from aiida.plugins import DataFactory 19 | 20 | StructureData = DataFactory("core.structure") 21 | 22 | 23 | def example_precision(cp2k_code): 24 | """Test structure roundtrip precision ase->aiida->cp2k->aiida->ase.""" 25 | 26 | print("Testing structure roundtrip precision ase->aiida->cp2k->aiida->ase...") 27 | 28 | thisdir = os.path.dirname(os.path.realpath(__file__)) 29 | 30 | # Structure. 31 | epsilon = 1e-10 # expected precision in Angstrom 32 | dist = 0.74 + epsilon 33 | positions = [(0, 0, 0), (0, 0, dist)] 34 | cell = np.diag([4, -4, 4 + epsilon]) 35 | atoms = ase.Atoms("H2", positions=positions, cell=cell) 36 | structure = StructureData(ase=atoms) 37 | 38 | # Basis set. 39 | basis_file = SinglefileData( 40 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 41 | ) 42 | 43 | # Pseudopotentials. 44 | pseudo_file = SinglefileData( 45 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 46 | ) 47 | 48 | # Parameters. 49 | parameters = Dict( 50 | { 51 | "GLOBAL": { 52 | "RUN_TYPE": "MD", 53 | }, 54 | "MOTION": { 55 | "MD": { 56 | "TIMESTEP": 0.0, # do not move atoms 57 | "STEPS": 1, 58 | }, 59 | }, 60 | "FORCE_EVAL": { 61 | "METHOD": "Quickstep", 62 | "DFT": { 63 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 64 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 65 | "SCF": { 66 | "MAX_SCF": 10, 67 | }, 68 | "XC": { 69 | "XC_FUNCTIONAL": { 70 | "_": "LDA", 71 | }, 72 | }, 73 | }, 74 | "SUBSYS": { 75 | "KIND": { 76 | "_": "DEFAULT", 77 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 78 | "POTENTIAL": "GTH-LDA", 79 | }, 80 | }, 81 | }, 82 | } 83 | ) 84 | 85 | # Construct process builder. 86 | builder = cp2k_code.get_builder() 87 | builder.structure = structure 88 | builder.parameters = parameters 89 | builder.code = cp2k_code 90 | builder.file = { 91 | "basis": basis_file, 92 | "pseudo": pseudo_file, 93 | } 94 | builder.metadata.options.resources = { 95 | "num_machines": 1, 96 | "num_mpiprocs_per_machine": 1, 97 | } 98 | builder.metadata.options.max_wallclock_seconds = 1 * 60 * 60 99 | 100 | print("Submitted calculation...") 101 | calc = run(builder) 102 | 103 | # Check structure preservation. 104 | atoms2 = calc["output_structure"].get_ase() 105 | 106 | # Zeros should be preserved exactly. 107 | if np.all(atoms2.positions[0] == 0.0): 108 | print("OK, zeros in structure were preserved exactly.") 109 | else: 110 | print("ERROR!") 111 | print("Zeros in structure changed: ", atoms2.positions[0]) 112 | sys.exit(3) 113 | 114 | # Other values should be preserved with epsilon precision. 115 | dist2 = atoms2.get_distance(0, 1) 116 | if abs(dist2 - dist) < epsilon: 117 | print("OK, structure preserved with %.1e Angstrom precision" % epsilon) 118 | else: 119 | print("ERROR!") 120 | print("Structure changed by %e Angstrom" % abs(dist - dist2)) 121 | sys.exit(3) 122 | 123 | # Check cell preservation. 124 | cell_diff = np.amax(np.abs(atoms2.cell - cell)) 125 | if cell_diff < epsilon: 126 | print("OK, cell preserved with %.1e Angstrom precision" % epsilon) 127 | else: 128 | print("ERROR!") 129 | print("Cell changed by %e Angstrom" % cell_diff) 130 | sys.exit(3) 131 | 132 | 133 | @click.command("cli") 134 | @click.argument("codelabel") 135 | def cli(codelabel): 136 | """Click interface.""" 137 | try: 138 | code = load_code(codelabel) 139 | except NotExistent: 140 | print("The code '{codelabel}' does not exist.") 141 | sys.exit(1) 142 | example_precision(code) 143 | 144 | 145 | if __name__ == "__main__": 146 | cli() 147 | -------------------------------------------------------------------------------- /examples/single_calculations/example_restart.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Test CP2K restart.""" 8 | 9 | import os 10 | import re 11 | import sys 12 | from copy import deepcopy 13 | 14 | import ase.io 15 | import click 16 | from aiida import common, engine, orm, plugins 17 | 18 | StructureData = plugins.DataFactory("core.structure") 19 | 20 | 21 | def example_restart(cp2k_code): 22 | """Test CP2K restart.""" 23 | 24 | print("Testing CP2K restart...") 25 | 26 | thisdir = os.path.dirname(os.path.realpath(__file__)) 27 | 28 | # Structure. 29 | structure = StructureData( 30 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "h2o.xyz")) 31 | ) 32 | 33 | # Basis set. 34 | basis_file = orm.SinglefileData( 35 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 36 | ) 37 | 38 | # Pseudopotentials. 39 | pseudo_file = orm.SinglefileData( 40 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 41 | ) 42 | 43 | # CP2K input. 44 | params1 = orm.Dict( 45 | { 46 | "GLOBAL": { 47 | "RUN_TYPE": "GEO_OPT", 48 | "WALLTIME": "00:00:20", # too short 49 | }, 50 | "MOTION": { 51 | "GEO_OPT": { 52 | "MAX_FORCE": 1e-20, # impossible to reach 53 | "MAX_ITER": 100000, # run forever 54 | }, 55 | }, 56 | "FORCE_EVAL": { 57 | "METHOD": "Quickstep", 58 | "DFT": { 59 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 60 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 61 | "QS": { 62 | "EPS_DEFAULT": 1.0e-12, 63 | "WF_INTERPOLATION": "ps", 64 | "EXTRAPOLATION_ORDER": 3, 65 | }, 66 | "MGRID": { 67 | "NGRIDS": 4, 68 | "CUTOFF": 280, 69 | "REL_CUTOFF": 30, 70 | }, 71 | "XC": { 72 | "XC_FUNCTIONAL": { 73 | "_": "LDA", 74 | }, 75 | }, 76 | "POISSON": { 77 | "PERIODIC": "none", 78 | "PSOLVER": "MT", 79 | }, 80 | "SCF": {"PRINT": {"RESTART": {"_": "ON"}}}, 81 | }, 82 | "SUBSYS": { 83 | "KIND": [ 84 | { 85 | "_": "O", 86 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 87 | "POTENTIAL": "GTH-LDA-q6", 88 | }, 89 | { 90 | "_": "H", 91 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 92 | "POTENTIAL": "GTH-LDA-q1", 93 | }, 94 | ], 95 | }, 96 | }, 97 | } 98 | ) 99 | 100 | # Construct process builder. 101 | builder = cp2k_code.get_builder() 102 | 103 | # Set up the first calculation. 104 | builder.structure = structure 105 | builder.parameters = params1 106 | builder.code = cp2k_code 107 | builder.file = { 108 | "basis": basis_file, 109 | "pseudo": pseudo_file, 110 | } 111 | builder.metadata.options.resources = { 112 | "num_machines": 1, 113 | "num_mpiprocs_per_machine": 1, 114 | } 115 | builder.metadata.options.max_wallclock_seconds = 1 * 2 * 60 116 | 117 | print("Submitted calculation 1.") 118 | calc1_outputs, calc1 = engine.run_get_node(builder) 119 | 120 | # Check walltime exceeded. 121 | if calc1.exit_status == 400: 122 | print("OK, walltime exceeded as expected.") 123 | else: 124 | print("FAIL, walltime wasn't exceeded as it should.") 125 | sys.exit(1) 126 | 127 | print(calc1_outputs) 128 | assert "output_structure" in calc1_outputs, "The output_structure is missing." 129 | print("OK, output_structure is present, even though the calculation has failed.") 130 | 131 | # Set up and start the second calculation. 132 | 133 | # Parameters. 134 | params2 = deepcopy(params1.get_dict()) 135 | del params2["GLOBAL"]["WALLTIME"] 136 | del params2["MOTION"]["GEO_OPT"]["MAX_FORCE"] 137 | restart_wfn_fn = "./parent_calc/aiida-RESTART.wfn" 138 | params2["FORCE_EVAL"]["DFT"]["RESTART_FILE_NAME"] = restart_wfn_fn 139 | params2["FORCE_EVAL"]["DFT"]["SCF"]["SCF_GUESS"] = "RESTART" 140 | params2["EXT_RESTART"] = {"RESTART_FILE_NAME": "./parent_calc/aiida-1.restart"} 141 | params2 = orm.Dict(params2) 142 | 143 | # Structure. 144 | atoms2 = ase.io.read(os.path.join(thisdir, "..", "files", "h2o.xyz")) 145 | atoms2.positions *= 0.0 # place all atoms at origin -> nuclear fusion :-) 146 | structure2 = StructureData(ase=atoms2) 147 | 148 | # Update the process builder. 149 | builder.structure = structure2 150 | builder.parameters = params2 151 | builder.parent_calc_folder = calc1_outputs["remote_folder"] 152 | 153 | print("Submitted calculation 2.") 154 | calc2 = engine.run(builder) 155 | 156 | # Check energy. 157 | expected_energy = -17.1566455959 158 | if abs(calc2["output_parameters"]["energy"] - expected_energy) < 1e-10: 159 | print("OK, energy has the expected value.") 160 | 161 | # Ensure that this warning originates from overwritting coordinates. 162 | output = calc2["retrieved"].base.repository.get_object_content("aiida.out") 163 | assert re.search( 164 | "WARNING .* :: Overwriting coordinates", output 165 | ), "No warning about overwritting coordinates." 166 | 167 | 168 | @click.command("cli") 169 | @click.argument("codelabel") 170 | def cli(codelabel): 171 | """Click interface.""" 172 | try: 173 | code = orm.load_code(codelabel) 174 | except common.NotExistent: 175 | print(f"The code '{codelabel}' does not exist.") 176 | sys.exit(1) 177 | example_restart(code) 178 | 179 | 180 | if __name__ == "__main__": 181 | cli() 182 | -------------------------------------------------------------------------------- /examples/single_calculations/example_sirius.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Run simple DFT with calculation with SIRIUS.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida import common, engine, orm, plugins 15 | 16 | StructureData = plugins.DataFactory("core.structure") 17 | 18 | 19 | def example_sirius(cp2k_code, setup_sssp_pseudos): 20 | """Run simple DFT calculation.""" 21 | 22 | print("Testing CP2K SIRIUS ENERGY on Si (DFT)...") 23 | 24 | thisdir = os.path.dirname(os.path.realpath(__file__)) 25 | 26 | # Structure. 27 | structure = StructureData( 28 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "si.xyz")) 29 | ) 30 | 31 | # Parameters. 32 | parameters = orm.Dict( 33 | { 34 | "FORCE_EVAL": { 35 | "METHOD": "SIRIUS", 36 | "STRESS_TENSOR": "ANALYTICAL", 37 | "PRINT": { 38 | "FORCES": {"FILENAME": "requested-forces", "ADD_LAST": "SYMBOLIC"} 39 | }, 40 | "PW_DFT": { 41 | "CONTROL": {"VERBOSITY": 2}, 42 | "PARAMETERS": { 43 | "ELECTRONIC_STRUCTURE_METHOD": "pseudopotential", 44 | "USE_SYMMETRY": True, 45 | "GK_CUTOFF": 5, 46 | "PW_CUTOFF": 20, 47 | "ENERGY_TOL": 0.1, 48 | "DENSITY_TOL": 0.1, 49 | "NUM_DFT_ITER": 400, 50 | "SMEARING": "FERMI_DIRAC", 51 | "SMEARING_WIDTH": 0.00225, 52 | }, 53 | "ITERATIVE_SOLVER": { 54 | "ENERGY_TOLERANCE": 0.001, 55 | "NUM_STEPS": 20, 56 | "SUBSPACE_SIZE": 4, 57 | "CONVERGE_BY_ENERGY": 1, 58 | }, 59 | }, 60 | "DFT": { 61 | "XC": { 62 | "XC_FUNCTIONAL": { 63 | "GGA_X_PBE": {"_": ""}, 64 | "GGA_C_PBE": {"_": ""}, 65 | } 66 | }, 67 | "PRINT": { 68 | "MO": { 69 | "_": "OFF", 70 | "ADD_LAST": "SYMBOLIC", 71 | "EIGENVALUES": True, 72 | "OCCUPATION_NUMBERS": True, 73 | "NDIGITS": 12, 74 | "EACH": {"CELL_OPT": 0, "GEO_OPT": 0, "MD": 0, "QS_SCF": 0}, 75 | }, 76 | "MULLIKEN": { 77 | "_": "ON", 78 | "ADD_LAST": "SYMBOLIC", 79 | "EACH": {"CELL_OPT": 0, "GEO_OPT": 0, "MD": 0}, 80 | }, 81 | "LOWDIN": {"_": "OFF"}, 82 | "HIRSHFELD": {"_": "OFF"}, 83 | }, 84 | }, 85 | "SUBSYS": { 86 | "KIND": [ 87 | { 88 | "_": "Si", 89 | "POTENTIAL": "UPF Si.json", 90 | }, 91 | ], 92 | }, 93 | }, 94 | } 95 | ) 96 | 97 | # Construct process builder. 98 | builder = cp2k_code.get_builder() 99 | builder.structure = structure 100 | builder.parameters = parameters 101 | builder.code = cp2k_code 102 | pseudo_family = orm.load_group("SSSP/1.3/PBE/efficiency") 103 | builder.pseudos_upf = pseudo_family.get_pseudos(structure=structure) 104 | builder.metadata.options.resources = { 105 | "num_machines": 1, 106 | "num_mpiprocs_per_machine": 1, 107 | } 108 | builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60 109 | 110 | print("Submitted calculation...") 111 | engine.run(builder) 112 | 113 | 114 | @click.command("cli") 115 | @click.argument("codelabel") 116 | def cli(codelabel): 117 | """Click interface.""" 118 | try: 119 | code = orm.load_code(codelabel) 120 | except common.NotExistent: 121 | print(f"The code '{codelabel}' does not exist.") 122 | sys.exit(1) 123 | example_sirius(code, setup_sssp_pseudos=None) 124 | 125 | 126 | if __name__ == "__main__": 127 | cli() 128 | -------------------------------------------------------------------------------- /examples/single_calculations/example_structure_through_file.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Run simple DFT calculation""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run 16 | from aiida.orm import Dict, SinglefileData, load_code 17 | from aiida.plugins import DataFactory 18 | 19 | StructureData = DataFactory("core.structure") 20 | 21 | 22 | def example_structure_through_file(cp2k_code): 23 | """Run simple DFT calculation""" 24 | 25 | print( 26 | "Testing CP2K ENERGY on H2O (DFT). Water molecule is provided through a file input..." 27 | ) 28 | 29 | thisdir = os.path.dirname(os.path.realpath(__file__)) 30 | 31 | # structure 32 | structure = StructureData( 33 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "h2o.xyz")) 34 | ) 35 | 36 | # basis set 37 | basis_file = SinglefileData( 38 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 39 | ) 40 | 41 | # pseudopotentials 42 | pseudo_file = SinglefileData( 43 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 44 | ) 45 | 46 | # parameters 47 | parameters = Dict( 48 | { 49 | "FORCE_EVAL": { 50 | "METHOD": "Quickstep", 51 | "DFT": { 52 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 53 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 54 | "QS": { 55 | "EPS_DEFAULT": 1.0e-12, 56 | "WF_INTERPOLATION": "ps", 57 | "EXTRAPOLATION_ORDER": 3, 58 | }, 59 | "MGRID": { 60 | "NGRIDS": 4, 61 | "CUTOFF": 280, 62 | "REL_CUTOFF": 30, 63 | }, 64 | "XC": { 65 | "XC_FUNCTIONAL": { 66 | "_": "LDA", 67 | }, 68 | }, 69 | "POISSON": { 70 | "PERIODIC": "none", 71 | "PSOLVER": "MT", 72 | }, 73 | }, 74 | "SUBSYS": { 75 | "TOPOLOGY": { 76 | "COORD_FILE_NAME": "water.xyz", 77 | "COORD_FILE_FORMAT": "XYZ", 78 | }, 79 | "CELL": { 80 | "ABC": "{:<15} {:<15} {:<15}".format( 81 | *[structure.cell[i][i] for i in range(3)] 82 | ), 83 | }, 84 | "KIND": [ 85 | { 86 | "_": "O", 87 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 88 | "POTENTIAL": "GTH-LDA-q6", 89 | }, 90 | { 91 | "_": "H", 92 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 93 | "POTENTIAL": "GTH-LDA-q1", 94 | }, 95 | ], 96 | }, 97 | } 98 | } 99 | ) 100 | 101 | # Construct process builder 102 | builder = cp2k_code.get_builder() 103 | builder.parameters = parameters 104 | builder.code = cp2k_code 105 | builder.file = { 106 | "basis": basis_file, 107 | "pseudo": pseudo_file, 108 | "water": structure, 109 | } 110 | builder.metadata.options.resources = { 111 | "num_machines": 1, 112 | "num_mpiprocs_per_machine": 1, 113 | } 114 | builder.metadata.options.max_wallclock_seconds = 1 * 3 * 60 115 | 116 | print("Submitted calculation...") 117 | run(builder) 118 | 119 | 120 | @click.command("cli") 121 | @click.argument("codelabel") 122 | def cli(codelabel): 123 | """Click interface""" 124 | try: 125 | code = load_code(codelabel) 126 | except NotExistent: 127 | print(f"The code '{codelabel}' does not exist.") 128 | sys.exit(1) 129 | example_structure_through_file(code) 130 | 131 | 132 | if __name__ == "__main__": 133 | cli() 134 | -------------------------------------------------------------------------------- /examples/workchains/example_base_energy_restart.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """An example testing the restart calculation handler for ENERGY run in CP2K.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run_get_node 16 | from aiida.orm import Dict, SinglefileData, load_code 17 | from aiida.plugins import DataFactory, WorkflowFactory 18 | 19 | Cp2kBaseWorkChain = WorkflowFactory("cp2k.base") 20 | StructureData = DataFactory("core.structure") 21 | 22 | 23 | def example_base(cp2k_code): 24 | """Run simple DFT calculation through a workchain.""" 25 | 26 | thisdir = os.path.dirname(os.path.realpath(__file__)) 27 | 28 | print("Testing CP2K ENERGY on H2O (DFT) through a workchain...") 29 | 30 | # Basis set. 31 | basis_file = SinglefileData( 32 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 33 | ) 34 | 35 | # Pseudopotentials. 36 | pseudo_file = SinglefileData( 37 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 38 | ) 39 | 40 | # Structure. 41 | structure = StructureData( 42 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "h2o.xyz")) 43 | ) 44 | 45 | # Parameters. 46 | parameters = Dict( 47 | { 48 | "GLOBAL": { 49 | "RUN_TYPE": "ENERGY", 50 | "WALLTIME": "00:00:30", # Not enough time to converge an SCF loop 51 | }, 52 | "FORCE_EVAL": { 53 | "METHOD": "Quickstep", 54 | "DFT": { 55 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 56 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 57 | "QS": { 58 | "EPS_DEFAULT": 1.0e-16, 59 | "WF_INTERPOLATION": "ps", 60 | "EXTRAPOLATION_ORDER": 3, 61 | }, 62 | "MGRID": { 63 | "NGRIDS": 4, 64 | "CUTOFF": 450, 65 | "REL_CUTOFF": 70, 66 | }, 67 | "XC": { 68 | "XC_FUNCTIONAL": { 69 | "_": "LDA", 70 | }, 71 | }, 72 | "POISSON": { 73 | "PERIODIC": "none", 74 | "PSOLVER": "MT", 75 | }, 76 | "SCF": {"PRINT": {"RESTART": {"_": "ON"}}}, 77 | }, 78 | "SUBSYS": { 79 | "KIND": [ 80 | { 81 | "_": "O", 82 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 83 | "POTENTIAL": "GTH-LDA-q6", 84 | }, 85 | { 86 | "_": "H", 87 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 88 | "POTENTIAL": "GTH-LDA-q1", 89 | }, 90 | ], 91 | }, 92 | }, 93 | } 94 | ) 95 | 96 | # Construct process builder. 97 | builder = Cp2kBaseWorkChain.get_builder() 98 | 99 | # Switch on resubmit_unconverged_geometry disabled by default. 100 | builder.handler_overrides = Dict( 101 | {"restart_incomplete_calculation": {"enabled": True}} 102 | ) 103 | 104 | # Input structure. 105 | builder.cp2k.structure = structure 106 | builder.cp2k.parameters = parameters 107 | builder.cp2k.code = cp2k_code 108 | builder.cp2k.file = { 109 | "basis": basis_file, 110 | "pseudo": pseudo_file, 111 | } 112 | builder.cp2k.metadata.options = { 113 | "resources": { 114 | "num_machines": 1, 115 | "num_mpiprocs_per_machine": 1, 116 | }, 117 | "max_wallclock_seconds": 1 * 1 * 60, 118 | } 119 | 120 | print("Submitted calculation...") 121 | _, process_node = run_get_node(builder) 122 | 123 | if process_node.exit_status == 0: 124 | print("Work chain is finished correctly.") 125 | else: 126 | print("ERROR! Work chain failed.") 127 | sys.exit(3) 128 | 129 | 130 | @click.command("cli") 131 | @click.argument("codelabel") 132 | def cli(codelabel): 133 | """Click interface.""" 134 | try: 135 | code = load_code(codelabel) 136 | except NotExistent: 137 | print(f"The code '{codelabel}' does not exist") 138 | sys.exit(1) 139 | example_base(code) 140 | 141 | 142 | if __name__ == "__main__": 143 | cli() 144 | -------------------------------------------------------------------------------- /examples/workchains/example_base_failed_restart.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """An example that fails due to lack of restart data.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run_get_node 16 | from aiida.orm import Dict, SinglefileData, load_code 17 | from aiida.plugins import DataFactory, WorkflowFactory 18 | 19 | Cp2kBaseWorkChain = WorkflowFactory("cp2k.base") 20 | StructureData = DataFactory("core.structure") 21 | 22 | 23 | def example_base(cp2k_code): 24 | """Run simple DFT calculation through a workchain.""" 25 | 26 | thisdir = os.path.dirname(os.path.realpath(__file__)) 27 | 28 | print("Testing CP2K ENERGY on H2O (DFT) through a workchain...") 29 | 30 | # Basis set. 31 | basis_file = SinglefileData( 32 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 33 | ) 34 | 35 | # Pseudopotentials. 36 | pseudo_file = SinglefileData( 37 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 38 | ) 39 | 40 | # Structure. 41 | structure = StructureData( 42 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "h2o.xyz")) 43 | ) 44 | 45 | # Parameters. 46 | parameters = Dict( 47 | { 48 | "GLOBAL": { 49 | "RUN_TYPE": "ENERGY", 50 | }, 51 | "FORCE_EVAL": { 52 | "METHOD": "Quickstep", 53 | "DFT": { 54 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 55 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 56 | "QS": { 57 | "EPS_DEFAULT": 1.0e-16, 58 | "WF_INTERPOLATION": "ps", 59 | "EXTRAPOLATION_ORDER": 3, 60 | }, 61 | "MGRID": { 62 | "NGRIDS": 4, 63 | "CUTOFF": 450, 64 | "REL_CUTOFF": 70, 65 | }, 66 | "XC": { 67 | "XC_FUNCTIONAL": { 68 | "_": "LDA", 69 | }, 70 | }, 71 | "POISSON": { 72 | "PERIODIC": "none", 73 | "PSOLVER": "MT", 74 | }, 75 | "SCF": {"PRINT": {"RESTART": {"_": "ON"}}}, 76 | }, 77 | "SUBSYS": { 78 | "KIND": [ 79 | { 80 | "_": "O", 81 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 82 | "POTENTIAL": "GTH-LDA-q6", 83 | }, 84 | { 85 | "_": "H", 86 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 87 | "POTENTIAL": "GTH-LDA-q1", 88 | }, 89 | ], 90 | }, 91 | }, 92 | } 93 | ) 94 | 95 | # Construct process builder. 96 | builder = Cp2kBaseWorkChain.get_builder() 97 | 98 | # Switch on resubmit_unconverged_geometry disabled by default. 99 | builder.handler_overrides = Dict( 100 | {"restart_incomplete_calculation": {"enabled": True}} 101 | ) 102 | 103 | # Input structure. 104 | builder.cp2k.structure = structure 105 | builder.cp2k.parameters = parameters 106 | builder.cp2k.code = cp2k_code 107 | builder.cp2k.file = { 108 | "basis": basis_file, 109 | "pseudo": pseudo_file, 110 | } 111 | builder.cp2k.metadata.options = { 112 | "resources": { 113 | "num_machines": 1, 114 | "num_mpiprocs_per_machine": 1, 115 | }, 116 | "max_wallclock_seconds": 1 * 1 * 60, # 30 min 117 | "mpirun_extra_params": [ 118 | "timeout", 119 | "1", 120 | ], # Kill the calculation after 1 second to test the restart failure. 121 | } 122 | print("Submitted calculation...") 123 | _, process_node = run_get_node(builder) 124 | 125 | if process_node.exit_status == 400: 126 | print("Work chain failure correctly recognized.") 127 | else: 128 | print("ERROR!") 129 | print("Work chain failure was not recognized.") 130 | sys.exit(3) 131 | 132 | 133 | @click.command("cli") 134 | @click.argument("codelabel") 135 | def cli(codelabel): 136 | """Click interface.""" 137 | try: 138 | code = load_code(codelabel) 139 | except NotExistent: 140 | print(f"The code '{codelabel}' does not exist") 141 | sys.exit(1) 142 | example_base(code) 143 | 144 | 145 | if __name__ == "__main__": 146 | cli() 147 | -------------------------------------------------------------------------------- /examples/workchains/example_base_geo_opt_ignore_converge_restart.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """An example testing the restart calculation handler for ENERGY run in CP2K.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run_get_node 16 | from aiida.orm import Dict, SinglefileData, load_code 17 | from aiida.plugins import DataFactory, WorkflowFactory 18 | 19 | Cp2kBaseWorkChain = WorkflowFactory("cp2k.base") 20 | StructureData = DataFactory("core.structure") 21 | 22 | 23 | def example_base(cp2k_code): 24 | """Run simple DFT calculation through a workchain.""" 25 | 26 | thisdir = os.path.dirname(os.path.realpath(__file__)) 27 | 28 | print("Testing CP2K ENERGY on H2O (DFT) through a workchain...") 29 | 30 | # Basis set. 31 | basis_file = SinglefileData( 32 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 33 | ) 34 | 35 | # Pseudopotentials. 36 | pseudo_file = SinglefileData( 37 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 38 | ) 39 | 40 | # Structure. 41 | structure = StructureData( 42 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "h2o.xyz")) 43 | ) 44 | 45 | # Parameters. 46 | parameters = Dict( 47 | { 48 | "GLOBAL": { 49 | "RUN_TYPE": "GEO_OPT", 50 | }, 51 | "FORCE_EVAL": { 52 | "METHOD": "Quickstep", 53 | "DFT": { 54 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 55 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 56 | "QS": { 57 | "EPS_DEFAULT": 1.0e-16, 58 | "WF_INTERPOLATION": "ps", 59 | "EXTRAPOLATION_ORDER": 3, 60 | }, 61 | "MGRID": { 62 | "NGRIDS": 4, 63 | "CUTOFF": 450, 64 | "REL_CUTOFF": 70, 65 | }, 66 | "XC": { 67 | "XC_FUNCTIONAL": { 68 | "_": "LDA", 69 | }, 70 | }, 71 | "POISSON": { 72 | "PERIODIC": "none", 73 | "PSOLVER": "MT", 74 | }, 75 | "SCF": { 76 | "MAX_SCF": 10, # not enough to converge 77 | "EPS_SCF": "1.e-6", 78 | "PRINT": {"RESTART": {"_": "ON"}}, 79 | }, 80 | }, 81 | "SUBSYS": { 82 | "KIND": [ 83 | { 84 | "_": "O", 85 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 86 | "POTENTIAL": "GTH-LDA-q6", 87 | }, 88 | { 89 | "_": "H", 90 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 91 | "POTENTIAL": "GTH-LDA-q1", 92 | }, 93 | ], 94 | }, 95 | }, 96 | } 97 | ) 98 | 99 | # Construct process builder. 100 | builder = Cp2kBaseWorkChain.get_builder() 101 | 102 | # Switch on resubmit_unconverged_geometry disabled by default. 103 | builder.handler_overrides = Dict( 104 | {"restart_incomplete_calculation": {"enabled": True}} 105 | ) 106 | 107 | # Input structure. 108 | builder.cp2k.structure = structure 109 | builder.cp2k.parameters = parameters 110 | builder.cp2k.code = cp2k_code 111 | builder.cp2k.file = { 112 | "basis": basis_file, 113 | "pseudo": pseudo_file, 114 | } 115 | builder.cp2k.metadata.options = { 116 | "resources": { 117 | "num_machines": 1, 118 | "num_mpiprocs_per_machine": 1, 119 | }, 120 | "max_wallclock_seconds": 1 * 10 * 60, 121 | } 122 | 123 | print("Submitted calculation...") 124 | _, process_node = run_get_node(builder) 125 | 126 | if process_node.exit_status == 0: 127 | print("Work chain is finished correctly.") 128 | else: 129 | print("ERROR! Work chain failed.") 130 | sys.exit(1) 131 | 132 | 133 | @click.command("cli") 134 | @click.argument("codelabel") 135 | def cli(codelabel): 136 | """Click interface.""" 137 | try: 138 | code = load_code(codelabel) 139 | except NotExistent: 140 | print(f"The code '{codelabel}' does not exist") 141 | sys.exit(1) 142 | example_base(code) 143 | 144 | 145 | if __name__ == "__main__": 146 | cli() 147 | -------------------------------------------------------------------------------- /examples/workchains/example_base_geoopt_restart.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """An example testing the restart calculation handler for geo_opt run in CP2K.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run 16 | from aiida.orm import Dict, SinglefileData, load_code 17 | from aiida.plugins import DataFactory, WorkflowFactory 18 | 19 | Cp2kBaseWorkChain = WorkflowFactory("cp2k.base") 20 | StructureData = DataFactory("core.structure") 21 | 22 | 23 | def example_base(cp2k_code): 24 | """Run simple DFT calculation through a workchain.""" 25 | 26 | thisdir = os.path.dirname(os.path.realpath(__file__)) 27 | 28 | print("Testing CP2K ENERGY on H2O (DFT) through a workchain...") 29 | 30 | # Basis set. 31 | basis_file = SinglefileData( 32 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 33 | ) 34 | 35 | # Pseudopotentials. 36 | pseudo_file = SinglefileData( 37 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 38 | ) 39 | 40 | # Structure. 41 | structure = StructureData( 42 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "h2o.xyz")) 43 | ) 44 | 45 | # Parameters. 46 | parameters = Dict( 47 | { 48 | "GLOBAL": { 49 | "RUN_TYPE": "GEO_OPT", 50 | }, 51 | "MOTION": { 52 | "GEO_OPT": { 53 | "MAX_ITER": 8, 54 | }, 55 | }, 56 | "FORCE_EVAL": { 57 | "METHOD": "Quickstep", 58 | "DFT": { 59 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 60 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 61 | "QS": { 62 | "EPS_DEFAULT": 1.0e-12, 63 | "WF_INTERPOLATION": "ps", 64 | "EXTRAPOLATION_ORDER": 3, 65 | }, 66 | "MGRID": { 67 | "NGRIDS": 4, 68 | "CUTOFF": 280, 69 | "REL_CUTOFF": 30, 70 | }, 71 | "XC": { 72 | "XC_FUNCTIONAL": { 73 | "_": "LDA", 74 | }, 75 | }, 76 | "POISSON": { 77 | "PERIODIC": "none", 78 | "PSOLVER": "MT", 79 | }, 80 | "SCF": {"PRINT": {"RESTART": {"_": "ON"}}}, 81 | }, 82 | "SUBSYS": { 83 | "KIND": [ 84 | { 85 | "_": "O", 86 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 87 | "POTENTIAL": "GTH-LDA-q6", 88 | }, 89 | { 90 | "_": "H", 91 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 92 | "POTENTIAL": "GTH-LDA-q1", 93 | }, 94 | ], 95 | }, 96 | }, 97 | } 98 | ) 99 | 100 | # Construct process builder. 101 | builder = Cp2kBaseWorkChain.get_builder() 102 | 103 | # Switch on resubmit_unconverged_geometry disabled by default. 104 | builder.handler_overrides = Dict( 105 | {"restart_incomplete_calculation": {"enabled": True}} 106 | ) 107 | 108 | # Input structure. 109 | builder.cp2k.structure = structure 110 | builder.cp2k.parameters = parameters 111 | builder.cp2k.code = cp2k_code 112 | builder.cp2k.file = { 113 | "basis": basis_file, 114 | "pseudo": pseudo_file, 115 | } 116 | builder.cp2k.metadata.options.resources = { 117 | "num_machines": 1, 118 | "num_mpiprocs_per_machine": 1, 119 | } 120 | builder.cp2k.metadata.options.max_wallclock_seconds = 1 * 3 * 60 121 | 122 | print("Submitted calculation...") 123 | calc = run(builder) 124 | 125 | if "EXT_RESTART" in calc["final_input_parameters"].dict: 126 | print("OK, EXT_RESTART section is present in the final_input_parameters.") 127 | else: 128 | print( 129 | "ERROR, EXT_RESTART section is NOT present in the final_input_parameters." 130 | ) 131 | sys.exit(3) 132 | 133 | 134 | @click.command("cli") 135 | @click.argument("codelabel") 136 | def cli(codelabel): 137 | """Click interface.""" 138 | try: 139 | code = load_code(codelabel) 140 | except NotExistent: 141 | print(f"The code '{codelabel}' does not exist") 142 | sys.exit(1) 143 | example_base(code) 144 | 145 | 146 | if __name__ == "__main__": 147 | cli() 148 | -------------------------------------------------------------------------------- /examples/workchains/example_base_md_restart.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """An example testing the restart calculation handler for geo_opt run in CP2K.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | from aiida.common import NotExistent 15 | from aiida.engine import run 16 | from aiida.orm import Dict, SinglefileData, load_code 17 | from aiida.plugins import DataFactory, WorkflowFactory 18 | 19 | Cp2kBaseWorkChain = WorkflowFactory("cp2k.base") 20 | StructureData = DataFactory("core.structure") 21 | 22 | 23 | def example_base(cp2k_code): 24 | """Run simple DFT calculation through a workchain.""" 25 | 26 | thisdir = os.path.dirname(os.path.realpath(__file__)) 27 | 28 | print("Testing CP2K ENERGY on H2O (DFT) through a workchain...") 29 | 30 | # Basis set. 31 | basis_file = SinglefileData( 32 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 33 | ) 34 | 35 | # Pseudopotentials. 36 | pseudo_file = SinglefileData( 37 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 38 | ) 39 | 40 | # Structure. 41 | structure = StructureData( 42 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "h2o.xyz")) 43 | ) 44 | 45 | # Parameters. 46 | parameters = Dict( 47 | { 48 | "GLOBAL": { 49 | "RUN_TYPE": "MD", 50 | "WALLTIME": "00:00:14", # too short 51 | }, 52 | "FORCE_EVAL": { 53 | "METHOD": "Quickstep", 54 | "STRESS_TENSOR": "analytical", 55 | "DFT": { 56 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 57 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 58 | "QS": { 59 | "EPS_DEFAULT": 1.0e-12, 60 | "WF_INTERPOLATION": "ps", 61 | "EXTRAPOLATION_ORDER": 3, 62 | }, 63 | "MGRID": { 64 | "NGRIDS": 4, 65 | "CUTOFF": 280, 66 | "REL_CUTOFF": 30, 67 | }, 68 | "XC": { 69 | "XC_FUNCTIONAL": { 70 | "_": "LDA", 71 | }, 72 | }, 73 | "POISSON": { 74 | "PERIODIC": "none", 75 | "PSOLVER": "MT", 76 | }, 77 | "SCF": {"PRINT": {"RESTART": {"_": "ON"}}}, 78 | }, 79 | "SUBSYS": { 80 | "KIND": [ 81 | { 82 | "_": "O", 83 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 84 | "POTENTIAL": "GTH-LDA-q6", 85 | }, 86 | { 87 | "_": "H", 88 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 89 | "POTENTIAL": "GTH-LDA-q1", 90 | }, 91 | ], 92 | }, 93 | }, 94 | "MOTION": { 95 | "CONSTRAINT": {}, 96 | "MD": { 97 | "THERMOSTAT": {"CSVR": {}, "TYPE": "csvr"}, 98 | "BAROSTAT": {}, 99 | "MAX_STEPS": 8, 100 | "STEPS": 10000, 101 | "ENSEMBLE": "npt_f", 102 | "TEMPERATURE": 300.0, 103 | }, 104 | "PRINT": { 105 | "RESTART": {"EACH": {"MD": 1}}, 106 | }, 107 | }, 108 | } 109 | ) 110 | 111 | # Construct process builder. 112 | builder = Cp2kBaseWorkChain.get_builder() 113 | 114 | # Switch on resubmit_unconverged_geometry disabled by default. 115 | builder.handler_overrides = Dict( 116 | {"restart_incomplete_calculation": {"enabled": True}} 117 | ) 118 | 119 | # Input structure. 120 | builder.cp2k.structure = structure 121 | builder.cp2k.parameters = parameters 122 | builder.cp2k.code = cp2k_code 123 | builder.cp2k.file = { 124 | "basis": basis_file, 125 | "pseudo": pseudo_file, 126 | } 127 | builder.cp2k.metadata.options.resources = { 128 | "num_machines": 1, 129 | "num_mpiprocs_per_machine": 1, 130 | } 131 | builder.cp2k.metadata.options.max_wallclock_seconds = 1 * 3 * 60 132 | 133 | print("Submitted calculation...") 134 | calc = run(builder) 135 | 136 | if "EXT_RESTART" in calc["final_input_parameters"].dict: 137 | print("OK, EXT_RESTART section is present in the final_input_parameters.") 138 | else: 139 | print( 140 | "ERROR, EXT_RESTART section is NOT present in the final_input_parameters." 141 | ) 142 | sys.exit(3) 143 | 144 | 145 | @click.command("cli") 146 | @click.argument("codelabel") 147 | def cli(codelabel): 148 | """Click interface.""" 149 | try: 150 | code = load_code(codelabel) 151 | except NotExistent: 152 | print(f"The code '{codelabel}' does not exist") 153 | sys.exit(1) 154 | example_base(code) 155 | 156 | 157 | if __name__ == "__main__": 158 | cli() 159 | -------------------------------------------------------------------------------- /examples/workchains/fixme_example_base_md_reftraj_restart.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """An example testing the restart calculation handler for geo_opt run in CP2K.""" 8 | 9 | import os 10 | import sys 11 | 12 | import ase.io 13 | import click 14 | import numpy as np 15 | from aiida import common, engine, orm, plugins 16 | 17 | Cp2kBaseWorkChain = plugins.WorkflowFactory("cp2k.base") 18 | StructureData = plugins.DataFactory("core.structure") 19 | TrajectoryData = plugins.DataFactory("core.array.trajectory") 20 | 21 | 22 | def example_base(cp2k_code): 23 | """Run simple DFT calculation through a workchain.""" 24 | 25 | thisdir = os.path.dirname(os.path.realpath(__file__)) 26 | 27 | print("Testing CP2K MD REFTRAJ on H2 (DFT) through a workchain...") 28 | 29 | # Basis set. 30 | basis_file = orm.SinglefileData( 31 | file=os.path.join(thisdir, "..", "files", "BASIS_MOLOPT") 32 | ) 33 | 34 | # Pseudopotentials. 35 | pseudo_file = orm.SinglefileData( 36 | file=os.path.join(thisdir, "..", "files", "GTH_POTENTIALS") 37 | ) 38 | 39 | # Structure. 40 | structure = StructureData( 41 | ase=ase.io.read(os.path.join(thisdir, "..", "files", "h2.xyz")) 42 | ) 43 | 44 | # Trajectory. 45 | steps = 20 46 | positions = np.array([[[2, 2, 2.73 + 0.01 * i], [2, 2, 2]] for i in range(steps)]) 47 | cells = np.array( 48 | [[[4, 0, 0], [0, 4, 0], [0, 0, 4.75 + 0.01 * i]] for i in range(steps)] 49 | ) 50 | symbols = ["H", "H"] 51 | trajectory = TrajectoryData() 52 | trajectory.set_trajectory(symbols, positions, cells=cells) 53 | 54 | # Parameters. 55 | parameters = orm.Dict( 56 | { 57 | "GLOBAL": { 58 | "RUN_TYPE": "MD", 59 | "PRINT_LEVEL": "LOW", 60 | "WALLTIME": 2, 61 | "PROJECT": "aiida", 62 | }, 63 | "MOTION": { 64 | "MD": { 65 | "ENSEMBLE": "REFTRAJ", 66 | "STEPS": steps, 67 | "REFTRAJ": { 68 | "FIRST_SNAPSHOT": 1, 69 | "LAST_SNAPSHOT": steps, 70 | "EVAL_FORCES": ".TRUE.", 71 | "TRAJ_FILE_NAME": "aiida-reftraj.xyz", 72 | "CELL_FILE_NAME": "aiida-reftraj.cell", 73 | "VARIABLE_VOLUME": ".TRUE.", 74 | }, 75 | }, 76 | "PRINT": { 77 | "RESTART": { 78 | "EACH": { 79 | "MD": 1, 80 | }, 81 | }, 82 | "FORCES": { 83 | "EACH": { 84 | "MD": 1, 85 | }, 86 | }, 87 | "CELL": { 88 | "EACH": { 89 | "MD": 1, 90 | }, 91 | }, 92 | }, 93 | }, 94 | "FORCE_EVAL": { 95 | "METHOD": "Quickstep", 96 | "DFT": { 97 | "BASIS_SET_FILE_NAME": "BASIS_MOLOPT", 98 | "POTENTIAL_FILE_NAME": "GTH_POTENTIALS", 99 | "QS": { 100 | "EPS_DEFAULT": 1.0e-12, 101 | "WF_INTERPOLATION": "ps", 102 | "EXTRAPOLATION_ORDER": 3, 103 | }, 104 | "MGRID": { 105 | "NGRIDS": 4, 106 | "CUTOFF": 280, 107 | "REL_CUTOFF": 30, 108 | }, 109 | "XC": { 110 | "XC_FUNCTIONAL": { 111 | "_": "LDA", 112 | }, 113 | }, 114 | "POISSON": { 115 | "PERIODIC": "none", 116 | "PSOLVER": "MT", 117 | }, 118 | }, 119 | "SUBSYS": { 120 | "KIND": [ 121 | { 122 | "_": "O", 123 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 124 | "POTENTIAL": "GTH-LDA-q6", 125 | }, 126 | { 127 | "_": "H", 128 | "BASIS_SET": "DZVP-MOLOPT-SR-GTH", 129 | "POTENTIAL": "GTH-LDA-q1", 130 | }, 131 | ], 132 | }, 133 | }, 134 | } 135 | ) 136 | 137 | # Construct process builder. 138 | builder = Cp2kBaseWorkChain.get_builder() 139 | 140 | # Switch on resubmit_unconverged_geometry disabled by default. 141 | builder.handler_overrides = orm.Dict( 142 | {"restart_incomplete_calculation": {"enabled": True}} 143 | ) 144 | 145 | # Input structure. 146 | builder.cp2k.structure = structure 147 | builder.cp2k.trajectory = trajectory 148 | builder.cp2k.parameters = parameters 149 | builder.cp2k.code = cp2k_code 150 | builder.cp2k.file = { 151 | "basis": basis_file, 152 | "pseudo": pseudo_file, 153 | } 154 | builder.cp2k.metadata.options = { 155 | "max_wallclock_seconds": 100, 156 | "resources": { 157 | "num_machines": 1, 158 | "num_mpiprocs_per_machine": 1, 159 | }, 160 | } 161 | 162 | print("Submitted calculation...") 163 | outputs, calc_node = engine.run_get_node(builder) 164 | 165 | if "EXT_RESTART" in outputs["final_input_parameters"].dict: 166 | print("OK, EXT_RESTART section is present in the final_input_parameters.") 167 | else: 168 | print( 169 | "ERROR, EXT_RESTART section is NOT present in the final_input_parameters." 170 | ) 171 | sys.exit(1) 172 | 173 | # Check stepids extracted from each individual calculation. 174 | stepids = np.concatenate( 175 | [ 176 | called.outputs.output_trajectory.get_stepids() 177 | for called in calc_node.called 178 | if isinstance(called, orm.CalcJobNode) 179 | ] 180 | ) 181 | 182 | if np.all(stepids == np.arange(1, steps + 1)): 183 | print("OK, stepids are correct.") 184 | else: 185 | print( 186 | f"ERROR, stepids are NOT correct. Expected: {np.arange(1, steps + 1)} but got: {stepids}" 187 | ) 188 | sys.exit(1) 189 | 190 | # Check the final trajectory. 191 | final_trajectory = outputs["output_trajectory"] 192 | 193 | if np.all(final_trajectory.get_stepids() == np.arange(1, steps + 1)): 194 | print("OK, final trajectory stepids are correct.") 195 | else: 196 | print( 197 | f"ERROR, final trajectory stepids are NOT correct. Expected: {np.arange(1, steps + 1)} but got: {final_trajectory.get_stepids()}" 198 | ) 199 | sys.exit(1) 200 | 201 | if final_trajectory.get_positions().shape == (steps, len(structure.sites), 3): 202 | print("OK, the shape of the positions array is correct.") 203 | else: 204 | print( 205 | f"ERROR, the shape of the positions array is NOT correct. Expected: {(steps, len(structure.sites), 3)} but got: {final_trajectory.get_positions().shape}" 206 | ) 207 | sys.exit(1) 208 | 209 | if final_trajectory.get_cells().shape == (steps, 3, 3): 210 | print("OK, the shape of the cells array is correct.") 211 | else: 212 | print( 213 | f"ERROR, the shape of the cells array is NOT correct. Expected: {(steps, 3, 3)} but got: {final_trajectory.get_cells().shape}" 214 | ) 215 | sys.exit(1) 216 | 217 | 218 | @click.command("cli") 219 | @click.argument("codelabel") 220 | def cli(codelabel): 221 | """Click interface.""" 222 | try: 223 | code = orm.load_code(codelabel) 224 | except common.NotExistent: 225 | print(f"The code '{codelabel}' does not exist") 226 | sys.exit(1) 227 | example_base(code) 228 | 229 | 230 | if __name__ == "__main__": 231 | cli() 232 | -------------------------------------------------------------------------------- /miscellaneous/logos/MARVEL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aiidateam/aiida-cp2k/c6b973e774c327066037544cff2e07f80a5fb4a4/miscellaneous/logos/MARVEL.png -------------------------------------------------------------------------------- /miscellaneous/logos/MaX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aiidateam/aiida-cp2k/c6b973e774c327066037544cff2e07f80a5fb4a4/miscellaneous/logos/MaX.png -------------------------------------------------------------------------------- /miscellaneous/logos/swissuniversities.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aiidateam/aiida-cp2k/c6b973e774c327066037544cff2e07f80a5fb4a4/miscellaneous/logos/swissuniversities.png -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["flit_core >=3.2,<4"] 3 | build-backend = "flit_core.buildapi" 4 | 5 | [tool.flit.module] 6 | name = "aiida_cp2k" 7 | 8 | [project] 9 | name = "aiida-cp2k" 10 | dynamic = ["version", "description"] 11 | readme = "README.md" 12 | license = {file = 'LICENSE.txt'} 13 | classifiers = [ 14 | "Development Status :: 5 - Production/Stable", 15 | "Framework :: AiiDA", 16 | "License :: OSI Approved :: MIT License", 17 | "Operating System :: POSIX :: Linux", 18 | "Operating System :: MacOS :: MacOS X", 19 | "Programming Language :: Python :: 3", 20 | ] 21 | requires-python = ">=3.9" 22 | dependencies = [ 23 | "aiida-core>=2.0.0,<3.0.0", 24 | "aiida-gaussian-datatypes", 25 | "ase", 26 | "ruamel.yaml>=0.16.5", 27 | "cp2k-output-tools", 28 | "aiida-pseudo~=1.2", 29 | "upf-to-json>=0.9", 30 | ] 31 | 32 | [[project.authors]] 33 | name = "The AiiDA team" 34 | 35 | [project.urls] 36 | Homepage = "https://github.com/aiidateam/aiida-cp2k" 37 | 38 | [project.optional-dependencies] 39 | dev = [ 40 | "bumpver==2022.1119", 41 | "pgtest~=1.3", 42 | "pytest~=6.0", 43 | "pytest-cov~=2.11.1", 44 | "coverage", 45 | "pre-commit~=3.6", 46 | ] 47 | docs = [ 48 | "sphinx", 49 | "sphinx-rtd-theme", 50 | "sphinxcontrib-contentui", 51 | "sphinxcontrib-details-directive", 52 | ] 53 | 54 | [project.entry-points."aiida.calculations"] 55 | cp2k = "aiida_cp2k.calculations:Cp2kCalculation" 56 | 57 | [project.entry-points."aiida.parsers"] 58 | cp2k_base_parser = "aiida_cp2k.parsers:Cp2kBaseParser" 59 | cp2k_advanced_parser = "aiida_cp2k.parsers:Cp2kAdvancedParser" 60 | cp2k_tools_parser = "aiida_cp2k.parsers:Cp2kToolsParser" 61 | 62 | [project.entry-points."aiida.workflows"] 63 | "cp2k.base" = "aiida_cp2k.workchains:Cp2kBaseWorkChain" 64 | 65 | [tool.pytest.ini_options] 66 | python_files = "test_*.py example_*.py" 67 | python_functions = "example_* test_*" 68 | filterwarnings = [ 69 | "ignore::DeprecationWarning:aiida:", 70 | "ignore::DeprecationWarning:plumpy:", 71 | "ignore::DeprecationWarning:django:", 72 | "ignore::DeprecationWarning:frozendict:", 73 | "ignore::DeprecationWarning:sqlalchemy:", 74 | "ignore::DeprecationWarning:yaml:", 75 | "ignore::DeprecationWarning:pymatgen:", 76 | ] 77 | 78 | [tool.bumpver] 79 | current_version = "v2.1.1" 80 | version_pattern = "vMAJOR.MINOR.PATCH[PYTAGNUM]" 81 | commit_message = "Bump version {old_version} -> {new_version}." 82 | commit = true 83 | tag = true 84 | push = true 85 | 86 | [tool.bumpver.file_patterns] 87 | "aiida_cp2k/__init__.py" = [ 88 | '__version__ = "{pep440_version}"', 89 | ] 90 | -------------------------------------------------------------------------------- /test/outputs/PBC_output_none.restart: -------------------------------------------------------------------------------- 1 | &GLOBAL 2 | PROJECT_NAME aiida 3 | RUN_TYPE GEO_OPT 4 | &END GLOBAL 5 | &FORCE_EVAL 6 | METHOD QS 7 | &DFT 8 | BASIS_SET_FILE_NAME BASIS_MOLOPT 9 | POTENTIAL_FILE_NAME GTH_POTENTIALS 10 | &QS 11 | EPS_DEFAULT 9.9999999999999998E-13 12 | EXTRAPOLATION PS 13 | EXTRAPOLATION_ORDER 3 14 | &END QS 15 | &MGRID 16 | NGRIDS 4 17 | CUTOFF 2.8000000000000000E+02 18 | REL_CUTOFF 3.0000000000000000E+01 19 | &END MGRID 20 | &XC 21 | DENSITY_CUTOFF 1.0000000000000000E-10 22 | GRADIENT_CUTOFF 1.0000000000000000E-10 23 | TAU_CUTOFF 1.0000000000000000E-10 24 | &XC_FUNCTIONAL NO_SHORTCUT 25 | &PBE T 26 | &END PBE 27 | &END XC_FUNCTIONAL 28 | &END XC 29 | &POISSON 30 | POISSON_SOLVER MT 31 | PERIODIC NONE 32 | &END POISSON 33 | &END DFT 34 | &SUBSYS 35 | &CELL 36 | A 4.0000000000000000E+00 0.0000000000000000E+00 0.0000000000000000E+00 37 | B 0.0000000000000000E+00 4.0000000000000000E+00 0.0000000000000000E+00 38 | C 0.0000000000000000E+00 0.0000000000000000E+00 4.7371660000000011E+00 39 | PERIODIC NONE 40 | MULTIPLE_UNIT_CELL 1 1 1 41 | &END CELL 42 | &COORD 43 | H1 2.0000000000000893E+00 1.9999999999999707E+00 2.7290247702949189E+00 44 | H1 2.0000000000000697E+00 2.0000000000001568E+00 2.0081412297053984E+00 45 | &END COORD 46 | &KIND O 47 | BASIS_SET DZVP-MOLOPT-SR-GTH 48 | POTENTIAL GTH-PBE-q6 49 | &END KIND 50 | &KIND H1 51 | ELEMENT H 52 | BASIS_SET DZVP-MOLOPT-SR-GTH 53 | POTENTIAL GTH-PBE-q1 54 | &POTENTIAL 55 | 1 56 | 0.2000000000000000E+00 2 -0.4178900440000000E+01 0.7244633100000000E+00 57 | 0 58 | # Potential name: GTH-PBE-Q1 for symbol: H 59 | # Potential read from the potential filename: GTH_POTENTIALS 60 | &END POTENTIAL 61 | &END KIND 62 | &TOPOLOGY 63 | COORD_FILE_NAME aiida.coords.xyz 64 | COORD_FILE_FORMAT XYZ 65 | NUMBER_OF_ATOMS 2 66 | MULTIPLE_UNIT_CELL 1 1 1 67 | &END TOPOLOGY 68 | &END SUBSYS 69 | &END FORCE_EVAL 70 | -------------------------------------------------------------------------------- /test/outputs/PBC_output_xyz.restart: -------------------------------------------------------------------------------- 1 | &GLOBAL 2 | PROJECT_NAME aiida 3 | RUN_TYPE GEO_OPT 4 | &END GLOBAL 5 | &FORCE_EVAL 6 | METHOD QS 7 | &DFT 8 | BASIS_SET_FILE_NAME BASIS_MOLOPT 9 | POTENTIAL_FILE_NAME GTH_POTENTIALS 10 | &QS 11 | EPS_DEFAULT 9.9999999999999998E-13 12 | EXTRAPOLATION PS 13 | EXTRAPOLATION_ORDER 3 14 | &END QS 15 | &MGRID 16 | NGRIDS 4 17 | CUTOFF 2.8000000000000000E+02 18 | REL_CUTOFF 3.0000000000000000E+01 19 | &END MGRID 20 | &XC 21 | DENSITY_CUTOFF 1.0000000000000000E-10 22 | GRADIENT_CUTOFF 1.0000000000000000E-10 23 | TAU_CUTOFF 1.0000000000000000E-10 24 | &XC_FUNCTIONAL NO_SHORTCUT 25 | &PBE T 26 | &END PBE 27 | &END XC_FUNCTIONAL 28 | &END XC 29 | &POISSON 30 | POISSON_SOLVER MT 31 | PERIODIC NONE 32 | &END POISSON 33 | &END DFT 34 | &SUBSYS 35 | &CELL 36 | A 4.0000000000000000E+00 0.0000000000000000E+00 0.0000000000000000E+00 37 | B 0.0000000000000000E+00 4.0000000000000000E+00 0.0000000000000000E+00 38 | C 0.0000000000000000E+00 0.0000000000000000E+00 4.7371660000000011E+00 39 | PERIODIC XYZ 40 | MULTIPLE_UNIT_CELL 1 1 1 41 | &END CELL 42 | &COORD 43 | H1 2.0000000000000893E+00 1.9999999999999707E+00 2.7290247702949189E+00 44 | H1 2.0000000000000697E+00 2.0000000000001568E+00 2.0081412297053984E+00 45 | &END COORD 46 | &KIND O 47 | BASIS_SET DZVP-MOLOPT-SR-GTH 48 | POTENTIAL GTH-PBE-q6 49 | &END KIND 50 | &KIND H1 51 | ELEMENT H 52 | BASIS_SET DZVP-MOLOPT-SR-GTH 53 | POTENTIAL GTH-PBE-q1 54 | &POTENTIAL 55 | 1 56 | 0.2000000000000000E+00 2 -0.4178900440000000E+01 0.7244633100000000E+00 57 | 0 58 | # Potential name: GTH-PBE-Q1 for symbol: H 59 | # Potential read from the potential filename: GTH_POTENTIALS 60 | &END POTENTIAL 61 | &END KIND 62 | &TOPOLOGY 63 | COORD_FILE_NAME aiida.coords.xyz 64 | COORD_FILE_FORMAT XYZ 65 | NUMBER_OF_ATOMS 2 66 | MULTIPLE_UNIT_CELL 1 1 1 67 | &END TOPOLOGY 68 | &END SUBSYS 69 | &END FORCE_EVAL 70 | -------------------------------------------------------------------------------- /test/outputs/PBC_output_xz.restart: -------------------------------------------------------------------------------- 1 | &GLOBAL 2 | PROJECT_NAME aiida 3 | RUN_TYPE GEO_OPT 4 | &END GLOBAL 5 | &FORCE_EVAL 6 | METHOD QS 7 | &DFT 8 | BASIS_SET_FILE_NAME BASIS_MOLOPT 9 | POTENTIAL_FILE_NAME GTH_POTENTIALS 10 | &QS 11 | EPS_DEFAULT 9.9999999999999998E-13 12 | EXTRAPOLATION PS 13 | EXTRAPOLATION_ORDER 3 14 | &END QS 15 | &MGRID 16 | NGRIDS 4 17 | CUTOFF 2.8000000000000000E+02 18 | REL_CUTOFF 3.0000000000000000E+01 19 | &END MGRID 20 | &XC 21 | DENSITY_CUTOFF 1.0000000000000000E-10 22 | GRADIENT_CUTOFF 1.0000000000000000E-10 23 | TAU_CUTOFF 1.0000000000000000E-10 24 | &XC_FUNCTIONAL NO_SHORTCUT 25 | &PBE T 26 | &END PBE 27 | &END XC_FUNCTIONAL 28 | &END XC 29 | &POISSON 30 | POISSON_SOLVER MT 31 | PERIODIC NONE 32 | &END POISSON 33 | &END DFT 34 | &SUBSYS 35 | &CELL 36 | A 4.0000000000000000E+00 0.0000000000000000E+00 0.0000000000000000E+00 37 | B 0.0000000000000000E+00 4.0000000000000000E+00 0.0000000000000000E+00 38 | C 0.0000000000000000E+00 0.0000000000000000E+00 4.7371660000000011E+00 39 | PERIODIC XZ 40 | MULTIPLE_UNIT_CELL 1 1 1 41 | &END CELL 42 | &COORD 43 | H1 2.0000000000000893E+00 1.9999999999999707E+00 2.7290247702949189E+00 44 | H1 2.0000000000000697E+00 2.0000000000001568E+00 2.0081412297053984E+00 45 | &END COORD 46 | &KIND O 47 | BASIS_SET DZVP-MOLOPT-SR-GTH 48 | POTENTIAL GTH-PBE-q6 49 | &END KIND 50 | &KIND H1 51 | ELEMENT H 52 | BASIS_SET DZVP-MOLOPT-SR-GTH 53 | POTENTIAL GTH-PBE-q1 54 | &POTENTIAL 55 | 1 56 | 0.2000000000000000E+00 2 -0.4178900440000000E+01 0.7244633100000000E+00 57 | 0 58 | # Potential name: GTH-PBE-Q1 for symbol: H 59 | # Potential read from the potential filename: GTH_POTENTIALS 60 | &END POTENTIAL 61 | &END KIND 62 | &TOPOLOGY 63 | COORD_FILE_NAME aiida.coords.xyz 64 | COORD_FILE_FORMAT XYZ 65 | NUMBER_OF_ATOMS 2 66 | MULTIPLE_UNIT_CELL 1 1 1 67 | &END TOPOLOGY 68 | &END SUBSYS 69 | &END FORCE_EVAL 70 | -------------------------------------------------------------------------------- /test/test_datatype_helpers.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pytest 3 | from aiida import orm 4 | 5 | from aiida_cp2k.utils import ( 6 | merge_trajectory_data_non_unique, 7 | merge_trajectory_data_unique, 8 | ) 9 | 10 | 11 | @pytest.mark.parametrize( 12 | "step_ranges", 13 | ( 14 | [(1, 20), (21, 40)], 15 | [(1, 20), (15, 30)], 16 | [(1, 20), (21, 40), (41, 60)], 17 | [(1, 25), (21, 30), (31, 60), (45, 80)], 18 | ), 19 | ) 20 | def test_merge_trajectory_data(step_ranges): 21 | def get_trajectory(step1=1, step2=20): 22 | nstes = step2 - step1 + 1 23 | positions = np.array( 24 | [ 25 | [[2, 2, 2.73 + 0.05 * np.random.random()], [2, 2, 2]] 26 | for i in range(nstes) 27 | ] 28 | ) 29 | cells = np.array( 30 | [ 31 | [[4, 0, 0], [0, 4, 0], [0, 0, 4.75 + 0.05 * np.random.random()]] 32 | for i in range(nstes) 33 | ] 34 | ) 35 | stepids = np.arange(step1, step2 + 1) 36 | symbols = ["H", "H"] 37 | trajectory = orm.TrajectoryData() 38 | trajectory.set_trajectory(symbols, positions, cells=cells, stepids=stepids) 39 | return trajectory 40 | 41 | trajectories = [get_trajectory(*step_range) for step_range in step_ranges] 42 | 43 | total_length = sum( 44 | [step_range[1] - step_range[0] + 1 for step_range in step_ranges] 45 | ) 46 | 47 | unique_elements = [] 48 | for step_range in step_ranges: 49 | unique_elements.extend(range(step_range[0], step_range[1] + 1)) 50 | total_lenght_unique = len(set(unique_elements)) 51 | 52 | merged_trajectory = merge_trajectory_data_non_unique(*trajectories) 53 | assert ( 54 | len(merged_trajectory.get_stepids()) == total_length 55 | ), "The merged trajectory has the wrong length." 56 | 57 | merged_trajectory_unique = merge_trajectory_data_unique(*trajectories) 58 | assert ( 59 | len(merged_trajectory_unique.get_stepids()) == total_lenght_unique 60 | ), "The merged trajectory with unique stepids has the wrong length." 61 | -------------------------------------------------------------------------------- /test/test_input_generator.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/cp2k/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Test Cp2k input generator""" 8 | 9 | import pytest 10 | 11 | from aiida_cp2k.utils import Cp2kInput 12 | 13 | 14 | def test_render_empty(): 15 | inp = Cp2kInput() 16 | assert inp.render() == inp.DISCLAIMER 17 | 18 | 19 | def test_render_str_val(): 20 | inp = Cp2kInput({"FOO": "bar"}) 21 | assert inp.render() == f"{inp.DISCLAIMER}\nFOO bar" 22 | 23 | 24 | def test_add_keyword(): 25 | """Test add_keyword()""" 26 | inp = Cp2kInput({"FOO": "bar"}) 27 | inp.add_keyword("BAR", "boo") 28 | assert inp.render() == f"{inp.DISCLAIMER}\nBAR boo\nFOO bar" 29 | 30 | inp.add_keyword("BOO/BAZ", "boo") 31 | assert ( 32 | inp.render() 33 | == f"""{inp.DISCLAIMER} 34 | BAR boo 35 | &BOO 36 | BAZ boo 37 | &END BOO 38 | FOO bar""" 39 | ) 40 | 41 | inp.add_keyword(["BOO", "BII"], "boo") 42 | assert ( 43 | inp.render() 44 | == f"""{inp.DISCLAIMER} 45 | BAR boo 46 | &BOO 47 | BAZ boo 48 | BII boo 49 | &END BOO 50 | FOO bar""" 51 | ) 52 | 53 | inp.add_keyword("BOO/BII", "bzzzzzz", override=False) 54 | assert ( 55 | inp.render() 56 | == f"""{inp.DISCLAIMER} 57 | BAR boo 58 | &BOO 59 | BAZ boo 60 | BII boo 61 | &END BOO 62 | FOO bar""" 63 | ) 64 | 65 | inp.add_keyword("BOO/BII/BCC", "bcr", override=False) 66 | assert ( 67 | inp.render() 68 | == f"""{inp.DISCLAIMER} 69 | BAR boo 70 | &BOO 71 | BAZ boo 72 | BII boo 73 | &END BOO 74 | FOO bar""" 75 | ) 76 | 77 | inp.add_keyword("BOO/BII/BCC", "bcr") 78 | assert ( 79 | inp.render() 80 | == f"""{inp.DISCLAIMER} 81 | BAR boo 82 | &BOO 83 | BAZ boo 84 | &BII 85 | BCC bcr 86 | &END BII 87 | &END BOO 88 | FOO bar""" 89 | ) 90 | 91 | inp.add_keyword("BOO/BII", "boo", override=False) 92 | assert ( 93 | inp.render() 94 | == f"""{inp.DISCLAIMER} 95 | BAR boo 96 | &BOO 97 | BAZ boo 98 | &BII 99 | BCC bcr 100 | &END BII 101 | &END BOO 102 | FOO bar""" 103 | ) 104 | 105 | inp.add_keyword("BOO/BII", "boo", override=True) 106 | assert ( 107 | inp.render() 108 | == f"""{inp.DISCLAIMER} 109 | BAR boo 110 | &BOO 111 | BAZ boo 112 | BII boo 113 | &END BOO 114 | FOO bar""" 115 | ) 116 | 117 | inp.add_keyword("BOO/BII", "boo", override=True) 118 | assert ( 119 | inp.render() 120 | == f"""{inp.DISCLAIMER} 121 | BAR boo 122 | &BOO 123 | BAZ boo 124 | BII boo 125 | &END BOO 126 | FOO bar""" 127 | ) 128 | 129 | inp.add_keyword("BOO/BIP", "bzz", override=False, conflicting_keys=["BII"]) 130 | assert ( 131 | inp.render() 132 | == f"""{inp.DISCLAIMER} 133 | BAR boo 134 | &BOO 135 | BAZ boo 136 | BII boo 137 | &END BOO 138 | FOO bar""" 139 | ) 140 | 141 | inp.add_keyword("BOO/BIP", "bzz", override=False, conflicting_keys=[]) 142 | assert ( 143 | inp.render() 144 | == f"""{inp.DISCLAIMER} 145 | BAR boo 146 | &BOO 147 | BAZ boo 148 | BII boo 149 | BIP bzz 150 | &END BOO 151 | FOO bar""" 152 | ) 153 | 154 | inp.add_keyword("BOO/BEE", "bee", override=True, conflicting_keys=["BAZ", "BII"]) 155 | assert ( 156 | inp.render() 157 | == f"""{inp.DISCLAIMER} 158 | BAR boo 159 | &BOO 160 | BEE bee 161 | BIP bzz 162 | &END BOO 163 | FOO bar""" 164 | ) 165 | 166 | 167 | def test_add_keyword_invariant_inp(): 168 | """Check that the input dictionary is not modified by add_keyword()""" 169 | param = {"FOO": "bar"} 170 | inp = Cp2kInput(param) 171 | inp.add_keyword("BAR", "boo") 172 | assert inp.render() == f"{inp.DISCLAIMER}\nBAR boo\nFOO bar" 173 | assert param == {"FOO": "bar"} 174 | 175 | 176 | def test_multiple_force_eval(): 177 | inp = Cp2kInput({"FORCE_EVAL": [{"FOO": "bar"}, {"FOO": "bar"}, {"FOO": "bar"}]}) 178 | assert ( 179 | inp.render() 180 | == f"""{inp.DISCLAIMER} 181 | &FORCE_EVAL 182 | FOO bar 183 | &END FORCE_EVAL 184 | &FORCE_EVAL 185 | FOO bar 186 | &END FORCE_EVAL 187 | &FORCE_EVAL 188 | FOO bar 189 | &END FORCE_EVAL""" 190 | ) 191 | 192 | 193 | def test_kinds(): 194 | inp = Cp2kInput({"KIND": [{"_": "H"}, {"_": "O"}]}) 195 | assert ( 196 | inp.render() 197 | == f"""{inp.DISCLAIMER} 198 | &KIND H 199 | &END KIND 200 | &KIND O 201 | &END KIND""" 202 | ) 203 | 204 | 205 | def test_invariant_under_render(): 206 | """Check that the input dictionary is not modified by Cp2kInput.render()""" 207 | param = {"KIND": [{"_": "H"}, {"_": "O"}]} 208 | Cp2kInput(param).render() 209 | assert param == {"KIND": [{"_": "H"}, {"_": "O"}]} 210 | 211 | param = {"SEC": {"_": "H"}} 212 | Cp2kInput(param).render() 213 | assert param == {"SEC": {"_": "H"}} 214 | 215 | 216 | def test_invalid_lowercase_key(): 217 | inp = Cp2kInput({"foo": "bar"}) 218 | with pytest.raises(ValueError): 219 | inp.render() 220 | 221 | 222 | def test_invalid_preprocessor(): 223 | inp = Cp2kInput({"@SET": "bar"}) 224 | with pytest.raises(ValueError): 225 | inp.render() 226 | -------------------------------------------------------------------------------- /test/test_xyz.py: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Copyright (c), The AiiDA-CP2K authors. # 3 | # SPDX-License-Identifier: MIT # 4 | # AiiDA-CP2K is hosted on GitHub at https://github.com/aiidateam/aiida-cp2k # 5 | # For further information on the license, see the LICENSE.txt file. # 6 | ############################################################################### 7 | """Test writing structures to xyz format""" 8 | from ase import Atoms 9 | 10 | from aiida_cp2k.calculations import _atoms_to_xyz 11 | 12 | 13 | def test_atoms_to_xyz(): 14 | """Test that writing atoms to xyz format is handled correctly in the presence of tags""" 15 | h2o = Atoms("H2O") 16 | h2o[0].charge = -1 17 | h2o[0].tag = 1 18 | h2o[1].tag = 2 19 | 20 | xyz = _atoms_to_xyz(h2o) 21 | 22 | assert "H1" in xyz, xyz 23 | assert "H2" in xyz, xyz 24 | --------------------------------------------------------------------------------