Exemplo n.º 1
0
def _phosphorylate(mols, status, deletes):
    replyobj.info("Deleting 5' phosphates from: %s\n" %
                  ", ".join([str(r) for r in deletes]))
    from chimera.molEdit import addAtom
    for r in deletes:
        r.amberName += "5"
        for p in r.atomsMap['P']:
            o = None
            for nb in p.neighbors:
                for nnb in nb.neighbors:
                    if nnb == p:
                        continue
                    if nnb.element.number > 1:
                        o = nb
                        continue
                    r.molecule.deleteAtom(nnb)
                if nb != o:
                    r.molecule.deleteAtom(nb)
            v = p.coord() - o.coord()
            sn = getattr(p, "serialNumber", None)
            r.molecule.deleteAtom(p)
            v.length = 0.96
            addAtom("H5T",
                    chimera.Element('H'),
                    r,
                    o.coord() + v,
                    serialNumber=sn,
                    bondedTo=o)
Exemplo n.º 2
0
def _methylate(na, n, atomNames):
    added = []
    aname = _getAName("C", atomNames)
    from chimera.molEdit import addAtom
    nn = addAtom(aname, chimera.Element('C'), na.residue, n.coord())
    added.append(nn)
    na.molecule.newBond(na, nn)
    from chimera.bondGeom import bondPositions
    for pos in bondPositions(nn.coord(), 4, 1.1, [na.coord()]):
        hname = _getAName("H", atomNames)
        nh = addAtom(hname, chimera.Element('H'), na.residue, pos)
        added.append(nh)
        na.molecule.newBond(nn, nh)
    return added
Exemplo n.º 3
0
def _methylate(na, n, atomNames):
	added = []
	aname = _getAName("C", atomNames)
	from chimera.molEdit import addAtom
	nn = addAtom(aname, chimera.Element('C'), na.residue, n.coord())
	added.append(nn)
	na.molecule.newBond(na, nn)
	from chimera.bondGeom import bondPositions
	for pos in bondPositions(nn.coord(), 4, 1.1, [na.coord()]):
		hname = _getAName("H", atomNames)
		nh = addAtom(hname, chimera.Element('H'), na.residue, pos)
		added.append(nh)
		na.molecule.newBond(nn, nh)
	return added
Exemplo n.º 4
0
def addNewOs(new_res, psi, **kw):

    new_N = new_res.atomsMap['N'][0]
    new_CA = new_res.atomsMap['CA'][0]
    new_C = new_res.atomsMap['C'][0]

    new_OXT = addDihedralAtom('OXT',
                              chimera.Element(8),
                              new_C,
                              new_CA,
                              new_N,
                              DIST_C_O,
                              114,
                              psi,
                              residue=new_res)
    new_OXT.drawMode = kw['atomDrawMode']
    new_OXT.bfactor = kw['bFactor']

    addBond(new_OXT, new_C, drawMode=kw['bondDrawMode'])

    avail_bond_pos = bondPositions(bondee=new_C.coord(),
                                   geom=chimera.Atom.Planar,
                                   bondLen=DIST_C_O,
                                   bonded=[a.coord() for a in new_C.neighbors])

    use_point = avail_bond_pos[0]

    new_O = addAtom('O', chimera.Element(8), new_res, use_point)
    new_O.drawMode = kw['atomDrawMode']
    new_O.bfactor = kw['bFactor']

    addBond(new_O, new_C, drawMode=kw['bondDrawMode'])

    return new_O, new_OXT
Exemplo n.º 5
0
def addNewCA(last_bbone_ats, new_res, **kw):
    last_CA = last_bbone_ats['CA']
    last_C = last_bbone_ats['C']
    last_O = last_bbone_ats['O']

    new_N = new_res.atomsMap['N'][0]

    ## add the CA atom (not dihedral!)
    ## first, find the location for the new CA atom
    new_CA_bond_pos = bondPositions(
        bondee=new_N.coord(),
        geom=chimera.Atom.Planar,
        bondLen=DIST_CA_N,
        bonded=[a.coord() for a in new_N.neighbors],
        coPlanar=[last_CA.coord(), last_O.coord()])

    shortest_point = getShortestPoint(last_O.coord(), new_CA_bond_pos)

    new_CA = addAtom('CA', chimera.Element(6), new_res, shortest_point)
    new_CA.drawMode = kw['atomDrawMode']
    new_CA.bfactor = kw['bFactor']

    addBond(new_N, new_CA, drawMode=kw['bondDrawMode'])

    return new_CA
Exemplo n.º 6
0
    def add_dummy_atom(self,
                       where,
                       name='dum',
                       element=None,
                       residue=None,
                       bonded_to=None,
                       serial=None):
        """
        Adds a placeholder atom at the coordinates specified by `where`

        Parameters
        ----------
        where : chimera.Atom or 3-tuple of float
            Coordinates of target location. A chimera.Atom can be supplied,
            in which case its coordinates will be used (via `.coord()`)
        name : str, optional
            Name for the new atom
        element : chimera.Element, optional
            Element of the new atom
        residue : chimera.Residue, optional
            Residue that will incorporate the new atom
        bonded_to : chimera.Atom, optional
            Atom that will form a bond with new atom
        serial : int
            Serial number that will be assigned to atom

        """
        if isinstance(where, chimera.Atom):
            element = where.element if not element else element
            where = where.coord()
        else:
            element = chimera.Element('C')

        residue = self.mol.residues[-1] if not residue else residue
        return addAtom(name, element, residue, where, serial, bonded_to)
Exemplo n.º 7
0
def _phosphorylate(mols, status, deletes):
	replyobj.info("Deleting 5' phosphates from: %s\n" %
					", ".join([str(r) for r in deletes]))
	from chimera.molEdit import addAtom
	for r in deletes:
		r.amberName += "5"
		for p in r.atomsMap['P']:
			o = None
			for nb in p.neighbors:
				for nnb in nb.neighbors:
					if nnb == p:
						continue
					if nnb.element.number > 1:
						o = nb
						continue
					r.molecule.deleteAtom(nnb)
				if nb != o:
					r.molecule.deleteAtom(nb)
			v = p.coord() - o.coord()
			sn = getattr(p, "serialNumber", None)
			r.molecule.deleteAtom(p)
			v.length = 0.96
			addAtom("H5T", chimera.Element('H'), r, o.coord() + v,
						serialNumber=sn, bondedTo=o)
def completeTerminalCarboxylate(cter):
    from chimera.bondGeom import bondPositions
    from chimera.molEdit import addAtom
    if "OXT" in cter.atomsMap:
        return
    try:
        cs = cter.atomsMap["C"]
    except KeyError:
        return
    for c in cs:  # alt locs are possible
        if len(c.primaryBonds()) != 2:
            return
        loc = bondPositions(c.coord(), 3, 1.229,
                            [n.coord() for n in c.primaryNeighbors()])[0]
        oxt = addAtom("OXT", chimera.Element("O"), cter, loc, bondedTo=c)
    replyobj.info("Missing OXT added to C-terminal residue %s\n" % str(cter))
Exemplo n.º 9
0
def placeFragment(fragment, resName, model="scratch", position=None):
	"""place a Fragment (see Fragment.py)

	   'resName' is the name of the new residue that will contain the
	   fragment.  (It will be in the 'het' chain.)

	   'model' can either be a chimera.Molecule instance or a string.
	   If the latter, then a new model is created with the string as
	   its .name attribute.

	   'position' can either be a chimera.Point or None.  If None, then
	   the fragment is positioned at the center of the view.
	"""

	if isinstance(model, basestring):
		model = _newModel(model)
	r = _newResidue(model, resName)
	needFocus = False
	if position is None:
		if len(chimera.openModels.list()) == 1:
			needFocus = True
		xf = model.openState.xform
		position = xf.inverse().apply(
				Point(*chimera.viewer.camera.center))
	# find fragment center
	x = y = z = 0.0
	for element, xyz in fragment.atoms:
		x += xyz[0]
		y += xyz[1]
		z += xyz[2]
	numAtoms = len(fragment.atoms)
	fragCenter = Point(x / numAtoms, y / numAtoms, z / numAtoms)
	correction = position - fragCenter

	from chimera.molEdit import addAtom, genAtomName
	atoms = []
	for element, xyz in fragment.atoms:
		atoms.append(addAtom(genAtomName(element, r), Element(element),
						r, Point(*xyz) + correction))
	for indices, depict in fragment.bonds:
		r.molecule.newBond(atoms[indices[0]], atoms[indices[1]])
	if needFocus:
		chimera.runCommand("focus")
	return r
Exemplo n.º 10
0
def placeFragment(fragment, resName, model="scratch", position=None):
    """place a Fragment (see Fragment.py)

	   'resName' is the name of the new residue that will contain the
	   fragment.  (It will be in the 'het' chain.)

	   'model' can either be a chimera.Molecule instance or a string.
	   If the latter, then a new model is created with the string as
	   its .name attribute.

	   'position' can either be a chimera.Point or None.  If None, then
	   the fragment is positioned at the center of the view.
	"""

    if isinstance(model, basestring):
        model = _newModel(model)
    r = _newResidue(model, resName)
    needFocus = False
    if position is None:
        if len(chimera.openModels.list()) == 1:
            needFocus = True
        xf = model.openState.xform
        position = xf.inverse().apply(Point(*chimera.viewer.camera.center))
    # find fragment center
    x = y = z = 0.0
    for element, xyz in fragment.atoms:
        x += xyz[0]
        y += xyz[1]
        z += xyz[2]
    numAtoms = len(fragment.atoms)
    fragCenter = Point(x / numAtoms, y / numAtoms, z / numAtoms)
    correction = position - fragCenter

    from chimera.molEdit import addAtom, genAtomName
    atoms = []
    for element, xyz in fragment.atoms:
        atoms.append(
            addAtom(genAtomName(element, r), Element(element), r,
                    Point(*xyz) + correction))
    for indices, depict in fragment.bonds:
        r.molecule.newBond(atoms[indices[0]], atoms[indices[1]])
    if needFocus:
        chimera.runCommand("focus")
    return r
