lammpsparser 0.0.10__tar.gz → 0.1.1__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.10 → lammpsparser-0.1.1}/PKG-INFO +7 -11
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/pyproject.toml +7 -10
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/src/lammpsparser/_version.py +2 -2
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/src/lammpsparser/compatibility/file.py +19 -2
- lammpsparser-0.1.1/src/lammpsparser/compatibility/neighbors.py +232 -0
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/src/lammpsparser/compatibility/structure.py +3 -8
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/src/lammpsparser/structure.py +2 -0
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/.gitignore +0 -0
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/LICENSE +0 -0
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/README.md +0 -0
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/src/lammpsparser/__init__.py +0 -0
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/src/lammpsparser/compatibility/__init__.py +0 -0
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/src/lammpsparser/compatibility/calculate.py +0 -0
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/src/lammpsparser/compatibility/constraints.py +0 -0
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/src/lammpsparser/compatibility/data.py +0 -0
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/src/lammpsparser/compatibility/output.py +0 -0
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/src/lammpsparser/output.py +0 -0
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/src/lammpsparser/output_raw.py +0 -0
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/src/lammpsparser/potential.py +0 -0
- {lammpsparser-0.0.10 → lammpsparser-0.1.1}/src/lammpsparser/units.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: lammpsparser
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.1.1
|
|
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
|
|
@@ -41,22 +41,18 @@ Classifier: Development Status :: 5 - Production/Stable
|
|
|
41
41
|
Classifier: Intended Audience :: Science/Research
|
|
42
42
|
Classifier: License :: OSI Approved :: BSD License
|
|
43
43
|
Classifier: Operating System :: OS Independent
|
|
44
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
45
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
46
44
|
Classifier: Programming Language :: Python :: 3.11
|
|
47
45
|
Classifier: Programming Language :: Python :: 3.12
|
|
48
46
|
Classifier: Programming Language :: Python :: 3.13
|
|
49
47
|
Classifier: Programming Language :: Python :: 3.14
|
|
50
48
|
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
51
|
-
Requires-Python: <3.15,>=3.
|
|
52
|
-
Requires-Dist: ase
|
|
53
|
-
Requires-Dist: numpy
|
|
54
|
-
Requires-Dist: pandas
|
|
55
|
-
Requires-Dist: scipy
|
|
56
|
-
Provides-Extra: compatibility
|
|
57
|
-
Requires-Dist: structuretoolkit<=0.0.47,>=0.0.30; extra == 'compatibility'
|
|
49
|
+
Requires-Python: <3.15,>=3.11
|
|
50
|
+
Requires-Dist: ase==3.29.0
|
|
51
|
+
Requires-Dist: numpy<2.6.0,>=1.26.0
|
|
52
|
+
Requires-Dist: pandas<3.2.0,>=2.0.3
|
|
53
|
+
Requires-Dist: scipy<1.19.0,>=1.11.1
|
|
58
54
|
Provides-Extra: h5md
|
|
59
|
-
Requires-Dist: h5py
|
|
55
|
+
Requires-Dist: h5py<3.17.0,>=3.9.0; extra == 'h5md'
|
|
60
56
|
Description-Content-Type: text/markdown
|
|
61
57
|
|
|
62
58
|
# lammpsparser
|
|
@@ -5,7 +5,7 @@ requires = [
|
|
|
5
5
|
"h5py",
|
|
6
6
|
"pandas",
|
|
7
7
|
"scipy",
|
|
8
|
-
"hatchling==1.
|
|
8
|
+
"hatchling==1.33.0",
|
|
9
9
|
"hatch-vcs==0.5.0",
|
|
10
10
|
]
|
|
11
11
|
build-backend = "hatchling.build"
|
|
@@ -19,25 +19,23 @@ authors = [
|
|
|
19
19
|
readme = "README.md"
|
|
20
20
|
license = { file = "LICENSE" }
|
|
21
21
|
keywords = ["pyiron"]
|
|
22
|
-
requires-python = ">=3.
|
|
22
|
+
requires-python = ">=3.11, <3.15"
|
|
23
23
|
classifiers = [
|
|
24
24
|
"Development Status :: 5 - Production/Stable",
|
|
25
25
|
"Topic :: Scientific/Engineering :: Physics",
|
|
26
26
|
"License :: OSI Approved :: BSD License",
|
|
27
27
|
"Intended Audience :: Science/Research",
|
|
28
28
|
"Operating System :: OS Independent",
|
|
29
|
-
"Programming Language :: Python :: 3.9",
|
|
30
|
-
"Programming Language :: Python :: 3.10",
|
|
31
29
|
"Programming Language :: Python :: 3.11",
|
|
32
30
|
"Programming Language :: Python :: 3.12",
|
|
33
31
|
"Programming Language :: Python :: 3.13",
|
|
34
32
|
"Programming Language :: Python :: 3.14",
|
|
35
33
|
]
|
|
36
34
|
dependencies = [
|
|
37
|
-
"ase
|
|
38
|
-
"numpy>=1.26.0
|
|
39
|
-
"pandas>=2.0.3
|
|
40
|
-
"scipy>=1.11.1
|
|
35
|
+
"ase==3.29.0",
|
|
36
|
+
"numpy>=1.26.0,<2.6.0",
|
|
37
|
+
"pandas>=2.0.3,<3.2.0",
|
|
38
|
+
"scipy>=1.11.1,<1.19.0",
|
|
41
39
|
]
|
|
42
40
|
dynamic = ["version"]
|
|
43
41
|
|
|
@@ -47,8 +45,7 @@ Documentation = "https://github.com/pyiron/lammpsparser"
|
|
|
47
45
|
Repository = "https://github.com/pyiron/lammpsparser"
|
|
48
46
|
|
|
49
47
|
[project.optional-dependencies]
|
|
50
|
-
h5md = ["h5py>=3.9.0
|
|
51
|
-
compatibility = ["structuretoolkit>=0.0.30,<=0.0.47"]
|
|
48
|
+
h5md = ["h5py>=3.9.0,<3.17.0"]
|
|
52
49
|
|
|
53
50
|
[tool.hatch.build]
|
|
54
51
|
include = [
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.1.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 1)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -36,6 +36,9 @@ def lammps_file_interface_function(
|
|
|
36
36
|
read_restart_file: bool = False,
|
|
37
37
|
restart_file: str = "restart.out",
|
|
38
38
|
dump_final_structure: bool = False,
|
|
39
|
+
n_print_dump: int | None = None,
|
|
40
|
+
n_print_thermo: int | None = None,
|
|
41
|
+
force_skewed: bool = False,
|
|
39
42
|
):
|
|
40
43
|
"""
|
|
41
44
|
A single function to execute a LAMMPS calculation based on the LAMMPS job interface implemented in lammpsparser
|
|
@@ -90,6 +93,13 @@ def lammps_file_interface_function(
|
|
|
90
93
|
restart_file (str): file name of the LAMMPS restart file to copy
|
|
91
94
|
dump_final_structure (bool): in "md" mode, append a ``write_dump`` command after the ``run`` command to capture
|
|
92
95
|
the final structure in ``dump.out`` if last step is not a regular dump step. Disabled by default.
|
|
96
|
+
n_print_dump (int, optional): Override the dump-file write interval (steps between successive
|
|
97
|
+
``dump`` writes), independently of ``calc_kwargs["n_print"]``. Defaults to ``None``, which
|
|
98
|
+
falls back to ``calc_kwargs.get("n_print", 1)`` (the pre-existing behavior).
|
|
99
|
+
n_print_thermo (int, optional): Override the thermodynamic print interval (steps between
|
|
100
|
+
successive ``thermo`` output lines), independently of ``calc_kwargs["n_print"]``. Defaults
|
|
101
|
+
to ``None``, which leaves ``calc_kwargs["n_print"]`` untouched (the pre-existing behavior).
|
|
102
|
+
Has no effect in ``"static"`` mode, since that mode only ever performs a single step.
|
|
93
103
|
executable_version (str): LAMMPS version to for the execution
|
|
94
104
|
executable_path (str): path to the LAMMPS executable
|
|
95
105
|
input_control_file (str|list|dict): Option to modify the LAMMPS input file directly
|
|
@@ -115,6 +125,12 @@ def lammps_file_interface_function(
|
|
|
115
125
|
else:
|
|
116
126
|
calc_kwargs = calc_kwargs.copy()
|
|
117
127
|
|
|
128
|
+
dump_interval = (
|
|
129
|
+
n_print_dump if n_print_dump is not None else calc_kwargs.get("n_print", 1)
|
|
130
|
+
)
|
|
131
|
+
if n_print_thermo is not None:
|
|
132
|
+
calc_kwargs["n_print"] = n_print_thermo
|
|
133
|
+
|
|
118
134
|
if lmp_command is None:
|
|
119
135
|
lmp_command = (
|
|
120
136
|
os.getenv("ASE_LAMMPSRUN_COMMAND", "mpiexec -n 1 --oversubscribe lmp_mpi")
|
|
@@ -150,7 +166,7 @@ def lammps_file_interface_function(
|
|
|
150
166
|
dump_format = '"%d %d %20.15g %20.15g %20.15g %20.15g %20.15g %20.15g %20.15g %20.15g %20.15g"'
|
|
151
167
|
|
|
152
168
|
lmp_str_lst += potential_lst
|
|
153
|
-
lmp_str_lst += ["variable dumptime equal {} "
|
|
169
|
+
lmp_str_lst += [f"variable dumptime equal {dump_interval} "]
|
|
154
170
|
lmp_str_lst += [
|
|
155
171
|
"dump 1 all custom ${dumptime} dump.out " + dump_fields,
|
|
156
172
|
"dump_modify 1 sort id format line " + dump_format,
|
|
@@ -195,7 +211,7 @@ def lammps_file_interface_function(
|
|
|
195
211
|
if read_restart_file:
|
|
196
212
|
lmp_str_lst += ["reset_timestep 0"]
|
|
197
213
|
lmp_str_lst += [f"run {n_ionic_steps} "]
|
|
198
|
-
last_step_is_regular_dump = n_ionic_steps %
|
|
214
|
+
last_step_is_regular_dump = n_ionic_steps % dump_interval == 0
|
|
199
215
|
if dump_final_structure and not last_step_is_regular_dump:
|
|
200
216
|
lmp_str_lst += [
|
|
201
217
|
"write_dump all custom dump.out "
|
|
@@ -245,6 +261,7 @@ def lammps_file_interface_function(
|
|
|
245
261
|
file_name="lammps.data",
|
|
246
262
|
working_directory=working_directory,
|
|
247
263
|
atom_type=atom_type,
|
|
264
|
+
force_skewed=force_skewed,
|
|
248
265
|
)
|
|
249
266
|
|
|
250
267
|
shell = subprocess.check_output(
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Minimal neighbour analysis for the compatibility layer.
|
|
3
|
+
|
|
4
|
+
This is a reduced port of :mod:`structuretoolkit.analyse.neighbors` (originally by
|
|
5
|
+
Joerg Neugebauer and Sam Waseda, Max-Planck-Institut für Eisenforschung GmbH,
|
|
6
|
+
distributed under the "New BSD License"). Only the functionality required to
|
|
7
|
+
derive bonds and angles for the LAMMPS ``bond`` and ``full`` atom styles is
|
|
8
|
+
included.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import warnings
|
|
14
|
+
|
|
15
|
+
import numpy as np
|
|
16
|
+
from ase.atoms import Atoms
|
|
17
|
+
from scipy.spatial import cKDTree
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def select_index(structure: Atoms, element: str) -> np.ndarray:
|
|
21
|
+
"""
|
|
22
|
+
Select the indices of atoms in the structure that belong to a specific element.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
structure (ase.atoms.Atoms): Atomic structure.
|
|
26
|
+
element (str): Chemical symbol.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
numpy.ndarray: Indices of the atoms of the given element.
|
|
30
|
+
"""
|
|
31
|
+
return structure.symbols.indices()[element]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_vertical_length(structure: Atoms) -> np.ndarray:
|
|
35
|
+
"""
|
|
36
|
+
Length of each cell vector projected on the normal of the plane spanned by the
|
|
37
|
+
other two cell vectors.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
structure (ase.atoms.Atoms): Atomic structure.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
numpy.ndarray: Projected cell lengths.
|
|
44
|
+
"""
|
|
45
|
+
return np.linalg.det(structure.cell) / np.linalg.norm(
|
|
46
|
+
np.cross(
|
|
47
|
+
np.roll(structure.cell, -1, axis=0), np.roll(structure.cell, 1, axis=0)
|
|
48
|
+
),
|
|
49
|
+
axis=-1,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_extended_positions(
|
|
54
|
+
structure: Atoms, width: float
|
|
55
|
+
) -> tuple[np.ndarray, np.ndarray]:
|
|
56
|
+
"""
|
|
57
|
+
Get the positions of all atoms in the supercell plus all periodic images within
|
|
58
|
+
``width`` of the cell boundary.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
structure (ase.atoms.Atoms): Atomic structure.
|
|
62
|
+
width (float): Width of the buffer layer on every periodic side of the box.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
tuple: Extended positions and the indices of the corresponding atoms in the
|
|
66
|
+
original structure.
|
|
67
|
+
"""
|
|
68
|
+
if width < 0:
|
|
69
|
+
raise ValueError("Invalid width")
|
|
70
|
+
positions = structure.positions
|
|
71
|
+
if width == 0:
|
|
72
|
+
return positions, np.arange(len(positions))
|
|
73
|
+
scaled_width = width / get_vertical_length(structure=structure)
|
|
74
|
+
rep = 2 * np.ceil(scaled_width).astype(int) * structure.pbc + 1
|
|
75
|
+
rep = [np.arange(r) - int(r / 2) for r in rep]
|
|
76
|
+
meshgrid = np.stack(np.meshgrid(rep[0], rep[1], rep[2]), axis=-1).reshape(-1, 3)
|
|
77
|
+
v_repeated = np.einsum("ni,ij->nj", meshgrid, structure.cell)
|
|
78
|
+
v_repeated = v_repeated[:, np.newaxis, :] + positions[np.newaxis, :, :]
|
|
79
|
+
v_repeated = v_repeated.reshape(-1, 3)
|
|
80
|
+
indices = np.tile(np.arange(len(positions)), len(meshgrid))
|
|
81
|
+
dist = v_repeated - np.sum(structure.cell * 0.5, axis=0)
|
|
82
|
+
dist = (
|
|
83
|
+
np.absolute(np.einsum("ni,ij->nj", dist + 1e-8, np.linalg.inv(structure.cell)))
|
|
84
|
+
- 0.5
|
|
85
|
+
)
|
|
86
|
+
check_dist = np.all(dist - scaled_width < 0, axis=-1)
|
|
87
|
+
return v_repeated[check_dist], indices[check_dist] % len(positions)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class Neighbors:
|
|
91
|
+
"""
|
|
92
|
+
Neighbourhood information of each atom in a structure.
|
|
93
|
+
|
|
94
|
+
Attributes:
|
|
95
|
+
distances (numpy.ndarray): Distances to the neighbours of each atom. Missing
|
|
96
|
+
entries (beyond the cutoff radius) are filled with ``numpy.inf``.
|
|
97
|
+
indices (numpy.ndarray): Indices of the neighbours of each atom. Missing
|
|
98
|
+
entries are filled with ``numpy.iinfo(numpy.int32).max``.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
def __init__(self, structure: Atoms, distances: np.ndarray, indices: np.ndarray):
|
|
102
|
+
self._structure = structure
|
|
103
|
+
self.distances = distances
|
|
104
|
+
self.indices = indices
|
|
105
|
+
|
|
106
|
+
def get_bonds(
|
|
107
|
+
self,
|
|
108
|
+
radius: float = np.inf,
|
|
109
|
+
max_shells: int | None = None,
|
|
110
|
+
prec: float = 0.1,
|
|
111
|
+
) -> list[dict[str, list[list[int]]]]:
|
|
112
|
+
"""
|
|
113
|
+
Group the neighbours of each atom into shells and chemical species.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
radius (float): Maximum distance for a bond to be considered.
|
|
117
|
+
max_shells (int, optional): Maximum number of shells per species.
|
|
118
|
+
prec (float): Minimum distance gap between two shells; shells closer
|
|
119
|
+
than ``prec`` are merged into one.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
list: For each atom a dictionary mapping the chemical symbol of the
|
|
123
|
+
neighbours to a list of shells, each shell being a list of atom indices.
|
|
124
|
+
"""
|
|
125
|
+
el_list = self._structure.get_chemical_symbols()
|
|
126
|
+
ind_shell = []
|
|
127
|
+
for d, i in zip(self.distances, self.indices):
|
|
128
|
+
cond = d < radius
|
|
129
|
+
dist_vec, ind_vec = d[cond], i[cond]
|
|
130
|
+
ind_where = np.where(np.diff(dist_vec) > prec)[0] + 1
|
|
131
|
+
ia_shells_dict: dict[str, list[list[int]]] = {}
|
|
132
|
+
for i_shell_list in [np.sort(g) for g in np.split(ind_vec, ind_where)]:
|
|
133
|
+
ia_shell_dict: dict[str, list[int]] = {}
|
|
134
|
+
for i_s in i_shell_list:
|
|
135
|
+
ia_shell_dict.setdefault(el_list[i_s], []).append(i_s)
|
|
136
|
+
for el, ia_lst in ia_shell_dict.items():
|
|
137
|
+
shells = ia_shells_dict.setdefault(el, [])
|
|
138
|
+
if max_shells is not None and len(shells) + 1 > max_shells:
|
|
139
|
+
continue
|
|
140
|
+
shells.append(ia_lst)
|
|
141
|
+
ind_shell.append(ia_shells_dict)
|
|
142
|
+
return ind_shell
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _estimate_width(
|
|
146
|
+
structure: Atoms,
|
|
147
|
+
num_neighbors: int,
|
|
148
|
+
cutoff_radius: float = np.inf,
|
|
149
|
+
width_buffer: float = 1.2,
|
|
150
|
+
) -> float:
|
|
151
|
+
"""
|
|
152
|
+
Estimate the width of the periodic buffer layer required to find all neighbours.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
structure (ase.atoms.Atoms): Atomic structure.
|
|
156
|
+
num_neighbors (int): Number of neighbours.
|
|
157
|
+
cutoff_radius (float): Cutoff radius.
|
|
158
|
+
width_buffer (float): Relative safety margin.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
float: Width of the buffer layer.
|
|
162
|
+
"""
|
|
163
|
+
if not any(structure.pbc):
|
|
164
|
+
return 0
|
|
165
|
+
elif cutoff_radius != np.inf:
|
|
166
|
+
return cutoff_radius
|
|
167
|
+
width = np.prod(np.linalg.norm(structure.cell, axis=-1))
|
|
168
|
+
width *= 4 / 3 * np.pi * np.max([num_neighbors, 8]) / len(structure)
|
|
169
|
+
return width_buffer * width ** (1 / 3)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def get_neighbors(
|
|
173
|
+
structure: Atoms,
|
|
174
|
+
num_neighbors: int = 12,
|
|
175
|
+
cutoff_radius: float = np.inf,
|
|
176
|
+
width_buffer: float = 1.2,
|
|
177
|
+
) -> Neighbors:
|
|
178
|
+
"""
|
|
179
|
+
Get the neighbours of each atom in a structure, taking periodic boundary
|
|
180
|
+
conditions into account.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
structure (ase.atoms.Atoms): Atomic structure.
|
|
184
|
+
num_neighbors (int): Maximum number of neighbours per atom.
|
|
185
|
+
cutoff_radius (float): Upper bound of the neighbour distance.
|
|
186
|
+
width_buffer (float): Relative safety margin of the periodic buffer layer.
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
Neighbors: Neighbour distances and indices.
|
|
190
|
+
"""
|
|
191
|
+
if num_neighbors <= 0:
|
|
192
|
+
raise ValueError("invalid number of neighbors")
|
|
193
|
+
if width_buffer < 0:
|
|
194
|
+
raise ValueError("width_buffer must be a positive float")
|
|
195
|
+
width = _estimate_width(
|
|
196
|
+
structure=structure,
|
|
197
|
+
num_neighbors=num_neighbors,
|
|
198
|
+
cutoff_radius=cutoff_radius,
|
|
199
|
+
width_buffer=width_buffer,
|
|
200
|
+
)
|
|
201
|
+
extended_positions, wrapped_indices = get_extended_positions(
|
|
202
|
+
structure=structure, width=width
|
|
203
|
+
)
|
|
204
|
+
if len(extended_positions) < num_neighbors + 1 and cutoff_radius == np.inf:
|
|
205
|
+
raise ValueError(
|
|
206
|
+
"num_neighbors too large - make width_buffer larger and/or make "
|
|
207
|
+
+ "num_neighbors smaller"
|
|
208
|
+
)
|
|
209
|
+
distances, indices = cKDTree(extended_positions).query(
|
|
210
|
+
structure.positions,
|
|
211
|
+
k=num_neighbors + 1,
|
|
212
|
+
distance_upper_bound=cutoff_radius,
|
|
213
|
+
)
|
|
214
|
+
distances = np.asarray(distances).reshape(len(structure), num_neighbors + 1)
|
|
215
|
+
indices = np.asarray(indices).reshape(len(structure), num_neighbors + 1)
|
|
216
|
+
if cutoff_radius < np.inf and np.any(distances[:, -1] < np.inf):
|
|
217
|
+
warnings.warn(
|
|
218
|
+
"Number of neighbors found within the cutoff_radius is equal to "
|
|
219
|
+
+ "num_neighbors. Increase num_neighbors to find all neighbors within "
|
|
220
|
+
+ "cutoff_radius.",
|
|
221
|
+
stacklevel=2,
|
|
222
|
+
)
|
|
223
|
+
valid = distances < np.inf
|
|
224
|
+
indices[valid] = wrapped_indices[indices[valid]]
|
|
225
|
+
indices[~valid] = np.iinfo(np.int32).max
|
|
226
|
+
# The first column is the atom itself
|
|
227
|
+
max_column = np.sum(valid, axis=-1).max()
|
|
228
|
+
return Neighbors(
|
|
229
|
+
structure=structure,
|
|
230
|
+
distances=distances[:, 1:max_column],
|
|
231
|
+
indices=indices[:, 1:max_column],
|
|
232
|
+
)
|
|
@@ -5,9 +5,8 @@ from typing import cast
|
|
|
5
5
|
|
|
6
6
|
import numpy as np
|
|
7
7
|
from ase.atoms import Atoms
|
|
8
|
-
from structuretoolkit.analyse import get_neighbors
|
|
9
|
-
from structuretoolkit.common import select_index
|
|
10
8
|
|
|
9
|
+
from lammpsparser.compatibility.neighbors import get_neighbors, select_index
|
|
11
10
|
from lammpsparser.structure import LammpsStructure
|
|
12
11
|
|
|
13
12
|
|
|
@@ -329,7 +328,7 @@ def get_bonds(
|
|
|
329
328
|
"""
|
|
330
329
|
Identify bonds in a structure based on neighbour distances.
|
|
331
330
|
|
|
332
|
-
Wraps :func:`
|
|
331
|
+
Wraps :func:`lammpsparser.compatibility.neighbors.get_neighbors` and its
|
|
333
332
|
``get_bonds`` method to return a shell-based bond list for each atom.
|
|
334
333
|
|
|
335
334
|
Args:
|
|
@@ -344,16 +343,12 @@ def get_bonds(
|
|
|
344
343
|
|
|
345
344
|
Returns:
|
|
346
345
|
list: Nested bond list as returned by
|
|
347
|
-
:meth:`
|
|
346
|
+
:meth:`lammpsparser.compatibility.neighbors.Neighbors.get_bonds`.
|
|
348
347
|
"""
|
|
349
348
|
neighbors = get_neighbors(
|
|
350
349
|
structure=structure,
|
|
351
350
|
cutoff_radius=radius,
|
|
352
351
|
num_neighbors=num_neighbors,
|
|
353
|
-
tolerance=2,
|
|
354
|
-
id_list=None,
|
|
355
352
|
width_buffer=1.2,
|
|
356
|
-
mode="ragged",
|
|
357
|
-
norm_order=2,
|
|
358
353
|
)
|
|
359
354
|
return neighbors.get_bonds(radius=radius, max_shells=max_shells, prec=prec)
|
|
@@ -554,6 +554,7 @@ def write_lammps_datafile(
|
|
|
554
554
|
file_name: str = "lammps.data",
|
|
555
555
|
working_directory: str | None = None,
|
|
556
556
|
atom_type: str = "atomic",
|
|
557
|
+
force_skewed: bool = False,
|
|
557
558
|
) -> None:
|
|
558
559
|
"""
|
|
559
560
|
Write an ASE structure to a LAMMPS data file.
|
|
@@ -579,6 +580,7 @@ def write_lammps_datafile(
|
|
|
579
580
|
(default), ``"charge"``, ``"bond"``, or ``"full"``.
|
|
580
581
|
"""
|
|
581
582
|
lammps_str = LammpsStructure(bond_dict=bond_dict, units=units, atom_type=atom_type)
|
|
583
|
+
lammps_str._force_skewed = force_skewed
|
|
582
584
|
lammps_str.el_eam_lst = cast(list[str], list(potential_elements))
|
|
583
585
|
lammps_str.structure = structure
|
|
584
586
|
lammps_str.write_file(file_name=file_name, cwd=working_directory)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|