Exemplo n.º 1
0
    def get_orient_angle(self, reference_point=numpy.array([0, 0, 0]),
                         monomer_index=0, res_label='CA', radians=False):
        """ Angle between reference_point and self[monomer_index][res_label].

        Notes
        -----
        Angle is calculated using the dihedral angle, with the 
        second and third points coming from the curve_primitive.

        Parameters
        ----------
        reference_point : list, tuple or numpy.array of length 3.
        monomer_index : int
            Index of the Residue to centre.
        res_label : str
            Atom name for centred atom, e.g. "CA" or "OE1".
        radians : bool
            If True, then desired_angle is in radians instead of degrees.
        """
        if (monomer_index < len(self)) and monomer_index != -1:
            adjacent_index = monomer_index + 1
        elif (monomer_index == len(self)) or monomer_index == -1:
            adjacent_index = monomer_index - 1
        else:
            raise ValueError(
                "centred_index ({0}) cannot be greater than the "
                "length of the polymer ({1})".format(
                    monomer_index, len(self)))
        angle = dihedral(reference_point,
                         self.curve_primitive[monomer_index]['CA'],
                         self.curve_primitive[adjacent_index]['CA'],
                         self[monomer_index][res_label])
        if radians:
            angle = numpy.deg2rad(angle)
        return angle
Exemplo n.º 2
0
def residues_per_turn(p):
    """ The number of residues per turn at each Monomer in the Polymer.

    Notes
    -----
    Each element of the returned list is the number of residues
    per turn, at a point on the Polymer primitive. Calculated using
    the relative positions of the CA atoms and the primitive of the
    Polymer. Element i is the calculated from the dihedral angle using
    the CA atoms of the Monomers with indices [i, i+1] and the
    corresponding atoms of the primitive. The final value is None.

    Parameters
    ----------
    p : ampal.Polypeptide
        `Polypeptide` from which residues per turn will be calculated.

    Returns
    -------
    rpts : [float]
        Residue per turn values.
    """
    cas = p.get_reference_coords()
    prim_cas = p.primitive.coordinates
    dhs = [
        abs(dihedral(cas[i], prim_cas[i], prim_cas[i + 1], cas[i + 1]))
        for i in range(len(prim_cas) - 1)
    ]
    rpts = [360.0 / dh for dh in dhs]
    rpts.append(None)
    return rpts
