Example #1
0
 def _straight_initial(self):
     from numpy import mean, dot, newaxis
     from numpy.linalg import norm
     if len(self.coords) > len(self.IDEAL_COORDS):
         # "Normal" helices can be approximated by using all
         # coordinates on the assumption that the helix length
         # is sufficiently larger than the helix radius that
         # the biggest eigenvector will be the helical axis
         from numpy.linalg import svd
         from numpy import argmax
         centroid = mean(self.coords, axis=0)
         rel_coords = self.coords - centroid
         ignore, vals, vecs = svd(rel_coords)
         axis = vecs[argmax(vals)]
     else:
         from chimerax.geometry import align_points
         num_pts = len(self.coords)
         tf, rmsd = align_points(self.IDEAL_COORDS[:num_pts], self.coords)
         centroid = tf * self.IDEAL_PARAMS[0]
         axis = tf.transform_vector(self.IDEAL_PARAMS[1])
         rel_coords = self.coords - centroid
     axis_pos = dot(rel_coords, axis)[:, newaxis]
     radial_vecs = rel_coords - axis * axis_pos
     radius = mean(norm(radial_vecs, axis=1))
     return centroid, axis, radius
Example #2
0
def make_fmet_from_met(session, residue):
    err_string = "make_fmet_from_met() is only applicable to N-terminal methionine residues!"
    if residue.name != 'MET':
        raise TypeError(err_string)
    n = residue.find_atom('N')
    if n is None:
        raise TypeError('Missing N atom! Is your residue complete?')
    for nb in n.neighbors:
        if nb.residue != residue:
            raise TypeError(err_string)
        if nb.element.name == 'H':
            nb.delete()
    from chimerax.mmcif import find_template_residue
    import numpy
    fme = find_template_residue(session, 'FME')
    ref_atoms = ('C', 'CA', 'N')
    r_coords = numpy.array([residue.find_atom(a).coord for a in ref_atoms])
    t_coords = numpy.array([fme.find_atom(a).coord for a in ref_atoms])
    from chimerax.geometry import align_points
    tf, rms = align_points(t_coords, r_coords)
    from chimerax.atomic.struct_edit import add_atom
    atom_pairs = (('N', 'H'), ('N', 'CN'), ('CN', 'O1'), ('CN', 'HCN'))
    for (bname, aname) in atom_pairs:
        ta = fme.find_atom(aname)
        add_atom(aname,
                 ta.element,
                 residue,
                 tf * ta.coord,
                 bonded_to=residue.find_atom(bname))
    residue.name = 'FME'
Example #3
0
def align_and_prune(xyz, ref_xyz, cutoff_distance, indices=None):

    import numpy
    if indices is None:
        indices = numpy.arange(len(xyz))
    axyz, ref_axyz = xyz[indices], ref_xyz[indices]
    from chimerax.geometry import align_points
    p, rms = align_points(axyz, ref_axyz)
    dxyz = p * axyz - ref_axyz
    d2 = (dxyz * dxyz).sum(axis=1)
    cutoff2 = cutoff_distance * cutoff_distance
    i = d2.argsort()
    if d2[i[-1]] <= cutoff2:
        return p, rms, indices

    # cull 10% or...
    index1 = int(len(d2) * 0.9)
    # cull half the long pairings
    index2 = int(((d2 <= cutoff2).sum() + len(d2)) / 2)
    # whichever is fewer
    index = max(index1, index2)
    survivors = indices[i[:index]]

    if len(survivors) < 3:
        raise IterationError(
            "Alignment failed;"
            " pruning distances > %g left less than 3 atom pairs" %
            cutoff_distance)
    return align_and_prune(xyz, ref_xyz, cutoff_distance, survivors)
Example #4
0
def minimize_link_lengths(mols, pbonds, iterations, frames, session):
    if len(mols) == 0:
        from chimerax.core.errors import UserError
        raise UserError('No structures specified for minimizing crosslinks.')
    mol_links, mol_pbonds = links_by_molecule(pbonds, mols)
    if len(mol_links) == 0:
        from chimerax.core.errors import UserError
        raise UserError('No pseudobonds between molecules.')
    if len(mols) == 1:
        iterations = min(1, iterations)
    if not frames is None:
        pos0 = dict((m, m.position) for m in mols)
    from numpy import array, float64
    from chimerax.geometry import align_points
    for i in range(iterations):
        for m in mols:
            if m in mol_links:
                atom_pairs = mol_links[m]
                moving = array([a1.scene_coord for a1, a2 in atom_pairs],
                               float64)
                fixed = array([a2.scene_coord for a1, a2 in atom_pairs],
                              float64)
                tf, rms = align_points(moving, fixed)
                m.position = tf * m.position

    lengths = [pb.length for pb in mol_pbonds]
    lengths.sort(reverse=True)
    lentext = ', '.join('%.1f' % d for d in lengths)
    session.logger.info('%d crosslinks, lengths: %s' %
                        (len(mol_pbonds), lentext))

    if not frames is None:
        for m in mols:
            interpolate_position(m, pos0[m], m.position, frames,
                                 session.triggers)
