Skip to content

Commit af99a79

Browse files
committed
update unit tests + fix atom selection bug
1 parent ff71a8e commit af99a79

2 files changed

Lines changed: 68 additions & 120 deletions

File tree

‎CodeEntropy/levels/axes.py‎

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -156,21 +156,26 @@ def get_residue_axes(
156156

157157
if len(edge_atom_set) == 1:
158158
edge_atom = edge_atom_set[0]
159-
bonded_atoms = uas.select_atoms(f"bonded index {edge_atom.index}")
159+
bonded_atoms = residue.select_atoms(
160+
f"(mass 2 to 999) and bonded index {edge_atom.index}"
161+
)
160162
# find the average position of heavy atoms bonded to edge atom
161-
average_bonded_atom = np.zeros(3)
162-
for atom in bonded_atoms:
163-
average_bonded_atom += atom.position
164-
average_bonded_atom /= len(bonded_atoms)
163+
if len(bonded_atoms) > 0:
164+
average_bonded_atom = np.zeros(3)
165+
for bonded_atom in bonded_atoms:
166+
average_bonded_atom += bonded_atom.position
167+
average_bonded_atom /= len(bonded_atoms)
165168
# find the average position of all other heavy atoms in residue
166169
other_atoms = []
167170
for atom in uas:
168171
if atom != edge_atom and atom not in bonded_atoms:
169172
other_atoms.append(atom)
170-
average_other_atoms = np.zeros(3)
171-
for atom in other_atoms:
172-
average_other_atoms += atom.position
173-
average_other_atoms /= len(other_atoms)
173+
if len(other_atoms) > 0:
174+
average_other_atoms = np.zeros(3)
175+
for atom in other_atoms:
176+
average_other_atoms += atom.position
177+
average_other_atoms /= len(average_other_atoms)
178+
174179
rot_center, rot_axes = self.get_residue_custom_axes(
175180
[edge_atom.position, average_other_atoms], average_bonded_atom
176181
)
@@ -179,9 +184,10 @@ def get_residue_axes(
179184
edges = [edge_atom_set[0].position, edge_atom_set[1].position]
180185
backbone = self.get_chain(residue, edge_atom_set[0], edge_atom_set[1])
181186
backbone_center = np.zeros(3)
182-
for heavy_atom in backbone:
183-
backbone_center += heavy_atom.position
184-
backbone_center = backbone_center / len(backbone)
187+
if len(backbone) > 0:
188+
for heavy_atom in backbone:
189+
backbone_center += heavy_atom.position
190+
backbone_center /= len(backbone)
185191
rot_center, rot_axes = self.get_residue_custom_axes(
186192
edges, backbone_center
187193
)
@@ -323,37 +329,40 @@ def get_UA_axes(self, data_container, index: int, res_position):
323329
residue = data_container.residues[0]
324330
resindex = residue.resindex
325331
resindex_next = resindex + 1
326-
edge_atom = data_container.select_atoms(
332+
edge_atom_set = data_container.select_atoms(
327333
f"resindex {resindex} and bonded resindex {resindex_next}"
328334
)
329335
else:
330336
# last residue
331337
residue = data_container.residues[1]
332338
resindex = residue.resindex
333339
resindex_prev = resindex - 1
334-
edge_atom = data_container.select_atoms(
340+
edge_atom_set = data_container.select_atoms(
335341
f"resindex {resindex} and bonded resindex {resindex_prev}"
336342
)
343+
edge_atom = edge_atom_set[0]
337344
residue_heavy_atoms = residue.atoms.select_atoms("mass 2 to 999")
338-
bonded_atoms = residue_heavy_atoms.select_atoms(
339-
f"bonded index {edge_atom[0].index}"
345+
bonded_atoms = residue.atoms.select_atoms(
346+
f"(mass 2 to 999) and bonded index {edge_atom.index}"
340347
)
341348
# find the average position of heavy atoms bonded to edge atom
342-
average_bonded_atom = np.zeros(3)
343-
for atom in bonded_atoms:
344-
average_bonded_atom += atom.position
345-
average_bonded_atom /= len(bonded_atoms)
349+
if len(bonded_atoms) > 0:
350+
average_bonded_atom = np.zeros(3)
351+
for atom in bonded_atoms:
352+
average_bonded_atom += atom.position
353+
average_bonded_atom /= len(bonded_atoms)
346354
# find the average position of all other heavy atoms in residue
347355
other_atoms = []
348356
for atom in residue_heavy_atoms:
349357
if atom != edge_atom and atom not in bonded_atoms:
350358
other_atoms.append(atom)
351359
average_other_atoms = np.zeros(3)
352-
for atom in other_atoms:
353-
average_other_atoms += atom.position
354-
average_other_atoms /= len(other_atoms)
360+
if len(other_atoms) > 0:
361+
for atom in other_atoms:
362+
average_other_atoms += atom.position
363+
average_other_atoms /= len(other_atoms)
355364
trans_center, trans_axes = self.get_residue_custom_axes(
356-
[edge_atom.positions[0], average_other_atoms],
365+
[edge_atom.position, average_other_atoms],
357366
average_bonded_atom,
358367
)
359368
else:
@@ -371,10 +380,11 @@ def get_UA_axes(self, data_container, index: int, res_position):
371380

372381
edges = edge_set.positions
373382
backbone = self.get_chain(residue, edge_set[0], edge_set[1])
374-
backbone_center = np.zeros(3)
375-
for heavy_atom in backbone:
376-
backbone_center += heavy_atom.position
377-
backbone_center = backbone_center / len(backbone)
383+
if len(backbone) > 0:
384+
backbone_center = np.zeros(3)
385+
for heavy_atom in backbone:
386+
backbone_center += heavy_atom.position
387+
backbone_center /= len(backbone)
378388

379389
trans_center, trans_axes = self.get_residue_custom_axes(
380390
edges, backbone_center

‎tests/unit/CodeEntropy/levels/test_axes.py‎

Lines changed: 30 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,7 +1220,7 @@ def test_get_residue_axes_custom_path(monkeypatch):
12201220

12211221
backbone_center = np.array([0.0, 1.0, 0.0])
12221222
rot_center, rot_axes = ax.get_residue_custom_axes(
1223-
[edge_atoms[0], edge_atoms[1]], backbone_center
1223+
[edge_atoms[0].position, edge_atoms[1].position], backbone_center
12241224
)
12251225

12261226
assert rot_center.shape == (3,)
@@ -1337,90 +1337,33 @@ def _select_atoms(q):
13371337
assert np.allclose(moi, np.array([1, 1, 1]))
13381338

13391339

1340-
def test_get_residue_bonded_axes_first_resid(monkeypatch):
1340+
def test_get_residue_bonded_axes_terminal_resid(monkeypatch):
13411341
ax = AxesCalculator()
13421342
u = MagicMock()
13431343
u.dimensions = np.array([10.0, 10.0, 10.0, 90, 90, 90])
13441344
monkeypatch.setattr("CodeEntropy.levels.axes.make_whole", lambda _ag: None)
13451345
residue = u.select_atoms("resindex 0")
13461346
residue.__len__.return_value = 3
1347-
residue.atoms = _FakeAtomGroup(
1347+
uas = _FakeAtomGroup(
13481348
[
13491349
_atom(index=0, mass=12.0, pos=[1, 0, 0]),
13501350
_atom(index=1, mass=12.0, pos=[0, 1, 0]),
13511351
_atom(index=2, mass=12.0, pos=[0, 0, 0]),
13521352
]
13531353
)
1354-
edge_atom_set = _FakeAtomGroup(
1355-
[
1356-
_atom(index=2, mass=12.0, pos=[0, 0, 0]),
1357-
]
1358-
)
1359-
1360-
def _select_atoms(q):
1361-
if q.endswith("(bonded resindex -1 or resindex 1)"):
1362-
return edge_atom_set
1363-
1364-
backbone_atom = residue.atoms[1]
1365-
u.atoms.principal_axes.return_value = np.eye(3)
1366-
u.atoms.select_atoms.side_effect = _select_atoms
1367-
monkeypatch.setattr(ax, "get_chain", backbone_atom)
1368-
monkeypatch.setattr(
1369-
ax,
1370-
"get_custom_residue_moment_of_inertia",
1371-
lambda center_of_mass, positions, masses, custom_rot_axes, dimensions: np.array(
1372-
[1, 1, 1]
1373-
),
1374-
)
1375-
1376-
trans_axes, rot_axes, rot_center, moi = ax.get_residue_axes(
1377-
u, index=0, relative_index=0
1378-
)
1379-
1380-
assert len(edge_atom_set) == 1
1381-
assert np.allclose(trans_axes, np.eye(3))
1382-
assert rot_axes.shape == (3, 3)
1383-
assert rot_center.shape == (3,)
1384-
assert np.allclose(moi, np.array([1, 1, 1]))
1385-
1386-
1387-
def test_get_residue_bonded_axes_last_resid(monkeypatch):
1388-
ax = AxesCalculator()
1389-
u = MagicMock()
1390-
u.dimensions = np.array([10.0, 10.0, 10.0, 90, 90, 90])
1391-
monkeypatch.setattr("CodeEntropy.levels.axes.make_whole", lambda _ag: None)
1392-
residue = u.select_atoms("resindex 2")
1393-
residue.__len__.return_value = 3
1394-
heavy_atoms = _FakeAtomGroup(
1395-
[
1396-
_atom(index=4, mass=12.0, pos=[1, 0, 0]),
1397-
_atom(index=5, mass=12.0, pos=[0, 1, 0]),
1398-
_atom(index=6, mass=12.0, pos=[0, 0, 0]),
1399-
]
1400-
)
1401-
edge_atom_set = _FakeAtomGroup(
1402-
[
1403-
_atom(index=4, mass=12.0, pos=[0, 0, 0]),
1404-
]
1405-
)
14061354

14071355
def _select_atoms(q):
14081356
if q == "mass 2 to 999":
1409-
# return heavy atoms group
1410-
return heavy_atoms
1411-
if q.endswith("(bonded resindex 1 or resindex 3)"):
1412-
return edge_atom_set
1413-
if q == ("(mass 2 to 999) and bonded index 6"):
1414-
return [heavy_atoms[1]]
1415-
if q == ("(mass 2 to 999) and bonded index 5"):
1416-
return [heavy_atoms[0], heavy_atoms[2]]
1357+
return uas
1358+
if q.startswith("(mass 2 to 999) and bonded"):
1359+
return [uas[1]]
1360+
if q.startswith("resindex 0 and (bonded resindex"):
1361+
return [uas[2]]
14171362

1418-
backbone_atom = heavy_atoms[1]
14191363
u.atoms.principal_axes.return_value = np.eye(3)
14201364
u.atoms.select_atoms.side_effect = _select_atoms
14211365
residue.select_atoms.side_effect = _select_atoms
1422-
residue.atoms.select_atoms.side_effect = _select_atoms
1423-
monkeypatch.setattr(ax, "get_chain", backbone_atom)
1366+
14241367
monkeypatch.setattr(
14251368
ax,
14261369
"get_custom_residue_moment_of_inertia",
@@ -1430,10 +1373,9 @@ def _select_atoms(q):
14301373
)
14311374

14321375
trans_axes, rot_axes, rot_center, moi = ax.get_residue_axes(
1433-
u, index=2, relative_index=0
1376+
u, index=0, relative_index=0
14341377
)
14351378

1436-
assert len(edge_atom_set) == 1
14371379
assert np.allclose(trans_axes, np.eye(3))
14381380
assert rot_axes.shape == (3, 3)
14391381
assert rot_center.shape == (3,)
@@ -1473,8 +1415,10 @@ def _select_atoms(q):
14731415
return [heavy_atoms[1]]
14741416

14751417
residue_group.select_atoms.side_effect = _select_atoms
1418+
residue.select_atoms.side_effect = _select_atoms
14761419
residue.atoms.select_atoms.side_effect = _select_atoms
1477-
monkeypatch.setattr(ax, "get_chain", lambda residue, first, last: heavy_atoms[1])
1420+
1421+
monkeypatch.setattr(ax, "get_chain", lambda residue, first, last: [heavy_atoms[1]])
14781422
monkeypatch.setattr(
14791423
ax,
14801424
"get_bonded_axes",
@@ -1560,25 +1504,23 @@ def test_get_ua_axes_bonded_axes_first_resid(monkeypatch):
15601504

15611505
residue.atoms[0] = heavy_atoms[0]
15621506
residue.atoms[0].position = heavy_atoms[0].position
1563-
edge_atom_set = _FakeAtomGroup(
1564-
[
1565-
_atom(index=2, mass=12.0, pos=(0, 0, 1)),
1566-
],
1567-
)
1507+
edge_atom_set = [heavy_atoms[2]]
1508+
bonded_atoms = [heavy_atoms[1]]
15681509

15691510
def _select_atoms(q):
15701511
if q == "mass 2 to 999":
15711512
# return heavy atoms group
15721513
return heavy_atoms
1514+
if q.startswith("index"):
1515+
return [heavy_atoms[0]]
15731516
if q.startswith("resindex "):
15741517
return edge_atom_set
1575-
if q.startswith("index "):
1576-
return [heavy_atoms[0]]
1518+
if q.startswith("(mass 2 to 999) and bonded index "):
1519+
return bonded_atoms
15771520

15781521
residue_group.select_atoms.side_effect = _select_atoms
15791522
residue.atoms.select_atoms.side_effect = _select_atoms
1580-
edge_atom_set.atoms = [edge_atom_set[0]]
1581-
monkeypatch.setattr(ax, "get_chain", lambda residue, first, last: heavy_atoms[1])
1523+
15821524
monkeypatch.setattr(
15831525
ax,
15841526
"get_bonded_axes",
@@ -1598,7 +1540,7 @@ def test_get_ua_axes_bonded_axes_last_resid(monkeypatch):
15981540
ax = AxesCalculator()
15991541
residue_group = MagicMock()
16001542
residue_group.__len__ = 2
1601-
residue = residue_group.residues[1]
1543+
residue = residue_group.residues[0]
16021544
heavy_atoms = _FakeAtomGroup(
16031545
[
16041546
_atom(index=0, mass=12.0, pos=(1, 0, 0)),
@@ -1607,29 +1549,25 @@ def test_get_ua_axes_bonded_axes_last_resid(monkeypatch):
16071549
],
16081550
)
16091551

1610-
edge_atom_set = _FakeAtomGroup(
1611-
[
1612-
_atom(index=0, mass=12.0, pos=(1, 0, 0)),
1613-
],
1614-
)
1552+
residue.atoms[0] = heavy_atoms[0]
1553+
residue.atoms[0].position = heavy_atoms[0].position
1554+
edge_atom_set = [heavy_atoms[0]]
1555+
bonded_atoms = [heavy_atoms[1]]
16151556

16161557
def _select_atoms(q):
16171558
if q == "mass 2 to 999":
16181559
# return heavy atoms group
16191560
return heavy_atoms
1561+
if q.startswith("index"):
1562+
return [heavy_atoms[0]]
16201563
if q.startswith("resindex "):
16211564
return edge_atom_set
1622-
if q.startswith("index "):
1623-
return [heavy_atoms[0]]
1624-
if q == ("(mass 2 to 999) and bonded index 2"):
1625-
return [heavy_atoms[1]]
1626-
if q == ("(mass 2 to 999) and bonded index 1"):
1627-
return [heavy_atoms[0], heavy_atoms[2]]
1565+
if q.startswith("(mass 2 to 999) and bonded index "):
1566+
return bonded_atoms
16281567

16291568
residue_group.select_atoms.side_effect = _select_atoms
16301569
residue.atoms.select_atoms.side_effect = _select_atoms
1631-
edge_atom_set.atoms = [edge_atom_set[0]]
1632-
monkeypatch.setattr(ax, "get_chain", lambda residue, first, last: heavy_atoms[1])
1570+
16331571
monkeypatch.setattr(
16341572
ax,
16351573
"get_bonded_axes",

0 commit comments

Comments
 (0)