def get_stem_rotation_matrix(stem, stem2, use_average_method=False): """ :param stem: The first StemModel :param stem2: The second StemModel :retuirns: A RotationMatrix. Use stem1.vec()*rotMat to rotate stem1 onto stem2 Use rotMat*stem2.vec() to rotate stem2 onto stem1 """ #twist1 = (stem.twists[0] + stem.twists[1]) / 2. if not use_average_method: twist1 = stem.twists[0] twist2 = stem2.twists[0] else: twist1 = ftug.virtual_res_3d_pos_core(stem.mids, stem.twists, 2, 4)[1] twist2 = ftug.virtual_res_3d_pos_core(stem2.mids, stem2.twists, 2, 4)[1] return ftuv.get_double_alignment_matrix((stem.vec(), twist1), (stem2.vec(), twist2)) # get normalvector to stem and twist. comp1 = np.cross(stem.vec(), twist1) # rotate around the first stem by t degrees rot_mat1 = ftuv.rotation_matrix(stem.vec(), t) rot_mat2 = ftuv.rotation_matrix(twist1, u - math.pi / 2) rot_mat3 = ftuv.rotation_matrix(comp1, v) rot_mat4 = np.dot(rot_mat3, np.dot(rot_mat2, rot_mat1)) return rot_mat4
def add_stem_like_core(self, rna_plotter, coords, twists, stem_len, text, key, color='green', width=2.4): (p, n) = coords width *= self.cylinder_width rna_plotter.add_segment(p, n, color, width, text, key=key) if self.show_twists: rna_plotter.add_cone(p, n, 'white', width, key) mult = 8. width = .3 (twist1o, twist2o) = twists rna_plotter.add_segment( p, p + mult * twist1o, "cyan", width, '', key=key) rna_plotter.add_segment( n, n + mult * twist2o, "magenta", width, '', key=key) for i in range(stem_len): res = ftug.virtual_res_3d_pos_core((p, n), twists, i, stem_len) (pos, vec_c, vec_l, vec_r) = res rna_plotter.add_segment( pos, pos + mult * vec_c, "orange", width, '', key=key) if self.add_letters: rna_plotter.labels += [('L', list(pos + mult * vec_l))] rna_plotter.labels += [('R', list(pos + mult * vec_r))]
def add_stem_like_core(self, coords, twists, stem_len, key, color='green', width=2.4): (p, n) = coords self.add_cone(p, n, 'white', width, key) self.add_segment(p, n, color, width, key, key=key) #self.add_sphere(p, 'light gray', width=2.0 ) #self.add_sphere(n, 'dark gray', width=2.0 ) if self.add_twists: mult = 8. width = .3 #twist1o = bg.get_twists(key)[0] #twist2o = bg.get_twists(key)[1] (twist1o, twist2o) = twists self.add_segment(p, p + mult * twist1o, "cyan", width, '', key=key) self.add_segment(n, n + mult * twist2o, "magenta", width, '', key=key) ''' twist_rot_mat_l = cuv.rotation_matrix(n - p, -(1.45 / 2.)) twist_rot_mat_r = cuv.rotation_matrix(n - p, (1.45 / 2.)) twist1 = np.dot(twist_rot_mat_l, twist1o) twist2 = np.dot(twist_rot_mat_l, twist2o) twist3 = np.dot(twist_rot_mat_r, twist1o) twist4 = np.dot(twist_rot_mat_r, twist2o) self.add_segment(p, p + mult * twist1, "white", width, '', key) self.add_segment(n, n + mult * twist2, "white", width, '', key) self.add_segment(p, p + mult * twist3, "red", width, '', key) self.add_segment(n, n + mult * twist4, "red", width, '', key) ''' #stem_len = bg.stem_length(key) for i in range(stem_len): #(pos, vec) = ftug.virtual_res_3d_pos(bg, key, i) res = ftug.virtual_res_3d_pos_core((p, n), twists, i, stem_len) (pos, vec_c, vec_l, vec_r) = res self.add_segment(pos, pos + mult * vec_c, "orange", width, '', key=key) if self.add_letters: self.labels += [('L', list(pos + mult * vec_l))] self.labels += [('R', list(pos + mult * vec_r))] ''' self.add_segment(pos, pos + mult * vec_l, "yellow", width, '', key) self.add_segment(pos, pos + mult * vec_r, "purple", width, '', key) ''' if self.display_virtual_residues: self.add_sphere(pos + mult * vec_l, "cyan", 1.) self.add_sphere(pos + mult * vec_r, "magenta", 1.) '''
def add_stem_like_core(self, coords, twists, stem_len, key, color='green', width=2.4): (p, n) = coords self.add_cone(p, n, 'white', width, key) self.add_segment(p, n, color, width, key, key=key) self.add_sphere(p, 'light gray', width=2.0 ) self.add_sphere(n, 'dark gray', width=2.0 ) if self.add_twists: mult = 8. width = .3 #twist1o = bg.get_twists(key)[0] #twist2o = bg.get_twists(key)[1] (twist1o, twist2o) = twists self.add_segment(p, p + mult * twist1o, "cyan", width, '', key=key) self.add_segment(n, n + mult * twist2o, "magenta", width, '', key=key) ''' twist_rot_mat_l = cuv.rotation_matrix(n - p, -(1.45 / 2.)) twist_rot_mat_r = cuv.rotation_matrix(n - p, (1.45 / 2.)) twist1 = np.dot(twist_rot_mat_l, twist1o) twist2 = np.dot(twist_rot_mat_l, twist2o) twist3 = np.dot(twist_rot_mat_r, twist1o) twist4 = np.dot(twist_rot_mat_r, twist2o) self.add_segment(p, p + mult * twist1, "white", width, '', key) self.add_segment(n, n + mult * twist2, "white", width, '', key) self.add_segment(p, p + mult * twist3, "red", width, '', key) self.add_segment(n, n + mult * twist4, "red", width, '', key) ''' #stem_len = bg.stem_length(key) for i in range(stem_len): #(pos, vec) = ftug.virtual_res_3d_pos(bg, key, i) res = ftug.virtual_res_3d_pos_core((p, n), twists, i, stem_len) (pos, vec_c, vec_l, vec_r) = res self.add_segment(pos, pos + mult * vec_c, "orange", width, '', key=key) if self.add_letters: self.labels += [('L', list(pos + mult * vec_l))] self.labels += [('R', list(pos + mult * vec_r))] ''' self.add_segment(pos, pos + mult * vec_l, "yellow", width, '', key) self.add_segment(pos, pos + mult * vec_r, "purple", width, '', key) ''' if self.display_virtual_residues: self.add_sphere(pos + mult * vec_l, "cyan", 1.) self.add_sphere(pos + mult * vec_r, "magenta", 1.) '''
def _align_chain_to_stem(cg, chains, elem_name, stem2, use_average_method=True): """ Rotate and tranlate chains to match the orientation of the coarse-grained stem. :param cg: The coarse-grained RNA where the fragment is originally from. :param chains: The PDB chains containing the original fragment. :param elem_name: The element name of the stem in cg. :param stem2: The target (cg-)stem. A StemModel object. """ #The stem fragment we will rotate and translate stem1 = _define_to_stem_model(cg, chains, elem_name) ''' (r, u, v, t) = ftug.get_stem_orientation_parameters(stem1.vec(), (stem1.twists[0] + stem1.twists[1]) / 2., stem2.vec(), (stem2.twists[0] + stem2.twists[1]) / 2.) ''' if not use_average_method: (r, u, v, t) = ftug.get_stem_orientation_parameters(stem1.vec(), stem1.twists[0], stem2.vec(), stem2.twists[0]) else: tw1 = ftug.virtual_res_3d_pos_core(stem1.mids, stem1.twists, 2, 4)[1] tw2 = ftug.virtual_res_3d_pos_core(stem2.mids, stem2.twists, 2, 4)[1] (r, u, v, t) = ftug.get_stem_orientation_parameters(stem1.vec(), tw1, stem2.vec(), tw2) rot_mat = get_stem_rotation_matrix(stem1, stem2, use_average_method) assert np.allclose(ftuv.normalize(stem2.vec()), ftuv.normalize(np.dot(stem1.vec(), rot_mat))) rotate_chain(chains, rot_mat, (stem1.mids[0] + stem1.mids[1]) / 2.) translate_chain(chains, (stem2.mids[0] + stem2.mids[1]) / 2. - (stem1.mids[0] + stem1.mids[1]) / 2.) assert _validate_pdb_to_stem(stem2, chains, cg, elem_name)
def verify_virtual_twist_angles(self, cg, s): sl = cg.stem_length(s) for i in range(0, sl): (pos, vec, vec_l, vec_r) = ftug.virtual_res_3d_pos_core(cg.coords[s], cg.twists[s],i,sl) if i > 1: self.assertGreater(ftuv.vec_angle(vec, prev_vec), 0.1) self.assertLess(ftuv.vec_angle(vec, prev_vec), 0.95) prev_vec = vec
def verify_virtual_twist_angles(self, cg, s): sl = cg.stem_length(s) for i in range(0, sl): (pos, vec, vec_l, vec_r) = ftug.virtual_res_3d_pos_core(cg.coords[s], cg.twists[s],i,sl) if i > 1: self.assertGreater(ftuv.vec_angle(vec, prev_vec), 0.53) self.assertLess(ftuv.vec_angle(vec, prev_vec), 0.73) prev_vec = vec
def add_stem_like_core(self, rna_plotter, coords, twists, stem_len, text, key, color='green', width=2.4): (p, n) = coords width *= self.cylinder_width rna_plotter.add_segment(p, n, color, width, text, key=key) if self.show_twists: rna_plotter.add_cone(p, n, 'white', width, key) mult = 8. width = .3 (twist1o, twist2o) = twists rna_plotter.add_segment(p, p + mult * twist1o, "cyan", width, '', key=key) rna_plotter.add_segment(n, n + mult * twist2o, "magenta", width, '', key=key) for i in range(stem_len): res = ftug.virtual_res_3d_pos_core((p, n), twists, i, stem_len) (pos, vec_c, vec_l, vec_r) = res rna_plotter.add_segment(pos, pos + mult * vec_c, "orange", width, '', key=key) if self.add_letters: rna_plotter.labels += [('L', list(pos + mult * vec_l))] rna_plotter.labels += [('R', list(pos + mult * vec_r))]
def get_relative_orientation(cg, l1, l2): ''' Return how l1 is related to l2 in terms of three parameters. l2 should be the receptor of a potential A-Minor interaction, whereas l1 should be the donor. 1. Distance between the closest points of the two elements 2. The angle between l2 and the vector between the two 3. The angle between the minor groove of l2 and the vector between l1 and l2 ''' (i1, i2) = ftuv.line_segment_distance(cg.coords[l1][0], cg.coords[l1][1], cg.coords[l2][0], cg.coords[l2][1]) ''' angle1 = ftuv.vec_angle(cg.coords[l2][1] - cg.coords[l2][0], i2 - i1) ''' angle1 = ftuv.vec_angle(cg.coords[l2][1] - cg.coords[l2][0], cg.coords[l1][1] - cg.coords[l1][0]) #fud.pv('angle1') tw = cg.get_twists(l2) if l2[0] != 's': angle2 = ftuv.vec_angle((tw[0] + tw[1]) / 2., i2 - i1) else: stem_len = cg.stem_length(l2) pos = ftuv.magnitude(i2 - cg.coords[l2][0]) / ftuv.magnitude(cg.coords[l2][1] - cg.coords[l2][0]) * stem_len vec = ftug.virtual_res_3d_pos_core(cg.coords[l2], cg.twists[l2], pos, stem_len)[1] angle2 = ftuv.vec_angle(vec, i2 - i1) dist = ftug.element_distance(cg, l1, l2) return (dist, angle1, angle2)
def stem_atoms(self, coords, twists, stem_len, side=0): ''' Add the locations of the virtual atoms as spheres. @param coords: The start and end coordinates of the stem. @param twists: The two twists of the stem. @param stem_len: The length of the stem. ''' prev_p = [None, None] first_p = [None, None] last_o3 = [None, None] first_o3 = [None, None] colors = ['yellow', 'purple'] for i in range(stem_len): vbasis = ftug.virtual_res_basis_core(coords, twists, i, stem_len) vpos = ftug.virtual_res_3d_pos_core(coords, twists, i, stem_len) # iterate once for each strand j = side # just use A for now for a in cua.avg_stem_vres_atom_coords[j]['A'].items(): c = a[1] new_coords = np.dot(vbasis.transpose(), c) + vpos[0] #self.add_sphere(new_coords, colors[j], 0.3) if a[0] == 'P' and i == 0: first_p[j] = new_coords if a[0] == 'P': if prev_p[j] is not None: self.add_segment(prev_p[j], new_coords, colors[j], 0.7) prev_p[j] = new_coords if a[0] == 'O3*' and i == 0: first_o3[j] = new_coords if a[0] == 'O3*': last_o3[j] = new_coords
def get_relative_orientation(cg, loop, stem): ''' Return how loop is related to stem in terms of three parameters. The stem is the receptor of a potential A-Minor interaction, whereas the loop is the donor. The 3 parameters are: 1. Distance between the closest points of the two elements 2. The angle between the stem and the vector between the two 3. The angle between the minor groove of l2 and the projection of the vector between stem and loop onto the plane normal to the stem direction. ''' point_on_stem, point_on_loop = ftuv.line_segment_distance( cg.coords[stem][0], cg.coords[stem][1], cg.coords[loop][0], cg.coords[loop][1]) conn_vec = point_on_loop - point_on_stem dist = ftuv.magnitude(conn_vec) angle1 = ftuv.vec_angle(cg.coords.get_direction(stem), conn_vec) # The direction of the stem vector is irrelevant, so # choose the smaller of the two angles between two lines if angle1 > np.pi / 2: angle1 = np.pi - angle1 tw = cg.get_twists(stem) if dist == 0: angle2 = float("nan") else: if stem[0] != 's': raise ValueError( "The receptor needs to be a stem, not {}".format(stem)) else: stem_len = cg.stem_length(stem) # Where along the helix our A-residue points to the minor groove. # This can be between residues. We express it as floating point nucleotide coordinates. # So 0.0 means at the first basepair, while 1.5 means between the second and the third basepair. pos = ftuv.magnitude( point_on_stem - cg.coords[stem][0]) / ftuv.magnitude( cg.coords.get_direction(stem)) * (stem_len - 1) # The vector pointing to the minor groove, even if we are not at a virtual residue (pos is a float value) virt_twist = ftug.virtual_res_3d_pos_core(cg.coords[stem], cg.twists[stem], pos, stem_len)[1] # The projection of the connection vector onto the plane normal to the stem conn_proj = ftuv.vector_rejection(conn_vec, cg.coords.get_direction(stem)) try: # Note: here the directions of both vectors are well defined, # so angles >90 degrees make sense. angle2 = ftuv.vec_angle(virt_twist, conn_proj) except ValueError: if np.all(virt_twist == 0): angle2 = float("nan") else: raise # Furthermore, the direction of the second angle is meaningful. # We call use a positive angle, if the cross-product of the two vectors # has the same sign as the stem vector and a negative angle otherwise cr = np.cross(virt_twist, conn_proj) sign = ftuv.is_almost_parallel(cr, cg.coords.get_direction(stem)) #assert sign != 0, "{} vs {} not (anti) parallel".format( # cr, cg.coords.get_direction(stem)) angle2 *= sign return dist, angle1, angle2
def get_relative_orientation(cg, loop, stem): ''' Return how loop is related to stem in terms of three parameters. The stem is the receptor of a potential A-Minor interaction, whereas the loop is the donor. The 3 parameters are: 1. Distance between the closest points of the two elements 2. The angle between the stem and the vector between the two 3. The angle between the minor groove of l2 and the projection of the vector between stem and loop onto the plane normal to the stem direction. ''' point_on_stem, point_on_loop = ftuv.line_segment_distance(cg.coords[stem][0], cg.coords[stem][1], cg.coords[loop][0], cg.coords[loop][1]) conn_vec = point_on_loop - point_on_stem dist = ftuv.magnitude(conn_vec) angle1 = ftuv.vec_angle(cg.coords.get_direction(stem), conn_vec) # The direction of the stem vector is irrelevant, so # choose the smaller of the two angles between two lines if angle1 > np.pi / 2: angle1 = np.pi - angle1 tw = cg.get_twists(stem) if dist == 0: angle2 = float("nan") else: if stem[0] != 's': raise ValueError( "The receptor needs to be a stem, not {}".format(stem)) else: stem_len = cg.stem_length(stem) # Where along the helix our A-residue points to the minor groove. # This can be between residues. We express it as floating point nucleotide coordinates. # So 0.0 means at the first basepair, while 1.5 means between the second and the third basepair. pos = ftuv.magnitude(point_on_stem - cg.coords[stem][0]) / ftuv.magnitude( cg.coords.get_direction(stem)) * (stem_len - 1) # The vector pointing to the minor groove, even if we are not at a virtual residue (pos is a float value) virt_twist = ftug.virtual_res_3d_pos_core( cg.coords[stem], cg.twists[stem], pos, stem_len)[1] # The projection of the connection vector onto the plane normal to the stem conn_proj = ftuv.vector_rejection( conn_vec, cg.coords.get_direction(stem)) try: # Note: here the directions of both vectors are well defined, # so angles >90 degrees make sense. angle2 = ftuv.vec_angle(virt_twist, conn_proj) except ValueError: if np.all(virt_twist == 0): angle2 = float("nan") else: raise # Furthermore, the direction of the second angle is meaningful. # We call use a positive angle, if the cross-product of the two vectors # has the same sign as the stem vector and a negative angle otherwise cr = np.cross(virt_twist, conn_proj) sign = ftuv.is_almost_parallel(cr, cg.coords.get_direction(stem)) #assert sign != 0, "{} vs {} not (anti) parallel".format( # cr, cg.coords.get_direction(stem)) angle2 *= sign return dist, angle1, angle2