Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions dpdata/formats/lammps/lmp.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ def detect_atom_style(lines: list[str]) -> str | None:
# If it's a small float, likely a charge
if abs(val) < 10 and val != int(val):
return "charge"
# Neutral charge is numerically integral (0.0), but the
# decimal/exponent notation still identifies a charge column.
if any(ch in first_line[2].lower() for ch in (".", "e")):
return "charge"
else:
# Likely molecule ID (integer), so bond/molecular style
return "bond"
Expand Down Expand Up @@ -327,6 +331,11 @@ def get_charges(lines: list[str], atom_style: str = "atomic") -> np.ndarray | No


def get_spins(lines: list[str], atom_style: str = "atomic") -> np.ndarray | None:
# This branch predates explicit LAMMPS spin-style support and stores spin
# columns only in dpdata's legacy atomic layout. Other registered styles
# use their extra columns for unrelated physical quantities.
if atom_style != "atomic":
return None
atom_lines = get_atoms(lines)
if len(atom_lines[0].split()) < 8:
return None
Expand Down
43 changes: 43 additions & 0 deletions tests/test_lammps_atom_styles.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,49 @@ def test_charge_style_no_comment_detection(self) -> None:
"""Test automatic detection of charge style without style comment."""
self._test_style_parsing("charge_no_comment")

def test_neutral_charge_style_no_comment_detection(self) -> None:
"""Integral-looking ``0.0`` charges must not be mistaken for bonds."""
path = "/tmp/test_neutral_charge_style.lmp"
self.test_files["neutral_charge"] = path
with open(path, "w") as fp:
fp.write(
"""2 atoms
1 atom types
0.0 2.0 xlo xhi
0.0 2.0 ylo yhi
0.0 2.0 zlo zhi

Atoms

1 1 0.0 0.0 0.0 0.0
2 1 0.0 1.0 1.0 1.0
"""
)
system = self._load_system("neutral_charge")
self.assertIn("charges", system.data)
np.testing.assert_allclose(system["charges"][0], [0.0, 0.0])

def test_dipole_style_does_not_create_spins(self) -> None:
"""Dipole moments are not magnetic spin vectors."""
path = "/tmp/test_dipole_style.lmp"
self.test_files["dipole"] = path
with open(path, "w") as fp:
fp.write(
"""1 atoms
1 atom types
0.0 10.0 xlo xhi
0.0 10.0 ylo yhi
0.0 10.0 zlo zhi

Atoms # dipole

1 1 0.0 1.0 2.0 3.0 0.1 0.2 0.3
"""
)
system = self._load_system("dipole")
self.assertIn("charges", system.data)
self.assertNotIn("spins", system.data)

def test_bond_style_no_comment_detection(self) -> None:
"""Test automatic detection of bond style without style comment."""
self._test_style_parsing("bond_no_comment")
Expand Down
Loading