Exemplo n.º 11
0
def addNewN(last_bbone_ats, new_res, **kw):

    ## add the N atom of new residue's backbone to the last residue
    last_C = last_bbone_ats['C']

    new_N_bond_pos = bondPositions(
        bondee=last_C.coord(),
        geom=chimera.Atom.Planar,
        bondLen=DIST_N_C,
        bonded=[a.coord() for a in last_C.neighbors])

    use_point = new_N_bond_pos[0]
    new_N = addAtom('N', chimera.Element(7), new_res, use_point)
    new_N.drawMode = kw['atomDrawMode']
    new_N.bfactor = kw['bFactor']

    addBond(last_C, new_N, drawMode=kw['bondDrawMode'])

    return new_N
Exemplo n.º 12
0
def reposLastO(last_res, last_bbone_ats, atom_drawMode, bond_drawMode):
    ## reposition the last residue's 'O' atom
    last_O = getBboneAtom(last_res, 'O')
    last_res.molecule.deleteAtom(last_O)

    last_C = last_bbone_ats['C']
    last_CA = last_bbone_ats['CA']

    old_O_bond_pos = bondPositions(
        bondee=last_C.coord(),
        geom=chimera.Atom.Planar,
        bondLen=1.229,
        bonded=[a.coord() for a in last_C.neighbors])

    ## should only be one spot left
    old_O_bond_pos = old_O_bond_pos[0]
    new_O = addAtom('O', chimera.Element(8), last_res, old_O_bond_pos)
    new_O.drawMode = atom_drawMode
    addBond(new_O, last_C, drawMode=bond_drawMode)

    return new_O
Exemplo n.º 13
0
def placeHelium(resName, model="scratch", position=None):
    """place a new helium atom

	   'resName' is the name of the new residue that will contain the
	   helium.  (It will be in the 'het' chain.)

	   'model' can either be a chimera.Molecule instance or a string.
	   If the latter, then a new model is created with the string as
	   its .name attribute.

	   'position' can either be a chimera.Point or None.  If None, then
	   the helium is positioned at the center of the view.
	"""

    if isinstance(model, basestring):
        model = _newModel(model)

    r = _newResidue(model, resName)
    if position is None:
        xf = model.openState.xform
        position = xf.inverse().apply(Point(*chimera.viewer.camera.center))
    from chimera.molEdit import addAtom
    return addAtom('He1', Element('He'), r, position)
def newHydrogen(parentAtom, Hnum, totalHydrogens, namingSchema, pos):
    global _serial, _metals
    nearbyMetals = _metals.searchTree(pos.data(), _metalDist)
    for metal in nearbyMetals:
        if metal.molecule != parentAtom.molecule:
            continue
        metalPos = metal.coord()
        parentPos = parentAtom.coord()
        if metalClash(metalPos, pos, parentPos):
            return
    newH = addAtom(_Hname(parentAtom, Hnum, totalHydrogens, namingSchema),
                   Element(1),
                   parentAtom.residue,
                   pos,
                   serialNumber=_serial,
                   bondedTo=parentAtom)
    _serial = newH.serialNumber + 1
    from Midas import elementColor
    parentColor = parentAtom.color
    if parentColor == elementColor(parentAtom.element.name):
        newH.color = elementColor("H")
    else:
        newH.color = parentColor
Exemplo n.º 15
0
def placeHelium(resName, model="scratch", position=None):
	"""place a new helium atom

	   'resName' is the name of the new residue that will contain the
	   helium.  (It will be in the 'het' chain.)

	   'model' can either be a chimera.Molecule instance or a string.
	   If the latter, then a new model is created with the string as
	   its .name attribute.

	   'position' can either be a chimera.Point or None.  If None, then
	   the helium is positioned at the center of the view.
	"""

	if isinstance(model, basestring):
		model = _newModel(model)

	r = _newResidue(model, resName)
	if position is None:
		xf = model.openState.xform
		position = xf.inverse().apply(
				Point(*chimera.viewer.camera.center))
	from chimera.molEdit import addAtom
	return addAtom('He1', Element('He'), r, position)
Exemplo n.º 16
0
    def include_dummies(self, metal_class):
        """
        Include oriented Dummy Atoms
        inside the molecular system.

        Parameters
        ----------

        metal_class: str
                Build - in Metal class pointer
        """
        metal = metal_class.metal
        residue = metal.residue

        # Remove existing pseudobonds
        if hasattr(metal, 'pseudoBonds') and metal.pseudoBonds:
            metal.pseudoBonds[0].pseudoBondGroup.deleteAll()

        # Adding Dummies
        for i, dummy in enumerate(metal_class.dummies):
            dummy.atom = addAtom("D{}".format(i + 1), Element(dummy.Type),
                                 residue, chimera.Coord(dummy.xyz))
            dummy.atom.drawMode = 3
            dummy.atom.radius = 0.2
def postAdd(fakeN, fakeC):
    # fix up non-"true" terminal residues (terminal simply because
    # next residue is missing)
    for fn in fakeN:
        try:
            n = fn.atomsMap["N"][0]
            ca = fn.atomsMap["CA"][0]
            c = fn.atomsMap["C"][0]
        except KeyError:
            continue
        dihed = None
        for cnb in c.primaryNeighbors():
            if cnb.name == "N":
                pn = cnb
                break
        else:
            dihed = 0.0
        if dihed is None:
            try:
                pr = pn.residue
                pc = pr.atomsMap["C"][0]
                pca = pr.atomsMap["CA"][0]
                if pr.type == "PRO":
                    ph = pr.atomsMap["CD"][0]
                else:
                    ph = pr.atomsMap["H"][0]
            except KeyError:
                dihed = 0.0
        for nb in n.primaryNeighbors():
            if nb.element.number == 1:
                nb.molecule.deleteAtom(nb)
        if fn.type == "PRO":
            continue
        if dihed is None:
            dihed = chimera.dihedral(pc.coord(), pca.coord(), pn.coord(),
                                     ph.coord())
        replyobj.info("Adding 'H' to %s\n" % str(fn))
        from chimera.molEdit import addDihedralAtom, addBond
        h = addDihedralAtom("H",
                            Element(1),
                            n,
                            ca,
                            c,
                            1.01,
                            120.0,
                            dihed,
                            bonded=True)
        # also need to set N's IDATM type, because if we leave it as
        # N3+ then the residue will be identified by AddCharge as
        # terminal and there will be no charge for the H atom
        n.idatmType = "Npl"

    for fc in fakeC:
        try:
            c = fc.atomsMap["C"][0]
        except KeyError:
            continue
        for nb in c.primaryNeighbors():
            if nb.element.number == 1:
                replyobj.info("Removing spurious proton from"
                              " 'C' of %s\n" % str(fc))
                nb.molecule.deleteAtom(nb)
        # the N proton may have been named 'HN'; fix that
        try:
            hn = fc.atomsMap["HN"][0]
        except KeyError:
            continue
        addAtom("H",
                Element(1),
                fc,
                hn.coord(),
                serialNumber=hn.serialNumber,
                bondedTo=hn.neighbors[0])
        fc.molecule.deleteAtom(hn)
Exemplo n.º 18
0
def placePeptide(sequence, phiPsis, model="scratch", position=None,
						rotlib=None, chainID='A'):
	"""place a peptide sequence

	   'sequence' contains the (upper case) sequence

	   'phiPsis' is a list of phi/psi tuples, one per residue

	   'model' can either be a chimera.Molecule instance or a string.
	   If the latter, then a new model is created with the string as
	   its .name attribute.

	   'position' can either be a chimera.Point or None.  If None, then
	   the fragment is positioned at the center of the view.
	"""

	if not sequence:
		raise ValueError("No sequence supplied")
	sequence = sequence.upper()
	if not sequence.isupper():
		raise ValueError("Sequence contains non-alphabetic characters")
	from chimera.resCode import protein1to3
	for c in sequence:
		if c not in protein1to3:
			raise ValueError("Unrecognized protein 1-letter code:"
								" %s" % c)
	if len(sequence) != len(phiPsis):
		raise ValueError("Number of phi/psis not equal to"
							" sequence length")
	if isinstance(model, basestring):
		model = _newModel(model)
	needFocus = False
	if position is None:
		if len(chimera.openModels.list()) == 1:
			needFocus = True
		xf = model.openState.xform
		position = xf.inverse().apply(
				Point(*chimera.viewer.camera.center))
	prev = [None] * 3
	pos = 1
	from Midas.addAA import DIST_N_C, DIST_CA_N, DIST_C_CA, DIST_C_O
	from chimera.molEdit import findPt, addAtom, addDihedralAtom
	serialNumber = None
	residues = []
	for c, phiPsi in zip(sequence, phiPsis):
		phi, psi = phiPsi
		while model.findResidue(chimera.MolResId(chainID, pos)):
			pos += 1
		r = model.newResidue(protein1to3[c], chainID, pos, ' ')
		residues.append(r)
		for backbone, dist, angle, dihed in (
				('N', DIST_N_C, 116.6, psi),
				('CA', DIST_CA_N, 121.9, 180.0),
				('C', DIST_C_CA, 110.1, phi)):
			if prev[0] == None:
				pt = Point(0.0, 0.0, 0.0)
			elif prev[1] == None:
				pt = Point(dist, 0.0, 0.0)
			elif prev[2] == None:
				pt = findPt(prev[0].coord(), prev[1].coord(),
					Point(0.0, 1.0, 0.0), dist, angle, 0.0)
			else:
				pt = findPt(prev[0].coord(), prev[1].coord(),
					prev[2].coord(), dist, angle, dihed)
			a = addAtom(backbone, Element(backbone[0]), r, pt,
				serialNumber=serialNumber, bondedTo=prev[0])
			serialNumber = a.serialNumber + 1
			prev = [a] + prev[:2]
		o = addDihedralAtom("O", Element("O"), prev[0], prev[1],
			prev[2], DIST_C_O, 120.4, 180.0 + psi, bonded=True)
	# C terminus O/OXT at different angle than mainchain O
	model.deleteAtom(o)
	addDihedralAtom("O", Element("O"), prev[0], prev[1],
			prev[2], DIST_C_O, 117.0, 180.0 + psi, bonded=True)
	addDihedralAtom("OXT", Element("O"), prev[0], prev[1], prev[2],
					DIST_C_O, 117.0, psi, bonded=True)
	from Rotamers import useBestRotamers
	# have to process one by one, otherwise side-chain clashes will occur
	kw = {}
	if rotlib:
		kw['lib'] = rotlib
	for r in residues:
		useBestRotamers("same", [r], criteria="cp", log=False, **kw)
				
	# find peptide center
	coords = []
	for r in residues:
		coords.extend([a.coord() for a in r.atoms])
	center = Point(coords)
	correction = position - center
	for r in residues:
		for a in r.atoms:
			a.setCoord(a.coord() + correction)
	from Midas import ksdssp
	ksdssp([model])
	if needFocus:
		chimera.runCommand("focus")
	return residues
