def restore_selected(self): items = [item for item in self.tree.selectedItems()] model_dict = self.session.filereader_manager.filereader_dict models = list(model_dict.keys()) for item in items: parent = item.parent() mdl = models[self.tree.indexOfTopLevelItem(parent)] if parent is None: fr = model_dict[mdl][-1] else: fr = model_dict[mdl][parent.indexOfChild(item)] fr_rescol = ResidueCollection(fr) fr_rescol.update_chix(mdl) if fr.all_geom is not None and len(fr.all_geom) > 1: coordsets = fr_rescol.all_geom_coordsets(fr) mdl.remove_coordsets() mdl.add_coordsets(coordsets) for i, coordset in enumerate(coordsets): mdl.active_coordset_id = i + 1 for atom, coord in zip(mdl.atoms, coordset): atom.coord = coord mdl.active_coordset_id = 1
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 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 job_finished(self, trigger_name, job): """when a job is finished, open or update the structure as requested""" if self.session.seqcrow_settings.settings.JOB_FINISHED_NOTIFICATION == \ 'log and popup notifications' and self.session.ui.is_gui: #it's just an error message for now #TODO: make my own logger self.session.logger.error("%s: %s" % (trigger_name, job)) else: job.session.logger.info("%s: %s" % (trigger_name, job)) if isinstance(job, LocalJob): self._thread = None if not hasattr(job, "output_name") or \ not os.path.exists(job.output_name): job.error = True else: fr = FileReader(job.output_name, just_geom=False) #XXX: finished is not added to the FileReader for ORCA and Psi4 when finished = False if 'finished' not in fr.other or not fr.other['finished']: job.error = True if job.auto_update and ( job.theory.geometry.chix_atomicstructure is not None and not job.theory.geometry.chix_atomicstructure.deleted): if os.path.exists(job.output_name): finfo = job.output_name try: finfo = (job.output_name, job.format_name, None) fr = FileReader(finfo, get_all=True, just_geom=False) if len(fr.atoms) > 0: job.session.filereader_manager.triggers.activate_trigger( ADD_FILEREADER, ([job.theory.geometry.chix_atomicstructure], [fr])) rescol = ResidueCollection(fr) rescol.update_chix( job.theory.geometry.chix_atomicstructure) except: job.update_structure() if fr.all_geom is not None and len(fr.all_geom) > 1: coordsets = rescol.all_geom_coordsets(fr) job.theory.geometry.chix_atomicstructure.remove_coordsets() job.theory.geometry.chix_atomicstructure.add_coordsets( coordsets) for i, coordset in enumerate(coordsets): job.theory.geometry.chix_atomicstructure.active_coordset_id = i + 1 for atom, coord in zip( job.theory.geometry.chix_atomicstructure.atoms, coordset): atom.coord = coord job.theory.geometry.chix_atomicstructure.active_coordset_id = job.theory.geometry.chix_atomicstructure.num_coordsets elif job.auto_open or job.auto_update: if hasattr(job, "output_name") and os.path.exists(job.output_name): if job.format_name: run( job.session, "open \"%s\" coordsets true format %s" % (job.output_name, job.format_name)) else: run(job.session, "open \"%s\" coordsets true" % job.output_name) else: self.session.logger.error("could not open output of %s" % repr(job)) self.triggers.activate_trigger(JOB_QUEUED, trigger_name) pass
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 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)