def covalent_bonds(atoms, threshold=1.1): """Returns all the covalent bonds in a list of `Atom` pairs. Notes ----- Uses information `element_data`, which can be accessed directly through this module i.e. `isambard.ampal.interactions.element_data`. Parameters ---------- atoms : [(`Atom`, `Atom`)] List of pairs of `Atoms`. threshold : float, optional Allows deviation from ideal covalent bond distance to be included. For example, a value of 1.1 would allow interactions up to 10% further from the ideal distance to be included. """ bonds = [] for a, b in atoms: bond_distance = ( element_data[a.element.title()]['atomic radius'] + element_data[b.element.title()]['atomic radius']) / 100 dist = distance(a._vector, b._vector) if dist <= bond_distance * threshold: bonds.append(CovalentBond(a, b, dist)) return bonds
def polymer_to_reference_axis_distances(p, reference_axis, tag=True, reference_axis_name='ref_axis'): """Returns distances between the primitive of a Polymer and a reference_axis. Notes ----- Distances are calculated between each point of the Polymer primitive and the corresponding point in reference_axis. In the special case of the helical barrel, if the Polymer is a helix and the reference_axis represents the centre of the barrel, then this function returns the radius of the barrel at each point on the helix primitive. The points of the primitive and the reference_axis are run through in the same order, so take care with the relative orientation of the reference axis when defining it. Parameters ---------- p : ampal.Polymer reference_axis : list(numpy.array or tuple or list) Length of reference_axis must equal length of the Polymer. Each element of reference_axis represents a point in R^3. tag : bool, optional If True, tags the Chain with the reference axis coordinates and each Residue with its distance to the ref axis. Distances are stored at the Residue level, but refer to distances from the CA atom. reference_axis_name : str, optional Used to name the keys in tags at Chain and Residue level. Returns ------- distances : list(float) Distance values between corresponding points on the reference axis and the `Polymer` `Primitive`. Raises ------ ValueError If the Polymer and the reference_axis have unequal length. """ if not len(p) == len(reference_axis): raise ValueError( "The reference axis must contain the same number of points " "as the Polymer primitive.") prim_cas = p.primitive.coordinates ref_points = reference_axis.coordinates distances = [ distance(prim_cas[i], ref_points[i]) for i in range(len(prim_cas)) ] if tag: p.tags[reference_axis_name] = reference_axis monomer_tag_name = 'distance_to_{0}'.format(reference_axis_name) for m, d in zip(p._monomers, distances): m.tags[monomer_tag_name] = d return distances
def make_primitive_extrapolate_ends(cas_coords, smoothing_level=2): """Generates smoothed helix primitives and extrapolates lost ends. Notes ----- From an input list of CA coordinates, the running average is calculated to form a primitive. The smoothing_level dictates how many times to calculate the running average. A higher smoothing_level generates a 'smoother' primitive - i.e. the points on the primitive more closely fit a smooth curve in R^3. Each time the smoothing level is increased by 1, a point is lost from either end of the primitive. To correct for this, the primitive is extrapolated at the ends to approximate the lost values. There is a trade-off then between the smoothness of the primitive and its accuracy at the ends. Parameters ---------- cas_coords : list(numpy.array or float or tuple) Each element of the list must have length 3. smoothing_level : int Number of times to run the averaging. Returns ------- final_primitive : list(numpy.array) Each array has length 3. """ try: smoothed_primitive = make_primitive_smoothed( cas_coords, smoothing_level=smoothing_level) except ValueError: smoothed_primitive = make_primitive_smoothed( cas_coords, smoothing_level=smoothing_level - 1) # if returned smoothed primitive is too short, lower the smoothing # level and try again. if len(smoothed_primitive) < 3: smoothed_primitive = make_primitive_smoothed( cas_coords, smoothing_level=smoothing_level - 1) final_primitive = [] for ca in cas_coords: prim_dists = [distance(ca, p) for p in smoothed_primitive] closest_indices = sorted([ x[0] for x in sorted(enumerate(prim_dists), key=lambda k: k[1])[:3] ]) a, b, c = [smoothed_primitive[x] for x in closest_indices] ab_foot = find_foot(a, b, ca) bc_foot = find_foot(b, c, ca) ca_foot = (ab_foot + bc_foot) / 2 final_primitive.append(ca_foot) return final_primitive
def rise_per_residue(self): """The rise per residue at each point on the Primitive. Notes ----- Each element of the returned list is the rise per residue, at a point on the Primitive. Element i is the distance between primitive[i] and primitive[i + 1]. The final value is None. """ rprs = [ distance(self[i]['CA'], self[i + 1]['CA']) for i in range(len(self) - 1) ] rprs.append(None) return rprs
def find_atoms_within_distance(atoms, cutoff_distance, point): """Returns atoms within the distance from the point. Parameters ---------- atoms : [ampal.atom] A list of `ampal.atoms`. cutoff_distance : float Maximum distance from point. point : (float, float, float) Reference point, 3D coordinate. Returns ------- filtered_atoms : [ampal.atoms] `atoms` list filtered by distance. """ return [x for x in atoms if distance(x, point) <= cutoff_distance]
def knob_end(self): """ Coordinates of the end of the knob residue (atom in side-chain furthest from CB atom. Returns CA coordinates for GLY. """ side_chain_atoms = self.knob_residue.side_chain if not side_chain_atoms: return self.knob_residue['CA'] distances = [ distance(self.knob_residue['CB'], x) for x in side_chain_atoms ] max_d = max(distances) knob_end_atoms = [ atom for atom, d in zip(side_chain_atoms, distances) if d == max_d ] if len(knob_end_atoms) == 1: return knob_end_atoms[0]._vector else: return numpy.mean([x._vector for x in knob_end_atoms], axis=0)
def find_contiguous_packing_segments(polypeptide, residues, max_dist=10.0): """ Assembly containing segments of polypeptide, divided according to separation of contiguous residues. Parameters ---------- polypeptide : Polypeptide residues : iterable containing Residues max_dist : float Separation beyond which splitting of Polymer occurs. Returns ------- segments : Assembly Each segment contains a subset of residues, each not separated by more than max_dist from the previous Residue. """ segments = Assembly(assembly_id=polypeptide.ampal_parent.id) residues_in_polypeptide = list( sorted(residues.intersection(set(polypeptide.get_monomers())), key=lambda x: int(x.id))) if not residues_in_polypeptide: return segments # residue_pots contains separate pots of residues divided according to their separation distance. residue_pots = [] pot = [residues_in_polypeptide[0]] for r1, r2 in zip(residues_in_polypeptide, residues_in_polypeptide[1:]): d = distance(r1['CA'], r2['CA']) if d <= max_dist: pot.append(r2) if sum([len(x) for x in residue_pots] + [len(pot)]) == len(residues_in_polypeptide): residue_pots.append(pot) else: residue_pots.append(pot) pot = [r2] for pot in residue_pots: segment = polypeptide.get_slice_from_res_id(pot[0].id, pot[-1].id) segment.ampal_parent = polypeptide.ampal_parent segments.append(segment) return segments
def find_kihs(assembly, hole_size=4, cutoff=7.0): """ KnobIntoHoles between residues of different chains in assembly. Notes ----- A KnobIntoHole is a found when the side-chain centre of a Residue a chain is close than (cutoff) Angstroms from at least (hole_size) side-chain centres of Residues of a different chain. Parameters ---------- assembly : Assembly hole_size : int Number of Residues required to form each hole. cutoff : float Maximum distance between the knob and each of the hole residues. Returns ------- kihs : [KnobIntoHole] """ pseudo_group = side_chain_centres(assembly=assembly, masses=False) pairs = itertools.permutations(pseudo_group, 2) kihs = [] for pp_1, pp_2 in pairs: for r in pp_1: close_atoms = pp_2.is_within(cutoff, r) # kihs occur between residue and (hole_size) closest side-chains on adjacent polypeptide. if len(close_atoms) < hole_size: continue elif len(close_atoms) > hole_size: close_atoms = sorted(close_atoms, key=lambda x: distance(x, r))[:hole_size] kih = OrderedDict() kih['k'] = r for i, hole_atom in enumerate(close_atoms): kih['h{0}'.format(i)] = hole_atom knob_into_hole = KnobIntoHole(pseudo_atoms=kih) kihs.append(knob_into_hole) return kihs
def max_knob_end_distance(self): """ Maximum distance between knob_end and each of the hole side-chain centres. """ return max([distance(self.knob_end, h) for h in self.hole])
def max_kh_distance(self): return max([distance(self.knob, h) for h in self.hole])