Exemplo n.º 19
0
def changeAtom(atom, element, geometry, numBonds, autoClose=True, name=None):
    if len(atom.primaryBonds()) > numBonds:
        raise ParamError(
            "Atom already has more bonds than requested.\n"
            "Either delete some bonds or choose a different number"
            " of requested bonds.")
    from chimera.molEdit import addAtom, genAtomName
    changedAtoms = [atom]
    if not name:
        name = genAtomName(element, atom.residue)
    changeAtomName(atom, name)
    atom.element = element
    if hasattr(atom, 'mol2type'):
        delattr(atom, 'mol2type')

    # if we only have one bond, correct its length
    if len(atom.primaryBonds()) == 1:
        neighbor = atom.primaryNeighbors()[0]
        newLength = bondLength(atom,
                               geometry,
                               neighbor.element,
                               a2info=(neighbor, numBonds))
        setBondLength(atom.primaryBonds()[0],
                      newLength,
                      movingSide="smaller side")

    if numBonds == len(atom.primaryBonds()):
        return changedAtoms

    from chimera.bondGeom import bondPositions
    coPlanar = None
    if geometry == 3 and len(atom.primaryBonds()) == 1:
        n = atom.primaryNeighbors()[0]
        if len(n.primaryBonds()) == 3:
            coPlanar = [
                nn.coord() for nn in n.primaryNeighbors() if nn != atom
            ]
    away = None
    if geometry == 4 and len(atom.primaryBonds()) == 1:
        n = atom.primaryNeighbors()[0]
        if len(n.primaryBonds()) > 1:
            nn = n.primaryNeighbors()[0]
            if nn == atom:
                nn = n.primaryNeighbors()[1]
            away = nn.coord()
    hydrogen = Element("H")
    positions = bondPositions(atom.coord(),
                              geometry,
                              bondLength(atom, geometry, hydrogen),
                              [n.coord() for n in atom.primaryNeighbors()],
                              coPlanar=coPlanar,
                              away=away)[:numBonds - len(atom.primaryBonds())]
    if autoClose:
        if len(atom.molecule.atoms) < 100:
            testAtoms = atom.molecule.atoms
        else:
            from CGLutil.AdaptiveTree import AdaptiveTree
            tree = AdaptiveTree(
                [a.coord().data() for a in atom.molecule.atoms],
                a.molecule.atoms, 2.5)
            testAtoms = tree.searchTree(atom.coord().data(), 5.0)
    else:
        testAtoms = []
    for pos in positions:
        for ta in testAtoms:
            if ta == atom:
                continue
            testLen = bondLength(ta, 1, hydrogen)
            testLen2 = testLen * testLen
            if (ta.coord() - pos).sqlength() < testLen2:
                bonder = ta
                # possibly knock off a hydrogen to
                # accomodate the bond...
                for bn in bonder.primaryNeighbors():
                    if bn.element.number > 1:
                        continue
                    if chimera.angle(atom.coord() - ta.coord(),
                                     bn.coord() - ta.coord()) > 45.0:
                        continue
                    if bn in testAtoms:
                        testAtoms.remove(bn)
                    atom.molecule.deleteAtom(bn)
                    break
                break
        else:
            bonder = addAtom(genAtomName(hydrogen, atom.residue),
                             hydrogen,
                             atom.residue,
                             pos,
                             bondedTo=atom)
            changedAtoms.append(bonder)
    return changedAtoms
Exemplo n.º 20
0
def placePeptide(sequence,
                 phiPsis,
                 model="scratch",
                 position=None,
                 rotlib=None,
                 chainID='A'):
    """place a peptide sequence

	   'sequence' contains the (upper case) sequence

	   'phiPsis' is a list of phi/psi tuples, one per residue

	   'model' can either be a chimera.Molecule instance or a string.
	   If the latter, then a new model is created with the string as
	   its .name attribute.

	   'position' can either be a chimera.Point or None.  If None, then
	   the fragment is positioned at the center of the view.
	"""

    if not sequence:
        raise ValueError("No sequence supplied")
    sequence = sequence.upper()
    if not sequence.isupper():
        raise ValueError("Sequence contains non-alphabetic characters")
    from chimera.resCode import protein1to3
    for c in sequence:
        if c not in protein1to3:
            raise ValueError("Unrecognized protein 1-letter code:" " %s" % c)
    if len(sequence) != len(phiPsis):
        raise ValueError("Number of phi/psis not equal to" " sequence length")
    if isinstance(model, basestring):
        model = _newModel(model)
    needFocus = False
    if position is None:
        if len(chimera.openModels.list()) == 1:
            needFocus = True
        xf = model.openState.xform
        position = xf.inverse().apply(Point(*chimera.viewer.camera.center))
    prev = [None] * 3
    pos = 1
    from Midas.addAA import DIST_N_C, DIST_CA_N, DIST_C_CA, DIST_C_O
    from chimera.molEdit import findPt, addAtom, addDihedralAtom
    serialNumber = None
    residues = []
    for c, phiPsi in zip(sequence, phiPsis):
        phi, psi = phiPsi
        while model.findResidue(chimera.MolResId(chainID, pos)):
            pos += 1
        r = model.newResidue(protein1to3[c], chainID, pos, ' ')
        residues.append(r)
        for backbone, dist, angle, dihed in (('N', DIST_N_C, 116.6, psi),
                                             ('CA', DIST_CA_N, 121.9, 180.0),
                                             ('C', DIST_C_CA, 110.1, phi)):
            if prev[0] == None:
                pt = Point(0.0, 0.0, 0.0)
            elif prev[1] == None:
                pt = Point(dist, 0.0, 0.0)
            elif prev[2] == None:
                pt = findPt(prev[0].coord(), prev[1].coord(),
                            Point(0.0, 1.0, 0.0), dist, angle, 0.0)
            else:
                pt = findPt(prev[0].coord(), prev[1].coord(), prev[2].coord(),
                            dist, angle, dihed)
            a = addAtom(backbone,
                        Element(backbone[0]),
                        r,
                        pt,
                        serialNumber=serialNumber,
                        bondedTo=prev[0])
            serialNumber = a.serialNumber + 1
            prev = [a] + prev[:2]
        o = addDihedralAtom("O",
                            Element("O"),
                            prev[0],
                            prev[1],
                            prev[2],
                            DIST_C_O,
                            120.4,
                            180.0 + psi,
                            bonded=True)
    # C terminus O/OXT at different angle than mainchain O
    model.deleteAtom(o)
    addDihedralAtom("O",
                    Element("O"),
                    prev[0],
                    prev[1],
                    prev[2],
                    DIST_C_O,
                    117.0,
                    180.0 + psi,
                    bonded=True)
    addDihedralAtom("OXT",
                    Element("O"),
                    prev[0],
                    prev[1],
                    prev[2],
                    DIST_C_O,
                    117.0,
                    psi,
                    bonded=True)
    from Rotamers import useBestRotamers
    # have to process one by one, otherwise side-chain clashes will occur
    kw = {}
    if rotlib:
        kw['lib'] = rotlib
    for r in residues:
        useBestRotamers("same", [r], criteria="cp", log=False, **kw)

    # find peptide center
    coords = []
    for r in residues:
        coords.extend([a.coord() for a in r.atoms])
    center = Point(coords)
    correction = position - center
    for r in residues:
        for a in r.atoms:
            a.setCoord(a.coord() + correction)
    from Midas import ksdssp
    ksdssp([model])
    if needFocus:
        chimera.runCommand("focus")
    return residues
