def create_box(self):

        m = chimera.Molecule()
        m.name = 'Subregion Selection Box'
        chimera.openModels.add([m], noprefs=True)
        chimera.addModelClosedCallback(m, self.model_closed_cb)

        rid = chimera.MolResId(1)
        r = m.newResidue('markers', rid)

        corners = []
        for name in ('a000', 'a001', 'a010', 'a011', 'a100', 'a101', 'a110',
                     'a111'):
            a = m.newAtom(name, chimera.elements.H)
            r.addAtom(a)
            corners.append(a)

        green = chimera.MaterialColor(0, 1, 0, 1)
        for a1, a2 in ((0, 1), (2, 3), (4, 5), (6, 7), (0, 2), (1, 3), (4, 6),
                       (5, 7), (0, 4), (1, 5), (2, 6), (3, 7)):
            b = m.newBond(corners[a1], corners[a2])
            b.halfbond = 0
            b.drawMode = chimera.Bond.Wire
            b.color = green

        return corners
Exemple #2
0
 def __init__(self, ensemble):
     self._ensemble = ensemble
     if hasattr(ensemble, 'molecule'):
         self._mol = ensemble.molecule
     else:
         self._mol = chimera.Molecule()
         self._mol.name = ensemble.name
Exemple #3
0
    def make_model(self, length, thickness, rgb, label, xy_offset, label_rgb,
                   model_id):

        m = chimera.Molecule()
        m.name = 'scale bar'

        #
        # Need to create a residue because atom without residue causes
        # unknown C++ exceptions.
        #
        rid = chimera.MolResId(1)
        r = m.newResidue('sb', rid)

        atoms = []
        for name, pos in (('1', (-length / 2.0, 0, 0)), ('2', (length / 2.0, 0,
                                                               0)),
                          ('label', (xy_offset[0],
                                     xy_offset[1] + thickness / 2.0, 0))):
            a = m.newAtom(name, chimera.elements.H)
            r.addAtom(a)
            c = chimera.Coord()
            c.x, c.y, c.z = pos
            a.setCoord(c)  # a.coord = c does not work
            a.display = 0
            atoms.append(a)
        m.atom1, m.atom2, m.label_atom = atoms
        m.label_atom.color = background_color()
        m.label_atom.display = 1

        b = m.newBond(m.atom1, m.atom2)
        b.display = b.Always
        b.drawMode = b.Stick
        b.radius = thickness / 2.0
        b.color = chimera_color(rgb)
        b.halfbond = 0
        m.label_atom.label = label
        m.label_atom.labelColor = chimera_color(label_rgb)

        self.model = m

        if model_id == None:
            id, subid = (self.model_id(), chimera.openModels.Default)
        else:
            id, subid = model_id
        chimera.openModels.add([m], baseId=id, subid=subid)
        chimera.addModelClosedCallback(m, self.model_closed_cb)

        import SimpleSession
        SimpleSession.noAutoRestore(m)

        m.openState.active = False
        z_near, z_far = clip_plane_positions()
        self.set_depth(.5 * (z_near + z_far))
        self.set_screen_position(self.screen_position)
        self.orientation_cb()

        return m
    def parse_PDB_channel(self, file_path, name):
        file = open(file_path)
        tunnelObject = chimera.Molecule()
        tunnel = tunnelObject.newResidue(name, " ", 1, " ")
        tunnel_number = 0

        for line in file:

            if line.startswith('HETATM'):

                tunnel_number = int(line[25:30])
                nodes = [float(line[31:39]), float(line[39:47]), float(line[47:55]), float(line[62:68])]
                self.append_node(tunnelObject, nodes, tunnel)

        file.close()
        self.make_channel(tunnelObject, tunnel_number)
Exemple #5
0
def copyMolecule(m, copyXformCoords=False):
	"""Copy molecule and return both copy and map of corresponding atoms"""
	# Copied from PDBmatrices.copy_molecule
	import chimera
	cm = chimera.Molecule()
	cs = cm.newCoordSet(1)
	cm.activeCoordSet = cs
	_copyAttributes(m, cm, _MoleculeAttrList)
	try:
		headers = getattr(m, "pdbHeaders")
	except AttributeError:
		pass
	else:
		cm.setAllPDBHeaders(headers)

	residueMap = {}
	for r in m.residues:
		cr = cm.newResidue(r.type, r.id)
		_copyAttributes(r, cr, _ResidueAttrList)
		residueMap[r] = cr

	atomMap = {}
	for a in primaryAtomSet(m):
		ca = cm.newAtom(a.name, a.element)
		if copyXformCoords:
			ca.setCoord(a.xformCoord())
		else:
			ca.setCoord(a.coord())
		_copyAttributes(a, ca, _AtomAttrList)
		atomMap[a] = ca
		residueMap[a.residue].addAtom(ca)

	for b in m.bonds:
		a1, a2 = b.atoms
		try:
			na1 = atomMap[a1]
			na2 = atomMap[a2]
		except KeyError:
			# At least one of the atom was not mapped,
			# so don't bother creating the bond
			pass
		else:
			cb = cm.newBond(na1, na2)
			_copyAttributes(b, cb, _BondAttrList)

	return cm, atomMap, residueMap
Exemple #6
0
def convert_gaussian_molecule_to_chimera(path_or_parser):
    if isinstance(path_or_parser, basestring):
        parsed = Gaussian(path_or_parser).parse()
    else:
        parsed = path_or_parser

    elements = parsed.atomnos
    coords = parsed.atomcoords[-1]
    m = chimera.Molecule()
    r = m.newResidue("UNK", " ", 1, " ")
    for i, (element, xyz) in enumerate(zip(elements, coords)):
        element = chimera.Element(element)
        a = m.newAtom('{}{}'.format(element, i), element)
        r.addAtom(a)
        a.setCoord(chimera.Point(*xyz))
        a.serialNumber = i
    chimera.connectMolecule(m)
    return m
Exemple #7
0
def _dummy_mol(name='dummy'):
    """
    Create an empty molecule, with an empty residue. Used for new molecules
    we intend to create on a per-atom basis.

    Parameters
    ----------
    name : str, optional

    Returns
    -------
    chimera.Molecule

    """
    m = chimera.Molecule()
    m.name = name
    r = m.newResidue(name, 'het', 1, ' ')
    r.isHet = True
    return m
