lammpsparser 0.0.3__tar.gz → 0.0.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.
- lammpsparser-0.0.4/.gitignore +218 -0
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/PKG-INFO +3 -1
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/pyproject.toml +1 -0
- lammpsparser-0.0.4/src/lammpsparser/_version.py +24 -0
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/src/lammpsparser/compatibility/calculate.py +5 -4
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/src/lammpsparser/compatibility/constraints.py +3 -3
- lammpsparser-0.0.4/src/lammpsparser/compatibility/data.py +33 -0
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/src/lammpsparser/compatibility/file.py +46 -21
- lammpsparser-0.0.4/src/lammpsparser/compatibility/output.py +38 -0
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/src/lammpsparser/compatibility/structure.py +2 -2
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/src/lammpsparser/output.py +10 -10
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/src/lammpsparser/output_raw.py +7 -7
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/src/lammpsparser/potential.py +4 -4
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/src/lammpsparser/structure.py +14 -12
- lammpsparser-0.0.3/src/lammpsparser/_version.py +0 -34
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/LICENSE +0 -0
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/README.md +0 -0
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/src/lammpsparser/__init__.py +0 -0
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/src/lammpsparser/compatibility/__init__.py +0 -0
- {lammpsparser-0.0.3 → lammpsparser-0.0.4}/src/lammpsparser/units.py +0 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
# Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
# poetry.lock
|
|
109
|
+
# poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
# pdm.lock
|
|
116
|
+
# pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
# pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# Redis
|
|
135
|
+
*.rdb
|
|
136
|
+
*.aof
|
|
137
|
+
*.pid
|
|
138
|
+
|
|
139
|
+
# RabbitMQ
|
|
140
|
+
mnesia/
|
|
141
|
+
rabbitmq/
|
|
142
|
+
rabbitmq-data/
|
|
143
|
+
|
|
144
|
+
# ActiveMQ
|
|
145
|
+
activemq-data/
|
|
146
|
+
|
|
147
|
+
# SageMath parsed files
|
|
148
|
+
*.sage.py
|
|
149
|
+
|
|
150
|
+
# Environments
|
|
151
|
+
.env
|
|
152
|
+
.envrc
|
|
153
|
+
.venv
|
|
154
|
+
env/
|
|
155
|
+
venv/
|
|
156
|
+
ENV/
|
|
157
|
+
env.bak/
|
|
158
|
+
venv.bak/
|
|
159
|
+
|
|
160
|
+
# Spyder project settings
|
|
161
|
+
.spyderproject
|
|
162
|
+
.spyproject
|
|
163
|
+
|
|
164
|
+
# Rope project settings
|
|
165
|
+
.ropeproject
|
|
166
|
+
|
|
167
|
+
# mkdocs documentation
|
|
168
|
+
/site
|
|
169
|
+
|
|
170
|
+
# mypy
|
|
171
|
+
.mypy_cache/
|
|
172
|
+
.dmypy.json
|
|
173
|
+
dmypy.json
|
|
174
|
+
|
|
175
|
+
# Pyre type checker
|
|
176
|
+
.pyre/
|
|
177
|
+
|
|
178
|
+
# pytype static type analyzer
|
|
179
|
+
.pytype/
|
|
180
|
+
|
|
181
|
+
# Cython debug symbols
|
|
182
|
+
cython_debug/
|
|
183
|
+
|
|
184
|
+
# PyCharm
|
|
185
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
186
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
187
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
188
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
189
|
+
# .idea/
|
|
190
|
+
|
|
191
|
+
# Abstra
|
|
192
|
+
# Abstra is an AI-powered process automation framework.
|
|
193
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
194
|
+
# Learn more at https://abstra.io/docs
|
|
195
|
+
.abstra/
|
|
196
|
+
|
|
197
|
+
# Visual Studio Code
|
|
198
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
199
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
200
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
201
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
202
|
+
# .vscode/
|
|
203
|
+
# Temporary file for partial code execution
|
|
204
|
+
tempCodeRunnerFile.py
|
|
205
|
+
|
|
206
|
+
# Ruff stuff:
|
|
207
|
+
.ruff_cache/
|
|
208
|
+
|
|
209
|
+
# PyPI configuration file
|
|
210
|
+
.pypirc
|
|
211
|
+
|
|
212
|
+
# Marimo
|
|
213
|
+
marimo/_static/
|
|
214
|
+
marimo/_lsp/
|
|
215
|
+
__marimo__/
|
|
216
|
+
|
|
217
|
+
# Streamlit
|
|
218
|
+
.streamlit/secrets.toml
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lammpsparser
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: Vector-oriented LAMMPS interface to rapidly iterate over series of atomistic structures or interatomic potentials.
|
|
5
5
|
Project-URL: Homepage, https://github.com/pyiron/lammpsparser
|
|
6
6
|
Project-URL: Documentation, https://github.com/pyiron/lammpsparser
|
|
@@ -53,6 +53,8 @@ Requires-Dist: ase<=3.28.0,>=3.22.1
|
|
|
53
53
|
Requires-Dist: numpy<=2.4.3,>=1.26.0
|
|
54
54
|
Requires-Dist: pandas<=3.0.2,>=2.0.3
|
|
55
55
|
Requires-Dist: scipy<=1.17.1,>=1.11.1
|
|
56
|
+
Provides-Extra: compatibility
|
|
57
|
+
Requires-Dist: structuretoolkit<=0.0.42,>=0.0.30; extra == 'compatibility'
|
|
56
58
|
Provides-Extra: h5md
|
|
57
59
|
Requires-Dist: h5py<=3.16.0,>=3.9.0; extra == 'h5md'
|
|
58
60
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '0.0.4'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 0, 4)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import warnings
|
|
2
|
+
from typing import Any, cast
|
|
2
3
|
|
|
3
4
|
import numpy as np
|
|
4
5
|
from ase.atoms import Atoms
|
|
@@ -121,7 +122,7 @@ def calc_md(
|
|
|
121
122
|
"Target temperature for fix nvt/npt/nph cannot be 0 or negative"
|
|
122
123
|
)
|
|
123
124
|
|
|
124
|
-
force_skewed = False
|
|
125
|
+
# force_skewed = False
|
|
125
126
|
pressure = _pressure_to_lammps(
|
|
126
127
|
pressure=pressure, rotation_matrix=rotation_matrix, units=units
|
|
127
128
|
)
|
|
@@ -139,8 +140,8 @@ def calc_md(
|
|
|
139
140
|
pressure_string += " {0} {1} {1} {2}".format(
|
|
140
141
|
coord, value, pressure_damping_timescale
|
|
141
142
|
)
|
|
142
|
-
if ii > 2:
|
|
143
|
-
|
|
143
|
+
# if ii > 2:
|
|
144
|
+
# force_skewed = True
|
|
144
145
|
|
|
145
146
|
if langevin: # NPT(Langevin)
|
|
146
147
|
fix_ensemble_str = "fix ensemble all nph" + pressure_string
|
|
@@ -277,7 +278,7 @@ def calc_minimize(
|
|
|
277
278
|
pressure=pressure, rotation_matrix=rotation_matrix, units=units
|
|
278
279
|
)
|
|
279
280
|
if np.isscalar(pressure):
|
|
280
|
-
str_press = " iso {}".format(pressure)
|
|
281
|
+
str_press = " iso {}".format(float(cast(Any, pressure)))
|
|
281
282
|
else:
|
|
282
283
|
str_press = ""
|
|
283
284
|
for ii, (press, str_axis) in enumerate(
|
|
@@ -2,7 +2,7 @@ import numpy as np
|
|
|
2
2
|
from ase.atoms import Atoms
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
def _get_fixed_atom_boolean_vector(structure: Atoms):
|
|
5
|
+
def _get_fixed_atom_boolean_vector(structure: Atoms) -> np.ndarray:
|
|
6
6
|
fixed_atom_vector = np.array([[False, False, False]] * len(structure))
|
|
7
7
|
for c in structure.constraints:
|
|
8
8
|
c_dict = c.todict()
|
|
@@ -27,8 +27,8 @@ def _get_fixed_atom_boolean_vector(structure: Atoms):
|
|
|
27
27
|
return fixed_atom_vector
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
def set_selective_dynamics(structure: Atoms, calc_md: bool = False):
|
|
31
|
-
control_dict = {}
|
|
30
|
+
def set_selective_dynamics(structure: Atoms, calc_md: bool = False) -> dict[str, str]:
|
|
31
|
+
control_dict: dict[str, str] = {}
|
|
32
32
|
if len(structure.constraints) > 0:
|
|
33
33
|
sel_dyn = _get_fixed_atom_boolean_vector(structure=structure)
|
|
34
34
|
# Enter loop only if constraints present
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Optional, Union
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class CalcMDInput:
|
|
9
|
+
temperature: Optional[Union[float, list]] = None
|
|
10
|
+
pressure: Optional[Union[float, list, np.ndarray]] = None
|
|
11
|
+
n_ionic_steps: int = 1
|
|
12
|
+
time_step: float = 1.0
|
|
13
|
+
n_print: int = 100
|
|
14
|
+
temperature_damping_timescale: float = 100.0
|
|
15
|
+
pressure_damping_timescale: float = 1000.0
|
|
16
|
+
seed: int = 80996
|
|
17
|
+
tloop: Optional[int] = None
|
|
18
|
+
initial_temperature: Optional[float] = None
|
|
19
|
+
langevin: bool = False
|
|
20
|
+
delta_temp: Optional[float] = None
|
|
21
|
+
delta_press: Optional[float] = None
|
|
22
|
+
rotation_matrix: Optional[Union[list, np.ndarray]] = None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class CalcMinimizeInput:
|
|
27
|
+
ionic_energy_tolerance: float = 0.0
|
|
28
|
+
ionic_force_tolerance: float = 1e-4
|
|
29
|
+
max_iter: int = 100000
|
|
30
|
+
pressure: Optional[Union[float, list, np.ndarray]] = None
|
|
31
|
+
n_print: int = 1
|
|
32
|
+
style: str = "cg"
|
|
33
|
+
rotation_matrix: Optional[Union[list, np.ndarray]] = None
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import shutil
|
|
3
3
|
import subprocess
|
|
4
|
-
from
|
|
4
|
+
from dataclasses import asdict
|
|
5
|
+
from typing import Optional, Union
|
|
5
6
|
|
|
6
7
|
import pandas
|
|
7
8
|
from ase.atoms import Atoms
|
|
@@ -12,6 +13,7 @@ from lammpsparser.compatibility.calculate import (
|
|
|
12
13
|
calc_static,
|
|
13
14
|
)
|
|
14
15
|
from lammpsparser.compatibility.constraints import set_selective_dynamics
|
|
16
|
+
from lammpsparser.compatibility.data import CalcMDInput, CalcMinimizeInput
|
|
15
17
|
from lammpsparser.output import parse_lammps_output
|
|
16
18
|
from lammpsparser.potential import get_potential_by_name
|
|
17
19
|
from lammpsparser.structure import write_lammps_datafile
|
|
@@ -23,8 +25,9 @@ def lammps_file_interface_function(
|
|
|
23
25
|
potential: str,
|
|
24
26
|
calc_mode: str = "static",
|
|
25
27
|
calc_kwargs: Optional[dict] = None,
|
|
28
|
+
calc_dataclass: Optional[Union[CalcMDInput, CalcMinimizeInput]] = None,
|
|
26
29
|
units: str = "metal",
|
|
27
|
-
lmp_command: str =
|
|
30
|
+
lmp_command: Optional[str] = None,
|
|
28
31
|
resource_path: Optional[str] = None,
|
|
29
32
|
input_control_file: Optional[dict] = None,
|
|
30
33
|
write_restart_file: bool = False,
|
|
@@ -61,13 +64,15 @@ def lammps_file_interface_function(
|
|
|
61
64
|
"static": No parameters
|
|
62
65
|
"md": "temperature", "pressure", "n_ionic_steps", "time_step", "n_print", "temperature_damping_timescale",
|
|
63
66
|
"pressure_damping_timescale", "seed", "tloop", "initial_temperature", "langevin", "delta_temp",
|
|
64
|
-
"delta_press",
|
|
67
|
+
"delta_press", "rotation_matrix"
|
|
65
68
|
"minimize": "ionic_energy_tolerance", "ionic_force_tolerance", "max_iter", "pressure", "n_print", "style",
|
|
66
69
|
"rotation_matrix"
|
|
67
70
|
"vcsgc": "mu", "ordered_element_list", "target_concentration", "kappa", "mc_step_interval", "swap_fraction",
|
|
68
71
|
"temperature_mc", "window_size", "window_moves", "temperature", "pressure", "n_ionic_steps",
|
|
69
72
|
"time_step", "n_print", "temperature_damping_timescale", "pressure_damping_timescale", "seed",
|
|
70
|
-
"initial_temperature", "langevin", "
|
|
73
|
+
"initial_temperature", "langevin", "rotation_matrix"
|
|
74
|
+
calc_dataclass (CalcMDInput or CalcMinimizeInput): dataclass containing the parameters for the calculation,
|
|
75
|
+
if calc_dataclass is provided
|
|
71
76
|
cutoff_radius (float): cut-off radius for the interatomic potential
|
|
72
77
|
units (str): Units for LAMMPS
|
|
73
78
|
bonds_kwargs (dict): key-word arguments to create atomistic bonds:
|
|
@@ -88,11 +93,29 @@ def lammps_file_interface_function(
|
|
|
88
93
|
str, dict, bool: Tuple consisting of the shell output (str), the parsed output (dict) and a boolean flag if
|
|
89
94
|
the execution raised an accepted error.
|
|
90
95
|
"""
|
|
96
|
+
if calc_dataclass is not None:
|
|
97
|
+
if isinstance(calc_dataclass, CalcMDInput):
|
|
98
|
+
calc_mode = "md"
|
|
99
|
+
calc_kwargs = asdict(calc_dataclass)
|
|
100
|
+
|
|
101
|
+
elif isinstance(calc_dataclass, CalcMinimizeInput):
|
|
102
|
+
calc_mode = "minimize"
|
|
103
|
+
calc_kwargs = asdict(calc_dataclass)
|
|
104
|
+
else:
|
|
105
|
+
raise TypeError(
|
|
106
|
+
"calc_dataclass must be an instance of either CalcMDInput or CalcMinimizeInput"
|
|
107
|
+
)
|
|
91
108
|
if calc_kwargs is None:
|
|
92
109
|
calc_kwargs = {}
|
|
93
110
|
else:
|
|
94
111
|
calc_kwargs = calc_kwargs.copy()
|
|
95
112
|
|
|
113
|
+
if lmp_command is None:
|
|
114
|
+
lmp_command = (
|
|
115
|
+
os.getenv("ASE_LAMMPSRUN_COMMAND", "mpiexec -n 1 --oversubscribe lmp_mpi")
|
|
116
|
+
+ " -in lmp.in"
|
|
117
|
+
)
|
|
118
|
+
|
|
96
119
|
os.makedirs(working_directory, exist_ok=True)
|
|
97
120
|
potential_lst, potential_replace, species = _get_potential(
|
|
98
121
|
potential=potential, resource_path=resource_path
|
|
@@ -100,21 +123,23 @@ def lammps_file_interface_function(
|
|
|
100
123
|
|
|
101
124
|
lmp_str_lst = []
|
|
102
125
|
atom_type = "atomic"
|
|
103
|
-
for
|
|
126
|
+
for line in lammps_file_initialization(
|
|
104
127
|
structure=structure,
|
|
105
128
|
units=units,
|
|
106
129
|
read_restart_file=read_restart_file,
|
|
107
130
|
restart_file=restart_file,
|
|
108
131
|
):
|
|
109
|
-
if
|
|
132
|
+
if line.strip().startswith("units") and "units" in potential_replace:
|
|
110
133
|
lmp_str_lst.append(potential_replace["units"])
|
|
111
|
-
elif
|
|
134
|
+
elif (
|
|
135
|
+
line.strip().startswith("atom_style") and "atom_style" in potential_replace
|
|
136
|
+
):
|
|
112
137
|
lmp_str_lst.append(potential_replace["atom_style"])
|
|
113
138
|
atom_type = potential_replace["atom_style"].split()[-1]
|
|
114
|
-
elif
|
|
139
|
+
elif line.strip().startswith("dimension") and "dimension" in potential_replace:
|
|
115
140
|
lmp_str_lst.append(potential_replace["dimension"])
|
|
116
141
|
else:
|
|
117
|
-
lmp_str_lst.append(
|
|
142
|
+
lmp_str_lst.append(line)
|
|
118
143
|
|
|
119
144
|
lmp_str_lst += potential_lst
|
|
120
145
|
lmp_str_lst += ["variable dumptime equal {} ".format(calc_kwargs.get("n_print", 1))]
|
|
@@ -185,7 +210,7 @@ def lammps_file_interface_function(
|
|
|
185
210
|
lmp_str_lst.append(f"write_restart {os.path.basename(restart_file)}")
|
|
186
211
|
|
|
187
212
|
with open(os.path.join(working_directory, "lmp.in"), "w") as f:
|
|
188
|
-
f.writelines([
|
|
213
|
+
f.writelines([line + "\n" for line in lmp_str_lst])
|
|
189
214
|
|
|
190
215
|
write_lammps_datafile(
|
|
191
216
|
structure=structure,
|
|
@@ -240,15 +265,15 @@ def _modify_input_dict(
|
|
|
240
265
|
):
|
|
241
266
|
if input_control_file is not None:
|
|
242
267
|
lmp_tmp_lst, keys_used = [], []
|
|
243
|
-
for
|
|
244
|
-
ls =
|
|
268
|
+
for line in lmp_str_lst:
|
|
269
|
+
ls = line.split()
|
|
245
270
|
if len(ls) >= 1: # Remove empty lines
|
|
246
271
|
key = ls[0]
|
|
247
272
|
if key in input_control_file.keys():
|
|
248
273
|
lmp_tmp_lst.append(key + " " + input_control_file[key])
|
|
249
274
|
keys_used.append(key)
|
|
250
275
|
else:
|
|
251
|
-
lmp_tmp_lst.append(
|
|
276
|
+
lmp_tmp_lst.append(line)
|
|
252
277
|
for k, v in input_control_file.items():
|
|
253
278
|
if k not in keys_used:
|
|
254
279
|
lmp_tmp_lst.append(k + " " + v)
|
|
@@ -272,14 +297,14 @@ def _get_potential(potential, resource_path: Optional[str] = None):
|
|
|
272
297
|
|
|
273
298
|
potential_replace = {}
|
|
274
299
|
potential_lst = []
|
|
275
|
-
for
|
|
276
|
-
if
|
|
277
|
-
potential_replace["units"] =
|
|
278
|
-
elif
|
|
279
|
-
potential_replace["atom_style"] =
|
|
280
|
-
elif
|
|
281
|
-
potential_replace["dimension"] =
|
|
300
|
+
for line in potential_dataframe["Config"]:
|
|
301
|
+
if line.startswith("units"):
|
|
302
|
+
potential_replace["units"] = line
|
|
303
|
+
elif line.startswith("atom_style"):
|
|
304
|
+
potential_replace["atom_style"] = line
|
|
305
|
+
elif line.startswith("dimension"):
|
|
306
|
+
potential_replace["dimension"] = line
|
|
282
307
|
else:
|
|
283
|
-
potential_lst.append(
|
|
308
|
+
potential_lst.append(line)
|
|
284
309
|
|
|
285
310
|
return potential_lst, potential_replace, potential_dataframe["Species"]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from ase.atoms import Atoms
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def structure_from_parsed_output(
|
|
5
|
+
initial_structure: Atoms,
|
|
6
|
+
parsed_output: dict,
|
|
7
|
+
*,
|
|
8
|
+
wrap: bool = False,
|
|
9
|
+
index: int = -1,
|
|
10
|
+
) -> Atoms:
|
|
11
|
+
"""Construct an `Atoms` object from parsed output data.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
initial_structure: The initial atomic structure to use as a template.
|
|
15
|
+
parsed_output: Parsed output containing atomic positions, cell, and indices.
|
|
16
|
+
wrap: Whether to wrap the atomic positions to the simulation cell (default is False).
|
|
17
|
+
Keeping the unwrapped positions is more beneficial if structures are passed between
|
|
18
|
+
different LAMMPS simulations in one workflow to ensure continuity.
|
|
19
|
+
index: The index of the frame to use from the parsed output (default is -1, i.e., the last frame).
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
An `Atoms` object with updated positions and cell.
|
|
23
|
+
|
|
24
|
+
Example:
|
|
25
|
+
>>> new_atoms = structure_from_parsed_output(atoms, lammps_output)
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
# Take a copy of the initial structure as template and update the relevant properties
|
|
29
|
+
atoms_copy = initial_structure.copy()
|
|
30
|
+
atoms_copy.set_array("indices", parsed_output["generic"]["indices"][index])
|
|
31
|
+
atoms_copy.set_positions(parsed_output["generic"]["positions"][index])
|
|
32
|
+
atoms_copy.set_velocities(parsed_output["generic"]["velocities"][index])
|
|
33
|
+
atoms_copy.set_cell(parsed_output["generic"]["cells"][index])
|
|
34
|
+
atoms_copy.set_pbc(True)
|
|
35
|
+
if wrap:
|
|
36
|
+
atoms_copy.wrap()
|
|
37
|
+
|
|
38
|
+
return atoms_copy
|
|
@@ -17,7 +17,7 @@ class LammpsStructureCompatibility(LammpsStructure):
|
|
|
17
17
|
atom_type: str = "atomic",
|
|
18
18
|
):
|
|
19
19
|
super().__init__(bond_dict=bond_dict, units=units, atom_type=atom_type)
|
|
20
|
-
self._molecule_ids = []
|
|
20
|
+
self._molecule_ids: list[int] = []
|
|
21
21
|
|
|
22
22
|
@property
|
|
23
23
|
def structure(self) -> Optional[Atoms]:
|
|
@@ -211,7 +211,7 @@ class LammpsStructureCompatibility(LammpsStructure):
|
|
|
211
211
|
<= cutoff_dist
|
|
212
212
|
)
|
|
213
213
|
act_ind = ind[bool_1]
|
|
214
|
-
bool_2 = np.
|
|
214
|
+
bool_2 = np.isin(act_ind, el_2_list)
|
|
215
215
|
final_ind = act_ind[bool_2]
|
|
216
216
|
# Get the bond and angle type
|
|
217
217
|
bond_type = val["bond_type_list"][i]
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import warnings
|
|
5
|
-
from typing import Dict, List, Optional, Tuple, Union
|
|
5
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
|
6
6
|
|
|
7
7
|
import numpy as np
|
|
8
8
|
import pandas as pd
|
|
@@ -66,8 +66,8 @@ def parse_lammps_output(
|
|
|
66
66
|
dump_h5_file_name: str = "dump.h5",
|
|
67
67
|
dump_out_file_name: str = "dump.out",
|
|
68
68
|
log_lammps_file_name: str = "log.lammps",
|
|
69
|
-
remap_indices_funct:
|
|
70
|
-
) -> Dict:
|
|
69
|
+
remap_indices_funct: Callable[..., np.ndarray] = remap_indices_ase,
|
|
70
|
+
) -> Dict[str, Dict[str, Any]]:
|
|
71
71
|
if prism is None:
|
|
72
72
|
prism = UnfoldingPrism(structure.cell)
|
|
73
73
|
dump_dict = _parse_dump(
|
|
@@ -86,7 +86,7 @@ def parse_lammps_output(
|
|
|
86
86
|
|
|
87
87
|
convert_units = UnitConverter(units).convert_array_to_pyiron_units
|
|
88
88
|
|
|
89
|
-
hdf_output = {"generic": {}, "lammps": {}}
|
|
89
|
+
hdf_output: Dict[str, Dict[str, Any]] = {"generic": {}, "lammps": {}}
|
|
90
90
|
hdf_generic = hdf_output["generic"]
|
|
91
91
|
hdf_lammps = hdf_output["lammps"]
|
|
92
92
|
|
|
@@ -128,8 +128,8 @@ def _parse_dump(
|
|
|
128
128
|
prism: UnfoldingPrism,
|
|
129
129
|
structure: Atoms,
|
|
130
130
|
potential_elements: Union[np.ndarray, List],
|
|
131
|
-
remap_indices_funct:
|
|
132
|
-
) -> Dict:
|
|
131
|
+
remap_indices_funct: Callable[..., np.ndarray] = remap_indices_ase,
|
|
132
|
+
) -> Dict[str, Any]:
|
|
133
133
|
if os.path.isfile(dump_h5_full_file_name):
|
|
134
134
|
if not _check_ortho_prism(prism=prism):
|
|
135
135
|
raise RuntimeError(
|
|
@@ -157,14 +157,14 @@ def _collect_dump_from_text(
|
|
|
157
157
|
prism: UnfoldingPrism,
|
|
158
158
|
structure: Atoms,
|
|
159
159
|
potential_elements: Union[np.ndarray, List],
|
|
160
|
-
remap_indices_funct:
|
|
161
|
-
) -> Dict:
|
|
160
|
+
remap_indices_funct: Callable[..., np.ndarray] = remap_indices_ase,
|
|
161
|
+
) -> Dict[str, Any]:
|
|
162
162
|
"""
|
|
163
163
|
general purpose routine to extract static from a lammps dump file
|
|
164
164
|
"""
|
|
165
165
|
rotation_lammps2orig = prism.R.T
|
|
166
166
|
dump_lammps_dict = parse_raw_dump_from_text(file_name=file_name)
|
|
167
|
-
dump_dict = {}
|
|
167
|
+
dump_dict: Dict[str, Any] = {}
|
|
168
168
|
for key, val in dump_lammps_dict.items():
|
|
169
169
|
if key in ["cells"]:
|
|
170
170
|
dump_dict[key] = [prism.unfold_cell(cell=cell) for cell in val]
|
|
@@ -337,4 +337,4 @@ def _check_ortho_prism(
|
|
|
337
337
|
Returns:
|
|
338
338
|
boolean: True or False
|
|
339
339
|
"""
|
|
340
|
-
return np.isclose(prism.R, np.eye(3), rtol=rtol, atol=atol).all()
|
|
340
|
+
return bool(np.isclose(prism.R, np.eye(3), rtol=rtol, atol=atol).all())
|
|
@@ -221,25 +221,25 @@ def parse_raw_lammps_log(file_name: str) -> pd.DataFrame:
|
|
|
221
221
|
with open(file_name, "r") as f:
|
|
222
222
|
dfs = []
|
|
223
223
|
read_thermo = False
|
|
224
|
-
for
|
|
225
|
-
|
|
224
|
+
for line in f:
|
|
225
|
+
line = line.lstrip()
|
|
226
226
|
|
|
227
|
-
if
|
|
227
|
+
if line.startswith("Step"):
|
|
228
228
|
thermo_lines = ""
|
|
229
229
|
read_thermo = True
|
|
230
230
|
|
|
231
231
|
if read_thermo:
|
|
232
|
-
if
|
|
232
|
+
if line.startswith("Loop") or line.startswith("ERROR"):
|
|
233
233
|
read_thermo = False
|
|
234
234
|
dfs.append(
|
|
235
235
|
pd.read_csv(StringIO(thermo_lines), sep="\\s+", engine="c")
|
|
236
236
|
)
|
|
237
237
|
|
|
238
|
-
elif
|
|
239
|
-
warnings.warn(f"A warning was found in the log:\n{
|
|
238
|
+
elif line.startswith("WARNING:"):
|
|
239
|
+
warnings.warn(f"A warning was found in the log:\n{line}")
|
|
240
240
|
|
|
241
241
|
else:
|
|
242
|
-
thermo_lines +=
|
|
242
|
+
thermo_lines += line
|
|
243
243
|
|
|
244
244
|
if len(dfs) == 1:
|
|
245
245
|
df = dfs[0]
|
|
@@ -49,8 +49,8 @@ class PotentialAbstract:
|
|
|
49
49
|
def __init__(
|
|
50
50
|
self,
|
|
51
51
|
potential_df: pandas.DataFrame,
|
|
52
|
-
default_df: pandas.DataFrame = None,
|
|
53
|
-
selected_atoms: list[str] = None,
|
|
52
|
+
default_df: Optional[pandas.DataFrame] = None,
|
|
53
|
+
selected_atoms: Optional[list[str]] = None,
|
|
54
54
|
):
|
|
55
55
|
self._potential_df = potential_df
|
|
56
56
|
self._default_df = default_df
|
|
@@ -328,7 +328,7 @@ def update_potential_paths(
|
|
|
328
328
|
|
|
329
329
|
|
|
330
330
|
def get_resource_path_from_conda(
|
|
331
|
-
env_variables: tuple[str] = ("CONDA_PREFIX", "CONDA_DIR"),
|
|
331
|
+
env_variables: tuple[str, ...] = ("CONDA_PREFIX", "CONDA_DIR"),
|
|
332
332
|
) -> str:
|
|
333
333
|
env = os.environ
|
|
334
334
|
for conda_var in env_variables:
|
|
@@ -359,7 +359,7 @@ def get_potential_by_name(potential_name: str, resource_path: Optional[str] = No
|
|
|
359
359
|
|
|
360
360
|
def validate_potential_dataframe(
|
|
361
361
|
potential_dataframe: pandas.DataFrame,
|
|
362
|
-
) -> pandas.DataFrame:
|
|
362
|
+
) -> Union[pandas.DataFrame, pandas.Series]:
|
|
363
363
|
if isinstance(potential_dataframe, pandas.Series):
|
|
364
364
|
return potential_dataframe
|
|
365
365
|
elif isinstance(potential_dataframe, pandas.DataFrame):
|
|
@@ -7,7 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
import decimal as dec
|
|
8
8
|
import posixpath
|
|
9
9
|
import warnings
|
|
10
|
-
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
10
|
+
from typing import Any, Dict, List, Optional, Tuple, Union, cast
|
|
11
11
|
|
|
12
12
|
import numpy as np
|
|
13
13
|
from ase.atoms import Atoms
|
|
@@ -16,12 +16,14 @@ from ase.data import atomic_masses, atomic_numbers
|
|
|
16
16
|
from lammpsparser.units import UnitConverter
|
|
17
17
|
|
|
18
18
|
try:
|
|
19
|
-
from ase.calculators.lammps import Prism
|
|
19
|
+
from ase.calculators.lammps import Prism as PrismBase
|
|
20
20
|
except ImportError:
|
|
21
21
|
try:
|
|
22
|
-
from ase.calculators.lammpsrun import Prism
|
|
22
|
+
from ase.calculators.lammpsrun import Prism as PrismBase
|
|
23
23
|
except ImportError:
|
|
24
|
-
from ase.calculators.lammpsrun import
|
|
24
|
+
from ase.calculators.lammpsrun import (
|
|
25
|
+
prism as PrismBase, # type: ignore[attr-defined,no-redef]
|
|
26
|
+
)
|
|
25
27
|
|
|
26
28
|
__author__ = "Joerg Neugebauer, Sudarsan Surendralal, Yury Lysogorskiy, Jan Janssen, Markus Tautschnig"
|
|
27
29
|
__copyright__ = (
|
|
@@ -35,7 +37,7 @@ __status__ = "production"
|
|
|
35
37
|
__date__ = "Sep 1, 2017"
|
|
36
38
|
|
|
37
39
|
|
|
38
|
-
class UnfoldingPrism(
|
|
40
|
+
class UnfoldingPrism(PrismBase):
|
|
39
41
|
"""
|
|
40
42
|
Create a lammps-style triclinic prism object from a cell
|
|
41
43
|
|
|
@@ -69,7 +71,7 @@ class UnfoldingPrism(Prism):
|
|
|
69
71
|
cell, pbc=np.array(pbc), tolerance=float("1e-{}".format(digits))
|
|
70
72
|
)
|
|
71
73
|
except TypeError:
|
|
72
|
-
super(UnfoldingPrism, self).__init__(cell, pbc=np.array(pbc), digits=digits)
|
|
74
|
+
super(UnfoldingPrism, self).__init__(cell, pbc=np.array(pbc), digits=digits) # type: ignore[call-arg]
|
|
73
75
|
a, b, c = cell
|
|
74
76
|
an, bn, cn = [np.linalg.norm(v) for v in cell]
|
|
75
77
|
|
|
@@ -270,8 +272,8 @@ class LammpsStructure:
|
|
|
270
272
|
input_str += format_str.format(id_atom, x, y, z)
|
|
271
273
|
elif len(self._structure.positions[0]) == 2:
|
|
272
274
|
format_str = "{0:d} {1:f} {2:f}\n"
|
|
273
|
-
for id_atom,
|
|
274
|
-
input_str += format_str.format(id_atom,
|
|
275
|
+
for id_atom, velocity in enumerate(vels, start=1):
|
|
276
|
+
input_str += format_str.format(id_atom, velocity[0], velocity[1])
|
|
275
277
|
return input_str
|
|
276
278
|
|
|
277
279
|
@property
|
|
@@ -352,7 +354,7 @@ class LammpsStructure:
|
|
|
352
354
|
+ "0. {} zlo zhi\n".format(zhi)
|
|
353
355
|
)
|
|
354
356
|
|
|
355
|
-
if is_skewed(self.
|
|
357
|
+
if is_skewed(self._structure) or self._force_skewed:
|
|
356
358
|
simulation_cell += "{0} {1} {2} xy xz yz\n".format(xy, xz, yz)
|
|
357
359
|
|
|
358
360
|
return simulation_cell
|
|
@@ -383,7 +385,7 @@ class LammpsStructure:
|
|
|
383
385
|
)
|
|
384
386
|
return (
|
|
385
387
|
self.lammps_header(
|
|
386
|
-
structure=self.
|
|
388
|
+
structure=self._structure,
|
|
387
389
|
cell_dimensions=self.simulation_cell(),
|
|
388
390
|
species_lammps_id_dict=species_lammps_id_dict,
|
|
389
391
|
)
|
|
@@ -500,7 +502,7 @@ def is_skewed(structure: Atoms, tolerance: float = 1.0e-8) -> bool:
|
|
|
500
502
|
|
|
501
503
|
def write_lammps_datafile(
|
|
502
504
|
structure: Atoms,
|
|
503
|
-
potential_elements: Union[np.ndarray, list],
|
|
505
|
+
potential_elements: Union[np.ndarray, list[str]],
|
|
504
506
|
bond_dict: Optional[Dict] = None,
|
|
505
507
|
units: str = "metal",
|
|
506
508
|
file_name: str = "lammps.data",
|
|
@@ -508,7 +510,7 @@ def write_lammps_datafile(
|
|
|
508
510
|
atom_type: str = "atomic",
|
|
509
511
|
) -> None:
|
|
510
512
|
lammps_str = LammpsStructure(bond_dict=bond_dict, units=units, atom_type=atom_type)
|
|
511
|
-
lammps_str.el_eam_lst = potential_elements
|
|
513
|
+
lammps_str.el_eam_lst = cast(List[str], list(potential_elements))
|
|
512
514
|
lammps_str.structure = structure
|
|
513
515
|
lammps_str.write_file(file_name=file_name, cwd=working_directory)
|
|
514
516
|
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# file generated by setuptools-scm
|
|
2
|
-
# don't change, don't track in version control
|
|
3
|
-
|
|
4
|
-
__all__ = [
|
|
5
|
-
"__version__",
|
|
6
|
-
"__version_tuple__",
|
|
7
|
-
"version",
|
|
8
|
-
"version_tuple",
|
|
9
|
-
"__commit_id__",
|
|
10
|
-
"commit_id",
|
|
11
|
-
]
|
|
12
|
-
|
|
13
|
-
TYPE_CHECKING = False
|
|
14
|
-
if TYPE_CHECKING:
|
|
15
|
-
from typing import Tuple
|
|
16
|
-
from typing import Union
|
|
17
|
-
|
|
18
|
-
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
-
COMMIT_ID = Union[str, None]
|
|
20
|
-
else:
|
|
21
|
-
VERSION_TUPLE = object
|
|
22
|
-
COMMIT_ID = object
|
|
23
|
-
|
|
24
|
-
version: str
|
|
25
|
-
__version__: str
|
|
26
|
-
__version_tuple__: VERSION_TUPLE
|
|
27
|
-
version_tuple: VERSION_TUPLE
|
|
28
|
-
commit_id: COMMIT_ID
|
|
29
|
-
__commit_id__: COMMIT_ID
|
|
30
|
-
|
|
31
|
-
__version__ = version = '0.0.3'
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 0, 3)
|
|
33
|
-
|
|
34
|
-
__commit_id__ = commit_id = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|