Exemplo n.º 21
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
Exemplo n.º 22
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
Exemplo n.º 23
0
def initiateAddions(models, iontype, numion, status):
    import os
    import chimera
    from chimera import replyobj
    from chimera.molEdit import addAtom
    from WriteMol2 import writeMol2
    from tempfile import mkdtemp

    for m in models:
        tempDir = mkdtemp()

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

        sleapIn = os.path.join(tempDir, "sleap.in.mol2")
        sleapOut = os.path.join(tempDir, "sleap.out.mol2")
        writeMol2([m], sleapIn, status=status, gaffType=True)

        leaprc = os.path.join(tempDir, "solvate.cmd")
        writeLeaprc(tempDir, iontype, numion, leaprc)

        chimeraRoot = os.environ["CHIMERA"]
        amberHome = os.path.join(chimeraRoot, "bin", "amber10")
        command = [os.path.join(amberHome, "exe", "sleap"), "-f", leaprc]

        if status:
            status("Running sleap")
        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 sleap command: %s\n" % " ".join(command))
        import os
        os.environ["AMBERHOME"] = amberHome
        sleapMessages = Popen(command,
                              stdin=PIPE,
                              stdout=PIPE,
                              stderr=STDOUT,
                              cwd=tempDir,
                              shell=shell,
                              bufsize=1).stdout
        while True:
            line = sleapMessages.readline()
            if not line:
                break
            replyobj.status("(addions) %s" % line, log=True)
        if not os.path.exists(sleapOut):
            _clean()
            from chimera import NonChimeraError
            raise NonChimeraError("Failure running sleap \n"
                                  "Check reply log for details\n")
        if status:
            status("Reading sleap output\n")
        from chimera import Mol2io, defaultMol2ioHelper
        mol2io = Mol2io(defaultMol2ioHelper)
        mols = mol2io.readMol2file(sleapOut)
        if not mol2io.ok():
            _clean()
            raise IOError(mol2io.error())
        if not mols:
            _clean()
            raise RuntimeError("No molecules in sleap output")

        assert len(mols) == 1

        outm = mols[0]
        solute_nresd = get_solute_nresd(m)
        print "total, solute, solvent: ", len(
            m.residues), solute_nresd, len(m.residues) - solute_nresd

        if status:
            status("Deleting old solvents")
        while len(m.residues) > solute_nresd:
            m.deleteResidue(m.residues[solute_nresd])

        inAtoms = m.atoms
        outAtoms = outm.atoms
        # sort in coordIndex (i.e. input) order
        # (due to deletions, coordIndex values need _not_ be consecutive)
        serialSort = lambda a1, a2: cmp(a1.coordIndex, a2.coordIndex)
        inAtoms.sort(serialSort)
        outAtoms.sort(serialSort)

        # sleap repositions solute...
        if status:
            status("Translating %d atoms" % len(inAtoms))
        for inA, outA in zip(inAtoms, outAtoms[:len(inAtoms)]):
            inA.setCoord(outA.coord())

        for r in outm.residues[solute_nresd:]:
            if status:
                status("Creating ions/solvent residue %d " %
                       (r.id.position - solute_nresd))

            atomMap = {}
            nr = m.newResidue(r.type, ' ', 1, ' ')
            for a in r.atoms:
                na = addAtom(a.name,
                             a.element,
                             nr,
                             a.coord(),
                             serialNumber=a.serialNumber)
                na.charge = a.charge
                na.gaffType = a.mol2type

                if len(a.neighbors) == 0:
                    na.drawMode = chimera.Atom.Sphere

                atomMap[a] = na

                if a.name[0:2] == "Br": na.element = 35
                elif a.name[0:2] == "Cl": na.element = 17
                elif a.name[0:2] == "Cs": na.element = 47
                elif a.name[0:2] == "Mg": na.element = 12
                elif a.name[0:2] == "Na": na.element = 11
                elif a.name[0:2] == "Rb": na.element = 48
                elif a.name[0] == 'F': na.element = 9
                elif a.name[0] == 'I': na.element = 53
                elif a.name[0] == 'K': na.element = 19
                elif a.name[0] == "H": na.element = 1
                elif a.name[0] == "C": na.element = 6
                elif a.name[0] == "N": na.element = 7
                elif a.name[0] == "O": na.element = 8
                elif a.name[0] == "P": na.element = 15
                elif a.name[0] == "S": na.element = 16

            for a in r.atoms:
                na = atomMap[a]
                for n in a.neighbors:
                    assert n.residue == r
                    nn = atomMap[n]
                    if nn in na.bondsMap:
                        continue
                    m.newBond(na, nn)
        _clean()
def combine(mols, refMol, newChainIDs=True, log=False, returnMapping=False):
    from chimera import replyobj

    # figure out residue chain/number remapping
    origChainIDs = {}
    numChains = 0
    minNums = {}
    maxNums = {}
    for m in mols:
        seenIDs = set()
        for r in m.residues:
            chainID = r.id.chainId
            num = r.id.position
            key = (m, chainID)
            if key in minNums:
                if num > maxNums[key]:
                    maxNums[key] = num
                elif num < minNums[key]:
                    minNums[key] = num
            else:
                minNums[key] = maxNums[key] = num
            if chainID in seenIDs:
                continue
            numChains += 1
            seenIDs.add(chainID)
            origChainIDs.setdefault(chainID, []).append(m)
    resMap = {}
    if newChainIDs:
        if numChains > 62:
            raise CombineError("More than 62 chains; cannot"
                               " uniquely identify with single characters")
        from string import uppercase, lowercase, digits
        possibleIDs = uppercase + lowercase + digits
        usedChainIDs = set(origChainIDs.keys())
        chainIDmap = {}
        for chainID, idMols in origChainIDs.items():
            if len(chainID) > 1:
                continue
            chainIDmap[(idMols[0], chainID)] = chainID
            usedChainIDs.add(chainID)
            for m in idMols[1:]:
                for c in possibleIDs:
                    if c not in usedChainIDs:
                        break
                if log:
                    replyobj.info("Remapping %s chain %s"
                                  " to %s\n" % (m, chainID, c))
                usedChainIDs.add(c)
                chainIDmap[(m, chainID)] = c
        for m in mols:
            for r in m.residues:
                chainID = r.id.chainId
                if len(chainID) > 1:
                    continue
                resMap[r] = (chainIDmap[(m, chainID)], r.id.position)
    # handle renumbering for all chains if newChainIDs False,
    # otherwise just water/het chains
    offsets = {}
    for chainID, idMols in origChainIDs.items():
        if newChainIDs and len(chainID) < 2:
            continue
        minMaxs = []
        for m in idMols:
            mmin = minNums[(m, chainID)]
            mmax = maxNums[(m, chainID)]
            for omin, omax in minMaxs:
                if omin < mmin < omax or omin < mmax < omax:
                    gmax = max([mm[1] for mm in minMaxs])
                    offset = gmax - mmin + 1
                    break
            else:
                offset = 0
            offsets[(m, chainID)] = offset
            minMaxs.append((mmin + offset, mmax + offset))
            if log and offset:
                replyobj.info("Adding %d to %s chain %s"
                              " numbering\n" % (offset, m, chainID))
    for m in mols:
        for r in m.residues:
            chainID = r.id.chainId
            try:
                offset = offsets[(m, chainID)]
            except KeyError:
                continue
            resMap[r] = (chainID, r.id.position + offset)

    # combine...
    from chimera import Atom, Bond, Residue, Molecule
    combined = Molecule()
    combined.name = "combination"
    from SimpleSession.save import optionalAttributes
    from chimera.molEdit import addAtom
    atomAttrs = optionalAttributes[Atom].keys() + [
        'color', 'vdwColor', 'labelColor', 'surfaceColor', 'drawMode',
        'display', 'label', 'radius', 'surfaceDisplay', 'surfaceCategory',
        'surfaceOpacity', 'vdw'
    ]
    bondAttrs = optionalAttributes[Bond].keys() + [
        'drawMode', 'display', 'radius'
    ]
    resAttrs = optionalAttributes[Residue].keys() + [
        'ribbonColor', 'labelColor', 'isHelix', 'isSheet', 'isTurn',
        'ribbonDrawMode', 'ribbonDisplay', 'label', 'isHet'
    ]
    serial = 1
    atomMap = {}
    for m in mols:
        if m.openState == refMol.openState:
            xform = None
        else:
            xform = refMol.openState.xform
            xform.invert()
        for r in m.residues:
            chainID, pos = resMap[r]
            nr = combined.newResidue(r.type, chainID, pos, r.id.insertionCode)
            for attrName in resAttrs:
                try:
                    setattr(nr, attrName, getattr(r, attrName))
                except AttributeError:
                    continue
            ratoms = r.atoms
            ratoms.sort(lambda a1, a2: cmp(a1.coordIndex, a2.coordIndex))
            for a in ratoms:
                if xform is None:
                    crd = a.coord()
                else:
                    crd = xform.apply(a.xformCoord())
                na = addAtom(a.name, a.element, nr, crd, serialNumber=serial)
                na.altLoc = a.altLoc
                atomMap[a] = na
                serial += 1
                for attrName in atomAttrs:
                    try:
                        setattr(na, attrName, getattr(a, attrName))
                    except AttributeError:
                        continue
        for b in m.bonds:
            a1, a2 = b.atoms
            nb = combined.newBond(atomMap[a1], atomMap[a2])
            for attrName in bondAttrs:
                try:
                    setattr(nb, attrName, getattr(b, attrName))
                except AttributeError:
                    continue
    consensusAttrs = [
        'color', 'display', 'lineWidth', 'pointSize', 'stickScale',
        'surfaceOpacity', 'ballScale', 'vdwDensity', 'autochain',
        'ribbonHidesMainchain'
    ]
    for attrName in consensusAttrs:
        consensusVal = None
        for m in mols:
            val = getattr(m, attrName)
            if consensusVal == None:
                consensusVal = val
            elif val != consensusVal:
                break
        else:
            setattr(combined, attrName, consensusVal)

    associatedModels = set()
    for m in mols:
        associatedModels.update(m.associatedModels())
    from chimera import PseudoBondMgr
    for opbg in PseudoBondMgr.mgr().pseudoBondGroups:
        if opbg in associatedModels:
            if opbg.category.startswith("internal-chain-"):
                continue
            assert (opbg.category.startswith("coordination complex"))
            from chimera.misc import getPseudoBondGroup
            pbg = getPseudoBondGroup("coordination complexes of %s" %
                                     combined.name,
                                     associateWith=[combined])
            for attrName in [
                    'color', 'showStubBonds', 'lineWidth', 'stickScale',
                    'lineType'
            ]:
                setattr(pbg, attrName, getattr(opbg, attrName))
        else:
            pbg = opbg
        for opb in opbg.pseudoBonds:
            oa1, oa2 = opb.atoms
            na1 = atomMap.get(oa1, oa1)
            na2 = atomMap.get(oa2, oa2)
            if oa1 == na1 and oa2 == na2:
                continue
            pb = pbg.newPseudoBond(na1, na2)
            for attrName in [
                    'drawMode', 'display', 'halfbond', 'label', 'color',
                    'labelColor'
            ]:
                setattr(pb, attrName, getattr(opb, attrName))

    if returnMapping:
        return atomMap, combined
    return combined
