def libadd_ring(self): """add ring to library or open it in a new model""" selection = self.session.seqcrow_ordered_selection_manager.selection if not selection.single_structure: raise RuntimeError("selected atoms must be on the same model") rescol = ResidueCollection(selection[0].structure) walk_atoms = rescol.find( [AtomSpec(atom.atomspec) for atom in selection]) if len(walk_atoms) < 1: raise RuntimeError("no walk direction could be determined") ring_name = self.ring_name.text() ring = Ring(rescol, name=ring_name, end=walk_atoms) ring.comment = "E:%s" % ",".join( [str(rescol.atoms.index(atom) + 1) for atom in walk_atoms]) if len(ring_name) == 0: chimerax_ring = ResidueCollection(ring).get_chimera(self.session) chimerax_ring.name = "ring preview" self.session.models.add([chimerax_ring]) bild_obj = show_walk_highlight(ring, chimerax_ring, [0.9, 0.4, 0.3, 0.9], self.session) self.session.models.add(bild_obj, parent=chimerax_ring) else: check_aaronlib_dir() filename = os.path.join(AARONLIB, "Rings", ring_name + ".xyz") if os.path.exists(filename): exists_warning = QMessageBox() exists_warning.setIcon(QMessageBox.Warning) exists_warning.setText( "%s already exists.\nWould you like to overwrite?" % filename) exists_warning.setStandardButtons(QMessageBox.Yes | QMessageBox.No) rv = exists_warning.exec_() if rv == QMessageBox.Yes: ring.write(outfile=filename) self.tool_window.status("%s added to ring library" % ring_name) else: self.tool_window.status( "%s has not been added to ring library" % ring_name) else: ring.write(outfile=filename) self.tool_window.status("%s added to ring library" % ring_name)
def substitute(self, sub, target, *args, attached_to=None, **kwargs): if attached_to is None: from SEQCROW.selectors import get_fragment frags = [] target = self.find(target)[0] target_chix = target.chix_atom for bonded_atom in target_chix.neighbors: frags.append(get_fragment(bonded_atom, target_chix, 1000)) attached_to = None longest_frag = None for test_end, (i, frag1) in zip(target_chix.neighbors, enumerate(frags)): cyclic = False for frag2 in frags[i + 1:]: if frag1.intersects(frag2): cyclic = True break if cyclic: continue if attached_to is None or len(longest_frag) < len(frag1): longest_frag = frag1 attached_to = test_end if attached_to is not None: attached_to = self.find(AtomSpec(attached_to.atomspec))[0] return super().substitute(sub, target, *args, attached_to=attached_to, **kwargs)
def calc_cone(self, *args): self.settings.cone_option = self.cone_option.currentText() self.settings.radii = self.radii_option.currentText() self.settings.display_radii = self.display_radii.checkState( ) == Qt.Checked self.settings.display_cone = self.display_cone.checkState( ) == Qt.Checked if self.cone_option.currentText() == "Tolman (Unsymmetrical)": method = "tolman" else: method = self.cone_option.currentText() radii = self.radii_option.currentText() return_cones = self.display_cone.checkState() == Qt.Checked display_radii = self.display_radii.checkState() == Qt.Checked # self.table.setRowCount(0) for center_atom in selected_atoms(self.session): rescol = ResidueCollection(center_atom.structure) at_center = rescol.find_exact(AtomSpec(center_atom.atomspec))[0] if center_atom.structure in self.ligands: comp = Component( rescol.find([ AtomSpec(atom.atomspec) for atom in self.ligands[center_atom.structure] ]), to_center=rescol.find_exact(AtomSpec( center_atom.atomspec)), key_atoms=rescol.find(BondedTo(at_center)), ) else: comp = Component( rescol.find(NotAny(at_center)), to_center=rescol.find_exact(AtomSpec( center_atom.atomspec)), key_atoms=rescol.find(BondedTo(at_center)), ) cone_angle = comp.cone_angle( center=rescol.find(AtomSpec(center_atom.atomspec)), method=method, radii=radii, return_cones=return_cones, ) if return_cones: cone_angle, cones = cone_angle s = ".transparency 0.5\n" for cone in cones: apex, base, radius = cone s += ".cone %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f %.3f open\n" % ( *apex, *base, radius) stream = BytesIO(bytes(s, "utf-8")) bild_obj, status = read_bild(self.session, stream, "Cone angle %s" % center_atom) self.session.models.add(bild_obj, parent=center_atom.structure) if display_radii: s = ".note radii\n" s += ".transparency 75\n" color = None for atom in comp.atoms: chix_atom = atom.chix_atom if radii.lower() == "umn": r = VDW_RADII[chix_atom.element.name] elif radii.lower() == "bondi": r = BONDI_RADII[chix_atom.element.name] if color is None or chix_atom.color != color: color = chix_atom.color rgb = [x / 255. for x in chix_atom.color] rgb.pop(-1) s += ".color %f %f %f\n" % tuple(rgb) s += ".sphere %f %f %f %f\n" % (*chix_atom.coord, r) stream = BytesIO(bytes(s, "utf-8")) bild_obj, status = read_bild(self.session, stream, "Cone angle radii") self.session.models.add(bild_obj, parent=center_atom.structure) row = self.table.rowCount() self.table.insertRow(row) name = QTableWidgetItem() name.setData(Qt.DisplayRole, center_atom.structure.name) self.table.setItem(row, 0, name) center = QTableWidgetItem() center.setData(Qt.DisplayRole, center_atom.atomspec) self.table.setItem(row, 1, center) ca = QTableWidgetItem() ca.setData(Qt.DisplayRole, "%.2f" % cone_angle) self.table.setItem(row, 2, ca) self.table.resizeColumnToContents(0) self.table.resizeColumnToContents(1) self.table.resizeColumnToContents(2)
def fuseRing(session, selection=None, rings=None, newName=None, modify=True, minimize=False, available=False): if available: fuseRing_list(session) return if not selection: selection = selected_atoms(session) if not rings: session.logger.error("missing required \"rings\" argument") return if newName is None: pass elif any(len(name.strip()) > 4 for name in newName): raise RuntimeError("residue names must be 4 characters or less") elif not all(name.isalnum() for name in newName): raise RuntimeError("invalid residue name: %s" % newName) elif len(rings) != len(newName): raise RuntimeError( "number of substituents is not the same as the number of new names" ) if len(selection) < 2: raise RuntimeWarning("two atoms must be selected per molecule") models = {} for atom in selection: if atom.structure not in models: models[atom.structure] = [atom] else: models[atom.structure].append(atom) if len(models[atom.structure]) > 2: raise RuntimeError("only two atoms can be selected on any model") first_pass = True new_structures = [] for i, ringname in enumerate(rings): ringname = ringname.strip() for model in models: atom1 = models[model][0] atom2 = models[model][1] if modify and first_pass: convert = minimal_ring_convert(model, *models[model]) if newName is not None: for res in convert: res.name = newName[i] rescol = ResidueCollection(model, convert_residues=convert) target = rescol.find( [AtomSpec(atom1.atomspec), AtomSpec(atom2.atomspec)]) elif modify and not first_pass: raise RuntimeError("only the first model can be replaced") else: model_copy = model.copy() a1 = model_copy.atoms[model.atoms.index(models[model][0])] a2 = model_copy.atoms[model.atoms.index(models[model][1])] convert = minimal_ring_convert(model_copy, a1, a2) if newName is not None: for res in convert: res.name = newName[i] rescol = ResidueCollection(model_copy, convert_residues=convert) target = rescol.find( [AtomSpec(a1.atomspec), AtomSpec(a2.atomspec)]) rescol.ring_substitute(target, ringname, minimize=minimize) if modify: rescol.update_chix(model) else: rescol.update_chix(model_copy) new_structures.append(model_copy) first_pass = False if not modify: session.models.add(new_structures)
def percent_vbur( session, selection, radii="UMN", radius=3.5, scale=1.17, method="Lebedev", radialPoints=20, angularPoints=1454, minimumIterations=25, onlyAtoms=None, center=None, useCentroid=True, displaySphere=None, pointSpacing=0.1, intersectionScale=6, palette="rainbow", return_values=False, steric_map=False, useScene=False, num_pts=100, shape="circle", labels="none", reportComponent="total", ): out = [] models = { model: [ atom for atom in model.atoms if onlyAtoms is not None and atom in onlyAtoms ] for model in selection if isinstance(model, AtomicStructure) } s = "<pre>model\tcenter\t%Vbur\n" for model in models: if len(models[model]) == 0: targets = None else: targets = [AtomSpec(atom.atomspec) for atom in models[model]] if center is not None: if isinstance(center, tuple): mdl_center = np.array(center) else: mdl_center = [ AtomSpec(atom.atomspec) for atom in model.atoms if atom in center ] else: mdl_center = [] rescol = ResidueCollection(model) if useScene: oop_vector = session.view.camera.get_position().axes()[2] ip_vector = session.view.camera.get_position().axes()[1] x_vec = session.view.camera.get_position().axes()[0] basis = np.array([x_vec, ip_vector, oop_vector]).T else: oop_vector = None ip_vector = None basis = None if len(mdl_center) == 0: rescol.detect_components() mdl_center = rescol.center elif not isinstance(center, np.ndarray): mdl_center = rescol.find([AtomSpec(c.atomspec) for c in center]) key_atoms = None if not useCentroid and not isinstance(center, np.ndarray): for c in mdl_center: if targets is not None: key_atoms = [] targets = rescol.find(targets) for atom in targets: if c in atom.connected or atom in c.connected: key_atoms.append(atom) else: key_atoms = None if (labels != "none" or reportComponent != "total") and not useScene: if not key_atoms: session.logger.warning( "bonds between center and coordinating atoms is required to" " properly orient octants") oop_vector = np.zeros(3) for atom in key_atoms: oop_vector += c.coords - atom.coords if len(key_atoms) == 1: ip_vector = perp_vector(oop_vector) x_vec = np.cross(ip_vector, oop_vector) else: coords = [atom.coords for atom in key_atoms] coords.append(c.coords) coords = np.array(coords) ip_vector = perp_vector(coords) x_vec = np.cross(ip_vector, oop_vector) x_vec /= np.linalg.norm(x_vec) ip_vector = -np.cross(x_vec, oop_vector) ip_vector /= np.linalg.norm(ip_vector) basis = np.array([x_vec, ip_vector, oop_vector]).T if steric_map: x, y, z, min_alt, max_alt, basis, _ = rescol.steric_map( center=c, key_atoms=key_atoms, radii=radii, oop_vector=oop_vector, ip_vector=ip_vector, radius=radius, return_basis=True, num_pts=num_pts, shape=shape, ) vbur = rescol.percent_buried_volume( targets=targets, basis=basis, center=c, radius=radius, radii=radii, scale=scale, method=method, rpoints=int(radialPoints), apoints=int(angularPoints), min_iter=minimumIterations, ) if steric_map: out.append( (model, c.atomspec, vbur, (x, y, z, min_alt, max_alt))) else: out.append((model, c.atomspec, vbur)) s += "%s\t%s\t" % (model.name, c.atomspec) if hasattr(vbur, "__iter__"): if reportComponent == "octants": s += "%s\n" % ",".join(["%.1f%%" % v for v in vbur]) elif reportComponent == "quadrants": s += "%s\n" % ",".join([ "%.1f%%" % v for v in [ vbur[0] + vbur[7], vbur[1] + vbur[6], vbur[2] + vbur[5], vbur[3] + vbur[4], ] ]) else: s += "%.1f%%\n" % sum(vbur) else: s += "%.1f%%\n" % vbur if displaySphere is not None: mdl = vbur_vis( session, rescol, targets, radii, scale, radius, c, pointSpacing, intersectionScale, displaySphere, vbur, labels, basis=basis, ) model.add(mdl) atomspec = mdl[0].atomspec center_coords = rescol.COM(c) args = [ "color", "radial", atomspec, "center", ",".join(["%.4f" % x for x in center_coords]), "palette", palette, "range", "0,%.2f" % radius, "coordinateSystem", model.atomspec, ";", "transparency", atomspec, "30", ] run(session, " ".join(args)) else: if targets is not None: key_atoms = [] targets = rescol.find(targets) for atom in targets: if any(c in atom.connected for c in mdl_center): key_atoms.append(atom) else: key_atoms = None if (labels != "none" or reportComponent != "total") and not useScene: if not key_atoms: session.logger.warning( "bonds between center and coordinating atoms is required to" " properly orient octants") oop_vector = np.zeros(3) for atom in key_atoms: if isinstance(mdl_center, np.ndarray): oop_vector += mdl_center - atom.coords else: for c in mdl_center: oop_vector += c.coords - atom.coords if len(key_atoms) == 1: ip_vector = perp_vector(oop_vector) x_vec = np.cross(ip_vector, oop_vector) else: coords = [atom.coords for atom in key_atoms] if isinstance(mdl_center, np.ndarray): coords.append(mdl_center) else: coords.extend([c.coords for c in mdl_center]) coords = np.array(coords) ip_vector = perp_vector(coords) x_vec = np.cross(ip_vector, oop_vector) x_vec /= np.linalg.norm(x_vec) ip_vector = -np.cross(x_vec, oop_vector) ip_vector /= np.linalg.norm(ip_vector) basis = np.array([x_vec, ip_vector, oop_vector]).T if steric_map: x, y, z, min_alt, max_alt, basis, _ = rescol.steric_map( center=mdl_center, key_atoms=key_atoms, radius=radius, radii=radii, oop_vector=oop_vector, ip_vector=ip_vector, return_basis=True, num_pts=num_pts, shape=shape, ) vbur = rescol.percent_buried_volume( targets=targets, basis=basis, center=mdl_center, radius=radius, radii=radii, scale=scale, method=method, rpoints=int(radialPoints), apoints=int(angularPoints), min_iter=minimumIterations, ) if steric_map: if not isinstance(mdl_center, np.ndarray): out.append( (model, ",".join([c.atomspec for c in mdl_center]), vbur, (x, y, z, min_alt, max_alt))) else: out.append( (model, ",".join(["%.3f" % c for c in mdl_center]), vbur, (x, y, z, min_alt, max_alt))) else: if not isinstance(mdl_center, np.ndarray): s += "%s\t%s\t" % (model.name, ", ".join( [c.atomspec for c in mdl_center])) out.append( (model, ", ".join([c.atomspec for c in mdl_center]), vbur)) else: s += "%s\t%s\t" % (model.name, ",".join( ["%.3f" % c for c in mdl_center])) out.append( (model, ",".join(["%.3f" % c for c in mdl_center]), vbur)) if hasattr(vbur, "__iter__"): if reportComponent == "octants": s += "%s\n" % ",".join(["%.1f%%" % v for v in vbur]) elif reportComponent == "quadrants": s += "%s\n" % ",".join([ "%.1f%%" % v for v in [ vbur[0] + vbur[7], vbur[1] + vbur[6], vbur[2] + vbur[5], vbur[3] + vbur[4], ] ]) else: s += "%.1f%%\n" % sum(vbur) else: s += "%.1f%%\n" % vbur if displaySphere is not None: mdl = vbur_vis( session, rescol, targets, radii, scale, radius, mdl_center, pointSpacing, intersectionScale, displaySphere, vbur, labels, basis=basis, ) model.add(mdl) atomspec = mdl[0].atomspec if not isinstance(mdl_center, np.ndarray): center_coords = rescol.COM(mdl_center) else: center_coords = mdl_center #XXX: the center will be wrong if the models are tiled args = [ "color", "radial", atomspec, "center", ",".join(["%.4f" % x for x in center_coords]), "palette", palette, "range", "0,%.2f" % radius, "coordinateSystem", model.atomspec, ";", "transparency", atomspec, "30", ] run(session, " ".join(args)) s = s.strip() s += "</pre>" if not return_values: session.logger.info(s, is_html=True) else: return out
def mouse_up(self, event): if event.shift_down(): _ElementPicker(self.session, "pick element") return if not self.element: self.session.logger.warning( "no element selected; shift-click to set element") self.session.logger.status( "no element selected; shift-click to set element") _ElementPicker(self.session, "pick element") return x, y = event.position() pick = self.view.picked_object(x, y) if not pick: x1, x2 = self.session.main_view.clip_plane_points(x, y) coords = (x1 + x2) / 2 new_fragment = _ModelSelector(self.session, "place atom in model", coords) if new_fragment.model_selector.count() == 1: new_fragment.new_atom() return # import cProfile # # profile = cProfile.Profile() # profile.enable() vsepr = self.vsepr if vsepr == "do not change": vsepr = False elif vsepr == "linear (1 bond)": vsepr = "linear 1" goal = 1 elif vsepr == "linear (2 bonds)": vsepr = "linear 2" goal = 2 elif vsepr == "trigonal planar (2 bonds)": vsepr = "bent 2 planar" goal = 2 elif vsepr == "tetrahedral (2 bonds)": vsepr = "bent 2 tetrahedral" goal = 2 elif vsepr == "trigonal planar": goal = 3 elif vsepr == "tetrahedral (3 bonds)": vsepr = "bent 3 tetrahedral" goal = 3 elif vsepr == "tetrahedral": goal = 4 else: goal = len(Atom.get_shape(vsepr)) - 1 if not isinstance(pick, PickedAtom): return atom = pick.atom # # use built-in ChimeraX command for some of the more common things # # because it's faster for proteins # if False: # run( # self.session, # "build modify %s %s %i geometry %s" % ( # atom.atomspec, # self.element, # goal, # vsepr, # ) # ) # frags = [] for neighbor in atom.neighbors: frags.append( get_fragment(neighbor, stop=atom, max_len=atom.structure.num_atoms)) residues = [atom.residue] hold_steady = None for i, frag in enumerate(sorted(frags, key=len)): if i == len(frags) - 1: hold_steady = AtomSpec(frag[0].atomspec) residues.append(frag[0].residue) continue residues.extend(frag.residues) rescol = ResidueCollection(atom.structure, convert_residues=set(residues), refresh_ranks=False) res = [ residue for residue in rescol.residues if residue.chix_residue is atom.residue ][0] target = res.find_exact(AtomSpec(atom.atomspec))[0] adjust_hydrogens = vsepr if vsepr is not False: cur_bonds = len(target.connected) change_Hs = goal - cur_bonds adjust_hydrogens = (change_Hs, vsepr) rescol.change_element( target, self.element, adjust_bonds=True, adjust_hydrogens=adjust_hydrogens, hold_steady=hold_steady, ) res.update_chix(res.chix_residue, apply_preset=True, refresh_connected=True) rescol.update_chix(atom.structure, apply_preset=False, refresh_connected=False)
def ligandSterimol(session, selection, radii="UMN", showVectors=True, showRadii=True, at_L=None, bisect_L=False, return_values=False): models, center, key_atoms = avoidTargets(session.logger, selection) radii = radii.lower() targets = [] coord_atoms = [] datas = [] info = "<pre>model\tcoord. atoms\tB1\tB2\tB3\tB4\tB5\tL\n" # if return_values: # if len(models.keys()) > 1: # raise RuntimeError("only one substituent may be selected") # if any(len(models[key]) > 1 for key in models.keys()): # raise RuntimeError("only one substituent may be selected") for model in models: rescol = ResidueCollection(model) comp_atoms = [AtomSpec(at.atomspec) for at in models[model]] key_atomspec = [AtomSpec(at.atomspec) for at in key_atoms[model]] center_atomspec = [AtomSpec(at.atomspec) for at in center[model]] if len(center_atomspec) != 1: session.logger.error( "ligand sterimol requires one central atom to which " + \ "the ligand is coordinated\n" + \ "%i were found on model %s:\n" % (len(center_atomspec), model.atomspec) + \ "\n".join([at.atomspec for at in center[model]]) ) continue comp = Component( rescol.find(comp_atoms), to_center=rescol.find(center_atomspec), key_atoms=rescol.find(key_atomspec), ) data = comp.sterimol( return_vector=True, radii=radii, at_L=at_L, to_center=rescol.find(center_atomspec), bisect_L=bisect_L, ) l = np.linalg.norm(data["L"][1] - data["L"][0]) b1 = np.linalg.norm(data["B1"][1] - data["B1"][0]) b2 = np.linalg.norm(data["B2"][1] - data["B2"][0]) b3 = np.linalg.norm(data["B3"][1] - data["B3"][0]) b4 = np.linalg.norm(data["B4"][1] - data["B4"][0]) b5 = np.linalg.norm(data["B5"][1] - data["B5"][0]) if showVectors: for key, color in zip( ["B1", "B2", "B3", "B4", "B5", "L"], ["black", "green", "purple", "orange", "red", "blue"]): start, end = data[key] s = ".color %s\n" % color s += ".note Sterimol %s\n" % key s += ".arrow %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n" % ( *start, *end) stream = BytesIO(bytes(s, "utf-8")) bild_obj, status = read_bild(session, stream, "Sterimol %s" % key) session.models.add(bild_obj, parent=model) if showRadii: s = ".note radii\n" s += ".transparency 75\n" color = None for atom in comp.atoms: chix_atom = atom.chix_atom if radii == "umn": r = VDW_RADII[chix_atom.element.name] elif radii == "bondi": r = BONDI_RADII[chix_atom.element.name] if color is None or chix_atom.color != color: color = chix_atom.color rgb = [x / 255. for x in chix_atom.color] rgb.pop(-1) s += ".color %f %f %f\n" % tuple(rgb) s += ".sphere %f %f %f %f\n" % (*chix_atom.coord, r) stream = BytesIO(bytes(s, "utf-8")) bild_obj, status = read_bild(session, stream, "Sterimol radii") session.models.add(bild_obj, parent=model) name = get_filename(model.name, include_parent_dir=False) info += "%-16s\t%-11s\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n" % ( name, ", ".join(at.atomspec for at in key_atoms[model]), b1, b2, b3, b4, b5, l) targets.append(name) coord_atoms.append([at.atomspec for at in key_atoms[model]]) datas.append(data) info = info.strip() info += "</pre>" if not return_values: session.logger.info(info, is_html=True) if return_values: return targets, coord_atoms, datas
def substitute( session, selection=None, substituents=None, newName=None, guessAttachment=True, modify=True, minimize=False, useRemoteness=False, available=False, newResidue=False, ): if available: substitute_list(session) return if not selection: selection = selected_atoms(session) if not substituents: session.logger.error("missing required \"substituents\" argument") return attached = {} if newName is None: newName = [None for s in substituents] elif any(len(name.strip()) > 4 for name in newName): raise RuntimeError("residue names must be 4 characters or less") elif not all(name.isalnum() for name in newName): raise RuntimeError("invalid residue name: %s" % " ".join(newName)) elif len(substituents) != len(newName): raise RuntimeError( "number of substituents is not the same as the number of new names" ) if not guessAttachment: models, attached = avoidTargets(selection) else: models, attached = guessAttachmentTargets(selection, session) first_pass = True new_structures = [] for ndx, subname in enumerate(substituents): subname = subname.strip() sub = Substituent(subname) # when minimizing, we only want to deal with residues that are close to the substituent # determine the size of the new substituent to limit this if minimize: size = 5 for atom in sub.atoms: d = np.linalg.norm(atom.coords) if d > size: size = d for model in models: if modify and first_pass: conv_res = [] for res in models[model]: if res not in conv_res: conv_res.append(res) if minimize: for chix_res in model.residues: if chix_res in conv_res: continue added_res = False for atom in chix_res.atoms: for target in models[model][res]: d = np.linalg.norm(atom.coord - target.coord) if d < (size + 3): conv_res.append(chix_res) added_res = True break if added_res: break rescol = ResidueCollection(model, convert_residues=conv_res) for res in models[model]: for target in models[model][res]: if attached is not None: end = AtomSpec(attached[target].atomspec) else: end = None # call substitute on the ResidueCollection b/c we need to see # the other residues if minimize=True rescol.substitute( sub.copy(), AtomSpec(target.atomspec), attached_to=end, minimize=minimize, use_greek=useRemoteness, new_residue=newResidue, new_name=newName[ndx], ) rescol.update_chix(model) elif modify and not first_pass: raise RuntimeError("only the first model can be replaced") else: model_copy = model.copy() conv_res = [ model_copy.residues[i] for i in [model.residues.index(res) for res in models[model]] ] # modifying_residues = [model_copy.residues[i] for i in [model.residues.index(res) for res in models[model]]] modifying_residues = [r for r in conv_res] if minimize: for chix_res in model_copy.residues: if chix_res in conv_res: continue added_res = False for res in models[model]: for target in models[model][res]: for atom in chix_res.atoms: d = np.linalg.norm(atom.coord - target.coord) if d < (size + 3): conv_res.append(chix_res) added_res = True break if added_res: break if added_res: break rescol = ResidueCollection(model_copy, convert_residues=conv_res) for residue, res in zip(modifying_residues, models[model]): for target in models[model][res]: if attached is not None: end = AtomSpec(model_copy.atoms[model.atoms.index( attached[target])].atomspec) else: end = None rescol.substitute( sub.copy(), AtomSpec(model_copy.atoms[model.atoms.index( target)].atomspec), attached_to=end, minimize=minimize, use_greek=useRemoteness, new_residue=newResidue, new_name=newName[ndx], ) rescol.update_chix(model_copy) new_structures.append(model_copy) first_pass = False if not modify: session.models.add(new_structures)
def sterimol( session, selection, radii="UMN", showVectors=True, showRadii=True, LCorrection="FORTRAN", return_values=False ): models, attached = avoidTargets(session.logger, selection) radii = radii.lower() old_L = False if LCorrection.upper() == "FORTRAN": old_L = True model_names = [] targets = [] datas = [] info = "<pre>model\tsubstituent atom\tB1\tB2\tB3\tB4\tB5\tL\n" # if return_values: # if len(models.keys()) > 1: # raise RuntimeError("only one substituent may be selected") # if any(len(models[key]) > 1 for key in models.keys()): # raise RuntimeError("only one substituent may be selected") for model in models: rescol = ResidueCollection(model, refresh_ranks=False) for res in models[model]: for target in models[model][res]: end_atomspec = AtomSpec(attached[target].atomspec) start_atomspec = AtomSpec(target.atomspec) sub_atoms = rescol.get_fragment(start_atomspec, end_atomspec) sub = Substituent( sub_atoms, end=rescol.find_exact(end_atomspec)[0], detect=False, ) data = sub.sterimol( return_vector=True, radii=radii, old_L=old_L, ) l = np.linalg.norm(data["L"][1] - data["L"][0]) b1 = np.linalg.norm(data["B1"][1] - data["B1"][0]) b2 = np.linalg.norm(data["B2"][1] - data["B2"][0]) b3 = np.linalg.norm(data["B3"][1] - data["B3"][0]) b4 = np.linalg.norm(data["B4"][1] - data["B4"][0]) b5 = np.linalg.norm(data["B5"][1] - data["B5"][0]) if showVectors: for key, color in zip( ["B1", "B2", "B3", "B4", "B5", "L"], ["black", "green", "purple", "orange", "red", "blue"] ): start, end = data[key] s = ".color %s\n" % color s += ".note Sterimol %s\n" % key s += ".arrow %6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n" % (*start, *end) stream = BytesIO(bytes(s, "utf-8")) bild_obj, status = read_bild(session, stream, "Sterimol %s" % key) session.models.add(bild_obj, parent=model) if showRadii: s = ".note radii\n" s += ".transparency 75\n" color = None for atom in sub.atoms: chix_atom = atom.chix_atom if radii == "umn": r = VDW_RADII[chix_atom.element.name] elif radii == "bondi": r = BONDI_RADII[chix_atom.element.name] if color is None or chix_atom.color != color: color = chix_atom.color rgb = [x/255. for x in chix_atom.color] rgb.pop(-1) s += ".color %f %f %f\n" % tuple(rgb) s += ".sphere %f %f %f %f\n" % (*chix_atom.coord, r) stream = BytesIO(bytes(s, "utf-8")) bild_obj, status = read_bild(session, stream, "Sterimol radii") session.models.add(bild_obj, parent=model) model_name = get_filename(model.name, include_parent_dir=False) info += "%-16s\t%-11s\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n" % ( model_name, target.atomspec, b1, b2, b3, b4, b5, l ) model_names.append(model_name) targets.append(target.atomspec) datas.append(data) info = info.strip() info += "</pre>" if not return_values: session.logger.info(info, is_html=True) if return_values: return model_names, targets, datas
def percent_vbur( session, selection, radii="UMN", radius=3.5, scale=1.17, method="Lebedev", radialPoints=20, angularPoints=1454, minimumIterations=25, onlyAtoms=None, center=None, useCentroid=True, displaySphere=None, pointSpacing=0.075, intersectionScale=2, palette="rainbow", return_values=False, steric_map=False, use_scene=False, num_pts=100, shape="circle", ): out = [] models = { model: [ atom for atom in model.atoms if onlyAtoms is not None and atom in onlyAtoms ] for model in selection if isinstance(model, AtomicStructure) } s = "<pre>model\tcenter\t%Vbur\n" for model in models: if len(models[model]) == 0: targets = None else: targets = [AtomSpec(atom.atomspec) for atom in models[model]] if center is not None: if isinstance(center, tuple): mdl_center = np.array(center) else: mdl_center = [ AtomSpec(atom.atomspec) for atom in model.atoms if atom in center ] else: mdl_center = [] rescol = ResidueCollection(model) if use_scene: oop_vector = session.view.camera.get_position().axes()[2] ip_vector = session.view.camera.get_position().axes()[1] else: oop_vector = None ip_vector = None if len(mdl_center) == 0: rescol.detect_components() mdl_center = rescol.center elif not isinstance(center, np.ndarray): mdl_center = rescol.find([AtomSpec(c.atomspec) for c in center]) if not useCentroid and not isinstance(center, np.ndarray): for c in mdl_center: if steric_map: if targets is not None: key_atoms = [] targets = rescol.find(targets) for atom in targets: if c in atom.connected or atom in c.connected: key_atoms.append(atom) else: key_atoms = None x, y, z, min_alt, max_alt, basis, targets = rescol.steric_map( center=c, key_atoms=key_atoms, radii=radii, oop_vector=oop_vector, ip_vector=ip_vector, radius=radius, return_basis=True, num_pts=num_pts, shape=shape, ) vbur = rescol.percent_buried_volume( targets=targets, basis=basis, center=c, radius=radius, radii=radii, scale=scale, method=method, rpoints=int(radialPoints), apoints=int(angularPoints), min_iter=minimumIterations, ) out.append((model.name, c.atomspec, vbur, (x, y, z, min_alt, max_alt))) else: vbur = rescol.percent_buried_volume( targets=targets, center=c, radius=radius, radii=radii, scale=scale, method=method, rpoints=int(radialPoints), apoints=int(angularPoints), min_iter=minimumIterations, ) s += "%s\t%s\t%4.1f%%\n" % (model.name, c.atomspec, vbur) out.append((model.name, c.atomspec, vbur)) if displaySphere is not None: mdl = vbur_vis( session, rescol, targets, radii, scale, radius, c, pointSpacing, intersectionScale, displaySphere, ) model.add([mdl]) atomspec = mdl.atomspec center_coords = rescol.COM(c) #XXX: the center will be wrong if the models are tiled args = [ "color", "radial", atomspec, "center", ",".join(["%.4f" % x for x in center_coords]), "palette", palette, ";", "transparency", atomspec, "30", ] run(session, " ".join(args)) else: if steric_map: if targets is not None: key_atoms = [] targets = rescol.find(targets) for atom in targets: if any(c in atom.connected for c in mdl_center): key_atoms.append(atom) else: key_atoms = None x, y, z, min_alt, max_alt, basis, targets = rescol.steric_map( center=mdl_center, key_atoms=key_atoms, radius=radius, radii=radii, oop_vector=oop_vector, ip_vector=ip_vector, return_basis=True, num_pts=num_pts, shape=shape, ) vbur = rescol.percent_buried_volume( targets=targets, basis=basis, center=mdl_center, radius=radius, radii=radii, scale=scale, method=method, rpoints=int(radialPoints), apoints=int(angularPoints), min_iter=minimumIterations, ) if not isinstance(mdl_center, np.ndarray): out.append( (model.name, ",".join([c.atomspec for c in mdl_center]), vbur, (x, y, z, min_alt, max_alt))) else: out.append( (model.name, ",".join(["%.3f" % c for c in mdl_center]), vbur, (x, y, z, min_alt, max_alt))) else: vbur = rescol.percent_buried_volume( targets=targets, center=mdl_center, radius=radius, radii=radii, scale=scale, method=method, rpoints=int(radialPoints), apoints=int(angularPoints), min_iter=minimumIterations, ) if not isinstance(mdl_center, np.ndarray): s += "%s\t%s\t%4.1f%%\n" % (model.name, ", ".join( [c.atomspec for c in mdl_center]), vbur) out.append( (model.name, ", ".join([c.atomspec for c in mdl_center]), vbur)) else: s += "%s\t%s\t%4.1f%%\n" % (model.name, ",".join( ["%.3f" % c for c in mdl_center]), vbur) out.append( (model.name, ",".join(["%.3f" % c for c in mdl_center]), vbur)) if displaySphere is not None: mdl = vbur_vis( session, rescol, targets, radii, scale, radius, mdl_center, pointSpacing, intersectionScale, displaySphere, ) model.add([mdl]) atomspec = mdl.atomspec if not isinstance(mdl_center, np.ndarray): center_coords = rescol.COM(mdl_center) else: center_coords = mdl_center #XXX: the center will be wrong if the models are tiled args = [ "color", "radial", atomspec, "center", ",".join(["%.4f" % x for x in center_coords]), "palette", palette, ";", "transparency", atomspec, "30", ] run(session, " ".join(args)) s = s.strip() s += "</pre>" if not return_values: session.logger.info(s, is_html=True) else: return out
def refresh_chix_connected(self, atomic_structure, sanity_check=True): """updates atomic_structure's bonds to match self's connectivity sanity_check - bool; check to make sure atomic_structure corresponds to self""" if sanity_check: diff = self.difference(atomic_structure) for key in diff: if len(diff[key]) != 0: raise Exception("ResidueCollection does not correspond to AtomicStructure: \n%s\n\n%s" % \ (repr(self), repr(ResidueCollection(atomic_structure)))) known_bonds = [] for bond in atomic_structure.bonds: if self.convert_residues is None or all( atom.residue in self.convert_residues for atom in bond.atoms): a1, a2 = bond.atoms aaron_atom1 = self.find_exact(AtomSpec(a1.atomspec))[0] aaron_atom2 = self.find_exact(AtomSpec(a2.atomspec))[0] if aaron_atom1 in aaron_atom2.connected: known_bonds.append(sorted(( aaron_atom1, aaron_atom2, ))) else: bond.delete() for i, aaron_atom1 in enumerate(self.atoms): atom1 = [ atom for atom in atomic_structure.atoms if aaron_atom1.chix_atom is atom ][0] for aaron_atom2 in aaron_atom1.connected: if sorted(( aaron_atom1, aaron_atom2, )) in known_bonds: continue # if not hasattr(aaron_atom2, "chix_atom"): # print(aaron_atom2, "has no chix_atom") known_bonds.append(sorted(( aaron_atom1, aaron_atom2, ))) atom2 = [ atom for atom in atomic_structure.atoms if atom == aaron_atom2.chix_atom ] if len(atom2) > 0: atom2 = atom2[0] else: #we cannot draw a bond to an atom that is not in the residue #this could happen when previewing a substituent or w/e with the libadd tool continue if atom2 not in atom1.neighbors: new_bond = atomic_structure.new_bond(atom1, atom2) if any([ aaron_atom.element in TMETAL for aaron_atom in [aaron_atom1, aaron_atom2] ]): pbg = atomic_structure.pseudobond_group( atomic_structure.PBG_METAL_COORDINATION, create_type='normal') pbg.new_pseudobond(atom1, atom2) new_bond.delete()
def __init__(self, molecule, name="new", bonds_matter=True, convert_residues=None, use_scene=False, **kwargs): """molecule - chimerax AtomicStructure or AaronTools Geometry (for easy compatibility stuff) convert_residues - None to convert everything or [chimerax.atomic.Residue] to convert only specific residues this only applies to chimerax AtomicStructures bonds_matter - False to skip adding bonds/determining connectivity based on ChimeraX AtomicStructure """ object.__setattr__(self, "_hashed", False) self.convert_residues = convert_residues if isinstance(molecule, AtomicStructure): self.chix_atomicstructure = molecule self.residues = [] self.atomspec = molecule.atomspec #convert chimerax stuff to AaronTools all_atoms = [] if convert_residues is None: convert_residues = molecule.residues for i, residue in enumerate(convert_residues): new_res = Residue( residue, comment=molecule.comment if hasattr(molecule, "comment") else None, use_scene=use_scene, ) self.residues.append(new_res) all_atoms.extend(new_res.atoms) super().__init__( all_atoms, name=molecule.name, comment=molecule.comment if hasattr(molecule, "comment") else "", refresh_connected=False, refresh_ranks=bonds_matter, **kwargs, ) if not bonds_matter: return #update bonding to match that of the chimerax molecule for atom in all_atoms: for atom2 in all_atoms: if atom2.chix_atom not in atom.chix_atom.neighbors: continue atom.connected.add(atom2) #add bonds to metals tm_bonds = molecule.pseudobond_group( molecule.PBG_METAL_COORDINATION, create_type=None) if tm_bonds is not None: for pseudobond in tm_bonds.pseudobonds: atom1, atom2 = pseudobond.atoms if self.convert_residues is not None and ( atom1.residue not in self.convert_residues or atom2.residue not in self.convert_residues): continue aaron_atom1 = self.find(AtomSpec(atom1.atomspec))[0] aaron_atom2 = self.find(AtomSpec(atom2.atomspec))[0] aaron_atom1.connected.add(aaron_atom2) aaron_atom2.connected.add(aaron_atom1) else: #assume whatever we got is something AaronTools can turn into a Geometry super().__init__(molecule, name=name, **kwargs) self.chix_atomicstructure = None self.atomspec = None if "comment" in kwargs: self.residues = [ Residue(molecule, resnum=1, name="UNK", **kwargs) ] elif hasattr(molecule, "comment"): self.residues = [ Residue(molecule, resnum=1, name="UNK", comment=molecule.comment, **kwargs) ] else: self.residues = [ Residue(molecule, resnum=1, name="UNK", **kwargs) ] return
def libadd_ligand(self): """add ligand to library or open it in a new model""" selection = selected_atoms(self.session) if not selection.single_structure: raise RuntimeError("selected atoms must be on the same model") rescol = ResidueCollection(selection[0].structure) ligand_atoms = [ atom for atom in rescol.atoms if atom.chix_atom in selection ] key_chix_atoms = [ atom for atom in self.key_atomspec if not atom.deleted ] if len(key_chix_atoms) < 1: key_atoms = set([]) for atom in ligand_atoms: for atom2 in atom.connected: if atom2 not in ligand_atoms: key_atoms.add(atom) else: key_atoms = rescol.find( [AtomSpec(atom.atomspec) for atom in key_chix_atoms]) if len(key_atoms) < 1: raise RuntimeError("no key atoms could be determined") lig_name = self.ligand_name.text() ligand = Component(ligand_atoms, name=lig_name, key_atoms=key_atoms) ligand.comment = "K:%s" % ",".join( [str(ligand.atoms.index(atom) + 1) for atom in key_atoms]) if len(lig_name) == 0: chimerax_ligand = ResidueCollection(ligand).get_chimera( self.session) chimerax_ligand.name = "ligand preview" self.session.models.add([chimerax_ligand]) bild_obj = key_atom_highlight(ligand, [0.2, 0.5, 0.8, 0.5], self.session) self.session.models.add(bild_obj, parent=chimerax_ligand) else: check_aaronlib_dir() filename = os.path.join(AARONLIB, "Ligands", lig_name + ".xyz") if os.path.exists(filename): exists_warning = QMessageBox() exists_warning.setIcon(QMessageBox.Warning) exists_warning.setText( "%s already exists.\nWould you like to overwrite?" % filename) exists_warning.setStandardButtons(QMessageBox.Yes | QMessageBox.No) rv = exists_warning.exec_() if rv == QMessageBox.Yes: ligand.write(outfile=filename) self.tool_window.status("%s added to ligand library" % lig_name) else: self.tool_window.status( "%s has not been added to ligand library" % lig_name) else: ligand.write(outfile=filename) self.tool_window.status("%s added to ligand library" % lig_name)
def do_change_element(self): element = self.element.text() adjust_bonds = self.change_bonds.isChecked() self.settings.change_bonds = adjust_bonds vsepr = self.vsepr.currentText() if vsepr == "do not change": vsepr = False elif vsepr == "linear (1 bond)": vsepr = "linear 1" goal = 1 elif vsepr == "linear (2 bonds)": vsepr = "linear 2" goal = 2 elif vsepr == "trigonal planar (2 bonds)": vsepr = "bent 2 planar" goal = 2 elif vsepr == "tetrahedral (2 bonds)": vsepr = "bent 2 tetrahedral" goal = 2 elif vsepr == "trigonal planar": goal = 3 elif vsepr == "tetrahedral (3 bonds)": vsepr = "bent 3 tetrahedral" goal = 3 else: goal = len(Atom.get_shape(vsepr)) - 1 sel = selected_atoms(self.session) models, _ = guessAttachmentTargets(sel, self.session, allow_adjacent=False) for model in models: conv_res = list(models[model].keys()) for res in models[model]: for target in models[model][res]: for neighbor in target.neighbors: if neighbor.residue not in conv_res: conv_res.append(neighbor.residue) for pbg in self.session.models.list(type=PseudobondGroup): for pbond in pbg.pseudobonds: if target in pbond.atoms and all(atom.structure is model for atom in pbond.atoms): other_atom = pbond.other_atom(target) if other_atom.residue not in conv_res: conv_res.append(other_atom.residue) rescol = ResidueCollection(model, convert_residues=conv_res) for res in models[model]: residue = [resi for resi in rescol.residues if resi.chix_residue is res][0] for target in models[model][res]: targ = rescol.find_exact(AtomSpec(target.atomspec))[0] adjust_hydrogens = vsepr if vsepr is not False: cur_bonds = len(targ.connected) change_Hs = goal - cur_bonds adjust_hydrogens = (change_Hs, vsepr) residue.change_element(targ, element, adjust_bonds=adjust_bonds, adjust_hydrogens=adjust_hydrogens, ) residue.update_chix(res)
def do_maplig(self): lignames = self.ligname.text() selection = selected_atoms(self.session) if len(selection) < 1: raise RuntimeWarning("nothing selected") models = {} for atom in selection: if atom.structure not in models: models[atom.structure] = [AtomSpec(atom.atomspec)] else: models[atom.structure].append(AtomSpec(atom.atomspec)) first_pass = True new_structures = [] for ligname in lignames.split(','): ligname = ligname.strip() lig = Component(ligname) for model in models: if self.close_previous_bool and first_pass: rescol = ResidueCollection(model) elif self.close_previous_bool and not first_pass: raise RuntimeError("only the first model can be replaced") else: model_copy = model.copy() rescol = ResidueCollection(model_copy) for i, atom in enumerate(model.atoms): rescol.atoms[i].atomspec = atom.atomspec rescol.atoms[i].add_tag(atom.atomspec) rescol.atoms[i].chix_atom = atom target = rescol.find(models[model]) if len(target) % len(lig.key_atoms) == 0: k = 0 ligands = [] while k != len(target): res_lig = ResidueCollection(lig.copy(), comment=lig.comment) res_lig.parse_comment() res_lig = Component(res_lig, key_atoms = ",".join([str(k + 1) for k in res_lig.other["key_atoms"]])) ligands.append(res_lig) k += len(lig.key_atoms) else: raise RuntimeError("number of key atoms no not match: %i now, new ligand has %i" % (len(target), len(lig.key_atoms))) rescol.map_ligand(ligands, target) for center_atom in rescol.center: center_atom.connected = set([]) for atom in rescol.atoms: if atom not in rescol.center: if center_atom.is_connected(atom): atom.connected.add(center_atom) center_atom.connected.add(atom) if self.close_previous_bool: rescol.update_chix(model) else: struc = rescol.get_chimera(self.session) new_structures.append(struc) first_pass = False if not self.close_previous_bool: self.session.models.add(new_structures)