atomistics 0.2.0__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.
Files changed (95) hide show
  1. {atomistics-0.2.0/atomistics.egg-info → atomistics-0.2.2}/PKG-INFO +11 -7
  2. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/_version.py +3 -3
  3. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/calculators/__init__.py +11 -0
  4. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/calculators/lammps/filecalculator.py +8 -8
  5. atomistics-0.2.2/atomistics/calculators/sphinxdft.py +212 -0
  6. atomistics-0.2.2/atomistics/calculators/vasp.py +219 -0
  7. {atomistics-0.2.0 → atomistics-0.2.2/atomistics.egg-info}/PKG-INFO +11 -7
  8. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics.egg-info/SOURCES.txt +6 -1
  9. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics.egg-info/requires.txt +12 -6
  10. {atomistics-0.2.0 → atomistics-0.2.2}/pyproject.toml +12 -6
  11. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_evcurve_eos.py +71 -0
  12. atomistics-0.2.2/tests/test_evcurve_sphinxdft.py +66 -0
  13. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_phonons_ase_emt.py +20 -0
  14. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_phonons_lammpsfile.py +20 -0
  15. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_phonons_lammpslib.py +20 -0
  16. atomistics-0.2.2/tests/test_sphinx_parser.py +137 -0
  17. atomistics-0.2.2/tests/test_vasp_parser.py +68 -0
  18. {atomistics-0.2.0 → atomistics-0.2.2}/LICENSE +0 -0
  19. {atomistics-0.2.0 → atomistics-0.2.2}/MANIFEST.in +0 -0
  20. {atomistics-0.2.0 → atomistics-0.2.2}/README.md +0 -0
  21. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/__init__.py +0 -0
  22. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/calculators/ase.py +0 -0
  23. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/calculators/hessian.py +0 -0
  24. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/calculators/interface.py +0 -0
  25. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/calculators/lammps/__init__.py +0 -0
  26. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/calculators/lammps/commands.py +0 -0
  27. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/calculators/lammps/helpers.py +0 -0
  28. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/calculators/lammps/libcalculator.py +0 -0
  29. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/calculators/lammps/phonon.py +0 -0
  30. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/calculators/lammps/potential.py +0 -0
  31. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/calculators/qe.py +0 -0
  32. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/calculators/wrapper.py +0 -0
  33. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/referencedata/__init__.py +0 -0
  34. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/referencedata/mendeleev.py +0 -0
  35. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/referencedata/wikipedia.py +0 -0
  36. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/referencedata/wolframalpha.py +0 -0
  37. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/shared/__init__.py +0 -0
  38. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/shared/output.py +0 -0
  39. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/shared/parallel.py +0 -0
  40. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/shared/thermal_expansion.py +0 -0
  41. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/shared/tqdm_iterator.py +0 -0
  42. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/__init__.py +0 -0
  43. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/elastic/__init__.py +0 -0
  44. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/elastic/elastic_moduli.py +0 -0
  45. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/elastic/helper.py +0 -0
  46. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/elastic/symmetry.py +0 -0
  47. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/elastic/workflow.py +0 -0
  48. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/evcurve/__init__.py +0 -0
  49. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/evcurve/debye.py +0 -0
  50. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/evcurve/fit.py +0 -0
  51. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/evcurve/helper.py +0 -0
  52. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/evcurve/thermo.py +0 -0
  53. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/evcurve/workflow.py +0 -0
  54. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/interface.py +0 -0
  55. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/langevin.py +0 -0
  56. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/molecular_dynamics.py +0 -0
  57. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/phonons/__init__.py +0 -0
  58. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/phonons/helper.py +0 -0
  59. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/phonons/units.py +0 -0
  60. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/phonons/workflow.py +0 -0
  61. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/quasiharmonic.py +0 -0
  62. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics/workflows/structure_optimization.py +0 -0
  63. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics.egg-info/dependency_links.txt +0 -0
  64. {atomistics-0.2.0 → atomistics-0.2.2}/atomistics.egg-info/top_level.txt +0 -0
  65. {atomistics-0.2.0 → atomistics-0.2.2}/setup.cfg +0 -0
  66. {atomistics-0.2.0 → atomistics-0.2.2}/setup.py +0 -0
  67. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_abstract_workflow_class.py +0 -0
  68. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_ase_md_emt.py +0 -0
  69. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_calc_stress_ase_emt.py +0 -0
  70. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_calc_stress_lammpslib.py +0 -0
  71. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_elastic_ase_emt.py +0 -0
  72. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_elastic_helper.py +0 -0
  73. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_elastic_lammpslib.py +0 -0
  74. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_elastic_lammpslib_functional.py +0 -0
  75. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_evcurve_ase_emt.py +0 -0
  76. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_evcurve_ase_lammps.py +0 -0
  77. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_evcurve_lammpsfile.py +0 -0
  78. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_evcurve_lammpslib.py +0 -0
  79. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_evcurve_lammpslib_function_parallel.py +0 -0
  80. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_evcurve_lammpslib_functional.py +0 -0
  81. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_evcurve_qe.py +0 -0
  82. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_hessian_lammpslib.py +0 -0
  83. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_lammps_calculator.py +0 -0
  84. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_lammpslib_md.py +0 -0
  85. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_lammpslib_md_phonons.py +0 -0
  86. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_langevin_lammpslib.py +0 -0
  87. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_molecular_dynamics_thermal_expansion_lammpslib.py +0 -0
  88. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_optimize_positions_ase_emt.py +0 -0
  89. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_optimize_positions_lammpsfile.py +0 -0
  90. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_optimize_positions_lammpslib.py +0 -0
  91. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_phonons_lammpslib_functional.py +0 -0
  92. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_quasiharmonic_ase_emt.py +0 -0
  93. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_quasiharmonic_lammpslib.py +0 -0
  94. {atomistics-0.2.0 → atomistics-0.2.2}/tests/test_quasiharmonic_lammpslib_functional.py +0 -0
  95. {atomistics-0.2.0 → 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.0
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
@@ -48,12 +48,12 @@ Classifier: Programming Language :: Python :: 3.12
48
48
  Requires-Python: <3.13,>=3.9
49
49
  Description-Content-Type: text/markdown
50
50
  License-File: LICENSE
51
- Requires-Dist: ase<=3.24.0,>=3.22.1
52
- Requires-Dist: numpy<=1.26.4,>=1.26.0
51
+ Requires-Dist: ase<=3.24.0,>=3.23.0
52
+ 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.37.0,>=2.20.0; extra == "phonopy"
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
@@ -62,22 +62,26 @@ Provides-Extra: lammps
62
62
  Requires-Dist: pylammpsmpi<=0.2.31,>=0.2.1; extra == "lammps"
63
63
  Requires-Dist: jinja2<=3.1.5,>=2.11.3; extra == "lammps"
64
64
  Requires-Dist: pandas<=2.2.3,>=2.0.3; extra == "lammps"
65
- Requires-Dist: pyiron_lammps==0.3.2; extra == "lammps"
65
+ Requires-Dist: pyiron_lammps<=0.4.0,>=0.3.2; extra == "lammps"
66
66
  Provides-Extra: lammps-phonons
67
67
  Requires-Dist: pylammpsmpi<=0.2.31,>=0.2.1; extra == "lammps-phonons"
68
68
  Requires-Dist: jinja2<=3.1.5,>=2.11.3; extra == "lammps-phonons"
69
69
  Requires-Dist: pandas<=2.2.3,>=2.0.3; extra == "lammps-phonons"
70
70
  Requires-Dist: dynaphopy<=1.17.16,>=1.17.5; extra == "lammps-phonons"
71
- Requires-Dist: pyiron_lammps==0.3.2; extra == "lammps-phonons"
71
+ Requires-Dist: pyiron_lammps<=0.4.0,>=0.3.2; extra == "lammps-phonons"
72
72
  Provides-Extra: experimental
73
73
  Requires-Dist: lxml<=5.3.1,>=4.9.1; extra == "experimental"
74
74
  Requires-Dist: mendeleev<=0.19.0,>=0.12.0; extra == "experimental"
75
75
  Requires-Dist: pandas<=2.2.3,>=2.0.3; extra == "experimental"
76
76
  Requires-Dist: requests<=2.32.3,>=2.24.0; extra == "experimental"
77
+ Provides-Extra: sphinxdft
78
+ Requires-Dist: sphinx-parser==0.0.1; extra == "sphinxdft"
77
79
  Provides-Extra: qe
78
- Requires-Dist: pwtools==1.2.3; extra == "qe"
80
+ Requires-Dist: pwtools==1.3.0; extra == "qe"
79
81
  Provides-Extra: tqdm
80
82
  Requires-Dist: tqdm==4.67.1; extra == "tqdm"
83
+ Provides-Extra: vasp
84
+ Requires-Dist: pyiron_vasp==0.2.4; extra == "vasp"
81
85
 
82
86
  # atomistics
83
87
  [![Pipeline](https://github.com/pyiron/atomistics/actions/workflows/pipeline.yml/badge.svg)](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-02-24T21:11:30+0100",
11
+ "date": "2025-03-05T08:13:01+0100",
12
12
  "dirty": true,
13
13
  "error": null,
14
- "full-revisionid": "53823480028d38eafea3d367560553bf44d35a6b",
15
- "version": "0.2.0"
14
+ "full-revisionid": "5b518f33f60f904bf2c88dff51b72a07fe99091c",
15
+ "version": "0.2.2"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -77,3 +77,14 @@ try:
77
77
  __all__ += ["calc_molecular_dynamics_phonons_with_lammpslib"]
78
78
  except ImportError:
79
79
  pass
80
+
81
+ try:
82
+ from atomistics.calculators.sphinxdft import (
83
+ evaluate_with_sphinx,
84
+ )
85
+
86
+ __all__ += [
87
+ "evaluate_with_sphinx",
88
+ ]
89
+ except ImportError:
90
+ pass
@@ -3,8 +3,8 @@ import os
3
3
  import pandas
4
4
  from ase.atoms import Atoms
5
5
  from jinja2 import Template
6
- from pyiron_lammps.output import parse_lammps_output as _parse_lammps_output
7
- from pyiron_lammps.structure import write_lammps_datafile as _write_lammps_datafile
6
+ from pyiron_lammps import parse_lammps_output_files as _parse_lammps_output_files
7
+ from pyiron_lammps import write_lammps_structure as _write_lammps_structure
8
8
 
9
9
  from atomistics.calculators.interface import get_quantities_from_tasks
10
10
  from atomistics.calculators.lammps.commands import (
@@ -56,13 +56,13 @@ def _lammps_file_initialization(structure):
56
56
  def _write_lammps_input_file(
57
57
  working_directory, structure, potential_dataframe, input_template
58
58
  ):
59
- _write_lammps_datafile(
59
+ _write_lammps_structure(
60
60
  structure=structure,
61
- el_eam_lst=potential_dataframe["Species"],
61
+ potential_elements=potential_dataframe["Species"],
62
62
  bond_dict=None,
63
63
  units="metal",
64
64
  file_name="lammps.data",
65
- cwd=working_directory,
65
+ working_directory=working_directory,
66
66
  )
67
67
  input_str = (
68
68
  "".join(_lammps_file_initialization(structure=structure))
@@ -111,7 +111,7 @@ def optimize_positions_and_volume_with_lammpsfile(
111
111
  input_template=input_template,
112
112
  )
113
113
  executable_function(working_directory)
114
- output = _parse_lammps_output(
114
+ output = _parse_lammps_output_files(
115
115
  working_directory=working_directory,
116
116
  structure=structure,
117
117
  potential_elements=potential_dataframe["Species"],
@@ -155,7 +155,7 @@ def optimize_positions_with_lammpsfile(
155
155
  input_template=input_template,
156
156
  )
157
157
  executable_function(working_directory)
158
- output = _parse_lammps_output(
158
+ output = _parse_lammps_output_files(
159
159
  working_directory=working_directory,
160
160
  structure=structure,
161
161
  potential_elements=potential_dataframe["Species"],
@@ -189,7 +189,7 @@ def calc_static_with_lammpsfile(
189
189
  input_template=input_template,
190
190
  )
191
191
  executable_function(working_directory)
192
- output = _parse_lammps_output(
192
+ output = _parse_lammps_output_files(
193
193
  working_directory=working_directory,
194
194
  structure=structure,
195
195
  potential_elements=potential_dataframe["Species"],
@@ -0,0 +1,212 @@
1
+ import os
2
+ from typing import Optional
3
+
4
+ import scipy.constants
5
+ from ase.atoms import Atoms
6
+ from sphinx_parser.ase import get_structure_group, id_spx_to_ase
7
+ from sphinx_parser.input import sphinx
8
+ from sphinx_parser.jobs import apply_minimization
9
+ from sphinx_parser.output import collect_energy_dat, collect_eval_forces
10
+ from sphinx_parser.potential import get_paw_from_structure
11
+ from sphinx_parser.toolkit import to_sphinx
12
+
13
+ from atomistics.calculators.interface import get_quantities_from_tasks
14
+ from atomistics.calculators.wrapper import as_task_dict_evaluator
15
+ from atomistics.shared.output import OutputStatic
16
+
17
+ BOHR_TO_ANGSTROM = (
18
+ scipy.constants.physical_constants["Bohr radius"][0] / scipy.constants.angstrom
19
+ )
20
+ HARTREE_TO_EV = scipy.constants.physical_constants["Hartree energy in eV"][0]
21
+ HARTREE_OVER_BOHR_TO_EV_OVER_ANGSTROM = HARTREE_TO_EV / BOHR_TO_ANGSTROM
22
+
23
+
24
+ def _generate_input(
25
+ structure: Atoms,
26
+ maxSteps: int = 100,
27
+ energy_cutoff_in_eV: float = 500.0,
28
+ kpoint_coords: Optional[list[float, float, float]] = None,
29
+ kpoint_folding: Optional[list[int, int, int]] = None,
30
+ ):
31
+ if kpoint_coords is None:
32
+ kpoint_coords = [0.5, 0.5, 0.5]
33
+ if kpoint_folding is None:
34
+ kpoint_folding = [3, 3, 3]
35
+ struct_group, spin_lst = get_structure_group(structure)
36
+ main_group = sphinx.main.create(
37
+ scfDiag=sphinx.main.scfDiag.create(maxSteps=maxSteps, blockCCG={}),
38
+ evalForces=sphinx.main.evalForces.create(file="relaxHist.sx"),
39
+ )
40
+ pawPot_group = get_paw_from_structure(structure)
41
+ basis_group = sphinx.basis.create(
42
+ eCut=energy_cutoff_in_eV / HARTREE_TO_EV,
43
+ kPoint=sphinx.basis.kPoint.create(coords=kpoint_coords),
44
+ folding=kpoint_folding,
45
+ )
46
+ paw_group = sphinx.PAWHamiltonian.create(xc=1, spinPolarized=False, ekt=0.2)
47
+ initial_guess_group = sphinx.initialGuess.create(
48
+ waves=sphinx.initialGuess.waves.create(
49
+ lcao=sphinx.initialGuess.waves.lcao.create()
50
+ ),
51
+ rho=sphinx.initialGuess.rho.create(atomicOrbitals=True),
52
+ )
53
+ return sphinx.create(
54
+ pawPot=pawPot_group,
55
+ structure=struct_group,
56
+ main=main_group,
57
+ basis=basis_group,
58
+ PAWHamiltonian=paw_group,
59
+ initialGuess=initial_guess_group,
60
+ )
61
+
62
+
63
+ class OutputParser:
64
+ def __init__(self, working_directory: str, structure: Atoms):
65
+ self._working_directory = working_directory
66
+ self._structure = structure
67
+
68
+ def get_energy(self):
69
+ return (
70
+ collect_energy_dat(os.path.join(self._working_directory, "energy.dat"))[
71
+ "scf_energy_int"
72
+ ][-1][-1]
73
+ * HARTREE_TO_EV
74
+ )
75
+
76
+ def get_forces(self):
77
+ return (
78
+ collect_eval_forces(os.path.join(self._working_directory, "relaxHist.sx"))[
79
+ "forces"
80
+ ][-1][id_spx_to_ase(self._structure)]
81
+ * HARTREE_OVER_BOHR_TO_EV_OVER_ANGSTROM
82
+ )
83
+
84
+ def get_volume(self):
85
+ return self._structure.get_volume()
86
+
87
+ def get_stress(self):
88
+ raise NotImplementedError()
89
+
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
+
133
+ def calc_static_with_sphinxdft(
134
+ structure: Atoms,
135
+ working_directory: str,
136
+ executable_function: callable,
137
+ max_electronic_steps: int = 100,
138
+ energy_cutoff_in_eV: float = 500.0,
139
+ kpoint_coords: Optional[list[float, float, float]] = None,
140
+ kpoint_folding: Optional[list[int, int, int]] = None,
141
+ output_keys=OutputStatic.keys(),
142
+ ) -> dict:
143
+ if kpoint_coords is None:
144
+ kpoint_coords = [0.5, 0.5, 0.5]
145
+ if kpoint_folding is None:
146
+ kpoint_folding = [3, 3, 3]
147
+ input_sx = _generate_input(
148
+ structure=structure,
149
+ maxSteps=max_electronic_steps,
150
+ energy_cutoff_in_eV=energy_cutoff_in_eV,
151
+ kpoint_coords=kpoint_coords,
152
+ kpoint_folding=kpoint_folding,
153
+ )
154
+ with open(os.path.join(working_directory, "input.sx"), "w") as f:
155
+ f.write(to_sphinx(input_sx))
156
+ executable_function(working_directory)
157
+ output_obj = OutputParser(working_directory=working_directory, structure=structure)
158
+ result_dict = OutputStatic(
159
+ forces=output_obj.get_forces,
160
+ energy=output_obj.get_energy,
161
+ stress=output_obj.get_stress,
162
+ volume=output_obj.get_volume,
163
+ ).get(output_keys=output_keys)
164
+ return result_dict
165
+
166
+
167
+ @as_task_dict_evaluator
168
+ def evaluate_with_sphinx(
169
+ structure: Atoms,
170
+ tasks: list,
171
+ working_directory: str,
172
+ executable_function: callable,
173
+ max_electronic_steps: int = 100,
174
+ energy_cutoff_in_eV: float = 500,
175
+ kpoint_coords: Optional[list[float, float, float]] = None,
176
+ kpoint_folding: Optional[list[int, int, int]] = None,
177
+ sphinx_optimizer_kwargs: Optional[dict] = None,
178
+ ) -> dict:
179
+ if kpoint_coords is None:
180
+ kpoint_coords = [0.5, 0.5, 0.5]
181
+ if kpoint_folding is None:
182
+ kpoint_folding = [3, 3, 3]
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:
200
+ return calc_static_with_sphinxdft(
201
+ structure=structure,
202
+ max_electronic_steps=max_electronic_steps,
203
+ energy_cutoff_in_eV=energy_cutoff_in_eV,
204
+ kpoint_coords=kpoint_coords,
205
+ kpoint_folding=kpoint_folding,
206
+ working_directory=working_directory,
207
+ executable_function=executable_function,
208
+ output_keys=get_quantities_from_tasks(tasks=tasks),
209
+ )
210
+ else:
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.0
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
@@ -48,12 +48,12 @@ Classifier: Programming Language :: Python :: 3.12
48
48
  Requires-Python: <3.13,>=3.9
49
49
  Description-Content-Type: text/markdown
50
50
  License-File: LICENSE
51
- Requires-Dist: ase<=3.24.0,>=3.22.1
52
- Requires-Dist: numpy<=1.26.4,>=1.26.0
51
+ Requires-Dist: ase<=3.24.0,>=3.23.0
52
+ 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.37.0,>=2.20.0; extra == "phonopy"
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
@@ -62,22 +62,26 @@ Provides-Extra: lammps
62
62
  Requires-Dist: pylammpsmpi<=0.2.31,>=0.2.1; extra == "lammps"
63
63
  Requires-Dist: jinja2<=3.1.5,>=2.11.3; extra == "lammps"
64
64
  Requires-Dist: pandas<=2.2.3,>=2.0.3; extra == "lammps"
65
- Requires-Dist: pyiron_lammps==0.3.2; extra == "lammps"
65
+ Requires-Dist: pyiron_lammps<=0.4.0,>=0.3.2; extra == "lammps"
66
66
  Provides-Extra: lammps-phonons
67
67
  Requires-Dist: pylammpsmpi<=0.2.31,>=0.2.1; extra == "lammps-phonons"
68
68
  Requires-Dist: jinja2<=3.1.5,>=2.11.3; extra == "lammps-phonons"
69
69
  Requires-Dist: pandas<=2.2.3,>=2.0.3; extra == "lammps-phonons"
70
70
  Requires-Dist: dynaphopy<=1.17.16,>=1.17.5; extra == "lammps-phonons"
71
- Requires-Dist: pyiron_lammps==0.3.2; extra == "lammps-phonons"
71
+ Requires-Dist: pyiron_lammps<=0.4.0,>=0.3.2; extra == "lammps-phonons"
72
72
  Provides-Extra: experimental
73
73
  Requires-Dist: lxml<=5.3.1,>=4.9.1; extra == "experimental"
74
74
  Requires-Dist: mendeleev<=0.19.0,>=0.12.0; extra == "experimental"
75
75
  Requires-Dist: pandas<=2.2.3,>=2.0.3; extra == "experimental"
76
76
  Requires-Dist: requests<=2.32.3,>=2.24.0; extra == "experimental"
77
+ Provides-Extra: sphinxdft
78
+ Requires-Dist: sphinx-parser==0.0.1; extra == "sphinxdft"
77
79
  Provides-Extra: qe
78
- Requires-Dist: pwtools==1.2.3; extra == "qe"
80
+ Requires-Dist: pwtools==1.3.0; extra == "qe"
79
81
  Provides-Extra: tqdm
80
82
  Requires-Dist: tqdm==4.67.1; extra == "tqdm"
83
+ Provides-Extra: vasp
84
+ Requires-Dist: pyiron_vasp==0.2.4; extra == "vasp"
81
85
 
82
86
  # atomistics
83
87
  [![Pipeline](https://github.com/pyiron/atomistics/actions/workflows/pipeline.yml/badge.svg)](https://github.com/pyiron/atomistics/actions/workflows/pipeline.yml)
@@ -15,6 +15,8 @@ atomistics/calculators/ase.py
15
15
  atomistics/calculators/hessian.py
16
16
  atomistics/calculators/interface.py
17
17
  atomistics/calculators/qe.py
18
+ atomistics/calculators/sphinxdft.py
19
+ atomistics/calculators/vasp.py
18
20
  atomistics/calculators/wrapper.py
19
21
  atomistics/calculators/lammps/__init__.py
20
22
  atomistics/calculators/lammps/commands.py
@@ -69,6 +71,7 @@ tests/test_evcurve_lammpslib.py
69
71
  tests/test_evcurve_lammpslib_function_parallel.py
70
72
  tests/test_evcurve_lammpslib_functional.py
71
73
  tests/test_evcurve_qe.py
74
+ tests/test_evcurve_sphinxdft.py
72
75
  tests/test_hessian_lammpslib.py
73
76
  tests/test_lammps_calculator.py
74
77
  tests/test_lammpslib_md.py
@@ -85,4 +88,6 @@ tests/test_phonons_lammpslib_functional.py
85
88
  tests/test_quasiharmonic_ase_emt.py
86
89
  tests/test_quasiharmonic_lammpslib.py
87
90
  tests/test_quasiharmonic_lammpslib_functional.py
88
- tests/test_referencedata.py
91
+ tests/test_referencedata.py
92
+ tests/test_sphinx_parser.py
93
+ tests/test_vasp_parser.py
@@ -1,5 +1,5 @@
1
- ase<=3.24.0,>=3.22.1
2
- numpy<=1.26.4,>=1.26.0
1
+ ase<=3.24.0,>=3.23.0
2
+ numpy==1.26.4
3
3
  scipy<=1.15.2,>=1.11.1
4
4
  spglib<=2.5.0,>=2.0.2
5
5
 
@@ -16,22 +16,28 @@ gpaw<=24.6.0,>=20.1.0
16
16
  pylammpsmpi<=0.2.31,>=0.2.1
17
17
  jinja2<=3.1.5,>=2.11.3
18
18
  pandas<=2.2.3,>=2.0.3
19
- pyiron_lammps==0.3.2
19
+ pyiron_lammps<=0.4.0,>=0.3.2
20
20
 
21
21
  [lammps_phonons]
22
22
  pylammpsmpi<=0.2.31,>=0.2.1
23
23
  jinja2<=3.1.5,>=2.11.3
24
24
  pandas<=2.2.3,>=2.0.3
25
25
  dynaphopy<=1.17.16,>=1.17.5
26
- pyiron_lammps==0.3.2
26
+ pyiron_lammps<=0.4.0,>=0.3.2
27
27
 
28
28
  [phonopy]
29
- phonopy<=2.37.0,>=2.20.0
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.2.3
34
+ pwtools==1.3.0
35
+
36
+ [sphinxdft]
37
+ sphinx-parser==0.0.1
35
38
 
36
39
  [tqdm]
37
40
  tqdm==4.67.1
41
+
42
+ [vasp]
43
+ pyiron_vasp==0.2.4