lammpsparser 0.0.7__tar.gz → 0.0.8__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 (19) hide show
  1. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/PKG-INFO +2 -2
  2. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/pyproject.toml +2 -2
  3. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/src/lammpsparser/_version.py +2 -2
  4. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/src/lammpsparser/compatibility/calculate.py +21 -45
  5. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/src/lammpsparser/compatibility/data.py +11 -10
  6. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/src/lammpsparser/compatibility/file.py +18 -15
  7. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/src/lammpsparser/compatibility/output.py +4 -1
  8. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/src/lammpsparser/compatibility/structure.py +45 -56
  9. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/src/lammpsparser/output.py +36 -38
  10. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/src/lammpsparser/output_raw.py +21 -22
  11. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/src/lammpsparser/potential.py +8 -9
  12. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/src/lammpsparser/structure.py +50 -69
  13. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/src/lammpsparser/units.py +10 -11
  14. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/.gitignore +0 -0
  15. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/LICENSE +0 -0
  16. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/README.md +0 -0
  17. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/src/lammpsparser/__init__.py +0 -0
  18. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/src/lammpsparser/compatibility/__init__.py +0 -0
  19. {lammpsparser-0.0.7 → lammpsparser-0.0.8}/src/lammpsparser/compatibility/constraints.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lammpsparser
3
- Version: 0.0.7
3
+ Version: 0.0.8
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
@@ -51,7 +51,7 @@ Classifier: Topic :: Scientific/Engineering :: Physics
51
51
  Requires-Python: <3.15,>=3.9
52
52
  Requires-Dist: ase<=3.29.0,>=3.22.1
53
53
  Requires-Dist: numpy<=2.4.6,>=1.26.0
54
- Requires-Dist: pandas<=3.0.3,>=2.0.3
54
+ Requires-Dist: pandas<=3.0.5,>=2.0.3
55
55
  Requires-Dist: scipy<=1.17.1,>=1.11.1
56
56
  Provides-Extra: compatibility
57
57
  Requires-Dist: structuretoolkit<=0.0.45,>=0.0.30; extra == 'compatibility'
@@ -5,7 +5,7 @@ requires = [
5
5
  "h5py",
6
6
  "pandas",
7
7
  "scipy",
8
- "hatchling==1.30.1",
8
+ "hatchling==1.31.0",
9
9
  "hatch-vcs==0.5.0",
10
10
  ]
11
11
  build-backend = "hatchling.build"
