atomistics 0.2.2__tar.gz → 0.2.4__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 (97) hide show
  1. {atomistics-0.2.2/atomistics.egg-info → atomistics-0.2.4}/PKG-INFO +4 -4
  2. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/_version.py +3 -3
  3. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/__init__.py +23 -0
  4. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/ase.py +53 -2
  5. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/interface.py +4 -0
  6. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/vasp.py +107 -1
  7. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/__init__.py +4 -0
  8. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/evcurve/fit.py +11 -109
  9. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/structure_optimization.py +28 -0
  10. {atomistics-0.2.2 → atomistics-0.2.4/atomistics.egg-info}/PKG-INFO +4 -4
  11. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics.egg-info/requires.txt +3 -3
  12. {atomistics-0.2.2 → atomistics-0.2.4}/pyproject.toml +3 -3
  13. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_calc_stress_ase_emt.py +3 -3
  14. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_elastic_ase_emt.py +3 -4
  15. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_evcurve_ase_emt.py +3 -4
  16. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_evcurve_ase_lammps.py +3 -4
  17. atomistics-0.2.4/tests/test_optimize_positions_ase_emt.py +108 -0
  18. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_phonons_ase_emt.py +3 -3
  19. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_quasiharmonic_ase_emt.py +3 -3
  20. atomistics-0.2.4/tests/test_vasp_parser.py +156 -0
  21. atomistics-0.2.2/tests/test_optimize_positions_ase_emt.py +0 -31
  22. atomistics-0.2.2/tests/test_vasp_parser.py +0 -68
  23. {atomistics-0.2.2 → atomistics-0.2.4}/LICENSE +0 -0
  24. {atomistics-0.2.2 → atomistics-0.2.4}/MANIFEST.in +0 -0
  25. {atomistics-0.2.2 → atomistics-0.2.4}/README.md +0 -0
  26. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/__init__.py +0 -0
  27. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/hessian.py +0 -0
  28. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/lammps/__init__.py +0 -0
  29. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/lammps/commands.py +0 -0
  30. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/lammps/filecalculator.py +0 -0
  31. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/lammps/helpers.py +0 -0
  32. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/lammps/libcalculator.py +0 -0
  33. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/lammps/phonon.py +0 -0
  34. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/lammps/potential.py +0 -0
  35. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/qe.py +0 -0
  36. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/sphinxdft.py +0 -0
  37. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/calculators/wrapper.py +0 -0
  38. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/referencedata/__init__.py +0 -0
  39. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/referencedata/mendeleev.py +0 -0
  40. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/referencedata/wikipedia.py +0 -0
  41. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/referencedata/wolframalpha.py +0 -0
  42. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/shared/__init__.py +0 -0
  43. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/shared/output.py +0 -0
  44. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/shared/parallel.py +0 -0
  45. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/shared/thermal_expansion.py +0 -0
  46. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/shared/tqdm_iterator.py +0 -0
  47. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/elastic/__init__.py +0 -0
  48. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/elastic/elastic_moduli.py +0 -0
  49. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/elastic/helper.py +0 -0
  50. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/elastic/symmetry.py +0 -0
  51. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/elastic/workflow.py +0 -0
  52. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/evcurve/__init__.py +0 -0
  53. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/evcurve/debye.py +0 -0
  54. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/evcurve/helper.py +0 -0
  55. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/evcurve/thermo.py +0 -0
  56. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/evcurve/workflow.py +0 -0
  57. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/interface.py +0 -0
  58. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/langevin.py +0 -0
  59. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/molecular_dynamics.py +0 -0
  60. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/phonons/__init__.py +0 -0
  61. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/phonons/helper.py +0 -0
  62. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/phonons/units.py +0 -0
  63. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/phonons/workflow.py +0 -0
  64. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics/workflows/quasiharmonic.py +0 -0
  65. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics.egg-info/SOURCES.txt +0 -0
  66. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics.egg-info/dependency_links.txt +0 -0
  67. {atomistics-0.2.2 → atomistics-0.2.4}/atomistics.egg-info/top_level.txt +0 -0
  68. {atomistics-0.2.2 → atomistics-0.2.4}/setup.cfg +0 -0
  69. {atomistics-0.2.2 → atomistics-0.2.4}/setup.py +0 -0
  70. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_abstract_workflow_class.py +0 -0
  71. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_ase_md_emt.py +0 -0
  72. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_calc_stress_lammpslib.py +0 -0
  73. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_elastic_helper.py +0 -0
  74. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_elastic_lammpslib.py +0 -0
  75. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_elastic_lammpslib_functional.py +0 -0
  76. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_evcurve_eos.py +0 -0
  77. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_evcurve_lammpsfile.py +0 -0
  78. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_evcurve_lammpslib.py +0 -0
  79. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_evcurve_lammpslib_function_parallel.py +0 -0
  80. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_evcurve_lammpslib_functional.py +0 -0
  81. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_evcurve_qe.py +0 -0
  82. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_evcurve_sphinxdft.py +0 -0
  83. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_hessian_lammpslib.py +0 -0
  84. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_lammps_calculator.py +0 -0
  85. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_lammpslib_md.py +0 -0
  86. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_lammpslib_md_phonons.py +0 -0
  87. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_langevin_lammpslib.py +0 -0
  88. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_molecular_dynamics_thermal_expansion_lammpslib.py +0 -0
  89. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_optimize_positions_lammpsfile.py +0 -0
  90. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_optimize_positions_lammpslib.py +0 -0
  91. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_phonons_lammpsfile.py +0 -0
  92. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_phonons_lammpslib.py +0 -0
  93. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_phonons_lammpslib_functional.py +0 -0
  94. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_quasiharmonic_lammpslib.py +0 -0
  95. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_quasiharmonic_lammpslib_functional.py +0 -0
  96. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_referencedata.py +0 -0
  97. {atomistics-0.2.2 → atomistics-0.2.4}/tests/test_sphinx_parser.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: atomistics
3
- Version: 0.2.2
3
+ Version: 0.2.4
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
@@ -51,7 +51,7 @@ License-File: LICENSE
51
51
  Requires-Dist: ase<=3.24.0,>=3.23.0
52
52
  Requires-Dist: numpy==1.26.4
53
53
  Requires-Dist: scipy<=1.15.2,>=1.11.1
54
- Requires-Dist: spglib<=2.5.0,>=2.0.2
54
+ Requires-Dist: spglib<=2.6.0,>=2.0.2
55
55
  Provides-Extra: phonopy
56
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"
@@ -60,12 +60,12 @@ Provides-Extra: gpaw
60
60
  Requires-Dist: gpaw<=24.6.0,>=20.1.0; extra == "gpaw"
61
61
  Provides-Extra: lammps
62
62
  Requires-Dist: pylammpsmpi<=0.2.31,>=0.2.1; extra == "lammps"
63
- Requires-Dist: jinja2<=3.1.5,>=2.11.3; extra == "lammps"
63
+ Requires-Dist: jinja2<=3.1.6,>=2.11.3; extra == "lammps"
64
64
  Requires-Dist: pandas<=2.2.3,>=2.0.3; extra == "lammps"
65
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
- Requires-Dist: jinja2<=3.1.5,>=2.11.3; extra == "lammps-phonons"
68
+ Requires-Dist: jinja2<=3.1.6,>=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
71
  Requires-Dist: pyiron_lammps<=0.4.0,>=0.3.2; extra == "lammps-phonons"
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2025-03-05T08:13:01+0100",
11
+ "date": "2025-03-10T21:45:26+0000",
12
12
  "dirty": true,
13
13
  "error": null,
14
- "full-revisionid": "5b518f33f60f904bf2c88dff51b72a07fe99091c",
15
- "version": "0.2.2"
14
+ "full-revisionid": "bb2b344b87932e4d5e02a4e7f44a87da5c83202b",
15
+ "version": "0.2.4"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -6,6 +6,7 @@ from atomistics.calculators.ase import (
6
6
  evaluate_with_ase,
7
7
  optimize_positions_and_volume_with_ase,
8
8
  optimize_positions_with_ase,
9
+ optimize_volume_with_ase,
9
10
  )
10
11
  from atomistics.calculators.hessian import evaluate_with_hessian
11
12
 
@@ -17,6 +18,7 @@ __all__ = [
17
18
  "evaluate_with_ase",
18
19
  "optimize_positions_with_ase",
19
20
  "optimize_positions_and_volume_with_ase",
21
+ "optimize_volume_with_ase",
20
22
  "evaluate_with_hessian",
21
23
  ]
22
24
 
@@ -88,3 +90,24 @@ try:
88
90
  ]
89
91
  except ImportError:
90
92
  pass