Example #5
0
def align_atoms(patoms, pto_atoms, xyz_to, cutoff_distance, atoms, to_atoms,
                move, log, report_matrix):

    xyz_from = patoms.scene_coords
    if cutoff_distance is None:
        from chimerax.geometry import align_points
        tf, rmsd = align_points(xyz_from, xyz_to)
        full_rmsd = rmsd
        matched_patoms, matched_pto_atoms = patoms, pto_atoms
        msg = 'RMSD between %d atom pairs is %.3f angstroms' % (len(patoms),
                                                                rmsd)
    else:
        if cutoff_distance <= 0.0:
            raise UserError("Distance cutoff must be positive")
        tf, rmsd, indices = align_and_prune(xyz_from, xyz_to, cutoff_distance)
        np = len(indices)
        dxyz = tf * xyz_from - xyz_to
        d2 = (dxyz * dxyz).sum(axis=1)
        import math
        full_rmsd = math.sqrt(d2.sum() / len(d2))
        matched_patoms, matched_pto_atoms = patoms[indices], pto_atoms[indices]
        msg = 'RMSD between %d pruned atom pairs is %.3f angstroms;' \
            ' (across all %d pairs: %.3f)' % (np, rmsd, len(patoms), full_rmsd)

    if report_matrix:
        log.info(matrix_text(tf, atoms, to_atoms))

    log.status(msg)
    log.info(msg)

    move_atoms(atoms, to_atoms, tf, move)

    return matched_patoms, matched_pto_atoms, rmsd, full_rmsd, tf
Example #6
0
def show_residue_fit(session, residues, map, range = 2, last_pos = None, motion_frames = 20):
    '''Set camera to show first residue in list and display map in zone around given residues.'''
    res = residues[0]
    ratoms = res.atoms
    anames = tuple(ratoms.names)
    try:
        i = [anames.index(aname) for aname in ('N', 'CA', 'C')]
    except ValueError:
        return None		# Missing backbone atom
    xyz = ratoms.filter(i).scene_coords

    # Align backbone to template backbone coords
    from chimerax.geometry import align_points, Place
    from numpy import array
    txyz = array([[ 12.83300018,   6.83900023,   6.73799992],
                  [ 12.80800056,   7.87400055,   5.70799971],
                  [ 11.91800022,   9.06700039,   5.9920001 ]])
    p, rms = align_points(txyz, xyz)

    # Set camera view relative to template.
    c = session.main_view.camera
    cp = c.position
    if last_pos is None:
        tc = Place(((-0.46696,0.38225,-0.79739,-3.9125),
                    (0.81905,-0.15294,-0.55296,-4.3407),
                    (-0.33332,-0.91132,-0.24166,-1.4889)))
        if c.name == 'orthographic':
            c.field_width = 12		# Set orthographic field of view, Angstroms
    else:
        # Maintain same relative camera position to backbone.
        tc = last_pos.inverse() * cp

    # Smooth interpolation
    np = p*tc
    if motion_frames > 1:
        def interpolate_camera(session, f, cp=cp, np=np, center=np.inverse()*xyz[1], frames=motion_frames):
            c = session.main_view.camera
            p = np if f+1 == frames else cp.interpolate(np, center, frac = (f+1)/frames)
            c.position = p
        from chimerax.core.commands import motion
        motion.CallForNFrames(interpolate_camera, motion_frames, session)
    else:
        c.position = np

    from numpy import concatenate
    zone_points = concatenate([r.atoms.scene_coords for r in residues])
    from chimerax.surface import zone
    for s in map.surfaces:
        zone.surface_zone(s, zone_points, range, auto_update = True)

    for r in residues:
        r.atoms.displays = True
    
    return p
Example #7
0
    def steady_transform(self, cset):

        tfc = self._steady_transforms
        if cset in tfc:
            return tfc[cset]
        atoms = self.steady_atoms
        coords = coordset_coords(atoms, cset, self.structure)
        if self._steady_coords is None:
            self._steady_coords = coords
        from chimerax.geometry import align_points
        tf = align_points(coords, self._steady_coords)[0]
        tfc[cset] = tf
        return tf
