def rotation_angle(helix_vector, axis_vector, rotation_vector): reference_vector = np.cross(np.cross(helix_vector, axis_vector), helix_vector) second_reference_vector = np.cross(axis_vector, helix_vector) screw_angle = mdamath.angle(reference_vector, rotation_vector) alt_screw_angle = mdamath.angle(second_reference_vector, rotation_vector) updown = np.cross(reference_vector, rotation_vector) if not (np.pi < screw_angle < 3 * np.pi / 4): if screw_angle < np.pi / 4 and alt_screw_angle < np.pi / 2: screw_angle = np.pi / 2 - alt_screw_angle elif screw_angle < np.pi / 4 and alt_screw_angle > np.pi / 2: screw_angle = alt_screw_angle - np.pi / 2 elif screw_angle > 3 * np.pi / 4 and alt_screw_angle < np.pi / 2: screw_angle = np.pi / 2 + alt_screw_angle elif screw_angle > 3 * np.pi / 4 and alt_screw_angle > np.pi / 2: screw_angle = 3 * np.pi / 2 - alt_screw_angle else: logger.debug("Big Screw Up: screw_angle=%g degrees", np.rad2deg(screw_angle)) if mdamath.norm(updown) == 0: logger.warn("PROBLEM (vector is at 0 or 180)") helix_dot_rehelix = mdamath.angle(updown, helix_vector) #if ( helix_dot_rehelix < np.pi/2 and helix_dot_rehelix >= 0 )or helix_dot_rehelix <-np.pi/2: if (-np.pi / 2 < helix_dot_rehelix < np.pi / 2) or (helix_dot_rehelix > 3 * np.pi / 2): screw_angle = -screw_angle return screw_angle
def wc_pair(universe, i, bp, seg1="SYSTEM", seg2="SYSTEM"): """Watson-Crick basepair distance for residue *i* with residue *bp*. The distance of the nitrogen atoms in a Watson-Crick hydrogen bond is computed. :Arguments: *universe* :class:`~MDAnalysis.core.AtomGroup.Universe` containing the trajectory *seg1* segment id for first base *i* resid of the first base *seg2* segment id for second base *bp* resid of the second base .. NOTE:: If failure occurs be sure to check the segment identification. .. versionadded:: 0.7.6 """ if universe.select_atoms(" resid %s " % (i, )).resnames[0] in [ "DC", "DT", "U", "C", "T", "CYT", "THY", "URA" ]: a1, a2 = "N3", "N1" if universe.select_atoms(" resid %s " % (i, )).resnames[0] in [ "DG", "DA", "A", "G", "ADE", "GUA" ]: a1, a2 = "N1", "N3" wc_dist = universe.select_atoms( " (segid %s and resid %s and name %s) or (segid %s and resid %s and name %s) " % (seg1, i, a1, seg2, bp, a2)) wc = mdamath.norm(wc_dist[0].pos - wc_dist[1].pos) return wc
def test_numpy_compliance(self): # Checks that the cython functions give identical results to the numpy versions bonds = MDAnalysis.lib.distances.calc_bonds(self.a, self.b, backend=self.backend) angles = MDAnalysis.lib.distances.calc_angles(self.a, self.b, self.c, backend=self.backend) dihedrals = MDAnalysis.lib.distances.calc_dihedrals(self.a, self.b, self.c, self.d, backend=self.backend) bonds_numpy = np.array([mdamath.norm(y - x) for x, y in zip(self.a, self.b)]) vec1 = self.a - self.b vec2 = self.c - self.b angles_numpy = np.array([mdamath.angle(x, y) for x, y in zip(vec1, vec2)]) ab = self.b - self.a bc = self.c - self.b cd = self.d - self.c dihedrals_numpy = np.array([mdamath.dihedral(x, y, z) for x, y, z in zip(ab, bc, cd)]) assert_almost_equal(bonds, bonds_numpy, self.prec, err_msg="Cython bonds didn't match numpy calculations") # numpy 0 angle returns NaN rather than 0 assert_almost_equal(angles[1:], angles_numpy[1:], self.prec, err_msg="Cython angles didn't match numpy calcuations") # same issue with first two dihedrals assert_almost_equal(dihedrals[2:], dihedrals_numpy[2:], self.prec, err_msg="Cython dihedrals didn't match numpy calculations")
def minor_pair(universe, i, bp, seg1="SYSTEM", seg2="SYSTEM"): """Minor-Groove basepair distance for residue *i* with residue *bp*. The distance of the nitrogen and oxygen atoms in a Minor-groove hydrogen bond is computed. :Arguments: *universe* :class:`~MDAnalysis.core.AtomGroup.Universe` containing the trajectory *seg1* segment id for first base *i* resid of the first base *seg2* segment id for second base *bp* resid of the second base .. NOTE:: If failure occurs be sure to check the segment identification. .. versionadded:: 0.7.6 """ if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in ["DC", "DT", "U", "C", "T", "CYT", "THY", "URA"]: a1, a2 = "O2", "C2" if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in ["DG", "DA", "A", "G", "ADE", "GUA"]: a1, a2 = "C2", "O2" c2o2_dist = universe.select_atoms( " (segid {0!s} and resid {1!s} and name {2!s}) or (segid {3!s} and resid {4!s} and name {5!s}) ".format(seg1, i, a1, seg2, bp, a2)) c2o2 = mdamath.norm(c2o2_dist[0].pos - c2o2_dist[1].pos) return c2o2
def minor_pair(universe, i, bp, seg1="SYSTEM", seg2="SYSTEM"): """Minor-Groove basepair distance for residue *i* with residue *bp*. The distance of the nitrogen and oxygen atoms in a Minor-groove hydrogen bond is computed. :Arguments: *universe* :class:`~MDAnalysis.core.AtomGroup.Universe` containing the trajectory *seg1* segment id for first base *i* resid of the first base *seg2* segment id for second base *bp* resid of the second base .. NOTE:: If failure occurs be sure to check the segment identification. .. versionadded:: 0.7.6 """ if universe.select_atoms(" resid %s " % (i,)).resnames[0] in ["DC", "DT", "U", "C", "T", "CYT", "THY", "URA"]: a1, a2 = "O2", "C2" if universe.select_atoms(" resid %s " % (i,)).resnames[0] in ["DG", "DA", "A", "G", "ADE", "GUA"]: a1, a2 = "C2", "O2" c2o2_dist = universe.select_atoms( " (segid %s and resid %s and name %s) or (segid %s and resid %s and name %s) " % (seg1, i, a1, seg2, bp, a2) ) c2o2 = mdamath.norm(c2o2_dist[0].pos - c2o2_dist[1].pos) return c2o2
def wc_pair(universe, i, bp, seg1="SYSTEM", seg2="SYSTEM"): """Watson-Crick basepair distance for residue *i* with residue *bp*. The distance of the nitrogen atoms in a Watson-Crick hydrogen bond is computed. :Arguments: *universe* :class:`~MDAnalysis.core.AtomGroup.Universe` containing the trajectory *seg1* segment id for first base *i* resid of the first base *seg2* segment id for second base *bp* resid of the second base .. NOTE:: If failure occurs be sure to check the segment identification. .. versionadded:: 0.7.6 """ if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in ["DC", "DT", "U", "C", "T", "CYT", "THY", "URA"]: a1, a2 = "N3", "N1" if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in ["DG", "DA", "A", "G", "ADE", "GUA"]: a1, a2 = "N1", "N3" wc_dist = universe.select_atoms("(segid {0!s} and resid {1!s} and name {2!s}) " "or (segid {3!s} and resid {4!s} and name {5!s}) " .format(seg1, i, a1, seg2, bp, a2)) wc = mdamath.norm(wc_dist[0].position - wc_dist[1].position) return wc
def rotation_angle(helix_vector, axis_vector, rotation_vector): reference_vector = np.cross(np.cross(helix_vector, axis_vector), helix_vector) second_reference_vector = np.cross(axis_vector, helix_vector) screw_angle = mdamath.angle(reference_vector, rotation_vector) alt_screw_angle = mdamath.angle(second_reference_vector, rotation_vector) updown = np.cross(reference_vector, rotation_vector) if not (np.pi < screw_angle < 3 * np.pi / 4): if screw_angle < np.pi / 4 and alt_screw_angle < np.pi / 2: screw_angle = np.pi / 2 - alt_screw_angle elif screw_angle < np.pi / 4 and alt_screw_angle > np.pi / 2: screw_angle = alt_screw_angle - np.pi / 2 elif screw_angle > 3 * np.pi / 4 and alt_screw_angle < np.pi / 2: screw_angle = np.pi / 2 + alt_screw_angle elif screw_angle > 3 * np.pi / 4 and alt_screw_angle > np.pi / 2: screw_angle = 3 * np.pi / 2 - alt_screw_angle else: logger.debug("Big Screw Up: screw_angle=%g degrees", np.rad2deg(screw_angle)) if mdamath.norm(updown) == 0: logger.warning("PROBLEM (vector is at 0 or 180)") helix_dot_rehelix = mdamath.angle(updown, helix_vector) #if ( helix_dot_rehelix < np.pi/2 and helix_dot_rehelix >= 0 )or helix_dot_rehelix <-np.pi/2: if (-np.pi / 2 < helix_dot_rehelix < np.pi / 2) or (helix_dot_rehelix > 3 * np.pi / 2): screw_angle = -screw_angle return screw_angle
def _angle(x, y): """ Calculate angle between two vectors return value in the range [-pi:pi] """ d = np.dot(x,y) n = mdamath.norm(np.cross(x,y)) return math.atan2(n,d)
def major_pair(universe, i, bp, seg1="SYSTEM", seg2="SYSTEM"): """Major-Groove basepair distance for residue `i` with residue `bp`. The distance of the nitrogen and oxygen atoms in a Major-groove hydrogen bond is computed. Parameters ---------- universe : Universe :class:`~MDAnalysis.core.universe.Universe` containing the trajectory i : int resid of the first base bp : int resid of the second base seg1 : str (optional) segment id for first base ["SYSTEM"] seg2 : str (optional) segment id for second base ["SYSTEM"] Returns ------- float Major groove base pair distance Notes ----- If failure occurs be sure to check the segment identification. .. versionadded:: 0.7.6 """ if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in [ "DC", "DG", "C", "G", "CYT", "GUA" ]: if universe.select_atoms( " resid {0!s} ".format(i)).resnames[0] in ["DC", "C", "CYT"]: a1, a2 = "N4", "O6" else: a1, a2 = "O6", "N4" if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in [ "DT", "DA", "A", "T", "U", "ADE", "THY", "URA" ]: if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in [ "DT", "T", "THY", "U", "URA" ]: a1, a2 = "O4", "N6" else: a1, a2 = "N6", "O4" no_dist = universe.select_atoms( "(segid {0!s} and resid {1!s} and name {2!s}) " "or (segid {3!s} and resid {4!s} and name {5!s}) ".format( seg1, i, a1, seg2, bp, a2)) major = mdamath.norm(no_dist[0].position - no_dist[1].position) return major
def major_pair(universe, i, bp, seg1="SYSTEM", seg2="SYSTEM"): """Major-Groove basepair distance for residue `i` with residue `bp`. The distance of the nitrogen and oxygen atoms in a Major-groove hydrogen bond is computed. Parameters ---------- universe : Universe :class:`~MDAnalysis.core.universe.Universe` containing the trajectory i : int resid of the first base bp : int resid of the second base seg1 : str (optional) segment id for first base ["SYSTEM"] seg2 : str (optional) segment id for second base ["SYSTEM"] Returns ------- float Major groove base pair distance Notes ----- If failure occurs be sure to check the segment identification. .. versionadded:: 0.7.6 """ if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in ["DC", "DG", "C", "G", "CYT", "GUA"]: if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in ["DC", "C", "CYT"]: a1, a2 = "N4", "O6" else: a1, a2 = "O6", "N4" if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in ["DT", "DA", "A", "T", "U", "ADE", "THY", "URA"]: if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in ["DT", "T", "THY", "U", "URA"]: a1, a2 = "O4", "N6" else: a1, a2 = "N6", "O4" no_dist = universe.select_atoms("(segid {0!s} and resid {1!s} and name {2!s}) " "or (segid {3!s} and resid {4!s} and name {5!s}) " .format(seg1, i, a1, seg2, bp, a2)) major = mdamath.norm(no_dist[0].position - no_dist[1].position) return major
def initialize_bm(self, box): """ Store box information and define direct and reciprocal box matrices. Rows of the direct matrix are the components of the central cell vectors. Rows of the reciprocal matrix are the components of the normalized reciprocal lattice vectors. Each row of the reciprocal matrix represents the vector normal to the unit cell face associated to each axis. For instance, in an orthorhombic cell the YZ-plane is associated to the X-axis and its normal vector is (1, 0, 0). In a triclinic cell, the plane associated to vector ``\vec{a}`` is perpendicular to the normalized cross product of ``\vec{b}`` and ``\vec{c}``. Parameters ---------- box : array-like or ``None``, optional, default ``None`` Simulation cell dimensions in the form of :attr:`MDAnalysis.trajectory.base.Timestep.dimensions` when periodic boundary conditions should be taken into account for the calculation of contacts. """ box_type = _box_check(box) if box_type == 'ortho': a, b, c = box[:3] dm = np.array([[a, 0, 0], [0, b, 0], [0, 0, c]], dtype=np.float32) rm = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]], dtype=np.float32) elif box_type in 'tri_box tri_vecs tri_vecs_bad': if box_type == 'tri_box': dm = triclinic_vectors(box) elif box_type == 'tri_vecs': dm = box.copy('C') else: # case 'tri_vecs_bad' dm = triclinic_vectors(triclinic_box(box[0], box[1], box[2])) rm = np.zeros(9, dtype=np.float32).reshape(3, 3) rm[0] = np.cross(dm[1], dm[2]) rm[1] = np.cross(dm[2], dm[0]) rm[2] = np.cross(dm[0], dm[1]) for i in range(self.dim): rm[i] /= norm(rm[i]) # normalize else: raise ValueError('Failed to initialize direct/reciprocal matrices') self.box = box self._dm = dm self._rm = rm
def major_pair(universe, i, bp, seg1="SYSTEM", seg2="SYSTEM"): """Major-Groove basepair distance for residue *i* with residue *bp*. The distance of the nitrogen and oxygen atoms in a Major-groove hydrogen bond is computed. :Arguments: *universe* :class:`~MDAnalysis.core.AtomGroup.Universe` containing the trajectory *i* *seg1* segment id for first base *i* resid of the first base *seg2* segment id for second base *bp* resid of the second base .. NOTE:: If failure occurs be sure to check the segment identification .. versionadded:: 0.7.6 """ if universe.select_atoms(" resid %s " % (i, )).resnames[0] in [ "DC", "DG", "C", "G", "CYT", "GUA" ]: if universe.select_atoms(" resid %s " % (i, )).resnames[0] in ["DC", "C", "CYT"]: a1, a2 = "N4", "O6" else: a1, a2 = "O6", "N4" if universe.select_atoms(" resid %s " % (i, )).resnames[0] in [ "DT", "DA", "A", "T", "U", "ADE", "THY", "URA" ]: if universe.select_atoms(" resid %s " % (i, )).resnames[0] in [ "DT", "T", "THY", "U", "URA" ]: a1, a2 = "O4", "N6" else: a1, a2 = "N6", "O4" no_dist = universe.select_atoms( " (segid %s and resid %s and name %s) or (segid %s and resid %s and name %s) " % (seg1, i, a1, seg2, bp, a2)) major = mdamath.norm(no_dist[0].pos - no_dist[1].pos) return major
def major_pair(universe, i, bp, seg1="SYSTEM", seg2="SYSTEM"): """Major-Groove basepair distance for residue *i* with residue *bp*. The distance of the nitrogen and oxygen atoms in a Major-groove hydrogen bond is computed. :Arguments: *universe* :class:`~MDAnalysis.core.AtomGroup.Universe` containing the trajectory *i* *seg1* segment id for first base *i* resid of the first base *seg2* segment id for second base *bp* resid of the second base .. NOTE:: If failure occurs be sure to check the segment identification .. versionadded:: 0.7.6 """ if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in ["DC", "DG", "C", "G", "CYT", "GUA"]: if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in ["DC", "C", "CYT"]: a1, a2 = "N4", "O6" else: a1, a2 = "O6", "N4" if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in ["DT", "DA", "A", "T", "U", "ADE", "THY", "URA"]: if universe.select_atoms(" resid {0!s} ".format(i)).resnames[0] in ["DT", "T", "THY", "U", "URA"]: a1, a2 = "O4", "N6" else: a1, a2 = "N6", "O4" no_dist = universe.select_atoms( " (segid {0!s} and resid {1!s} and name {2!s}) or (segid {3!s} and resid {4!s} and name {5!s}) ".format( seg1, i, a1, seg2, bp, a2 ) ) major = mdamath.norm(no_dist[0].pos - no_dist[1].pos) return major
def test_numpy_compliance(self, positions, backend): a, b, c, d = positions # Checks that the cython functions give identical results to the numpy versions bonds = MDAnalysis.lib.distances.calc_bonds(a, b, backend=backend) angles = MDAnalysis.lib.distances.calc_angles(a, b, c, backend=backend) dihedrals = MDAnalysis.lib.distances.calc_dihedrals(a, b, c, d, backend=backend) bonds_numpy = np.array([mdamath.norm(y - x) for x, y in zip(a, b)]) vec1 = a - b vec2 = c - b angles_numpy = np.array( [mdamath.angle(x, y) for x, y in zip(vec1, vec2)]) ab = a - b bc = b - c cd = c - d dihedrals_numpy = np.array( [mdamath.dihedral(x, y, z) for x, y, z in zip(ab, bc, cd)]) assert_almost_equal( bonds, bonds_numpy, self.prec, err_msg="Cython bonds didn't match numpy calculations") # numpy 0 angle returns NaN rather than 0 assert_almost_equal( angles[1:], angles_numpy[1:], self.prec, err_msg="Cython angles didn't match numpy calcuations") assert_almost_equal( dihedrals, dihedrals_numpy, self.prec, err_msg="Cython dihedrals didn't match numpy calculations")
def _reduce_residues(residues, ffmols, size): """ Reduce the number of residue by grouping them together """ #taken = [len(ffmol.beadnames) > 1 for ffmol in ffmols] taken = [ffmol.resname != "SOL" for ffmol in ffmols] skip = [False for ffmol in ffmols] norig = len(residues) - sum(taken) ntaken = 0 i = 0 while ntaken < norig: first_res = residues[taken.index(False)] taken[first_res.resid - 1] = True coord = first_res.atoms.positions # Find size - 1 other residues closes to the first non-taken residue resid = [ res.resid - 1 for res, itaken in zip(residues, taken) if not itaken ] dist = [ mdutil.norm(coord[0, :] - res.atoms.positions[0, :]) for res, itaken in zip(residues, taken) if not itaken ] sortlst = np.asarray(dist).argsort() # Marken the closest residues for skipping for isort in sortlst[:size - 1]: idsort = resid[isort] skip[idsort] = True taken[idsort] = True coord = coord + residues[idsort].atoms.positions # Move the first non-taken residue to the centroid of the group coord = coord / float(size) first_res.atoms.positions = coord ntaken += size return skip
def vecnorm(a): """Return a/|a|""" return a / mdamath.norm(a)
def main_loop(positions, ref_axis=None): # rewrite in cython? if ref_axis is None: ref_axis = np.array([0., 0., 1.]) else: ref_axis = np.asarray(ref_axis) twist = [] rnou = [] height = [] origins = [[0., 0., 0.] for item in positions[:-2]] local_helix_axes = [] location_rotation_vectors = [] for i in range(len(positions) - 3): vec12 = positions[i + 1] - positions[i] vec23 = positions[i + 2] - positions[i + 1] vec34 = positions[i + 3] - positions[i + 2] dv13 = vec12 - vec23 dv24 = vec23 - vec34 #direction of the local helix axis current_uloc = vecnorm(np.cross(dv13, dv24)) local_helix_axes.append(current_uloc) #TESTED- Axes correct #print current_uloc dmag = mdamath.norm(dv13) emag = mdamath.norm(dv24) costheta = np.dot(dv13, dv24) / (dmag * emag) #rnou is the number of residues per turn current_twist = np.arccos(costheta) twist.append(np.rad2deg(current_twist)) rnou.append(2 * np.pi / current_twist) #radius of local helix cylinder radmag costheta1 = 1.0 - costheta radmag = (dmag * emag)**0.5 / (2 * costheta1) #Height of local helix cylinder current_height = np.dot(vec23, current_uloc) height.append(current_height) #TESTED- Twists etc correct #print current_twist*180/np.pi, 2*np.pi/current_twist, height dv13 = vecnorm(dv13) dv24 = vecnorm(dv24) #record local rotation location_rotation_vectors.append(dv13) rad = [radmag * item for item in dv13] current_origin = [(item[0] - item[1]) for item in zip(positions[i + 1], rad)] origins[i] = current_origin #TESTED- origins are correct #print current_origin rad = [radmag * item for item in dv24] current_origin = [(item[0] - item[1]) for item in zip(positions[i + 2], rad)] origins[i + 1] = current_origin #Record final rotation vector location_rotation_vectors.append(dv24) #local bending angles (eg i > i+3, i+3 > i+6) bending_angles = [0 for item in range(len(local_helix_axes) - 3)] for axis in range(len(local_helix_axes) - 3): angle = np.arccos( np.dot(local_helix_axes[axis], local_helix_axes[axis + 3])) bending_angles[axis] = np.rad2deg(angle) #TESTED- angles are correct #print np.rad2deg(angle) local_screw_angles = [] #Calculate rotation angles for (+1) to (n-1) fit_vector, fit_tilt = vector_of_best_fit(origins) for item in location_rotation_vectors: local_screw_tmp = np.rad2deg(rotation_angle(fit_vector, ref_axis, item)) #print local_screw_tmp local_screw_angles.append(local_screw_tmp) return twist, bending_angles, height, rnou, origins, local_helix_axes, local_screw_angles
def _check_NormRange(self, x): r = 1000. v = r * np.array([np.cos(x), np.sin(x), 0]) assert_almost_equal(mdamath.norm(v), r, 6)
def testNormRandom(self): for x in np.random.uniform(0, np.pi, 20): r = np.random.uniform(0, 1000) v = r * np.array([np.cos(x), np.sin(x), 0]) assert_almost_equal(mdamath.norm(v), r, 6)
def test_norm_range(self, x): r = 1000. v = r * np.array([np.cos(x), np.sin(x), 0]) assert_almost_equal(mdamath.norm(v), r, 6)
def testNorm(self): assert_equal(mdamath.norm(self.e3), 1) assert_equal(mdamath.norm(self.a), numpy.linalg.norm(self.a))
def test_norm(self, vector, value): assert mdamath.norm(vector) == value
def testNormNullVector(self): assert_equal(mdamath.norm(self.null), 0.0)
def testNormRandom(self): for x in numpy.random.uniform(0, pi, 20): r = numpy.random.uniform(0, 1000) v = r * numpy.array([cos(x), sin(x), 0]) assert_almost_equal(mdamath.norm(v), r, 6)
def testNorm(self): assert_equal(mdamath.norm(self.e3), 1) assert_equal(mdamath.norm(self.a), np.linalg.norm(self.a))
def main_loop(positions, ref_axis=None): # rewrite in cython? if ref_axis is None: ref_axis = np.array([0., 0., 1.]) else: ref_axis = np.asarray(ref_axis) twist = [] rnou = [] height = [] origins = [[0., 0., 0.] for item in positions[:-2]] local_helix_axes = [] location_rotation_vectors = [] for i in range(len(positions) - 3): vec12 = positions[i + 1] - positions[i] vec23 = positions[i + 2] - positions[i + 1] vec34 = positions[i + 3] - positions[i + 2] dv13 = vec12 - vec23 dv24 = vec23 - vec34 #direction of the local helix axis current_uloc = vecnorm(np.cross(dv13, dv24)) local_helix_axes.append(current_uloc) #TESTED- Axes correct #print current_uloc dmag = mdamath.norm(dv13) emag = mdamath.norm(dv24) costheta = np.dot(dv13, dv24) / (dmag * emag) #rnou is the number of residues per turn current_twist = np.arccos(costheta) twist.append(np.rad2deg(current_twist)) rnou.append(2 * np.pi / current_twist) #radius of local helix cylinder radmag costheta1 = 1.0 - costheta radmag = (dmag * emag) ** 0.5 / (2 * costheta1) #Height of local helix cylinder current_height = np.dot(vec23, current_uloc) height.append(current_height) #TESTED- Twists etc correct #print current_twist*180/np.pi, 2*np.pi/current_twist, height dv13 = vecnorm(dv13) dv24 = vecnorm(dv24) #record local rotation location_rotation_vectors.append(dv13) rad = [radmag * item for item in dv13] current_origin = [(item[0] - item[1]) for item in zip(positions[i + 1], rad)] origins[i] = current_origin #TESTED- origins are correct #print current_origin rad = [radmag * item for item in dv24] current_origin = [(item[0] - item[1]) for item in zip(positions[i + 2], rad)] origins[i + 1] = current_origin #Record final rotation vector location_rotation_vectors.append(dv24) #local bending angles (eg i > i+3, i+3 > i+6) bending_angles = [0 for item in range(len(local_helix_axes) - 3)] for axis in range(len(local_helix_axes) - 3): angle = np.arccos(np.dot(local_helix_axes[axis], local_helix_axes[axis + 3])) bending_angles[axis] = np.rad2deg(angle) #TESTED- angles are correct #print np.rad2deg(angle) local_screw_angles = [] #Calculate rotation angles for (+1) to (n-1) fit_vector, fit_tilt = vector_of_best_fit(origins) for item in location_rotation_vectors: local_screw_tmp = np.rad2deg(rotation_angle(fit_vector, ref_axis, item)) #print local_screw_tmp local_screw_angles.append(local_screw_tmp) return twist, bending_angles, height, rnou, origins, local_helix_axes, local_screw_angles