def get_peptide_bond_parameters(): '''Print peptide parameters.''' d = { 'c_n_length': 1.32869, 'n_ca_length': 1.458, 'ca_c_length': 1.52326, 'c_n_ca_angle': np.radians(121.7), 'n_ca_c_angle': np.radians(111.2), 'ca_c_n_angle': np.radians(116.2), 'omega': np.radians(180) } p1 = np.array([0, 0, 0]) p2 = np.array([0, 0, d['ca_c_length']]) p3 = p2 + d['c_n_length'] * np.array( [np.sin(d['ca_c_n_angle']), 0, -np.cos(d['ca_c_n_angle'])]) p4 = geometry.cartesian_coord_from_internal_coord(p1, p2, p3, d['n_ca_length'], d['n_ca_c_angle'], d['omega']) d['theta_c'] = geometry.angle(p4 - p1, p2 - p1) d['theta_n'] = geometry.angle(p1 - p4, p3 - p4) return d
def get_ideal_parameters_from_internal_coordinates(theta1, tau1, theta2, tau2): '''Get ideal parameters R, delta, alpha and eta from internal coordinates.''' # Always requires theta2 >= theta1 if theta2 < theta1: theta1, tau1, theta2, tau2 = theta2, tau2, theta1, tau1 # Get all the points p0 = D_MEAN * np.array([np.sin(theta1), np.cos(theta1), 0]) p1 = np.array([0, 0, 0]) p2 = np.array([0, D_MEAN, 0]) p3 = geometry.cartesian_coord_from_internal_coord(p0, p1, p2, D_MEAN, theta2, tau1) p4 = geometry.cartesian_coord_from_internal_coord(p1, p2, p3, D_MEAN, theta1, tau2) # Get the rotation and translation of the middle point between p0 and p2 M = np.transpose(geometry.create_frame_from_three_points(p2, p3, p4)) t = (p4 - p0) / 2 # Get parameters v, delta = geometry.rotation_matrix_to_axis_and_angle(M) if delta < 0: delta = -delta v = -v R = np.linalg.norm(t - np.dot(t, v) * v) / (2 * np.sin(delta / 2)) alpha = np.pi / 2 - geometry.angle(v, p2 - p0) if alpha < 0: alpha += np.pi p1_0 = np.cross(p2 - p0, v) if np.dot(p1_0, p1 - (p2 + p0) / 2) < 0: p1_0 = -p1_0 eta = geometry.angle(p1 - (p2 + p0) / 2, p1_0) if np.dot(np.cross(p1_0, p1 - (p2 + p0) / 2), p2 - p0) < 0: eta = -eta return R, delta, alpha, eta
def extend_a_strand(strand, forward=True): '''Extend a strand by one atom. Angle and torsion of the strand will be used to extend the new atom. ''' if forward: last_p = geometry.cartesian_coord_from_internal_coord( strand[-3], strand[-2], strand[-1], D_MEAN, geometry.angle(strand[-4] - strand[-3], strand[-2] - strand[-3]), geometry.dihedral(strand[-5], strand[-4], strand[-3], strand[-2])) return strand + [last_p] else: first_p = geometry.cartesian_coord_from_internal_coord( strand[2], strand[1], strand[0], D_MEAN, geometry.angle(strand[3] - strand[2], strand[1] - strand[2]), geometry.dihedral(strand[4], strand[3], strand[2], strand[1])) return [first_p] + strand
def twist_minimum_unit(thetas, taus, M_init, axis, pitch_angle, omega): '''Twist a minimum twist unit. Return new values for thetas and taus. Return None if the twist failed. ''' if len(thetas) != 3 or len(taus) != 3: raise Exception( "A minimum twist unit must have 3 angles and 3 torsions!") screw_axes = [] # Get the new value of the first axis axis1_local = geometry.rotation_matrix_to_axis_and_angle( theta_tau_to_rotation_matrix(thetas[0], taus[0]))[0] axis1_global = np.dot(M_init, axis1_local) angle_to_rotate = pitch_angle - geometry.angle(axis, axis1_global) rotate_axis = geometry.normalize(np.cross(axis, axis1_global)) for i in range(1, 5): M_rot = geometry.rotation_matrix_from_axis_and_angle( rotate_axis, angle_to_rotate) new_axis_global = np.dot(M_rot, axis1_global) new_axis_local = np.dot(np.transpose(M_init), new_axis_global) theta, tau = axis_to_theta_tau(new_axis_local) if check_theta_tau(theta, tau): screw_axes.append(new_axis_global) break angle_to_rotate /= 2 if len(screw_axes) == 0: return None, None # Get the new screw axes M_rot = geometry.rotation_matrix_from_axis_and_angle(axis, omega) for i in range(1, 3): screw_axes.append(np.dot(M_rot, screw_axes[i - 1])) # Get the internal coordinates try: thetas, taus, M = get_theta_tau_and_rotation_matrix_from_screw_axes( screw_axes, M_init=M_init) except: return None, None return thetas[1:], taus
def get_internal_coordinates_for_ideal_strand(R, delta, alpha, eta): '''Get 4 internal coordinates for an ideal beta strand. The inputs are the screw redius R, the angle alpha which is between a tangent of the screw spiral and the horizontal plane and the screw angle omega between Ca_i and Ca_i+2, delta which is the screw angle from Ca_i to Ca_i+2 and eta which is the value of tilting. Note that alpha is in the range (0, pi/2) for right handed strands and (pi/2, pi) for left handed strands. The outputs are theta1, tau1, theta2, tau2. ''' # Adjust the sign of delta for left handed strand if alpha > np.pi / 2: delta = -delta theta1 = 2 * np.arcsin(R * np.absolute(np.tan(delta / 2)) / (D_MEAN * np.absolute(np.cos(alpha)))) h = 2 * D_MEAN * np.sin(theta1 / 2) * np.sin(alpha) p2 = np.array([0, D_MEAN * np.sin(theta1 / 2) * np.cos(alpha), h / 2]) # Get p1 p1_0 = np.array([D_MEAN * np.cos(theta1 / 2), 0, 0]) M1 = geometry.rotation_matrix_from_axis_and_angle(p2, eta) p1 = np.dot(M1, p1_0) # Get p3 and p4 M_screw, t_screw = geometry.get_screw_transformation( np.array([0, 0, 1]), delta, 2 * np.pi / np.absolute(delta) * h, np.array([-R, 0, 0])) p3 = np.dot(M_screw, p1) + t_screw p4 = np.dot(M_screw, p2) + t_screw theta2 = geometry.angle(p1 - p2, p3 - p2) tau1 = geometry.dihedral(-p2, p1, p2, p3) tau2 = geometry.dihedral(p1, p2, p3, p4) return theta1, tau1, theta2, tau2
def get_internal_coordinates_from_ca_list(ca_list): '''Get the list of ds, thetas and taus from a ca list.''' ds = [] thetas = [] taus = [] for i in range(len(ca_list) - 1): ds.append(np.linalg.norm(ca_list[i + 1] - ca_list[i])) for i in range(1, len(ca_list) - 1): thetas.append( geometry.angle(ca_list[i - 1] - ca_list[i], ca_list[i + 1] - ca_list[i])) for i in range(1, len(ca_list) - 2): taus.append( geometry.dihedral(ca_list[i - 1], ca_list[i], ca_list[i + 1], ca_list[i + 2])) return ds, thetas, taus
def get_c_for_pp_bond_forward(ca1, ca2, v_n, z_sign=1): '''Get the coordinate of the C atom in a peptide bond. Inputs are the two ends of the peptide bond, the direction from ca1 to the position of the previous N and the sign of Z direction that is used to pick one solution from two. ''' params = get_peptide_bond_parameters() frame = geometry.create_frame_from_three_points(ca1 + v_n, ca1, ca2) beta = geometry.angle(v_n, ca2 - ca1) gamma = z_sign * np.arccos((np.cos(params['n_ca_c_angle']) - np.cos(params['theta_c']) * np.cos(beta)) \ / (np.sin(params['theta_c']) * np.sin(beta))) c_local = params['ca_c_length'] * np.array([ np.sin(params['theta_c']) * np.cos(gamma), np.cos(params['theta_c']), np.sin(params['theta_c']) * np.sin(gamma) ]) return ca1 + np.dot(np.transpose(frame), c_local)
def get_screw_transformation_for_strand(strand, distance, direction): '''Get the screw transformation for a strand. The first five atoms of the strand are used to calculate relative parameters. ''' # Get internal coordinates theta1 = geometry.angle(strand[0] - strand[1], strand[2] - strand[1]) theta2 = geometry.angle(strand[1] - strand[2], strand[3] - strand[2]) tau1 = geometry.dihedral(strand[0], strand[1], strand[2], strand[3]) tau2 = geometry.dihedral(strand[1], strand[2], strand[3], strand[4]) # Get the direction vector d_v = geometry.normalize( np.cross(strand[1] - strand[2], strand[3] - strand[2])) if direction == '-': d_v = -d_v # Get the ideal parameters R, delta, alpha, eta = get_ideal_parameters_from_internal_coordinates( theta1, tau1, theta2, tau2) # If theta1 == theta2 or the alpha is zero, do a pure translation if np.absolute(theta1 - theta2) < 0.001 \ or np.absolute(alpha) < 0.001 or np.absolute(alpha - np.pi) < 0.001: M = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) t = distance * d_v return M, t # Get the anchor anchor = strand[:3] if theta1 <= theta2 else strand[1:4] # Get the outer cylinder radius R_out = R + D_MEAN * np.cos(min(theta1, theta2) / 2) # Get the screw axis rot_p2_p0 = geometry.rotation_matrix_from_axis_and_angle( anchor[2] - anchor[0], -eta) x = geometry.normalize( np.dot(rot_p2_p0, anchor[1] - (anchor[2] + anchor[0]) / 2)) rot_x = geometry.rotation_matrix_from_axis_and_angle(x, np.pi / 2 - alpha) z = geometry.normalize(np.dot(rot_x, anchor[2] - anchor[0])) if np.dot(d_v, z) < 0: z = -z u = (anchor[0] + anchor[2]) / 2 - R * x # Get the pitch pitch = np.absolute(geometry.pitch_angle_to_pitch(alpha, R_out)) # Get the screw angle screw_angle = -distance * np.sin(alpha) / R_out if alpha < np.pi / 2 \ else distance * np.sin(alpha) / R_out # Get the screw rotation and translation return geometry.get_screw_transformation(z, screw_angle, pitch, u)