Example #8
0
 def _orient(self):
     gc = []
     la = []
     for g, (x, y) in zip(self.groups, self._layout_positions):
         if g.shown():
             gc.append(g.centroid())
             la.append((x, y, 0))
     if len(gc) < 2:
         return
     from chimerax.geometry import align_points, translation
     from numpy import array, mean
     p, rms = align_points(array(gc), array(la))
     ra = p.zero_translation()
     center = mean(gc, axis=0)
     v = self._session().main_view
     rc = v.camera.position.zero_translation()
     rot = translation(center) * rc * ra * translation(-center)
     v.move(rot)
Example #9
0
def ncs_average_map(session, asu_map, full_map, reference_chain, ncs_chains):
    from chimerax.match_maker.match import (
        defaults, align
        )
    grid_points = asu_map.grid_points(asu_map.model_transform().inverse())
    from chimerax.atomic import Residues, Atoms
    interpolated_maps = []
    interpolated_maps.append(asu_map.data.matrix())
    original_map_position = full_map.position
    dssp_cache={}
    for ncs in ncs_chains:
        score, s1, s2 = align(session, ncs, reference_chain, defaults['matrix'],
            'nw', defaults['gap_open'], defaults['gap_extend'], dssp_cache)
        ref_residues = []
        ncs_residues = []
        for i, (mr, rr) in enumerate(zip(s1, s2)):
            if mr=='.' or rr=='.':
                continue
            ref_res = s1.residues[s1.gapped_to_ungapped(i)]
            match_res = s2.residues[s2.gapped_to_ungapped(i)]
            if not ref_res or not match_res:
                continue
            ref_residues.append(ref_res)
            ncs_residues.append(match_res)
        ref_residues = Residues(ref_residues)
        ncs_residues = Residues(ncs_residues)

        (ref_pa, ncs_pa) = paired_principal_atoms([ref_residues, ncs_residues])

        from chimerax.geometry import align_points
        tf, rms = align_points(ncs_pa.coords, ref_pa.coords)
        #full_map.position = tf * full_map.position
        from chimerax.core.commands import run
        #run(session, "fitmap #{} in #{}".format(full_map.id_string, asu_map.id_string))
        interpolated_maps.append(
            full_map.interpolated_values(grid_points, point_xform=tf.inverse()).reshape(asu_map.data.size))
        #full_map.position = original_map_position

    asu_map.data.matrix()[:] = sum(interpolated_maps)/len(interpolated_maps)
    asu_map.data.values_changed()
Example #10
0
def build_next_atom_from_coords(residue, found_neighbors, template_new_atom):
    # print('Building next atom {} from aligned coords of {}'.format(template_new_atom.name,
    #     ','.join([f[0].name for f in found_neighbors])))
    bonded_to = [f[0] for f in found_neighbors]
    m = residue.structure
    n = len(found_neighbors)
    found = set(f[0] for f in found_neighbors)
    while len(found_neighbors) < 3:
        for ra, ta in found_neighbors:
            for tn in ta.neighbors:
                rn = residue.find_atom(tn.name)
                if rn and rn not in found:
                    found_neighbors.append((rn, tn))
                    found.add(rn)
        if len(found_neighbors) <= n:
            residue.session.logger.warning(
                "Couldn't find more than two neighbor atoms. Falling back to simple geometry-based addition."
            )
            return build_next_atom_from_geometry(residue, *found_neighbors[0],
                                                 template_new_atom)
        n = len(found_neighbors)
    from chimerax.geometry import align_points
    import numpy
    ra_coords = numpy.array([f[0].coord for f in found_neighbors])
    ta_coords = numpy.array([f[1].coord for f in found_neighbors])
    bfactor = numpy.mean([f[0].bfactor for f in found_neighbors])
    occupancy = numpy.mean([f[0].occupancy for f in found_neighbors])
    tf, rms = align_points(ta_coords, ra_coords)
    from chimerax.atomic.struct_edit import add_atom
    ta = template_new_atom
    a = add_atom(ta.name,
                 ta.element,
                 residue,
                 tf * ta.coord,
                 occupancy=occupancy,
                 bfactor=bfactor)
    from chimerax.atomic.struct_edit import add_bond
    for b in bonded_to:
        add_bond(a, b)