Exemplo n.º 3
0
def alpha_angles(p, reference_axis, tag=True, reference_axis_name='ref_axis'):
    """Alpha angle calculated using points on the primitive of helix and axis.

    Notes
    -----
    The final value is None, since the angle calculation requires pairs
    of points along the primitive and axis. This is a generalisation
    of the calculation used to measure the tilt of a helix in a
    coiled-coil with respect to the central axis of the coiled coil.

    Parameters
    ----------
    p : ampal.Polymer
        Reference `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 alpha angle. Alpha angles are stored
        at the Residue level, but are calculated using the CA atom.
    reference_axis_name : str, optional
        Used to name the keys in tags at Chain and Residue level.

    Returns
    -------
    alphas : list of float
        The alpha angle for the Polymer at each point of its primitive,
        in degrees.

    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
    alphas = [
        abs(
            dihedral(ref_points[i + 1], ref_points[i], prim_cas[i],
                     prim_cas[i + 1])) for i in range(len(prim_cas) - 1)
    ]
    alphas.append(None)

    if tag:
        p.tags[reference_axis_name] = reference_axis
        monomer_tag_name = 'alpha_angle_{0}'.format(reference_axis_name)
        for m, a in zip(p._monomers, alphas):
            m.tags[monomer_tag_name] = a
    return alphas
Exemplo n.º 4
0
 def build(self):
     """Builds the `HelicalHelix`."""
     helical_helix = Polypeptide()
     primitive_coords = self.curve_primitive.coordinates
     helices = [Helix.from_start_and_end(start=primitive_coords[i],
                                         end=primitive_coords[i + 1],
                                         helix_type=self.minor_helix_type,
                                         aa=1)
                for i in range(len(primitive_coords) - 1)]
     residues_per_turn = self.minor_residues_per_turn(
         minor_repeat=self.minor_repeat)
     if residues_per_turn == 0:
         residues_per_turn = _helix_parameters[self.minor_helix_type][0]
     if self.minor_handedness == 'l':
         residues_per_turn *= -1
     # initial phi_c_alpha value calculated using the first Helix in helices.
     if self.orientation != -1:
         initial_angle = dihedral(numpy.array([0, 0, 0]),
                                  primitive_coords[0],
                                  primitive_coords[1],
                                  helices[0][0]['CA'])
     else:
         initial_angle = dihedral(
             numpy.array([0, 0, primitive_coords[0][2]]),
             primitive_coords[0],
             numpy.array([primitive_coords[0][0],
                          primitive_coords[0][1], primitive_coords[1][2]]),
             helices[0][0]['CA'])
     # angle required to achieve desired phi_c_alpha value of self.phi_c_alpha.
     addition_angle = self.phi_c_alpha - initial_angle
     for i, h in enumerate(helices):
         angle = (i * (360.0 / residues_per_turn)) + addition_angle
         h.rotate(angle=angle, axis=h.axis.unit_tangent,
                  point=h.helix_start)
         helical_helix.extend(h)
     helical_helix.relabel_all()
     self._monomers = helical_helix._monomers[:]
     for monomer in self._monomers:
         monomer.ampal_parent = self
     return
Exemplo n.º 5
0
def crick_angles(p, reference_axis, tag=True, reference_axis_name='ref_axis'):
    """Returns the Crick angle for each CA atom in the `Polymer`.

    Notes
    -----
    The final value is in the returned list is `None`, since the angle
    calculation requires pairs of points on both the primitive and
    reference_axis.

    Parameters
    ----------
    p : ampal.Polymer
        Reference `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 `Polymer` with the reference axis coordinates
        and each Residue with its Crick angle. Crick angles are stored
        at the Residue level, but are calculated using the CA atom.
    reference_axis_name : str, optional
        Used to name the keys in tags at Chain and Residue level.

    Returns
    -------
    cr_angles : list(float)
        The crick angles in degrees for each CA atom of the Polymer.

    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
    p_cas = p.get_reference_coords()
    ref_points = reference_axis.coordinates
    cr_angles = [
        dihedral(ref_points[i], prim_cas[i], prim_cas[i + 1], p_cas[i])
        for i in range(len(prim_cas) - 1)
    ]
    cr_angles.append(None)

    if tag:
        p.tags[reference_axis_name] = reference_axis
        monomer_tag_name = 'crick_angle_{0}'.format(reference_axis_name)
        for m, c in zip(p._monomers, cr_angles):
            m.tags[monomer_tag_name] = c
    return cr_angles
Exemplo n.º 6
0
 def generate_complementary_strand(strand1):
     """Takes a SingleStrandHelix and creates the antisense strand."""
     rise_adjust = (
         strand1.rise_per_nucleotide * strand1.axis.unit_tangent) * 2
     strand2 = NucleicAcidStrand.from_start_and_end(
         strand1.helix_end - rise_adjust, strand1.helix_start - rise_adjust,
         generate_antisense_sequence(strand1.base_sequence),
         phos_3_prime=strand1.phos_3_prime)
     ad_ang = dihedral(strand1[0]["C1'"]._vector, strand1.axis.start,
                       strand2.axis.start + rise_adjust,
                       strand2[-1]["C1'"]._vector)
     strand2.rotate(
         225.0 + ad_ang, strand2.axis.unit_tangent,
         point=strand2.helix_start)  # 225 is the base adjust
     return strand2
Exemplo n.º 7
0
def measure_sidechain_torsion_angles(residue, verbose=True):
    """Calculates sidechain dihedral angles for a residue

    Parameters
    ----------
    residue : [ampal.Residue]
        `Residue` object.
    verbose : bool, optional
        If `true`, tells you when a residue does not have any known
        dihedral angles to measure.

    Returns
    -------
    chi_angles: [float]
        Length depends on residue type, in range [-pi, pi]

        [0] = chi1 [if applicable]
        [1] = chi2 [if applicable]
        [2] = chi3 [if applicable]
        [3] = chi4 [if applicable]
    """
    chi_angles = []
    aa = residue.mol_code
    if aa not in side_chain_dihedrals:
        if verbose:
            print("Amino acid {} has no known side-chain dihedral".format(aa))
    else:
        for set_atoms in side_chain_dihedrals[aa]:
            required_for_dihedral = set_atoms[0:4]
            try:
                angle = dihedral(residue[required_for_dihedral[0]]._vector,
                                 residue[required_for_dihedral[1]]._vector,
                                 residue[required_for_dihedral[2]]._vector,
                                 residue[required_for_dihedral[3]]._vector)
                chi_angles.append(angle)
            except KeyError as k:
                print("{0} atom missing from residue {1} {2} "
                      "- can't assign dihedral".format(k, residue.mol_code,
                                                       residue.id))
                chi_angles.append(None)
    return chi_angles
Exemplo n.º 8
0
def measure_torsion_angles(residues):
    """Calculates the dihedral angles for a list of backbone atoms.

    Parameters
    ----------
    residues : [ampal.Residue]
        List of `Residue` objects.

    Returns
    -------
    torsion_angles : (float, float, float)
        One triple for each residue, containing torsion angles in
        the range [-pi, pi].
            [0] omega
            [1] phi
            [2] psi
        For the first residue, omega and phi are not defined. For
        the final residue, psi is not defined.

    Raises
    ------
    ValueError
        If the number of input residues is less than 2.
    """
    if len(residues) < 2:
        torsion_angles = [(None, None, None)] * len(residues)
    else:
        torsion_angles = []
        for i in range(len(residues)):
            if i == 0:
                res1 = residues[i]
                res2 = residues[i + 1]
                omega = None
                phi = None
                try:
                    psi = dihedral(res1['N']._vector, res1['CA']._vector,
                                   res1['C']._vector, res2['N']._vector)
                except KeyError as k:
                    print("{0} atom missing - can't assign psi".format(k))
                    psi = None
                torsion_angles.append((omega, phi, psi))
            elif i == len(residues) - 1:
                res1 = residues[i - 1]
                res2 = residues[i]
                try:
                    omega = dihedral(res1['CA']._vector, res1['C']._vector,
                                     res2['N']._vector, res2['CA']._vector)
                except KeyError as k:
                    print("{0} atom missing - can't assign omega".format(k))
                    omega = None
                try:
                    phi = dihedral(res1['C']._vector, res2['N']._vector,
                                   res2['CA']._vector, res2['C']._vector)
                except KeyError as k:
                    print("{0} atom missing - can't assign phi".format(k))
                    phi = None
                psi = None
                torsion_angles.append((omega, phi, psi))
            else:
                res1 = residues[i - 1]
                res2 = residues[i]
                res3 = residues[i + 1]
                try:
                    omega = dihedral(res1['CA']._vector, res1['C']._vector,
                                     res2['N']._vector, res2['CA']._vector)
                except KeyError as k:
                    print("{0} atom missing - can't assign omega".format(k))
                    omega = None
                try:
                    phi = dihedral(res1['C']._vector, res2['N']._vector,
                                   res2['CA']._vector, res2['C']._vector)
                except KeyError as k:
                    print("{0} atom missing - can't assign phi".format(k))
                    phi = None
                try:
                    psi = dihedral(res2['N']._vector, res2['CA']._vector,
                                   res2['C']._vector, res3['N']._vector)
                except KeyError as k:
                    print("{0} atom missing - can't assign psi".format(k))
                    psi = None
                torsion_angles.append((omega, phi, psi))
    return torsion_angles
 def build(self):
     """Build single DNA strand along z-axis, starting with P on x-axis"""
     ang_per_res = (2 * numpy.pi) / self.nucleotides_per_turn
     atom_offset_coords = _backbone_properties[self.helix_type]['atoms']
     if self.handedness == 'l':
         handedness = -1
     else:
         handedness = 1
     base_atom_labels = _backbone_properties[self.helix_type]['labels']
     monomers = []
     mol_code_format = _backbone_properties[
         self.helix_type]['mol_code_format']
     for i, b in enumerate(self.base_sequence):
         nucleotide = Nucleotide(mol_code=mol_code_format.format(b),
                                 ampal_parent=self)
         atoms_dict = OrderedDict()
         if (i == (len(self.base_sequence) - 1)) and not self.phos_3_prime:
             # Do not include phosphate on last nucleotide
             atom_labels = base_atom_labels[3:] + [_bases[b]['labels'][2]]
             atom_offsets = {
                 k: v
                 for k, v in zip(atom_labels, atom_offset_coords[3:])
             }
         else:
             atom_labels = base_atom_labels + [_bases[b]['labels'][2]]
             atom_offsets = {
                 k: v
                 for k, v in zip(atom_labels, atom_offset_coords)
             }
         for atom_label in atom_labels:
             r, zeta, z_shift = atom_offsets[atom_label]
             rot_ang = ((i * ang_per_res) + zeta) * handedness
             z = (self.rise_per_nucleotide * i) + z_shift
             coords = cylindrical_to_cartesian(radius=r,
                                               azimuth=rot_ang,
                                               z=z,
                                               radians=True)
             atom = Atom(coordinates=coords,
                         element=atom_label[0],
                         ampal_parent=nucleotide,
                         res_label=atom_label)
             atoms_dict[atom_label] = atom
         base_ref = _bases[b]['ref_atom']
         rot_adj = _bases[b]['rot_adj']
         base_dict = OrderedDict(
             zip(_bases[b]['labels'], _bases[b]['atoms']))
         translation, angle, axis, point = find_transformations(
             base_dict[base_ref], base_dict["C1'"],
             atoms_dict[base_ref]._vector, atoms_dict["C1'"]._vector)
         q1 = Quaternion.angle_and_axis(angle, axis)
         # Align N9 C1'
         for k, v in base_dict.items():
             base_dict[k] = q1.rotate_vector(v, point) + translation
         # Rotate to align O4'
         axis = numpy.array(base_dict["C1'"]) - base_dict[base_ref]
         angle = dihedral(base_dict["O4'"], base_dict[base_ref],
                          base_dict["C1'"], atoms_dict["O4'"]) - rot_adj
         q2 = Quaternion.angle_and_axis(angle, axis)
         for k, v in list(base_dict.items()):
             if k not in atoms_dict:
                 atom = Atom(q2.rotate_vector(v, base_dict[base_ref]),
                             element=k[0],
                             ampal_parent=nucleotide,
                             res_label=k)
                 atoms_dict[k] = atom
         nucleotide.atoms = atoms_dict
         monomers.append(nucleotide)
     self._monomers = monomers
     self.relabel_monomers()
     self.relabel_atoms()
     return