Exemple #8
0
def restoreMolecules(molInfo, resInfo, atomInfo, bondInfo, crdInfo):
    from SimpleSession import registerAttribute
    items = []
    sm = globals.sessionMap

    res2mol = []
    atom2mol = []
    for ids, name, cid, display, lineWidth, pointSize, stickScale, \
    pdbHeaders, surfaceOpacity, ballScale, vdwDensity, autochain, \
    ribbonHidesMainchain, riCID, aromaticCID, aromaticDisplay, \
    aromaticLineType, aromaticMode, hidden in zip(
       expandSummary(molInfo['ids']),
       expandSummary(molInfo['name']),
       expandSummary(molInfo['color']),
       expandSummary(molInfo['display']),
       expandSummary(molInfo['lineWidth']),
       expandSummary(molInfo['pointSize']),
       expandSummary(molInfo['stickScale']),
       molInfo['pdbHeaders'],
       expandSummary(molInfo['surfaceOpacity']),
       expandSummary(molInfo['ballScale']),
       expandSummary(molInfo['vdwDensity']),
       expandSummary(molInfo['autochain']),
       expandSummary(molInfo['ribbonHidesMainchain']),
       expandSummary(molInfo['ribbonInsideColor']),
       expandSummary(molInfo['aromaticColor']),
       expandSummary(molInfo['aromaticDisplay']),
       expandSummary(molInfo['aromaticLineType']),
       expandSummary(molInfo['aromaticMode']),
       expandSummary(molInfo['hidden'])
       ):
        m = chimera.Molecule()
        sm[len(items)] = m
        items.append(m)
        m.name = name
        from SimpleSession import modelMap, modelOffset
        chimera.openModels.add([m],
                               baseId=ids[0] + modelOffset,
                               subid=ids[1],
                               hidden=hidden)
        modelMap.setdefault(ids, []).append(m)
        m.color = getColor(cid)
        m.display = display
        m.lineWidth = lineWidth
        m.pointSize = pointSize
        m.stickScale = stickScale
        m.setAllPDBHeaders(pdbHeaders)
        m.surfaceOpacity = surfaceOpacity
        m.ballScale = ballScale
        m.vdwDensity = vdwDensity
        m.autochain = autochain
        m.ribbonHidesMainchain = ribbonHidesMainchain
        m.ribbonInsideColor = getColor(riCID)
        m.aromaticColor = getColor(aromaticCID)
        m.aromaticDisplay = aromaticDisplay
        m.aromaticLineType = aromaticLineType
        m.aromaticMode = aromaticMode
    if molInfo['optional']:
        for attrName, info in molInfo['optional'].items():
            hashable, sv = info
            registerAttribute(chimera.Molecule, attrName, hashable=hashable)
            vals = expandSummary(sv, hashable=hashable)
            for m, val in zip(items, vals):
                if val is not None:
                    setattr(m, attrName, val)

    resStart = len(items)
    for mid, name, chain, pos, insert, rcid, lcid, ss, ssId, ribbonDrawMode, \
    ribbonDisplay, label, labelOffset, isHet, fillDisplay, fillMode in zip(
       expandSummary(resInfo['molecule']),
       expandSummary(resInfo['name']),
       expandSummary(resInfo['chain']),
       expandSequentialSummary(resInfo['position']),
       expandSummary(resInfo['insert']),
       expandSummary(resInfo['ribbonColor']),
       expandSummary(resInfo['labelColor']),
       expandSummary(resInfo['ss']),
       expandSummary(resInfo['ssId']),
       expandSummary(resInfo['ribbonDrawMode']),
       expandSummary(resInfo['ribbonDisplay']),
       expandSummary(resInfo['label']),
       expandSummary(resInfo['labelOffset']),
       expandSummary(resInfo['isHet']),
       expandSummary(resInfo['fillDisplay']),
       expandSummary(resInfo['fillMode']),
       ):
        m = idLookup(mid)
        r = m.newResidue(name, chain, pos, insert)
        sm[len(items)] = r
        items.append(r)
        r.ribbonColor = getColor(rcid)
        r.labelColor = getColor(lcid)
        r.isHelix, r.isStrand, r.isTurn = ss
        r.ssId = ssId
        r.ribbonDrawMode = ribbonDrawMode
        r.ribbonDisplay = ribbonDisplay
        r.label = label
        if labelOffset is not None:
            r.labelOffset = labelOffset
        r.isHet = isHet
        r.fillDisplay = fillDisplay
        r.fillMode = fillMode
    if resInfo['optional']:
        residues = items[resStart:]
        for attrName, info in resInfo['optional'].items():
            hashable, sv = info
            registerAttribute(chimera.Residue, attrName, hashable=hashable)
            vals = expandSummary(sv, hashable=hashable)
            for r, val in zip(residues, vals):
                if val is not None:
                    setattr(r, attrName, val)

    atomStart = len(items)
    for rid, name, element, cid, vcid, lcid, scid, drawMode, display, \
    label, labelOffet, surfaceDisplay, surfaceCategory, surfaceOpacity, \
    radius, vdw, idatmType, altLoc in zip(
       expandSummary(atomInfo['residue']),
       expandSummary(atomInfo['name']),
       expandSummary(atomInfo['element']),
       expandSummary(atomInfo['color']),
       expandSummary(atomInfo['vdwColor']),
       expandSummary(atomInfo['labelColor']),
       expandSummary(atomInfo['surfaceColor']),
       expandSummary(atomInfo['drawMode']),
       expandSummary(atomInfo['display']),
       expandSummary(atomInfo['label']),
       expandSummary(atomInfo['labelOffset']),
       expandSummary(atomInfo['surfaceDisplay']),
       expandSummary(atomInfo['surfaceCategory']),
       expandSummary(atomInfo['surfaceOpacity']),
       expandSummary(atomInfo['radius']),
       expandSummary(atomInfo['vdw']),
       expandSummary(atomInfo['idatmType']),
       expandSummary(atomInfo['altLoc'])
       ):
        r = idLookup(rid)
        a = r.molecule.newAtom(name, chimera.Element(element))
        sm[len(items)] = a
        items.append(a)
        r.addAtom(a)
        a.color = getColor(cid)
        a.vdwColor = getColor(vcid)
        a.labelColor = getColor(lcid)
        a.surfaceColor = getColor(scid)
        a.drawMode = drawMode
        a.display = display
        a.label = label
        if labelOffset is not None:
            a.labelOffset = labelOffset
        a.surfaceDisplay = surfaceDisplay
        a.surfaceCategory = surfaceCategory
        a.surfaceOpacity = surfaceOpacity
        a.radius = radius
        a.vdw = vdw
        if idatmType:
            a.idatmType = idatmType
        a.altLoc = altLoc
    if atomInfo['optional']:
        atoms = items[atomStart:]
        for attrName, info in atomInfo['optional'].items():
            hashable, sv = info
            registerAttribute(chimera.Atom, attrName, hashable=hashable)
            vals = expandSummary(sv, hashable=hashable)
            for a, val in zip(atoms, vals):
                if val is not None:
                    setattr(a, attrName, val)

    bondStart = len(items)
    for atoms, drawMode, display, label, labelOffset, radius in zip(
            bondInfo['atoms'], expandSummary(bondInfo['drawMode']),
            expandSummary(bondInfo['display']),
            expandSummary(bondInfo['label']),
            expandSummary(bondInfo['labelOffset']),
            expandSummary(bondInfo['radius'])):
        a1, a2 = [idLookup(a) for a in atoms]
        b = a1.molecule.newBond(a1, a2)
        sm[len(items)] = b
        items.append(b)
        b.drawMode = drawMode
        b.display = display
        b.label = label
        if labelOffset is not None:
            b.labelOffset = labelOffset
        b.radius = radius
    if bondInfo.get('optional', {}):
        bonds = items[bondStart:]
        for attrName, info in bondInfo['optional'].items():
            hashable, sv = info
            registerAttribute(chimera.Bond, attrName, hashable=hashable)
            vals = expandSummary(sv, hashable=hashable)
            for b, val in zip(bonds, vals):
                if val is not None:
                    setattr(b, attrName, val)

    from chimera import Point
    for mid, crdSets in crdInfo.items():
        m = idLookup(mid)
        active = crdSets.pop('active')
        for key, crds in crdSets.items():
            coordSet = m.newCoordSet(key, len(crds))
            for aid, crdString in crds:
                idLookup(aid).setCoord(
                    Point(*tuple([float(c) for c in crdString.split()])),
                    coordSet)
            if key == active:
                m.activeCoordSet = coordSet
