Skip to content

Commit 12880e8

Browse files
authored
Merge pull request #274 from CCPBioSim/273-bug-complex-number-forces-produced
Use MDAnalysis `principal_axes()` for single-UA molecules to prevent complex axes
2 parents 0e01cdf + 513664f commit 12880e8

File tree

2 files changed

+25
-24
lines changed

2 files changed

+25
-24
lines changed

CodeEntropy/axes.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -92,21 +92,25 @@ def get_UA_axes(self, data_container, index):
9292
moment_of_inertia: moment of inertia (3,)
9393
"""
9494

95-
index = int(index)
95+
index = int(index) # bead index
9696

9797
# use the same customPI trans axes as the residue level
98-
UAs = data_container.select_atoms("mass 2 to 999")
99-
UA_masses = self.get_UA_masses(data_container.atoms)
100-
center = data_container.atoms.center_of_mass(unwrap=True)
101-
moment_of_inertia_tensor = self.get_moment_of_inertia_tensor(
102-
center, UAs.positions, UA_masses, data_container.dimensions[:3]
103-
)
104-
trans_axes, _moment_of_inertia = self.get_custom_principal_axes(
105-
moment_of_inertia_tensor
106-
)
98+
heavy_atoms = data_container.select_atoms("prop mass > 1.1")
99+
if len(heavy_atoms) > 1:
100+
UA_masses = self.get_UA_masses(data_container.atoms)
101+
center = data_container.atoms.center_of_mass(unwrap=True)
102+
moment_of_inertia_tensor = self.get_moment_of_inertia_tensor(
103+
center, heavy_atoms.positions, UA_masses, data_container.dimensions[:3]
104+
)
105+
trans_axes, _moment_of_inertia = self.get_custom_principal_axes(
106+
moment_of_inertia_tensor
107+
)
108+
else:
109+
# use standard PA for UA not bonded to anything else
110+
make_whole(data_container.atoms)
111+
trans_axes = data_container.atoms.principal_axes()
107112

108113
# look for heavy atoms in residue of interest
109-
heavy_atoms = data_container.select_atoms("prop mass > 1.1")
110114
heavy_atom_indices = []
111115
for atom in heavy_atoms:
112116
heavy_atom_indices.append(atom.index)

tests/test_CodeEntropy/test_axes.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ def test_get_residue_axes_bonded_default_axes_branch(self):
118118
np.testing.assert_allclose(center_out, center_expected)
119119
np.testing.assert_allclose(moi_out, np.array([3.0, 2.0, 1.0]))
120120

121-
def test_get_UA_axes_returns_expected_outputs(self):
121+
@patch("CodeEntropy.axes.make_whole", autospec=True)
122+
def test_get_UA_axes_returns_expected_outputs(self, mock_make_whole):
122123
"""
123124
Tests that: `get_UA_axes` returns expected UA axes.
124125
"""
@@ -129,20 +130,17 @@ def test_get_UA_axes_returns_expected_outputs(self):
129130
dc.dimensions = np.array([1.0, 2.0, 3.0, 90.0, 90.0, 90.0])
130131
dc.atoms.center_of_mass.return_value = np.array([0.0, 0.0, 0.0])
131132

132-
uas = MagicMock()
133-
uas.positions = np.zeros((2, 3))
134-
135133
a0 = MagicMock()
136134
a0.index = 7
137135
a1 = MagicMock()
138136
a1.index = 9
139-
heavy_atoms = [a0, a1]
140137

141-
heavy_ag = MagicMock()
142-
heavy_ag.positions = np.array([[9.9, 8.8, 7.7]])
143-
heavy_ag.__getitem__.return_value = MagicMock()
138+
heavy_atoms = MagicMock()
139+
heavy_atoms.__len__.return_value = 2
140+
heavy_atoms.__iter__.return_value = iter([a0, a1])
141+
heavy_atoms.positions = np.array([[9.9, 8.8, 7.7], [1.1, 2.2, 3.3]])
144142

145-
dc.select_atoms.side_effect = [uas, heavy_atoms, heavy_ag]
143+
dc.select_atoms.side_effect = [heavy_atoms, heavy_atoms]
146144

147145
axes.get_UA_masses = MagicMock(return_value=[1.0, 1.0])
148146
axes.get_moment_of_inertia_tensor = MagicMock(return_value=np.eye(3))
@@ -160,13 +158,12 @@ def test_get_UA_axes_returns_expected_outputs(self):
160158

161159
np.testing.assert_array_equal(trans_axes, trans_axes_expected)
162160
np.testing.assert_array_equal(rot_axes, rot_axes_expected)
163-
np.testing.assert_array_equal(center, heavy_ag.positions[0])
161+
np.testing.assert_array_equal(center, heavy_atoms.positions[0])
164162
np.testing.assert_array_equal(moi, moi_expected)
165163

166164
calls = [c.args[0] for c in dc.select_atoms.call_args_list]
167-
assert calls[0] == "mass 2 to 999"
168-
assert calls[1] == "prop mass > 1.1"
169-
assert calls[2] == "index 9"
165+
assert calls[0] == "prop mass > 1.1"
166+
assert calls[1] == "index 9"
170167

171168
def test_get_bonded_axes_returns_none_for_light_atom(self):
172169
"""

0 commit comments

Comments
 (0)