Exemplo n.º 25
0
    def join(self, molecule, acceptor, donor, newres=False):
        """
        Take a molecule and bond it to `self.mol`, copying the atoms in the
        process so they're contained in the same `chimera.Molecule` object.

        Parameters
        ----------
        molecule : Compound
            The molecule that will be attached to `self`
        acceptor : chimera.Atom
            Atom of `self` that will participate in the new bond
        donor : chimera.Atom
            Atom of `molecule` that will participate in the new bond
        newres : bool
            If True, don't reuse `acceptor.residue` for the new molecule,
            and create a new blank one instead.

        Returns
        -------
        built_atoms : dict
            Maps original atoms in `molecules` to their new counterparts
            in `self.mol`.

        Notes
        -----
        .. note ::

            Chimera does not allow bonds between different chimera.Molecule
            objects, so firstly, we have to copy the atoms of ``molecule`` to
            ``self.mol`` and, only then, make the joining bond.

            It traverses the atoms of ``molecule`` and adds a copy of each
            of them to ``self.mol`` using ``chimera.molEdit.addAtom`` in the same spot
            of space. All the bonds are preserved and, finally, bond the two molecules.

            The algorithm starts by adding the bonding atom of ``molecule`` (``donor``), to
            the ``sprouts`` list. Then, the loop starts:

            .. code-block:: python

                while sprouts contains atoms:
                    sprout = sprouts.pop(0)
                    copy sprout to self.mol
                    for each neighbor of sprout
                        copy neighbor to self.mol
                        if neighbor itself has more than one neighbor (ie, sprout)
                            add neighbor to sprouts

            Along the way, we have to take care of already processed sprouts, so we
            don't repeat ourselves. That's what the built_atoms dict is for.

            Also, instead of letting addAtom guess new serial numbers, we calculate
            them beforehand by computing the highest serial number in ``self.mol``
            prior to the additions and then incremeting one by one on a per-element
            basis.

        .. todo ::

            This code is UGLY. Find a better way!
        """
        target = acceptor
        sprouts = [donor]
        res = _dummy_mol().residues[0] if newres else target.residue
        # I think I was trying to keep a copy of the original residue,
        # but this does not copy anything. Since lists are mutable, we
        # are just aliasing res.atoms with res_atoms.
        # Maybe I want something like:
        # res_atoms = res.atoms[:] # ?
        res_atoms = res.atoms

        i = max(a.serialNumber for a in self.mol.atoms)
        index = box.highest_atom_indices(self.mol)
        for a in molecule.mol.atoms:
            try:
                index[a.element.name] += 1
            except KeyError:
                index[a.element.name] = 1
            finally:
                a.name = a.element.name + str(index[a.element.name])
        built_atoms = {}
        while sprouts:
            sprout = sprouts.pop(0)  # get first atom
            if sprout.name in res.atomsMap:
                target = res.atomsMap[sprout.name][-1]
            else:
                i += 1
                built_atoms[sprout] = target = addAtom(sprout.name,
                                                       sprout.element,
                                                       res,
                                                       sprout.coord(),
                                                       bondedTo=target,
                                                       serialNumber=i)

            for a in sprout.neighbors:
                if a.element.number == 1:
                    continue
                if a.name not in res.atomsMap:
                    needBuild = True
                else:
                    # atom is already present, but it can be part of a cycle
                    # if we get to it it's because another atom is linking it
                    needBuild = False
                    built = res.atomsMap[a.name][-1]
                if needBuild:
                    i += 1
                    built_atoms[a] = built = addAtom(a.name,
                                                     a.element,
                                                     res,
                                                     a.coord(),
                                                     bondedTo=target,
                                                     serialNumber=i)
                    # if a has more than one neighbor:
                    if len(a.neighbors) > 1:
                        sprouts.append(a)  # this new atom can be a new sprout
                # link!
                if built not in target.bondsMap and built not in res_atoms:
                    addBond(target, built)

        self.built_atoms.append(
            {a.serialNumber: b
             for (a, b) in built_atoms.items()})
        return built_atoms
Exemplo n.º 26
0
def swap(res, newRes, preserve=0, bfactor=True):
    """change 'res' into type 'newRes'"""

    if res == "HIS":
        res = "HIP"
    fixed, buds, start, end = getResInfo(res)

    tmplRes = chimera.restmplFindResidue(newRes, start, end)
    if not tmplRes:
        raise ValueError, "No connectivity template for residue '%s'"\
               % newRes
    # sanity check:  does the template have the bud atoms?
    for bud in buds:
        if not tmplRes.atomsMap.has_key(bud):
            raise ValueError, "New residue type (%s) " \
              "not compatible with starting residue type (%s)" \
                  % (newRes, res.type)

    # if bfactor not specified, find highest bfactor in molecule
    # and use that for swapped-in atoms
    if bfactor is False:
        bfactor = None
    if bfactor is True:
        for a in res.molecule.atoms:
            try:
                if bfactor is True or a.bfactor > bfactor:
                    bfactor = a.bfactor
            except AttributeError:
                pass

    if preserve:
        raise ValueError, "'preserve' keyword not yet implemented"

    # prune non-backbone atoms
    for a in res.oslChildren():
        if a.name not in fixed:
            a.molecule.deleteAtom(a)

    # add new sidechain
    while len(buds) > 0:
        bud = buds.pop()
        tmplBud = tmplRes.atomsMap[bud]
        resBud = res.atomsMap[bud][0]

        try:
            info = typeInfo[tmplBud.idatmType]
            geom = info.geometry
            subs = info.substituents
        except KeyError:
            print tmplBud.idatmType
            raise AssertionError, "Can't determine atom type" \
             " information for atom %s of residue %s" % (
             bud, res.oslIdent())

        # use coord() rather than xformCoord():  we want to set
        # the new atom's coord(), to which the proper xform will
        # then be applied
        for a, b in tmplBud.bondsMap.items():
            if a.element.number == 1:
                # don't add hydrogens
                continue
            if res.atomsMap.has_key(a.name):
                resBonder = res.atomsMap[a.name][0]
                if not resBud.bondsMap.has_key(resBonder):
                    addBond(a, resBonder)
                continue

            newAtom = None
            numBonded = len(resBud.bonds)
            if numBonded >= subs:
                raise AssertionError, \
                 "Too many atoms bonded to %s of" \
                 " residue %s" % (bud, res.oslIdent())
            if numBonded == 0:
                raise AssertionError, \
                 "Atom %s of residue %s has no" \
                 " neighbors after pruning?!?" % (
                 bud, res.oslIdent())
            elif numBonded == 1:
                # only one connected atom -- have to use
                # dihedral
                real1 = resBud.neighbors[0]
                newAtom = formDihedral(resBud, real1, tmplRes, a, b)
            elif numBonded == 2:
                crd = resBud.coord()
                bonded = resBud.neighbors
                bcrds = map(lambda a: a.coord(), bonded)
                positions = bondPositions(crd, geom, b.length(), bcrds)
                if len(positions) > 1:
                    # need to disambiguate choices;
                    # check improper dihedral

                    # but first, make sure the bonded
                    # atoms are in this residue
                    inres = filter(lambda a, r=res: a.residue == r, bonded)
                    if len(inres) == 0:
                        raise AssertionError, \
                        "Can't disambiguate " \
                        "tetrahedral position by " \
                        "forming in-residue dihedral " \
                        "for %s of residue %s" % (
                        bud, res.oslIdent())
                    if len(inres) == 1:
                        newAtom = formDihedral(resBud, inres[0], tmplRes, a, b)
                    else:
                        # okay, check improper dihedral
                        tmplBonded = map(
                            lambda a, tra=tmplRes.atomsMap: tra[a.name],
                            bonded)
                        tmplPts = map(lambda a: a.coord(),
                                      [a, tmplBud] + tmplBonded)
                        tmplDihed = apply(dihedral, tmplPts, {})
                        backPts = map(lambda a: a.coord(), [resBud] + bonded)
                        dh1 = apply(dihedral, tuple(positions[:1] + backPts),
                                    {})
                        dh2 = apply(dihedral, tuple(positions[1:] + backPts),
                                    {})
                        diff1 = abs(dh1 - tmplDihed)
                        diff2 = abs(dh2 - tmplDihed)
                        if diff1 > 180:
                            diff1 = 360 - diff1
                        if diff2 > 180:
                            diff2 = 360 - diff2
                        if diff1 < diff2:
                            position = positions[0]
                        else:
                            position = positions[1]
                else:
                    position = positions[0]
            else:
                crd = resBud.coord()
                bonded = resBud.neighbors
                bcrds = map(lambda a: a.coord(), bonded)
                positions = bondPositions(crd, geom, b.length(), bcrds)
                if len(positions) > 1:
                    raise AssertionError, \
                     "Too many positions returned" \
                     " for atom %s of residue %s" % (
                     bud, res.oslIdent())
                position = positions[0]

            if not newAtom:
                newAtom = addAtom(a.name, a.element, res, position)
            newAtom.drawMode = resBud.drawMode
            if bfactor is not None and bfactor is not True:
                newAtom.bfactor = bfactor

            # TODO: need to iterate over coordSets
            for bonded in a.bondsMap.keys():
                if not res.atomsMap.has_key(bonded.name):
                    continue
                addBond(newAtom, res.atomsMap[bonded.name][0])
            buds.append(newAtom.name)

    res.label = res.label.replace(res.type, newRes)
    res.type = newRes
