pyiron-workflow-vasp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,231 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyiron_workflow_vasp
3
+ Version: 0.1.0
4
+ Summary: A VASP workflow integration package for pyiron
5
+ Author-email: pyiron Team <pyiron@mpie.de>
6
+ License: BSD-3-Clause
7
+ Project-URL: Homepage, https://github.com/pyiron/pyiron_workflow_vasp
8
+ Project-URL: Documentation, https://github.com/pyiron/pyiron_workflow_vasp
9
+ Project-URL: Repository, https://github.com/pyiron/pyiron_workflow_vasp.git
10
+ Project-URL: Bug Tracker, https://github.com/pyiron/pyiron_workflow_vasp/issues
11
+ Keywords: pyiron,vasp,workflow,dft,materials-science
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Topic :: Scientific/Engineering :: Physics
15
+ Classifier: License :: OSI Approved :: BSD License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Requires-Python: <3.13,>=3.10
21
+ Description-Content-Type: text/markdown
22
+ Requires-Dist: numpy<2.0.0,>=1.26.4
23
+ Requires-Dist: pandas<4.0.0,>=3.0.0
24
+ Requires-Dist: matplotlib<4.0.0,>=3.10.9
25
+ Requires-Dist: ase<4.0.0,>=3.27.0
26
+ Requires-Dist: scipy<2.0.0,>=1.17.0
27
+ Requires-Dist: pyiron-workflow==0.15.6
28
+ Requires-Dist: pyiron-workflow-atomistics==0.0.6
29
+ Requires-Dist: pyiron_vasp==0.2.19
30
+ Requires-Dist: pymatgen<2027.0.0,>=2026.5.4
31
+ Requires-Dist: pyiron_snippets<2.0.0,>=1.2.1
32
+ Requires-Dist: scikit-learn<2.0.0,>=1.8.0
33
+ Requires-Dist: tqdm<5.0.0,>=4.67.3
34
+ Provides-Extra: test
35
+ Requires-Dist: pytest>=6.0; extra == "test"
36
+ Requires-Dist: pytest-cov>=2.0; extra == "test"
37
+ Requires-Dist: nbformat; extra == "test"
38
+ Requires-Dist: nbclient; extra == "test"
39
+ Provides-Extra: dev
40
+ Requires-Dist: pytest>=6.0; extra == "dev"
41
+ Requires-Dist: pytest-cov>=2.0; extra == "dev"
42
+ Requires-Dist: black>=22.0; extra == "dev"
43
+ Requires-Dist: isort>=5.0; extra == "dev"
44
+ Requires-Dist: flake8>=4.0; extra == "dev"
45
+ Requires-Dist: ruff>=0.5; extra == "dev"
46
+ Provides-Extra: notebook
47
+ Requires-Dist: jupyter>=1.0.0; extra == "notebook"
48
+ Requires-Dist: notebook>=6.0.0; extra == "notebook"
49
+
50
+ # pyiron_workflow_vasp
51
+
52
+ A VASP workflow integration package for pyiron, providing tools and utilities for running and managing VASP calculations within the pyiron workflow framework.
53
+
54
+ ## Installation
55
+
56
+ The package can be installed using pip:
57
+
58
+ ```bash
59
+ # Basic installation
60
+ pip install pyiron_workflow_vasp
61
+
62
+ # Installation with development tools
63
+ pip install "pyiron_workflow_vasp[dev]"
64
+
65
+ # Installation with notebook support
66
+ pip install "pyiron_workflow_vasp[notebook]"
67
+
68
+ # Installation with all optional dependencies
69
+ pip install "pyiron_workflow_vasp[dev,notebook]"
70
+ ```
71
+
72
+ ## Dependencies
73
+
74
+ The package requires the following core dependencies:
75
+ - Python >= 3.8
76
+ - numpy >= 1.20.0
77
+ - pandas >= 1.3.0
78
+ - pymatgen >= 2023.0.0
79
+ - pyiron_workflow >= 0.1.0
80
+ - ase >= 3.22.0
81
+
82
+ ## Project Information
83
+
84
+ - **License**: BSD-3-Clause
85
+ - **Development Status**: Alpha
86
+ - **Documentation**: [GitHub Repository](https://github.com/pyiron/pyiron_workflow_vasp)
87
+ - **Bug Tracker**: [GitHub Issues](https://github.com/pyiron/pyiron_workflow_vasp/issues)
88
+
89
+ ## Usage
90
+
91
+ The package provides a set of tools for running VASP calculations within pyiron workflows. A minimal end-to-end example:
92
+
93
+ ```python
94
+ from ase.build import bulk
95
+ from pymatgen.io.vasp.inputs import Incar
96
+ from pyiron_workflow_vasp.vasp import VaspInput, vasp_job
97
+
98
+ structure = bulk("Fe", cubic=True, a=2.83)
99
+ incar = Incar.from_dict({
100
+ "ENCUT": 400,
101
+ "ISMEAR": 1,
102
+ "SIGMA": 0.1,
103
+ "ISPIN": 2,
104
+ "MAGMOM": "2*3.0",
105
+ })
106
+
107
+ # VaspInput bundles structure + INCAR (+ optional KPOINTS / explicit POTCARs).
108
+ # Without an explicit potcar_paths kwarg, POTCAR generation uses the
109
+ # pseudopotential library configured in ~/.pyiron_vasp_config.
110
+ vasp_input = VaspInput(structure=structure, incar=incar)
111
+
112
+ job = vasp_job(workdir="./bulk_fe_run", vasp_input=vasp_input)
113
+ job.run()
114
+
115
+ print("converged:", job.outputs.convergence_status.value)
116
+ print("E_pot: ", job.outputs.to_value_dict()["vasp_output"]["generic"]["energy_pot"])
117
+ ```
118
+
119
+ For more examples — including an equation-of-state scan and a queued cluster
120
+ run — see:
121
+
122
+ - [`examples/run_bulk_fe.py`](examples/run_bulk_fe.py) — a runnable script with no hardcoded cluster paths.
123
+ - [`example_notebooks/QuickStart.ipynb`](example_notebooks/QuickStart.ipynb) — the original walkthrough (uses MPIE cluster paths).
124
+ - [`.pyiron_vasp_config.example`](.pyiron_vasp_config.example) — annotated template for the config file.
125
+
126
+ ## VASP Configuration
127
+
128
+ The `.pyiron_vasp_config` file is essential for configuring the paths to the VASP pseudopotential files (POTCAR files) used in pyiron_workflow's VASP nodes. The file specifies the locations of different VASP potential sets and the default potential set to be used.
129
+
130
+ For detailed configuration instructions, see [generate_vasp_pyiron_config.md](generate_vasp_pyiron_config.md), which includes:
131
+ - Basic configuration setup
132
+ - Configuring custom pseudopotential sets
133
+ - Adding new pseudopotential variants to CSV files
134
+
135
+ ## 1. Determine the Locations of Your VASP POTCAR Files
136
+
137
+ Before creating the `.pyiron_vasp_config` file, ensure that you know the locations of the different POTCAR sets on your system. The common VASP potential directories are `potpaw_64`, `potpaw_54`, and `potpaw_52`, but your setup may vary. The directory structure should look something like this:
138
+
139
+ ```
140
+ /home/pyiron_resources_cmmc/vasp/potpaw_64/LDA
141
+ /home/pyiron_resources_cmmc/vasp/potpaw_64/GGA
142
+ /home/pyiron_resources_cmmc/vasp/potpaw_54/LDA
143
+ /home/pyiron_resources_cmmc/vasp/potpaw_54/GGA
144
+ /home/pyiron_resources_cmmc/vasp/potpaw_52/LDA
145
+ /home/pyiron_resources_cmmc/vasp/potpaw_52/GGA
146
+ ```
147
+
148
+ - **LDA** and **GGA** refer to the functional types for the VASP potentials.
149
+
150
+ ## 2. Create the .pyiron_vasp_config File
151
+
152
+ 1. Open a terminal and navigate to your home directory:
153
+
154
+ ```bash
155
+ cd ~
156
+ ```
157
+
158
+ 2. Use a text editor (such as `nano` or `vim`) to create and open the `.pyiron_vasp_config` file. For example:
159
+
160
+ ```bash
161
+ nano .pyiron_vasp_config
162
+ ```
163
+
164
+ 3. Add the following lines to the file. Make sure to modify the paths according to your setup.
165
+
166
+ ```ini
167
+ # Set the default POTCAR set
168
+ # Make sure that the default_POTCAR_set matches one of the suffixes in the vasp_POTCAR_path_*
169
+ default_POTCAR_set = potpaw64
170
+
171
+ # Path to the root directory containing the VASP pseudopotential files
172
+ pyiron_vasp_resources = /home/pyiron_resources_cmmc/vasp
173
+
174
+ # Path for different POTPAW versions (adjust these paths according to your setup)
175
+ vasp_POTCAR_path_potpaw64 = {pyiron_vasp_resources}/potpaw_64
176
+ vasp_POTCAR_path_potpaw54 = {pyiron_vasp_resources}/potpaw_54
177
+ vasp_POTCAR_path_potpaw52 = {pyiron_vasp_resources}/potpaw_52
178
+ # Note that pyiron vasp nodes can detect variants of vasp_POTCAR_path_{randomsuffix}
179
+ # So if you want to do something with custom pseudopotentials, you can...
180
+ # Each of these dirs must have a "GGA" and "LDA" subdirectory structure
181
+ # i.e.
182
+ # The structure should look like
183
+ # .../vasp/potpaw_64/LDA
184
+ # .../vasp/potpaw_64/GGA
185
+ # .../vasp/potpaw_54/LDA etc.
186
+ ```
187
+
188
+ 4. After you have added the configuration details, save the file:
189
+ - If you're using `nano`, press `Ctrl + O`, then `Enter` to save. Press `Ctrl + X` to exit.
190
+ - If you're using `vim`, press `Esc`, type `:wq`, and press `Enter` to save and exit.
191
+
192
+ ## 3. Verify File Permissions
193
+
194
+ Ensure that your `.pyiron_vasp_config` file and the POTCAR directories are readable by your user. Run the following command to check the file permissions of the `.pyiron_vasp_config`:
195
+
196
+ ```bash
197
+ ls -l ~/.pyiron_vasp_config
198
+ ```
199
+
200
+ If necessary, you can modify the permissions to ensure read access:
201
+
202
+ ```bash
203
+ chmod 644 ~/.pyiron_vasp_config
204
+ ```
205
+
206
+ Also, verify that you have read/copy access to the files inside the VASP resource directories (`potpaw_64`, `potpaw_54`, etc.):
207
+
208
+ ```bash
209
+ ls -l /home/pyiron_resources_cmmc/vasp/potpaw_64
210
+ ```
211
+
212
+ ## 4. Testing Your Configuration
213
+
214
+ To verify that pyiron is correctly reading the `.pyiron_vasp_config` file, you can either check within your pyiron scripts or write a simple Python script to test the configuration:
215
+
216
+ ```python
217
+ import os
218
+ from pathlib import Path
219
+
220
+ # Read the config file
221
+ config_file = Path.home().joinpath(".pyiron_vasp_config")
222
+ with open(config_file, "r") as f:
223
+ print(f.read())
224
+ ```
225
+
226
+ This should print out the contents of your `.pyiron_vasp_config`, and you can check if the paths are correctly generated.
227
+
228
+ ### Additional Notes:
229
+ - **Ensure Correct Paths**: Double-check that the paths to your POTCAR directories are correct. Incorrect paths will lead to pyiron not being able to find the necessary POTCAR files for your VASP calculations.
230
+
231
+ By following these instructions, you'll have a correctly configured `.pyiron_vasp_config` file that points to the appropriate VASP pseudopotential directories.
@@ -0,0 +1,182 @@
1
+ # pyiron_workflow_vasp
2
+
3
+ A VASP workflow integration package for pyiron, providing tools and utilities for running and managing VASP calculations within the pyiron workflow framework.
4
+
5
+ ## Installation
6
+
7
+ The package can be installed using pip:
8
+
9
+ ```bash
10
+ # Basic installation
11
+ pip install pyiron_workflow_vasp
12
+
13
+ # Installation with development tools
14
+ pip install "pyiron_workflow_vasp[dev]"
15
+
16
+ # Installation with notebook support
17
+ pip install "pyiron_workflow_vasp[notebook]"
18
+
19
+ # Installation with all optional dependencies
20
+ pip install "pyiron_workflow_vasp[dev,notebook]"
21
+ ```
22
+
23
+ ## Dependencies
24
+
25
+ The package requires the following core dependencies:
26
+ - Python >= 3.8
27
+ - numpy >= 1.20.0
28
+ - pandas >= 1.3.0
29
+ - pymatgen >= 2023.0.0
30
+ - pyiron_workflow >= 0.1.0
31
+ - ase >= 3.22.0
32
+
33
+ ## Project Information
34
+
35
+ - **License**: BSD-3-Clause
36
+ - **Development Status**: Alpha
37
+ - **Documentation**: [GitHub Repository](https://github.com/pyiron/pyiron_workflow_vasp)
38
+ - **Bug Tracker**: [GitHub Issues](https://github.com/pyiron/pyiron_workflow_vasp/issues)
39
+
40
+ ## Usage
41
+
42
+ The package provides a set of tools for running VASP calculations within pyiron workflows. A minimal end-to-end example:
43
+
44
+ ```python
45
+ from ase.build import bulk
46
+ from pymatgen.io.vasp.inputs import Incar
47
+ from pyiron_workflow_vasp.vasp import VaspInput, vasp_job
48
+
49
+ structure = bulk("Fe", cubic=True, a=2.83)
50
+ incar = Incar.from_dict({
51
+ "ENCUT": 400,
52
+ "ISMEAR": 1,
53
+ "SIGMA": 0.1,
54
+ "ISPIN": 2,
55
+ "MAGMOM": "2*3.0",
56
+ })
57
+
58
+ # VaspInput bundles structure + INCAR (+ optional KPOINTS / explicit POTCARs).
59
+ # Without an explicit potcar_paths kwarg, POTCAR generation uses the
60
+ # pseudopotential library configured in ~/.pyiron_vasp_config.
61
+ vasp_input = VaspInput(structure=structure, incar=incar)
62
+
63
+ job = vasp_job(workdir="./bulk_fe_run", vasp_input=vasp_input)
64
+ job.run()
65
+
66
+ print("converged:", job.outputs.convergence_status.value)
67
+ print("E_pot: ", job.outputs.to_value_dict()["vasp_output"]["generic"]["energy_pot"])
68
+ ```
69
+
70
+ For more examples — including an equation-of-state scan and a queued cluster
71
+ run — see:
72
+
73
+ - [`examples/run_bulk_fe.py`](examples/run_bulk_fe.py) — a runnable script with no hardcoded cluster paths.
74
+ - [`example_notebooks/QuickStart.ipynb`](example_notebooks/QuickStart.ipynb) — the original walkthrough (uses MPIE cluster paths).
75
+ - [`.pyiron_vasp_config.example`](.pyiron_vasp_config.example) — annotated template for the config file.
76
+
77
+ ## VASP Configuration
78
+
79
+ The `.pyiron_vasp_config` file is essential for configuring the paths to the VASP pseudopotential files (POTCAR files) used in pyiron_workflow's VASP nodes. The file specifies the locations of different VASP potential sets and the default potential set to be used.
80
+
81
+ For detailed configuration instructions, see [generate_vasp_pyiron_config.md](generate_vasp_pyiron_config.md), which includes:
82
+ - Basic configuration setup
83
+ - Configuring custom pseudopotential sets
84
+ - Adding new pseudopotential variants to CSV files
85
+
86
+ ## 1. Determine the Locations of Your VASP POTCAR Files
87
+
88
+ Before creating the `.pyiron_vasp_config` file, ensure that you know the locations of the different POTCAR sets on your system. The common VASP potential directories are `potpaw_64`, `potpaw_54`, and `potpaw_52`, but your setup may vary. The directory structure should look something like this:
89
+
90
+ ```
91
+ /home/pyiron_resources_cmmc/vasp/potpaw_64/LDA
92
+ /home/pyiron_resources_cmmc/vasp/potpaw_64/GGA
93
+ /home/pyiron_resources_cmmc/vasp/potpaw_54/LDA
94
+ /home/pyiron_resources_cmmc/vasp/potpaw_54/GGA
95
+ /home/pyiron_resources_cmmc/vasp/potpaw_52/LDA
96
+ /home/pyiron_resources_cmmc/vasp/potpaw_52/GGA
97
+ ```
98
+
99
+ - **LDA** and **GGA** refer to the functional types for the VASP potentials.
100
+
101
+ ## 2. Create the .pyiron_vasp_config File
102
+
103
+ 1. Open a terminal and navigate to your home directory:
104
+
105
+ ```bash
106
+ cd ~
107
+ ```
108
+
109
+ 2. Use a text editor (such as `nano` or `vim`) to create and open the `.pyiron_vasp_config` file. For example:
110
+
111
+ ```bash
112
+ nano .pyiron_vasp_config
113
+ ```
114
+
115
+ 3. Add the following lines to the file. Make sure to modify the paths according to your setup.
116
+
117
+ ```ini
118
+ # Set the default POTCAR set
119
+ # Make sure that the default_POTCAR_set matches one of the suffixes in the vasp_POTCAR_path_*
120
+ default_POTCAR_set = potpaw64
121
+
122
+ # Path to the root directory containing the VASP pseudopotential files
123
+ pyiron_vasp_resources = /home/pyiron_resources_cmmc/vasp
124
+
125
+ # Path for different POTPAW versions (adjust these paths according to your setup)
126
+ vasp_POTCAR_path_potpaw64 = {pyiron_vasp_resources}/potpaw_64
127
+ vasp_POTCAR_path_potpaw54 = {pyiron_vasp_resources}/potpaw_54
128
+ vasp_POTCAR_path_potpaw52 = {pyiron_vasp_resources}/potpaw_52
129
+ # Note that pyiron vasp nodes can detect variants of vasp_POTCAR_path_{randomsuffix}
130
+ # So if you want to do something with custom pseudopotentials, you can...
131
+ # Each of these dirs must have a "GGA" and "LDA" subdirectory structure
132
+ # i.e.
133
+ # The structure should look like
134
+ # .../vasp/potpaw_64/LDA
135
+ # .../vasp/potpaw_64/GGA
136
+ # .../vasp/potpaw_54/LDA etc.
137
+ ```
138
+
139
+ 4. After you have added the configuration details, save the file:
140
+ - If you're using `nano`, press `Ctrl + O`, then `Enter` to save. Press `Ctrl + X` to exit.
141
+ - If you're using `vim`, press `Esc`, type `:wq`, and press `Enter` to save and exit.
142
+
143
+ ## 3. Verify File Permissions
144
+
145
+ Ensure that your `.pyiron_vasp_config` file and the POTCAR directories are readable by your user. Run the following command to check the file permissions of the `.pyiron_vasp_config`:
146
+
147
+ ```bash
148
+ ls -l ~/.pyiron_vasp_config
149
+ ```
150
+
151
+ If necessary, you can modify the permissions to ensure read access:
152
+
153
+ ```bash
154
+ chmod 644 ~/.pyiron_vasp_config
155
+ ```
156
+
157
+ Also, verify that you have read/copy access to the files inside the VASP resource directories (`potpaw_64`, `potpaw_54`, etc.):
158
+
159
+ ```bash
160
+ ls -l /home/pyiron_resources_cmmc/vasp/potpaw_64
161
+ ```
162
+
163
+ ## 4. Testing Your Configuration
164
+
165
+ To verify that pyiron is correctly reading the `.pyiron_vasp_config` file, you can either check within your pyiron scripts or write a simple Python script to test the configuration:
166
+
167
+ ```python
168
+ import os
169
+ from pathlib import Path
170
+
171
+ # Read the config file
172
+ config_file = Path.home().joinpath(".pyiron_vasp_config")
173
+ with open(config_file, "r") as f:
174
+ print(f.read())
175
+ ```
176
+
177
+ This should print out the contents of your `.pyiron_vasp_config`, and you can check if the paths are correctly generated.
178
+
179
+ ### Additional Notes:
180
+ - **Ensure Correct Paths**: Double-check that the paths to your POTCAR directories are correct. Incorrect paths will lead to pyiron not being able to find the necessary POTCAR files for your VASP calculations.
181
+
182
+ By following these instructions, you'll have a correctly configured `.pyiron_vasp_config` file that points to the appropriate VASP pseudopotential directories.
@@ -0,0 +1,19 @@
1
+ """pyiron_workflow_vasp - VASP integration for the pyiron workflow system.
2
+
3
+ Public API:
4
+ VaspEngine - satisfies pyiron_workflow_atomistics.engine.Engine
5
+ for Static + Minimize modes; wraps the helpers in
6
+ vasp.py and vasp_parser/output.py.
7
+
8
+ Plus the existing standalone helper functions in vasp and generic
9
+ (re-exported via wildcard for backwards compatibility with the 0.0.x
10
+ script-style API).
11
+ """
12
+
13
+ from ._version import get_versions
14
+ from .engine import VaspEngine
15
+ from .generic import * # noqa: F401,F403 -- legacy helpers
16
+ from .vasp import * # noqa: F401,F403 -- legacy helpers
17
+
18
+ __version__ = get_versions()["version"]
19
+ __all__ = ["VaspEngine"]
@@ -0,0 +1,202 @@
1
+ """Internal: assemble VASP inputs, run the binary, parse -> EngineOutput.
2
+
3
+ Not part of the public API - callers should go through
4
+ ``VaspEngine.get_calculate_fn`` which returns this function as its
5
+ callable. The kwargs surface mirrors the keys VaspEngine bakes into
6
+ the return tuple.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import os
12
+ from pathlib import Path
13
+ from typing import Any
14
+
15
+ from ase import Atoms
16
+ from pyiron_workflow_atomistics.engine import (
17
+ CalcInputMinimize,
18
+ CalcInputStatic,
19
+ EngineOutput,
20
+ )
21
+
22
+
23
+ def run_vasp(
24
+ structure: Atoms,
25
+ working_directory: str,
26
+ engine_input: CalcInputStatic | CalcInputMinimize,
27
+ potcar_config_file: Path | None,
28
+ functional: str,
29
+ encut: float,
30
+ kpoints_density: float,
31
+ command: str,
32
+ mode: str,
33
+ ) -> EngineOutput:
34
+ """Run a VASP single-point or relaxation and return an EngineOutput.
35
+
36
+ Workflow:
37
+ 1. mkdir working_directory
38
+ 2. write POSCAR (via ASE)
39
+ 3. write INCAR (built from engine_input + mode + encut)
40
+ 4. write KPOINTS (built from kpoints_density)
41
+ 5. write POTCAR (via potcar_config_file)
42
+ 6. shell out to `command`
43
+ 7. parse via pyiron_vasp.vasp.output.parse_vasp_output
44
+ 8. map parsed dict -> EngineOutput
45
+ """
46
+ from pyiron_vasp.vasp.output import parse_vasp_output
47
+
48
+ from pyiron_workflow_vasp.generic import shell
49
+ from pyiron_workflow_vasp.vasp import (
50
+ VaspInput,
51
+ get_default_POTCAR_paths,
52
+ read_potcar_config,
53
+ write_INCAR,
54
+ write_KPOINTS,
55
+ write_POSCAR,
56
+ write_POTCAR,
57
+ )
58
+
59
+ os.makedirs(working_directory, exist_ok=True)
60
+
61
+ # 1. POSCAR (via the existing helper - ASE-Atoms-aware)
62
+ write_POSCAR(workdir=working_directory, structure=structure)
63
+
64
+ # 2. INCAR - build dict from engine_input + mode, hand to pymatgen Incar
65
+ incar = _build_incar(engine_input=engine_input, mode=mode, encut=encut)
66
+ write_INCAR(workdir=working_directory, incar=incar)
67
+
68
+ # 3. KPOINTS - automatic density via pymatgen Kpoints
69
+ kpoints = _build_kpoints(structure=structure, kpoints_density=kpoints_density)
70
+ write_KPOINTS(workdir=working_directory, kpoints=kpoints)
71
+
72
+ # 4. POTCAR - resolve via potcar_config_file
73
+ if potcar_config_file is not None:
74
+ config = read_potcar_config(potcar_config_file)
75
+ pseudopot_lib_path = config["default_POTCAR_library_path"]
76
+ else:
77
+ pseudopot_lib_path = None
78
+
79
+ potcar_paths = get_default_POTCAR_paths(
80
+ structure=structure,
81
+ pseudopot_lib_path=pseudopot_lib_path,
82
+ pseudopot_functional=functional,
83
+ )
84
+ vasp_input = VaspInput(
85
+ structure=structure,
86
+ potcar_paths=potcar_paths,
87
+ pseudopot_lib_path=pseudopot_lib_path,
88
+ pseudopot_functional=functional,
89
+ )
90
+ write_POTCAR(workdir=working_directory, vasp_input=vasp_input)
91
+
92
+ # 5. Run the binary - shell is a pyiron_workflow Node; use the raw callable
93
+ shell.node_function(command=command, workdir=working_directory)
94
+
95
+ # 6. Parse the output
96
+ parsed = parse_vasp_output(working_directory=working_directory)
97
+
98
+ # 7. Map -> EngineOutput
99
+ return _to_engine_output(parsed=parsed)
100
+
101
+
102
+ def _build_incar(
103
+ engine_input: CalcInputStatic | CalcInputMinimize,
104
+ mode: str,
105
+ encut: float,
106
+ ):
107
+ """Build a pymatgen Incar from the engine_input + mode + encut."""
108
+ from pymatgen.io.vasp.inputs import Incar
109
+
110
+ params: dict[str, Any] = {
111
+ "ENCUT": encut,
112
+ "PREC": "Accurate",
113
+ "EDIFF": 1e-5,
114
+ "ISMEAR": 0,
115
+ "SIGMA": 0.05,
116
+ "LREAL": "Auto",
117
+ }
118
+
119
+ if mode == "static":
120
+ params["NSW"] = 0
121
+ params["IBRION"] = -1
122
+ elif mode == "minimize":
123
+ assert isinstance(engine_input, CalcInputMinimize)
124
+ params["NSW"] = engine_input.max_iterations
125
+ params["IBRION"] = 2 # conjugate gradient
126
+ params["EDIFFG"] = -abs(engine_input.force_convergence_tolerance)
127
+ params["ISIF"] = 3 if engine_input.relax_cell else 2
128
+ if engine_input.energy_convergence_tolerance is not None:
129
+ params["EDIFF"] = engine_input.energy_convergence_tolerance
130
+ else:
131
+ raise ValueError(f"Unknown mode {mode!r}")
132
+
133
+ return Incar.from_dict(params)
134
+
135
+
136
+ def _build_kpoints(structure: Atoms, kpoints_density: float):
137
+ """Build a pymatgen Kpoints using automatic density (A^-1)."""
138
+ from pymatgen.io.ase import AseAtomsAdaptor
139
+ from pymatgen.io.vasp.inputs import Kpoints
140
+
141
+ pmg_structure = AseAtomsAdaptor.get_structure(structure)
142
+ return Kpoints.automatic_density(
143
+ structure=pmg_structure,
144
+ kppa=int(1000 / max(kpoints_density, 0.01)), # rough density mapping
145
+ )
146
+
147
+
148
+ def _to_engine_output(parsed: dict) -> EngineOutput:
149
+ """Map the pyiron_vasp parse_vasp_output return dict to EngineOutput.
150
+
151
+ The parse_vasp_output result is structured as
152
+ {"generic": {"energy_tot": [...], "positions": [...], "cells": [...],
153
+ "forces": [...], "stresses": [...], ...},
154
+ "converged": bool, ...}
155
+ Specific keys depend on pyiron_vasp version - adapt here.
156
+ """
157
+ from ase import Atoms as ASEAtoms
158
+
159
+ generic = parsed.get("generic", parsed)
160
+
161
+ # Trajectory
162
+ energies = list(generic.get("energy_pot", generic.get("energy_tot", [])))
163
+ forces_traj = list(generic.get("forces", []))
164
+ stresses_traj = list(generic.get("stresses", generic.get("pressures", [])))
165
+
166
+ # Reconstruct trajectory structures if cell/positions are present
167
+ structures_traj: list = []
168
+ cells = generic.get("cells")
169
+ positions = generic.get("positions")
170
+ indices = generic.get("indices")
171
+ if cells is not None and positions is not None and indices is not None:
172
+ species = parsed.get("species") or parsed.get("species_list")
173
+ for c, p, idx in zip(cells, positions, indices):
174
+ if species is None:
175
+ # Best effort: fall back to atom symbols from initial structure
176
+ continue
177
+ symbols = [species[i] for i in idx]
178
+ structures_traj.append(
179
+ ASEAtoms(symbols=symbols, positions=p, cell=c, pbc=True)
180
+ )
181
+
182
+ final_structure = (
183
+ structures_traj[-1] if structures_traj else parsed.get("final_structure")
184
+ )
185
+ final_energy = energies[-1] if energies else parsed.get("final_total_energy")
186
+ converged = bool(parsed.get("converged", False))
187
+
188
+ return EngineOutput(
189
+ final_structure=final_structure,
190
+ final_energy=final_energy,
191
+ converged=converged,
192
+ final_forces=forces_traj[-1] if forces_traj else None,
193
+ final_stress=stresses_traj[-1] if stresses_traj else None,
194
+ final_volume=(
195
+ final_structure.get_volume() if final_structure is not None else None
196
+ ),
197
+ energies=energies or None,
198
+ forces=forces_traj or None,
199
+ stresses=stresses_traj or None,
200
+ structures=structures_traj or None,
201
+ n_ionic_steps=len(energies) if energies else None,
202
+ )
@@ -0,0 +1,21 @@
1
+
2
+ # This file was generated by 'versioneer.py' (0.29) from
3
+ # revision-control system data, or from the parent directory name of an
4
+ # unpacked source archive. Distribution tarballs contain a pre-generated copy
5
+ # of this file.
6
+
7
+ import json
8
+
9
+ version_json = '''
10
+ {
11
+ "date": "2026-05-13T01:47:14+0200",
12
+ "dirty": true,
13
+ "error": null,
14
+ "full-revisionid": "b5ee3cfb986b43d9a19f5fe54e30dc867c5a2ae8",
15
+ "version": "0.1.0"
16
+ }
17
+ ''' # END VERSION_JSON
18
+
19
+
20
+ def get_versions():
21
+ return json.loads(version_json)