Skip to content

Commit 6be94e6

Browse files
committed
changed residue axes to match NCC for proteins
1 parent 246c72b commit 6be94e6

1 file changed

Lines changed: 40 additions & 34 deletions

File tree

‎CodeEntropy/levels/axes.py‎

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ def get_residue_axes(self, data_container, index: int, residue=None):
118118

119119
uas = residue.select_atoms("mass 2 to 999")
120120
ua_masses = self.get_UA_masses(residue)
121-
121+
print(f"The edge atoms: {edge_atom_set}")
122122
if len(edge_atom_set) == 0:
123123
# No UAS are bonded to other residues
124124
# Use a custom principal axes, from a MOI tensor that uses positions of
@@ -132,7 +132,7 @@ def get_residue_axes(self, data_container, index: int, residue=None):
132132
)
133133
rot_axes, moment_of_inertia = self.get_custom_principal_axes(moi_tensor)
134134
trans_axes = rot_axes # per original convention
135-
center = np.array(residue.center_of_mass())
135+
rot_center = np.array(residue.center_of_mass())
136136
else:
137137
# If bonded to other residues, use local axes.
138138
make_whole(data_container.atoms)
@@ -169,17 +169,20 @@ def get_residue_axes(self, data_container, index: int, residue=None):
169169
backbone = self.get_chain(residue, edge_atom_set[0], edge_atom_set[1])
170170
# get edge atoms of the residue
171171
# for terminal residues, this will include the C/N terminus
172-
center = np.array(backbone.center_of_mass())
173-
rot_axes = self.get_residue_custom_axes(edges, center)
172+
backbone_center = np.zeros(3)
173+
for heavy_atom in backbone:
174+
backbone_center += heavy_atom.position
175+
backbone_center = backbone_center / len(backbone)
176+
rot_center, rot_axes = self.get_residue_custom_axes(edges, backbone_center)
174177

175178
moment_of_inertia = self.get_custom_residue_moment_of_inertia(
176-
center_of_mass=center,
179+
center_of_mass=rot_center,
177180
positions=uas.positions,
178181
masses=ua_masses,
179182
custom_rot_axes=rot_axes,
180183
dimensions=data_container.dimensions[:3],
181184
)
182-
return trans_axes, rot_axes, center, moment_of_inertia
185+
return trans_axes, rot_axes, rot_center, moment_of_inertia
183186

184187
def get_UA_axes(self, data_container, index: int, res_position):
185188
"""Compute united-atom-level translational and rotational axes.
@@ -287,8 +290,13 @@ def get_UA_axes(self, data_container, index: int, res_position):
287290
edges = [first_edge.atoms[0], last]
288291
backbone = self.get_chain(residue, first_edge.atoms[0], last)
289292

290-
trans_center = np.array(backbone.center_of_mass())
291-
trans_axes = self.get_residue_custom_axes(edges, trans_center)
293+
backbone_center = np.zeros(3)
294+
for heavy_atom in backbone:
295+
backbone_center += heavy_atom.position
296+
backbone_center = backbone_center / len(backbone)
297+
trans_center, trans_axes = self.get_residue_custom_axes(
298+
edges, backbone_center
299+
)
292300

293301
residue_heavy_atoms = residue.atoms.select_atoms("mass 2 to 999")
294302
# look for heavy atoms in residue of interest
@@ -338,49 +346,45 @@ def get_residue_custom_axes(self, edges, center):
338346
"""
339347
Compute rotation axes at the residue level, given
340348
two edge atoms of the residue (E1+E2),
341-
and the rotation centre (O).
349+
and the centre of geometry of backbone atoms
350+
that are not edges (C).
342351
- x axis is O-E1
343-
- y axis is O-Q (perpendicular to O-E1 in the
352+
- y axis is O-C (perpendicular to O-E1 in the
344353
same plane as E2)
345354
- z axis is perpendicular to the two other axes
346355
347-
Q --- E2
348-
| |
349-
| |
350-
E1 ---- O --- P
356+
C
357+
|
358+
|
359+
E1 ---- O --- E2
351360
Args:
352361
edges: (2,3) positions of two edge atoms
353-
center: (3,) coordinates of the rotation centre
362+
center: (3,) coordinates of the inner backbone
363+
centre of geometry
354364
Returns:
365+
rot_center: (3,) rotation centre --
366+
it lies on the E1-E2 vector
355367
rot_axes: (3,3) rotation axes of residue
356368
"""
357369
# x axis is O-E1
358-
E1O_vector = center - edges[0].position
359-
x_axis = -E1O_vector
360-
# y axis is perpendicular to x
361-
# in the same plane as E2
362-
# look for projection of E1-E2 on E1-O (E1-P)
370+
E1C_vector = center - edges[0].position
371+
# look for projection of E1-O onto E1-E2 (E1-C)
363372
E1E2_vector = edges[1].position - edges[0].position
364-
projection = (
365-
np.dot(E1O_vector, E1E2_vector) / (np.linalg.norm(E1O_vector) ** 2)
366-
) * E1O_vector
367-
# get the perpendicular onto E1-O (P-E2)
368-
# P-E2 = P-E1 + E1-E2
369-
perpendicular = E1E2_vector - projection
370-
# get the perpendicular through O (Q-O)
371-
# first get P-Q diagonal through paralellogram rule
372-
# P- Q = P-E2 + P-O
373-
diagonal = -(projection - E1O_vector) + perpendicular
374-
# get the parallel of P-E2 through O
375-
# OQ = OP + PQ
376-
y_axis = (projection - E1O_vector) + diagonal
373+
E1O_vector = (
374+
np.dot(E1E2_vector, E1C_vector) / (np.linalg.norm(E1E2_vector) ** 2)
375+
) * E1E2_vector
376+
x_axis = -E1O_vector
377+
# O-C = O-E1 + E1-C
378+
OC_vector = -E1O_vector + E1C_vector
379+
y_axis = OC_vector
377380
z_axis = np.cross(x_axis, y_axis)
378381
x_axis /= np.linalg.norm(x_axis)
379382
y_axis /= np.linalg.norm(y_axis)
380383
z_axis /= np.linalg.norm(z_axis)
381384
rot_axes = np.array([x_axis, y_axis, z_axis])
385+
rot_center = E1O_vector - edges[0].position
382386

383-
return rot_axes
387+
return rot_center, rot_axes
384388

385389
def get_bonded_axes(self, system, atom, dimensions: np.ndarray):
386390
"""Compute UA rotational axes from bonded topology around a heavy atom.
@@ -906,6 +910,8 @@ def get_chain(self, residue, first, last):
906910
chain.append(current)
907911
chain_indices.append(current.index - residue.atoms.indices[0])
908912
chain_indices = np.flip(chain_indices)
913+
# only get in between residues
914+
chain_indices = chain_indices[1:-1]
909915
# accout for in-residue index
910916
chain_AtomGroup = residue.atoms[chain_indices]
911917
chain = chain_AtomGroup.atoms.select_atoms("all")

0 commit comments

Comments
 (0)