Exemplo n.º 27
0
def changeAtom(atom, element, geometry, numBonds, autoClose=True, name=None):
	if len(atom.primaryBonds()) > numBonds:
		raise ParamError("Atom already has more bonds than requested.\n"
			"Either delete some bonds or choose a different number"
			" of requested bonds.")
	from chimera.molEdit import addAtom, genAtomName
	changedAtoms = [atom]
	if not name:
		name = genAtomName(element, atom.residue)
	changeAtomName(atom, name)
	atom.element = element
	if hasattr(atom, 'mol2type'):
		delattr(atom, 'mol2type')
		
	# if we only have one bond, correct its length
	if len(atom.primaryBonds()) == 1:
		neighbor = atom.primaryNeighbors()[0]
		newLength = bondLength(atom, geometry, neighbor.element,
						a2info=(neighbor, numBonds))
		setBondLength(atom.primaryBonds()[0], newLength,
					movingSide="smaller side")

	if numBonds == len(atom.primaryBonds()):
		return changedAtoms

	from chimera.bondGeom import bondPositions
	coPlanar = None
	if geometry == 3 and len(atom.primaryBonds()) == 1:
		n = atom.primaryNeighbors()[0]
		if len(n.primaryBonds()) == 3:
			coPlanar = [nn.coord() for nn in n.primaryNeighbors()
								if nn != atom]
	away = None
	if geometry == 4 and len(atom.primaryBonds()) == 1:
		n = atom.primaryNeighbors()[0]
		if len(n.primaryBonds()) > 1:
			nn = n.primaryNeighbors()[0]
			if nn == atom:
				nn = n.primaryNeighbors()[1]
			away = nn.coord()
	hydrogen = Element("H")
	positions = bondPositions(atom.coord(), geometry,
		bondLength(atom, geometry, hydrogen),
		[n.coord() for n in atom.primaryNeighbors()], coPlanar=coPlanar,
		away=away)[:numBonds-len(atom.primaryBonds())]
	if autoClose:
		if len(atom.molecule.atoms) < 100:
			testAtoms = atom.molecule.atoms
		else:
			from CGLutil.AdaptiveTree import AdaptiveTree
			tree = AdaptiveTree([a.coord().data()
						for a in atom.molecule.atoms],
						a.molecule.atoms, 2.5)
			testAtoms = tree.searchTree(atom.coord().data(), 5.0)
	else:
		testAtoms = []
	for pos in positions:
		for ta in testAtoms:
			if ta == atom:
				continue
			testLen = bondLength(ta, 1, hydrogen)
			testLen2 = testLen * testLen
			if (ta.coord() - pos).sqlength() < testLen2:
				bonder = ta
				# possibly knock off a hydrogen to
				# accomodate the bond...
				for bn in bonder.primaryNeighbors():
					if bn.element.number > 1:
						continue
					if chimera.angle(atom.coord()
							- ta.coord(), bn.coord()
							- ta.coord()) > 45.0:
						continue
					if bn in testAtoms:
						testAtoms.remove(bn)
					atom.molecule.deleteAtom(bn)
					break
				break
		else:
			bonder = addAtom(genAtomName(hydrogen, atom.residue),
				hydrogen, atom.residue, pos, bondedTo=atom)
			changedAtoms.append(bonder)
	return changedAtoms
Exemplo n.º 28
0
def useRotamer(oldRes, rots, log=False):
    """Takes a Residue instance and a list of one or more rotamers (as
	   returned by getRotamers) and swaps the Residue's side chain with
	   the given rotamers.  If more than one rotamer is in the list,
	   then alt locs will be used to distinguish the different side chains.
	"""
    try:
        oldN = oldRes.atomsMap["N"][0]
        oldCA = oldRes.atomsMap["CA"][0]
        oldC = oldRes.atomsMap["C"][0]
    except KeyError:
        raise LimitationError("N, CA, or C missing from %s:"
                              " needed for side-chain pruning algorithm" %
                              oldRes)
    import string
    altLocs = string.ascii_uppercase + string.ascii_lowercase \
       + string.digits + string.punctuation
    if len(rots) > len(altLocs):
        raise LimitationError("Don't have enough unique alternate "
                              "location characters to place %d rotamers." %
                              len(rots))
    rotAnchors = {}
    for rot in rots:
        rotRes = rot.residues[0]
        try:
            rotAnchors[rot] = (rotRes.atomsMap["N"][0],
                               rotRes.atomsMap["CA"][0])
        except KeyError:
            raise LimitationError("N or CA missing from rotamer:"
                                  " cannot matchup with original residue")
    # prune old side chain
    retain = set([oldN, oldCA, oldC])
    deathrow = [nb for nb in oldCA.neighbors if nb not in retain]
    serials = {}
    while deathrow:
        prune = deathrow.pop()
        serials[prune.name] = getattr(prune, "serialNumber", None)
        for nb in prune.neighbors:
            if nb not in deathrow and nb not in retain:
                deathrow.append(nb)
        oldRes.molecule.deleteAtom(prune)

    totProb = sum([r.rotamerProb for r in rots])
    oldAtoms = set([a.name for a in oldRes.atoms])
    for i, rot in enumerate(rots):
        rotRes = rot.residues[0]
        rotN, rotCA = rotAnchors[rot]
        if len(rots) > 1:
            altLoc = altLocs[i]
            extra = " using alt loc %s" % altLoc
        else:
            altLoc = None
            extra = ""
        if log:
            replyobj.info(
                "Applying %s rotamer (chi angles: %s) to"
                " %s%s\n" %
                (rotRes.type, " ".join(["%.1f" % c
                                        for c in rot.chis]), oldRes, extra))
        from BuildStructure import changeResidueType
        changeResidueType(oldRes, rotRes.type)
        # add new side chain
        from chimera.molEdit import addAtom, addBond
        sprouts = [rotCA]
        while sprouts:
            sprout = sprouts.pop()
            builtSprout = oldRes.atomsMap[sprout.name][-1]
            for nb, b in sprout.bondsMap.items():
                try:
                    builtNBs = oldRes.atomsMap[nb.name]
                except KeyError:
                    needBuild = True
                else:
                    if nb.name in oldAtoms or len(builtNBs) == i + 1:
                        needBuild = False
                    else:
                        needBuild = True
                if needBuild:
                    if i == 0:
                        serial = serials.get(nb.name, None)
                    else:
                        serial = None
                    builtNB = addAtom(nb.name,
                                      nb.element,
                                      oldRes,
                                      nb.coord(),
                                      serialNumber=serial,
                                      bondedTo=builtSprout)
                    if altLoc:
                        builtNB.altLoc = altLoc
                    builtNB.occupancy = rot.rotamerProb / totProb
                    sprouts.append(nb)
                else:
                    builtNB = builtNBs[-1]
                if builtNB not in builtSprout.bondsMap:
                    addBond(builtSprout, builtNB)
