def __init__(self, residue, resType, lib, sessionData=None): self._sesHandlerID = chimera.triggers.addHandler( SAVE_SESSION, self._sessionCB, None) self.residue = residue self.lib = lib self.resType = resType self.title = "%s Side-Chain Rotamers" % residue if sessionData: self.bbdep, self.rotamers, self.tableData = sessionData else: from Rotamers import getRotamers self.bbdep, self.rotamers = getRotamers(residue, log=True, lib=lib, resType=resType) from Midas import linewidth, color linewidth(2, self.rotamers) color('byhet', self.rotamers) chimera.openModels.add(self.rotamers, sameAs=residue.molecule, hidden=True, noprefs=True) registerAttribute(chimera.Molecule, "chis") registerAttribute(chimera.Molecule, "rotamerProb") self.tableData = None self.resHandlerID = chimera.triggers.addHandler( 'Residue', self._resChangeCB, None) self.dependentDialogInfo = [('Clashes', 'clash'), ('H-Bonds', 'hbond'), ('Density', 'volume')] for label, ddn in self.dependentDialogInfo: setattr(self, ddn + "Dialog", None) ModelessDialog.__init__(self)
def __init__(self, residue, resType, lib, sessionData=None): self._sesHandlerID = chimera.triggers.addHandler(SAVE_SESSION, self._sessionCB, None) self.residue = residue self.lib = lib self.resType = resType self.title = "%s Side-Chain Rotamers" % residue if sessionData: self.bbdep, self.rotamers, self.tableData = sessionData else: from Rotamers import getRotamers self.bbdep, self.rotamers = getRotamers(residue, log=True, lib=lib, resType=resType) from Midas import linewidth, color linewidth(2, self.rotamers) color('byhet', self.rotamers) chimera.openModels.add(self.rotamers, sameAs=residue.molecule, hidden=True, noprefs=True) registerAttribute(chimera.Molecule, "chis") registerAttribute(chimera.Molecule, "rotamerProb") self.tableData = None self.resHandlerID = chimera.triggers.addHandler( 'Residue', self._resChangeCB, None) self.dependentDialogInfo = [('Clashes', 'clash'), ('H-Bonds', 'hbond'), ('Density', 'volume')] for label, ddn in self.dependentDialogInfo: setattr(self, ddn + "Dialog", None) ModelessDialog.__init__(self)
def addVolumeColumn(self, columnName, *args): from Rotamers import processVolume format = processVolume(self.rotamers, columnName, *args) self.rotTable.addColumn(columnName, "lambda r: r.volumeScores[%s]" % repr(columnName), format=format, display=True) registerAttribute(chimera.Molecule, "volumeScores")
def addHbondColumn(self, *args): from Rotamers import processHbonds processHbonds(self.residue, self.rotamers, *args) self.rotTable.addColumn("H-Bonds", "numHbonds", format="%d", display=True) registerAttribute(chimera.Molecule, "numHbonds")
def addClashColumn(self, *args): from Rotamers import processClashes format = processClashes(self.residue, self.rotamers, *args) self.rotTable.addColumn("Clashes", "clashScore", format=format, display=True) registerAttribute(chimera.Molecule, "clashScore")
def Apply(self): liveModels = [m for m in self.models if not m.__destroyed__] if not liveModels: return note = self.text.getvalue().strip() track = chimera.TrackChanges.get() for m in liveModels: if note: m.note = note elif hasattr(m, "note"): delattr(m, "note") track.addModified(m, "note changed") if note: from SimpleSession import registerAttribute registerAttribute(chimera.Molecule, "note") from base import _mp _mp._confDialog.showColumn("Note", True)
def restoreMolecules(molInfo, resInfo, atomInfo, bondInfo, crdInfo): from SimpleSession import registerAttribute items = [] sm = globals.sessionMap res2mol = [] atom2mol = [] for ids, name, cid, display, lineWidth, pointSize, stickScale, \ pdbHeaders, surfaceOpacity, ballScale, vdwDensity, autochain, \ ribbonHidesMainchain, riCID, aromaticCID, aromaticDisplay, \ aromaticLineType, aromaticMode, hidden in zip( expandSummary(molInfo['ids']), expandSummary(molInfo['name']), expandSummary(molInfo['color']), expandSummary(molInfo['display']), expandSummary(molInfo['lineWidth']), expandSummary(molInfo['pointSize']), expandSummary(molInfo['stickScale']), molInfo['pdbHeaders'], expandSummary(molInfo['surfaceOpacity']), expandSummary(molInfo['ballScale']), expandSummary(molInfo['vdwDensity']), expandSummary(molInfo['autochain']), expandSummary(molInfo['ribbonHidesMainchain']), expandSummary(molInfo['ribbonInsideColor']), expandSummary(molInfo['aromaticColor']), expandSummary(molInfo['aromaticDisplay']), expandSummary(molInfo['aromaticLineType']), expandSummary(molInfo['aromaticMode']), expandSummary(molInfo['hidden']) ): m = chimera.Molecule() sm[len(items)] = m items.append(m) m.name = name from SimpleSession import modelMap, modelOffset chimera.openModels.add([m], baseId=ids[0]+modelOffset, subid=ids[1], hidden=hidden) modelMap.setdefault(ids, []).append(m) m.color = getColor(cid) m.display = display m.lineWidth = lineWidth m.pointSize = pointSize m.stickScale = stickScale m.setAllPDBHeaders(pdbHeaders) m.surfaceOpacity = surfaceOpacity m.ballScale = ballScale m.vdwDensity = vdwDensity m.autochain = autochain m.ribbonHidesMainchain = ribbonHidesMainchain m.ribbonInsideColor = getColor(riCID) m.aromaticColor = getColor(aromaticCID) m.aromaticDisplay = aromaticDisplay m.aromaticLineType = aromaticLineType m.aromaticMode = aromaticMode if molInfo['optional']: for attrName, info in molInfo['optional'].items(): hashable, sv = info registerAttribute(chimera.Molecule, attrName, hashable=hashable) vals = expandSummary(sv, hashable=hashable) for m, val in zip(items, vals): if val is not None: setattr(m, attrName, val) resStart = len(items) for mid, name, chain, pos, insert, rcid, lcid, ss, ssId, ribbonDrawMode, \ ribbonDisplay, label, labelOffset, isHet, fillDisplay, fillMode in zip( expandSummary(resInfo['molecule']), expandSummary(resInfo['name']), expandSummary(resInfo['chain']), expandSequentialSummary(resInfo['position']), expandSummary(resInfo['insert']), expandSummary(resInfo['ribbonColor']), expandSummary(resInfo['labelColor']), expandSummary(resInfo['ss']), expandSummary(resInfo['ssId']), expandSummary(resInfo['ribbonDrawMode']), expandSummary(resInfo['ribbonDisplay']), expandSummary(resInfo['label']), expandSummary(resInfo['labelOffset']), expandSummary(resInfo['isHet']), expandSummary(resInfo['fillDisplay']), expandSummary(resInfo['fillMode']), ): m = idLookup(mid) r = m.newResidue(name, chain, pos, insert) sm[len(items)] = r items.append(r) r.ribbonColor = getColor(rcid) r.labelColor = getColor(lcid) r.isHelix, r.isStrand, r.isTurn = ss r.ssId = ssId r.ribbonDrawMode = ribbonDrawMode r.ribbonDisplay = ribbonDisplay r.label = label if labelOffset is not None: r.labelOffset = labelOffset r.isHet = isHet r.fillDisplay = fillDisplay r.fillMode = fillMode if resInfo['optional']: residues = items[resStart:] for attrName, info in resInfo['optional'].items(): hashable, sv = info registerAttribute(chimera.Residue, attrName, hashable=hashable) vals = expandSummary(sv, hashable=hashable) for r, val in zip(residues, vals): if val is not None: setattr(r, attrName, val) atomStart = len(items) for rid, name, element, cid, vcid, lcid, scid, drawMode, display, \ label, labelOffet, surfaceDisplay, surfaceCategory, surfaceOpacity, \ radius, vdw, idatmType, altLoc in zip( expandSummary(atomInfo['residue']), expandSummary(atomInfo['name']), expandSummary(atomInfo['element']), expandSummary(atomInfo['color']), expandSummary(atomInfo['vdwColor']), expandSummary(atomInfo['labelColor']), expandSummary(atomInfo['surfaceColor']), expandSummary(atomInfo['drawMode']), expandSummary(atomInfo['display']), expandSummary(atomInfo['label']), expandSummary(atomInfo['labelOffset']), expandSummary(atomInfo['surfaceDisplay']), expandSummary(atomInfo['surfaceCategory']), expandSummary(atomInfo['surfaceOpacity']), expandSummary(atomInfo['radius']), expandSummary(atomInfo['vdw']), expandSummary(atomInfo['idatmType']), expandSummary(atomInfo['altLoc']) ): r = idLookup(rid) a = r.molecule.newAtom(name, chimera.Element(element)) sm[len(items)] = a items.append(a) r.addAtom(a) a.color = getColor(cid) a.vdwColor = getColor(vcid) a.labelColor = getColor(lcid) a.surfaceColor = getColor(scid) a.drawMode = drawMode a.display = display a.label = label if labelOffset is not None: a.labelOffset = labelOffset a.surfaceDisplay = surfaceDisplay a.surfaceCategory = surfaceCategory a.surfaceOpacity = surfaceOpacity a.radius = radius a.vdw = vdw if idatmType: a.idatmType = idatmType a.altLoc = altLoc if atomInfo['optional']: atoms = items[atomStart:] for attrName, info in atomInfo['optional'].items(): hashable, sv = info registerAttribute(chimera.Atom, attrName, hashable=hashable) vals = expandSummary(sv, hashable=hashable) for a, val in zip(atoms, vals): if val is not None: setattr(a, attrName, val) bondStart = len(items) for atoms, drawMode, display, label, labelOffset, radius in zip( bondInfo['atoms'], expandSummary(bondInfo['drawMode']), expandSummary(bondInfo['display']), expandSummary(bondInfo['label']), expandSummary(bondInfo['labelOffset']), expandSummary(bondInfo['radius']) ): a1, a2 = [idLookup(a) for a in atoms] b = a1.molecule.newBond(a1, a2) sm[len(items)] = b items.append(b) b.drawMode = drawMode b.display = display b.label = label if labelOffset is not None: b.labelOffset = labelOffset b.radius = radius if bondInfo.get('optional', {}): bonds = items[bondStart:] for attrName, info in bondInfo['optional'].items(): hashable, sv = info registerAttribute(chimera.Bond, attrName, hashable=hashable) vals = expandSummary(sv, hashable=hashable) for b, val in zip(bonds, vals): if val is not None: setattr(b, attrName, val) from chimera import Point for mid, crdSets in crdInfo.items(): m = idLookup(mid) active = crdSets.pop('active') for key, crds in crdSets.items(): coordSet = m.newCoordSet(key, len(crds)) for aid, crdString in crds: idLookup(aid).setCoord(Point(*tuple([float(c) for c in crdString.split()])), coordSet) if key == active: m.activeCoordSet = coordSet
def restoreMolecules(molInfo, resInfo, atomInfo, bondInfo, crdInfo): from SimpleSession import registerAttribute items = [] sm = globals.sessionMap res2mol = [] atom2mol = [] for ids, name, cid, display, lineWidth, pointSize, stickScale, \ pdbHeaders, surfaceOpacity, ballScale, vdwDensity, autochain, \ ribbonHidesMainchain, riCID, aromaticCID, aromaticDisplay, \ aromaticLineType, aromaticMode, hidden in zip( expandSummary(molInfo['ids']), expandSummary(molInfo['name']), expandSummary(molInfo['color']), expandSummary(molInfo['display']), expandSummary(molInfo['lineWidth']), expandSummary(molInfo['pointSize']), expandSummary(molInfo['stickScale']), molInfo['pdbHeaders'], expandSummary(molInfo['surfaceOpacity']), expandSummary(molInfo['ballScale']), expandSummary(molInfo['vdwDensity']), expandSummary(molInfo['autochain']), expandSummary(molInfo['ribbonHidesMainchain']), expandSummary(molInfo['ribbonInsideColor']), expandSummary(molInfo['aromaticColor']), expandSummary(molInfo['aromaticDisplay']), expandSummary(molInfo['aromaticLineType']), expandSummary(molInfo['aromaticMode']), expandSummary(molInfo['hidden']) ): m = chimera.Molecule() sm[len(items)] = m items.append(m) m.name = name from SimpleSession import modelMap, modelOffset chimera.openModels.add([m], baseId=ids[0] + modelOffset, subid=ids[1], hidden=hidden) modelMap.setdefault(ids, []).append(m) m.color = getColor(cid) m.display = display m.lineWidth = lineWidth m.pointSize = pointSize m.stickScale = stickScale m.setAllPDBHeaders(pdbHeaders) m.surfaceOpacity = surfaceOpacity m.ballScale = ballScale m.vdwDensity = vdwDensity m.autochain = autochain m.ribbonHidesMainchain = ribbonHidesMainchain m.ribbonInsideColor = getColor(riCID) m.aromaticColor = getColor(aromaticCID) m.aromaticDisplay = aromaticDisplay m.aromaticLineType = aromaticLineType m.aromaticMode = aromaticMode if molInfo['optional']: for attrName, info in molInfo['optional'].items(): hashable, sv = info registerAttribute(chimera.Molecule, attrName, hashable=hashable) vals = expandSummary(sv, hashable=hashable) for m, val in zip(items, vals): if val is not None: setattr(m, attrName, val) resStart = len(items) for mid, name, chain, pos, insert, rcid, lcid, ss, ssId, ribbonDrawMode, \ ribbonDisplay, label, labelOffset, isHet, fillDisplay, fillMode in zip( expandSummary(resInfo['molecule']), expandSummary(resInfo['name']), expandSummary(resInfo['chain']), expandSequentialSummary(resInfo['position']), expandSummary(resInfo['insert']), expandSummary(resInfo['ribbonColor']), expandSummary(resInfo['labelColor']), expandSummary(resInfo['ss']), expandSummary(resInfo['ssId']), expandSummary(resInfo['ribbonDrawMode']), expandSummary(resInfo['ribbonDisplay']), expandSummary(resInfo['label']), expandSummary(resInfo['labelOffset']), expandSummary(resInfo['isHet']), expandSummary(resInfo['fillDisplay']), expandSummary(resInfo['fillMode']), ): m = idLookup(mid) r = m.newResidue(name, chain, pos, insert) sm[len(items)] = r items.append(r) r.ribbonColor = getColor(rcid) r.labelColor = getColor(lcid) r.isHelix, r.isStrand, r.isTurn = ss r.ssId = ssId r.ribbonDrawMode = ribbonDrawMode r.ribbonDisplay = ribbonDisplay r.label = label if labelOffset is not None: r.labelOffset = labelOffset r.isHet = isHet r.fillDisplay = fillDisplay r.fillMode = fillMode if resInfo['optional']: residues = items[resStart:] for attrName, info in resInfo['optional'].items(): hashable, sv = info registerAttribute(chimera.Residue, attrName, hashable=hashable) vals = expandSummary(sv, hashable=hashable) for r, val in zip(residues, vals): if val is not None: setattr(r, attrName, val) atomStart = len(items) for rid, name, element, cid, vcid, lcid, scid, drawMode, display, \ label, labelOffet, surfaceDisplay, surfaceCategory, surfaceOpacity, \ radius, vdw, idatmType, altLoc in zip( expandSummary(atomInfo['residue']), expandSummary(atomInfo['name']), expandSummary(atomInfo['element']), expandSummary(atomInfo['color']), expandSummary(atomInfo['vdwColor']), expandSummary(atomInfo['labelColor']), expandSummary(atomInfo['surfaceColor']), expandSummary(atomInfo['drawMode']), expandSummary(atomInfo['display']), expandSummary(atomInfo['label']), expandSummary(atomInfo['labelOffset']), expandSummary(atomInfo['surfaceDisplay']), expandSummary(atomInfo['surfaceCategory']), expandSummary(atomInfo['surfaceOpacity']), expandSummary(atomInfo['radius']), expandSummary(atomInfo['vdw']), expandSummary(atomInfo['idatmType']), expandSummary(atomInfo['altLoc']) ): r = idLookup(rid) a = r.molecule.newAtom(name, chimera.Element(element)) sm[len(items)] = a items.append(a) r.addAtom(a) a.color = getColor(cid) a.vdwColor = getColor(vcid) a.labelColor = getColor(lcid) a.surfaceColor = getColor(scid) a.drawMode = drawMode a.display = display a.label = label if labelOffset is not None: a.labelOffset = labelOffset a.surfaceDisplay = surfaceDisplay a.surfaceCategory = surfaceCategory a.surfaceOpacity = surfaceOpacity a.radius = radius a.vdw = vdw if idatmType: a.idatmType = idatmType a.altLoc = altLoc if atomInfo['optional']: atoms = items[atomStart:] for attrName, info in atomInfo['optional'].items(): hashable, sv = info registerAttribute(chimera.Atom, attrName, hashable=hashable) vals = expandSummary(sv, hashable=hashable) for a, val in zip(atoms, vals): if val is not None: setattr(a, attrName, val) bondStart = len(items) for atoms, drawMode, display, label, labelOffset, radius in zip( bondInfo['atoms'], expandSummary(bondInfo['drawMode']), expandSummary(bondInfo['display']), expandSummary(bondInfo['label']), expandSummary(bondInfo['labelOffset']), expandSummary(bondInfo['radius'])): a1, a2 = [idLookup(a) for a in atoms] b = a1.molecule.newBond(a1, a2) sm[len(items)] = b items.append(b) b.drawMode = drawMode b.display = display b.label = label if labelOffset is not None: b.labelOffset = labelOffset b.radius = radius if bondInfo.get('optional', {}): bonds = items[bondStart:] for attrName, info in bondInfo['optional'].items(): hashable, sv = info registerAttribute(chimera.Bond, attrName, hashable=hashable) vals = expandSummary(sv, hashable=hashable) for b, val in zip(bonds, vals): if val is not None: setattr(b, attrName, val) from chimera import Point for mid, crdSets in crdInfo.items(): m = idLookup(mid) active = crdSets.pop('active') for key, crds in crdSets.items(): coordSet = m.newCoordSet(key, len(crds)) for aid, crdString in crds: idLookup(aid).setCoord( Point(*tuple([float(c) for c in crdString.split()])), coordSet) if key == active: m.activeCoordSet = coordSet
def addStandardCharges(models=None, status=None, phosphorylation=None, chargeModel=None, nogui=False, showCharges=False): """add AMBER charges to well-known residues 'models' restricts the addition to the specified models 'status' is where status messages go (e.g. replyobj.status) 'phosphorylation' controls whether chain-terminal nucleic acids will have their phosphorylation state changed to correspond to AMBER charge files (3' phosphorylated, 5' not). A value of None means that the user will be queried if possible [treated as True if not possible]. 'showCharges' controls whether atoms get labeled with their charge. The return value is a 2-tuple of dictionaries: the first of which details the residues that did not receive charges [key: residue type, value: list of residues], and the second lists remaining uncharged atoms [key: (residue type, atom name), value: list of atoms] Hydrogens need to be present. """ from AddAttr import addAttributes import os.path attrFile = os.path.join(os.path.split(__file__)[0], "amberName.defattr") if status: status("Defining AMBER residue types\n") addAttributes(attrFile, models=models, raiseAttrDialog=False) if models is None: mols = chimera.openModels.list(modelTypes=[chimera.Molecule]) else: mols = models if phosphorylation != False: if status: status("Checking phosphorylation of chain-terminal" " nucleic acids\n") likeAmber = True deletes = [] for m in mols: for r in m.residues: amberName = getattr(r, 'amberName', "UNK") if len(amberName) != 2 \ or amberName[0] not in 'DR' \ or amberName[1] not in 'ACGTU' \ or 'P' not in r.atomsMap: continue p = r.atomsMap['P'][0] for nb in p.neighbors: if nb.residue != r: break else: # trailing phosphate deletes.append(r) if deletes: if phosphorylation is None: if nogui or chimera.nogui: phosphorylation = True else: from gui import PhosphorylateDialog phosphorylation = PhosphorylateDialog().run( chimera.tkgui.app) if phosphorylation: _phosphorylate(mols, status, deletes) if status: status("Adding standard charges\n") unchargedResTypes = {} unchargedAtoms = {} unchargedResidues = set() from dict import ffChargeTypeData from SimpleSession import registerAttribute registerAttribute(chimera.Molecule, "chargeModel") registerAttribute(chimera.Atom, "gaffType") if chargeModel == None: chargeModel = defaultChargeModel replyobj.info("Charge model: %s\n" % chargeModel) chargeTypeData = ffChargeTypeData[chargeModel] track = chimera.TrackChanges.get() for m in mols: m.chargeModel = chargeModel track.addModified(m, ATTR_SET) for r in m.residues: if getattr(r, '_solvateCharged', False): continue if not hasattr(r, 'amberName'): unchargedResidues.add(r) unchargedResTypes.setdefault(r.type, []).append(r) for a in m.atoms: if getattr(a.residue, '_solvateCharged', False): continue a.charge = 0.0 track.addModified(a, ATTR_SET) if a.residue.type in unchargedResTypes: if showCharges: a.label = str(a.charge) continue atomKeys = [a.name.lower()] if a.element.number == 1 and a.name.lower()[0] in "dt": atomKeys.append('h' + a.name.lower()[1:]) atomKeys.append(a.element) for ak in atomKeys: key = (a.residue.amberName, ak) try: a.charge, a.gaffType = chargeTypeData[key] except KeyError: continue if showCharges: a.label = "%+g" % a.charge break else: unchargedAtoms.setdefault((a.residue.type, a.name), []).append(a) # merge connected non-standard residues into a "mega" residue. # also any standard residues directly connected for urt, urs in unchargedResTypes.items(): for ur in urs[:]: if urt not in unchargedResTypes: break if ur not in unchargedResTypes[urt]: # connected to residue of same type and # previously removed continue connected = [ur] queue = [ur] while queue: curRes = queue.pop(0) neighbors = set() stdConnects = {} for a in curRes.atoms: for na in a.neighbors: naRes = na.residue if naRes == curRes \ or naRes in connected: continue # don't add standard residue # if connected through chain # bond if naRes not in unchargedResidues: from chimera.misc \ import principalAtom pa = principalAtom(naRes) if pa != None: if pa.name == 'CA': testNames = ['N', 'C'] else: testNames = ['P', "O3'"] if na.name in testNames and na.name not in stdConnects.get( naRes, set()): stdConnects.setdefault(naRes, set()).add(na.name) continue neighbors.add(naRes) neighbors = list(neighbors) neighbors.sort(lambda r1, r2: cmp(r1.type, r2.type)) connected.extend(neighbors) queue.extend( [nb for nb in neighbors if nb in unchargedResidues]) # avoid using atom names with the trailing "-number" # distinguisher if possible... if len(connected) > 1: fr = FakeRes(connected) else: fr = connected[0] unchargedResTypes.setdefault(fr.type, []).append(fr) for cr in connected: if cr in unchargedResidues: unchargedResTypes[cr.type].remove(cr) if not unchargedResTypes[cr.type]: del unchargedResTypes[cr.type] continue # remove standard-residue atoms from # uncharged list for ca in cr.atoms: uas = unchargedAtoms.get((cr.type, ca.name), []) if ca not in uas: continue uas.remove(ca) if not uas: del unchargedAtoms[(cr.type, ca.name)] # split isolated atoms (e.g. metals) into separate "residues" for resType, residues in unchargedResTypes.items(): bondResidues = residues brType = resType while True: if len(bondResidues[0].atoms) == 1: break for a in bondResidues[0].atoms: if a.bonds: continue hasIso = [r for r in bondResidues if a.name in r.atomsMap] if len(hasIso) == len(bondResidues): rem = [] else: rem = [r for r in bondResidues if r not in hasIso] iso = [] nonIso = rem isoType = "%s[%s]" % (resType, a.name) brType = "%s[non-%s]" % (brType, a.name) for r in hasIso: isoRes = FakeRes( isoType, [fa for fa in r.atoms if fa.name == a.name]) iso.append(isoRes) nonIsoAtoms = [fa for fa in r.atoms if fa.name != a.name] if not nonIsoAtoms: brType = None continue nonIsoRes = FakeRes(brType, nonIsoAtoms) nonIso.append(nonIsoRes) unchargedResTypes[isoType] = iso bondResidues = nonIso else: # no isolated atoms break if brType != resType: del unchargedResTypes[resType] if brType != None: unchargedResTypes[brType] = bondResidues # despite same residue type, residues may still differ -- particularly # terminal vs. non-terminal... for resType, residues in unchargedResTypes.items(): if len(residues) < 2: continue varieties = {} for r in residues: key = tuple([a.name for a in r.oslChildren()]) varieties.setdefault(key, []).append(r) if len(varieties) == 1: continue # in order to give the varieties distinguishing names, # find atoms in common keys = varieties.keys() common = set(keys[0]) for k in keys[1:]: common = common.intersection(set(k)) uncommon = set() for k in keys: uncommon = uncommon.union(set(k) - common) del unchargedResTypes[resType] for k, residues in varieties.items(): names = set(k) more = names - common less = uncommon - names newKey = resType if more: newKey += " (w/%s)" % ",".join(list(more)) if less: newKey += " (wo/%s)" % ",".join(list(less)) unchargedResTypes[newKey] = residues if status: status("Standard charges added\n") return unchargedResTypes, unchargedAtoms
def _addAttr(attrFile, models, log, raiseAttrDialog): setAttrs = {} colors = {} from CGLutil.annotatedDataFile import readDataFile control = { 'match mode': _MATCH_MODE_ANY, 'recipient': "atoms" } for rawControl, data in readDataFile(attrFile): control.update(rawControl) legalNames = ["attribute", "match mode", "recipient"] for name in control.keys(): if name not in legalNames: raise SyntaxError("Unknown name part of control" " line: '%s'\nMust be one of: %s" % ( name, ", ".join(legalNames))) if "attribute" not in control: raise SyntaxError("No attribute name specified in file") attrName = control["attribute"] if not attrName.replace("_", "").isalnum() \ or attrName[0].isdigit(): raise SyntaxError("Attribute name (%s) is bad.\n" "It must be strictly alphanumeric characters or" " underscores with no spaces and must not start" " with a digit." % control["attribute"]) colorAttr = attrName.lower().endswith("color") matchMode = control["match mode"] if matchMode not in _matchModes: raise SyntaxError("Unknown match mode (%s) specified.\n" "It must be one of: %s" % ( control["match mode"], ", ".join(_matchModes))) recipient = control["recipient"] if not hasattr(selection.ItemizedSelection, recipient): raise SyntaxError("Unknown attribute recipient (%s)" " specified.\nSuggest using atoms, residues, or" " molecules" % control["recipient"]) dataErrors = [] for lineNum, d in enumerate(data): try: selector, value = d except ValueError: dataErrors.append("Data line %d of file either" " not selector/value or not" " tab-delimited" % (lineNum+1)) continue try: sel = specifier.evalSpec(selector, models) except: import sys dataErrors.append("Mangled selector (%s) on" " data line %d: %s" % (selector, lineNum+1, sys.exc_value)) continue matches = getattr(sel, recipient)() # restrict to models; the "models" argument to evalSpec # only works if the selector is an OSL if matches and models is not None: md = set(models) level = matches[0].oslLevel() if level == selection.SelGraph: filterFunc = lambda x, md=md: x in md elif level == selection.SelEdge: filterFunc = lambda x, md=md: \ x.atoms[0].molecule in md else: filterFunc = lambda x, md=md: \ x.molecule in md matches = filter(filterFunc, matches) if not matches: if matchMode != _MATCH_MODE_ANY: dataErrors.append("Selector (%s) on" " data line %d matched nothing" % (selector, lineNum+1)) continue elif len(matches) > 1: if matchMode == _MATCH_MODE_1_TO_1: dataErrors.append("Selector (%s) on" " data line %d matched multiple" " items: %s" % (selector, lineNum+1, ", ".join(map(lambda m: m.oslIdent(), matches)))) if log: replyobj.info("Selector %s matched " % selector + ", ".join(map(misc.chimeraLabel, matches)) + "\n") if colorAttr: if value[0].isalpha(): # color name from chimera.colorTable \ import getColorByName try: value = getColorByName(value) except KeyError: dataErrors.append("Unknown" " color name on data" " line %d: '%s'" % (lineNum+1, value)) continue else: try: rgba = tuple(map(float, value.split())) except ValueError: dataErrors.append( "Unrecognizable color" " value on data line" " %d: '%s'; Must be" " either color name or" " 3 or 4 numbers" " between 0 and 1" " (RGBA)" % (lineNum+1)) continue if max(rgba) > 1.0 or min(rgba) < 0.0: dataErrors.append("Color" " component values on" " data line %d not" " in the range 0 to 1" % (lineNum+1)) continue if rgba in colors: value = colors[rgba] elif len(rgba) in [3, 4]: value = chimera.MaterialColor( *rgba) colors[rgba] = value else: dataErrors.append("Bad number" " of color components" " on data line %d; Must" " be either 3 or 4 (was" " %d)" % (lineNum+1, len(rgba))) continue else: value = convertType(value) for match in matches: setattr(match, attrName, value) if matches and not colorAttr: setAttrs[(recipient, attrName)] = value recipMapping = { "molecules": chimera.Molecule, "residues": chimera.Residue, "bonds": chimera.Bond, "atoms": chimera.Atom } from SimpleSession import registerAttribute for recipient, attrName in setAttrs: if recipient in recipMapping: registerAttribute(recipMapping[recipient], attrName) if setAttrs and not chimera.nogui and raiseAttrDialog: from ShowAttr import ShowAttrDialog, screenedAttrs from chimera import dialogs showableAttr = False reasons = [] for recipient, attrName in setAttrs.keys(): if recipient == "molecules": recipient = "models" validRecipients = ["atoms", "residues", "models"] if recipient not in validRecipients: reasons.append("%s not assigned to atoms," " residues, or models" % attrName) continue key = [chimera.Atom, chimera.Residue, chimera.Model][ validRecipients.index(recipient)] if attrName in screenedAttrs[key]: reasons.append("%s automatically screened out" " by Render By Attribute" % attrName) continue if attrName[0] == '_': reasons.append("%s considered to be a private" " variable" % attrName) continue if attrName[0].isupper(): reasons.append("%s considered to be a symbolic" " constant due to initial capital" " letter" % attrName) continue showableAttr = True break if showableAttr: if models is None: ms = chimera.openModels.list() else: ms = models if colorAttr: an = None mode = None else: an = attrName from types import StringTypes if type(setAttrs[(recipient, attrName)]) in ( bool,) + StringTypes: mode = "Select" else: mode = "Render" d = dialogs.display(ShowAttrDialog.name) d.configure(models=[m for m in ms if isinstance(m, chimera.Molecule)], attrsOf=recipient, attrName=an, mode=mode) else: replyobj.warning("No attributes usable by Render dialog" " were defined:\n" + "\n".join(reasons) + "\n") if dataErrors: raise SyntaxError, "\n".join(dataErrors) return setAttrs
def addStandardCharges(models=None, status=None, phosphorylation=None, chargeModel=None, nogui=False, showCharges=False): """add AMBER charges to well-known residues 'models' restricts the addition to the specified models 'status' is where status messages go (e.g. replyobj.status) 'phosphorylation' controls whether chain-terminal nucleic acids will have their phosphorylation state changed to correspond to AMBER charge files (3' phosphorylated, 5' not). A value of None means that the user will be queried if possible [treated as True if not possible]. 'showCharges' controls whether atoms get labeled with their charge. The return value is a 2-tuple of dictionaries: the first of which details the residues that did not receive charges [key: residue type, value: list of residues], and the second lists remaining uncharged atoms [key: (residue type, atom name), value: list of atoms] Hydrogens need to be present. """ from AddAttr import addAttributes import os.path attrFile = os.path.join(os.path.split(__file__)[0], "amberName.defattr") if status: status("Defining AMBER residue types\n") addAttributes(attrFile, models=models, raiseAttrDialog=False) if models is None: mols = chimera.openModels.list(modelTypes=[chimera.Molecule]) else: mols = models if phosphorylation != False: if status: status("Checking phosphorylation of chain-terminal" " nucleic acids\n") likeAmber = True deletes = [] for m in mols: for r in m.residues: amberName = getattr(r, 'amberName', "UNK") if len(amberName) != 2 \ or amberName[0] not in 'DR' \ or amberName[1] not in 'ACGTU' \ or 'P' not in r.atomsMap: continue p = r.atomsMap['P'][0] for nb in p.neighbors: if nb.residue != r: break else: # trailing phosphate deletes.append(r) if deletes: if phosphorylation is None: if nogui or chimera.nogui: phosphorylation = True else: from gui import PhosphorylateDialog phosphorylation = PhosphorylateDialog( ).run(chimera.tkgui.app) if phosphorylation: _phosphorylate(mols, status, deletes) if status: status("Adding standard charges\n") unchargedResTypes = {} unchargedAtoms = {} unchargedResidues = set() from dict import ffChargeTypeData from SimpleSession import registerAttribute registerAttribute(chimera.Molecule, "chargeModel") registerAttribute(chimera.Atom, "gaffType") if chargeModel == None: chargeModel = defaultChargeModel replyobj.info("Charge model: %s\n" % chargeModel) chargeTypeData = ffChargeTypeData[chargeModel] track = chimera.TrackChanges.get() for m in mols: m.chargeModel = chargeModel track.addModified(m, ATTR_SET) for r in m.residues: if getattr(r, '_solvateCharged', False): continue if not hasattr(r, 'amberName'): unchargedResidues.add(r) unchargedResTypes.setdefault(r.type, []).append(r) for a in m.atoms: if getattr(a.residue, '_solvateCharged', False): continue a.charge = 0.0 track.addModified(a, ATTR_SET) if a.residue.type in unchargedResTypes: if showCharges: a.label = str(a.charge) continue atomKeys = [a.name.lower()] if a.element.number == 1 and a.name.lower()[0] in "dt": atomKeys.append('h' + a.name.lower()[1:]) atomKeys.append(a.element) for ak in atomKeys: key = (a.residue.amberName, ak) try: a.charge, a.gaffType = chargeTypeData[ key] except KeyError: continue if showCharges: a.label = "%+g" % a.charge break else: unchargedAtoms.setdefault((a.residue.type, a.name), []).append(a) # merge connected non-standard residues into a "mega" residue. # also any standard residues directly connected for urt, urs in unchargedResTypes.items(): for ur in urs[:]: if urt not in unchargedResTypes: break if ur not in unchargedResTypes[urt]: # connected to residue of same type and # previously removed continue connected = [ur] queue = [ur] while queue: curRes = queue.pop(0) neighbors = set() stdConnects = {} for a in curRes.atoms: for na in a.neighbors: naRes = na.residue if naRes == curRes \ or naRes in connected: continue # don't add standard residue # if connected through chain # bond if naRes not in unchargedResidues: from chimera.misc \ import principalAtom pa = principalAtom( naRes) if pa != None: if pa.name == 'CA': testNames = ['N', 'C'] else: testNames = ['P', "O3'"] if na.name in testNames and na.name not in stdConnects.get(naRes, set()): stdConnects.setdefault(naRes, set()).add(na.name) continue neighbors.add(naRes) neighbors = list(neighbors) neighbors.sort(lambda r1, r2: cmp(r1.type, r2.type)) connected.extend(neighbors) queue.extend([nb for nb in neighbors if nb in unchargedResidues]) # avoid using atom names with the trailing "-number" # distinguisher if possible... if len(connected) > 1: fr = FakeRes(connected) else: fr = connected[0] unchargedResTypes.setdefault(fr.type, []).append(fr) for cr in connected: if cr in unchargedResidues: unchargedResTypes[cr.type].remove(cr) if not unchargedResTypes[cr.type]: del unchargedResTypes[cr.type] continue # remove standard-residue atoms from # uncharged list for ca in cr.atoms: uas = unchargedAtoms.get((cr.type, ca.name), []) if ca not in uas: continue uas.remove(ca) if not uas: del unchargedAtoms[(cr.type, ca.name)] # split isolated atoms (e.g. metals) into separate "residues" for resType, residues in unchargedResTypes.items(): bondResidues = residues brType = resType while True: if len(bondResidues[0].atoms) == 1: break for a in bondResidues[0].atoms: if a.bonds: continue hasIso = [r for r in bondResidues if a.name in r.atomsMap] if len(hasIso) == len(bondResidues): rem = [] else: rem = [r for r in bondResidues if r not in hasIso] iso = [] nonIso = rem isoType = "%s[%s]" % (resType, a.name) brType = "%s[non-%s]" % (brType, a.name) for r in hasIso: isoRes = FakeRes(isoType, [fa for fa in r.atoms if fa.name == a.name]) iso.append(isoRes) nonIsoAtoms = [fa for fa in r.atoms if fa.name != a.name] if not nonIsoAtoms: brType = None continue nonIsoRes = FakeRes(brType, nonIsoAtoms) nonIso.append(nonIsoRes) unchargedResTypes[isoType] = iso bondResidues = nonIso else: # no isolated atoms break if brType != resType: del unchargedResTypes[resType] if brType != None: unchargedResTypes[brType] = bondResidues # despite same residue type, residues may still differ -- particularly # terminal vs. non-terminal... for resType, residues in unchargedResTypes.items(): if len(residues) < 2: continue varieties = {} for r in residues: key = tuple([a.name for a in r.oslChildren()]) varieties.setdefault(key, []).append(r) if len(varieties) == 1: continue # in order to give the varieties distinguishing names, # find atoms in common keys = varieties.keys() common = set(keys[0]) for k in keys[1:]: common = common.intersection(set(k)) uncommon = set() for k in keys: uncommon = uncommon.union(set(k) - common) del unchargedResTypes[resType] for k, residues in varieties.items(): names = set(k) more = names - common less = uncommon - names newKey = resType if more: newKey += " (w/%s)" % ",".join(list(more)) if less: newKey += " (wo/%s)" % ",".join(list(less)) unchargedResTypes[newKey] = residues if status: status("Standard charges added\n") return unchargedResTypes, unchargedAtoms