diff --git a/dpdata/formats/gromacs/gro.py b/dpdata/formats/gromacs/gro.py index 0c61544fd..a5950c7be 100644 --- a/dpdata/formats/gromacs/gro.py +++ b/dpdata/formats/gromacs/gro.py @@ -77,7 +77,12 @@ def file_to_system_data(fname: FileType, format_atom_name=True, **kwargs): posis = np.array(posis) if frame == 1: system["orig"] = np.zeros(3) - system["atom_names"] = list(set(names)) + # A .gro file does not carry a separate atom-type table. When + # callers do not provide ``type_map``, infer that table from + # the first occurrence of each atom name. ``dict`` preserves + # insertion order, unlike ``set`` whose hash-dependent order + # could silently change the type IDs used by later exporters. + system["atom_names"] = list(dict.fromkeys(names)) system["atom_numbs"] = [ names.count(ii) for ii in system["atom_names"] ] diff --git a/tests/gromacs/type_order.gro b/tests/gromacs/type_order.gro new file mode 100644 index 000000000..ac52c7386 --- /dev/null +++ b/tests/gromacs/type_order.gro @@ -0,0 +1,7 @@ +Generated with MDTraj, t= 0.0 + 4 + 1MOL LI 1 0.254 0.254 0.024 + 2MOL CL 2 0.507 0.000 0.000 + 3MOL P 3 0.507 0.507 0.507 + 4MOL S1 4 0.896 0.389 0.118 + 1.01400 1.01400 1.01400 0.00000 0.00000 0.00000 0.00000 0.00000 0.00000 diff --git a/tests/test_gromacs_gro.py b/tests/test_gromacs_gro.py index 674c65100..a779a8f4b 100644 --- a/tests/test_gromacs_gro.py +++ b/tests/test_gromacs_gro.py @@ -7,6 +7,16 @@ class TestGromacsGro(unittest.TestCase): + def test_infer_atom_types_in_first_seen_order(self): + # Without an explicit type_map, atom names define the type IDs in the + # order in which they first occur in the .gro file. Checking membership + # alone would miss the order regression reported for this conversion. + system = dpdata.System("gromacs/type_order.gro") + + self.assertEqual(system["atom_names"], ["Li", "Cl", "P", "S"]) + self.assertEqual(system["atom_numbs"], [1, 1, 1, 1]) + self.assertEqual(system["atom_types"].tolist(), [0, 1, 2, 3]) + def test_read_file(self): system = dpdata.System("gromacs/1h.gro", type_map=["H", "O"]) self.assertTrue("H" in system["atom_names"])