93
+
94
+ try:
95
+ from atomistics.calculators.vasp import (
96
+ calc_static_with_vasp,
97
+ evaluate_with_vasp,
98
+ optimize_cell_with_vasp,
99
+ optimize_positions_and_volume_with_vasp,
100
+ optimize_positions_with_vasp,
101
+ optimize_volume_with_vasp,
102
+ )
103
+
104
+ __all__ += [
105
+ "evaluate_with_vasp",
106
+ "calc_static_with_vasp",
107
+ "optimize_positions_and_volume_with_vasp",
108
+ "optimize_positions_with_vasp",
109
+ "optimize_cell_with_vasp",
110
+ "optimize_volume_with_vasp",
111
+ ]
112
+ except ImportError:
113
+ pass
@@ -5,7 +5,8 @@ from ase import units
5
5
  from ase.atoms import Atoms
6
6
  from ase.calculators.calculator import Calculator as ASECalculator
7
7
  from ase.calculators.calculator import PropertyNotImplementedError
8
- from ase.constraints import UnitCellFilter
8
+ from ase.constraints import FixAtoms
9
+ from ase.filters import Filter, UnitCellFilter
9
10
  from ase.md.langevin import Langevin
10
11
  from ase.md.npt import NPT
11
12
  from ase.md.velocitydistribution import MaxwellBoltzmannDistribution
@@ -149,6 +150,7 @@ def evaluate_with_ase(
149
150
  ase_calculator: ASECalculator,
150
151
  ase_optimizer: Optimizer = None,
151
152
  ase_optimizer_kwargs: dict = None,
153
+ filter_class: Filter = UnitCellFilter,
152
154
  ) -> dict:
153
155
  """
154
156
  Evaluate tasks using ASE calculator.
@@ -159,6 +161,7 @@ def evaluate_with_ase(
159
161
  ase_calculator (ASECalculator): The ASE calculator object.
160
162
  ase_optimizer (Optimizer, optional): The ASE optimizer object. Defaults to None.
161
163
  ase_optimizer_kwargs (dict, optional): Keyword arguments for the ASE optimizer. Defaults to {}.
164
+ filter_class (Filter): The ASE filter class to use for filtering during structure optimization.
162
165
 
163
166
  Returns:
164
167
  dict: Dictionary containing the results of the evaluated tasks.
@@ -180,8 +183,17 @@ def evaluate_with_ase(
180
183
  ase_calculator=ase_calculator,
181
184
  ase_optimizer=ase_optimizer,
182
185
  ase_optimizer_kwargs=ase_optimizer_kwargs,
186
+ filter_class=filter_class,
183
187
  )
184
188
  )
189
+ elif "optimize_volume" in tasks:
190
+ results["structure_with_optimized_volume"] = optimize_volume_with_ase(
191
+ structure=structure,
192
+ ase_calculator=ase_calculator,
193
+ ase_optimizer=ase_optimizer,
194
+ ase_optimizer_kwargs=ase_optimizer_kwargs,
195
+ filter_class=filter_class,
196
+ )
185
197
  elif "calc_energy" in tasks or "calc_forces" in tasks or "calc_stress" in tasks:
186
198
  return calc_static_with_ase(
187
199
  structure=structure,
@@ -287,6 +299,7 @@ def optimize_positions_and_volume_with_ase(
287
299
  ase_calculator: ASECalculator,
288
300
  ase_optimizer: Optimizer,
289
301
  ase_optimizer_kwargs: dict,
302
+ filter_class: Filter = UnitCellFilter,
290
303
  ) -> Atoms:
291
304
  """
292
305
  Optimize the atomic positions and cell volume of the structure using ASE optimizer.
