def surface_zone_piece(p, points, distance): varray, tarray = p.geometry from _closepoints import find_close_points, BOXES_METHOD i1, i2 = find_close_points(BOXES_METHOD, varray, points, distance) from numpy import zeros, intc, put mask = zeros((len(varray),), intc) put(mask, i1, 1) p.setTriangleMaskFromVertexMask(mask) p.showing_zone = True
def surface_zone_piece(p, points, distance): varray, tarray = p.geometry from _closepoints import find_close_points, BOXES_METHOD i1, i2 = find_close_points(BOXES_METHOD, varray, points, distance) from numpy import zeros, intc, put mask = zeros((len(varray), ), intc) put(mask, i1, 1) p.setTriangleMaskFromVertexMask(mask) p.showing_zone = True
def surface_distance(v1, v2, t2, d, optimize = True): from _surface import surface_distance as surf_dist if optimize: from numpy import empty, float32 dist = empty((len(v1),), float32) dist[:] = 2*d # Use only vertices within 2*d contact range. import _closepoints as cp i1, i2 = cp.find_close_points(cp.BOXES_METHOD, v1, v2, 2*d) if len(i1) > 0 and len(i2) > 0: v1r = v1[i1] s2 = set(i2) t2r = [tri for tri in t2 if tri[0] in s2 or tri[1] in s2 or tri[2] in s2] dr = surf_dist(v1r, v2, t2r)[:,0] dist[i1] = dr else: dist = surf_dist(v1, v2, t2)[:,0] # n by 5 array (d,x,y,z,side) return dist
def surface_geometry(triangles, tolerance = 1e-5): from numpy import array, reshape, single as floatc, intc varray = reshape(triangles, (3*len(triangles),3)).astype(floatc) uindex = {} unique = [] from _closepoints import find_close_points, BOXES_METHOD for v in range(len(varray)): if not v in uindex: i1, i2 = find_close_points(BOXES_METHOD, varray[v:v+1,:], varray, tolerance) for i in i2: if not i in uindex: uindex[i] = len(unique) unique.append(varray[v]) uvarray = array(unique, floatc) tlist = map(lambda t: (uindex[3*t],uindex[3*t+1],uindex[3*t+2]), range(len(triangles))) tarray = array(tlist, intc) return uvarray, tarray
def search_for_ligands(metal): """ Search for ligands near by the metal center excluding candidates through the next steps: 1-How many electrons on the outter shell 2-Metal-Ligand distance 3-Geometry angles 4-Exclude Hydrogens and other atoms Parameters: ----------- metal: chimera metal object Output: ------- chimera ligands object """ # Extracted directly from: # Metal Geom Chimera data = [] coordLim = 4.0 from numpy import array atoms = array(metal.molecule.atoms) from _multiscale import get_atom_coordinates as gac from _closepoints import find_close_points, BOXES_METHOD ignore, close = find_close_points(BOXES_METHOD, gac(array([metal])), gac(atoms), coordLim) candidates = list(set(atoms[close])) mcrd = metal.coord() candidates.sort(lambda a1, a2: cmp(a1.coord().sqdistance(mcrd), a2.coord().sqdistance(mcrd))) exclude = [] userIncluded = [] for candidate in candidates: if candidate == metal: continue if candidate in exclude: continue if candidate not in userIncluded: valence = (candidate.element.number - 2) % 8 if valence < 5 or candidate.element.number == 1: continue if candidate.coord().distance(mcrd) > coordLim: break if candidate not in metal.bondsMap: from chimera import angle from chimera.idatm import typeInfo angleOK = True try: cnGeom = typeInfo[candidate.idatmType].geometry except KeyError: cnGeom = 0 else: if len(candidate.primaryNeighbors()) == cnGeom: # no lone pairs, no possibility of deprotonation continue angleCutoff = [0.0, 72.98, 120.0, 80.0, 72.98][cnGeom] for cnb in candidate.neighbors: if cnb == metal: continue if angle(cnb.coord(), candidate.coord(), metal.coord()) < angleCutoff: angleOK = False break if not angleOK: continue data.append(candidate) return data
def computeVolume(self, atoms, startFrame=None, endFrame=None, bound=None, volumeName=None, step=1, spacing=0.5): # load and process frames if startFrame is None: startFrame = self.startFrame if endFrame is None: endFrame = self.endFrame if bound is not None: from _closepoints import find_close_points, BOXES_METHOD from Matrix import xform_matrix if self.holdingSteady: steadyAtoms, steadySel, steadyCS, inverse = \ self.holdingSteady # all the above used later... inverse = xform_matrix(inverse) gridData = {} from math import floor from numpy import array, float32 from _contour import affine_transform_vertices for fn in range(startFrame, endFrame + 1, step): cs = self.findCoordSet(fn) if not cs: self.status("Loading frame %d" % fn) self._LoadFrame(fn, makeCurrent=False) cs = self.findCoordSet(fn) self.status("Processing frame %d" % fn) pts = array([a.coord(cs) for a in atoms], float32) if self.holdingSteady: if bound is not None: steadyPoints = array([a.coord(cs) for a in steadyAtoms], float32) closeIndices = find_close_points( BOXES_METHOD, steadyPoints, #otherPoints, bound)[1] pts, bound)[1] pts = pts[closeIndices] try: xf, inv = self.transforms[fn] except KeyError: xf, inv = self.steadyXform(cs=cs) self.transforms[fn] = (xf, inv) xf = xform_matrix(xf) affine_transform_vertices(pts, xf) affine_transform_vertices(pts, inverse) # add a half-voxel since volume positions are # considered to be at the center of their voxel from numpy import floor, zeros pts = floor(pts / spacing + 0.5).astype(int) for pt in pts: center = tuple(pt) gridData[center] = gridData.get(center, 0) + 1 # generate volume self.status("Generating volume") axisData = zip(*tuple(gridData.keys())) minXyz = [min(ad) for ad in axisData] maxXyz = [max(ad) for ad in axisData] # allow for zero-padding on both ends dims = [maxXyz[axis] - minXyz[axis] + 3 for axis in range(3)] from numpy import zeros, transpose volume = zeros(dims, int) for index, val in gridData.items(): adjIndex = tuple([index[i] - minXyz[i] + 1 for i in range(3)]) volume[adjIndex] = val from VolumeData import Array_Grid_Data gd = Array_Grid_Data( volume.transpose(), # the "cushion of zeros" means d-1... [(d - 1) * spacing for d in minXyz], [spacing] * 3) if volumeName is None: volumeName = self.ensemble.name gd.name = volumeName # show volume self.status("Showing volume") import VolumeViewer dataRegion = VolumeViewer.volume_from_grid_data(gd) vd = VolumeViewer.volumedialog.volume_dialog(create=True) vd.message("Volume can be saved from File menu") self.status("Volume shown")
def computeVolume(self, atoms, startFrame=None, endFrame=None, bound=None, volumeName=None, step=1, spacing=0.5): # load and process frames if startFrame is None: startFrame = self.startFrame if endFrame is None: endFrame = self.endFrame if bound is not None: from _closepoints import find_close_points, BOXES_METHOD from Matrix import xform_matrix if self.holdingSteady: steadyAtoms, steadySel, steadyCS, inverse = \ self.holdingSteady # all the above used later... inverse = xform_matrix(inverse) gridData = {} from math import floor from numpy import array, float32 from _contour import affine_transform_vertices for fn in range(startFrame, endFrame+1, step): cs = self.findCoordSet(fn) if not cs: self.status("Loading frame %d" % fn) self._LoadFrame(fn, makeCurrent=False) cs = self.findCoordSet(fn) self.status("Processing frame %d" % fn) pts = array([a.coord(cs) for a in atoms], float32) if self.holdingSteady: if bound is not None: steadyPoints = array([a.coord(cs) for a in steadyAtoms], float32) closeIndices = find_close_points( BOXES_METHOD, steadyPoints, #otherPoints, bound)[1] pts, bound)[1] pts = pts[closeIndices] try: xf, inv = self.transforms[fn] except KeyError: xf, inv = self.steadyXform(cs=cs) self.transforms[fn] = (xf, inv) xf = xform_matrix(xf) affine_transform_vertices(pts, xf) affine_transform_vertices(pts, inverse) # add a half-voxel since volume positions are # considered to be at the center of their voxel from numpy import floor, zeros pts = floor(pts/spacing + 0.5).astype(int) for pt in pts: center = tuple(pt) gridData[center] = gridData.get(center, 0) + 1 # generate volume self.status("Generating volume") axisData = zip(*tuple(gridData.keys())) minXyz = [min(ad) for ad in axisData] maxXyz = [max(ad) for ad in axisData] # allow for zero-padding on both ends dims = [maxXyz[axis] - minXyz[axis] + 3 for axis in range(3)] from numpy import zeros, transpose volume = zeros(dims, int) for index, val in gridData.items(): adjIndex = tuple([index[i] - minXyz[i] + 1 for i in range(3)]) volume[adjIndex] = val from VolumeData import Array_Grid_Data gd = Array_Grid_Data(volume.transpose(), # the "cushion of zeros" means d-1... [(d-1) * spacing for d in minXyz], [spacing] * 3) if volumeName is None: volumeName = self.ensemble.name gd.name = volumeName # show volume self.status("Showing volume") import VolumeViewer dataRegion = VolumeViewer.volume_from_grid_data(gd) vd = VolumeViewer.volumedialog.volume_dialog(create=True) vd.message("Volume can be saved from File menu") self.status("Volume shown")
display.add(r) elif getattr(principalAtom(r), "name", None) == "C4'": # decide whether to display later nukes.append(r) if nukes: nucleic[m] = nukes if allAtoms or not ligand: continue from numpy import array, float32 ligPoints = array([a.coord() for r in ligand for a in r.atoms], float32) atoms = m.atoms molPoints = array([a.coord() for a in atoms], float32) from _closepoints import find_close_points, BOXES_METHOD closeIndices = find_close_points(BOXES_METHOD, ligPoints, molPoints, 3.5)[1] interacting.update(array(atoms).take(closeIndices)) if publication: for srf in chimera.openModels.list( modelTypes=[chimera.MSMSModel]): if (srf.colorMode != chimera.MSMSModel.Custom and srf.density < 10.0 and srf.molecule is not None): srf.density = 10.0 return if surface: if ribMolecules: mols = ribMolecules else: mols = chimera.openModels.list( modelTypes=[chimera.Molecule])
def detectClash(testAtoms, test="others", clashThreshold=clashDef, hbondAllowance=hbondDef, assumedMaxVdw=2.1, bondSeparation=bondSepDef, intraRes=False, interSubmodel=False): """Detect steric clashes 'testAtoms' should be a list of atoms. If 'test' is 'others' then non-bonded clashes between atoms in 'testAtoms' and non-'testAtoms' atoms will be found. If 'test' is 'model' then the same clashes as 'others' will be found, but inter-model clashes will be eliminated. If 'test' is 'self' then non-bonded clashes within 'testAtoms' atoms will be found. Otherwise 'test' should be a list of atoms to test against. The "clash value" is the sum of the VDW radii minus the distance, keeping only the maximal clash (which must exceed 'clashThreshold'). 'hbondAllowance' is how much the clash value is reduced if one atom is a donor and the other an acceptor. Atom pairs are eliminated from consideration if they are less than or equal to 'bondSeparation' bonds apart. Intra-residue clashes are ignored unless intraRes is True. Inter-submodel clashes are ignored unless interSubmodel is True. Returns a dictionary keyed on atoms, with values that are dictionaries keyed on clashing atom with value being the clash value. """ # use the fast _closepoints module to cut down candidate atoms if we # can (since _closepoints doesn't know about "non-bonded" it isn't as # useful as it might otherwise be) if test in ("others", "model"): mList = chimera.openModels.list(modelTypes=[chimera.Molecule]) testSet = set(testAtoms) from numpy import array testList = array(testAtoms) otherAtoms = [a for m in mList for a in m.atoms if a not in testSet] otherAtoms = array(otherAtoms) if len(otherAtoms) == 0: from chimera import UserError raise UserError("All atoms are in test set: no others" " available to test against") from _multiscale import get_atom_coordinates tPoints = get_atom_coordinates(testList, transformed = True) oPoints = get_atom_coordinates(otherAtoms, transformed = True) cutoff = 2.0 * assumedMaxVdw - clashThreshold from _closepoints import find_close_points, BOXES_METHOD tClose, oClose = find_close_points(BOXES_METHOD, tPoints, oPoints, cutoff) testAtoms = testList.take(tClose) searchAtoms = otherAtoms.take(oClose) elif not isinstance(test, basestring): searchAtoms = test else: searchAtoms = testAtoms from chimera.misc import atomSearchTree tree = atomSearchTree(list(searchAtoms)) clashes = {} for a in testAtoms: cutoff = a.radius + assumedMaxVdw - clashThreshold nearby = tree.searchTree(a.xformCoord().data(), cutoff) if not nearby: continue needExpansion = a.allLocations() exclusions = set(needExpansion) for i in range(bondSeparation): nextNeed = [] for expand in needExpansion: for n in expand.neighbors: if n in exclusions: continue exclusions.add(n) nextNeed.append(n) needExpansion = nextNeed for nb in nearby: if nb in exclusions: continue if not intraRes and a.residue == nb.residue: continue if a in clashes and nb in clashes[a]: continue if not interSubmodel \ and a.molecule.id == nb.molecule.id \ and a.molecule.subid != nb.molecule.subid: continue if test == "model" and a.molecule != nb.molecule: continue clash = a.radius + nb.radius - a.xformCoord().distance( nb.xformCoord()) if hbondAllowance: if (_donor(a) and _acceptor(nb)) or ( _donor(nb) and _acceptor(a)): clash -= hbondAllowance if clash < clashThreshold: continue clashes.setdefault(a, {})[nb] = clash clashes.setdefault(nb, {})[a] = clash return clashes
def detectClash(testAtoms, test="others", clashThreshold=clashDef, hbondAllowance=hbondDef, assumedMaxVdw=2.1, bondSeparation=bondSepDef, intraRes=False, interSubmodel=False): """Detect steric clashes 'testAtoms' should be a list of atoms. If 'test' is 'others' then non-bonded clashes between atoms in 'testAtoms' and non-'testAtoms' atoms will be found. If 'test' is 'model' then the same clashes as 'others' will be found, but inter-model clashes will be eliminated. If 'test' is 'self' then non-bonded clashes within 'testAtoms' atoms will be found. Otherwise 'test' should be a list of atoms to test against. The "clash value" is the sum of the VDW radii minus the distance, keeping only the maximal clash (which must exceed 'clashThreshold'). 'hbondAllowance' is how much the clash value is reduced if one atom is a donor and the other an acceptor. Atom pairs are eliminated from consideration if they are less than or equal to 'bondSeparation' bonds apart. Intra-residue clashes are ignored unless intraRes is True. Inter-submodel clashes are ignored unless interSubmodel is True. Returns a dictionary keyed on atoms, with values that are dictionaries keyed on clashing atom with value being the clash value. """ # use the fast _closepoints module to cut down candidate atoms if we # can (since _closepoints doesn't know about "non-bonded" it isn't as # useful as it might otherwise be) if test in ("others", "model"): mList = chimera.openModels.list(modelTypes=[chimera.Molecule]) testSet = set(testAtoms) from numpy import array testList = array(testAtoms) otherAtoms = [a for m in mList for a in m.atoms if a not in testSet] otherAtoms = array(otherAtoms) if len(otherAtoms) == 0: from chimera import UserError raise UserError("All atoms are in test set: no others" " available to test against") from _multiscale import get_atom_coordinates tPoints = get_atom_coordinates(testList, transformed=True) oPoints = get_atom_coordinates(otherAtoms, transformed=True) cutoff = 2.0 * assumedMaxVdw - clashThreshold from _closepoints import find_close_points, BOXES_METHOD tClose, oClose = find_close_points(BOXES_METHOD, tPoints, oPoints, cutoff) testAtoms = testList.take(tClose) searchAtoms = otherAtoms.take(oClose) elif not isinstance(test, basestring): searchAtoms = test else: searchAtoms = testAtoms from chimera.misc import atomSearchTree tree = atomSearchTree(list(searchAtoms)) clashes = {} for a in testAtoms: cutoff = a.radius + assumedMaxVdw - clashThreshold nearby = tree.searchTree(a.xformCoord().data(), cutoff) if not nearby: continue needExpansion = a.allLocations() exclusions = set(needExpansion) for i in range(bondSeparation): nextNeed = [] for expand in needExpansion: for n in expand.neighbors: if n in exclusions: continue exclusions.add(n) nextNeed.append(n) needExpansion = nextNeed for nb in nearby: if nb in exclusions: continue if not intraRes and a.residue == nb.residue: continue if a in clashes and nb in clashes[a]: continue if not interSubmodel \ and a.molecule.id == nb.molecule.id \ and a.molecule.subid != nb.molecule.subid: continue if test == "model" and a.molecule != nb.molecule: continue clash = a.radius + nb.radius - a.xformCoord().distance( nb.xformCoord()) if hbondAllowance: if (_donor(a) and _acceptor(nb)) or (_donor(nb) and _acceptor(a)): clash -= hbondAllowance if clash < clashThreshold: continue clashes.setdefault(a, {})[nb] = clash clashes.setdefault(nb, {})[a] = clash return clashes