Example #11
0
def optimized_placement(polygon, vertex_degree):

    lpairs = []
    for l0 in polygon.edges:
        l0j = joined_edge(l0)
        if l0j:
            lpairs.append((l0, l0j))

    from chimerax.geometry import Place, align_points
    if len(lpairs) == 0:
        tf = Place()
    elif len(lpairs) == 1:
        l0, l1 = lpairs[0]
        tf = edge_join_transform(l0, l1, vertex_degree)
    else:
        xyz0 = []
        xyz1 = []
        for l0, l1 in lpairs:
            xyz0.extend(edge_alignment_points(l0))
            xyz1.extend(reversed(edge_alignment_points(l1)))
        from numpy import array
        tf, rms = align_points(array(xyz0), array(xyz1))
    return tf
Example #12
0
 def __init__(self, residue_groups, method, coordset0, coordset1):
         # Get transform for each rigid segment
         t0 = time()
         calc_motion_parameters = segment_motion_methods[method]
         self.motion_parameters = motion_params = []
         self.motion_transforms = motion_transforms = []
         from .util import segment_alignment_atoms
         from chimerax.geometry import align_points
         from chimerax.atomic import Atoms
         for rList in residue_groups:
                 aatoms = Atoms(segment_alignment_atoms(rList))
                 raindices = aatoms.coord_indices
                 cList0 = coordset0[raindices]
                 c0 = cList0.mean(axis = 0)
                 cList1 = coordset1[raindices]
                 c1 = cList1.mean(axis = 0)
                 xform, rmsd = align_points(cList0, cList1)
                 atom_indices = rList.atoms.coord_indices
                 motion_transforms.append((atom_indices, xform))
                 axis, angle, center, shift = calc_motion_parameters(xform, c0, c1)
                 motion_params.append((atom_indices, axis, angle, center, shift))
         t1 = time()
         global stt
         stt += t1-t0
Example #13
0
def template_swap_res(res, res_type, *, preserve=False, bfactor=None):
    """change 'res' into type 'res_type'"""

    fixed, buds, start, end = get_res_info(res)

    if res_type == "HIS":
        res_type = "HIP"
    if res_type in ["A", "C", "G", "T"
                    ] and res.name in ["DA", "DC", "DT", "DG"]:
        res_type = "D" + res_type
    from chimerax.atomic import TmplResidue, Atom
    tmpl_res = TmplResidue.get_template(res_type, start=start, end=end)
    if not tmpl_res:
        raise TemplateError("No connectivity template for residue '%s'" %
                            res_type)
    # sanity check:  does the template have the bud atoms?
    for bud in buds:
        if tmpl_res.find_atom(bud) is None:
            raise TemplateError("New residue type (%s) not compatible with"
                                " starting residue type (%s)" %
                                (res_type, res.name))
    color_by_element = False
    uniform_color = res.find_atom(buds[0]).color
    het = res.find_atom("N") or res.find_atom("O4'")
    if het:
        carbon = res.find_atom("CA") or res.find_atom("C4'")
        if carbon:
            color_by_element = het.color != carbon.color
            if color_by_element:
                carbon_color = carbon.color
            else:
                uniform_color = het.color

    bfactor = bfactor_for_res(res, bfactor)

    if preserve:
        if "CA" in fixed and res_type not in ['GLY', 'ALA']:
            raise TemplateSwapError(
                "'preserve' keyword not yet implemented for amino acids")
        a1 = res.find_atom("O4'")
        a2 = res.find_atom("C1'")
        if not a1 or not a2:
            preserve_pos = None
        else:
            dihed_names = {"N9": ["C4", "C8"], "N1": ["C2", "C6"]}
            a3 = res.find_atom("N9") or res.find_atom("N1")
            if a3:
                if a2 not in a3.neighbors:
                    preserve_pos = None
                else:
                    preserve_pos = a3.coord
            else:
                preserve_pos = None
        if preserve_pos:
            p1, p2, p3 = [a.coord for a in (a1, a2, a3)]
            preserved_pos = False
            prev_name, alt_name = dihed_names[a3.name]
            a4 = res.find_atom(prev_name)
            if a4 and a3 in a4.neighbors:
                p4 = a4.coord
                from chimerax.geometry import dihedral
                preserve_dihed = dihedral(p1, p2, p3, p4)
            else:
                preserve_dihed = None
        else:
            preserve_dihed = None

    # prune non-backbone atoms
    for a in res.atoms:
        if a.name not in fixed:
            a.structure.delete_atom(a)

    # add new sidechain
    new_atoms = []
    xf = None
    from chimerax.atomic.struct_edit import add_bond
    while len(buds) > 0:
        bud = buds.pop()
        tmpl_bud = tmpl_res.find_atom(bud)
        res_bud = res.find_atom(bud)

        try:
            info = Atom.idatm_info_map[tmpl_bud.idatm_type]
            geom = info.geometry
            subs = info.substituents
        except KeyError:
            raise AssertionError(
                "Can't determine atom type information for atom %s of residue %s"
                % (bud, res))

        # use .coord rather than .scene_coord:  we want to set the new atom's coord,
        # to which the proper xform will then be applied
        for a, b in zip(tmpl_bud.neighbors, tmpl_bud.bonds):
            if a.element.number == 1:
                # don't add hydrogens
                continue
            if res.find_atom(a.name):
                res_bonder = res.find_atom(a.name)
                if res_bonder not in res_bud.neighbors:
                    add_bond(a, res_bonder)
                continue

            new_atom = None
            num_bonded = len(res_bud.bonds)
            if num_bonded >= subs:
                raise AssertionError(
                    "Too many atoms bonded to %s of residue %s" % (bud, res))
            if num_bonded == 0:
                raise AssertionError(
                    "Atom %s of residue %s has no neighbors after pruning?!?" %
                    (bud, res))
            # since fused ring systems may have distorted bond angles, always use dihedral placement
            real1 = res_bud.neighbors[0]
            kw = {}
            if preserve:
                if preserve_pos and not preserved_pos:
                    kw['pos'] = preserve_pos
                    preserved_pos = True
                    preserved_name = a.name
                elif preserve_dihed is not None:
                    prev_name, alt_name = dihed_names[preserved_name]
                    if a.name == prev_name:
                        kw['dihed'] = preserve_dihed
                    elif a.name == alt_name:
                        kw['dihed'] = preserve_dihed + 180.0
            if not kw and xf is not None:
                kw['pos'] = xf * a.coord

            new_atom = form_dihedral(res_bud, real1, tmpl_res, a, b, **kw)
            new_atom.draw_mode = res_bud.draw_mode
            new_atom.bfactor = bfactor
            if color_by_element:
                if new_atom.element.name == "C":
                    new_atom.color = carbon_color
                else:
                    from chimerax.atomic.colors import element_color
                    new_atom.color = element_color(new_atom.element.number)
            else:
                new_atom.color = uniform_color
            new_atoms.append(new_atom)

            for bonded in a.neighbors:
                bond_atom = res.find_atom(bonded.name)
                if not bond_atom:
                    continue
                add_bond(new_atom, bond_atom)
            buds.append(new_atom.name)

        # once we've placed 3 side chain atoms, we use superpositioning to
        # place the remainder of the side chain, since dihedrals will
        # likely distort ring closures if 'preserve' is true
        if buds and not xf and len(new_atoms) >= 3:
            placed_positions = []
            tmpl_positions = []
            for na in new_atoms:
                placed_positions.append(na.coord)
                tmpl_positions.append(tmpl_res.find_atom(na.name).coord)
            import numpy
            from chimerax.geometry import align_points
            xf = align_points(numpy.array(tmpl_positions),
                              numpy.array(placed_positions))[0]

    res.name = res_type