Exemplo n.º 29
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
Exemplo n.º 30
0
def combine(mols, refMol, newChainIDs=True, log=False, returnMapping=False):
	from chimera import replyobj

	# figure out residue chain/number remapping
	origChainIDs = {}
	numChains = 0
	minNums = {}
	maxNums = {}
	for m in mols:
		seenIDs = set()
		for r in m.residues:
			chainID = r.id.chainId
			num = r.id.position
			key = (m, chainID)
			if key in minNums:
				if num > maxNums[key]:
					maxNums[key] = num
				elif num < minNums[key]:
					minNums[key] = num
			else:
				minNums[key] = maxNums[key] = num
			if chainID in seenIDs:
				continue
			numChains += 1
			seenIDs.add(chainID)
			origChainIDs.setdefault(chainID, []).append(m)
	resMap = {}
	if newChainIDs:
		if numChains > 62:
			raise CombineError("More than 62 chains; cannot"
				" uniquely identify with single characters")
		from string import uppercase, lowercase, digits
		possibleIDs = uppercase + lowercase + digits
		usedChainIDs = set(origChainIDs.keys())
		chainIDmap = {}
		for chainID, idMols in origChainIDs.items():
			if len(chainID) > 1:
				continue
			chainIDmap[(idMols[0], chainID)] = chainID
			usedChainIDs.add(chainID)
			for m in idMols[1:]:
				for c in possibleIDs:
					if c not in usedChainIDs:
						break
				if log:
					replyobj.info("Remapping %s chain %s"
						" to %s\n" % (m, chainID, c))
				usedChainIDs.add(c)
				chainIDmap[(m, chainID)] = c
		for m in mols:
			for r in m.residues:
				chainID = r.id.chainId
				if len(chainID) > 1:
					continue
				resMap[r] = (chainIDmap[(m, chainID)],
								r.id.position)
	# handle renumbering for all chains if newChainIDs False,
	# otherwise just water/het chains
	offsets = {}
	for chainID, idMols in origChainIDs.items():
		if newChainIDs and len(chainID) < 2:
			continue
		minMaxs = []
		for m in idMols:
			mmin = minNums[(m, chainID)]
			mmax = maxNums[(m, chainID)]
			for omin, omax in minMaxs:
				if omin < mmin < omax or omin < mmax < omax:
					gmax = max([mm[1] for mm in minMaxs])
					offset = gmax - mmin + 1
					break
			else:
				offset = 0
			offsets[(m, chainID)] = offset
			minMaxs.append((mmin+offset, mmax+offset))
			if log and offset:
				replyobj.info("Adding %d to %s chain %s"
					" numbering\n" % (offset, m, chainID))
	for m in mols:
		for r in m.residues:
			chainID = r.id.chainId
			try:
				offset = offsets[(m, chainID)]
			except KeyError:
				continue
			resMap[r] = (chainID, r.id.position + offset)

	# combine...
	from chimera import Atom, Bond, Residue, Molecule
	combined = Molecule()
	combined.name = "combination"
	from SimpleSession.save import optionalAttributes
	from chimera.molEdit import addAtom
	atomAttrs = optionalAttributes[Atom].keys() + ['color', 'vdwColor',
		'labelColor', 'surfaceColor', 'drawMode', 'display', 'label',
		'radius', 'surfaceDisplay', 'surfaceCategory', 'surfaceOpacity',
		'vdw']
	bondAttrs = optionalAttributes[Bond].keys() + ['drawMode', 'display',
		'radius']
	resAttrs = optionalAttributes[Residue].keys() + ['ribbonColor',
		'labelColor', 'isHelix', 'isSheet', 'isTurn', 'ribbonDrawMode',
		'ribbonDisplay', 'label', 'isHet']
	serial = 1
	atomMap = {}
	for m in mols:
		if m.openState == refMol.openState:
			xform = None
		else:
			xform = refMol.openState.xform
			xform.invert()
		for r in m.residues:
			chainID, pos = resMap[r]
			nr = combined.newResidue(r.type, chainID, pos,
							r.id.insertionCode)
			for attrName in resAttrs:
				try:
					setattr(nr, attrName,
							getattr(r, attrName))
				except AttributeError:
					continue
			ratoms = r.atoms
			ratoms.sort(lambda a1, a2:
					cmp(a1.coordIndex, a2.coordIndex))
			for a in ratoms:
				if xform is None:
					crd = a.coord()
				else:
					crd = xform.apply(a.xformCoord())
				na = addAtom(a.name, a.element, nr, crd,
							serialNumber=serial)
				na.altLoc = a.altLoc
				atomMap[a] = na
				serial += 1
				for attrName in atomAttrs:
					try:
						setattr(na, attrName,
							getattr(a, attrName))
					except AttributeError:
						continue
		for b in m.bonds:
			a1, a2 = b.atoms
			nb = combined.newBond(atomMap[a1], atomMap[a2])
			for attrName in bondAttrs:
				try:
					setattr(nb, attrName,
						getattr(b, attrName))
				except AttributeError:
					continue
	consensusAttrs = ['color', 'display', 'lineWidth', 'pointSize',
		'stickScale', 'surfaceOpacity', 'ballScale', 'vdwDensity',
		'autochain', 'ribbonHidesMainchain']
	for attrName in consensusAttrs:
		consensusVal = None
		for m in mols:
			val = getattr(m, attrName)
			if consensusVal == None:
				consensusVal = val
			elif val != consensusVal:
				break
		else:
			setattr(combined, attrName, consensusVal)

	associatedModels = set()
	for m in mols:
		associatedModels.update(m.associatedModels())
	from chimera import PseudoBondMgr
	for opbg in PseudoBondMgr.mgr().pseudoBondGroups:
		if opbg in associatedModels:
			if opbg.category.startswith("internal-chain-"):
				continue
			assert(opbg.category.startswith("coordination complex"))
			from chimera.misc import getPseudoBondGroup
			pbg = getPseudoBondGroup("coordination complexes of %s"
				% combined.name, associateWith=[combined])
			for attrName in ['color', 'showStubBonds', 'lineWidth',
						'stickScale', 'lineType']:
				setattr(pbg, attrName, getattr(opbg, attrName))
		else:
			pbg = opbg
		for opb in opbg.pseudoBonds:
			oa1, oa2 = opb.atoms
			na1 = atomMap.get(oa1, oa1)
			na2 = atomMap.get(oa2, oa2)
			if oa1 == na1 and oa2 == na2:
				continue
			pb = pbg.newPseudoBond(na1, na2)
			for attrName in ['drawMode', 'display', 'halfbond',
					'label', 'color', 'labelColor']:
				setattr(pb, attrName, getattr(opb, attrName))
		
	if returnMapping:
		return atomMap, combined
	return combined
Exemplo n.º 31
0
def initiateAddions(models, iontype, numion, status):
    import os
    import chimera
    from chimera import replyobj
    from chimera.molEdit import addAtom
    from WriteMol2 import writeMol2
    from tempfile import mkdtemp

    for m in models:
	tempDir = mkdtemp()

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

	sleapIn = os.path.join(tempDir, "sleap.in.mol2")
	sleapOut= os.path.join(tempDir, "sleap.out.mol2")
	writeMol2([m], sleapIn, status=status, gaffType=True)

	leaprc = os.path.join(tempDir, "solvate.cmd")
	writeLeaprc(tempDir, iontype, numion, leaprc)

	chimeraRoot = os.environ["CHIMERA"]
        amberHome = os.path.join(chimeraRoot, "bin", "amber10")
	command = [os.path.join(amberHome, "exe", "sleap"), "-f", leaprc]

	if status:
		status("Running sleap" )
	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 sleap command: %s\n" % " ".join(command))
	import os
	os.environ["AMBERHOME"]=amberHome
	sleapMessages = Popen(command, stdin=PIPE, stdout=PIPE, stderr=STDOUT,
			cwd=tempDir, shell=shell, bufsize=1).stdout
	while True:
		line = sleapMessages.readline()
		if not line:
			break
		replyobj.status("(addions) %s" % line, log=True)
	if not os.path.exists(sleapOut):
		_clean()
		from chimera import NonChimeraError
		raise NonChimeraError("Failure running sleap \n"
			"Check reply log for details\n")
	if status:
		status("Reading sleap output\n")
	from chimera import Mol2io, defaultMol2ioHelper
	mol2io = Mol2io(defaultMol2ioHelper)
	mols = mol2io.readMol2file(sleapOut)
	if not mol2io.ok():
		_clean()
		raise IOError(mol2io.error())
	if not mols:
		_clean()
		raise RuntimeError("No molecules in sleap output")

        assert len(mols)==1

	outm = mols[0]
	solute_nresd = get_solute_nresd(m)
        print "total, solute, solvent: ", len(m.residues), solute_nresd, len(m.residues)-solute_nresd

        if status:
            status( "Deleting old solvents" )
        while len(m.residues) > solute_nresd:
            m.deleteResidue( m.residues[solute_nresd] )


	inAtoms = m.atoms
	outAtoms = outm.atoms
	# sort in coordIndex (i.e. input) order
	# (due to deletions, coordIndex values need _not_ be consecutive)
	serialSort = lambda a1, a2: cmp(a1.coordIndex, a2.coordIndex)
	inAtoms.sort(serialSort)
	outAtoms.sort(serialSort)

	# sleap repositions solute...
	if status:
		status("Translating %d atoms" % len(inAtoms))
	for inA, outA in zip(inAtoms, outAtoms[:len(inAtoms)]):
		inA.setCoord(outA.coord())

	for r in outm.residues[solute_nresd:]:
		if status:
			status("Creating ions/solvent residue %d " % (r.id.position-solute_nresd) )

		atomMap = {}
		nr = m.newResidue(r.type, ' ', 1, ' ')
		for a in r.atoms:
			na = addAtom(a.name, a.element, nr, a.coord(),
						serialNumber=a.serialNumber)
			na.charge = a.charge
			na.gaffType = a.mol2type

			if len(a.neighbors)==0:
				na.drawMode = chimera.Atom.Sphere

			atomMap[a] = na

			if a.name[0:2]=="Br": na.element = 35
			elif a.name[0:2]=="Cl": na.element = 17
			elif a.name[0:2]=="Cs": na.element = 47
			elif a.name[0:2]=="Mg": na.element = 12
			elif a.name[0:2]=="Na": na.element = 11
			elif a.name[0:2]=="Rb": na.element = 48
			elif a.name[0]=='F': na.element = 9
			elif a.name[0]=='I': na.element = 53
			elif a.name[0]=='K': na.element = 19
			elif a.name[0]=="H": na.element = 1
			elif a.name[0]=="C": na.element = 6
			elif a.name[0]=="N": na.element = 7
			elif a.name[0]=="O": na.element = 8
			elif a.name[0]=="P": na.element = 15
			elif a.name[0]=="S": na.element = 16

		for a in r.atoms:
			na = atomMap[a]
			for n in a.neighbors:
				assert n.residue == r
				nn = atomMap[n]
				if nn in na.bondsMap:
					continue
				m.newBond(na, nn)
	_clean()
