@@ -278,6 +278,9 @@ def modify(system, k_hard=100, k_soft=5, optimise_angles=True, num_optimise=10):
278278 num_optimise = num_optimise ,
279279 )
280280
281+ # Remove any improper dihedrals connecting ghosts to the physical region.
282+ mol = _remove_impropers (mol , ghosts0 , modifications , is_lambda1 = True )
283+
281284 # Now lambda = 1.
282285 for b in bridges1 :
283286 junction = len (physical1 [b ])
@@ -336,6 +339,9 @@ def modify(system, k_hard=100, k_soft=5, optimise_angles=True, num_optimise=10):
336339 is_lambda1 = True ,
337340 )
338341
342+ # Remove any improper dihedrals connecting ghosts to the physical region.
343+ mol = _remove_impropers (mol , ghosts1 , modifications , is_lambda1 = True )
344+
339345 # Update the molecule in the system.
340346 system .update (mol )
341347
@@ -1286,6 +1292,72 @@ def _higher(
12861292 )
12871293
12881294
1295+ def _remove_impropers (mol , ghosts , modifications , is_lambda1 = False ):
1296+ """
1297+ Remove improper dihedral terms that bridge the ghost and physical systems.
1298+
1299+ Parameters
1300+ ----------
1301+
1302+ mol : sire.mol.Molecule
1303+ The perturbable molecule.
1304+
1305+ ghosts : List[sire.legacy.Mol.AtomIdx]
1306+ The list of ghost atoms.
1307+
1308+ modifications : dict
1309+ A dictionary to store details of the modifications made.
1310+
1311+ is_lambda1 : bool, optional
1312+ Whether to remove the improper dihedrals at lambda = 1.
1313+
1314+ Returns
1315+ -------
1316+
1317+ mol : sire.mol.Molecule
1318+ The updated molecule.
1319+ """
1320+
1321+ # Store the molecular info.
1322+ info = mol .info ()
1323+
1324+ # Get the end state bond functions.
1325+ suffix = "1" if is_lambda1 else "0"
1326+ impropers = mol .property ("improper" + suffix )
1327+
1328+ # Initialise a container to store the updated bonded terms.
1329+ new_impropers = _SireMM .FourAtomFunctions (mol .info ())
1330+
1331+ # Loop over the improper dihedrals.
1332+ for p in impropers .potentials ():
1333+ idx0 = info .atom_idx (p .atom0 ())
1334+ idx1 = info .atom_idx (p .atom1 ())
1335+ idx2 = info .atom_idx (p .atom2 ())
1336+ idx3 = info .atom_idx (p .atom3 ())
1337+
1338+ # Remove any improper dihedrals that bridge the ghost and physical systems.
1339+ if not all (idx in ghosts for idx in (idx0 , idx1 , idx2 , idx3 )) and any (
1340+ idx in ghosts for idx in (idx0 , idx1 , idx2 , idx3 )
1341+ ):
1342+ _logger .debug (
1343+ f" Removing improper dihedral: [{ idx0 .value ()} -{ idx1 .value ()} -{ idx2 .value ()} -{ idx3 .value ()} ], { p .function ()} "
1344+ )
1345+ dih_idx = (idx0 .value (), idx1 .value (), idx2 .value (), idx3 .value ())
1346+ dih_idx = "," .join ([str (i ) for i in dih_idx ])
1347+ key = "lambda_1" if is_lambda1 else "lambda_0"
1348+ modifications [key ]["removed_dihedrals" ].append (dih_idx )
1349+ else :
1350+ new_impropers .set (idx0 , idx1 , idx2 , idx3 , p .function ())
1351+
1352+ # Set the updated impropers.
1353+ mol = (
1354+ mol .edit ().set_property ("improper" + suffix , new_impropers ).molecule ().commit ()
1355+ )
1356+
1357+ # Return the updated molecule.
1358+ return mol
1359+
1360+
12891361def _create_connectivity (mol ):
12901362 """
12911363 Create a connectivity object for an end state molecule.
0 commit comments