def get_matching_ligands(name): name_info = name coordinating_elements = None denticity = None if isinstance(name_info, str): if ("name:" not in name_info.lower() and "elements:" not in name_info.lower() and "denticity:" not in name_info.lower()): name_info = "^%s$" % name_info else: lig_info = name.split(":") for i, info in enumerate(lig_info): if info.lower() == "name" and i + 1 < len(lig_info): name_info = name_info.replace( "%s:%s" % (info, lig_info[i + 1]), "") name_info = lig_info[i + 1] elif info.lower() == "elements" and i + 1 < len(lig_info): name_info = name_info.replace( "%s:%s" % (info, lig_info[i + 1]), "") coordinating_elements = lig_info[i + 1].split(",") elif info.lower() == "denticity" and i + 1 < len(lig_info): name_info = name_info.replace( "%s:%s" % (info, lig_info[i + 1]), "") denticity = int(lig_info[i + 1]) if not name_info: name_info = None return Component.list(name_regex=name_info, coordinating_elements=coordinating_elements, denticity=denticity)
def test_sub_rotate(self): geom = TestComponent.RQ_tBu.copy() geom.sub_rotate("4", angle=60) geom.sub_rotate("6", angle=60) geom.sub_rotate("5", angle=60) ref = Component(os.path.join(prefix, "ref_files", "sub_rotate.xyz")) self.assertTrue(validate(geom, ref, heavy_only=True))
def test_minimize_torsion(self): geom = TestComponent.benz.copy() ref = Component("ref_files/minimize_torsion.xyz") geom.substitute(Substituent("tBu"), "12") geom.substitute(Substituent("Ph"), "10") geom.substitute(Substituent("OH"), "7") geom.minimize_sub_torsion() rmsd = geom.RMSD(ref, align=True) self.assertTrue(rmsd < 1)
def test_minimize_torsion(self): ref = Component( os.path.join(prefix, "ref_files", "minimize_torsion.xyz") ) geom = TestComponent.benz.copy() geom.substitute(Substituent("tBu"), "12") geom.substitute(Substituent("Ph"), "10") geom.substitute(Substituent("OH"), "7") geom.minimize_sub_torsion() self.assertTrue(validate(geom, ref, heavy_only=True))
def refresh_selection(self): lig_names = [] for row in self.lig_table.table.selectionModel().selectedRows(): if self.lig_table.table.isRowHidden(row.row()): continue lig_names.append(row.data()) if not lig_names: return self.nameWidget.setData(Qt.DisplayRole, ",".join(lig_names)) comp = Component(lig_names[0]) if len(comp.key_atoms) == 2: self.symmetryWidget.setEnabled(True) c2_symmetric = comp.c2_symmetric() if c2_symmetric: self.symmetryWidget.setCheckState(Qt.Checked) else: self.symmetryWidget.setCheckState(Qt.Unchecked) else: self.symmetryWidget.setEnabled(False)
def _decode_geometry(self, obj): if ATDecoder.with_progress: print("Loading structure", obj["name"], " " * 50, end="\r") kwargs = {"structure": obj["atoms"]} for key in ["name", "comment"]: kwargs[key] = obj[key] geom = Geometry(**kwargs, refresh_connected=False, refresh_ranks=False) for i, connected in enumerate(obj["connectivity"]): for c in connected: geom.atoms[i].connected.add(geom.atoms[c]) if obj["_type"] == "Component": key_atom_names = [a.name for a in obj["key_atoms"]] return Component(geom, key_atoms=key_atom_names) else: return geom
def do_new_lig(self): ligands = self.ligname.text() for lig in ligands.split(","): lig = lig.strip() rescol = ResidueCollection(Component(lig)) model = self.lig_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.lig_model_selector.setCurrentIndex(self.lig_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]))
def _decode_geometry(self, obj): kwargs = {"structure": obj["atoms"]} for key in ["name", "comment"]: kwargs[key] = obj[key] geom = Geometry(**kwargs, refresh_connected=False) for i, connected in enumerate(obj["connectivity"]): for c in connected: geom.atoms[i].connected.add(geom.atoms[c]) if obj["_type"] == "Component": key_atom_names = [a.name for a in obj["key_atoms"]] return Component(geom, key_atoms=key_atom_names, refresh_connected=False) elif obj["_type"] == "Catalyst": conf_spec = {} for key, val in obj["conf_spec"].items(): key = geom.find_exact(key)[0] conf_spec[key] = val kwargs = {"conf_spec": conf_spec} return Catalyst(geom, **kwargs, refresh_connected=False) else: return geom
def open_ligands(self): for row in self.lig_table.table.selectionModel().selectedRows(): if self.lig_table.table.isRowHidden(row.row()): continue lig_name = row.data() ligand = Component(lig_name) chimera_ligand = ResidueCollection( ligand, name=lig_name).get_chimera(self.session) self.session.models.add([chimera_ligand]) apply_seqcrow_preset(chimera_ligand, fallback="Ball-Stick-Endcap") if self.showLigKeyBool: color = self.lig_color.get_color() color = [c / 255. for c in color] self.settings.key_atom_color = tuple(color) bild_obj = key_atom_highlight(ligand, color, self.session) self.session.models.add(bild_obj, parent=chimera_ligand)
def test_map_ligand(self): monodentate = Component(TestGeometry.monodentate) tridentate = Component(TestGeometry.tridentate) debug = False # import cProfile # # profile = cProfile.Profile() # profile.enable() """ #TODO: get a reference file for this # two monodentate -> bidentate ptco4 = TestGeometry.ptco4.copy() ptco4.map_ligand('EDA', ["3", "5"]) """ # bidentate -> monodentate, none ref = Geometry(os.path.join(prefix, "ref_files", "lig_map_1.xyz")) tm_simple = Geometry(TestGeometry.tm_simple) tm_simple.map_ligand(monodentate.copy(), ["35"]) self.assertTrue( validate(tm_simple, ref, heavy_only=True, thresh="loose", debug=debug)) # bidentate -> two monodentate ref = Geometry(os.path.join(prefix, "ref_files", "lig_map_2.xyz")) tm_simple = Geometry(TestGeometry.tm_simple) tm_simple.map_ligand([monodentate.copy(), "ACN"], ["35", "36"]) self.assertTrue( validate(tm_simple, ref, thresh="loose", heavy_only=True, debug=debug)) # bidentate -> bidentate ref = Geometry(os.path.join(prefix, "ref_files", "lig_map_3.xyz")) tm_simple = Geometry(TestGeometry.tm_simple) tm_simple.map_ligand("S-tBu-BOX", ["35", "36"]) self.assertTrue( validate(tm_simple, ref, thresh="loose", heavy_only=True, debug=debug)) # tridentate -> tridentate ref = Geometry(os.path.join(prefix, "ref_files", "lig_map_4.xyz")) org_tri = Geometry(TestGeometry.org_tri) org_tri.map_ligand(tridentate, ["30", "28", "58"]) self.assertTrue( validate(org_tri, ref, thresh="loose", heavy_only=True, debug=debug)) # tridentate -> monodentate + bidentate -> tridentate ref = Geometry(os.path.join(prefix, "ref_files", "lig_map_6.xyz")) org_tri = Geometry(TestGeometry.org_tri) org_tri.map_ligand(["EDA", "ACN"], ["30", "28", "58"]) self.assertTrue( validate(org_tri, ref, thresh="loose", heavy_only=True, debug=debug)) ref = Geometry(os.path.join(prefix, "ref_files", "lig_map_7.xyz")) org_tri = Geometry(os.path.join(prefix, "ref_files", "lig_map_6.xyz")) org_tri.map_ligand(tridentate, ["10", "11", "2"]) self.assertTrue( validate(org_tri, ref, thresh="loose", heavy_only=True, debug=debug)) # bidentate -> two bulky monodentate ref = Geometry(os.path.join(prefix, "ref_files", "lig_map_5.xyz")) tm_simple = Geometry(TestGeometry.tm_simple) tm_simple.map_ligand(["iPr-NC3C"] * 2, ["35", "36"]) self.assertTrue( validate(tm_simple, ref, thresh="loose", heavy_only=True, debug=debug))
if args.input_format is not None: infile = FileReader((f, args.input_format[0], None)) else: infile = FileReader(f, just_geom=False) else: if args.input_format is not None: infile = FileReader(("from stdin", args.input_format[0], f)) else: if len(sys.argv) >= 1: infile = FileReader(("from stdin", "xyz", f)) geom = Geometry(infile) ligand = geom.get_fragment(args.key_atoms, stop=args.center) comp = Component(ligand, key_atoms=args.key_atoms, detect_backbone=False) angle = comp.cone_angle( center=geom.find(args.center), method=args.method, radii=args.radii, return_cones=args.print_cones, ) if args.print_cones: angle, cones = angle if len(args.infile) > 1: s += "%20s:\t" % f s += "%4.1f\n" % angle
def main(argv): sterimol_parser = argparse.ArgumentParser( description= "calculate B1-B5, and L sterimol parameters for ligands - see Verloop, A. and Tipker, J. (1976), Use of linear free energy related and other parameters in the study of fungicidal selectivity. Pestic. Sci., 7: 379-390.", formatter_class=argparse.RawTextHelpFormatter) sterimol_parser.add_argument("infile", metavar="input file", type=str, nargs="*", default=[sys.stdin], help="a coordinate file") sterimol_parser.add_argument( "-if", "--input-format", type=str, default=None, choices=read_types, dest="input_format", help="file format of input\nxyz is assumed if input is stdin") sterimol_parser.add_argument( "-k", "--key-atoms", type=str, required=True, dest="key", help="1-indexed position of the ligand's coordinating atoms") sterimol_parser.add_argument("-c", "--center-atom", type=str, required=True, dest="center", help="atom the ligand is coordinated to") sterimol_parser.add_argument( "-r", "--radii", type=str, default="bondi", choices=["bondi", "umn"], dest="radii", help="VDW radii to use in calculation\n" "umn: main group vdw radii from J. Phys. Chem. A 2009, 113, 19, 5806–5812\n" " (DOI: 10.1021/jp8111556)\n" " transition metals are crystal radii from Batsanov, S.S. Van der Waals\n" " Radii of Elements. Inorganic Materials 37, 871–885 (2001).\n" " (DOI: 10.1023/A:1011625728803)\n" "bondi: radii from J. Phys. Chem. 1964, 68, 3, 441–451\n(DOI: 10.1021/j100785a001)\n" "Default: bondi") sterimol_parser.add_argument( "-bl", "--bisect-L", action="store_true", required=False, dest="bisect_L", help="L axis will bisect (or analogous for higher denticity\n" "ligands) the L-M-L angle\n" "Default: center to centroid of key atoms") sterimol_parser.add_argument( "-al", "--at-L", default=[None], dest="L_value", type=lambda x: [float(v) for v in x.split(",")], help="get widths at specific L values (comma-separated)\n" "can be used for Sterimol2Vec parameters\n" "Default: use the entire ligand", ) sterimol_parser.add_argument( "-v", "--vector", action="store_true", required=False, dest="vector", help= "print Chimera/ChimeraX bild file for vectors instead of parameter values" ) sterimol_parser.add_argument("-o", "--output", type=str, default=False, required=False, metavar="output destination", dest="outfile", help="output destination\n" + "Default: stdout") args = sterimol_parser.parse_args(args=argv) s = "" if not args.vector: s += "B1\tB2\tB3\tB4\tB5\tL\tfile\n" for infile in glob_files(args.infile, parser=sterimol_parser): if isinstance(infile, str): if args.input_format is not None: f = FileReader((infile, args.input_format, infile)) else: f = FileReader(infile) else: if args.input_format is not None: f = FileReader(("from stdin", args.input_format, infile)) else: f = FileReader(("from stdin", "xyz", infile)) geom = Geometry(f, refresh_ranks=False) comp = Component( geom.get_fragment(args.key, stop=args.center), to_center=geom.find(args.center), key_atoms=args.key, detect_backbone=False, ) for val in args.L_value: data = comp.sterimol( to_center=geom.find(args.center), return_vector=args.vector, radii=args.radii, bisect_L=args.bisect_L, at_L=val, ) if args.vector: 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) else: s += "%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\t%s\n" % ( data["B1"], data["B2"], data["B3"], data["B4"], data["B5"], data["L"], infile, ) if not args.outfile: print(s) else: with open(args.outfile, "w") as f: f.write(s)
key_atoms = args.ligand.split("=")[0] lig_names = [ l for l in "=".join(args.ligand.split("=")[1:]).split(",") ] else: lig_names = [ l for l in "=".join(args.ligand.split("=")[1:]).split(",") ] key_atoms = [] for lig_names in [ get_matching_ligands(lig_name) for lig_name in lig_names ]: for lig_name in lig_names: ligands = [Component(lig_name)] cat_copy = cat.copy() if key_atoms != []: key = cat_copy.find(key_atoms) else: key = [] original_ligands = [l for l in ligands] lig_keys = sum([len(ligand.key_atoms) for ligand in ligands]) while len(key) > lig_keys: ligands.extend(l.copy() for l in original_ligands) lig_keys += sum( [len(ligand.key_atoms) for ligand in original_ligands])
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)
def test_component(self): lig = Component(TestJSON.lig) self.json_tester(lig, self.component_equal)
def map_ligand(self, ligands, old_keys, minimize=True): """ Maps new ligand according to key_map Parameters: :ligand: the name of a ligand in the ligand library :old_keys: the key atoms of the old ligand to map to """ def get_rotation(old_axis, new_axis): w = np.cross(old_axis, new_axis) angle = np.dot(old_axis, new_axis) angle /= np.linalg.norm(old_axis) angle /= np.linalg.norm(new_axis) # occasionally there will be some round-off errors, # so let's fix those before we take arccos if angle > 1 + 10**-12 or angle < -1 - 10**-12: # and check to make sure we aren't covering something # more senister up... raise ValueError("Bad angle value for arccos():", angle) elif angle > 1: angle = 1.0 elif angle < -1: angle = -1.0 angle = np.arccos(angle) return w, -1 * angle def map_1_key(self, ligand, old_key, new_key): # align new key to old key shift = new_key.bond(old_key) ligand.coord_shift(shift) # rotate ligand targets = old_key.connected - set(self.center) old_axis = self.COM(targets=targets) - old_key.coords new_axis = ligand.COM(targets=new_key.connected) - new_key.coords w, angle = get_rotation(old_axis, new_axis) ligand.rotate(w, angle, center=new_key) return ligand def map_2_key(old_ligand, ligand, old_keys, new_keys, rev_ang=False): # align COM of key atoms center = old_ligand.COM(targets=old_keys) shift = old_ligand.COM(targets=old_keys) - ligand.COM( targets=new_keys) ligand.coord_shift(shift) # rotate for best overlap old_axis = old_keys[0].bond(old_keys[1]) new_axis = new_keys[0].bond(new_keys[1]) w, angle = get_rotation(old_axis, new_axis) ligand.rotate(w, angle, center=center) # bend around key axis old_con = set([]) for k in old_keys: for c in k.connected: old_con.add(c) old_vec = old_ligand.COM(targets=old_con) - center new_con = set([]) for k in new_keys: for c in k.connected: new_con.add(c) new_vec = ligand.COM(targets=new_con) - center w, angle = get_rotation(old_vec, new_vec) if rev_ang: angle = -angle ligand.rotate(old_axis, -angle, center=center) def map_rot_frag(frag, a, b, ligand, old_key, new_key): old_vec = old_key.coords - b.coords new_vec = new_key.coords - b.coords axis, angle = get_rotation(old_vec, new_vec) ligand.rotate(b.bond(a), -1 * angle, targets=frag, center=b.coords) for c in new_key.connected: con_frag = ligand.get_fragment(new_key, c) if len(con_frag) > len(frag): continue old_vec = self.COM(targets=old_key.connected) old_vec -= old_key.coords new_vec = ligand.COM(targets=new_key.connected) new_vec -= new_key.coords axis, angle = get_rotation(old_vec, new_vec) ligand.rotate( c.bond(new_key), -1 * angle, targets=con_frag, center=new_key.coords, ) def map_more_key(self, old_ligand, ligand, old_keys, new_keys): # backbone fragments separated by rotatable bonds frag_list = ligand.get_frag_list(ligand.backbone, max_order=1) # get key atoms on each side of rotatable bonds key_count = {} for frag, a, b in frag_list: tmp = [] for i in frag: if i not in ligand.key_atoms: continue tmp += [i] if len(tmp) not in key_count: key_count[len(tmp)] = [(frag, a, b)] else: key_count[len(tmp)] += [(frag, a, b)] partial_map = False mapped_frags = [] for k in sorted(key_count.keys(), reverse=True): if k == 2 and not partial_map: frag, a, b = key_count[k][0] ok = [] nk = [] for i, n in enumerate(new_keys): if n not in frag: continue ok += [old_keys[i]] nk += [n] map_2_key(old_ligand, ligand, ok, nk, rev_ang=True) partial_map = True mapped_frags += [frag] continue if k == 1 and not partial_map: frag, a, b = key_count[k][0] for i, n in enumerate(new_keys): if n not in frag: continue map_1_key(self, ligand, n, old_keys[i]) partial_map = True mapped_frags += [frag] break continue if k == 1 and partial_map: for frag, a, b in key_count[k]: for i, n in enumerate(new_keys): if n not in frag: continue map_rot_frag(frag, a, b, ligand, old_keys[i], n) mapped_frags += [frag] break return old_keys = self.find(old_keys) if not hasattr(ligands, "__iter__") or isinstance(ligands, str): ligands = [ligands] new_keys = [] for i, ligand in enumerate(ligands): if not isinstance(ligand, Component): ligand = Component(ligand) ligands[i] = ligand ligand.refresh_connected() new_keys += ligand.key_atoms if len(old_keys) != len(new_keys): raise ValueError("Cannot map ligand. " + "Differing number of key atoms. " + "Old keys: " + ",".join([i.name for i in old_keys]) + "; " + "New keys: " + ",".join([i.name for i in new_keys])) old_ligands = [] for k in old_keys: for c in self.components["ligand"]: if k in c.atoms: old_ligands += [c] start = 0 end = None for i, ligand in enumerate(ligands): end = start + len(ligand.key_atoms) if len(ligand.key_atoms) == 1: map_1_key(self, ligand, old_keys[start], new_keys[start]) elif len(ligand.key_atoms) == 2: map_2_key( old_ligands[start], ligand, old_keys[start:end], new_keys[start:end], ) else: map_more_key( self, old_ligands[start], ligand, old_keys[start:end], new_keys[start:end], ) for l in ligand.atoms: l.name = old_keys[start].name + "." + l.name start = end # remove old for ol in old_ligands: try: self.components["ligand"].remove(ol) except ValueError: continue for atom in ol.atoms: if atom in self.conf_spec: del self.conf_spec[atom] for atom in self.atoms: if atom.connected & set(ol.atoms): atom.connected = atom.connected - set(ol.atoms) # add new for ligand in ligands: self.components["ligand"] += [ligand] for sub in ligand.substituents: if sub.conf_num is None or sub.conf_num <= 1: continue self.conf_spec[sub.atoms[0]] = [1, []] self.rebuild() self.remove_clash() if minimize: self.minimize()
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)
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 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)
class TestCatalyst(TestWithTimer): # C:34 L:35-93 K:1,2 F:1-34;1-2;2-34;2-3;3-34 tm_simple = Catalyst(prefix + "test_files/catalysts/tm_single-lig.xyz") tm_multi = Catalyst(prefix + "test_files/catalysts/tm_multi-lig.xyz") org_1 = Catalyst(prefix + "test_files/catalysts/org_1.xyz") org_tri = Catalyst(prefix + "test_files/catalysts/org_tri.xyz") catalysts = [tm_simple, tm_multi, org_1, org_tri] monodentate = Component(prefix + "test_files/ligands/ACN.xyz") bidentate = Component(prefix + "test_files/ligands/S-tBu-BOX.xyz") tridentate = Component(prefix + "test_files/ligands/squaramide.xyz") def validate(self, test, ref, thresh=None): if thresh is None: thresh = rmsd_tol(ref) t_el = sorted([t.element for t in test.atoms]) r_el = sorted([r.element for r in ref.atoms]) if len(t_el) != len(r_el): return False for t, r in zip(t_el, r_el): if t != r: return False rmsd = ref.RMSD(test, align=True) return rmsd < thresh def test_init(self): self.assertRaises(IOError, Catalyst, prefix + "test_files/R-Quinox-tBu3.xyz") def test_detect_components(self): def tester(ref, test): for comp, r in zip(test.components["ligand"], ref["ligand"]): good = True for i, j in zip(sorted([float(a) for a in comp.atoms]), r): if i != j: good = False self.assertTrue(good) for comp, r in zip(test.components["substrate"], ref["substrate"]): good = True for i, j in zip(sorted([float(a) for a in comp.atoms]), r): if i != j: good = False self.assertTrue(good) return def printer(test): print(test.comment) for name, component in test.components.items(): print(name) for comp in component: print("\t", sorted([float(a) for a in comp.atoms])) return args = [] ref = {} ref["ligand"] = [[float(i) for i in range(35, 94)]] ref["substrate"] = [[ 1.0, 2.0, 4.0, 5.0, 6.0, 7.0, 10.0, 11.0, 12.0, 15.0, 16.0, 17.0 ]] ref["substrate"] += [[ 3.0, 8.0, 9.0, 13.0, 14.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, 32.0, 33.0, ]] args += [(deepcopy(ref), TestCatalyst.tm_simple)] ref["ligand"] = [[9.0], [10.0]] ref["ligand"] += [[float(i) for i in range(11, 23)]] ref["ligand"] += [[float(i) for i in range(23, 93)]] ref["substrate"] = [[float(i) for i in range(1, 8)]] args += [(deepcopy(ref), TestCatalyst.tm_multi)] ref["ligand"] = [[float(i) for i in range(44, 144)]] ref["substrate"] = [[float(i) for i in range(1, 44)]] args += [(deepcopy(ref), TestCatalyst.org_1)] for a in args: tester(*a) def test_map_ligand(self): monodentate = TestCatalyst.monodentate tridentate = TestCatalyst.tridentate tm_simple = TestCatalyst.tm_simple.copy() tm_simple.map_ligand([monodentate, "ACN"], ["35", "36"]) self.assertTrue( self.validate(tm_simple, Geometry(prefix + "ref_files/lig_map_2.xyz"))) tm_simple = TestCatalyst.tm_simple.copy() tm_simple.map_ligand("S-tBu-BOX", ["35", "36"]) self.assertTrue( self.validate(tm_simple, Geometry(prefix + "ref_files/lig_map_3.xyz"))) org_tri = TestCatalyst.org_tri.copy() org_tri.map_ligand(tridentate, ["30", "28", "58"]) self.assertTrue( self.validate(org_tri, Geometry(prefix + "ref_files/lig_map_4.xyz"))) tm_simple = TestCatalyst.tm_simple.copy() tm_simple.map_ligand(monodentate, ["35"]) self.assertTrue( self.validate(tm_simple, Geometry(prefix + "ref_files/lig_map_1.xyz"))) def test_conf_spec(self): test_str = "" count = 0 for cat in TestCatalyst.catalysts: count += 1 for sub in sorted(cat.get_substituents()): start = sub.atoms[0] conf_num = cat.conf_spec[start] test_str += "{} {} {} {}\n".format(start.name, sub.name, sub.conf_num, conf_num) test_str += "\n" with open(prefix + "ref_files/conf_spec.txt") as f: self.assertEqual(test_str, f.read()) def test_fix_comment(self): cat = TestCatalyst.tm_simple.copy() cat.write("tmp") self.assertEqual(cat.comment, "C:34 K:1,5 L:35-93 F:1-2;1-34;2-13;2-34;13-34") cat.substitute("Me", "4") self.assertEqual(cat.comment, "C:37 K:1,5 L:38-96 F:1-2;1-37;2-16;2-37;16-37") def test_next_conformer(self): total = 24 + 32 + 4 big_count = 0 count = 0 for cat in TestCatalyst.catalysts: if cat == TestCatalyst.org_1: continue if count: big_count += count count = 1 cat.remove_clash() while True: if not cat.next_conformer(): break count += 1 utils.progress_bar(big_count + count, total) subs = sorted( [cat.find_substituent(c).name for c in cat.conf_spec.keys()]) if cat == TestCatalyst.tm_simple: self.assertListEqual(subs, sorted(["tBu", "tBu", "tBu", "Et"])) self.assertEqual(count, 24) elif cat == TestCatalyst.tm_multi: self.assertListEqual(subs, sorted(["Ph", "Ph", "Ph", "Ph", "CHO"])) self.assertEqual(count, 32) elif cat == TestCatalyst.org_tri: self.assertListEqual(subs, sorted(["Ph", "OMe"])) self.assertEqual(count, 4) utils.clean_progress_bar()
class TestComponent(TestWithTimer): # simple geometries benz = Component(os.path.join(prefix, "test_files", "benzene.xyz")) benz_Cl = Component(os.path.join(prefix, "test_files", "benzene_4-Cl.xyz")) benz_NO2_Cl = Component( os.path.join(prefix, "test_files", "benzene_1-NO2_4-Cl.xyz") ) benz_OH_Cl = Component( os.path.join(prefix, "test_files", "benzene_1-OH_4-Cl.xyz") ) benz_Ph_Cl = Component( os.path.join(prefix, "test_files", "benzene_1-Ph_4-Cl.xyz") ) Et_NO2 = Component(os.path.join(prefix, "test_files", "Et_1-NO2.xyz")) pent = Component(os.path.join(prefix, "test_files", "pentane.xyz")) # ligands RQ_tBu = Component(os.path.join(prefix, "test_files", "R-Quinox-tBu3.xyz")) for a in RQ_tBu.find("P"): a.add_tag("key") tri = Component( os.path.join(prefix, "test_files", "ligands", "squaramide.xyz") ) def is_member(self, valid, test): for a in valid: try: test.remove(a) except KeyError: return False if len(test) == 0: return True else: return False def test_substitute(self): mol = TestComponent.benz.copy() benz_Cl = TestComponent.benz_Cl.copy() benz_NO2_Cl = TestComponent.benz_NO2_Cl.copy() benz_OH_Cl = TestComponent.benz_OH_Cl.copy() benz_Ph_Cl = TestComponent.benz_Ph_Cl.copy() mol.substitute(Substituent("Cl"), "11") res = validate(mol, benz_Cl) self.assertTrue(res) mol.substitute(Substituent("NO2"), "12", "1") res = validate(mol, benz_NO2_Cl, sort=True) self.assertTrue(res) mol.substitute(Substituent("OH"), "NO2") res = validate(mol, benz_OH_Cl, sort=True) self.assertTrue(res) mol.substitute(Substituent("Ph"), ["12", "12.*"]) res = validate(mol, benz_Ph_Cl, sort=True, thresh="loose") self.assertTrue(res) def test_detect_backbone(self): geom = TestComponent.RQ_tBu.copy() backbone = geom.find("1,2,7-20") Me = geom.find("3,21-23") tBu = geom.find("4-6,24-59") try: test_Me = set(geom.find(["Me", "CH3"])) test_tBu = set(geom.find("tBu")) test_backbone = set(geom.find("backbone")) except LookupError: self.assertTrue(False) self.assertTrue(self.is_member(Me, test_Me)) self.assertTrue(self.is_member(tBu, test_tBu)) self.assertTrue(self.is_member(backbone, test_backbone)) def test_minimize_torsion(self): ref = Component( os.path.join(prefix, "ref_files", "minimize_torsion.xyz") ) geom = TestComponent.benz.copy() geom.substitute(Substituent("tBu"), "12") geom.substitute(Substituent("Ph"), "10") geom.substitute(Substituent("OH"), "7") geom.minimize_sub_torsion() self.assertTrue(validate(geom, ref, heavy_only=True)) def test_sub_rotate(self): geom = TestComponent.RQ_tBu.copy() geom.sub_rotate("4", angle=60) geom.sub_rotate("6", angle=60) geom.sub_rotate("5", angle=60) ref = Component(os.path.join(prefix, "ref_files", "sub_rotate.xyz")) self.assertTrue(validate(geom, ref, heavy_only=True))
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 detect_components(self, debug=False): self.components = {} self.center = [] # get center lig_assigned = False center_max = None for a in self.atoms: if "ligand" not in a.tags and a.element in TMETAL.keys(): # detect transition metal center if a not in self.center: self.center += [a] a.add_tag("center") if "center" in a.tags: # center provided by comment line in xyz file if a not in self.center: self.center += [a] if not lig_assigned and "ligand" in a.tags: lig_assigned = True if a in self.center: if center_max is None or center_max < float(a): center_max = float(a) if not lig_assigned and len(self.center) < 1: msg = ( "Non-transition metal centered catalysts must either have " + "active centers or ligand atoms specified in the comment " + "line of the XYZ input file") raise IOError(msg) # label ligand and substrate lig = [] subst = [] for a in self.atoms: if lig_assigned: if "ligand" in a.tags: lig += [a] elif float(a) > center_max: a.add_tag("ligand") lig += [a] for a in self.atoms: if "ligand" not in a.tags and "center" not in a.tags: a.add_tag("substrate") subst += [a] if debug: print("lig", [a.name for a in lig]) print("sub", [a.name for a in subst]) print("center", [a.name for a in self.center]) # label key atoms: for i, a in enumerate(lig): if "key_atoms" not in self.other: break if i in self.other["key_atoms"]: a.add_tag("key") else: del self.other["key_atoms"] # get components if len(self.center) > 0: self.components["ligand"] = self.detect_fragments(lig) self.components["substrate"] = self.detect_fragments(subst) else: self.components["ligand"] = self.detect_fragments(lig, subst) self.components["substrate"] = self.detect_fragments(subst, lig) # rename for i, lig in enumerate(self.components["ligand"]): name = self.name + "_lig-{}".format(lig[0].name) self.components["ligand"][i] = Component(lig, name, refresh_connected=False) for i, sub in enumerate(self.components["substrate"]): name = self.name + "_sub-{}".format(sub[0].name) self.components["substrate"][i] = Component( sub, name, refresh_connected=False) self.rebuild() return
class TestComponent(TestWithTimer): # simple geometries benz = Component(prefix + "test_files/benzene.xyz") benz_Cl = Component(prefix + "test_files/benzene_4-Cl.xyz") benz_NO2_Cl = Component(prefix + "test_files/benzene_1-NO2_4-Cl.xyz") benz_OH_Cl = Component(prefix + "test_files/benzene_1-OH_4-Cl.xyz") benz_Ph_Cl = Component(prefix + "test_files/benzene_1-Ph_4-Cl.xyz") Et_NO2 = Component(prefix + "test_files/Et_1-NO2.xyz") pent = Component(prefix + "test_files/pentane.xyz") # ligands RQ_tBu = Component(prefix + "test_files/R-Quinox-tBu3.xyz") for a in RQ_tBu.find("P"): a.add_tag("key") tri = Component(prefix + "test_files/ligands/squaramide.xyz") def is_member(self, valid, test): for a in valid: try: test.remove(a) except KeyError: return False if len(test) == 0: return True else: return False def is_same(self, valid, test): # same number of atoms if len(valid.atoms) != len(test.atoms): return False # of same elements tmp = [a.element for a in test.atoms] for e in [a.element for a in valid.atoms]: try: tmp.remove(e) except ValueError: return False # with reasonable rmsd if valid.RMSD(test, sort=True) > 10**-4: return False return True def test_substitute(self): mol = TestComponent.benz.copy() benz_Cl = TestComponent.benz_Cl.copy() benz_NO2_Cl = TestComponent.benz_NO2_Cl.copy() benz_OH_Cl = TestComponent.benz_OH_Cl.copy() benz_Ph_Cl = TestComponent.benz_Ph_Cl.copy() mol.substitute(Substituent("Cl"), "11") rmsd = mol.RMSD(benz_Cl, sort=True) self.assertTrue(rmsd < rmsd_tol(benz_Cl)) mol.substitute(Substituent("NO2"), "12", "1") rmsd = mol.RMSD(benz_NO2_Cl, sort=True) self.assertTrue(rmsd < rmsd_tol(benz_NO2_Cl)) mol.substitute(Substituent("OH"), "NO2") rmsd = mol.RMSD(benz_OH_Cl, sort=True) self.assertTrue(rmsd < rmsd_tol(benz_OH_Cl)) mol.substitute(Substituent("Ph"), "12.*") rmsd = mol.RMSD(benz_Ph_Cl) self.assertTrue(rmsd < rmsd_tol(benz_Ph_Cl)) def test_detect_backbone(self): geom = TestComponent.RQ_tBu.copy() geom.detect_backbone() backbone = geom.find("1,2,7-20") Me = geom.find("3,21-23") tBu = geom.find("4-6,24-59") try: test_Me = set(geom.find("Me")) test_tBu = set(geom.find("tBu")) test_backbone = set(geom.find("backbone")) except LookupError: self.assertTrue(False) self.assertTrue(self.is_member(Me, test_Me)) self.assertTrue(self.is_member(tBu, test_tBu)) self.assertTrue(self.is_member(backbone, test_backbone)) def test_minimize_torsion(self): geom = TestComponent.benz.copy() ref = Component("ref_files/minimize_torsion.xyz") geom.substitute(Substituent("tBu"), "12") geom.substitute(Substituent("Ph"), "10") geom.substitute(Substituent("OH"), "7") geom.minimize_sub_torsion() rmsd = geom.RMSD(ref, align=True) self.assertTrue(rmsd < 1)