Exemple #9
0
def build_chimera_molecule(mmlib_structure):

    from mmLib.Structure import fragment_id_split
    import chimera
    import numpy
    from string import letters

    modelMap = {}  # mmLib structure to Chimera molecule
    atoms = {}  # mmLib atom to chimera atom mapping
    residues = {}  # fragment to chimera residue mapping
    seq2frag = {}  # entity-sequence to fragment mapping
    sa2r = {}  # sequence-asym_id to chimera residue mapping
    e2c = {}  # entity to chain mapping

    # Make molecules
    for mm in mmlib_structure.iter_models():
        m = chimera.Molecule()
        modelMap[mm] = m
        seq2frag[m] = {}
        sa2r[m] = {}
        e2c[m] = {}

    # Make atoms and residues as needed
    name_to_element = element_table()
    for mm in mmlib_structure.iter_models():
        m = modelMap[mm]
        for ma in mm.iter_all_atoms():
            mf = ma.get_fragment()
            try:
                chain_id = ma.asym_id.strip()
            except AttributeError:
                chain_id = ma.chain_id.strip()
            try:
                r = residues[mf]
            except KeyError:
                seq, icode = fragment_id_split(mf.fragment_id)
                if icode is None:
                    rid = chimera.MolResId(chain_id, seq)
                else:
                    rid = chimera.MolResId(chain_id, seq, insert=icode)
                r = m.newResidue(mf.res_name, rid)
                residues[mf] = r
                if not mf.is_standard_residue():
                    r.isHet = True
                sf_key = (ma.label_entity_id, ma.label_seq_id)
                d = seq2frag[m].setdefault(sf_key, {})
                d[chain_id] = mf
                sa2r[m][(ma.label_seq_id, ma.label_asym_id)] = r
                s = e2c[m].setdefault(ma.label_entity_id, set([]))
                s.add(chain_id)
            if not ma.element:
                ename = ma.name[0]
                if len(ma.name) > 1 and ma.name[1] in letters:
                    ename += ma.name[1].lower()
            elif len(ma.element) > 1:
                ename = ma.element[0].upper() + ma.element[1:].lower()
            else:
                ename = ma.element
            try:
                element = name_to_element[ename]
            except KeyError:
                # Don't know what it is, guess carbon
                element = name_to_element['C']
            a = m.newAtom(ma.name.replace('*', "'"), element)
            a.altLoc = ma.alt_loc
            c = chimera.Coord()
            c.x, c.y, c.z = ma.position
            a.setCoord(c)  # a.coord = c does not work
            a.bfactor = ma.temp_factor
            a.occupancy = ma.occupancy
            if ma.U is not None:
                a.anisoU = numpy.array(ma.U, 'f')
            atoms[ma] = a
            r.addAtom(a)

    # Make bonds
    numBonds = 0
    for mm in mmlib_structure.iter_models():
        m = modelMap[mm]
        for ma in mm.iter_all_atoms():
            for mb in ma.iter_bonds():
                a1 = atoms[mb.get_atom1()]
                a2 = atoms[mb.get_atom2()]
                try:
                    m.newBond(a1, a2)
                except TypeError:
                    pass
                else:
                    numBonds += 1

    # Make inter-residue bonds
    from chimera.resCode import res3to1
    from chimera import Sequence
    residueAfter = {}
    try:
        table = mmlib_structure.cifdb["entity_poly_seq"]
    except KeyError:
        pass
    else:
        for m in modelMap.itervalues():
            seqMap = {}
            prevEntity = None
            prevDict = None
            for row in table.iter_rows():
                thisEntity = row["entity_id"]
                try:
                    chains = e2c[m][thisEntity]
                except KeyError:
                    pass
                else:
                    monomer = res3to1(row["mon_id"])
                    for chainId in chains:
                        try:
                            seq = seqMap[chainId]
                        except KeyError:
                            if chainId == " ":
                                name = Sequence.PRINCIPAL
                            else:
                                name = Sequence.CHAIN_FMT % chainId
                            seq = Sequence.Sequence(name)
                            seqMap[chainId] = seq
                        seq.append(monomer)
                num = row["num"]
                try:
                    thisDict = seq2frag[m][(thisEntity, num)]
                except KeyError:
                    # leave the prev variables so we will connect
                    # residues in the same chain.
                    continue
                if prevDict is not None and prevEntity == thisEntity:
                    for chain_id, prevR in prevDict.iteritems():
                        try:
                            thisR = thisDict[chain_id]
                        except KeyError:
                            continue
                        isAA = thisR.is_amino_acid()
                        isNA = thisR.is_nucleic_acid()
                        wasAA = prevR.is_amino_acid()
                        wasNA = prevR.is_nucleic_acid()
                        if isAA and wasAA:
                            numBonds += connectResidues(
                                prevR, ["C"], thisR, ["N"], atoms,
                                residueAfter)
                        if isNA and wasNA:
                            numBonds += connectResidues(
                                prevR, ["O3'", "O3*"], thisR, ["P"], atoms,
                                residueAfter)
                prevDict = thisDict
                prevEntity = thisEntity
            m.cifPolySeq = seqMap

    # If no bonds were made, make them
    if numBonds == 0:
        import chimera
        for m in modelMap.itervalues():
            chimera.connectMolecule(m)

    # Assign secondary structure (helix and turn)
    try:
        table = mmlib_structure.cifdb["struct_conf"]
    except KeyError:
        pass
    else:
        for m in modelMap.itervalues():
            for row in table.iter_rows():
                typeId = row["conf_type_id"]
                if typeId.startswith("HELX"):
                    ssType = "isHelix"
                elif typeId.startswith("TURN"):
                    ssType = "isTurn"
                else:
                    continue
                bAsymId = row["beg_label_asym_id"]
                bSeqId = row["beg_label_seq_id"]
                eAsymId = row["end_label_asym_id"]
                eSeqId = row["end_label_seq_id"]
                try:
                    bRes = sa2r[m][(bSeqId, bAsymId)]
                except KeyError:
                    print "No residue match asym_id=%s seq_id=%s" % (bAsymId,
                                                                     bSeqId)
                    continue
                try:
                    eRes = sa2r[m][(eSeqId, eAsymId)]
                except KeyError:
                    print "No residue match asym_id=%s seq_id=%s" % (eAsymId,
                                                                     eSeqId)
                    continue
                # Make sure we have a clear list of residues
                # from beginning to end
                r = bRes
                while r is not eRes and r is not None:
                    r = residueAfter.get(r, None)
                if r is None:
                    print "Non-consecutive residues (%s.%s) -> (%s.%s)" % (
                        bSeqId, bAsymId, eSeqId, eAsymId)
                    continue
                r = bRes
                while r is not eRes:
                    setattr(r, ssType, True)
                    r = residueAfter[r]
                setattr(eRes, ssType, True)
    # Assign secondary structure (sheet)
    try:
        table = mmlib_structure.cifdb["struct_sheet_range"]
    except KeyError:
        pass
    else:
        for m in modelMap.itervalues():
            for row in table.iter_rows():
                bAsymId = row["beg_label_asym_id"]
                bSeqId = row["beg_label_seq_id"]
                eAsymId = row["end_label_asym_id"]
                eSeqId = row["end_label_seq_id"]
                try:
                    bRes = sa2r[m][(bSeqId, bAsymId)]
                except KeyError:
                    print "No residue match asym_id=%s seq_id=%s" % (bAsymId,
                                                                     bSeqId)
                    continue
                try:
                    eRes = sa2r[m][(eSeqId, eAsymId)]
                except KeyError:
                    print "No residue match asym_id=%s seq_id=%s" % (eAsymId,
                                                                     eSeqId)
                    continue
                # Make sure we have a clear list of residues
                # from beginning to end
                r = bRes
                while r is not eRes and r is not None:
                    r = residueAfter.get(r, None)
                if r is None:
                    print "Non-consecutive residues (%s.%s) -> (%s.%s)" % (
                        bSeqId, bAsymId, eSeqId, eAsymId)
                    continue
                r = bRes
                while r is not eRes:
                    r.isSheet = True
                    r = residueAfter[r]
                eRes.isSheet = True

    # Add any modres information to resCode dictionaries
    try:
        table = mmlib_structure.cifdb["struct_conn"]
    except KeyError:
        pass
    else:
        from chimera import resCode
        dicts = (resCode.regex3to1, resCode.nucleic3to1, resCode.protein3to1,
                 resCode.standard3to1)
        for row in table.iter_rows():
            if row["conn_type_id"] != "modres":
                continue
            try:
                name = row["ptnr1_auth_comp_id"]
            except KeyError:
                name = row["ptnr1_label_comp_id"]
            stdName = row["pdbx_ptnr1_standard_comp_id"]
            for d in dicts:
                if stdName in d:
                    d[name] = d[stdName]
    return modelMap.values()
Exemple #10
0
def ReadMol ( fpath, log=False ) :

    from random import random

    cif, loops = ReadCif ( fpath, log )

    # descriptions by chain id:
    descrByEntityId = GetEntityDescr ( cif, loops )

    try :
        atoms = loops['_atom_site']['data']
        print " - %d atom records" % len(atoms)
    except :
        print " - no atoms in cif?"
        return None

    labels = loops['_atom_site']['labels']
    if 0 :
        print "Labels:"
        for l in labels :
            print " : ", l

    import time
    start = time.time()

    rmap = {}

    nmol = chimera.Molecule()
    from os import path
    #nmol.name = path.splitext ( path.split (fpath)[1] )[0]
    nmol.name = path.split (fpath) [1]
    nmol.openedAs = [ fpath, [] ]
    nmol.cif = cif
    nmol.cifLoops = loops

    nmol.chainColors = {}
    nmol.chainDescr = {}

    numQ = 0
    first = True
    for at in atoms :
        mp = at['asMap']

        if log and first :
            #for label, val in mp.iteritems () :
            for li, label in enumerate ( labels ) :
                print "   %d : %s : %s" % (li+1, label, mp[label])

        first = False

        atType = mp['type_symbol']
        atName = mp['label_atom_id']
        rtype = mp['label_comp_id']
        chainId = mp['label_asym_id']
        chainEId = mp['label_entity_id']
        px = mp['Cartn_x']
        py = mp['Cartn_y']
        pz = mp['Cartn_z']
        occ = mp['occupancy']
        bfactor = mp['B_iso_or_equiv']
        altLoc = mp['label_alt_id']
        if altLoc == "." : altLoc = ''

        if chainEId in descrByEntityId :
            nmol.chainDescr [chainId] = descrByEntityId [chainEId]

        resId = ResId ( mp )
        if resId == None :
            continue

        ris = "%s%d" % (chainId, resId)
        res = None
        if not ris in rmap :
            res = nmol.newResidue ( rtype, chimera.MolResId(chainId, resId) )
            rmap[ris] = res
        else :
            res = rmap[ris]

        clr = None
        if not chainId in nmol.chainColors :
            clr = chimera.MaterialColor ( random(), random(), random(), 1.0 )
            nmol.chainColors[chainId] = clr
            if 0 and log :
                print " - chain %s" % chainId
        else :
            clr = nmol.chainColors [chainId]

        nat = nmol.newAtom ( atName, chimera.Element(atType) )

        drawRib = rtype in protein3to1 or rtype in nucleic3to1

        #aMap[at] = nat
        res.addAtom( nat )
        nat.setCoord ( chimera.Point( float(px), float(py), float(pz) ) )
        nat.altLoc = altLoc
        nat.occupancy = float(occ)
        nat.bfactor = float(bfactor)

        if 'Q-score' in mp :
            try :
                Q = float ( mp['Q-score'] )
                nat.Q = Q
                numQ += 1
            except :
                #print " - q score is",  mp['Q-score']
                pass

    end = time.time()
    print " - created %d atoms, %.1fs, %d q-scores" % ( len(nmol.atoms), end-start, numQ )

    return nmol
Exemple #11
0
def LoadMolCh_ ( fpath, log=False, task=None ) :

    mol = ReadMol ( fpath, log=False )

    from chimera.resCode import nucleic3to1
    from chimera.resCode import protein3to1, protein1to3
    protein3to1['HSD'] = protein3to1['HIS']
    protein3to1['HSE'] = protein3to1['HIS']

    nucleic1to3 = { 'T':'THY', 'C':'CYT', 'G':'GUA', 'A':'ADE', 'U':'URA'}
    nucleic3to1['GDP'] = nucleic3to1['GUA']

    crmap = {}
    rmolmap = {}

    print " - adding bonds"

    import time
    start = time.time()

    for r in mol.residues :
        if not r.id.chainId in crmap :
            crmap[r.id.chainId] = { r.id.position : r }
        else :
            crmap[r.id.chainId][r.id.position] = r

    chains = mol.chainColors.keys()

    print "%d residues - %d chains" % ( len(mol.residues), len(chains) )
    from os.path import splitext

    chMols = {}
    for ch in chains :

        start = time.time()

        chMol = chimera.Molecule()
        chMol.name = splitext ( mol.name )[0] + "_" + ch
        rmap0 = crmap[ch]
        chMols[ch] = chMol
        print " - %s - %d residues" % (ch, len(rmap0)),

        rmap = {}
        for ri, res in rmap0.iteritems() :
            nr = chMol.newResidue ( res.type, chimera.MolResId(ch, res.id.position) )
            rmap[nr.id.position] = nr
            for at in res.atoms :
                nat = chMol.newAtom ( at.name, at.element )
                nr.addAtom ( nat )
                nat.setCoord ( at.coord() )

        print ", %d atoms" % len(chMol.atoms),

        for ri, r in rmap.iteritems() :
            #if ri % 100 == 0 :
            #    print "%d/%d" % ( ri, len(mol.residues) )
            #    if task :
            #        task.updateStatus( "%d/%d" % ( ri, len(mol.residues) ) )

            rmol = None
            rtype = r.type.upper()
            if rtype.lower() in rmolmap :
                rmol = rmolmap[ rtype.lower() ]
            else :
                rmol = GetResMol ( rtype.lower() )
                if rmol != None :
                    rmolmap[rtype.lower()] = rmol

            if rmol != None :
                for b in rmol.bonds :
                    a1n, a2n = b.atoms[0].name, b.atoms[1].name
                    if a1n in r.atomsMap and a2n in r.atomsMap :
                        for a1 in r.atomsMap[a1n] :
                            for a2 in r.atomsMap[a2n] :
                                #print "%s - %s" % ( At(a1), At(a2) )
                                nb = chMol.newBond ( a1, a2 )
                                pass
            else :
                print " - rmol %s not found" % rtype

            if 1 :
                if r.type.upper() in protein3to1 :
                    if r.id.position-1 in rmap :
                        pres = rmap[r.id.position-1]
                        if pres.type.upper() in protein3to1 :
                            #GetSS ( pres, r )
                            if "C" in pres.atomsMap and "N" in r.atomsMap :
                                for a1 in pres.atomsMap["C"] :
                                    for a2 in r.atomsMap["N"] :
                                        #print a1.name, pres.id.position, a2.name, r.id.position
                                        nb = chMol.newBond ( a1, a2 )
                                        pass

                if r.type.upper() in nucleic1to3 or r.type.upper() in nucleic3to1 :
                    if r.id.position-1 in rmap :
                        pres = rmap[r.id.position-1]
                        if pres.type.upper() in nucleic1to3 or pres.type.upper() in nucleic3to1 :
                            if "O3'" in pres.atomsMap and "P" in r.atomsMap :
                                for a1 in pres.atomsMap["O3'"] :
                                    for a2 in r.atomsMap["P"] :
                                        #print a1.name, pres.id.position, a2.name, r.id.position
                                        nb = chMol.newBond ( a1, a2 )
                                        pass

        print ( ", %d bonds, %.1fs" % (len(chMol.bonds), time.time()-start)  )

        #start = time.time()
        #chimera.openModels.add ( [chMol] )
        #print " - added mol %ss, %.1fs" % (chMol.name, time.time()-start)

        start = time.time()
        for r in chMol.residues :
            rt = r.type.upper()
            if rt in protein3to1 or rt in nucleic3to1 or rt in nucleic1to3 :
                r.ribbonDisplay = True
                r.ribbonDrawMode = 2
                r.ribbonColor = mol.chainColors[r.id.chainId]
                for at in r.atoms :
                    at.display = False
                    at.drawMode = at.EndCap
                    if at.element.name.upper() in atomColors :
                        at.color = atomColors[at.element.name.upper()]
                    else :
                        at.color = mol.chainColors[r.id.chainId]
            else :
                for at in r.atoms :
                    at.display = True
                    at.drawMode = at.EndCap
                    if at.element.name.upper() in atomColors :
                        at.color = atomColors[at.element.name.upper()]
                    else :
                        at.color = mol.chainColors[r.id.chainId]

        for b in mol.bonds :
            b.drawMode = b.Stick
            b.display = b.Smart

        #print " - changed mol disp %s - %.1fs" % (chMol.name, time.time()-start)

    return mol
