From 774f3b63d2f3c36e3c6ba2d51c9b9c2c10fd3f49 Mon Sep 17 00:00:00 2001 From: Jan Janssen Date: Thu, 27 Nov 2025 11:22:01 +0100 Subject: [PATCH] Bug fix for constraints --- src/pylammpsmpi/wrapper/ase.py | 2 +- tests/test_ase_interface.py | 95 ++++++++++++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 5 deletions(-) diff --git a/src/pylammpsmpi/wrapper/ase.py b/src/pylammpsmpi/wrapper/ase.py index dda0660..0d821a2 100644 --- a/src/pylammpsmpi/wrapper/ase.py +++ b/src/pylammpsmpi/wrapper/ase.py @@ -561,7 +561,7 @@ def get_fixed_atom_boolean_vector(structure): if c_dict["name"] == "FixAtoms": fixed_atom_vector[c_dict["kwargs"]["indices"]] = [True, True, True] elif c_dict["name"] == "FixedPlane": - if all(np.isin(c_dict["kwargs"]["direction"], [0, 1])): + if all(np.isin(c_dict["kwargs"]["direction"], [0, 1, 1 / np.sqrt(2)])): if "indices" in c_dict["kwargs"]: fixed_atom_vector[c_dict["kwargs"]["indices"]] = np.array( c_dict["kwargs"]["direction"] diff --git a/tests/test_ase_interface.py b/tests/test_ase_interface.py index 0419360..09fe60e 100644 --- a/tests/test_ase_interface.py +++ b/tests/test_ase_interface.py @@ -416,7 +416,7 @@ def setUpClass(cls): structure.symbols[2:] = "Al" cls.structure = structure - def test_selective_dynamics_mixed_calcmd(self): + def test_selective_dynamics_mixed_calcmd_x(self): atoms = self.structure.copy() c1 = FixAtoms(indices=[atom.index for atom in atoms if atom.symbol == "Cu"]) c2 = FixedPlane( @@ -433,11 +433,98 @@ def test_selective_dynamics_mixed_calcmd(self): self.assertTrue(control_dict["velocity constraintxyz"], "set 0.0 0.0 0.0") self.assertTrue(control_dict["group constraintx"], "id 3 4") self.assertTrue( - control_dict["fix constraintx"], "constraintx setforce 0.0 NULL NULL" + control_dict["fix constraintx"], "constraintx setforce NULL NULL 0.0" + ) + self.assertTrue(control_dict["velocity constraintx"], "set NULL NULL 0.0") + + def test_selective_dynamics_mixed_calcmd_y(self): + atoms = self.structure.copy() + c1 = FixAtoms(indices=[atom.index for atom in atoms if atom.symbol == "Cu"]) + c2 = FixedPlane( + [atom.index for atom in atoms if atom.symbol == "Al"], + [0, 1, 0], + ) + atoms.set_constraint([c1, c2]) + control_dict = set_selective_dynamics(structure=atoms, calc_md=True) + self.assertEqual(len(control_dict), 6) + self.assertTrue(control_dict["group constraintxyz"], "id 1 2") + self.assertTrue( + control_dict["fix constraintxyz"], "constraintxyz setforce 0.0 0.0 0.0" + ) + self.assertTrue(control_dict["velocity constraintxyz"], "set 0.0 0.0 0.0") + self.assertTrue(control_dict["group constrainty"], "id 3 4") + self.assertTrue( + control_dict["fix constrainty"], "constrainty setforce NULL 0.0 NULL" + ) + self.assertTrue(control_dict["velocity constrainty"], "set NULL 0.0 NULL") + + def test_selective_dynamics_mixed_calcmd_z(self): + atoms = self.structure.copy() + c1 = FixAtoms(indices=[atom.index for atom in atoms if atom.symbol == "Cu"]) + c2 = FixedPlane( + [atom.index for atom in atoms if atom.symbol == "Al"], + [0, 0, 1], + ) + atoms.set_constraint([c1, c2]) + control_dict = set_selective_dynamics(structure=atoms, calc_md=True) + self.assertEqual(len(control_dict), 6) + self.assertTrue(control_dict["group constraintxyz"], "id 1 2") + self.assertTrue( + control_dict["fix constraintxyz"], "constraintxyz setforce 0.0 0.0 0.0" + ) + self.assertTrue(control_dict["velocity constraintxyz"], "set 0.0 0.0 0.0") + self.assertTrue(control_dict["group constraintz"], "id 3 4") + self.assertTrue( + control_dict["fix constraintz"], "constraintz setforce NULL NULL 0.0" + ) + self.assertTrue(control_dict["velocity constraintz"], "set NULL NULL 0.0") + + def test_selective_dynamics_calcmd_xy(self): + atoms = self.structure.copy() + c1 = FixedPlane( + [atom.index for atom in atoms if atom.symbol == "Al"], + [1, 1, 0], + ) + atoms.set_constraint([c1]) + control_dict = set_selective_dynamics(structure=atoms, calc_md=True) + self.assertEqual(len(control_dict), 3) + self.assertTrue(control_dict["group constraintxy"], "id 3 4") + self.assertTrue( + control_dict["fix constraintxy"], "constraintxy setforce NULL 0.0 0.0" + ) + self.assertTrue(control_dict["velocity constraintxy"], "set NULL 0.0 0.0") + + def test_selective_dynamics_calcmd_xz(self): + atoms = self.structure.copy() + c1 = FixedPlane( + [atom.index for atom in atoms if atom.symbol == "Al"], + [1, 0, 1], + ) + atoms.set_constraint([c1]) + control_dict = set_selective_dynamics(structure=atoms, calc_md=True) + self.assertEqual(len(control_dict), 3) + self.assertTrue(control_dict["group constraintxz"], "id 3 4") + self.assertTrue( + control_dict["fix constraintxz"], "constraintxz setforce NULL 0.0 0.0" + ) + self.assertTrue(control_dict["velocity constraintxz"], "set NULL 0.0 0.0") + + def test_selective_dynamics_calcmd_yz(self): + atoms = self.structure.copy() + c1 = FixedPlane( + [atom.index for atom in atoms if atom.symbol == "Al"], + [0, 1, 1], + ) + atoms.set_constraint([c1]) + control_dict = set_selective_dynamics(structure=atoms, calc_md=True) + self.assertEqual(len(control_dict), 3) + self.assertTrue(control_dict["group constraintyz"], "id 3 4") + self.assertTrue( + control_dict["fix constraintyz"], "constraintyz setforce NULL 0.0 0.0" ) - self.assertTrue(control_dict["velocity constraintx"], "set 0.0 NULL NULL") + self.assertTrue(control_dict["velocity constraintyz"], "set NULL 0.0 0.0") - def test_selective_dynamics_mixed(self): + def test_selective_dynamics_mixed_x(self): atoms = self.structure.copy() c1 = FixAtoms(indices=[atom.index for atom in atoms if atom.symbol == "Cu"]) c2 = FixedPlane(