Example #14
0
def get_rotamers(session,
                 res,
                 phi=None,
                 psi=None,
                 cis=False,
                 res_type=None,
                 rot_lib="Dunbrack",
                 log=False):
    """Takes a Residue instance and optionally phi/psi angles (if different from the Residue), residue
       type (e.g. "TYR"), and/or rotamer library name.  Returns a list of AtomicStructure instances (sublass of
       AtomicStructure).  The AtomicStructure are each a single residue (a rotamer) and are in descending
       probability order.  Each has an attribute "rotamer_prob" for the probability and "chis" for the
       chi angles.
    """
    res_type = res_type or res.name
    if res_type == "ALA" or res_type == "GLY":
        raise NoResidueRotamersError("No rotamers for %s" % res_type)

    if not isinstance(rot_lib, RotamerLibrary):
        rot_lib = session.rotamers.library(rot_lib)

    # check that the residue has the n/c/ca atoms needed to position the rotamer
    # and to ensure that it is an amino acid
    from chimerax.atomic import Residue
    match_atoms = {}
    for bb_name in Residue.aa_min_backbone_names:
        match_atoms[bb_name] = a = res.find_atom(bb_name)
        if a is None:
            raise LimitationError("%s missing from %s; needed to position CB" %
                                  (bb_name, res))
    match_atoms["CB"] = res.find_atom("CB")
    if not phi and not psi:
        phi, psi = res.phi, res.psi
        omega = res.omega
        cis = False if omega is None or abs(omega) > 90 else True
        if log:

            def _info(ang):
                if ang is None:
                    return "none"
                return "%.1f" % ang

            if match_atoms["CA"].alt_locs:
                al_info = " (alt loc %s)" % match_atoms["CA"].alt_loc
            else:
                al_info = ""
            session.logger.info("%s%s: phi %s, psi %s %s" %
                                (res, al_info, _info(phi), _info(psi),
                                 "cis" if cis else "trans"))
    session.logger.status("Retrieving rotamers from %s library" %
                          rot_lib.display_name)
    res_template_func = rot_lib.res_template_func
    params = rot_lib.rotamer_params(res_type, phi, psi, cis=cis)
    session.logger.status("Rotamers retrieved from %s library" %
                          rot_lib.display_name)

    mapped_res_type = rot_lib.res_name_mapping.get(res_type, res_type)
    template = rot_lib.res_template_func(mapped_res_type)
    tmpl_N = template.find_atom("N")
    tmpl_CA = template.find_atom("CA")
    tmpl_C = template.find_atom("C")
    tmpl_CB = template.find_atom("CB")
    if match_atoms['CB']:
        res_match_atoms, tmpl_match_atoms = [
            match_atoms[x] for x in ("C", "CA", "CB")
        ], [tmpl_C, tmpl_CA, tmpl_CB]
    else:
        res_match_atoms, tmpl_match_atoms = [
            match_atoms[x] for x in ("N", "CA", "C")
        ], [tmpl_N, tmpl_CA, tmpl_C]
    from chimerax.geometry import align_points
    from numpy import array
    xform, rmsd = align_points(array([fa.coord for fa in tmpl_match_atoms]),
                               array([ta.coord for ta in res_match_atoms]))
    n_coord = xform * tmpl_N.coord
    ca_coord = xform * tmpl_CA.coord
    cb_coord = xform * tmpl_CB.coord
    info = Residue.chi_info[mapped_res_type]
    bond_cache = {}
    angle_cache = {}
    from chimerax.atomic.struct_edit import add_atom, add_dihedral_atom, add_bond
    structs = []
    middles = {}
    ends = {}
    for i, rp in enumerate(params):
        s = AtomicStructure(session, name="rotamer %d" % (i + 1))
        structs.append(s)
        r = s.new_residue(mapped_res_type, 'A', 1)
        registerer = "swap_res get_rotamers"
        AtomicStructure.register_attr(session,
                                      "rotamer_prob",
                                      registerer,
                                      attr_type=float)
        s.rotamer_prob = rp.p
        AtomicStructure.register_attr(session, "chis", registerer)
        s.chis = rp.chis
        rot_N = add_atom("N", tmpl_N.element, r, n_coord)
        rot_CA = add_atom("CA", tmpl_CA.element, r, ca_coord, bonded_to=rot_N)
        rot_CB = add_atom("CB", tmpl_CB.element, r, cb_coord, bonded_to=rot_CA)
        todo = []
        for j, chi in enumerate(rp.chis):
            n3, n2, n1, new = info[j]
            b_len, angle = _len_angle(new, n1, n2, template, bond_cache,
                                      angle_cache)
            n3 = r.find_atom(n3)
            n2 = r.find_atom(n2)
            n1 = r.find_atom(n1)
            new = template.find_atom(new)
            a = add_dihedral_atom(new.name,
                                  new.element,
                                  n1,
                                  n2,
                                  n3,
                                  b_len,
                                  angle,
                                  chi,
                                  bonded=True)
            todo.append(a)
            middles[n1] = [a, n1, n2]
            ends[a] = [a, n1, n2]

        # if there are any heavy non-backbone atoms bonded to template
        # N and they haven't been added by the above (which is the
        # case for Richardson proline parameters) place them now
        for tnnb in tmpl_N.neighbors:
            if r.find_atom(tnnb.name) or tnnb.element.number == 1:
                continue
            tnnb_coord = xform * tnnb.coord
            add_atom(tnnb.name, tnnb.element, r, tnnb_coord, bonded_to=rot_N)

        # fill out bonds and remaining heavy atoms
        from chimerax.geometry import distance, align_points
        done = set([rot_N, rot_CA])
        while todo:
            a = todo.pop(0)
            if a in done:
                continue
            tmpl_A = template.find_atom(a.name)
            for bonded, bond in zip(tmpl_A.neighbors, tmpl_A.bonds):
                if bonded.element.number == 1:
                    continue
                rbonded = r.find_atom(bonded.name)
                if rbonded is None:
                    # use middles if possible...
                    try:
                        p1, p2, p3 = middles[a]
                        conn = p3
                    except KeyError:
                        p1, p2, p3 = ends[a]
                        conn = p2
                    t1 = template.find_atom(p1.name)
                    t2 = template.find_atom(p2.name)
                    t3 = template.find_atom(p3.name)
                    xform = align_points(
                        array([t.coord for t in [t1, t2, t3]]),
                        array([p.coord for p in [p1, p2, p3]]))[0]
                    pos = xform * template.find_atom(bonded.name).coord
                    rbonded = add_atom(bonded.name,
                                       bonded.element,
                                       r,
                                       pos,
                                       bonded_to=a)
                    middles[a] = [rbonded, a, conn]
                    ends[rbonded] = [rbonded, a, conn]
                if a not in rbonded.neighbors:
                    add_bond(a, rbonded)
                if rbonded not in done:
                    todo.append(rbonded)
            done.add(a)
    return structs