def molecule_from_atoms(m, atoms):

    import chimera
    cm = chimera.Molecule()
    cm.color = m.color
    cm.display = m.display

    for attr in ('name', 'openedAs'):
        if hasattr(m, attr):
            setattr(cm, attr, getattr(m, attr))

    if hasattr(m, 'pdbHeaders'):
        cm.setAllPDBHeaders(m.pdbHeaders)

    rmap = {}
    rlist = atom_residues(atoms)
    rlist.sort(lambda r1, r2: cmp(r1.id.position, r2.id.position))
    for r in rlist:
        crid = chimera.MolResId(r.id.chainId, r.id.position)
        cr = cm.newResidue(r.type, crid)
        cr.isHet = r.isHet
        cr.isHelix = r.isHelix
        cr.isSheet = r.isSheet
        cr.isTurn = r.isTurn
        cr.ribbonColor = r.ribbonColor
        cr.ribbonStyle = r.ribbonStyle
        cr.ribbonDrawMode = r.ribbonDrawMode
        cr.ribbonDisplay = r.ribbonDisplay
        rmap[r] = cr

    amap = {}
    for a in atoms:
        ca = cm.newAtom(a.name, a.element)
        ca.setCoord(a.coord())
        ca.altLoc = a.altLoc
        ca.color = a.color
        ca.drawMode = a.drawMode
        ca.display = a.display
        if hasattr(a, 'bfactor'):
            ca.bfactor = a.bfactor
        amap[a] = ca
        cr = rmap[a.residue]
        cr.addAtom(ca)

    for b in atom_bonds(atoms):
        a1, a2 = b.atoms
        cb = cm.newBond(amap[a1], amap[a2])
        cb.color = b.color
        cb.drawMode = b.drawMode
        cb.display = b.display

    for am in m.associatedModels():
        if not isinstance(am, chimera.PseudoBondGroup):
            continue
        if not am.category.startswith("coordination complexes"):
            continue
        for pb in am.pseudoBonds:
            a1, a2 = pb.atoms
            if a1 not in amap or a2 not in amap:
                continue
            cm.newBond(amap[a1], amap[a2])

    return cm
Exemple #13
0
def _newModel(name):
    m = chimera.Molecule()
    m.name = name
    chimera.openModels.add([m])
    return m
def restoreMolecules(molInfo, resInfo, atomInfo, bondInfo, crdInfo):
    items = []
    sm = globals.sessionMap

    res2mol = []
    atom2mol = []
    openModelsArgs = {}
    for ids, name, cid, display, lineWidth, pointSize, stickScale, \
    pdbHeaders, surfaceOpacity, ballScale, vdwDensity, autochain, \
    ribbonHidesMainchain in zip(
       expandSummary(molInfo['ids']),
       expandSummary(molInfo['name']),
       expandSummary(molInfo['color']),
       expandSummary(molInfo['display']),
       expandSummary(molInfo['lineWidth']),
       expandSummary(molInfo['pointSize']),
       expandSummary(molInfo['stickScale']),
       molInfo['pdbHeaders'],
       expandSummary(molInfo['surfaceOpacity']),
       expandSummary(molInfo['ballScale']),
       expandSummary(molInfo['vdwDensity']),
       expandSummary(molInfo['autochain']),
       expandSummary(molInfo['ribbonHidesMainchain'])
       ):
        m = chimera.Molecule()
        sm[len(items)] = m
        items.append(m)
        m.name = name
        from SimpleSession import modelMap, modelOffset
        chimera.openModels.add([m], baseId=ids[0] + modelOffset, subid=ids[1])
        modelMap.setdefault(ids, []).append(m)
        m.color = getColor(cid)
        m.display = display
        m.lineWidth = lineWidth
        m.pointSize = pointSize
        m.stickScale = stickScale
        m.setAllPDBHeaders(pdbHeaders)
        m.surfaceOpacity = surfaceOpacity
        m.ballScale = ballScale
        m.vdwDensity = vdwDensity
        m.autochain = autochain
        m.ribbonHidesMainchain = ribbonHidesMainchain

    for mid, name, chain, pos, insert, rcid, lcid, ss, ribbonDrawMode, \
    ribbonDisplay, label in zip(
       expandSummary(resInfo['molecule']),
       expandSummary(resInfo['name']),
       expandSummary(resInfo['chain']),
       resInfo['position'],
       expandSummary(resInfo['insert']),
       expandSummary(resInfo['ribbonColor']),
       expandSummary(resInfo['labelColor']),
       expandSummary(resInfo['ss']),
       expandSummary(resInfo['ribbonDrawMode']),
       expandSummary(resInfo['ribbonDisplay']),
       expandSummary(resInfo['label'])
       ):
        m = idLookup(mid)
        r = m.newResidue(name, chain, pos, insert)
        sm[len(items)] = r
        items.append(r)
        r.ribbonColor = getColor(rcid)
        r.labelColor = getColor(lcid)
        r.isHelix, r.isStrand, r.isTurn = ss
        r.ribbonDrawMode = ribbonDrawMode
        r.ribbonDisplay = ribbonDisplay
        r.label = label

    for rid, name, element, cid, vcid, lcid, scid, drawMode, display, \
    label, surfaceDisplay, surfaceCategory, surfaceOpacity, radius, vdw, \
    bfactor, occupancy, charge, idatmType in zip(
       expandSummary(atomInfo['residue']),
       expandSummary(atomInfo['name']),
       expandSummary(atomInfo['element']),
       expandSummary(atomInfo['color']),
       expandSummary(atomInfo['vdwColor']),
       expandSummary(atomInfo['labelColor']),
       expandSummary(atomInfo['surfaceColor']),
       expandSummary(atomInfo['drawMode']),
       expandSummary(atomInfo['display']),
       expandSummary(atomInfo['label']),
       expandSummary(atomInfo['surfaceDisplay']),
       expandSummary(atomInfo['surfaceCategory']),
       expandSummary(atomInfo['surfaceOpacity']),
       expandSummary(atomInfo['radius']),
       expandSummary(atomInfo['vdw']),
       expandSummary(atomInfo['bfactor']),
       expandSummary(atomInfo['occupancy']),
       expandSummary(atomInfo['charge']),
       expandSummary(atomInfo['idatmType'])
       ):
        r = idLookup(rid)
        a = r.molecule.newAtom(name, chimera.Element(element))
        sm[len(items)] = a
        items.append(a)
        r.addAtom(a)
        a.color = getColor(cid)
        a.vdwColor = getColor(vcid)
        a.labelColor = getColor(lcid)
        a.surfaceColor = getColor(scid)
        a.drawMode = drawMode
        a.display = display
        a.label = label
        a.surfaceDisplay = surfaceDisplay
        a.surfaceCategory = surfaceCategory
        a.surfaceOpacity = surfaceOpacity
        a.radius = radius
        a.vdw = vdw
        if bfactor is not None:
            a.bfactor = bfactor
        if occupancy is not None:
            a.occupancy = occupancy
        if charge is not None:
            a.charge = charge
        if idatmType:
            a.idatmType = idatmType

    for atoms, drawMode, display in zip(bondInfo['atoms'],
                                        expandSummary(bondInfo['drawMode']),
                                        expandSummary(bondInfo['display'])):
        a1, a2 = [idLookup(a) for a in atoms]
        b = a1.molecule.newBond(a1, a2)
        sm[len(items)] = b
        items.append(b)
        b.drawMode = drawMode
        b.display = display

    from chimera import Point
    for mid, crdSets in crdInfo.items():
        m = idLookup(mid)
        active = crdSets.pop('active')
        for key, crds in crdSets.items():
            coordSet = m.newCoordSet(key, len(crds))
            for aid, crdString in crds:
                idLookup(aid).setCoord(
                    Point(*tuple([float(c) for c in crdString.split()])),
                    coordSet)
            if key == active:
                m.activeCoordSet = coordSet
