diff --git a/tests/test_neighbors.py b/tests/test_neighbors.py index 5e775c53c..9e682ce42 100644 --- a/tests/test_neighbors.py +++ b/tests/test_neighbors.py @@ -286,11 +286,13 @@ def test_neighbor_list_invariant_under_lattice_image_shifts( _nl_backends_x_cutoffs(), ) @pytest.mark.parametrize("self_interaction", [True, False]) +@pytest.mark.parametrize("molecule_dummy_cell", [0.0, 1.0]) def test_neighbor_list_implementations( *, nl_implementation: Callable[..., tuple[torch.Tensor, torch.Tensor, torch.Tensor]], cutoff: float, self_interaction: bool, + molecule_dummy_cell: float, molecule_atoms_set: list[Atoms], periodic_atoms_set: list[Atoms], ) -> None: @@ -298,8 +300,17 @@ def test_neighbor_list_implementations( Tests all implementations in batched mode with mixed periodic and non-periodic systems, comparing sorted distances against ASE reference values. + + With molecule_dummy_cell != 0 the non-periodic molecules carry a non-zero + (dummy) cell, e.g. from ase.Atoms.get_cell(complete=True). Since pbc stays False + the neighbor list must remain cell-independent and still match ASE values. """ - atoms_list = molecule_atoms_set + periodic_atoms_set + molecules = molecule_atoms_set + if molecule_dummy_cell: + molecules = [atoms.copy() for atoms in molecule_atoms_set] + for atoms in molecules: + atoms.set_cell([molecule_dummy_cell] * 3) # dummy cell; pbc stays False + atoms_list = molecules + periodic_atoms_set is_alchemiops = "alchemiops" in nl_implementation.__name__ if is_alchemiops and cutoff >= 3: atoms_list = [a for a in atoms_list if not a.info.get("very_skewed")] diff --git a/torch_sim/neighbors/alchemiops.py b/torch_sim/neighbors/alchemiops.py index 565a1173e..6c8914d94 100644 --- a/torch_sim/neighbors/alchemiops.py +++ b/torch_sim/neighbors/alchemiops.py @@ -71,6 +71,17 @@ def alchemiops_nl_n2( if _batch_naive_neighbor_list is None: raise RuntimeError("nvalchemiops neighbor list is unavailable") + + # Temporary fix: the naive kernel wraps on every axis ignoring pbc, so a + # non-zero cell breaks non-periodic and partial-pbc systems. Zeroing the cell + # makes the wrap a no-op, fixing fully non-periodic systems (e.g. molecules). + # Slabs / partial pbc are not covered yet and need the upstream fix. + # See https://github.com/TorchSim/torch-sim/issues/575 + non_periodic = ~pbc.any(dim=1) # [n_systems] + if non_periodic.any(): + cell = cell.clone() # avoid modifying the original + cell[non_periodic] = 0.0 + res = _batch_naive_neighbor_list( positions=positions, cutoff=cutoff,