Example #15
0
def add_amino_acid_residue(model,
                           resname,
                           prev_res=None,
                           next_res=None,
                           chain_id=None,
                           number=None,
                           center=None,
                           insertion_code=' ',
                           add_b_factor=0,
                           occupancy=1,
                           phi=-135,
                           psi=135):
    session = model.session
    if (not chain_id or not number or center is None) and (not prev_res
                                                           and not next_res):
        raise TypeError('If no anchor residues are specified, chain ID, '
                        'number and center must be provided!')
    if prev_res and next_res:
        raise TypeError('Cannot specify both previous and next residues!')
    other_atom = None
    insertion_point = None
    import numpy
    if prev_res:
        ref_res = prev_res
        b_factor = prev_res.atoms[numpy.in1d(
            prev_res.atoms.names,
            ('N', 'CA', 'C', 'O', 'CB'))].bfactors.mean() + add_b_factor
        pri = model.residues.index(prev_res)
        if pri > 0 and pri < len(model.residues) - 1:
            insertion_point = model.residues[pri + 1]
        catom = prev_res.find_atom('C')
        for n in catom.neighbors:
            if n.residue != prev_res:
                raise TypeError(
                    'This residue already has another bonded to its '
                    'C terminus!')
        if chain_id is not None:
            session.logger.warning(
                'AddAA: chain_id argument is ignored when adding to an existing residue.'
            )
        chain_id = prev_res.chain_id
        oxt = prev_res.find_atom('OXT')
        if oxt is not None:
            oxt.delete()
    elif next_res:
        ref_res = next_res
        b_factor = next_res.atoms[numpy.in1d(
            next_res.atoms.names,
            ('N', 'CA', 'C', 'O', 'CB'))].bfactors.mean() + add_b_factor
        insertion_point = next_res
        natom = next_res.find_atom('N')
        for n in natom.neighbors:
            if n.residue != next_res:
                raise TypeError(
                    'This residue already has another bonded to its '
                    'N terminus!')
        if chain_id is not None:
            session.logger.warning(
                'AddAA: chain_id argument is ignored when adding to an existing residue.'
            )
        chain_id = next_res.chain_id
        for hname in ('H2', 'H3'):
            h = next_res.find_atom(hname)
            if h is not None:
                h.delete()
            h = next_res.find_atom('H1')
            if h is not None:
                h.name = 'H'
            if next_res.name == 'PRO':
                h = next_res.find_atom('H')
                if h:
                    h.delete()
    if number is None:
        if prev_res:
            number = prev_res.number + 1
        elif next_res:
            number = next_res.number - 1

    from chimerax import mmcif
    tmpl = mmcif.find_template_residue(session, resname)
    from .place_ligand import new_residue_from_template
    import numpy
    # delete extraneous atoms
    r = new_residue_from_template(model,
                                  tmpl,
                                  chain_id, [0, 0, 0],
                                  number,
                                  insert_code=insertion_code,
                                  b_factor=b_factor,
                                  precedes=insertion_point)
    r.atoms[numpy.in1d(r.atoms.names,
                       ['OXT', 'HXT', 'H2', 'H1', 'HN1', 'HN2'])].delete()

    # Translate and rotate residue to (roughly) match the desired position
    if not next_res and not prev_res:
        r.atoms.coords += numpy.array(center) - r.atoms.coords.mean(axis=0)
        b_factor = max(add_b_factor, 5)
    else:
        from chimerax.geometry import align_points
        from chimerax.atomic.struct_edit import add_bond
        if prev_res:
            correct_o_position(prev_res, psi)
            add_bond(r.find_atom('N'), prev_res.find_atom('C'))
            n_pos = _find_next_N_position(prev_res)
            ca_pos = _find_next_CA_position(n_pos, prev_res)
            c_pos = _find_next_C_position(ca_pos, n_pos, prev_res, phi)
            target_coords = numpy.array([n_pos, ca_pos, c_pos])
            align_coords = numpy.array(
                [r.find_atom(a).coord for a in ['N', 'CA', 'C']])
        elif next_res:
            add_bond(r.find_atom('C'), next_res.find_atom('N'))
            c_pos = _find_prev_C_position(next_res, psi)
            ca_pos = _find_prev_CA_position(c_pos, next_res)
            #o_pos = _find_prev_O_position(c_pos, next_res)
            n_pos = _find_prev_N_position(c_pos, ca_pos, next_res, psi)
            target_coords = numpy.array([c_pos, ca_pos, n_pos])
            align_coords = numpy.array(
                [r.find_atom(a).coord for a in ['C', 'CA', 'N']])

        tf = align_points(align_coords, target_coords)[0]
        r.atoms.coords = tf * r.atoms.coords
        correct_o_position(r, psi)
    if r.name in ('GLU', 'ASP'):
        fix_amino_acid_protonation_state(r)
    if r.name == 'PRO':
        r.atoms[r.atoms.names == 'H'].delete()

    r.atoms.bfactors = b_factor
    r.atoms.occupancies = occupancy

    from . import copy_atom_style_from
    copy_atom_style_from(session, r.atoms, ref_res)
    model.atoms.selecteds = False
    r.atoms.selecteds = True
    return r