Exemplo n.º 32
0
def swap(res, newRes, preserve=0, bfactor=True):
	"""change 'res' into type 'newRes'"""

	if res == "HIS":
		res = "HIP"
	fixed, buds, start, end = getResInfo(res)
	
	tmplRes = chimera.restmplFindResidue(newRes, start, end)
	if not tmplRes:
		raise ValueError, "No connectivity template for residue '%s'"\
									% newRes
	# sanity check:  does the template have the bud atoms?
	for bud in buds:
		if not tmplRes.atomsMap.has_key(bud):
			raise ValueError, "New residue type (%s) " \
			  "not compatible with starting residue type (%s)" \
			  				% (newRes, res.type)
		
	# if bfactor not specified, find highest bfactor in molecule
	# and use that for swapped-in atoms
	if bfactor is False:
		bfactor = None
	if bfactor is True:
		for a in res.molecule.atoms:
			try:
				if bfactor is True or a.bfactor > bfactor:
					bfactor = a.bfactor
			except AttributeError:
				pass

	if preserve:
		raise ValueError, "'preserve' keyword not yet implemented"

	# prune non-backbone atoms
	for a in res.oslChildren():
		if a.name not in fixed:
			a.molecule.deleteAtom(a)

	# add new sidechain
	while len(buds) > 0:
		bud = buds.pop()
		tmplBud = tmplRes.atomsMap[bud]
		resBud = res.atomsMap[bud][0]

		try:
			info = typeInfo[tmplBud.idatmType]
			geom = info.geometry
			subs = info.substituents
		except KeyError:
			print tmplBud.idatmType
			raise AssertionError, "Can't determine atom type" \
				" information for atom %s of residue %s" % (
				bud, res.oslIdent())

		# use coord() rather than xformCoord():  we want to set
		# the new atom's coord(), to which the proper xform will
		# then be applied
		for a, b in tmplBud.bondsMap.items():
			if a.element.number == 1:
				# don't add hydrogens
				continue
			if res.atomsMap.has_key(a.name):
				resBonder = res.atomsMap[a.name][0]
				if not resBud.bondsMap.has_key(resBonder):
					addBond(a, resBonder)
				continue

			newAtom = None
			numBonded = len(resBud.bonds)
			if numBonded >= subs:
				raise AssertionError, \
					"Too many atoms bonded to %s of" \
					" residue %s" % (bud, res.oslIdent())
			if numBonded == 0:
				raise AssertionError, \
					"Atom %s of residue %s has no" \
					" neighbors after pruning?!?" % (
					bud, res.oslIdent())
			elif numBonded == 1:
				# only one connected atom -- have to use
				# dihedral
				real1 = resBud.neighbors[0]
				newAtom = formDihedral(resBud, real1,
								tmplRes, a, b)
			elif numBonded == 2:
				crd = resBud.coord()
				bonded = resBud.neighbors
				bcrds = map(lambda a: a.coord(), bonded)
				positions = bondPositions(crd, geom,
							b.length(), bcrds)
				if len(positions) > 1:
					# need to disambiguate choices;
					# check improper dihedral

					# but first, make sure the bonded
					# atoms are in this residue
					inres = filter(lambda a, r=res:
							a.residue == r, bonded)
					if len(inres) == 0:
						raise AssertionError, \
						"Can't disambiguate " \
						"tetrahedral position by " \
						"forming in-residue dihedral " \
						"for %s of residue %s" % (
						bud, res.oslIdent())
					if len(inres) == 1:
						newAtom = formDihedral(resBud,
							inres[0], tmplRes, a, b)
					else:
						# okay, check improper dihedral
						tmplBonded = map(lambda a,
							tra=tmplRes.atomsMap:
							tra[a.name], bonded)
						tmplPts = map(lambda a:
							a.coord(), [a, 
							tmplBud] + tmplBonded)
						tmplDihed = apply(dihedral,
								tmplPts, {})
						backPts = map(lambda a:
							a.coord(), [resBud]
							+ bonded)
						dh1 = apply(dihedral, tuple(
								positions[:1]
								+ backPts), {})
						dh2 = apply(dihedral, tuple(
								positions[1:]
								+ backPts), {})
						diff1 = abs(dh1 - tmplDihed)
						diff2 = abs(dh2 - tmplDihed)
						if diff1 > 180:
							diff1 = 360 - diff1
						if diff2 > 180:
							diff2 = 360 - diff2
						if diff1 < diff2:
							position = positions[0]
						else:
							position = positions[1]
				else:
					position = positions[0]
			else:
				crd = resBud.coord()
				bonded = resBud.neighbors
				bcrds = map(lambda a: a.coord(), bonded)
				positions = bondPositions(crd, geom,
							b.length(), bcrds)
				if len(positions) > 1:
					raise AssertionError, \
						"Too many positions returned" \
						" for atom %s of residue %s" % (
						bud, res.oslIdent())
				position = positions[0]

			if not newAtom:
				newAtom = addAtom(a.name, a.element,
								res, position)
			newAtom.drawMode = resBud.drawMode
			if bfactor is not None and bfactor is not True:
				newAtom.bfactor = bfactor

			# TODO: need to iterate over coordSets
			for bonded in a.bondsMap.keys():
				if not res.atomsMap.has_key(bonded.name):
					continue
				addBond(newAtom, res.atomsMap[bonded.name][0])
			buds.append(newAtom.name)

	res.label = res.label.replace(res.type, newRes)
	res.type = newRes
Exemplo n.º 33
0
def initiateSolvate(models, method, solvent, extent, center, status):
    import os
    import chimera
    from chimera import replyobj
    from chimera.molEdit import addAtom
    from WriteMol2 import writeMol2
    from tempfile import mkdtemp

    for m in models:
	tempDir = mkdtemp()
	print 'tempDir: ', tempDir

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

	sleapIn = os.path.join(tempDir, "sleap.in.mol2")
	sleapOut= os.path.join(tempDir, "sleap.out.mol2")
	writeMol2([m], sleapIn, status=status)

	leaprc = os.path.join(tempDir, "solvate.cmd")
	writeLeaprc(tempDir, method, solvent, extent, center, leaprc)

	chimeraRoot = os.environ["CHIMERA"]
        amberHome = os.path.join(chimeraRoot, "bin", "amber10")
	command = [os.path.join(amberHome, "exe", "sleap"), "-f", leaprc]

	print 'command: ', command
	if status:
		status("Running sleap" )
	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 sleap command: %s\n" % " ".join(command))
	import os
	os.environ["AMBERHOME"]=amberHome
	sleapMessages = Popen(command, stdin=PIPE, stdout=PIPE, stderr=STDOUT,
			cwd=tempDir, shell=shell, bufsize=1).stdout
	while True:
		line = sleapMessages.readline()
		if not line:
			break
		replyobj.status("(solvate) %s" % line, log=True)
	if not os.path.exists(sleapOut):
		_clean()
		from chimera import NonChimeraError
		raise NonChimeraError("Failure running sleap \n"
			"Check reply log for details\n")
	if status:
		status("Reading sleap output\n")
	from chimera import Mol2io, defaultMol2ioHelper
	mol2io = Mol2io(defaultMol2ioHelper)
	mols = mol2io.readMol2file(sleapOut)
	if not mol2io.ok():
		_clean()
		raise IOError(mol2io.error())
	if not mols:
		_clean()
		raise RuntimeError("No molecules in sleap output")

        assert len(mols)==1

	outm = mols[0]
	natom = len(m.atoms)
	nresd = len(m.residues)
	inAtoms = m.atoms
	outAtoms = outm.atoms
	# sort in coordIndex (i.e. input) order
	# (due to deletions, coordIndex values need _not_ be consecutive)
	serialSort = lambda a1, a2: cmp(a1.coordIndex, a2.coordIndex)
	inAtoms.sort(serialSort)
	outAtoms.sort(serialSort)

	if status:
		status("Translating %d atoms" % len(inAtoms))
	for inA, outA in zip(inAtoms, outAtoms[:len(inAtoms)]):
		inA.setCoord(outA.coord())
	
	# added solvent hydrogens may not have been categorized yet, so use
	# this less obvious way of gathering solvent atoms...
	existingSolvent = set()
	from chimera.elements import metals, alkaliMetals
	nonAlkaliMetals = metals - alkaliMetals
	for r in m.residues:
		if len(r.atoms) == 1 and r.atoms[0].element in nonAlkaliMetals:
			continue
		for a in r.atoms:
			if a.surfaceCategory in ["solvent", "ions"]:
				existingSolvent.update(r.atoms)
				break

	# copy mol2 comment which contain the info of the solvent: shape, size, etc
        if hasattr( outm, "mol2comments" ) and len(outm.mol2comments) > 0:
		m.solventInfo = outm.mol2comments[0]
		print "solvent info: ", m.solventInfo


	if existingSolvent:
		solventCharges = {}
	for r in outm.residues[nresd:]:
		solventNum = r.id.position - nresd
		if status:
			status("Creating solvent residue %d " % solventNum )

		atomMap = {}
		nr = m.newResidue(r.type, ' ', solventNum, ' ')
		# mark residue for exclusion by AddCharge...
		nr._solvateCharged = True
		for a in r.atoms:
			na = addAtom(a.name, a.element, nr, a.coord(),
						serialNumber=a.serialNumber)
			na.charge = a.charge
			na.gaffType = a.mol2type
			atomMap[a] = na
			if a.name[0]=="H": na.element = 1
			if a.name[0]=="C": na.element = 6
			if a.name[0]=="N": na.element = 7
			if a.name[0]=="O": na.element = 8
			if a.name[0]=="P": na.element = 15
			if a.name[0]=="S": na.element = 16
			if a.name[0:2]=="Cl": na.element = 17
			if existingSolvent:
				solventCharges[(r.type, a.name)] = a.charge
				if r.type == "WAT":
					solventCharges[
						("HOH", a.name)] = a.charge


		for a in r.atoms:
			na = atomMap[a]
			for n in a.neighbors:
				assert n.residue == r
				nn = atomMap[n]
				if nn in na.bondsMap:
					continue
				m.newBond(na, nn)
	
	if existingSolvent:
		unknowns = set()
		for sa in existingSolvent:
			key = (sa.residue.type, sa.name)
			try:
				sa.charge = solventCharges[key]
			except KeyError:
				unknowns.add(key)
			sa.residue._solvateCharged = True
		if unknowns:
			replyobj.warning("Could not determine charges for"
				" pre-existing solvent/ions from added solvent"
				"/ions for: " + ", ".join([" ".join(x)
				for x in unknowns]))
	_clean()
				
    from Midas import window
    window(models)