atomistics 0.2.1__tar.gz → 0.2.2__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.
- {atomistics-0.2.1/atomistics.egg-info → atomistics-0.2.2}/PKG-INFO +5 -3
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/_version.py +3 -3
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/calculators/sphinxdft.py +77 -18
- atomistics-0.2.2/atomistics/calculators/vasp.py +219 -0
- {atomistics-0.2.1 → atomistics-0.2.2/atomistics.egg-info}/PKG-INFO +5 -3
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics.egg-info/SOURCES.txt +3 -1
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics.egg-info/requires.txt +5 -2
- {atomistics-0.2.1 → atomistics-0.2.2}/pyproject.toml +5 -2
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_evcurve_eos.py +71 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_evcurve_sphinxdft.py +6 -6
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_phonons_ase_emt.py +20 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_phonons_lammpsfile.py +20 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_phonons_lammpslib.py +20 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_sphinx_parser.py +58 -20
- atomistics-0.2.2/tests/test_vasp_parser.py +68 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/LICENSE +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/MANIFEST.in +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/README.md +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/__init__.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/calculators/__init__.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/calculators/ase.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/calculators/hessian.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/calculators/interface.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/calculators/lammps/__init__.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/calculators/lammps/commands.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/calculators/lammps/filecalculator.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/calculators/lammps/helpers.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/calculators/lammps/libcalculator.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/calculators/lammps/phonon.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/calculators/lammps/potential.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/calculators/qe.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/calculators/wrapper.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/referencedata/__init__.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/referencedata/mendeleev.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/referencedata/wikipedia.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/referencedata/wolframalpha.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/shared/__init__.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/shared/output.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/shared/parallel.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/shared/thermal_expansion.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/shared/tqdm_iterator.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/__init__.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/elastic/__init__.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/elastic/elastic_moduli.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/elastic/helper.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/elastic/symmetry.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/elastic/workflow.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/evcurve/__init__.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/evcurve/debye.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/evcurve/fit.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/evcurve/helper.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/evcurve/thermo.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/evcurve/workflow.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/interface.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/langevin.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/molecular_dynamics.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/phonons/__init__.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/phonons/helper.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/phonons/units.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/phonons/workflow.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/quasiharmonic.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics/workflows/structure_optimization.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics.egg-info/dependency_links.txt +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/atomistics.egg-info/top_level.txt +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/setup.cfg +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/setup.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_abstract_workflow_class.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_ase_md_emt.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_calc_stress_ase_emt.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_calc_stress_lammpslib.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_elastic_ase_emt.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_elastic_helper.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_elastic_lammpslib.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_elastic_lammpslib_functional.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_evcurve_ase_emt.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_evcurve_ase_lammps.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_evcurve_lammpsfile.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_evcurve_lammpslib.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_evcurve_lammpslib_function_parallel.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_evcurve_lammpslib_functional.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_evcurve_qe.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_hessian_lammpslib.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_lammps_calculator.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_lammpslib_md.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_lammpslib_md_phonons.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_langevin_lammpslib.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_molecular_dynamics_thermal_expansion_lammpslib.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_optimize_positions_ase_emt.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_optimize_positions_lammpsfile.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_optimize_positions_lammpslib.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_phonons_lammpslib_functional.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_quasiharmonic_ase_emt.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_quasiharmonic_lammpslib.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_quasiharmonic_lammpslib_functional.py +0 -0
- {atomistics-0.2.1 → atomistics-0.2.2}/tests/test_referencedata.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: atomistics
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Interfaces for atomistic simulation codes and workflows
|
|
5
5
|
Author-email: Jan Janssen <janssen@mpie.de>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -53,7 +53,7 @@ Requires-Dist: numpy==1.26.4
|
|
|
53
53
|
Requires-Dist: scipy<=1.15.2,>=1.11.1
|
|
54
54
|
Requires-Dist: spglib<=2.5.0,>=2.0.2
|
|
55
55
|
Provides-Extra: phonopy
|
|
56
|
-
Requires-Dist: phonopy<=2.
|
|
56
|
+
Requires-Dist: phonopy<=2.38.0,>=2.20.0; extra == "phonopy"
|
|
57
57
|
Requires-Dist: seekpath<=2.1.0,>=1.9.0; extra == "phonopy"
|
|
58
58
|
Requires-Dist: structuretoolkit<=0.0.31,>=0.0.10; extra == "phonopy"
|
|
59
59
|
Provides-Extra: gpaw
|
|
@@ -77,9 +77,11 @@ Requires-Dist: requests<=2.32.3,>=2.24.0; extra == "experimental"
|
|
|
77
77
|
Provides-Extra: sphinxdft
|
|
78
78
|
Requires-Dist: sphinx-parser==0.0.1; extra == "sphinxdft"
|
|
79
79
|
Provides-Extra: qe
|
|
80
|
-
Requires-Dist: pwtools==1.
|
|
80
|
+
Requires-Dist: pwtools==1.3.0; extra == "qe"
|
|
81
81
|
Provides-Extra: tqdm
|
|
82
82
|
Requires-Dist: tqdm==4.67.1; extra == "tqdm"
|
|
83
|
+
Provides-Extra: vasp
|
|
84
|
+
Requires-Dist: pyiron_vasp==0.2.4; extra == "vasp"
|
|
83
85
|
|
|
84
86
|
# atomistics
|
|
85
87
|
[](https://github.com/pyiron/atomistics/actions/workflows/pipeline.yml)
|
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2025-
|
|
11
|
+
"date": "2025-03-05T08:13:01+0100",
|
|
12
12
|
"dirty": true,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "0.2.
|
|
14
|
+
"full-revisionid": "5b518f33f60f904bf2c88dff51b72a07fe99091c",
|
|
15
|
+
"version": "0.2.2"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -5,6 +5,7 @@ import scipy.constants
|
|
|
5
5
|
from ase.atoms import Atoms
|
|
6
6
|
from sphinx_parser.ase import get_structure_group, id_spx_to_ase
|
|
7
7
|
from sphinx_parser.input import sphinx
|
|
8
|
+
from sphinx_parser.jobs import apply_minimization
|
|
8
9
|
from sphinx_parser.output import collect_energy_dat, collect_eval_forces
|
|
9
10
|
from sphinx_parser.potential import get_paw_from_structure
|
|
10
11
|
from sphinx_parser.toolkit import to_sphinx
|
|
@@ -20,11 +21,10 @@ HARTREE_TO_EV = scipy.constants.physical_constants["Hartree energy in eV"][0]
|
|
|
20
21
|
HARTREE_OVER_BOHR_TO_EV_OVER_ANGSTROM = HARTREE_TO_EV / BOHR_TO_ANGSTROM
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
def
|
|
24
|
+
def _generate_input(
|
|
24
25
|
structure: Atoms,
|
|
25
|
-
working_directory: str,
|
|
26
26
|
maxSteps: int = 100,
|
|
27
|
-
|
|
27
|
+
energy_cutoff_in_eV: float = 500.0,
|
|
28
28
|
kpoint_coords: Optional[list[float, float, float]] = None,
|
|
29
29
|
kpoint_folding: Optional[list[int, int, int]] = None,
|
|
30
30
|
):
|
|
@@ -39,7 +39,7 @@ def _write_input(
|
|
|
39
39
|
)
|
|
40
40
|
pawPot_group = get_paw_from_structure(structure)
|
|
41
41
|
basis_group = sphinx.basis.create(
|
|
42
|
-
eCut=
|
|
42
|
+
eCut=energy_cutoff_in_eV / HARTREE_TO_EV,
|
|
43
43
|
kPoint=sphinx.basis.kPoint.create(coords=kpoint_coords),
|
|
44
44
|
folding=kpoint_folding,
|
|
45
45
|
)
|
|
@@ -50,7 +50,7 @@ def _write_input(
|
|
|
50
50
|
),
|
|
51
51
|
rho=sphinx.initialGuess.rho.create(atomicOrbitals=True),
|
|
52
52
|
)
|
|
53
|
-
|
|
53
|
+
return sphinx.create(
|
|
54
54
|
pawPot=pawPot_group,
|
|
55
55
|
structure=struct_group,
|
|
56
56
|
main=main_group,
|
|
@@ -58,8 +58,6 @@ def _write_input(
|
|
|
58
58
|
PAWHamiltonian=paw_group,
|
|
59
59
|
initialGuess=initial_guess_group,
|
|
60
60
|
)
|
|
61
|
-
with open(os.path.join(working_directory, "input.sx"), "w") as f:
|
|
62
|
-
f.write(to_sphinx(input_sx))
|
|
63
61
|
|
|
64
62
|
|
|
65
63
|
class OutputParser:
|
|
@@ -90,12 +88,54 @@ class OutputParser:
|
|
|
90
88
|
raise NotImplementedError()
|
|
91
89
|
|
|
92
90
|
|
|
91
|
+
def optimize_positions_with_sphinxdft(
|
|
92
|
+
structure: Atoms,
|
|
93
|
+
working_directory: str,
|
|
94
|
+
executable_function: callable,
|
|
95
|
+
max_electronic_steps: int = 100,
|
|
96
|
+
energy_cutoff_in_eV: float = 500.0,
|
|
97
|
+
mode: str = "linQN",
|
|
98
|
+
dEnergy: float = 1.0e-6,
|
|
99
|
+
max_ionic_steps: int = 50,
|
|
100
|
+
kpoint_coords: Optional[list[float, float, float]] = None,
|
|
101
|
+
kpoint_folding: Optional[list[int, int, int]] = None,
|
|
102
|
+
) -> Atoms:
|
|
103
|
+
if kpoint_coords is None:
|
|
104
|
+
kpoint_coords = [0.5, 0.5, 0.5]
|
|
105
|
+
if kpoint_folding is None:
|
|
106
|
+
kpoint_folding = [3, 3, 3]
|
|
107
|
+
input_sx = _generate_input(
|
|
108
|
+
structure=structure,
|
|
109
|
+
maxSteps=max_electronic_steps,
|
|
110
|
+
energy_cutoff_in_eV=energy_cutoff_in_eV,
|
|
111
|
+
kpoint_coords=kpoint_coords,
|
|
112
|
+
kpoint_folding=kpoint_folding,
|
|
113
|
+
)
|
|
114
|
+
input_sx = apply_minimization(
|
|
115
|
+
sphinx_input=input_sx,
|
|
116
|
+
mode=mode,
|
|
117
|
+
dEnergy=dEnergy,
|
|
118
|
+
maxSteps=max_ionic_steps,
|
|
119
|
+
)
|
|
120
|
+
with open(os.path.join(working_directory, "input.sx"), "w") as f:
|
|
121
|
+
f.write(to_sphinx(input_sx))
|
|
122
|
+
executable_function(working_directory)
|
|
123
|
+
structure_copy = structure.copy()
|
|
124
|
+
structure_copy.positions = (
|
|
125
|
+
collect_eval_forces(os.path.join(working_directory, "relaxHist.sx"))[
|
|
126
|
+
"positions"
|
|
127
|
+
][-1][id_spx_to_ase(structure)]
|
|
128
|
+
/ BOHR_TO_ANGSTROM
|
|
129
|
+
)
|
|
130
|
+
return structure_copy
|
|
131
|
+
|
|
132
|
+
|
|
93
133
|
def calc_static_with_sphinxdft(
|
|
94
134
|
structure: Atoms,
|
|
95
135
|
working_directory: str,
|
|
96
136
|
executable_function: callable,
|
|
97
|
-
|
|
98
|
-
|
|
137
|
+
max_electronic_steps: int = 100,
|
|
138
|
+
energy_cutoff_in_eV: float = 500.0,
|
|
99
139
|
kpoint_coords: Optional[list[float, float, float]] = None,
|
|
100
140
|
kpoint_folding: Optional[list[int, int, int]] = None,
|
|
101
141
|
output_keys=OutputStatic.keys(),
|
|
@@ -104,14 +144,15 @@ def calc_static_with_sphinxdft(
|
|
|
104
144
|
kpoint_coords = [0.5, 0.5, 0.5]
|
|
105
145
|
if kpoint_folding is None:
|
|
106
146
|
kpoint_folding = [3, 3, 3]
|
|
107
|
-
|
|
147
|
+
input_sx = _generate_input(
|
|
108
148
|
structure=structure,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
eCut=eCut,
|
|
149
|
+
maxSteps=max_electronic_steps,
|
|
150
|
+
energy_cutoff_in_eV=energy_cutoff_in_eV,
|
|
112
151
|
kpoint_coords=kpoint_coords,
|
|
113
152
|
kpoint_folding=kpoint_folding,
|
|
114
153
|
)
|
|
154
|
+
with open(os.path.join(working_directory, "input.sx"), "w") as f:
|
|
155
|
+
f.write(to_sphinx(input_sx))
|
|
115
156
|
executable_function(working_directory)
|
|
116
157
|
output_obj = OutputParser(working_directory=working_directory, structure=structure)
|
|
117
158
|
result_dict = OutputStatic(
|
|
@@ -129,20 +170,37 @@ def evaluate_with_sphinx(
|
|
|
129
170
|
tasks: list,
|
|
130
171
|
working_directory: str,
|
|
131
172
|
executable_function: callable,
|
|
132
|
-
|
|
133
|
-
|
|
173
|
+
max_electronic_steps: int = 100,
|
|
174
|
+
energy_cutoff_in_eV: float = 500,
|
|
134
175
|
kpoint_coords: Optional[list[float, float, float]] = None,
|
|
135
176
|
kpoint_folding: Optional[list[int, int, int]] = None,
|
|
177
|
+
sphinx_optimizer_kwargs: Optional[dict] = None,
|
|
136
178
|
) -> dict:
|
|
137
179
|
if kpoint_coords is None:
|
|
138
180
|
kpoint_coords = [0.5, 0.5, 0.5]
|
|
139
181
|
if kpoint_folding is None:
|
|
140
182
|
kpoint_folding = [3, 3, 3]
|
|
141
|
-
if
|
|
183
|
+
if sphinx_optimizer_kwargs is None:
|
|
184
|
+
sphinx_optimizer_kwargs = {}
|
|
185
|
+
results = {}
|
|
186
|
+
if "optimize_positions" in tasks:
|
|
187
|
+
results["structure_with_optimized_positions"] = (
|
|
188
|
+
optimize_positions_with_sphinxdft(
|
|
189
|
+
structure=structure,
|
|
190
|
+
max_electronic_steps=max_electronic_steps,
|
|
191
|
+
energy_cutoff_in_eV=energy_cutoff_in_eV,
|
|
192
|
+
kpoint_coords=kpoint_coords,
|
|
193
|
+
kpoint_folding=kpoint_folding,
|
|
194
|
+
working_directory=working_directory,
|
|
195
|
+
executable_function=executable_function,
|
|
196
|
+
**sphinx_optimizer_kwargs,
|
|
197
|
+
)
|
|
198
|
+
)
|
|
199
|
+
elif "calc_energy" in tasks or "calc_forces" in tasks or "calc_stress" in tasks:
|
|
142
200
|
return calc_static_with_sphinxdft(
|
|
143
201
|
structure=structure,
|
|
144
|
-
|
|
145
|
-
|
|
202
|
+
max_electronic_steps=max_electronic_steps,
|
|
203
|
+
energy_cutoff_in_eV=energy_cutoff_in_eV,
|
|
146
204
|
kpoint_coords=kpoint_coords,
|
|
147
205
|
kpoint_folding=kpoint_folding,
|
|
148
206
|
working_directory=working_directory,
|
|
@@ -151,3 +209,4 @@ def evaluate_with_sphinx(
|
|
|
151
209
|
)
|
|
152
210
|
else:
|
|
153
211
|
raise ValueError("The SphinxDFT calculator does not implement:", tasks)
|
|
212
|
+
return results
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from ase.atoms import Atoms
|
|
5
|
+
from ase.calculators.vasp.create_input import GenerateVaspInput
|
|
6
|
+
from pyiron_vasp.vasp.output import parse_vasp_output
|
|
7
|
+
|
|
8
|
+
from atomistics.calculators.interface import get_quantities_from_tasks
|
|
9
|
+
from atomistics.calculators.wrapper import as_task_dict_evaluator
|
|
10
|
+
from atomistics.shared.output import OutputStatic
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class OutputParser:
|
|
14
|
+
def __init__(self, working_directory, structure):
|
|
15
|
+
self._output_dict = parse_vasp_output(
|
|
16
|
+
working_directory=working_directory, structure=structure
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
def get_energy(self):
|
|
20
|
+
return self._output_dict["generic"]["energy_tot"][-1]
|
|
21
|
+
|
|
22
|
+
def get_forces(self):
|
|
23
|
+
return self._output_dict["generic"]["forces"][-1]
|
|
24
|
+
|
|
25
|
+
def get_volume(self):
|
|
26
|
+
return self._output_dict["generic"]["volume"][-1]
|
|
27
|
+
|
|
28
|
+
def get_stress(self):
|
|
29
|
+
return self._output_dict["generic"]["stresses"][-1]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def write_input(working_directory, atoms, **kwargs):
|
|
33
|
+
vip = GenerateVaspInput()
|
|
34
|
+
vip.set(**kwargs)
|
|
35
|
+
vip.initialize(atoms=atoms)
|
|
36
|
+
os.makedirs(working_directory, exist_ok=True)
|
|
37
|
+
vip.write_input(atoms=atoms, directory=working_directory)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def calc_static_with_vasp(
|
|
41
|
+
structure: Atoms,
|
|
42
|
+
working_directory: str,
|
|
43
|
+
executable_function: callable,
|
|
44
|
+
prec: str = "Accurate",
|
|
45
|
+
algo: str = "Fast",
|
|
46
|
+
lreal: bool = False,
|
|
47
|
+
lwave: bool = False,
|
|
48
|
+
lorbit: int = 0,
|
|
49
|
+
kpts: Optional[list[int, int, int]] = None,
|
|
50
|
+
output_keys: dict = OutputStatic.keys(),
|
|
51
|
+
**kwargs,
|
|
52
|
+
) -> dict:
|
|
53
|
+
if kpts is None:
|
|
54
|
+
kpts = [4, 4, 4]
|
|
55
|
+
write_input(
|
|
56
|
+
working_directory=working_directory,
|
|
57
|
+
atoms=structure,
|
|
58
|
+
prec=prec,
|
|
59
|
+
algo=algo,
|
|
60
|
+
lreal=lreal,
|
|
61
|
+
lwave=lwave,
|
|
62
|
+
lorbit=lorbit,
|
|
63
|
+
kpts=kpts,
|
|
64
|
+
**kwargs,
|
|
65
|
+
)
|
|
66
|
+
executable_function(working_directory)
|
|
67
|
+
output_obj = OutputParser(working_directory=working_directory, structure=structure)
|
|
68
|
+
result_dict = OutputStatic(
|
|
69
|
+
forces=output_obj.get_forces,
|
|
70
|
+
energy=output_obj.get_energy,
|
|
71
|
+
stress=output_obj.get_stress,
|
|
72
|
+
volume=output_obj.get_volume,
|
|
73
|
+
).get(output_keys=output_keys)
|
|
74
|
+
return result_dict
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def optimize_positions_with_vasp(
|
|
78
|
+
structure: Atoms,
|
|
79
|
+
working_directory: str,
|
|
80
|
+
executable_function: callable,
|
|
81
|
+
prec: str = "Accurate",
|
|
82
|
+
algo: str = "Fast",
|
|
83
|
+
lreal: bool = False,
|
|
84
|
+
lwave: bool = False,
|
|
85
|
+
lorbit: int = 0,
|
|
86
|
+
isif: int = 2,
|
|
87
|
+
ibrion: int = 2,
|
|
88
|
+
nsw: int = 100,
|
|
89
|
+
kpts: Optional[list[int, int, int]] = None,
|
|
90
|
+
**kwargs,
|
|
91
|
+
) -> Atoms:
|
|
92
|
+
if kpts is None:
|
|
93
|
+
kpts = [4, 4, 4]
|
|
94
|
+
write_input(
|
|
95
|
+
working_directory=working_directory,
|
|
96
|
+
atoms=structure,
|
|
97
|
+
prec=prec,
|
|
98
|
+
algo=algo,
|
|
99
|
+
lreal=lreal,
|
|
100
|
+
lwave=lwave,
|
|
101
|
+
lorbit=lorbit,
|
|
102
|
+
kpts=kpts,
|
|
103
|
+
isif=isif,
|
|
104
|
+
ibrion=ibrion,
|
|
105
|
+
nsw=nsw,
|
|
106
|
+
**kwargs,
|
|
107
|
+
)
|
|
108
|
+
executable_function(working_directory)
|
|
109
|
+
output_dict = parse_vasp_output(
|
|
110
|
+
working_directory=working_directory, structure=structure
|
|
111
|
+
)
|
|
112
|
+
structure_copy = structure.copy()
|
|
113
|
+
structure_copy.positions = output_dict["generic"]["positions"][-1]
|
|
114
|
+
return structure_copy
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def optimize_positions_and_volume_with_vasp(
|
|
118
|
+
structure: Atoms,
|
|
119
|
+
working_directory: str,
|
|
120
|
+
executable_function: callable,
|
|
121
|
+
prec: str = "Accurate",
|
|
122
|
+
algo: str = "Fast",
|
|
123
|
+
lreal: bool = False,
|
|
124
|
+
lwave: bool = False,
|
|
125
|
+
lorbit: int = 0,
|
|
126
|
+
isif: int = 3,
|
|
127
|
+
ibrion: int = 2,
|
|
128
|
+
nsw: int = 100,
|
|
129
|
+
kpts: Optional[list[int, int, int]] = None,
|
|
130
|
+
**kwargs,
|
|
131
|
+
) -> Atoms:
|
|
132
|
+
if kpts is None:
|
|
133
|
+
kpts = [4, 4, 4]
|
|
134
|
+
write_input(
|
|
135
|
+
working_directory=working_directory,
|
|
136
|
+
atoms=structure,
|
|
137
|
+
prec=prec,
|
|
138
|
+
algo=algo,
|
|
139
|
+
lreal=lreal,
|
|
140
|
+
lwave=lwave,
|
|
141
|
+
lorbit=lorbit,
|
|
142
|
+
kpts=kpts,
|
|
143
|
+
isif=isif,
|
|
144
|
+
ibrion=ibrion,
|
|
145
|
+
nsw=nsw,
|
|
146
|
+
**kwargs,
|
|
147
|
+
)
|
|
148
|
+
executable_function(working_directory)
|
|
149
|
+
output_dict = parse_vasp_output(
|
|
150
|
+
working_directory=working_directory, structure=structure
|
|
151
|
+
)
|
|
152
|
+
structure_copy = structure.copy()
|
|
153
|
+
structure_copy.set_cell(output_dict["generic"]["cells"][-1], scale_atoms=True)
|
|
154
|
+
structure_copy.positions = output_dict["generic"]["positions"][-1]
|
|
155
|
+
return structure_copy
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@as_task_dict_evaluator
|
|
159
|
+
def evaluate_with_vasp(
|
|
160
|
+
structure: Atoms,
|
|
161
|
+
tasks: list,
|
|
162
|
+
working_directory: str,
|
|
163
|
+
executable_function: callable,
|
|
164
|
+
prec: str = "Accurate",
|
|
165
|
+
algo: str = "Fast",
|
|
166
|
+
lreal: bool = False,
|
|
167
|
+
lwave: bool = False,
|
|
168
|
+
lorbit: int = 0,
|
|
169
|
+
kpts: Optional[list[int, int, int]] = None,
|
|
170
|
+
**kwargs,
|
|
171
|
+
) -> dict:
|
|
172
|
+
if kpts is None:
|
|
173
|
+
kpts = [4, 4, 4]
|
|
174
|
+
results = {}
|
|
175
|
+
if "optimize_positions_and_volume" in tasks:
|
|
176
|
+
results["structure_with_optimized_positions_and_volume"] = (
|
|
177
|
+
optimize_positions_and_volume_with_vasp(
|
|
178
|
+
structure=structure,
|
|
179
|
+
working_directory=working_directory,
|
|
180
|
+
executable_function=executable_function,
|
|
181
|
+
prec=prec,
|
|
182
|
+
algo=algo,
|
|
183
|
+
lreal=lreal,
|
|
184
|
+
lwave=lwave,
|
|
185
|
+
lorbit=lorbit,
|
|
186
|
+
kpts=kpts,
|
|
187
|
+
**kwargs,
|
|
188
|
+
)
|
|
189
|
+
)
|
|
190
|
+
elif "optimize_positions" in tasks:
|
|
191
|
+
results["structure_with_optimized_positions"] = optimize_positions_with_vasp(
|
|
192
|
+
structure=structure,
|
|
193
|
+
working_directory=working_directory,
|
|
194
|
+
executable_function=executable_function,
|
|
195
|
+
prec=prec,
|
|
196
|
+
algo=algo,
|
|
197
|
+
lreal=lreal,
|
|
198
|
+
lwave=lwave,
|
|
199
|
+
lorbit=lorbit,
|
|
200
|
+
kpts=kpts,
|
|
201
|
+
**kwargs,
|
|
202
|
+
)
|
|
203
|
+
elif "calc_energy" in tasks or "calc_forces" in tasks or "calc_stress" in tasks:
|
|
204
|
+
return calc_static_with_vasp(
|
|
205
|
+
structure=structure,
|
|
206
|
+
working_directory=working_directory,
|
|
207
|
+
executable_function=executable_function,
|
|
208
|
+
prec=prec,
|
|
209
|
+
algo=algo,
|
|
210
|
+
lreal=lreal,
|
|
211
|
+
lwave=lwave,
|
|
212
|
+
lorbit=lorbit,
|
|
213
|
+
kpts=kpts,
|
|
214
|
+
output_keys=get_quantities_from_tasks(tasks=tasks),
|
|
215
|
+
**kwargs,
|
|
216
|
+
)
|
|
217
|
+
else:
|
|
218
|
+
raise ValueError("The VASP calculator does not implement:", tasks)
|
|
219
|
+
return results
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: atomistics
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Interfaces for atomistic simulation codes and workflows
|
|
5
5
|
Author-email: Jan Janssen <janssen@mpie.de>
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -53,7 +53,7 @@ Requires-Dist: numpy==1.26.4
|
|
|
53
53
|
Requires-Dist: scipy<=1.15.2,>=1.11.1
|
|
54
54
|
Requires-Dist: spglib<=2.5.0,>=2.0.2
|
|
55
55
|
Provides-Extra: phonopy
|
|
56
|
-
Requires-Dist: phonopy<=2.
|
|
56
|
+
Requires-Dist: phonopy<=2.38.0,>=2.20.0; extra == "phonopy"
|
|
57
57
|
Requires-Dist: seekpath<=2.1.0,>=1.9.0; extra == "phonopy"
|
|
58
58
|
Requires-Dist: structuretoolkit<=0.0.31,>=0.0.10; extra == "phonopy"
|
|
59
59
|
Provides-Extra: gpaw
|
|
@@ -77,9 +77,11 @@ Requires-Dist: requests<=2.32.3,>=2.24.0; extra == "experimental"
|
|
|
77
77
|
Provides-Extra: sphinxdft
|
|
78
78
|
Requires-Dist: sphinx-parser==0.0.1; extra == "sphinxdft"
|
|
79
79
|
Provides-Extra: qe
|
|
80
|
-
Requires-Dist: pwtools==1.
|
|
80
|
+
Requires-Dist: pwtools==1.3.0; extra == "qe"
|
|
81
81
|
Provides-Extra: tqdm
|
|
82
82
|
Requires-Dist: tqdm==4.67.1; extra == "tqdm"
|
|
83
|
+
Provides-Extra: vasp
|
|
84
|
+
Requires-Dist: pyiron_vasp==0.2.4; extra == "vasp"
|
|
83
85
|
|
|
84
86
|
# atomistics
|
|
85
87
|
[](https://github.com/pyiron/atomistics/actions/workflows/pipeline.yml)
|
|
@@ -16,6 +16,7 @@ atomistics/calculators/hessian.py
|
|
|
16
16
|
atomistics/calculators/interface.py
|
|
17
17
|
atomistics/calculators/qe.py
|
|
18
18
|
atomistics/calculators/sphinxdft.py
|
|
19
|
+
atomistics/calculators/vasp.py
|
|
19
20
|
atomistics/calculators/wrapper.py
|
|
20
21
|
atomistics/calculators/lammps/__init__.py
|
|
21
22
|
atomistics/calculators/lammps/commands.py
|
|
@@ -88,4 +89,5 @@ tests/test_quasiharmonic_ase_emt.py
|
|
|
88
89
|
tests/test_quasiharmonic_lammpslib.py
|
|
89
90
|
tests/test_quasiharmonic_lammpslib_functional.py
|
|
90
91
|
tests/test_referencedata.py
|
|
91
|
-
tests/test_sphinx_parser.py
|
|
92
|
+
tests/test_sphinx_parser.py
|
|
93
|
+
tests/test_vasp_parser.py
|
|
@@ -26,15 +26,18 @@ dynaphopy<=1.17.16,>=1.17.5
|
|
|
26
26
|
pyiron_lammps<=0.4.0,>=0.3.2
|
|
27
27
|
|
|
28
28
|
[phonopy]
|
|
29
|
-
phonopy<=2.
|
|
29
|
+
phonopy<=2.38.0,>=2.20.0
|
|
30
30
|
seekpath<=2.1.0,>=1.9.0
|
|
31
31
|
structuretoolkit<=0.0.31,>=0.0.10
|
|
32
32
|
|
|
33
33
|
[qe]
|
|
34
|
-
pwtools==1.
|
|
34
|
+
pwtools==1.3.0
|
|
35
35
|
|
|
36
36
|
[sphinxdft]
|
|
37
37
|
sphinx-parser==0.0.1
|
|
38
38
|
|
|
39
39
|
[tqdm]
|
|
40
40
|
tqdm==4.67.1
|
|
41
|
+
|
|
42
|
+
[vasp]
|
|
43
|
+
pyiron_vasp==0.2.4
|
|
@@ -38,7 +38,7 @@ Repository = "https://github.com/pyiron/atomistics"
|
|
|
38
38
|
|
|
39
39
|
[project.optional-dependencies]
|
|
40
40
|
phonopy = [
|
|
41
|
-
"phonopy>=2.20.0,<=2.
|
|
41
|
+
"phonopy>=2.20.0,<=2.38.0",
|
|
42
42
|
"seekpath>=1.9.0,<=2.1.0",
|
|
43
43
|
"structuretoolkit>=0.0.10,<=0.0.31",
|
|
44
44
|
]
|
|
@@ -68,11 +68,14 @@ sphinxdft = [
|
|
|
68
68
|
"sphinx-parser==0.0.1"
|
|
69
69
|
]
|
|
70
70
|
qe = [
|
|
71
|
-
"pwtools==1.
|
|
71
|
+
"pwtools==1.3.0"
|
|
72
72
|
]
|
|
73
73
|
tqdm = [
|
|
74
74
|
"tqdm==4.67.1"
|
|
75
75
|
]
|
|
76
|
+
vasp = [
|
|
77
|
+
"pyiron_vasp==0.2.4"
|
|
78
|
+
]
|
|
76
79
|
|
|
77
80
|
[tool.setuptools.packages.find]
|
|
78
81
|
include = ["atomistics*"]
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
from ase.build import bulk
|
|
1
2
|
import numpy as np
|
|
2
3
|
|
|
3
4
|
import unittest
|
|
4
5
|
|
|
5
6
|
from atomistics.workflows.evcurve.fit import fit_equation_of_state
|
|
7
|
+
from atomistics.workflows.evcurve.debye import DebyeModel
|
|
8
|
+
from atomistics.workflows.evcurve.thermo import get_thermo_bulk_model
|
|
6
9
|
|
|
7
10
|
|
|
8
11
|
class TestEvCurve(unittest.TestCase):
|
|
@@ -72,6 +75,74 @@ class TestEvCurve(unittest.TestCase):
|
|
|
72
75
|
fit_dict = fit_equation_of_state(
|
|
73
76
|
volume_lst=self.volumes, energy_lst=self.energies, fittype="vinet"
|
|
74
77
|
)
|
|
78
|
+
print(fit_dict)
|
|
75
79
|
self.assertAlmostEqual(fit_dict["volume_eq"], 66.43032532814925)
|
|
76
80
|
self.assertAlmostEqual(fit_dict["bulkmodul_eq"], 77.61265363975706)
|
|
77
81
|
self.assertAlmostEqual(fit_dict["b_prime_eq"], 1.2734991618131122)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class TestThermo(unittest.TestCase):
|
|
85
|
+
def setUp(self):
|
|
86
|
+
self._volumes = [
|
|
87
|
+
63.10883669478296,
|
|
88
|
+
63.77314023893856,
|
|
89
|
+
64.43744378309412,
|
|
90
|
+
65.10174732724975,
|
|
91
|
+
65.7660508714054,
|
|
92
|
+
66.43035441556098,
|
|
93
|
+
67.09465795971657,
|
|
94
|
+
67.7589615038722,
|
|
95
|
+
68.42326504802779,
|
|
96
|
+
69.08756859218344,
|
|
97
|
+
69.75187213633905,
|
|
98
|
+
]
|
|
99
|
+
self._thermo = get_thermo_bulk_model(
|
|
100
|
+
temperatures=np.arange(1.0, 1550.0, 50.0),
|
|
101
|
+
debye_model=DebyeModel(
|
|
102
|
+
fit_dict={
|
|
103
|
+
"energy_eq": -13.439961346483864,
|
|
104
|
+
"volume_eq": 66.43032532814925,
|
|
105
|
+
"bulkmodul_eq": 77.61265363975706,
|
|
106
|
+
"b_prime_eq": 1.2734991618131122,
|
|
107
|
+
"volume": self._volumes,
|
|
108
|
+
"fit_dict": {
|
|
109
|
+
"fit_type": "vinet",
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
masses=bulk("Al", cubic=True).get_masses(),
|
|
113
|
+
num_steps=50,
|
|
114
|
+
),
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def test_copy(self):
|
|
118
|
+
thermo_copy = self._thermo.copy()
|
|
119
|
+
self.assertEqual(len(thermo_copy.__dict__), len(self._thermo.__dict__))
|
|
120
|
+
|
|
121
|
+
def test_num_atoms(self):
|
|
122
|
+
self.assertEqual(self._thermo.num_atoms, 1)
|
|
123
|
+
self._thermo.num_atoms = 2
|
|
124
|
+
self.assertEqual(self._thermo.num_atoms, 2)
|
|
125
|
+
self._thermo.num_atoms = 1
|
|
126
|
+
|
|
127
|
+
def test_d_temp(self):
|
|
128
|
+
self.assertEqual(self._thermo._d_temp, 50.0)
|
|
129
|
+
|
|
130
|
+
def test_d_vol(self):
|
|
131
|
+
self.assertTrue(np.isclose(self._thermo._d_vol, 0.13557215186849447))
|
|
132
|
+
|
|
133
|
+
def test_volumes(self):
|
|
134
|
+
self.assertTrue(np.isclose(self._thermo.volumes[0], self._volumes[0]))
|
|
135
|
+
self.assertTrue(np.isclose(self._thermo.volumes[-1], self._volumes[-1]))
|
|
136
|
+
self.assertEqual(len(self._thermo.volumes), 50)
|
|
137
|
+
|
|
138
|
+
def test_entropy(self):
|
|
139
|
+
self._thermo._entropy = None
|
|
140
|
+
self.assertEqual(self._thermo.entropy.shape[0], 31)
|
|
141
|
+
self.assertEqual(self._thermo.entropy.shape[1], 50)
|
|
142
|
+
self._thermo._entropy = None
|
|
143
|
+
|
|
144
|
+
def test_pressure(self):
|
|
145
|
+
self._thermo._pressure = None
|
|
146
|
+
self.assertEqual(self._thermo.pressure.shape[0], 31)
|
|
147
|
+
self.assertEqual(self._thermo.pressure.shape[1], 50)
|
|
148
|
+
self._thermo._pressure = None
|
|
@@ -19,10 +19,10 @@ def validate_fitdict(fit_dict):
|
|
|
19
19
|
lst = [
|
|
20
20
|
fit_dict["bulkmodul_eq"] > 55,
|
|
21
21
|
fit_dict["bulkmodul_eq"] < 65,
|
|
22
|
-
fit_dict["energy_eq"] > -227.
|
|
23
|
-
fit_dict["energy_eq"] < -227.
|
|
24
|
-
fit_dict["volume_eq"] > 70.
|
|
25
|
-
fit_dict["volume_eq"] < 70.
|
|
22
|
+
fit_dict["energy_eq"] > -227.72,
|
|
23
|
+
fit_dict["energy_eq"] < -227.71,
|
|
24
|
+
fit_dict["volume_eq"] > 70.92,
|
|
25
|
+
fit_dict["volume_eq"] < 70.93,
|
|
26
26
|
]
|
|
27
27
|
if not all(lst):
|
|
28
28
|
print(fit_dict)
|
|
@@ -57,8 +57,8 @@ class TestEvCurve(unittest.TestCase):
|
|
|
57
57
|
task_dict=task_dict,
|
|
58
58
|
working_directory=os.path.abspath("."),
|
|
59
59
|
executable_function=evaluate_sphinx,
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
max_electronic_steps=100,
|
|
61
|
+
energy_cutoff_in_eV=500.0,
|
|
62
62
|
kpoint_coords=[0.5, 0.5, 0.5],
|
|
63
63
|
kpoint_folding=[3, 3, 3],
|
|
64
64
|
)
|
|
@@ -39,3 +39,23 @@ class TestPhonons(unittest.TestCase):
|
|
|
39
39
|
self.assertTrue("group_velocities" in mesh_dict.keys())
|
|
40
40
|
self.assertTrue("frequency_points" in dos_dict.keys())
|
|
41
41
|
self.assertTrue("total_dos" in dos_dict.keys())
|
|
42
|
+
dynmat_shape = workflow.get_dynamical_matrix().shape
|
|
43
|
+
self.assertEqual(dynmat_shape[0], 12)
|
|
44
|
+
self.assertEqual(dynmat_shape[1], 12)
|
|
45
|
+
hessmat_shape = workflow.get_hesse_matrix().shape
|
|
46
|
+
self.assertEqual(hessmat_shape[0], 324)
|
|
47
|
+
self.assertEqual(hessmat_shape[1], 324)
|
|
48
|
+
band_dict = workflow.get_band_structure()
|
|
49
|
+
self.assertEqual(len(band_dict['qpoints']), 6)
|
|
50
|
+
for vec in band_dict['qpoints']:
|
|
51
|
+
self.assertTrue(vec.shape[0] in [34, 39, 78, 101, 95])
|
|
52
|
+
self.assertEqual(vec.shape[1], 3)
|
|
53
|
+
self.assertEqual(len(band_dict['distances']), 6)
|
|
54
|
+
for vec in band_dict['distances']:
|
|
55
|
+
self.assertTrue(vec.shape[0] in [34, 39, 78, 101, 95])
|
|
56
|
+
self.assertEqual(len(band_dict['frequencies']), 6)
|
|
57
|
+
for vec in band_dict['frequencies']:
|
|
58
|
+
self.assertTrue(vec.shape[0] in [34, 39, 78, 101, 95])
|
|
59
|
+
self.assertEqual(vec.shape[1], 12)
|
|
60
|
+
self.assertIsNone(band_dict['eigenvectors'])
|
|
61
|
+
self.assertIsNone(band_dict['group_velocities'])
|
|
@@ -131,3 +131,23 @@ class TestPhonons(unittest.TestCase):
|
|
|
131
131
|
self.assertTrue(thermal_dict["free_energy"][0] > 0.1)
|
|
132
132
|
self.assertTrue(thermal_dict["free_energy"][-1] < -2.6)
|
|
133
133
|
self.assertTrue(thermal_dict["free_energy"][-1] > -2.7)
|
|
134
|
+
dynmat_shape = workflow.get_dynamical_matrix().shape
|
|
135
|
+
self.assertEqual(dynmat_shape[0], 12)
|
|
136
|
+
self.assertEqual(dynmat_shape[1], 12)
|
|
137
|
+
hessmat_shape = workflow.get_hesse_matrix().shape
|
|
138
|
+
self.assertEqual(hessmat_shape[0], 324)
|
|
139
|
+
self.assertEqual(hessmat_shape[1], 324)
|
|
140
|
+
band_dict = workflow.get_band_structure()
|
|
141
|
+
self.assertEqual(len(band_dict['qpoints']), 6)
|
|
142
|
+
for vec in band_dict['qpoints']:
|
|
143
|
+
self.assertTrue(vec.shape[0] in [34, 39, 78, 101, 95])
|
|
144
|
+
self.assertEqual(vec.shape[1], 3)
|
|
145
|
+
self.assertEqual(len(band_dict['distances']), 6)
|
|
146
|
+
for vec in band_dict['distances']:
|
|
147
|
+
self.assertTrue(vec.shape[0] in [34, 39, 78, 101, 95])
|
|
148
|
+
self.assertEqual(len(band_dict['frequencies']), 6)
|
|
149
|
+
for vec in band_dict['frequencies']:
|
|
150
|
+
self.assertTrue(vec.shape[0] in [34, 39, 78, 101, 95])
|
|
151
|
+
self.assertEqual(vec.shape[1], 12)
|
|
152
|
+
self.assertIsNone(band_dict['eigenvectors'])
|
|
153
|
+
self.assertIsNone(band_dict['group_velocities'])
|
|
@@ -107,3 +107,23 @@ class TestPhonons(unittest.TestCase):
|
|
|
107
107
|
self.assertTrue(thermal_dict["free_energy"][0] > 0.1)
|
|
108
108
|
self.assertTrue(thermal_dict["free_energy"][-1] < -2.6)
|
|
109
109
|
self.assertTrue(thermal_dict["free_energy"][-1] > -2.7)
|
|
110
|
+
dynmat_shape = workflow.get_dynamical_matrix().shape
|
|
111
|
+
self.assertEqual(dynmat_shape[0],12)
|
|
112
|
+
self.assertEqual(dynmat_shape[1], 12)
|
|
113
|
+
hessmat_shape = workflow.get_hesse_matrix().shape
|
|
114
|
+
self.assertEqual(hessmat_shape[0], 324)
|
|
115
|
+
self.assertEqual(hessmat_shape[1], 324)
|
|
116
|
+
band_dict = workflow.get_band_structure()
|
|
117
|
+
self.assertEqual(len(band_dict['qpoints']), 6)
|
|
118
|
+
for vec in band_dict['qpoints']:
|
|
119
|
+
self.assertTrue(vec.shape[0] in [34, 39, 78, 101, 95])
|
|
120
|
+
self.assertEqual(vec.shape[1], 3)
|
|
121
|
+
self.assertEqual(len(band_dict['distances']), 6)
|
|
122
|
+
for vec in band_dict['distances']:
|
|
123
|
+
self.assertTrue(vec.shape[0] in [34, 39, 78, 101, 95])
|
|
124
|
+
self.assertEqual(len(band_dict['frequencies']), 6)
|
|
125
|
+
for vec in band_dict['frequencies']:
|
|
126
|
+
self.assertTrue(vec.shape[0] in [34, 39, 78, 101, 95])
|
|
127
|
+
self.assertEqual(vec.shape[1], 12)
|
|
128
|
+
self.assertIsNone(band_dict['eigenvectors'])
|
|
129
|
+
self.assertIsNone(band_dict['group_velocities'])
|
|
@@ -6,7 +6,17 @@ import numpy as np
|
|
|
6
6
|
from ase.build import bulk
|
|
7
7
|
|
|
8
8
|
try:
|
|
9
|
-
from
|
|
9
|
+
from sphinx_parser.toolkit import to_sphinx
|
|
10
|
+
from atomistics.calculators.sphinxdft import (
|
|
11
|
+
OutputParser,
|
|
12
|
+
_generate_input,
|
|
13
|
+
calc_static_with_sphinxdft,
|
|
14
|
+
optimize_positions_with_sphinxdft,
|
|
15
|
+
evaluate_with_sphinx,
|
|
16
|
+
HARTREE_TO_EV,
|
|
17
|
+
HARTREE_OVER_BOHR_TO_EV_OVER_ANGSTROM,
|
|
18
|
+
BOHR_TO_ANGSTROM,
|
|
19
|
+
)
|
|
10
20
|
|
|
11
21
|
skip_sphinx_test = False
|
|
12
22
|
except ImportError:
|
|
@@ -37,30 +47,25 @@ class TestSphinxParser(unittest.TestCase):
|
|
|
37
47
|
def test_write_input(self):
|
|
38
48
|
folder = "test"
|
|
39
49
|
os.makedirs(folder, exist_ok=True)
|
|
40
|
-
|
|
50
|
+
input_sx = to_sphinx(_generate_input(
|
|
41
51
|
structure=self._structure,
|
|
42
|
-
working_directory=folder,
|
|
43
52
|
maxSteps=100,
|
|
44
|
-
|
|
53
|
+
energy_cutoff_in_eV=25.0 * HARTREE_TO_EV,
|
|
45
54
|
kpoint_coords=None,
|
|
46
55
|
kpoint_folding=None,
|
|
47
|
-
)
|
|
48
|
-
file = os.path.join(folder, "input.sx")
|
|
49
|
-
self.assertTrue(os.path.exists(file))
|
|
50
|
-
with open(file, "r") as f:
|
|
51
|
-
lines = f.readlines()
|
|
56
|
+
))
|
|
52
57
|
|
|
53
58
|
self.assertEqual(
|
|
54
|
-
" eCut = 25.0
|
|
55
|
-
"".join([l for l in
|
|
59
|
+
" eCut = " + str(25.0 * HARTREE_TO_EV / HARTREE_TO_EV) + ";",
|
|
60
|
+
"".join([l for l in input_sx.split("\n") if "eCut" in l])
|
|
56
61
|
)
|
|
57
62
|
self.assertEqual(
|
|
58
|
-
" folding = [3, 3, 3]
|
|
59
|
-
"".join([l for l in
|
|
63
|
+
" folding = [3, 3, 3];",
|
|
64
|
+
"".join([l for l in input_sx.split("\n") if "folding" in l])
|
|
60
65
|
)
|
|
61
66
|
self.assertEqual(
|
|
62
|
-
" potType = \"AtomPAW\"
|
|
63
|
-
"".join([l for l in
|
|
67
|
+
" potType = \"AtomPAW\";",
|
|
68
|
+
"".join([l for l in input_sx.split("\n") if "potType" in l])
|
|
64
69
|
)
|
|
65
70
|
shutil.rmtree(folder)
|
|
66
71
|
|
|
@@ -69,8 +74,8 @@ class TestSphinxParser(unittest.TestCase):
|
|
|
69
74
|
structure=self._structure,
|
|
70
75
|
working_directory=self._output_directory,
|
|
71
76
|
executable_function=executable_function,
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
max_electronic_steps=100,
|
|
78
|
+
energy_cutoff_in_eV=25.0 * HARTREE_TO_EV,
|
|
74
79
|
kpoint_coords=None,
|
|
75
80
|
kpoint_folding=None,
|
|
76
81
|
output_keys=["volume", "forces", "energy"],
|
|
@@ -82,13 +87,28 @@ class TestSphinxParser(unittest.TestCase):
|
|
|
82
87
|
np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]),
|
|
83
88
|
)))
|
|
84
89
|
|
|
85
|
-
def
|
|
90
|
+
def test_optimize_positions_with_sphinxdft(self):
|
|
91
|
+
structure_result = optimize_positions_with_sphinxdft(
|
|
92
|
+
structure=self._structure,
|
|
93
|
+
working_directory=self._output_directory,
|
|
94
|
+
executable_function=executable_function,
|
|
95
|
+
max_electronic_steps=100,
|
|
96
|
+
energy_cutoff_in_eV=25.0 * HARTREE_TO_EV,
|
|
97
|
+
kpoint_coords=None,
|
|
98
|
+
kpoint_folding=None,
|
|
99
|
+
mode="linQN",
|
|
100
|
+
dEnergy=1.0e-6,
|
|
101
|
+
max_ionic_steps=50,
|
|
102
|
+
)
|
|
103
|
+
self.assertEqual(len(structure_result), len(self._structure))
|
|
104
|
+
|
|
105
|
+
def test_evaluate_with_sphinx_energy_and_forces(self):
|
|
86
106
|
results = evaluate_with_sphinx(
|
|
87
107
|
task_dict={"calc_energy": self._structure, "calc_forces": self._structure},
|
|
88
108
|
working_directory=self._output_directory,
|
|
89
109
|
executable_function=executable_function,
|
|
90
|
-
|
|
91
|
-
|
|
110
|
+
max_electronic_steps=100,
|
|
111
|
+
energy_cutoff_in_eV=25.0 * HARTREE_TO_EV,
|
|
92
112
|
kpoint_coords=None,
|
|
93
113
|
kpoint_folding=None,
|
|
94
114
|
)
|
|
@@ -97,3 +117,21 @@ class TestSphinxParser(unittest.TestCase):
|
|
|
97
117
|
results["forces"],
|
|
98
118
|
np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]),
|
|
99
119
|
)))
|
|
120
|
+
|
|
121
|
+
def test_evaluate_with_sphinx_structure_optimization(self):
|
|
122
|
+
results = evaluate_with_sphinx(
|
|
123
|
+
task_dict={"optimize_positions": self._structure},
|
|
124
|
+
working_directory=self._output_directory,
|
|
125
|
+
executable_function=executable_function,
|
|
126
|
+
max_electronic_steps=100,
|
|
127
|
+
energy_cutoff_in_eV=25.0 * HARTREE_TO_EV,
|
|
128
|
+
kpoint_coords=None,
|
|
129
|
+
kpoint_folding=None,
|
|
130
|
+
sphinx_optimizer_kwargs={
|
|
131
|
+
"mode": "linQN",
|
|
132
|
+
"dEnergy": 1.0e-6,
|
|
133
|
+
"max_ionic_steps": 50,
|
|
134
|
+
},
|
|
135
|
+
)
|
|
136
|
+
self.assertTrue("structure_with_optimized_positions" in results.keys())
|
|
137
|
+
self.assertEqual(len(results), 1)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
from unittest import TestCase
|
|
4
|
+
|
|
5
|
+
from ase.build import bulk
|
|
6
|
+
|
|
7
|
+
from atomistics.calculators.vasp import (
|
|
8
|
+
evaluate_with_vasp,
|
|
9
|
+
)
|
|
10
|
+
from atomistics.workflows import optimize_positions, optimize_positions_and_volume
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
os.environ["VASP_PP_PATH"] = os.path.abspath(os.path.join(__file__, "..", "static", "vasp"))
|
|
14
|
+
|
|
15
|
+
def copy_file_funct(working_directory):
|
|
16
|
+
outcar_file = os.path.abspath(os.path.join(__file__, "..", "static", "vasp", "OUTCAR"))
|
|
17
|
+
shutil.copy(outcar_file, working_directory)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TestVaspParser(TestCase):
|
|
21
|
+
def setUp(self):
|
|
22
|
+
self._structure = bulk("Al", a=4.05, cubic=True)
|
|
23
|
+
|
|
24
|
+
def test_optimize_positions_with_vasp_task(self):
|
|
25
|
+
result = evaluate_with_vasp(
|
|
26
|
+
task_dict=optimize_positions(self._structure),
|
|
27
|
+
working_directory="opt_pos_task",
|
|
28
|
+
executable_function=copy_file_funct,
|
|
29
|
+
prec="Accurate",
|
|
30
|
+
algo="Fast",
|
|
31
|
+
lreal=False,
|
|
32
|
+
lwave=False,
|
|
33
|
+
lorbit=0,
|
|
34
|
+
xc="pbe"
|
|
35
|
+
)
|
|
36
|
+
self.assertEqual(len(result), 1)
|
|
37
|
+
|
|
38
|
+
def test_optimize_positions_and_volume_with_vasp_task(self):
|
|
39
|
+
result = evaluate_with_vasp(
|
|
40
|
+
task_dict=optimize_positions_and_volume(self._structure),
|
|
41
|
+
working_directory="opt_vol_task",
|
|
42
|
+
executable_function=copy_file_funct,
|
|
43
|
+
prec="Accurate",
|
|
44
|
+
algo="Fast",
|
|
45
|
+
lreal=False,
|
|
46
|
+
lwave=False,
|
|
47
|
+
lorbit=0,
|
|
48
|
+
xc="pbe"
|
|
49
|
+
)
|
|
50
|
+
self.assertEqual(len(result), 1)
|
|
51
|
+
|
|
52
|
+
def test_calc_static_task(self):
|
|
53
|
+
result = evaluate_with_vasp(
|
|
54
|
+
task_dict={
|
|
55
|
+
"calc_energy": self._structure,
|
|
56
|
+
"calc_forces": self._structure,
|
|
57
|
+
"calc_stress": self._structure,
|
|
58
|
+
},
|
|
59
|
+
working_directory="opt_vol_task",
|
|
60
|
+
executable_function=copy_file_funct,
|
|
61
|
+
prec="Accurate",
|
|
62
|
+
algo="Fast",
|
|
63
|
+
lreal=False,
|
|
64
|
+
lwave=False,
|
|
65
|
+
lorbit=0,
|
|
66
|
+
xc="pbe"
|
|
67
|
+
)
|
|
68
|
+
self.assertEqual(len(result), 3)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{atomistics-0.2.1 → atomistics-0.2.2}/tests/test_molecular_dynamics_thermal_expansion_lammpslib.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|