Example #16
0
    def _new_camera_position(self, residue, block_spotlight=True):
        session = self.session
        r = residue
        from chimerax.atomic import Residue, Atoms
        pt = residue.polymer_type
        if pt == Residue.PT_NONE:
            # No preferred orientation
            ref_coords = None
            target_coords = r.atoms.coords
            centroid = target_coords.mean(axis=0)
        elif pt == Residue.PT_AMINO:
            ref_coords = self.peptide_ref_coords
            try:
                target_coords = Atoms(
                    [r.find_atom(name) for name in ('N', 'CA', 'C')]).coords
                centroid = target_coords[1]
            except ValueError:
                # Either a key atom is missing, or this is a special residue
                # e.g. NH2
                ref_coords = None
                target_coords = r.atoms.coords
                centroid = target_coords.mean(axis=0)
        elif pt == Residue.PT_NUCLEIC:
            ref_coords = self.nucleic_ref_coords
            try:
                target_coords = Atoms([
                    r.find_atom(name) for name in ("C2'", "C1'", "O4'")
                ]).coords
                centroid = target_coords[1]
            except ValueError:
                ref_coords = None
                target_coords = r.atoms.coords
                centroid = target_coords.mean(axis=0)

        c = session.main_view.camera
        cp = c.position
        old_cofr = session.main_view.center_of_rotation

        if ref_coords is not None:
            from chimerax.geometry import align_points, Place
            p, rms = align_points(ref_coords, target_coords)
        else:
            from chimerax.geometry import Place
            p = Place(origin=centroid)

        tc = self._camera_ref_pos(self.view_distance)
        np = p * tc
        new_cofr = centroid
        if c.name == 'orthographic':
            fw = c.field_width
        new_fw = self._view_distance * 2

        def interpolate_camera(session,
                               f,
                               cp=cp,
                               np=np,
                               oc=old_cofr,
                               nc=new_cofr,
                               fw=fw,
                               nfw=new_fw,
                               vr=self._view_distance,
                               center=np.inverse() * centroid,
                               frames=self._interpolate_frames):
            frac = (f + 1) / frames
            v = session.main_view
            c = v.camera
            p = np if f + 1 == frames else cp.interpolate(
                np, center, frac=frac)
            cofr = oc + frac * (nc - oc)
            c.position = p
            vd = c.view_direction()
            cp = v.clip_planes
            ncm, fcm = _get_clip_distances(session)
            cp.set_clip_position('near', cofr - ncm * vr * vd, v)
            cp.set_clip_position('far', cofr + fcm * vr * vd, v)
            if c.name == 'orthographic':
                c.field_width = fw + frac * (nfw - fw)

        from chimerax.geometry import distance
        if distance(new_cofr, old_cofr) < self._view_distance:
            if block_spotlight:
                self._block_clipper_spotlights()
                from .delayed_reaction import call_after_n_events
                call_after_n_events(self.session.triggers, 'frame drawn',
                                    self._interpolate_frames,
                                    self._release_clipper_spotlights, [])
            from chimerax.core.commands import motion
            motion.CallForNFrames(interpolate_camera, self._interpolate_frames,
                                  session)
        else:
            interpolate_camera(session, 0, frames=1)