Skip to content

Commit 30d3b28

Browse files
authored
Merge pull request #488 from OpenBioSim/fix_merge_bugs
Fix inconsistencies in merge code
2 parents cc56ae7 + 2d5043c commit 30d3b28

1 file changed

Lines changed: 115 additions & 123 deletions

File tree

python/BioSimSpace/Align/_merge.py

Lines changed: 115 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ def merge(
8989
merged : Sire.Mol.Molecule
9090
The merged molecule.
9191
"""
92+
from sire.legacy import CAS as _SireCAS
9293
from sire.legacy import Mol as _SireMol
9394
from sire.legacy import Base as _SireBase
9495
from sire.legacy import MM as _SireMM
@@ -1027,45 +1028,29 @@ def merge(
10271028
"or 'allow_ring_size_change' options."
10281029
)
10291030

1030-
# Create the connectivity object.
1031-
conn = _SireMol.Connectivity(edit_mol.info()).edit()
1032-
10331031
# Connectivity in the merged molecule.
10341032
conn0 = _SireMol.Connectivity(edit_mol.info()).edit()
10351033
conn1 = _SireMol.Connectivity(edit_mol.info()).edit()
10361034

1037-
bonds_atoms0 = {
1038-
frozenset([bond.atom0(), bond.atom1()])
1039-
for bond in edit_mol.property("bond0").potentials()
1040-
}
1041-
bonds_atoms1 = {
1042-
frozenset([bond.atom0(), bond.atom1()])
1043-
for bond in edit_mol.property("bond1").potentials()
1044-
}
1045-
1046-
for atom0, atom1 in bonds_atoms0:
1047-
conn0.connect(atom0, atom1)
1048-
1049-
for atom0, atom1 in bonds_atoms1:
1050-
conn1.connect(atom0, atom1)
1051-
1052-
# We only add a bond to the total connectivity if it's defined in both states
1053-
# This results in a "broken" topology if one writes it in GROMACS
1054-
# But GROMACS can't handle bond breaks anyway
1055-
for atom0, atom1 in bonds_atoms0 & bonds_atoms1:
1056-
conn.connect(atom0, atom1)
1057-
1058-
conn = conn.commit()
1035+
# Connect the bonded atoms in both end states.
1036+
for bond in edit_mol.property("bond0").potentials():
1037+
# Only connect bonds with non-zero force constants.
1038+
ab = _SireMM.AmberBond(bond.function(), _SireCAS.Symbol("r"))
1039+
if ab.k() != 0.0:
1040+
conn0.connect(bond.atom0(), bond.atom1())
10591041
conn0 = conn0.commit()
1042+
for bond in edit_mol.property("bond1").potentials():
1043+
# Only connect bonds with non-zero force constants.
1044+
ab = _SireMM.AmberBond(bond.function(), _SireCAS.Symbol("r"))
1045+
if ab.k() != 0.0:
1046+
conn1.connect(bond.atom0(), bond.atom1())
10601047
conn1 = conn1.commit()
10611048

1062-
# Get the connectivity of the two molecules.
1049+
# Get the original connectivity of the two molecules.
10631050
c0 = molecule0.property("connectivity")
10641051
c1 = molecule1.property("connectivity")
10651052

10661053
# Check that the merge hasn't modified the connectivity.
1067-
1068-
# The checking was blocked when merging a protein
10691054
if roi is None:
10701055
# molecule0
10711056
for x in range(0, molecule0.num_atoms()):
@@ -1083,7 +1068,7 @@ def merge(
10831068
idy_map = mol0_merged_mapping[idy]
10841069

10851070
# Was a ring opened/closed?
1086-
is_ring_broken = _is_ring_broken(c0, conn, idx, idy, idx_map, idy_map)
1071+
is_ring_broken = _is_ring_broken(c0, conn1, idx, idy, idx_map, idy_map)
10871072

10881073
# A ring was broken and it is not allowed.
10891074
if is_ring_broken and not allow_ring_breaking:
@@ -1095,7 +1080,7 @@ def merge(
10951080

10961081
# Did a ring change size?
10971082
is_ring_size_change = _is_ring_size_changed(
1098-
c0, conn, idx, idy, idx_map, idy_map
1083+
c0, conn1, idx, idy, idx_map, idy_map
10991084
)
11001085

11011086
# A ring changed size and it is not allowed.
@@ -1113,7 +1098,7 @@ def merge(
11131098
)
11141099

11151100
# The connectivity has changed.
1116-
if c0.connection_type(idx, idy) != conn.connection_type(
1101+
if c0.connection_type(idx, idy) != conn1.connection_type(
11171102
idx_map, idy_map
11181103
):
11191104
# The connectivity changed for an unknown reason.
@@ -1141,7 +1126,7 @@ def merge(
11411126
idy_map = mol1_merged_mapping[idy]
11421127

11431128
# Was a ring opened/closed?
1144-
is_ring_broken = _is_ring_broken(c1, conn, idx, idy, idx_map, idy_map)
1129+
is_ring_broken = _is_ring_broken(c1, conn0, idx, idy, idx_map, idy_map)
11451130

11461131
# A ring was broken and it is not allowed.
11471132
if is_ring_broken and not allow_ring_breaking:
@@ -1153,7 +1138,7 @@ def merge(
11531138

11541139
# Did a ring change size?
11551140
is_ring_size_change = _is_ring_size_changed(
1156-
c1, conn, idx, idy, idx_map, idy_map
1141+
c1, conn0, idx, idy, idx_map, idy_map
11571142
)
11581143

11591144
# A ring changed size and it is not allowed.
@@ -1171,7 +1156,7 @@ def merge(
11711156
)
11721157

11731158
# The connectivity has changed.
1174-
if c1.connection_type(idx, idy) != conn.connection_type(
1159+
if c1.connection_type(idx, idy) != conn0.connection_type(
11751160
idx_map, idy_map
11761161
):
11771162
# The connectivity changed for an unknown reason.
@@ -1266,90 +1251,95 @@ def merge(
12661251
iterlen = len(molecule1_roi_idx)
12671252
iterrange = molecule1_roi_idx
12681253

1269-
for x in range(0, iterlen):
1254+
for x in range(0, iterlen):
1255+
# Convert to an AtomIdx.
1256+
idx = iterrange[x]
1257+
idx = _SireMol.AtomIdx(idx)
1258+
1259+
# Map the index to its position in the merged molecule.
1260+
idx_map = mol1_merged_mapping[idx]
1261+
1262+
for y in range(x + 1, iterlen):
1263+
idy = iterrange[y]
12701264
# Convert to an AtomIdx.
1271-
idx = iterrange[x]
1272-
idx = _SireMol.AtomIdx(idx)
1265+
idy = _SireMol.AtomIdx(idy)
12731266

12741267
# Map the index to its position in the merged molecule.
1275-
idx_map = mol1_merged_mapping[idx]
1276-
1277-
for y in range(x + 1, iterlen):
1278-
idy = iterrange[y]
1279-
# Convert to an AtomIdx.
1280-
idy = _SireMol.AtomIdx(idy)
1268+
idy_map = mol1_merged_mapping[idy]
12811269

1282-
# Map the index to its position in the merged molecule.
1283-
idy_map = mol1_merged_mapping[idy]
1270+
conn_type = conn0.connection_type(idx_map, idy_map)
1271+
# The atoms aren't bonded.
1272+
if conn_type == 0:
1273+
clj_scale_factor = _SireMM.CLJScaleFactor(1, 1)
1274+
clj_nb_pairs0.set(idx_map, idy_map, clj_scale_factor)
12841275

1285-
conn_type = conn0.connection_type(idx_map, idy_map)
1286-
# The atoms aren't bonded.
1287-
if conn_type == 0:
1288-
clj_scale_factor = _SireMM.CLJScaleFactor(1, 1)
1289-
clj_nb_pairs0.set(idx_map, idy_map, clj_scale_factor)
1276+
# The atoms are part of a dihedral.
1277+
elif conn_type == 4:
1278+
clj_scale_factor = _SireMM.CLJScaleFactor(
1279+
ff.electrostatic14_scale_factor(), ff.vdw14_scale_factor()
1280+
)
1281+
clj_nb_pairs0.set(idx_map, idy_map, clj_scale_factor)
12901282

1291-
# The atoms are part of a dihedral.
1292-
elif conn_type == 4:
1293-
clj_scale_factor = _SireMM.CLJScaleFactor(
1294-
ff.electrostatic14_scale_factor(), ff.vdw14_scale_factor()
1295-
)
1296-
clj_nb_pairs0.set(idx_map, idy_map, clj_scale_factor)
1283+
# The atoms are bonded
1284+
else:
1285+
clj_scale_factor = _SireMM.CLJScaleFactor(0, 0)
1286+
clj_nb_pairs0.set(idx_map, idy_map, clj_scale_factor)
12971287

1298-
# The atoms are bonded
1299-
else:
1300-
clj_scale_factor = _SireMM.CLJScaleFactor(0, 0)
1301-
clj_nb_pairs0.set(idx_map, idy_map, clj_scale_factor)
1288+
# Now copy in all intrascale values from molecule0 into clj_nb_pairs0.
13021289

1303-
# Now copy in all intrascale values from molecule0 into both
1304-
# clj_nb_pairs matrices.
1290+
# Work out the iteration length and range.
13051291
if roi is None:
13061292
iterlen = molecule0.num_atoms()
13071293
iterrange = list(range(molecule0.num_atoms()))
1308-
# When region of interest is defined, perfrom loop from these indices
13091294
else:
13101295
for roi_res in roi:
1311-
# Get atom indices of ROI residue in molecule0
1296+
# Get atom indices of ROI residue in molecule0.
13121297
molecule0_roi = molecule0.residues()[roi_res]
13131298
molecule0_roi_idx = [a.index() for a in molecule0_roi]
13141299
iterlen = len(molecule0_roi_idx)
13151300
iterrange = molecule0_roi_idx
13161301

1317-
# Perform a triangular loop over atoms from molecule0.
1318-
for x in range(0, iterlen):
1319-
# Convert to an AtomIdx.
1320-
idx = iterrange[x]
1321-
idx = _SireMol.AtomIdx(idx)
1302+
# Perform a triangular loop over atoms from molecule0.
1303+
for x in range(0, iterlen):
1304+
# Convert to an AtomIdx.
1305+
idx = iterrange[x]
1306+
idx = _SireMol.AtomIdx(idx)
13221307

1323-
# Map the index to its position in the merged molecule.
1324-
idx_map = mol0_merged_mapping[idx]
1325-
1326-
for y in range(x + 1, iterlen):
1327-
idy = iterrange[y]
1328-
# Convert to an AtomIdx.
1329-
idy = _SireMol.AtomIdx(idy)
1330-
1331-
# Map the index to its position in the merged molecule.
1332-
idy_map = mol0_merged_mapping[idy]
1333-
1334-
conn_type = conn0.connection_type(idx_map, idy_map)
1335-
# The atoms aren't bonded.
1336-
if conn_type == 0:
1337-
clj_scale_factor = _SireMM.CLJScaleFactor(1, 1)
1338-
clj_nb_pairs0.set(idx_map, idy_map, clj_scale_factor)
1339-
1340-
# The atoms are part of a dihedral.
1341-
elif conn_type == 4:
1342-
clj_scale_factor = _SireMM.CLJScaleFactor(
1343-
ff.electrostatic14_scale_factor(), ff.vdw14_scale_factor()
1344-
)
1345-
clj_nb_pairs0.set(idx_map, idy_map, clj_scale_factor)
1308+
# Map the index to its position in the merged molecule.
1309+
idx_map = mol0_merged_mapping[idx]
13461310

1347-
# The atoms are bonded
1348-
else:
1349-
clj_scale_factor = _SireMM.CLJScaleFactor(0, 0)
1350-
clj_nb_pairs0.set(idx_map, idy_map, clj_scale_factor)
1311+
for y in range(x + 1, iterlen):
1312+
idy = iterrange[y]
1313+
# Convert to an AtomIdx.
1314+
idy = _SireMol.AtomIdx(idy)
1315+
1316+
# Map the index to its position in the merged molecule.
1317+
idy_map = mol0_merged_mapping[idy]
1318+
1319+
# Get the connection type between the atoms.
1320+
conn_type = conn0.connection_type(idx_map, idy_map)
1321+
1322+
# The atoms aren't bonded.
1323+
if conn_type == 0:
1324+
clj_scale_factor = _SireMM.CLJScaleFactor(1, 1)
1325+
clj_nb_pairs0.set(idx_map, idy_map, clj_scale_factor)
1326+
1327+
# The atoms are part of a dihedral.
1328+
elif conn_type == 4:
1329+
clj_scale_factor = _SireMM.CLJScaleFactor(
1330+
ff.electrostatic14_scale_factor(),
1331+
ff.vdw14_scale_factor(),
1332+
)
1333+
clj_nb_pairs0.set(idx_map, idy_map, clj_scale_factor)
1334+
1335+
# The atoms are bonded
1336+
else:
1337+
clj_scale_factor = _SireMM.CLJScaleFactor(0, 0)
1338+
clj_nb_pairs0.set(idx_map, idy_map, clj_scale_factor)
13511339

13521340
# Finally, copy the intrascale from molecule1 into clj_nb_pairs1.
1341+
1342+
# Work out the iteration length and range.
13531343
if roi is None:
13541344
iterlen = molecule1.num_atoms()
13551345
iterrange = list(range(molecule1.num_atoms()))
@@ -1361,40 +1351,42 @@ def merge(
13611351
iterlen = len(molecule1_roi_idx)
13621352
iterrange = molecule1_roi_idx
13631353

1364-
# Perform a triangular loop over atoms from molecule1.
1365-
for x in range(0, iterlen):
1366-
# Convert to an AtomIdx.
1367-
idx = iterrange[x]
1368-
idx = _SireMol.AtomIdx(idx)
1354+
# Perform a triangular loop over atoms from molecule1.
1355+
for x in range(0, iterlen):
1356+
# Convert to an AtomIdx.
1357+
idx = iterrange[x]
1358+
idx = _SireMol.AtomIdx(idx)
13691359

1370-
# Map the index to its position in the merged molecule.
1371-
idx = mol1_merged_mapping[idx]
1360+
# Map the index to its position in the merged molecule.
1361+
idx = mol1_merged_mapping[idx]
13721362

1373-
for y in range(x + 1, iterlen):
1374-
idy = iterrange[y]
1375-
# Convert to an AtomIdx.
1376-
idy = _SireMol.AtomIdx(idy)
1363+
for y in range(x + 1, iterlen):
1364+
idy = iterrange[y]
1365+
# Convert to an AtomIdx.
1366+
idy = _SireMol.AtomIdx(idy)
13771367

1378-
# Map the index to its position in the merged molecule.
1379-
idy = mol1_merged_mapping[idy]
1368+
# Map the index to its position in the merged molecule.
1369+
idy = mol1_merged_mapping[idy]
13801370

1381-
conn_type = conn1.connection_type(idx, idy)
1371+
# Get the connection type between the atoms.
1372+
conn_type = conn1.connection_type(idx, idy)
13821373

1383-
if conn_type == 0:
1384-
clj_scale_factor = _SireMM.CLJScaleFactor(1, 1)
1385-
clj_nb_pairs1.set(idx, idy, clj_scale_factor)
1374+
if conn_type == 0:
1375+
clj_scale_factor = _SireMM.CLJScaleFactor(1, 1)
1376+
clj_nb_pairs1.set(idx, idy, clj_scale_factor)
13861377

1387-
# The atoms are part of a dihedral.
1388-
elif conn_type == 4:
1389-
clj_scale_factor = _SireMM.CLJScaleFactor(
1390-
ff.electrostatic14_scale_factor(), ff.vdw14_scale_factor()
1391-
)
1392-
clj_nb_pairs1.set(idx, idy, clj_scale_factor)
1378+
# The atoms are part of a dihedral.
1379+
elif conn_type == 4:
1380+
clj_scale_factor = _SireMM.CLJScaleFactor(
1381+
ff.electrostatic14_scale_factor(),
1382+
ff.vdw14_scale_factor(),
1383+
)
1384+
clj_nb_pairs1.set(idx, idy, clj_scale_factor)
13931385

1394-
# The atoms are bonded
1395-
else:
1396-
clj_scale_factor = _SireMM.CLJScaleFactor(0, 0)
1397-
clj_nb_pairs1.set(idx, idy, clj_scale_factor)
1386+
# The atoms are bonded
1387+
else:
1388+
clj_scale_factor = _SireMM.CLJScaleFactor(0, 0)
1389+
clj_nb_pairs1.set(idx, idy, clj_scale_factor)
13981390

13991391
# Store the two molecular components.
14001392
edit_mol.set_property("molecule0", molecule0)

0 commit comments

Comments
 (0)