Exemple #15
0
def _nonStdCharge(residues, netCharge, method, gaffType, status, showCharges):
    r = residues[0]
    if status:
        status("Copying residue %s\n" % r.type)

    # create a fake Molecule that we can write to a Mol2 file
    nm = chimera.Molecule()
    nm.name = r.type

    # write out the residue's atoms first, since those are the
    # ones we will be caring about
    nr = nm.newResidue(r.type, ' ', 1, ' ')
    from chimera.molEdit import addAtom
    atomMap = {}
    atomNames = set()
    ratoms = r.atoms
    # use same ordering of atoms as they had in input, to improve
    # consistency of antechamber charges
    ratoms.sort(lambda a1, a2: cmp(a1.coordIndex, a2.coordIndex))
    for a in ratoms:
        atomMap[a] = addAtom(a.name, a.element, nr, a.coord())
        atomNames.add(a.name)

    # add the intraresidue bonds and remember the interresidue ones
    nearby = set()
    for a in ratoms:
        na = atomMap[a]
        for n in a.neighbors:
            if n.residue != r:
                nearby.add(n)
                continue
            nn = atomMap[n]
            if nn in na.bondsMap:
                continue
            nm.newBond(na, nn)
    from chimera.idatm import typeInfo
    extras = set()
    while nearby:
        nb = nearby.pop()
        aname = _getAName(str(nb.element), atomNames)
        na = addAtom(aname, nb.element, nr, nb.coord())
        atomMap[nb] = na
        extras.add(na)
        for nbn in nb.neighbors:
            if nbn in atomMap:
                nm.newBond(na, atomMap[nbn])
            else:
                try:
                    ti = typeInfo[nbn.idatmType]
                except KeyError:
                    fc = 0
                    geom = 4
                else:
                    fc = estimateNetCharge([nbn])
                    geom = ti.geometry
                if fc or geom != 4:
                    nearby.add(nbn)
                else:
                    extras.update(_methylate(na, nbn, atomNames))
    totalNetCharge = netCharge + estimateNetCharge(extras)

    from tempfile import mkdtemp
    import os, os.path
    tempDir = mkdtemp()

    def _clean():
        for fn in os.listdir(tempDir):
            os.unlink(os.path.join(tempDir, fn))
        os.rmdir(tempDir)

    from WriteMol2 import writeMol2
    anteIn = os.path.join(tempDir, "ante.in.mol2")
    writeMol2([nm], anteIn, status=status)

    chimeraRoot = os.environ["CHIMERA"]
    anteHome = os.path.join(chimeraRoot, 'bin', 'antechamber')
    anteOut = os.path.join(tempDir, "ante.out.mol2")
    if method.lower().startswith("am1"):
        mth = "bcc"
    elif method.lower().startswith("gas"):
        mth = "gas"
    else:
        _clean()
        raise ValueError("Unknown charge method: %s" % method)

    command = [
        os.path.join(anteHome, "exe", "antechamber"), "-i", anteIn, "-fi",
        "mol2", "-o", anteOut, "-fo", "mol2", "-c", mth, "-nc",
        str(totalNetCharge), "-df", "0", "-j", "5", "-s", "2"
    ]
    if status:
        status("Running ANTECHAMBER for residue %s\n" % r.type)
    from subprocess import Popen, STDOUT, PIPE
    # For some reason on Windows, if shell==False then antechamber
    # cannot run bondtype via system().
    import sys
    if sys.platform == "win32":
        shell = True
    else:
        shell = False
    replyobj.info("Running ANTECHAMBER command: %s\n" % " ".join(command))
    import os
    os.environ['ACHOME'] = anteHome
    anteMessages = Popen(command,
                         stdin=PIPE,
                         stdout=PIPE,
                         stderr=STDOUT,
                         cwd=tempDir,
                         shell=shell,
                         bufsize=1).stdout
    while True:
        line = anteMessages.readline()
        if not line:
            break
        replyobj.status("(%s) %s" % (r.type, line), log=True)
    if not os.path.exists(anteOut):
        _clean()
        raise ChargeError("Failure running ANTECHAMBER for residue %s\n"
                          "Check reply log for details\n" % r.type)
    if status:
        status("Reading ANTECHAMBER output for residue %s\n" % r.type)
    from chimera import Mol2io, defaultMol2ioHelper
    mol2io = Mol2io(defaultMol2ioHelper)
    mols = mol2io.readMol2file(anteOut)
    if not mol2io.ok():
        _clean()
        raise IOError(mol2io.error())
    if not mols:
        _clean()
        raise RuntimeError("No molecules in ANTECHAMBER output for"
                           " residue %s" % r.type)
    chargedAtoms = mols[0].atoms
    if len(chargedAtoms) != len(nm.atoms):
        _clean()
        raise RuntimeError("Wrong number of atoms (%d, should be %d)"
                           " in ANTECHAMBER output for residue %s" %
                           (r.type, len(chargedAtoms), len(nm.atoms)))
    if status:
        status("Assigning charges for residue %s\n" % r.type)
    # put charges in template
    templateAtoms = nm.atoms
    # can't rely on order...
    templateAtoms.sort(lambda a1, a2: cmp(a1.serialNumber, a2.serialNumber))
    nonZero = False
    addedChargeSum = 0.0
    _totalCharge = 0.0
    for ta, ca in zip(templateAtoms, chargedAtoms):
        _totalCharge += ca.charge
        if ta in extras:
            addedChargeSum += ca.charge
            continue
        if ca.charge:
            nonZero = True
    if not nonZero:
        _clean()
        raise ChargeError("Failure running ANTECHAMBER for residue %s\n"
                          "Check reply log for details\n" % r.type)

    # adjust charges to compensate for added atoms...
    adjustment = (addedChargeSum -
                  (totalNetCharge - netCharge)) / (len(templateAtoms) -
                                                   len(extras))
    for ta, ca in zip(templateAtoms, chargedAtoms):
        if ta in extras:
            continue
        ta.charge = ca.charge + adjustment
        if gaffType:
            ta.gaffType = ca.mol2type
    # map template charges onto first residue
    track = chimera.TrackChanges.get()
    for fa, ta in atomMap.items():
        if ta in extras:
            continue
        fa.charge = ta.charge
        if showCharges:
            fa.label = "%+g" % fa.charge
        track.addModified(fa, ATTR_SET)
        if gaffType:
            fa.gaffType = ta.gaffType
    # map charges onto remaining residues
    for rr in residues[1:]:
        for fa, ra in zip(r.oslChildren(), rr.oslChildren()):
            ra.charge = fa.charge
            if showCharges:
                ra.label = "%+g" % ra.charge
            track.addModified(ra, ATTR_SET)
            if gaffType:
                ra.gaffType = fa.gaffType
    _clean()
    if status:
        status("Charges for residue %s determined\n" % r.type)
    replyobj.info("Charges for residue %s determined\n" % r.type)
    return True
