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 perturb_strand_local(strand, position, perturb_function): '''Perturb a strand at a given position according to a perturb_function. ''' # get internal coordinates ds, thetas, taus = basic.get_internal_coordinates_from_ca_list(strand) # get old geometry parameters R, delta, alpha, eta = perturb_function( get_ideal_parameters_from_internal_coordinates(thetas[position - 1], taus[position - 1], thetas[position], taus[position])) # update internal coordinates thetas[position - 1], taus[position - 1], thetas[position], taus[position] = \ get_internal_coordinates_for_ideal_strand(R, delta, alpha, eta) thetas[position + 1] = thetas[position - 1] taus[position + 1] = taus[position - 1] # return a new strand new_strand = strand[:3] for i in range(3, len(strand)): new_strand.append( geometry.cartesian_coord_from_internal_coord( new_strand[i - 3], new_strand[i - 2], new_strand[i - 1], ds[i - 1], thetas[i - 2], taus[i - 3])) return new_strand
def generate_segment_from_internal_coordinates(ds, thetas, taus): '''Generate a protein segment from a set of internal coordinates. Return a list of Ca coordinates. ''' # Make sure that the sizes of internal coordinates are correct if len(ds) < 3 or len(thetas) < 2 or len(taus) < 1 \ or len(ds) != len(thetas) + 1 or len(ds) != len(taus) + 2: raise Exception("Incompatible sizes of internal coordinates.") # Make the first three Ca atoms ca_list = [] ca_list.append(ds[0] * np.array([np.sin(thetas[0]), np.cos(thetas[0]), 0])) ca_list.append(np.array([0, 0, 0])) ca_list.append(np.array([0, ds[1], 0])) # Make the rest of Ca atoms for i in range(len(taus)): ca_list.append( geometry.cartesian_coord_from_internal_coord( ca_list[i], ca_list[i + 1], ca_list[i + 2], ds[i + 2], thetas[i + 1], taus[i])) return ca_list
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 change_strand_internal_coord_global(strand, perturb_function): '''Perturb the internal coordinates of a strand according to a perturb_function. ''' # get internal coordinates ds, thetas, taus = basic.get_internal_coordinates_from_ca_list(strand) # append two thetas and taus for i in range(2): thetas.append(thetas[-2]) taus.append(taus[-2]) # perturb internal coordinates position = 0 while position < len(strand) - 2: thetas[position], taus[position], thetas[position + 1], taus[position + 1] = \ perturb_function((thetas[position], taus[position], thetas[position + 1], taus[position + 1])) position += 2 # return a new strand new_strand = strand[:2] new_strand.append( geometry.change_angle(strand[0], strand[1], strand[2], thetas[0])) for i in range(3, len(strand)): new_strand.append( geometry.cartesian_coord_from_internal_coord( new_strand[i - 3], new_strand[i - 2], new_strand[i - 1], ds[i - 1], thetas[i - 2], taus[i - 3])) # Superimpose the old and new strand M, t = geometry.get_superimpose_transformation(new_strand, strand) new_strand = [np.dot(M, p) + t for p in new_strand] return new_strand
def random_perturb_strand(strand, strand_type, perturb_coef): '''Randomly perturb a strand.''' # get internal coordinates ds, thetas, taus = basic.get_internal_coordinates_from_ca_list(strand) # Get parameters for the strand params = get_strand_parameters(strand_type) # Perturb the internal coordinates for i in range(len(thetas)): thetas[i] = thetas[i] + np.random.normal( 0, perturb_coef * params['angle_std']) for i in range(len(taus)): taus[i] = taus[i] + np.random.normal( 0, perturb_coef * params['torsion_std']) # return a new strand new_strand = strand[:3] for i in range(3, len(strand)): new_strand.append( geometry.cartesian_coord_from_internal_coord( new_strand[i - 3], new_strand[i - 2], new_strand[i - 1], ds[i - 1], thetas[i - 2], taus[i - 3])) com_old = sum(strand) / len(strand) com_new = sum(new_strand) / len(new_strand) new_strand = [p + com_old - com_new for p in new_strand] return new_strand
def change_strand_internal_coord_local(strand, position, perturb_function): '''Perturb the internal coordinates of a strand at position and position + 1 according to a perturb_function. ''' # get internal coordinates ds, thetas, taus = basic.get_internal_coordinates_from_ca_list(strand) # perturb internal coordinates thetas[position], taus[position], thetas[position + 1], taus[position + 1] = \ perturb_function((thetas[position], taus[position], thetas[position + 1], taus[position + 1])) # return a new strand new_strand = strand[:3] for i in range(3, len(strand)): new_strand.append( geometry.cartesian_coord_from_internal_coord( new_strand[i - 3], new_strand[i - 2], new_strand[i - 1], ds[i - 1], thetas[i - 2], taus[i - 3])) return new_strand
def get_o_for_peptide_bond(c, n, ca2): '''Get the coordinate of the O atom in a peptide bond.''' return geometry.cartesian_coord_from_internal_coord( ca2, n, c, 1.24, np.radians(125), 0)
def thread_backbone_for_strand(ca_list, strand_type): '''Thread backbone atoms for a ca list of a beta strand.''' # Make the N termial residue residue_list = [{ 'ca': ca_list[0], 'n': geometry.cartesian_coord_from_internal_coord( ca_list[2], ca_list[1], ca_list[0], 1.45, np.radians(123.1) if strand_type == 'parallel' else np.radians(125.2), np.radians(-136.0) if strand_type == 'parallel' else np.radians(-116.2)), 'c': geometry.cartesian_coord_from_internal_coord( ca_list[2], ca_list[1], ca_list[0], 1.52, np.radians(20.8) if strand_type == 'parallel' else np.radians(20.8), np.radians(-93.0) if strand_type == 'parallel' else np.radians(-94.4)) }] # Make middle residues for i in range(1, len(ca_list) - 1): residue_list.append({ 'ca': ca_list[i], 'n': geometry.cartesian_coord_from_internal_coord( ca_list[i - 1], ca_list[i + 1], ca_list[i], 1.45, np.radians(120.8) if strand_type == 'parallel' else np.radians(121.9), np.radians(16.4) if strand_type == 'parallel' else np.radians(15.7)), 'c': geometry.cartesian_coord_from_internal_coord( ca_list[i + 1], ca_list[i - 1], ca_list[i], 1.52, np.radians(114.0) if strand_type == 'parallel' else np.radians(115.2), np.radians(-20.0) if strand_type == 'parallel' else np.radians(-17.2)) }) # Make the N terminal residue residue_list.append({ 'ca': ca_list[-1], 'n': geometry.cartesian_coord_from_internal_coord( ca_list[-3], ca_list[-2], ca_list[-1], 1.45, np.radians(15.4) if strand_type == 'parallel' else np.radians(15.2), np.radians(99.6) if strand_type == 'parallel' else np.radians(100.5)), 'c': geometry.cartesian_coord_from_internal_coord( ca_list[-3], ca_list[-2], ca_list[-1], 1.52, np.radians(113.5) if strand_type == 'parallel' else np.radians(112.8), np.radians(11.6) if strand_type == 'parallel' else np.radians(-8.5)) }) # Buil O atoms for i in range(1, len(ca_list)): residue_list[i - 1]['o'] = basic.get_o_for_peptide_bond( residue_list[i - 1]['c'], residue_list[i]['n'], residue_list[i]['ca']) return residue_list
def build_a_random_strand_from_a_reference(strand, strand_type, direction, seed=None, adjust_first_atom=False): '''Build a random beta strand based on a reference strand.''' if seed is None: seed = make_strand_seed(strand, strand_type, direction) new_strand = seed # Add a atom to the reference strand such that we can build a frame for the last atom strand_params = get_strand_parameters(strand_type) extended_strand = strand + [ geometry.cartesian_coord_from_internal_coord( strand[-3], strand[-2], strand[-1], strand_params['length_mean'], strand_params['angle_mean'], strand_params['torsion_mean']) ] # Extend the strand randomly for i in range(3, len(strand)): ref_frame = geometry.create_frame_from_three_points( extended_strand[i - 1], extended_strand[i], extended_strand[i + 1]) # Try to find a proper value of theta and tau theta_best = 0 tau_best = 0 score_best = 0 p_best = None for j in range(300): theta = np.random.normal(strand_params['angle_mean'], strand_params['angle_std']) tau = np.random.normal(strand_params['torsion_mean'], strand_params['torsion_std']) p = geometry.cartesian_coord_from_internal_coord( new_strand[i - 3], new_strand[i - 2], new_strand[i - 1], strand_params['length_mean'], theta, tau) p_local = np.dot(ref_frame, p - strand[i]) score = get_bp_vector_score(p_local, strand_type, direction) if score > score_best: theta_best = theta tau_best = tau score_best = score p_best = p if score_best < 0.01: return None new_strand.append(p_best) direction = '-' if direction == '+' else '+' #Flip the direction # Adjust the position of the first atom if adjust_first_atom: new_strand[0] = new_strand[1] + new_strand[2] - new_strand[3] return new_strand
def thread_backbone_for_helix(ca_list): '''Thread backbone atoms for a ca list of a helix using the method and parameters from the G. Grigoryan, W. F. DeGrado paper. Return a list of residue dictionaries. ''' # Make the N termial residue residue_list = [{ 'ca': ca_list[0], 'n': geometry.cartesian_coord_from_internal_coord(ca_list[2], ca_list[1], ca_list[0], 1.45, np.radians(95.0), np.radians(65.0)), 'c': geometry.cartesian_coord_from_internal_coord(ca_list[2], ca_list[1], ca_list[0], 1.52, np.radians(21.0), np.radians(-79.0)) }] # Make middle residues for i in range(1, len(ca_list) - 1): residue_list.append({ 'ca': ca_list[i], 'n': geometry.cartesian_coord_from_internal_coord( ca_list[i - 1], ca_list[i + 1], ca_list[i], 1.45, np.radians(95.0), np.radians(14.0)), 'c': geometry.cartesian_coord_from_internal_coord( ca_list[i + 1], ca_list[i - 1], ca_list[i], 1.52, np.radians(104.0), np.radians(16.0)) }) # Make the N terminal residue residue_list.append({ 'ca': ca_list[-1], 'n': geometry.cartesian_coord_from_internal_coord(ca_list[-3], ca_list[-2], ca_list[-1], 1.45, np.radians(15.0), np.radians(-56.0)), 'c': geometry.cartesian_coord_from_internal_coord(ca_list[-3], ca_list[-2], ca_list[-1], 1.52, np.radians(104.0), np.radians(67.0)) }) # Buil O atoms for i in range(1, len(ca_list)): residue_list[i - 1]['o'] = basic.get_o_for_peptide_bond( residue_list[i - 1]['c'], residue_list[i]['n'], residue_list[i]['ca']) return residue_list