@@ -296,13 +309,51 @@ def optimize_positions_and_volume_with_ase(
296
309
  ase_calculator (ASECalculator): The ASE calculator object.
297
310
  ase_optimizer (Optimizer): The ASE optimizer object.
298
311
  ase_optimizer_kwargs (dict): Keyword arguments for the ASE optimizer.
312
+ filter_class (Filter): The ASE filter class to use for filtering during structure optimization.
313
+
314
+ Returns:
315
+ Atoms: The optimized structure.
316
+ """
317
+ structure_optimized = structure.copy()
318
+ structure_optimized.calc = ase_calculator
319
+ ase_optimizer_obj = ase_optimizer(filter_class(structure_optimized))
320
+ ase_optimizer_obj.run(**ase_optimizer_kwargs)
321
+ return structure_optimized
322
+
323
+
324
+ def optimize_volume_with_ase(
325
+ structure: Atoms,
326
+ ase_calculator: ASECalculator,
327
+ ase_optimizer: Optimizer,
328
+ ase_optimizer_kwargs: dict,
329
+ filter_class: Filter = UnitCellFilter,
330
+ hydrostatic_strain: bool = True,
331
+ ) -> Atoms:
332
+ """
333
+ Optimize the cell volume of the structure using ASE optimizer.
334
+
335
+ Args:
336
+ structure (Atoms): The ASE structure object.
337
+ ase_calculator (ASECalculator): The ASE calculator object.
338
+ ase_optimizer (Optimizer): The ASE optimizer object.
339
+ ase_optimizer_kwargs (dict): Keyword arguments for the ASE optimizer.
340
+ filter_class (Filter): The ASE filter class to use for filtering during structure optimization.
341
+ hydrostatic_strain (bool): Constrain the cell by only allowing hydrostatic deformation.
299
342
 
300
343
  Returns:
301
344
  Atoms: The optimized structure.
302
345
  """
303
346
  structure_optimized = structure.copy()
304
347
  structure_optimized.calc = ase_calculator
305
- ase_optimizer_obj = ase_optimizer(UnitCellFilter(structure_optimized))
348
+ structure_optimized.set_constraint(
349
+ FixAtoms(np.ones(len(structure_optimized), dtype=bool))
350
+ )
351
+ ase_optimizer_obj = ase_optimizer(
352
+ filter_class(
353
+ atoms=structure_optimized,
354
+ hydrostatic_strain=hydrostatic_strain,
355
+ )
356
+ )
306
357
  ase_optimizer_obj.run(**ase_optimizer_kwargs)
307
358
  return structure_optimized
308
359
 
@@ -19,6 +19,8 @@ class TaskEnum(StrEnum):
19
19
  calc_stress = "calc_stress"
20
20
  optimize_positions = "optimize_positions"
21
21
  optimize_positions_and_volume = "optimize_positions_and_volume"
22
+ optimize_volume = "optimize_volume"
23
+ optimize_cell = "optimize_cell"
22
24
  calc_molecular_dynamics_thermal_expansion = (
23
25
  "calc_molecular_dynamics_thermal_expansion"
24
26
  )
@@ -28,8 +30,10 @@ class TaskOutputEnum(Enum):
28
30
  energy = "calc_energy"
29
31
  forces = "calc_forces"
30
32
  stress = "calc_stress"
33
+ structure_with_optimized_cell = "optimize_cell"
31
34
  structure_with_optimized_positions = "optimize_positions"
32
35
  structure_with_optimized_positions_and_volume = "optimize_positions_and_volume"
36
+ structure_with_optimized_volume = "optimize_volume"
33
37
  volume_over_temperature = "calc_molecular_dynamics_thermal_expansion"
34
38
 
35
39
 
@@ -155,6 +155,86 @@ def optimize_positions_and_volume_with_vasp(
155
155
  return structure_copy
156
156
 
157
157
 
158
+ def optimize_volume_with_vasp(
159
+ structure: Atoms,
160
+ working_directory: str,
161
+ executable_function: callable,
162
+ prec: str = "Accurate",
163
+ algo: str = "Fast",
164
+ lreal: bool = False,
165
+ lwave: bool = False,
166
+ lorbit: int = 0,
167
+ isif: int = 7,
168
+ ibrion: int = 2,
169
+ nsw: int = 100,
170
+ kpts: Optional[list[int, int, int]] = None,
171
+ **kwargs,
172
+ ) -> Atoms:
173
+ if kpts is None:
174
+ kpts = [4, 4, 4]
175
+ write_input(
176
+ working_directory=working_directory,
177
+ atoms=structure,
178
+ prec=prec,
179
+ algo=algo,
180
+ lreal=lreal,
181
+ lwave=lwave,
182
+ lorbit=lorbit,
183
+ kpts=kpts,
184
+ isif=isif,
185
+ ibrion=ibrion,
186
+ nsw=nsw,
187
+ **kwargs,
188
+ )
189
+ executable_function(working_directory)
190
+ output_dict = parse_vasp_output(
191
+ working_directory=working_directory, structure=structure
192
+ )
193
+ structure_copy = structure.copy()
194
+ structure_copy.set_cell(output_dict["generic"]["cells"][-1], scale_atoms=True)
195
+ return structure_copy
196
+
197
+
198
+ def optimize_cell_with_vasp(
199
+ structure: Atoms,
200
+ working_directory: str,
201
+ executable_function: callable,
202
+ prec: str = "Accurate",
203
+ algo: str = "Fast",
204
+ lreal: bool = False,
205
+ lwave: bool = False,
206
+ lorbit: int = 0,
207
+ isif: int = 5,
208
+ ibrion: int = 2,
209
+ nsw: int = 100,
210
+ kpts: Optional[list[int, int, int]] = None,
211
+ **kwargs,
212
+ ) -> Atoms:
213
+ if kpts is None:
214
+ kpts = [4, 4, 4]
215
+ write_input(
216
+ working_directory=working_directory,
217
+ atoms=structure,
218
+ prec=prec,
219
+ algo=algo,
220
+ lreal=lreal,
221
+ lwave=lwave,
222
+ lorbit=lorbit,
223
+ kpts=kpts,
224
+ isif=isif,
225
+ ibrion=ibrion,
226
+ nsw=nsw,
227
+ **kwargs,
228
+ )
229
+ executable_function(working_directory)
230
+ output_dict = parse_vasp_output(
231
+ working_directory=working_directory, structure=structure
232
+ )
233
+ structure_copy = structure.copy()
234
+ structure_copy.set_cell(output_dict["generic"]["cells"][-1], scale_atoms=True)
235
+ return structure_copy
236
+
237
+
158
238
  @as_task_dict_evaluator
159
239
  def evaluate_with_vasp(
160
240
  structure: Atoms,
@@ -172,7 +252,20 @@ def evaluate_with_vasp(
172
252
  if kpts is None:
173
253
  kpts = [4, 4, 4]
174
254
  results = {}
175
- if "optimize_positions_and_volume" in tasks:
255
+ if "optimize_cell" in tasks:
256
+ results["structure_with_optimized_cell"] = optimize_cell_with_vasp(
257
+ structure=structure,
258
+ working_directory=working_directory,
259
+ executable_function=executable_function,
260
+ prec=prec,
261
+ algo=algo,
262
+ lreal=lreal,
263
+ lwave=lwave,
264
+ lorbit=lorbit,
265
+ kpts=kpts,
266
+ **kwargs,
267
+ )
268
+ elif "optimize_positions_and_volume" in tasks:
176
269
  results["structure_with_optimized_positions_and_volume"] = (
177
270
  optimize_positions_and_volume_with_vasp(
178
271
  structure=structure,
@@ -200,6 +293,19 @@ def evaluate_with_vasp(
200
293
  kpts=kpts,
201
294
  **kwargs,
202
295
  )
296
+ elif "optimize_volume" in tasks:
297
+ results["structure_with_optimized_volume"] = optimize_volume_with_vasp(
298
+ structure=structure,
299
+ working_directory=working_directory,
300
+ executable_function=executable_function,
301
+ prec=prec,
302
+ algo=algo,
303
+ lreal=lreal,
304
+ lwave=lwave,
305
+ lorbit=lorbit,
306
+ kpts=kpts,
307
+ **kwargs,
308
+ )
203
309
  elif "calc_energy" in tasks or "calc_forces" in tasks or "calc_stress" in tasks:
204
310
  return calc_static_with_vasp(
205
311
  structure=structure,
@@ -5,8 +5,10 @@ from atomistics.workflows.molecular_dynamics import (
5
5
  calc_molecular_dynamics_thermal_expansion,
6
6
  )
7
7
  from atomistics.workflows.structure_optimization import (
8
+ optimize_cell,
8
9
  optimize_positions,
9
10
  optimize_positions_and_volume,
11
+ optimize_volume,
10
12
  )
11
13
 
12
14
  __all__ = [
@@ -14,8 +16,10 @@ __all__ = [
14
16
  "EnergyVolumeCurveWorkflow",
15
17
  "LangevinWorkflow",
16
18
  "calc_molecular_dynamics_thermal_expansion",
19
+ "optimize_cell",
17
20
  "optimize_positions",
18
21
  "optimize_positions_and_volume",
22
+ "optimize_volume",
19
23
  ]
20
24
 
21
25
 
@@ -1,121 +1,23 @@
1
1
  import numpy as np
2
2
  import scipy.constants
3
3
  import scipy.optimize
4
+ from ase.eos import (
5
+ birch,
6
+ murnaghan,
7
+ pouriertarantola,
8
+ )
9
+ from ase.eos import (
10
+ birchmurnaghan as birchmurnaghan_energy,
11
+ )
12
+ from ase.eos import (
13
+ vinet as vinet_energy,
14
+ )
4
15
 
5
16
  eV_div_A3_to_GPa = (
6
17
  1e21 / scipy.constants.physical_constants["joule-electron volt relationship"][0]
7
18
  )
8
19
 
9
20
 
10
- # https://gitlab.com/ase/ase/blob/master/ase/eos.py
11
- def birchmurnaghan_energy(
12
- V: np.ndarray, E0: float, B0: float, BP: float, V0: float
13
- ) -> np.ndarray:
14
- """
15
- BirchMurnaghan equation from PRB 70, 224107
16
-
17
- Args:
18
- V (np.ndarray): Array of volumes
19
- E0 (float): Energy at equilibrium volume
20
- B0 (float): Bulk modulus at equilibrium volume
21
- BP (float): Pressure derivative of bulk modulus
22
- V0 (float): Equilibrium volume
23
-
24
- Returns:
25
- np.ndarray: Array of energies
26
- """
27
- eta = (V0 / V) ** (1 / 3)
28
- return E0 + 9 * B0 * V0 / 16 * (eta**2 - 1) ** 2 * (
29
- 6 + BP * (eta**2 - 1) - 4 * eta**2
30
- )
31
-
32
-
33
- def vinet_energy(
34
- V: np.ndarray, E0: float, B0: float, BP: float, V0: float
35
- ) -> np.ndarray:
36
- """
37
- Vinet equation from PRB 70, 224107
38
-
39
- Args:
40
- V (np.ndarray): Array of volumes
41
- E0 (float): Energy at equilibrium volume
42
- B0 (float): Bulk modulus at equilibrium volume
43
- BP (float): Pressure derivative of bulk modulus
44
- V0 (float): Equilibrium volume
45
-
46
- Returns:
47
- np.ndarray: Array of energies
48
- """
49
- eta = (V / V0) ** (1 / 3)
50
- return E0 + 2 * B0 * V0 / (BP - 1) ** 2 * (
51
- 2 - (5 + 3 * BP * (eta - 1) - 3 * eta) * np.exp(-3 * (BP - 1) * (eta - 1) / 2)
52
- )
53
-
54
-
55
- def murnaghan(V: np.ndarray, E0: float, B0: float, BP: float, V0: float) -> np.ndarray:
56
- """
57
- Murnaghan equation from PRB 28, 5480 (1983)
58
-
59
- Args:
60
- V (np.ndarray): Array of volumes
61
- E0 (float): Energy at equilibrium volume
62
- B0 (float): Bulk modulus at equilibrium volume
63
- BP (float): Pressure derivative of bulk modulus
64
- V0 (float): Equilibrium volume
65
-
66
- Returns:
67
- np.ndarray: Array of energies
68
- """
69
- E = E0 + B0 * V / BP * (((V0 / V) ** BP) / (BP - 1) + 1) - V0 * B0 / (BP - 1)
70
- return E
71
-
72
-
73
- def birch(V: np.ndarray, E0: float, B0: float, BP: float, V0: float) -> np.ndarray:
74
- """
75
- Birch equation from Intermetallic compounds: Principles and Practice, Vol. I: Principles
76
- Chapter 9 pages 195-210 by M. Mehl. B. Klein, D. Papaconstantopoulos
77
-
78
- Args:
79
- V (np.ndarray): Array of volumes
80
- E0 (float): Energy at equilibrium volume
81
- B0 (float): Bulk modulus at equilibrium volume
82
- BP (float): Pressure derivative of bulk modulus
83
- V0 (float): Equilibrium volume
84
-
85
- Returns:
86
- np.ndarray: Array of energies
87
- """
88
- E = (
89
- E0
90
- + 9 / 8 * B0 * V0 * ((V0 / V) ** (2 / 3) - 1) ** 2
91
- + 9 / 16 * B0 * V0 * (BP - 4) * ((V0 / V) ** (2 / 3) - 1) ** 3
92
- )
93
- return E
94
-
95
-
96
- def pouriertarantola(
97
- V: np.ndarray, E0: float, B0: float, BP: float, V0: float
98
- ) -> np.ndarray:
99
- """
100
- Pourier-Tarantola equation from PRB 70, 224107
101
-
102
- Args:
103
- V (np.ndarray): Array of volumes
104
- E0 (float): Energy at equilibrium volume
105
- B0 (float): Bulk modulus at equilibrium volume
106
- BP (float): Pressure derivative of bulk modulus
107
- V0 (float): Equilibrium volume
108
-
109
- Returns:
110
- np.ndarray: Array of energies
111
- """
112
- eta = (V / V0) ** (1 / 3)
113
- squiggle = -3 * np.log(eta)
114
-
115
- E = E0 + B0 * V0 * squiggle**2 / 6 * (3 + squiggle * (BP - 2))
116
- return E
117
-
118
-
119
21
  def fitfunction(
120
22
  parameters: tuple[float], vol: np.ndarray, fittype: str = "vinet"
121
23
  ) -> np.ndarray:
@@ -15,6 +15,34 @@ def optimize_positions_and_volume(structure: Atoms) -> dict:
15
15
  return {"optimize_positions_and_volume": structure}
16
16
 
17
17
 
18
+ def optimize_volume(structure: Atoms) -> dict:
19
+ """
20
+ Optimize the volume of the given structure.
21
+
22
+ Parameters:
23
+ structure (Atoms): The structure to be optimized.
24
+
25
+ Returns:
26
+ dict: A dictionary containing the optimized structure.
27
+
28
+ """
29
+ return {"optimize_volume": structure}
30
+
31
+
32
+ def optimize_cell(structure: Atoms) -> dict:
33
+ """
34
+ Optimize the cell of the given structure.
35
+
36
+ Parameters:
37
+ structure (Atoms): The structure to be optimized.
38
+
39
+ Returns:
40
+ dict: A dictionary containing the optimized structure.
41
+
42
+ """
43
+ return {"optimize_cell": structure}
44
+
45
+
18
46
  def optimize_positions(structure: Atoms) -> dict:
19
47
  """
20
48
  Optimize the positions of the given structure.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: atomistics
3
- Version: 0.2.2
3
+ Version: 0.2.4
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
@@ -51,7 +51,7 @@ License-File: LICENSE
51
51
  Requires-Dist: ase<=3.24.0,>=3.23.0
52
52
  Requires-Dist: numpy==1.26.4
53
53
  Requires-Dist: scipy<=1.15.2,>=1.11.1
54
- Requires-Dist: spglib<=2.5.0,>=2.0.2
54
+ Requires-Dist: spglib<=2.6.0,>=2.0.2
55
55
  Provides-Extra: phonopy
56
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"
@@ -60,12 +60,12 @@ Provides-Extra: gpaw
60
60
  Requires-Dist: gpaw<=24.6.0,>=20.1.0; extra == "gpaw"
61
61
  Provides-Extra: lammps
62
62
  Requires-Dist: pylammpsmpi<=0.2.31,>=0.2.1; extra == "lammps"
63
- Requires-Dist: jinja2<=3.1.5,>=2.11.3; extra == "lammps"
63
+ Requires-Dist: jinja2<=3.1.6,>=2.11.3; extra == "lammps"
64
64
  Requires-Dist: pandas<=2.2.3,>=2.0.3; extra == "lammps"
65
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
- Requires-Dist: jinja2<=3.1.5,>=2.11.3; extra == "lammps-phonons"
68
+ Requires-Dist: jinja2<=3.1.6,>=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
71
  Requires-Dist: pyiron_lammps<=0.4.0,>=0.3.2; extra == "lammps-phonons"
@@ -1,7 +1,7 @@
1
1
  ase<=3.24.0,>=3.23.0
2
2
  numpy==1.26.4
3
3
  scipy<=1.15.2,>=1.11.1
4
- spglib<=2.5.0,>=2.0.2
4
+ spglib<=2.6.0,>=2.0.2
5
5
 
6
6
  [experimental]
7
7
  lxml<=5.3.1,>=4.9.1
@@ -14,13 +14,13 @@ gpaw<=24.6.0,>=20.1.0
14
14
 
15
15
  [lammps]
16
16
  pylammpsmpi<=0.2.31,>=0.2.1
17
- jinja2<=3.1.5,>=2.11.3
17
+ jinja2<=3.1.6,>=2.11.3
18
18
  pandas<=2.2.3,>=2.0.3
19
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
- jinja2<=3.1.5,>=2.11.3
23
+ jinja2<=3.1.6,>=2.11.3
24
24
  pandas<=2.2.3,>=2.0.3
25
25
  dynaphopy<=1.17.16,>=1.17.5
26
26
  pyiron_lammps<=0.4.0,>=0.3.2
@@ -27,7 +27,7 @@ dependencies = [
27
27
  "ase>=3.23.0,<=3.24.0",
28
28
  "numpy==1.26.4",
29
29
  "scipy>=1.11.1,<=1.15.2",
30
- "spglib>=2.0.2,<=2.5.0",
30
+ "spglib>=2.0.2,<=2.6.0",
31
31
  ]
32
32
  dynamic = ["version"]
33
33
 
@@ -47,13 +47,13 @@ gpaw = [
47
47
  ]
48
48
  lammps = [
49
49
  "pylammpsmpi>=0.2.1,<=0.2.31",
50
- "jinja2>=2.11.3,<=3.1.5",
50
+ "jinja2>=2.11.3,<=3.1.6",
51
51
  "pandas>=2.0.3,<=2.2.3",
52
52
  "pyiron_lammps>=0.3.2,<=0.4.0",
53
53
  ]
54
54
  lammps_phonons = [
55
55
  "pylammpsmpi>=0.2.1,<=0.2.31",
56
- "jinja2>=2.11.3,<=3.1.5",
56
+ "jinja2>=2.11.3,<=3.1.6",
57
57
  "pandas>=2.0.3,<=2.2.3",
58
58
  "dynaphopy>=1.17.5,<=1.17.16",
59
59
  "pyiron_lammps>=0.3.2,<=0.4.0",
@@ -4,7 +4,7 @@ from ase.optimize import LBFGS
4
4
  import unittest
5
5
 
6
6
  from atomistics.calculators import evaluate_with_ase
7
- from atomistics.workflows import optimize_positions_and_volume
7
+ from atomistics.workflows import optimize_volume
8
8
 
9
9
 
10
10
  class TestStess(unittest.TestCase):
@@ -15,7 +15,7 @@ class TestStess(unittest.TestCase):
15
15
  task_dict=task_dict,
16
16
  ase_calculator=EMT(),
17
17
  )
18
- task_dict = optimize_positions_and_volume(structure=structure)
18
+ task_dict = optimize_volume(structure=structure)
19
19
  result_dict = evaluate_with_ase(
20
20
  task_dict=task_dict,
21
21
  ase_calculator=EMT(),
@@ -23,7 +23,7 @@ class TestStess(unittest.TestCase):
23
23
  ase_optimizer_kwargs={"fmax": 0.000001},
24
24
  )
25
25
  task_dict = {
26
- "calc_stress": result_dict["structure_with_optimized_positions_and_volume"]
26
+ "calc_stress": result_dict["structure_with_optimized_volume"]
27
27
  }
28
28
  stress_post_dict = evaluate_with_ase(
29
29
  task_dict=task_dict,
@@ -1,17 +1,16 @@
1
1
  from ase.build import bulk
2
2
  from ase.calculators.emt import EMT
3
3
  from ase.optimize import LBFGS
4
- import numpy as np
5
4
  import unittest
6
5
 
7
6
  from atomistics.calculators import evaluate_with_ase
8
- from atomistics.workflows import ElasticMatrixWorkflow, optimize_positions_and_volume
7
+ from atomistics.workflows import ElasticMatrixWorkflow, optimize_volume
9
8
 
10
9
 
11
10
  class TestElastic(unittest.TestCase):
12
11
  def test_calc_elastic(self):
13
12
  structure = bulk("Al", cubic=True)
14
- task_dict = optimize_positions_and_volume(structure=structure)
13
+ task_dict = optimize_volume(structure=structure)
15
14
  result_dict = evaluate_with_ase(
16
15
  task_dict=task_dict,
17
16
  ase_calculator=EMT(),
@@ -19,7 +18,7 @@ class TestElastic(unittest.TestCase):
19
18
  ase_optimizer_kwargs={"fmax": 0.000001},
20
19
  )
21
20
  workflow = ElasticMatrixWorkflow(
22
- structure=result_dict["structure_with_optimized_positions_and_volume"],
21
+ structure=result_dict["structure_with_optimized_volume"],
23
22
  num_of_point=5,
24
23
  eps_range=0.005,
25
24
  sqrt_eta=True,