Exemple #16
0
def getRotamers(res,
                phi=None,
                psi=None,
                cisTrans="trans",
                resType=None,
                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 boolean and a list of Molecule  
	   instances.  The boolean indicates whether the rotamers are backbone  
	   dependent.  The Molecules are each a single residue (a rotamer) and  
	   are in descending probability order.  Each has an attribute  
	   "rotamerProb" for the probability and "chis" for the chi angles.
	"""
    # find n/c/ca early to identify swapping non-amino acid before
    # the NoResidueRotamersError gets raised, which will attempt
    # a swap for ALA/GLY (and result in a traceback)
    resAtomsMap = res.atomsMap
    try:
        n = resAtomsMap["N"][0]
        ca = resAtomsMap["CA"][0]
        c = resAtomsMap["C"][0]
    except KeyError:
        raise LimitationError("N, CA, or C missing from %s:"
                              " needed to position CB" % res)
    resType = resType or res.type
    if not phi and not psi:
        ignore, phi, psi, cisTrans = extractResInfo(res)
        if log:

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

            replyobj.info("%s: phi %s, psi %s" % (res, _info(phi), _info(psi)))
            if cisTrans:
                replyobj.info(" " + cisTrans)
            replyobj.info("\n")
    replyobj.status("Retrieving rotamers from %s library\n" %
                    getattr(lib, "displayName", lib))
    bbdep, params = getRotamerParams(resType,
                                     phi=phi,
                                     psi=psi,
                                     cisTrans=cisTrans,
                                     lib=lib)
    replyobj.status("Rotamers retrieved from %s library\n" %
                    getattr(lib, "displayName", lib))

    template = chimera.restmplFindResidue(resType, False, False)
    tmplMap = template.atomsMap
    tmplN = tmplMap["N"]
    tmplCA = tmplMap["CA"]
    tmplC = tmplMap["C"]
    tmplCB = tmplMap["CB"]
    from chimera.molEdit import addAtom, addDihedralAtom, addBond
    from chimera.match import matchPositions, _coordArray
    xform, rmsd = matchPositions(_coordArray([n, ca, c]),
                                 _coordArray([tmplN, tmplCA, tmplC]))
    ncoord = xform.apply(tmplN.coord())
    cacoord = xform.apply(tmplCA.coord())
    cbcoord = xform.apply(tmplCB.coord())
    from data import chiInfo
    info = chiInfo[resType]
    bondCache = {}
    angleCache = {}
    torsionCache = {}
    from chimera.bondGeom import bondPositions
    mols = []
    middles = {}
    ends = {}
    for i, rp in enumerate(params):
        m = chimera.Molecule()
        mols.append(m)
        m.name = "rotamer %d of %s" % (i + 1, res)
        r = m.newResidue(resType, ' ', 1, ' ')
        # can't use a local variable for r.atomsMap since we receive
        # only an unchanging copy of the map
        m.rotamerProb = rp.p
        m.chis = rp.chis
        rotN = addAtom("N", tmplN.element, r, ncoord)
        rotCA = addAtom("CA", tmplCA.element, r, cacoord, bondedTo=rotN)
        rotCB = addAtom("CB", tmplCB.element, r, cbcoord, bondedTo=rotCA)
        todo = []
        for i, chi in enumerate(rp.chis):
            n3, n2, n1, new = info[i]
            blen, angle = _lenAngle(new, n1, n2, tmplMap, bondCache,
                                    angleCache)
            n3 = r.atomsMap[n3][0]
            n2 = r.atomsMap[n2][0]
            n1 = r.atomsMap[n1][0]
            new = tmplMap[new]
            a = addDihedralAtom(new.name,
                                new.element,
                                n1,
                                n2,
                                n3,
                                blen,
                                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 tmplN.bondsMap.keys():
            if tnnb.name in r.atomsMap or tnnb.element.number == 1:
                continue
            tnnbcoord = xform.apply(tnnb.coord())
            addAtom(tnnb.name, tnnb.element, r, tnnbcoord, bondedTo=rotN)

        # fill out bonds and remaining heavy atoms
        from chimera.idatm import typeInfo
        from chimera import distance
        done = set([rotN, rotCA])
        while todo:
            a = todo.pop(0)
            if a in done:
                continue
            tmplA = tmplMap[a.name]
            for bonded, bond in tmplA.bondsMap.items():
                if bonded.element.number == 1:
                    continue
                try:
                    rbonded = r.atomsMap[bonded.name][0]
                except KeyError:
                    # use middles if possible...
                    try:
                        p1, p2, p3 = middles[a]
                        conn = p3
                    except KeyError:
                        p1, p2, p3 = ends[a]
                        conn = p2
                    t1 = tmplMap[p1.name]
                    t2 = tmplMap[p2.name]
                    t3 = tmplMap[p3.name]
                    xform, rmsd = matchPositions(_coordArray([p1, p2, p3]),
                                                 _coordArray([t1, t2, t3]))
                    pos = xform.apply(tmplMap[bonded.name].coord())
                    rbonded = addAtom(bonded.name,
                                      bonded.element,
                                      r,
                                      pos,
                                      bondedTo=a)
                    middles[a] = [rbonded, a, conn]
                    ends[rbonded] = [rbonded, a, conn]
                if a not in rbonded.bondsMap:
                    addBond(a, rbonded)
                if rbonded not in done:
                    todo.append(rbonded)
            done.add(a)
    return bbdep, mols