@@ -36,7 +36,7 @@ classifiers = [
36
36
  dependencies = [
37
37
  "ase>=3.22.1,<=3.29.0",
38
38
  "numpy>=1.26.0,<=2.4.6",
39
- "pandas>=2.0.3,<=3.0.3",
39
+ "pandas>=2.0.3,<=3.0.5",
40
40
  "scipy>=1.11.1,<=1.17.1",
41
41
  ]
42
42
  dynamic = ["version"]
@@ -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.0.7'
22
- __version_tuple__ = version_tuple = (0, 0, 7)
21
+ __version__ = version = '0.0.8'
22
+ __version_tuple__ = version_tuple = (0, 0, 8)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -64,10 +64,10 @@ def calc_md(
64
64
  delta_press (float): Barostat timescale, but in your Lammps time units, whatever those
65
65
  are. (DEPRECATED.)
66
66
  job_name (str): Job name of the job to generate a unique random seed.
67
- rotation_matrix (numpy.ndarray): The rotation matrix from the pyiron to Lammps coordinate
67
+ rotation_matrix (numpy.ndarray): The rotation matrix from the ASE to Lammps coordinate
68
68
  frame.
69
69
  """
70
- if units not in LAMMPS_UNIT_CONVERSIONS.keys():
70
+ if units not in LAMMPS_UNIT_CONVERSIONS:
71
71
  raise NotImplementedError
72
72
  time_units = LAMMPS_UNIT_CONVERSIONS[units]["time"]
73
73
  temperature_units = LAMMPS_UNIT_CONVERSIONS[units]["temperature"]
@@ -103,7 +103,7 @@ def calc_md(
103
103
  raise ValueError(
104
104
  "At most two temperatures can be provided "
105
105
  "(for a linearly ramping target temperature), "
106
- "but got {}".format(len(temperature))
106
+ f"but got {len(temperature)}"
107
107
  )
108
108
  temperature *= temperature_units
109
109
 
@@ -128,35 +128,24 @@ def calc_md(
128
128
  )
129
129
 
130
130
  if np.isscalar(pressure):
131
- pressure_string = " iso {0} {0} {1}".format(
132
- pressure, pressure_damping_timescale
133
- )
131
+ pressure_string = f" iso {pressure} {pressure} {pressure_damping_timescale}"
134
132
  else:
135
133
  pressure_string = ""
136
134
  for ii, (coord, value) in enumerate(
137
135
  zip(["x", "y", "z", "xy", "xz", "yz"], pressure)
138
136
  ):
139
137
  if value is not None:
140
- pressure_string += " {0} {1} {1} {2}".format(
141
- coord, value, pressure_damping_timescale
138
+ pressure_string += (
139
+ f" {coord} {value} {value} {pressure_damping_timescale}"
142
140
  )
143
141
  # if ii > 2:
144
142
  # force_skewed = True
145
143
 
146
144
  if langevin: # NPT(Langevin)
147
145
  fix_ensemble_str = "fix ensemble all nph" + pressure_string
148
- thermo_str = "fix langevin all langevin {0} {1} {2} {3} zero yes".format(
149
- str(temperature[0]),
150
- str(temperature[1]),
151
- str(temperature_damping_timescale),
152
- str(seed),
153
- )
146
+ thermo_str = f"fix langevin all langevin {temperature[0]!s} {temperature[1]!s} {temperature_damping_timescale!s} {seed!s} zero yes"
154
147
  else: # NPT(Nose-Hoover)
155
- fix_ensemble_str = "fix ensemble all npt temp {0} {1} {2}".format(
156
- str(temperature[0]),
157
- str(temperature[1]),
158
- str(temperature_damping_timescale),
159
- )
148
+ fix_ensemble_str = f"fix ensemble all npt temp {temperature[0]!s} {temperature[1]!s} {temperature_damping_timescale!s}"
160
149
  fix_ensemble_str += pressure_string
161
150
  elif temperature is not None: # NVT
162
151
  if temperature.min() <= 0:
@@ -166,18 +155,9 @@ def calc_md(
166
155
 
167
156
  if langevin: # NVT(Langevin)
168
157
  fix_ensemble_str = "fix ensemble all nve"
169
- thermo_str = "fix langevin all langevin {0} {1} {2} {3} zero yes".format(
170
- str(temperature[0]),
171
- str(temperature[1]),
172
- str(temperature_damping_timescale),
173
- str(seed),
174
- )
158
+ thermo_str = f"fix langevin all langevin {temperature[0]!s} {temperature[1]!s} {temperature_damping_timescale!s} {seed!s} zero yes"
175
159
  else: # NVT(Nose-Hoover)
176
- fix_ensemble_str = "fix ensemble all nvt temp {0} {1} {2}".format(
177
- str(temperature[0]),
178
- str(temperature[1]),
179
- str(temperature_damping_timescale),
180
- )
160
+ fix_ensemble_str = f"fix ensemble all nvt temp {temperature[0]!s} {temperature[1]!s} {temperature_damping_timescale!s}"
181
161
  else: # NVE
182
162
  if langevin:
183
163
  warnings.warn("Temperature not set; Langevin ignored.")
@@ -190,8 +170,8 @@ def calc_md(
190
170
  if thermo_str != "":
191
171
  line_lst.append(thermo_str)
192
172
 
193
- line_lst.append("variable thermotime equal {} ".format(n_print))
194
- line_lst.append("timestep {}".format(time_step))
173
+ line_lst.append(f"variable thermotime equal {n_print} ")
174
+ line_lst.append(f"timestep {time_step}")
195
175
  if initial_temperature is not None and initial_temperature > 0:
196
176
  line_lst.append(
197
177
  _set_initial_velocity(
@@ -241,18 +221,14 @@ def calc_minimize(
241
221
  style ('cg'/'sd'/other values from Lammps docs): The style of the numeric minimization, either conjugate
242
222
  gradient, steepest descent, or other keys permissible from the Lammps docs on 'min_style'. (Default
243
223
  is 'cg' -- conjugate gradient.)
244
- rotation_matrix (numpy.ndarray): The rotation matrix from the pyiron to Lammps coordinate frame.
224
+ rotation_matrix (numpy.ndarray): The rotation matrix from the ASE to Lammps coordinate frame.
245
225
  """
246
- # This docstring is a source for the calc_minimize method in pyiron_atomistics.lammps.base.LammpsBase.calc_minimize and
247
- # pyiron_atomistics.lammps.interactive.LammpsInteractive.calc_minimize -- Please ensure that changes to signature or
248
- # defaults stay consistent!
249
-
250
226
  max_evaluations = 100 * max_iter
251
227
  if n_print > max_iter:
252
228
  warnings.warn("n_print larger than max_iter, adjusting to n_print=max_iter")
253
229
  n_print = max_iter
254
230
 
255
- if units not in LAMMPS_UNIT_CONVERSIONS.keys():
231
+ if units not in LAMMPS_UNIT_CONVERSIONS:
256
232
  raise NotImplementedError
257
233
  energy_units = LAMMPS_UNIT_CONVERSIONS[units]["energy"]
258
234
  force_units = LAMMPS_UNIT_CONVERSIONS[units]["force"]
@@ -260,7 +236,7 @@ def calc_minimize(
260
236
  ionic_energy_tolerance *= energy_units
261
237
  ionic_force_tolerance *= force_units
262
238
 
263
- line_lst = ["variable thermotime equal {} ".format(n_print)]
239
+ line_lst = [f"variable thermotime equal {n_print} "]
264
240
  line_lst += _get_thermo()
265
241
  if pressure is not None:
266
242
  if rotation_matrix is None:
@@ -278,14 +254,14 @@ def calc_minimize(
278
254
  pressure=pressure, rotation_matrix=rotation_matrix, units=units
279
255
  )
280
256
  if np.isscalar(pressure):
281
- str_press = " iso {}".format(float(cast(Any, pressure)))
257
+ str_press = f" iso {float(cast(Any, pressure))}"
282
258
  else:
283
259
  str_press = ""
284
260
  for ii, (press, str_axis) in enumerate(
285
261
  zip(pressure, ["x", "y", "z", "xy", "xz", "yz"])
286
262
  ):
287
263
  if press is not None:
288
- str_press += " {} {}".format(str_axis, press)
264
+ str_press += f" {str_axis} {press}"
289
265
  # if ii > 2:
290
266
  # force_skewed = True
291
267
  if len(str_press) > 1:
@@ -407,11 +383,11 @@ def _pressure_to_lammps(pressure, rotation_matrix, units="metal"):
407
383
  In case of a single pressure value, it is again returned as a single pressure value, to be used with the "iso"
408
384
  option (i.e., coupled deformation in x, y, and z).
409
385
 
410
- Finally, we also ensure that the units are converted from pyiron's GPa to whatever Lammps needs.
386
+ Finally, we also ensure that the units are converted from lammpsparser's GPa to whatever Lammps needs.
411
387
 
412
388
  Args:
413
389
  pressure (float/list/tuple/numpy.ndarray): The pressure(s) to convert.
414
- rotation_matrix (numpy.ndarray): The 3x3 matrix rotating from the pyiron to Lammps coordinate frame.
390
+ rotation_matrix (numpy.ndarray): The 3x3 matrix rotating from the ASE to Lammps coordinate frame.
415
391
 
416
392
  Returns:
417
393
  (list): pxx, pyy, pzz, pxy, pxz, and pyz to be passed to Lammps.
@@ -433,7 +409,7 @@ def _pressure_to_lammps(pressure, rotation_matrix, units="metal"):
433
409
  if len(pressure) > 6:
434
410
  raise ValueError(
435
411
  "Pressure can have a maximum of 6 values, (x, y, z, xy, xz, and yz), but got "
436
- + "{}".format(len(pressure))
412
+ + f"{len(pressure)}"
437
413
  )
438
414
  pressure = [float(p) if p is not None else None for p in pressure]
439
415
  pressure += (6 - len(pressure)) * [None]
@@ -451,7 +427,7 @@ def _pressure_to_lammps(pressure, rotation_matrix, units="metal"):
451
427
  "Cells which are not orthorhombic or an upper-triangular cell are incompatible with Lammps "
452
428
  "constant pressure calculations unless the entire pressure tensor is defined. "
453
429
  "The reason is that Lammps demands such cells be represented with an "
454
- "upper-triangular unit cell, thus a rotation between Lammps and pyiron coordinate "
430
+ "upper-triangular unit cell, thus a rotation between Lammps and ASE coordinate "
455
431
  "frames is required; it is not possible to rotate the pressure tensor if any of "
456
432
  "its components is None."
457
433
  )
@@ -1,5 +1,6 @@
1
+ from __future__ import annotations
2
+
1
3
  from dataclasses import dataclass
2
- from typing import Optional, Union
3
4
 
4
5
  import numpy as np
5
6
 
@@ -41,20 +42,20 @@ class CalcMDInput:
41
42
  frame. Derived automatically when ``None``.
42
43
  """
43
44
 
44
- temperature: Optional[Union[float, list]] = None
45
- pressure: Optional[Union[float, list, np.ndarray]] = None
45
+ temperature: float | list | None = None
46
+ pressure: float | list | np.ndarray | None = None
46
47
  n_ionic_steps: int = 1
47
48
  time_step: float = 1.0
48
49
  n_print: int = 100
49
50
  temperature_damping_timescale: float = 100.0
50
51
  pressure_damping_timescale: float = 1000.0
51
52
  seed: int = 80996
52
- tloop: Optional[int] = None
53
- initial_temperature: Optional[float] = None
53
+ tloop: int | None = None
54
+ initial_temperature: float | None = None
54
55
  langevin: bool = False
55
- delta_temp: Optional[float] = None
56
- delta_press: Optional[float] = None
57
- rotation_matrix: Optional[Union[list, np.ndarray]] = None
56
+ delta_temp: float | None = None
57
+ delta_press: float | None = None
58
+ rotation_matrix: list | np.ndarray | None = None
58
59
 
59
60
 
60
61
  @dataclass
@@ -81,7 +82,7 @@ class CalcMinimizeInput:
81
82
  ionic_energy_tolerance: float = 0.0
82
83
  ionic_force_tolerance: float = 1e-4
83
84
  max_iter: int = 100000
84
- pressure: Optional[Union[float, list, np.ndarray]] = None
85
+ pressure: float | list | np.ndarray | None = None
85
86
  n_print: int = 1
86
87
  style: str = "cg"
87
- rotation_matrix: Optional[Union[list, np.ndarray]] = None
88
+ rotation_matrix: list | np.ndarray | None = None
@@ -1,8 +1,9 @@
1
+ from __future__ import annotations
2
+
1
3
  import os
2
4
  import shutil
3
5
  import subprocess
4
6
  from dataclasses import asdict
5
- from typing import Optional, Union
6
7
 
7
8
  import pandas
8
9
  from ase.atoms import Atoms
@@ -24,27 +25,27 @@ def lammps_file_interface_function(
24
25
  structure: Atoms,
25
26
  potential: str,
26
27
  calc_mode: str = "static",
27
- calc_kwargs: Optional[dict] = None,
28
- calc_dataclass: Optional[Union[CalcMDInput, CalcMinimizeInput]] = None,
28
+ calc_kwargs: dict | None = None,
29
+ calc_dataclass: CalcMDInput | CalcMinimizeInput | None = None,
29
30
  units: str = "metal",
30
- lmp_command: Optional[str] = None,
31
- resource_path: Optional[str] = None,
32
- input_control_file: Optional[dict] = None,
31
+ lmp_command: str | None = None,
32
+ resource_path: str | None = None,
33
+ input_control_file: dict | None = None,
33
34
  write_restart_file: bool = False,
34
35
  read_restart_file: bool = False,
35
36
  restart_file: str = "restart.out",
36
37
  dump_final_structure: bool = False,
37
38
  ):
38
39
  """
39
- A single function to execute a LAMMPS calculation based on the LAMMPS job implemented in pyiron
40
+ A single function to execute a LAMMPS calculation based on the LAMMPS job interface implemented in lammpsparser
40
41
 
41
42
  Examples:
42
43
 
43
44
  >>> import os
44
45
  >>> from ase.build import bulk
45
- >>> from pyiron_atomistics.lammps.lammps import lammps_function
46
+ >>> from lammpsparser.compatibility.file import lammps_file_interface_function
46
47
  >>>
47
- >>> shell_output, parsed_output, job_crashed = lammps_function(
48
+ >>> shell_output, parsed_output, job_crashed = lammps_file_interface_function(
48
49
  ... working_directory=os.path.abspath("lmp_working_directory"),
49
50
  ... structure=bulk("Al", cubic=True),
50
51
  ... potential='2009--Mendelev-M-I--Al-Mg--LAMMPS--ipr1',
@@ -178,7 +179,7 @@ def lammps_file_interface_function(
178
179
  structure=structure, calc_md=True
179
180
  ).items()
180
181
  ]
181
- if "n_ionic_steps" in calc_kwargs.keys():
182
+ if "n_ionic_steps" in calc_kwargs:
182
183
  n_ionic_steps = int(calc_kwargs.pop("n_ionic_steps"))
183
184
  else:
184
185
  n_ionic_steps = 1
@@ -192,7 +193,7 @@ def lammps_file_interface_function(
192
193
  )
193
194
  if read_restart_file:
194
195
  lmp_str_lst += ["reset_timestep 0"]
195
- lmp_str_lst += ["run {} ".format(n_ionic_steps)]
196
+ lmp_str_lst += [f"run {n_ionic_steps} "]
196
197
  last_step_is_regular_dump = n_ionic_steps % calc_kwargs.get("n_print", 1) == 0
197
198
  if dump_final_structure and not last_step_is_regular_dump:
198
199
  lmp_str_lst += [
@@ -305,8 +306,8 @@ def lammps_file_initialization(
305
306
 
306
307
 
307
308
  def _modify_input_dict(
308
- input_control_file: Optional[dict] = None,
309
- lmp_str_lst: list[str] = [],
309
+ input_control_file: dict | None = None,
310
+ lmp_str_lst: list[str] | None = None,
310
311
  ):
311
312
  """
312
313
  Apply user-supplied overrides to a LAMMPS input line list.
@@ -325,13 +326,15 @@ def _modify_input_dict(
325
326
  Returns:
326
327
  list[str]: Modified (or unchanged) list of LAMMPS input lines.
327
328
  """
329
+ if lmp_str_lst is None:
330
+ lmp_str_lst = []
328
331
  if input_control_file is not None:
329
332
  lmp_tmp_lst, keys_used = [], []
330
333
  for line in lmp_str_lst:
331
334
  ls = line.split()
332
335
  if len(ls) >= 1: # Remove empty lines
333
336
  key = ls[0]
334
- if key in input_control_file.keys():
337
+ if key in input_control_file:
335
338
  lmp_tmp_lst.append(key + " " + input_control_file[key])
336
339
  keys_used.append(key)
337
340
  else:
@@ -345,7 +348,7 @@ def _modify_input_dict(
345
348
  return lmp_str_lst
346
349
 
347
350
 
348
- def _get_potential(potential, resource_path: Optional[str] = None):
351
+ def _get_potential(potential, resource_path: str | None = None):
349
352
  """
350
353
  Resolve a potential specification to LAMMPS input lines and species list.
351
354
 
@@ -6,6 +6,7 @@ def structure_from_parsed_output(
6
6
  parsed_output: dict,
7
7
  *,
8
8
  wrap: bool = False,
9
+ scale_atoms: bool = True,
9
10
  index: int = -1,
10
11
  ) -> Atoms:
11
12
  """Construct an `Atoms` object from parsed output data.
@@ -27,10 +28,12 @@ def structure_from_parsed_output(
27
28
  """
28
29
  # Take a copy of the initial structure as template and update the relevant properties
29
30
  atoms_copy = initial_structure.copy()
31
+ atoms_copy.set_cell(
32
+ parsed_output["generic"]["cells"][index], scale_atoms=scale_atoms
33
+ )
30
34
  atoms_copy.set_array("indices", parsed_output["generic"]["indices"][index])
31
35
  atoms_copy.set_positions(parsed_output["generic"]["positions"][index])
32
36
  atoms_copy.set_velocities(parsed_output["generic"]["velocities"][index])
33
- atoms_copy.set_cell(parsed_output["generic"]["cells"][index])
34
37
  atoms_copy.set_pbc(True)
35
38
  if wrap:
36
39
  atoms_copy.wrap()
@@ -1,5 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  from collections import OrderedDict
2
- from typing import Dict, List, Optional, Union, cast
4
+ from typing import cast
3
5
 
4
6
  import numpy as np
5
7
  from ase.atoms import Atoms
@@ -12,15 +14,15 @@ from lammpsparser.structure import LammpsStructure
12
14
  class LammpsStructureCompatibility(LammpsStructure):
13
15
  def __init__(
14
16
  self,
15
- bond_dict: Optional[Dict] = None,
17
+ bond_dict: dict | None = None,
16
18
  units: str = "metal",
17
19
  atom_type: str = "atomic",
18
20
  ):
19
21
  super().__init__(bond_dict=bond_dict, units=units, atom_type=atom_type)
20
- self._molecule_ids: Optional[List[int]] = []
22
+ self._molecule_ids: list[int] | None = []
21
23
 
22
24
  @property
23
- def structure(self) -> Optional[Atoms]:
25
+ def structure(self) -> Atoms | None:
24
26
  """The ASE :class:`~ase.atoms.Atoms` object associated with this instance."""
25
27
  return self._structure
26
28
 
@@ -49,14 +51,14 @@ class LammpsStructureCompatibility(LammpsStructure):
49
51
  self._string_input = input_str + self._get_velocities_input_string()
50
52
 
51
53
  @property
52
- def molecule_ids(self) -> Union[List[int], np.ndarray]:
54
+ def molecule_ids(self) -> list[int] | np.ndarray:
53
55
  """Per-atom molecule IDs; defaults to all atoms in a single molecule."""
54
56
  if self._molecule_ids is None or len(self._molecule_ids) == 0:
55
57
  return np.ones(len(cast(Atoms, self._structure)), dtype=int)
56
58
  return self._molecule_ids
57
59
 
58
60
  @molecule_ids.setter
59
- def molecule_ids(self, molecule_ids: Optional[List[int]]):
61
+ def molecule_ids(self, molecule_ids: list[int] | None):
60
62
  self._molecule_ids = molecule_ids
61
63
 
62
64
  def structure_bond(self):
@@ -154,9 +156,7 @@ class LammpsStructureCompatibility(LammpsStructure):
154
156
 
155
157
  bonds_str = "Bonds \n\n"
156
158
  for i_bond, (i_a, i_b, b_type) in enumerate(bonds):
157
- bonds_str += (
158
- "{0:d} {1:d} {2:d} {3:d}".format(i_bond + 1, b_type, i_a, i_b) + "\n"
159
- )
159
+ bonds_str += f"{i_bond + 1:d} {b_type:d} {i_a:d} {i_b:d}" + "\n"
160
160
 
161
161
  return (
162
162
  self.lammps_header(
@@ -209,7 +209,7 @@ class LammpsStructureCompatibility(LammpsStructure):
209
209
  # Using a cutoff distance to draw the bonds instead of the number of neighbors
210
210
  # Only if any bonds are defined
211
211
  if self._bond_dict is not None and len(self._bond_dict.keys()) > 0:
212
- cutoff_list = list()
212
+ cutoff_list = []
213
213
  for val in self._bond_dict.values():
214
214
  cutoff_list.append(np.max(val["cutoff_list"]))
215
215
  max_cutoff = np.max(cutoff_list)
@@ -222,45 +222,42 @@ class LammpsStructureCompatibility(LammpsStructure):
222
222
  # Go through all elements for which bonds are defined
223
223
  for element, val in self._bond_dict.items():
224
224
  el_1_list = select_index(structure=self._structure, element=element)
225
- if el_1_list is not None:
226
- if len(el_1_list) > 0:
227
- for i, v in enumerate(val["element_list"]):
228
- el_2_list = select_index(
229
- structure=self._structure, element=v
225
+ if el_1_list is not None and len(el_1_list) > 0:
226
+ for i, v in enumerate(val["element_list"]):
227
+ el_2_list = select_index(structure=self._structure, element=v)
228
+ cutoff_dist = val["cutoff_list"][i]
229
+ for j, ind in enumerate(
230
+ np.array(neighbors.indices, dtype=object)[el_1_list]
231
+ ):
232
+ # Only chose those indices within the cutoff distance and which belong
233
+ # to the species defined in the element_list
234
+ # i is the index of each bond type, and j is the element index
235
+ id_el = el_1_list[j]
236
+ bool_1 = (
237
+ np.array(neighbors.distances, dtype=object)[id_el]
238
+ <= cutoff_dist
230
239
  )
231
- cutoff_dist = val["cutoff_list"][i]
232
- for j, ind in enumerate(
233
- np.array(neighbors.indices, dtype=object)[el_1_list]
240
+ act_ind = ind[bool_1]
241
+ bool_2 = np.isin(act_ind, el_2_list)
242
+ final_ind = act_ind[bool_2]
243
+ # Get the bond and angle type
244
+ bond_type = val["bond_type_list"][i]
245
+ angle_type = val["angle_type_list"][i]
246
+ # Draw only maximum allowed bonds
247
+ final_ind = final_ind[: val["max_bond_list"][i]]
248
+ for fi in final_ind:
249
+ bonds_lst.append([id_el + 1, fi + 1])
250
+ bond_type_lst.append(bond_type)
251
+ # Draw angles if at least 2 bonds are present and if an angle type is defined for this
252
+ # particular set of bonds
253
+ if (
254
+ len(final_ind) >= 2
255
+ and val["angle_type_list"][i] is not None
234
256
  ):
235
- # Only chose those indices within the cutoff distance and which belong
236
- # to the species defined in the element_list
237
- # i is the index of each bond type, and j is the element index
238
- id_el = el_1_list[j]
239
- bool_1 = (
240
- np.array(neighbors.distances, dtype=object)[id_el]
241
- <= cutoff_dist
257
+ angles_lst.append(
258
+ [final_ind[0] + 1, id_el + 1, final_ind[1] + 1]
242
259
  )
243
- act_ind = ind[bool_1]
244
- bool_2 = np.isin(act_ind, el_2_list)
245
- final_ind = act_ind[bool_2]
246
- # Get the bond and angle type
247
- bond_type = val["bond_type_list"][i]
248
- angle_type = val["angle_type_list"][i]
249
- # Draw only maximum allowed bonds
250
- final_ind = final_ind[: val["max_bond_list"][i]]
251
- for fi in final_ind:
252
- bonds_lst.append([id_el + 1, fi + 1])
253
- bond_type_lst.append(bond_type)
254
- # Draw angles if at least 2 bonds are present and if an angle type is defined for this
255
- # particular set of bonds
256
- if (
257
- len(final_ind) >= 2
258
- and val["angle_type_list"][i] is not None
259
- ):
260
- angles_lst.append(
261
- [final_ind[0] + 1, id_el + 1, final_ind[1] + 1]
262
- )
263
- angle_type_lst.append(angle_type)
260
+ angle_type_lst.append(angle_type)
264
261
 
265
262
  if len(bond_type_lst) == 0:
266
263
  num_bond_types = 0
@@ -294,9 +291,7 @@ class LammpsStructureCompatibility(LammpsStructure):
294
291
  bonds_str = "Bonds \n\n"
295
292
  for i_bond, id_vec in enumerate(bonds_lst):
296
293
  bonds_str += (
297
- "{0:d} {1:d} {2:d} {3:d}".format(
298
- i_bond + 1, bond_type_lst[i_bond], id_vec[0], id_vec[1]
299
- )
294
+ f"{i_bond + 1:d} {bond_type_lst[i_bond]:d} {id_vec[0]:d} {id_vec[1]:d}"
300
295
  + "\n"
301
296
  )
302
297
  else:
@@ -306,13 +301,7 @@ class LammpsStructureCompatibility(LammpsStructure):
306
301
  angles_str = "Angles \n\n"
307
302
  for i_angle, id_vec in enumerate(angles_lst):
308
303
  angles_str += (
309
- "{0:d} {1:d} {2:d} {3:d} {4:d}".format(
310
- i_angle + 1,
311
- angle_type_lst[i_angle],
312
- id_vec[0],
313
- id_vec[1],
314
- id_vec[2],
315
- )
304
+ f"{i_angle + 1:d} {angle_type_lst[i_angle]:d} {id_vec[0]:d} {id_vec[1]:d} {id_vec[2]:d}"
316
305
  + "\n"
317
306
  )
318
307
  else: