def test_ring(self): try: import rdkit ring = Ring.from_string( "benzene", end_length=1, end_atom="C", form="iupac" ) ref = self.benzene self.assertTrue(validate(ring, ref, thresh="loose")) except ImportError: if any( user == os.getenv("USER", os.getenv("USERNAME", False)) for user in ["ajs99778", "normn"] ): ring = Ring.from_string( "benzene", end_length=1, end_atom="C", form="iupac" ) print(ring.comment) ref = self.benzene self.assertTrue( validate(ring, ref, thresh="loose", debug=True) ) else: self.skipTest("RDKit not installed, CACTVS is not tested")
def ring_substitute(self, target, ring, *args, **kwargs): """put a ring on the given targets""" if not isinstance(ring, Ring): ring = Ring(ring) residue = self.find_residue(target[0])[0] super().ring_substitute(target, ring, *args, **kwargs) new_atoms = [ atom for atom in self.atoms if not hasattr(atom, "chix_atom") ] residue.atoms.extend(new_atoms) for res in self.residues: deleted_atoms = [] for atom in res.atoms: if not hasattr(atom, "chix_atom"): continue if atom.chix_atom.residue is not res.chix_residue and atom in self.atoms: deleted_atoms.append(atom) elif atom not in self.atoms: deleted_atoms.append(atom) for atom in deleted_atoms: res.atoms.remove(atom)
def test_close_ring(self): mol = Geometry(TestGeometry.benzene) ref1 = Geometry(TestGeometry.naphthalene) mol1 = mol.copy() mol1.ring_substitute(["7", "8"], Ring("benzene")) self.assertTrue(validate(mol1, ref1, thresh="loose")) ref2 = Geometry(TestGeometry.tetrahydronaphthalene) mol2 = mol.copy() mol2.ring_substitute(["7", "8"], Ring("cyclohexane")) rmsd = mol2.RMSD(ref2, align=True, sort=True) self.assertTrue(rmsd < rmsd_tol(ref2, superLoose=True)) mol3 = Geometry(TestGeometry.naphthalene) ref3 = Geometry(TestGeometry.pyrene) targets1 = mol3.find(["9", "15"]) targets2 = mol3.find(["10", "16"]) mol3.ring_substitute(targets1, Ring("benzene")) mol3.ring_substitute(targets2, Ring("benzene")) rmsd = mol3.RMSD(ref3, align=True, sort=True) self.assertTrue(rmsd < rmsd_tol(ref3, superLoose=True))
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 open_rings(self): for row in self.ring_table.table.selectionModel().selectedRows(): if self.ring_table.table.isRowHidden(row.row()): continue ring_name = row.data() ring = Ring(ring_name, name=ring_name) chimera_ring = ResidueCollection(ring.copy()).get_chimera( self.session) self.session.models.add([chimera_ring]) apply_seqcrow_preset(chimera_ring, fallback="Ball-Stick-Endcap") if self.showRingWalkBool: color = self.ring_color.get_color() color = [c / 255. for c in color] self.ring_walk_color = tuple(color) bild_obj = show_walk_highlight(ring, chimera_ring, color, self.session) self.session.models.add(bild_obj, parent=chimera_ring)
def do_new_ring(self): rings = self.ringname.text() for ring in rings.split(","): ring = ring.strip() rescol = ResidueCollection(Ring(ring)) model = self.ring_model_selector.currentData() if model is None: chix = rescol.get_chimera(self.session) self.session.models.add([chix]) apply_seqcrow_preset(chix, fallback="Ball-Stick-Endcap") self.ring_model_selector.setCurrentIndex(self.ring_model_selector.count()-1) else: res = model.new_residue("new", "a", len(model.residues)+1) rescol.residues[0].update_chix(res) run(self.session, "select add %s" % " ".join([atom.atomspec for atom in res.atoms]))
"if no name is given, the ring will be printed to STDOUT" ) libaddring_parser.add_argument( '-w', '--walk', type=str, nargs=1, required=True, dest='walk', help="comma-separated list of atoms to define" + "the direction the ring is traversed (1-indexed)" ) args = libaddring_parser.parse_args() ring = Ring(args.infile) walk_atoms = args.walk.split(',') ring.find_end(len(walk_atoms), walk_atoms) ring.comment = "E:%s" % args.walk if args.name is None: print(ring.write(outfile=False)) else: ring_lib = Ring.AARON_LIBS ring_file = os.path.join(os.path.dirname(Ring.AARON_LIBS), args.name + '.xyz') if os.path.exists(ring_file): overwrite = input( "%s already exists.\nWould you like to overwrite it? (YES/no)\n" % ring_file )
class TestFromString(TestWithTimer): """ these only get run if RDKit is installed molecules can be fetched from CATCVS, but there can be discrepencies that make these tests "fail" """ COCH3 = Substituent("COCH3") NO2 = Substituent("NO2") benzene = Ring("benzene") chiral_geom = Geometry( os.path.join(prefix, "test_files", "chiral_ring.xyz") ) def is_COCH3(self, sub, thresh=0.03): ref = TestFromString.COCH3 ref.refresh_connected() sub.refresh_connected() ref.refresh_ranks() ref.refresh_ranks() ref.atoms = ref.reorder(start=ref.atoms[0])[0] sub.atoms = sub.reorder(start=sub.atoms[0])[0] self.assertTrue( validate( sub, ref, thresh=thresh, heavy_only=True, sort=False, debug=False, ) ) def is_NO2(self, sub): ref = TestFromString.NO2 self.assertTrue(validate(sub, ref, thresh=2e-1)) def test_substituent(self): try: import rdkit sub = Substituent.from_string( "acetyl", form="iupac", strict_use_rdkit=True ) self.is_COCH3(sub) with self.assertLogs(Substituent.LOG, level="WARNING"): sub = Substituent.from_string( "nitro", form="iupac", strict_use_rdkit=True ) self.is_NO2(sub) sub = Substituent.from_string( "O=[N.]=O", form="smiles", strict_use_rdkit=True ) self.is_NO2(sub) sub = Substituent.from_string( "O=[N]=O", form="smiles", strict_use_rdkit=True ) self.is_NO2(sub) except (ImportError, ModuleNotFoundError): # I still want to test CACTVS things because sometimes they change stuff # that breaks our stuff if any( user == os.getenv("USER", os.getenv("USERNAME", False)) for user in ["ajs99778", "normn"] ): sub = Substituent.from_string("acetyl", form="iupac") print(sub.write(outfile=False)) self.is_COCH3(sub, thresh=0.3) sub = Substituent.from_string("nitro", form="iupac") print(sub.write(outfile=False)) self.is_NO2(sub) sub = Substituent.from_string("O=[N.]=O", form="smiles") print(sub.write(outfile=False)) self.is_NO2(sub) sub = Substituent.from_string("O=[N]=O", form="smiles") print(sub.write(outfile=False)) self.is_NO2(sub) else: self.skipTest("RDKit not installed, CACTVS is not tested") def test_geometry(self): try: import rdkit geom = Geometry.from_string( "(1R,2R)-1-Chloro-2-methylcyclohexane", form="iupac" ) ref = TestFromString.chiral_geom # really loose threshhold b/c rdkit can give a boat cyclohexane... self.assertTrue(validate(geom, ref, thresh=0.35, heavy_only=True)) except (ImportError, ModuleNotFoundError): if any( user == os.getenv("USER", os.getenv("USERNAME", False)) for user in ["ajs99778", "normn"] ): geom = Geometry.from_string( "(1R,2R)-1-Chloro-2-methylcyclohexane", form="iupac" ) ref = TestFromString.chiral_geom # really loose threshhold b/c rdkit can give a boat cyclohexane... self.assertTrue( validate(geom, ref, thresh=0.35, heavy_only=True) ) else: self.skipTest("RDKit not installed, CACTVS is not tested") def test_ring(self): try: import rdkit ring = Ring.from_string( "benzene", end_length=1, end_atom="C", form="iupac" ) ref = self.benzene self.assertTrue(validate(ring, ref, thresh="loose")) except ImportError: if any( user == os.getenv("USER", os.getenv("USERNAME", False)) for user in ["ajs99778", "normn"] ): ring = Ring.from_string( "benzene", end_length=1, end_atom="C", form="iupac" ) print(ring.comment) ref = self.benzene self.assertTrue( validate(ring, ref, thresh="loose", debug=True) ) else: self.skipTest("RDKit not installed, CACTVS is not tested")
def fuseRing_list(session): s = "" for ringname in Ring.list(): s += "%s\n" % ringname session.logger.info(s.strip())
def _build_ui(self): layout = QGridLayout() self.alchemy_tabs = QTabWidget() #substitute substitute_tab = QWidget() substitute_layout = QGridLayout(substitute_tab) sublabel = QLabel("substituent name:") substitute_layout.addWidget(sublabel, 0, 0, Qt.AlignVCenter) self.subname = QLineEdit() # self.subname.setText("Et") sub_completer = NameCompleter(Substituent.list(), self.subname) self.subname.setCompleter(sub_completer) self.subname.setToolTip("name of substituent in the AaronTools library or your personal library\nseparate names with commas and uncheck 'modify selected structure' to create several structures") substitute_layout.addWidget(self.subname, 0, 1, Qt.AlignVCenter) open_sub_lib = QPushButton("from library...") open_sub_lib.clicked.connect(self.open_sub_selector) substitute_layout.addWidget(open_sub_lib, 0, 2, Qt.AlignTop) substitute_layout.addWidget(QLabel("modify selected structure:"), 1, 0, 1, 1, Qt.AlignVCenter) self.close_previous_sub = QCheckBox() self.close_previous_sub.setToolTip("checked: selected structure will be modified\nunchecked: new model will be created for the modified structure") self.close_previous_sub.setChecked(self.settings.modify) self.close_previous_sub.stateChanged.connect(self.close_previous_change) substitute_layout.addWidget(self.close_previous_sub, 1, 1, 1, 2, Qt.AlignTop) substitute_layout.addWidget(QLabel("relax substituent:"), 2, 0, 1, 1, Qt.AlignVCenter) self.minimize = QCheckBox() self.minimize.setToolTip("spin the added substituents to try to minimize the LJ potential energy") self.minimize.setChecked(self.settings.minimize) substitute_layout.addWidget(self.minimize, 2, 1, 1, 1, Qt.AlignTop) substitute_layout.addWidget(QLabel("guess previous substituent:"), 3, 0, 1, 1, Qt.AlignVCenter) self.guess_old = QCheckBox() self.guess_old.setToolTip("checked: leave the longest connected fragment in the residue\nunchecked: previous substituent must be selected") self.guess_old.setChecked(self.settings.guess) self.guess_old.stateChanged.connect(lambda state, settings=self.settings: settings.__setattr__("guess", True if state == Qt.Checked else False)) substitute_layout.addWidget(self.guess_old, 3, 1, 1, 2, Qt.AlignTop) substitute_layout.addWidget(QLabel("new residue:"), 5, 0, 1, 1, Qt.AlignVCenter) self.new_residue = QCheckBox() self.new_residue.setToolTip("put the new substituent in its own residue instead\nof adding it to the residue of the old substituent") self.new_residue.setChecked(self.settings.new_residue) self.new_residue.stateChanged.connect(lambda state, settings=self.settings: settings.__setattr__("new_residue", True if state == Qt.Checked else False)) substitute_layout.addWidget(self.new_residue, 5, 1, 1, 2, Qt.AlignTop) substitute_layout.addWidget(QLabel("use distance names:"), 4, 0, 1, 1, Qt.AlignVCenter) self.use_greek = QCheckBox() self.use_greek.setChecked(self.settings.use_greek) self.use_greek.setToolTip("indicate distance from point of attachment with atom name") substitute_layout.addWidget(self.use_greek, 4, 1, 1, 1, Qt.AlignTop) substitute_layout.addWidget(QLabel("change residue name:"), 6, 0, 1, 1, Qt.AlignVCenter) self.new_sub_name = QLineEdit() self.new_sub_name.setToolTip("change name of modified residues") self.new_sub_name.setPlaceholderText("leave blank to keep current") substitute_layout.addWidget(self.new_sub_name, 6, 1, 1, 2, Qt.AlignTop) substitute_button = QPushButton("substitute current selection") substitute_button.clicked.connect(self.do_substitute) substitute_layout.addWidget(substitute_button, 7, 0, 1, 3, Qt.AlignTop) self.substitute_button = substitute_button substitute_layout.setRowStretch(0, 0) substitute_layout.setRowStretch(1, 0) substitute_layout.setRowStretch(2, 0) substitute_layout.setRowStretch(3, 0) substitute_layout.setRowStretch(4, 0) substitute_layout.setRowStretch(5, 0) substitute_layout.setRowStretch(6, 0) substitute_layout.setRowStretch(7, 1) #map ligand maplig_tab = QWidget() maplig_layout = QGridLayout(maplig_tab) liglabel = QLabel("ligand name:") maplig_layout.addWidget(liglabel, 0, 0, Qt.AlignVCenter) self.ligname = QLineEdit() lig_completer = NameCompleter(Component.list(), self.ligname) self.ligname.setCompleter(lig_completer) self.ligname.setToolTip("name of ligand in the AaronTools library or your personal library\nseparate names with commas and uncheck 'modify selected structure' to create several structures") maplig_layout.addWidget(self.ligname, 0, 1, Qt.AlignVCenter) open_lig_lib = QPushButton("from library...") open_lig_lib.clicked.connect(self.open_lig_selector) maplig_layout.addWidget(open_lig_lib, 0, 2, Qt.AlignTop) maplig_layout.addWidget(QLabel("modify selected structure:"), 1, 0, 1, 1, Qt.AlignVCenter) self.close_previous_lig = QCheckBox() self.close_previous_lig.setToolTip("checked: selected structure will be modified\nunchecked: new model will be created for the modified structure") self.close_previous_lig.setChecked(self.settings.modify) self.close_previous_lig.stateChanged.connect(self.close_previous_change) maplig_layout.addWidget(self.close_previous_lig, 1, 1, 1, 2, Qt.AlignTop) maplig_button = QPushButton("swap ligand with selected coordinating atoms") maplig_button.clicked.connect(self.do_maplig) maplig_layout.addWidget(maplig_button, 2, 0, 1, 3, Qt.AlignTop) self.maplig_button = maplig_button start_structure_button = QPushButton("place in:") self.lig_model_selector = ModelComboBox(self.session, addNew=True) start_structure_button.clicked.connect(self.do_new_lig) maplig_layout.addWidget(start_structure_button, 3, 0, 1, 1, Qt.AlignTop) maplig_layout.addWidget(self.lig_model_selector, 3, 1, 1, 2, Qt.AlignTop) maplig_layout.setRowStretch(0, 0) maplig_layout.setRowStretch(1, 0) maplig_layout.setRowStretch(2, 0) maplig_layout.setRowStretch(3, 1) #close ring closering_tab = QWidget() closering_layout = QGridLayout(closering_tab) ringlabel = QLabel("ring name:") closering_layout.addWidget(ringlabel, 0, 0, Qt.AlignVCenter) self.ringname = QLineEdit() ring_completer = NameCompleter(Ring.list(), self.ringname) self.ringname.setCompleter(ring_completer) self.ringname.setToolTip("name of ring in the AaronTools library or your personal library\nseparate names with commas and uncheck 'modify selected structure' to create several structures") closering_layout.addWidget(self.ringname, 0, 1, Qt.AlignVCenter) open_ring_lib = QPushButton("from library...") open_ring_lib.clicked.connect(self.open_ring_selector) closering_layout.addWidget(open_ring_lib, 0, 2, Qt.AlignTop) closering_layout.addWidget(QLabel("modify selected structure:"), 1, 0, 1, 1, Qt.AlignVCenter) self.close_previous_ring = QCheckBox() self.close_previous_ring.setToolTip("checked: selected structure will be modified\nunchecked: new model will be created for the modified structure") self.close_previous_ring.setChecked(self.settings.modify) self.close_previous_ring.stateChanged.connect(self.close_previous_change) closering_layout.addWidget(self.close_previous_ring, 1, 1, 1, 2, Qt.AlignTop) closering_layout.addWidget(QLabel("try multiple:"), 2, 0, 1, 1, Qt.AlignVCenter) self.minimize_ring = QCheckBox() self.minimize_ring.setToolTip("try to use other versions of this ring in the library to find the one that fits best") self.minimize_ring.setChecked(self.settings.minimize_ring) closering_layout.addWidget(self.minimize_ring, 2, 1, 1, 2, Qt.AlignTop) closering_layout.addWidget(QLabel("new residue name:"), 3, 0, 1, 1, Qt.AlignVCenter) self.new_ring_name = QLineEdit() self.new_ring_name.setToolTip("change name of modified residues") self.new_ring_name.setPlaceholderText("leave blank to keep current") closering_layout.addWidget(self.new_ring_name, 3, 1, 1, 2, Qt.AlignTop) closering_button = QPushButton("put a ring on current selection") closering_button.clicked.connect(self.do_fusering) closering_layout.addWidget(closering_button, 4, 0, 1, 3, Qt.AlignTop) self.closering_button = closering_button start_structure_button = QPushButton("place in:") self.ring_model_selector = ModelComboBox(self.session, addNew=True) start_structure_button.clicked.connect(self.do_new_ring) closering_layout.addWidget(start_structure_button, 5, 0, 1, 1, Qt.AlignTop) closering_layout.addWidget(self.ring_model_selector, 5, 1, 1, 2, Qt.AlignTop) closering_layout.setRowStretch(0, 0) closering_layout.setRowStretch(1, 0) closering_layout.setRowStretch(2, 0) closering_layout.setRowStretch(3, 0) closering_layout.setRowStretch(4, 0) closering_layout.setRowStretch(5, 1) #change element changeelement_tab = QWidget() changeelement_layout = QFormLayout(changeelement_tab) self.element = ElementButton("C", single_state=True) self.element.clicked.connect(self.open_ptable) changeelement_layout.addRow("element:", self.element) self.vsepr = QComboBox() self.vsepr.addItems([ "do not change", # 0 "linear (1 bond)", # 1 "linear (2 bonds)", # 2 "trigonal planar (2 bonds)", # 3 "tetrahedral (2 bonds)", # 4 "trigonal planar", # 5 "tetrahedral (3 bonds)", # 6 "T-shaped", # 7 "trigonal pyramidal", # 8 "tetrahedral", # 9 "sawhorse", #10 "seesaw", #11 "square planar", #12 "trigonal bipyramidal", #13 "square pyramidal", #14 "pentagonal", #15 "octahedral", #16 "hexagonal", #17 "trigonal prismatic", #18 "pentagonal pyramidal", #19 "capped octahedral", #20 "capped trigonal prismatic", #21 "heptagonal", #22 "hexagonal pyramidal", #23 "pentagonal bipyramidal", #24 "biaugmented trigonal prismatic", #25 "cubic", #26 "elongated trigonal bipyramidal", #27 "hexagonal bipyramidal", #28 "heptagonal pyramidal", #29 "octagonal", #30 "square antiprismatic", #31 "trigonal dodecahedral", #32 "capped cube", #33 "capped square antiprismatic", #34 "enneagonal", #35 "heptagonal bipyramidal", #36 "hula-hoop", #37 "triangular cupola", #38 "tridiminished icosahedral", #39 "muffin", #40 "octagonal pyramidal", #41 "tricapped trigonal prismatic", #42 ]) self.vsepr.setCurrentIndex(9) self.vsepr.insertSeparator(33) self.vsepr.insertSeparator(25) self.vsepr.insertSeparator(20) self.vsepr.insertSeparator(16) self.vsepr.insertSeparator(13) self.vsepr.insertSeparator(8) self.vsepr.insertSeparator(5) self.vsepr.insertSeparator(2) self.vsepr.insertSeparator(1) self.vsepr.insertSeparator(0) changeelement_layout.addRow("geometry:", self.vsepr) self.change_bonds = QCheckBox() self.change_bonds.setChecked(self.settings.change_bonds) changeelement_layout.addRow("adjust bond lengths:", self.change_bonds) change_element_button = QPushButton("change selected elements") change_element_button.clicked.connect(self.do_change_element) changeelement_layout.addRow(change_element_button) self.change_element_button = change_element_button start_structure_button = QPushButton("place in:") self.model_selector = ModelComboBox(self.session, addNew=True) start_structure_button.clicked.connect(self.do_new_atom) changeelement_layout.addRow(start_structure_button, self.model_selector) delete_atoms_button = QPushButton("delete selected atoms") delete_atoms_button.clicked.connect(self.delete_atoms) changeelement_layout.addRow(delete_atoms_button) self.alchemy_tabs.addTab(substitute_tab, "substitute") self.alchemy_tabs.addTab(maplig_tab, "swap ligand") self.alchemy_tabs.addTab(closering_tab, "fuse ring") self.alchemy_tabs.addTab(changeelement_tab, "change element") layout.addWidget(self.alchemy_tabs) self.tool_window.ui_area.setLayout(layout) self.tool_window.manage(None)
help="try to minimize structure difference") ring_parser.add_argument("-f", "--flip-rings", action="store_const", const=True, default=False, required=False, dest="flip", help="also try swapping target order when minimizing") args = ring_parser.parse_args() if args.list_avail: s = "" for i, name in enumerate(sorted(Ring.list())): s += "%-20s" % name # if (i + 1) % 3 == 0: if (i + 1) % 1 == 0: s += "\n" print(s.strip()) exit(0) for infile in glob_files(args.infile, parser=ring_parser): if isinstance(infile, str): if args.input_format is not None: f = FileReader((infile, args.input_format, infile)) else: f = FileReader(infile) else: